Integrate the Relayer API

Integrate just-in-time mint/redeems of 80+ uAssets directly in your app or protocol.

The Universal Relayer API allows developers to seamlessly integrate uAssets into their applications. The Relayer acts as an intermediary, connecting users with Merchants to facilitate buying, selling, and cross-chain transactions.

What is the Relayer?

DeFi typically relies on liquidity pools (LPs) to provide assets for swaps. However, LPs are capital inefficient because liquidity sits unused until needed.

Universal solves this with JIT (just-in-time) Liquidity via the Universal Relayer meaning:

  • Instead of pre-depositing liquidity, Merchants mint and fulfill orders dynamically when demand arises.

  • Liquidity is provided on an as-needed basis, optimizing capital efficiency.

To obtain API access with higher rate limits, please reach out to the Universal Partnerships team for an API key.

Basics

API Basics

Base URL

This is the base URL for all API requests.

https://relayer.universal.xyz/api (with an API key)
https://www.universal.xyz/api (without an API key)

Authentication

All API requests require authentication via a Bearer Token.

Authorization: Bearer <YOUR_API_KEY>

Ensure that your API key is included in every request to authenticate and authorize API usage.


Types
  • TokenName: BTC, SOL, XRP, DOGE, DOT, NEAR, LTC, ADA, BCH, ALGO

  • PairTokenName: USDC

  • BlockchainName: BASE

  • Quote

      type: "BUY" | "SELL";
      token: TokenName;
      token_amount: string; // wei
      pair_token: PairTokenName;
      slippage_bips: number; // 0-100
      blockchain: BlockchainName;
      deadline: string; // unix epoch
      pair_token_amount: string; // wei
      id: string;
      user_address: string; // 0x..
      merchant_address: string; // 0x..
      gas_fee_nominal: string; // wei
      gas_fee_dollars: number; // e.g. $1.23 = 1.23
      relayer_nonce: number;
      merchant_id: string; 
Requesting a Quote

Send a Quote Request

To retrieve a price quote for a uAsset transaction, make a POST request to the following endpoint:

POST /quote

Request Body Parameters

  • type: Specifies if the user wants to BUY or SELL.

  • token: The uAsset being bought or sold.

  • token_amount: (Optional) The amount of the asset being transacted.

  • pair_token: The stable asset used for the trade (e.g., USDC).

  • pair_token_amount: (Optional) The amount of the paired asset.

  • slippage_bips: Slippage tolerance in basis points (0-100).

  • blockchain: The blockchain network where the transaction is executed.

  • user_address: The wallet address initiating the trade.

{
  type: "BUY" | "SELL";
  token: TokenName;
  token_amount?: string;
  pair_token_amount?: string;
  pair_token: PairTokenName;
  slippage_bips: number;
  blockchain: BlockchainName;
  user_address: string;
}

Response (200 OK)

Upon success, the API returns a quote containing:

  • Quoted amounts

  • Gas fees

  • Merchant details

  • A unique quote ID for later use

{
  ...Quote
}

Signing a Quote

User Signs the Quote

The user must sign the quote using EIP-712 signature standards before submitting the order.

Example Code (Signing a Quote with EIP-712)

import { DutchOrderBuilder } from "@uniswap/uniswapx-sdk";
import { BigNumber } from "ethers5"; // ethers v5

type TokenName = "BTC" | "SOL" | "XRP" | "DOGE" | "DOT" | "NEAR" | "LTC" | "ADA" | "BCH" | "ALGO";
type PairTokenName = "USDC";
type BlockchainName = "BASE";

interface Quote {
  type: "BUY" | "SELL";
  token: TokenName;
  token_amount: bigint;
  pair_token: PairTokenName;
  slippage_bips: number;
  blockchain: BlockchainName;
  deadline: bigint;
  pair_token_amount: bigint;
  id: string;
  user_address: string;
  merchant_address: string;
  gas_fee_nominal: bigint;
  gas_fee_dollars: number;
  relayer_nonce: number;
}

const CHAIN_ID: number = <CHAIN_ID>;
const REACTOR_ADDRESS: string = <REACTOR_ADDRESS>;
const PERMIT2_ADDRESS: string = <PERMIT2_ADDRESS>;

async function signTypedQuote(quote: Quote) {
  const builder = new DutchOrderBuilder(
    CHAIN_ID,
    REACTOR_ADDRESS,
    PERMIT2_ADDRESS
  );
  const TOKEN_ADDRESS = <TOKEN_ADDRESS>;
  const PAIR_TOKEN_ADDRESS = <PAIR_TOKEN_ADDRESS>;

  const order = builder
    .deadline(Number(quote.deadline))
    .decayEndTime(Number(quote.deadline))
    .decayStartTime(Number(quote.deadline) - 100)
    .nonce(BigNumber.from(quote.relayer_nonce))
    .input({
      token: quote.type == "BUY" ? PAIR_TOKEN_ADDRESS : TOKEN_ADDRESS,
      startAmount:
        quote.type == "BUY"
          ? BigNumber.from(quote.pair_token_amount.toString())
          : BigNumber.from(quote.token_amount.toString()),
      endAmount:
        quote.type == "BUY"
          ? BigNumber.from(quote.pair_token_amount.toString())
          : BigNumber.from(quote.token_amount.toString()),
    })
    .output({
      token: quote.type == "BUY" ? TOKEN_ADDRESS : PAIR_TOKEN_ADDRESS,
      startAmount:
        quote.type == "BUY"
          ? BigNumber.from(quote.token_amount.toString())
          : BigNumber.from(quote.pair_token_amount.toString()),
      endAmount:
        quote.type == "BUY"
          ? BigNumber.from(quote.token_amount.toString())
          : BigNumber.from(quote.pair_token_amount.toString()),
      recipient: quote.user_address,
    })
    .swapper(quote.user_address)
    .exclusiveFiller(quote.merchant_address, BigNumber.from(0))
    .build();

  const { domain, types, values } = order.permitData();
  const primaryType: "PermitWitnessTransferFrom" = "PermitWitnessTransferFrom";
  const typedData = {
    domain,
    types,
    primaryType,
    message: values,
  };
  const signer = <SIGNER>;
  const signature = await signer.signTypedData(typedData);
  return signature;
}
Submitting an Order

Submit a Signed Order

Once the quote is signed, submit it using the /order endpoint:

POST /order

Request Body Parameters

This request includes the signed quote along with the necessary parameters from the previous steps.

{
 ...Quote, 
 "signature": string, // Quote signed by the user
}

Response (200 OK)

Upon success, the API will return the transaction hash confirming the execution of the trade.Response

{
  "transaction_hash": string // Transaction hash of the fulfillment
}

Last updated