Signing & meta-transactions
Every state-changing call to Boson is signed. There are five distinct signing flows; this page is the canonical reference for all of them. Anywhere else in the docs that mentions signing links here, not to a duplicate explainer.
At a glance
| Flow | Who signs | Who pays gas | Where it's used |
|---|---|---|---|
| Direct on-chain | The user/caller | The user/caller | Default for SDK and send_signed_transaction |
| Boson meta-tx (Biconomy) | The user | A relayer | Gas-less UX for users |
| Token-auth meta-tx | The user (+ token sig) | A relayer | Gas-less UX for users |
| FullOffer EIP-712 | The offer creator | (varies) | Non-listed (private) offers, x402 |
| Mutual dispute resolution | Buyer + seller (both) | Whoever submits | resolveDispute |
Direct on-chain
You sign and broadcast yourself. The SDK does this transparently when you call sdk.commitToOffer(...) etc.
For MCP-driven agents, the 3-step pattern:
- Call the tool (e.g.
commit_to_offer) → returns an unsigned{ to, data, value, gasLimit, chainId }. - Sign locally with your wallet.
- Broadcast via
send_signed_transactionor your own RPC.
const unsigned = await mcp.commitToOffer({ /* … */ })
const signed = await wallet.signTransaction(unsigned)
await mcp.sendSignedTransaction({ chainId: 84532, signedTx: signed })See Build for AI agents → The 3-step signing pattern for the agent-specific deep dive.
Boson meta-tx (Biconomy)
The user signs an EIP-712 envelope; a relayer (Biconomy or your own) calls MetaTransactionsHandlerFacet.executeMetaTransaction and pays gas.
// Sign on the client:
const signedMetaTx = await sdk.metaTx.signMetaTxCommitToOffer({
buyer: userAddress,
offerId,
})
// Relay (either via Biconomy directly, or your own forwarder):
await sdk.metaTx.relayMetaTransaction(signedMetaTx)Or via MCP:
send_meta_transaction { chainId, functionName, functionSignature, userAddress, nonce, signature }Token-auth meta-tx
Th user can pay the protocol in a single signed envelope, without prior approve. Three variants:
- ERC-3009 —
receiveWithAuthorization(used by USDC, EURC, others). - EIP-2612 Permit — for tokens that implement
permit. - Permit2 — the Uniswap Permit2 variant.
The relayed call is executeMetaTransactionWithTokenTransferAuthorization. See Reference → Contracts → Diamond facets → MetaTransactionsHandlerFacet.
Via MCP:
send_forwarded_meta_transaction {
chainId, functionName, functionSignature, userAddress, nonce, signature,
tokenAuth: { type: "ERC3009" | "Permit" | "Permit2", … }
}FullOffer EIP-712
A FullOffer is a seller-signed payload representing an offer that hasn't been written on-chain. Used for non-listed (private) offers and for the x402 stack.
const fullOffer = await sdk.signFullOffer({ /* offer params */ })
// fullOffer.signature, fullOffer.offerHash, …
// Later, atomic commit:
await sdk.createOfferAndCommit({ fullOffer })The signature can be verified on-chain (EOA or EIP-1271 smart account). The hash, once committed, is recorded as used so it can't be re-played.
Mutual dispute resolution
resolveDispute requires both buyer and seller to sign the same payload (offering buyerPercent). Whichever party submits the on-chain call attaches both signatures.
See Build → Buyers → Raise a dispute and Recipes → Mutual dispute resolution.
Nonce management
Each user has a per-chain nonce in the Diamond's MetaTransactionsHandlerFacet. Read with isUsedNonce(address, nonce). The SDK reads + bumps for you; agents using raw MCP must manage their own.
Common footguns
- Mismatched EIP-712 typed-data. The SDK builds the payload identically to the on-chain verifier. Don't hand-build typed-data; always use
sdk.metaTx.signMetaTx*or the MCPsign_*tools. - Stale nonces under concurrency. If two transactions for the same user are signed in parallel with the same nonce, one will fail. Serialize or use distinct nonces.
- Permit2 has a different domain separator than EIP-2612. Don't mix them.
signTypedDataUI varies wildly across wallets. Test with MetaMask, Coinbase Wallet, and a hardware wallet before assuming any signed-data flow works.
Where to look in code
- Reference → Core SDK → MetaTx mixin
- Reference → MCP tools →
sign_full_offer,send_meta_transaction,send_native_meta_transaction,send_forwarded_meta_transaction,send_signed_transaction - Reference → Contracts → Diamond facets →
MetaTransactionsHandlerFacet