Last active
June 6, 2022 01:47
-
-
Save EmmanuelAdeiza/7bb57c3ee56ffa46bd1642f03c0401db to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=builtin&optimize=false&runs=200&gist=
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: GPL-3.0 | |
pragma solidity ^0.8.4; | |
contract Purchase { | |
uint public value; | |
address payable public seller; | |
address payable public buyer; | |
uint256 public lastRun; | |
enum State { Created, Locked, Release, Inactive } | |
// The state variable has a default value of the first member, `State.created` | |
State public state; | |
modifier condition(bool condition_) { | |
require(condition_); | |
_; | |
} | |
/// Only the buyer can call this function. | |
error OnlyBuyer(); | |
/// Only the seller can call this function. | |
error OnlySeller(); | |
/// The function cannot be called at the current state. | |
error InvalidState(); | |
/// The provided value has to be even. | |
error ValueNotEven(); | |
modifier onlyBuyer() { | |
if (msg.sender != buyer) | |
revert OnlyBuyer(); | |
_; | |
} | |
modifier onlySeller() { | |
if (msg.sender != seller) | |
revert OnlySeller(); | |
_; | |
} | |
modifier inState(State state_) { | |
if (state != state_) | |
revert InvalidState(); | |
_; | |
} | |
modifier OnlyBuyerOnlyAfter () { | |
if ((block.timestamp - lastRun < 5 minutes)||(msg.sender != buyer)) | |
revert ("Last RUN NOT GREATER THAN 5 MINUTES or Only callable by Buyer"); | |
_; | |
} | |
event Aborted(); | |
event PurchaseConfirmed(); | |
event ItemReceived(); | |
event SellerRefunded(); | |
// 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() payable { | |
seller = payable(msg.sender); | |
value = msg.value / 2; | |
if ((2 * value) != msg.value) | |
revert ValueNotEven(); | |
} | |
/// Abort the purchase and reclaim the ether. | |
/// Can only be called by the seller before | |
/// the contract is locked. | |
function abort() | |
external | |
onlySeller | |
inState(State.Created) | |
{ | |
emit Aborted(); | |
state = State.Inactive; | |
// We use transfer here directly. It is | |
// reentrancy-safe, because it is the | |
// last call in this function and we | |
// already changed the state. | |
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() | |
external | |
inState(State.Created) | |
condition(msg.value == (2 * value)) | |
payable | |
{ | |
emit PurchaseConfirmed(); | |
buyer = payable(msg.sender); | |
state = State.Locked; | |
lastRun = block.timestamp; | |
} | |
/// Confirm that you (the buyer) received the item. | |
/// This will release the locked ether. | |
/// And | |
/// Refunds the seller, i.e. | |
/// pays back the locked funds of the seller. | |
function completePurchase() external inState(State.Locked) OnlyBuyerOnlyAfter { | |
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.Release; | |
buyer.transfer(value); | |
emit SellerRefunded(); | |
// It is important to change the state first because | |
// otherwise, the contracts called using `send` below | |
// can call in again here. | |
state = State.Inactive; | |
seller.transfer(3 * value); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment