Skip to content
SDK

Overview

@automark/sdk — the tx builder + state reader every plugin calls.

Mirrors packages/sdk/public

@automark/sdk

TypeScript SDK for interacting with Automark vaults on Sui. Builds PTBs and reads on-chain state — the SDK never custodies keys or submits transactions, your wallet does that.

Status: early-access. The current surface is stable in shape, but the package is pre-v1.0 and minor versions may introduce breaking changes until the contract API freezes. See Roadmap for what is already shipped vs planned.

Install

npm install @automark/sdk @mysten/sui
# or
pnpm add @automark/sdk @mysten/sui

@mysten/sui is a peer dependency.

Quick start

Discover a market and read its live price

import { SuiClient } from "@mysten/sui/client";
import { Market } from "@automark/sdk";

const suiClient = new SuiClient({ url: "https://fullnode.testnet.sui.io" });

// Find the nearest BTC market expiring more than 5 minutes from now.
const btc = await Market.find({
  asset: "BTC",
  expiryAfterMs: Date.now() + 5 * 60 * 1000,
  client: suiClient,
});

// One read-only RPC, ~200-400ms typical, no gas.
const p = await btc.price();
console.log({
  spot: p.spotUsd,        // live BTC spot in USD
  forward: p.forwardUsd,  // SVI forward (probabilistic center)
});

// Strikes snapped to the on-chain tick grid, ready for mintBinary/mintRange.
const upper = btc.strikeAbove(p.forwardRaw, { pctBps: 300 });   // 3% above forward
const atm   = btc.strikeNear(p.forwardRaw);                     // ATM

Read vault state

import { Vault } from "@automark/sdk";

const vault = await Vault.fetch(vaultId, { suiClient });

console.log({
  nav: vault.nav,
  navPerShare: vault.navPerShare,
  totalShares: vault.totalShares,
  paused: vault.paused,
});

Refresh NAV + crystallize fees (permissionless)

import { Transaction } from "@mysten/sui/transactions";
import { Vault } from "@automark/sdk";

const vault = await Vault.fetch(vaultId, { suiClient });

const tx = new Transaction();
// Auto-picks update_nav_snapshot vs the begin/add_oracle/finalize builder
// depending on whether the vault has open positions.
vault.crystallizeFees(tx, {
  refs: { predictPackageId, predictObjectId },
});

await wallet.signAndExecuteTransaction({ transaction: tx });

Compose trade ops in a single PTB

import { Transaction } from "@mysten/sui/transactions";
import { Vault, Market } from "@automark/sdk";

const vault = await Vault.fetch(vaultId, { suiClient });
const { packageId: strategyPackageId, module: strategyModule } =
  vault.parseStrategyType();

// Discover the target market and its current price.
const btc = await Market.find({ asset: "BTC", expiryAfterMs: Date.now() + 5*60_000, client: suiClient });
const p = await btc.price();

const tx = new Transaction();

// Fund PM first, then mint — same PTB for atomicity
vault.pmDeposit(tx, { strategyPackageId, strategyModule, amount: 500_000_000n });
vault.mintBinary(tx, {
  strategyPackageId, strategyModule,
  predictPackageId, predictObjectId,
  oracleId: btc.id,
  strike: btc.strikeAbove(p.forwardRaw, { pctBps: 300 }),
  isUp: true,
  quantity: 100_000_000n,
});

await wallet.signAndExecuteTransaction({ transaction: tx });

Create a vault (3 sequential transactions)

import { Vault } from "@automark/sdk";

// TX 1 — publish share-token package
const tx1 = Vault.publishShareTokenTx({ modules, dependencies, sender });
const res1 = await wallet.signAndExecuteTransaction({ transaction: tx1 });
const share = Vault.parsePublishedShareToken(res1, moduleName, structName);

// TX 2 — finalize Currency registration (promotes to shared)
const tx2 = Vault.finalizeShareRegistrationTx({
  sender,
  shareType: share.shareType,
  currencyReceivingId: share.currencyReceivingId,
  currencyReceivingVersion,
  currencyReceivingDigest,
});
await wallet.signAndExecuteTransaction({ transaction: tx2 });

// TX 3 — atomic PredictManager + Vault creation
const tx3 = Vault.create({
  sender,
  vaultPackageId,
  predictPackageId,
  shareType: share.shareType,
  quoteType,
  treasuryCapId: share.treasuryCapId,
  shareCurrencyId: share.currencyReceivingId,
  witnessType,
  initialQuoteCoinId,
  initialQuoteAmountMicros,
  riskParams,
  feeParams,
  navParams,
  governanceAdmin,
  emergencyAdmin,
  creatorAddress,
  platformTreasury,
  initialPermissions,
  operatorAddress,
});
const res3 = await wallet.signAndExecuteTransaction({ transaction: tx3 });
const created = Vault.parseCreatedVault(res3);
// → { vaultId, vaultPackageId, predictManagerId, strategyPackageId, strategyModuleName, shareType }

Map Move-abort codes to names

import { parseMoveAbort } from "@automark/sdk";

try {
  await wallet.signAndExecuteTransaction({ transaction: tx });
} catch (err) {
  const info = parseMoveAbort(err);
  if (info) {
    console.log(info.code, info.name); // e.g. 9, "E_SNAPSHOT_STALE"
  } else {
    // not a MoveAbort (RPC, user reject, network) — handle separately
  }
}

Permission bits

import { PERMISSIONS, combinePermissions, decomposePermissions } from "@automark/sdk";

const perms = combinePermissions(
  PERMISSIONS.MINT_BINARY,
  PERMISSIONS.REDEEM_BINARY,
  PERMISSIONS.PM_DEPOSIT,
  PERMISSIONS.PM_WITHDRAW,
); // → 195

decomposePermissions(perms);
// → ["MINT_BINARY", "REDEEM_BINARY", "PM_DEPOSIT", "PM_WITHDRAW"]

Subpath exports

import { Vault }            from "@automark/sdk/vault";
import { Market }           from "@automark/sdk/market";
import { Oracle }           from "@automark/sdk/oracle";
import { days, hours }      from "@automark/sdk/duration";
import { usdFromRaw }       from "@automark/sdk/math";
import { getNetworkConfig } from "@automark/sdk/network";
import { PERMISSIONS,
         hasPermission }    from "@automark/sdk/permissions";
import { parseMoveAbort,
         VAULT_ERROR_CODES } from "@automark/sdk/errors";
import type { VaultState,
              MarketKey }   from "@automark/sdk/types";

The main barrel re-exports everything, but subpath imports help tree-shaking when bundle size matters.

Roadmap

What's available today:

SurfaceStatus
Vault.fetch, refresh, full state getters
uniqueOracleIds getter
Creation flow: publishShareTokenTx, publishStrategyTx, finalizeShareRegistrationTx, create + parsers
Trade ops on the vault: mintBinary, mintRange, pmDeposit, pmWithdraw
NAV snapshot: refreshNavSnapshot (auto-select), updateNavSnapshot
Fees: crystallizeFees + Vault.crystallizeFeesTx + parseCrystallizedFees
Market — discovery + live price + strike helpers (strikeNear, strikeAbove, strikeBelow, strikeAtSigma)
Oracle — lower-level Predict vocabulary (listActive, findActive, getById, getSnapshot)
Duration helpers (days, hours, minutes, seconds)
Math helpers (usdFromRaw, usdToRaw, bigintMin/Max/Clamp)
Network refs (getNetworkConfig, NETWORK_CONFIG, default RPC + predict-server URLs)
PERMISSIONS constants + helpers
parseMoveAbort, VAULT_ERROR_CODES, getErrorName
Re-exported types: VaultState, MarketKey, RangeKey, NavParams, RiskParamsState, FeeParamsState, PMPositionSummary, OracleState

Planned:

SurfaceStatus
LP-facing tx builders (requestDeposit, requestWithdrawal, cancels, process_*)
Standalone Strategy class with operator-facing ops (redeemBinary/redeemRange/supplyPlp/withdrawPlp/tick)
Strategy authoring helpers (createStrategyDeployment, witness setup, replace_strategy boilerplate)
Keeper helpers (listPendingDeposits/listPendingWithdrawals, scheduler)
Governance ops (proposeXUpgrade, activatePendingUpgrade)
React hooks (useVault, useNav, usePositions) — likely a @automark/sdk/react subpath
Batch reads (Vault.fetchMany)

Design notes

  • Methods accept a Transaction, not return one. This is intentional: PTB requires every moveCall in a single tx, so the SDK never wraps Transaction — you compose freely.
  • bigint for every on-chain quantity (u64 exceeds Number.MAX_SAFE_INTEGER). The SDK converts to tx.pure.u64() internally.
  • static fetch() instead of new Vault(id): a Vault constructed without on-chain reads would be incomplete (no NAV, params, admins). Forcing fetch guarantees the object always carries a real snapshot.
  • Vault.refresh() mutates in place for ergonomics. If you want immutability, just call Vault.fetch() again — same RPC cost.
  • Market wraps Oracle with vocabulary that fits builders. Internally they delegate; use whichever feels right for the layer you're at.

Error handling

The SDK throws on:

  • Missing predict_manager_id when calling mintBinary/mintRange/pmDeposit/pmWithdraw
  • higherStrike <= lowerStrike in mintRange
  • refreshNavSnapshot called without refs on a vault with positions
  • refreshNavSnapshot exceeding 10 unique oracles (split into multiple PTBs)
  • Malformed object types or parse failures in parseVaultType / parseStrategyType
  • Market.price() without a SuiClient (passed at find/list/byId time or to price())
  • Oracle.findActive when no active oracle matches the time filters
  • bigintClamp with min > max (swapped args)

For on-chain failures (Move aborts), use parseMoveAbort(err) to get a structured { code, name, raw } object.

License

MIT.