TSender

Cyfrin
DeFiFoundry
15,000 USDC
View results
Submission Details
Severity: medium
Invalid

Using Push over Pull strategy causes the airdrop to revert

Summary

TSender contract is using push over pull technique for sending tokens to multiple addresses for airdropping purposes.

Vulnerability Details

TSender::airdropERC20 is taking Recipient Addresses's Array and Amounts Array for recipients as arguments. And then it iterates over the loop to send tokens to all the addresses in the array. This is a very expensive operation and can lead to out of gas error if the array is too large.

Exploit PoC

By looking at the function as it doesn't have any bounds on recipients array, so we can make array of any size and send it to the function. Opened the contract in remix and tried to send 20000 addresses and 20000 addresses compared to one of the uniswap airdrops where 250k addresses were airdropped with free $UNI Tokens so it's feasible to assume that there can be 20000 addresses in an airdrop.

Lazy enough to input 20000 addresses, wrote python script to generate random 20,000 addresses and amounts arrays.

  • Addresses Script:

import random
import string
def generate_ethereum_address():
address_length = 40
random_hex = ''.join(random.choices(string.hexdigits.lower(), k=address_length))
ethereum_address = '0x' + random_hex
return '"' + ethereum_address + '"' # Wrap the address with double quotes
num_addresses = 200000
ethereum_addresses = [generate_ethereum_address() for _ in range(num_addresses)]
addresses_string = '[' + ', '.join(ethereum_addresses) + ']'
print(addresses_string[:20000]) # Print the first 20,000 arrays as a sample
  • Amounts Script:

def generate_amounts(num_addresses, amount_per_address):
return [amount_per_address] * num_addresses
# Generate 200,000 arrays of amounts, each containing 10 for each address
num_addresses = 200000
amount_per_address = 10
amounts_array = generate_amounts(num_addresses, amount_per_address)
print(amounts_array[:20000]) # Print the first 20,000 arrays as a sample

After generating the arrays, copied the arrays and pasted them in the remix and tried to send the transaction. The transaction failed to execute and reverted to its initial state.

Error Message:

transact to TSender.airdropERC20 pending ...
[vm]from: 0x5B3...eddC4to: TSender.airdropERC20(address,address[],uint256[],uint256) 0x9D7...b5E99value: 0 weidata: 0x829...0000alogs: 0hash: 0xac4...506eb
transact to TSender.airdropERC20 errored: Error occurred: revert.
revert
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
You may want to cautiously increase the gas limit if the transaction went out of gas.

Impact

There are multiple impacts:

  • As it is stated by Cyfrin Team, that It can be used in production. With this design it would be impossible to airdrop to a large number of addresses which is actually most of the time the case.

  • Using push over pull strategy cause the contract to revert

  • Sending tokens to a large number of addresses let's say even for executable array needs a lot of gas to proceed which is not sufficient model for airdropping.

Tools Used

Remix/Python/Manual Testing

Recommendations

  • Use pull over push strategy

  • Let the user claim airdrop instead of sending it to all the addresses.

  • Make recipients array bounded i.e, 1000 addresses at a time as so it can be feasible to send tokens to multiple addresses in batches.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice
ihtishamsudo Submitter
about 1 year ago
patrickalphac Auditor
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.