LogoLogo
  • Overview
    • Introduction
    • Table of Contents
  • Token Information
    • Symmio Foundation
  • Protocol Architecture
    • Protocol Introduction
    • Technical Documentation
      • Building an Application with SYMM
        • Introduction and Diamond Explainer
        • Querying Info from the SYMM Diamond
        • MultiAccount
        • Creating an Account and Depositing Funds
        • Sending a Quote
        • Closing a Quote
        • Instant Trading
          • Instant Login (EOA)
          • Instant Login (Account Abstraction)
          • Sending a Quote (Instant Open)
          • Sending a Quote (Instant Close)
        • Frequently Used Queries
      • Solver Docs
        • Solver Docs (github)
        • Solver Implementation Guide (High Level Overview)
        • Building a Solver on SYMMIO
          • 1. Intent Creation
          • 2. Seeing the Intent
          • 3. Hedging Off-Chain
          • 4. Opening/Closing a Position On-Chain
          • Creating the APIs
            • GET Contract Symbols
            • GET Open Interest
            • GET Notional Cap
            • GET Price Range
            • GET Error Codes
            • GET Get Locked Params
            • GET Get Funding Info
            • POST Position State
          • Solver Flow Summary Example
          • Recommended Architecture for Solvers
          • Glossary
        • Conditional Orders Handler
        • Rasa Solver TP/SL Implementation
        • Instant Trading
          • Instant Trading (Solvers)
          • Rasa Instant Trading Implementation
          • Instant Trading Condition Checks
        • Fetching Gas Prices Script
        • How to Add a Market as a Solver
        • Verifying Account Abstracted Instant Actions (ERC-4337)
      • Frontend Docs
        • Setting up a Frontend with SYMMIO
        • Frontend SDK Setup Guide
        • MultiAccount Deployment Guide
        • Instant Trading (Frontends)
          • Account Abstracted Instant Actions (Frontends)
        • Implement a Trading Bot on Symmio (OLD)
          • Setup
          • Creating a Sub-Account
          • Minting Collateral Tokens (Optional)
          • Depositing and Allocating Tokens
          • Obtaining Muon Signatures
          • Sending a Quote
          • Monitoring Price for Execution
      • Contract Docs
        • SYMMIO CORE v0.82
        • Contracts Documentation 0.8.2
          • Main Flow
          • The SYMM Diamond
          • Facets
            • Account Facet
            • Control Facet
            • Funding Rate Facet
            • PartyA Facet
            • PartyB Facet
            • Liquidation Facet
            • View Facet
          • MultiAccount
            • PartyA
            • PartyB
          • SYMM App (Muon)
            • LibMuon
            • MuonStorage
        • Contracts Documentation 0.8.3
          • Facets
            • Control Facet
            • Account Facet
            • PartyA Facet
            • PartyB Facet
            • View Facet
            • Bridge Facet
            • Liquidation Facet (Implementation)
          • Modified Events
          • New Events
          • MuonStorage
        • Contracts Documentation 0.8.4
          • Main Flow (0.8.4)
          • The SYMM Diamond (0.8.4)
          • Facets
            • Account Facet (0.8.4)
            • Bridge Facet (0.8.4)
            • Control Facet (0.8.4)
            • Force Actions Facet (0.8.4)
            • Funding Rate Facet (0.8.4)
            • Liquidations Facet (0.8.4)
            • PartyA Facet (0.8.4)
            • PartyB Group Actions Facet (0.8.4)
            • PartyB Quote Actions Facet (0.8.4)
            • PartyB Position Actions Facet (0.8.4)
            • Settlement Facet (0.8.4)
            • View Facet (0.8.4)
          • MultiAccount (0.8.4)
            • SymmioPartyA
            • SymmioPartyB
          • SYMM App (Muon)
            • LibMuon (0.8.4)
            • MuonStorage (0.8.4)
      • Contract Addresses / Solver Endpoints
        • Mantle
        • Mode
        • IOTA
        • Base
        • BSC
        • Arbitrum
        • Polygon
        • Berachain
        • Solver Endpoints and Addresses
          • Perps Hub
          • Rasa Capital
          • Rasa Capital (Zero Spread)
          • Zenith
      • How to Query our Contracts
      • Muon API Queries
      • Solver Error Codes
      • Interacting with SYMMIO Contracts
    • Protocol higher level architecture
      • 12-Hour Fraud Proof Window
      • PartyB
      • Solver Settings
      • Max Leverage
      • Maintenance Margin (CVA) Calculations
    • Symmio Whitepaper
  • Building on Symmio
    • Builders introduction
    • Solving for Symmio
      • Solver documentation
      • Solver - Example Flow
    • Trading Fees
      • Perps - Settlement Costs
      • Pair Trading - Settlement costs
    • Exchanges (Frontends)
      • Frontend Introduction
      • SDK - SYMM client
      • Trade on Symmio
  • Legal & Brand & Security
    • Security (Audits / Bugbounty)
      • Bug bounty / Coverage
        • How to contact ?
      • Audits
        • SYMM - V0.8 - 0.81
          • Sherlock Audit - Jun 15, 2023
          • Smart State - Jul 2, 2023
        • SYMM - 0.82
          • Sherlock Audit -Aug 30, 2023
        • SYMM - 0.83
          • Sherlock Audit - Jun 17, 2024
        • SYMM - 0.84
          • Sherlock Audit - Oct 3, 2024
        • Vaults
          • Sherlock Audit - Jan 2, 2024
    • Terms of Service & Licensing
      • TRADEMARK & COPYRIGHT NOTICE
      • CONTACT US
      • TERMS OF SERVICE
      • FRONTEND LICENSE
        • Frontend Modifications
        • Frontend Use Grants
      • CONTRACT LICENSE
        • Contract Use Grants
        • Contract Modifications
    • Brand - Assets Logos
Powered by GitBook
LogoLogo

All rights to the people (c) 2023 Symmetry Labs A.G.

On this page
  • Fetching the Market by SymbolId
  • Fetching the Locked Parameters
  • Executing a MARKET Order
  • Using the Locked Values
  1. Protocol Architecture
  2. Technical Documentation
  3. Frontend Docs
  4. Implement a Trading Bot on Symmio (OLD)

Sending a Quote

Sending a quote requires us to fetch the various collateral requirements necessary to open a position from the hedger.

async function executeSendQuoteMarket(subAccount, positionType, quantity, slippage) {
  const { markets } = await fetchMarketSymbolId(config.HEDGER_URL, userConfig.SYMBOL);
  const lockedParams = await fetchLockedParams(markets[0].name, userConfig.LEVERAGE);

Let's first look at how we can fetch the markets from the hedger, which contains the autoSlippage for a specific pair.

Fetching the Market by SymbolId

The fetchMarketSymbolId() function is designed to asynchronously fetch market data from specified URLs by the Symbol ID. Here we're simply querying the hedger for symbols, then filtering them by the provided symbol. At the end we return the market object. The 'error_codes' API endpoint helps us understand the meaning of error codes.

async function fetchMarketSymbolId(url, symbol) {
  if (!url) {
    throw new Error("hedgerUrl is empty");
  }
  const marketsUrl = new URL('contract-symbols', url).href;
  const errorMessagesUrl = new URL('error_codes', url).href;

  try {
    const [marketsResponse, errorMessagesResponse] = await Promise.all([
      axios.get(marketsUrl),
      axios.get(errorMessagesUrl),
    ]);
      const filteredMarkets = marketsResponse.data.symbols
      .filter(market => market.symbol === symbol)
      .map(market => ({
          id: market.symbol_id,
          name: market.name,
          symbol: market.symbol,
          asset: market.asset,
          pricePrecision: market.price_precision,
          quantityPrecision: market.quantity_precision,
          isValid: market.is_valid,
          minAcceptableQuoteValue: market.min_acceptable_quote_value,
          minAcceptablePortionLF: market.min_acceptable_portion_lf,
          tradingFee: market.trading_fee,
          maxLeverage: market.max_leverage,
          maxNotionalValue: market.max_notional_value,
          maxFundingRate: market.max_funding_rate,
          rfqAllowed: market.rfq_allowed,
          hedgerFeeOpen: market.hedger_fee_open,
          hedgerFeeClose: market.hedger_fee_close,
          autoSlippage: (60 / market.max_leverage / 100) + 1,
      }));
    const errorMessages = errorMessagesResponse.data;
    return { markets: filteredMarkets, errorMessages };
  } catch (error) {
    console.error("Error fetching market symbols:", error);
  }
}

Parameters

  • url (String): The base URL from which the contract-symbols and error_codes endpoints can be constructed.

  • symbol (String): The market symbol for which detailed information is requested.

Returns:

  • filteredMarkets (Object): The information related to the symbol.

  • errorMessages(String): Any error messages associated with the hedger query

Fetching the Locked Parameters

The fetchLockedParams() function asynchronously retrieves the locked values required to enter a position for a trading pair. This is the cva, the lf, and the mm. These variables are percentages of the notional value and will fluctuate depending on the leverage and the pair.

async function fetchLockedParams(pair, leverage) {
  const url = `${config.HEDGER_URL}get_locked_params/${pair}?leverage=${leverage}`;

  try {
    const response = await axios.get(url);
    const data = response.data;

    const output = {
      cva: data.cva,
      partyAmm: data.partyAmm,
      lf: data.lf,
      leverage: data.leverage,
      partyBmm: data.partyBmm
    };

    return output;
  } catch (error) {
    console.error('Error fetching data:', error);
  }

}

Parameters:

  • pair (String): The currency pair for which to fetch locked parameters (e.g., "BTCUSD").

  • leverage (Number): The leverage level for which the parameters are to be fetched.

Returns:

An object containing the following keys with their respective values from the fetched data:

  • cva (Number): The Credit valuation adjustment. This is

  • partyAmm (Number): PartyA's maintenance margin.

  • lf (Number): The liquidation fee awarded to liquidators.

  • leverage (Number): The leverage.

  • partyBmm (Number): PartyA's maintenance margin.

Now that we've declared these required functions, we can move onto defining the sendQuote() function. For this example we'll be sending a MARKET order.

Executing a MARKET Order

First we need to determine the requestedPrice of the asset. This is the market price from the Muon Signature +- the slippage (either from the hedger or determined by the user).

async function executeSendQuoteMarket(subAccount, positionType, quantity, slippage) {
  const { markets } = await fetchMarketSymbolId(config.HEDGER_URL, userConfig.SYMBOL);
  const lockedParams = await fetchLockedParams(markets[0].name, userConfig.LEVERAGE);
  const autoSlippage = markets[0].autoSlippage;
  
  const signatureResult = await getMuonSigImplementation(subAccount);
  let adjustedPrice = BigInt(signatureResult.signature.price); //Getting Price from the Muon Signature
  let numericSlippage;

  if (signatureResult.success) {
    if (slippage === "auto") {
      const autoSlippageNumerator = BigInt(Math.floor(autoSlippage * 1000));
      const autoSlippageDenominator = BigInt(1000); 
      adjustedPrice = positionType === 1
        ? (adjustedPrice * autoSlippageDenominator) / autoSlippageNumerator
        : (adjustedPrice * autoSlippageNumerator) / autoSlippageDenominator;
    } else {
      numericSlippage = Number(slippage); 
      if (isNaN(numericSlippage)) {
        console.error("Slippage must be a number or 'auto'");
        return;
      }
      const spSigned = positionType === 1 ? numericSlippage : -numericSlippage;
      const slippageFactored = (100 - spSigned) / 100;
      const slippageFactorBigInt = BigInt(Math.floor(slippageFactored * 100));
      adjustedPrice = (adjustedPrice * slippageFactorBigInt) / BigInt(100);
    }
  
    const requestedPrice = adjustedPrice;

The next step is to format the signature we received from Muon so it can be processed by the smart contract. This is done by converting the reqId and gatewaySignature to bytes arrays, and converting the other values to strings:

    const { reqId, timestamp, upnl, price, gatewaySignature, sigs } = signatureResult.signature;
    console.log("Price of asset: ", price);
    if (typeof reqId === 'undefined' || !reqId.startsWith('0x')) {
      console.error("reqId is undefined or not a hex string:", reqId);
    }
    if (typeof gatewaySignature === 'undefined' || !gatewaySignature.startsWith('0x')) {
      console.error("gatewaySignature is undefined or not a hex string:", gatewaySignature);
    }
    const upnlSigFormatted = {
        reqId: web3.utils.hexToBytes(reqId),
        timestamp: timestamp.toString(),
        upnl: upnl.toString(),
        price: price.toString(),
        gatewaySignature: web3.utils.hexToBytes(gatewaySignature),
        sigs: {
            signature: sigs.signature.toString(),
            owner: sigs.owner,
            nonce: sigs.nonce,
        }
    };
    const partyBsWhiteList = [config.PARTY_B_WHITELIST];
    const symbolId = markets[0].id;
    const orderType = 1; // This will be a MARKET order

Using the Locked Values

The locked values provided by the hedger should be implemented by applying them to the notional value of the quote. This can be done with the following logic:

Getting the Notional Value of the Quote:

    const requestedQuantityWei = web3.utils.toWei(quantity.toString(), 'ether');
    console.log("requestedQuantityWei:", requestedQuantityWei);
    const adjustedPriceStr = adjustedPrice.toString();
    const notionalValue = new BigNumber(requestedQuantityWei).multipliedBy(new BigNumber(adjustedPriceStr));
    console.log("notionalValue:", notionalValue.toString());

Getting the CVA (Credit Value Adjustment):

    const cvaWei = notionalValue
    * (new BigNumber(lockedParams.cva * 100))
    / (new BigNumber(10000)) 
    / (new BigNumber(lockedParams.leverage))
    / (new BigNumber(1e18));

Getting the LF (Liquidator Fee):

    const lfWei = notionalValue
    * (new BigNumber(lockedParams.lf * 100))
    / (new BigNumber(10000)) 
    / (new BigNumber(lockedParams.leverage))
    / (new BigNumber(1e18));

Getting the Maintenance Margin (Also required for partyB)

    const partyAmmWei = notionalValue
    * (new BigNumber(lockedParams.partyAmm * 100))
    / (new BigNumber(10000)) 
    / (new BigNumber(lockedParams.leverage))
    / (new BigNumber(1e18));

Finally, set the maxFundingRate and deadline:

    const maxFundingRate = web3.utils.toWei('200', 'ether'); 
    const deadline = (Math.floor(Date.now() / 1000) + 120).toString(); //120 seconds

We can then create an array of sendQuoteParamaters with all the variables we've defined:

    const sendQuoteParameters = [
      partyBsWhiteList,
      symbolId,
      positionType,
      orderType,
      requestedPrice.toString(), 
      requestedQuantityWei.toString(),
      cvaWei.toString(), 
      lfWei.toString(),
      partyAmmWei.toString(),
      partyBmmWei.toString(), 
      maxFundingRate.toString(), 
      deadline.toString(),
      upnlSigFormatted
  ];

To finalize the transaction, first encode it using the ABI from the sendQuote() function within the Diamond Facet. Then, leverage the _call function from the MultiAccount contract to pass the encoded data (_callData).

  //Encoding the Parameters
  const encodedSendQuoteData = web3.eth.abi.encodeFunctionCall(sendQuoteFunctionAbi, sendQuoteParameters);

  //Creating the Calldata
  const _callData = [
    subAccount,
    [ encodedSendQuoteData ]
  ];

    try {
    //Gas Estimates
      const bufferPercentage = 0.20;
      const bufferFactor = BigInt(Math.floor(bufferPercentage * 100));
      const sendQuoteGasEstimate = await multiAccountContract.methods._call(..._callData).estimateGas({ from: process.env.WALLET_ADDRESS });
      const adjustedGasLimit = sendQuoteGasEstimate + (sendQuoteGasEstimate * bufferFactor / BigInt(100));
      const sendQuotePrice = await web3.eth.getGasPrice();
      
    //Sending the Quote
      const sendQuoteReceipt = await multiAccountContract.methods._call(..._callData).send({
        from: account.address,
        gas: adjustedGasLimit.toString(), 
        gasPrice: sendQuotePrice.toString() 
      });

    } catch (error) {
        console.error('Error sending quote:', error);
    }
  } else {
    console.error('Failed to obtain signature:', signatureResult.error);
  }
}
PreviousObtaining Muon SignaturesNextMonitoring Price for Execution

Last updated 11 months ago

For more information on the returned data, consult the for this API query.

documentation