07 · API reference

Every public export of @ballast/sdk, with real signatures from packages/sdk/src. Two entry points:

@ballast/sdk re-exports everything in @ballast/sdk/parse, so the full package is a superset.


BallastClient

new BallastClient(opts: BallastClientOptions)

interface BallastClientOptions {
  packageId: string;          // Ballast call target (v3)
  deepbookPackageId: string;  // DeepBook package the live pools accept
  client?: SuiClient;         // an existing client, or…
  rpcUrl?: string;            // …an RPC url, or…
  network?: 'testnet' | 'mainnet' | 'devnet' | 'localnet'; // …a network (default 'testnet')
  signer?: Keypair;           // required for writes
  attestation?: AttestationProvider; // default: MockAttestationProvider
}
Member Signature Notes
client SuiClient the underlying read client
packageId / deepbookPackageId string as passed
attestation AttestationProvider the active provider
address get(): string \| undefined the signer’s Sui address
getCapState (capId: string) => Promise<CapState> live cap read
getIdentityState (identityId: string) => Promise<IdentityState> live identity read
getReputation (identityId: string) => Promise<bigint> convenience
mintIdentity (label: string) => Promise<{ identityId: string; digest: string }> shared AgentIdentity
issueCap (limits: Limits) => Promise<{ capId: string; digest: string }> mint + share a BallastCap
revokeCap (capId: string) => Promise<{ digest: string }> owner-only
depositSui (balanceManagerId: string, amount: bigint) => Promise<{ digest: string }> DeepBook venue glue
executeGated (p: ExecuteGatedParams) => Promise<GatedResult> the headline; act through the cap

executeGated behavior. It reads the pool’s type args (unless typeArgs is given), asks the attestation provider to attest(...), builds either execute_trade (mock) or execute_trade_attested (when the provider exposes an enclaveId), sets an explicit gas budget so even a rejected action commits a digest, submits, and returns a typed GatedResult. A capability violation is { ok: false }, never a throw.


PTB builders (pure)

Each returns an unsigned Transaction you can sign anywhere (e.g. a wallet).

buildMintIdentityTx(packageId: string, label: string): Transaction
buildIssueCapTx(packageId: string, a: IssueCapArgs): Transaction
buildRevokeTx(packageId: string, capId: string): Transaction
buildExecuteGatedTx(a: ExecuteGatedTxArgs): Transaction
buildExecuteAttestedTx(a: ExecuteAttestedTxArgs): Transaction
buildDepositTx(deepbookPackageId: string, balanceManagerId: string, coinType: string, amount: bigint): Transaction
interface IssueCapArgs {
  identityId: string; spendLimit: bigint; maxLeverageBps: bigint;
  allowedMarkets: string[]; expiryMs: bigint;
}
interface ExecuteGatedTxArgs {
  packageId: string; identityId: string; capId: string; poolId: string;
  balanceManagerId: string; typeArgs: [string, string]; amount: bigint;
  leverageBps: bigint; isBid: boolean; payWithDeep: boolean;
  clientOrderId: bigint; attestation: Attestation;
}
interface ExecuteAttestedTxArgs {
  packageId: string; identityId: string; capId: string; poolId: string;
  balanceManagerId: string; enclaveId: string; typeArgs: [string, string];
  amount: bigint; leverageBps: bigint; isBid: boolean; payWithDeep: boolean;
  clientOrderId: bigint; timestampMs: bigint; sig: Uint8Array;
}

Builder arg order mirrors the Move signatures exactly. See MOVE_TARGETS.


Reads (pure parsers + client reads)

getCapState(client: SuiClient, capId: string): Promise<CapState>
getIdentityState(client: SuiClient, identityId: string): Promise<IdentityState>
readPoolTypeArgs(client: SuiClient, poolId: string): Promise<[string, string]>

// pure (operate on already-fetched JSON):
parseCapState(obj: unknown): CapState
parseIdentityState(obj: unknown): IdentityState
parseTradeExecuted(events: unknown[] | null | undefined): TradeExecutedEvent | undefined
extractAbortCode(errText: string | null | undefined): number | undefined
abortReason(code: number | undefined): string
ABORT_REASONS: Record<number, string>

ABORT_REASONS: 1 capability revoked · 2 capability expired · 3 market not allowed · 4 leverage exceeds the cap · 5 spend exceeds the cap · 6 caller is not the owner.


MOVE_TARGETS

Stable call-target strings (the single source of truth for which on-chain functions to call):

MOVE_TARGETS.identityMint(pkg)             // `${pkg}::identity::mint`
MOVE_TARGETS.capabilityIssue(pkg)          // `${pkg}::capability::issue`
MOVE_TARGETS.capabilityRevoke(pkg)         // `${pkg}::capability::revoke`
MOVE_TARGETS.tradingExecute(pkg)           // `${pkg}::trading::execute_trade`
MOVE_TARGETS.tradingExecuteAttested(pkg)   // `${pkg}::trading::execute_trade_attested`
MOVE_TARGETS.deepbookDeposit(deepbookPkg)  // `${deepbookPkg}::balance_manager::deposit`

Presets

TESTNET: BallastNetwork              // the reference deployment (mirrors DEPLOYMENTS.md)
TESTNET_ORIGIN_PACKAGE: string       // 0xe12fe8ef… — match `${ORIGIN}::trading::TradeExecuted`
SUI_TYPE / DBUSDC_TYPE / DEEP_TYPE: string
SUI: bigint                          // 1_000_000_000n (one SUI in MIST)
CLOCK_ID: string                     // '0x6'

Types

interface BallastNetwork { packageId; deepbookPackageId; identityId; balanceManagerId; poolId: string }
interface Limits { identityId: string; spendLimit: bigint; maxLeverage: number; allowedMarkets: string[]; expiryMs: number }
interface CapState { spendLimit; spent; remaining; maxLeverageBps; expiryMs: bigint; allowedMarkets: string[]; revoked: boolean; owner; agent: string }
interface IdentityState { label: string; reputation; actionsOk; actionsBlocked: bigint; owner: string }
interface TradeExecutedEvent { agent; cap; pool; amount; is_bid; leverage_bps; client_order_id; reputation }
interface ExecuteGatedParams { identityId; capId; poolId; balanceManagerId: string; amount: bigint; isBid: boolean; leverage?: number; payWithDeep?: boolean; clientOrderId?: bigint; typeArgs?: [string,string]; gasBudget?: bigint }

type GatedResult =
  | { ok: true;  digest: string; filled: string; reputation: string; event?: TradeExecutedEvent }
  | { ok: false; digest?: string; abortCode?: number; abortReason: string };

The attestation seam

The point of the design: executeGated only ever calls provider.attest(...), so a real TEE provider drops in with zero call-site change.

interface AttestationContext { agent: string; market: string; amount: bigint; isBid: boolean; ts: number }
interface Attestation { payload: Uint8Array; sig: Uint8Array; timestampMs?: bigint }
interface AttestationProvider { attest(ctx: AttestationContext): Promise<Attestation> | Attestation }

class MockAttestationProvider implements AttestationProvider { /* dev: JSON payload + dummy sig */ }

interface NautilusOptions { enclaveUrl: string; enclaveId: string; fetchImpl?: typeof fetch }
class NautilusAttestationProvider implements AttestationProvider {
  readonly enclaveId: string;
  constructor(opts: NautilusOptions);
  attest(ctx: AttestationContext): Promise<Attestation>; // POSTs to the enclave /process_data
}

The presence of enclaveId on the provider is what marks a client as attested and routes executeGated to execute_trade_attested.