Liquorice
  • Intro
    • What is Liquorice
    • General flow
  • For market makers
    • Guide for PMMs
    • Basic Market Making API
    • Lending pools intro
      • Using lending pools via RFQ API
      • Onchain interactions with lending pools
  • For solvers
    • Guide for Solvers
    • WebSocket API
    • REST API
    • Settlement
      • Bebop JAM
      • CoW Protocol
  • For Liquidity Providers
    • Guide for LPs
  • LINKS
    • 🔗website
    • 👩‍💻github
    • 🐦twitter
    • Discord
    • Past audits
    • Smart contracts
Powered by GitBook
On this page
  • 1. Connecting to the Liquorice WebSocket API
  • 2. Sending RFQ
  • 3. Receiving Quote
  • 4. Partial fills
  • 5. Error handling
  1. For solvers

WebSocket API

This page explains how solvers can interact with the Liquorice RFQ WebSocket API

1. Connecting to the Liquorice WebSocket API

Production: wss://api.liquorice.tech/v1/solver/ws

Include the following headers with the WebSocket request

  • solver - name of the Solver

  • authorization - authorization token

WebSocket server sends Ping message every 30 seconds.

2. Sending RFQ

To obtain a quote from Liquorice, send an RFQ using the following message

{
  messageType: "rfq";
  message: {
    /// Chain ID (e.g for ArbitrumOne chainId = 42161)
    chainId: number;
    /// UUID of the RFQ (Must be generated by caller)
    rfqId: string;
    /// RFQ expiration UNIX timestamp (seconds)
    expiry: number,
    /// Address of token to be sent by trader
    baseToken: string;
    /// Address of the token to be received by trader
    quoteToken: string;
    /// Address of the account receiving quoteToken   
    trader: string;
    /// Optional address of the account sending baseToken
    /// If omitted, the system assumes that baseToken will be sent from trader address 
    effectiveTrader?: string;
    /// Note: Exactly one of the following two fields must be present
    /// Amount of baseToken with up to 18 decimal places, e.g. 100000000 (1 WBTC)
    baseTokenAmount?: string;
    /// Amount of quoteToken with up to 18 decimal places
    quoteTokenAmount?: string;
    /// List of maker names excluded from RFQ processing
    excludedMakers?: string[];
  }
}

The RFQ must include either baseTokenAmount or quoteTokenAmount, but not both.

When baseTokenAmount is specified, the trader (order initiator) is requesting the amount of quoteToken they would receive in exchange for a specific amount of baseToken.

When quoteTokenAmount is specified, the trader (order initiator) is requesting the amount of baseToken they need to provide to receive a specific amount of quoteToken.

3. Receiving Quote

The quote response is sent through the same WebSocket connection that received the RFQ, using the following format:

{
  messageType: "rfqQuote",
  message: {
    /// UUID of the RFQ
    rfqId: string,
    /// Indicates whether liquidity is available to fulfill RFQ
    liquidityAvailable: boolean,
    /// Array of available quote levels.
    /// Empty when liquidityAvailable is false
    levels: [{
      /// UUID of the maker RFQ that sourced this quote level
      makerRfqId: string,
      /// Name of the maker providing this quote level
      maker: string,
      /// Hex-encoded 32-byte nonce
      nonce: string,
      /// Quote expiration UNIX timestamp (seconds)
      expiry: number,
      /// Transaction details
      tx: {
        /// Address of the LiquoriceSettlement contract
        to: string,
        /// 0x-prefixed calldata string for the function within 
        /// LiquoriceSettlement contract
        data: string
      },
      /// Address of token to be sent by trader
      baseToken: string,
      /// Address of the token to be received by trader
      quoteToken: string,
      /// Amount of baseToken with up to 18 decimal places, e.g. 100000000 (1 WBTC)
      baseTokenAmount: string,
      /// Amount of quoteToken with up to 18 decimal places
      quoteTokenAmount: string,
      /// Settings for partial fill functionality.
      /// If absent, the order cannot be filled partially
      partialFill?: {
        /// Byte offset of the fill amount parameter in tx.data
        offset: number,
        /// Minimum fillable amount of baseToken, with up to 18 decimal places
        minBaseTokenAmount: string
      }
    }]
  }
}

Market makers can provide multiple quote levels with different amounts, but the quoted amounts will not exceed those specified in the RFQ.

Example For an RFQ where:

  • baseToken = ETH

  • quoteToken = USDT

  • baseTokenAmount = 1 ETH

The resulting quote may contain these levels:

Level 0: Exchange 1 ETH for 3,000 USDT

Level 1: Exchange 0.5 ETH for 1,502 USDT

Level 2: Exchange 0.1 ETH for 310 USDT

IMPORTANT NOTE: While solvers typically execute a single quote level, it is technically possible to execute multiple quote levels if they come from different market makers. When using multiple quote levels, ensure that they come from different makers, as quotes from the same maker will result in only one successful execution.

4. Partial fills

The quote level's partialFill.offset field specifies the byte offset of filledTakerAmount parameter within tx.data.

The partial fill amount must be greater than or equal to partialFill.minBaseTokenAmount.

If the partialFill field is not present, the quote level must be filled completely.

let calldata = tx.data.slice(0, 10 + partialFill.offset * 2) // Calldata up to offset. 2 is for `0x` prefix and 8 for the function selector.
    + fillAmount.toString(16).padStart(64, "0") // Replace with partial fill amount in hex, padded to 64 chars
    + tx.data.slice(10 + partialFillOffset * 2 + 64); // Remaining calldata after filledTakerAmount

5. Error handling

Error responses are sent through the same WebSocket connection using the following format:

{
  "messageType": "error",
  "message": {
    /// Type of the error
    errorType: string;
    /// Error message
    message: string;
  }
}
PreviousGuide for SolversNextREST API

Last updated 3 months ago

excludedMakers- to exclude specific makers from RFQ processing, obtain the complete maker list from the relevant

API endpoint