diff options
-rw-r--r-- | docs/examples/safe-remote.rst | 107 | ||||
-rw-r--r-- | docs/solidity-by-example.rst | 108 |
2 files changed, 108 insertions, 107 deletions
diff --git a/docs/examples/safe-remote.rst b/docs/examples/safe-remote.rst new file mode 100644 index 00000000..cfc63a24 --- /dev/null +++ b/docs/examples/safe-remote.rst @@ -0,0 +1,107 @@ +.. index:: purchase, remote purchase, escrow + +******************** +Safe Remote Purchase +******************** + +:: + + pragma solidity >=0.4.22 <0.6.0; + + contract Purchase { + uint public value; + address payable public seller; + address payable public buyer; + enum State { Created, Locked, Inactive } + State public state; + + // Ensure that `msg.value` is an even number. + // Division will truncate if it is an odd number. + // Check via multiplication that it wasn't an odd number. + constructor() public payable { + seller = msg.sender; + value = msg.value / 2; + require((2 * value) == msg.value, "Value has to be even."); + } + + modifier condition(bool _condition) { + require(_condition); + _; + } + + modifier onlyBuyer() { + require( + msg.sender == buyer, + "Only buyer can call this." + ); + _; + } + + modifier onlySeller() { + require( + msg.sender == seller, + "Only seller can call this." + ); + _; + } + + modifier inState(State _state) { + require( + state == _state, + "Invalid state." + ); + _; + } + + event Aborted(); + event PurchaseConfirmed(); + event ItemReceived(); + + /// Abort the purchase and reclaim the ether. + /// Can only be called by the seller before + /// the contract is locked. + function abort() + public + onlySeller + inState(State.Created) + { + emit Aborted(); + state = State.Inactive; + seller.transfer(address(this).balance); + } + + /// Confirm the purchase as buyer. + /// Transaction has to include `2 * value` ether. + /// The ether will be locked until confirmReceived + /// is called. + function confirmPurchase() + public + inState(State.Created) + condition(msg.value == (2 * value)) + payable + { + emit PurchaseConfirmed(); + buyer = msg.sender; + state = State.Locked; + } + + /// Confirm that you (the buyer) received the item. + /// This will release the locked ether. + function confirmReceived() + public + onlyBuyer + inState(State.Locked) + { + emit ItemReceived(); + // It is important to change the state first because + // otherwise, the contracts called using `send` below + // can call in again here. + state = State.Inactive; + + // NOTE: This actually allows both the buyer and the seller to + // block the refund - the withdraw pattern should be used. + + buyer.transfer(value); + seller.transfer(address(this).balance); + } + }
\ No newline at end of file diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index ddead4d5..933b0765 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -5,113 +5,7 @@ Solidity by Example .. include:: examples/voting.rst .. include:: examples/blind-auction.rst -.. index:: purchase, remote purchase, escrow - -******************** -Safe Remote Purchase -******************** - -:: - - pragma solidity >=0.4.22 <0.6.0; - - contract Purchase { - uint public value; - address payable public seller; - address payable public buyer; - enum State { Created, Locked, Inactive } - State public state; - - // Ensure that `msg.value` is an even number. - // Division will truncate if it is an odd number. - // Check via multiplication that it wasn't an odd number. - constructor() public payable { - seller = msg.sender; - value = msg.value / 2; - require((2 * value) == msg.value, "Value has to be even."); - } - - modifier condition(bool _condition) { - require(_condition); - _; - } - - modifier onlyBuyer() { - require( - msg.sender == buyer, - "Only buyer can call this." - ); - _; - } - - modifier onlySeller() { - require( - msg.sender == seller, - "Only seller can call this." - ); - _; - } - - modifier inState(State _state) { - require( - state == _state, - "Invalid state." - ); - _; - } - - event Aborted(); - event PurchaseConfirmed(); - event ItemReceived(); - - /// Abort the purchase and reclaim the ether. - /// Can only be called by the seller before - /// the contract is locked. - function abort() - public - onlySeller - inState(State.Created) - { - emit Aborted(); - state = State.Inactive; - seller.transfer(address(this).balance); - } - - /// Confirm the purchase as buyer. - /// Transaction has to include `2 * value` ether. - /// The ether will be locked until confirmReceived - /// is called. - function confirmPurchase() - public - inState(State.Created) - condition(msg.value == (2 * value)) - payable - { - emit PurchaseConfirmed(); - buyer = msg.sender; - state = State.Locked; - } - - /// Confirm that you (the buyer) received the item. - /// This will release the locked ether. - function confirmReceived() - public - onlyBuyer - inState(State.Locked) - { - emit ItemReceived(); - // It is important to change the state first because - // otherwise, the contracts called using `send` below - // can call in again here. - state = State.Inactive; - - // NOTE: This actually allows both the buyer and the seller to - // block the refund - the withdraw pattern should be used. - - buyer.transfer(value); - seller.transfer(address(this).balance); - } - } +.. include:: examples/safe-remote.rst ******************** Micropayment Channel |