batchSwapthat hops through two Weighted Pools.
Token Aand wants to trade them all to
batchSwap()in the Vault instead of multiple calls to
swap(), which saves gas on multi-hop trades
_swapWithPools()doesn't actually perform token transfers, rather it calculates the token input/output
assetDeltasto tell the Vault how many of each token should be transferred.
TWO_TOKEN: the pool has only two tokens
MINIMAL_SWAP_INFO: the pool has >= 2 tokens, but the balances for only input/output tokens are needed to calculate swaps
GENERAL: the pool has >= 2 tokens and all token balances are needed to calculate swaps
MINIMAL_SWAP_INFO. This is because only the input and output token balances are needed to determine prices.
_getMinimalSwapInfoPoolBalance()which is defined in
bytes32s that contain encoded data including amounts both held by the Vault and held externally via Asset Managers. We add those two amounts together so that we can make trades based on the full amount that is under the pool's management. In the following line, we also grab the
lastChangeBlocksfor each in/out token.
GIVEN_OUTtrades. We calculate what the new balances will be in the pool once the swap is finished.
assetDeltasarray. We accumulate them over all swap steps since a
batchSwapcan have multiple steps that use the same tokens multiple times.
batchSwap, we can pass
0for the amount. Doing so tells the Vault that you want the previous
batchSwapStepto feed directly into the current one. Therefore, after we verify that we have a previous step and that the previous step's output is our input token for a
GIVEN_IN(or vice versa for
GIVEN_OUT), we populate
batchSwapStep.amount = previousAmountCalculated;From here, we dive back into the individual swap at the pool level. Since we already covered how that works, though, we'll just continue on.
assetDeltas. First, we verify that all deltas are within their user-defined limits, and then we call receive and send assets at
_receiveAsset()on each token the user needs to send to the Vault, and
_sendAsset()on each token the Vault needs to send to the user. If there is any remaining ETH left over at the end of the operation,
_handleRemainingEth()sends it back to the calling contract (not
msg.sender, so relayers must handle this properly!). All three of these functions are handled by AssetTransfersHandler.sol and are pretty self explanatory.
handleRemainingdeals with any excess ETH that needs to go back to the user.
batchSwapworks! I invite you to explore the codebase to see how different pool specializations and pool types behave in their own ways. For example,
StablePools is a
GENERALspecialization so all token balances influence the swap prices.