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
  • Opening a Position
  • Allocating Collateral for partyB
  • Locking the Quote
  • Opening the Position Script
  • Combined Methods: lockAndOpenQuote()
  • Closing a Position
  • How fillCloseRequest Works
  • Preconditions for Closing
  • Closing the Position Script
  1. Protocol Architecture
  2. Technical Documentation
  3. Solver Docs
  4. Building a Solver on SYMMIO

4. Opening/Closing a Position On-Chain

Previous3. Hedging Off-ChainNextCreating the APIs

Last updated 24 days ago

Opening a Position

At this stage, the solver calls openPosition() or a combined function (lockAndOpenQuote()).

  • Partial Fills are possible: if Hedger only wants to open half the quantity, the remainder might get reposted as a new Intent.

  • The contract does a final solvency check via Muon. If any party is insolvent, the contract disallows opening.

Before a Hedger can lockQuote() or openPosition(), sufficient collateral must be allocated to PartyB. This allocation ensures that PartyB meets the margin requirements for handling the position. If the allocated balance is insufficient, the contract will reject the lockQuote or openPosition transaction.

Allocating Collateral for partyB

Below is a short script that shows how a solver would allocate collateral to a partyA. More information can be found .

async function allocateForPartyB(amount, partyB, partyA) {
  try {
    console.log(`Allocating ${amount} tokens for PartyB with address ${partyA} from ${partyB}...`);

    // Estimate gas for the transaction
    const allocateGasEstimate = await diamondContract.methods.allocateForPartyB(amount, partyA).estimateGas({ from: partyB });
    console.log("Estimated Gas: ", allocateGasEstimate);

    // Fetch current gas price
    const allocateGasPrice = await web3.eth.getGasPrice();
    console.log("Current Gas Price: ", allocateGasPrice);

    // Execute the allocation transaction
    const receipt = await diamondContract.methods.allocateForPartyB(amount, partyA).send({
      from: partyB,
      gas: allocateGasEstimate,
      gasPrice: allocateGasPrice,
    });

    console.log("Allocation successful!");
    return { success: true, receipt: receipt };
  } catch (error) {
    console.error("Error during allocation:", error);
    return { success: false, error: error.toString() };
  }
}

Locking the Quote

async function lockQuote(accountAddress, partyA, quoteId, increaseNonce, muonUrls, chainId, diamondAddress) {
  const lockQuoteClient = LockQuoteClient.createInstance(true);
  const signatureResult = await lockQuoteClient.getMuonSig(accountAddress, partyA, 'symmio', muonUrls, chainId, diamondAddress);

  if (signatureResult.success) {
    const { reqId, timestamp, upnl, gatewaySignature, sigs } = signatureResult.signature;
    const upnlSigFormatted = {
      reqId: web3.utils.hexToBytes(reqId),
      timestamp: timestamp.toString(),
      upnl: upnl.toString(),
      gatewaySignature: web3.utils.hexToBytes(gatewaySignature),
      sigs: {
        signature: sigs.signature.toString(),
        owner: sigs.owner,
        nonce: sigs.nonce,
      },
    };

    const gasEstimate = await diamondContract.methods.lockQuote(quoteId, upnlSigFormatted, increaseNonce).estimateGas({ from: accountAddress });
    const gasPrice = await web3.eth.getGasPrice();

    const receipt = await diamondContract.methods.lockQuote(quoteId, upnlSigFormatted, increaseNonce).send({
      from: accountAddress,
      gas: gasEstimate,
      gasPrice,
    });

    console.log("Lock Quote successful!", receipt);
  } else {
    console.error("Failed to fetch Muon signature:", signatureResult.error);
  }
}

Opening the Position Script

Once the quote is locked, the solver calls openPosition() to finalize the transaction. This method performs a solvency check before opening.

async function openPosition(accountAddress, partyA, quoteId, filledAmount, openedPrice, symbolId, muonUrls, chainId, diamondAddress) {
  const openPositionClient = OpenPositionClient.createInstance(true);
  const signatureResult = await openPositionClient.getPairUpnlAndPriceSig(accountAddress, partyA, symbolId, 'symmio', muonUrls, chainId, diamondAddress);

  if (signatureResult.success) {
    const { reqId, timestamp, uPnlA, uPnlB, price, gatewaySignature, sigs } = signatureResult.signature;
    const upnlSigFormatted = {
      reqId: web3.utils.hexToBytes(reqId),
      timestamp: timestamp.toString(),
      upnlPartyA: uPnlA.toString(),
      upnlPartyB: uPnlB.toString(),
      price: price.toString(),
      gatewaySignature: web3.utils.hexToBytes(gatewaySignature),
      sigs: {
        signature: sigs.signature.toString(),
        owner: sigs.owner,
        nonce: sigs.nonce,
      },
    };

    const gasEstimate = await diamondContract.methods.openPosition(quoteId, filledAmount, openedPrice, upnlSigFormatted).estimateGas({ from: accountAddress });
    const gasPrice = await web3.eth.getGasPrice();

    const receipt = await diamondContract.methods.openPosition(quoteId, filledAmount, openedPrice, upnlSigFormatted).send({
      from: accountAddress,
      gas: gasEstimate,
      gasPrice,
    });

    console.log("Open Position successful!", receipt);
  } else {
    console.error("Failed to fetch Muon signature:", signatureResult.error);
  }
}

Combined Methods: lockAndOpenQuote()

For efficiency, solvers can use combined methods like lockAndOpenQuote(). These methods execute the locking and opening steps in a single transaction.

	/**
	 * @notice Locks and opens the specified quote with the provided details and signatures.
	 * @param quoteId The ID of the quote to be locked and opened.
	 * @param filledAmount PartyB has the option to open the position with either the full amount requested by the user or a specific fraction of it
	 * @param openedPrice The price at which the position is opened.
	 * @param upnlSig The Muon signature containing the single UPNL value used to lock the quote.
	 * @param pairUpnlSig The Muon signature containing the pair UPNL and price values used to open the position.
	 */
	function lockAndOpenQuote(
		uint256 quoteId,
		uint256 filledAmount,
		uint256 openedPrice,
		SingleUpnlSig memory upnlSig,
		PairUpnlAndPriceSig memory pairUpnlSig
	) external whenNotPartyBActionsPaused onlyPartyB notLiquidated(quoteId) {}

Closing a Position

PartyA calls requestToCloseQuote() with parameters (quantity, price if limit, etc.). The solver can close his corresponding off-chain hedge, then call fillCloseRequest() on-chain.

Closing a position on SYMMIO involves calling the fillCloseRequest() function. The solver (PartyB) can close an open position partially or fully, depending on the request type and specified amount.

How fillCloseRequest Works

Parameters:

  • quoteId: The unique identifier of the quote to be closed.

  • filledAmount: The amount being closed.

  • closedPrice: The final price at which the position is being closed.

  • upnlSig: A Muon signature that ensures solvency and validates the closing action.

LIMIT requests can be closed incrementally in multiple steps however MARKET requests must be closed in a single transaction.

Preconditions for Closing

  • Ensure the Hedger (PartyB) is authorized to act on the quote. If not, contact SYMMIO developers to enable whitelisting.

  • A Muon signature validates solvency for both parties before the close action is processed.

  • The position must not be in the LIQUIDATED state, and the partyA must be solvent after the close.

Closing the Position Script

const Web3 = require('web3');
const OpenPositionClient = require('./OpenPositionClient'); // Assuming OpenPositionClient exists in your setup
const { abi } = require('./DiamondContractABI.json'); // ABI for the diamond contract

async function fillCloseRequest(accountAddress, partyA, partyB, quoteId, filledAmount, closedPrice, symbolId, muonUrls, chainId, diamondAddress) {
  console.log("Filling close request...");

  const closeRequestClient = OpenPositionClient.createInstance(true);
  if (!closeRequestClient) {
    console.error("OpenPositionClient is not enabled.");
    return { success: false, error: "Initialization failed" };
  }

  const web3 = new Web3(process.env.RPC_URL);
  const diamondContract = new web3.eth.Contract(abi, diamondAddress);
  const appName = "symmio";
  const urls = [muonUrls];

  try {
    // Fetch Muon signature
    const signatureResult = await closeRequestClient.getPairUpnlAndPriceSig(accountAddress, partyA, symbolId, appName, urls, chainId, diamondAddress);
    if (!signatureResult.success) {
      throw new Error(signatureResult.error || "Muon signature fetch failed");
    }

    const { reqId, timestamp, uPnlA, uPnlB, price, gatewaySignature, sigs } = signatureResult.signature;
    const upnlSigFormatted = {
      reqId: web3.utils.hexToBytes(reqId),
      timestamp: timestamp.toString(),
      upnlPartyA: uPnlA.toString(),
      upnlPartyB: uPnlB.toString(),
      price: price.toString(),
      gatewaySignature: web3.utils.hexToBytes(gatewaySignature),
      sigs: {
        signature: sigs.signature.toString(),
        owner: sigs.owner,
        nonce: sigs.nonce,
      },
    };

    // Call fillCloseRequest
    const receipt = await diamondContract.methods.fillCloseRequest(
      quoteId,
      filledAmount,
      closedPrice,
      upnlSigFormatted
    ).send({
      from: partyB,
      gas: 500000,
    });

    console.log("Close request successfully filled!");
    return { success: true, receipt };
  } catch (error) {
    console.error("Error filling close request:", error);
    return { success: false, error: error.toString() };
  }
}

module.exports = fillCloseRequest;

Locking the quote ensures that no other Hedger can act on the same quoteId. This step requires a valid Muon signature for the uPnl (uPnl_B) of the position. You can read more about this method . The formatted signature and quoteId must be passed to the lockQuote() method.

The Muon is used for solvency verification. The positionState will change to OPENED upon successful execution. If any party is insolvent, the contract will reject the transaction.

Both uPnlSig (derived from ) and a pairUpnlSig (derived from ) are required for this group action

Once opened, the position remains active until fully closed or liquidated. PartyA can place limit or market close requests, which the solver can fill. If the solver fails to respond within a certain timeframe the partyA can execute .

The script allows PartyB to close a trade initiated by PartyA using the fillCloseRequest() function on the smart contract. The Muon signature is used for solvency validation. The correct Muon method here is also

here
here
force closes or force cancels
uPnlWithSymbolPrice method
uPnL_B
uPnlWithSymbolPrice
uPnlWithSymbolPrice