Repository navigation
Releases
v0.35.0-devnet-20261108182734
Minor Changes
-
Breaking:
realtime.isConnectedis removed. It was true whenever a socket object existed, even one that never connected. Readrealtime.connectioninstead:{ public, private }, each{ state, error }, wherestateis"connecting","connected"or"disconnected"anderroris the first failure of the current outage (a socket failure after a connection token failure replaces it), cleared once the socket connects.realtime.onConnectionChange(listener)calls the listener with the current value after each change, in a microtask, and returns an unsubscribe function. Private order streams run on their own socket and are not included. CustomPolyesterRealtimeimplementations must add both members. (#232)A realtime socket that cannot connect now reports it. On the first failed attempt, every channel on that socket gets one
onErrorwithtype: "transport"and a retryableRealtimeError, not one per reconnect retry; a channel subscribed while the socket is still failing gets it on subscribe. On the private socket, a failed connection token request is reported as"connection_token"on each attempt instead. The order book (whose snapshot waits for the channel to open) and trades no longer wait silently forever when the socket is unreachable;onOpenfollows once it recovers.Once a channel's unsubscribe function has run, that consumer gets no further
onErrororonUnsubscribed, even from a notification already in progress (for example, unsubscribing from inside a terminal close'sonErrorno longer also callsonUnsubscribed). Channels that actually closed are still told, even if a handler callsdisconnect()meanwhile.
Patch Changes
-
API-key auth takes an optional
recvWindow: a whole number of milliseconds from 1 to 60000, sent asX-API-RECV-WINDOWand signed on the line after the timestamp. The backend processes a request only until its timestamp plus the window, which defaults to 10000 when omitted. A value outside the range throwsConfigurationErrorbefore the request is sent. AnAUTH_RECV_WINDOW_INVALIDrefusal maps to a non-retryableValidationErrorrather thanAuthenticationError, because the credentials are not at fault. (#237) -
The
orders.batchCreateJSDoc now gives the batch's 15-minute idempotency window. It previously said 60 seconds, which is thebatchReplacewindow. Within 15 minutes, a retry with the samerequestIdand payload returns each decided item's original result and retries the unresolved ones. After that the ID is free, and a repeat can place its orders again. (#235) -
The
orders.getBatchReplaceStatusJSDoc now gives the 60-second status window. The status is readable as soon asbatchReplacereturns. Retry aServiceUnavailableErrorwith the same request within the window. AResourceNotFoundErrornever means the replacement was rejected: reconcile the individual orders and never resubmit an accepted batch. An item'supdatedTsNscan be a later recovery time, so it does not identify a refusal. (#236) -
Changelog post summaries add
revisionandupdatedAt. A post can now be republished to correct its copy or withdraw a change:revisionstarts at 1 and increases with each republication, andupdatedAtis when the current revision was published. To follow edits, read a post again when itsrevisionchanges.listChangesrestarts paging at the first change of a post republished during the walk, so deduplicate changes byid. (#236) -
Checkpointnow carriesopeningValueUsd, the season-end USD value of the holdings restored when the season opened ("0"when it opened with no balances,undefinedwhen a restored balance had no USD value). With it,seasonResultUsdreconciles asfinalValueUsd - openingValueUsd - netInflowUsd. (#235) -
expandColumnarTimestampsSecandcolumnarTimestampSecAtnow end atendTsSec, so the last columnar history point is no longer one bucket early. (#233) -
lifecycle.listFlowswith anaccountSelectornow also returns the transfers the account received from other accounts, such as transfers from other users or subaccounts and reward payouts. Each row carriesparticipation:"owner"for a flow the account owns, including a transfer it sent, and"recipient"for a received transfer. Rows are"unspecified"without an account selector and in flow detail and realtime updates. Passparticipation: "owner"to keep the previous owner-only list or"recipient"for received transfers only.participationrequiresaccountSelectorand throwsValidationErrorwithout one. ApageTokennow resumes only the request it came from, so change nothing butlimitbetween pages. (#237) -
A ConnectRPC
resource_exhaustedthat carries aRateLimitDetail, as wallet sign-in and the public catalog calls now send, maps to aRateLimitErrorwithrateLimitset andretryAfterMstaken from the detail. Itsdetailis{ service: "rate_limit", code: "RATE_LIMIT_EXCEEDED", rateLimit }. The gateway's own refusal has no detail:retryAfterMscomes fromRetry-Afterwhen present and isundefinedfor a concurrency refusal, so back off without a server hint. (#236) -
Realtime token requests honor
Retry-After. When the connection or subscription token endpoint answers 429 with aRetry-Afterheader, theRateLimitErrorcarries it asretryAfterMs, and the realtime client sends no further token request until it has passed (at most 60 seconds), even when the socket retries sooner. This covers public, private and private order stream sockets. (#232) -
A signed request refused with
AUTH_REPLAY_CAPACITY_EXHAUSTEDmaps to a retryableRateLimitErrorwithoutretryAfterMs. Before, a full replay store answeredSIGNATURE_INVALID. Now each API key and account holds a fixed share, so only the key or account at its share is refused. Back off briefly and retry, which signs again. A shorterrecvWindowfrees room sooner. (#237) -
An order or trigger write refused with
REQUEST_DEADLINE_EXCEEDEDmaps to the newRequestDeadlineExceededError(code"REQUEST_DEADLINE_EXCEEDED", retryable), a subclass ofTimestampSkewError. The signed request passed authentication, but its receive window ended before admission. Nothing changed, and this is never an unknown outcome, so retrying, which signs again with a fresh timestamp, is safe. Every signed request now has this deadline, including requests sent withoutrecvWindow, which get the 10-second default. (#237) -
An HTTP 413 now maps to the new
RequestTooLargeError(code"REQUEST_TOO_LARGE", not retryable) instead of a plainRequestError. Every service now refuses an oversized body with the same 413 problem, including ledger reads and API-key authentication of ConnectRPC calls. Send a smaller request; the size limit does not change. A ConnectRPC message over the limit still arrives asresource_exhaustedand maps as before. (#236) -
rewards.listAwardsnow returnsawardsMayChange. It istruewhile a campaign can still publish awards or one of the account's awards is awaiting a destination, ready for payout, or failed and retryable. When it isfalse, polling cannot return new awards or award changes until a new campaign is created. (#235) -
PolyesterErrorCodenow includes"SUBACCOUNT_CHALLENGE_INVALID", the codeSubaccountChallengeInvalidErroralready carries, so an exhaustiveswitchover the union covers it. (#235) -
Subaccountrecords now carryremoved.subaccounts.subscribeemitsremoved: true(withrole: "unspecified") when the caller loses access to a subaccount, for example after the owner removes them as a member, so drop it from local state. List and get responses always returnfalse. Access and role changes do not bumprevisionorupdatedAt, so apply them in arrival order. (#235) -
tradeWsPbin@polyester/sdk/unstable/genadds thecancelAllAfterclient command and acknowledgement, which arm, refresh or disarm the account's dead-man switch, plus theClientFramefieldstimestampMsandrecvWindowMs, which set a per-command receive window. The SDK has no trading WebSocket client yet. (#237) -
A wallet login refused with
AUTH_WALLET_ALREADY_LINKEDmaps to a non-retryableAlreadyExistsError. The wallet already belongs to another account, so the same login fails again. Log in with the account address the wallet already uses. (#236)
v0.34.0
Minor Changes
- Breaking: every SDK label, key and filter value now uses the
canceledspelling. Trigger status (output and thetriggers.liststatusfilter), sub-account invite status and social-verification status change from"cancelled"to"canceled", matching order status and trigger events. Theorders.cancelAllresult renamescancelledOrderstocanceledOrdersandtotalCancelledtototalCanceled. There are no aliases: update any code that compares against"cancelled"or reads the old keys. (#230)
Patch Changes
-
Order, trade, market trade, balance and candle streams (and their list reads) no longer re-validate protobuf-decoded messages with Valibot before formatting them. Payloads are unchanged; per-message formatting is roughly 1.5-2.5x faster. (#231)
-
ValidationErrormessages name the field that failed. When an input matches none of the shapes a method accepts, the message now comes from the closest shape and is prefixed with its path, such asitems.0.symbolId: Invalid key: Expected "symbolId" but received undefinedfororders.batchCreatewithsymbolIdon the request instead of each item. Before, this was the genericInvalid type: Expected Object but received Object. The same applies to an unsupportedexecution.clientRefPriceonorders.create, andtriggers.createnow reportssliceIntervalMs cannot exceed durationMsfor a TWAP. Messages that already name their field are unchanged. (#228)
v0.34.0-devnet-20261105175510
Minor Changes
- Breaking: every SDK label, key and filter value now uses the
canceledspelling. Trigger status (output and thetriggers.liststatusfilter), sub-account invite status and social-verification status change from"cancelled"to"canceled", matching order status and trigger events. Theorders.cancelAllresult renamescancelledOrderstocanceledOrdersandtotalCancelledtototalCanceled. There are no aliases: update any code that compares against"cancelled"or reads the old keys. (#230)
Patch Changes
-
Order, trade, market trade, balance and candle streams (and their list reads) no longer re-validate protobuf-decoded messages with Valibot before formatting them. Payloads are unchanged; per-message formatting is roughly 1.5-2.5x faster. (#231)
-
ValidationErrormessages name the field that failed. When an input matches none of the shapes a method accepts, the message now comes from the closest shape and is prefixed with its path, such asitems.0.symbolId: Invalid key: Expected "symbolId" but received undefinedfororders.batchCreatewithsymbolIdon the request instead of each item. Before, this was the genericInvalid type: Expected Object but received Object. The same applies to an unsupportedexecution.clientRefPriceonorders.create, andtriggers.createnow reportssliceIntervalMs cannot exceed durationMsfor a TWAP. Messages that already name their field are unchanged. (#228)
v0.33.0
Minor Changes
-
Breaking: the holds list is removed.
ledgerReadPbin@polyester/sdk/unstable/gendropsLedgerReadService.ListHolds,ListHoldsRequest,ListHoldsResponseandHoldRow. Read held amounts from each asset'sreservedamount inbalances.list. (#225) -
trades.listtakessymbolIdas a number, like every other symbol filter and like thesymbolIdon returned trades, orders and triggers. A string,0, negative or fractionalsymbolIdis rejected. "symbolId is required when afterMatchId is set" now appears only whenafterMatchIdis set withoutsymbolId. (#226)
Patch Changes
-
API key refusals on ConnectRPC now carry an auth
detail.codethat names the reason:AUTH_SIGNATURE_INVALID,AUTH_TIMESTAMP_SKEW,AUTH_MISSING_HEADERS,AUTH_KEY_EXPIRED,AUTH_KEY_DISABLED,AUTH_IP_NOT_ALLOWEDorAUTH_API_KEY_NOT_ACCEPTED.AUTH_TIMESTAMP_SKEWstill maps to the retryableTimestampSkewError, and a retry signs the request again. (#223) -
Attached take-profit, stop-loss and trailing stop exits never trade with the order they protect. Order
cancelReasonaddsattached_exit_fired: the exit fired while the order still rested, so its unfilled remainder was canceled first. Fills before the cancel stand. Trigger failure reasons addself_trade_prevented, reported only as a"fire_refused"event'sfireRefusalReason: self-trade prevention expired the exit's order against another of the account's resting orders, and the trigger stays live and fires again. That event'schildSeqnames the expired child order. (#224) -
An order's
attachedRisk.trailingStopnow carrieslimitPrice, the most its buy-back pays per unit, set when the order sells andundefinedwhen it buys. Previously it was dropped, so a selling order's trailing stop read back and passed tomodifyOrderlost its limit price and was rejected with a bad-price error. (#227) -
Add
autoWithdraw, which manages an account's scheduled auto-withdraw rule:getRule,setRule,disableRuleandlistRuns.setRuleanddisableRuleneed a freshstepUpToken, and a staleexpectedVersionthrowsRevisionConflictError. (#222) -
Changelog surfaces add
market_data,quickswapandrewards, for output and forlistChangesfilters. Each post section has asurface, the product area it covers, or"unspecified"when it covers more than one. (#223) -
Order and trigger
cancelReasonaddmarket_halted: the exchange halted the market and canceled every open order and trigger of it, attached take-profit and stop-loss included, and released their reserved funds. Fills before the cancel stand, and the market refuses new orders until it trades again. Show it as "market halted", not as a user cancel. (#221) -
Orders carry their exact execution totals.
avgPxis now the exact average execution price, up to 18 decimal places instead of rounded down to 9.cumQuoteis the quote amount the fills used before fees,"0"with no fills.feeTotal({ amount, isRebate, qty }) is the net fee in the order'sfeeAsset: order history andgetDetailsinclude it, open orders leave it out. It covers every fill oncefeeTotal.qtyequalscumQty. (#223) -
Add
changelog, a public reader for the environment's product changelog:listPosts,getPost({ slug })andlistChanges, which filters changes by category, audience, surface and time. The generated protobufs are exported aschangelogPb. (#218) -
fees.getSpotRatesrows addreserveFeeRatePercentandpostOnlyReserveFeeRatePercent, the rates a new order reserves its quote-asset fee at: the highest rate of any VIP tier on the market, so at least the effective rates. Size buy orders by the reserve rate, not the effective one.breakdownlists the components of the effective rates: the VIP tier rates, an optionalmarketMultiplier,accountDiscounts([]when none) and an optionalreferralDiscount, witheffectiveFromandeffectiveToin Unix milliseconds.nextChangeAtis when a component next starts or ends, orundefinedwhen no change is scheduled. (#225) -
subaccounts.getacceptsincludeBalances: trueand then returns the sub-account's currentbalances, in the shape ofbalances.list. It needs the read-balances action on the sub-account or fails with PermissionDenied. When balances cannot be read right now it fails with the retryableAUTH_TEMPORARILY_UNAVAILABLE. WithoutincludeBalances,getis unchanged and returns nobalances. (#224) -
Trigger events add the
"fire_refused"event type: a fire was refused and the trigger stayed live, so it is not terminal. The event'sfireRefusalReasonsays why, using the trigger failure reason labels.listEventsacceptseventType: "fire_refused"as a filter, and trigger failure reasons addaccount_repairing. (#223)
v0.33.0-devnet-20261104214343
Minor Changes
-
Breaking: the holds list is removed.
ledgerReadPbin@polyester/sdk/unstable/gendropsLedgerReadService.ListHolds,ListHoldsRequest,ListHoldsResponseandHoldRow. Read held amounts from each asset'sreservedamount inbalances.list. (#225) -
trades.listtakessymbolIdas a number, like every other symbol filter and like thesymbolIdon returned trades, orders and triggers. A string,0, negative or fractionalsymbolIdis rejected. "symbolId is required when afterMatchId is set" now appears only whenafterMatchIdis set withoutsymbolId. (#226)
Patch Changes
-
API key refusals on ConnectRPC now carry an auth
detail.codethat names the reason:AUTH_SIGNATURE_INVALID,AUTH_TIMESTAMP_SKEW,AUTH_MISSING_HEADERS,AUTH_KEY_EXPIRED,AUTH_KEY_DISABLED,AUTH_IP_NOT_ALLOWEDorAUTH_API_KEY_NOT_ACCEPTED.AUTH_TIMESTAMP_SKEWstill maps to the retryableTimestampSkewError, and a retry signs the request again. (#223) -
Attached take-profit, stop-loss and trailing stop exits never trade with the order they protect. Order
cancelReasonaddsattached_exit_fired: the exit fired while the order still rested, so its unfilled remainder was canceled first. Fills before the cancel stand. Trigger failure reasons addself_trade_prevented, reported only as a"fire_refused"event'sfireRefusalReason: self-trade prevention expired the exit's order against another of the account's resting orders, and the trigger stays live and fires again. That event'schildSeqnames the expired child order. (#224) -
An order's
attachedRisk.trailingStopnow carrieslimitPrice, the most its buy-back pays per unit, set when the order sells andundefinedwhen it buys. Previously it was dropped, so a selling order's trailing stop read back and passed tomodifyOrderlost its limit price and was rejected with a bad-price error. (#227) -
Add
autoWithdraw, which manages an account's scheduled auto-withdraw rule:getRule,setRule,disableRuleandlistRuns.setRuleanddisableRuleneed a freshstepUpToken, and a staleexpectedVersionthrowsRevisionConflictError. (#222) -
Changelog surfaces add
market_data,quickswapandrewards, for output and forlistChangesfilters. Each post section has asurface, the product area it covers, or"unspecified"when it covers more than one. (#223) -
Order and trigger
cancelReasonaddmarket_halted: the exchange halted the market and canceled every open order and trigger of it, attached take-profit and stop-loss included, and released their reserved funds. Fills before the cancel stand, and the market refuses new orders until it trades again. Show it as "market halted", not as a user cancel. (#221) -
Orders carry their exact execution totals.
avgPxis now the exact average execution price, up to 18 decimal places instead of rounded down to 9.cumQuoteis the quote amount the fills used before fees,"0"with no fills.feeTotal({ amount, isRebate, qty }) is the net fee in the order'sfeeAsset: order history andgetDetailsinclude it, open orders leave it out. It covers every fill oncefeeTotal.qtyequalscumQty. (#223) -
Add
changelog, a public reader for the environment's product changelog:listPosts,getPost({ slug })andlistChanges, which filters changes by category, audience, surface and time. The generated protobufs are exported aschangelogPb. (#218) -
fees.getSpotRatesrows addreserveFeeRatePercentandpostOnlyReserveFeeRatePercent, the rates a new order reserves its quote-asset fee at: the highest rate of any VIP tier on the market, so at least the effective rates. Size buy orders by the reserve rate, not the effective one.breakdownlists the components of the effective rates: the VIP tier rates, an optionalmarketMultiplier,accountDiscounts([]when none) and an optionalreferralDiscount, witheffectiveFromandeffectiveToin Unix milliseconds.nextChangeAtis when a component next starts or ends, orundefinedwhen no change is scheduled. (#225) -
subaccounts.getacceptsincludeBalances: trueand then returns the sub-account's currentbalances, in the shape ofbalances.list. It needs the read-balances action on the sub-account or fails with PermissionDenied. When balances cannot be read right now it fails with the retryableAUTH_TEMPORARILY_UNAVAILABLE. WithoutincludeBalances,getis unchanged and returns nobalances. (#224) -
Trigger events add the
"fire_refused"event type: a fire was refused and the trigger stayed live, so it is not terminal. The event'sfireRefusalReasonsays why, using the trigger failure reason labels.listEventsacceptseventType: "fire_refused"as a filter, and trigger failure reasons addaccount_repairing. (#223)
v0.32.1
Patch Changes
- An order's attached
risk.trailingStoptakeslimitPrice, the most its buy-back pays per unit. A selling order's attached trailing stop buys back, and the API now rejects it without this price, solimitPriceis required when the order sells and must be omitted when it buys; the SDK rejects either mismatch withValidationErrorbefore sending. It must be at leastactivationPricewhen both are set.orders.modifyand batch replace pass it through; the API checks it against the order's side. (#216)
v0.32.0
Minor Changes
-
Add a
timeoutMsrequest option, passed to Connect as the call deadline, so timed-out requests reject withTimeoutError. It must be a positive integer of at most 2147483647; other values throwValidationError.AbortSignal.timeout()expiries also map toTimeoutError, whether the signal comes from the caller or an interceptor; previously they rejected as an abort or as aConnectErrorwithCode.Canceled. A caller signal that already expired before the call started still rejects as a non-retryable abort, so retry loops stop instead of spinning on it.isTimeoutAbortErroris exported alongsideisAbortError. (#190) -
Trailing-stop triggers can buy. Pass
side: "buy"with alimitPrice, the most the child pays. It must be at leastactivationPricewhen that is set. A sell trailing stop is still the default and rejectslimitPrice. Trigger configurations decodelimitPricefor a buy trailing stop. (#209) -
orders.cancelAllAfterreturns the armed switch'seffectiveScope:{ accountId, symbolId, side }, where an unsetsymbolIdorsidecovers all of them. It is absent while the switch is disabled. (#209) -
orders.cancelAllreturnslistingStatus. A retry with the samerequestIdreturns"not_retained_read_open_orders"with an emptycancelledOrders, which does not mean nothing was canceled; read open orders instead. (#209) -
orders.cancelAllreturnscancelledOrders: up to 200{ orderId, clientOrderId }entries, oldest first. It also returnstotalCancelled, andtruncatedwhen not every canceled order is listed. (#209) -
Candle timeframes add
3m,2h,6h,8hand3d. (#209) -
Checkpoint asset amounts add
excludedFromValue. When it is true, the asset is not account equity (for example a testnet faucet token): it is listed by amount only,usdis always absent, and it counts toward no USD total. A missingusdon such an asset is not a pricing gap. A response that gives such an asset ausdvalue is rejected withValidationError. (#210) -
Daily claims add the
payout_delayedstate andpayoutDelayReason, a claims error code name such asCLAIM_PAYOUT_UNAVAILABLE. Claims errors addCLAIM_PAYOUT_UNAVAILABLE. (#209) -
claims.claimDailyRewardtakes an input object before the request options, soclaimDailyReward({ subaccountId })pays the daily reward to a subaccount owned by the authenticated root account. OmitsubaccountIdto pay the root account as before. Breaking: pass request options as the second argument, as inclaimDailyReward({}, { signal }); options passed first now throwValidationError. AsubaccountIdthat decodes to zero also throwsValidationErrorinstead of silently paying the root account. The first claim of the day fixes the destination, and retries return that claim and its destination.DailyClaimStatusandClaimDailyRewardResultaddsubaccountId, which isundefinedwhen the reward goes to the root account. Claims errors addSUBACCOUNT_NOT_FOUNDandSUBACCOUNT_INACTIVE. (#202) -
Stop-loss, take-profit and trailing-stop triggers, and the attached
takeProfit,stopLossandtrailingStoplegs of an order, taketriggerPriceSource: "last" | "index". Omitted watches the last traded price as before."index"watches the market's index price and waits while it is stale. Spot markets do not support"mark", which the SDK rejects withValidationError. Attached legs decode theirtriggerPriceSource. (#209) -
Lifecycle flows add
isDelayedon summaries,milestoneTxChainIdon steps andtxChainIdon step activities. The lifecycle reason addsdeposit_source_not_confirmedand the lifecycle source addslifecycle. (#209) -
Buy stop-loss and take-profit triggers accept a
market_iocchild. Amarket_iocchild takes an optionalmaxSlippage: 1 to 10000 bps for a buy, 1 to 9999 for a sell. Without it, the pair's default market slippage applies. Trigger configurations decode the child'smaxSlippage. (#209) -
OrderErrorCodeaddsMAX_OPEN_ORDERS_PER_PAIR, and trigger failure reasons addmax_open_orders_per_pair. Order error details addexistingOrderId: on aCONFLICT_DUPLICATE_CLIENT_ORDER_IDrejection, it is the ID of the order that already holds the client order ID, when that order is known. Batch create rejections carry it too. (#210) -
Breaking:
triggers.modifyno longer takeslimitPrice, because the backend rejects any change to a child's limit price. Cancel the trigger and create a new one instead. (#209) -
OrderErrorCodegains the new order validation, capacity, auction, trigger, TWAP, ladder, batch, and Quick Swap codes. Breaking:TRIGGER_CANCEL_REJECTEDis removed; a refused trigger cancel now returnsTRIGGER_STATUS_INVALIDorTRIGGER_NOT_MODIFIABLE. (#209) -
orders.getDetailsreturnsexecutionsComplete. It is true once the trades across every page add up to the filled quantity; while it is false, read again for the rest. (#209) -
Breaking: order reads drop
terminalReasonandterminalReasonCode. A rejected order carriesrejectReason, theOrderErrorCodethe Orders API returns for the same refusal, such as"TWAP_CAPACITY_REACHED". A canceled order carriescancelReason, such as"user_request","ioc_remainder","stp_expire_maker","replaced","gtd_expired","pair_drain"(market disabled),"cancel_all_after"or"twap_rollover". Both are omitted for every other status. A code newer than this build reads as"UNSPECIFIED"or"unspecified": treat it as a generic refusal or cancel. Onorders.subscribe, order updates dropreasonCode: readrejectReasonfor a rejected order andcancelReasonfor a canceled order or for the replaced update of the order a replace ended.OrderErrorCodeaddsATTACHED_LEGS_EXCEEDED,FEE_ASSET_INVALID,FEE_CEILING_INVALID,UNSUPPORTED_FIELD_SET,TRIGGER_FIRE_LIMIT_REACHED,CONDITION_FLAGS_INVALID,CONDITION_PARAMETER_SET,TWAP_CAPACITY_REACHEDandCHILD_ORDER_INCONSISTENT. (#212) -
orders.subscribe'sonStalereceivesorderIdswhen only those orders are behind. Their rows show an earlier state while the rest of the view is current. A later call replaces the earlier one, andonStale(false)means every order is current again. (#209) -
Breaking: every order and trigger outcome-unknown code (
ORDER_CREATE_OUTCOME_UNKNOWN,ORDER_CANCEL_OUTCOME_UNKNOWN,ORDER_MODIFY_OUTCOME_UNKNOWN,TRIGGER_CREATE_OUTCOME_UNKNOWNandTRIGGER_CONTROL_OUTCOME_UNKNOWN) now throws the new non-retryableOutcomeUnknownErrorinstead of a retryableTimeoutError. The change may already have applied, so read the order by its client order ID, or list triggers by client trigger ID, before sending it again.detail.codenames the operation. A deadline without one of these details is still a retryableTimeoutError. (#209) -
Pair status adds
halted: only cancellations are accepted. (#209) -
Stream
orders.subscribeover the private WebSocket (/v1/ws/private), since the realtime channelsprivate:spot:orders:<account>(JSON and:proto) andprivate:spot:orders:batch-replace:<account>are no longer served.onEventstill receives each changed order complete; keep the copy with the higherversion. A new order now arrives withversion0 while it is still pending. Orders on symbols missing from the catalog are skipped, as order reads already do, instead of reachingonError. New optional callbacks:onSnapshotreceives the account's full live view when the subscription starts and after a server resync, and it takes over snapshot orders fromonEvent.onRemovedreceives IDs of orders that left the live view, including, withoutonSnapshot, orders missing from a resync snapshot.onStalereports when that view is temporarily behind. Subscriptions to the same account share one server subscription, and one that joins later starts from the current live view; a connection carries up to 64 accounts. The stream resumes from its last cursor after a sequence gap, an expired token, a dropped heartbeat, or a reconnect, reporting each interruption throughonCloseandonOpenrather thanonError; token fetch failures along the way still reachonError. Reconnects back off from 0.5 to 10 seconds with jitter; close codes 4400 and 4403 end the stream instead. (#203)Breaking:
orders.subscribethrowsValidationErrorunlessaccountIdis the account's base58 public ID. CustomPolyesterRealtimeimplementations passed asrealtimeClientmust addconnectPrivateOrders.
-...
v0.31.0
Minor Changes
-
Realtime
onErrorcontexts now always carry anError. Server and websocket failures arrive as the newRealtimeError(codeREALTIME_ERROR) with the Centrifugo code onrealtimeCode, instead of plain{ code, message }objects.retryableis true for errors the realtime client is already retrying on its own, such as code 109 (token expired), so callers can skip reporting them. Snapshot failures keep their original typed SDK error. (#193)Browser clients end the session and emit
loggedOutwhen an authenticated RPC is rejected as unauthenticated with the current token, for example when the backend revoked it or the device clock lags. Rejections of a token that has since been replaced, and those arriving while a login or refresh is in flight, are ignored.AccountSignerAuthService.handleRejectedTokenexposes the same check.PreparedTradingWithdrawexposes the signeddeadlineandisExpired(), which turns true a minute before the deadline. Prepare again before resubmitting an expired withdraw, for example after a slow MFA enrollment.
v0.30.2
Patch Changes
patchZipperCatalogSupplycaches the snapshot it returns as already validated, so passing it tocatalog.setSnapshotno longer re-validates the whole catalog on every supply update. (#191)
v0.30.1
Patch Changes
-
Add
rewards.listAwards(alsorewardsService(core)from@polyester/sdk/services/rewards) to list published reward campaign awards for the authenticated root account, newest first. Each award includes its campaign, asset, exactamountBaseUnits,fulfillmentMethod,fulfillmentState,publishedAt, payoutnetwork,fulfillmentRevision,destinationAddress, andtransactionId.limitaccepts 0 through 100 (0 or omitted uses 50), andpageTokenis capped at 256 characters. Requires a session token; API keys are not accepted. (#187) -
Add
rewards.setDestinationto record a write-once payout destination for an award owned by the authenticated root account. Pass the award'sfulfillmentRevisionasexpectedRevision(a positive decimal string) and a client-generatedrequestId(1 through 128 characters, reused on retry);awardIdaccepts 1 through 128 characters anddestinationAddress1 through 512. Requires a session token and a fresh step-up proof viastepUpToken; it does not execute a transfer or mark the award delivered. (#189)