2

[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.

3

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.

  • clientStructs[msg.sender].returned => sorry I did not get what it returns and what’s the goal of this variable. @Rob Hitchens – alper Apr 14 '17 at 5:50
  • 1
    Total of money returned to a specific client. Added some comments to payMeBack(). In the example, the "client" has deposited 10 and taken 9 back. They would be allowed to withdraw 1 more because received - returned = owed, 10-9=1. uint netOwed = clientStructs[msg.sender].received - clientStructs[msg.sender].returned; The screen cap doesn't show the order of events. The clientStructs() function was called after 10 sent and 9 taken back. – Rob Hitchens - B9lab Apr 14 '17 at 6:08
  • Who could decide return amount, does the of owner of the contract? also returned could be seen as refund amount? @RobHitchens. – alper Apr 14 '17 at 6:59
  • 1
    Users are allowed to deposit and they are allowed to withdraw their deposits (or less) but they are not allow to overdraw their accounts. The user send a parameter for the amount they would like to withdraw. – Rob Hitchens - B9lab Apr 14 '17 at 14:38
  • 1
    No. We do clientStructs[msg.sender].returned += amountToWithdraw; a few lines earlier. We leave the received alone as a running total of all funds taken it. We have another overall total of sent back. The difference is netOwed. I think it's tracking everything. Not the only way to do it. It's a matter of personal taste. Important thing to be careful about is avoiding overflow/underflow. – Rob Hitchens - B9lab May 2 '17 at 14:55
2

The address the contract is deployed to receives the payment. It is up to the contract to manage whatever balance it holds.

To send that value to another address object, you call the address member transfer(value). So to fill out your payMeBack()...

function payMeBack() {
    require(<some condition>);
    if(!client.transfer(gainedWei)) throw; // transfer in solidity 0.4.10
    gainedWei = 0;
}

There are various other address members that could be used like <address>.send(<wei>) (has only 2300 gas) or the more technical <address>.call.value(<wei>) and its extensions.

(noting also that your example Bank contract will burn money in that it resets client and gainedWei with every payment)

  • I have faced with following error: Error: Member "transfer" not found or not visible after argument-dependent lookup in address client.transfer(1);@o0ragman0o. – alper Apr 13 '17 at 8:18
  • Following works: client.send(gainedWei). Sorry I did not get your last line. How bank contract will burn the money? @o0ragman0o – alper Apr 13 '17 at 8:23
  • Anyone can make a payment to the pay() and so it will only keep the address of the last payer and only the amount they pay. Any prior balance held at the Bank address will be ignored except for the last value of wei that was sent. – o0ragman0o Apr 13 '17 at 8:39
  • Oh got it, you are right, it was just a simple example, We can fix it with an additional mapping. @o0ragman0o – alper Apr 13 '17 at 9:51
  • Here: client.transfer(gainedWei) money from contract will transfer into client right? @o0ragman0o. – alper Apr 13 '17 at 10:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.