SwapVM engine

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 Extruction opcode. 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.

Did you find what you need?