Understanding Solidity Withdrawal Pattern

By having a Solidity withdrawal pattern, it is ensured that direct transfers are not made, which would pose a security risk. An example of an insecure use of transfer calls to send ether can be seen in the following contract.

In this article, we will explore the various ways to withdraw funds from a Solidity smart contract and discuss best practices for implementing secure and efficient withdrawal mechanisms.



Solidity Withdrawal Patterns

According to the withdrawal pattern, the fund receiver has the responsibility of proof. If the fund recipient wants to withdraw funds and retrieve them, they need to send a transaction.

In this way, a smart contract that sends payments to recipients can be simplified.

Consequently, the contract is not affected by non-delivery of funds.

When money is sent to a smart contract, it has no way of knowing whether an error occurred or if the receiver is a malicious smart contract refusing to accept the payment for some reason.

The given example shows the working of the withdraw pattern:

Example: 

pragma solidity ^0.8.0;contract SolidityTest { address payable public buyer; constructor() { buyer = payable(msg.sender); } function allow_Access_To_withdraw(uint amount) public { require(msg.sender == buyer, "Only the Specified Buyer can Withdraw amount"); require(address(this).balance >= amount, "Not Enough funds in the contract"); buyer.transfer(amount); } }
<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>

Example Explanation

In above example we have create a contract named SolidityTest and has a single state variable called buyer.

The address payable type indicates that this variable can receive ether (the cryptocurrency of the Ethereum blockchain).

The constructor sets the value of the buyer to the address of the person who deployed the contract.

The msg.sender variable is a special global variable in Solidity that represents the address of the person or contract that called the current function.

The allow_Access_To_withdraw function is a public function that allows the specified buyer to withdraw a certain amount of ether from the contract.

The required statements are used to ensure that the conditions for withdrawing funds are met.

  • The first require statement checks that the person calling the function is indeed the buyer specified in the contract.
  • The second required statement checks that there are enough funds in the contract to withdraw the requested amount.

Finally, the buyer.transfer(amount) line transfers the requested amount of ether from the contract to the buyer address.

Note: The transfer function automatically throws an exception if the transfer fails (e.g. due to insufficient funds or invalid address), which would revert the entire transaction.

Instead of just checking the address of the buyer we can also check the remaining balance in the contract to see if the corresponding amount even exists in the contract to get transferred or not.

The code below provides better understanding of the solidity withdraw pattern:

Example: 

pragma solidity ^0.8.0;contract SolidityTest { address payable public buyer; mapping(address => uint) public contract_balance; constructor() { buyer = payable(msg.sender); } function deposit_mrx_amount() external payable { contract_balance[msg.sender] += msg.value; } function withdraw(uint mrx_amount) external { require(msg.sender == buyer, "Only the Buyer has the option to withdraw mrx_amount"); require(mrx_amount > 0, "Make sure the withdraw mrx_amount is greater than 0"); require(mrx_amount <= contract_balance[buyer], "The mrx_amount you want to transfer does not exists in the contract"); contract_balance[buyer] -= mrx_amount; payable(msg.sender).transfer(mrx_amount); } }
<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>

Example Explanation

This is a simple Solidity contract that allows the contract owner (the buyer) to deposit and withdraw a specific cryptocurrency token called “MRX“.

The contract has two state variables: buyer and contract_balance. buyer is an address that is specified in the constructor, and contract_balance is a mapping that stores the MRX balance for each address that has deposited funds into the contract.

The address payable type indicates that the buyer and payable(msg.sender) variables can receive ether or MRX.

The constructor sets the value of the buyer to the address of the person who deployed the contract.

The msg.sender variable is a special global variable in Solidity that represents the address of the person or contract that called the current function.

The deposit_mrx_amount function is a public function that allows anyone to deposit MRX into the contract.

The payable modifier indicates that this function can receive MRX along with ether.

The contract_balance[msg.sender] += msg.value; line adds the deposited MRX to the balance of the address that called the function.

The withdraw function is a public function that allows the buyer to withdraw a specified amount of MRX from the contract.

The required statements are used to ensure that the conditions for withdrawing MRX are met.

  1. First require statement checks that the person calling the function is indeed the buyer specified in the contract.
  2. Second require statement checks that the requested withdrawal amount is greater than zero.
  3. Third require statement checks that the buyer has sufficient balance to withdraw the requested amount.

Finally, the contract_balance[buyer] -= mrx_amount; line subtracts the withdrawn amount from the buyer balance.

The payable(msg.sender).transfer(mrx_amount); line transfers the requested amount of MRX to the address that called the function.

Note that the transfer function automatically throws an exception if the transfer fails (e.g. due to insufficient funds or invalid address), which would revert the entire transaction.

Conclusion

Withdrawing funds from a Solidity smart contract is a complex process which must be considered carefully for both security and usability reasons.

We’ve discussed Solidity withdrawal patterns in this article as a good starting point for building convenient and secure withdrawal mechanisms.

Important: If you are choosing Solidity withdrawal pattern for your specific use case, it is important to weigh the tradeoffs between gas costs, security, and usability.
We value your feedback.
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0

Subscribe To Our Newsletter
Enter your email to receive a weekly round-up of our best posts. Learn more!
icon

Leave a Reply

Your email address will not be published. Required fields are marked *