Solidity Contract Design – How to Transfer All msg.sender.balance to Contract Without msg.value Input

contract-designdappsethereum-wallet-dappremixsolidity

Is there a way to drain all the user.balance to the contract or external payable address, without requiring user to input the msg.value?

The most intuitive version I had looks a bit like this on solidity 0.5.0:

address(this).transfer(msg.sender.balance)

However it seems like contract address is inherently not payable, so I tried to first cast it into a payable address:

address payable payableContract = address(uint160(address(this)))

But it doesn’t seem to work either. Someone suggested me to look into Contract Factory which might solve the problem. What would be the best way to get around it, in order to achieve the same result?

Best Answer

You need to reverse the flow of things or this will never make sense.

There is no way to code a contract to transfer funds from a user wallet. Not all, not some, not any.

address(this).transfer(msg.sender.balance)

That means the destination (to) is address(this) and the amount is the msg.sender's balance. from: address is implicitly address(this) because nothing else is possible. Therefore, from isn't mentioned in the syntax.

What you actually want to happen is for the user to sign a transaction that sends their money to your contract. I don't know why it has to be their entire balance and that sounds to me like another design misstep but here is how you would do it.

It's a front-end concern. Again, for emphasis, because only the user can authorize the transfer of their own funds. On the contract side, all you can do is receive it, validate the transaction and possibly reject it if something is wrong.

function depositFunds() public payable {
  // carry on
  // msg.value and msg.sender inform about who and how much
}

On the front end you would Web3 or a similar library to help the user form a valid transaction with amount: as much as possible, to: your contract, {gas: amount, gasPrice: bid}.

The user has to pay for gas, and this will reduce the amount of funds available to send to your contract. You have to take that into account. Your front end will have to figure out:

  • gas estimate for the transaction
  • gasPrice (Ether cost consumed = gas estimate * gasPrice)
  • Funds available to send (user's balance - cost consumed), leaving the user with exactly 0 remaining balance.

If the browser (or server) performs the computation, then the user will be presented the option to sign a transaction sending x amount, and bidding y for gas, with a gas estimate of z leaving them with a final balance of 0.

It's unclear to me why anyone would agree to such terms.

Hope it helps.