Payable Contracts – Implementing Sent, Hold, and Sent Back Mechanism

contract-designpayablesolidity

[Q] When following transaction get called: Bank.pay({"from": eth.accounts[0], "value": 1});, who retrieves the money, does the owner of the contract? (Sorry I get lost who actually gains the money). And later on how could that money transfer back to the sender on another function call(this could be viewed as a refund process)?

I would like to carry out following scenario, if possible.

  1. Client A sents some money (lets say 1 wei) to the contract's function, via Client_A calls following: Bank.pay({"from": eth.accounts[0], "value": 1}).
  2. That money should be locked to be used by the gainer until payMeBack() is called. Basically owner of the money is not allowed to spend msg.value => 1 wei.
  3. When Client_A calls following: Bank.payMeBack(): Contract's function will send back the money(imagine is refund process) to Client A, if condition passed. If condition fails, now lock on money should be removed and money is gained by the contract and owner of the money could spent it.

Example contract:

pragma solidity ^0.4.8;

contract Bank{       
    address client;
    uint gainedWei;
    function pay() payable {
       client    = msg.sender;
       gainedWei = msg.value;
    }
    function payMeBack() {
     if(<some condition check>)
        //Some how it has to send back ether to client-A. We know the address we would like to send and the amount. 
    }
}

Thank you for your valuable time and help.

Best Answer

Short answer is Contracts are full participants, so when someone sends funds, then the contract has the funds.

The contract can then decide if/when to send the funds and to whom. In your use-case, it implies keeping track of who is owed funds. You would do that as funds are received.

Very sketchy example to help illustrate the flow.

pragma solidity ^0.4.8;

contract Bank{       

    address public owner;
    uint public receivedWei;
    uint public returnedWei;

    // simple storage pattern descibed here: https://ethereum.stackexchange.com/questions/13167/are-there-well-solved-and-simple-storage-patterns-for-solidity

    struct Client {
        uint received;
        uint returned;
        uint clientListPointer;
    }

    mapping(address => Client) public clientStructs;
    address[] public clientList;

    event LogReceivedFunds(address sender, uint amount);
    event LogReturnedFunds(address recipient, uint amount);

    function Bank() {
        owner = msg.sender;
    }

    function getClientCount()
        public 
        constant
        returns(uint clientCount)
    {
        return clientList.length;
    }

    function isClient(address client)
        public
        constant
        returns(bool isIndeed)
    {
        if(clientList.length==0) return false;
        return clientList[clientStructs[client].clientListPointer]==client;
    }

    function pay() payable 
        public
        returns(bool success)
    {
        // push new client, update existing
        if(!isClient(msg.sender)) {
            clientStructs[msg.sender].clientListPointer = clientList.push(msg.sender)-1;
        }
        // track cumulative receipts per client
        clientStructs[msg.sender].received += msg.value;
        receivedWei += msg.value;
        LogReceivedFunds(msg.sender, msg.value);
        return true;
    }

    function payMeBack(uint amountToWithdraw) 
        public
        returns(bool success)
    {
        // if not a client, then throw;
        if(!isClient(msg.sender)) throw;

        // owed = moneyReceived - moneyAlreadyReturned;
        uint netOwed = clientStructs[msg.sender].received - clientStructs[msg.sender].returned;

        // cannot ask for more than is owed
        if(amountToWithdraw > netOwed) throw;

        // safe-send pattern

        // keep track of money returned
        // to this client (user)
        clientStructs[msg.sender].returned += amountToWithdraw;

        // and overall (contract)
        returnedWei += amountToWithdraw;
        LogReturnedFunds(msg.sender, amountToWithdraw);
        if(!msg.sender.send(amountToWithdraw)) throw;
        return true;
    }
}

Here it is in Remix. 10 deposited, then 9 withdrawn. Running totals and client balances.

enter image description here

Hope it helps.

Related Topic