Guides

Publish an adaptor

Turn a deployed adaptor package into a listing any wallet and agent can use. Permissionless — you sign register(); no approval, no gatekeeper.

#Why publish?

The marketplace is early — which is exactly the advantage. A listing is a permanent, on-chain claim, and the trust signals that decide which adaptor an agent picks (usage, verified reviews) only accrue with time. Listing now costs one transaction and compounds.

#Stake your claim

  • The service-type is first-come. One register() and that service-type is yours — namespaced by your package id, unforgeable, the canonical entry for that protocol/op. Re-registering a taken service-type fails; the first mover holds it.
  • Reputation accrues on-chain to you. Usage and verified reviews attach to your listing, and agents rank by real, hard-to-fake usage. The track record you start today is a moat a later entrant can't buy.
  • Shape the standard while it's soft — the ops, categories, and conventions the catalog settles on are still being set by whoever shows up first.

#Earn on what you route

  • Declare a fee. Set feeBps + feeRecipient in your manifest to take a disclosed integrator fee on volume flowing through your ops. It's disclosed, not silently taken — and bounded by the user's minOut floor — which is exactly why users are comfortable routing through it.
  • Get attributed. The integrator field (auto-filled when you draft with an API key) ties every listing and on-chain action you bring back to you — the receipts you need for partnerships, grants, and BD.

#Near-zero cost, no downside

  • Permissionless + keyless — no gatekeeper, no integration meeting, no custody. You sign one transaction; nothing to maintain server-side.
  • Distribution you don't build. As Sup wallets and agents grow, every one of them can already reach your adaptor — you ship no frontend, no agent, no per-app integration.
  • Sandboxed by design. Users try your adaptor under a bounded, revocable allowance, so a brand-new publisher clears the trust bar far faster than a raw contract would.

Early is the edge: the cost to list is one transaction, but the service-type you claim and the reputation you start accruing compound from the day you publish.

#What makes a package an adaptor

Two requirements (the rest is metadata):

  1. A witness typepublic struct XAdaptor has drop {}. Its FQN 0x<pkg>::<module>::XAdaptor is the service_type.
  2. It moves funds only through SupWallet::intent — so the owner's grant_service_coin allowance bounds every operation. (An adaptor that takes a raw Coin and runs off with it would never get authorized, and couldn't pull from a vault anyway.)

#Fast path — let the helper draft it

curl -X POST "$SUP/api/adaptors/draft" -H 'content-type: application/json' -d '{
  "packageId": "0x…", "name": "MySwap", "summary": "…",
  "category": "Swap", "network": "testnet", "upload": true
}'

The host:

  1. introspects the ABI (witnesses + ops + each arg's role),
  2. mines each executable op's past calls to fill the fixed object ids + scalars,
  3. builds an executable manifest,
  4. pins it to Walrus (upload:true) and returns its walrus:// uri,
  5. returns the manifest hash and the unsigned register call.

Then review the draft (the name/summary are yours to choose — the AI guesses generically), and sign register():

sui client ptb --move-call <regPkg>::registry::register \
  @<regObj> @<packageId> '"<serviceType>"' '"<walrus://uri>"' \
  '<vector[..hash bytes..]>' @0x6

Confirm it shows up in GET /api/adaptors. Done.

#Manual path — full control

  1. POST /api/adaptors/introspect → witnesses + ops (+ each arg's guessed role + typeParamCount).
  2. For each executable op, POST /api/adaptors/infer → the object ids/scalars it was really called with. Singletons (a GlobalConfig that's identical across all past calls) are safe to use directly; for varied args (pools that differ by coin pair) pick by coin pair and liquidity.
  3. Hand-write the manifest (see Manifest & call spec for the exact shape), and compute manifest_hash = sha256(canonical JSON: recursively sorted keys, no whitespace).
  4. Upload the canonical manifest bytes to Walrus; use the walrus://<blobId> as manifest_uri. The uploaded bytes must be the canonical bytes so the hash matches.
  5. Sign register(...) as above.

#Making an op executable

The ABI gives parameter types, not meaning, so attach a call spec declaring each argument's role. A complete Cetus swap_a_to_b example:

"call": {
  "typeArgs": ["coinIn", "coinOut"],
  "args": [
    { "kind": "wallet" },                              // the vault (auto)
    { "kind": "object", "id": "0x<GlobalConfig>" },    // mined singleton
    { "kind": "object", "id": "0x<Pool>" },            // mined (per-pair)
    { "kind": "amount" },                              // user's amount_in
    { "kind": "minOut" },                              // slippage floor
    { "kind": "pure", "type": "u128", "value": "4295048016" }, // mined sqrt limit
    { "kind": "clock" }                                // 0x6
  ]
}

Without a call spec, the op is discover/authorize-only (an agent can't run it).

#Fees & attribution

  • feeBps + feeRecipient — a disclosed integrator fee. (It's declared, not enforced by the registry; the user's minOut slippage floor bounds what an op can actually take.)
  • integrator — a partner id, to attribute the listings + on-chain usage you bring.

Pass them to draft. With an API key, integrator is auto-filled — see Rate limits & webhooks.

#Manage your listing

  • registry::update(service_type, package_id, manifest_uri, manifest_hash, clock) — re-point the package or refresh the manifest. Publisher-gated (only the original publisher).
  • registry::unlist(service_type, clock) — remove it. Publisher-gated.
  • registry::attest(service_type, score, comment_uri, clock) — anyone can leave a 1–5 review.

#Gotchas

  • Object id selection. For pool-like args, mining returns several ids; pick the one for the pair/liquidity you intend. A wrong object makes the op abort (it never loses funds — it just fails).
  • Package immutability. If your package's UpgradeCap is live, you can change the adaptor's behavior later. Consumers may prefer immutable (frozen) packages — consider freezing.
  • Canonical bytes. Upload exactly the canonical JSON you hashed, or manifestVerified will be false for everyone.