Skip to content

Market Orders

To open a market position, you interact with the TradingPortalFacet on the LeverUp Diamond Proxy.

Method: openMarketTradeV2

Opens a market trade with oracle update data.

solidity
struct OracleUpdateData {
    bytes[] pythPriceUpdateData;
    bytes[] pythProPriceUpdateData;
}

function openMarketTradeV2(
    IBook.OpenDataInput memory data,
    OracleUpdateData memory updateData,
    uint96 extraFee
) external payable returns (bytes32 tradeHash)

Parameters

data (OpenDataInput)

The OpenDataInput struct contains all trade parameters. This struct is used for both market trades and limit orders.

solidity
struct OpenDataInput {
    address pairBase;   // Address of the pair base contract
    bool isLong;        // true for Long, false for Short
    address tokenIn;    // Token used for collateral (e.g. USDC)
    address lvToken;    // LP token address (e.g. LVUSD)
    uint96 amountIn;    // Amount of tokenIn to deposit
    uint128 qty;        // Position size in BASE ASSET (e.g. BTC) with 10 DECIMALS
    uint128 price;      // Execution price with 18 DECIMALS
    uint128 stopLoss;   // Stop Loss price (0 to disable)
    uint128 takeProfit; // Take Profit price (0 to disable)
    uint24 broker;      // Broker ID (optional, use 0)
}

updateData

Oracle update data returned by the LeverUp backend. The client no longer needs to call Pyth Hermes directly.

extraFee

Additional oracle verification fee returned by the backend as verifition_fee. Use 0 if the field is absent.

Fetching Oracle Data

Before opening a position, request oracle update data from the LeverUp backend. Pass the returned data into openMarketTradeV2.

1. Fetch Update Data

javascript
const API_BASE_URL = "https://service.leverup.xyz";

const response = await fetch(`${API_BASE_URL}/v1/oracle/price/updates/by-position`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    pairBase: "0xcf5a6076cfa32686c0df13abada2b40dec133f1d",
    collateral: "0x754704Bc059F8C67012fEd69BC8A327a5aafb603",
    blockChain: "MONAD",
    options: {
      includeEncodingData: true,
      includeEncodingDataByOracleId: false,
      includeFee: true,
      includePrice: false,
      includePublishTime: false
    }
  })
});
if (!response.ok) throw new Error(`Failed to fetch oracle updates: ${response.statusText}`);

const oracleData = await response.json();
const oracleUpdateData = {
  pythPriceUpdateData: oracleData.pythPriceUpdateData ?? [],
  pythProPriceUpdateData: oracleData.pythProPriceUpdateData ?? []
};
const updateFee = BigInt(oracleData.updateFee ?? "0");
const extraFee = BigInt(oracleData.verifition_fee ?? "0");

If the user pays with native MON, use the wrapped native token address as collateral when requesting oracle data, and include amountIn + updateFee + extraFee as the transaction value. For ERC20 collateral, the transaction value is updateFee + extraFee.

2. Backend Response

json
{
  "pythPriceUpdateData": ["0x..."],
  "pythProPriceUpdateData": ["0x..."],
  "updateFee": "123456789",
  "verifition_fee": "0"
}

Example Usage (Viem)

Here is a complete, runnable example using Viem. This script connects to the Monad Mainnet, fetches oracle data from the LeverUp backend, approves tokens, and opens a 10x long position on BTC/USD.

Note: Replace YOUR_PRIVATE_KEY with your actual private key. Ensure your wallet has MON for gas and USDC for collateral.

javascript
import { createWalletClient, createPublicClient, http, parseUnits, formatEther } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { monad } from 'viem/chains'; // or define custom chain

// --- Configuration ---
const RPC_URL = "https://rpc.monad.xyz/";
const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY"; // WARNING: Handle securely!
const API_BASE_URL = "https://service.leverup.xyz";

// Contract Addresses (Monad Mainnet)
const LEVERUP_DIAMOND = "0xea1b8E4aB7f14F7dCA68c5B214303B13078FC5ec";
const USDC_ADDRESS = "0x754704Bc059F8C67012fEd69BC8A327a5aafb603";

// Trade Parameters
// Note: This is an example placeholder. You must query the correct PairBase address for BTC/USD on Mainnet.
const PAIR_BASE = "0xcf5a6076cfa32686c0df13abada2b40dec133f1d"; 
const LV_TOKEN = "0xFD44B35139Ae53FFF7d8F2A9869c503D987f00d1";   // LVUSD (Mainnet)

// --- ABIs ---
const ERC20_ABI = [
  {
    name: "approve",
    type: "function",
    stateMutability: "nonpayable",
    inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }],
    outputs: [{ name: "", type: "bool" }]
  },
  {
    name: "decimals",
    type: "function",
    stateMutability: "view",
    inputs: [],
    outputs: [{ name: "", type: "uint8" }]
  }
];

const TRADING_PORTAL_ABI = [
  {
    inputs: [
      {
        components: [
          { type: "address", name: "pairBase" },
          { type: "bool", name: "isLong" },
          { type: "address", name: "tokenIn" },
          { type: "address", name: "lvToken" },
          { type: "uint96", name: "amountIn" },
          { type: "uint128", name: "qty" },
          { type: "uint128", name: "price" },
          { type: "uint128", name: "stopLoss" },
          { type: "uint128", name: "takeProfit" },
          { type: "uint24", name: "broker" }
        ],
        name: "data",
        type: "tuple"
      },
      {
        components: [
          { type: "bytes[]", name: "pythPriceUpdateData" },
          { type: "bytes[]", name: "pythProPriceUpdateData" }
        ],
        name: "updateData",
        type: "tuple"
      },
      { type: "uint96", name: "extraFee" }
    ],
    name: "openMarketTradeV2",
    outputs: [{ type: "bytes32", name: "tradeHash" }],
    stateMutability: "payable",
    type: "function"
  }
];

async function main() {
  // 1. Setup Clients
  const account = privateKeyToAccount(PRIVATE_KEY);
  
  const publicClient = createPublicClient({
    chain: monad,
    transport: http(RPC_URL)
  });

  const walletClient = createWalletClient({
    account,
    chain: monad,
    transport: http(RPC_URL)
  });

  console.log(`Connected wallet: ${account.address}`);

  // 2. Fetch Oracle Update Data from LeverUp Backend
  console.log("Fetching oracle updates...");
  const oracleResponse = await fetch(`${API_BASE_URL}/v1/oracle/price/updates/by-position`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      pairBase: PAIR_BASE,
      collateral: USDC_ADDRESS,
      blockChain: "MONAD",
      options: {
        includeEncodingData: true,
        includeEncodingDataByOracleId: false,
        includeFee: true,
        includePrice: false,
        includePublishTime: false
      }
    })
  });
  if (!oracleResponse.ok) throw new Error(`Failed to fetch oracle updates: ${oracleResponse.statusText}`);

  const oracleData = await oracleResponse.json();
  const oracleUpdateData = {
    pythPriceUpdateData: oracleData.pythPriceUpdateData ?? [],
    pythProPriceUpdateData: oracleData.pythProPriceUpdateData ?? []
  };
  const updateFee = BigInt(oracleData.updateFee ?? "0");
  const extraFee = BigInt(oracleData.verifition_fee ?? "0");
  
  console.log(`Oracle Fee: ${formatEther(updateFee + extraFee)} MON`);

  // 3. Approve USDC
  const amountInRaw = parseUnits("10", 6); // 10 USDC Margin
  const fee = parseUnits("0.07", 6);       // 0.07 USDC Open Fee (Estimate)
  const amountIn = amountInRaw + fee;

  console.log(`Approving ${formatEther(amountIn)} USDC...`); // Note: formatEther used for simplicity, real decimals is 6
  
  const approveTx = await walletClient.writeContract({
    address: USDC_ADDRESS,
    abi: ERC20_ABI,
    functionName: 'approve',
    args: [LEVERUP_DIAMOND, amountIn]
  });
  
  await publicClient.waitForTransactionReceipt({ hash: approveTx });
  console.log("USDC Approved.");

  // 4. Prepare Trade Data
  const positionSizeUsd = 100; 
  const executionPrice = 100000; 
  
  // Calculate Qty in BTC: 100 / 100,000 = 0.001 BTC * 1e10
  const qty = parseUnits((positionSizeUsd / executionPrice).toFixed(10), 10);
  
  // Slippage: 101,000 USD
  const maxPrice = parseUnits("101000", 18); 

  const openData = {
    pairBase: PAIR_BASE,
    isLong: true,
    tokenIn: USDC_ADDRESS,
    lvToken: LV_TOKEN,
    amountIn: amountIn, 
    qty: qty,           
    price: maxPrice,    
    stopLoss: 0n,        
    takeProfit: 0n,      
    broker: 0
  };

  // 5. Execute Trade
  console.log("Sending Open Market Trade...");
  
  const tx = await walletClient.writeContract({
    address: LEVERUP_DIAMOND,
    abi: TRADING_PORTAL_ABI,
    functionName: 'openMarketTradeV2',
    args: [openData, oracleUpdateData, extraFee],
    value: updateFee + extraFee
  });

  console.log(`Transaction sent: ${tx}`);
  const receipt = await publicClient.waitForTransactionReceipt({ hash: tx });
  console.log("Trade executed successfully!");
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});