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); // ATMRead 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:
| Surface | Status |
|---|---|
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:
| Surface | Status |
|---|---|
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 wrapsTransaction— you compose freely. bigintfor every on-chain quantity (u64 exceedsNumber.MAX_SAFE_INTEGER). The SDK converts totx.pure.u64()internally.static fetch()instead ofnew Vault(id): a Vault constructed without on-chain reads would be incomplete (no NAV, params, admins). Forcingfetchguarantees the object always carries a real snapshot.Vault.refresh()mutates in place for ergonomics. If you want immutability, just callVault.fetch()again — same RPC cost.MarketwrapsOraclewith 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_idwhen callingmintBinary/mintRange/pmDeposit/pmWithdraw higherStrike <= lowerStrikeinmintRangerefreshNavSnapshotcalled withoutrefson a vault with positionsrefreshNavSnapshotexceeding 10 unique oracles (split into multiple PTBs)- Malformed object types or parse failures in
parseVaultType/parseStrategyType Market.price()without aSuiClient(passed atfind/list/byIdtime or toprice())Oracle.findActivewhen no active oracle matches the time filtersbigintClampwithmin > max(swapped args)
For on-chain failures (Move aborts), use parseMoveAbort(err) to get a structured { code, name, raw } object.
License
MIT.