Start

Concepts

The few ideas everything else builds on. Read this once and the rest of the docs click.

#Adaptor

A Move package that wraps an external protocol so a Sup vault can use it through the SupWallet::intent flow. It moves funds only via intent — never by holding a raw Coin — so the owner's allowance always bounds it. A minimal adaptor looks like:

module my_adaptor::adaptor {
    use SupWallet::intent;
    public struct MyAdaptor has drop {}            // the witness (see below)

    public fun swap<CoinIn, CoinOut>(
        wallet: &mut SupWallet::wallet::Wallet,
        pool: &mut some_dex::Pool<CoinIn, CoinOut>, // protocol object
        amount_in: u64, min_out: u64, clock: &Clock, ctx: &mut TxContext,
    ) {
        // pulls CoinIn from the vault via intent (allowance-checked),
        // calls the DEX, deposits CoinOut back into the vault.
    }
}

Examples on Sui today: a Cetus swap adaptor, a Scallop lending adaptor, an OS-account trading adaptor.

#Witness / service-type

Every adaptor declares a witness type: a struct with has drop and nothing else, e.g. public struct MyAdaptor has drop {}. Its fully-qualified name — 0x<pkg>::<module>::MyAdaptor — is the service-type: the unique key for the listing and the exact thing a wallet owner authorizes.

Because the type name is namespaced by the publisher's package id (type_name::with_defining_ids), nobody can register your witness type and have it resolve to their package. Service-types are globally unique and unforgeable by construction.

#Allowance — the safety model

Before an adaptor can touch a coin, the owner must grant it. There are three on-chain gates, all enforced by SupWallet:

  1. Service allowlistwallet::grant_service_coin<Witness, Coin>(wallet) adds the (service-type, coin) pair to the vault's allowlist. This is the gate every op checks.
  2. Per-service allowance — an optional spend cap for a delegate (e.g. an AI agent) on that service.
  3. Per-coin allowance — an optional spend cap on that coin across services.

Using a listed adaptor therefore only ever moves funds the owner granted, capped by these allowances. Even a malicious listing is sandboxed to exactly what you authorized. Revoke any time with revoke_service_coin.

#Intent

SupWallet::intent is the hot-potato engine adaptors call to pull funds out of the vault and credit results back, all in one transaction. It has four modes (A = self-spend, B = designated payer, C = unmetered/cap-gated, D = internal swap) — you rarely touch them directly; the manifest's intentMode is just informational.

#Manifest

The listing's rich metadata (name, summary, category, ops, fees, call specs). It lives off-chain on Walrus; the registry stores its manifest_uri + a sha256 content hash, so the body is tamper-evident. Full shape: Manifest & call spec.

#Call spec

The on-chain ABI tells you a parameter's type, not its meaning: it says "param 4 is a u64" but not "param 4 is the input amount", and "param 2 is a Pool" but not which pool. A call spec fills that gap — the publisher declares each argument's role (wallet | amount | minOut | object | clock | pure), so an agent can turn "swap 1 SUI to USDC" into a concrete transaction. Ops with a call spec are agent-executable; without one they are discover/authorize-only.

#Mining

Where do the fixed object ids (pools, configs) and scalars in a call spec come from? They are recovered by reading the package's own past on-chain transactions — those calls already passed the real objects. The tooling tallies them per argument position: an argument that's always the same id is a singleton (e.g. a global config) and auto-fills; one that varies is pool-like and comes back as candidates. No hand-typing required.

#Keyless

Every helper — HTTP API, SDK, CLI, MCP server — returns data and unsigned transactions. Signing is always done by the user with their own wallet (in a browser) or local sui keypair (in a shell). We never hold, request, or see your keys. The phrase "you sign" appears throughout these docs for exactly this reason.

Next: Quickstart.