Hyper gas efficient smart contracts for air dropping tokens to a large number of users. Inspired by the work of the Gaslite team. In the src
folder, we have 4 main contracts:
TSender.sol
: The Yul/Solidity implementationTSender.huff
: The Huff implementationTSender_NoCheck.huff
: The Huff implementation without the extra checks, making the output similar toGasliteDrop
. Much more gas efficient, but without any safety rails.TSenderReference.sol
: The pure Solidity implementation
Each contract has 1 or 2 functions:
airdropERC20
(required): A function that takes in an array of recipients and an array of amounts, and sends the amounts to the recipients.areValidLists
(optional): A function that takes in an array of recipients and an array of amounts, and checks if the lists are valid.
- Checks the
totalAmount
parameter matches the sum of theamounts
array - Doesn't allow ETH to be sent with function calls
- Makes sure the total lengths of the
amounts
array andrecipients
array are the same - Checks for zero address recipients
Additionally, we did not want to spend gas checking a few things, so we added a function called areListsValid
that takes in a address[] recipients
and uint256[] amounts
to check for:
- Duplicate addresses
- Zero address sends
- There is at least 1 recipient
- All amounts are > 0
- recipients.length == amounts.length
The work here was inspired by the Gaslite team with a few changes.
- The Yul & Huff have added safety checks (see TSender Features)
- The
TSender_NoCheck.huff
does not have the extra checks, but is just a gas optimized version of the original GasliteDrop contract.
Note: Since our implementation adds more checks, the Huff code is slightly less gas efficient when working with additional recipients than the original gaslite codebase, but it is a safer smart contract. However, we did include a Huff contract the did not include those checks to show the power of using Huff to reduce gas costs.
# of recipients | Yul | Gaslite | Huff | Huff (No Checks) |
---|---|---|---|---|
1 | 2.10% | 2.26% | 3.42% | 3.61% |
10 | 3.23% | 3.38% | 3.51% | 3.65% |
100 | 3.48% | 3.62% | 3.52% | 3.66% |
1000 | 3.51% | 3.66% | 3.53% | 3.66% |
Solidity | Yul | Gaslite | Huff | Huff, no check | |
---|---|---|---|---|---|
1 Recipient Drop | 57377 | 56170 | 56080 | 55409 | 55300 |
10 Recipient Drops | 295287 | 285737 | 285296 | 284931 | 284507 |
100 Recipient Drops | 2674618 | 2581616 | 2577665 | 2580360 | 2576786 |
1000 Recipient Drops | 26490540 | 25561280 | 25522229 | 25553551 | 25520471 |
- git
- You'll know you did it right if you can run
git --version
and you see a response likegit version x.x.x
- You'll know you did it right if you can run
- foundry
- You'll know you did it right if you can run
forge --version
and you see a response likeforge 0.2.0 (816e00b 2023-03-16T00:05:26.396218Z)
- You'll know you did it right if you can run
- huff
- You'll know you did it right if you can run
huffc --version
and you see a response likehuffc 0.3.2
- You'll know you did it right if you can run
- halmos
- You'll know you've done it right if you can run
halmos --version
and you see a response likeHalmos 0.1.12
- You'll know you've done it right if you can run
When we work with zksync, we plan to use foundry-zksync. You'll know you did it right if you can run forge --version
and you see a response like forge 0.0.2 (816e00b 2023-03-16T00:05:26.396218Z)
. At the moment, it doesn't play nicely with Huff, so when we go to build with zksync, we remove all the Huff related code.
git clone https://github.com/cyfrin/tsender
cd tsender
make
To test the codebase, you can run the following 2 commands:
make test
make halmos
To test with zkSync, we must first remove our Huff
tests. We will not be deploying the huff code to zkSync, and the codebases doesn't play nice with foundry-zksync
.
To run zkSync tests:
- Comment out the following files
TSenderHuffTest.t.sol
TSenderHuffNoCheckTest.t.sol
EquivalenceTest.sol
DeployHuff.s.sol
You'll need to leave this line uncommented in each file:
pragma solidity 0.8.24;
- Run the tests:
make zktest
or
forge test --zksync
We have an issue in foundry-zksync
to fix the issue with avoid-contracts
. That would be the ideal solution in the future.
Our contract is expected to never have state. There are no SSTORE
opcodes in the bytecode of this contract.
You'll need to uncomment out the DeployHuff.s.sol
codebase. It's commented out because zkSync has a hard time compiling it at the moment. This is ok because we do not intend to deploy huff to zksync.
make deployYul
make deployHuff
- Does not work with fee-on-transfer tokens
- Does not check the return value of ERC20s, but it does check to see if the
transferFrom
ortransfer
call was successful. Meaning ERC20s that returnfalse
on a failedtransfer
ortransferFrom
but successfully execute, are not supported. If any of the expected token integrations are vulnerable to this pattern, flag it. - Upgradable/Deny List tokens can prevent this contract from working. We expect that, in the case that this contract or any recipient is on a deny list, the entire transaction will revert.
#-- interfaces
| #-- ITSender.sol
#-- protocol
| #-- TSender.huff
| #-- TSender.sol
| #-- TSender_NoCheck.huff
Ignore:
#-- reference
#-- TSenderReference.sol
#-- script/
Deploy scripts are not in scope because we can easily redeploy if we have an issue.
We expect to be able to run our deploy scripts, and it will prevent us from deploying contracts to chains that are not supported. Right now, zkSync will work with the yul
based TSender.sol
, and all other chains listed in the HelperConfig.sol
will work with the TSender.huff
contract.
TSender.sol
:- zkSync Era
- Everything in the
TSender.huff
list
TSender.huff
:- Ethereum
- Arbitrum
- Optimism
- Base
- ZKSync Era:
- USDC
- WETH
- LINK
- Ethereum:
- USDC
- WETH
- LINK
- Arbitrum:
- USDC
- WETH
- LINK
- Optimism:
- USDC
- WETH
- LINK
- Base:
- USDC
- WETH
- LINK
- There is an issue with how quickly the
foundry-zksync
compiler works, so we avoid compiling theDeployHuff.s.sol
contract. - Compliation takes a long time, so run tests accordingly. It may make sense to run tests with the standard foundry implementation before swapping to the
foundry-zksync
implementation. - Please take note of the target deployment chains during audit and check to see if our Huff or Solidity will work there.