Funds, escrow & payouts
Money in Boson moves through a single on-chain treasury per entity (seller, buyer, agent, DR, royalty recipient). All deposits and withdrawals go through the FundsHandlerFacet.
The lifecycle
Seller deposits to their treasury
Optional — sellers can also rely on per-commit deposit funding.
Buyer commits to an offer
The buyer's price and the seller's sellerDeposit lock in escrow.
Buyer redeems
No fund movement yet. Redemption only starts the dispute window.
Exchange completes
After the dispute window ends, the buyer's price flows to the seller treasury, and the seller's sellerDeposit is released back to the seller treasury.
Seller withdraws
withdrawFunds moves the tokens out of the protocol to the seller's treasury address.
Disputes branch step 4 to the dispute state machine, which splits escrow per buyerPercent.
Fees taken at completion
| Fee | Recipient | Taken from |
|---|---|---|
| Protocol fee | Boson protocol treasury | Seller's price share |
| Agent fee | Agent treasury | Seller's price share |
| Dispute resolver fee | DR treasury | Escrow (only on DECIDED outcome) |
| Royalty | Royalty recipients | Secondary sales |
Configured per chain and per token via ConfigHandlerFacet. Read current values from coreSdk.getFees() or the Fee schedule reference page.
Native vs. ERC-20
- Native (ETH, MATIC, etc.) —
exchangeTokenisaddress(0). Transactions arepayable; the buyer attachesmsg.value. - ERC-20 (USDC, DAI, etc.) —
exchangeTokenis the token address. The buyer mustapprovethe Diamond first (or use a permit / ERC-3009) — see Approve · Permit · Permit2 troubleshooting.
Withdrawal
Funds in a treasury are inert until withdrawn. Use:
withdrawFunds(entityId, tokenList, amountsList)— SDKwithdraw_funds— MCP
The treasury address is set at seller / agent creation and can be updated.
Common footguns
- Withdrawals are not instant earnings. Funds enter the treasury only when an exchange
COMPLETEDs (or is otherwise terminated favorably). Until then they're in escrow. - Per-offer seller deposit vs. seller-treasury deposit. Most offers have
sellerDeposit = 0; the seller stakes only when they want skin in the game for high-trust offers. - Token addresses are chain-specific. USDC on Polygon ≠ USDC on Base ≠ USDC on Mainnet. Pull the right address from Supported tokens.
Where to look in code
- Reference → Core SDK → Funds mixin
- Reference → MCP tools →
deposit_funds,withdraw_funds,get_funds - Reference → Contracts → Diamond facets →
FundsHandlerFacet