Handling Nested Parameters in the functionSignature
This guide demonstrates how to handle nested parameters in your functionSignature when using the Swap API. The goal is to show how to structure the request body so that the API can properly index all arguments, even when your function expects arrays of structs or deeply nested tuples.
In the Introduction to Swap API, we learned that each argument in args supports:
value→ the static value for this argument.populateDynamically→ set totrueif this argument should be populated with the balance of a token at execution time.balanceSourceToken→ required whenpopulateDynamically=true, indicates which token balance to use.
When nesting is involved, the nested arguments are handled collectively. This means that you define them as an array (or tuple) in the value property and collectively define populateDynamically and/or balanceSourceToken for them.
Example Use Case — Calling handleOps on ERC-4337 to execute userOp
handleOps on ERC-4337 to execute userOpA common advanced use case is interacting with an ERC-4337 (Account Abstraction) EntryPoint contract. The handleOps function on this contract is a perfect example of a nested parameter, as it accepts an array of UserOperation structs.
Request URL
POST https://app.across.to/api/swap/approval
  ?tradeType=exactOutput
  &amount=1000000
  &inputToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
  &outputToken=0xaf88d065e77c8cC2239327C5EDb3A432268e5831
  &originChainId=8453
  &destinationChainId=42161
  &depositor=0xf479F10B98a66180ebcA5AAe652512b1CFCDf0d3
  &recipient=0xf479F10B98a66180ebcA5AAe652512b1CFCDf0d3Request Body
{
  "actions": [
    {
      "target": "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
      "functionSignature": "function handleOps((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes)[],address)",
      "args": [
        {
          "value": [
            [
              "0xf479F10B98a66180ebcA5AAe652512b1CFCDf0d3", 
              "18446744073709551647", 
              "0x", 
              "0xb61d27f6000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831...", 
              "0x0000000000000000000000000001175d0000000000000000000000000000c7e1", 
              "0", 
              "0x0000000000000000000000000000000000000000000000000000000000000000", 
              "0x", 
              "0xFF003b4c54175c8a10959a29148443a372cd6aed99ff4fca5066346244ccf19495f01e..."
            ]
          ],
          "populateDynamically": false
        },
        {
          "value": "0xf479F10B98a66180ebcA5AAe652512b1CFCDf0d3",
          "populateDynamically": false
        }
      ],
      "value": "0"
    }
  ]
}Key Takeaways
Nested Tuples The first argument is an array of
UserOperationstructs, which itself contains multiple values. Each nested field is placed in the inner array in the same order as defined in the struct.Static vs Dynamic Values
All values above are static (
populateDynamically=false).If any values inside the first argument have to change, then
populateDynamically=truewill apply to the entire array and not just that specific value inside the array
Consistency with ABI Always ensure the order of values matches the tuple definition in the ABI. Incorrect ordering will cause the call to fail.
Mixing Types Even when you have nested bytes, addresses, and uints in one array, each entry still follows the
{ value, populateDynamically, balanceSourceToken }shape.
By precisely mirroring your Solidity function's signature and parameter order within the args array, you can compose any arbitrarily complex on-chain action to execute post-swap.
In case you face any errors or need support, please feel free to reach out to us.
Last updated