phasis.
Phasis Docs
Developers

Deposit, trade, withdraw

Step-by-step SDK examples for opening an account, depositing USDC, placing option trades, cancelling orders, refreshing margin, and withdrawing.

All write operations use Sui programmable transaction blocks (PTBs). The pattern is:

  1. Create a Transaction object.
  2. Call the SDK builder to append move calls.
  3. Set the sender and gas payment on the transaction.
  4. Sign and execute via your Sui client.

Step 1: Open an account

Every address must open an account once before depositing or trading.

import { genUserEntry, PACKAGE_ID_TESTNET, QUOTE_COIN_TYPE_TESTNET, REGISTRY_ID_TESTNET } from '@phasis-lab/sdk';
import { Transaction } from '@mysten/sui/transactions';

const ACCOUNT_REGISTRY_ID = '0x5b6ca0125fb39530de62186f7e5973d60f6cf27c879a901ce6f415cdafe38704';

const tx = new Transaction();
genUserEntry.openAccountV2({
  package: PACKAGE_ID_TESTNET,
  typeArguments: [QUOTE_COIN_TYPE_TESTNET],
  arguments: {
    registry: REGISTRY_ID_TESTNET,
    accounts: ACCOUNT_REGISTRY_ID,
  },
})(tx);

tx.setSender(walletAddress);
tx.setGasPayment([gasPaymentRef]);
// sign and execute

This is a one-time call per address. It creates the account inside the shared AccountRegistry with zero balance and no positions.

Step 2: Deposit USDC

import { genUserEntry, PACKAGE_ID_TESTNET, QUOTE_COIN_TYPE_TESTNET, REGISTRY_ID_TESTNET } from '@phasis-lab/sdk';
import { Transaction } from '@mysten/sui/transactions';

const tx = new Transaction();
genUserEntry.depositUsdcV2({
  package: PACKAGE_ID_TESTNET,
  typeArguments: [QUOTE_COIN_TYPE_TESTNET],
  arguments: {
    registry: REGISTRY_ID_TESTNET,
    accounts: ACCOUNT_REGISTRY_ID,
    coin: usdcCoinObjectId,  // object ID of a Coin<USDC> object you own
  },
})(tx);

tx.setSender(walletAddress);
tx.setGasPayment([gasPaymentRef]);
// sign and execute

The entire coin is deposited. To deposit a specific amount, use tx.splitCoins() first:

const tx = new Transaction();

// Split 50 USDC from your largest USDC coin
const [depositCoin] = tx.splitCoins(tx.object(largeUsdcCoinId), [50_000_000n]);

genUserEntry.depositUsdcV2({
  package: PACKAGE_ID_TESTNET,
  typeArguments: [QUOTE_COIN_TYPE_TESTNET],
  arguments: {
    registry: REGISTRY_ID_TESTNET,
    accounts: ACCOUNT_REGISTRY_ID,
    coin: depositCoin,  // TransactionArgument from splitCoins
  },
})(tx);

Step 3: Place a trade

Use placeTrade to buy or sell an option series. The series is identified by (marketId, strike, isCall).

import {
  placeTrade,
  intentToSide,
  TradeIntent,
  OrderType,
  PACKAGE_ID_TESTNET,
  REGISTRY_ID_TESTNET,
} from '@phasis-lab/sdk';
import { Transaction } from '@mysten/sui/transactions';

const BTC_MARKET_ID = '0xbac3cacd5169a741ab179f34e94011a3653835402732ebbfaad8bc18a5d8d264';
const BTC_SNAPSHOT_ID = '0x513b72314c521cf4d20c31ace3f2e2a13e8813aa0c5a59700c02f5a39fc1f1d4';

const tx = new Transaction();
placeTrade(tx, {
  registryId: REGISTRY_ID_TESTNET,
  marketId: BTC_MARKET_ID,
  accountRegistryId: ACCOUNT_REGISTRY_ID,
  snapshotId: BTC_SNAPSHOT_ID,

  // Series identity
  strike: 70_000_000_000_000n,  // $70,000 in UD30x9 (70_000 × 1e9)
  isCall: true,                  // true = call, false = put

  // Order parameters
  side: intentToSide(TradeIntent.OpenLong, null),  // BID (0) — buy to open long
  orderType: OrderType.NO_RESTRICTION,              // rest if not immediately matched
  qty: 2_000_000n,                                 // 2 contracts (2 × 1e6)
  limitPrice: 50_000_000n,                         // $0.05 limit price (0.05 × 1e9)

  // Optional (defaults to testnet package & quote type)
  packageId: PACKAGE_ID_TESTNET,
});

tx.setSender(walletAddress);
tx.setGasPayment([gasPaymentRef]);
// sign and execute

PlaceTradeArgs reference

FieldTypeDescription
registryIdstringShared OptionsRegistry object ID
marketIdstringMarket object ID (e.g. BTC market)
accountRegistryIdstringShared AccountRegistry object ID
snapshotIdstringStressSnapshot object ID for the asset
strikebigint | numberStrike in UD30x9 raw (strike × 1e9)
isCallbooleantrue for call, false for put
side0 | 1Book side — DeepBookSide.BID (buy) or DeepBookSide.ASK (sell)
orderType0–3Use OrderType constants
qtybigint | numberQuantity in raw units (contracts × 1e6)
limitPricebigint | numberLimit price in UD30x9 raw (price × 1e9)
packageIdstring?Defaults to PACKAGE_ID_TESTNET

Encoding reminder

// Strike: multiply USD value by 1e9
const strike = BigInt(Math.round(strikeUsd * 1e9));  // e.g. 70_000 USD → 70_000_000_000_000n

// Limit price: multiply USD per contract by 1e9
const limitPrice = BigInt(Math.round(priceUsd * 1e9));  // e.g. $0.05 → 50_000_000n

// Quantity: multiply number of contracts by 1e6
const qty = BigInt(Math.round(contracts * 1e6));  // e.g. 2 contracts → 2_000_000n

Step 4: Cancel an order

Cancel a resting limit order by its orderId (a u128 value returned by getAccountOrders).

import { cancelOrder, REGISTRY_ID_TESTNET } from '@phasis-lab/sdk';
import { Transaction } from '@mysten/sui/transactions';

const tx = new Transaction();
cancelOrder(tx, {
  registryId: REGISTRY_ID_TESTNET,
  marketId: BTC_MARKET_ID,
  accountRegistryId: ACCOUNT_REGISTRY_ID,
  snapshotId: BTC_SNAPSHOT_ID,
  strike: 70_000_000_000_000n,
  isCall: true,
  orderId: pendingOrderId,  // bigint — the u128 order_id from getAccountOrders
});

tx.setSender(walletAddress);
tx.setGasPayment([gasPaymentRef]);
// sign and execute

Cancels work during a protocol halt window — only the !paused check and snapshot-asset gate apply, so users can always recover resting orders.

Step 5: Refresh margin

Call refreshAssetMargin to recompute and apply the margin lock for all of the sender's positions under a given stress snapshot's asset. This is useful if the stress snapshot has been updated by the publisher since the account last traded.

import { refreshAssetMargin, REGISTRY_ID_TESTNET } from '@phasis-lab/sdk';
import { Transaction } from '@mysten/sui/transactions';

const tx = new Transaction();
refreshAssetMargin(tx, {
  registryId: REGISTRY_ID_TESTNET,
  accountRegistryId: ACCOUNT_REGISTRY_ID,
  snapshotId: BTC_SNAPSHOT_ID,
});

tx.setSender(walletAddress);
tx.setGasPayment([gasPaymentRef]);
// sign and execute

The snapshot determines which asset's positions are recomputed — passing the BTC snapshot recomputes the BTC margin lock.

Step 6: Withdraw USDC

import { genUserEntry, PACKAGE_ID_TESTNET, QUOTE_COIN_TYPE_TESTNET, REGISTRY_ID_TESTNET } from '@phasis-lab/sdk';
import { Transaction } from '@mysten/sui/transactions';

const tx = new Transaction();
genUserEntry.withdrawUsdcV2({
  package: PACKAGE_ID_TESTNET,
  typeArguments: [QUOTE_COIN_TYPE_TESTNET],
  arguments: {
    registry: REGISTRY_ID_TESTNET,
    accounts: ACCOUNT_REGISTRY_ID,
    amount: 10_000_000n,  // 10 USDC (6 decimals)
  },
})(tx);

tx.setSender(walletAddress);
tx.setGasPayment([gasPaymentRef]);
// sign and execute — an owned Coin<USDC> is returned to the sender

The withdrawal gate enforces:

  • Protocol is not paused (full halt includes withdraw — anti-drain protection).
  • amount <= free balance where free = balanceQuote − lockedMargin − quoteLocked.

Checking free balance before withdrawal

import { getAccount, accountFreeQuote } from '@phasis-lab/sdk';

const account = await getAccount(client, accountId);
const free = accountFreeQuote(account);  // bigint, USDC 6-decimal

console.log('Withdrawable:', Number(free) / 1e6, 'USDC');

Connect a Wallet

No Sui wallet detected in this browser.

Install Sui Wallet

Phasis supports any wallet that implements the Sui Wallet Standard.