# Quickstart

This page opens a real position on Monad mainnet from a standalone script, then reads it back and
closes it. Budget about 10 minutes.

If you would rather trade without holding gas or signing every transaction, skip to
[Gasless Trading](/gasless/overview) — but read this page first, because the trade parameters are
identical.

::: danger Real funds
Everything here targets mainnet. Start with a few dollars of collateral.
:::

## 1. Prerequisites

- Node 18+ and `viem` (`npm i viem`).
- An account holding `MON` for gas and `USDC` for collateral.
- A Monad mainnet RPC URL.

## 2. Shared setup

Create `config.ts`. Every other snippet on this site assumes these exports.

```ts
import { defineChain, createPublicClient, createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'

export const monad = defineChain({
  id: 143,
  name: 'Monad',
  nativeCurrency: { name: 'MON', symbol: 'MON', decimals: 18 },
  rpcUrls: { default: { http: [process.env.RPC_URL!] } },
  blockExplorers: { default: { name: 'MonadVision', url: 'https://monadvision.com' } },
  contracts: { multicall3: { address: '0xcA11bde05977b3631167028862bE2a173976CA11' } },
})

export const DIAMOND = '0xea1b8E4aB7f14F7dCA68c5B214303B13078FC5ec' as const
export const USDC = '0x754704Bc059F8C67012fEd69BC8A327a5aafb603' as const
export const LVUSD = '0xFD44B35139Ae53FFF7d8F2A9869c503D987f00d1' as const
export const API = 'https://service.leverup.xyz'

export const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)

export const publicClient = createPublicClient({ chain: monad, transport: http() })
export const walletClient = createWalletClient({ account, chain: monad, transport: http() })
```

## 3. Find the pair

Pair addresses are not stable across listings. Look them up:

```ts
import { API } from './config'

const res = await fetch(`${API}/v1/pairs?symbol=BTC&size=1`)
const { content } = await res.json()
const pairBase = content[0].base as `0x${string}`

console.log(content[0].pairName, pairBase, content[0].status)
```

## 4. Fetch oracle data

Opening a position requires a fresh oracle payload and the fee to attach. Fetch it immediately
before sending the transaction.

```ts
async function fetchOracleUpdate(pairBase: `0x${string}`, collateral: `0x${string}`) {
  const res = await fetch(`${API}/v1/oracle/price/updates/by-position`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      pairBase,
      collateral,
      blockChain: 'MONAD',
      options: {
        includeEncodingData: true,
        includeFee: true,
        includePrice: true,
        includePublishTime: false,
      },
    }),
  })
  if (!res.ok) throw new Error(`oracle: HTTP ${res.status}`)

  const data = await res.json()

  return {
    updateData: {
      pythPriceUpdateData: data.pythPriceUpdateData ?? [],
      pythProPriceUpdateData: data.pythProPriceUpdateData ?? [],
    },
    // Attach the sum as msg.value; `verifition_fee` is spelled that way in the API.
    value: BigInt(data.updateFee ?? '0') + BigInt(data.verifition_fee ?? '0'),
    extraFee: 0n,
  }
}
```

## 5. Approve collateral

One-time, per collateral token. Approve the Diamond, not a facet address.

```ts
import { parseUnits, erc20Abi } from 'viem'
import { publicClient, walletClient, DIAMOND, USDC } from './config'

const hash = await walletClient.writeContract({
  address: USDC,
  abi: erc20Abi,
  functionName: 'approve',
  args: [DIAMOND, parseUnits('1000', 6)],
})
await publicClient.waitForTransactionReceipt({ hash })
```

## 6. Open a position

$100 notional BTC long, backed by 10 USDC of margin — roughly 10x.

```ts
import { parseUnits } from 'viem'
import { publicClient, walletClient, DIAMOND, USDC, LVUSD } from './config'

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

const oracle = await fetchOracleUpdate(pairBase, USDC)

// Read the current price from the same oracle response and allow 1% of slippage.
const markPrice = 100_000                       // replace with the live price
const qty = parseUnits((100 / markPrice).toFixed(10), 10)   // $100 notional
const worstPrice = parseUnits(String(markPrice * 1.01), 18)  // long -> max price

const hash = await walletClient.writeContract({
  address: DIAMOND,
  abi: OPEN_ABI,
  functionName: 'openMarketTradeV2',
  args: [
    {
      pairBase,
      isLong: true,
      tokenIn: USDC,
      lvToken: LVUSD,
      amountIn: parseUnits('10', 6),
      qty,
      price: worstPrice,
      stopLoss: 0n,
      takeProfit: 0n,
      broker: 0,
    },
    oracle.updateData,
    oracle.extraFee,
  ],
  value: oracle.value,
})

await publicClient.waitForTransactionReceipt({ hash })
```

::: warning This does not mean you have a position yet
`openMarketTradeV2` creates a *pending* trade. A keeper fills it in a follow-up transaction.
Poll until the position appears.
:::

## 7. Read the position back

```ts
import { formatUnits } from 'viem'

const READ_ABI = [{
  type: 'function',
  name: 'getPositionsV4',
  stateMutability: 'view',
  inputs: [{ name: 'user', type: 'address' }, { name: 'pairBase', type: 'address' }],
  outputs: [{
    type: 'tuple[]', name: '', components: [
      { name: 'positionHash', type: 'bytes32' },
      { name: 'pair', type: 'string' },
      { name: 'pairBase', type: 'address' },
      { name: 'tokenIn', type: 'address' },
      { name: 'marginToken', type: 'address' },
      { name: 'isLong', type: 'bool' },
      { name: 'margin', type: 'uint96' },
      { name: 'qty', type: 'uint128' },
      { name: 'entryPrice', type: 'uint128' },
      { name: 'stopLoss', type: 'uint128' },
      { name: 'takeProfit', type: 'uint128' },
      { name: 'openFee', type: 'uint96' },
      { name: 'executionFee', type: 'uint96' },
      { name: 'fundingFee', type: 'int256' },
      { name: 'timestamp', type: 'uint32' },
      { name: 'holdingFee', type: 'uint96' },
      { name: 'earliestCloseTime', type: 'uint256' },
      { name: 'accruedFundingFee', type: 'int256' },
      { name: 'accruedHoldingFee', type: 'uint256' },
    ],
  }],
}] as const

for (let i = 0; i < 30; i++) {
  const positions = await publicClient.readContract({
    address: DIAMOND,
    abi: READ_ABI,
    functionName: 'getPositionsV4',
    args: [account.address, pairBase],
  })

  if (positions.length > 0) {
    const p = positions[0]
    console.log('hash   ', p.positionHash)
    console.log('side   ', p.isLong ? 'LONG' : 'SHORT')
    console.log('qty    ', formatUnits(p.qty, 10))
    console.log('entry  ', formatUnits(p.entryPrice, 18))
    console.log('margin ', formatUnits(p.margin, 18), 'LVUSD')
    break
  }
  await new Promise((r) => setTimeout(r, 1000))
}
```

## 8. Close it

```ts
const CLOSE_ABI = [{
  type: 'function',
  name: 'closeTrade',
  stateMutability: 'nonpayable',
  inputs: [{ name: 'positionHash', type: 'bytes32' }],
  outputs: [],
}] as const

const hash = await walletClient.writeContract({
  address: DIAMOND,
  abi: CLOSE_ABI,
  functionName: 'closeTrade',
  args: [positionHash],
})
await publicClient.waitForTransactionReceipt({ hash })
```

Like opening, this requests a close. The position disappears once the keeper settles it.

## Where to go next

| Goal | Page |
| :--- | :--- |
| Understand the units you just used | [Precision & Units](/introduction/precision) |
| Limit orders, TP/SL, margin management | [Onchain Integration](/onchain/overview) |
| Trade without gas or wallet popups | [Gasless Trading](/gasless/overview) |
| Query data over HTTP instead | [REST API](/api/overview) |
| Something reverted | [Error Reference](/reference/errors) |
