@symmio/trading-react 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/dist/account-layer/index.d.ts +28 -28
  2. package/dist/account-layer/index.js +29 -0
  3. package/dist/account-layer/use-account-balance-info.d.ts +1 -1
  4. package/dist/account-layer/use-account-balance-of.d.ts +1 -1
  5. package/dist/account-layer/use-add-margin.d.ts +2 -2
  6. package/dist/account-layer/use-allocate.d.ts +2 -2
  7. package/dist/account-layer/use-create-sub-accounts.d.ts +2 -2
  8. package/dist/account-layer/use-deallocate.d.ts +2 -2
  9. package/dist/account-layer/use-delete-sub-account.d.ts +2 -2
  10. package/dist/account-layer/use-deposit-and-allocate.d.ts +2 -2
  11. package/dist/account-layer/use-deposit.d.ts +2 -2
  12. package/dist/account-layer/use-edit-account-name.d.ts +2 -2
  13. package/dist/account-layer/use-predicted-next-virtual-account.d.ts +1 -1
  14. package/dist/account-layer/use-remove-margin.d.ts +2 -2
  15. package/dist/account-layer/use-simulate-add-margin.d.ts +1 -1
  16. package/dist/account-layer/use-simulate-allocate.d.ts +1 -1
  17. package/dist/account-layer/use-simulate-create-sub-accounts.d.ts +1 -1
  18. package/dist/account-layer/use-simulate-deallocate.d.ts +1 -1
  19. package/dist/account-layer/use-simulate-delete-sub-account.d.ts +1 -1
  20. package/dist/account-layer/use-simulate-deposit-and-allocate.d.ts +1 -1
  21. package/dist/account-layer/use-simulate-deposit.d.ts +1 -1
  22. package/dist/account-layer/use-simulate-edit-account-name.d.ts +1 -1
  23. package/dist/account-layer/use-simulate-remove-margin.d.ts +1 -1
  24. package/dist/account-layer/use-sub-account-virtual-nonce.d.ts +1 -1
  25. package/dist/account-layer/use-sub-account.d.ts +1 -1
  26. package/dist/account-layer/use-sub-accounts-count-of-user.d.ts +1 -1
  27. package/dist/account-layer/use-user-sub-accounts-addresses.d.ts +1 -1
  28. package/dist/account-layer/use-user-sub-accounts.d.ts +1 -1
  29. package/dist/account-layer/use-virtual-account.d.ts +1 -1
  30. package/dist/account-layer/use-virtual-accounts-addresses-of-sub-account.d.ts +1 -1
  31. package/dist/balance-history/index.d.ts +3 -3
  32. package/dist/balance-history/use-balance-history.d.ts +1 -1
  33. package/dist/balance-history/use-deposit-history.d.ts +1 -1
  34. package/dist/balance-history/use-withdraw-history.d.ts +1 -1
  35. package/dist/collateral/index.d.ts +4 -4
  36. package/dist/collateral/use-approve-collateral.d.ts +2 -2
  37. package/dist/collateral/use-collateral-allowance.d.ts +1 -1
  38. package/dist/collateral/use-collateral-balance.d.ts +1 -1
  39. package/dist/collateral/use-simulate-approve-collateral.d.ts +1 -1
  40. package/dist/error-codes/index.d.ts +2 -2
  41. package/dist/error-codes/use-solver-error-codes.d.ts +1 -1
  42. package/dist/error-codes/use-solver-error-message.d.ts +1 -1
  43. package/dist/errors/index.d.ts +3 -3
  44. package/dist/errors/index.js +3 -0
  45. package/dist/errors/normalize-symm-error.d.ts +1 -1
  46. package/dist/errors/symmio-request-error.d.ts +1 -1
  47. package/dist/fees/index.d.ts +1 -1
  48. package/dist/fees/index.js +2 -0
  49. package/dist/fees/use-fee-for-user.d.ts +1 -1
  50. package/dist/funding-info/index.d.ts +2 -0
  51. package/dist/funding-info/index.d.ts.map +1 -0
  52. package/dist/funding-info/use-funding-info.d.ts +25 -0
  53. package/dist/funding-info/use-funding-info.d.ts.map +1 -0
  54. package/dist/funding-info/use-funding-info.js +27 -0
  55. package/dist/funding-info/use-funding-info.js.map +1 -0
  56. package/dist/index.d.ts +40 -24
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +74 -69
  59. package/dist/instant-layer/index.d.ts +14 -13
  60. package/dist/instant-layer/index.d.ts.map +1 -1
  61. package/dist/instant-layer/index.js +15 -0
  62. package/dist/instant-layer/use-delegation-expiry.d.ts +1 -1
  63. package/dist/instant-layer/use-grant-delegation.d.ts +2 -2
  64. package/dist/instant-layer/use-instant-close-auto.d.ts +1 -1
  65. package/dist/instant-layer/use-instant-close-bulk-auto.d.ts +1 -1
  66. package/dist/instant-layer/use-instant-close-bulk.d.ts +1 -1
  67. package/dist/instant-layer/use-instant-close.d.ts +1 -1
  68. package/dist/instant-layer/use-instant-closes.d.ts +1 -1
  69. package/dist/instant-layer/use-instant-open-auto.d.ts +1 -1
  70. package/dist/instant-layer/use-instant-open-quote-id.d.ts +1 -1
  71. package/dist/instant-layer/use-instant-open-with-tpsl.d.ts +55 -0
  72. package/dist/instant-layer/use-instant-open-with-tpsl.d.ts.map +1 -0
  73. package/dist/instant-layer/use-instant-open-with-tpsl.js +56 -0
  74. package/dist/instant-layer/use-instant-open-with-tpsl.js.map +1 -0
  75. package/dist/instant-layer/use-instant-open.d.ts +1 -1
  76. package/dist/instant-layer/use-instant-opens.d.ts +1 -1
  77. package/dist/instant-layer/use-is-delegation-active.d.ts +1 -1
  78. package/dist/instant-layer/use-simulate-grant-delegation.d.ts +1 -1
  79. package/dist/locked-params/index.d.ts +1 -1
  80. package/dist/locked-params/use-locked-params.d.ts +1 -1
  81. package/dist/market-info/index.d.ts +2 -0
  82. package/dist/market-info/index.d.ts.map +1 -0
  83. package/dist/market-info/use-market-info.d.ts +28 -0
  84. package/dist/market-info/use-market-info.d.ts.map +1 -0
  85. package/dist/market-info/use-market-info.js +27 -0
  86. package/dist/market-info/use-market-info.js.map +1 -0
  87. package/dist/markets/index.d.ts +2 -2
  88. package/dist/markets/index.js +3 -0
  89. package/dist/markets/use-markets.d.ts +1 -1
  90. package/dist/markets/use-onchain-contract-markets.d.ts +1 -1
  91. package/dist/muon/index.d.ts +10 -10
  92. package/dist/muon/use-deallocate-upnl-sig.d.ts +1 -1
  93. package/dist/muon/use-muon-party-a-overview.d.ts +1 -1
  94. package/dist/muon/use-muon-price-range.d.ts +1 -1
  95. package/dist/muon/use-muon-price.d.ts +1 -1
  96. package/dist/muon/use-muon-settle-upnl.d.ts +1 -1
  97. package/dist/muon/use-muon-upnl-a-with-symbol-price.d.ts +1 -1
  98. package/dist/muon/use-muon-upnl-a.d.ts +1 -1
  99. package/dist/muon/use-muon-upnl-b.d.ts +1 -1
  100. package/dist/muon/use-muon-upnl-with-symbol-price.d.ts +1 -1
  101. package/dist/muon/use-muon-upnl.d.ts +1 -1
  102. package/dist/notifications/index.d.ts +1 -1
  103. package/dist/notifications/use-search-notifications.d.ts +1 -1
  104. package/dist/notional-cap/index.d.ts +3 -3
  105. package/dist/notional-cap/use-notional-cap-all.d.ts +1 -1
  106. package/dist/notional-cap/use-notional-cap-by-symbol-id.d.ts +1 -1
  107. package/dist/notional-cap/use-open-interest-by-symbol-id.d.ts +1 -1
  108. package/dist/price-service/index.d.ts +8 -8
  109. package/dist/price-service/index.js +9 -0
  110. package/dist/price-service/use-enigma-price-by-market-id.d.ts +1 -1
  111. package/dist/price-service/use-enigma-price-by-name.d.ts +1 -1
  112. package/dist/price-service/use-enigma-price-service-health.d.ts +1 -1
  113. package/dist/price-service/use-enigma-price-service-metadata.d.ts +1 -1
  114. package/dist/price-service/use-enigma-price-service-prices-by-addresses.d.ts +1 -1
  115. package/dist/price-service/use-enigma-price-service-prices-by-names.d.ts +1 -1
  116. package/dist/price-service/use-enigma-price-service-symbols-info.d.ts +1 -1
  117. package/dist/price-service/use-enigma-prices.d.ts +1 -1
  118. package/dist/provider/index.d.ts +3 -3
  119. package/dist/provider/index.js +4 -0
  120. package/dist/quotes/index.d.ts +15 -15
  121. package/dist/quotes/use-account-liquidation-price.d.ts +4 -7
  122. package/dist/quotes/use-account-liquidation-price.d.ts.map +1 -1
  123. package/dist/quotes/use-account-liquidation-price.js.map +1 -1
  124. package/dist/quotes/use-grouped-quotes.d.ts +1 -1
  125. package/dist/quotes/use-managed-quotes.d.ts +1 -1
  126. package/dist/quotes/use-managed-quotes.d.ts.map +1 -1
  127. package/dist/quotes/use-managed-quotes.js +125 -122
  128. package/dist/quotes/use-managed-quotes.js.map +1 -1
  129. package/dist/quotes/use-party-a-open-positions.d.ts +4 -4
  130. package/dist/quotes/use-party-a-open-positions.js.map +1 -1
  131. package/dist/quotes/use-party-a-pending-quotes.d.ts +1 -1
  132. package/dist/quotes/use-quote-events-by-type.d.ts +1 -1
  133. package/dist/quotes/use-quote-funding.d.ts +1 -1
  134. package/dist/quotes/use-quote-history.d.ts +1 -1
  135. package/dist/quotes/use-quote-price-history.d.ts +1 -1
  136. package/dist/quotes/use-quote.d.ts +1 -1
  137. package/dist/quotes/use-quotes-funding.d.ts +1 -1
  138. package/dist/quotes/use-subgraph-query.d.ts +1 -1
  139. package/dist/tpsl/index.d.ts +8 -7
  140. package/dist/tpsl/index.d.ts.map +1 -1
  141. package/dist/tpsl/tpsl-store.d.ts +84 -0
  142. package/dist/tpsl/tpsl-store.d.ts.map +1 -0
  143. package/dist/tpsl/tpsl-store.js +154 -0
  144. package/dist/tpsl/tpsl-store.js.map +1 -0
  145. package/dist/tpsl/use-delete-quote-tpsl.d.ts +15 -0
  146. package/dist/tpsl/use-delete-quote-tpsl.d.ts.map +1 -0
  147. package/dist/tpsl/use-delete-quote-tpsl.js +31 -0
  148. package/dist/tpsl/use-delete-quote-tpsl.js.map +1 -0
  149. package/dist/tpsl/use-quote-tpsl.d.ts +19 -20
  150. package/dist/tpsl/use-quote-tpsl.d.ts.map +1 -1
  151. package/dist/tpsl/use-quote-tpsl.js +24 -53
  152. package/dist/tpsl/use-quote-tpsl.js.map +1 -1
  153. package/dist/tpsl/use-set-quote-tpsl.d.ts +11 -10
  154. package/dist/tpsl/use-set-quote-tpsl.d.ts.map +1 -1
  155. package/dist/tpsl/use-set-quote-tpsl.js +18 -22
  156. package/dist/tpsl/use-set-quote-tpsl.js.map +1 -1
  157. package/dist/tpsl/use-tpsl-config.d.ts +1 -1
  158. package/dist/tpsl/use-tpsl-signing-spec.d.ts +1 -1
  159. package/dist/tpsl/use-watch-tpsl-notifications.d.ts +1 -1
  160. package/dist/transactions/index.d.ts +3 -3
  161. package/dist/transactions/index.js +3 -0
  162. package/dist/transactions/resolve-write-result.d.ts +1 -1
  163. package/dist/transfers/index.d.ts +1 -1
  164. package/dist/transfers/use-transfer-history.d.ts +1 -1
  165. package/dist/utils/index.d.ts +1 -1
  166. package/dist/wallet/index.d.ts +4 -4
  167. package/dist/wallet/index.js +5 -0
  168. package/dist/wallet/use-connect-wallet.d.ts +1 -1
  169. package/dist/wallet/use-switch-to-symmio-chain.d.ts +1 -1
  170. package/dist/websocket/index.d.ts +1 -1
  171. package/dist/websocket/use-notifications.d.ts +1 -1
  172. package/dist/withdraw/index.d.ts +10 -10
  173. package/dist/withdraw/use-finalize-withdraw-request.d.ts +2 -2
  174. package/dist/withdraw/use-initiate-withdraw.d.ts +2 -2
  175. package/dist/withdraw/use-last-withdraw-request-id.d.ts +1 -1
  176. package/dist/withdraw/use-pending-withdraw-requests.d.ts +1 -1
  177. package/dist/withdraw/use-request-cancel-withdraw.d.ts +2 -2
  178. package/dist/withdraw/use-simulate-finalize-withdraw-request.d.ts +1 -1
  179. package/dist/withdraw/use-simulate-initiate-withdraw.d.ts +1 -1
  180. package/dist/withdraw/use-simulate-request-cancel-withdraw.d.ts +1 -1
  181. package/dist/withdraw/use-withdraw-requests.d.ts +1 -1
  182. package/dist/withdraw/use-withdrawable-time.d.ts +1 -1
  183. package/package.json +7 -5
  184. package/dist/tpsl/tpsl-confirming.d.ts +0 -36
  185. package/dist/tpsl/tpsl-confirming.d.ts.map +0 -1
  186. package/dist/tpsl/tpsl-confirming.js +0 -28
  187. package/dist/tpsl/tpsl-confirming.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"use-managed-quotes.js","names":[],"sources":["../../src/quotes/use-managed-quotes.ts"],"sourcesContent":["\"use client\";\n\nimport {\n classifyQuoteNotificationAction,\n getInstantClosesQueryKey,\n getInstantOpensQueryKey,\n getPartyAOpenPositionsQueryKey,\n getPartyAOpenPositionsQueryOptions,\n getPartyAPendingQuotesQueryKey,\n getPartyAPendingQuotesQueryOptions,\n getPredictedNextVirtualAccountQueryOptions,\n getQuoteQueryKey,\n getQuoteQueryOptions,\n isolationTypeForSide,\n QuoteLifecycle,\n reconcileQuotes,\n shouldAccelerateOnchainReads,\n type Notification,\n type Quote,\n type ReconcileQuotesResult,\n type SocketStatus,\n type UnifiedQuote,\n} from \"@symmio/trading-core\";\nimport { useQueries, useQueryClient } from \"@tanstack/react-query\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { getAddress, type Address } from \"viem\";\nimport { useVirtualAccountsAddressesOfSubAccount } from \"../account-layer/use-virtual-accounts-addresses-of-sub-account\";\nimport { normalizeSymmError } from \"../errors/normalize-symm-error\";\nimport type { SymmioRequestError } from \"../errors/symmio-request-error\";\nimport { useInstantCloses } from \"../instant-layer/use-instant-closes\";\nimport { useInstantOpens } from \"../instant-layer/use-instant-opens\";\nimport { useSymmioChainId } from \"../provider/use-symmio-chain-id\";\nimport { useSymmioConfig } from \"../provider/use-symmio-config\";\nimport { predicateMatch } from \"../utils\";\nimport { useNotifications } from \"../websocket/use-notifications\";\nimport { useOptimisticQuotesStore } from \"./optimistic-quotes-store\";\n\n/**\n * Baseline poll interval (ms) used **only as a fallback** when the live event channel\n * is unavailable (`live` is off, or the notifications socket is not `open`). With the\n * socket up the feature is events-first: there is no idle on-chain poll unless the\n * consumer opts into one via `pollingInterval`.\n */\nconst FALLBACK_POLLING_INTERVAL = 5_000;\n\n/** Accelerated quote-polling interval (ms) while a row is mid-transition. */\nconst ACCELERATED_POLLING_INTERVAL = 1_500;\n\n/**\n * Cap on the live-notification buffer fed back into the merge. Reconciliation is\n * idempotent over already-applied notifications, so only a recent window is kept\n * to bound memory and reprocessing.\n *\n * TODO: check this and packages/trading-react/src/quotes/use-managed-quotes.ts#L188-L206\n */\nconst NOTIFICATION_BUFFER_LIMIT = 100;\n\n/** Stable empty array so the `accounts` memo doesn't churn while no VAs are retained. */\nconst NO_RETAINED_VAS: readonly Address[] = [];\n\n/** Debounce (ms) for coalescing a burst of notifications into one set of read invalidations. */\nconst NOTIFICATION_INVALIDATE_DEBOUNCE = 250;\n\n/**\n * Lifecycle stages that mean an open is in flight, so the hedger instant-opens\n * feed is worth polling. Outside these stages the feed has nothing new (a\n * settled position is tracked by the on-chain reads), so polling it is wasted.\n */\nconst OPEN_INTENT_LIFECYCLES = new Set<QuoteLifecycle>([\n QuoteLifecycle.OPTIMISTIC,\n QuoteLifecycle.PRICE_FILLED,\n QuoteLifecycle.WRITE_ONCHAIN,\n]);\n\n/**\n * Lifecycle stages that mean a close is in flight, so the hedger instant-closes\n * feed is worth polling. Outside these stages there is no pending close, so\n * polling the feed (merely holding open positions) is wasted.\n */\nconst CLOSE_INTENT_LIFECYCLES = new Set<QuoteLifecycle>([QuoteLifecycle.WRITE_ONCHAIN_CLOSE, QuoteLifecycle.CLOSING]);\n\n/**\n * Which underlying quote sources {@link useManagedQuotes} should read. Every\n * source defaults to `true`; set one to `false` to skip its query/subscription\n * entirely (e.g. a screen that never opens instant trades).\n */\nexport interface ManagedQuotesSources {\n /** Read on-chain open positions via `usePartyAOpenPositions`. Default `true`. */\n openPositions?: boolean;\n /** Read on-chain pending quote ids (hydrated per-id) via `usePartyAPendingQuotes`. Default `true`. */\n pendingQuotes?: boolean;\n /** Read pending instant-opens from the hedger via `useInstantOpens`. Default `true`. */\n instantOpens?: boolean;\n /** Read pending instant-closes from the hedger via `useInstantCloses`. Default `true`. */\n instantCloses?: boolean;\n}\n\n/**\n * Parameters for {@link useManagedQuotes}.\n */\nexport interface UseManagedQuotesParameters {\n /** Sub-account (partyA) to manage quotes for. The hook is idle until this is set. */\n partyA?: Address;\n /** Target chain id. Defaults to the connected chain. */\n chainId?: number;\n /**\n * Opt-in idle polling cadence (ms). **Default off** — with `live` notifications the\n * feature is events-first: it does not poll at idle, only (a) accelerates on-chain\n * reads briefly while a row awaits on-chain confirmation (the RPC-lag retry), and\n * (b) falls back to a baseline poll when the event channel is down. Set this to make\n * it poll on a fixed cadence regardless (e.g. a live-inspector panel).\n */\n pollingInterval?: number;\n /** Subscribe to the live notifications stream. Default `true`; set `false` for poll-only. */\n live?: boolean;\n /** Master switch. When `false` every source is idle regardless of `sources`. Default `true`. */\n enabled?: boolean;\n /**\n * Union the sub-account's existing on-chain Virtual Accounts (VAs) — plus the\n * predicted VAs of its pending instant-opens and any VAs seen on the\n * notifications stream — into the on-chain reads. In lowcap each isolated\n * position lives under a VA, so this is required to see the full picture.\n * Default `true`.\n */\n includeVirtualAccounts?: boolean;\n /** Extra accounts to read quotes across (e.g. VAs already known to the consumer). */\n extraAccounts?: readonly Address[];\n /** Per-source toggles; omit to read every source. */\n sources?: ManagedQuotesSources;\n}\n\n/**\n * Value returned by {@link useManagedQuotes}.\n */\nexport interface UseManagedQuotesResult {\n /** Merged, de-duplicated, lifecycle-tagged rows, newest first. */\n quotes: UnifiedQuote[];\n /** The same rows indexed by their stable {@link UnifiedQuote.key}. */\n byKey: Record<string, UnifiedQuote>;\n /** The on-chain `partyA` accounts the quotes were read across (sub-account + VAs + predicted + extras). */\n accounts: Address[];\n /** `true` while any enabled source has not produced its first result. */\n isLoading: boolean;\n /** `true` while any enabled source is fetching (background refetch included). */\n isFetching: boolean;\n /** Live connection status of the notifications socket (`\"closed\"` when `live` is off). */\n socketStatus: SocketStatus;\n /** The first error surfaced by any source, normalized, or `null`. */\n error: SymmioRequestError | null;\n /** Force every enabled source to refetch immediately. */\n refetch: () => void;\n}\n\n/**\n * Orchestrate every quote source for one sub-account — fanned out across every\n * account that holds its positions — into a single, stable, lifecycle-tagged\n * table.\n *\n * In lowcap, isolated positions live under Virtual Accounts (VAs), so a\n * sub-account's quotes are spread across its VAs rather than the sub-account\n * itself. This resolves the full account set — the sub-account, its existing\n * VAs (`useVirtualAccountsAddressesOfSubAccount`), the predicted VAs of its\n * pending instant-opens (`getPredictedNextVirtualAccount`), VAs seen on the\n * notifications stream, and any `extraAccounts` — then reads\n * `getPartyAOpenPositions` and `getPartyAPendingQuotes` (+ per-id `getQuote`\n * hydration) across that set via `useQueries`. Off-chain hedger reads\n * (`useInstantOpens` / `useInstantCloses`) stay scoped to the sub-account.\n *\n * Every source is gated by `sources`, `enabled`, and a set `partyA`, then their\n * snapshots flow through the pure core `reconcileQuotes` (\"active quotes only\" —\n * a quote shows iff it is in a source this tick), stamping each optimistic\n * instant-open with its predicted VA via `instantOpenVaByTempId`. Live\n * notifications (via `useNotifications`, unless `live` is `false`) are applied in\n * the same merge. With `live` notifications the feature is **events-first**: it does\n * not poll at idle, only accelerating the on-chain reads briefly while a row awaits\n * on-chain confirmation (`shouldAccelerateOnchainReads`, the RPC-lag retry), and\n * falling back to a baseline poll only when the event channel is down.\n *\n * Optimistic instant-opens seeded into {@link useOptimisticQuotesStore} are\n * merged in as extra `instantOpens` so a just-submitted trade shows instantly,\n * then cleared once the same `tempQuoteId` lands on-chain.\n *\n * @example\n * ```tsx\n * const { quotes, accounts, socketStatus, isLoading } = useManagedQuotes({ partyA });\n * ```\n */\nexport function useManagedQuotes(parameters: UseManagedQuotesParameters): UseManagedQuotesResult {\n const { partyA, chainId, pollingInterval, live = true, enabled = true } = parameters;\n const config = useSymmioConfig();\n const defaultChainId = useSymmioChainId();\n const resolvedChainId = chainId ?? defaultChainId;\n const includeVirtualAccounts = parameters.includeVirtualAccounts ?? true;\n const extraAccounts = parameters.extraAccounts;\n const sources = parameters.sources;\n const wantOpenPositions = sources?.openPositions ?? true;\n const wantPendingQuotes = sources?.pendingQuotes ?? true;\n const wantInstantOpens = sources?.instantOpens ?? true;\n const wantInstantCloses = sources?.instantCloses ?? true;\n const active = enabled && Boolean(partyA);\n\n /**\n * Identity of the current account set's owner. VA retention (below) is scoped\n * to this `(chainId, partyA)` so switching sub-accounts never carries another\n * account's VAs into the read set.\n */\n const retentionOwner = active && partyA ? `${resolvedChainId}:${partyA.toLowerCase()}` : undefined;\n\n /**\n * VAs retained across the optimistic→on-chain hand-off. A predicted VA leaves\n * `predictedVas` the instant its instant-open lands on-chain (the hedger drops\n * the pending open), while `getVirtualAccountsAddressesOfSubAccount` and the\n * notification `va_address` can lag a poll behind — so without retention we'd\n * stop polling the exact VA the position just landed in, and the row would\n * vanish for a tick before reappearing as its `ONCHAIN` twin. VAs are\n * append-only on-chain, so once discovered we keep reading them while the owner\n * is unchanged. See reference-va-address-resolution in agent memory.\n */\n const [retained, setRetained] = useState<{ owner?: string; vas: Address[] }>({ vas: [] });\n const retainedVas = retained.owner === retentionOwner ? retained.vas : NO_RETAINED_VAS;\n\n /**\n * Notification-driven invalidation. Reads are kept in sync off the live\n * notifications stream — not polling — so the feature works with polling off.\n * `queryClient` and the cache scope (`configKey`) are mirrored into refs so the\n * `onNotification` callback below can stay referentially stable (a new callback\n * identity would resubscribe the socket). The debounce timer coalesces a burst\n * of notifications into one invalidation pass.\n */\n const queryClient = useQueryClient();\n const queryClientRef = useRef(queryClient);\n queryClientRef.current = queryClient;\n const configKey = config.getChainConfigKey(resolvedChainId);\n const configKeyRef = useRef(configKey);\n configKeyRef.current = configKey;\n const invalidateTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n /**\n * Which hedger feeds a debounced notification burst should invalidate. A burst\n * can mix open and close events, so the kinds are accumulated here across the\n * debounce window and read (then reset) when the timer fires — scoping the\n * invalidation to the feeds the events can actually affect.\n */\n const pendingInvalidationRef = useRef<{ opens: boolean; closes: boolean }>({ opens: false, closes: false });\n\n /**\n * Last reconciliation result, kept in a ref so it survives renders without\n * triggering one. Its only remaining job is to feed\n * {@link shouldAccelerateOnchainReads} (and the feed-intent gates) the previous\n * tick's result, since the source queries set their `refetchInterval` before this\n * render's result exists. (\"Active quotes only\" dropped the grace window, and\n * `links` are recomputed fresh on each merge.)\n */\n const previousRef = useRef<ReconcileQuotesResult | undefined>(undefined);\n\n /**\n * Rows anchored on a prior tick (a notification set their `quoteId`) but not yet\n * returned by the on-chain read — the previous merge's `pendingAnchors`. Fed back\n * into {@link reconcileQuotes} so an anchored row keeps showing while the RPC\n * catches up, instead of vanishing once the hedger drops its pending open. Held in\n * a ref so it survives renders without triggering one; the source query that\n * dropped the row drives the recompute that reads it.\n */\n const retainedAnchorsRef = useRef<UnifiedQuote[]>([]);\n\n /**\n * Last tick's socket status, read one render behind (like `previousRef`) to decide\n * whether the live event channel is up. Updated right after `useNotifications` below.\n * When the channel is live the feature is events-first (no idle poll); when it is\n * down we fall back to polling so state still advances without notifications.\n */\n const socketStatusRef = useRef<SocketStatus>(\"closed\");\n\n const optimisticEntries = useOptimisticQuotesStore((state) => state.entries);\n const clearSettled = useOptimisticQuotesStore((state) => state.clearSettled);\n\n /** Live event channel = subscribed (`live`) and the socket was `open` last render. */\n const eventChannelLive = live && socketStatusRef.current === \"open\";\n /** Consumer's opt-in idle cadence (off by default). */\n const idleInterval = pollingInterval && pollingInterval > 0 ? pollingInterval : false;\n\n /**\n * On-chain reads accelerate to {@link ACCELERATED_POLLING_INTERVAL} **only** while a\n * row awaits on-chain confirmation (`WRITE_ONCHAIN` / `WRITE_ONCHAIN_CLOSE` /\n * `CLOSING`) — the RPC-lag retry. Otherwise: no idle poll when the event channel is\n * live (events drive updates) unless the consumer opted into `idleInterval`; a\n * baseline fallback when the channel is down so state still progresses. Read from the\n * previous result because the queries set their interval before this render's result\n * exists (an on-chain poll / notification re-render advances it a tick later).\n */\n const accelerateOnchain = previousRef.current ? shouldAccelerateOnchainReads(previousRef.current) : false;\n const onchainIdleInterval = eventChannelLive ? idleInterval : idleInterval || FALLBACK_POLLING_INTERVAL;\n const refetchInterval = active ? (accelerateOnchain ? ACCELERATED_POLLING_INTERVAL : onchainIdleInterval) : false;\n\n /**\n * Hedger feeds are event-driven while the channel is live: the open/close mutation\n * invalidates the matching feed once and the notifications advance the stage, so they\n * do not poll (unless the consumer opted into `idleInterval`). When the channel is\n * down they poll while the matching flow is in flight, to track it without\n * notifications. `hasOpenIntent` / `hasCloseIntent` come from the previous tick.\n */\n const previousQuotes = previousRef.current?.quotes;\n const hasOpenIntent = previousQuotes?.some((quote) => OPEN_INTENT_LIFECYCLES.has(quote.lifecycle)) ?? false;\n const hasCloseIntent = previousQuotes?.some((quote) => CLOSE_INTENT_LIFECYCLES.has(quote.lifecycle)) ?? false;\n const feedInterval = (hasIntent: boolean) =>\n !eventChannelLive && hasIntent ? ACCELERATED_POLLING_INTERVAL : idleInterval;\n const instantOpensInterval = active && wantInstantOpens ? feedInterval(hasOpenIntent) : false;\n const instantClosesInterval = active && wantInstantCloses ? feedInterval(hasCloseIntent) : false;\n\n /**\n * Off-chain hedger reads — always scoped to the sub-account, never the VAs. Kept\n * `enabled` so a mutation's `onSuccess` invalidation can fetch them on demand, but\n * polled only while the matching flow is in flight (see the interval gates above).\n */\n const instantOpens = useInstantOpens({\n partyA: partyA as Address,\n chainId: resolvedChainId,\n query: { enabled: active && wantInstantOpens, refetchInterval: instantOpensInterval },\n });\n\n const instantCloses = useInstantCloses({\n partyA: partyA as Address,\n chainId: resolvedChainId,\n query: { enabled: active && wantInstantCloses, refetchInterval: instantClosesInterval },\n });\n\n /** The sub-account's existing on-chain VAs. Empty (harmless) when `partyA` is itself a VA. */\n const virtualAccounts = useVirtualAccountsAddressesOfSubAccount({\n subAccount: partyA,\n chainId: resolvedChainId,\n query: { enabled: active && includeVirtualAccounts, refetchInterval },\n });\n\n /**\n * Brand-new-VA bridge: a position can open in a market the sub-account has\n * never traded, landing in a freshly created VA that is not yet in\n * `getVirtualAccountsAddressesOfSubAccount`. The predicted VA below covers it\n * while the instant-open is pending; once it lands on-chain the hedger drops the\n * open and the prediction with it, so VA retention (`retained`, above) keeps the\n * VA in the poll set across the hand-off — the row transitions to `ONCHAIN` in\n * place instead of flickering out and back.\n */\n\n /**\n * Predict the VA each pending instant-open will land in. The set of opens is\n * dynamic, but `useQueries` over a dynamic array is allowed — the hook count\n * stays one regardless of length.\n */\n const pendingOpens = wantInstantOpens ? (instantOpens.data ?? []) : [];\n const predictedVas = useQueries({\n queries: pendingOpens.map((open) => ({\n ...getPredictedNextVirtualAccountQueryOptions(config, {\n subAccount: partyA,\n chainId: resolvedChainId,\n isolationType: isolationTypeForSide(open.positionType),\n symbolId: BigInt(open.marketId),\n query: { enabled: active && includeVirtualAccounts, refetchInterval },\n }),\n })),\n combine: (results) => ({\n byTempId: pendingOpens.reduce<Record<number, Address>>((map, open, index) => {\n const predicted = results[index]?.data;\n if (predicted) map[open.tempQuoteId] = getAddress(predicted);\n return map;\n }, {}),\n addresses: results.map((result) => result.data).filter((address): address is Address => Boolean(address)),\n isLoading: results.some((result) => result.isLoading),\n isFetching: results.some((result) => result.isFetching),\n }),\n });\n\n const [notifications, setNotifications] = useState<Notification[]>([]);\n const { status: socketStatus } = useNotifications({\n account: partyA,\n chainId: resolvedChainId,\n enabled: active && live,\n onNotification: useCallback((notification: Notification) => {\n setNotifications((prev) => [...prev, notification].slice(-NOTIFICATION_BUFFER_LIMIT));\n /**\n * Refetch the authoritative reads off the live event so both tables stay in\n * sync without polling. The on-chain reads always refresh (any lifecycle event\n * can change them); the hedger feeds refresh only for the matching flow, so an\n * open event never re-fetches the closes feed and vice versa. Kinds are\n * accumulated across the debounce window because a burst can mix open and close\n * events. Scoped to this chain (`configKey`); React Query dedups concurrent\n * refetches of the same query.\n */\n const kind = classifyQuoteNotificationAction(notification.lastSeenAction);\n const pending = pendingInvalidationRef.current;\n if (kind === \"open\") pending.opens = true;\n else if (kind === \"close\") pending.closes = true;\n else {\n pending.opens = true;\n pending.closes = true;\n }\n if (invalidateTimerRef.current) clearTimeout(invalidateTimerRef.current);\n invalidateTimerRef.current = setTimeout(() => {\n const client = queryClientRef.current;\n const scope = { configKey: configKeyRef.current };\n const { opens, closes } = pendingInvalidationRef.current;\n pendingInvalidationRef.current = { opens: false, closes: false };\n void client.invalidateQueries({ predicate: predicateMatch(getPartyAOpenPositionsQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getPartyAPendingQuotesQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getQuoteQueryKey, scope) });\n if (opens) void client.invalidateQueries({ predicate: predicateMatch(getInstantOpensQueryKey, scope) });\n if (closes) void client.invalidateQueries({ predicate: predicateMatch(getInstantClosesQueryKey, scope) });\n }, NOTIFICATION_INVALIDATE_DEBOUNCE);\n }, []),\n });\n\n /** Mirror the live socket status into the ref the interval gating reads next render. */\n socketStatusRef.current = socketStatus;\n\n /**\n * One-shot re-sync when the notifications socket **reconnects**. The stream does not\n * replay messages missed while it was down, so on a re-`open` we invalidate the reads\n * once to catch up — this replaces a continuous fallback poll. The first connect is\n * skipped (the queries already fetched on mount).\n */\n const hasBeenOpenRef = useRef(false);\n useEffect(() => {\n if (!live || socketStatus !== \"open\") return;\n if (hasBeenOpenRef.current) {\n const client = queryClientRef.current;\n const scope = { configKey: configKeyRef.current };\n void client.invalidateQueries({ predicate: predicateMatch(getPartyAOpenPositionsQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getPartyAPendingQuotesQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getQuoteQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getInstantOpensQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getInstantClosesQueryKey, scope) });\n }\n hasBeenOpenRef.current = true;\n }, [socketStatus, live]);\n\n /** Clear the pending invalidation timer on unmount. */\n useEffect(() => {\n return () => {\n if (invalidateTimerRef.current) clearTimeout(invalidateTimerRef.current);\n };\n }, []);\n\n /** Distinct VA addresses seen on the notifications stream. */\n const notificationVas = useMemo<Address[]>(() => {\n const seen = new Set<string>();\n const result: Address[] = [];\n for (const notification of notifications) {\n if (!notification.vaAddress) continue;\n const checksummed = getAddress(notification.vaAddress);\n const lower = checksummed.toLowerCase();\n if (seen.has(lower)) continue;\n seen.add(lower);\n result.push(checksummed);\n }\n return result;\n }, [notifications]);\n\n /**\n * The deduplicated (case-insensitive), checksummed set of on-chain accounts to\n * read quotes across — the sub-account, its VAs, the predicted VAs, the\n * notification VAs, and any extras. Order: sub-account first, then the rest.\n */\n const accounts = useMemo<Address[]>(() => {\n if (!active || !partyA) return [];\n const seen = new Set<string>();\n const result: Address[] = [];\n const add = (address: Address) => {\n const checksummed = getAddress(address);\n const lower = checksummed.toLowerCase();\n if (seen.has(lower)) return;\n seen.add(lower);\n result.push(checksummed);\n };\n add(partyA);\n if (includeVirtualAccounts) {\n for (const virtualAccount of virtualAccounts.data ?? []) add(virtualAccount);\n for (const predicted of predictedVas.addresses) add(predicted);\n for (const notificationVa of notificationVas) add(notificationVa);\n for (const retainedVa of retainedVas) add(retainedVa);\n }\n for (const extra of extraAccounts ?? []) add(extra);\n return result;\n }, [\n active,\n partyA,\n includeVirtualAccounts,\n virtualAccounts.data,\n predictedVas.addresses,\n notificationVas,\n retainedVas,\n extraAccounts,\n ]);\n\n /**\n * Accumulate every VA we discover (list + predicted + notification) into the\n * retained set so none ever leaves the poll set mid-hand-off. Monotonic per\n * owner; resets when the owner `(chainId, partyA)` changes. Setting state only\n * when something new appears keeps this from looping.\n */\n useEffect(() => {\n if (!retentionOwner) return;\n const discovered = [...(virtualAccounts.data ?? []), ...predictedVas.addresses, ...notificationVas];\n setRetained((prev) => {\n const carryOver = prev.owner === retentionOwner ? prev.vas : [];\n const seen = new Set(carryOver.map((address) => address.toLowerCase()));\n const next = [...carryOver];\n let changed = prev.owner !== retentionOwner;\n for (const va of discovered) {\n const checksummed = getAddress(va);\n const lower = checksummed.toLowerCase();\n if (seen.has(lower)) continue;\n seen.add(lower);\n next.push(checksummed);\n changed = true;\n }\n return changed ? { owner: retentionOwner, vas: next } : prev;\n });\n }, [retentionOwner, virtualAccounts.data, predictedVas.addresses, notificationVas]);\n\n /** On-chain open positions, fanned out across every account, flattened to one `Quote[]`. */\n const openPositions = useQueries({\n queries: accounts.map((account) => {\n const options = getPartyAOpenPositionsQueryOptions(config, {\n partyA: account,\n chainId: resolvedChainId,\n query: { enabled: active && wantOpenPositions, refetchInterval },\n });\n return {\n ...options,\n queryFn: async () => {\n try {\n return await options.queryFn();\n } catch (err) {\n throw normalizeSymmError(err);\n }\n },\n };\n }),\n combine: (results) => ({\n quotes: results.flatMap((result) => result.data ?? []),\n isLoading: results.some((result) => result.isLoading),\n isFetching: results.some((result) => result.isFetching),\n error: (results.find((result) => result.error)?.error as SymmioRequestError | undefined) ?? null,\n refetch: () => results.forEach((result) => result.refetch()),\n }),\n });\n /** Pending quote ids, fanned out across every account, then hydrated per id. */\n const pendingQuoteIds = useQueries({\n queries: accounts.map((account) => {\n const options = getPartyAPendingQuotesQueryOptions(config, {\n partyA: account,\n chainId: resolvedChainId,\n query: { enabled: active && wantPendingQuotes, refetchInterval },\n });\n return {\n ...options,\n queryFn: async () => {\n try {\n return await options.queryFn();\n } catch (err) {\n throw normalizeSymmError(err);\n }\n },\n };\n }),\n combine: (results) => ({\n ids: results.flatMap((result) => result.data ?? []),\n isLoading: results.some((result) => result.isLoading),\n isFetching: results.some((result) => result.isFetching),\n error: (results.find((result) => result.error)?.error as SymmioRequestError | undefined) ?? null,\n refetch: () => results.forEach((result) => result.refetch()),\n }),\n });\n\n const hydratedPending = useQueries({\n queries: pendingQuoteIds.ids.map((quoteId) => {\n const options = getQuoteQueryOptions(config, {\n quoteId,\n chainId: resolvedChainId,\n query: { enabled: active && wantPendingQuotes, refetchInterval },\n });\n return {\n ...options,\n queryFn: async () => {\n try {\n return await options.queryFn();\n } catch (err) {\n throw normalizeSymmError(err);\n }\n },\n };\n }),\n combine: (results) => ({\n quotes: results.map((result) => result.data).filter((quote): quote is Quote => Boolean(quote)),\n isLoading: results.some((result) => result.isLoading),\n isFetching: results.some((result) => result.isFetching),\n error: (results.find((result) => result.error)?.error as SymmioRequestError | undefined) ?? null,\n }),\n });\n\n const result = useMemo<ReconcileQuotesResult>(() => {\n if (!active || !partyA) {\n previousRef.current = undefined;\n retainedAnchorsRef.current = [];\n return { quotes: [], links: {}, pendingAnchors: [] };\n }\n const seededInstantOpens = [...(instantOpens.data ?? []), ...Object.values(optimisticEntries)];\n const next = reconcileQuotes({\n partyA,\n onchainPositions: wantOpenPositions ? openPositions.quotes : [],\n onchainPendingQuotes: wantPendingQuotes ? hydratedPending.quotes : [],\n instantOpens: wantInstantOpens ? seededInstantOpens : [],\n instantCloses: wantInstantCloses ? (instantCloses.data ?? []) : [],\n instantOpenVaByTempId: predictedVas.byTempId,\n notifications,\n retainedAnchors: retainedAnchorsRef.current,\n });\n previousRef.current = next;\n retainedAnchorsRef.current = next.pendingAnchors;\n return next;\n }, [\n active,\n partyA,\n openPositions.quotes,\n hydratedPending.quotes,\n instantOpens.data,\n instantCloses.data,\n predictedVas.byTempId,\n optimisticEntries,\n notifications,\n wantOpenPositions,\n wantPendingQuotes,\n wantInstantOpens,\n wantInstantCloses,\n ]);\n\n const byKey = useMemo<Record<string, UnifiedQuote>>(() => {\n const map: Record<string, UnifiedQuote> = {};\n for (const quote of result.quotes) map[quote.key] = quote;\n return map;\n }, [result.quotes]);\n\n /**\n * Drop optimistic seeds once their `tempQuoteId` has been **confirmed by the\n * on-chain read** — the linked row carries the polled struct (`raw.onchain`).\n * Clearing on the notification link alone would drop the seed while the row is\n * still `WRITE_ONCHAIN`, before any source but the notification holds it, so the\n * row would flicker out until the RPC catches up.\n */\n useEffect(() => {\n const settled = Object.keys(optimisticEntries)\n .map(Number)\n .filter((tempQuoteId) => {\n const key = result.links[tempQuoteId];\n return key !== undefined && byKey[key]?.raw.onchain !== undefined;\n });\n if (settled.length > 0) clearSettled(settled);\n }, [result, byKey, optimisticEntries, clearSettled]);\n\n const isLoading =\n (active && includeVirtualAccounts && virtualAccounts.isLoading) ||\n (active && includeVirtualAccounts && predictedVas.isLoading) ||\n (active && wantOpenPositions && openPositions.isLoading) ||\n (active && wantPendingQuotes && (pendingQuoteIds.isLoading || hydratedPending.isLoading)) ||\n (active && wantInstantOpens && instantOpens.isLoading) ||\n (active && wantInstantCloses && instantCloses.isLoading);\n\n const isFetching =\n (includeVirtualAccounts && (virtualAccounts.isFetching || predictedVas.isFetching)) ||\n (wantOpenPositions && openPositions.isFetching) ||\n (wantPendingQuotes && (pendingQuoteIds.isFetching || hydratedPending.isFetching)) ||\n (wantInstantOpens && instantOpens.isFetching) ||\n (wantInstantCloses && instantCloses.isFetching);\n\n const error =\n openPositions.error ??\n pendingQuoteIds.error ??\n hydratedPending.error ??\n virtualAccounts.error ??\n instantOpens.error ??\n instantCloses.error ??\n null;\n\n /**\n * `openPositions` / `pendingQuoteIds` are `useQueries` fan-outs (no single\n * query handle), so their combined results expose a `refetch` that fires every\n * per-account query. Refetching the ids re-drives the per-id hydration.\n */\n const refetchOpenPositions = openPositions.refetch;\n const refetchPendingQuoteIds = pendingQuoteIds.refetch;\n const refetch = useCallback(() => {\n if (includeVirtualAccounts) virtualAccounts.refetch();\n if (wantOpenPositions) refetchOpenPositions();\n if (wantPendingQuotes) refetchPendingQuoteIds();\n if (wantInstantOpens) instantOpens.refetch();\n if (wantInstantCloses) instantCloses.refetch();\n }, [\n includeVirtualAccounts,\n wantOpenPositions,\n wantPendingQuotes,\n wantInstantOpens,\n wantInstantCloses,\n virtualAccounts,\n refetchOpenPositions,\n refetchPendingQuoteIds,\n instantOpens,\n instantCloses,\n ]);\n\n return {\n quotes: result.quotes,\n byKey,\n accounts,\n isLoading: Boolean(isLoading),\n isFetching: Boolean(isFetching),\n socketStatus: live ? socketStatus : \"closed\",\n error,\n refetch,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-managed-quotes.js","names":[],"sources":["../../src/quotes/use-managed-quotes.ts"],"sourcesContent":["\"use client\";\n\nimport {\n classifyQuoteNotificationAction,\n getInstantClosesQueryKey,\n getInstantOpensQueryKey,\n getPartyAOpenPositionsQueryKey,\n getPartyAOpenPositionsQueryOptions,\n getPartyAPendingQuotesQueryKey,\n getPartyAPendingQuotesQueryOptions,\n getPredictedNextVirtualAccountQueryOptions,\n getQuoteQueryKey,\n getQuoteQueryOptions,\n isolationTypeForSide,\n QuoteLifecycle,\n reconcileQuotes,\n shouldAccelerateOnchainReads,\n type Notification,\n type Quote,\n type ReconcileQuotesResult,\n type SocketStatus,\n type UnifiedQuote,\n} from \"@symmio/trading-core\";\nimport { useQueries, useQueryClient } from \"@tanstack/react-query\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { getAddress, type Address } from \"viem\";\nimport { useVirtualAccountsAddressesOfSubAccount } from \"../account-layer/use-virtual-accounts-addresses-of-sub-account\";\nimport { normalizeSymmError } from \"../errors/normalize-symm-error\";\nimport type { SymmioRequestError } from \"../errors/symmio-request-error\";\nimport { useInstantCloses } from \"../instant-layer/use-instant-closes\";\nimport { useInstantOpens } from \"../instant-layer/use-instant-opens\";\nimport { useSymmioChainId } from \"../provider/use-symmio-chain-id\";\nimport { useSymmioConfig } from \"../provider/use-symmio-config\";\nimport { useTpSlStore } from \"../tpsl/tpsl-store\";\nimport { predicateMatch } from \"../utils\";\nimport { useNotifications } from \"../websocket/use-notifications\";\nimport { useOptimisticQuotesStore } from \"./optimistic-quotes-store\";\n\n/**\n * Baseline poll interval (ms) used **only as a fallback** when the live event channel\n * is unavailable (`live` is off, or the notifications socket is not `open`). With the\n * socket up the feature is events-first: there is no idle on-chain poll unless the\n * consumer opts into one via `pollingInterval`.\n */\nconst FALLBACK_POLLING_INTERVAL = 5_000;\n\n/** Accelerated quote-polling interval (ms) while a row is mid-transition. */\nconst ACCELERATED_POLLING_INTERVAL = 1_500;\n\n/**\n * Cap on the live-notification buffer fed back into the merge. Reconciliation is\n * idempotent over already-applied notifications, so only a recent window is kept\n * to bound memory and reprocessing.\n *\n * TODO: check this and packages/trading-react/src/quotes/use-managed-quotes.ts#L188-L206\n */\nconst NOTIFICATION_BUFFER_LIMIT = 100;\n\n/** Stable empty array so the `accounts` memo doesn't churn while no VAs are retained. */\nconst NO_RETAINED_VAS: readonly Address[] = [];\n\n/** Debounce (ms) for coalescing a burst of notifications into one set of read invalidations. */\nconst NOTIFICATION_INVALIDATE_DEBOUNCE = 250;\n\n/**\n * Lifecycle stages that mean an open is in flight, so the hedger instant-opens\n * feed is worth polling. Outside these stages the feed has nothing new (a\n * settled position is tracked by the on-chain reads), so polling it is wasted.\n */\nconst OPEN_INTENT_LIFECYCLES = new Set<QuoteLifecycle>([\n QuoteLifecycle.OPTIMISTIC,\n QuoteLifecycle.PRICE_FILLED,\n QuoteLifecycle.WRITE_ONCHAIN,\n]);\n\n/**\n * Lifecycle stages that mean a close is in flight, so the hedger instant-closes\n * feed is worth polling. Outside these stages there is no pending close, so\n * polling the feed (merely holding open positions) is wasted.\n */\nconst CLOSE_INTENT_LIFECYCLES = new Set<QuoteLifecycle>([QuoteLifecycle.WRITE_ONCHAIN_CLOSE, QuoteLifecycle.CLOSING]);\n\n/**\n * Which underlying quote sources {@link useManagedQuotes} should read. Every\n * source defaults to `true`; set one to `false` to skip its query/subscription\n * entirely (e.g. a screen that never opens instant trades).\n */\nexport interface ManagedQuotesSources {\n /** Read on-chain open positions via `usePartyAOpenPositions`. Default `true`. */\n openPositions?: boolean;\n /** Read on-chain pending quote ids (hydrated per-id) via `usePartyAPendingQuotes`. Default `true`. */\n pendingQuotes?: boolean;\n /** Read pending instant-opens from the hedger via `useInstantOpens`. Default `true`. */\n instantOpens?: boolean;\n /** Read pending instant-closes from the hedger via `useInstantCloses`. Default `true`. */\n instantCloses?: boolean;\n}\n\n/**\n * Parameters for {@link useManagedQuotes}.\n */\nexport interface UseManagedQuotesParameters {\n /** Sub-account (partyA) to manage quotes for. The hook is idle until this is set. */\n partyA?: Address;\n /** Target chain id. Defaults to the connected chain. */\n chainId?: number;\n /**\n * Opt-in idle polling cadence (ms). **Default off** — with `live` notifications the\n * feature is events-first: it does not poll at idle, only (a) accelerates on-chain\n * reads briefly while a row awaits on-chain confirmation (the RPC-lag retry), and\n * (b) falls back to a baseline poll when the event channel is down. Set this to make\n * it poll on a fixed cadence regardless (e.g. a live-inspector panel).\n */\n pollingInterval?: number;\n /** Subscribe to the live notifications stream. Default `true`; set `false` for poll-only. */\n live?: boolean;\n /** Master switch. When `false` every source is idle regardless of `sources`. Default `true`. */\n enabled?: boolean;\n /**\n * Union the sub-account's existing on-chain Virtual Accounts (VAs) — plus the\n * predicted VAs of its pending instant-opens and any VAs seen on the\n * notifications stream — into the on-chain reads. In lowcap each isolated\n * position lives under a VA, so this is required to see the full picture.\n * Default `true`.\n */\n includeVirtualAccounts?: boolean;\n /** Extra accounts to read quotes across (e.g. VAs already known to the consumer). */\n extraAccounts?: readonly Address[];\n /** Per-source toggles; omit to read every source. */\n sources?: ManagedQuotesSources;\n}\n\n/**\n * Value returned by {@link useManagedQuotes}.\n */\nexport interface UseManagedQuotesResult {\n /** Merged, de-duplicated, lifecycle-tagged rows, newest first. */\n quotes: UnifiedQuote[];\n /** The same rows indexed by their stable {@link UnifiedQuote.key}. */\n byKey: Record<string, UnifiedQuote>;\n /** The on-chain `partyA` accounts the quotes were read across (sub-account + VAs + predicted + extras). */\n accounts: Address[];\n /** `true` while any enabled source has not produced its first result. */\n isLoading: boolean;\n /** `true` while any enabled source is fetching (background refetch included). */\n isFetching: boolean;\n /** Live connection status of the notifications socket (`\"closed\"` when `live` is off). */\n socketStatus: SocketStatus;\n /** The first error surfaced by any source, normalized, or `null`. */\n error: SymmioRequestError | null;\n /** Force every enabled source to refetch immediately. */\n refetch: () => void;\n}\n\n/**\n * Orchestrate every quote source for one sub-account — fanned out across every\n * account that holds its positions — into a single, stable, lifecycle-tagged\n * table.\n *\n * In lowcap, isolated positions live under Virtual Accounts (VAs), so a\n * sub-account's quotes are spread across its VAs rather than the sub-account\n * itself. This resolves the full account set — the sub-account, its existing\n * VAs (`useVirtualAccountsAddressesOfSubAccount`), the predicted VAs of its\n * pending instant-opens (`getPredictedNextVirtualAccount`), VAs seen on the\n * notifications stream, and any `extraAccounts` — then reads\n * `getPartyAOpenPositions` and `getPartyAPendingQuotes` (+ per-id `getQuote`\n * hydration) across that set via `useQueries`. Off-chain hedger reads\n * (`useInstantOpens` / `useInstantCloses`) stay scoped to the sub-account.\n *\n * Every source is gated by `sources`, `enabled`, and a set `partyA`, then their\n * snapshots flow through the pure core `reconcileQuotes` (\"active quotes only\" —\n * a quote shows iff it is in a source this tick), stamping each optimistic\n * instant-open with its predicted VA via `instantOpenVaByTempId`. Live\n * notifications (via `useNotifications`, unless `live` is `false`) are applied in\n * the same merge. With `live` notifications the feature is **events-first**: it does\n * not poll at idle, only accelerating the on-chain reads briefly while a row awaits\n * on-chain confirmation (`shouldAccelerateOnchainReads`, the RPC-lag retry), and\n * falling back to a baseline poll only when the event channel is down.\n *\n * Optimistic instant-opens seeded into {@link useOptimisticQuotesStore} are\n * merged in as extra `instantOpens` so a just-submitted trade shows instantly,\n * then cleared once the same `tempQuoteId` lands on-chain.\n *\n * @example\n * ```tsx\n * const { quotes, accounts, socketStatus, isLoading } = useManagedQuotes({ partyA });\n * ```\n */\nexport function useManagedQuotes(parameters: UseManagedQuotesParameters): UseManagedQuotesResult {\n const { partyA, chainId, pollingInterval, live = true, enabled = true } = parameters;\n const config = useSymmioConfig();\n const defaultChainId = useSymmioChainId();\n const resolvedChainId = chainId ?? defaultChainId;\n const includeVirtualAccounts = parameters.includeVirtualAccounts ?? true;\n const extraAccounts = parameters.extraAccounts;\n const sources = parameters.sources;\n const wantOpenPositions = sources?.openPositions ?? true;\n const wantPendingQuotes = sources?.pendingQuotes ?? true;\n const wantInstantOpens = sources?.instantOpens ?? true;\n const wantInstantCloses = sources?.instantCloses ?? true;\n const active = enabled && Boolean(partyA);\n\n /**\n * Identity of the current account set's owner. VA retention (below) is scoped\n * to this `(chainId, partyA)` so switching sub-accounts never carries another\n * account's VAs into the read set.\n */\n const retentionOwner = active && partyA ? `${resolvedChainId}:${partyA.toLowerCase()}` : undefined;\n\n /**\n * VAs retained across the optimistic→on-chain hand-off. A predicted VA leaves\n * `predictedVas` the instant its instant-open lands on-chain (the hedger drops\n * the pending open), while `getVirtualAccountsAddressesOfSubAccount` and the\n * notification `va_address` can lag a poll behind — so without retention we'd\n * stop polling the exact VA the position just landed in, and the row would\n * vanish for a tick before reappearing as its `ONCHAIN` twin. VAs are\n * append-only on-chain, so once discovered we keep reading them while the owner\n * is unchanged. See reference-va-address-resolution in agent memory.\n */\n const [retained, setRetained] = useState<{ owner?: string; vas: Address[] }>({ vas: [] });\n const retainedVas = retained.owner === retentionOwner ? retained.vas : NO_RETAINED_VAS;\n\n /**\n * Notification-driven invalidation. Reads are kept in sync off the live\n * notifications stream — not polling — so the feature works with polling off.\n * `queryClient` and the cache scope (`configKey`) are mirrored into refs so the\n * `onNotification` callback below can stay referentially stable (a new callback\n * identity would resubscribe the socket). The debounce timer coalesces a burst\n * of notifications into one invalidation pass.\n */\n const queryClient = useQueryClient();\n const queryClientRef = useRef(queryClient);\n queryClientRef.current = queryClient;\n const configKey = config.getChainConfigKey(resolvedChainId);\n const configKeyRef = useRef(configKey);\n configKeyRef.current = configKey;\n const invalidateTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n /**\n * Which hedger feeds a debounced notification burst should invalidate. A burst\n * can mix open and close events, so the kinds are accumulated here across the\n * debounce window and read (then reset) when the timer fires — scoping the\n * invalidation to the feeds the events can actually affect.\n */\n const pendingInvalidationRef = useRef<{ opens: boolean; closes: boolean }>({ opens: false, closes: false });\n\n /**\n * Last reconciliation result, kept in a ref so it survives renders without\n * triggering one. Its only remaining job is to feed\n * {@link shouldAccelerateOnchainReads} (and the feed-intent gates) the previous\n * tick's result, since the source queries set their `refetchInterval` before this\n * render's result exists. (\"Active quotes only\" dropped the grace window, and\n * `links` are recomputed fresh on each merge.)\n */\n const previousRef = useRef<ReconcileQuotesResult | undefined>(undefined);\n\n /**\n * Rows anchored on a prior tick (a notification set their `quoteId`) but not yet\n * returned by the on-chain read — the previous merge's `pendingAnchors`. Fed back\n * into {@link reconcileQuotes} so an anchored row keeps showing while the RPC\n * catches up, instead of vanishing once the hedger drops its pending open. Held in\n * a ref so it survives renders without triggering one; the source query that\n * dropped the row drives the recompute that reads it.\n */\n const retainedAnchorsRef = useRef<UnifiedQuote[]>([]);\n\n /**\n * Last tick's socket status, read one render behind (like `previousRef`) to decide\n * whether the live event channel is up. Updated right after `useNotifications` below.\n * When the channel is live the feature is events-first (no idle poll); when it is\n * down we fall back to polling so state still advances without notifications.\n */\n const socketStatusRef = useRef<SocketStatus>(\"closed\");\n\n const optimisticEntries = useOptimisticQuotesStore((state) => state.entries);\n const clearSettled = useOptimisticQuotesStore((state) => state.clearSettled);\n\n /** Live event channel = subscribed (`live`) and the socket was `open` last render. */\n const eventChannelLive = live && socketStatusRef.current === \"open\";\n /** Consumer's opt-in idle cadence (off by default). */\n const idleInterval = pollingInterval && pollingInterval > 0 ? pollingInterval : false;\n\n /**\n * On-chain reads accelerate to {@link ACCELERATED_POLLING_INTERVAL} **only** while a\n * row awaits on-chain confirmation (`WRITE_ONCHAIN` / `WRITE_ONCHAIN_CLOSE` /\n * `CLOSING`) — the RPC-lag retry. Otherwise: no idle poll when the event channel is\n * live (events drive updates) unless the consumer opted into `idleInterval`; a\n * baseline fallback when the channel is down so state still progresses. Read from the\n * previous result because the queries set their interval before this render's result\n * exists (an on-chain poll / notification re-render advances it a tick later).\n */\n const accelerateOnchain = previousRef.current ? shouldAccelerateOnchainReads(previousRef.current) : false;\n const onchainIdleInterval = eventChannelLive ? idleInterval : idleInterval || FALLBACK_POLLING_INTERVAL;\n const refetchInterval = active ? (accelerateOnchain ? ACCELERATED_POLLING_INTERVAL : onchainIdleInterval) : false;\n\n /**\n * Hedger feeds are event-driven while the channel is live: the open/close mutation\n * invalidates the matching feed once and the notifications advance the stage, so they\n * do not poll (unless the consumer opted into `idleInterval`). When the channel is\n * down they poll while the matching flow is in flight, to track it without\n * notifications. `hasOpenIntent` / `hasCloseIntent` come from the previous tick.\n */\n const previousQuotes = previousRef.current?.quotes;\n const hasOpenIntent = previousQuotes?.some((quote) => OPEN_INTENT_LIFECYCLES.has(quote.lifecycle)) ?? false;\n const hasCloseIntent = previousQuotes?.some((quote) => CLOSE_INTENT_LIFECYCLES.has(quote.lifecycle)) ?? false;\n const feedInterval = (hasIntent: boolean) =>\n !eventChannelLive && hasIntent ? ACCELERATED_POLLING_INTERVAL : idleInterval;\n const instantOpensInterval = active && wantInstantOpens ? feedInterval(hasOpenIntent) : false;\n const instantClosesInterval = active && wantInstantCloses ? feedInterval(hasCloseIntent) : false;\n\n /**\n * Off-chain hedger reads — always scoped to the sub-account, never the VAs. Kept\n * `enabled` so a mutation's `onSuccess` invalidation can fetch them on demand, but\n * polled only while the matching flow is in flight (see the interval gates above).\n */\n const instantOpens = useInstantOpens({\n partyA: partyA as Address,\n chainId: resolvedChainId,\n query: { enabled: active && wantInstantOpens, refetchInterval: instantOpensInterval },\n });\n\n const instantCloses = useInstantCloses({\n partyA: partyA as Address,\n chainId: resolvedChainId,\n query: { enabled: active && wantInstantCloses, refetchInterval: instantClosesInterval },\n });\n\n /** The sub-account's existing on-chain VAs. Empty (harmless) when `partyA` is itself a VA. */\n const virtualAccounts = useVirtualAccountsAddressesOfSubAccount({\n subAccount: partyA,\n chainId: resolvedChainId,\n query: { enabled: active && includeVirtualAccounts, refetchInterval },\n });\n\n /**\n * Brand-new-VA bridge: a position can open in a market the sub-account has\n * never traded, landing in a freshly created VA that is not yet in\n * `getVirtualAccountsAddressesOfSubAccount`. The predicted VA below covers it\n * while the instant-open is pending; once it lands on-chain the hedger drops the\n * open and the prediction with it, so VA retention (`retained`, above) keeps the\n * VA in the poll set across the hand-off — the row transitions to `ONCHAIN` in\n * place instead of flickering out and back.\n */\n\n /**\n * Predict the VA each pending instant-open will land in. The set of opens is\n * dynamic, but `useQueries` over a dynamic array is allowed — the hook count\n * stays one regardless of length.\n */\n const pendingOpens = wantInstantOpens ? (instantOpens.data ?? []) : [];\n const predictedVas = useQueries({\n queries: pendingOpens.map((open) => ({\n ...getPredictedNextVirtualAccountQueryOptions(config, {\n subAccount: partyA,\n chainId: resolvedChainId,\n isolationType: isolationTypeForSide(open.positionType),\n symbolId: BigInt(open.marketId),\n query: { enabled: active && includeVirtualAccounts, refetchInterval },\n }),\n })),\n combine: (results) => ({\n byTempId: pendingOpens.reduce<Record<number, Address>>((map, open, index) => {\n const predicted = results[index]?.data;\n if (predicted) map[open.tempQuoteId] = getAddress(predicted);\n return map;\n }, {}),\n addresses: results.map((result) => result.data).filter((address): address is Address => Boolean(address)),\n isLoading: results.some((result) => result.isLoading),\n isFetching: results.some((result) => result.isFetching),\n }),\n });\n\n const [notifications, setNotifications] = useState<Notification[]>([]);\n const { status: socketStatus } = useNotifications({\n account: partyA,\n chainId: resolvedChainId,\n enabled: active && live,\n onNotification: useCallback((notification: Notification) => {\n setNotifications((prev) => [...prev, notification].slice(-NOTIFICATION_BUFFER_LIMIT));\n // Solver notification carries both `tempQuoteId` and the on-chain\n // `quoteId` on the frame that anchors a pre-chain quote. Link the two\n // in the TP/SL store so a record that was written under the temp id\n // (via `useSetQuoteTpSl` post-instant-open) is instantly reachable via\n // the on-chain id once the anchor lands — no re-fetch needed.\n const tempId = notification.tempQuoteId;\n const onchainStr = notification.quoteId;\n if (tempId && onchainStr && onchainStr !== `${tempId}`) {\n useTpSlStore.getState().link(BigInt(tempId), BigInt(onchainStr));\n }\n /**\n * Refetch the authoritative reads off the live event so both tables stay in\n * sync without polling. The on-chain reads always refresh (any lifecycle event\n * can change them); the hedger feeds refresh only for the matching flow, so an\n * open event never re-fetches the closes feed and vice versa. Kinds are\n * accumulated across the debounce window because a burst can mix open and close\n * events. Scoped to this chain (`configKey`); React Query dedups concurrent\n * refetches of the same query.\n */\n const kind = classifyQuoteNotificationAction(notification.lastSeenAction);\n const pending = pendingInvalidationRef.current;\n if (kind === \"open\") pending.opens = true;\n else if (kind === \"close\") pending.closes = true;\n else {\n pending.opens = true;\n pending.closes = true;\n }\n if (invalidateTimerRef.current) clearTimeout(invalidateTimerRef.current);\n invalidateTimerRef.current = setTimeout(() => {\n const client = queryClientRef.current;\n const scope = { configKey: configKeyRef.current };\n const { opens, closes } = pendingInvalidationRef.current;\n pendingInvalidationRef.current = { opens: false, closes: false };\n void client.invalidateQueries({ predicate: predicateMatch(getPartyAOpenPositionsQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getPartyAPendingQuotesQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getQuoteQueryKey, scope) });\n if (opens) void client.invalidateQueries({ predicate: predicateMatch(getInstantOpensQueryKey, scope) });\n if (closes) void client.invalidateQueries({ predicate: predicateMatch(getInstantClosesQueryKey, scope) });\n }, NOTIFICATION_INVALIDATE_DEBOUNCE);\n }, []),\n });\n\n /** Mirror the live socket status into the ref the interval gating reads next render. */\n socketStatusRef.current = socketStatus;\n\n /**\n * One-shot re-sync when the notifications socket **reconnects**. The stream does not\n * replay messages missed while it was down, so on a re-`open` we invalidate the reads\n * once to catch up — this replaces a continuous fallback poll. The first connect is\n * skipped (the queries already fetched on mount).\n */\n const hasBeenOpenRef = useRef(false);\n useEffect(() => {\n if (!live || socketStatus !== \"open\") return;\n if (hasBeenOpenRef.current) {\n const client = queryClientRef.current;\n const scope = { configKey: configKeyRef.current };\n void client.invalidateQueries({ predicate: predicateMatch(getPartyAOpenPositionsQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getPartyAPendingQuotesQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getQuoteQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getInstantOpensQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getInstantClosesQueryKey, scope) });\n }\n hasBeenOpenRef.current = true;\n }, [socketStatus, live]);\n\n /** Clear the pending invalidation timer on unmount. */\n useEffect(() => {\n return () => {\n if (invalidateTimerRef.current) clearTimeout(invalidateTimerRef.current);\n };\n }, []);\n\n /** Distinct VA addresses seen on the notifications stream. */\n const notificationVas = useMemo<Address[]>(() => {\n const seen = new Set<string>();\n const result: Address[] = [];\n for (const notification of notifications) {\n if (!notification.vaAddress) continue;\n const checksummed = getAddress(notification.vaAddress);\n const lower = checksummed.toLowerCase();\n if (seen.has(lower)) continue;\n seen.add(lower);\n result.push(checksummed);\n }\n return result;\n }, [notifications]);\n\n /**\n * The deduplicated (case-insensitive), checksummed set of on-chain accounts to\n * read quotes across — the sub-account, its VAs, the predicted VAs, the\n * notification VAs, and any extras. Order: sub-account first, then the rest.\n */\n const accounts = useMemo<Address[]>(() => {\n if (!active || !partyA) return [];\n const seen = new Set<string>();\n const result: Address[] = [];\n const add = (address: Address) => {\n const checksummed = getAddress(address);\n const lower = checksummed.toLowerCase();\n if (seen.has(lower)) return;\n seen.add(lower);\n result.push(checksummed);\n };\n add(partyA);\n if (includeVirtualAccounts) {\n for (const virtualAccount of virtualAccounts.data ?? []) add(virtualAccount);\n for (const predicted of predictedVas.addresses) add(predicted);\n for (const notificationVa of notificationVas) add(notificationVa);\n for (const retainedVa of retainedVas) add(retainedVa);\n }\n for (const extra of extraAccounts ?? []) add(extra);\n return result;\n }, [\n active,\n partyA,\n includeVirtualAccounts,\n virtualAccounts.data,\n predictedVas.addresses,\n notificationVas,\n retainedVas,\n extraAccounts,\n ]);\n\n /**\n * Accumulate every VA we discover (list + predicted + notification) into the\n * retained set so none ever leaves the poll set mid-hand-off. Monotonic per\n * owner; resets when the owner `(chainId, partyA)` changes. Setting state only\n * when something new appears keeps this from looping.\n */\n useEffect(() => {\n if (!retentionOwner) return;\n const discovered = [...(virtualAccounts.data ?? []), ...predictedVas.addresses, ...notificationVas];\n setRetained((prev) => {\n const carryOver = prev.owner === retentionOwner ? prev.vas : [];\n const seen = new Set(carryOver.map((address) => address.toLowerCase()));\n const next = [...carryOver];\n let changed = prev.owner !== retentionOwner;\n for (const va of discovered) {\n const checksummed = getAddress(va);\n const lower = checksummed.toLowerCase();\n if (seen.has(lower)) continue;\n seen.add(lower);\n next.push(checksummed);\n changed = true;\n }\n return changed ? { owner: retentionOwner, vas: next } : prev;\n });\n }, [retentionOwner, virtualAccounts.data, predictedVas.addresses, notificationVas]);\n\n /** On-chain open positions, fanned out across every account, flattened to one `Quote[]`. */\n const openPositions = useQueries({\n queries: accounts.map((account) => {\n const options = getPartyAOpenPositionsQueryOptions(config, {\n partyA: account,\n chainId: resolvedChainId,\n query: { enabled: active && wantOpenPositions, refetchInterval },\n });\n return {\n ...options,\n queryFn: async () => {\n try {\n return await options.queryFn();\n } catch (err) {\n throw normalizeSymmError(err);\n }\n },\n };\n }),\n combine: (results) => ({\n quotes: results.flatMap((result) => result.data ?? []),\n isLoading: results.some((result) => result.isLoading),\n isFetching: results.some((result) => result.isFetching),\n error: (results.find((result) => result.error)?.error as SymmioRequestError | undefined) ?? null,\n refetch: () => results.forEach((result) => result.refetch()),\n }),\n });\n /** Pending quote ids, fanned out across every account, then hydrated per id. */\n const pendingQuoteIds = useQueries({\n queries: accounts.map((account) => {\n const options = getPartyAPendingQuotesQueryOptions(config, {\n partyA: account,\n chainId: resolvedChainId,\n query: { enabled: active && wantPendingQuotes, refetchInterval },\n });\n return {\n ...options,\n queryFn: async () => {\n try {\n return await options.queryFn();\n } catch (err) {\n throw normalizeSymmError(err);\n }\n },\n };\n }),\n combine: (results) => ({\n ids: results.flatMap((result) => result.data ?? []),\n isLoading: results.some((result) => result.isLoading),\n isFetching: results.some((result) => result.isFetching),\n error: (results.find((result) => result.error)?.error as SymmioRequestError | undefined) ?? null,\n refetch: () => results.forEach((result) => result.refetch()),\n }),\n });\n\n const hydratedPending = useQueries({\n queries: pendingQuoteIds.ids.map((quoteId) => {\n const options = getQuoteQueryOptions(config, {\n quoteId,\n chainId: resolvedChainId,\n query: { enabled: active && wantPendingQuotes, refetchInterval },\n });\n return {\n ...options,\n queryFn: async () => {\n try {\n return await options.queryFn();\n } catch (err) {\n throw normalizeSymmError(err);\n }\n },\n };\n }),\n combine: (results) => ({\n quotes: results.map((result) => result.data).filter((quote): quote is Quote => Boolean(quote)),\n isLoading: results.some((result) => result.isLoading),\n isFetching: results.some((result) => result.isFetching),\n error: (results.find((result) => result.error)?.error as SymmioRequestError | undefined) ?? null,\n }),\n });\n\n const result = useMemo<ReconcileQuotesResult>(() => {\n if (!active || !partyA) {\n previousRef.current = undefined;\n retainedAnchorsRef.current = [];\n return { quotes: [], links: {}, pendingAnchors: [] };\n }\n const seededInstantOpens = [...(instantOpens.data ?? []), ...Object.values(optimisticEntries)];\n const next = reconcileQuotes({\n partyA,\n onchainPositions: wantOpenPositions ? openPositions.quotes : [],\n onchainPendingQuotes: wantPendingQuotes ? hydratedPending.quotes : [],\n instantOpens: wantInstantOpens ? seededInstantOpens : [],\n instantCloses: wantInstantCloses ? (instantCloses.data ?? []) : [],\n instantOpenVaByTempId: predictedVas.byTempId,\n notifications,\n retainedAnchors: retainedAnchorsRef.current,\n });\n previousRef.current = next;\n retainedAnchorsRef.current = next.pendingAnchors;\n return next;\n }, [\n active,\n partyA,\n openPositions.quotes,\n hydratedPending.quotes,\n instantOpens.data,\n instantCloses.data,\n predictedVas.byTempId,\n optimisticEntries,\n notifications,\n wantOpenPositions,\n wantPendingQuotes,\n wantInstantOpens,\n wantInstantCloses,\n ]);\n\n const byKey = useMemo<Record<string, UnifiedQuote>>(() => {\n const map: Record<string, UnifiedQuote> = {};\n for (const quote of result.quotes) map[quote.key] = quote;\n return map;\n }, [result.quotes]);\n\n /**\n * Drop optimistic seeds once their `tempQuoteId` has been **confirmed by the\n * on-chain read** — the linked row carries the polled struct (`raw.onchain`).\n * Clearing on the notification link alone would drop the seed while the row is\n * still `WRITE_ONCHAIN`, before any source but the notification holds it, so the\n * row would flicker out until the RPC catches up.\n */\n useEffect(() => {\n const settled = Object.keys(optimisticEntries)\n .map(Number)\n .filter((tempQuoteId) => {\n const key = result.links[tempQuoteId];\n return key !== undefined && byKey[key]?.raw.onchain !== undefined;\n });\n if (settled.length > 0) clearSettled(settled);\n }, [result, byKey, optimisticEntries, clearSettled]);\n\n const isLoading =\n (active && includeVirtualAccounts && virtualAccounts.isLoading) ||\n (active && includeVirtualAccounts && predictedVas.isLoading) ||\n (active && wantOpenPositions && openPositions.isLoading) ||\n (active && wantPendingQuotes && (pendingQuoteIds.isLoading || hydratedPending.isLoading)) ||\n (active && wantInstantOpens && instantOpens.isLoading) ||\n (active && wantInstantCloses && instantCloses.isLoading);\n\n const isFetching =\n (includeVirtualAccounts && (virtualAccounts.isFetching || predictedVas.isFetching)) ||\n (wantOpenPositions && openPositions.isFetching) ||\n (wantPendingQuotes && (pendingQuoteIds.isFetching || hydratedPending.isFetching)) ||\n (wantInstantOpens && instantOpens.isFetching) ||\n (wantInstantCloses && instantCloses.isFetching);\n\n const error =\n openPositions.error ??\n pendingQuoteIds.error ??\n hydratedPending.error ??\n virtualAccounts.error ??\n instantOpens.error ??\n instantCloses.error ??\n null;\n\n /**\n * `openPositions` / `pendingQuoteIds` are `useQueries` fan-outs (no single\n * query handle), so their combined results expose a `refetch` that fires every\n * per-account query. Refetching the ids re-drives the per-id hydration.\n */\n const refetchOpenPositions = openPositions.refetch;\n const refetchPendingQuoteIds = pendingQuoteIds.refetch;\n const refetch = useCallback(() => {\n if (includeVirtualAccounts) virtualAccounts.refetch();\n if (wantOpenPositions) refetchOpenPositions();\n if (wantPendingQuotes) refetchPendingQuoteIds();\n if (wantInstantOpens) instantOpens.refetch();\n if (wantInstantCloses) instantCloses.refetch();\n }, [\n includeVirtualAccounts,\n wantOpenPositions,\n wantPendingQuotes,\n wantInstantOpens,\n wantInstantCloses,\n virtualAccounts,\n refetchOpenPositions,\n refetchPendingQuoteIds,\n instantOpens,\n instantCloses,\n ]);\n\n return {\n quotes: result.quotes,\n byKey,\n accounts,\n isLoading: Boolean(isLoading),\n isFetching: Boolean(isFetching),\n socketStatus: live ? socketStatus : \"closed\",\n error,\n refetch,\n };\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { ConfigParameter, GetPartyAOpenPositionsOptions, GetPartyAOpenPositionsReturnType } from '@symmio/trading-core';
2
2
  import { UseQueryResult } from '@tanstack/react-query';
3
- import { SymmioRequestError } from '../errors/symmio-request-error';
3
+ import { SymmioRequestError } from '../errors/symmio-request-error.js';
4
4
  /**
5
5
  * Parameters for {@link usePartyAOpenPositions}: the core query options (partyA,
6
6
  * pagination, chain id, TanStack `query` overrides) plus an optional `config`.
@@ -10,9 +10,9 @@ export type UsePartyAOpenPositionsParameters = GetPartyAOpenPositionsOptions & C
10
10
  export type UsePartyAOpenPositionsReturnType = UseQueryResult<GetPartyAOpenPositionsReturnType, SymmioRequestError>;
11
11
  /**
12
12
  * Read a partyA's open positions (full `Quote` structs) from the SYMMIO core.
13
- * `partyA` is a SubAccount (Majors) or Virtual Account (VibeCaps). The query is
14
- * disabled until `partyA` is set. `chainId` defaults to the connected chain.
15
- * Errors are normalized to {@link SymmioRequestError}.
13
+ * `partyA` is a virtual account (lowcap). The query is disabled until `partyA`
14
+ * is set. `chainId` defaults to the connected chain. Errors are normalized to
15
+ * {@link SymmioRequestError}.
16
16
  *
17
17
  * @example
18
18
  * ```tsx
@@ -1 +1 @@
1
- {"version":3,"file":"use-party-a-open-positions.js","names":[],"sources":["../../src/quotes/use-party-a-open-positions.ts"],"sourcesContent":["\"use client\";\n\nimport {\n getPartyAOpenPositionsQueryOptions,\n type ConfigParameter,\n type GetPartyAOpenPositionsOptions,\n type GetPartyAOpenPositionsReturnType,\n} from \"@symmio/trading-core\";\nimport { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { normalizeSymmError } from \"../errors/normalize-symm-error\";\nimport type { SymmioRequestError } from \"../errors/symmio-request-error\";\nimport { useSymmioChainId } from \"../provider/use-symmio-chain-id\";\nimport { useSymmioConfig } from \"../provider/use-symmio-config\";\n\n/**\n * Parameters for {@link usePartyAOpenPositions}: the core query options (partyA,\n * pagination, chain id, TanStack `query` overrides) plus an optional `config`.\n */\nexport type UsePartyAOpenPositionsParameters = GetPartyAOpenPositionsOptions & ConfigParameter;\n\n/** Return type of {@link usePartyAOpenPositions}. */\nexport type UsePartyAOpenPositionsReturnType = UseQueryResult<GetPartyAOpenPositionsReturnType, SymmioRequestError>;\n\n/**\n * Read a partyA's open positions (full `Quote` structs) from the SYMMIO core.\n * `partyA` is a SubAccount (Majors) or Virtual Account (VibeCaps). The query is\n * disabled until `partyA` is set. `chainId` defaults to the connected chain.\n * Errors are normalized to {@link SymmioRequestError}.\n *\n * @example\n * ```tsx\n * const { data: positions, isLoading } = usePartyAOpenPositions({ partyA: \"0xva…\" });\n * ```\n */\nexport function usePartyAOpenPositions(\n parameters: UsePartyAOpenPositionsParameters = {},\n): UsePartyAOpenPositionsReturnType {\n const config = useSymmioConfig(parameters);\n const chainId = useSymmioChainId();\n const options = getPartyAOpenPositionsQueryOptions(config, {\n ...parameters,\n chainId: parameters.chainId ?? chainId,\n });\n\n return useQuery({\n ...options,\n queryFn: async () => {\n try {\n return await options.queryFn();\n } catch (err) {\n throw normalizeSymmError(err);\n }\n },\n }) as UsePartyAOpenPositionsReturnType;\n}\n"],"mappings":";;;;;;;AAkCA,SAAgB,EACd,IAA+C,CAAC,GACd;CAClC,IAAM,IAAS,EAAgB,CAAU,GACnC,IAAU,EAAiB,GAC3B,IAAU,EAAmC,GAAQ;EACzD,GAAG;EACH,SAAS,EAAW,WAAW;CACjC,CAAC;CAED,OAAO,EAAS;EACd,GAAG;EACH,SAAS,YAAY;GACnB,IAAI;IACF,OAAO,MAAM,EAAQ,QAAQ;GAC/B,SAAS,GAAK;IACZ,MAAM,EAAmB,CAAG;GAC9B;EACF;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"use-party-a-open-positions.js","names":[],"sources":["../../src/quotes/use-party-a-open-positions.ts"],"sourcesContent":["\"use client\";\n\nimport {\n getPartyAOpenPositionsQueryOptions,\n type ConfigParameter,\n type GetPartyAOpenPositionsOptions,\n type GetPartyAOpenPositionsReturnType,\n} from \"@symmio/trading-core\";\nimport { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { normalizeSymmError } from \"../errors/normalize-symm-error\";\nimport type { SymmioRequestError } from \"../errors/symmio-request-error\";\nimport { useSymmioChainId } from \"../provider/use-symmio-chain-id\";\nimport { useSymmioConfig } from \"../provider/use-symmio-config\";\n\n/**\n * Parameters for {@link usePartyAOpenPositions}: the core query options (partyA,\n * pagination, chain id, TanStack `query` overrides) plus an optional `config`.\n */\nexport type UsePartyAOpenPositionsParameters = GetPartyAOpenPositionsOptions & ConfigParameter;\n\n/** Return type of {@link usePartyAOpenPositions}. */\nexport type UsePartyAOpenPositionsReturnType = UseQueryResult<GetPartyAOpenPositionsReturnType, SymmioRequestError>;\n\n/**\n * Read a partyA's open positions (full `Quote` structs) from the SYMMIO core.\n * `partyA` is a virtual account (lowcap). The query is disabled until `partyA`\n * is set. `chainId` defaults to the connected chain. Errors are normalized to\n * {@link SymmioRequestError}.\n *\n * @example\n * ```tsx\n * const { data: positions, isLoading } = usePartyAOpenPositions({ partyA: \"0xva…\" });\n * ```\n */\nexport function usePartyAOpenPositions(\n parameters: UsePartyAOpenPositionsParameters = {},\n): UsePartyAOpenPositionsReturnType {\n const config = useSymmioConfig(parameters);\n const chainId = useSymmioChainId();\n const options = getPartyAOpenPositionsQueryOptions(config, {\n ...parameters,\n chainId: parameters.chainId ?? chainId,\n });\n\n return useQuery({\n ...options,\n queryFn: async () => {\n try {\n return await options.queryFn();\n } catch (err) {\n throw normalizeSymmError(err);\n }\n },\n }) as UsePartyAOpenPositionsReturnType;\n}\n"],"mappings":";;;;;;;AAkCA,SAAgB,EACd,IAA+C,CAAC,GACd;CAClC,IAAM,IAAS,EAAgB,CAAU,GACnC,IAAU,EAAiB,GAC3B,IAAU,EAAmC,GAAQ;EACzD,GAAG;EACH,SAAS,EAAW,WAAW;CACjC,CAAC;CAED,OAAO,EAAS;EACd,GAAG;EACH,SAAS,YAAY;GACnB,IAAI;IACF,OAAO,MAAM,EAAQ,QAAQ;GAC/B,SAAS,GAAK;IACZ,MAAM,EAAmB,CAAG;GAC9B;EACF;CACF,CAAC;AACH"}
@@ -1,6 +1,6 @@
1
1
  import { ConfigParameter, GetPartyAPendingQuotesOptions, GetPartyAPendingQuotesReturnType } from '@symmio/trading-core';
2
2
  import { UseQueryResult } from '@tanstack/react-query';
3
- import { SymmioRequestError } from '../errors/symmio-request-error';
3
+ import { SymmioRequestError } from '../errors/symmio-request-error.js';
4
4
  /**
5
5
  * Parameters for {@link usePartyAPendingQuotes}: the core query options (partyA,
6
6
  * chain id, TanStack `query` overrides) plus an optional `config`.
@@ -1,6 +1,6 @@
1
1
  import { ConfigParameter, GetQuoteEventsByTypeOptions, GetQuoteEventsByTypeReturnType } from '@symmio/trading-core';
2
2
  import { UseQueryResult } from '@tanstack/react-query';
3
- import { SymmioRequestError } from '../errors/symmio-request-error';
3
+ import { SymmioRequestError } from '../errors/symmio-request-error.js';
4
4
  /**
5
5
  * Parameters for {@link useQuoteEventsByType}: the core query options (quote id,
6
6
  * types, paging, sort, chain id, TanStack `query` overrides) plus an optional
@@ -1,5 +1,5 @@
1
1
  import { ConfigParameter, QuoteFundingData } from '@symmio/trading-core';
2
- import { SymmioRequestError } from '../errors/symmio-request-error';
2
+ import { SymmioRequestError } from '../errors/symmio-request-error.js';
3
3
  /**
4
4
  * Parameters for {@link useQuoteFunding}.
5
5
  */
@@ -1,6 +1,6 @@
1
1
  import { ConfigParameter, GetQuoteHistoryOptions, GetQuoteHistoryReturnType } from '@symmio/trading-core';
2
2
  import { UseQueryResult } from '@tanstack/react-query';
3
- import { SymmioRequestError } from '../errors/symmio-request-error';
3
+ import { SymmioRequestError } from '../errors/symmio-request-error.js';
4
4
  /**
5
5
  * Parameters for {@link useQuoteHistory}: the core query options (subAccounts,
6
6
  * close type, paging, time range, chain id, TanStack `query` overrides) plus an
@@ -1,5 +1,5 @@
1
1
  import { ConfigParameter } from '@symmio/trading-core';
2
- import { UseQuoteEventsByTypeParameters, UseQuoteEventsByTypeReturnType } from './use-quote-events-by-type';
2
+ import { UseQuoteEventsByTypeParameters, UseQuoteEventsByTypeReturnType } from './use-quote-events-by-type.js';
3
3
  /**
4
4
  * Parameters for {@link useQuotePriceHistory}. Same as {@link useQuoteEventsByType}
5
5
  * minus the `types` field (preset to {@link PRICE_HISTORY_EVENT_TYPES}).
@@ -1,6 +1,6 @@
1
1
  import { ConfigParameter, GetQuoteOptions, GetQuoteReturnType } from '@symmio/trading-core';
2
2
  import { UseQueryResult } from '@tanstack/react-query';
3
- import { SymmioRequestError } from '../errors/symmio-request-error';
3
+ import { SymmioRequestError } from '../errors/symmio-request-error.js';
4
4
  /**
5
5
  * Parameters for {@link useQuote}: the core query options (quote id, chain id,
6
6
  * TanStack `query` overrides) plus an optional `config`.
@@ -1,5 +1,5 @@
1
1
  import { ConfigParameter, GetQuoteFundingOptions, QuoteFundingData } from '@symmio/trading-core';
2
- import { SymmioRequestError } from '../errors/symmio-request-error';
2
+ import { SymmioRequestError } from '../errors/symmio-request-error.js';
3
3
  /** Minimum quote shape `useQuotesFunding` needs: just the on-chain id. */
4
4
  export interface QuotesFundingInputQuote {
5
5
  /** On-chain quote id. Off-chain (pending) rows pass `undefined` and are skipped. */
@@ -1,6 +1,6 @@
1
1
  import { ConfigParameter, QuerySubgraphOptions } from '@symmio/trading-core';
2
2
  import { UseQueryResult } from '@tanstack/react-query';
3
- import { SymmioRequestError } from '../errors/symmio-request-error';
3
+ import { SymmioRequestError } from '../errors/symmio-request-error.js';
4
4
  /**
5
5
  * Parameters for {@link useSubgraphQuery}: the raw-GraphQL query options
6
6
  * (document, variables, optional subgraph/chain id, TanStack `query` overrides)
@@ -1,8 +1,9 @@
1
- export * from './to-quote-tpsl';
2
- export * from './tpsl-confirming';
3
- export * from './use-quote-tpsl';
4
- export * from './use-set-quote-tpsl';
5
- export * from './use-tpsl-config';
6
- export * from './use-tpsl-signing-spec';
7
- export * from './use-watch-tpsl-notifications';
1
+ export * from './to-quote-tpsl.js';
2
+ export * from './tpsl-store.js';
3
+ export * from './use-delete-quote-tpsl.js';
4
+ export * from './use-quote-tpsl.js';
5
+ export * from './use-set-quote-tpsl.js';
6
+ export * from './use-tpsl-config.js';
7
+ export * from './use-tpsl-signing-spec.js';
8
+ export * from './use-watch-tpsl-notifications.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tpsl/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tpsl/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC"}
@@ -0,0 +1,84 @@
1
+ import { QuoteTpSlRow, TpSlInfoState, TpSlNotification, TpSlPriceType } from '@symmio/trading-core';
2
+ /**
3
+ * One quote's folded TP/SL state. The same record instance is referenced from
4
+ * every id that resolves to it via {@link TpSlStoreState.index} — the caller
5
+ * can pass either the on-chain `quoteId` or the hedger `tempQuoteId` and get
6
+ * the same record back.
7
+ *
8
+ * `tpState` / `slState` is the single source of truth for how a side is
9
+ * rendered — including the transient `"confirming"` phase between a POST
10
+ * accepting and the WS report landing. No separate overlay field.
11
+ */
12
+ export interface TpSlRecord {
13
+ /** On-chain quote id — set once the quote anchors. */
14
+ quoteId?: bigint;
15
+ /** Hedger `tempQuoteId` — set during the pre-chain window. */
16
+ tempQuoteId?: bigint;
17
+ tp: string;
18
+ sl: string;
19
+ tpOpenPrice: string;
20
+ slOpenPrice: string;
21
+ tpPriceType: TpSlPriceType;
22
+ slPriceType: TpSlPriceType;
23
+ tpState: TpSlInfoState;
24
+ slState: TpSlInfoState;
25
+ tpCohQuoteId?: string;
26
+ slCohQuoteId?: string;
27
+ }
28
+ /** Internal identity of a record — opaque string, never leaks to consumers. */
29
+ type TpSlRecordKey = string;
30
+ /**
31
+ * Zustand store shape. `records` holds one entry per quote; `index` maps every
32
+ * id we've ever seen for that quote — on-chain and temp — to the same
33
+ * `records` key.
34
+ */
35
+ export interface TpSlStoreState {
36
+ records: Map<TpSlRecordKey, TpSlRecord>;
37
+ index: Map<bigint, TpSlRecordKey>;
38
+ /** Read a record via any id. Returns `undefined` when the id is unknown. */
39
+ get(id: bigint): TpSlRecord | undefined;
40
+ /** Fold the raw handler rows into snapshot fields and commit under `id`. */
41
+ setRows(id: bigint, rows: QuoteTpSlRow[]): void;
42
+ /**
43
+ * Mark a side as "POST accepted, awaiting handler acknowledgement". Sets
44
+ * `tpState` / `slState` to `"confirming"` directly. Optional `patch`
45
+ * seeds the trigger price / priceType / cohQuoteId so the UI can show
46
+ * the target value during the confirming window; a later
47
+ * {@link applyNotification} transitions the state to the wire report.
48
+ */
49
+ markConfirming(id: bigint, side: "tp" | "sl", patch?: {
50
+ price?: string;
51
+ priceType?: TpSlPriceType;
52
+ cohQuoteId?: string;
53
+ }): void;
54
+ /**
55
+ * Apply a WS notification to the record's side state (and optionally its
56
+ * trigger price when `details.trigger_price` is present). Maps the raw
57
+ * notification state onto {@link TpSlInfoState}. Failure frames
58
+ * (`successful: false`) are ignored — the confirming state remains until
59
+ * the next successful frame or REST fetch resolves it.
60
+ */
61
+ applyNotification(id: bigint, notification: TpSlNotification): void;
62
+ /**
63
+ * Declare that two ids refer to the same TP/SL record — typically called
64
+ * when the quote reconciliation layer learns a `tempQuoteId ↔ quoteId`
65
+ * pairing from a solver notification.
66
+ */
67
+ link(a: bigint, b: bigint): void;
68
+ }
69
+ /**
70
+ * Module-level Zustand store for the folded TP/SL snapshot per quote. Single
71
+ * instance across the app is intentional (see AGENTS.md — "TP/SL data live in
72
+ * one place"); tests can call {@link __resetTpSlStore} between runs to reset.
73
+ */
74
+ export declare const useTpSlStore: import('zustand').UseBoundStore<import('zustand').StoreApi<TpSlStoreState>>;
75
+ /**
76
+ * Selector hook: subscribe to the record addressed by `id`. Returns
77
+ * `undefined` until a row set or mutation has landed for that id (or for
78
+ * another id linked to the same record).
79
+ */
80
+ export declare function useTpSlRecord(id: bigint | undefined): TpSlRecord | undefined;
81
+ /** Reset the store — intended for tests only. */
82
+ export declare function __resetTpSlStore(): void;
83
+ export {};
84
+ //# sourceMappingURL=tpsl-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tpsl-store.d.ts","sourceRoot":"","sources":["../../src/tpsl/tpsl-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EAEZ,aAAa,EACb,gBAAgB,EAChB,aAAa,EACd,MAAM,sBAAsB,CAAC;AAI9B;;;;;;;;;GASG;AACH,MAAM,WAAW,UAAU;IACzB,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,aAAa,CAAC;IAC3B,WAAW,EAAE,aAAa,CAAC;IAC3B,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,+EAA+E;AAC/E,KAAK,aAAa,GAAG,MAAM,CAAC;AAE5B;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,GAAG,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IACxC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAElC,4EAA4E;IAC5E,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAExC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAEhD;;;;;;OAMG;IACH,cAAc,CACZ,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,IAAI,GAAG,IAAI,EACjB,KAAK,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,aAAa,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACzE,IAAI,CAAC;IAER;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAEpE;;;;OAIG;IACH,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAoCD;;;;GAIG;AACH,eAAO,MAAM,YAAY,6EA4LvB,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAM5E;AAED,iDAAiD;AACjD,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
@@ -0,0 +1,154 @@
1
+ "use client";
2
+ import { toQuoteTpSl as e } from "./to-quote-tpsl.js";
3
+ import { create as t } from "zustand";
4
+ //#region src/tpsl/tpsl-store.ts
5
+ function n() {
6
+ return {
7
+ tp: "",
8
+ sl: "",
9
+ tpOpenPrice: "",
10
+ slOpenPrice: "",
11
+ tpPriceType: "markPrice",
12
+ slPriceType: "markPrice",
13
+ tpState: "canceled",
14
+ slState: "canceled"
15
+ };
16
+ }
17
+ function r(e) {
18
+ switch (e) {
19
+ case "new":
20
+ case "edit": return "new";
21
+ case "pending": return "pending";
22
+ case "triggered":
23
+ case "trigger": return "triggered";
24
+ case "cancel":
25
+ case "canceled":
26
+ case "cancelled":
27
+ case "close": return "canceled";
28
+ default: return "new";
29
+ }
30
+ }
31
+ var i = t((t, i) => {
32
+ let a = 0;
33
+ function o() {
34
+ return a += 1, `r${a}`;
35
+ }
36
+ function s(e, r) {
37
+ t((t) => {
38
+ let i = new Map(t.records), a = new Map(t.index), s = a.get(e), c;
39
+ s === void 0 ? (s = o(), c = n(), a.set(e, s)) : c = i.get(s) ?? n();
40
+ let l = r(c);
41
+ return e < 0n ? l.tempQuoteId ??= e : l.quoteId ??= e, i.set(s, l), {
42
+ records: i,
43
+ index: a
44
+ };
45
+ });
46
+ }
47
+ return {
48
+ records: /* @__PURE__ */ new Map(),
49
+ index: /* @__PURE__ */ new Map(),
50
+ get(e) {
51
+ let t = i(), n = t.index.get(e);
52
+ return n === void 0 ? void 0 : t.records.get(n);
53
+ },
54
+ setRows(t, n) {
55
+ let r = e(n), a = n.find((e) => e.quote_id && e.quote_id !== 0)?.quote_id;
56
+ if (s(t, (e) => ({
57
+ ...e,
58
+ ...r
59
+ })), a !== void 0) {
60
+ let e = BigInt(a);
61
+ e !== t && i().link(t, e);
62
+ }
63
+ },
64
+ markConfirming(e, t, n) {
65
+ s(e, (e) => {
66
+ let r = { ...e };
67
+ return t === "tp" ? (r.tpState = "confirming", n?.price !== void 0 && (r.tp = n.price), n?.priceType !== void 0 && (r.tpPriceType = n.priceType), n?.cohQuoteId !== void 0 && (r.tpCohQuoteId = n.cohQuoteId)) : (r.slState = "confirming", n?.price !== void 0 && (r.sl = n.price), n?.priceType !== void 0 && (r.slPriceType = n.priceType), n?.cohQuoteId !== void 0 && (r.slCohQuoteId = n.cohQuoteId)), r;
68
+ });
69
+ },
70
+ applyNotification(e, t) {
71
+ if (!t.successful) return;
72
+ let n = t.conditionalOrderType === "take_profit" ? "tp" : t.conditionalOrderType === "stop_loss" ? "sl" : null;
73
+ if (!n) return;
74
+ let i = r(t.state), a = t.details?.trigger_price;
75
+ s(e, (e) => {
76
+ let r = { ...e };
77
+ return n === "tp" ? (r.tpState = i, i === "canceled" ? (r.tp = "", r.tpOpenPrice = "", r.tpCohQuoteId = void 0) : (a !== void 0 && (r.tp = String(a)), t.cohQuoteId && (r.tpCohQuoteId = t.cohQuoteId))) : (r.slState = i, i === "canceled" ? (r.sl = "", r.slOpenPrice = "", r.slCohQuoteId = void 0) : (a !== void 0 && (r.sl = String(a)), t.cohQuoteId && (r.slCohQuoteId = t.cohQuoteId))), r;
78
+ });
79
+ },
80
+ link(e, r) {
81
+ e !== r && t((t) => {
82
+ let i = new Map(t.records), a = new Map(t.index), s = a.get(e), c = a.get(r);
83
+ if (s === void 0 && c === void 0) {
84
+ let t = o(), s = n();
85
+ return e < 0n ? s.tempQuoteId = e : s.quoteId = e, r < 0n ? s.tempQuoteId ??= r : s.quoteId ??= r, i.set(t, s), a.set(e, t), a.set(r, t), {
86
+ records: i,
87
+ index: a
88
+ };
89
+ }
90
+ if (s !== void 0 && c === void 0) {
91
+ a.set(r, s);
92
+ let e = i.get(s);
93
+ if (e) {
94
+ let t = { ...e };
95
+ r < 0n ? t.tempQuoteId ??= r : t.quoteId ??= r, i.set(s, t);
96
+ }
97
+ return {
98
+ records: i,
99
+ index: a
100
+ };
101
+ }
102
+ if (s === void 0 && c !== void 0) {
103
+ a.set(e, c);
104
+ let t = i.get(c);
105
+ if (t) {
106
+ let n = { ...t };
107
+ e < 0n ? n.tempQuoteId ??= e : n.quoteId ??= e, i.set(c, n);
108
+ }
109
+ return {
110
+ records: i,
111
+ index: a
112
+ };
113
+ }
114
+ if (s === c) return t;
115
+ let l = i.get(s) ?? n(), u = i.get(c) ?? n(), d = {
116
+ ...l,
117
+ quoteId: l.quoteId ?? u.quoteId,
118
+ tempQuoteId: l.tempQuoteId ?? u.tempQuoteId,
119
+ ...l.tpState === "canceled" && u.tpState !== "canceled" ? {
120
+ tp: u.tp,
121
+ tpOpenPrice: u.tpOpenPrice,
122
+ tpPriceType: u.tpPriceType,
123
+ tpState: u.tpState,
124
+ tpCohQuoteId: u.tpCohQuoteId
125
+ } : {},
126
+ ...l.slState === "canceled" && u.slState !== "canceled" ? {
127
+ sl: u.sl,
128
+ slOpenPrice: u.slOpenPrice,
129
+ slPriceType: u.slPriceType,
130
+ slState: u.slState,
131
+ slCohQuoteId: u.slCohQuoteId
132
+ } : {}
133
+ };
134
+ i.set(s, d), i.delete(c);
135
+ for (let [e, t] of a) t === c && a.set(e, s);
136
+ return {
137
+ records: i,
138
+ index: a
139
+ };
140
+ });
141
+ }
142
+ };
143
+ });
144
+ function a(e) {
145
+ return i((t) => {
146
+ if (e === void 0) return;
147
+ let n = t.index.get(e);
148
+ return n === void 0 ? void 0 : t.records.get(n);
149
+ });
150
+ }
151
+ //#endregion
152
+ export { a as useTpSlRecord, i as useTpSlStore };
153
+
154
+ //# sourceMappingURL=tpsl-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tpsl-store.js","names":[],"sources":["../../src/tpsl/tpsl-store.ts"],"sourcesContent":["\"use client\";\n\nimport type {\n QuoteTpSlRow,\n RawTpSlNotificationState,\n TpSlInfoState,\n TpSlNotification,\n TpSlPriceType,\n} from \"@symmio/trading-core\";\nimport { create } from \"zustand\";\nimport { toQuoteTpSl } from \"./to-quote-tpsl\";\n\n/**\n * One quote's folded TP/SL state. The same record instance is referenced from\n * every id that resolves to it via {@link TpSlStoreState.index} — the caller\n * can pass either the on-chain `quoteId` or the hedger `tempQuoteId` and get\n * the same record back.\n *\n * `tpState` / `slState` is the single source of truth for how a side is\n * rendered — including the transient `\"confirming\"` phase between a POST\n * accepting and the WS report landing. No separate overlay field.\n */\nexport interface TpSlRecord {\n /** On-chain quote id — set once the quote anchors. */\n quoteId?: bigint;\n /** Hedger `tempQuoteId` — set during the pre-chain window. */\n tempQuoteId?: bigint;\n\n tp: string;\n sl: string;\n tpOpenPrice: string;\n slOpenPrice: string;\n tpPriceType: TpSlPriceType;\n slPriceType: TpSlPriceType;\n tpState: TpSlInfoState;\n slState: TpSlInfoState;\n tpCohQuoteId?: string;\n slCohQuoteId?: string;\n}\n\n/** Internal identity of a record — opaque string, never leaks to consumers. */\ntype TpSlRecordKey = string;\n\n/**\n * Zustand store shape. `records` holds one entry per quote; `index` maps every\n * id we've ever seen for that quote — on-chain and temp — to the same\n * `records` key.\n */\nexport interface TpSlStoreState {\n records: Map<TpSlRecordKey, TpSlRecord>;\n index: Map<bigint, TpSlRecordKey>;\n\n /** Read a record via any id. Returns `undefined` when the id is unknown. */\n get(id: bigint): TpSlRecord | undefined;\n\n /** Fold the raw handler rows into snapshot fields and commit under `id`. */\n setRows(id: bigint, rows: QuoteTpSlRow[]): void;\n\n /**\n * Mark a side as \"POST accepted, awaiting handler acknowledgement\". Sets\n * `tpState` / `slState` to `\"confirming\"` directly. Optional `patch`\n * seeds the trigger price / priceType / cohQuoteId so the UI can show\n * the target value during the confirming window; a later\n * {@link applyNotification} transitions the state to the wire report.\n */\n markConfirming(\n id: bigint,\n side: \"tp\" | \"sl\",\n patch?: { price?: string; priceType?: TpSlPriceType; cohQuoteId?: string },\n ): void;\n\n /**\n * Apply a WS notification to the record's side state (and optionally its\n * trigger price when `details.trigger_price` is present). Maps the raw\n * notification state onto {@link TpSlInfoState}. Failure frames\n * (`successful: false`) are ignored — the confirming state remains until\n * the next successful frame or REST fetch resolves it.\n */\n applyNotification(id: bigint, notification: TpSlNotification): void;\n\n /**\n * Declare that two ids refer to the same TP/SL record — typically called\n * when the quote reconciliation layer learns a `tempQuoteId ↔ quoteId`\n * pairing from a solver notification.\n */\n link(a: bigint, b: bigint): void;\n}\n\nfunction blank(): TpSlRecord {\n return {\n tp: \"\",\n sl: \"\",\n tpOpenPrice: \"\",\n slOpenPrice: \"\",\n tpPriceType: \"markPrice\",\n slPriceType: \"markPrice\",\n tpState: \"canceled\",\n slState: \"canceled\",\n };\n}\n\n/** Map the WS notification state onto {@link TpSlInfoState}. */\nfunction mapNotificationState(state: RawTpSlNotificationState): TpSlInfoState {\n switch (state) {\n case \"new\":\n case \"edit\":\n return \"new\";\n case \"pending\":\n return \"pending\";\n case \"triggered\":\n case \"trigger\":\n return \"triggered\";\n case \"cancel\":\n case \"canceled\":\n case \"cancelled\":\n case \"close\":\n return \"canceled\";\n default:\n return \"new\";\n }\n}\n\n/**\n * Module-level Zustand store for the folded TP/SL snapshot per quote. Single\n * instance across the app is intentional (see AGENTS.md — \"TP/SL data live in\n * one place\"); tests can call {@link __resetTpSlStore} between runs to reset.\n */\nexport const useTpSlStore = create<TpSlStoreState>((set, get) => {\n let keyCounter = 0;\n function newKey(): TpSlRecordKey {\n keyCounter += 1;\n return `r${keyCounter}`;\n }\n\n function upsert(id: bigint, mutator: (prev: TpSlRecord) => TpSlRecord): void {\n set((state) => {\n const records = new Map(state.records);\n const index = new Map(state.index);\n let key = index.get(id);\n let prev: TpSlRecord;\n if (key === undefined) {\n key = newKey();\n prev = blank();\n index.set(id, key);\n } else {\n prev = records.get(key) ?? blank();\n }\n const next = mutator(prev);\n if (id < 0n) {\n next.tempQuoteId ??= id;\n } else {\n next.quoteId ??= id;\n }\n records.set(key, next);\n return { records, index };\n });\n }\n\n return {\n records: new Map(),\n index: new Map(),\n\n get(id) {\n const state = get();\n const key = state.index.get(id);\n return key === undefined ? undefined : state.records.get(key);\n },\n\n setRows(id, rows) {\n const folded = toQuoteTpSl(rows);\n const rowQuoteId = rows.find((r) => r.quote_id && r.quote_id !== 0)?.quote_id;\n upsert(id, (prev) => ({ ...prev, ...folded }));\n if (rowQuoteId !== undefined) {\n const rowId = BigInt(rowQuoteId);\n if (rowId !== id) get().link(id, rowId);\n }\n },\n\n markConfirming(id, side, patch) {\n upsert(id, (prev) => {\n const next: TpSlRecord = { ...prev };\n if (side === \"tp\") {\n next.tpState = \"confirming\";\n if (patch?.price !== undefined) next.tp = patch.price;\n if (patch?.priceType !== undefined) next.tpPriceType = patch.priceType;\n if (patch?.cohQuoteId !== undefined) next.tpCohQuoteId = patch.cohQuoteId;\n } else {\n next.slState = \"confirming\";\n if (patch?.price !== undefined) next.sl = patch.price;\n if (patch?.priceType !== undefined) next.slPriceType = patch.priceType;\n if (patch?.cohQuoteId !== undefined) next.slCohQuoteId = patch.cohQuoteId;\n }\n return next;\n });\n },\n\n applyNotification(id, notification) {\n if (!notification.successful) return;\n const side =\n notification.conditionalOrderType === \"take_profit\"\n ? \"tp\"\n : notification.conditionalOrderType === \"stop_loss\"\n ? \"sl\"\n : null;\n if (!side) return;\n const nextState = mapNotificationState(notification.state);\n const trigger = notification.details?.trigger_price;\n upsert(id, (prev) => {\n const next: TpSlRecord = { ...prev };\n if (side === \"tp\") {\n next.tpState = nextState;\n if (nextState === \"canceled\") {\n next.tp = \"\";\n next.tpOpenPrice = \"\";\n next.tpCohQuoteId = undefined;\n } else {\n if (trigger !== undefined) next.tp = String(trigger);\n if (notification.cohQuoteId) next.tpCohQuoteId = notification.cohQuoteId;\n }\n } else {\n next.slState = nextState;\n if (nextState === \"canceled\") {\n next.sl = \"\";\n next.slOpenPrice = \"\";\n next.slCohQuoteId = undefined;\n } else {\n if (trigger !== undefined) next.sl = String(trigger);\n if (notification.cohQuoteId) next.slCohQuoteId = notification.cohQuoteId;\n }\n }\n return next;\n });\n },\n\n link(a, b) {\n if (a === b) return;\n set((state) => {\n const records = new Map(state.records);\n const index = new Map(state.index);\n const keyA = index.get(a);\n const keyB = index.get(b);\n\n if (keyA === undefined && keyB === undefined) {\n const key = newKey();\n const record = blank();\n if (a < 0n) record.tempQuoteId = a;\n else record.quoteId = a;\n if (b < 0n) record.tempQuoteId ??= b;\n else record.quoteId ??= b;\n records.set(key, record);\n index.set(a, key);\n index.set(b, key);\n return { records, index };\n }\n\n if (keyA !== undefined && keyB === undefined) {\n index.set(b, keyA);\n const prev = records.get(keyA);\n if (prev) {\n const next: TpSlRecord = { ...prev };\n if (b < 0n) next.tempQuoteId ??= b;\n else next.quoteId ??= b;\n records.set(keyA, next);\n }\n return { records, index };\n }\n\n if (keyA === undefined && keyB !== undefined) {\n index.set(a, keyB);\n const prev = records.get(keyB);\n if (prev) {\n const next: TpSlRecord = { ...prev };\n if (a < 0n) next.tempQuoteId ??= a;\n else next.quoteId ??= a;\n records.set(keyB, next);\n }\n return { records, index };\n }\n\n if (keyA === keyB) return state;\n\n const recordA = records.get(keyA!) ?? blank();\n const recordB = records.get(keyB!) ?? blank();\n const merged: TpSlRecord = {\n ...recordA,\n quoteId: recordA.quoteId ?? recordB.quoteId,\n tempQuoteId: recordA.tempQuoteId ?? recordB.tempQuoteId,\n ...(recordA.tpState === \"canceled\" && recordB.tpState !== \"canceled\"\n ? {\n tp: recordB.tp,\n tpOpenPrice: recordB.tpOpenPrice,\n tpPriceType: recordB.tpPriceType,\n tpState: recordB.tpState,\n tpCohQuoteId: recordB.tpCohQuoteId,\n }\n : {}),\n ...(recordA.slState === \"canceled\" && recordB.slState !== \"canceled\"\n ? {\n sl: recordB.sl,\n slOpenPrice: recordB.slOpenPrice,\n slPriceType: recordB.slPriceType,\n slState: recordB.slState,\n slCohQuoteId: recordB.slCohQuoteId,\n }\n : {}),\n };\n records.set(keyA!, merged);\n records.delete(keyB!);\n for (const [id, k] of index) {\n if (k === keyB) index.set(id, keyA!);\n }\n return { records, index };\n });\n },\n };\n});\n\n/**\n * Selector hook: subscribe to the record addressed by `id`. Returns\n * `undefined` until a row set or mutation has landed for that id (or for\n * another id linked to the same record).\n */\nexport function useTpSlRecord(id: bigint | undefined): TpSlRecord | undefined {\n return useTpSlStore((state) => {\n if (id === undefined) return undefined;\n const key = state.index.get(id);\n return key === undefined ? undefined : state.records.get(key);\n });\n}\n\n/** Reset the store — intended for tests only. */\nexport function __resetTpSlStore(): void {\n useTpSlStore.setState({ records: new Map(), index: new Map() });\n}\n"],"mappings":"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"}