@symmio/trading-react 1.1.0 → 3.0.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.
- package/dist/account-layer/index.d.ts +1 -0
- package/dist/account-layer/index.d.ts.map +1 -1
- package/dist/account-layer/index.js +26 -25
- package/dist/account-layer/use-deallocate-and-initiate-withdraw.d.ts +53 -0
- package/dist/account-layer/use-deallocate-and-initiate-withdraw.d.ts.map +1 -0
- package/dist/account-layer/use-deallocate-and-initiate-withdraw.js +49 -0
- package/dist/account-layer/use-deallocate-and-initiate-withdraw.js.map +1 -0
- package/dist/account-layer/use-deposit-and-allocate.d.ts +4 -2
- package/dist/account-layer/use-deposit-and-allocate.d.ts.map +1 -1
- package/dist/account-layer/use-deposit-and-allocate.js +17 -15
- package/dist/account-layer/use-deposit-and-allocate.js.map +1 -1
- package/dist/account-layer/use-edit-account-name.d.ts.map +1 -1
- package/dist/account-layer/use-edit-account-name.js +14 -14
- package/dist/account-layer/use-edit-account-name.js.map +1 -1
- package/dist/account-layer/use-virtual-accounts-addresses-of-sub-account.d.ts +1 -1
- package/dist/account-layer/use-virtual-accounts-addresses-of-sub-account.js.map +1 -1
- package/dist/candles/index.d.ts +5 -0
- package/dist/candles/index.d.ts.map +1 -0
- package/dist/candles/index.js +5 -0
- package/dist/candles/use-binance-candle-source.d.ts +27 -0
- package/dist/candles/use-binance-candle-source.d.ts.map +1 -0
- package/dist/candles/use-binance-candle-source.js +24 -0
- package/dist/candles/use-binance-candle-source.js.map +1 -0
- package/dist/candles/use-candle-stream.d.ts +65 -0
- package/dist/candles/use-candle-stream.d.ts.map +1 -0
- package/dist/candles/use-candle-stream.js +44 -0
- package/dist/candles/use-candle-stream.js.map +1 -0
- package/dist/candles/use-candles.d.ts +40 -0
- package/dist/candles/use-candles.d.ts.map +1 -0
- package/dist/candles/use-candles.js +22 -0
- package/dist/candles/use-candles.js.map +1 -0
- package/dist/candles/use-tradingview-datafeed.d.ts +31 -0
- package/dist/candles/use-tradingview-datafeed.d.ts.map +1 -0
- package/dist/candles/use-tradingview-datafeed.js +21 -0
- package/dist/candles/use-tradingview-datafeed.js.map +1 -0
- package/dist/index.d.ts +125 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +201 -113
- package/dist/instant-layer/index.d.ts +4 -0
- package/dist/instant-layer/index.d.ts.map +1 -1
- package/dist/instant-layer/index.js +10 -6
- package/dist/instant-layer/use-instant-close-auto.d.ts.map +1 -1
- package/dist/instant-layer/use-instant-close-auto.js +12 -11
- package/dist/instant-layer/use-instant-close-auto.js.map +1 -1
- package/dist/instant-layer/use-instant-close-bulk-auto.d.ts.map +1 -1
- package/dist/instant-layer/use-instant-close-bulk-auto.js +12 -11
- package/dist/instant-layer/use-instant-close-bulk-auto.js.map +1 -1
- package/dist/instant-layer/use-instant-close-bulk.d.ts.map +1 -1
- package/dist/instant-layer/use-instant-close-bulk.js +12 -11
- package/dist/instant-layer/use-instant-close-bulk.js.map +1 -1
- package/dist/instant-layer/use-instant-close.d.ts.map +1 -1
- package/dist/instant-layer/use-instant-close.js +12 -11
- package/dist/instant-layer/use-instant-close.js.map +1 -1
- package/dist/instant-layer/use-instant-open-auto.d.ts.map +1 -1
- package/dist/instant-layer/use-instant-open-auto.js +12 -11
- package/dist/instant-layer/use-instant-open-auto.js.map +1 -1
- package/dist/instant-layer/use-instant-open-fees.d.ts +43 -0
- package/dist/instant-layer/use-instant-open-fees.d.ts.map +1 -0
- package/dist/instant-layer/use-instant-open-fees.js +111 -0
- package/dist/instant-layer/use-instant-open-fees.js.map +1 -0
- package/dist/instant-layer/use-instant-open-with-tpsl.d.ts.map +1 -1
- package/dist/instant-layer/use-instant-open-with-tpsl.js +34 -31
- package/dist/instant-layer/use-instant-open-with-tpsl.js.map +1 -1
- package/dist/instant-layer/use-instant-open.d.ts +23 -18
- package/dist/instant-layer/use-instant-open.d.ts.map +1 -1
- package/dist/instant-layer/use-instant-open.js +12 -11
- package/dist/instant-layer/use-instant-open.js.map +1 -1
- package/dist/instant-layer/use-instant-opens.d.ts +6 -6
- package/dist/instant-layer/use-instant-opens.d.ts.map +1 -1
- package/dist/instant-layer/use-instant-opens.js.map +1 -1
- package/dist/instant-layer/use-instant-trade-required-selectors.d.ts +25 -0
- package/dist/instant-layer/use-instant-trade-required-selectors.d.ts.map +1 -0
- package/dist/instant-layer/use-instant-trade-required-selectors.js +13 -0
- package/dist/instant-layer/use-instant-trade-required-selectors.js.map +1 -0
- package/dist/instant-layer/use-limit-close-auto.d.ts +30 -0
- package/dist/instant-layer/use-limit-close-auto.d.ts.map +1 -0
- package/dist/instant-layer/use-limit-close-auto.js +33 -0
- package/dist/instant-layer/use-limit-close-auto.js.map +1 -0
- package/dist/instant-layer/use-limit-open-auto.d.ts +30 -0
- package/dist/instant-layer/use-limit-open-auto.d.ts.map +1 -0
- package/dist/instant-layer/use-limit-open-auto.js +33 -0
- package/dist/instant-layer/use-limit-open-auto.js.map +1 -0
- package/dist/inventory/index.d.ts +3 -0
- package/dist/inventory/index.d.ts.map +1 -0
- package/dist/inventory/index.js +3 -0
- package/dist/inventory/use-inventory-tvl-history.d.ts +27 -0
- package/dist/inventory/use-inventory-tvl-history.d.ts.map +1 -0
- package/dist/inventory/use-inventory-tvl-history.js +28 -0
- package/dist/inventory/use-inventory-tvl-history.js.map +1 -0
- package/dist/inventory/use-inventory-tvl.d.ts +23 -0
- package/dist/inventory/use-inventory-tvl.d.ts.map +1 -0
- package/dist/inventory/use-inventory-tvl.js +27 -0
- package/dist/inventory/use-inventory-tvl.js.map +1 -0
- package/dist/margin/index.d.ts +1 -0
- package/dist/margin/index.d.ts.map +1 -1
- package/dist/margin/use-account-margin-risk.d.ts +68 -0
- package/dist/margin/use-account-margin-risk.d.ts.map +1 -0
- package/dist/margin/use-account-margin-risk.js +31 -0
- package/dist/margin/use-account-margin-risk.js.map +1 -0
- package/dist/margin/use-available-instant-open-margin.d.ts +27 -7
- package/dist/margin/use-available-instant-open-margin.d.ts.map +1 -1
- package/dist/margin/use-available-instant-open-margin.js +117 -46
- package/dist/margin/use-available-instant-open-margin.js.map +1 -1
- package/dist/market-info/use-market-info.d.ts +13 -13
- package/dist/market-info/use-market-info.d.ts.map +1 -1
- package/dist/market-info/use-market-info.js.map +1 -1
- package/dist/markets/use-markets.d.ts +14 -8
- package/dist/markets/use-markets.d.ts.map +1 -1
- package/dist/markets/use-markets.js.map +1 -1
- package/dist/muon/index.d.ts +2 -0
- package/dist/muon/index.d.ts.map +1 -1
- package/dist/muon/use-force-close-price-sig.d.ts +34 -0
- package/dist/muon/use-force-close-price-sig.d.ts.map +1 -0
- package/dist/muon/use-force-close-price-sig.js +31 -0
- package/dist/muon/use-force-close-price-sig.js.map +1 -0
- package/dist/muon/use-send-quote-upnl-sig.d.ts +30 -0
- package/dist/muon/use-send-quote-upnl-sig.d.ts.map +1 -0
- package/dist/muon/use-send-quote-upnl-sig.js +28 -0
- package/dist/muon/use-send-quote-upnl-sig.js.map +1 -0
- package/dist/notifications/use-search-notifications.d.ts +12 -12
- package/dist/notifications/use-search-notifications.d.ts.map +1 -1
- package/dist/notifications/use-search-notifications.js.map +1 -1
- package/dist/notional-cap/use-notional-cap-by-symbol-id.d.ts +7 -7
- package/dist/notional-cap/use-notional-cap-by-symbol-id.d.ts.map +1 -1
- package/dist/notional-cap/use-notional-cap-by-symbol-id.js.map +1 -1
- package/dist/orderbook/index.d.ts +5 -0
- package/dist/orderbook/index.d.ts.map +1 -0
- package/dist/orderbook/index.js +5 -0
- package/dist/orderbook/use-binance-orderbook-source.d.ts +28 -0
- package/dist/orderbook/use-binance-orderbook-source.d.ts.map +1 -0
- package/dist/orderbook/use-binance-orderbook-source.js +26 -0
- package/dist/orderbook/use-binance-orderbook-source.js.map +1 -0
- package/dist/orderbook/use-live-orderbook.d.ts +104 -0
- package/dist/orderbook/use-live-orderbook.d.ts.map +1 -0
- package/dist/orderbook/use-live-orderbook.js +77 -0
- package/dist/orderbook/use-live-orderbook.js.map +1 -0
- package/dist/orderbook/use-orderbook-stream.d.ts +73 -0
- package/dist/orderbook/use-orderbook-stream.d.ts.map +1 -0
- package/dist/orderbook/use-orderbook-stream.js +49 -0
- package/dist/orderbook/use-orderbook-stream.js.map +1 -0
- package/dist/orderbook/use-orderbook.d.ts +35 -0
- package/dist/orderbook/use-orderbook.d.ts.map +1 -0
- package/dist/orderbook/use-orderbook.js +22 -0
- package/dist/orderbook/use-orderbook.js.map +1 -0
- package/dist/pools/index.d.ts +30 -0
- package/dist/pools/index.d.ts.map +1 -0
- package/dist/pools/index.js +30 -0
- package/dist/pools/use-add-market.d.ts +57 -0
- package/dist/pools/use-add-market.d.ts.map +1 -0
- package/dist/pools/use-add-market.js +30 -0
- package/dist/pools/use-add-market.js.map +1 -0
- package/dist/pools/use-authenticate-listing.d.ts +45 -0
- package/dist/pools/use-authenticate-listing.d.ts.map +1 -0
- package/dist/pools/use-authenticate-listing.js +30 -0
- package/dist/pools/use-authenticate-listing.js.map +1 -0
- package/dist/pools/use-cancel-withdraw.d.ts +47 -0
- package/dist/pools/use-cancel-withdraw.d.ts.map +1 -0
- package/dist/pools/use-cancel-withdraw.js +30 -0
- package/dist/pools/use-cancel-withdraw.js.map +1 -0
- package/dist/pools/use-claim-history.d.ts +25 -0
- package/dist/pools/use-claim-history.d.ts.map +1 -0
- package/dist/pools/use-claim-history.js +27 -0
- package/dist/pools/use-claim-history.js.map +1 -0
- package/dist/pools/use-claim-profit.d.ts +53 -0
- package/dist/pools/use-claim-profit.d.ts.map +1 -0
- package/dist/pools/use-claim-profit.js +30 -0
- package/dist/pools/use-claim-profit.js.map +1 -0
- package/dist/pools/use-deposit-address.d.ts +43 -0
- package/dist/pools/use-deposit-address.d.ts.map +1 -0
- package/dist/pools/use-deposit-address.js +28 -0
- package/dist/pools/use-deposit-address.js.map +1 -0
- package/dist/pools/use-listing-config.d.ts +28 -0
- package/dist/pools/use-listing-config.d.ts.map +1 -0
- package/dist/pools/use-listing-config.js +27 -0
- package/dist/pools/use-listing-config.js.map +1 -0
- package/dist/pools/use-listing-market-config-projection.d.ts +66 -0
- package/dist/pools/use-listing-market-config-projection.d.ts.map +1 -0
- package/dist/pools/use-listing-market-config-projection.js +57 -0
- package/dist/pools/use-listing-market-config-projection.js.map +1 -0
- package/dist/pools/use-listing-market-config.d.ts +49 -0
- package/dist/pools/use-listing-market-config.d.ts.map +1 -0
- package/dist/pools/use-listing-market-config.js +28 -0
- package/dist/pools/use-listing-market-config.js.map +1 -0
- package/dist/pools/use-listing-market-detail.d.ts +29 -0
- package/dist/pools/use-listing-market-detail.d.ts.map +1 -0
- package/dist/pools/use-listing-market-detail.js +27 -0
- package/dist/pools/use-listing-market-detail.js.map +1 -0
- package/dist/pools/use-listing-markets.d.ts +32 -0
- package/dist/pools/use-listing-markets.d.ts.map +1 -0
- package/dist/pools/use-listing-markets.js +27 -0
- package/dist/pools/use-listing-markets.js.map +1 -0
- package/dist/pools/use-listing-status.d.ts +29 -0
- package/dist/pools/use-listing-status.d.ts.map +1 -0
- package/dist/pools/use-listing-status.js +28 -0
- package/dist/pools/use-listing-status.js.map +1 -0
- package/dist/pools/use-pool-quotes.d.ts +26 -0
- package/dist/pools/use-pool-quotes.d.ts.map +1 -0
- package/dist/pools/use-pool-quotes.js +27 -0
- package/dist/pools/use-pool-quotes.js.map +1 -0
- package/dist/pools/use-pool-reward-chart.d.ts +32 -0
- package/dist/pools/use-pool-reward-chart.d.ts.map +1 -0
- package/dist/pools/use-pool-reward-chart.js +28 -0
- package/dist/pools/use-pool-reward-chart.js.map +1 -0
- package/dist/pools/use-pool-total-reward.d.ts +27 -0
- package/dist/pools/use-pool-total-reward.d.ts.map +1 -0
- package/dist/pools/use-pool-total-reward.js +28 -0
- package/dist/pools/use-pool-total-reward.js.map +1 -0
- package/dist/pools/use-pool-trade-history.d.ts +26 -0
- package/dist/pools/use-pool-trade-history.d.ts.map +1 -0
- package/dist/pools/use-pool-trade-history.js +27 -0
- package/dist/pools/use-pool-trade-history.js.map +1 -0
- package/dist/pools/use-pool-transactions.d.ts +23 -0
- package/dist/pools/use-pool-transactions.d.ts.map +1 -0
- package/dist/pools/use-pool-transactions.js +27 -0
- package/dist/pools/use-pool-transactions.js.map +1 -0
- package/dist/pools/use-refund-market.d.ts +51 -0
- package/dist/pools/use-refund-market.d.ts.map +1 -0
- package/dist/pools/use-refund-market.js +30 -0
- package/dist/pools/use-refund-market.js.map +1 -0
- package/dist/pools/use-retry-listing-info.d.ts +23 -0
- package/dist/pools/use-retry-listing-info.d.ts.map +1 -0
- package/dist/pools/use-retry-listing-info.js +27 -0
- package/dist/pools/use-retry-listing-info.js.map +1 -0
- package/dist/pools/use-retry-listing.d.ts +46 -0
- package/dist/pools/use-retry-listing.d.ts.map +1 -0
- package/dist/pools/use-retry-listing.js +30 -0
- package/dist/pools/use-retry-listing.js.map +1 -0
- package/dist/pools/use-supports-listing-service.d.ts +21 -0
- package/dist/pools/use-supports-listing-service.d.ts.map +1 -0
- package/dist/pools/use-supports-listing-service.js +13 -0
- package/dist/pools/use-supports-listing-service.js.map +1 -0
- package/dist/pools/use-update-listing-market-config.d.ts +60 -0
- package/dist/pools/use-update-listing-market-config.d.ts.map +1 -0
- package/dist/pools/use-update-listing-market-config.js +30 -0
- package/dist/pools/use-update-listing-market-config.js.map +1 -0
- package/dist/pools/use-user-listing-markets.d.ts +40 -0
- package/dist/pools/use-user-listing-markets.d.ts.map +1 -0
- package/dist/pools/use-user-listing-markets.js +28 -0
- package/dist/pools/use-user-listing-markets.js.map +1 -0
- package/dist/pools/use-user-profit.d.ts +39 -0
- package/dist/pools/use-user-profit.d.ts.map +1 -0
- package/dist/pools/use-user-profit.js +28 -0
- package/dist/pools/use-user-profit.js.map +1 -0
- package/dist/pools/use-user-reward-chart.d.ts +28 -0
- package/dist/pools/use-user-reward-chart.d.ts.map +1 -0
- package/dist/pools/use-user-reward-chart.js +28 -0
- package/dist/pools/use-user-reward-chart.js.map +1 -0
- package/dist/pools/use-user-total-reward.d.ts +30 -0
- package/dist/pools/use-user-total-reward.d.ts.map +1 -0
- package/dist/pools/use-user-total-reward.js +28 -0
- package/dist/pools/use-user-total-reward.js.map +1 -0
- package/dist/pools/use-user-transactions.d.ts +24 -0
- package/dist/pools/use-user-transactions.d.ts.map +1 -0
- package/dist/pools/use-user-transactions.js +27 -0
- package/dist/pools/use-user-transactions.js.map +1 -0
- package/dist/pools/use-weekly-listing-limit.d.ts +28 -0
- package/dist/pools/use-weekly-listing-limit.d.ts.map +1 -0
- package/dist/pools/use-weekly-listing-limit.js +28 -0
- package/dist/pools/use-weekly-listing-limit.js.map +1 -0
- package/dist/pools/use-withdraw-lp.d.ts +52 -0
- package/dist/pools/use-withdraw-lp.d.ts.map +1 -0
- package/dist/pools/use-withdraw-lp.js +30 -0
- package/dist/pools/use-withdraw-lp.js.map +1 -0
- package/dist/price-service/index.d.ts +8 -0
- package/dist/price-service/index.d.ts.map +1 -1
- package/dist/price-service/index.js +17 -9
- package/dist/price-service/use-binance-health.d.ts +16 -0
- package/dist/price-service/use-binance-health.d.ts.map +1 -0
- package/dist/price-service/use-binance-health.js +27 -0
- package/dist/price-service/use-binance-health.js.map +1 -0
- package/dist/price-service/use-binance-premium-index.d.ts +24 -0
- package/dist/price-service/use-binance-premium-index.d.ts.map +1 -0
- package/dist/price-service/use-binance-premium-index.js +27 -0
- package/dist/price-service/use-binance-premium-index.js.map +1 -0
- package/dist/price-service/use-binance-prices.d.ts +54 -0
- package/dist/price-service/use-binance-prices.d.ts.map +1 -0
- package/dist/price-service/use-binance-prices.js +57 -0
- package/dist/price-service/use-binance-prices.js.map +1 -0
- package/dist/price-service/use-binance-symbols-info.d.ts +18 -0
- package/dist/price-service/use-binance-symbols-info.d.ts.map +1 -0
- package/dist/price-service/use-binance-symbols-info.js +27 -0
- package/dist/price-service/use-binance-symbols-info.js.map +1 -0
- package/dist/price-service/use-enigma-price-by-market-id.d.ts +7 -1
- package/dist/price-service/use-enigma-price-by-market-id.d.ts.map +1 -1
- package/dist/price-service/use-enigma-price-by-market-id.js +1 -1
- package/dist/price-service/use-enigma-price-by-market-id.js.map +1 -1
- package/dist/price-service/use-mark-prices.d.ts +25 -0
- package/dist/price-service/use-mark-prices.d.ts.map +1 -0
- package/dist/price-service/use-mark-prices.js +27 -0
- package/dist/price-service/use-mark-prices.js.map +1 -0
- package/dist/price-service/use-price-by-market-id.d.ts +53 -0
- package/dist/price-service/use-price-by-market-id.d.ts.map +1 -0
- package/dist/price-service/use-price-by-market-id.js +33 -0
- package/dist/price-service/use-price-by-market-id.js.map +1 -0
- package/dist/price-service/use-price-by-name.d.ts +48 -0
- package/dist/price-service/use-price-by-name.d.ts.map +1 -0
- package/dist/price-service/use-price-by-name.js +23 -0
- package/dist/price-service/use-price-by-name.js.map +1 -0
- package/dist/price-service/use-prices.d.ts +87 -0
- package/dist/price-service/use-prices.d.ts.map +1 -0
- package/dist/price-service/use-prices.js +77 -0
- package/dist/price-service/use-prices.js.map +1 -0
- package/dist/provider/symmio-provider.d.ts +8 -2
- package/dist/provider/symmio-provider.d.ts.map +1 -1
- package/dist/provider/symmio-provider.js +19 -19
- package/dist/provider/symmio-provider.js.map +1 -1
- package/dist/quotes/confirm-hold.d.ts +121 -0
- package/dist/quotes/confirm-hold.d.ts.map +1 -0
- package/dist/quotes/confirm-hold.js +59 -0
- package/dist/quotes/confirm-hold.js.map +1 -0
- package/dist/quotes/index.d.ts +14 -0
- package/dist/quotes/index.d.ts.map +1 -1
- package/dist/quotes/use-account-upnl.d.ts +66 -0
- package/dist/quotes/use-account-upnl.d.ts.map +1 -0
- package/dist/quotes/use-account-upnl.js +73 -0
- package/dist/quotes/use-account-upnl.js.map +1 -0
- package/dist/quotes/use-close-quote-group.d.ts +126 -0
- package/dist/quotes/use-close-quote-group.d.ts.map +1 -0
- package/dist/quotes/use-close-quote-group.js +172 -0
- package/dist/quotes/use-close-quote-group.js.map +1 -0
- package/dist/quotes/use-cool-downs-of-ma.d.ts +26 -0
- package/dist/quotes/use-cool-downs-of-ma.d.ts.map +1 -0
- package/dist/quotes/use-cool-downs-of-ma.js +27 -0
- package/dist/quotes/use-cool-downs-of-ma.js.map +1 -0
- package/dist/quotes/use-force-cancel-close-request.d.ts +27 -0
- package/dist/quotes/use-force-cancel-close-request.d.ts.map +1 -0
- package/dist/quotes/use-force-cancel-close-request.js +41 -0
- package/dist/quotes/use-force-cancel-close-request.js.map +1 -0
- package/dist/quotes/use-force-cancel-quote.d.ts +26 -0
- package/dist/quotes/use-force-cancel-quote.d.ts.map +1 -0
- package/dist/quotes/use-force-cancel-quote.js +42 -0
- package/dist/quotes/use-force-cancel-quote.js.map +1 -0
- package/dist/quotes/use-force-close-eligibility.d.ts +30 -0
- package/dist/quotes/use-force-close-eligibility.d.ts.map +1 -0
- package/dist/quotes/use-force-close-eligibility.js +39 -0
- package/dist/quotes/use-force-close-eligibility.js.map +1 -0
- package/dist/quotes/use-force-close-params.d.ts +22 -0
- package/dist/quotes/use-force-close-params.d.ts.map +1 -0
- package/dist/quotes/use-force-close-params.js +27 -0
- package/dist/quotes/use-force-close-params.js.map +1 -0
- package/dist/quotes/use-force-close.d.ts +30 -0
- package/dist/quotes/use-force-close.d.ts.map +1 -0
- package/dist/quotes/use-force-close.js +38 -0
- package/dist/quotes/use-force-close.js.map +1 -0
- package/dist/quotes/use-grouped-quotes.d.ts +50 -10
- package/dist/quotes/use-grouped-quotes.d.ts.map +1 -1
- package/dist/quotes/use-grouped-quotes.js +40 -14
- package/dist/quotes/use-grouped-quotes.js.map +1 -1
- package/dist/quotes/use-grouping-isolation.d.ts +35 -0
- package/dist/quotes/use-grouping-isolation.d.ts.map +1 -0
- package/dist/quotes/use-grouping-isolation.js +39 -0
- package/dist/quotes/use-grouping-isolation.js.map +1 -0
- package/dist/quotes/use-limit-orders.d.ts +62 -0
- package/dist/quotes/use-limit-orders.d.ts.map +1 -0
- package/dist/quotes/use-limit-orders.js +82 -0
- package/dist/quotes/use-limit-orders.js.map +1 -0
- package/dist/quotes/use-managed-quotes.d.ts.map +1 -1
- package/dist/quotes/use-managed-quotes.js +198 -166
- package/dist/quotes/use-managed-quotes.js.map +1 -1
- package/dist/quotes/use-party-a-open-positions.d.ts +26 -6
- package/dist/quotes/use-party-a-open-positions.d.ts.map +1 -1
- package/dist/quotes/use-party-a-open-positions.js +32 -12
- package/dist/quotes/use-party-a-open-positions.js.map +1 -1
- package/dist/quotes/use-quote-funding.d.ts +2 -2
- package/dist/quotes/use-quote-funding.js.map +1 -1
- package/dist/quotes/use-quote-group-funding-history.d.ts +70 -0
- package/dist/quotes/use-quote-group-funding-history.d.ts.map +1 -0
- package/dist/quotes/use-quote-group-funding-history.js +38 -0
- package/dist/quotes/use-quote-group-funding-history.js.map +1 -0
- package/dist/quotes/use-quote-group-funding.d.ts +67 -0
- package/dist/quotes/use-quote-group-funding.d.ts.map +1 -0
- package/dist/quotes/use-quote-group-funding.js +26 -0
- package/dist/quotes/use-quote-group-funding.js.map +1 -0
- package/dist/quotes/use-quote-group-margin-risk.d.ts +111 -0
- package/dist/quotes/use-quote-group-margin-risk.d.ts.map +1 -0
- package/dist/quotes/use-quote-group-margin-risk.js +63 -0
- package/dist/quotes/use-quote-group-margin-risk.js.map +1 -0
- package/dist/quotes/use-quote-upnl-and-pnl.d.ts +4 -3
- package/dist/quotes/use-quote-upnl-and-pnl.d.ts.map +1 -1
- package/dist/quotes/use-quote-upnl-and-pnl.js +2 -1
- package/dist/quotes/use-quote-upnl-and-pnl.js.map +1 -1
- package/dist/quotes/use-quotes-funding.d.ts +46 -10
- package/dist/quotes/use-quotes-funding.d.ts.map +1 -1
- package/dist/quotes/use-quotes-funding.js +44 -42
- package/dist/quotes/use-quotes-funding.js.map +1 -1
- package/dist/quotes/use-request-to-cancel-close-request.d.ts +27 -0
- package/dist/quotes/use-request-to-cancel-close-request.d.ts.map +1 -0
- package/dist/quotes/use-request-to-cancel-close-request.js +41 -0
- package/dist/quotes/use-request-to-cancel-close-request.js.map +1 -0
- package/dist/quotes/use-request-to-cancel-quote.d.ts +32 -0
- package/dist/quotes/use-request-to-cancel-quote.d.ts.map +1 -0
- package/dist/quotes/use-request-to-cancel-quote.js +42 -0
- package/dist/quotes/use-request-to-cancel-quote.js.map +1 -0
- package/dist/rasa-solver/index.d.ts +7 -0
- package/dist/rasa-solver/index.d.ts.map +1 -0
- package/dist/rasa-solver/use-error-message.d.ts +14 -0
- package/dist/rasa-solver/use-error-message.d.ts.map +1 -0
- package/dist/rasa-solver/use-error-message.js +27 -0
- package/dist/rasa-solver/use-error-message.js.map +1 -0
- package/dist/rasa-solver/use-party-a-upnl.d.ts +14 -0
- package/dist/rasa-solver/use-party-a-upnl.d.ts.map +1 -0
- package/dist/rasa-solver/use-party-a-upnl.js +27 -0
- package/dist/rasa-solver/use-party-a-upnl.js.map +1 -0
- package/dist/rasa-solver/use-solver-balance-info.d.ts +14 -0
- package/dist/rasa-solver/use-solver-balance-info.d.ts.map +1 -0
- package/dist/rasa-solver/use-solver-balance-info.js +27 -0
- package/dist/rasa-solver/use-solver-balance-info.js.map +1 -0
- package/dist/rasa-solver/use-solver-open-interest.d.ts +14 -0
- package/dist/rasa-solver/use-solver-open-interest.d.ts.map +1 -0
- package/dist/rasa-solver/use-solver-open-interest.js +27 -0
- package/dist/rasa-solver/use-solver-open-interest.js.map +1 -0
- package/dist/rasa-solver/use-solver-price-range.d.ts +14 -0
- package/dist/rasa-solver/use-solver-price-range.d.ts.map +1 -0
- package/dist/rasa-solver/use-solver-price-range.js +27 -0
- package/dist/rasa-solver/use-solver-price-range.js.map +1 -0
- package/dist/rasa-solver/use-solver-readiness.d.ts +13 -0
- package/dist/rasa-solver/use-solver-readiness.d.ts.map +1 -0
- package/dist/rasa-solver/use-solver-readiness.js +27 -0
- package/dist/rasa-solver/use-solver-readiness.js.map +1 -0
- package/dist/revenue-records/index.d.ts +2 -0
- package/dist/revenue-records/index.d.ts.map +1 -0
- package/dist/revenue-records/use-revenue-records.d.ts +25 -0
- package/dist/revenue-records/use-revenue-records.d.ts.map +1 -0
- package/dist/revenue-records/use-revenue-records.js +27 -0
- package/dist/revenue-records/use-revenue-records.js.map +1 -0
- package/dist/solvers/index.d.ts +3 -0
- package/dist/solvers/index.d.ts.map +1 -0
- package/dist/solvers/use-solver-capabilities.d.ts +31 -0
- package/dist/solvers/use-solver-capabilities.d.ts.map +1 -0
- package/dist/solvers/use-solver-capabilities.js +30 -0
- package/dist/solvers/use-solver-capabilities.js.map +1 -0
- package/dist/solvers/use-solver-revenue.d.ts +28 -0
- package/dist/solvers/use-solver-revenue.d.ts.map +1 -0
- package/dist/solvers/use-solver-revenue.js +27 -0
- package/dist/solvers/use-solver-revenue.js.map +1 -0
- package/dist/symbols/index.d.ts +2 -0
- package/dist/symbols/index.d.ts.map +1 -0
- package/dist/symbols/use-symbols.d.ts +25 -0
- package/dist/symbols/use-symbols.d.ts.map +1 -0
- package/dist/symbols/use-symbols.js +27 -0
- package/dist/symbols/use-symbols.js.map +1 -0
- package/dist/tpsl/apply-tpsl-search-snapshot.d.ts +33 -0
- package/dist/tpsl/apply-tpsl-search-snapshot.d.ts.map +1 -0
- package/dist/tpsl/apply-tpsl-search-snapshot.js +51 -0
- package/dist/tpsl/apply-tpsl-search-snapshot.js.map +1 -0
- package/dist/tpsl/await-tpsl-confirmation.d.ts +77 -0
- package/dist/tpsl/await-tpsl-confirmation.d.ts.map +1 -0
- package/dist/tpsl/await-tpsl-confirmation.js +42 -0
- package/dist/tpsl/await-tpsl-confirmation.js.map +1 -0
- package/dist/tpsl/index.d.ts +11 -0
- package/dist/tpsl/index.d.ts.map +1 -1
- package/dist/tpsl/invalidate-tpsl.d.ts +23 -0
- package/dist/tpsl/invalidate-tpsl.d.ts.map +1 -0
- package/dist/tpsl/invalidate-tpsl.js +14 -0
- package/dist/tpsl/invalidate-tpsl.js.map +1 -0
- package/dist/tpsl/match-tpsl-notification.d.ts +27 -0
- package/dist/tpsl/match-tpsl-notification.d.ts.map +1 -0
- package/dist/tpsl/match-tpsl-notification.js +22 -0
- package/dist/tpsl/match-tpsl-notification.js.map +1 -0
- package/dist/tpsl/run-with-concurrency.d.ts +20 -0
- package/dist/tpsl/run-with-concurrency.d.ts.map +1 -0
- package/dist/tpsl/run-with-concurrency.js +15 -0
- package/dist/tpsl/run-with-concurrency.js.map +1 -0
- package/dist/tpsl/settled-side.d.ts +31 -0
- package/dist/tpsl/settled-side.d.ts.map +1 -0
- package/dist/tpsl/settled-side.js +21 -0
- package/dist/tpsl/settled-side.js.map +1 -0
- package/dist/tpsl/tpsl-fallback-poll.d.ts +74 -0
- package/dist/tpsl/tpsl-fallback-poll.d.ts.map +1 -0
- package/dist/tpsl/tpsl-fallback-poll.js +101 -0
- package/dist/tpsl/tpsl-fallback-poll.js.map +1 -0
- package/dist/tpsl/tpsl-store.d.ts +98 -2
- package/dist/tpsl/tpsl-store.d.ts.map +1 -1
- package/dist/tpsl/tpsl-store.js +111 -63
- package/dist/tpsl/tpsl-store.js.map +1 -1
- package/dist/tpsl/use-delete-quote-group-tpsl.d.ts +165 -0
- package/dist/tpsl/use-delete-quote-group-tpsl.d.ts.map +1 -0
- package/dist/tpsl/use-delete-quote-group-tpsl.js +247 -0
- package/dist/tpsl/use-delete-quote-group-tpsl.js.map +1 -0
- package/dist/tpsl/use-delete-quote-tpsl.d.ts.map +1 -1
- package/dist/tpsl/use-delete-quote-tpsl.js +11 -10
- package/dist/tpsl/use-delete-quote-tpsl.js.map +1 -1
- package/dist/tpsl/use-quote-group-tpsl-editor.d.ts +66 -0
- package/dist/tpsl/use-quote-group-tpsl-editor.d.ts.map +1 -0
- package/dist/tpsl/use-quote-group-tpsl-editor.js +78 -0
- package/dist/tpsl/use-quote-group-tpsl-editor.js.map +1 -0
- package/dist/tpsl/use-quote-group-tpsl.d.ts +74 -0
- package/dist/tpsl/use-quote-group-tpsl.d.ts.map +1 -0
- package/dist/tpsl/use-quote-group-tpsl.js +67 -0
- package/dist/tpsl/use-quote-group-tpsl.js.map +1 -0
- package/dist/tpsl/use-quote-tpsl.d.ts +18 -2
- package/dist/tpsl/use-quote-tpsl.d.ts.map +1 -1
- package/dist/tpsl/use-quote-tpsl.js +32 -24
- package/dist/tpsl/use-quote-tpsl.js.map +1 -1
- package/dist/tpsl/use-search-tpsl-orders.d.ts +30 -0
- package/dist/tpsl/use-search-tpsl-orders.d.ts.map +1 -0
- package/dist/tpsl/use-search-tpsl-orders.js +27 -0
- package/dist/tpsl/use-search-tpsl-orders.js.map +1 -0
- package/dist/tpsl/use-set-quote-group-tpsl.d.ts +234 -0
- package/dist/tpsl/use-set-quote-group-tpsl.d.ts.map +1 -0
- package/dist/tpsl/use-set-quote-group-tpsl.js +358 -0
- package/dist/tpsl/use-set-quote-group-tpsl.js.map +1 -0
- package/dist/tpsl/use-set-quote-tpsl.d.ts +4 -4
- package/dist/tpsl/use-set-quote-tpsl.d.ts.map +1 -1
- package/dist/tpsl/use-set-quote-tpsl.js +15 -12
- package/dist/tpsl/use-set-quote-tpsl.js.map +1 -1
- package/dist/tpsl/use-tpsl-supported.d.ts +22 -0
- package/dist/tpsl/use-tpsl-supported.d.ts.map +1 -0
- package/dist/tpsl/use-tpsl-supported.js +16 -0
- package/dist/tpsl/use-tpsl-supported.js.map +1 -0
- package/dist/tpsl/use-watch-tpsl-accounts.d.ts +33 -0
- package/dist/tpsl/use-watch-tpsl-accounts.d.ts.map +1 -0
- package/dist/tpsl/use-watch-tpsl-accounts.js +44 -0
- package/dist/tpsl/use-watch-tpsl-accounts.js.map +1 -0
- package/dist/trade-volume/index.d.ts +2 -0
- package/dist/trade-volume/index.d.ts.map +1 -0
- package/dist/trade-volume/use-trade-volume.d.ts +26 -0
- package/dist/trade-volume/use-trade-volume.d.ts.map +1 -0
- package/dist/trade-volume/use-trade-volume.js +27 -0
- package/dist/trade-volume/use-trade-volume.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/invalidate-account-balances.d.ts +36 -0
- package/dist/utils/invalidate-account-balances.d.ts.map +1 -0
- package/dist/utils/invalidate-account-balances.js +10 -0
- package/dist/utils/invalidate-account-balances.js.map +1 -0
- package/dist/websocket/use-notifications.d.ts +3 -1
- package/dist/websocket/use-notifications.d.ts.map +1 -1
- package/dist/websocket/use-notifications.js +22 -20
- package/dist/websocket/use-notifications.js.map +1 -1
- package/dist/withdraw/index.d.ts +1 -0
- package/dist/withdraw/index.d.ts.map +1 -1
- package/dist/withdraw/use-initiate-withdraw.d.ts +1 -1
- package/dist/withdraw/use-initiate-withdraw.js.map +1 -1
- package/dist/withdraw/use-request-cancel-withdraw.d.ts +4 -2
- package/dist/withdraw/use-request-cancel-withdraw.d.ts.map +1 -1
- package/dist/withdraw/use-request-cancel-withdraw.js +15 -13
- package/dist/withdraw/use-request-cancel-withdraw.js.map +1 -1
- package/dist/withdraw/use-withdraw.d.ts +67 -0
- package/dist/withdraw/use-withdraw.d.ts.map +1 -0
- package/dist/withdraw/use-withdraw.js +49 -0
- package/dist/withdraw/use-withdraw.js.map +1 -0
- package/package.json +18 -2
|
@@ -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 { 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
|
+
{"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 isCancelAction,\n isCloseFillAction,\n isolationTypeForSide,\n isOpenAnchorAction,\n NotificationType,\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, type QueryClient } 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 { invalidateAccountBalances, predicateMatch } from \"../utils\";\nimport { useNotifications } from \"../websocket/use-notifications\";\nimport {\n nextConfirmDelay,\n pruneCancelConfirmHold,\n pruneCloseConfirmHold,\n pruneOpenConfirmHold,\n type CloseConfirmEntry,\n} from \"./confirm-hold\";\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 * Confirm-hold backoff (see `openConfirmRef` / `closeConfirmRef` / `pumpConfirm`).\n * A notification reports a state change the on-chain read lags behind, so the reads\n * are refetched immediately and then again on a backoff that starts at\n * {@link CONFIRM_FIRST_DELAY}, doubles each round, and caps at\n * {@link CONFIRM_MAX_INTERVAL} — until the chain reflects the change or the total\n * {@link CONFIRM_MAX_MS} budget passes. It covers both directions:\n *\n * - an **open** anchor (`SendQuoteTransaction` & friends), which the solver emits when\n * it *broadcasts* the transaction: the single invalidation that frame triggers races\n * the block and usually loses, and it is the last frame of an instant open, so\n * without the chase the position stays invisible until something else refetches;\n * - a **close** fill, the rasa case where the quote lingers OPENED after\n * `FillMarketOrderInstantClose` and the settle lags;\n * - a **cancel** request, where the confirming transaction is the solver's\n * `acceptCancelRequest` and is never announced at all (see\n * {@link CANCEL_CONFIRM_MAX_MS}).\n */\nconst CONFIRM_FIRST_DELAY = 500;\n/** Ceiling for the doubling confirm-hold backoff interval (ms). */\nconst CONFIRM_MAX_INTERVAL = 60_000;\n/** Total budget (ms) to chase a reported change before giving up (a stuck / failed action). */\nconst CONFIRM_MAX_MS = 120_000;\n/**\n * Budget (ms) for the **cancel** confirm hold, longer than {@link CONFIRM_MAX_MS}\n * because a cancel can legitimately sit unanswered far longer than an open or a\n * close: `requestToCancelQuote` on a `LOCKED` quote only asks, and partyA cannot\n * force the issue until the market-agent force-cancel cooldown elapses (150 s on\n * Base at the time of writing, read from `coolDownsOfMA()[1]`). Giving up at two\n * minutes would go blind right as that window closes. The backoff is capped at\n * {@link CONFIRM_MAX_INTERVAL}, so a long wait costs about one read per minute, and\n * the hold releases itself the moment the chain drops the quote.\n */\nconst CANCEL_CONFIRM_MAX_MS = 600_000;\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/**\n * Invalidate the authoritative on-chain quote reads for one chain scope — the open\n * positions and the pending-quote ids, fanned out across every account. Scoped by\n * `configKey`, so another chain's cache is untouched; React Query dedups concurrent\n * refetches of the same query.\n */\nfunction invalidateOnchainQuoteReads(client: QueryClient, scope: { configKey: string }): void {\n void client.invalidateQueries({ predicate: predicateMatch(getPartyAOpenPositionsQueryKey, scope) });\n void client.invalidateQueries({ predicate: predicateMatch(getPartyAPendingQuotesQueryKey, scope) });\n}\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 in-flight close (the\n * close has either not started or already landed on-chain, where the feed drops\n * it and the close-confirm hold takes over), so polling the feed is wasted.\n */\nconst CLOSE_INTENT_LIFECYCLES = new Set<QuoteLifecycle>([QuoteLifecycle.WRITE_ONCHAIN_CLOSE]);\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 * Open-confirm hold: on-chain quoteId → deadline (ms). An open-anchor notification\n * (`onNotification`) records the quote here and kicks off `pumpConfirm`, which\n * refetches the on-chain reads on a doubling backoff until the read returns the\n * quote. The solver emits that frame when it *broadcasts* the transaction, so the\n * one invalidation it triggers races the block — and it is the **last** frame of an\n * instant open, so nothing else would ever re-read: with the event channel live\n * there is no idle poll, and the accelerated retry needs a `WRITE_ONCHAIN` row,\n * which only exists if a pre-chain row from the hedger feed was still there to\n * anchor. Entries are pruned once the polled struct lands or the\n * {@link CONFIRM_MAX_MS} budget passes.\n */\n const openConfirmRef = useRef<Map<string, number>>(new Map());\n /**\n * Close-confirm hold: on-chain quoteId → deadline (ms). A close notification\n * (`onNotification`) records the quote here and kicks off `pumpConfirm`, which\n * refetches the on-chain reads on a doubling backoff until the chain reflects the\n * close — the rasa case, where the quote lingers OPENED after\n * `FillMarketOrderInstantClose` and the stateless reconcile reverts the row to\n * `ONCHAIN`. Entries are pruned once the chain confirms the close (row dropped /\n * closed) or the {@link CONFIRM_MAX_MS} budget passes; when every map empties the\n * backoff stops.\n */\n const closeConfirmRef = useRef<Map<string, CloseConfirmEntry>>(new Map());\n /**\n * Cancel-confirm hold: on-chain quoteId → deadline (ms). A cancel notification\n * (`onNotification`) records the quote here and kicks off `pumpConfirm`, which\n * refetches the on-chain reads on a doubling backoff until the chain settles the\n * cancel. Cancelling a `LOCKED` order takes two transactions and only the first is\n * announced: `requestToCancelQuote` moves the quote to `CANCEL_PENDING` and leaves\n * it in `partyAPendingQuotes`, then the solver's `acceptCancelRequest` sets\n * `CANCELED` and removes it — with **no** notification frame. A `CANCEL_PENDING`\n * row is lifecycle `ONCHAIN`, so it accelerates nothing either; without this chase\n * the cancelled order stays on screen indefinitely. Entries are pruned once the\n * chain drops the quote or the {@link CANCEL_CONFIRM_MAX_MS} budget passes.\n */\n const cancelConfirmRef = useRef<Map<string, number>>(new Map());\n /** Pending confirm-hold backoff timer (the next scheduled refetch), if any. */\n const confirmTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n /** Current confirm-hold backoff interval (ms); doubles each round up to the cap. */\n const confirmDelayRef = useRef(CONFIRM_FIRST_DELAY);\n /** Latest `pumpConfirm`, called from the backoff timer (assigned below each render). */\n const pumpConfirmRef = useRef<() => void>(() => {});\n\n /**\n * (Re)start the confirm-hold backoff from its first delay — called whenever a\n * notification registers a new hold, so a fresh event always gets a prompt retry\n * even if a long-running chase had already backed off to the cap. Stable (refs\n * only), so it never re-creates `onNotification` and never resubscribes the socket.\n */\n const restartConfirmChase = useCallback(() => {\n confirmDelayRef.current = CONFIRM_FIRST_DELAY;\n if (confirmTimerRef.current) clearTimeout(confirmTimerRef.current);\n confirmTimerRef.current = setTimeout(() => pumpConfirmRef.current(), CONFIRM_FIRST_DELAY);\n }, []);\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. (An anchor or a close the read has not caught up\n * with is chased separately by `pumpConfirm`'s backoff, which needs no row at all,\n * not by this steady interval.) Otherwise:\n * no idle poll when the event channel is live (events drive updates) unless the\n * consumer opted into `idleInterval`; a baseline fallback when the channel is down so\n * state still progresses. Read from the previous result because the queries set their\n * interval before this render's result exists (an on-chain poll / notification\n * 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(\n (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 !== \"0\" && 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 /**\n * The quote **anchored on-chain**: the solver reports this when it broadcasts\n * the transaction, so the read is typically still a block behind and the\n * debounced invalidation below lands on the pre-anchor state. Register the hold\n * and chase it (`pumpConfirm`) until the read returns the quote — this is the\n * last frame of an instant open, so without the chase a confirmed position can\n * stay out of the table indefinitely. Only for a `SUCCESS` frame carrying a real\n * on-chain id (still-off-chain frames repeat the negative temp id), so a\n * reverted anchor is not chased for the full budget.\n */\n if (\n notification.type === NotificationType.SUCCESS &&\n isOpenAnchorAction(notification.lastSeenAction) &&\n onchainStr &&\n onchainStr !== \"0\" &&\n onchainStr !== `${tempId}`\n ) {\n openConfirmRef.current.set(onchainStr, Date.now() + CONFIRM_MAX_MS);\n invalidateOnchainQuoteReads(queryClientRef.current, { configKey: configKeyRef.current });\n restartConfirmChase();\n }\n // Close *filled* successfully (not merely requested, and not a failed fill):\n // refetch the on-chain reads immediately, then chase the settle on a doubling\n // backoff (`pumpConfirm`) until the chain reflects it or the budget passes.\n // Covers rasa, where the quote lingers OPENED after `FillMarketOrderInstantClose`\n // and the row would otherwise revert to ONCHAIN before the settle lands. The\n // `closedAmount` at fill-time is captured so a **partial** settle (closedAmount\n // advances, quote stays OPENED) releases the hold instead of hanging at \"closing\".\n if (\n notification.type === NotificationType.SUCCESS &&\n isCloseFillAction(notification.lastSeenAction) &&\n onchainStr &&\n onchainStr !== \"0\"\n ) {\n const baseClosed = previousRef.current?.quotes.find((q) => `${q.quoteId}` === onchainStr)?.closedAmount ?? 0n;\n closeConfirmRef.current.set(onchainStr, { deadline: Date.now() + CONFIRM_MAX_MS, baseClosed });\n invalidateOnchainQuoteReads(queryClientRef.current, { configKey: configKeyRef.current });\n restartConfirmChase();\n }\n // A close that **failed** (reverted / rejected): release the hold so the row\n // drops back to its on-chain state (still OPENED) instead of hanging at\n // `WRITE_ONCHAIN_CLOSE`, and re-read in case the revert moved anything.\n if (\n notification.type === NotificationType.FAILED &&\n classifyQuoteNotificationAction(notification.lastSeenAction) === \"close\" &&\n onchainStr &&\n onchainStr !== \"0\"\n ) {\n closeConfirmRef.current.delete(onchainStr);\n invalidateOnchainQuoteReads(queryClientRef.current, { configKey: configKeyRef.current });\n }\n /**\n * A cancel was **requested**. The frame arrives around the time the request\n * transaction is broadcast, so the debounced invalidation below still reads\n * `LOCKED` or at best `CANCEL_PENDING` — and the transaction that actually ends\n * the order, the solver's `acceptCancelRequest`, is never announced. Register\n * the hold and chase the read until the chain drops the quote. Unlike the open\n * anchor this deliberately does **not** require `type === SUCCESS`: a failed\n * cancel frame still means the chain may have moved, and the hold costs one read\n * that releases itself immediately if nothing changed.\n */\n if (isCancelAction(notification.lastSeenAction) && onchainStr && onchainStr !== \"0\") {\n cancelConfirmRef.current.set(onchainStr, Date.now() + CANCEL_CONFIRM_MAX_MS);\n invalidateOnchainQuoteReads(queryClientRef.current, { configKey: configKeyRef.current });\n invalidateAccountBalances(queryClientRef.current, { configKey: configKeyRef.current });\n restartConfirmChase();\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 invalidateOnchainQuoteReads(client, 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 [restartConfirmChase],\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 invalidateOnchainQuoteReads(client, 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 onchainPositions = wantOpenPositions ? openPositions.quotes : [];\n /**\n * On-chain ids whose close is filled-but-unsettled — held at\n * WRITE_ONCHAIN_CLOSE across ticks so the row does not flash back to \"Opened\"\n * while the settle mines. Dropped the moment the on-chain `closedAmount` moves\n * past the fill-time baseline (a partial settle back to a live position); the\n * full-settle and CLOSE_PENDING cases fall out of the reconcile on their own,\n * and a failed close already released its hold on the FAILED frame.\n */\n const closingQuoteIds: string[] = [];\n for (const [id, { baseClosed }] of closeConfirmRef.current) {\n const onchainClosed = onchainPositions.find((q) => `${q.id}` === id)?.closedAmount;\n if (onchainClosed !== undefined && onchainClosed > baseClosed) continue;\n closingQuoteIds.push(id);\n }\n const next = reconcileQuotes({\n partyA,\n onchainPositions,\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 closingQuoteIds,\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 /**\n * One backoff round for every confirm hold. Prunes the entries the on-chain read has\n * caught up with — an anchored open the read now returns ({@link pruneOpenConfirmHold}),\n * a close the chain reflects ({@link pruneCloseConfirmHold}), or a cancel the chain\n * settled ({@link pruneCancelConfirmHold}), all against the latest reconcile — plus\n * any whose budget passed; if any map still holds something, refetches the on-chain\n * reads and reschedules itself with a doubled interval (capped). When they are all\n * empty it stops, so the chase self-terminates the moment the chain catches up. Reads\n * only refs, so it always sees the latest quotes / config; reassigned each render and\n * invoked through {@link pumpConfirmRef} from the timer.\n */\n pumpConfirmRef.current = () => {\n const quotes = previousRef.current?.quotes ?? [];\n const now = Date.now();\n const expiredOpens = pruneOpenConfirmHold(openConfirmRef.current, quotes, now);\n const expiredCloses = pruneCloseConfirmHold(closeConfirmRef.current, quotes, now);\n const expiredCancels = pruneCancelConfirmHold(cancelConfirmRef.current, quotes, now);\n if (process.env.NODE_ENV !== \"production\") {\n if (expiredOpens.length > 0) {\n console.debug(\"[useManagedQuotes] open-confirm hold expired without on-chain confirmation\", expiredOpens);\n }\n if (expiredCloses.length > 0) {\n console.debug(\"[useManagedQuotes] close-confirm hold expired without on-chain confirmation\", expiredCloses);\n }\n if (expiredCancels.length > 0) {\n console.debug(\"[useManagedQuotes] cancel-confirm hold expired without on-chain confirmation\", expiredCancels);\n }\n }\n if (\n openConfirmRef.current.size === 0 &&\n closeConfirmRef.current.size === 0 &&\n cancelConfirmRef.current.size === 0\n ) {\n confirmTimerRef.current = undefined;\n return;\n }\n invalidateOnchainQuoteReads(queryClientRef.current, { configKey: configKeyRef.current });\n /**\n * A cancel still in flight also owes the account a refund: `acceptCancelRequest`\n * (and `forceCancelQuote`) return the open trading fee and release the reserved\n * margin. That transaction is not the consumer's own — no mutation `onSuccess`\n * covers it — and no frame announces it, so the balance reads only come back\n * with this chase. The open and close holds are not included: their balance\n * moves land in the consumer's own instant-layer mutation, which already\n * invalidates on success.\n */\n if (cancelConfirmRef.current.size > 0) {\n invalidateAccountBalances(queryClientRef.current, { configKey: configKeyRef.current });\n }\n confirmDelayRef.current = nextConfirmDelay(confirmDelayRef.current, CONFIRM_MAX_INTERVAL);\n confirmTimerRef.current = setTimeout(() => pumpConfirmRef.current(), confirmDelayRef.current);\n };\n\n /** Stop the confirm-hold backoff on unmount so a pending timer cannot fire after teardown. */\n useEffect(\n () => () => {\n if (confirmTimerRef.current) clearTimeout(confirmTimerRef.current);\n },\n [],\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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"}
|
|
@@ -3,20 +3,40 @@ import { UseQueryResult } from '@tanstack/react-query';
|
|
|
3
3
|
import { SymmioRequestError } from '../errors/symmio-request-error.js';
|
|
4
4
|
/**
|
|
5
5
|
* Parameters for {@link usePartyAOpenPositions}: the core query options (partyA,
|
|
6
|
-
* pagination, chain id, TanStack `query` overrides) plus an optional `config
|
|
6
|
+
* pagination, chain id, TanStack `query` overrides) plus an optional `config`
|
|
7
|
+
* and a `live` flag.
|
|
7
8
|
*/
|
|
8
|
-
export type UsePartyAOpenPositionsParameters = GetPartyAOpenPositionsOptions & ConfigParameter
|
|
9
|
+
export type UsePartyAOpenPositionsParameters = GetPartyAOpenPositionsOptions & ConfigParameter & {
|
|
10
|
+
/**
|
|
11
|
+
* Subscribe to settle notifications and burst-refetch when an open/close
|
|
12
|
+
* settles on-chain — so a just-closed position drops (or a partial close's
|
|
13
|
+
* remaining quantity updates) without a manual refresh. Shared WebSocket;
|
|
14
|
+
* requires the provider tree.
|
|
15
|
+
*
|
|
16
|
+
* Settle frames key on the **sub-account**. This resolves the right stream
|
|
17
|
+
* automatically: a Virtual Account (`partyA` on Enigma) is looked up via
|
|
18
|
+
* `getVirtualAccount` and its `parentAccount` sub-account is watched; a
|
|
19
|
+
* cross-margin sub-account (`partyA` on Rasa, `parentAccount == 0x0`) is its
|
|
20
|
+
* own stream. Works for both kinds without the caller supplying the
|
|
21
|
+
* sub-account. `@default false`
|
|
22
|
+
*/
|
|
23
|
+
live?: boolean;
|
|
24
|
+
};
|
|
9
25
|
/** Return type of {@link usePartyAOpenPositions}. */
|
|
10
26
|
export type UsePartyAOpenPositionsReturnType = UseQueryResult<GetPartyAOpenPositionsReturnType, SymmioRequestError>;
|
|
11
27
|
/**
|
|
12
28
|
* Read a partyA's open positions (full `Quote` structs) from the SYMMIO core.
|
|
13
|
-
* `partyA` is a virtual account (lowcap)
|
|
14
|
-
*
|
|
15
|
-
*
|
|
29
|
+
* `partyA` is a virtual account (lowcap) or the sub-account itself
|
|
30
|
+
* (cross-margin). The query is disabled until `partyA` is set. `chainId`
|
|
31
|
+
* defaults to the connected chain. Errors are normalized to
|
|
32
|
+
* {@link SymmioRequestError}. Pass `live: true` to auto-refetch when a close /
|
|
33
|
+
* open settles on-chain — it resolves the owning sub-account's notification
|
|
34
|
+
* stream for you (VA → `parentAccount`, sub-account → itself).
|
|
16
35
|
*
|
|
17
36
|
* @example
|
|
18
37
|
* ```tsx
|
|
19
|
-
*
|
|
38
|
+
* // Rasa (partyA = sub-account) or Enigma (partyA = VA) — `live` handles both.
|
|
39
|
+
* const { data } = usePartyAOpenPositions({ partyA, live: true });
|
|
20
40
|
* ```
|
|
21
41
|
*/
|
|
22
42
|
export declare function usePartyAOpenPositions(parameters?: UsePartyAOpenPositionsParameters): UsePartyAOpenPositionsReturnType;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-party-a-open-positions.d.ts","sourceRoot":"","sources":["../../src/quotes/use-party-a-open-positions.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"use-party-a-open-positions.d.ts","sourceRoot":"","sources":["../../src/quotes/use-party-a-open-positions.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,6BAA6B,EAClC,KAAK,gCAAgC,EAEtC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAKtF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAOzE;;;;GAIG;AACH,MAAM,MAAM,gCAAgC,GAAG,6BAA6B,GAC1E,eAAe,GAAG;IAChB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEJ,qDAAqD;AACrD,MAAM,MAAM,gCAAgC,GAAG,cAAc,CAAC,gCAAgC,EAAE,kBAAkB,CAAC,CAAC;AAEpH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,GAAE,gCAAqC,GAChD,gCAAgC,CA2ElC"}
|
|
@@ -2,26 +2,46 @@
|
|
|
2
2
|
import { useSymmioChainId as e } from "../provider/use-symmio-chain-id.js";
|
|
3
3
|
import { useSymmioConfig as t } from "../provider/use-symmio-config.js";
|
|
4
4
|
import { normalizeSymmError as n } from "../errors/normalize-symm-error.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { SETTLE_REFETCH_DELAYS_MS as r, isSettleNotification as i } from "../websocket/is-settle-notification.js";
|
|
6
|
+
import { useNotifications as a } from "../websocket/use-notifications.js";
|
|
7
|
+
import { predicateMatch as o } from "../utils/predicate-match.js";
|
|
8
|
+
import { useVirtualAccount as s } from "../account-layer/use-virtual-account.js";
|
|
9
|
+
import { NotificationType as c, getPartyAOpenPositionsQueryKey as l, getPartyAOpenPositionsQueryOptions as u } from "@symmio/trading-core";
|
|
10
|
+
import { useCallback as d } from "react";
|
|
11
|
+
import { zeroAddress as f } from "viem";
|
|
12
|
+
import { useQuery as p, useQueryClient as m } from "@tanstack/react-query";
|
|
7
13
|
//#region src/quotes/use-party-a-open-positions.ts
|
|
8
|
-
function
|
|
9
|
-
let
|
|
10
|
-
...
|
|
11
|
-
chainId:
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
...c,
|
|
14
|
+
function h(h = {}) {
|
|
15
|
+
let { live: g, ..._ } = h, v = t(_), y = e(), b = _.chainId ?? y, x = _.partyA, S = u(v, {
|
|
16
|
+
..._,
|
|
17
|
+
chainId: b
|
|
18
|
+
}), C = p({
|
|
19
|
+
...S,
|
|
15
20
|
queryFn: async () => {
|
|
16
21
|
try {
|
|
17
|
-
return await
|
|
22
|
+
return await S.queryFn();
|
|
18
23
|
} catch (e) {
|
|
19
24
|
throw n(e);
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
|
-
})
|
|
27
|
+
}), w = s({
|
|
28
|
+
account: x ?? f,
|
|
29
|
+
chainId: b,
|
|
30
|
+
config: _.config,
|
|
31
|
+
query: { enabled: !!(g && x) }
|
|
32
|
+
}).data?.parentAccount, T = w && w !== f ? w : x, E = m();
|
|
33
|
+
return a({
|
|
34
|
+
account: T,
|
|
35
|
+
chainId: b,
|
|
36
|
+
config: _.config,
|
|
37
|
+
enabled: !!(g && T) && _.query?.enabled !== !1,
|
|
38
|
+
onNotification: d((e) => {
|
|
39
|
+
let t = e.type === c.SUCCESS && e.lastSeenAction === "InstantRequestToLimitClose";
|
|
40
|
+
if (!(!i(e) && !t) && x) for (let e of r) setTimeout(() => void E.invalidateQueries({ predicate: o(l, { partyA: x }) }), e);
|
|
41
|
+
}, [E, x])
|
|
42
|
+
}), C;
|
|
23
43
|
}
|
|
24
44
|
//#endregion
|
|
25
|
-
export {
|
|
45
|
+
export { h as usePartyAOpenPositions };
|
|
26
46
|
|
|
27
47
|
//# sourceMappingURL=use-party-a-open-positions.js.map
|
|
@@ -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
|
|
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 getPartyAOpenPositionsQueryKey,\n getPartyAOpenPositionsQueryOptions,\n NotificationType,\n type ConfigParameter,\n type GetPartyAOpenPositionsOptions,\n type GetPartyAOpenPositionsReturnType,\n type Notification,\n} from \"@symmio/trading-core\";\nimport { useQuery, useQueryClient, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useCallback } from \"react\";\nimport { zeroAddress } from \"viem\";\nimport { useVirtualAccount } from \"../account-layer/use-virtual-account\";\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\";\nimport { predicateMatch } from \"../utils\";\nimport { isSettleNotification, SETTLE_REFETCH_DELAYS_MS } from \"../websocket/is-settle-notification\";\nimport { useNotifications } from \"../websocket/use-notifications\";\n\n/**\n * Parameters for {@link usePartyAOpenPositions}: the core query options (partyA,\n * pagination, chain id, TanStack `query` overrides) plus an optional `config`\n * and a `live` flag.\n */\nexport type UsePartyAOpenPositionsParameters = GetPartyAOpenPositionsOptions &\n ConfigParameter & {\n /**\n * Subscribe to settle notifications and burst-refetch when an open/close\n * settles on-chain — so a just-closed position drops (or a partial close's\n * remaining quantity updates) without a manual refresh. Shared WebSocket;\n * requires the provider tree.\n *\n * Settle frames key on the **sub-account**. This resolves the right stream\n * automatically: a Virtual Account (`partyA` on Enigma) is looked up via\n * `getVirtualAccount` and its `parentAccount` sub-account is watched; a\n * cross-margin sub-account (`partyA` on Rasa, `parentAccount == 0x0`) is its\n * own stream. Works for both kinds without the caller supplying the\n * sub-account. `@default false`\n */\n live?: boolean;\n };\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) or the sub-account itself\n * (cross-margin). The query is disabled until `partyA` is set. `chainId`\n * defaults to the connected chain. Errors are normalized to\n * {@link SymmioRequestError}. Pass `live: true` to auto-refetch when a close /\n * open settles on-chain — it resolves the owning sub-account's notification\n * stream for you (VA → `parentAccount`, sub-account → itself).\n *\n * @example\n * ```tsx\n * // Rasa (partyA = sub-account) or Enigma (partyA = VA) — `live` handles both.\n * const { data } = usePartyAOpenPositions({ partyA, live: true });\n * ```\n */\nexport function usePartyAOpenPositions(\n parameters: UsePartyAOpenPositionsParameters = {},\n): UsePartyAOpenPositionsReturnType {\n const { live, ...queryParameters } = parameters;\n const config = useSymmioConfig(queryParameters);\n const chainId = useSymmioChainId();\n const resolvedChainId = queryParameters.chainId ?? chainId;\n const partyA = queryParameters.partyA;\n const options = getPartyAOpenPositionsQueryOptions(config, {\n ...queryParameters,\n chainId: resolvedChainId,\n });\n\n const query = 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 // Resolve the account whose notification stream carries `partyA`'s settle\n // frames: a VA's frames arrive on its `parentAccount` sub-account; a\n // sub-account (parent `0x0`) is its own. The mapping is fixed at creation so\n // this caches forever, and read only when `live`. If it errors or is still\n // loading, we fall back to `partyA` — already correct for a cross-margin\n // sub-account, so a failed read never breaks the Rasa case.\n const vaDetail = useVirtualAccount({\n account: partyA ?? zeroAddress,\n chainId: resolvedChainId,\n config: queryParameters.config,\n query: { enabled: Boolean(live && partyA) },\n });\n const parentAccount = vaDetail.data?.parentAccount;\n const notificationAccount = parentAccount && parentAccount !== zeroAddress ? parentAccount : partyA;\n\n const queryClient = useQueryClient();\n useNotifications({\n account: notificationAccount,\n chainId: resolvedChainId,\n config: queryParameters.config,\n enabled: Boolean(live && notificationAccount) && queryParameters.query?.enabled !== false,\n onNotification: useCallback(\n (notification: Notification) => {\n // Settle frames (open anchored / close filled) already cover market closes\n // — a market close's fill is a settle. The one close that isn't a settle is\n // the **limit-close anchor** (`InstantRequestToLimitClose`): a resting close\n // that flips the position to CLOSE_PENDING with no fill and no balance move,\n // so refetch on exactly that in addition to settles.\n const isLimitCloseAnchor =\n notification.type === NotificationType.SUCCESS &&\n notification.lastSeenAction === \"InstantRequestToLimitClose\";\n if (!isSettleNotification(notification) && !isLimitCloseAnchor) return;\n if (!partyA) return;\n // Invalidate (not `refetch`) so every consumer of this partyA's open\n // positions updates — including `useManagedQuotes`, which reads the same\n // data under a different query key (no `start`/`size`); a partial-key\n // predicate matches them all. The on-chain read lags the block, so fire a\n // short burst until the updated positions land.\n for (const ms of SETTLE_REFETCH_DELAYS_MS) {\n setTimeout(\n () =>\n void queryClient.invalidateQueries({\n predicate: predicateMatch(getPartyAOpenPositionsQueryKey, { partyA }),\n }),\n ms,\n );\n }\n },\n [queryClient, partyA],\n ),\n });\n\n return query;\n}\n"],"mappings":";;;;;;;;;;;;;AAgEA,SAAgB,EACd,IAA+C,CAAC,GACd;CAClC,IAAM,EAAE,SAAM,GAAG,MAAoB,GAC/B,IAAS,EAAgB,CAAe,GACxC,IAAU,EAAiB,GAC3B,IAAkB,EAAgB,WAAW,GAC7C,IAAS,EAAgB,QACzB,IAAU,EAAmC,GAAQ;EACzD,GAAG;EACH,SAAS;CACX,CAAC,GAEK,IAAQ,EAAS;EACrB,GAAG;EACH,SAAS,YAAY;GACnB,IAAI;IACF,OAAO,MAAM,EAAQ,QAAQ;GAC/B,SAAS,GAAK;IACZ,MAAM,EAAmB,CAAG;GAC9B;EACF;CACF,CAAC,GAcK,IANW,EAAkB;EACjC,SAAS,KAAU;EACnB,SAAS;EACT,QAAQ,EAAgB;EACxB,OAAO,EAAE,SAAS,GAAQ,KAAQ,GAAQ;CAC5C,CACsB,EAAS,MAAM,eAC/B,IAAsB,KAAiB,MAAkB,IAAc,IAAgB,GAEvF,IAAc,EAAe;CAqCnC,OApCA,EAAiB;EACf,SAAS;EACT,SAAS;EACT,QAAQ,EAAgB;EACxB,SAAS,GAAQ,KAAQ,MAAwB,EAAgB,OAAO,YAAY;EACpF,gBAAgB,GACb,MAA+B;GAM9B,IAAM,IACJ,EAAa,SAAS,EAAiB,WACvC,EAAa,mBAAmB;GAC9B,OAAC,EAAqB,CAAY,KAAK,CAAC,MACvC,GAML,KAAK,IAAM,KAAM,GACf,iBAEI,KAAK,EAAY,kBAAkB,EACjC,WAAW,EAAe,GAAgC,EAAE,UAAO,CAAC,EACtE,CAAC,GACH,CACF;EAEJ,GACA,CAAC,GAAa,CAAM,CACtB;CACF,CAAC,GAEM;AACT"}
|
|
@@ -21,8 +21,8 @@ export interface UseQuoteFundingReturnType {
|
|
|
21
21
|
error: SymmioRequestError | null;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* Read funding totals (paid / received /
|
|
25
|
-
* Disabled while `quoteId` is `undefined` (off-chain row).
|
|
24
|
+
* Read funding totals (paid / received / netReceived) for a single on-chain
|
|
25
|
+
* quote. Disabled while `quoteId` is `undefined` (off-chain row).
|
|
26
26
|
*
|
|
27
27
|
* Thin wrapper over {@link useQuotesFunding} with a one-element batch.
|
|
28
28
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-quote-funding.js","names":[],"sources":["../../src/quotes/use-quote-funding.ts"],"sourcesContent":["\"use client\";\n\nimport type { ConfigParameter, QuoteFundingData } from \"@symmio/trading-core\";\nimport { useMemo } from \"react\";\nimport type { SymmioRequestError } from \"../errors/symmio-request-error\";\nimport { useQuotesFunding } from \"./use-quotes-funding\";\n\n/**\n * Parameters for {@link useQuoteFunding}.\n */\nexport interface UseQuoteFundingParameters extends ConfigParameter {\n /** On-chain quote id. `undefined` (off-chain) disables the query. */\n quoteId?: bigint;\n /** Optional chain id override; defaults to the connected chain. */\n chainId?: number;\n}\n\n/**\n * Return type of {@link useQuoteFunding}.\n */\nexport interface UseQuoteFundingReturnType {\n /** The funding row for this quote, or `null` until it resolves. */\n data: QuoteFundingData | null;\n /** `true` while the subgraph query is loading. */\n isLoading: boolean;\n /** Normalized request error, when one occurred. */\n error: SymmioRequestError | null;\n}\n\nconst EMPTY_QUOTES: readonly { quoteId?: bigint }[] = [];\n\n/**\n * Read funding totals (paid / received /
|
|
1
|
+
{"version":3,"file":"use-quote-funding.js","names":[],"sources":["../../src/quotes/use-quote-funding.ts"],"sourcesContent":["\"use client\";\n\nimport type { ConfigParameter, QuoteFundingData } from \"@symmio/trading-core\";\nimport { useMemo } from \"react\";\nimport type { SymmioRequestError } from \"../errors/symmio-request-error\";\nimport { useQuotesFunding } from \"./use-quotes-funding\";\n\n/**\n * Parameters for {@link useQuoteFunding}.\n */\nexport interface UseQuoteFundingParameters extends ConfigParameter {\n /** On-chain quote id. `undefined` (off-chain) disables the query. */\n quoteId?: bigint;\n /** Optional chain id override; defaults to the connected chain. */\n chainId?: number;\n}\n\n/**\n * Return type of {@link useQuoteFunding}.\n */\nexport interface UseQuoteFundingReturnType {\n /** The funding row for this quote, or `null` until it resolves. */\n data: QuoteFundingData | null;\n /** `true` while the subgraph query is loading. */\n isLoading: boolean;\n /** Normalized request error, when one occurred. */\n error: SymmioRequestError | null;\n}\n\nconst EMPTY_QUOTES: readonly { quoteId?: bigint }[] = [];\n\n/**\n * Read funding totals (paid / received / netReceived) for a single on-chain\n * quote. Disabled while `quoteId` is `undefined` (off-chain row).\n *\n * Thin wrapper over {@link useQuotesFunding} with a one-element batch.\n *\n * @example\n * ```tsx\n * const { data, isLoading } = useQuoteFunding({ quoteId: quote.quoteId });\n * ```\n */\nexport function useQuoteFunding(parameters: UseQuoteFundingParameters): UseQuoteFundingReturnType {\n const { quoteId, chainId, config } = parameters;\n\n const quotes = useMemo(() => (quoteId === undefined ? EMPTY_QUOTES : [{ quoteId }]), [quoteId]);\n\n const batch = useQuotesFunding({ quotes, chainId, config });\n\n return {\n data: batch.rows[0] ?? null,\n isLoading: batch.isLoading,\n error: batch.error,\n };\n}\n"],"mappings":";;;;AA6BA,IAAM,IAAgD,CAAC;AAavD,SAAgB,EAAgB,GAAkE;CAChG,IAAM,EAAE,YAAS,YAAS,cAAW,GAI/B,IAAQ,EAAiB;EAAE,QAFlB,QAAe,MAAY,KAAA,IAAY,IAAe,CAAC,EAAE,WAAQ,CAAC,GAAI,CAAC,CAAO,CAE5D;EAAQ;EAAS;CAAO,CAAC;CAE1D,OAAO;EACL,MAAM,EAAM,KAAK,MAAM;EACvB,WAAW,EAAM;EACjB,OAAO,EAAM;CACf;AACF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ConfigParameter, GetQuotesEventsByTypeOptions, GetQuotesEventsByTypeReturnType, QuoteGroup } from '@symmio/trading-core';
|
|
2
|
+
import { UseQueryResult } from '@tanstack/react-query';
|
|
3
|
+
import { SymmioRequestError } from '../errors/symmio-request-error.js';
|
|
4
|
+
/**
|
|
5
|
+
* Parameters for {@link useQuoteGroupFundingHistory}: the batched core query
|
|
6
|
+
* options minus the two fields this hook owns — `quoteIds` (derived from the
|
|
7
|
+
* group's children) and `types` (locked to {@link FUNDING_HISTORY_EVENT_TYPES}) —
|
|
8
|
+
* plus an optional `config`.
|
|
9
|
+
*/
|
|
10
|
+
export type UseQuoteGroupFundingHistoryParameters = Omit<GetQuotesEventsByTypeOptions, "quoteIds" | "types"> & ConfigParameter & {
|
|
11
|
+
/** The group whose children's funding ticks are merged into one timeline. */
|
|
12
|
+
group: QuoteGroup;
|
|
13
|
+
};
|
|
14
|
+
/** Return type of {@link useQuoteGroupFundingHistory}. */
|
|
15
|
+
export type UseQuoteGroupFundingHistoryReturnType = UseQueryResult<GetQuotesEventsByTypeReturnType, SymmioRequestError>;
|
|
16
|
+
/**
|
|
17
|
+
* Read the funding history of a whole {@link QuoteGroup} as **one merged,
|
|
18
|
+
* time-sorted timeline** — the group analogue of `useQuotePriceHistory`.
|
|
19
|
+
*
|
|
20
|
+
* Every on-chain child of the group is fetched in a single subgraph round-trip
|
|
21
|
+
* and the rows come back already interleaved and sorted by `timestamp` (newest
|
|
22
|
+
* first unless `orderDirection: "asc"` is passed). Each row carries its own
|
|
23
|
+
* `quoteId`, so a caller that wants a per-position breakdown groups by that
|
|
24
|
+
* field client-side.
|
|
25
|
+
*
|
|
26
|
+
* Per-row funding fields are `fundingPaid` / `fundingReceived` (18-decimal wei)
|
|
27
|
+
* plus the `rate` applied for that tick (a signed `int256` as wei). Those fields
|
|
28
|
+
* are verbatim from the subgraph; net a row the way the rest of the SDK does —
|
|
29
|
+
* `fundingReceived − fundingPaid`, so a **positive** net means the position
|
|
30
|
+
* **earned** funding on that tick, matching `QuoteFundingData.netReceived`.
|
|
31
|
+
*
|
|
32
|
+
* Children with no on-chain `quoteId` (optimistic rows that have not anchored
|
|
33
|
+
* yet) have no subgraph events and are dropped from the request; ids are
|
|
34
|
+
* de-duplicated so a group holding the same quote twice does not fragment the
|
|
35
|
+
* cache. When the group has no on-chain children the query stays disabled.
|
|
36
|
+
*
|
|
37
|
+
* Paging is over the **merged** stream, not per quote id: pass `first` / `skip`
|
|
38
|
+
* and page while `data.hasMore` is `true`. Omitting `first` asks for the 1000-row
|
|
39
|
+
* ceiling the subgraph enforces, so an un-paged call loads the whole timeline
|
|
40
|
+
* unless the group has more ticks than a single request can return.
|
|
41
|
+
*
|
|
42
|
+
* `chainId` defaults to the connected chain. Errors are normalized to
|
|
43
|
+
* {@link SymmioRequestError}.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* This is funding **settled to date** — what the analytics subgraph has indexed.
|
|
47
|
+
* Funding that has accrued since the last on-chain charge is not indexed and is
|
|
48
|
+
* therefore absent from this timeline.
|
|
49
|
+
*
|
|
50
|
+
* @remarks
|
|
51
|
+
* On current deployments effectively every row is `CHARGE_FUNDING_RATE`.
|
|
52
|
+
* `CHARGE_ACCUMULATED_FUNDING_FEE` is part of {@link FUNDING_HISTORY_EVENT_TYPES}
|
|
53
|
+
* for completeness but is not yet emitted, so do not rely on seeing it.
|
|
54
|
+
*
|
|
55
|
+
* @param parameters - The group, optional paging/sort/chain id, TanStack `query`
|
|
56
|
+
* overrides, and an optional `config`.
|
|
57
|
+
* @returns A TanStack query result holding the merged `rows` and a `hasMore` flag.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* const { data, isLoading } = useQuoteGroupFundingHistory({ group, first: 100 });
|
|
62
|
+
*
|
|
63
|
+
* for (const row of data?.rows ?? []) {
|
|
64
|
+
* const net = (row.fundingPaid ?? 0n) - (row.fundingReceived ?? 0n);
|
|
65
|
+
* // net > 0n → the user paid funding on this tick.
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function useQuoteGroupFundingHistory(parameters: UseQuoteGroupFundingHistoryParameters): UseQuoteGroupFundingHistoryReturnType;
|
|
70
|
+
//# sourceMappingURL=use-quote-group-funding-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-quote-group-funding-history.d.ts","sourceRoot":"","sources":["../../src/quotes/use-quote-group-funding-history.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,EACpC,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAIzE;;;;;GAKG;AACH,MAAM,MAAM,qCAAqC,GAAG,IAAI,CAAC,4BAA4B,EAAE,UAAU,GAAG,OAAO,CAAC,GAC1G,eAAe,GAAG;IAChB,6EAA6E;IAC7E,KAAK,EAAE,UAAU,CAAC;CACnB,CAAC;AAEJ,0DAA0D;AAC1D,MAAM,MAAM,qCAAqC,GAAG,cAAc,CAAC,+BAA+B,EAAE,kBAAkB,CAAC,CAAC;AAExH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,qCAAqC,GAChD,qCAAqC,CAwCvC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useSymmioChainId as e } from "../provider/use-symmio-chain-id.js";
|
|
3
|
+
import { useSymmioConfig as t } from "../provider/use-symmio-config.js";
|
|
4
|
+
import { normalizeSymmError as n } from "../errors/normalize-symm-error.js";
|
|
5
|
+
import { FUNDING_HISTORY_EVENT_TYPES as r, getQuotesEventsByTypeQueryOptions as i } from "@symmio/trading-core";
|
|
6
|
+
import { useMemo as a } from "react";
|
|
7
|
+
import { useQuery as o } from "@tanstack/react-query";
|
|
8
|
+
//#region src/quotes/use-quote-group-funding-history.ts
|
|
9
|
+
function s(s) {
|
|
10
|
+
let { group: c, ...l } = s, u = t(s), d = e(), f = a(() => {
|
|
11
|
+
let e = /* @__PURE__ */ new Set(), t = [];
|
|
12
|
+
for (let n of c.quotes) {
|
|
13
|
+
if (n.quoteId === void 0) continue;
|
|
14
|
+
let r = n.quoteId.toString();
|
|
15
|
+
e.has(r) || (e.add(r), t.push(n.quoteId));
|
|
16
|
+
}
|
|
17
|
+
return t;
|
|
18
|
+
}, [c.quotes]), p = i(u, {
|
|
19
|
+
...l,
|
|
20
|
+
chainId: l.chainId ?? d,
|
|
21
|
+
quoteIds: f,
|
|
22
|
+
types: r
|
|
23
|
+
});
|
|
24
|
+
return o({
|
|
25
|
+
...p,
|
|
26
|
+
queryFn: async () => {
|
|
27
|
+
try {
|
|
28
|
+
return await p.queryFn();
|
|
29
|
+
} catch (e) {
|
|
30
|
+
throw n(e);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { s as useQuoteGroupFundingHistory };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=use-quote-group-funding-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-quote-group-funding-history.js","names":[],"sources":["../../src/quotes/use-quote-group-funding-history.ts"],"sourcesContent":["\"use client\";\n\nimport {\n FUNDING_HISTORY_EVENT_TYPES,\n getQuotesEventsByTypeQueryOptions,\n type ConfigParameter,\n type GetQuotesEventsByTypeOptions,\n type GetQuotesEventsByTypeReturnType,\n type QuoteGroup,\n} from \"@symmio/trading-core\";\nimport { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useMemo } from \"react\";\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 useQuoteGroupFundingHistory}: the batched core query\n * options minus the two fields this hook owns — `quoteIds` (derived from the\n * group's children) and `types` (locked to {@link FUNDING_HISTORY_EVENT_TYPES}) —\n * plus an optional `config`.\n */\nexport type UseQuoteGroupFundingHistoryParameters = Omit<GetQuotesEventsByTypeOptions, \"quoteIds\" | \"types\"> &\n ConfigParameter & {\n /** The group whose children's funding ticks are merged into one timeline. */\n group: QuoteGroup;\n };\n\n/** Return type of {@link useQuoteGroupFundingHistory}. */\nexport type UseQuoteGroupFundingHistoryReturnType = UseQueryResult<GetQuotesEventsByTypeReturnType, SymmioRequestError>;\n\n/**\n * Read the funding history of a whole {@link QuoteGroup} as **one merged,\n * time-sorted timeline** — the group analogue of `useQuotePriceHistory`.\n *\n * Every on-chain child of the group is fetched in a single subgraph round-trip\n * and the rows come back already interleaved and sorted by `timestamp` (newest\n * first unless `orderDirection: \"asc\"` is passed). Each row carries its own\n * `quoteId`, so a caller that wants a per-position breakdown groups by that\n * field client-side.\n *\n * Per-row funding fields are `fundingPaid` / `fundingReceived` (18-decimal wei)\n * plus the `rate` applied for that tick (a signed `int256` as wei). Those fields\n * are verbatim from the subgraph; net a row the way the rest of the SDK does —\n * `fundingReceived − fundingPaid`, so a **positive** net means the position\n * **earned** funding on that tick, matching `QuoteFundingData.netReceived`.\n *\n * Children with no on-chain `quoteId` (optimistic rows that have not anchored\n * yet) have no subgraph events and are dropped from the request; ids are\n * de-duplicated so a group holding the same quote twice does not fragment the\n * cache. When the group has no on-chain children the query stays disabled.\n *\n * Paging is over the **merged** stream, not per quote id: pass `first` / `skip`\n * and page while `data.hasMore` is `true`. Omitting `first` asks for the 1000-row\n * ceiling the subgraph enforces, so an un-paged call loads the whole timeline\n * unless the group has more ticks than a single request can return.\n *\n * `chainId` defaults to the connected chain. Errors are normalized to\n * {@link SymmioRequestError}.\n *\n * @remarks\n * This is funding **settled to date** — what the analytics subgraph has indexed.\n * Funding that has accrued since the last on-chain charge is not indexed and is\n * therefore absent from this timeline.\n *\n * @remarks\n * On current deployments effectively every row is `CHARGE_FUNDING_RATE`.\n * `CHARGE_ACCUMULATED_FUNDING_FEE` is part of {@link FUNDING_HISTORY_EVENT_TYPES}\n * for completeness but is not yet emitted, so do not rely on seeing it.\n *\n * @param parameters - The group, optional paging/sort/chain id, TanStack `query`\n * overrides, and an optional `config`.\n * @returns A TanStack query result holding the merged `rows` and a `hasMore` flag.\n *\n * @example\n * ```tsx\n * const { data, isLoading } = useQuoteGroupFundingHistory({ group, first: 100 });\n *\n * for (const row of data?.rows ?? []) {\n * const net = (row.fundingPaid ?? 0n) - (row.fundingReceived ?? 0n);\n * // net > 0n → the user paid funding on this tick.\n * }\n * ```\n */\nexport function useQuoteGroupFundingHistory(\n parameters: UseQuoteGroupFundingHistoryParameters,\n): UseQuoteGroupFundingHistoryReturnType {\n const { group, ...rest } = parameters;\n const config = useSymmioConfig(parameters);\n const chainId = useSymmioChainId();\n\n /**\n * On-chain ids of the group's children: optimistic rows (no `quoteId`) have no\n * subgraph events and are dropped, and duplicates are collapsed so the query\n * key stays stable.\n */\n const quoteIds = useMemo(() => {\n const seen = new Set<string>();\n const ids: bigint[] = [];\n for (const quote of group.quotes) {\n if (quote.quoteId === undefined) continue;\n const key = quote.quoteId.toString();\n if (seen.has(key)) continue;\n seen.add(key);\n ids.push(quote.quoteId);\n }\n return ids;\n }, [group.quotes]);\n\n const options = getQuotesEventsByTypeQueryOptions(config, {\n ...rest,\n chainId: rest.chainId ?? chainId,\n quoteIds,\n types: FUNDING_HISTORY_EVENT_TYPES,\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 UseQuoteGroupFundingHistoryReturnType;\n}\n"],"mappings":";;;;;;;;AAqFA,SAAgB,EACd,GACuC;CACvC,IAAM,EAAE,UAAO,GAAG,MAAS,GACrB,IAAS,EAAgB,CAAU,GACnC,IAAU,EAAiB,GAO3B,IAAW,QAAc;EAC7B,IAAM,oBAAO,IAAI,IAAY,GACvB,IAAgB,CAAC;EACvB,KAAK,IAAM,KAAS,EAAM,QAAQ;GAChC,IAAI,EAAM,YAAY,KAAA,GAAW;GACjC,IAAM,IAAM,EAAM,QAAQ,SAAS;GAC/B,EAAK,IAAI,CAAG,MAChB,EAAK,IAAI,CAAG,GACZ,EAAI,KAAK,EAAM,OAAO;EACxB;EACA,OAAO;CACT,GAAG,CAAC,EAAM,MAAM,CAAC,GAEX,IAAU,EAAkC,GAAQ;EACxD,GAAG;EACH,SAAS,EAAK,WAAW;EACzB;EACA,OAAO;CACT,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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ConfigParameter, GetQuoteFundingOptions, QuoteFundingData, QuoteGroup, QuoteGroupFunding } from '@symmio/trading-core';
|
|
2
|
+
import { SymmioRequestError } from '../errors/symmio-request-error.js';
|
|
3
|
+
/**
|
|
4
|
+
* Parameters for {@link useQuoteGroupFunding}.
|
|
5
|
+
*/
|
|
6
|
+
export interface UseQuoteGroupFundingParameters extends Omit<GetQuoteFundingOptions, "quoteIds">, ConfigParameter {
|
|
7
|
+
/** The group to read settled funding for. */
|
|
8
|
+
group: QuoteGroup;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Return type of {@link useQuoteGroupFunding}.
|
|
12
|
+
*/
|
|
13
|
+
export interface UseQuoteGroupFundingReturnType {
|
|
14
|
+
/** Aggregated settled funding for the group. */
|
|
15
|
+
funding: QuoteGroupFunding;
|
|
16
|
+
/** Funding row per child quote, aligned 1:1 with `group.quotes`; `null` when unresolved. */
|
|
17
|
+
rows: Array<QuoteFundingData | null>;
|
|
18
|
+
/** `true` while the underlying subgraph query is loading. */
|
|
19
|
+
isLoading: boolean;
|
|
20
|
+
/** Normalized request error, when one occurred. */
|
|
21
|
+
error: SymmioRequestError | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read the settled funding of a whole {@link QuoteGroup} — the group-level
|
|
25
|
+
* counterpart of `useQuoteFunding`.
|
|
26
|
+
*
|
|
27
|
+
* Every child quote's funding is fetched in one subgraph round-trip via
|
|
28
|
+
* {@link useQuotesFunding}, then folded by core's pure `aggregateGroupFunding`.
|
|
29
|
+
* All arithmetic lives in core; this hook only wires the read to the fold and
|
|
30
|
+
* memoizes the result, so the returned object is referentially stable while the
|
|
31
|
+
* group and its rows are unchanged.
|
|
32
|
+
*
|
|
33
|
+
* **Sign convention** — `funding.netReceived = received − paid`, so a **positive**
|
|
34
|
+
* value means the group has **earned** funding and a negative one means it has
|
|
35
|
+
* **paid** for it. This matches {@link QuoteFundingData} and the uPnL folds, so
|
|
36
|
+
* "green = income" coloring renders it as-is; it is the inverse of the
|
|
37
|
+
* cost-positive on-chain `int256`.
|
|
38
|
+
*
|
|
39
|
+
* **Check `funding.isComplete` before presenting the total as final.**
|
|
40
|
+
* `netReceived` is always the sum over the children that resolved, i.e. a lower
|
|
41
|
+
* bound while the subgraph is still indexing (`funding.missingQuoteIds`
|
|
42
|
+
* non-empty). An all-optimistic or empty group reports `isComplete: false` with
|
|
43
|
+
* `netReceived: 0n`, so treat `isComplete: false` as "funding unknown", not as
|
|
44
|
+
* "no funding".
|
|
45
|
+
*
|
|
46
|
+
* **Settled to date only** — these totals cover funding the protocol has already
|
|
47
|
+
* charged and the analytics subgraph has indexed. Funding accrued since a
|
|
48
|
+
* quote's last funding charge is not indexed anywhere and is therefore not
|
|
49
|
+
* included.
|
|
50
|
+
*
|
|
51
|
+
* @param parameters - The group to read, plus optional chain/query/config overrides.
|
|
52
|
+
* @returns The aggregated group funding, the per-child rows, and query state.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* function GroupedPositionCard({ group }: { group: QuoteGroup }) {
|
|
57
|
+
* const { funding, isLoading } = useQuoteGroupFunding({ group });
|
|
58
|
+
*
|
|
59
|
+
* if (isLoading || !funding.isComplete) return <FundingSkeleton />;
|
|
60
|
+
*
|
|
61
|
+
* // Already income-positive: `netReceived > 0n` means the group EARNED funding.
|
|
62
|
+
* return <Money amount={funding.netReceived} label="Funding" />;
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function useQuoteGroupFunding(parameters: UseQuoteGroupFundingParameters): UseQuoteGroupFundingReturnType;
|
|
67
|
+
//# sourceMappingURL=use-quote-group-funding.d.ts.map
|