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 totrue
if 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 userOp
A 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=0xf479F10B98a66180ebcA5AAe652512b1CFCDf0d3
Request 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
UserOperation
structs, 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=true
will 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