1

I have an implementation where I'm needing to send 0x parameters (from the API) to a swap function that's being used in another function's logic.

To pass the data over a struct is being used, which is being populated with data at the time of the function call.

I'm finding that 0x's calldata is massive, requiring a large amount of gas to set.

Here is some code to explain what I'm doing:


//0x swap struct

struct OxSwap {
    bytes swapCallData;
    IERC20 sellToken;
    IERC20 buyToken;
    address spender;
    address payable swapTarget;
}

function _setCallData(
        bytes calldata swapCallData
    ) private {
        oxswapstruct.swapCallData = swapCallData;
    }

//Setting this struct variable costs 1+ million gas. 

//Can calldata size be reduced? 

Is there a way to reduce the size of the calldata being generated by the API call?

I'm trying to reduce gas costs as much as possible and the large 0x calldata size is an issue.

Thanks.


@Sky, thanks for your help.

I can't provide the full code, but here's the relevant sections.

//0x swap struct

struct OxSwap {
    bytes swapCallData;
    IERC20 sellToken;
    IERC20 buyToken;
    address spender;
    address payable swapTarget;
}

contract Example is Interface, Ownable {

/* Interface is where the swap is being fired. It's an external interface. Ideally, the calldata would be sent in the function parameters, but this implementation does not allow for that, given that the external contract interface has set parameters and the calldata can't be inserted in this step. So, the struct is being created to send the 0x data. */

--- State Variables   ---

    OxSwap public oxAPIswap;

--- Struct Setters ---

//calldata variable is set seperately from the rest of the struct to identify gas costs of just setting this variable 

function _setOxAPIswapStruct(
        address spender,
        address payable swapTarget,
        IERC20 sellToken,
        IERC20 buyToken
    ) private {
        oxAPIswap.spender = spender;
        oxAPIswap.swapTarget = swapTarget;
        oxAPIswap.sellToken = sellToken;
        oxAPIswap.buyToken = buyToken;
    }

    function _setOxAPICallData(
        bytes calldata swapCallData
    ) private {

        oxAPIswap.swapCallData = swapCallData;
    }

....

//Swap function 

function _swapAssets()
        private
    {
        require(
            oxAPIswap.sellToken.approve(oxAPIswap.spender, type(uint256).max)
        );
        (bool success, ) = oxAPIswap.swapTarget.call{value: msg.value}(
        oxAPIswap.swapCallData
        );
        
        require(success, "Swap failed. Low Dai balance / error.");

        payable(msg.sender).transfer(address(this).balance);
    }


//Swap data is being captured external to the contract and then sent to the contract via the struct setter. 

//I'm looking to find out how to radically reduce the call data being sent with 0x calls. For example, can the calldata be packed to eliminate 0s? 

//Sample call data:

'Swap Call Data': '0x6af479b200000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000001e8d026c4d56105000000000000000000000000000000000000000000000000000066bd1ca1749622840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b6b175474e89094c44da98b954eedeac495271d0f0001f4c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000869584cd00000000000000000000000010000000000000000000000000000000000000110000000000000000000000000000000000000000000000e27b435a91637772ec', 'Guaranteed Price': '0.000821015485425686'}
....

4
  • I think the issue here is IERC20 sellToken && IERC20 buyToken (Are you sending the entire interface??)
    – Sky
    Nov 18, 2022 at 8:32
  • Thanks. No I've narrowed the issue down to the calldata. - Sample gas of function without setting the callData struct variable: 526463 -Sample gas of function with setting the callData struct variable: 2040242 Nov 18, 2022 at 11:20
  • Could I get more of your code so I can test this myself in the remix?
    – Sky
    Nov 18, 2022 at 11:33
  • Calldata is cheap, unless you send a very large string. I'd study 0x protocol, because the only option seems to be to unpack swapCallData.
    – Ismael
    Nov 20, 2022 at 17:35

1 Answer 1

0

The payload you are posting is "only" 500 bytes, and I've seen calldata north of 10k bytes. Are you sure this is actually the problem? Have you tried using apps like Tenderly to debug your calldata?

3
  • I'm pretty sure the gas size has to do with the calldata being generated by 0x. I'm not generating it on my own, and simply passing the calldata from the 0x call to the struct. Nov 27, 2022 at 23:23
  • Have you tried using Tenderly (tool suggested above)? It really helps debug these kinds of issues
    – acilia
    Nov 28, 2022 at 22:25
  • Yes. I'm using various tools (call_trace, etc.) to look at txs. The calldata size depends on the 0x routing sent by the API. When the routing is simpler, the calldata size is smaller. The only other option would be to not use the API, and call the contracts directly, but that's time-intensive. Dec 6, 2022 at 2:56

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.