1inch Aqua is a shared liquidity layer. Its swap engine is SwapVM, and its on-chain registry is the Aqua contract (Aqua.sol, deployed as the Aqua registry). This page covers the concepts you need before writing a strategy: the maker and taker roles, what a strategy is, how virtual balances keep liquidity self-custodial, the strategy lifecycle, and the Shared Liquidity Ratio.
Positions and strategies are the same thing. In the 1inch dApp you create a position. On-chain, and throughout the SDK, the API and these developer docs, that same object is called a strategy. The code identifiers are fixed and cannot be renamed: strategyHash, the Strategy struct/DTO, the /strategies endpoint and ship()/dock(). These developer docs use strategy so the prose matches the code you call. Read it as the dApp's position.
Aqua is self-custodial. A maker's tokens stay in the maker's own wallet under a revocable ERC-20 allowance that is granted per chain and per token. The protocol holds zero tokens and never borrows them. Standard smart-contract and token-approval risk still applies.
1. Maker and taker
Maker is the liquidity provider. A maker allocates tokens to one or more strategies by calling ship() on the Aqua registry. The maker's tokens are never transferred to Aqua. Instead, Aqua records a virtual allocation: an internal counter that represents a claim against the maker's existing ERC-20 allowance. The maker keeps full custody and can continue to use the same tokens for governance, money-market collateral, or any other DeFi purpose. Becoming a maker is permissionless.
Taker is the swap initiator. A taker references an active strategy and fills against it by calling swap() on the AquaApp (the deployed swap router is AquaSwapVMRouter). The taker supplies the input token, and the maker supplies the output token directly from their wallet. The fill is atomic: if any condition fails (insufficient maker balance, slippage exceeded, expired order) the entire transaction reverts with no partial state change. At launch, takers are gated: the app checks a KycNFT access credential on-chain at swap time, so only approved takers can fill. Makers are not gated.
A maker and a taker are not necessarily different entities. A smart contract can act as both, providing liquidity as a maker while routing swaps as a taker.
2. Strategy
A strategy (shown as a position in the 1inch dApp) is the central unit of Aqua. It is the on-chain artifact a maker ships to express: "I will provide this liquidity, under these pricing rules, with these permissions."
A strategy is modeled as four layers:
| Layer | Answers | Where it lives |
|---|---|---|
| Identification | Which strategy is this? | (maker, app, strategyHash) triple |
| Registry state | What liquidity backs it? | balances[maker][app][strategyHash][token] in Aqua.sol |
| Program | How does it price and fill? | SwapVM bytecode: an ordered sequence of opcodes inside a SwapVM Order, ABI-encoded as the Strategy |
| Configuration | Who authorized it and when? | MakerTraits + TakerTraits headers |
With SwapVM, the Strategy is the ABI-encoded form of a SwapVM Order. The Order wraps a Program. SwapVM executes the Program instructions, not the Strategy. Aqua only manages balance accounting against the strategy hash, which it treats as opaque bytes.
A strategy is immutable once shipped. To change parameters, dock the old strategy and ship a new one, which produces a new strategyHash.
3. Virtual balances
Aqua never takes custody of tokens. Instead, Aqua.sol maintains a virtual balance, an internal counter that represents a claim against the maker's ERC-20 allowance to the registry contract. Tokens remain in the maker's wallet at all times, and the protocol's own token balance is always zero.
The on-chain storage is a four-level nested mapping:
Solidity
12345
Maker Address
→ Application Address
→ Strategy Hash (bytes32)
→ Token Address → Virtual Balance
A concrete example: a maker holds 10 WETH in their wallet with a 10 WETH allowance granted to Aqua.sol.
Maker wallet: 10 WETH (allowance to Aqua: 10 WETH)
└── Strategy A: 4 WETH virtual
└── Strategy B: 3 WETH virtual
└── Unallocated: 3 WETH
Both strategies are live at the same time. The same 10 WETH backs both of them, and this is what "shared liquidity" means. A virtual balance is a ceiling on what a strategy can make available, not a promise of returns. Every fill still draws from the maker's real wallet balance.
What happens during a swap
When a taker fills against Strategy A:
pull(): the AquaApp calls Aqua to transfer the output token (for example 1 WETH) directly from the maker's wallet to the taker. Aqua decrements Strategy A's virtual balance by 1 WETH.push(): the AquaApp calls Aqua to transfer the input token (for example 3,000 USDC) from the taker to the maker's wallet. Aqua increments Strategy A's virtual balance for USDC by 3,000. This increment is immediate, so received tokens (including swap fees) auto-compound into available liquidity with no manual rebalancing step.
Neither operation moves tokens through Aqua itself. Aqua only updates the internal counter and triggers the ERC-20 transfer directly between maker and taker.
Coverage and underfunded strategies
If the maker's actual wallet balance falls below their virtual commitment, pull() reverts. Aqua keeps quoting prices from virtual balances, because it does not check real balances at quote time, so price continuity is preserved. Swaps simply stop filling until the maker's wallet is topped up. This is an economic effect (temporary illiquidity), not bad debt or protocol insolvency, and there is no on-chain pause and no liquidation. Makers are advised to dock() strategies that become chronically underfunded to avoid accumulating adverse price exposure while a strategy cannot fill.
4. The lifecycle
Every strategy moves through states controlled by four entry points on Aqua.sol:
[Not shipped]
|
| ship(app, strategy, tokens, amounts)
v
[Active]
|
| pull() / push() execute on every swap
|
| dock(app, strategyHash, tokens)
v
[Docked]
|
| re-ship with updated params
v
back to [Active]
| Verb | Who calls it | What it does |
|---|---|---|
ship |
Maker | Allocates virtual balances; the strategy becomes fillable |
dock |
Maker | Revokes virtual balances instantly; strategy stops accepting swaps; no tokens move |
pull |
AquaApp | Transfers output token from maker's wallet to taker; decrements virtual balance |
push |
AquaApp | Transfers input token from taker to maker's wallet; increments virtual balance |
ship() and dock() are pure configuration operations. There is no token transfer, no withdrawal delay, and no liquidity migration. A maker can move from zero liquidity to a live strategy, or exit a strategy entirely, in a single transaction.
pull() and push() are never called directly by makers or takers. They are internal calls made by the AquaApp contract during swap execution, where a fill runs pull() and push() atomically in one transaction.
See Strategy lifecycle for the full state machine, event log (Shipped / Docked / Pulled / Pushed / Swapped), and SDK helpers.
5. Shared Liquidity Ratio
The Shared Liquidity Ratio (SLR) is Aqua's core efficiency metric. It measures how much liquidity a maker makes available across strategies relative to the wallet equity backing it. Because the same tokens can back several strategies at once, SLR is always at least 1:
sum of liquidity made available across all strategies
SLR = --------------------------------------------------------- ≥ 1
sum of wallet equity backing those strategies
SLR describes availability and capital efficiency. It is not leverage, margin, or borrowing, and no tokens are ever borrowed. Any multiplier it implies is a theoretical ceiling that is always capped by the maker's real wallet balance, and it is never a forecast of returns.
An example
A maker holds $1,000 in their wallet and grants the corresponding allowance. They ship three strategies, each able to reference up to that same $1,000 of liquidity:
The wallet equity is $1,000.
The three strategies together reference $3,000 of available liquidity, drawn from the same $1,000.
That is an SLR of 3×: $3,000 of concurrently available liquidity from $1,000 of wallet equity, achieved purely by sharing one balance across strategies. No borrowing is involved, and total fills can never exceed the real $1,000 in the wallet at any instant.
This works because swap activity is asynchronous. Different strategies fill at different times, so one wallet balance can service many strategies' occasional fills without collision. While any single strategy may sit idle most of the time (consistent with on-chain data across major AMMs), the same idle capital stays available to every strategy it backs, turning it into concurrent fee-earning strategies. Swap fees are not guaranteed.
The Shared Liquidity Ratio is an efficiency metric, not a safety invariant.
SLR measures how efficiently wallet equity is shared across strategies. Safety properties are enforced separately:
ERC-20 allowance cap: a strategy's virtual balance cannot exceed the maker's total ERC-20 allowance to
Aqua.sol, which gives explicit per-token risk control. The allowance is per chain and per token, and it is revocable at any time.Atomic
pull()fill: if the maker's real wallet balance is insufficient at swap execution time,pull()reverts. There are no partial fills and no bad debt.Underfunding is recoverable: underfunded strategies stop filling but do not create protocol-level losses. The maker can dock and re-evaluate.
What to read next
Strategy: the full four-layer model
Strategy lifecycle: lifecycle state machine with events and SDK parsers
Quickstart: ship your first strategy
Taker access
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 unfillable 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 & Pathfinder.