AdManager pays the bridger on the ad chain, the OrderPortal
pays the maker on the order chain. The signatures and proofs are what the contracts check, so the
finished packages are public and anyone can submit them. See Co-signing.
Endpoints
A client’s part is small: read
GET /v1/trades/:id/params,
sign, upload, then watch GET /v1/trades/:id/settlement (or the trade:status socket event) until
Filled.
The bridge fee
The ad chain takes a fee from what the bridger receives: a share stays in the maker’s ad and a share goes to the protocol. The order chain takes nothing. The split is fixed per trade bylpFeeBps and
protocolFeeBps in the order, so a later change does not affect it. Each payout emits
FeeCharged(orderHash, lpFee, protocolFee). See Fees.
Upload a co-signature
POST /v1/trades/:id/cosign stores one party’s signature. Both parties upload the same auth;
only signer, blsSig and blsPubKey differ.
auth is the SettlementAuth (v4): the domain tag plus eight fields. The signature is over their
288-byte concatenation, hashed to G2. Don’t build it by hand: use buildSettlementPreimage and
signSettlement from @proofbridge/bls-encodings.
What the signature binds:
- The order.
orderHashmust be the trade’s. Both verifiers refuse a co-signature for another order. - The roots. They must be the pair
/paramspinned. A deposit landing between the two parties’ fetches cannot split them. - The maker key. A maker upload under any key other than
makerKeyCommitmentis refused, and so is a pair aggregated under another key. - The nullifiers. Each payout must consume the nullifier signed for its leg.
Aggregated. Re-uploading the same bytes is a no-op.
On any roots-not-pinned refusal, read /params again and sign once more.
Settlement status
GET /v1/trades/:id/settlement returns where the trade’s settlement stands. Only the trade’s parties
may read it.
partyKeys and secretCustody are always present here. The cosign response and the trade:status
push carry only tradeId, state, signaturesCollected, parties and updatedAt.
The collected pair
GET /v1/trades/:id/settlement/pair returns both co-signatures, so either party can keep its own
claiming material and aggregate locally. It is served only once both halves exist: the first
signature is never shown to the second signer before they sign.
complete: false. Later, once the relayer’s short-lived copy has expired,
signatures is empty and aggSig, pkMaker and pkBridger carry the aggregated material instead.
After both legs settle and the material is pruned, you get settled: true with auth: null.
Public leg package
GET /v1/trades/:id/settlement/legs/:side returns everything needed to submit one payout. It needs no
auth: every field is public, and the payout is gated on chain by the proof and the co-signatures, not
by who sends it. Anyone holding the trade id can finish the settlement if both parties and the
relayer’s submitter are down.
side is 0 (the AdManager payout on the ad chain, to the bridger) or 1 (the OrderPortal
payout on the order chain, to the maker). A leg is served only when the relayer would release it
itself: when the other leg’s package exists too, or the other leg already paid out, and (while neither
has landed) the deadline is not too close.
unlock(unlockParams, nullifierHash, targetRoot, proof, cosigData).
Settlement states
Claimed and Disputed take priority over Settling, so a leg that already paid shows only in the
trade’s adCreatorClaimed and bridgerClaimed. If the trade leaves CLAIMED or DISPUTED without
ending, the state is worked out again from the pair and the payouts. Between Aggregated and
Settling the progress signal is legs.
Halting and resuming settlement
There is no endpoint for this. A maker halts co-signed payouts from their ads with their own transaction on the ad chain’sAdManager, from the account that owns the ads:
One transaction covers every ad that maker owns on that
AdManager, and takes effect in the same
block or ledger. An agent cannot halt or resume.
While halted, the co-signed AdManager payout reverts. Nothing else reads the halt: settlement
evidence still pays the bridger, and new locks still work. A halt in force at or after the deadline
makes a later cancel wait an extra grace period, so a maker already paid on the order chain cannot
also take the lock back.
The relayer checks the halt before every payout it sends, for both legs, and holds them while it
stands. The status then shows halt: { "by": "maker", "since": … } with the state still Aggregated
and both legs RELEASED. It clears at the next sweep after the maker resumes, when the leg lands, or
when the deadline passes, after which the trade ends through the cancel path. For
the chain’s own answer, read halted(maker) or halt_of(maker) directly. The public leg route keeps
serving packages while halted.