1

If I create a token, and then want to distribute it to 1000 people, I am worried about the gas price of those transactions. Which is why I wanted to analyse the different options for distributing and their inherent costs.

option 1: function in token that distributes to an array of users

function distributeToken(address[] addresses, uint256 _value) onlyOwner {
     for (uint i = 0; i < addresses.length; i++) {
         balances[owner] -= _value;
         balances[addresses[i]] += _value;
         Transfer(owner, addresses[i], _value);
     }
}

source: Distribute token to multiple address

ELABORATIONG ON OPTION ONE: is it possible to use parameters with an array of 1000 different addresses? That would be a massively large parameter and I'm curious as to what the gas price would look like.

option 2: using an exchange

This option is very restrictive however. It would allow anyone to buy the coins, and I don't necessarily want them to be bought but given away for free to specific users.

QUESTIONS

  • Are there other options people are aware of?
  • Which option would be most suitable and cost the least amount of gass?

DIFFERENCES BETWEEN THE LINKED DUPLICATE QUESTION AND THIS ONE: ( How to transfer tokens to bounty participants? )

The questions have noticeable differences

  • The details that are being discussed.
  • I also have 2 specific questions at the end which are not identical to that

while the question linked that is similar asks:

  • What is best practice to send ERC20-compliant tokens to bounty participants?

It doesn't provide the specific criteria for what best would refer to, while I do, and I also ask the other available options to make a comparison with. Even though they have similarities, they are not the same.

  • @ElishaDrion Thanks for the link, though I do believe the questions have noticeable differences, the main one people the details that are being discussed. I also have 2 specific questions at the end which are not identical to that question. Even though they are similar, they are not the same. – Webeng Apr 1 '18 at 14:29
2

The best way

The best way is quite an objective term.

The most cost effective way is definitely to execute them all in one loop (option 1), although there will be a limit to how many addresses you can perform at once (you'll probably need to do 10 batches of 100 addresses each).

Option 2 may indirectly cost you less in gas, but someone still has to pay the gas, and since they will be (presumably) executing one by one, the overall gas cost will be more, but since you won't be paying it, maybe that's better for you?

A slightly better implementation:

function distributeToken(address[] addresses, uint256 _value) onlyOwner {
     uint total = _value * addresses.length;
     require(total/_value == addresses.length); // Overflow check
     require(balances[owner] >= total); // Underflow check
     balances[owner] -= total;
     for (uint i = 0; i < addresses.length; i++) {
         balances[addresses[i]] += _value;
         require(balances[addresses[i]] >= _value); // Overflow check
         Transfer(owner, addresses[i], _value);
     }
}

Gas estimations:

For single calls to a typical transfer() function, it's the same cost per call, which means that for each address you'll be paying 23,500 gas.

However when you perform a bulk update instead, you save the overhead of the invocation cost and just have to pay the cost of the loop and storage etc. After a base cost of 27,947 gas, each address only costs an extra 9,703 gas.

┌─────┬────────────┬─────────────────┐
│  #  │  transfer  │ distributeToken │
├─────┼────────────┼─────────────────┤
│   1 │     23,500 │          37,650 │
│   2 │     47,000 │          47,353 │
│   3 │     70,500 │          57,056 │
│  10 │    235,000 │         124,977 │
│  50 │  1,175,000 │         513,097 │
│ 500 │ 11,750,000 │       4,879,447 │
└─────┴────────────┴─────────────────┘

That means after 2 addresses it's cheaper.

For 8 Mgas (maximum for a single call), you could do around 821 addresses:

27,947 base call gas + 9,703 gas/address * 821 addresses = 7,994,110 gas
  • Why not use the transfer function of the token, beside for sparing JUMP instructions? – Eli Drion Apr 1 '18 at 14:34
  • Generally airdrop functions tend to want to be as efficient as possible. Calling the transfer function is also usually a public function which is quite a bit more expensive than jumping to an internal transfer function, but still managing it within an single function even saves that cost. – norganna Apr 1 '18 at 14:37
  • very interesting, I wonder how much difference in gas this would bring. For instance if sending to 100 people with the distributeToken function costs the same as sending to 2 people through the ERC-20 transfer function – Webeng Apr 1 '18 at 14:38
  • There's a minimum cost of 21,000 gas per call, so even at absolute minimum cost (excluding storage costs etc), 2 calls to transfer() would cost 42,000 gas. – norganna Apr 1 '18 at 14:44
  • Yeah, I realized that, but I wonder if the differences are that big, if it's worth the repetition of code. – Eli Drion Apr 1 '18 at 15:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.