SwapVM, the Aqua swap engine, is the bytecode execution engine for Aqua strategies. It is a purpose-built virtual machine deployed as the AquaSwapVMRouter contract (0x111111338c5091e8440b67b168bae16a668ac0de), the AquaApp that runs SwapVM programs and interprets them at swap time.
Aqua and SwapVM own separate concerns. The Aqua registry (Aqua.sol) owns custody and balance accounting; SwapVM owns strategy pricing and swap execution.
Separation of concerns
| Concern | Handled by |
|---|---|
| Asset ownership and custody | Maker's wallet |
| Balance accounting and authorization | Aqua.sol (the Aqua registry) |
| Strategy pricing and swap execution | SwapVM (deployed as AquaSwapVMRouter), or a custom AquaApp |
Aqua.sol is strategy-agnostic. It does not know or care how a strategy prices a swap; it only enforces that pull() and push() are balanced and authorized. Any contract that calls pull() and push() correctly is a valid AquaApp.
Self-custodial by design: tokens stay in the maker's wallet under a revocable, per-chain, per-token allowance and move only when a taker fills a swap atomically. The protocol holds 0 tokens. The balances tracked in Aqua.sol are an internal accounting counter, not deposits. Smart-contract and approval risk still apply.
From program to order to strategy
When building with SwapVM, you do not ship a Strategy directly. You compose a Program, wrap it in an Order, and Aqua registers the ABI-encoded Order as a Strategy:
Program (opcodes + args) -> SwapVM Order -> Aqua Strategy (ABI-encoded)
Aqua treats the Strategy body as opaque bytes. It does not parse instructions or execute pricing logic; it only manages balance accounting. The AquaSwapVMRouter executes the Program instructions at swap time.
Three paths to building on Aqua
Path A: custom AquaApp (no SwapVM)
Write a Solidity contract that implements swap logic directly. The contract calls pull() and push() on Aqua.sol to move tokens. SwapVM is not involved; this shows that Aqua is execution-engine-agnostic.
Full flexibility. It requires auditing and deploying a new contract per strategy type.
See Build an AquaApp for the full pattern.
Path B: SwapVM with existing opcodes
Compose a Program from SwapVM's built-in instruction set (AMM formula, fee model, range logic, and so on) without writing any new smart contracts. Wrap the Program in an Order, then register the ABI-encoded Order as an Aqua Strategy via ship().
The AquaSwapVMRouter interprets the Program at swap time against swap-state registers. No new contract is required; a new strategy is a new Program.
The deployed Aqua opcode set covers:
| Category | Opcode |
|---|---|
| Constant-product AMM | XYCSwap |
| Concentrated liquidity | XYCConcentrate |
| Pegged and reward-bearing pricing | PeggedSwap |
| Fee logic | Fee |
| Price decay over time | Decay |
| Control flow | Controls |
| External calls | Extruction |
The deployed AquaSwapVMRouter inherits the AquaOpcodes set: Controls, XYCSwap, XYCConcentrate, Decay, Fee, PeggedSwap, Extruction. Instructions such as Invalidators and SeriesEpochManager, and the Dutch-auction price modifier, belong to the separate limit-order and Fusion router, not the Aqua router. v1.0 ships two-token strategies only.
See SwapVM Instructions for the full bytecode format and opcode table.
Path C: SwapVM with an external contract extension
Deploy a custom smart contract with proprietary logic and call it from inside a Program via SwapVM's Extruction opcode (IExtruction). The value returned by the external contract is written back into SwapVM's execution context (ctx); this extends VM state with arbitrary external logic while SwapVM remains the execution coordinator.
This path enables novel pricing formulas or external oracle integrations without forking the VM. The Program still runs inside an Order registered as an Aqua Strategy, and the external contract call happens mid-execution. The Extruction target must be non-upgradeable, and quote() and swap() must return identical amounts for the same inputs.
Architecture overview
DEVELOPER PATHS
+----------------+ +--------------------+ +------------------------------+
| Path A: | | Path B: | | Path C: |
| Custom AquaApp | | Built-in opcodes | | External Contract Extension |
+----------------+ +--------------------+ +------------------------------+
| | |
| registers | assembles Program | Extruction opcode
| custom payload | into Order | modifies ctx
| as Strategy | |
| v v
| ............ SWAPVM ............
| +---------+ builds into +-----------+
| | Order | --------------> | Program |
| +---------+ +-----------+
| |
| | Order is ABI-encoded and registered as Strategy
v v
.............. AQUA ..............
+------------+ authorizes +--------------+
| Strategy | <------------- | Balance |
| | --accounts--> | Accounting |
+------------+ +--------------+
Choosing a path
Does your pricing logic fit SwapVM's existing instruction set?
- Yes. Choose Path B. Compose a Program from the deployed opcode set. No new contracts required; a new strategy is a new Program. This is the fastest path to deployment.
- No, but you want SwapVM to coordinate execution. Choose Path C. Deploy a contract with your custom logic and call it mid-Program via the
Extructionopcode. SwapVM remains the executor; your contract handles the custom computation. - No, and you need full control over swap logic in Solidity. Choose Path A. Write a custom AquaApp contract from scratch. Maximum flexibility; it requires auditing and deploying a new contract per strategy type.
Related
- Program Order Strategy: the SwapVM container that wraps a Program and becomes an Aqua Strategy.
- Program Model: bytecode format, registers, and instruction ordering rules.
- Build an AquaApp: implement swap logic in Solidity.
- Patterns & decision tree: recipes for common strategy types.
- Contract Addresses: the
AquaSwapVMRouteraddress across all 13 supported chains.