Airdrop contract never work due to “Transfer amount exceeds the maxTxAmount.” error

Hello Solidity community,

I am having hard time moving forward with my airdrop contract due to a weird errors, and have no idea why this is happening.

I will explain the problem in detail below:

Basically, I am trying to write a airdrop contract for a token ($LOFI)

Airdrop Contract:

My airdrop contract is very simple, I have a function that takes token address, list of addresses to airdrop and total token value, where it will call the transferFrom function from the token contract.

My airdrop contract source code goes here: Contract Address 0x3518711f5ffe4108ea4532a854e7314895ebe7d1 | BscScan

/**
 *Submitted for verification at BscScan.com on 2021-10-30
*/

pragma solidity ^0.4.22;

contract ERC20 {
	function totalSupply() external view returns (uint256);
	function balanceOf(address account) external view returns (uint256);
	function transfer(address recipient, uint256 amount) external returns (bool);
	function allowance(address owner, address spender) external view returns (uint256);
	function approve(address spender, uint256 amount) external returns (bool);
	function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
	event Transfer(address indexed from, address indexed to, uint256 value);
	event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract LofiAirdropContract {
    function airdrop(address tokenAddr, address[] dests, uint256 value) public payable {
        uint256 valuePerCount = value / dests.length;
        for (uint i = 0; i < dests.length; i++) {
            ERC20(tokenAddr).transferFrom(msg.sender, dests[i], valuePerCount);
        }
    }
}

However, when I invoke my airdrop contract to distribute the token, it always failed with this error:
"Fail with error 'Transfer amount exceeds the maxTxAmount.'"
image

Token Contract:

After troubleshooting, I figured, it is this condition in LOFI token contract that cause it at line 530 ( Contract Address 0x17D8519F57450E2B7E6aE1163E0E448322a8aF17 | BscScan):

Failed at this condition:

		if(from != owner() && to != owner())
			require(amount <= _maxTxAmount, "Transfer amount exceeds the maxTxAmount.");

Full method:

	function _transfer(
		address from,
		address to,
		uint256 amount
	) private {
		require(from != address(0), "ERC20: transfer from the zero address");
		require(to != address(0), "ERC20: transfer to the zero address");
		require(amount > 0, "Transfer amount must be greater than zero");
		if(from != owner() && to != owner())
			require(amount <= _maxTxAmount, "Transfer amount exceeds the maxTxAmount.");
		bool takeFee = true;
		if(_isExcludedFromFee[from] || _isExcludedFromFee[to]){
			takeFee = false;
		}
		_tokenTransfer(from,to,amount,takeFee);
	}

Python script:

Basically, I will do the following to conduct the airdrop process:

For instance we have 3 addresses:

  1. Airdrop contract address 0xabc...
  2. Wallet address 0xdef...
  3. Token address 0xopq....

Step1: approve the 0xabc... address to spend token on behalf of the 0xdef... address

Step2: invoke airdrop function from airdrop contract to do the airdrop to given destination addresses,

def approve(wallet_address, token_address, airdrop_contract_address, token_count, gas_price, web3):
    nonce = web3.eth.getTransactionCount(wallet_address)
    checksum_token_address = Web3.toChecksumAddress(token_address)
    checksum_airdrop_contract_address = Web3.toChecksumAddress(airdrop_contract_address)

    contract_instance = web3.eth.contract(address=checksum_token_address, abi=token_contract_abi)

    tx = contract_instance.functions.approve(checksum_airdrop_contract_address, web3.toWei(token_count, 'ether')).buildTransaction({
        "from": wallet_address,
        "nonce": nonce,
        "gas": 100000,
        "gasPrice": web3.toWei(gas_price, 'gwei')
    })

    # Wait for transaction to complete
    signed_tx = web3.eth.account.signTransaction(tx, private_key)
    tx_hash = web3.eth.sendRawTransaction(signed_tx.rawTransaction)
    web3.eth.wait_for_transaction_receipt(tx_hash)

    time.sleep(5)

    return True

def airdrop(wallet_address, token_address, airdrop_contract_address, token_count, gas_price, dest_account_addrs, web3):
    nonce = web3.eth.getTransactionCount(wallet_address)
    checksum_token_address = Web3.toChecksumAddress(token_address)
    checksum_airdrop_contract_address = Web3.toChecksumAddress(airdrop_contract_address)

    contract_instance = web3.eth.contract(address=checksum_airdrop_contract_address, abi=airdrop_contract_abi)
    tx = contract_instance.functions.airdrop( checksum_token_address,
                                                dest_account_addrs,
                                                web3.toWei(token_count, 'ether')).buildTransaction({
        "from": wallet_address,
        "nonce": nonce,
        "gas": 100000,
        "gasPrice": web3.toWei(gas_price, 'gwei')
    })

    signed_tx = web3.eth.account.signTransaction(tx, private_key)
    tx_hash = web3.eth.sendRawTransaction(signed_tx.rawTransaction)
    web3.eth.wait_for_transaction_receipt(tx_hash)
    trans = web3.toHex(tx_hash)
    trans = web3.eth.get_transaction(trans)
    time.sleep(5)

    return True

I am not sure how I can bypass this, and really appreciate if anyone from the community know how to fix it!

Thank you very much for your help!

HI, it seems like for the failed transaction, your input data are:

tokenAddr => "0x17d8519f57450e2b7e6ae1163e0e448322a8af17"
value => "5000000000000000000"

And for this token, the owner of this contract is 0xaebc17d3f78ee968b9e5dd547b1fbda52aa378da , the caller is your LofiAirdropContract, the _maxTxAmount is 1e18.

if(from != owner() && to != owner())
    require(amount <= _maxTxAmount, "Transfer amount exceeds the maxTxAmount.");

So according to above code, I think you can set value as 2e18 when want to distribute tokens to two users.

Hi Skyge,

Thanks for the reply, I understand that there is a hard limit of _maxTxAmount which equal to 1 token. That's not the intend of this question.

What I want to do is how can I get rid of this condition:

		if(from != owner() && to != owner())
			require(amount <= _maxTxAmount, "Transfer amount exceeds the maxTxAmount.");

Meaning, how can I airdrop and made either from address or to address is an owner account.

Not sure if you have been implemented an airdrop contract before, but this owner check conditions seems very common across bsc chain and I can't find answer about it on Google surprisingly