0
votes

I'm currently trying to develop a simple smart contract

Being relatively new to this, can multiple pairs of users interact with the contract at the same time and benefit from the escrow (will it instantiate a new version for every pair) ?

It's essentially an escrow contract that will hold the funds from a transaction until both the buyer and the seller have accepted the release. Additionally, if the either one of them does not accept the funds will be withheld by the smart contract for a duration of 30 days. Also, how can I add the address that initially deployed the smart and transfer 3% of the total deposit to that address if the transaction was successful ?

This is what I have tried for now:

pragma solidity 0.7.0;

contract NewEscrow {


enum State {AWAITING_FUNDS,AWAITING_CLAIM,CLAIM,COMPLETE}

State public currentState; 


address payable public buyer; 
address payable public seller; 
address payable public owner; 

uint256 public agreementDay; 

mapping (address => uint256) deposits;




// checks if msg.sender is equal to buyer
modifier onlyBuyer (){
    require(msg.sender == buyer);
    _; 
}


// checks if msg.sender is equal to seller
modifier onlySeller(){
    require(msg.sender == seller);
    _; 
}


constructor (){
    owner = msg.sender; 
}


function setVariables (address payable _buyer, address payable _seller, uint256 _agreementDay) public {
    buyer = _buyer; 
    seller = _seller; 
    agreementDay = _agreementDay + 30 days; 
    currentState = State.AWAITING_FUNDS;
}



function deposit() public onlyBuyer payable {
    require(currentState == State.AWAITING_FUNDS);
    uint256 amount = msg.value;
    deposits[seller] = deposits[seller] + amount; 
    currentState = State.AWAITING_CLAIM;
}


function claim () public onlySeller {
    require(currentState == State.AWAITING_CLAIM);
    currentState = State.CLAIM;
}


function confirm () public onlyBuyer {
    uint256 payment = deposits[seller];
    deposits[seller] = 0; 
    seller.transfer(payment); 
    currentState = State.COMPLETE;
}



function cancelPayement () public onlySeller  {
    uint256 payment = deposits[seller];
    deposits[seller] = 0; 
    buyer.transfer(payment); 
    currentState = State.COMPLETE;
}


function release() public{
    
    
        // funds cannot be retrieved before release day
        require (agreementDay < block.timestamp);
        uint256 payment = deposits[seller];
        deposits[seller] = 0; 
        buyer.transfer(payment);
        revert('funds returned');
    }
}
1

1 Answers

0
votes
  1. can multiple pairs of users interact with the contract at the same time and benefit from the escrow

    Currently not. Only the first pair of users would be able to use it, as currently buyer and seller variables can only hold one value each.

    If you want to scale for multiple pairs, you need to make an array of structs representing the buyer and seller connection. From the top of my head, it would look like:

    struct Pair {
       address buyer;
       address seller;
    }
    
    Pair[] pairs;
    

    Or another approach, where a common index of the arrays shows that the buyer and seller are connected.

    address[] buyers;
    address[] sellers;
    

    This scaling would also mean expanding most of the current logic to validate whether the input buyer and seller are connected.

  2. if the either one of them does not accept the funds will be withheld by the smart contract for a duration of 30 days

    You'll need to create a new function that checks whether the deposit has been withdrawn and whether it's (deposit date + 30 days) and some validation who can actually withdraw this money.

    address constant contractOwner = '0x123'
    
    function withdrawOwner() external {
        require(msg.sender == contractOwner); // validate who can withdraw
        require(agreementDay + 30 days <= block.timestamp); // check if 30 days has passed since the deposit date
        require(deposits[seller] > 0); // check that it hasn't been withdrawn
        uint256 amount = deposits[seller]; // make sure the contract is not vulnerable to reentrancy
        deposits[seller] = 0;
        payable(contractOwner).transfer(amount); // withdraw the money
    }
    
  3. how can I add the address that initially deployed the smart and transfer 3% of the total deposit

    Let's expand the 2nd point and use the contractOwner. You'll need to update the deposit function:

    function deposit() public onlyBuyer payable {
        require(currentState == State.AWAITING_FUNDS);
        uint256 amount = msg.value;
    
    
        // these lines calculate the fee, update the amount and send the fee to the contract owner
        // make sure you're not vulnerable to overflow
        uint256 fee = (amount / 100) * 3;
        payable(contractOwner).transfer(fee); // transfer 3% to the contract owner
        amount -= fee; // substract the fee from the amount that is going to be saved
    
    
        deposits[seller] = deposits[seller] + amount; 
        currentState = State.AWAITING_CLAIM;
    }
    

    Make sure you're not vulnerable to integer overflow. Imagine a scenario:

    1. Buyer deposits 1 wei
    2. Fee is calculated as 3 wei
    3. The contract has enough ETH so it sends the 3 wei to the owner
    4. But the 3 wei is substracted from the 1 in amount so that results in 2^256 - 3 instead of -2

    Solidity 0.8+ reverts the transaction automatically if underflow/overflow would happen. If you're using older version of Solidity, you can use for example OpenZeppelin's SafeMath library.