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;
}