Builder Fees

Builder codes let a front-end or integrator charge a per-fill fee on orders it submits on a user's behalf. A wallet must first approve a builder, authorizing it to charge up to a chosen rate; orders are then tagged with that builder via the builder field on POST /v0/markets/{symbol}/orders.

Approval is keyed on the order owner (the signing wallet), not the submitter, and is bounded by a protocol-wide cap. Rates are expressed in BPS_TIMES_1K units (one basis point = 1000). The flow is:

  1. Check the protocol cap with max-fee. A cap of 0 means builder codes are disabled for that pool.
  2. Approve the builder for a rate at or below the cap (sign and broadcast the returned transaction). Approving 0 revokes.
  3. Read back the granted rate with approval; effective is min(approved, protocolMaxFee) - the rate actually enforced at order placement.

GET /v0/markets/{symbol}/builder/max-fee

POST /v0/markets/{symbol}/builder/approve

GET /v0/markets/{symbol}/builder/approval

Collecting earned fees

Builder fees are not pushed to your wallet per fill. Each charged fee is credited to the builder's own vault balance on the pool it was earned on (see BuilderFeeCharged), where it sits as a free, withdrawable balance until you claim it. Fees accrue per pool and per token: buy-side (bid) fills pay in the pool's quote token, sell-side (ask) fills in the base token.

To collect:

  1. Read what you've earned with getWithdrawableBalance(builder, token) on the pool, or GET /v0/markets/{symbol}/vault/balance, for each token you've earned in. For a native-SOMI side, pass the sentinel 0x28f34DeFd2b4CB48d9eE6d89f2Be4Bc601694c00, not address(0).
  2. Withdraw it to your wallet with withdraw(token, amount), signed by your builder wallet — or via POST /v0/markets/{symbol}/vault/withdraw, which returns an unsigned transaction for you to sign and broadcast. Your key never leaves your control.

The builder fee is charged on top of the trade: auto-pull pulls principal + max(makerFee, takerFee) + builderFee from the order owner's wallet at placement, and the builder-fee slice is routed to your withdrawable balance.

Attributing a routed swap

Multi-hop swaps through the SpotRouter can be attributed too, via its …WithBuilder entrypoints. Two differences from a direct order matter for accounting:

  • The fee is charged once, on leg 0 only — not once per hop. A three-leg route pays the same builder fee as a one-leg route, and it accrues on the leg-0 pool, in that leg's input token. Check your balance there, not on the pool the route ends at.
  • Approval is read on the leg-0 pool. The user must have approved you on whichever pool the route starts at, so a builder serving arbitrary routes needs approval on every pool that can appear first.

See Builder attribution for the entrypoints and the SwapAttributed event.