Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tests Format Docs

Async Swap AMM

Install

To install dependencies in all our packages in packages/*

bun install

Install foundry dependencies (v4-periphery)

forge install

Setup

[!TIP] We suggest you set up local anvil account with cast.

cast wallet import --mnemonic "test test test test test test test test test test test junk" anvil

Run local anvil node with Unichain fork

anvil --fork-url https://unichain.drpc.org
# or simulate block mining and finality
anvil --block-time 13

Local Deployment

Run deployment script

./dev/start_script.sh # scripts that you use --account setup of you choice

[!NOTE]

The start scripts will do the following:

  1. Deploy local PoolManger ./script/00_DeployPoolManager.s.sol
  2. Deploy Hook & Router contracts ./script/01_DeployHook.s.sol
  3. Initialize a pool with your hook attached ./script/02_InitilizePool.s.sol
  4. Add liqudity to previously initialized pool ./script/03_AddLiquidity.s.sol
  5. Submit an async swap transaction through custom router ./script/04_Swap.s.sol
  6. Fill previously submitted swap transaction ./script/05_ExecuteOrder.s.sol

Testing

Run tests

forge test -vvvv

Huff tests:

# sender is poolManager address
hnc src/AsyncSwap.huff test --sender 0x0000000000000000000000000000000000000000

Offchain Indexer

Start local indexer

bun run dev

[!Tip]

  • If you need typescript abi for your contracts on frontend or indexer use this script ./dev/generateAbi.sh
./dev/generateAbi.sh

Go to http://localhost:42069 to query orders from hook events

Docs

View documentation:

forge doc --serve --port 4000 --watch

Acknowledgment

Thanks to Atrium Academy, over the past 2 months we build this project during Uniswap Hook incubator program.

Team Socials:

Contents

BaseAlgorithm

Git Source

Inherits: IAlgorithm

State Variables

HOOKADDRESS

The address of the hook that will call this algorithm.

address public immutable HOOKADDRESS

Functions

constructor

Constructor to set the hook address.

constructor(address _hookAddress) ;

Parameters

NameTypeDescription
_hookAddressaddressThe address of the hook that will call this algorithm.

onlyHook

Modifier to restrict access to the hook address.

only hook contract can call

modifier onlyHook() ;

_checkCallerIsHookContract

function _checkCallerIsHookContract() internal view;

name

Returns the name of the ordering algorithm.

function name() external pure virtual returns (string memory);

Returns

NameTypeDescription
<none>stringThe name of the algorithm as a string.

version

Version of the algorithm.

function version() external pure virtual returns (string memory);

Returns

NameTypeDescription
<none>stringThe version of the algorithm as a string.

orderingRule

Executes the transaction ordering algorithm.

function orderingRule(bool zeroForOne, uint256 amount) external virtual;

Parameters

NameTypeDescription
zeroForOneboolIndicates the direction of the trade (true for currency0 to currency1, false for currency1 to currency0).
amountuint256The amount of the order being processed.

getVolatility

function getVolatility(AsyncOrder[] memory orders) external pure virtual override returns (uint256);

CLVR

Git Source

Inherits: BaseAlgorithm

Author: Meek Msaki @ Async Labs

This contract implements the CLVR algorithm for ordering transactions.

CLVR selects the next trade that minimizes price volatility (ln p0 - ln P(d, t))^2. The rule picks at each step t as the next trade that causes minimal local one-step price volatility from the status quo price p0.

Note: reference: https://arxiv.org/abs/2408.02634

Functions

constructor

constructor(address _hookAddress) BaseAlgorithm(_hookAddress);

name

Returns the name of the ordering algorithm.

function name() external pure override returns (string memory);

Returns

NameTypeDescription
<none>stringThe name of the algorithm as a string.

version

Version of the algorithm.

function version() external pure override returns (string memory);

Returns

NameTypeDescription
<none>stringThe version of the algorithm as a string.

orderingRule

Executes the transaction ordering algorithm.

function orderingRule(bool zeroForOne, uint256 amount) external override onlyHook;

Parameters

NameTypeDescription
zeroForOneboolIndicates the direction of the trade (true for currency0 to currency1, false for currency1 to currency0).
amountuint256The amount of the order being processed.

getVolatility

function getVolatility(AsyncOrder[] memory orders) external pure override returns (uint256);

Contents

IAlgorithm

Git Source

Author: Async Labs

This interface defines the functions for transaction ordering algorithms used in the Async Swap AMM hook.

Functions

orderingRule

Executes the transaction ordering algorithm.

function orderingRule(bool zeroForOne, uint256 amount) external;

Parameters

NameTypeDescription
zeroForOneboolIndicates the direction of the trade (true for currency0 to currency1, false for currency1 to currency0).
amountuint256The amount of the order being processed.

name

Returns the name of the ordering algorithm.

function name() external view returns (string memory);

Returns

NameTypeDescription
<none>stringThe name of the algorithm as a string.

version

Version of the algorithm.

function version() external view returns (string memory);

Returns

NameTypeDescription
<none>stringThe version of the algorithm as a string.

getVolatility

function getVolatility(AsyncOrder[] memory orders) external pure returns (uint256);

IAsyncSwapAMM

Git Source

Inherits: IAsyncSwapOrder

Author: Async Labs

This interface defines the functions for the Async CSMM (Constant Sum Market Maker) contract.

Functions

executeOrder

Fill an async order in an Async Swap AMM.

function executeOrder(AsyncOrder calldata order, bytes calldata userParams) external;

Parameters

NameTypeDescription
orderAsyncOrderThe async order to be filled.
userParamsbytesAdditional data for the user.

executeOrders

Fills async orders in batching mode, allowing multiple orders to be executed in a single transaction.

function executeOrders(AsyncOrder[] calldata orders, bytes calldata userParams) external;

Parameters

NameTypeDescription
ordersAsyncOrder[]An array of async orders to be executed.
userParamsbytesAdditional data for the user, allowing user to specify an executor.

Structs

UserParams

Struct representing the user parameters for executing an async order.

struct UserParams {
  address user;
  address executor;
}

Properties

NameTypeDescription
useraddress
executoraddress

IAsyncSwapOrder

Git Source

Author: Async Labs

This interface defines the functions for the Async Swap orders.

Functions

asyncOrderAmount

Returns the claimable amount for an async order.

function asyncOrderAmount(PoolId poolId, address user, bool zeroForOne) external view returns (uint256 claimable);

Parameters

NameTypeDescription
poolIdPoolIdThe poolId of the pool where the order is placed.
useraddressThe user who placed the order.
zeroForOneboolWhether the order is for a swap from currency0 to currency1 (true) or currency1 to currency0 (false).

Returns

NameTypeDescription
claimableuint256The amount that can be claimed by the user.

isExecutor

Checks if the given executor is valid for the async order.

function isExecutor(PoolId poolId, address owner, address executor) external returns (bool);

Parameters

NameTypeDescription
poolIdPoolIdThe poolId the executor is interacting with.
owneraddressThe async order owner be checked against.
executoraddressThe address of the executor to be checked.

Returns

NameTypeDescription
<none>boolisExecutor True if the executor is valid for the async order, false otherwise.

Events

AsyncOrderFilled

Emitted when an async order is filled.

event AsyncOrderFilled(PoolId poolId, address owner, bool zeroForOne, uint256 amount);

Parameters

NameTypeDescription
poolIdPoolIdThe poolId of the pool where the order is placed.
owneraddressThe owner of the order, who can claim the order.
zeroForOneboolWhether the order is for a swap from currency0 to currency1 (true) or currency1 to currency0 (false).
amountuint256The amount of the order.

AsyncSwapOrder

Emitted when an async swap order is created.

event AsyncSwapOrder(PoolId poolId, address owner, bool indexed zeroForOne, int256 indexed amountIn);

Parameters

NameTypeDescription
poolIdPoolIdThe poolId of the pool where the order is placed.
owneraddressThe owner of the order, who can claim the order.
zeroForOneboolWhether the order is for a swap from currency0 to currency1 (true) or currency1 to currency0 (false).
amountInint256The amount of the order that is being filled.

Errors

InvalidOrder

Error thrown when an order is invalid.

error InvalidOrder();

ZeroFillOrder

Error thrown when an order is of zero amount.

error ZeroFillOrder();

IRouter

Git Source

Author: Async Labs

This interface defines the functions for the Router contract, which allows users to swap tokens and fill orders using async orders.

Functions

swap

Swaps tokens using an async order.

function swap(AsyncOrder calldata order, bytes calldata userData) external;

Parameters

NameTypeDescription
orderAsyncOrderThe async order to be placed.
userDatabytesAdditional data for the user, allowing user to specify an executor.

fillOrder

Fills an async order.

function fillOrder(AsyncOrder calldata order, bytes calldata userData) external;

Parameters

NameTypeDescription
orderAsyncOrderThe async order to be filled.
userDatabytesAdditional data for the user, allowing user to specify an executor.

Structs

SwapCallback

Callback structure for the swap function.

struct SwapCallback {
  ActionType action;
  AsyncOrder order;
}

Properties

NameTypeDescription
actionActionTypeThe action type, either Swap or FillOrder.
orderAsyncOrderThe async order that is in context for the swap or fill operation.

Enums

ActionType

Enum representing the action type for the swap callback.

  1. Swap - If the action is a swap, this will specify the async swap order intent.
  2. FillOrder - If the action is a fill order, this will specify fill order intent.
enum ActionType {
  Swap,
  FillOrder
}

Contents

AsyncFiller

Git Source

Author: Async Labs

This library provides functionality for filling async swap orders in the Uniswap V4 pool.

Functions

isExecutor

Checks if the given executor is valid for the async order.

function isExecutor(AsyncOrder calldata order, State storage self, address executor) internal view returns (bool);

Parameters

NameTypeDescription
orderAsyncOrderThe async order to be filled.
selfStateThe storage slot that controls the state of orders.
executoraddressThe address of the executor to be checked.

Returns

NameTypeDescription
<none>boolisExecutor True if the executor is valid for the async order, false otherwise.

executeOrder

Fills async orders in batching mode, allowing multiple orders to be executed in a single transaction.

function executeOrder(AsyncOrder[] calldata orders, State storage self, bytes calldata userParams) external;

Parameters

NameTypeDescription
ordersAsyncOrder[]An array of async orders to be executed.
selfState
userParamsbytesAdditional data for the user, allowing user to specify an executor.

_execute

Fill an async order in an Async Swap AMM.

function _execute(AsyncOrder calldata order, State storage self, bytes calldata) internal;

Parameters

NameTypeDescription
orderAsyncOrderThe async order to be filled.
selfStateThe state of the AsyncFiller library, containing async orders and executors.
<none>bytes

Events

AsyncOrderFilled

Emitted when an async order is filled.

event AsyncOrderFilled(PoolId poolId, address owner, bool zeroForOne, uint256 amount);

Parameters

NameTypeDescription
poolIdPoolIdThe poolId of the pool where the order is placed.
owneraddressThe owner of the order, who can claim the order.
zeroForOneboolWhether the order is for a swap from currency0 to currency1 (true) or currency1 to currency0 (false).
amountuint256The amount of the order.

Errors

InvalidOrder

Error thrown when an order is invalid.

error InvalidOrder();

ZeroFillOrder

Error thrown when an order is of zero amount.

error ZeroFillOrder();

Structs

State

Represents the state of the AsyncFiller library storage for async orders and executors.

struct State {
  IPoolManager poolManager;
  IAlgorithm algorithm;
  mapping(address user => mapping(bool zeroForOne => uint256 claimable)) asyncOrderAmount;
  mapping(address owner => mapping(address executor => bool)) isExecutor;
}

Properties

NameTypeDescription
poolManagerIPoolManagerThe PoolManager contract that manages the pools.
algorithmIAlgorithm
asyncOrderAmountmapping(address user => mapping(bool zeroForOne => uint256 claimable))
isExecutormapping(address owner => mapping(address executor => bool))

Contents

AsyncOrder

Git Source

Represents an async order for a swap in the Uniswap V4 pool.

struct AsyncOrder {
PoolKey key;
address owner;
bool zeroForOne;
uint256 amountIn;
uint160 sqrtPrice;
}

Properties

NameTypeDescription
keyPoolKeyThe Uniswap V4 PoolKey that identifies the pool.
owneraddressThe owner of the order, who can claim the order.
zeroForOneboolWhether the order is for a swap from currency0 to currency1 (true) or currency1 to currency0 (false).
amountInuint256The amount of the order that is being filled.
sqrtPriceuint160The square root price of the pool at the time of the order.

Contents

TransientStorage

Git Source

Author: Async Labs

This contract provides functions to interact with the transient storage.

Functions

tload

Load a value from the transient storage.

function tload(bytes32 key) internal view returns (bytes32 value);

Parameters

NameTypeDescription
keybytes32The key to store or retrieve the value.

tstore

Store a value in the transient storage.

function tstore(bytes32 key, bytes32 value) internal;

Parameters

NameTypeDescription
keybytes32The key to store or retrieve the value.
valuebytes32The value to store in the transient storage.

AsyncSwap

Git Source

Inherits: BaseHook, IAsyncSwapAMM

Author: Asyncswap Labs

State Variables

asyncOrders

Mapping to store async orders.

mapping(PoolId poolId => AsyncFiller.State) public asyncOrders

ALGORITHM

Ordering algortim

IAlgorithm public immutable ALGORITHM

kvolatility

mapping(uint256 block => uint256 volatility) public kvolatility

Functions

constructor

Initializes the Async Swap Hook contract with the PoolManager address and sets an transaction ordering algorithm.

constructor(IPoolManager poolManager, IAlgorithm orderingAlgorithm) BaseHook(poolManager);

Parameters

NameTypeDescription
poolManagerIPoolManagerThe address of the PoolManager contract.
orderingAlgorithmIAlgorithmThe address of the ordering algorithm

_beforeInitialize

function _beforeInitialize(address, PoolKey calldata key, uint160) internal virtual override returns (bytes4);

getHookPermissions

Returns a struct of permissions to signal which hook functions are to be implemented

Used at deployment to validate the address correctly represents the expected permissions

function getHookPermissions() public pure override returns (Hooks.Permissions memory);

_beforeAddLiquidity

function _beforeAddLiquidity(address, PoolKey calldata, IPoolManager.ModifyLiquidityParams calldata, bytes calldata)
  internal
  pure
  override
  returns (bytes4);

asyncOrderAmount

function asyncOrderAmount(PoolId poolId, address user, bool zeroForOne) external view returns (uint256 claimable);

isExecutor

function isExecutor(PoolId poolId, address user, address executor) external view returns (bool);

calculateHookFee

function calculateHookFee(uint256) public pure returns (uint256);

calculatePoolFee

function calculatePoolFee(uint24, uint256) public pure returns (uint256);

executeOrders

Fills async orders in batching mode, allowing multiple orders to be executed in a single transaction.

function executeOrders(AsyncOrder[] calldata orders, bytes calldata userParams) external;

Parameters

NameTypeDescription
ordersAsyncOrder[]An array of async orders to be executed.
userParamsbytesAdditional data for the user, allowing user to specify an executor.

executeOrder

Fill an async order in an Async Swap AMM.

function executeOrder(AsyncOrder calldata order, bytes calldata) external;

Parameters

NameTypeDescription
orderAsyncOrderThe async order to be filled.
<none>bytes

_beforeSwap

function _beforeSwap(
  address sender,
  PoolKey calldata key,
  IPoolManager.SwapParams calldata params,
  bytes calldata hookParams
) internal override returns (bytes4, BeforeSwapDelta, uint24);

Events

HookSwap

Event emitted when a swap is executed.

event HookSwap(
  bytes32 indexed id,
  address indexed sender,
  int128 amount0,
  int128 amount1,
  uint128 hookLPfeeAmount0,
  uint128 hookLPfeeAmount1
);

Parameters

NameTypeDescription
idbytes32The poolId of the pool where the swap occurred.
senderaddressThe address that initiated the swap.
amount0int128The amount of currency0 taken in the swap (negative for exact input).
amount1int128The amount of currency1 taken in the swap (negative for exact input).
hookLPfeeAmount0uint128Fee amount taken for LP in currency0.
hookLPfeeAmount1uint128Fee amount taken for LP in currency1.

Errors

UnsupportedLiquidity

Error thrown when liquidity is not supported in this hook.

error UnsupportedLiquidity();

Router

Git Source

Inherits: IRouter

Author: Async Labs

This contract implements the Router interface, allowing users to swap tokens and fill async orders through the PoolManager and Async Swap hook.

State Variables

POOLMANAGER

PoolManager contract to interact with the pools.

IPoolManager immutable POOLMANAGER

HOOK

Async Swap Hook contract to execute async orders.

IAsyncSwapAMM immutable HOOK

ACTION_LOCATION

keccak256("Router.ActionType") - 1

bytes32 constant ACTION_LOCATION = 0xf3b150ebf41dad0872df6788629edb438733cb4a5c9ea779b1b1f3614faffc69

USER_LOCATION

keccak256("Router.User") - 1

bytes32 constant USER_LOCATION = 0x3dde20d9bf5cc25a9f487c6d6b54d3c19e3fa4738b91a7a509d4fc4180a72356

ASYNC_FILLER_LOCATION

keccak256("Router.AsyncFiller") - 1

bytes32 constant ASYNC_FILLER_LOCATION = 0xd972a937b59dc5cb8c692dd9f211e85afa8def4caee6e05b31db0f53e16d02e0

Functions

constructor

Initializes the Router contract with the PoolManager and Async CSMM hook.

constructor(IPoolManager _poolManager, IAsyncSwapAMM _hook) ;

Parameters

NameTypeDescription
_poolManagerIPoolManagerThe PoolManager contract that manages the pools.
_hookIAsyncSwapAMMThe Async CSMM hook contract that executes async orders.

onlyPoolManager

Only allow the PoolManager to call certain functions.

modifier onlyPoolManager() ;

_checkCallerIsPoolManager

function _checkCallerIsPoolManager() internal view;

swap

Swaps tokens using an async order.

function swap(AsyncOrder calldata order, bytes memory userData) external;

Parameters

NameTypeDescription
orderAsyncOrderThe async order to be placed.
userDatabytesAdditional data for the user, allowing user to specify an executor.

fillOrder

Fills an async order.

function fillOrder(AsyncOrder calldata order, bytes calldata) external;

Parameters

NameTypeDescription
orderAsyncOrderThe async order to be filled.
<none>bytes

unlockCallback

Callback handler to unlock the PoolManager after a swap or fill order.

function unlockCallback(bytes calldata data) external onlyPoolManager returns (bytes memory);

Parameters

NameTypeDescription
databytesThe callback data containing the action type and order information.

Returns

NameTypeDescription
<none>bytesData to return back to the PoolManager after unlock.