0

I am working on a contract that makes calls to other contracts, so naturally I wanted to use the Calls.huff from Huffmate. However, I noticed in testing that the calls kept reverting. I started narrowing down the issue by copying the Calls.huff file to my local directory, which still reverted, and then copying the STATICCALL function to my contract file. In the end, it seems that there is an issue with passing arguments to the macro

Contract.huff:

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

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

/* Methods */
#define macro CALL_CONTRACT() = takes(0) returns (0) {
    __FUNC_SIG("getReserves()") 0x00 mstore

    STATICCALL(0x00, 0x00, 0x04, 0x1C, 0x04 calldataload, gas)

    // store returndata in memory
    returndatasize      // [returndatasize, success]
    0x00                // [mem_offset, returndatasize, success]
    0x00                // [destOffset, mem_offset, returndatasize, success]
    returndatacopy      // [success] // this stores the return data in memory

    // return the returndata from memory to the msg.sender
    0x40                // [returndatasize, success]
    0x00                // [mem_offset, returndatasize, success]
    return
}

#define macro STATICCALL(
    ret_size,
    ret_offset,
    arg_size,
    arg_offset,
    to,
    maxgas
) = takes (0) returns (1) {
    <ret_size>              // [retSize]
    <ret_offset>            // [retOffset, retSize]
    <arg_size>              // [argSize, retOffset, retSize]
    <arg_offset>            // [argOffset, argSize, retOffset, retSize]
    <to>                    // [to, argOffset, argSize, retOffset, retSize]
    <maxgas>                // [gas, to, argOffset, argSize, retOffset, retSize]
    staticcall              // [success]
}

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

    0x00 0x00 revert

    callContract:
        CALL_CONTRACT()
}

1 Answer 1

1

Macros take in one instruction per arguments so something like 0x04 calldataload cannot be an argument. A way to go about this would be to push the value of 0x04 calldataload to the stack first then in place of the to argument, place an opcode that when called where <to> is invoked in STATICCALL macro, it will push our earlier pushed to to the stack.

something like this works. (added more stack comments to show where to would be on the stack as you push it and within the STATICCALL macro)

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

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

/* Methods */
#define macro CALL_CONTRACT() = takes(0) returns (0) {
    __FUNC_SIG("getReserves()") 0x00 mstore            // []
    0x04 calldataload                                  // [to]

    STATICCALL(0x00, 0x00, 0x04, 0x1C, dup5, gas)     

    // store returndata in memory
    returndatasize      // [returndatasize, success]
    0x00                // [mem_offset, returndatasize, success]
    0x00                // [destOffset, mem_offset, returndatasize, success]
    returndatacopy      // [success] // this stores the return data in memory

    // return the returndata from memory to the msg.sender
    0x40                // [returndatasize, success]
    0x00                // [mem_offset, returndatasize, success]
    return
}

#define macro STATICCALL(
    ret_size,
    ret_offset,
    arg_size,
    arg_offset,
    to,
    maxgas
) = takes (0) returns (1) {
    <ret_size>              // [retSize, to]
    <ret_offset>            // [retOffset, retSize, to]
    <arg_size>              // [argSize, retOffset, retSize, to]
    <arg_offset>            // [argOffset, argSize, retOffset, retSize, to]
    <to>                    // [to, argOffset, argSize, retOffset, retSize] calling dup5 here pushes to the top of the stack
    <maxgas>                // [gas, to, argOffset, argSize, retOffset, retSize]
    staticcall              // [success]
}

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

    0x00 0x00 revert

    callContract:
        CALL_CONTRACT()
}

Check it out in this cool huff playground here

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.