Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Wallets & key management · Boson Protocol
Skip to content

Wallets & key management

Boson is signer-agnostic. The SDK takes a Web3LibAdapter; the MCP server never sees keys (it returns unsigned transactions). The question is how your code holds and uses keys.

The five patterns

PatternWhenNotes
Browser wallet (MetaMask, Coinbase Wallet, WalletConnect, RainbowKit)Human-facing appsStandard; integrate via EthersAdapter(provider, provider.getSigner()).
Server EOABackend automation, dev/stagingEasy. Risky in production — protect with KMS, vault, restricted IP.
MPC / threshold sig (Fireblocks, Privy, Turnkey, etc.)Multi-party custodyBridge to ethers/viem; your provider's SDK gives you a signer.
Smart account (Safe, ERC-4337)Programmable rules, batched ops, session keysSign through the account's userOp flow; relay via your bundler.
Session keyAgent commerce, mobile appsShort-lived key scoped to specific actions, delegated from a master account.

Pick the pattern that matches your security model. Boson doesn't care which.

Browser wallet (typical Next.js / React app)

import { CoreSDK } from "@bosonprotocol/core-sdk"
import { EthersAdapter } from "@bosonprotocol/ethers-sdk"
import { ethers } from "ethers"
 
const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer = provider.getSigner()
 
const sdk = CoreSDK.fromDefaultConfig({
  web3Lib: new EthersAdapter(provider, signer),
  envName: "production",
  configId: "production-137-0",
})

Server EOA (Node script, cron, queue worker)

import { ethers } from "ethers"
const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL)
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider)
// pass `wallet` to EthersAdapter the same way

In production, never hold private keys in environment variables on a long-running host. Use AWS KMS, Hashicorp Vault, or a managed signer (Fireblocks, Privy, Turnkey). The SDK doesn't care; just hand it an object with signMessage, signTransaction, etc.

Agent wallets

Autonomous agents call state-changing tools in tight loops. Special considerations:

  • Nonce management. Don't send tx N+1 before tx N is mined unless you're tracking nonces yourself.
  • Gas funding. Refill the agent wallet automatically if it dips below a threshold.
  • Spending caps. Use a smart account with a session key bounded by max-spend rules.
  • Restart safety. On crash, check on-chain state (e.g. get_exchanges) before re-trying — see Idempotency & retry.

For deep coverage: Build for AI agents → Wallet patterns.

Smart accounts

A Safe (multisig) can be a seller or buyer. The SDK signs typed data with the smart account; the Safe owners co-sign offline; the resulting Safe-tx is what hits the Diamond.

For ERC-4337 accounts, the SDK builds the inner calldata; you wrap it in a userOp and send to a bundler. The Diamond's meta-tx facet accepts EIP-1271 signatures (smart-account signatures), so this works out of the box.

Session keys

Use these to delegate scoped authority to an agent or mobile app:

  1. Master account (Safe / 4337) authorizes a session key.
  2. Session key signs Boson actions within a scope (max value, allowed selectors, time-boxed).
  3. Master can revoke any time.

Useful for sandboxing an autonomous buyer agent so it can spend ≤ $100/day on commits, redeem, and dispute — but nothing else.

Common footguns

  • MetaMask switches networks asynchronously. If you switch from L1 to L2 mid-flow, your provider may still be on the old chain for a beat. Always check provider.network before broadcasting.
  • Hardware wallets can be slow with EIP-712. Build in a 30s timeout for signTypedData, and don't auto-retry — you'll just trigger a second user-confirm dialog.
  • Don't reuse a buyer wallet as a seller treasury. It works, but it conflates accounting. Different wallets for different roles.

Next