Skip to main content

Trading & Settlement

This page covers what happens after a user picks a market: how the order is built, signed, and submitted; what approvals are needed; how positions are redeemed; how MAGMA captures fees/referrals; and how DFlow's gasless path works. The invariant across all eight venues: the user's wallet produces the signature in the browser, and MAGMA never holds the key.

Order lifecycle: build → sign → submit

There are three construction models (see Architecture). The sign step is always the user's browser wallet; build and submit vary.

Model A — backend-built order, client signs, backend relays

Used by Limitless, Predict.fun, and Opinion (CLOB venues with an SDK).

  1. BuildPOST /v1/<p>/order/build. The backend SDK (@limitless-exchange/sdk, @predictdotfun/sdk, Opinion CLOB) computes the authoritative order (FOK/LIMIT amounts, salt, fee) and returns the unsigned order + EIP-712 domain/types. No order math runs in the browser.
  2. Approve (see below) and sign — the lib signs the Order typed data with viem (signTypedData). Bigints are rebuilt from the strings the backend returned.
  3. SubmitPOST /v1/<p>/order. The backend relays the signed order to the venue: Limitless under partner HMAC (ownerId/onBehalfOf = the user's profileId); Predict and Opinion under x-api-key.

Model B — backend-built transaction, client signs/sends

Used by Rain (AMM) and Kalshi/DFlow (Solana).

  • Rain: POST /v1/rain/trade/build returns contractAddress + txData (an unsigned EVM tx derived from a fresh quote and slippage-derived minShares). The lib approves the AMM, then sends the prepared tx (walletClient.sendTransaction with the returned to + data) on the market's chain.
  • Kalshi/DFlow: POST /v1/dflow/trade returns a base64 VersionedTransaction pre-built by DFlow's /order. The lib deserializes and either signAndSendTransaction (normal) or signs without sending (sponsored — see Gasless).

Model C — client-built order, client signs/sends

Used by Polymarket and Overtime V2 — the venue SDK/contract is called directly from the browser, so even construction happens on the user's IP.

  • Polymarket: @polymarket/clob-client-v2 in the browser; createAndPostMarketOrder(... FOK) posts straight to the Polymarket CLOB. Never proxied server-side.
  • Overtime V2: writeContract against SportsAMMV2.trade() on Optimism with the assembled TradeData tuple, expected quote, slippage, and referrer.

Approvals

EVM venues require ERC-20 / ERC-1155 approvals before a trade; the libs check allowance and approve-max once:

PlatformBUY approvesSELL approvesCollateral
PolymarketUSDC.e → CTF/exchange (collateral allowance)conditional tokensUSDC.e (Polygon)
LimitlessUSDC → exchangeCTF setApprovalForAll → exchange (+ adapter)USDC (Base, 6dp)
Predict.funUSDT → exchangeCTF setApprovalForAll → exchange (+ neg-risk adapter)USDT (BSC, 18dp)
Raincollateral → AMM (to)per-chain USDC (BNB → USDT)
Overtime V2USDC → SportsAMMV2USDC (Optimism, 6dp)
Kalshi/DFlow(handled inside the DFlow tx; ATA/rent can be sponsored)USDC / CASH (6dp)

Solana (Kalshi/DFlow) has no ERC-style approval; associated-token-account creation and rent are part of the DFlow tx and can be sponsored.

Redemption

Winning positions are redeemed on-chain from the user's own wallet (no MAGMA creds), valid only after settlement:

  • Polymarket — CTF redeemPositions(collateral, parentCollectionId, conditionId, [1,2]); neg-risk markets use the NegRiskAdapter redeemPositions(conditionId, amounts).
  • Limitless — CTF redeemPositions(collateral, ZERO_HASH, conditionId, [1,2]) (valid once payoutDenominator(conditionId) != 0).
  • Predict.fun — standard CTF redeem, or family-aware neg-risk-adapter / yield-bearing redeem (the lib picks the right contract from isNegRisk / isYieldBearing).
  • Kalshi/DFlow — redeem is a regular sell of the winning outcome mint back to settlement via /order once redemptionStatus is open (no special flag, no KYC); POST /v1/dflow/redeem.
  • Rain / Opinion / Overtime — settlement/redemption follow the venue's own model; positions are surfaced read-only via the proxy.

Fee & referral capture

MAGMA captures revenue per platform without custodying funds:

  • Kalshi/DFlow — a builder fee (platformFeeBps, default 20 = 0.2%) is attached to the DFlow /order only when a feeAccount (MAGMA-owned USDC ATA) is configured. Declaring a fee with no account collects nothing and worsens slippage, so it is skipped otherwise.
  • Predict.fun — a one-time referral enrolment sets MAGMA as the user's referrer (PREDICT_FUN_REFERRAL_CODE), giving MAGMA a fee share on the user's trades. Done via /auth-messagepersonal_sign/referral, gated by localStorage, non-blocking to the trade.
  • Limitless — orders are placed under MAGMA's partner account (HMAC); the partner relationship is the revenue mechanism. The order is signed with the profile's real feeRateBps.
  • Polymarket — optional BUILDER_CODE attribution on each order.
  • Overtime V2 — the configured referrer address is passed into SportsAMMV2.trade().

DFlow supports gasless Kalshi trades so users with no SOL (especially embedded wallets) can trade — MAGMA's sponsor wallet pays the tx fee + ATA/rent. It is off unless DFLOW_SPONSOR_ENABLED=true and a sponsor secret key is set.

Flow (sponsorExec):

  1. Backend builds the order with sponsor=<pubkey>&sponsorExec=true; the fee-payer is the sponsor, so the tx needs both user and sponsor signatures. The backend caches the message bytes of the issued order and returns a sponsorOrderId.
  2. The user signs without broadcasting (signTransactionOnly) and sends the signed tx to POST /v1/dflow/sponsor-submit with the orderId.
  3. The backend co-signs with the sponsor key and broadcasts — but only if the submitted tx's message bytes match a recently-issued order (anti blind-sign on the hot sponsor wallet).

Settlement / fill confirmation

  • Kalshi/DFlow — fills are async (continuous liquidity provision). Landing on-chain is not the fill; the lib polls GET /v1/dflow/order-status?signature= to terminal (closed/filled/expired/failed).
  • CLOB venues (Polymarket/Limitless/Predict/Opinion) — FOK orders return a fill result from the submit/relay call.
  • AMM / on-chain (Rain/Overtime) — the lib waitForTransactionReceipt on the sent tx.

See also