Skip to content

Core Concepts

The Diamond

Every contract interaction goes through a single address — the LeverUp Diamond (0xea1b8E4aB7f14F7dCA68c5B214303B13078FC5ec). Opening trades, limit orders, TP/SL orders, one-click trading, pair configuration and all read functions are facets behind that one proxy.

Practically, this means: point every readContract / writeContract at the Diamond address, and supply only the ABI fragment for the function you are calling.

Pairs

A market is identified by its pairBase — an address that acts as the pair's identifier. It is not a token you can hold or transfer; it is the key you pass to every trading and read function.

Pair addresses change as markets are listed and delisted. Fetch them from GET /v1/pairs rather than hardcoding.

Pairs carry a status:

StatusMeaning
AVAILABLEOpen and close both allowed
REDUCE_ONLYOnly closes and reductions allowed
CLOSEMarket disabled

Non-crypto markets (equities, indices, forex, commodities) also have trading hours. GET /v1/pairs returns nextOpen / nextClose; attempting to trade a closed market reverts with MarketClosed.

Collateral and lvToken

Every position references two tokens:

  • tokenIn — what you deposit.
  • lvToken — the protocol's settlement token for that position. Margin, fees and PnL are denominated in it.

The pairing is fixed:

tokenInRequired lvToken
USDCLVUSD
LVUSDLVUSD
Native MON (0x0 address)LVMON
WMONLVMON
LVMONLVMON

In short: USD-denominated collateral settles in LVUSD, MON-denominated collateral settles in LVMON. Passing a mismatched pair reverts.

You do not need to hold LV tokens to trade. Depositing USDC mints the LVUSD side internally. If you already hold LVUSD or LVMON you can pass it directly as tokenIn, which skips a conversion step.

WARNING

One-click trading only accepts ERC-20 collateral. To trade MON via 1CT, wrap it to WMON first.

Positions are merged slots

A position is keyed by (user, pairBase, isLong, lvToken), not by trade:

positionHash = keccak256(abi.encode(user, pairBase, isLong, lvToken, "position.v1"))

Opening the same market and direction twice increases the existing position and blends the entry price — you never get two BTC-long positions with the same collateral. Consequences:

Legacy positions

Positions created before the merged-position upgrade use a random hash instead of the deterministic key. They are full-close only and do not support TP/SL orders — they keep using the embedded updateTradeTp / updateTradeSl fields. Read functions return both kinds; a position whose hash does not match getPositionHash(...) for its own parameters is a legacy position.

Oracle updates

LeverUp settles against Pyth. Price-sensitive contract calls take an OracleUpdateData struct and a native-token fee alongside it:

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

You do not fetch this from Pyth directly. Request it from the LeverUp backend, which selects the right feeds for the pair and collateral and returns the fee to attach:

Payloads are short-lived. Fetch immediately before sending the transaction, not at the start of a long-running flow.

Calls that need oracle data: opening market and limit orders, removing margin, and closes. Calls that only change stored values — updating a take-profit, cancelling an order — do not.

1CT skips this entirely

When trading through 1CT, the relayer fetches oracle data for you. Intents never carry oracle payloads.

Fees

FeeWhenPaid in
Open feeOn openlvToken
Close feeOn closelvToken
Holding feeAccrues while openlvToken
Funding feeAccrues while open, signedlvToken
Oracle update feePer price-sensitive transactionNative MON
Execution fee (1CT only)Per intentConfigurable ERC-20, see Execution Fee
extraFee (optional)Per open, if you set ittokenIn — see Brokers & Referrals

Fee rates are per pair and readable onchain via getPairFeeConfig. Some markets have a minimum holding period (minHoldingSeconds in GET /v1/pairs) before a position can be closed; a position also exposes earliestCloseTime.

Part of the open and close fee can be credited to a referral channel via the broker field that appears on every fee-charging call. This does not change what the trader pays — see Brokers & Referrals.

Slippage

Fills are not at the raw oracle price. Each pair has a slippage model that adjusts the fill based on open interest and trade size. This is why every open takes a price field — it is the worst acceptable price, not a limit price:

  • Long: the maximum price you will accept.
  • Short: the minimum price you will accept.

If the adjusted fill falls outside it, the trade is refunded rather than filled. See Reading Data for reading the model's parameters.

For limit orders, price is the actual limit price.

Keepers

Two things happen asynchronously, executed by protocol keepers:

  1. Fills. A pending open or close is settled once the keeper delivers the oracle price.
  2. Triggers. Limit orders, TP/SL orders and liquidations fire when the price condition is met.

Your transaction succeeding means the request was accepted, not that the position exists. Confirm via events or by polling getPositionsV4.

Next: Precision & Units, then pick an integration path — Onchain or Gasless.

Trading perpetuals involves risk. Nothing here is financial advice.