Modify data with mapping and array

I'm looking for ways to improve code execution and also drastically reduce rates on an airdrop. I got a lot of results from that.

I'm testing the following approach:

function airdrop (address[] calldata addresses, uint256[] calldata tokens) external onlyOwner {
    
    uint256 totalTokens = 0;

    for(uint i=0; i < addresses.length; i++){
    // already tried some changes in the following line            
    _balances[addresses[i]].push(tokens[i]);
       
        totalTokens = totalTokens + tokens[i];

    }

    _balances[address(this)] = _balances[address(this)].sub(totalTokens);

}

The code above gives the error "Member "push" not found or not visible after argument"

The line below compiles, is implemented on the network, but when the function is called it just doesn't work and doesn't change wallet balances.

        _balances[addresses][i] = _balances[addresses][i].add(tokens[i]);

The code below does not compile. The remix says: "Type address[] calldata is not implicitly convertible to expected type address". But when converting to address(addresses) it says: "Explicit type conversion not allowed from "address[] calldata" to "address".

                    _balances[addresses[i]] = _balances[addresses[i]].add(tokens[i]);

How can I resolve this?

I am not a pro but instead of using calldata you can use memory.

function airdrop (address[] memory addresses, uint256[] memory tokens) external onlyOwner {
    
    uint256 totalTokens = 0;

    for(uint i=0; i < addresses.length; i++){        

    _balances[addresses[i]] += tokens[i];
       
        totalTokens += tokens[i];

    }

    _balances[address(this)] = _balances[address(this)].sub(totalTokens);

}

I've replaced _balances[addresses[i]].push(tokens[i]); with _balances[addresses[i]] += tokens[i]; because .push is for arrays and as we know balances should be a mapping. also you can use += operator instead of = if you want to add value to something (same with *=, -=, /=).

1 Like

Thanks for your comment. Your code helped me to lower the cost of gas a little more.

But I discovered the problem of my question, of not updating the balance. Failure to issue a transfer event causes the balance on bscscan not to be kept up to date in the holders list. The added line is as follows:

        emit Transfer(address(this), addresses[i], tokens[i]);

That is, bscscan cannot show in the list of holders the balance of an account that had its balance changed by the function with the lines above and without issuing a transfer event. But if we look in the mapping for the balance of an account, the contract will respond with the correct balance.

I think this is due to the fact that it is not possible to look for values ​​in a mapping without having a key (the wallet address). There is no way for bscscan to display the balances precisely because it is not possible to read the mapping only by request.


The problem here has been solved, but I still can't reduce the cost of gas further.
The first call of an airdrop function is very expensive, only the next calls are reasonably cheap. This, without a doubt, is due to the fact that the wallet balance is stored in the balance mapping.

Can anyone help me with some good code or techniques that make an airdrop very cheap?

Well the only other method is using a set amount of tokens for everyone, so that everyone gets the same amount of tokens. With that you only need to use uint256 and not an array also you only need to multiply the per user with the amount of user. You can try just loweing the gas and then it maybe takes a few hours. I don't think there is anything else that you can do

1 Like

But if I lower the suggested gas for the transaction on the network (especially on the BSC), the transaction will not process.

The way to solve this is to look for alternative codes and techniques. The codes above are the best there is that I know of, but even then gas is still expensive. Can you imagine an airdrop for more than a thousand holders? It's too expensive.

About setting the same amount of tokens seems like an alternative that solves part of the problem. For example, in an airdrop a large amount will receive x tokens, another 2x tokens... So I'll see if a common uint256 for a single shipment makes everything cheaper.