The Aori Protocol is currently in closed beta and undergoing extensive security audits. A preliminary audit has been completed, with follow-up audits in progress to ensure protocol stability before stable release.
Interested in beta testing? Contact us
Aori is designed to securely facilitate omnichain trading, with low latency execution, amd trust minimized settlement. To accomplish this, Aori uses a combination of off-chain infrastructure, on-chain settlement contracts, and LayerZero messaging.
Solvers can expose a simple API to ingest and process orderflow directly to their trading system. The Aori Protocol's smart contracts ensure that the user's intents are satisfied by the Solver on the destination chain according to the parameters of a user signed intent submitted on the source chain.
The Aori contract revolves around a central Order
struct that contains all parameters needed to fulfill a user's cross-chain intent:
struct Order {
uint128 inputAmount; // Amount of tokens to be sent
uint128 outputAmount; // Amount of tokens to be received
address inputToken; // Token address on source chain
address outputToken; // Token address on destination chain
uint32 startTime; // When the order becomes valid
uint32 endTime; // When the order expires
uint32 srcEid; // Source chain endpoint ID
uint32 dstEid; // Destination chain endpoint ID
address offerer; // User who created the order
address recipient; // Address to receive output tokens
}
Note: The protocol currently supports ERC-20 tokens only. Native token (ETH/native chain currency) will be supported in a future update.
An order moves through various status states as it progresses through the settlement process:
flowchart LR
Unknown -->|deposit| Active
Active -->|fill| Filled
Active -->|cancel| Cancelled
Filled -->|settle| Settled
Cancelled --> End
Settled --> End
The Aori protocol consists of paired smart contracts deployed on different blockchains, enabling secure cross-chain intent settlement through LayerZero's messaging infrastructure.
sequenceDiagram
actor User
actor Solver
participant AoriSrc as Aori (Source)
participant LZ as LayerZero
participant AoriDst as Aori (Destination)
%% Order Fill Flow
User->>Solver: Signed Order
Solver->>AoriSrc: deposit()
User-->>AoriSrc: Locks user tokens
Solver->>AoriDst: fill()
AoriDst-->>User: Transfers tokens to recipient
Solver->>AoriDst: settle()
AoriDst->>LZ: _lzSend
Note over AoriDst: Emits SettleSent with MessagingReceipt
LZ-->>AoriSrc: _lzReceive
Note over AoriSrc: Credit Solver
Solver->>AoriSrc: withdraw()
AoriSrc-->>Solver: Transfer tokens to solver
- User signs an order with EIP-712 signature
- Solver submits the order and signature to source chain
- Tokens are locked in the source chain contract
- Solver fulfills the order on the destination chain
- Tokens are transferred to the recipient on destination chain
- Settlement message is sent back to source chain (with MessagingReceipt data captured in events)
- Source chain transfers locked tokens to solver
Aori supports two types of cancellation:
- Source Cancellation: Solvers can cancel directly on source chain
- Destination Cancellation: After expiry, users or solvers can cancel from destination chain, which sends a message to source chain and confirms the order has not been filled.
sequenceDiagram
actor User
actor Solver
participant AoriSrc as Aori (Source)
participant LZ as LayerZero
participant AoriDst as Aori (Destination)
%% Cancellation Flow
note right of User: Cancellation Flow
User->>AoriDst: cancel
AoriDst->>LZ: _lzSend
Note over AoriDst: Emits CancelSent with MessagingReceipt
LZ-->>AoriSrc: _lzReceive
Note over AoriSrc: Unlock tokens
User->>AoriSrc: withdraw()
AoriSrc-->>User: Transfer tokens to user
- Fill Recording: When orders are filled on destination chain, they're stored in the solver's fill array.
- Batch Settlement: Solvers can batch up to MAX_FILLS_PER_SETTLE orders for efficient processing.
- Cross-Chain Message: A settlement payload containing filler address and order hashes is sent via LayerZero.
- Receipt Tracking: MessagingReceipt information (guid, nonce, fee) is captured and included in the SettleSent event.
- Source Chain Processing: The source chain:
- Validates orders are in Active state
- Transfers tokens from locked to unlocked state for the solver
- Marks orders as Settled
- Skips problematic orders without reverting the entire batch
- Events: Emits Settle events for successful settlements.
This design ensures efficient, secure settlement while gracefully handling partial failures.
Single-chain swap orders are also supported by Aori.sol. These orders bypass the complex cross-chain messaging and offer efficient peer to peer settlement. The contract supports three main fulfillment paths for single-chain swaps:
sequenceDiagram
actor User
actor Solver
participant Aori as Aori Contract
User->>Solver: Signed Order
Solver->>Aori: swap(order, signature)
User-->>Aori: Input tokens locked
Solver-->>Aori: Output tokens provided
Aori-->>User: Output tokens transferred to recipient
Aori-->>Solver: Input tokens credited (unlocked)
In this atomic flow:
- Solver calls
swap()
with the user's signed order - Input tokens are transferred from the user to the contract
- Output tokens are transferred from the solver to the recipient
- Input tokens are immediately credited to the solver (unlocked balance)
- Order is marked as Settled in a single transaction
This is the most gas-efficient path but requires the solver to already have the output tokens.
sequenceDiagram
actor User
actor Solver
participant Aori as Aori Contract
participant LiqSrc as Liquidity Source
User->>Solver: Signed Order
Solver->>Aori: deposit(order, signature)
User-->>Aori: Input tokens locked
Note over Solver: Time delay (sourcing liquidity)
LiqSrc->>Solver: Output tokens provided
Solver->>Aori: fill(order)
Aori-->>User: Output tokens transferred to recipient
Aori-->>Solver: Input tokens credited (unlocked)
In this two-step flow:
- Solver first calls
deposit()
with the user's signed order - Input tokens are transferred from the user and locked in the contract
- Order is marked as Active
- Later, when the solver has sourced the output tokens (from a DEX or other liquidity source)
- Solver calls
fill()
with the same order - Output tokens are transferred from the solver to the recipient
- Order is immediately settled, and input tokens are credited to the solver
This pattern gives solvers flexibility to lock in the user's intent first, then source the output tokens before completing the trade. The settlement happens immediately after the fill call without needing cross-chain messaging.
The contract also supports a hook-based deposit mechanism for single-chain swaps:
sequenceDiagram
actor User
actor Solver
participant Aori as Aori Contract
participant Hook as Hook
User->>Solver: Signed Order
Solver->>Aori: deposit(order, signature, hook)
User-->>Aori: Input tokens transferred
Aori->>Hook: Input tokens + execute hook
Hook-->>Aori: Output tokens returned
Aori-->>User: Output tokens to recipient
Aori-->>Solver: Input tokens credited
In this path:
- Solver calls
deposit()
with the user's order, signature, and hook configuration - Input tokens are transferred directly to the hook contract
- The hook executes a route
- Output tokens are returned to the Aori contract
- Output tokens are transferred to the recipient
- Settlement happens immediately, crediting the input amount to the solver
This pattern enables advanced liquidity sourcing directly within the transaction.
pnpm install
forge build
forge test
See code test coverage
forge coverage --report --ir-minimum
MIT