Smart Contract

Complete function reference for Aqua.sol (the Aqua registry) and AquaApp (the base contract that swap applications inherit). In production, the deployed AquaSwapVMRouter is the AquaApp that drives fills against strategies registered here. It is the router for SwapVM, the Aqua swap engine.


Aqua.sol registry

Liquidity lifecycle

ship()

Solidity
1
2
3
4
5
6
function ship(
    address app,
    bytes calldata strategy,
    address[] calldata tokens,
    uint256[] calldata amounts
) external returns (bytes32 strategyHash);

Registers a strategy and allocates its virtual balances so it can be filled. No tokens move: only the maker's ERC-20 allowance is consumed. The tokens stay in the maker's wallet under a revocable, per-chain, per-token allowance.

Parameter Description
app The AquaApp contract governing swap logic for this strategy
strategy ABI-encoded strategy struct (shape defined by the AquaApp)
tokens Ordered list of token addresses to allocate
amounts Virtual amounts to allocate per token (parallel to tokens)

Returns the strategyHash, computed as keccak256(abi.encode(strategy)). Emits Shipped(maker, app, strategyHash, strategy), plus one Pushed event per token for the initial allocation.


dock()

Solidity
1
2
3
4
5
function dock(
    address app,
    bytes32 strategyHash,
    address[] calldata tokens
) external;

Revokes the strategy's virtual balances and stops it from accepting swaps. No tokens move, because the balances were always held in the maker's wallet.

Parameter Description
app The AquaApp contract this strategy belongs to
strategyHash Hash identifying the strategy to deactivate
tokens All tokens to zero out (must match tokens used at ship())

Emits Docked(maker, app, strategyHash).


Swap execution

These functions are called only by AquaApp contracts during swap execution, such as the production AquaSwapVMRouter. Makers and takers never call them directly.

A taker's fill is atomic. On the router, swap() performs a pull() followed by a push() in a single transaction, all or nothing. quote() is a static simulation that returns the same amounts without moving any tokens.

pull()

Solidity
1
2
3
4
5
6
7
function pull(
    address maker,
    bytes32 strategyHash,
    address token,
    uint256 amount,
    address to
) external;

Transfers output tokens from the maker's wallet to the taker and decrements the virtual balance.

Parameter Description
maker Maker whose tokens are being transferred
strategyHash Strategy the swap is executing against
token Token to transfer (the output token)
amount Amount to transfer
to Recipient (usually the taker)

Reverts if the maker's real wallet balance is insufficient. Emits Pulled(maker, app, strategyHash, token, amount).


push()

Solidity
1
2
3
4
5
6
7
function push(
    address maker,
    address app,
    bytes32 strategyHash,
    address token,
    uint256 amount
) external;

Transfers input tokens from the taker into the maker's wallet and increments the virtual balance, so received tokens immediately add to the strategy's available liquidity.

Parameter Description
maker Maker receiving the tokens
app AquaApp contract calling push
strategyHash Strategy the swap is executing against
token Token to transfer (the input token)
amount Amount to transfer

Emits Pushed(maker, app, strategyHash, token, amount). Any accrued LP swap fees auto-compound here into the maker's balance.


Queries

rawBalances()

Solidity
1
2
3
4
5
6
function rawBalances(
    address maker,
    address app,
    bytes32 strategyHash,
    address token
) external view returns (uint248 balance, uint8 tokensCount);

Returns the raw on-chain storage value. Does not validate that token belongs to the strategy. Use for debugging or querying arbitrary slots.

Return Description
balance Virtual balance in token base units
tokensCount Number of tokens registered in this strategy at ship() time

safeBalances()

Solidity
1
2
3
4
5
6
7
function safeBalances(
    address maker,
    address app,
    bytes32 strategyHash,
    address token0,
    address token1
) external view returns (uint256 balance0, uint256 balance1);

Returns balances for two tokens with active strategy validation. Reverts if either token was not registered in the strategy at ship() time. Use in production integrations and before executing swaps.


AquaApp base contract

Base contract for all swap applications. Inherit to build AMMs, limit orders, auctions, and other strategy types.

Solidity
1
2
3
4
5
// Immutable reference to the Aqua registry
IAqua public immutable AQUA;

// Transient reentrancy locks per (maker, strategyHash)
mapping(address maker => mapping(bytes32 strategyHash => TransientLock)) internal _reentrancyLocks;

nonReentrantStrategy modifier

Solidity
1
modifier nonReentrantStrategy(address maker, bytes32 strategyHash);

Locks the (maker, strategyHash) pair using transient storage for the duration of a swap. Prevents the callback pattern from being re-entered mid-swap. Two different strategies owned by the same maker can execute concurrently; the same (maker, strategyHash) pair cannot.


_safeCheckAquaPush()

Solidity
1
2
3
4
5
6
function _safeCheckAquaPush(
    address maker,
    bytes32 strategyHash,
    address token,
    uint256 expectedBalance
) internal view;

Verifies that the taker deposited the expected input tokens by comparing the current virtual balance against expectedBalance. Requires the nonReentrantStrategy modifier to be active, since it relies on the locked state to detect the push.

Used in the callback-based swap pattern. See Build an AquaApp for usage.


Events

Event Signature Emitted by
Shipped Shipped(address maker, address app, bytes32 strategyHash, bytes strategy) ship()
Docked Docked(address maker, address app, bytes32 strategyHash) dock()
Pulled Pulled(address maker, address app, bytes32 strategyHash, address token, uint256 amount) pull()
Pushed Pushed(address maker, address app, bytes32 strategyHash, address token, uint256 amount) push()
Swapped Swapped(bytes32 orderHash, address maker, address taker, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut) AquaSwapVMRouter.swap()

Shipped, Docked, Pulled, and Pushed are emitted by the Aqua registry. In the Pulled event, app is the calling AquaApp (msg.sender), since pull() takes no app argument. Swapped is emitted by the router on each fill, where Swapped.orderHash equals the strategyHash from Shipped. No parameters on Swapped are indexed.


Strategy hash formula

Solidity
1
bytes32 strategyHash = keccak256(abi.encode(strategy));

The hash encodes all strategy parameters. The same inputs always produce the same hash, and any parameter change produces a different hash, which enforces immutability at the identity level.


Taker access gate (checked at swap time). At launch every dApp strategy carries the Controls opcode _onlyTxOriginTokenBalanceNonZero, which reverts TxOriginTokenBalanceIsZero unless balanceOf(tx.origin) > 0. It is evaluated at swap time, not ship time, so a strategy can be live yet untradeable until a permitted taker holds the credential. Because it reads tx.origin, smart-contract wallets, multisigs and ERC-4337 bundlers cannot pass it as takers today. Permitted takers at launch are KYB-verified 1inch Resolvers. See Access & resolvers.

Did you find what you need?