How To Proxy Payments During Charity Donation Campaign

Thanks to our beloved community. The charity donation campaign has been a great success! During the campaign, we received many interesting questions from the community regarding how the donation pipeline works and why it is so powerful. The answers are in this blog post!

The Tale of Two Roles

In general, there are two major roles in our pipeline that a donor interacts with: the bot and the smart contract. Concretely:

  1. A donor Bob starts a conversation with the bot to signal his intention to join the campaign; Once validated, the bot discloses the address of the smart contract to Bob;
  2. Bob sends a certain amount of ETH to the given smart contract;
  3. The smart contract validates the eligibility of the donor and the payment, and proxies the payment to the address of the charity;
  4. Meanwhile, the bot periodically retrieves transactions against the smart contract and checks if they went through;
  5. If so, the bot awards Bob with the points and notifies him on Telegram.

Basically, a smart contract is a computer protocol intended to digitally facilitate, verify, or enforce the negotiation or performance of a contract. Smart contracts allow the performance of credible transactions without third parties. These transactions are trackable and irreversible. Smart contracts were first proposed by Nick Szabo, who coined the term, in 1994. Ethereum implements a Turing-complete language on its blockchain as the framework for realizing smart contract in a decentralized manner. IoTeX uses a smart contract running on top of Ethereum to proxy payments to charities’ Ethereum wallets.

Make it Simple to Receive Payments

To ensure the donors have a great experience, the pay-to-smart-contract process should be as simple as possible — sending ETH from any Ethereum wallets/clients without special operations. To make this happen, IoTeX makes use of the fallback function, which is the only unnamed function in a contract and is executed on a call to the contract if none of the other functions match the given function signature. We implemented it as below, e.g., once a payment is sent to the contract, the fallback function is executed which in turn calls donate() to do the actual work.

function () external payable {
function donate(address _donor) public payable {
_preValidateDonate(_donor, msg.value);
uint GAS_LIMIT = 4000000;;
Donated(msg.sender, msg.value);

To proxy the actual payment to the intended charity address, we first attempted to use the“charity.send()” function, which works great if the charity uses a normal Ethereum account but fails if the charity uses a contract account for receiving donations. This is because “charity.send()” is reentrant-safe and only forwards 2,300 gas stipend to the next contract which makes the next one easily run out of gas. The “” function is the correct choice in this situation since it forwards a specified amount of gas to the next contract.

Though “” is much more powerful, it is non-reentrancy-safe, and if used incorrectly, it could easily lead to a Reentrancy Attack like the DAO attack back in 2016. To be safe, one has to either grab a mutex in the function which calls “” or mutate internal states, e.g., zeroing out the balance, before calling of “”. In our case, a reentrancy attack is not a concern since: a) our smart contract is stateless; b) we use the charity’s address rather than the sender’s address. In addition, we audited the charity’s smart contract to make sure it has no malicious code.

Watch Out for Donors

“All humans make mistakes” and the contract needs to watch out for our donors. Therefore, the contract is devised to validate every payment to:

  • Prevent non-whitelisted donors from donating, i.e., we imported ~2600 approved whitelisted addresses to the contract, only the payments from which are allowed;
  • Prevent whitelisted donors from donating at a wrong time, i.e., the contract only opens during 3/20/2018 5PM PDT — 3/21/2018 5PM PDT;
  • Prevent whitelisted donors from donating an unintended amount, i.e., the contract only accepts payment >=0.2ETH and <=1.0ETH and turns down the rest;
  • Prevent from receiving payments from too many donors, i.e., we capped the number of donors to 2600.

In addition, we’ve embedded a pair of admin-only knobs in the smart contract, namely pause() and unpause(), which canhalt the smart contract from receiving payments under emergent circumstances, and resume that when needed.

In all, the validation condition for donation is coded as below.

function _preValidateDonate(address _donor, uint256 _weiAmount) internal {
require(now >= openingTime && now <= closingTime);
require(donors.length <= maxNumDonors);
require(_donor != address(0));
require(minWeiAmount <= _weiAmount && _weiAmount <= maxWeiAmount);

The development of this contract follows the standard software engineering flow strictly:

  1. High coverage by local unit tests;
  2. Functional and load testing in Kovan testnet of Ethereum;
  3. Canaried in the mainnet of Ethereum and dogfooded by the team;
  4. Released for the campaign.

Finally, we open-sourced our smart contract on GitHub. Please feel free to send us a pull request if you see a way to improve it!

About IoTeX

IoTeX is dedicated to creating the next generation of the IoT-oriented blockchain platform. The cutting edge blockchain-in-blockchain architecture will address the scalability, privacy, isolatability, and developability issues relating to the IoT DApps and ecosystem growth. By combining token incentives with our vibrant, global community, we believe we can crowdsource top industry and community talents to push the frontier of blockchain 3.0.

Telegram Group:

Telegram Announcement Channel:


Join us:

More by IoTeX

Topics of interest

More Related Stories