Changelog
What shipped across the sufwan-local-test platform and the @agg-build packages.
Weekly entries cover everything that shipped across the platform, including
API and data-pipeline work. Version entries are the published
@agg-build packages — those four are version-linked, so a release usually
bumps them together, and the tags show which ones shipped.
Subscribe via RSS.
2026-11-05 · v4.37.0
- sdk, hooks: Add optional
orderbookUrlso the orderbook channel can use a second socket, andorderbookLatencyto opt orderbook subscriptions into the realtime tier. With that URL set, orderbook liveness follows the orderbook socket and an orderbook-only subscription does not hold the primary socket open. - ui: The place-order panel no longer shows the
self_custody_app_feecustody warning. A partner fee that a self-custody wallet cannot pay is now waived and the trade fills without it, so the user has nothing to act on. - ui: Replace the placeholder Lighter monogram with its official brand-kit icon and theme-aware colors, and use official application artwork for image logos.
- ui: Show Lighter balances in the manage-balances modal with their venue label.
2026-11-04 · v4.36.1
- Withdrawals can pay out to HyperEVM (chain
999) inUSDCorUSDT(USD₮0).useWithdrawFlowoffers it as a network even though deposit addresses never list it (HyperEVM is a withdrawal destination only), and the UI shows its name, icon and explorer link.
2026-11-03 · v4.36.0
-
sdk:
listVenueEvents({ live: true })returns only sports events in play: open, with a sport, and agameStartTimewithin the last 6 hours. Pass the returned ids toGET /sports/livefor scores and game state. -
sdk:
getLeaderboardSeriesacceptsinterval: "hour"for one user's stats per hour over a timestamp window, and series points carry astarttimestamp.getLeaderboardtimestamp windows accept up to 20userIds. -
sdk: Document
bridge_shortfallas apartialFillReason: the bridge delivered less than quoted, so the order was downsized before submit. It replaces the previously documented but never emittedbridge_short. It replacesvenue_capacityon a downsized market order that endspartial_fill; a downsized order the venue filled in full still endsfilled.Market-order
partial_fills now also carryremainingSizeRaw(requested shares minus filled shares). It staysnullon afilledmarket order; limit orders keep reporting it as before. -
sdk: Retry explicitly unavailable WebSocket snapshots for active outcomes with bounded jittered backoff, without reconnecting healthy sockets. Limit recovery to three attempts per outcome and twenty outcomes per second per socket; cancel obsolete retries after snapshots, unsubscribe or disconnect.
-
hooks, ui: Refresh buy quotes as soon as the orderbook moves under them, instead of waiting for the next poll.
- Hooks:
useSmartRouteBookRefresh({ venueMarketOutcomeId, quote, refetch, isFetching, enabled?, minIntervalMs? })watches the outcome's live orderbook and callsrefetchwhen a level the quote depends on changes: on each venue the quote fills, the levels at or below the worst price it took there; on every other venue, the levels at or below the route's worst price. It refetches at most once every 2 seconds and only whileenabled, live updates are on and the page is visible. Pass it the values fromuseSmartRoute. The quote shown is always the server's, anduseSmartRoute's polling stays as the fallback. - UI: the place-order panel uses it for buy quotes while the panel is active and the user isn't editing or submitting.
- Hooks:
-
hooks: The wagmi wallet signer now checks which chain the wallet is on at signing time before switching chains for a typed-data request. A run of requests signed back to back can change chain in between, for example a Hyperliquid chainId-1 signature followed by a Polygon one. Previously the signer used the chain from the last render, skipped the switch, and the wallet refused the request ("Provided chainId … must match the active chainId …").
-
ui: Keep order progress moving forward: the "Submitting order" step now sits just before the fill, so setup and bridging show their own progress instead of resetting to the first step, and the step being waited on always shows a spinner.
2026-11-03 · v4.35.0
- Add
PromoBannerto@agg-build/ui/primitives: a full-width brand strip for the top of a page.textandhrefset the message and where it links (opens in a new tab).- Pass
onDismissto show a close button; the caller decides what dismissing means (for example, remembering it in storage).
2026-11-02 · v4.34.1
getLeaderboard()accepts ISO-8601 timestamps (with an offset) forfromandto, alongside UTC days. With the client's server-sideapiKeyand a single-user lookup it returns that user's row over[from, to)— for windows shorter than a UTC day — withrank: null.todefaults to now; at most 366 days. Without an API key issued for that app, a timestamp window returns 403.
2026-10-30 · v4.34.0
-
sdk:
listVenueEvents({ live: true })returns only sports events in play: open, with a sport, and agameStartTimewithin the last 6 hours. Pass the returned ids toGET /sports/livefor scores and game state. -
sdk: Document
bridge_shortfallas apartialFillReason: the bridge delivered less than quoted, so the order was downsized before submit. It replaces the previously documented but never emittedbridge_short. It replacesvenue_capacityon a downsized market order that endspartial_fill; a downsized order the venue filled in full still endsfilled.Market-order
partial_fills now also carryremainingSizeRaw(requested shares minus filled shares). It staysnullon afilledmarket order; limit orders keep reporting it as before. -
hooks: The wagmi wallet signer now checks which chain the wallet is on at signing time before switching chains for a typed-data request. A run of requests signed back to back can change chain in between, for example a Hyperliquid chainId-1 signature followed by a Polygon one. Previously the signer used the chain from the last render, skipped the switch, and the wallet refused the request ("Provided chainId … must match the active chainId …").
2026-10-29 · v4.33.0
-
sdk, hooks: Add the catalog feed: get new, changed and deleted events and markets pushed instead of polling the list endpoints.
client.watchCatalog({ since, venues?, entities?, matchedOnly?, onChange, onSynced?, onError?, onResyncRequired? })keeps your copy of the catalog in sync. It subscribes to the WebSocketcatalogchannel, catches up overGET /catalog/changeson start and after every reconnect, and callsonChangeonce per newer state of each event or market, with duplicates already removed. Savehandle.lastChangedAtand pass it back assinceto resume after a restart. If that point is more than 24 hours old,onResyncRequiredfires: re-list, then callhandle.resync(startOfReList). WithmatchedOnly: trueyou get only cross-venue matched entities, plus a final update when one you already received leaves its cluster or is deleted.client.getCatalogChanges({ since | cursor, limit?, venues?, entities? })for paging the REST endpoint directly. A position older than the 24-hour window throws anAggApiErrorwith coderesync_required(isCatalogResyncRequired(err)).AggWebSocket.subscribeCatalog(filter, cb, { onSubscribed?, onInterrupted? })for the raw live channel.- New types:
CatalogChange,CatalogEventSnapshot,CatalogMarketSnapshot,CatalogEntity,WsCatalogChangeand related types. - Hooks:
useCatalogFeed(options)wrapswatchCatalogand returns{ status, lastChangedAt, error, resync }.
-
sdk: Market outcomes now carry
winnerSource("venue"or"matched"), so you can tell a winner sufwan-local-test inferred (from matched markets on other venues, or from the moneyline for a soccer ±0.5 spread) apart from the venue's own result. It is on REST outcomes, the WebSocketmarket_resolvedframe andmarket.resolvedwebhook outcomes, and isnull(REST) or absent (WebSocket, webhook) whenwinneris null or predates this field.ProphetX names no winner when a market resolves, so sufwan-local-test fills one from agreeing matched markets about every 15 minutes. That
matchedwinner can change when ProphetX settles (for example a void after a tennis retirement), which flips the source tovenueand bumps the market'supdatedAt. The matched fill sends nomarket_resolvedevent or webhook, and the correction may or may not send one, so pollupdatedAtto catch both. Settle held ProphetX positions only onwinnerSource: "venue"orrefundAtCost: true. See Market resolution in the docs. -
sdk, ui:
custody=selfbalances: each chain row now carrieswalletAddress, the linked wallet the balance belongs to. A row for the wallet itself names that wallet. A row for its Polymarket deposit wallet or legacy wallet names the wallet that owns it.The "Trade from" and "Withdraw from" selectors now include a wallet's deposit wallet and legacy Safe in its balance. A legacy proxy, which can only be spent on Polymarket, is still left out.
-
sdk:
client.getWithdrawalQuote({ ..., signingAddress })quotes the Max a linked self-custody wallet can withdraw, using the same source rules the withdrawal itself applies, so a withdrawal of exactly that amount is always accepted.previewWithdrawalready acceptssigningAddressand now prices the withdrawal from that wallet. -
Self-custody withdrawals from wallets that cannot sign an EIP-7702 batch (e.g. MetaMask).
- SDK:
getWithdrawalQuote,withdrawPreviewandwithdrawManagedacceptapproveMode: "sponsored" | "user_broadcast"alongsidesigningAddress. Underuser_broadcastthe wallet is never asked for a transaction or gas: a same-chain native USDC withdrawal is two EIP-3009 signatures, and sources that would need an approval or a batch (e.g. USDT, USDC.e) are left out of Max, preview and the withdrawal. - Hooks:
useWithdrawFlowanduseWithdrawPreviewsend the wallet'sapproveMode(picked by the same rule as a fill, now exported asselfCustodyApproveMode(walletSigner, addresses)).useWithdrawPreviewno longer sendsmaxwith asigningAddress, which the server refused. - UI: place-order uses the shared
selfCustodyApproveModerule; behaviour unchanged.
- SDK:
-
sdk: Add self-custody withdrawals.
client.withdrawManaged({ ..., signingAddress })withdraws from a wallet linked to the account instead of the managed wallet. The response carriespendingSignaturesonce the withdrawal is waiting on that wallet.client.submitWithdrawalSignatures(withdrawalId, signatures)answers those requests (POST /execution/withdrawals/:withdrawalId/signatures) and returns the withdrawal's current status.- New type:
SubmitSignature.
-
sdk: Add
matchedAttoExecutionStatusOrder: set when the venue has matched an order whose fill still awaits the venue's confirmation (TipRun L2 approval, usually ~15s). It is a signal, not a fill;status,eventand the filled amounts change only once the fill is confirmed. -
sdk, hooks: The
searchoption ongetVenueEvents/getVenueMarketsand onuseVenueEvents/useVenueMarketsis deprecated. Useclient.search({ q, type: "events" | "markets" })for text search.searchkeeps working: it is a case-insensitive substring match on the event title (or the market question and its event title), now limited to rows the search index matches by word or typed prefix, so a fragment inside a word (for examplePIinGPI) no longer matches. -
sdk: Coalesce concurrent event-detail reads, bound their concurrency and queue, and delay subsequent reads after HTTP 429 according to Retry-After plus jitter. Abort subscribers independently and cancel obsolete reads when the authentication session changes. Existing request signatures and server errors are preserved; writes are never retried automatically.
-
sdk, hooks: Wake self-custody status polling when an authenticated signature-wait event arrives for the current order. Keep timed polling as recovery and coalesce notifications received during an outstanding status request.
-
hooks, ui:
AggWalletSignerhas a new optional member,canSignEip7702Authorization(address). Return true when yoursignRequestcan sign aneip7702_authorizationfor that wallet, for example when it wraps a local account or an embedded wallet's 7702 API.PlaceOrderthen fills self-custody orders insponsoredapprove mode when it returns true for the signing wallet and, on a buy, every funding wallet. Without the member, or when it returns false,PlaceOrderkeeps usinguser_broadcast, and a retry of a failed fill reuses the mode the first attempt was sent with. The bundled wagmi signer does not set it: a browser wallet cannot sign an EIP-7702 authorization, so it stays onuser_broadcast. -
hooks, ui: Add an opt-in self-custody option to the withdraw modal.
- New feature flag
features.enableSelfCustodyWithdraw(defaultfalse). When it is on,tradingCustodyallows self-custody, anAggWalletSignerProvideris present and the user has a linked EVM wallet,WithdrawModalshows a "Withdraw from" selector. The Agg balance stays the default; with the flag off nothing changes. - With a wallet selected, the modal's balance and Max come from
getWithdrawalQuote({ ..., signingAddress }), the most that wallet can withdraw, so Max is always accepted. It previews fees withsigningAddresslike the managed preview, sendssigningAddress(nevermax), and asks the wallet for each signature the withdrawal needs. A declined signature ends the flow and the withdrawal expires. - Hooks:
useWithdrawFlow({ ..., signingAddress }),useWithdrawPreview({ ..., signingAddress })anduseWithdrawalSignatures({ withdrawalId, signingAddress, pendingSignatures }).useSelfCustodySigningtakes an optionalsubmitso it can answer a withdrawal as well as a fill. WithdrawModalcontrolled props accept an optionalselfCustody(WithdrawSelfCustodyProps).
- New feature flag
-
hooks, ui: The withdraw modal's "Withdraw from" row for the selected wallet now shows what can be withdrawn to the chosen token and network. That is the same server Max the Max button fills in, so the two numbers match. Unselected wallets, and the "Trade from" selector, still show the total held.
useWithdrawFlowaddswithdrawFlow.withdrawable(self-custody only), andTradeFromSelecttakes an optionalselectedWalletUsd. -
hooks, ui: Add
ensureHyperliquidAgentFor(walletSigner, masterAddress, onApproving?): before a Hyperliquid self-custody fill, it throwsWalletNotConnectedErrornaming the master wallet when that wallet is not connected, and otherwise approves a Hyperliquid agent key in this browser when one is missing, expired or replaced. The positions-table quick sell now runs it before a Hyperliquid fill, as the order ticket already did, so a sell from an unconnected wallet no longer fails at signing with the agent's address. -
hooks:
useWithdrawFlow: a wallet (self-custody) Max now follows the server quote. Changing the destination chain, token or wallet after clicking Max updates the amount to the new Max instead of keeping the old one. -
hooks, ui: Keep midpoint request cleanup tied to the effect that issued the request.
Keep comparison chart selections stable when additional markets have cached prices before they load.
-
hooks, ui: Show "Matched on {venue}, confirming..." on the place-order fill step while a venue has matched the order but not yet confirmed the fill (
ExecutionStatusOrder.matchedAt, e.g. TipRun L2 approval). The step never says filled until the fill is confirmed. New label:trading.matchedConfirmingOnVenue. -
ui:
PlaceOrdernow refuses a Hyperliquid wallet trade before it is sent when the wallet holding the position is not connected, with aWalletNotConnectedErrornaming that wallet. Previously the order was parked against the account's Hyperliquid agent and failed at signing with the agent's address, which is not a wallet the user can connect. -
ui: Raise the minimum
@radix-ui/*versions so installs resolve@radix-ui/react-slot@1.5.0. Older Slot releases (1.2.x, pulled in by@radix-ui/react-dialog@1.1.15) build a new composed ref on every render, which can cause "Maximum update depth exceeded" crashes under React 19.
2026-10-27 · v4.32.0
-
sdk: Market outcomes now carry
winnerSource("venue"or"matched"), so you can tell a winner sufwan-local-test inferred (from matched markets on other venues, or from the moneyline for a soccer ±0.5 spread) apart from the venue's own result. It is on REST outcomes, the WebSocketmarket_resolvedframe andmarket.resolvedwebhook outcomes, and isnull(REST) or absent (WebSocket, webhook) whenwinneris null or predates this field.ProphetX names no winner when a market resolves, so sufwan-local-test fills one from agreeing matched markets about every 15 minutes. That
matchedwinner can change when ProphetX settles (for example a void after a tennis retirement), which flips the source tovenueand bumps the market'supdatedAt. The matched fill sends nomarket_resolvedevent or webhook, and the correction may or may not send one, so pollupdatedAtto catch both. Settle held ProphetX positions only onwinnerSource: "venue"orrefundAtCost: true. See Market resolution in the docs. -
sdk, hooks: The
searchoption ongetVenueEvents/getVenueMarketsand onuseVenueEvents/useVenueMarketsis deprecated. Useclient.search({ q, type: "events" | "markets" })for text search.searchkeeps working: it is a case-insensitive substring match on the event title (or the market question and its event title), now limited to rows the search index matches by word or typed prefix, so a fragment inside a word (for examplePIinGPI) no longer matches. -
hooks, ui:
AggWalletSignerhas a new optional member,canSignEip7702Authorization(address). Return true when yoursignRequestcan sign aneip7702_authorizationfor that wallet, for example when it wraps a local account or an embedded wallet's 7702 API.PlaceOrderthen fills self-custody orders insponsoredapprove mode when it returns true for the signing wallet and, on a buy, every funding wallet. Without the member, or when it returns false,PlaceOrderkeeps usinguser_broadcast, and a retry of a failed fill reuses the mode the first attempt was sent with. The bundled wagmi signer does not set it: a browser wallet cannot sign an EIP-7702 authorization, so it stays onuser_broadcast. -
hooks, ui: Add
ensureHyperliquidAgentFor(walletSigner, masterAddress, onApproving?): before a Hyperliquid self-custody fill, it throwsWalletNotConnectedErrornaming the master wallet when that wallet is not connected, and otherwise approves a Hyperliquid agent key in this browser when one is missing, expired or replaced. The positions-table quick sell now runs it before a Hyperliquid fill, as the order ticket already did, so a sell from an unconnected wallet no longer fails at signing with the agent's address. -
ui:
PlaceOrdernow refuses a Hyperliquid wallet trade before it is sent when the wallet holding the position is not connected, with aWalletNotConnectedErrornaming that wallet. Previously the order was parked against the account's Hyperliquid agent and failed at signing with the agent's address, which is not a wallet the user can connect.
2026-10-27 · v4.31.0
- Add
redeemSelfCustodyto redeem a resolved position held in a self-custody wallet. Limitless, Predict and Myriad prompt a transaction (the user pays gas); Polymarket prompts one typed-data signature.fillSelfCustodyandredeemSelfCustodyaccept a per-callsigner. Position legs carrysignerAddressfor self-custody holdings, andcomputeClosedPositionTotalsreturnssignerAddressByOutcome.useRedeem().mutateAsynctakes that map and redeems those outcomes from the wallet signer, one prompt at a time, and the rest throughclient.redeem. The Claim winnings button uses it, so self-custody winners can be claimed in the UI. - sdk: Add
finalizedAttofees.actual.appFeeon orders: the time the app fee stopped changing (collected in full, skipped, or no longer retried). It is absent, nevernull, while the fee may still change, so a$0under_collectedwithout it is still being retried. - sdk, hooks: Self-custody Hyperliquid buys funded from the deposit wallet now sign their app-fee pre-sign.
fillSelfCustodyanduseSelfCustodySigningheld that pre-sign until a Polymarket order signature (poly-sign-) was submitted, so on a Hyperliquid order (hl-sign-) it was never signed. The fee then fell to a prompt after the fill, which often went unsigned. The newisOrderSignatureStepexport recognises both order steps;isPolymarketOrderSignatureStepis unchanged. - sdk, hooks: Deprecate
includeDirectVenueMarketsonlistRecurringCryptoMarkets. The API now ignores it: every recurring crypto window is listed from sufwan-local-test's own market data before it opens, so the response is the same with or without it. The SDK still accepts and sends the option, and the recurring-markets hooks no longer set it. - hooks:
useMarketChartkeeps retrying a warming chart at the server's retry hint for up to about 30 seconds instead of giving up after 8 attempts, so a chart whose history is still filling renders as soon as the data lands instead of staying empty until the next refetch. - hooks, ui: Sports pages paint the first market page while later pages load, and price only the section on screen. Order books mount the rows around the spread. The first midpoint fetch for a visible set asks for every market that still has no price, and later polls ask only for cold books. Scrolling retries a midpoint request that was still in flight. The chart summary waits to load the deferred event description so that request does not compete with the first market and order-book reads.
- hooks, ui: Selling a self-custody position from the positions table now works. The quick-sell button quotes against the wallet that holds the position and fills through
fillSelfCustodywith theAggWalletSignerProvidersigner. Before, it always sent a managed sell and gotinsufficient_position. A row whose legs sit with different holders hides quick sell; sell it from the market page. AddssignerFor(walletSigner, address)to@agg-build/hooks, which connects the wallet if needed and returns the signer to pass as the SDK's per-callsigner.
2026-10-24 · v4.30.0
- Add
redeemSelfCustodyto redeem a resolved position held in a self-custody wallet. Limitless, Predict and Myriad prompt a transaction (the user pays gas); Polymarket prompts one typed-data signature.fillSelfCustodyandredeemSelfCustodyaccept a per-callsigner. Position legs carrysignerAddressfor self-custody holdings, andcomputeClosedPositionTotalsreturnssignerAddressByOutcome.useRedeem().mutateAsynctakes that map and redeems those outcomes from the wallet signer, one prompt at a time, and the rest throughclient.redeem. The Claim winnings button uses it, so self-custody winners can be claimed in the UI. - sdk: Add
finalizedAttofees.actual.appFeeon orders: the time the app fee stopped changing (collected in full, skipped, or no longer retried). It is absent, nevernull, while the fee may still change, so a$0under_collectedwithout it is still being retried. - hooks, ui: Selling a self-custody position from the positions table now works. The quick-sell button quotes against the wallet that holds the position and fills through
fillSelfCustodywith theAggWalletSignerProvidersigner. Before, it always sent a managed sell and gotinsufficient_position. A row whose legs sit with different holders hides quick sell; sell it from the market page. AddssignerFor(walletSigner, address)to@agg-build/hooks, which connects the wallet if needed and returns the signer to pass as the SDK's per-callsigner.
2026-10-23 · v4.29.1
- Deprecate
includeDirectVenueMarketsonlistRecurringCryptoMarkets. The API now ignores it: every recurring crypto window is listed from sufwan-local-test's own market data before it opens, so the response is the same with or without it. The SDK still accepts and sends the option, and the recurring-markets hooks no longer set it. - hooks:
useMarketChartkeeps retrying a warming chart at the server's retry hint for up to about 30 seconds instead of giving up after 8 attempts, so a chart whose history is still filling renders as soon as the data lands instead of staying empty until the next refetch.
2026-10-22 · v4.29.0
-
@agg-build/sdkexports the self-custody signing policyfillSelfCustodyuses (orderSignatureRound,signatureTimeoutMs,userSignerAddresses,isPostFillFeeRequest,areOrdersFilled,isOptionalFeeRequest,isPolymarketOrderSignatureStep,isSameWalletAddress,withTimeout).useSelfCustodySigningnow follows it too: it takes the fill'ssigningAddress, so an optional request the user's own wallet signs (a referral code) waits for the user instead of being dropped after 15 seconds, and withordersFilleda declined post-fill sell fee no longer reports a failed fill.PlaceOrderpasses both.@agg-build/hooksalso exportsisWalletUserRejection(error), the one check for a user declining a wallet prompt (EIP-1193 code 4001 or the usual wallet copy);@agg-build/authandPlaceOrderuse it. The open-order Cancel button is disabled, with the reason as its tooltip, on a Hyperliquid order placed from the user's own wallet, which can't be cancelled from this UI yet. -
Self-custody trading UI (off by default:
tradingCustodydefaults to"managed"). The SDK typesfundingAddresses, smart-routesigningAddress/fundingAddressesandcustodyWarnings, anddisconnectAccount(provider, { providerAccountId }). Hooks addfeatures.tradingCustody("managed"default,"both", or"self-custody"; any other value is"managed") withgetTradingCustodyMode/useTradingCustodyMode,features.enableMultiWalletAccountLink,AggWalletSignerProvider,useSelfCustodySigning,useLinkedWallets, and a@agg-build/hooks/self-custodyentry with a wagmi + Solana signer. The UI adds a "Trade from" selector and "Pay from" list to PlaceOrder, a wallet line in the order progress view, a wallet-only"self-custody"mode (no Agg balance option; a "Link an Ethereum wallet to trade" prompt when none is linked; Agg balance, Deposit and Withdraw hidden in the connect button and profile page), and wallet Disconnect plus "ETH wallet" / "SOL wallet" Connect rows in the Profile modal (mirrored as Link rows in the Trade from menu);requestLinkWalletOpen(chain)asks for a wallet on that chain. Auth addsWalletLinkBridge, which links the wallet through the same SIWE/SIWS flow as sign-in (auth methods acceptmode: "link"). SIWS now connects MetaMask's Solana wallet, which reports its account after connecting.Open-order rows now expose
signerAddress, and PlaceOrder signs cancels of wallet orders with that wallet. Wallet fills useapproveMode: "user_broadcast".useSelfCustodySigningskips a declined or unanswerable optional signature instead of failing the trade and holds an optional fee pre-sign until the Polymarket order signature is in, PlaceOrder keeps answering post-fill wallet requests (the exact sell fee) until the run is terminal, anduseExecutionProgressreturnsisTerminal. -
sdk: WebSocket hardening for trading and server-side use:
- Server-side clients authenticate the WebSocket handshake with their API key:
createAggClient({ apiKey, wsUrl })on Node 22+ sendsx-app-api-key, so backends no longer set anOrigin.AggWebSocketacceptswebSocketImplandheadersfor other runtimes. The key is never sent from a browser. - User events carry an
eventId. After a reconnect the SDK resumes from the last one, so fills, balance and withdrawal updates sent while the connection was down are replayed, with duplicates dropped. NewonResumedcallback:complete: falsemeans reconcile over REST. - New
subscribeAppEvents()streams every user event of the app to an API-key connection. - New
onAuthExpiring/onAuthExpiredcallbacks. Clients created byAggClientrefresh the token when the gateway warns, and re-authenticate the socket. - New
onStreamInterruptedcallback, plusconnection_rejectedandstream_interrupteddiagnostics. - A socket held only for user events now reconnects after a drop. Reconnect backoff is jittered. Configuration errors (close codes 4001 and 4003) are no longer retried until
connect()is called. Id lists are split into frames of at most 500. WsErrorcarries a machine-readablecode(WsErrorCode) and the affectedoutcomeIds.
- Server-side clients authenticate the WebSocket handshake with their API key:
-
sdk: Declare
@sinclair/typeboxas a dependency. Published SDK declarations now importStaticfrom TypeBox instead of bundling those types. -
sdk: Self-custody fills (signingAddress) now execute Limitless market orders; the wallet signs the order, a one-time registration, and broadcasts missing Limitless approvals on Base.
A wallet that already has its own Limitless account (made on limitless.exchange or through another app), or whose Limitless account is in smart-wallet trading mode, cannot be traded through a partner app. Self-custody quotes now route such wallets away from Limitless with a
self_custody_limitless_foreign_profileorself_custody_limitless_smart_walletwarning, and fills refuse them withquote_self_custody_limitless_foreign_profile/quote_self_custody_limitless_smart_walletbefore any funds move. -
sdk: Add
priceChange24hto venue market outcomes: the outcome's price change over the last 24 hours in absolute probability points (0.05= up 5 cents).nullmeans unknown, never zero. -
sdk: Self-custody fills (signingAddress) now execute Predict and Myriad market orders. Predict asks the wallet for a
personal_signauth message and the EIP-712 order, and has the wallet broadcast missing USDT and conditional-token approvals on BNB; its buy minimum is $1 notional. Myriad asks for the EIP-712 order and has the wallet broadcast missing USD1 and conditional-token approvals on BNB. A wallet that is EIP-7702 delegated on BNB is asked to sign a revocation of that delegation before the order is posted. Both venues are market fills only: self-custody limit orders are refused and positions not created through sufwan-local-test are not offered for sale. -
sdk:
fillSelfCustodyno longer throws when the user declines the exact post-fill sell-fee signature: the orders have already filled, so it returns the filled result and the fee stays uncollected. -
sdk: Docs: the self-custody recipe gains a Solana section. Link a Solana wallet with
provider: siws, name it infundingAddresses(EVM hex or base58 entries are both accepted), and handle thesolana_transactionsignature request in the signer: its payload carriesmessageBase64/transactionBase64; sign the unmodified message and return the hex-encoded 64-byte ed25519 signature. sufwan-local-test co-signs as fee payer, so the wallet needs no SOL. Novig and ProphetX clearinghouse self-custody orders are documented as not yet enabled (theirdirectbackend is unaffected). No SDK code changed. -
sdk: Self-custody fills (signingAddress) can now include Kalshi legs and Novig / ProphetX legs on the app's
directbackend. These legs trade on the user's own connected account and cash, so they ask the wallet for no signature, and a route that mixes them with wallet-signed venues no longer fails to start. Kalshi needs the user's stored Kalshi API key; without it the fill is refused withquote_insufficient_balance. Direct Novig / ProphetX settlement is credited to the account that placed the order, so a user holding both a managed and a self-custody position on the same outcome is paid once. Self-custody limit orders, and sells of positions sufwan-local-test did not create, stay refused for these venues. -
sdk: Self-custody fills (signingAddress) now execute TipRun market orders, buys and sells, funded from the wallet's Arbitrum USDC (bridged in when needed). A buy deposits only the shortfall into the wallet's TipRun account: cash already in that account is used first. TipRun account cash cannot be allocated as a separate funding source. The wallet signs an EIP-712
RegisterAccountonly when it has no TipRun account yet (an existing one is adopted), an EIP-712Permitfor each buy that deposits, and the EIP-712LimitOrder. TipRun self-custody limit orders and withdrawals are not supported; withdraw in TipRun's own app.A wallet that owns more than one TipRun account cannot be traded: self-custody quotes route it away from TipRun with a
self_custody_tiprun_ambiguous_accountwarning, and fills refuse it withquote_self_custody_tiprun_ambiguous_accountbefore any funds move. -
sdk, hooks: The signed-in trade socket stays open through quoting, so a fill is not missed while the browser is still connecting. Sending an order reuses that socket and only confirms the user stream when that confirmation has not already been sent.
-
sdk:
WsTradeframes carry an optionaltradeId, the venue's own id for the fill (Hyperliquid today), so clients can drop duplicate trades reliably. -
hooks, ui: Self-custody Hyperliquid trades now work from browser wallets such as MetaMask. Hyperliquid order signatures use chainId 1337, which browser wallets refuse to sign. Before the first Hyperliquid fill or limit order from a wallet, the wallet signs a one-time Hyperliquid
approveAgenton its active chain. That creates an agent key namedagg, valid for 90 days and stored in the browser's localStorage. The agent key then signs Hyperliquid orders locally, with no wallet prompt. It can trade the account but cannot move funds.useWagmiSolanaWalletSignertakes a newhyperliquidNetworkoption ("mainnet"by default), andAggWalletSignergains optionalcanSignAsandensureHyperliquidAgentmembers. The trade's execution line shows "Enable trading on Hyperliquid (one-time signature)" while the approval is open. The API uses the agent only whenHL_AGENT_SIGNING_ENABLEDis on. -
hooks: Chart history retries for a range the server reported as warming go straight to
/charts/barsinstead of re-reading the history manifest first, saving one round-trip before a cold chart range appears. -
hooks, ui: Event and market views keep a single orderbook socket for each visible market.
useMarketOrderbook({ live: false })reads a parent-owned book and still REST-seeds it, without opening another subscription. Homepage event cards compare only their own midpoint rows. -
hooks: Keep execution status reconciliation running when polling inputs change during an outstanding request, so completed trades can reach their final UI state after missed WebSocket events.
-
hooks: The demo starts the default homepage event list from its inline preload.
useVenueEventsuses that response when the query string matches, and sends the normal request for every other query. -
hooks: Preserve market traversal order when batching midpoint requests while keeping canonical query cache keys.
-
hooks, ui: Use order WebSocket frames as the fast path for Place Order confirmation, and keep status polling as the reconcile path. A submitted order's confirmation now survives navigation: Place Order restores it when its event is opened again (including after a reload in the same tab), and orders left mid-fill are polled in the background so their fill or failure toast still arrives.
-
hooks, ui: Open positions have a Sell button. It sells the position, and a toast reports when the order fills or when the sell cannot be submitted.
-
hooks, ui: Avoid fetching child categories for unrelated homepage tabs, share top-level category requests, and cache category results for five minutes across navigation, including empty responses.
-
ui: Probability charts fit the value axis to the data, draw evenly spaced lines that hold the last price, label each line's end with its name and price, and mark every line under the crosshair while dimming the time after it.
LineChartSeriesgains an optionalendLabel.The event chart opens on the lines a reader expects first: the Yes side of each market, and the moneyline on sports events. No sides, spreads, totals and further markets stay listed and turn on from their pills; up to four markets are listed. Live lines end on the live price, every event chart opens on ALL, and ProphetX and Novig (no price history) no longer appear in charts.
-
ui: Left-align the BETDEX balance line under the order balance so it lines up with the "Trade from" balance row.
-
ui: Line charts start at the beginning of the selected range: before a market's first price the line is drawn flat at that price, as Kalshi does, instead of leaving the start of the chart empty.
-
ui: Collapsed event cards request live prices only for the two outcome rows that are visible, plus those markets' matched siblings. Scrolling that card loads prices for the remaining embedded markets.
-
ui: Event chart lines follow the API's market order (by chance on multi-option events) instead of re-ranking by volume.
-
ui: Event detail charts open on the 24H (1D) range instead of ALL. Resolved events still open on ALL, since their last 24 hours have nothing to show.
-
ui: The event chart picks its markets by the page's live prices instead of the API's stored order, ranking once per venue so lines do not swap as prices move.
EventMarketsCharttakes an optionalpricesmap of each outcome's own venue price, ornullwhile those load (no lines are drawn until then). The chart's hover tooltip, shown when more than four lines are on, now follows the crosshair instead of sitting fixed in the corner. -
ui: Name venue setup for the venue on a bridged order, and label a buy's potential return "To win" instead of "Payout".
-
ui: Preserve quarter-line precision in sports line selectors and signed spread outcome labels.
-
ui: With event discovery URL persistence on, the home page no longer waits for
GET /categoriesbefore rendering its first event list when the URL names no category or subcategory. The default "all" tab is known up front, so the first titles paint as soon as the list arrives. -
ui: Switching markets reuses the image the event page already decoded, so the order ticket updates without a loading flash. A position opens that market on the sell side for the full size. Profile tabs stay in view while the position rows scroll. A subcategory click highlights that row before the homepage re-renders the event list.
-
ui: Order book depth bars animate with
transform: scaleXinstead ofwidth, so live book updates no longer re-lay out every row. The bars look and animate the same. -
ui: Keep market quotes and submission tied to the current buy/sell amount while input debouncing settles, and skip buy previews below the existing UI minimum.
-
ui: Smoother event list scrolling and search results fixes:
- Event cards keep their lazy-market placeholder row still until a page of markets is actually loading, and the event list's pagination skeleton tiles stay still until the next page is fetching. Idle infinite pulses forced a main-thread layerize every frame and capped list scrolling at 60fps.
- Order book rows only re-render when a level's price, size, total, venues or depth bar changed, instead of re-rendering the whole depth on every live update.
- Full search results now use the scrollable venue strip, so the venue filters no longer overflow the header, and the category tabs stay visible so results can be filtered by category.
2026-10-20 · v4.28.2
- Add
priceChange24hto venue market outcomes: the outcome's price change over the last 24 hours in absolute probability points (0.05= up 5 cents).nullmeans unknown, never zero.
2026-10-17 · v4.28.1
useRecurringCryptoMarketsnow loads a live recurring market's timeline in one request: the timeline query is bounded to the windows the pills render (two back, four ahead), and the viewed window is found inside it instead of by a separate lookup.
2026-10-16 · v4.28.0
- sdk, hooks, ui: Search: the
deepoption onsearch()/useSearchis deprecated and no longer requests the server-side reranker.useMarketSearchsubmits and the home page full results now run a normal full search. The option still type-checks, so existing code keeps compiling; it will be removed in a future major version. - sdk: Clarify effective fill-price reporting in order responses.
executionPriceis filled USD divided by received/sold shares, including fee effects already reflected in those quantities. Missing fill quantities producenullrather than a quoted-price fallback;quotedPriceRawremains the separate quote reference. - sdk: Keep active WebSockets authenticated when sessions refresh, and reset private event delivery safely when accounts change.
- sdk, hooks:
handleAuthCallback()now throwsAggIdentityExistsError(code: "identity_exists",existingMethod,attemptedMethod) when an app that refuses duplicate identities sends a sign-in back to the user's existing method.requestAggAuthChooserOpen()accepts an optional{ highlightMethod }.UserProfilegains optionalotherIdentities. - ui, auth: When an app refuses duplicate identities for a shared email, the sign-in chooser now reopens on the user's existing method with a short explanation, and after they sign in offers to add the method they first tried. The profile shows a notice when the user has another identity with the same email. Upgrade before enabling "Use existing sign-in for shared emails" in the admin dashboard.
- ui: User profile: resolved positions in the Closed tab are no longer hidden by the small-position share filter.
2026-10-15 · v4.27.7
- Venue-account balance rows from
getManagedBalancescarryregisteredByAgg:truewhen sufwan-local-test registered the TipRun account for the user,falsewhen sufwan-local-test reused an account the user already had.
2026-10-15 · v4.27.6
executeManagedaccepts an optionalexternalId, your own idempotency key for the trade. It is saved on every order the quote splits into and carried on eachtrades.filledwebhook, and reusing it on a different quote returns 409.getManagedBalances,getPositions,getExecutionOrders,getUserActivityandgetDepositAddressesaccept{ signal }to cancel the request. Execution orders carrycancelReason, and the event detail carriessettlementDiffStatus(computed,pendingornot_applicable) to explain anullsettlementDiff.
2026-10-15 · v4.27.5
getExecutionOrdersacceptsclientOrderIdto look up a limit order by the id you placed it with — for example, after a retry returns 409.TradesFilledEventnow carriesclientOrderId(a limit order's id,nullotherwise).
2026-10-14 · v4.27.4
- Keep active WebSockets authenticated when sessions refresh, and reset private event delivery safely when accounts change.
2026-10-14 · v4.27.3
- Document that
OrderbookState.marketIdholds the outcome id, not a venue market id, and deprecate it in favour ofoutcomeId. WebSocket orderbook frames are keyed by outcome and carry no market id, sosnapshotToOrderbooksetsmarketIdto the outcome id. The same applies touseAggOrderbook: itsmarketIdoption anddata.venueMarketIdhold the outcome id. Use the RESTvenueMarketIdor your own outcome → market mapping when you need the market. No behaviour change. - sdk: Document that
SmartRouteResponse.positionAvailabilityis returned on every sell quote,okincluded, not only oninsufficient_position, and that it is a snapshot rather than a reservation.
2026-10-14 · v4.27.2
- Document
executionPriceRawon order events as the fill's own price,filledAmountRaw / actualSharesRaw, rather than the quote. A sell's is net of fee; most venues report a buy's fee separately inactualVenueFeeRaw. On Hyperliquid thefilledevent still carries the quote; the realized price lands on the order shortly after.
2026-10-14 · v4.27.1
- Sports event pages no longer render regulation-only books as a second Moneyline card. A market whose question names a 60-minute regulation window ("Dallas Stars To Win (60 Min)", "Draw (60 Min)") settles a regulation tie differently from the overtime-inclusive moneyline, so
isBinarySportsMoneylineMarketnow rejects it. Its win/draw/win legs group into one "Regulation Time (3-Way)" card with a pill per leg.
2026-10-13 · v4.27.0
-
sdk: Expose optional accepted price bounds and orderbook freshness metadata on smart-route quotes.
-
sdk: Submit order signatures before optional Polymarket buy fee pre-signs, and bound the optional fee prompt so a rejection or unanswered signer cannot discard the order.
-
sdk: Wait up to 55 seconds (was 15) for an optional Polymarket buy fee pre-sign, so a slow wallet's approval is used instead of being discarded and asked for again after the fill. The order is never held by it.
-
sdk: Recognize the ProphetX venue-rate-limit code and venue in public error response types. Preserve retry hints without automatically replaying execution requests.
-
Modernize package builds with tsdown, preserve CJS/ESM exports, and share the SDK's public type contracts across hooks. Add opt-in React Compiler output with a React 18-compatible runtime while validating applications on React 19.
-
sdk: Do not sign an optional Polymarket buy fee pre-sign until the fill's order signatures are submitted. A fee prompt listed before the order prompt no longer stops polling and holds the order for up to 55 seconds.
-
sdk: Sign an optional Polymarket buy fee pre-sign only after the Polymarket order signature itself is submitted. An auth or setup signature posted before the order prompt exists no longer unlocks it, so it cannot hold the order for up to 55 seconds.
-
sdk: Withdrawal status sources can carry an optional
pendingReason(for exampleawaiting_venue_approval) while a venue-account source is submitted but not yet confirmed, so apps can show what the withdrawal is waiting on. -
hooks, ui: New opt-in
features.uncrossMergedOrderbookUI config flag (defaultfalse). When enabled, the merged cross-venue orderbook inMarketDetailsand the chart orderbook nets locked or crossed levels — one venue's bid at or above another venue's ask — the way a single matching engine would, so the same price never appears on both sides and the spread is never negative.mergeVenueOutcomeOrderbookstakes the matchinguncrossoption. Display only; quotes still route against the real venue books. -
hooks:
useSettlementDetailsDatascopes its selected-market lookup by the market's ownvenueEventId, so/venue-marketsreturns the market's description and rules again. The settlement panel showed no rules when the lookup was byexternalIdentifieralone. -
hooks, ui: Background smart-route polls no longer block the BUY button.
PlaceOrderused to swap the CTA for "Refreshing quotes…" on every poll; it now keeps the current quote usable and updates the route cards in place when the response changes. The CTA is still disabled while a quote for a new amount loads.useSmartRoutenow reportsloadingReason: "updating-route"when the previous amount's quote is shown as placeholder data. Before, it reported"refreshing-quotes"because TanStack Query v5 leavesisLoadingfalse in that case. -
ui: Pin only the highest-volume moneyline card on sports event pages; other moneyline-typed cards (e.g. a Tie leg) sort by total volume with the rest.
-
ui: Show the settled per-share price on resolved split-payout winners (for example a 50/50 tie paying 50¢) instead of a flat 100¢ in the profile positions list.
-
ui: Sort sports event market cards by total volume (every market in the card plus its matched cross-venue markets), keeping moneyline cards pinned on top, instead of a fixed moneyline → spread → total order.
-
ui: Always show the period heading on sports period tabs (Halves, Quarters, …), so a tab holding only one period still says which half or quarter its lines are for.
2026-10-06 · v4.26.1
- Show settlement differences under the event chart again when the event page loads from the bootstrap payload. The summary now loads the deferred event details itself instead of reading the empty bootstrap value.
useSettlementDetailsDataaccepts an omittedmarketfor event-only loads.
2026-10-05 · v4.26.0
-
sdk: Leaderboard by category, league and event, with win rate.
getLeaderboard()takescategoryIds(one category; a league is a category),venueEventIds(up to 5 events, merged across venues),userIds(up to 100 users) and now forwards the single-user lookups (userId,externalId,username,walletAddress). Rows gainwins,lossesandwinRate: wins and losses count settled position legs by the sign of their settlement P&L (a zero settlement, such as a void, is neither; a position sold before settlement counts toward P&L only), andwinRateis wins / (wins + losses),nullbefore any settlement.getLeaderboardSeries()takescategoryIds, makes the user optional (no user = the whole app's daily totals), and returnswins,losses,winRate,cumulativeWinRateper point plus rangetotals;userIdisnullfor an app-wide series.getPositions()/getExecutionPositions()takecategoryIdsandsort: "realizedPnl", and each position outcome carriesrealizedPnl. -
BatchOrderbooksResponsegains optionalsizeStepRawandminSizeRaw(6-decimal share units) next totickSizeon eachvenueOrderbooksentry, eachmatchedMarketsitem andrequestedMarket: Polymarket 0.01 share, Hyperliquid whole shares, PRED 0.001 share and TipRun 0.01 share, plus the market's minimum order size. Other venues omit both.useLimitOrderVenueQuotesnow returns each venue'ssizeStepRawandminSizeRawfrom that orderbook metadata, plusisMetadataPending, andresolveLimitOrderSizeRulesByVenueis exported.The
PlaceOrderlimit form takes its size step and minimum from the market's orderbook metadata instead of the per-venue quote, so they no longer depend on the entered amount or on a quote resolving. Submit on a venue with a size step waits only for that metadata to load. Venues with no step keep the same sizing as before. -
sdk, ui:
SmartRouteResponsegains optionalsizeStepRawandminSizeRaw(6-decimal share units). A quote restricted to one venue (allowedVenuesof length 1) returns that venue's limit-order size step and minimum: TipRun from the contract, Hyperliquid whole shares, PRED 0.001 share, and Polymarket 0.01 share plus the market minimum. Other venues omit both.The
PlaceOrderlimit form floors the order size to that step, so a dollar-based limit buy never spends more than you enter, marks a venue whose minimum the amount misses as unavailable so another venue is picked, and blocks submit when every venue is below its minimum. Venues with no step keep the same sizing as before. -
sdk: Add a per-outcome orderbook watchdog to
AggWebSocket. Sockets fromAggClient.createWebSocket()now check, once a minute, any subscribed book with no update for 5 minutes againstGET /orderbooks/outcomes. If the server'sseqmatches, the market is just quiet and nothing happens. If it differs, the SDK requests a resnapshot; if the next check still differs, it unsubscribes and resubscribes that outcome. A book whose snapshot never arrives, or whose recovery stalls, is retried the same way. Outcomes the server can't serve are counted as checked, so a large subscription set rotates through every book. Each check costs one market-data quota unit per silent outcome (at most 100 per call), is abandoned after 15 seconds, and pauses forRetry-Afteron a 429. New diagnostics:book_watchdog_resyncandbook_watchdog_error.On by default for
createWebSocket(). Pass{ bookWatchdog: false }to turn it off, or{ bookWatchdog: { silenceMs, checkIntervalMs } }to tune it. A directly constructedAggWebSocketenables it with the newbookWatchdogoption.AggWebSocket.authenticate(token)now also stores the token for reconnects, so a socket that reconnects after a token refresh authenticates as the user instead of dropping to app level with the old token. -
sdk, ui: Sell quotes report
estimatedNetProceeds, net of partner app and referral fees; the place-order proceeds use it. -
hooks, ui: Limit-order tick and size rules are now fetched for every venue's own market, not only the selected one, so matched venues such as TipRun round sizes to their own step.
2026-10-01 · v4.25.0
-
Add
referralActivationSponsorAddresstogetSmartRoute()andplaceOrder(). On a user-paid referral routed to a self-custody Hyperliquid buy, the named wallet pays Hyperliquid's one-time 1 USDC activation fee for a referrer that has never received anything on HyperCore. Before the fill yoursignerreceives an optionalhl_activation_sponsorrequest with that wallet assignerAddress; declining it never affects the trade. The quote'sreferralechoes it asactivationSponsorAddress.fillSelfCustody()now asks yoursignerfor required requests before optional ones and still submits everything in one batch. An optional request signed by a wallet other than the user's (e.g. a partner's activation sponsor) is bounded byOPTIONAL_SIGNATURE_TIMEOUT_MS(15 s, exported); after that it is declined and the required signatures go out without it, so a hung sponsor signer can delay the order's signature by at most that long. Optional requests the user's own wallet signs (such as anhl_referralprompt) are awaited as before.
2026-10-01 · v4.24.0
-
sdk: Add
getLeaderboardSeries()forGET /leaderboard/series: one user's leaderboard stats (orders, volume, spent, realized P&L) per UTC day over a range (default 30 days, max 366), with a running cumulative realized P&L, ready to chart. Look the user up by exactly one ofuserId,externalId,usernameorwalletAddress. P&L is gross of venue and app fees; unrealized P&L is not included. -
Add an opt-in
minVolumefilter.getVenueEvents,getVenueMarkets,getVenueEventByIdandgetEventBootstrapacceptminVolume(USD lifetime volume floor);useVenueEvents,useVenueMarkets,useVenueEventanduseEnrichedVenueEventforward it; setconfig.market.minVolumeonAggProviderto hide events and markets below the floor across the events list, event cards, the event page and the sports event page. Unset by default — no behavior change.useVenueMarkets' React Query key gains a trailingminVolumeslot (now 17 elements), anduseVenueEvent's key gains one too (now["venue-event", eventId, cluster, minVolume]); code that hand-builds either key forsetQueryData/getQueryDatamust append it. -
sdk: Add per-trade venue-specific fees:
appFeeBipsByVenueandreferrerFeeBipsByVenueongetSmartRouteandplaceOrder, with the per-venue rates reported on the quote's fee breakdown.
2026-10-01 · v4.23.0
- Add Novig Direct account connections, per-organization execution mode, and native-cash trading in the shared order ticket. Users connect a Novig v3 trading key for a funded subaccount; wallet and clearinghouse funds remain separate.
- ui: Show the shares a BETDEX runner holds when its market is folded under another venue's Yes/No market, so Sell works from that page. In Manage balances, venue badges wrap instead of overlapping the refill status when a network lists four venues.
- ui: List BETDEX with the other Solana venues in Manage balances, and drop its separate row from the Balance card.
2026-09-30 · v4.22.6
- Sports spread and combined-leg outcome pills now take their price and venue logo from the same cross-venue selector as every other market pill (live best price first, then REST), instead of a fixed REST midpoint paired with the anchor venue's logo. A spread pill could previously show a price no venue offered.
2026-09-30 · v4.22.5
- Sports spread/total cards rank lines by the volume of the whole matched cluster (every venue offering the line), not just the anchor venue's market, when choosing the default line.
2026-09-30 · v4.22.4
- Sports spread/total cards now open on the main line. Among lines priced within 30–70¢ the highest-volume one is the default; with none in that band, the line closest to 50/50 is. The card follows that default once live midpoints load, unless the user or URL already picked a line.
2026-09-30 · v4.22.3
- Order and fee types now carry field descriptions and exact value sets: order
statusis typed with every order status,fees.venueFeeBasis,fees.actual.appFee.statusandfees.actual.referral.statusare typed unions, and money fields document their units. No runtime behavior changes. - Clarify
redeemStatusand redeem legineligible: it now covers outcomes that lost, venues that settle on their own, and self-custody positions claimed on the venue. Documentation only; no runtime behavior changes.
2026-09-30 · v4.22.2
- Sports spread/total cards now open on the main line. When line volumes tie (most lines report zero volume), the rail defaults to the line priced closest to 50/50 instead of the lowest rung, and follows it once live midpoints load unless the user or URL already picked a line.
2026-09-29 · v4.22.1
WsResolvedOutcome(themarket_resolvedstream event) now carries optionalpayoutPerShareandrefundAtCost, so a voided or split market (e.g.payoutPerShare: 0.5on every side) can be told apart from a $1 win.
2026-09-29 · v4.22.0
- Add the
trades.fee_reconciledwebhook event type (TradesFeeReconciledEvent). It fires once per self-custody trade when the app fee reaches its final state, a few seconds aftertrades.filled, with the full fee breakdown and transaction hashes.
2026-09-29 · v4.21.2
SignatureRequestgainsoptional.fillSelfCustodynow skips an optional request (such as a Hyperliquid partner referral,purpose: "hl_referral") when your signer throws or it has expired, instead of failing the fill; required requests behave exactly as before.
2026-09-29 · v4.21.1
- Restore compact venue badges and outcome pills on event comparison charts. Show only the three highest-volume markets for the selected venue, keeping both Yes/No histories available and allowing each to be hidden independently. Remove the series pager and bound chart requests and live subscriptions to visible outcomes in those three markets.
- ui: Show a single-market 1X2 result (team / Draw / team) as the Moneyline card once it anchors the event's matched moneyline legs.
2026-09-28 · v4.21.0
-
Use Trading access for BETDEX configuration and the normal wallet transfer flow for funding. Show real venue prices in Smart Routing before funding. The Buy action prepares the user's owned account, journals an idempotent transfer, waits for native credit and obtains a fresh executable quote within the original spend and slippage.
-
hooks, ui: Replace the event list venue tabs with a logo strip. Matched · All stay as pills, then each venue is a 28px logo tile that names itself on hover and when active. Venues that do not fit the width the strip is given fold into a
+Nchip that lists the folded venues; the active venue always stays in the strip. On phones the strip spans the row and Matched · All shrink to glyph tiles. The strip is exported asEventListVenueStrip, and a deep-linked venue is no longer reset while/app/configis loading.Hooks adds the
eventList.moreVenuesAriaandeventList.moreVenuesListArialabels. -
ui: Submit executable BETDEX quotes through the normal managed order API. The server prepares any required wallet transfer or bridge, confirms credit in the user's owned account, and executes the accepted order; the Buy button no longer runs a separate client funding sequence.
2026-09-27 · v4.20.1
- Support self-custody post-fill fee authorization operations for HyperCore and Polymarket wallets, including user-paid referrals, while polling through fee completion.
2026-09-26 · v4.20.0
- Add
appFeeBipstogetSmartRouteandplaceOrder: a per-trade app fee (0–10000 bips) that replaces the app's configured rate. Honoured only on requests authenticated with an app API key.
2026-09-25 · v4.19.3
-
Outcomes now include
refundAtCost.When a venue voids a market and returns every holder their stake (ProphetX), both outcomes carry
winner: true,payoutPerShare: nullandrefundAtCost: true. The refund per share is the holder's own average entry price. CheckrefundAtCostbeforepayoutPerShareand thewinner ? 1/winnerCount : 0fallback. -
skipBalanceonplaceOrderno longer requiresskipQuote. WithoutskipQuoteit keeps the smart route but skips the quote-time balance refresh, so the route uses the last stored balances; the fund hold and balance check still run. Requires aread_writeAPI key.
2026-09-25 · v4.19.2
- Venue markets and their matched cross-venue siblings now include
volume24hr, the rolling 24-hour USD volume reported by each venue. A value of 0 can mean the venue does not report a 24h figure.
2026-09-25 · v4.19.1
- Use Trading access for BETDEX configuration and the normal wallet transfer flow for funding. Show real venue prices in Smart Routing before funding. The Buy action prepares the user's owned account, journals an idempotent transfer, waits for native credit and obtains a fresh executable quote within the original spend and slippage.
- ui: Submit executable BETDEX quotes through the normal managed order API. The server prepares any required wallet transfer or bridge, confirms credit in the user's owned account, and executes the accepted order; the Buy button no longer runs a separate client funding sequence.
2026-09-25 · v4.19.0
- sdk: Add
cancelVenueOrder()to cancel a Polymarket or Hyperliquid limit order a linked self-custody wallet placed outside sufwan-local-test.cancelManagedOrder()now callsPOST /execution/orders/cancel;POST /execution/orders/{orderId}/cancelis deprecated. - sdk: Add the
deposits.confirmedwebhook event type (DepositsConfirmedEvent) to the server-side webhook types. - Add the trader leaderboard
client.getLeaderboard(params?)callsGET /leaderboard: traders ranked by realized P&L or volume over an inclusive UTC day range, cursor-paginated,rankexact within the top 100.useLeaderboard({ period, metric, limit })wraps it with the1d | 7d | 30d | allpresets and flattens pages;leaderboardRange(period)is exported for custom UIs.LeaderboardPage(@agg-build/ui/pages) renders the board with period and rank-by controls, a highlighted "You" row, and identity fields gated by the app'sleaderboardIdentitysetting. Newlabels.leaderboardblock for copy overrides.
2026-09-24 · v4.18.2
- Show BETDEX prices, history and artwork: re-poll incomplete midpoint responses instead of caching them for the session, seed BETDEX outcome books on market cards, start the initial chart range at market creation when the start date is a future kickoff, explain missing BETDEX hosted cash instead of reporting no orderbooks, and show the venue mark when an event or market has no image.
- ui: Show existing pre-kickoff history and selected native outcome prices in sports pages, and use venue artwork for an image-less order ticket.
2026-09-24 · v4.18.1
- Add a BETDEX venue tab to the event list. Like other opt-in venues, it stays hidden for apps that disable BETDEX, and while app config is still loading.
- Show BETDEX and Tip Run in the default event venue selector when the app enables them.
2026-09-24 · v4.18.0
-
Add explicit BETDEX hosted-account setup, account status and venue-held USDC balances. Hosted balances remain separate from signing-wallet balances. The profile uses the existing labels and UI primitives, distinguishes sandbox funds, and disables custody in paper mode. BETDEX remains disabled by default.
Add owned BETDEX account activity to the API, SDK, hooks and expandable profile view. Exact signed ledger entries retain their native precision and distinguish credits, transfers, payouts, refunds and commissions. They are not presented as spendable cash, per-order fees or withdrawal-completion evidence.
Describe BETDEX's published fee as 1% of net market winnings and explain its settlement timing in quote previews. Actual per-order charges remain unknown until supported by authoritative settlement evidence.
-
Register and activate the BETDEX venue identifier, labels and native logo. BETDEX remains disabled by default for existing apps.
-
Add an optional native Worker browser adapter and framework-independent market-data engine. The demo runs the shared socket protocol, incremental orderbook checksums, candle accumulation, and chart history decoding off the main thread with bounded delivery. Hooks use per-outcome external stores, websocket-first snapshot selection and one abortable batch fallback. SDK browser, Node and React Native defaults remain compatible; browser-only APIs use the separate
@agg-build/sdk/browserentry point.Lean bootstrap settlement details load for the selected visible market only, with centralized loading/error/retry states and request cancellation.
Market-data reads now have scoped rate budgets and expose server retry hints through
AggApiError.retryAfterMs. Search and chart hooks honor those hints without adding automatic trading retries. Public API guides document the endpoint contracts, quotas and Worker lifecycle. -
Show a user's open limit orders on the event page. A new card between the event hero and the markets list lists every resting limit order on the markets on screen — the whole matched cross-venue cluster — with its limit price, live mark, fill progress, total and expiration, and cancels in place. The card is gated on the
showLimitOrdersfeature flag and hidden in paper mode, matching the trade panel and the profile, and states a failed order query instead of rendering as empty. AddseventMarketPage.openOrderslabels and anopenOrdersentry toEventMarketPageClassNames.getExecutionOrdersanduseExecutionOrdersacceptvenueMarketIdsto scope the order list to a set of venue markets. NewuseExecutionOrdersForMarketstakes any number of markets, batches them 75 per request to keep URLs short (asgetMidpointsdoes) and merges the results. The event page uses it, so the card loads with one request for nearly every event instead of one per open status. -
Support organization-configured ProphetX Direct accounts alongside clearinghouse execution. Add the ProphetX connection modal, isolated venue cash balances, execution-backend metadata, and cancellation events. Direct accounts use their own ProphetX funds and do not support funding transfers through sufwan-local-test.
Direct positions settle on ProphetX; native selling is not exposed by the current integration.
-
sdk, hooks:
getManagedBalancesanduseManagedBalancesacceptcustody: "self".It returns cash held by the wallets linked to the account — plus their Polymarket deposit and legacy Safe/proxy wallets — instead of the managed wallet. Each chain row then carries
addressandcustodyKind(EOA,DEPOSIT_WALLETorPOLYMARKET_LEGACY, withlegacyKindnaming the legacy shape). Omittingcustodyreturns exactly what it did before. -
Represent native venue collateral with
custodyKind: "VENUE_ACCOUNT"andsourceVenueAccountId/sourceExternalAccountIdon smart-route allocations, including solo quotes. Native IDs remain strings; these are account claims, not EVM addresses. Existing EOA and deposit-wallet allocation shapes remain compatible. The SDK also exposes the existing optionalsourceAddressfield.Execution previews do not show native TipRun cash as an on-chain bridge merely because another venue uses the same source chain. This contract change does not enable TipRun or publish/deploy a live integration.
Register Tip Run in the venue enum, official logo and consumer labels. Preserve native account identity/freshness on managed cash, positions and withdrawal responses, with a separate native-cash row in balance management. Quote refresh keys ignore observation-clock-only changes so balance polling does not abort an otherwise unchanged route. Existing EOA and other venue behavior is retained.
-
sdk: Self-custody fills that include a Kalshi leg are now admitted. Kalshi is funded from the user's own venue cash and signed with the user's own API key, so a mixed Polymarket + Kalshi route with
signingAddressno longer returnsquote_self_custody_unsupported_venue. A self-custody redeem-only fill on Kalshi now returnsquote_self_custody_redeem_unsupportedinstead ofquote_self_custody_unsupported_venue(both terminal).On apps that charge a partner fee (or user-paid referral), a Kalshi-only self-custody fill is still refused with
quote_self_custody_app_fee— there is no funding batch for the fee to ride; mixed routes with an EVM leg collect the whole-quote fee there and are fine. -
hooks, ui: Add owned BETDEX deposit and withdrawal controls, with exact USDC amounts, persistent withdrawal intents and status recovery after reload.
-
hooks, ui: Add a probability chart presentation with native historical samples, precise percentage labels, real aggregated orderbook liquidity, and optional multi-outcome overlays. Both sides keep independent histories and can be hidden through the chart legend.
Short recurring contracts use their own opening and closing times. Their live edges advance with the clock between quote updates and stop at close, without writing synthetic observations to the history cache. Existing streaming and candlestick presentations remain available, and partner applications can opt into the event overlay with
defaultChartView="all". -
hooks: Cancel obsolete event-list requests when filters change or the last consumer leaves. Avoid restoring pagination while disabled, another request is pending, or a page has failed, while preserving completed cached pages and shared consumers.
-
hooks, ui: Show BETDEX hosted cash in the trade panel, check route funding against the correct account, and open BETDEX account controls for native funding needs.
-
hooks, ui: Limit orders get the same submitting and success states as market orders: a progress view with a "
<venue>limit order" row while the order is sent, and a success view that shows the order amount at its limit price and the payout if it fills, with no "Better" line. Adds theorderAmount,orderLimitPrice,limitVenueOrder,limitOrderSubmittingandlimitOrderSubmittedtrading labels. -
hooks, ui: Serve 2x image variants to high-density screens so event and market thumbnails render sharp, falling back to the 1x variant for assets that do not have one yet.
-
hooks, ui: Keep visible market-card prices live within a bounded subscription budget, retaining selected and expanded cards when offscreen and releasing other subscriptions on viewport exit or cleanup. Preserve explicit parent-owned streams and standalone live-card behavior. Scope live selectors to the relevant market cluster.
Honor disabled market queries in eager pagination so a bootstrap-seeded progressive event does not silently fetch every remaining page. Add a 150-market Storybook state and public performance notes. Public hook signatures and REST/WebSocket contracts remain unchanged.
Bound the all-markets comparison chart to eight active outcome series with accessible pagination and a retained selection. Hidden and off-page lines release history observers and live subscriptions; usable series render while other series warm. Centralized labels and a 150-market comparison story document the controls.
-
ui: Event list design QA: 40px venue tab bar and sort select, skeleton tiles instead of dimmed results while filters refetch, venue and sort reset on category change, category folders that collapse when the path is controlled, and footer venue logos that reveal their colours on hover.
-
ui: Use BETDEX outcome titles in order-book headers and last-price labels while preserving native routing identities.
-
ui: Loading skeletons no longer blend together: the event hero's chart block is inset like the loaded plot (so it no longer fuses with the toolbar pills above it), and the order panel shows a skeleton block instead of a literal "$0" amount.
-
ui: Match loading skeletons to the components they stand in for (event tiles, event list header and sidebar, event hero, market rows, order panel, settlement, search results, profile positions) so content no longer shifts when it loads.
-
ui: Keep comparison chart legend widths stable while history loads, prices update, or series become hidden/unavailable. Reserve the configured status text width without adding it to accessible names, and keep long labels within narrow viewports.
2026-09-23 · v4.17.4
-
Add
totalCostIncFeestoVenueSoloQuoteEach single-venue quote now carries
totalCostIncFees: the router's total cost plus that venue's own app fee and user-paid referral fee — the same composition as the route'stotalCostIncFees.
2026-09-22 · v4.17.3
- Positions whose shares Agg has no purchase record for — bought directly on
Polymarket or Hyperliquid, or transferred in — no longer render a fabricated
entry price and profit. When the venue has no acquisition price we can
reconcile, the API marks the outcome
costBasisUnknownand the profile now shows "—" for entry price, amount traded and P&L instead of 0¢ and a 100% gain. Quantity and current value are known and still shown.
2026-09-21 · v4.17.2
-
Show the Kalshi balance as a row inside the profile Balance card instead of a separate card, and remove it from the header and profile menu. The
kalshiBalanceprop onAuthConnectButtonViewis removed, and the defaultuserProfile.balance.availableBalancelabel is now "Balance". -
hooks, ui: Reworked the Connect Kalshi modal to match the design. It now opens scrolled to its header (the API Key ID input is focused explicitly rather than racing Radix for it), renders the Kalshi logo at 60px on desktop and 40px inline with the title on mobile, and drops the non-interactive "Having trouble?" help links. Below
mdit lays out as a bottom sheet with left-aligned copy and a sticky Cancel / Verify Connection footer; the success confirmation uses the narrower 480px card with a tinted success mark and a secondary Done action.Modal.Containeraccepts anonOpenAutoFocushandler so a modal can place initial focus itself instead of competing with Radix's default. The now-unusedonboarding.connectKalshiModal.helplabels have been removed. -
hooks, ui: When the user has no Kalshi account connected, Smart Routing now selects the next best route instead of Kalshi, and the Kalshi route card shows a warning icon with "Requires Kalshi account". Kalshi stays selectable; choosing it still prompts the user to connect, and that button now reads "Connect Kalshi to trade".
-
hooks, ui: Show the side and the live price on open limit orders. The outcome pill now reads "Buy Yes" / "Sell Yes" instead of the bare outcome, and the limit price carries the current market price beneath it ("now 25¢"). The mark is matched at the outcome level from
GET /midpoints, so the two sides of one market show their own prices; an order whose outcome has no live book keeps the limit price alone rather than showing a guessed mark. -
ui: Honor the Closed bucket for resolved Kalshi winners and display their Won result on desktop and mobile rows.
-
ui: Settlement: list every cluster venue on each key difference and under Full rules by venue, drop differences whose venues all say the same thing, stop repeating the question in the body when the description restates it, hide the cross-venue differences section for single-venue clusters, and scope the venue-rule hover state to its toggle.
-
ui: Remove the average-price liquidity warning banner from the order panel while preserving regional restrictions, fee disclosures, and footer spacing.
2026-09-18 · v4.17.1
-
Ignore funding fields with
skipQuoteallowedSourceChainIdsandchainBalancesare now ignored whenskipQuoteis set, instead of returning 400. AskipQuoteorder is always funded on the venue's own chain.
2026-09-18 · v4.17.0
-
Support
PT30MandPT4Hrecurring crypto cadencesRecurringCryptoDurationnow includesPT30MandPT4Halongside the existingPT5M,PT15M,PT1H, andP1D. The API can now return recurring crypto up/down markets on these cadences (Hyperliquid sub-daily windows), and the SDK, hooks (slug/aggKey parsing, canonical window polling), and UI (recurring cadence labels) recognize them end to end.RECURRENCE_CADENCES— the cadence list behind therecurrencefilter onlistVenueEvents/useVenueEvents— gains the same two entries, so filtering venue events by them type-checks. -
sdk: Add
skipQuote,skipBalanceandpricetoPlaceOrderParamsPOST /execution/orderscan now skip the smart-route solver (skipQuote) and, on buys, the balance check (skipBalance) to send one order straight to predict or hyperliquid.pricesets the trade price for askipQuoteorder. These optional fields let a TypeScript partner pass them without a cast. -
sdk: Document
skipQuoteon novig and prophetxPlaceOrderBody.skipQuotenow lists novig and prophetx alongside predict and hyperliquid.priceis ignored on prophetx, which prices the order itself withinslipCapBps.
2026-09-16 · v4.16.0
-
Expose
minOrderSizeandtickSizeon venue marketsLimit orders are placed without a quote, so nothing validated size or price before the request.
GET /venue-markets(and the markets embedded in venue events) now carryminOrderSizeandtickSize.minOrderSizeis populated for Polymarket (the market's own floor, the exact valuePOST /execution/limit-ordersvalidatessizeRawagainst) and PRED (0.001). Elsewhere it isnull, which means no value was ingested — not that the market has no minimum; other venues enforce floors this field does not carry.Align
limitPriceRawto the runtime-inferredtickfrom the orderbook endpoints where one is available;tickSizeis the ingestion-time seed and the live grid can be finer.
2026-09-16 · v4.15.2
- Expose source-chain restrictions and per-chain funding budgets on direct order requests.
2026-09-15 · v4.15.1
-
Discovery outcomes now include
payoutPerShare.Events, markets, and outcomes responses return each outcome's settled per-share payout alongside
winner. It is set when a market pays more than one outcome — a Polymarket 50/50 pays 0.5 on each side, a Novig void refunds each side at its price — and isnullotherwise, in which casewinner ? 1/winnerCount : 0still applies.
2026-09-15 · v4.15.0
-
sdk:
placeLimitOrderacceptsfundingAddressesfor self-custody limit buys.Pass other wallets linked to the same account alongside
signingAddress. Their balances can fund the buy by bridging in, the same way a self-custody market fill funds from several wallets. On the venue's own chain only the signing wallet's balance is used. -
ui: Paper-mode and card interaction fixes.
PlaceOrderno longer asks a user to connect Kalshi when the app is in paper mode. Paper fills are simulated and never use venue keys, matching how the shared KYC prompt is already skipped for paper orders.EventListItemDetailsis only clickable when anonClickis passed. It previously always attached a click handler, so the event hero showed a pointer cursor with nothing to click.Cardonly lifts on hover (hover:shadow-agg-card-hover) when it is interactive (onClickorhref). Static cards keep their resting shadow.
2026-09-15 · v4.14.0
-
Add
labelandshowWhenAuthenticatedprops toPaperTradingBadge.labeloverrides the pill text for one placement (defaults tolabels.paperTrading.badge).showWhenAuthenticatedkeeps the mobilebrandpill visible for signed-in users, which is hidden by default because the full label does not fit beside the wallet chip. Both are optional; existing usage renders exactly as before.
2026-09-14 · v4.13.2
-
Group order book rows to the nearest 0.1¢.
Venues that quote finer than 0.1¢ (Hyperliquid, PRED, ProphetX) produced several order book rows that all displayed the same price, e.g. three "8.5¢" rows. Levels are now grouped to the nearest 0.1¢ — the precision the order book renders — with shares and venue breakdown summed into one row, including across venues.
Total still sums each level's real price × size, and spread and midpoint use the real best bid and ask. This is display-only: quotes and execution use the ungrouped venue books.
-
Show ProphetX and Novig in the profile modal's Trading access tab.
The tab lists venues from a fixed set that did not include ProphetX or Novig, so enabling either venue for an app never added its row. Both now appear alongside the other venues and follow the same app-config and geo-block rules.
2026-09-14 · v4.13.1
-
Type
client.verify()for Privy sign-in.client.verify({ kind: "privy", privyToken })already worked at runtime, butAggAuthVerifyBodyonly allowed{ message, signature }, so TypeScript callers got a compile error.AggAuthVerifyBodyis now a union matchingPOST /auth/verify:// wallet (SIWE / SIWS) — unchanged, `kind` may be omitted { message, signature, earlyAccessCode? } // privy { kind: "privy", privyToken, earlyAccessCode? }The two branches are also exported as
AggAuthWalletVerifyBodyandAggAuthPrivyVerifyBody. Existing wallet callers need no changes.
2026-09-14 · v4.13.0
-
Accept a Privy access token at
POST /auth/verify.Partner apps that use Privy as their wallet provider can let users sign in with a token minted by that same Privy app, alongside the existing OAuth, email, and wallet-signature methods. There is no separate Auth-tab setting: saving Privy under Settings → Wallet Provider turns it on.
VerifyBodybecomes a union discriminated onkind:// wallet — unchanged, and `kind` may be omitted { message, signature, earlyAccessCode? } // privy { kind: "privy", privyToken, earlyAccessCode? }Existing callers keep working. Every wallet caller predates the discriminator, so
kindis optional on that branch and existing payloads still validate. Code that readsbody.messageoff aVerifyBodyvalue without narrowing will need akindcheck.This extends the existing endpoint rather than adding a new one: how identity is proven is the only thing that differs between the two. Principal creation, the early-access gate, user creation, and token issuing are shared, so the branch lives in the auth strategy and the route is unchanged.
Privy auth stores no extra configuration: access tokens are ES256 JWTs verified against Privy's published public keys, using the Privy app ID from the wallet provider credentials. Every failure is a 401 with a message.
2026-09-14 · v4.12.0
-
Expose the linked signing wallet and signing quote ID for self-custody limit orders, and accept a fresh cancellation signature without changing existing managed-order calls.
Support Hyperliquid GTC/ALO self-custody limit buys and sells, with client-held EOA or agent signing and signed cancellation payloads.
2026-09-12 · v4.11.3
- sdk: Add
settlementFeeto smart-route buy fills and document thatestimatedPayoutis net of it.settlementFeeis what the venue takes from a leg's $1 payout if the outcome wins — today only Hyperliquid HIP-4's close fee — and is not a cost at fill. - ui: Show and rank net payout in the place-order panel: buy routes use estimated payout after settlement fees, and sell routes show proceeds after fill fees. Keep solo routes from distinct outcomes on the same venue visible.
2026-09-11 · v4.11.2
- Document
SmartRouteBridgeStep.amountandSmartRouteBridgeStep.cost.costis the delivery margin sent on top of the route's allocations, not the expected bridge fee — readfeeBreakdown.bridgeFeesfor that.
2026-09-10 · v4.11.1
- Fee breakdown: fold the builder fee into the Venue row instead of listing it separately, and render a partner's non-zero app fee as a dollar amount on the agg.market row. The 0% fee badge and the 0% platform fees trust line now appear only when the app fee really is zero, and the app fee is counted in the estimated-fees total.
2026-09-10 · v4.11.0
- sdk, hooks: Remove the
categoryIdsfilter fromgetVenueMarkets/useVenueMarkets. Category is an event-level attribute, so filtering markets by it was slow on large categories and is better expressed as an event filter. Filter events by category instead —getVenueEvents({ categoryIds, status })— then fetch that event's markets withgetVenueMarkets({ venueEventId }). - Report the builder fee as its own line in the quote fee breakdown. It was previously folded into venueFees, which labelled a partner's own charge as the venue's. Fee totals are unchanged; the builder slice is now visible separately on the route breakdown, on each per-venue breakdown, and on every fill. Also surfaces the partner app fee on quotes that are not executable and on per-venue quotes, where it was reserved from the budget but never reported.
2026-09-10 · v4.10.0
-
Add PRED (
pred.app) as the distinctpredvenue across SDK request and response types. PRED is unrelated to Predict.fun (predict) and settles through a per-user Safe on Base.PRED custody uses the existing
custodyKind: "DEPOSIT_WALLET"discriminator, qualified byvenue: "pred"and its custody address. Existing venues' source shapes remain unchanged. Hooks and UI add the corresponding PRED labels, filters and logo.PRED is default-hidden for existing and newly created apps until an app explicitly removes
predfrom itsdisabledVenueslist.
2026-09-09 · v4.9.2
- Use Clearinghouse executable prices and normalized amounts on ProphetX tickets. Preserve the reviewed spend and output limits during refresh, and show quote failures before order execution starts.
2026-09-08 · v4.9.1
- Verify that ProphetX fixed-input quotes show no execution-reserve amount or held-funds tooltip. ProphetX quote sizing uses the available book without a speculative commission or slippage reserve; other venues retain their existing behavior.
2026-09-08 · v4.9.0
-
sdk, hooks: App config is now cached per App and refreshed on a bounded schedule.
AggClientexposes a publicappIdgetter, anduseAppConfig/useCachedAppConfigkey their React Query entry as["agg", "app-config", appId]instead of the previously global["agg", "app-config"]. Two clients for different Apps sharing oneQueryClientno longer read each other's config — which matters now that the response carries the app-leveltradingModethat every execution surface renders from. Admin-key-only clients get a"__no-app__"scope. Use the exportedappConfigQueryKey(appId)to seed or invalidate the entry yourself.The query keeps its existing 5-minute
staleTimeand adds a matchingrefetchInterval, so a tab left open on one screen still picks up an App being flipped between paper and live instead of needing a reload. Nothing else about its refresh behaviour changes:refetchOnWindowFocusandrefetchOnReconnectare left at the hostQueryClient's settings rather than forced.The interval is skipped entirely while a tab is unfocused, so a background tab costs nothing. A stale
tradingModeis cosmetic in any case — the API resolves mode from the App on every request, so a client holding the old value renders the wrong chrome but cannot execute in the wrong mode. -
Integrate shared clearinghouse KYC for Novig and ProphetX using authoritative wallet status, skip repeat verification for approved wallets, and remove the Kalshi v2 KYC prompt while retaining account connection. Add user-scoped status queries, pending-decision handling, and protection against duplicate or stale verification actions.
-
Separate clearing-house execution reserves from estimated quote fees. Preview-only slippage tolerance no longer inflates Novig or ProphetX funding reserves; actual execution reserves and spend-cap checks remain enforced. Quotes expose an optional executionReserve amount and the trading panel explains it separately from fees.
-
sdk: Mark ProphetX as an active, Solana-settled venue. It stays disabled by default per app until the app explicitly enables it.
-
hooks: Keep live managed balance queries refreshed every five seconds while the page is visible. This lets the shared provider and balance hook recover when a fill notification arrives before the settled balance snapshot. Existing post-trade invalidation remains immediate; paper balances retain their event-driven behavior.
-
hooks, ui: Keep temporarily unavailable venue quotes visible as disabled comparison cards, including ProphetX when clearing-house readiness fails. Preserve available price previews and support a customizable availability label.
-
ui: Paper trading UI, gated so live apps render exactly as they do today.
An app is paper or live at the App level (
tradingModeonGET /app/config), and the components resolve it throughuseResolvedExecutionModefrom@agg-build/hooks. In a paper app the library now renders a "Paper trading" header pill, a three-step onboarding modal, and Buying Power / Earnings cards on the profile, and it hides the surfaces that have no paper equivalent — deposit, withdraw, venue cash balances, and the Limit order tab.Nothing here changes how a live app renders. Every layout change this feature needed is behind the paper branch, including the ones that would otherwise have been global:
Headerkeeps its 24px mobile inset and no brand-group gap unless abrandAccessoryis supplied.- The sign-in button keeps the
largepreset at every breakpoint; the tighter 79x28 mobile size is paper-only, and the signed-out control is no longer wrapped in an extra flex box. - The profile summary grid keeps its
1fr / 300–420pxcolumns and 32px gap; the wider 626px column is paper-only. - Profile summary cards keep 20px padding and wrapping labels; the compact 16px padding and single-line label are paper-only.
- A card that supplies no
captionrenders its value exactly as before, with no extra row wrapper.
Headergains an optionalbrandAccessoryslot, rendered after the logo inside the brand group. Supplying it also opts that header into the brand-group gap and the 16px mobile inset the accessory layout is drawn against — so pass it conditionally rather than handing it a child that hides itself, since the header cannot see that the element it was given renderednull.Modal.Containergains acenterclass slot for overriding the default bottom-sheet positioning belowmd.
2026-09-06 · v4.8.1
fillSelfCustodynow follows thepollAfterMsthe server sends on each/execution/statusresponse instead of sleeping a fixed 2s, and takes a short first poll rather than burning a full interval before its first read. The API asks for 1s today, so a pending signature request is found in roughly half the time.SELF_CUSTODY_POLL_INTERVAL_MSis unchanged and is still the fallback when the server does not send the field. Server values are clamped to 250ms–30s.- Add
venueMarketOutcomeIdtoVenueSoloQuote. A venue can list the same matched outcome more than once (two Hyperliquid deployers on one game), sovenuealone does not identify a solo card. Key onvenueplusvenueMarketOutcomeIdwhen tracking a selected route.
2026-09-03 · v4.8.0
- Self-custody fills can now be funded from a legacy Polymarket Safe — the Gnosis Safe
Polymarket deployed for a user before they joined this platform — at any venue, not just
Polymarket. Nothing changes for wallets that never had one.
SignatureRequestTypegains"safe_tx". The payload is the Safe transaction as EIP-712 typed data, but the wallet mustpersonal_signthe RAW 32 bytes ofhashTypedData(payload)(viem:signMessage({ message: { raw: hash } }); MetaMask:personal_signwith the hex hash). The wallet shows a hash rather than a structured prompt — that is the only shape Polymarket's relayer accepts, so a plainsignTypedDataover the same struct is rejected.payload.safeTxHashcarries the digest for convenience; the server recomputes it and never trusts the copy. As with every request type, throwing from your signer is not a rejection: the request expires and the fill fails.SmartRouteAllocation.custodyKindgains"POLYMARKET_LEGACY", withcustodyAddressset to the Safe. Signers that switch oncustodyKindshould treat it as a source the user does not hold directly.
2026-09-02 · v4.7.4
-
sdk: Correct what
approveModesays about cost.The previous
sponsoreddocblock described only the one-time ERC-20 approve and could be read as saying bridging has no cost. It does: the bridge fee is deducted from the amount delivered on every bridge, and one-time costs such as a Hyperliquid first-deposit activation still apply.The wording now describes what each mode does to the wallet — whether it is asked for gas — without implying anything about the total cost of a bridge, and points at
feeBreakdown.bridgeFeesandfeeBreakdown.setupCostson adeepEstimatequote as the figures to actually read. Documentation only; no behaviour changes. -
sdk, ui: Surface Hyperliquid's one-time address activation fee as a setup cost.
Hyperliquid charges 1 USDC to activate an address on its first deposit. Deep-estimate quotes (
deepEstimate=true) now carry it as afeeBreakdown.setupCostsline withkind: "hyperliquidActivation",alreadyPaid: trueonce the address exists on Hyperliquid, and it counts towardsetupCostsTotalandtotalCost. The fee is deducted inside the bridge leg rather than run as its own step, so the execution progress view does not render a setup step for it. -
sdk, hooks: Fix two EIP-4361 conformance bugs that made SIWE sign-in fail with a misleading
Invalid SIWE signature401.buildSiweMessagenow keeps the empty statement slot when no statement is given. The ABNF isaddress LF LF [statement] LF LF, so omitting the blank line produced a message no conforming parser accepts.buildSiweMessagenow applies the EIP-55 checksum itself, in any input casing, instead of building a message the server rejects before it ever checks the signature. wagmi users were unaffected because its connectors already normalise; partners bringing their own wallet were not. The SDK stays dependency-free: it carries a self-contained Keccak-256 for this (toChecksumAddressis exported for partners who want it directly).
2026-09-02 · v4.7.3
-
Add ProphetX to the Venue enum. Discovery only for now, so the venue is in
INACTIVE_VENUESand hidden by default; it renders with the neutral venue icon until brand artwork lands.Add ProphetX to the event list venue tabs. The tab follows the same per-app gate as every other venue, so it is hidden for any app whose
/app/configlists prophetx indisabledVenues. -
ui: Fix duplicate cards on the sports market detail page.
- Group decomposed N-way legs (halftime result, second-half result, first to score, NRFI) into one card with a pill per leg instead of one card per leg, unioning the venues that offer each leg. A bucket that cannot render as a decomposition splits back to one card per market, so no market is ever hidden.
- Collapse whole-number line rungs onto the same ladder as half-step ones. The aggKey encoder writes 8.5 as 8p5 but 8 as a bare integer, so integer rungs used to strand themselves in their own card.
- Parse the signed leg token in a spread aggKey. Spread keys now carry m/p on the line, so the previous pattern matched nothing and the signed ladder axis was inert, collapsing both halves of a symmetric spread onto one stop.
- Read the favoured and underdog roles off that leg token rather than assuming outcome 0 is always the favourite, which mislabelled every underdog-leg rung.
- Head each period section when a tab spans more than one period, so two cards that share a title are distinguishable.
-
ui: Render a sports line ladder as a ladder, never one pill per rung.
Every rung of a line ladder is its own Yes/No market with its own question, which by shape alone is indistinguishable from a decomposed N-way leg. A seven-rung team total therefore rendered seven pills on top of the rail that already selects between them. A leg is an outcome of one question and a rung is a line of one market, so a group carrying any lineValue now renders as a ladder and its pills are the active rung's two outcomes.
2026-09-01 · v4.7.2
- Fix limit-order sells on matched (multi-venue) markets.
- The sell venue picker no longer offers venues the user holds no shares on. The automatic pick sorts on price alone, so on a matched cluster it could choose a venue with no position — the API then rejected the order with "Insufficient available position size".
- The "max shares" figure now matches positions across the whole matched cluster
instead of only the selected venue market. Limit mode has no smart-route quote
to fall back on, so a position held on another venue of the cluster read as
0 shares.
2026-09-01 · v4.7.1
- Hide default-disabled venues (Novig today) in the event list tabs while
/app/configis loading, so a partner-opt-in venue no longer flashes in and out for apps that disable it.
2026-08-31 · v4.7.0
- Market lists for an event now cover its whole matched cluster by default.
-
getVenueMarkets({ venueEventId })anduseVenueMarkets({ venueEventId })return every venue's markets for that real-world event, not just the markets belonging to the one event you named. Matched siblings are folded into a single anchor row rather than repeated, and each row still carries its cross-venue counterparts inmatchedVenueMarkets[]. Naming any member of a cluster returns the same page in the same order, so you no longer need to know which event id is the anchor.This is the only way to reach markets that trade on a single venue and therefore have no cross-venue counterpart — previously they were unreachable unless you happened to ask for the exact event that carried them.
-
New
clusteroption on both, plusgetVenueEventByIdanduseVenueEvent. Passcluster: falsefor the previous behaviour: only the named event's own markets. If you render a market list from an event'sidand rely on it matching that one venue's markets exactly, passcluster: falseto keep today's output. -
marketCountand the rolled-upvolumeongetVenueEventById/useVenueEventnow cover the whole cluster to match.marketCountis the number of rows the market list returns for that event (open markets, matched siblings folded into their anchor), so it can be paged to exactly — passstatus: ["open"]to the market list to see the same set, since an unfiltered list also returns closed and resolved markets.volumesums every open and closed market in the cluster, including the siblings folded out of the list, so it is deliberately not a total over those rows. The embedded (deprecated)venueMarketsarray is unchanged — always the one event's own markets. Pass the sameclustervalue to the event and market calls so the count agrees with the list you render.
-
2026-08-29 · v4.6.0
-
Self-custody fills take a new optional
approveModeonfillSelfCustody(), for wallets that cannot sign a raw-digest EIP-7702 authorization.Omit it (the default,
"sponsored") and nothing changes: the wallet is not prompted for gas for the ERC-20 approve, and your signer may be asked for theeip7702_authorizationrequest as before — an EOA that is already delegated skips that step.Pass
"user_broadcast"when you know your wallet cannot produce that signature. The approve comes back as atransactionrequest instead — the user sends it themselves and pays its gas. Only your client can make this call, because whether the signature is possible is a property of the wallet software, not of the address or the chain, so the API cannot detect it.Worth surfacing in your UI:
"user_broadcast"never establishes the delegation, so the wallet is asked to broadcast an approve and pay its gas on every bridge, while the default asks for one authorization signature per chain. Reach for"user_broadcast"as a fallback, not a default. -
Self-custody users can now fund a trade from their own wallet, not just from money already sitting in their Polymarket deposit wallet.
SignerFnmay now return{ txHash: string }as well as a signature string. Returning a string keeps working exactly as before — this is additive, and existing signers need no change. The object form is for the newtransactionrequests, where the wallet broadcasts and you hand back the hash. Return it immediately, without awaiting the receipt; the server watches for the mined receipt itself.SignatureRequestTypegains"eip7702_authorization". Its payload is{ contractAddress, chainId, nonce }and it is signed over a raw EIP-7702 digest — not EIP-191, not EIP-712. Many wallets do not expose this. Throwing from your signer is not a fallback — nothing reads it as a rejection, so the request expires and the fill dies. If your wallet cannot sign it, sendapproveMode: "user_broadcast"on the fill and the ERC-20 approve is requested as atransactionthe user broadcasts themselves. With the authorization signed, the wallet is not prompted for gas on the funding step. -
Add a
signeroption andfillSelfCustody()for self-custodial fills. Supply asignerfunction and the wallet that will sign, and the SDK drives the sign-and-resume round trip; the key never leaves your process.
2026-08-29 · v4.5.0
-
Expose wallet account linking (SIWE/SIWS), matching the API that shipped in
feat(auth): link an external wallet to an existing account.AggLinkAccountBodygains{ provider: "siwe" | "siws"; address: string }, andAggLinkAccountResultgains{ type: "wallet_challenge"; message: string }.linkAccountConfirm()/useLinkAccount().confirmLink()now accept either the existinglink_confirm_tokenstring (OAuth/email) or{ kind: "wallet_signature"; message; signature }(wallet). Pass themessagereturned by/startverbatim — the server compares it byte-for-byte, so any client-side reconstruction fails.
Both are additive and backward-compatible; existing callers are unaffected.
2026-08-28 · v4.4.0
-
hooks: Add
useSportsLiveanduseRecurringCryptoMarkets, and harden execution progress reporting.useSportsLivepolls live sports scores and exposesSportsLiveStatewith participant scores and game status. ShipssportsLiveQueryKey,sportsLiveRefetchIntervaland theSPORTS_LIVE_POLL_INTERVAL_MS/SPORTS_SCHEDULED_POLL_INTERVAL_MSconstants so callers can align their own cache with the poll cadence.useRecurringCryptoMarketsresolves the rolling window of a recurring crypto market — current instance, timeline and identity — alongsidefetchRecurringCryptoMarkets,mergeRecurringCryptoWindows,resolveRecurringCryptoIdentity,resolveRecurringCryptoTimelineandrecurringCryptoTransitionPollIntervalfor callers driving their own polling.- Execution progress recovers from failed execution steps more predictably, and now exports the
ExecutionStepProgressandExecutionRawStepProgresstypes. - Limit orders accept fractional sizes, and venue quotes surface a slippage warning.
- Novig added to the exhaustive frontend venue maps.
- New
sportsLiveand recurring-market label keys, all defaulted.AggUiLabelsInputremains a deep partial, so existing label overrides are unaffected.
-
ui: Add live sports scores and recurring-market navigation to event views, and fix a batch of order-flow issues.
- New sports live-score display, exported from
@agg-build/ui/events, showing participant scores and game status on event items and market details. - Event item details gain recurring-market navigation — window selector, countdown and a
"go to live" affordance — driven by the new optional
recurringMarketsprop. - Order-placement fixes from QA, covering state clearing between orders and slippage presentation in the place-order flow.
- Balance management fixes, including raising the default refill maximum to 1000 USDC.
- Live scores removed from the event list; they remain on detail views.
No exports were removed and no existing prop became required.
- New sports live-score display, exported from
2026-08-28 · v4.3.0
-
Add
placeOrder()for direct single-venue order entry viaPOST /execution/orders, and surface the partnerexternalIdon order reads, webhooks and order events. -
Kalshi is now a fully active venue.
isVenueActive("kalshi")returnstrue,INACTIVE_VENUESis empty, andgetEffectiveDisabledVenues()no longer adds Kalshi to the disabled set by default. Apps that relied on Kalshi being filtered out automatically should add it to their owndisabledVenuesif they still want it hidden.isVenueExecutablehas been removed. Every active venue is executable, soisVenueActiveis the single predicate — replace anyisVenueExecutable(v, override)call withisVenueActive(v). It was never exported from the partner-facing entry point, so partner code is unaffected. -
getEffectiveDisabledVenuesnow treats an app's venue list as authoritative instead of merging it with the platform's default-hidden set.Previously the two were unioned, so the result always included every not-yet-launched venue no matter what the app passed. Now:
getEffectiveDisabledVenues(undefined)— no app context — returns the platform defaults, as before.getEffectiveDisabledVenues([])returns[]. An app that disables nothing excludes nothing.getEffectiveDisabledVenues(["kalshi"])returns["kalshi"], not["kalshi", ...defaults].
The distinction between
undefinedand[]is new and load-bearing:undefinedmeans "no app configuration exists",[]means "this app has opted into everything". Passing?? []where you mean "no context" will now reveal default-hidden venues, so pass the value through unchanged.This matters because venue visibility is moving from a compile-time constant to per-app configuration. Read your effective list from
/app/config(disabledVenues), which already resolves this for you — that is unchanged and remains the recommended source.isVenueActive,isVenueInactive,INACTIVE_VENUESandACTIVE_VENUESare unchanged. -
Add
deployerVenueto the orderbook batch types.MatchedOrderbookMarket.deployerVenuenames which Hyperliquid HIP-4 deployer a cluster member belongs to, andVenueOrderbookEntry.deployerVenuenames which deployer's book the published entry carries —venueOrderbooksis keyed by bare venue name, so it holds at most one Hyperliquid book even when a cluster has several deployer members. Both arenullfor every other venue. Mirrors fields already present on the API contract and the published OpenAPI spec.
2026-08-18 · v4.2.0
-
Add Novig to the canonical event-list venue tabs, and stop inactive-venue tabs flashing while
/app/configloads.getDefaultEventListTabsnow emits a Novig tab. It renders only where Novig is data-visible — the venue sits inINACTIVE_VENUES, so/app/configreports it underdisabledVenuesuntil Novig is enabled, anduseEventListTabsdrops disabled venues before render. Until then partners see no change.useEventListTabspreviously special-cased Kalshi when deciding whether to treat an unresolved app config as hidden. Any compile-time-inactive venue has the same problem — its tab is "available" until the config resolves, so it appears and then vanishes on first paint. The check now uses the sharedisVenueInactivehelper and covers Novig too.
2026-08-17 · v4.1.0
-
Export the
QuoteErrorCode/QuoteErrortypes, and add aquote_min_order_sizecode./execution/fillpreviously rejected a quote minted withstatus: "min_order_size_violated"as the genericquote_unfillable, which named neither the cause nor the fix. It now returnsquote_min_order_size, and the accompanyingmessagenames the venue minimum. Both the paper and live fill paths derive the code from the cached quote's status.QuoteErrorCodewas previously unexported, soAggApiError.codecould only be compared as a bare string. Branch on it with autocomplete instead:if (isAggApiError(err) && err.code === "quote_min_order_size") { // re-quote with a larger amount }Checking
status === "ok"on the smart-route response before calling/execution/fillavoids the round-trip entirely.
2026-08-16 · v4.0.1
-
Fix READMEs left stale by v4.
Both packages still documented
quoteManaged/useQuoteManaged, which were removed in v4 — the npm pages described methods that no longer exist. Replaced with thegetSmartRoute()→executeManaged()flow (useSmartRoute→useExecuteManagedin React) and a note explaining the removal.The SDK's "Peer dependencies" section also claimed the package "bundles its own clients for
viem,ethers@5,@polymarket/clob-clientand@polymarket/builder-signing-sdk". That was never accurate — those were declared as runtime dependencies but no code path imported them, and none were bundled. It now states the truth: zero runtime dependencies,node:cryptothe only imported module, bring your own signer.Also documents
AggApiError/isAggApiError, added in v4 but missing from the exports table.
2026-08-16 · v4.0.0
-
sdk, hooks: Remove
quoteManagedanduseQuoteManaged, along with theQuoteManagedParams,QuoteManagedResponse,QuoteManagedStep,QuoteManagedSplitandUseQuoteManagedOptionstypes.Their endpoint,
POST /execution/quote, does not exist on the API — the call has only ever returned 404, so no working integration can depend on it. Nothing in the SDK, hooks, UI library or demo app used them.To quote and fill a managed trade:
const route = await client.getSmartRoute({ venueMarketOutcomeId, tradeSide: "buy", maxSpend: 50, }); await client.executeManaged({ quoteId: route.quoteId });The React equivalents are
useSmartRouteanduseExecuteManaged. -
sdk: Export
AggApiErrorandisAggApiError. Every non-2xx API response has always been thrown withstatus,code,retryableanderrorsattached, but the thrown value was an untypedError, so consumers had no way to reach those fields without matching on message text. The class and type guard are now exported; runtime behaviour is unchanged. -
sdk: Remove four unused runtime dependencies (
ethers,viem,@polymarket/clob-client,@polymarket/builder-signing-sdk). None were imported by any code path — the SDK's only external import isnode:crypto. This cuts roughly 65 MB from a fresh install and removes the corresponding bundler traversal, which was the single largest install-size contributor for React Native consumers.
2026-08-12 · v3.0.0
- sdk, hooks: Remove
yesPricefromsortByonlistVenueMarkets/useVenueMarkets. The cross-event browse sort by price had no consumer and its dedicated index was one of the largest on the table. Markets listed under an event still order by price where the event's structure calls for it, and theminYesPrice/maxYesPricefilters are unchanged. Callers passingsortBy: "yesPrice"should drop the option.
2026-08-11 · v2.9.0
- Add display metadata to execution status steps:
orderIds,kind,groupId,groupStatus,label, andbridgedetails, so clients can render per-leg execution progress without classifying raw step types. - Add
getVenueGeoPolicy()— returns the per-venue blocked-country lists (ISO 3166-1 alpha-2) fromGET /app/venue-geo-policy. This is the raw venue policy, not per-user eligibility; keep using the quote'swarningsarray to gate a fill.
2026-08-08 · v2.8.2
-
Add the missing
slippagefield toSmartRouteResponse.The API has always returned route slippage metrics on the smart-route response (
SmartRouteResponseTB.slippagein the contract:vwap,refMidpoint,slippage,slippageBps), but the SDK's hand-mirrored interface never declared it.@agg-build/hooksreadsslippage.slippageBpsto flag thin liquidity, so that code — and its test — could not typecheck against the published type.Purely additive: the field is optional, so no existing consumer changes behaviour. The new
SmartRouteSlippageinterface is exported alongside it.
2026-08-07 · v2.8.1
- Widen
WithdrawalSourceTokenSymbolto includeUSD1. BNB USD1 (Myriad settlement inventory) can now fund a withdrawal, so it can appear in a withdrawal'ssources[]. It is a source-only token —WithdrawTokenSymbol(the request/destination union) is unchanged, same aspUSD.
2026-08-06 · v2.8.0
-
Add
config.formatting.formatPriceso partners can override how prices render.formatPercentalready governed probability rendering on discovery surfaces, but every cents surface formatted prices with a hardcoded formatter. Partners using a non-percentage odds convention (decimal, fractional, moneyline) ended up with converted probabilities on discovery pages and unconverted cents everywhere else.formatPricereceives the same0..1probability asformatPercentand now governs the order book, event page outcome chips, place-order, and positions. Set both to the same function to apply one odds convention app-wide.The positions view model also honors
formatCurrency, which it previously ignored.formatPriceis optional and unset by default, so every surface keeps its current rendering until a partner opts in. The order book spread and position PnL percentages stay on the built-in formatters by design — neither is a price.
2026-08-03 · v2.7.3
- Scope the order-book view for a selected outcome to that market's own matched set. The label fallback in
collectEligibleVenueOutcomesno longer merges same-label outcomes from other markets that are on the opposite semantic side: a second same-venue market with a different question (a decomposed per-team sibling leg or a same-family total) and markets of a different framing shape (bare Yes/No leg vs team-titled single) are excluded when the user's exact outcome is known. Fixes the unmatched kalshi moneyline leg's No view showing polymarket rows the router can never fill on, and the crossed book / negative spread produced by merging opposite-side books.
2026-08-02 · v2.7.2
- Event detail page: load every market instead of only the first page of 20.
useVenueMarketsgains afetchAlloption that eagerly fetches remaining cursor pages until exhausted;MarketDetailsListanduseEnrichedVenueEventnow use it with a 100-row page size, so events with many markets (e.g. 80+ open markets) render their full market list instead of a silently truncated one. - ui: Sports moneyline card: when a bare Yes/No leg and a cross-venue titled single collide on one aggKey (venue mis-keys a leg with the event base), keep the titled single — it renders one pill per team and carries the cluster — instead of first-wins evicting it.
2026-08-02 · v2.7.1
- Sports game-detail page: fix period tab ordering and add a sport-aware gate so a market never surfaces a nonsense tab for its sport. first_N_innings tabs now sort together, numerically by N (5 Innings no longer sorts before 3 Innings). A period family implausible for the events sport (e.g. a Sets period on a baseball event) demotes to the Other tab instead of rendering its own tab, closing the gap left by an upstream Rust classification fix. The gate fails open: unknown or unlisted sports keep every existing tab.
2026-08-01 · v2.7.0
-
Sports game-detail tabs are now derived from the game's own markets instead of a fixed, soccer-shaped list. A baseball game renders Game Lines / 5 Innings / Home Runs / Strikeouts rather than Game Lines / Halves / Other.
Three tab kinds are derived per game: Game Lines (full-game moneyline, spreads and totals, plus team props and specials such as the first-inning-run and extra-innings markets), one tab per period family that has lines (1h and 2h collapse into a single Halves tab as before, while first_5_innings reads as 5 Innings), and one tab per player-prop stat, labelled from the market subtype.
Soccer Corners / Goals / Assists / Shots tabs are unchanged and still resolve their labels through the existing cornersTab / goalsTab / assistsTab / shotsTab ui-config keys, so partner overrides keep working. Three new overridable label keys are added: quartersTab, setsTab and playerPropsTab.
The Game Lines tab no longer filters to regular time. Period-scoped markets now have their own tabs, and that filter had been hiding the period-scoped game props which belong on Game Lines.
-
ui: Sports moneyline card: drop decomposed per-team legs as a set once their merged single is present, instead of only the legs carrying a match edge. The matcher routinely pairs just some of a game's legs, which left an orphan leg beside the anchor and still rendered the whole matchup question as a pill.
-
ui: Trade panel: stop presenting an unaffordable primary route as a dead end when the same quote carries an executable solo. Solo route cards with their own quoteId no longer inherit the primary's
insufficient_balancestatus/error, and the default card selection prefers the executable solo when the primary is blocked on funding — a Kalshi-funded user with no on-chain balance now lands on a submittable Kalshi route instead of a blocking "Insufficient balance" alert. Quotes where nothing is executable still block exactly as before.
2026-08-01 · v2.6.0
-
Sports game-detail tabs are now derived from the game's own markets instead of a fixed, soccer-shaped list. A baseball game renders Game Lines / 5 Innings / Home Runs / Strikeouts rather than Game Lines / Halves / Other.
Three tab kinds are derived per game: Game Lines (full-game moneyline, spreads and totals, plus team props and specials such as the first-inning-run and extra-innings markets), one tab per period family that has lines (1h and 2h collapse into a single Halves tab as before, while first_5_innings reads as 5 Innings), and one tab per player-prop stat, labelled from the market subtype.
Soccer Corners / Goals / Assists / Shots tabs are unchanged and still resolve their labels through the existing cornersTab / goalsTab / assistsTab / shotsTab ui-config keys, so partner overrides keep working. Three new overridable label keys are added: quartersTab, setsTab and playerPropsTab.
The Game Lines tab no longer filters to regular time. Period-scoped markets now have their own tabs, and that filter had been hiding the period-scoped game props which belong on Game Lines.
-
ui: Sports moneyline card: drop decomposed per-team legs as a set once their merged single is present, instead of only the legs carrying a match edge. The matcher routinely pairs just some of a game's legs, which left an orphan leg beside the anchor and still rendered the whole matchup question as a pill.
2026-07-31 · v2.5.3
- Sports moneyline card: render one pill per team when a venue's decomposed per-team legs and their merged cross-venue single are both in scope. Opening the leg venue's own event (e.g. kalshi's side of an MLB game) previously showed the merged anchor as an extra pill labelled with the whole matchup question.
2026-07-30 · v2.5.2
- Show every quoted venue in Smart Routing, not just the fundable ones. A solo
venue whose own funding source was short came back without an executable quote id
and was dropped from the comparison list — so when an off-chain venue won the
route (which keeps the overall quote
ok), the alternative venue vanished from the panel entirely. The card now renders with its payout for comparison; the panel's existing Deposit / Add funds CTA remains the funding signal.
2026-07-28 · v2.5.1
- Add
isVenueExecutablevenue predicate (@agg/common) for gating per-venue order-execution eligibility, distinct fromisVenueActive(compile-time) andisVenueDataVisible(data display).
2026-07-27
Changed
- Markets listed under an event are ordered more sensibly. Sets of competing candidates now sort by odds, and events whose legs are labelled by month sort chronologically instead of falling back to a shared settlement date.
- Limitless recurring short-window crypto markets now appear as soon as the venue publishes the next slot, ahead of the window opening, instead of showing up part-way through it. They arrive with
statusofunopenedand only become tradable once the window starts.
Fixed
- Orders and transfers no longer fail with invalid- or insufficient-balance errors in two cases: Limitless positions reported more shares than the wallet could actually sell, and BNB transfers were quoted against a larger amount than the one that landed in the wallet.
- Polymarket deposit wallets now resolve to the address the venue actually deployed. Funding and orders were being pointed at a predicted address that no longer exists on chain.
- Activity now lists only deposits a user actually made. Settlement and bridge transfers made during trading that arrived in a managed wallet were being reported as incoming deposits.
- Polymarket events that were missing some of their markets, and quiet markets whose prices had stopped updating, now stay current.
- Markets Polymarket has shelved no longer show as open and tradable, and events that have finished report a
volume24hrof0rather than a frozen figure. - Full settlement rules are returned for every venue on a matched market instead of just one of them, and Limitless grouped markets now carry their own rules text.
- Search and orderbook reads stay fast and reliable under heavy load. Both previously slowed to several seconds or failed outright when traffic was high.
2026-07-24 · v2.5.0
-
Add
bookQualityto position responses (OutcomePosition,VenuePositionBalance).Positions are marked at the price the held size could actually be closed at, by walking the venue's resting book. When a venue's book is degenerate — a handful of contracts of real bid behind a stub ladder — that mark collapses, but
priceSourcestill reports"orderbook"because the walk did fill. Nothing in the response distinguished that from a healthy fill.bookQualitycarries the engine's existingBookQualityverdict (healthy/wide_spread/bid_only/ask_only/endpoint_stub/crossed/empty) for the worst book across the position's legs, so clients can label a low-confidence mark instead of rendering it as a market price. Values are unchanged — this adds a signal, it does not re-mark.Read
priceSourcefirst:bookQualityonly qualifies book-derived marks, and asettledposition reportsemptybecause it consults no book.
2026-07-23 · v2.4.9
-
Fix Tailwind utilities resolving theme tokens at
:rootinstead of at the element.The
@themeblock is now@theme inline, so.bg-agg-primary& friends emitvar(--agg-color-primary)directly rather than a--color-agg-*alias bound at:root. Two consequences of the old form are fixed:- Dark mode.
:rootnever matches.dark .agg-root:not(.light), so every utility resolved against the light defaults regardless of theme —.bg-agg-primaryrendered#536dfeand.text-agg-foregroundrendered#020205on dark surfaces. - Consumer theming. Overrides scoped to
.agg-root(including Partner Theme Studio's exported CSS) never reached any utility class.
Apps that worked around this by re-declaring the palette at
:rootcan drop that block. - Dark mode.
2026-07-21 · v2.4.8
- Surface auth-callback failures as a toast. Account linking (and sign-in) completes on the OAuth redirect-return page, detached from the UI that started it — so when
linkAccountConfirmrejects (e.g. HTTP 409already_linked_elsewherewhen the provider identity is already linked to a different user) the error only landed silently inAggAuthProvider's error state and the user saw nothing.AggAuthProvidernow toasts the callback error (when a toast provider is mounted) with a readable message —already_linked_elsewhere→ "That account is already linked to a different user." — titled for linking vs sign-in based on whether alink_confirm_tokenis present.
2026-07-21 · v2.4.7
- Fix
client.linkAccountConfirm()401'ing with "Missing Authorization header". Confirm runs on the OAuth redirect-return page, where the full-page reload has wiped the in-memory access token (tokens are never persisted). The request therefore went out with noAuthorizationheader, andrequest()'s 401-refresh-retry is gated on an existing token so it couldn't recover — so account linking failed at the final step.linkAccountConfirm()now mints a fresh access token from the refresh cookie/token (deduped) before the request when the in-memory token is absent; if the session is genuinely gone the refresh throws and the caller surfaces it.
2026-07-21 · v2.4.6
- Complete the ProfileModal account-linking flow. The initial fix (#2503) switched ProfileModal's connect buttons to
client.linkAccount(), but the rest of the round-trip was missing — this finishes it:@agg-build/sdk—client.linkAccount()now sendscredentials: "include"in the default bearer delivery mode. Without it the same-origin link-proof cookie the server sets on/users/me/link-account/startwas dropped on the cross-origin response, so the OAuth link callback rejected every link withlink_proof_invalid.@agg-build/hooks—handleAuthCallback(the shared callback handler auto-run by@agg-build/auth'sAggAuthProvideranduseAggAuthCallback) now detects thelink_confirm_tokenthe provider callback returns, callsclient.linkAccountConfirm(), refreshes the user, and strips the token from the URL. Previously nothing consumed the token and the link silently never persisted. A collision (identity already linked to a different principal) surfaces as the callback error (HTTP 409);already_linked_sameresolves idempotently.@agg-build/ui— email linking (magic link, no redirect) now shows a "check your inbox" success toast so the click has visible feedback.
2026-07-21 · v2.4.5
- Fix ProfileModal social connect/disconnect. Connect now links the provider to the already-signed-in principal via
client.linkAccount()(POST /users/me/link-account/start) instead of starting a fresh sign-in viastartAuth()(POST /auth/start), which could not attach to the current user and caused a competing double-redirect. Disconnect (and connect) calls are now guarded and surface the API error (e.g. "Cannot disconnect the only linked auth provider") through the modal's toast instead of escaping as an unhandled promise rejection with no user feedback.
2026-07-14 · v2.4.4
- Poll the venue-event query while a market lingers "open" past its endDate, so short-cadence markets (e.g. Kalshi 15-min BTC) transition to their resolved state instead of rendering a stale open market with no orderbooks (SNA-3047). endDate only triggers refetches — server status stays authoritative, so venues with inaccurate endDates can't disable trading.
2026-07-13 · v2.4.3
- Update settlement differences UI behavior
2026-07-11 · v2.4.2
- Stop the combined-moneyline card from rendering unmerged cross-venue duplicates of one market as two identical pills ("Match Winner" ×2 showing the same Yes price twice). When per-leg labels aren't distinct, the card falls back to the standard single-market rendering with team-title pills (SNA-3028, esports).
2026-07-10 · v2.4.1
- Render "Team to Advance" in the Game Lines tab, above the Moneyline (Polymarket parity). Knockout advance markets are primary game lines (multi-million volume) and were buried in Other; for a venue whose only market is the advance single (hyperliquid) this is what makes Game Lines exist at all. One card per game, anchored by the 2-outcome single with team-name pills (SNA-3028).
2026-07-10 · v2.4.0
- The Search primitive now requests
status: ["open"]so open-only filtering happens server-side: pages arrive full of tradeable results and pagination is honest, instead of fetching all statuses and emptying resolved-heavy pages client-side (which rendered "No markets found" for queries like "5m btc" whose top results are recurring-series history).
2026-07-10 · v2.3.0
- sdk, hooks: Add an optional
statusfilter to search:client.search({ status: ["open"] }),useSearch({ status: ["open"] }), anduseMarketSearch({ status: ["open"] })return only markets/events in the given statuses. Pass["open"]for tradeable-only results — without it, recurring series (e.g. 5-minute up/down markets) can fill a page with resolved history, which a UI that hides non-open rows renders as an empty result. - ui: Give whole-match totals a clean unit-based title ("Total Goals" / "Total Corners" / "Total Rounds") derived from the group's stat, instead of a raw venue question that produced labels like "Reg Time: Over 0.5 goals scored Totals" when a kalshi market anchored the group (SNA-3028). Per-team totals keep their subject ("Argentina Totals").
2026-07-10 · v2.2.4
- Show consistent team names on sports spread outcome pills (
{Favored} −X/{Dog} +X) regardless of which venue anchors the ladder stop. A kalshi/limitless anchor storesYes/Nolabels; the team names are now borrowed from the cross-venue twins (poly/predict) at the same signed line, falling back toYes/Noonly when no venue carries a team title (SNA-3028).
2026-07-10 · v2.2.3
- Raise the sports event per-tab market fetch page size from 20 to 100 (the API max), so a prop-heavy tab like "Other" loads in 1–3 requests instead of ~15.
- Render sports spreads as a single symmetric ladder (home ← center → away) like Polymarket, instead of two same-titled "Spreads" cards. Both favored-side families (
…_sp_arg/…_sp_che) now collapse into one spread group, and the ladder lays them on a signed magnitude axis with the home/first team anchoring the negative side (SNA-3028).
2026-07-10 · v2.2.2
- Group sports spread/total ladders by the aggKey line-family instead of the market question, so the same total (e.g. match total O/U) no longer fragments into separate cards across venues that phrase it differently (SNA-3028).
2026-07-08 · v2.2.1
- Clarify the id vocabulary across the WS surface and surface resolved-market status on
/midpoints.useMarketOrderbooknow acceptsvenueMarketOutcomeId(theoutcomes[].idfrom REST market responses); the oldmarketIdoption keeps working but is deprecated — it has always carried a venueMarketOutcomeId, not a venueMarketId.- SDK
onSnapshot/onDeltacallback parameters are renamedoutcomeId(type-level only, no runtime change). subscribed/unsubscribedconfirmations on the arb channel now also echo the ids undermarketIds(arb subscriptions are keyed by marketIds); the misleadingoutcomeIdsmirror stays for backwards compatibility.- The gateway's
Snapshot unavailable for <id>error now explains that orderbook subscriptions take venueMarketOutcomeIds, not venueMarketIds. GET /midpointsentries now carrymarketStatus, and resolved markets return null prices plus a structurederror(code: "market_resolved") instead of a stale settled-market mark; unknown ids getcode: "market_not_found".
2026-07-07 · v2.2.0
- Discovery responses no longer carry outcome prices.
GET /venue-events,GET /venue-events/:id, andGET /venue-markets(and/search, which shares the same shapes) stop returningvenueMarketOutcomes[].price— including onmatchedVenueMarkets[]siblings. TheVenueMarketOutcome.pricetype is now optional and deprecated. Fetch live prices fromGET /midpoints(or theuseMidpoints/useViewportMidpoints/ live WS hooks), keyed byvenueMarketOutcomeId. UI components already prefer live midpoints; the staticpricewas only a pre-live seed and is now ignored when absent.
2026-07-05 · v2.1.5
- Sports detail page: honor the documented open period grammar (
set_N,map_N,game_N,period_N,inning_N,first_N_innings) instead of collapsing those markets into the "Other" period bucket; treatmatchas full-game scope so whole-match markets stay in Game Lines; stop parsing the opaqueaggKeyfor the league label (categories are the only label source).
2026-07-03 · v2.1.4
- Fold cross-venue moneyline legs into the 3-way Moneyline card regardless of which venue anchors the merged representative:
isBinarySportsMoneylineMarketnow also recognizes a leg by its deterministic_ml_aggKey (e.g. a kalshi-anchored "Reg Time: Brazil" withmarketSubtype=null), so no leg drops out as a standalone row. Mis-tagged props stay excluded (they are never_ml_-keyed).
2026-07-02 · v2.1.3
-
Add a
context: "list" | "detail"option togetVenueMarkets/useVenueMarketsand passcontext: "list"from the event tile's market-scroll query.On list/tile surfaces, axis and dates events now sort their markets by lifetime volume (biggest market first) for both the embedded top-3 and the scroll-loaded tail, while the detail page keeps its structured order (threshold/date ascending).
candidate/sportevents are unchanged.
2026-06-23 · v2.1.2
- Improve live trading and resolved-market handling across the sufwan-local-test React packages.
@agg-build/hooks- invalidate and optimistically refresh cached market, balance, position, and activity data when
market_resolvedWebSocket events arrive - export venue-attributed live best-price candidate helpers/hooks so UI surfaces can keep the displayed venue logo aligned with the freshest live price
- invalidate and optimistically refresh cached market, balance, position, and activity data when
@agg-build/ui- add shared claim-winnings and resolved-market claim hooks for resolved positions
- show the new resolved-market earnings/claim state in the event market flow
- add
onBeforePrimaryActionso partners can run a pre-submit gate before normal order execution - keep market detail outcome prices and venue logos in sync with live best-price updates
@agg-build/sdk- no direct SDK source or API changes landed in this push
- patch bump only to keep the linked public package versions aligned for release/publishing with the updated hooks and UI peers
2026-06-19 · v2.1.1
-
Add provider-level sufwan-local-test UI trading execution mode config.
AggProvidernow acceptsconfig.trading.executionModeso hosted UI surfaces can share a global live or paper trading mode without threadingexecutionModethrough every page or order panel.PlaceOrder,HomePage,EventMarketPage, andUserProfilePageuse the configured mode by default while preserving explicit component-level overrides.The shared balance provider now also uses the configured paper mode, so
ConnectButtonheader totals andUserProfilePagebalance/positions value cards read paper balances instead of falling back to live-mode zeroes.Paper balances are labeled as Paper in the user profile network breakdown, use a shared paper-mode icon, and show a tooltip warning when the app is running with simulated paper funds.
2026-06-17 · v2.1.0
-
Add safe midpoint batching for component-driven market pages.
AggClient.getMidpointsnow splits large/midpointsGET requests into smaller batches and merges the responses, defaulting to 75 venue market IDs per request to stay below common CDN URL limits. React hooks and UI components read the same default throughconfig.market.maxMidpointIdsPerRequest, and direct hook/SDK callers can override the cap when needed.
2026-06-12 · v2.0.0
-
sdk, hooks: Narrow recurrence filters to the documented public cadence enum and expose the full supported venue-event cadence list through
RECURRENCE_CADENCES, includingPT10M,P1M, andP1Y.Migration guidance: replace dynamic recurrence-catalog calls with the SDK
RECURRENCE_CADENCESexport or the OpenAPI enum. Pass the literal"null"only when filtering one-off venue events.listRecurringCryptoMarketsremains limited to deterministic crypto durations:PT5M,PT15M,PT1H, andP1D.
2026-06-12 · v1.3.0
- Frontend feature round-up since the last release: live arbitrage signals, nested category navigation, event-tile price gaps, paper-trading mode, and position/redeem fixes.
- Live arbitrage (
@agg-build/sdk,@agg-build/hooks,@agg-build/ui)- SDK added
subscribeArbandsubscribeArbFeed, with the supporting wire types (WsArbMarketUpdate,WsArbFeedBatch,WsArbFeedEntry), socket dispatch, reconnect, and refcount handling, and documented the new arb actions in theWsClientMessageunion. - Hooks added
useMarketArb(live per-market arb) anduseArbFeed(event-level MAX rollup), exported with theirUseMarketArbResult/UseArbFeedResulttypes. - UI brought back the arbitrage sort option and added event-list filters; event tiles and lists now surface arb-driven ordering.
- SDK added
- Nested categories (
@agg-build/hooks,@agg-build/ui)- Hooks added
useCategoryChildren(withUseCategoryChildrenOptions) for fetching subcategories. - UI renders the category
displayNameon home tabs and event-list filters, supports nested subcategories, andEventListPropsgainedonCategoryRootChange.HomePageCategorynow carries an optionaldisplayName.
- Hooks added
- Event-tile price gaps (
@agg-build/hooks,@agg-build/ui)- Hooks exported the
computePriceGapshelper plusMAX_PRICE_GAP_PCT/MIN_PRICE_GAP_PCTand theComputePriceGapsOptions/PriceGapValuetypes. - A new
enablePriceGapfeature flag andpriceGaplabel gate compact price-gap signals on aggregated event tiles; tiles wait for midpoints before computing gaps to avoid flicker.
- Hooks exported the
- Paper-trading mode (
@agg-build/sdk,@agg-build/hooks,@agg-build/ui)- SDK introduced the
ExecutionMode("live" | "paper") type and threaded an optionalmodethroughExecuteManagedParams, smart-route params, positions/orders queries, andManagedBalancesParams. - UI's place-order panel accepts an
executionModeprop and reports the chosenmodeback throughonPrimaryAction.
- SDK introduced the
- Positions, redeem, and claim fixes (
@agg-build/hooks,@agg-build/ui)- Hooks exported
invalidateUserClaimStateand now walk the active bucket when counting redeem-eligible positions; auto-settled HL winners are reported as redeemed rather than ineligible. - UI user-profile tabs trust server-provided position buckets, redeem payout renders from the 6-decimal
totalPayoutRaw(no longer derived fromlegs[0]decimals), and a new partner-overridableclaimlabel group powers claim lifecycle notifications.
- Hooks exported
- Withdrawals & misc (
@agg-build/sdk,@agg-build/ui)- SDK added the
WithdrawalSourceTokenSymboltype to support pUSD withdrawal sources;WithdrawManagedSourceItem.tokenSymbolnow acceptspUSD. - UI event-list skeletons can render the discovery sidebar (
withSidebar), with refreshed event-tile coloring, volume sort, and updatedsort-volume-24hr/shield-trusticons.
- SDK added the
- Live arbitrage (
2026-06-05 · v1.2.13
- Add
email: string | nullto the typedaccounts.createdwebhook event payload so partners can read email addresses supplied by magic-link or OAuth sign-in.
2026-05-26 · v1.2.12
-
Expand the trading labels surface with 9 new partner-overridable keys for execution failure messaging (
sellNoOnchainPosition,venueQuoteUnfillable,venueMinOrderSize,sourceBalanceChanged,venueMarketResolved,dflowWalletUnverified,venueNoQuotePath,solanaBlockhashExpired,venueRateLimited,serviceBlockedOrder), and wire matching patterns intonormalizePlaceOrderErrorMessageso the SDK renders friendly copy for everyUserActionableStepErrorreason code the API now emits.Also rewrites the venue-terminated pattern coverage to handle Limitless's
FAILED/UNMATCHEDsettlement statuses with dedicated friendly copy ("Order didn't settle on-chain"and"No liquidity matched your order at the quoted price"), and extends the min-order-size pattern to recognize predict.fun's existingpredict_min_quantityuser-actionable copy. -
Centralize execution failure labels and clean up place-order error normalization for venue outages and expired submission deadlines.
2026-05-21 · v1.2.11
- Deposit & withdraw UX overhaul:
- New
useWithdrawEstimatehook surfaces per-route fee and ETA estimates before submit. - Refreshed deposit and withdraw flows, including new amount/method/success screens, transfer fee summary, and friendly error states.
WithdrawManagedResponsenow exposescompletedAmountRaw, and the WSWithdrawalLifecycleEventincludesrequestedAmountRawandcompletedAmountRawso consumers can render the terminal settled amount.- New balance/activity invalidation helpers (
invalidateUserActivityQueries,invalidateUserMoneyState,userActivityQueryKeys) exported from@agg-build/hooks. - User profile activity rows and balance cards updated with refined states; new
spinnerandcircle-xmarkicons; tooltip primitive tweaks.
- New
2026-05-07 · v1.2.10
- Fix a bug in geo-blocking behavior for order splitting
2026-05-07 · v1.2.9
- UI updates for Positions tab and removed hardcoded colors
2026-05-06 · v1.2.8
- Added new prop in tooltip for gap and UI adjustments
2026-05-06 · v1.2.7
- Fix a bug in geo-blocking behavior for order splitting
2026-05-06 · v1.2.6
- UI updates in the withdraw modal and claim flow for design QA
2026-05-05 · v1.2.5
- Bug fix for nullable venueMarketOutcomeId
2026-05-05 · v1.2.4
- Bug fix for nullable venueMarketOutcomeId
- Update network chain logos to prediction-markets CDN paths; fix Solana missing from deposit modal network list
2026-05-05 · v1.2.3
- removed redundant div from venue selection
2026-05-04 · v1.2.2
- Sorting user positions
2026-05-04 · v1.2.1
- Market details UX updates
2026-05-04 · v1.2.0
-
Added smart-route fee breakdown support across sufwan-local-test packages.
@agg-build/sdknow includes optionalfeeBreakdowndata on smart-route quote responses so integrators can display venue fees, bridge fees, execution gas, and total fees.@agg-build/hooksaddsfeatures.showFeesBreakdownto UI config and new label keys for fees and updated positions table/status copy.@agg-build/uiadds optional fee breakdown display in the place-order flow, updates route ordering to prioritize better executable value, improves mobile event-market trade opening from outcome selection, and upgrades positions UX (active/closed filtering, status/result badges, and claim-state handling).
These changes are backward compatible and require no migration for existing integrations unless you want to enable the new fee breakdown UI (
showFeesBreakdown).
2026-04-30 · v1.1.0
- Added xs size for icons and geo block updates for order
2026-04-30 · v1.0.2
-
Refresh published package metadata and fixes for the sufwan-local-test SDK package stack.
Updates:
- @agg-build/hooks: fix midpoint price calculation in
useViewportMidpoints; minor adjustments to UI-config labels and theuseWithdrawFlowhook. - @agg-build/ui: settlement formatting refactor (new
settlement-text-renderer+settlement-text.utils);PlaceOrderflow updates including default amount, sell-tab default, partially-filled state, best-price wiring, max label, and a sign-in-to-trade flow; refreshed typography variants; newappsandcircle-overlapicons; customSelectmigration for TBAs; connect-button view rewrite; event-list search/filter improvements. - @agg-build/auth: updates to the SIWE adapter and shared auth utils.
- @agg-build/hooks: fix midpoint price calculation in
2026-04-28 · v1.0.1
-
sdk: Add withdrawal lifecycle WebSocket support — new
WsWithdrawalLifecycleEventmessage type,onWithdrawalLifecycleSDK callback, and associated types (WsWithdrawalLifecycleStatus,WsWithdrawalLegStatus,WsWithdrawalLifecycleLeg).hooks: Add
useWithdrawFlow,useWithdrawalLifecycle, anduseOnWithdrawalLifecyclehooks with full withdrawal lifecycle tracking via WebSocket. Fix live outcome price fallback so REST midpoints surface when no WS midpoint exists. ImproveuseMidpointsto prefer the venue with the lower YES midpoint for better buyer pricing. Fix hooks package exports to use format-specific type declarations (.d.mtsfor ESM consumers).ui: Add wallet withdrawal flow — recipient address input, amount/token/network selection, confirmation step, and an order-style execution timeline showing per-leg bridge/transfer progress with live lifecycle status. Add
CopyButtonprimitive. Show wallet address on card-payment pending step in the deposit flow. Surface best-price venue indicators in the event list, market details, and orderbook. Fix cluster-aware market deduplication to collapse cross-page duplicates.
2026-04-27 · v1.0.0
- Initial v1.0.0 release of the sufwan-local-test client libraries on npm under the
@agg-buildscope.