Code has been added to clipboard!
Remote Purchase with Smart Contracts
Example
pragma solidity ^0.4.11;
contract Purchase {
uint public purchaseValue;
address public sellerAddress;
address public buyerAddress;
enum purchaseState { Created, Locked, Inactive }
purchaseState public purchasestate;
// Make sure that `msg.value` is an even number.
// Division truncates if the number is odd.
// Use multiplication to check that it wasn't an odd number.
function Purchase() payable {
sellerAddress = msg.sender;
purchaseValue = msg.value / 2;
require((2 * purchaseValue) == msg.value);
}
modifier condition(bool _condition) {
require(_condition);
_;
}
modifier onlyBuyerAddress() {
require(msg.sender == buyerAddress);
_;
}
modifier onlySellerAddress() {
require(msg.sender == sellerAddress);
_;
}
modifier inPurchaseState(purchaseState _purchasestate) {
require(purchasestate == _purchasestate);
_;
}
event abortedPurchase();
event confirmedPurchase();
event receivedItem();
/// Purchase is aborted and ether is reclaimed.
/// May only be called by the seller before
/// locking the contract.
function abortPurchase()
onlySellerAddress
inPurchaseState(purchaseState.Created)
{
abortedPurchase();
purchasestate = purchaseState.Inactive;
sellerAddress.transfer(this.balance);
}
/// The purchase confirmed as a buyer.
/// Transaction includes `2 * purchaseValue` ether.
/// The ether is locked until receivedConfirm
/// is called.
function purchaseConfirm()
inPurchaseState(purchaseState.Created)
condition(msg.value == (2 * purchaseValue))
payable
{
confirmedPurchase();
buyerAddress = msg.sender;
purchasestate = purchaseState.Locked;
}
/// Confirm that you (the buyerAddress) received the item.
/// This will release the locked ether.
function receivedConfirm()
onlyBuyerAddress
inPurchaseState(purchaseState.Locked)
{
receivedItem();
// It is crucial to change the purchasestate firsthand since
// otherwise, the contracts called using `send` below
// can call in again here.
purchasestate = purchaseState.Inactive;
// NOTE: this will allow both sellerAddress and the buyerAddress to
// block the refund - it is recommended to use the withdraw pattern.
buyerAddress.transfer(purchaseValue);
sellerAddress.transfer(this.balance);
}
}