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.
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.
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
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
{
"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_KEYwith your actual private key. Ensure your wallet hasMONfor gas andUSDCfor collateral.
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);
});