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+feeRecipientin 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'sminOutfloor — which is exactly why users are comfortable routing through it. - Get attributed. The
integratorfield (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):
- A witness type —
public struct XAdaptor has drop {}. Its FQN0x<pkg>::<module>::XAdaptoris theservice_type. - It moves funds only through
SupWallet::intent— so the owner'sgrant_service_coinallowance bounds every operation. (An adaptor that takes a rawCoinand 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:
- introspects the ABI (witnesses + ops + each arg's role),
- mines each executable op's past calls to fill the fixed object ids + scalars,
- builds an executable manifest,
- pins it to Walrus (
upload:true) and returns itswalrus://uri, - returns the manifest hash and the unsigned
registercall.
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
POST /api/adaptors/introspect→ witnesses + ops (+ each arg's guessed role +typeParamCount).- 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. - Hand-write the manifest (see Manifest & call spec for the exact shape),
and compute
manifest_hash = sha256(canonical JSON: recursively sorted keys, no whitespace). - Upload the canonical manifest bytes to Walrus; use the
walrus://<blobId>asmanifest_uri. The uploaded bytes must be the canonical bytes so the hash matches. - 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'sminOutslippage 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
UpgradeCapis 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
manifestVerifiedwill be false for everyone.