0

I am trying to make an external function call, with multiple arguments, to a contract written in Solidity from a contract written in Huff. I am able to successfully call an external contract when the function accepts a single argument, however when it accepts two or more arguments, the fallback function is always triggered and caused the transaction to revert. I know this because if I will add a simple fallback function that does nothing, then the transaction doesn't revert anymore. This tells me that the issue is something to do with the ABI encoding of the function call. I have created a set of files to reproduce the issue and please note that I am using Foundry and foundry-huff for development.

Counter.sol:

// SPDX-License-Identifier: BSL-1.1
pragma solidity 0.8.19;

contract Counter {
    uint256 public count;

    constructor() {}

    // fallback() external {} // uncomment to stop tests from failing

    function increaseA(uint256 amount_) public {
        count += amount_;
    }

    function increaseB(uint256 amount1_, uint256 amount2_) public {
        count += (amount1_ + amount2_);
    }
}

HuffCounter.huff:

/// @title HuffCounter
/// @notice SPDX-License-Identifier: BSL-1.1

/* Interface */
#define function increaseA(address, uint256) nonpayable returns ()
#define function increaseB(address, uint256, uint256) nonpayable returns ()

/* Constructor */
#define macro CONSTRUCTOR() = takes (0) returns (0) {}

/* Methods */    
#define macro INCREASE_COUNT_A() = takes(0) returns (0) {
    __FUNC_SIG("increaseA(uint256)") 0x00 mstore
    0x24 calldataload
    0x20 mstore

    0x00                // [ret_size]
    0x00                // [ret_offset, ret_size]
    0x24                // [args_size, ret_offset, ret_size]
    0x1C                // [args_offset, args_size, ret_offset, ret_size]
    0x00                // [value, args_offset, args_size, ret_offset, ret_size]
    0x04 calldataload   // [counter_addr, value, args_offset, args_size, ret_offset, ret_size]
    gas                 // [gas, counter_addr, value, args_offset, args_size, ret_offset, ret_size]
    call                // [successs]

    0x00 eq err jumpi
    cont jump

    err:
        0x00 0x00 revert
    cont:
        0x00 0x00 return
}

#define macro INCREASE_COUNT_B() = takes(0) returns (0) {
    __FUNC_SIG("increaseB(uint256, uint256)") 0x00 mstore
    0x24 calldataload
    0x20 mstore
    0x44 calldataload
    0x40 mstore

    0x00                // [ret_size]
    0x00                // [ret_offset, ret_size]
    0x44                // [args_size, ret_offset, ret_size]
    0x1C                // [args_offset, args_size, ret_offset, ret_size]
    0x00                // [value, args_offset, args_size, ret_offset, ret_size]
    0x04 calldataload   // [counter_addr, value, args_offset, args_size, ret_offset, ret_size]
    gas                 // [gas, counter_addr, value, args_offset, args_size, ret_offset, ret_size]
    call                // [successs]

    0x00 eq err jumpi
    cont jump

    err:
        0x00 0x00 revert
    cont:
        0x00 0x00 return
}

#define macro MAIN() = takes (0) returns (0) {
    // Identify which function is being called.
    0x00 calldataload 0xE0 shr
    
    dup1 __FUNC_SIG(increaseA) eq increaseA jumpi
    dup1 __FUNC_SIG(increaseB) eq increaseB jumpi

    0x00 0x00 revert

    increaseA:
        INCREASE_COUNT_A()
    increaseB:
        INCREASE_COUNT_B()
}

Counter.t.sol:

// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;

import "forge-std/Test.sol";
import "foundry-huff/HuffDeployer.sol";
import "forge-std/console.sol";

import {Counter} from "src/Counter.sol";

contract BundleExecutorTest is Test {
    Counter public counter;
    IHuffCounter public huffCounter;

    function setUp() public {
        counter = new Counter();
        huffCounter = IHuffCounter(HuffDeployer.deploy("HuffCounter"));
    }

    function testIncreaseA() public {
        huffCounter.increaseA(address(counter), 3);

        uint256 count_ = counter.count();

        console.log(count_);
    }

    function testIncreaseB() public {
        huffCounter.increaseB(address(counter), 3, 4);

        uint256 count_ = counter.count();

        console.log(count_);
    }
}

interface IHuffCounter {
    function increaseA(address, uint256) external;
    function increaseB(address, uint256, uint256) external;
}

1 Answer 1

1
+100

The function signature of of increaseB should be increaseB(uint256,uint256), not increaseB(uint256, uint256). Function sigs are hashed with no spaces between words or letters. Your encoding of parameters and everything else LGTM

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.