Axelar Transaction mined but execution failed on CallContractWithToken

58 Views Asked by At

I am trying to see if I can make Axelar send aUSDC from Optimism Goerli to Base Goerli. Attached below, I've written two contracts, OPSender.sol and BaseReceiver.sol, and deployed it on Optimism Goerli and Base Goerli, respectively. I tried calling the sendToMany function on OPSender to send the aUSDC from OP Goerli to Base Goerli, however I got the error Transaction mined but execution failed

I am running everything on Remix IDE.

Here are the parameters I put into sendToMany

{
    "string _destChain": "Base",
    "string _destContractAddr": "0x291b1B6EB9DE79f0cb181bCF68Ae1ea70d9B8760",
    "address[] _destinationAddrs": [
        "0xD1872508B5A49eD6Ea5EefD93e643623c0F83a78"
    ],
    "string _symbol": "aUSDC",
    "uint256 _amount": "100"
}

val    10000000000000000 wei

Here is the tx

tx : https://goerli-optimism.etherscan.io/tx/0xa8cf2c170326dc27905f6a88c50db0e67630ce97345cb0a4d319e5fe4998b6ae

I put the tx into tenderly to try and debug and it gave me an arthimetic error (arthimetic overflow / underflow), however I'm not dealing with much math here.

Here are the contracts

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { IERC20 } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IERC20.sol';
import { IAxelarGateway } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IAxelarExecutable.sol';
import { IAxelarGasService } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IAxelarGasService.sol';

contract OPSender {
    IAxelarGasService gasReceiver;
    IAxelarGateway gateway;

    constructor (
        address _gateway,
        address _gasReceiver
    ) {
        gateway = IAxelarGateway(_gateway);
        gasReceiver = IAxelarGasService(_gasReceiver);
    }

    function sendToMany(
        string memory _destChain,
        string memory _destContractAddr,
        address[] calldata _destinationAddrs,
        string memory _symbol,
        uint256 _amount
    ) external payable {
        require(msg.value > 0, "Gas payment required");

        // get token address from symbol
        address tokenAddress = gateway.tokenAddresses(_symbol);

        // send funds to this contract
        IERC20(tokenAddress).transferFrom(msg.sender, address(this), _amount);

        // approve gateway to spend funds
        IERC20(tokenAddress).approve(address(gateway), _amount);

        // encode recipient addresses tx on destination chain
        bytes memory _payload = abi.encode(_destinationAddrs);
        
        //pay gas from source chain
        gasReceiver.payNativeGasForContractCallWithToken{value: msg.value} (
            address(this),
            _destChain,
            _destContractAddr,
            _payload,
            _symbol,
            _amount,
            msg.sender
        );

        // send token and execute call
        gateway.callContractWithToken(
            _destChain,
            _destContractAddr,
            _payload,
            _symbol,
            _amount
        );
    }
}
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { IERC20 } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IERC20.sol';
import { IAxelarExecutable } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IAxelarExecutable.sol';
import { IAxelarGasService } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IAxelarGasService.sol';

contract BaseReceiver is IAxelarExecutable {
    IAxelarGasService public immutable gasService;

    constructor (address _gateway, address _gasService) 
        IAxelarExecutable(_gateway) 
    {
        gasService = IAxelarGasService(_gasService);
    }

    event Executed();

    function _executeWithToken(
        string memory,
        string memory,
        bytes calldata _payload,
        string memory _tokenSymbol,
        uint256 _amount
    ) internal override {
        // decode recipients
        address[] memory recipients = abi.decode(_payload, (address[]));

        // get token addr
        address tokenAddress = gateway.tokenAddresses(_tokenSymbol);

        // get first address
        address recipient = recipients[0];

        // transfer to recipient  
        IERC20(tokenAddress).transfer(recipient, _amount);

        emit Executed();
    }
}

I am not sure why when I call the sendToMany() function I get the Transaction mined but execution failed error message

1

There are 1 best solutions below

0
On BEST ANSWER

I think the missing step here is approval, you need to approve the amount to be spent spent by the contract before calling the sendToMany function.

Check this guide: https://axelar.network/blog/cross-chain-airdrop-dapp-tutorial scroll to the Implementing smart-contract write functionality section to see how the approval is done on the frontend before calling the sendToMany function.

Or you can approve directly on the aUSDC contract in Optimism Goerli https://goerli-optimism.etherscan.io/address/0x254d06f33bDc5b8ee05b2ea472107E300226659A#writeContract

Note: The arithmetic error (arithmetic overflow/underflow) occurs because the amount is currently 0. The error arises from an attempt to divide by 0. However, once you approve the spender amount, a valid value will be present, and as a result, such an error will no longer occur.