Search code examples
javascriptethereumsolidity

Splitting ETH when transferring


I would be very grateful if you can help me with this simple question!

I want to make a split of funds in a smart contract: 10% will go to my friend and 90% will go to me. I created a variable and wrote the following code in the withdraw () function:

address private constant _friend = 0xAb8483F64d9C6d1EcF9b849Aeblablalbasomeaddress;

In the beginning of contract and:

function withdraw() public payable onlyOwner {
    uint balance = address(this).balance;
    payable(msg.sender).transfer(balance / 100 * 10);
    payable(_friend).transfer(balance / 100 * 90);
}

I tested this on a testnet, but i'm a little paranoid.😆 Will this code work?

Why do I think there might be problems with this? When sending ETH, you have to pay a commission, so if I send msg.sender, then I send this 90% + commission, will I have enough money to send 10%?


Solution

  • payable(msg.sender).transfer(balance / 100 * 10);
    payable(_friend).transfer(balance / 100 * 90);
    

    This will work as expected for amounts (in wei) that are divisible by 100. Amounts not divisible by 100 will result in rounding errors, because you're dealing with division of integers (not decimals). So either of you could get a little less than expected.

    Example:

    • balance = 200 wei

      • msg.sender gets (200 / 100) * 10 = (2) * 10 = 20
      • _friend gets (200 / 100) * 90 = (2) * 90 = 180
    • balance = 150 wei

      • msg.sender gets (150 / 100) * 10 = (1) * 10 = 10
      • _friend gets (150 / 100) * 90 = (1) * 90 = 90
      • The remaining 60 wei stays on contract address

    Solidity resolves both operators from the left. So first it calculates balance / 100 and then multiplies the result by 10 or 90.


    When sending ETH, you have to pay a commission

    You probably mean the gas fee. This is paid on top of the transaction value by the address executing the withdraw() function. The gas fee does not affect the internal transactions (and their value) that will be generated by each of the transfer() functions.

    Example:

    1. You are sending 1 ETH (or 1000000000000000000 wei) value along with the transaction executing the withdraw() function. The gas fee is 0.001 ETH, so the total amount you pay is 1.001 ETH. However, the fee goes to the network, so the contract still receives only the value of 1 ETH.

    2. Then it gets split into the two internal transactions - 0.1 ETH to you (as the msg.sender) and 0.9 ETH to the _friend address. The gas fee for these internal transactions is already included in the main transaction (point 1) fee.