pragma solidity ^0.4.8; contract Purchase { string public title; string public description; uint public value; address public seller; address public buyer; enum State { Created, Locked, Inactive } State public state; function Purchase(string _title, string _description) payable { value = msg.value / 2; if (2 * value != msg.value) throw; seller = msg.sender; title = _title; description = _description; state = State.Created; } modifier require(bool _condition) { if (!_condition) throw; _; } modifier onlyBuyer() { if (msg.sender != buyer) throw; _; } modifier onlySeller() { if (msg.sender != seller) throw; _; } modifier inState(State _state) { if (state != _state) throw; _; } 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() onlySeller inState(State.Created) { aborted(); state = State.Inactive; if (!seller.send(this.balance)) throw; } /// Confirm the purchase as buyer. /// Transaction has to include `2 * value` ether. /// The ether will be locked until confirmReceived /// is called. function confirmPurchase() inState(State.Created) require(msg.value == 2 * value) payable { purchaseConfirmed(); buyer = msg.sender; state = State.Locked; } /// Confirm that you (the buyer) received the item. /// This will release the locked ether. function confirmReceived() onlyBuyer inState(State.Locked) { 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; // This actually allows both the buyer and the seller to // block the refund. if (!buyer.send(value) || !seller.send(this.balance)) throw; } }