Ax Protocol

Posted on 27 October 2023ax-protocol

NOTE: I contributed to this project using the 0xhashmap pseudonym due to regulatory uncertainty in the United States. However, I have decided to use my real name for building and communicating ideas moving forward.

All the work described below was completed solely by me and another engineer.

Summary

The Ax Protocol is an interoperability protocol powered by its own cross-chain native stablecoin, USX. The USX stablecoin is pegged to the US dollar and backed by Curve's 3Pool. The stablecoin is fungible across all supported chains, requires only gas fees for transfers, and is immune to slippage when transferring across chains.

Official Docs

The official docs for the Ax Protocol can be found at docs.ax.finance.

Smart Contracts

The Ax Protocol has four primary ERC-1967 proxy contracts:

These smart contracts underwent rigorous internal and external audits. The external auditor was Ottersec, one of the top smart contract security firms at the time the protocol was built. The final draft of Ottersec's audit report can be found here.

Deployed Addresses

USX, LayerZeroBridge, and WormholeBridge were deployed to 9 different chains: Ethereum, Optimism, Arbitrum One, Polygon, Gnosis, Celo, Avalanche C-Chain, Fantom, and BNB Smart Chain. The Treasury contract was only deployed to Ethereum.

USX

The USX contract adheres to the ERC-20 standard and incorporates cross-chain messaging for seamless transfers between blockchains. The contract has all standard ERC-20 functions like approve(), transfer() and balanceOf(), along with sendFrom(), a specialized function that enables cross-chain transfers of USX. Transfers are executed by burning USX on the source chain and minting an equal amount on the destination chain.

USX is designed to be bridge-agnostic, enabling the use of any message-passing protocol for cross-chain transfers. Although it makes sense to only use one message-passing protocol at a time to minimize attack vectors, the ability to switch between primary and backup bridges provides an additional layer of security. This bridge modularity also future-proofs USX, considering that better message-passing protocols may emerge in the future. LayerZero and Wormhole are the only message-passing protocols supported at the time of writing this. Supporting other protocols, like Axelar, would require building a bridging contract that integrates with the Axelar network (e.g., AxelarBridge).

Treasury

The Treasury contract manages the asset-backing of USX, maintaining its value pegged to the US dollar (1 USX ≈ $1). It uses Curve's 3Pool to create and remove stable USX liquidity.

Users can deposit DAI, USDC, USDT, or 3CRV (the 3Pool LP token) into the Treasury contract to receive USX. This process involves the mint() function in the Treasury contract: when called, it deposits the provided token into Curve's 3Pool, which gives back 3CRV. If 3CRV is already provided, this step is skipped. The 3CRV is staked on Convex and the mint() function is subsequently called in the USX contract to mint the user USX.

Conversely, users can exchange USX for DAI, USDC, USDT, or 3CRV through the Treasury contract. This involves the redeem() function: users specify an amount of USX to exchange, which triggers the unstaking of an equivalent amount of 3CRV from Convex. If necessary, this 3CRV is swapped in Curve's 3Pool for the desired token (DAI, USDC, or USDT). The supplied USX is burnt using the burn() function in the USX contract and the chosen token is given to the user.

LayerZeroBridge

The LayerZeroBridge contract is specifically designed to enable the USX contract to send and receive cross-chain messages via LayerZero. The LayerZeroBridge contract serves as a User Application in the LayerZero network, since it implements the logic to talk to LayerZero Endpoint contracts, which handle message transmissions. LayerZero runs their own message relaying system to handle message verification and delivery to destination chains. When the sendFrom() function in the USX contract is called on the source chain, with the _bridgeAddress parameter set to the LayerZeroBridge address, a cross-chain USX transfer is initiated via LayerZero. Below is the flow that is triggered by this function call.

  1. The specified amount of USX is burnt for the sender on the source chain by calling the burn() function in the USX contract.
  2. The sendMessage() function is called on the source chain's LayerZeroBridge contract.
  3. The send() function is called on the source chain's LayerZeroEndpoint contract.
  4. A SendToChain event is emitted on the source chain.
  5. An off-chain LayerZero service verifies the message. Following this verification, this service calls the validateTransactionProof() function on the destination chain's UltraLightNodeV2 contract. This action triggers the receivePayload() function on the LayerZeroEndpoint, which then calls the lzReceive() function on the destination chain's LayerZeroBridge contract.
  6. The recipient is minted the specified amount of USX on the destination chain by calling the mint() function on the USX contract.
  7. A ReceiveFromChain event is emitted on the destination chain.

WormholeBridge

The WormholeBridge contract is specifically designed to enable the USX contract to send and receive cross-chain messages via Wormhole. The WormholeBridge contract serves as an Emitter (or xDapp) contracts in the Wormhole network, since it implements the logic to talk to Wormhole Core contracts, which Guardians (validator nodes) in the Wormhole network observe to validate messages. A specialized off-chain relayer was built by the Ax Protocol team to listen for validated USX messages in the Wormhole network and deliver them to their respective destination chain. When the sendFrom() function in the USX contract is called on the source chain, with the _bridgeAddress parameter set to the WormholeBridge address, a cross-chain USX transfer is initiated via Wormhole. Below is the flow that is triggered by this function call.

  1. The specified amount of USX is burnt for the sender on the source chain by calling the burn() function on the USX contract.
  2. The sendMessage() function is called on the source chain's WormholeBridge contract.
  3. The publishMessage() function is called on the source chain's WormholeCore contract.
  4. A SendToChain event is emitted on the source chain.
  5. Guardians (validator nodes) in the Wormhole network validate the message off chain.
  6. The off-chain Wormhole message relaying system built by the Ax Protocol team picks up the verified message from the Wormhole network and delivers it by calling the processMessage() function on the destination chain's WormholeBridge contract.
  7. The recipient is minted the specified amount of USX on the destination chain by calling the mint() function on the USX contract.
  8. A ReceiveFromChain event is emitted on the destination chain.

Off-Chain Backend Services

Wormhole Message Relayer

This was the first Python relayer system built for Wormhole cross-chain messages. This service consists of two primary components: (1) the Spy Listener and (2) the Relayer.

The Spy Listener listens to the Wormhole network for validated Ax Protocol messages via gRPC stream. When a message is picked up, it is parsed and sent to a Redis queue. The Relayer then picks up messages from the Redis queue and delivers them to their respective destination chain.

AxScan

The AxScan service listens to on-chain events emitted by LayerZeroBridge and WormholeBridge to track the status of USX cross-chain transfers. The status can be obtained via a public API endpoint.

Gas System

This service is tasked with running a statistical analysis on the gas prices of all Ax Protocol-supported chains to update the destination chain fees on WormholeBridge. This is done by calling the setSendFees() function.

Frontends

All frontends were built using TypeScript, Next.js, and TailwindCSS.

Ax Protocol Homepage

The landing page for the Ax Protocol.

USX Frontend

User interface for transferring USX across chains, minting USX, and redeeming USX.

AxScan Frontend

User interface for checking the status of USX cross-chain transfers.

Developer Libraries

USX Transfer Widget

This is a React library that enables third-party apps to facilitate USX cross-chain transfers direclty within their user interface.