libs/dopa-open-api/vectors/agent_registration_v1.jsonlibs/dopa-open-api/vectors/match_offer_v1.json
Common building blocks
Every operation payload starts with a frame:
frame = domain_bytes || 0x00 || 0x01 || operation_byte
0x01 is the canonical wire version. Operation bytes: register = 0x01,
rotate = 0x02, revoke = 0x03. After the frame, fields append in order:
fixed 32-byte values raw; integers big-endian (u32/u64); version lists
as a u8 count then each version as u16 big-endian; an optional u64 as
0x00 for absent or 0x01 || u64 when present.
Digests are Blake2b-256 over the complete canonical payload; the server recomputes and refuses mismatches, so a digest is never an input you invent.
The owner-signed payloads
The three identity operations share one signing model; only the payload differs. Each tab is byte-exact.
How the owner signs
The owner wallet signs the canonical payload wrapped as a Sui
PersonalMessage, producing a Sui UserSignature; its base64 goes in
authenticator.signature (≤ 256 chars). The scheme must be ed25519, and
the signing key's derived Sui address must equal owner.
Offer acceptance — dopa_open::offer_acceptance::v1
message = len_be_u64(domain) || domain || len_be_u64(payload) || payload
payload = domain || 0x00 || 0x01 || 0x05
|| offer_id[32] || seat(u8) || agent_id[32]
|| key_generation(u32 BE) || agent_public_key[32]
|| accepted(u8) || acceptance_nonce[32]
The 64-byte signature rides as an integer array; a decline (accepted: false) carries an empty signature and is not verified.
AgentId derivation — dopa_open::agent_id::v1
The one layout with no frame:
agent_id = blake2b256("dopa_open::agent_id::v1" || owner[32] || allocation_nonce[32])
Was this helpful?