in

Ethereum : Bulk API enables token transfer 9600x more efficiently on Ethereum mainnet

Ethereum update: Bulk API enables token transfer 9600x more efficiently on Ethereum mainnet



Full post: [Medium link](https://medium.com/human-protocol/transfer-your-tokens-9-600x-more-efficiently-on-ethereum-using-the-bulk-api-fbc2f10669ed)

To save the click, here’s the body of the post (sans images):

If you’ve developed on Ethereum before you have probably noticed how limiting transfers can be. Sending tokens to many Ethereum addresses is slow and expensive when using the standard methods defined in the [ERC20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md)standard. This has prevented wide adoption of Ethereum’s public chain for micropayments and other high-volume use cases.

As part of our work on the HUMAN Protocol we needed to scale settlements to handle billions of task payments per day. Turns out this is possible to do in a backwards-compatible way even on the Ethereum mainnet. We call it the Bulk API.

Many of our friends at other projects have asked us to share these results, so in order to give back to the community we are open sourcing our reference implementation. We will also be proposing the Bulk API as an extension to the existing ERC20 standard so that everyone can benefit from faster and cheaper token transfers to multiple Ethereum addresses.

### Background

[EIP20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md), now known as ERC20 is an Ethereum API for tokens within smart contracts that defines standard methods for common needs. You can create your own token in a matter of minutes, and thousands of projects have done so due to this ease of use.

ERC20’s main functions are:

* **totalSupply**: get the total amount of tokens that the ERC20 contract holds.
* **balanceOf**: get the amount of tokens an Ethereum address holds.
* **transfer**: transfer tokens to an Ethereum address.
* **approve**: used for the [withdrawal pattern](https://solidity.readthedocs.io/en/v0.4.24/common-patterns.html#withdrawal-from-contracts) to let tokens to be approved so they can be spent by another on-chain third party.

### Problem

Using the **transfer** function lets you send tokens to only one address at a time. When sending tokens to many addresses, you need to wait for the transaction to be mined first before sending tokens to the next address in line. The reason for this is due to the way Ethereum was designed: every Ethereum address has its own nonce (not to be confused with miners’ nonces) which tracks its transaction count.

The problematic part is that you have to wait each and every time for the confirmation of the network that your nonce has been incremented successfully before you can continue with the next token transfer.

### Solution

In the [HUMAN Protocol](https://hmt.ai/) we need to transfer tokens to huge numbers of website owners for the captchas their clients solve during the lifecycle of each smart bounty. Trying to use the **transfer** function of ERC20 would have made our system far too slow for production workloads.

The biggest issue with relying on **transfer** for token payments in this scenario is that it doesn’t properly support payments to multiple Ethereum addresses. The programmer has to handle the looping of token transfers on the client level for example with [web3](https://github.com/ethereum/web3.js/).

What if we used [Solidity](https://solidity.readthedocs.io/en/v0.4.24/)’s built-in loops and handled the bulk payments at the contract level instead? Enter the **Bulk API**.

The Bulk API adds two new functions to the existing ERC20:

* **transferBulk**: send tokens to multiple Ethereum addresses with one function call
* **approveBulk**: used for [withdrawal pattern](https://solidity.readthedocs.io/en/v0.4.24/common-patterns.html#withdrawal-from-contracts) to let multiple Ethereum addresses “withdraw” their tokens instead of direct bulk transfer

### Benchmarking

We measure two main factors in our benchmark tests: speed and gas cost. The variable we use to simulate different benchmarks is the number of wallet recipients receiving tokens. Due to possible congestion and other testnet-specific instabilities the **Execution time** results should be treated as indicative. **Gas cost** results are generally stable within each benchmark test.

The immediate observation is that there are no results for the **transfer**function on 64 and 96 wallet benchmarks. This is due to problems in the Ropsten testnet. Several attempts to get 64 wallet transfers through led to known errors such as “known transaction” and “nonce too low”. On **transferBulk** side we found that 96 wallets seems to be the maximum amount of wallets that we can have reliable confidence in succeeding.

As it can be seen from the charts, **transferBulk** scales much better than **transfer** as it doesn’t suffer from the nonce incrementation loop of the **transfer** function between token transfers. The fact that there needs to be a nonce incrementation between every token transfer makes **transfer** more error-prone, to split the contract’s state between paid and non-paid wallet recipients. If transaction timeouts trigger due to network congestion, there could be a real problem tracking which ethereum addresses have been paid: the state has to be maintained off-chain. With **transferBulk** the token transfers are by design transactional. This means that the transaction receipt gets returned only if all the specified Ethereum addresses have been paid. The state gets reverted if any token transfers fails.

### Scaling Factors

The improvements you can obtain with the Bulk API are substantial. **transferBulk**’s execution time scales in constant time as O(1) which is a radical improvement over the standard ERC20 **transfer** method which scales linearly as O(n). N is currently limited by the argument count, which is 96 wallet recipients.

Comparison of the scaling results between **transfer** and **transferBulk** methods is limited to 32 wallets as we never got **transfer** to successfully send tokens to 64 wallets.

It is quite clear that the increase in wallets affects **transfer**. We didn’t witness the same behaviour in **transferBulk**’s benchmark tests however. The results were more likely to indicate that the difference between **transferBulk**transfers had more to do with the state of the Ropsten testnet than the amount of wallet recipients. For example: 4 wallet transfers with **transferBulk** benchmarked to an average of 37.18 seconds whereas 64 and 96 wallets benchmarked to 12.44 and 37.02 seconds respectively. We can state from this that **transferBulk** closely resembles an O(1) time complexity as the amount of wallets doesn’t influence the execution time linearly.

### What’s Next

We are preparing to submit a fully comprehensive EIP in the near future where we specify in more detail the implementation of **transferBulk** and **approveBulk** functions. That said, we’ve been testing this functionality for some time and our open source [reference implementation](https://github.com/hCaptcha/hmt-token) has been audited and is ready for production use today if this is a problem that you face. Let us know if you’ve had similar experiences in your token transfers and if you would like to hear more!

*Want to see an example of this work in action?* [*hCaptcha*](http://hcaptcha.com/) *(the first app built on top of HUMAN Protocol) is now available for you to deploy on your website — if you already serve captchas and would like to be compensated for the effort, sign up at*[ *hCaptcha.com*](http://hcaptcha.com/)*.*




View the link

About Ethereum



Ethereum is a decentralized platform that runs smart contracts: applications that run exactly as programmed without any possibility of downtime, censorship, fraud or third-party interference.

Author: ajcajcajcajcajc

Score: 0

Don’t forget to share the post if you love it !

Ripple : Regarding XRP transaction time exchange <–> hardwallet

Bitcoin : While everybody is distracted by Bitcoin ETFs, Bakkt will make them completely redundant