Balances

The Balances instruction loads virtual reserves into the swap context, giving the downstream swap-formula instruction the balanceIn and balanceOut values it prices against. Every SwapVM program must run a Balances instruction before any swap-formula instruction.

These reserves are virtual accounting values used by the pricing math. They are not a token deposit: the maker's tokens stay in the maker's own wallet under a revocable allowance and move only when a taker fills a swap.

Engine: Balances belongs to the SwapVM instruction set (SwapVM is the Aqua swap engine) and executes on the Aqua router (AquaSwapVMRouter, the deployed SwapVM router). The static variant embeds reserves in the program args; the dynamic variant persists them in SwapVM storage.

Source: src/instructions/Balances.sol


Static vs dynamic

Both variants share one packed args layout but differ in where the reserves live and how they evolve.

Variant Reserves live in Typical use
_staticBalancesXD Embedded in the program args (read-only) Limit order or auction priced from fixed embedded values rather than evolving reserves
_dynamicBalancesXD SwapVM contract storage, keyed by (orderHash, token) Stateful AMM (XYC constant product, concentrated liquidity) where reserves change with each fill

Args encoding

Both instructions share the same packed args layout:

Field Size Description
tokensCount 2 bytes (uint16) Number of tokens in the list
tokens[] 20 × tokensCount bytes Token addresses
initialBalances[] 32 × tokensCount bytes Initial balance for each token (same order)

Total: 2 + 20N + 32N bytes.

Build with BalancesArgsBuilder.build(address[] tokens, uint256[] balances).


Instructions

_staticBalancesXD

Solidity
1
function _staticBalancesXD(Context memory ctx, bytes calldata args) internal pure

Sets ctx.swap.balanceIn and ctx.swap.balanceOut from the embedded initialBalances array. No state is read or written; balances are fixed for the lifetime of this program execution.

Use when liquidity reserves do not change between swaps, for example a limit order or auction priced at a fixed rate.

Errors

Error Condition
SetBalancesExpectZeroBalances(balanceIn, balanceOut) balances already set before this instruction
StaticBalancesRequiresSettingBothBalances(tokenIn, tokenOut, tokens) tokenIn or tokenOut not found in the token list

_dynamicBalancesXD

Solidity
1
function _dynamicBalancesXD(Context memory ctx, bytes calldata args) internal

Loads or initializes balances from SwapVM contract storage keyed by (orderHash, token). After running the nested sub-instructions (via ctx.runLoop()), it writes the resulting swapAmountIn and swapAmountOut back to storage:

balances[orderHash][tokenIn] += swapAmountIn
balances[orderHash][tokenOut] -= swapAmountOut

Use for stateful AMM strategies (XYC constant product, concentrated liquidity) where reserves evolve with each swap.

Quote/swap divergence: In quote mode (isStaticContext = true) balances are read but not updated after the nested loop. A quote may succeed while the swap reverts if another transaction fills the order first. Do not use backward jumps to this instruction.

Errors

Error Condition
DynamicBalancesLoadingRequiresSettingBothBalances(tokenIn, tokenOut, tokens) tokenIn or tokenOut not found during load
DynamicBalancesInitRequiresSettingBothBalances(tokenIn, tokenOut, tokens) tokenIn or tokenOut not found during init

Public state

Solidity
1
mapping(bytes32 orderHash => mapping(address token => uint256)) public balances;

  • XYCSwap — constant product swap, uses these reserves
  • XYCConcentrate — concentrated liquidity swap
  • LimitSwap — limit order price, uses these reserves
  • PeggedSwap — pegged-asset swap, uses these reserves

Did you find what you need?