Understanding the MultiPath Callpath
The MultiPath callpath provides a callpath enabling users to sequence arbitrary commands in a single transaction.
We walk through an example BEX transaction to see how MultiPath performs the multiple actions of:
- Creating a new pool.
- Adding liquidity to this pool.
https://bartio.beratrail.io//tx/0x113c50e59148c06aeac42a91ab11df4436a2c9b1b0febaebad93f9d905ff9256
In particular, we make sense of the input calldata of this transaction.
Invocation
Following is a simplified TypeScript example of how this MultiPath call would be invoked:
const multiPathArgs = [2, 3, initPoolCalldata, 128, mintCalldata];
const multiCmd = encodeAbiParameters(
parseAbiParameters("uint8, uint8, bytes, uint8, bytes"),
multiPathArgs as any[5]
);
write({
address: crocDexAddress,
abi: bexAbi,
functionName: "userCmd",
params: [6, multiCmd],
});
Step 1 - MultiPath
At the highest level, userCmd
is called with the arguments [6, multiCmd]
. 6
corresponds to MultiPath callpath.
The decoded MultiPath cmdCode
is 2
, corresponding to the instruction to execute two commands.
Step 2 - Pool Creation
The first userCmd
is called with the following in MultiPath:
callUserCmdMem(3, initPoolCalldata)
Let's break this down:
- The callpath of
3
, corresponds to the ColdProxy - within ColdProxy, the
cmdCode
ofinitPoolCalldata
is71
, corresponding to the code for initializing a pool
Execution then flows to the initPool
method, where the remaining parameters are extracted for creating a new pool:
(, address base, address quote, uint256 poolIdx, uint128 price) =
abi.decode(initPoolCalldata, (uint8, address,address,uint256,uint128));
Step 3 - Liquidity Provision
Things should be more straightforward at this point. The second MultiPath code is 128
, corresponding to the liquidity provision command here.
This command is routed through WarmPath.sol
and decoded as follows:
(uint8 code, address base, address quote, uint256 poolIdx,
int24 bidTick, int24 askTick, uint128 liq, uint128,limitLower, uint128 limitHigher,
uint8 reserveFlags, address lpConduit) =
abi.decode(input, (uint8,address,address,uint256,int24,int24,uint128,uint128,uint128,uint8,address));
The code
here is 31
, representing the MINT_AMBIENT_BASE_LP
command.
Transaction Summary
1. Initialize Pool
The first command (code 3) calls the ColdPath contract to initialize the pool:
- Base token: 0x4dc594ce9752af1290402d2d9fd8eb0b6c863bd6
- Quote token: 0xb2292e4b23b21bf44455b3ffeca9d25eacc07a7c
- Pool ID: 36000
- Initial price: 1.600000000000000000
2. Add Liquidity
The second command (code 128) calls the WarmPath contract to mint liquidity (the sub-code 31 is for minting full-range liquidity):
- Code: 31
- Base token: 0x4dc594ce9752af1290402d2d9fd8eb0b6c863bd6
- Quote token: 0xb2292e4b23b21bf44455b3ffeca9d25eacc07a7c
- Pool ID: 36000
- Bid tick: 0
- Ask tick: 0
- Liquidity: 8223039985483627371447
- Lower limit: 1.600000000000000000
- Upper limit: 1.600000000000000000
- Reserve flags: 0
- LP Conduit: 0x2b15c8526162163a12fcda6d75f4dab13d02da5f
Appendix - Calldata Decoded
We provide the decoded calldata shown in the example transaction:
Function: userCmd(uint16, bytes)
MethodID: 0xa15112f9
[0]: 0000000000000000000000000000000000000000000000000000000000000006
// callpath (6 for MultiPath)
[1]: 0000000000000000000000000000000000000000000000000000000000000040
// Offset to the cmd data
[2]: 00000000000000000000000000000000000000000000000000000000000002e0
// Length of the cmd data
[3]: 0000000000000000000000000000000000000000000000000000000000000002
// Number of commands (2)
[4]: 0000000000000000000000000000000000000000000000000000000000000003
// First command code (3 for ColdPath)
[5]: 00000000000000000000000000000000000000000000000000000000000000a0
// Offset to first command data
[6]: 0000000000000000000000000000000000000000000000000000000000000080
// Length of first command data
[7]: 0000000000000000000000000000000000000000000000000000000000000160
// Offset to second command data
[8]: 00000000000000000000000000000000000000000000000000000000000000a0
// Length of second command data
[9]: 0000000000000000000000000000000000000000000000000000000000000047
// Command code for initPool (71 in decimal, which is 0x47 in hex)
[10]: 0000000000000000000000004dc594ce9752af1290402d2d9fd8eb0b6c863bd6
// Base token address for pool initialization
[11]: 000000000000000000000000b2292e4b23b21bf44455b3ffeca9d25eacc07a7c
// Quote token address for pool initialization
[12]: 0000000000000000000000000000000000000000000000000000000000008ca0
// Pool index (36000) for pool initialization
[13]: 0000000000000000000000000000000000000000000000016a09e667f3bd0000
// Initial price (1.600000000000000000 in fixed-point representation) for pool initialization
[14]: 0000000000000000000000000000000000000000000000000000000000000160
// Offset to second command data
[15]: 000000000000000000000000000000000000000000000000000000000000001f
// Second command code (31 for MINT_AMBIENT_BASE_LP in WarmPath)
[16]: 0000000000000000000000004dc594ce9752af1290402d2d9fd8eb0b6c863bd6
// Base token address for liquidity addition
[17]: 000000000000000000000000b2292e4b23b21bf44455b3ffeca9d25eacc07a7c
// Quote token address for liquidity addition
[18]: 0000000000000000000000000000000000000000000000000000000000008ca0
// Pool index (36000) for liquidity addition
[19]: 0000000000000000000000000000000000000000000000000000000000000000
// Bid tick (0) for liquidity addition
[20]: 0000000000000000000000000000000000000000000000000000000000000000
// Ask tick (0) for liquidity addition
[21]: 0000000000000000000000000000000000000000019d2d3d4200d9a7a37fb727
// Amount of liquidity to add
[22]: 0000000000000000000000000000000000000000000000016a09e667f3bd0000
// Lower price limit (1.6) for liquidity addition
[23]: 0000000000000000000000000000000000000000000000016a09e667f3bd0000
// Upper price limit (1.6) for liquidity addition
[24]: 0000000000000000000000000000000000000000000000000000000000000000
// Reserve flags (0) for liquidity addition
[25]: 0000000000000000000000002b15c8526162163a12fcda6d75f4dab13d02da5f
// LP conduit address for liquidity addition