This repository contains a series of tests to measure gas usage for popular airdrop patterns with various token standards and airdrop mechanisms. Including:
- native currency (ETH);
- ERC20;
- ERC721;
- ERC1155.
The custom mapping-based contracts (AirdropClaimMappingERC{20/721/1155}
), and to some extent AirdropClaimMerkleERC{20/721/1155}
and AirdropClaimSignatureERC{20/721/1155}
as well, are purposely written poorly to fit common assumptions and patterns found in the wild.
Type | Tokens | Contract |
---|---|---|
Claimable airdrop (data inscribed into a mapping) | ERC20, ERC721, ERC1155 | AirdropClaimMappingERC20 , AirdropClaimMappingERC721 , AirdropClaimMappingERC1155 |
Claimable airdrop (merkle proof) | ERC20, ERC721, ERC1155 | AirdropClaimMerkleERC20 , AirdropClaimMerkleERC721 , AirdropClaimMerkleERC1155 |
Claimable airdrop (signature) | ERC20, ERC721, ERC1155 | AirdropClaimSignatureERC20 , AirdropClaimSignatureERC721 , AirdropClaimSignatureERC1155 |
Airdrop (bytecode contract) | ERC20 | BytecodeDrop |
Type | Tokens | Contract | Website/source code |
---|---|---|---|
GasliteDrop (airdrop) | ETH, ERC20, ERC721 | GasliteDrop |
drop.gaslite.org |
GasliteDrop1155 (airdrop) | ERC1155 | GasliteDrop1155 |
drop.gaslite.org |
GasliteMerkleDN (claimable airdrop, merkle proof) | ETH | GasliteMerkleDN |
gaslite.org |
GasliteMerkleDT (claimable airdrop, merkle proof) | ERC20 | GasliteMerkleDT |
gaslite.org |
Disperse.app (airdrop) | ETH, ERC20 | Disperse |
disperse.app |
wentokens (airdrop) | ETH, ERC20 | Airdrop |
www.wentokens.xyz |
Thirdweb (airdrop) | ERC20, ERC721, ERC1155 | AirdropERC20 , AirdropERC721 , AirdropERC1155 |
thirdweb.com |
Thirdweb (claimable airdrop, merkle proof) | ERC20, ERC721, ERC1155 | AirdropERC20Claimable , AirdropERC721Claimable , AirdropERC1155Claimable |
thirdweb.com |
This Readme is an attempt to showcase the results in an organized and sorted manner.
Note
The benchmarks do not include the gas consumption for the bytecode contract, as a current limitation with Forge; this should actually be the most efficient way for airdropping ERC20 tokens.
The tables below are based on gas benchmarks with the following parameters:
- 1,000 different random recipients;
- random amounts between 1e10 and 1e19 (10 * 18 decimals), except for ERC721 (1 token per recipient);
- some amounts are repeated randomly to better simulate real world scenarios (see here);
- randomness is generated with Solady LibPRNG, taking advantage of random calldata generated with fuzzing (see the unnamed uint256 parameter in each test function);
- the gas consumption is measured with Forge;
- Thirdweb contracts are supposed to be deployed as a proxy pointing to the actual implementation, so the cost of deploying the implementation is not included in the report.
See the full report for more details or generate it yourself.
For claim-based airdrops, multiple measurements are taken into account:
- deployment/initilization (e.g. Thirdweb contracts require only a proxy to be deployed, but the proxy needs to be initialized with the airdrop data, which can be quite expensive);
- deposit/airdrop (e.g. depositing tokens, writing the airdrop data to the contract);
- claim.
Steps 1 and 2 are aggregated into Gas deployment
, with the details for each amount in such way: total (deployment/initialization + deposit/airdrop)
.
For push-based airdrops, the gas cost of deploying and initializing the contract is ignored, as all solutions, excluding Thirdweb, are already deployed and available for use (direct call to the airdrop function).
Rank | Contract | Gas (1,000 recipients) | Difference from #1 |
---|---|---|---|
1 | GasliteDrop |
25,542,088 | 0 |
2 | Wentokens Airdrop |
25,586,923 | +44,835 (+0.18%) |
3 | Disperse (disperseToken ) |
26,342,497 | +800,409 (+3.13%) |
4 | Disperse (disperseTokenSimple ) |
26,852,552 | +1,310,464 (+5.13%) |
5 | Thirdweb AirdropERC20 |
26,925,358 | +1,383,270 (+5.41%) |
Rank | Contract | Gas deployment (1,000 recipients) | Difference from #1 | Gas claim (1 recipient) | Difference from #1 |
---|---|---|---|---|---|
1 | AirdropClaimSignature |
496,127 (496,127 + 0) | 0 | 85,766 | 0 |
2 | AirdropClaimMerkle |
464,492 (464,492 + 0) | -31,635 (-6.81%) | 87,547 | +1,781 (+2.03%) |
3 | GasliteMerkleDT |
647,007 (601,488 + 45,519) | +150,880 (+30.41%) | 88,613 | +2,847 (+3.32%) |
4 | Thirdweb AirdropERC20Claimable |
207,525 (66,769 + 140,756) | -288,602 (-58.17%) | 90,267 | +4,501 (+5.25%) |
5 | AirdropClaimMapping |
25,666,389 (538,776 + 25,127,613) | +25,170,262 (+5,073.25%) | 57,631 | -28,135 (-32.80%) |
This comparison is opinionated. Some arguments to support it:
- The difference in deployment cost is too significant for
AirdropClaimMapping
to be considered a viable solution. Although, in pure gas terms, for 1,000 recipients, it's still cheaper than the Thirdweb and signature-based solutions, i.e. it will spend less gas in total. - Although the deployment for Thirdweb's
AirdropERC20Claimable
is half the cost ofAirdropClaimMerkle
orAirdropClaimSignature
, the increase in gas for claiming is too significant to have it ranked higher. I believe that the deployer paying ~400-500,000 gas instead of ~200,000 cannot justify each single claimer having to pay ~90,000 gas instead of ~86,000.
In any case, these are only benchmarks, with a ranking provided for convenience.
It's also worth noting that the top 1 and 2 custom contracts are really just mock implementations. Although they do allow claiming on behalf of another account, they lack some checks and utility functions (e.g. pausing the claim)—the position of these contracts in the ranking is not a recommendation to use them, but rather based on the gas consumption.
Rank | Contract | Gas (1,000 recipients) | Difference from #1 |
---|---|---|---|
1 | GasliteDrop |
33,103,232 | 0 |
2 | Thirdweb AirdropERC721 |
35,844,727 | +2,741,495 (+8.28%) |
Rank | Contract | Gas deployment (1,000 recipients) | Difference from #1 | Gas claim (1 recipient) | Difference from #1 |
---|---|---|---|---|---|
1 | AirdropClaimSignature |
479,098 (479,098 + 0) | 0 | 93,072 | 0 |
2 | AirdropClaimMerkle |
447,613 (447,613 + 0) | -31,485 (-6.57%) | 94,953 | +1,881 (+2.02%) |
3 | AirdropClaimMapping |
36,472,337 (520,397 + 35,951,940) | +35,993,239 (+7,512.71%) | 65,162 | -27,910 (-29.99%) |
4 | Thirdweb AirdropERC721Claimable |
22,452,426 (66,769 + 22,385,657) | +21,973,328 (+4,586.40%) | 2,257,594 | +2,164,522 (+2,325.64%) |
It really hurts to not put AirdropClaimMapping
in the last place, but Thirdweb's AirdropERC721Claimable
really is too much with both the ~30M gas deployment and the ~218k gas claims. With 1,000 recipients, it is more than 219M in gas just for users to claim their tokens...
Also, AirdropERC721Claimable
does not allow for airdroping specific tokens to specific accounts, it will just allow to claim n
amount of tokens, and read the tokenIds array in ascending order. So it basically looks like a minting function.
Rank | Contract | Gas (1,000 recipients) | Difference from #1 |
---|---|---|---|
1 | GasliteDrop1155 |
29,910,313 | 0 |
2 | Thirdweb AirdropERC1155 |
30,320,907 | +410,594 (+1.37%) |
It's worth noting that GasliteDrop1155
takes advantage of multiple recipients with same amount by packing them into a single struct. Which much better simulates real world scenarios (e.g. users being rewarded the same amounts for the same token IDs after accomplishing a similar task). See:
struct AirdropTokenAmount {
uint256 amount;
address[] recipients;
}
In these tests, there are ~14% of recipients aggregated with the same amount. As the proportion of recipients with the same amount increases, the gap in gas consumption between GasliteDrop1155
and Thirdweb's AirdropERC1155
contract will increase as well.
Rank | Contract | Gas deployment (1,000 recipients) | Difference from #1 | Gas claim (1 recipient) | Difference from #1 |
---|---|---|---|---|---|
1 | AirdropClaimSignature |
609,717 (609717 + 0) | 0 | 87,405 | 0 |
2 | AirdropClaimMerkle |
577,332 (577,332 + 0) | -32,385 (-5.31%) | 89,236 | +1,831 (+2.10%) |
3 | Thirdweb AirdropERC1155Claimable |
1,556,310 (66,769 + 1,489,541) | +946,593 (+155.25%) | 88,990 | +1,585 (+1.81%) |
4 | AirdropClaimMapping |
27,929,999 (697,536 + 27,232,463) | +27,320,282 (+4,480.81%) | 59,402 | -28,003 (-32.03%) |
These contracts allow only for claiming a single token ID per recipient, to fit the Thirdweb pattern.
Rank | Contract | Gas (1,000 recipients) | Difference from #1 |
---|---|---|---|
1 | GasliteDrop |
9,996,017 | 0 |
2 | Wentokens Airdrop |
10,050,255 | +54,238 (+0.54%) |
3 | Disperse |
10,314,834 | +318,817 (+3.19%) |
Note
There tests use already initialized accounts—that is, accounts that were sent 1 wei prior to the measurement—to better simulate real world scenarios. This helps to avoid the cost of both the cold account access (2,500 gas) and the initialization surcharges (25,000 gas). See here for reference
Rank | Contract | Gas deployment (1,000 recipients) | Difference from #1 | Gas claim (1 recipient) | Difference from #1 |
---|---|---|---|---|---|
1 | GasliteMerkleDN |
536,646 (491,127 + 45,519) | 0 | 87,177 | 0 |
- Clone the repository and navigate to the root directory
git clone [email protected]:0xpolarzero/airdrop-gas-benchmarks.git
cd airdrop-gas-benchmarks
- Run all tests with gas snapshots
# Output to stdout
forge test --gas-report
# Output to file
forge test --gas-report > gas-report.txt
- Run benchmarks for a specific token/currency
# BenchmarksERC20
# BenchmarksERC721
# BenchmarksERC1155
# BenchmarksETH
forge test --mc BenchmarksERC20 --gas-report
- Run benchmarks for a specific contract/solution
# AirdropClaimMapping
# AirdropClaimMerkle
# AirdropClaimSignature
# Disperse
# wentokens
# GasliteDrop
# BytecodeDrop
# Thirdweb
# ...
forge test --mt AirdropClaimMapping_ERC20 --gas-report
- Run a specific test
# See the name of each test
forge test --mt test_ERC20_GasliteDrop --gas-report
Warning
The custom contracts shared in this repository are not meant to be used in production. They are not audited, and some of them are written precisely to showcase how inefficient airdrops can be if not properly designed. This does not only apply to gas consumption, but also to security and usability.