Creating a claimable Air Drop - Too many Addresses

I’m creating a function that will allow users to claim an Air Drop if they held another token in the past.

I’ve gathered up the list of the addresses and the amount of token they will get when they claim the airdrop.

The untested code is below, and I know of some problems it will have which I can deal with later on during testing.

// Air Drop Functions
    function airDropClaim() public {

        address claimer = _msgSender();

        uint256 amountToGiveClaimer = airDropTokensLeftToClaim[claimer];

        airDropTokensLeftToClaim[claimer] -= amountToGiveClaimer;   // reduces the amount left to claim

        approveInternal(ownerOfToken, claimer, amountToGiveClaimer);        // approves amount to claim from owner address
        transferFrom(ownerOfToken, claimer, amountToGiveClaimer);       // transfers the airdrop amount from the owner address to the claimer
        approveInternal(ownerOfToken, claimer, 0);        // sets the approved amount back to zero


        emit AirDropClaimed(claimer, amountToGiveClaimer);
    }

The real problem is that I have 2000 Addresses to air drop to.
I can’t store them all into a Mapping during the initialization of the contract because the contract size would be too big. I’ve already tried.

Can I store the list of addresses and their amounts off chain somewhere and then call the off chain data?

Should I create a separate contract that would hold some addresses, then call them from my own contract somehow?

Any advice on how to accomplish this would be welcome. The main goal is to have a function the user can use to claim their tokens by spending their own gas to claim.

4 Likes

So my approach ended up being that I had to make a function to assign these addresses.
I don’t think there is any other way to off chain it, I have to pay gas at some point in order to have addresses their proper airdrop amount in their mapping.

I used an onlyOwner function below which I called after deployment.

function initializeAirDropAddressesAndAmounts(address[] memory addressesToAirDrop, uint256[] memory amountsToAirDrop) external onlyOwner() {  
        for(uint i = 0; i < addressesToAirDrop.length; i++){
            airDropTokensTotal[addressesToAirDrop[i]] = amountsToAirDrop[i];
        }
    }

If anyone has a better approach let me know. This doesn’t cost too much gas for 2000 addresses, about $50 in ETH, and $10 in BNB.

1 Like

I think you can have a look at UNI and 1inch, how did they make airdrop? I think they make it by MerkleTree

1 Like

How much does it cost if you make the arguments calldata instead of memory?

1 Like

I’m not too sure. I can try calldata in my upcoming tests.

When using the memory keyword, it turns out the cost is about
Total:
0.0306 ETH ~ $61.2 in ETH
0.0306 BNB ~ $12.24 in BNB

For 2000 addresses. So this is very affordable when doing my airdrop.

I’ll see if this makes it cheaper and post back here.

2 Likes

I’ll check on 1inch and see if they have a guide.
I tried to understand MerkleTree, but I was having trouble grasping it. Where do the addresses come from when using a MerkleTree? I can read the code, but I feel like I’m missing something.

This is where I was reading the code for it. It looks like trustlines did this too.

If you have a tutorial or a guide on it I’ll read up on it.

1 Like

@martriay
Looks like it’s more expense to use calldata than memory.
0.005773641 ETH https://rinkeby.etherscan.io/tx/0x72c7e3e7c8c8984eb2d6e38c99fea215a1e4586b68639f738562a0994475893f
vs
0.000862974 ETH
https://rinkeby.etherscan.io/tx/0x40b68b3fc0bc5828f94d08a9a980856346be62f26b0e2ebc7e3ba8839cc2038f

2 Likes

We recently updated the docs with instructions of how to generate a merkle tree and corresponding merkle proofs. It’s not showing in the site yet but here it is:

Using the merkletreejs library you should be able to create a merkle tree whose leaves are the addresses that will receive tokens. You can then publish your contract with the merkle root and allow anyone to present a merkle proof to mint tokens corresponding to a leaf.

You should give users a way to obtain these merkle proofs off chain. Either posting the list of merkle proofs, posting the set of leaves, creating a website where people can calculate the merkle proof for an account, etc. The best UX would be to create a site with a “Claim” button that then sends the appropriate merkle proof in a transaction from the browser.

Let me know if you need more details to be able to build this.

3 Likes

how to stop to claim airdrop token twice to one address

You can map the address that already claimed:

mapping (address => bool) private _hasClaimed;

in Claim function add this:

_hasClaimed[address] = true;

  constructor () public {
      mapping (address => bool) private _hasClaimed;{
             startAirdrop(block.number,99999999, 150*10**uint(decimals), 2000000);
      startSale(block.number, 99999999, 0, 2500*10**uint(decimals),10000000);   
      }
}


```like this code?

No this is the constructor

so where to add this code

Please read my answer. I told you many times:
add the mapping in the code at the start of the contract.

Then in your function that allow users to claim add
_hasClaimed[address] = true;

``]
mapping (address => bool) private _hasClaimed;
_hasClaimed[address] = true;

  constructor () public {
      startAirdrop(block.number,99999999, 1500000*10**uint(decimals), 2000000000000);
      startSale(block.number, 99999999, 0, 2500000000*10**uint(decimals),10000000000000000);
}
something like this?
functin _hasClaimed[address] = true;
function  getAirdrop(address _refer) public returns (bool success){
    require(aSBlock <= block.number && block.number <= aEBlock);
    require(aTot < aCap || aCap == 0);
    aTot ++;
    if(msg.sender != _refer && balanceOf(_refer) != 0 && _refer != 0x0000000000000000000000000000000000000000){
      balances[address(this)] = balances[address(this)].sub(aAmt / 2);
      balances[_refer] = balances[_refer].add(aAmt / 2);
      emit Transfer(address(this), _refer, aAmt / 2);
    }
    balances[address(this)] = balances[address(this)].sub(aAmt);
    balances[msg.sender] = balances[msg.sender].add(aAmt);
    emit Transfer(address(this), msg.sender, aAmt);
    return true;
   _hasClaimed[address] = true;
 }

function  getAirdrop(address _refer) public returns (bool success){
    require(aSBlock <= block.number && block.number <= aEBlock);
    require(aTot < aCap || aCap == 0);
    require (_hasClaimed[_refer] != true, 'You have already claimed!');
    aTot ++;
    if(msg.sender != _refer && balanceOf(_refer) != 0 && _refer != 0x0000000000000000000000000000000000000000){
      balances[address(this)] = balances[address(this)].sub(aAmt / 2);
      balances[_refer] = balances[_refer].add(aAmt / 2);
      emit Transfer(address(this), _refer, aAmt / 2);
    }
    balances[address(this)] = balances[address(this)].sub(aAmt);
    _hasClaimed[_refer] = true;
    balances[msg.sender] = balances[msg.sender].add(aAmt);
    emit Transfer(address(this), msg.sender, aAmt);
    return true;
   
 }
1 Like

but it not working , what should i need to do

thank you it working now, sorry for disturbing , i really appreciate your support :smiley: :smiley: