@gala-chain/gswap-sdk 1.2.0 → 2.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/README.md +42 -8
  2. package/dist/browser/classes/apply_results.js +1 -1
  3. package/dist/browser/classes/apply_results.js.map +1 -1
  4. package/dist/browser/classes/assets.js +1 -1
  5. package/dist/browser/classes/assets.js.map +1 -1
  6. package/dist/browser/classes/dex_fees.js +1 -1
  7. package/dist/browser/classes/dex_fees.js.map +1 -1
  8. package/dist/browser/classes/gateway.js +1 -1
  9. package/dist/browser/classes/gateway.js.map +1 -1
  10. package/dist/browser/classes/gdex_stream.js +1 -1
  11. package/dist/browser/classes/gdex_stream.js.map +1 -1
  12. package/dist/browser/classes/gswap.js +1 -1
  13. package/dist/browser/classes/gswap.js.map +1 -1
  14. package/dist/browser/classes/gswap_error_catalog.js +2 -0
  15. package/dist/browser/classes/gswap_error_catalog.js.map +1 -0
  16. package/dist/browser/classes/gswap_error_phase_table.js +2 -0
  17. package/dist/browser/classes/gswap_error_phase_table.js.map +1 -0
  18. package/dist/browser/classes/gswap_sdk_error.js +1 -1
  19. package/dist/browser/classes/gswap_sdk_error.js.map +1 -1
  20. package/dist/browser/classes/http_client.js +1 -1
  21. package/dist/browser/classes/http_client.js.map +1 -1
  22. package/dist/browser/classes/leaderboard.js +2 -0
  23. package/dist/browser/classes/leaderboard.js.map +1 -0
  24. package/dist/browser/classes/market.js +2 -0
  25. package/dist/browser/classes/market.js.map +1 -0
  26. package/dist/browser/classes/pending_swap_fate.js.map +1 -1
  27. package/dist/browser/classes/pending_swaps.js +1 -1
  28. package/dist/browser/classes/pending_swaps.js.map +1 -1
  29. package/dist/browser/classes/pools.js +1 -1
  30. package/dist/browser/classes/pools.js.map +1 -1
  31. package/dist/browser/classes/positions.js +1 -1
  32. package/dist/browser/classes/positions.js.map +1 -1
  33. package/dist/browser/classes/quoting.js +1 -1
  34. package/dist/browser/classes/quoting.js.map +1 -1
  35. package/dist/browser/classes/shadow_submit.js.map +1 -1
  36. package/dist/browser/classes/storage_adapters.js.map +1 -1
  37. package/dist/browser/classes/submitted_transaction.js +1 -1
  38. package/dist/browser/classes/submitted_transaction.js.map +1 -1
  39. package/dist/browser/classes/swaps.js +1 -1
  40. package/dist/browser/classes/swaps.js.map +1 -1
  41. package/dist/browser/classes/symbols.js +1 -1
  42. package/dist/browser/classes/symbols.js.map +1 -1
  43. package/dist/browser/index.js +1 -1
  44. package/dist/browser/types/env.js.map +1 -1
  45. package/dist/browser/types/fees.js.map +1 -1
  46. package/dist/browser/types/market.js +2 -0
  47. package/dist/browser/types/market.js.map +1 -0
  48. package/dist/browser/utils/classification.js.map +1 -1
  49. package/dist/browser/utils/confirmation_schedule.js.map +1 -1
  50. package/dist/browser/utils/confirmation_state.js +1 -1
  51. package/dist/browser/utils/confirmation_state.js.map +1 -1
  52. package/dist/browser/utils/debug.js.map +1 -1
  53. package/dist/browser/utils/dto_builders.js +1 -1
  54. package/dist/browser/utils/dto_builders.js.map +1 -1
  55. package/dist/browser/utils/failure_classification.js +1 -1
  56. package/dist/browser/utils/failure_classification.js.map +1 -1
  57. package/dist/browser/utils/failure_guards.js +1 -1
  58. package/dist/browser/utils/failure_guards.js.map +1 -1
  59. package/dist/browser/utils/lenient.js +1 -1
  60. package/dist/browser/utils/lenient.js.map +1 -1
  61. package/dist/browser/utils/ordering.js +1 -1
  62. package/dist/browser/utils/ordering.js.map +1 -1
  63. package/dist/browser/utils/reconnection.js +1 -1
  64. package/dist/browser/utils/reconnection.js.map +1 -1
  65. package/dist/browser/utils/resolve_pre_send.js +2 -0
  66. package/dist/browser/utils/resolve_pre_send.js.map +1 -0
  67. package/dist/browser/utils/server_message.js.map +1 -1
  68. package/dist/browser/utils/shadow_errors.js +1 -1
  69. package/dist/browser/utils/shadow_errors.js.map +1 -1
  70. package/dist/browser/utils/submit_state.js.map +1 -1
  71. package/dist/browser/utils/tick_align.js.map +1 -1
  72. package/dist/browser/utils/tick_math.js.map +1 -1
  73. package/dist/browser/utils/tick_range.js.map +1 -1
  74. package/dist/browser/utils/ticks.js +1 -1
  75. package/dist/browser/utils/ticks.js.map +1 -1
  76. package/dist/browser/utils/validation.js +1 -1
  77. package/dist/browser/utils/validation.js.map +1 -1
  78. package/dist/index.cjs +1033 -2925
  79. package/dist/index.cjs.map +1 -1
  80. package/dist/index.d.cts +439 -1604
  81. package/dist/index.d.ts +439 -1604
  82. package/dist/index.mjs +964 -2810
  83. package/dist/index.mjs.map +1 -1
  84. package/package.json +36 -60
  85. package/dist/browser/classes/error_catalog.js +0 -2
  86. package/dist/browser/classes/error_catalog.js.map +0 -1
  87. package/dist/browser/classes/error_phase_table.js +0 -2
  88. package/dist/browser/classes/error_phase_table.js.map +0 -1
  89. package/dist/browser/classes/error_phases.js +0 -2
  90. package/dist/browser/classes/error_phases.js.map +0 -1
  91. package/dist/browser/classes/signers.js +0 -2
  92. package/dist/browser/classes/signers.js.map +0 -1
  93. package/dist/browser/utils/axios_requestor.js +0 -2
  94. package/dist/browser/utils/axios_requestor.js.map +0 -1
  95. package/dist/browser/utils/chain_dto_signing.js +0 -3
  96. package/dist/browser/utils/chain_dto_signing.js.map +0 -1
  97. package/dist/browser/utils/class_key.js +0 -2
  98. package/dist/browser/utils/class_key.js.map +0 -1
  99. package/dist/browser/utils/eip712.js +0 -4
  100. package/dist/browser/utils/eip712.js.map +0 -1
  101. package/dist/browser/utils/error_brand.js +0 -2
  102. package/dist/browser/utils/error_brand.js.map +0 -1
  103. package/dist/browser/utils/ethers_provider.js +0 -2
  104. package/dist/browser/utils/ethers_provider.js.map +0 -1
  105. package/dist/browser/utils/failure_outcomes.js +0 -2
  106. package/dist/browser/utils/failure_outcomes.js.map +0 -1
  107. package/dist/browser/utils/failure_view.js +0 -2
  108. package/dist/browser/utils/failure_view.js.map +0 -1
  109. package/dist/browser/utils/fetch_failure.js +0 -2
  110. package/dist/browser/utils/fetch_failure.js.map +0 -1
  111. package/dist/browser/utils/pre_send.js +0 -2
  112. package/dist/browser/utils/pre_send.js.map +0 -1
  113. package/dist/browser/utils/signing.js +0 -3
  114. package/dist/browser/utils/signing.js.map +0 -1
  115. package/dist/browser/utils/transport.js +0 -2
  116. package/dist/browser/utils/transport.js.map +0 -1
  117. package/dist/browser/utils/typed_data.js +0 -2
  118. package/dist/browser/utils/typed_data.js.map +0 -1
  119. package/dist/browser/utils/unique_key.js +0 -2
  120. package/dist/browser/utils/unique_key.js.map +0 -1
  121. package/dist/browser/utils/unique_key_syntax.js +0 -2
  122. package/dist/browser/utils/unique_key_syntax.js.map +0 -1
  123. package/dist/browser/utils/wallet_rejection.js +0 -2
  124. package/dist/browser/utils/wallet_rejection.js.map +0 -1
  125. package/dist/browser/version.js +0 -2
  126. package/dist/browser/version.js.map +0 -1
  127. package/dist/browser/wallet.js +0 -2
  128. package/dist/browser/wallet.js.map +0 -1
  129. package/dist/wallet.cjs +0 -159
  130. package/dist/wallet.cjs.map +0 -1
  131. package/dist/wallet.d.cts +0 -74
  132. package/dist/wallet.d.ts +0 -74
  133. package/dist/wallet.mjs +0 -156
  134. package/dist/wallet.mjs.map +0 -1
  135. /package/dist/browser/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/defineProperty.js +0 -0
  136. /package/dist/browser/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/toPrimitive.js +0 -0
  137. /package/dist/browser/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/toPropertyKey.js +0 -0
  138. /package/dist/browser/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/typeof.js +0 -0
package/README.md CHANGED
@@ -8,17 +8,33 @@ Gateway. Swap requests are queued for later application.
8
8
  ## Install
9
9
 
10
10
  ```bash
11
- npm install @gala-chain/gswap-sdk
11
+ npm install @gala-chain/gswap-sdk@next @gala-chain/gala-core-sdk@next
12
12
  ```
13
13
 
14
- `latest` is `1.2.0` (signing primitives, the error catalog, failure
15
- classification, the `/wallet` subpath). Pin an exact version
16
- (`@gala-chain/gswap-sdk@1.2.0`) for a wallet or app build.
14
+ `@gala-chain/gala-core-sdk` is a peer dependency (range `>=1.0.0-rc.4 <2`):
15
+ install it next to the SDK. 2.0 is a release candidate under the `next`
16
+ dist-tag; `latest` is still 1.2.0, so an install without `@next` gets 1.x.
17
+ Pin exact versions for a wallet or app build.
18
+
19
+ ## 2.0: signing moved to @gala-chain/gala-core-sdk
20
+
21
+ Since 2.0.0 the signing, transport, wallet-helper and base-error layer lives in
22
+ `@gala-chain/gala-core-sdk`. This package no longer exports or re-exports it:
23
+ signers (`PrivateKeySigner`, `GalaWalletSigner`, `BrowserWalletSigner`), the
24
+ signing and EIP-712 primitives, the transport adapters, the failure views, the
25
+ unique-key helpers and the wallet helpers are imported from the core package.
26
+ `GSwap`, the DEX API and the DEX error catalog stay here. The old
27
+ `@gala-chain/gswap-sdk/wallet` subpath is now `@gala-chain/gala-core-sdk/wallet`,
28
+ and some identifiers were renamed (`isGSwapErrorLike` is `isGalaErrorLike`).
29
+ The full old-path to new-path table is in
30
+ [`../gala-core-sdk/MIGRATING-FROM-GSWAP.md`](../gala-core-sdk/MIGRATING-FROM-GSWAP.md);
31
+ see also [MIGRATION-SIGNING.md](./MIGRATION-SIGNING.md).
17
32
 
18
33
  ## Quick start
19
34
 
20
35
  ```typescript
21
- import { GSwap, PrivateKeySigner } from '@gala-chain/gswap-sdk';
36
+ import { GSwap } from '@gala-chain/gswap-sdk';
37
+ import { PrivateKeySigner } from '@gala-chain/gala-core-sdk';
22
38
 
23
39
  const signer = new PrivateKeySigner(process.env.GALACHAIN_PRIVATE_KEY!);
24
40
  const gSwap = new GSwap({ signer, walletAddress: process.env.GALACHAIN_ADDRESS, env: 'stage' });
@@ -42,6 +58,21 @@ resolve it later from the persisted key alone. Liquidity writes continue to
42
58
  confirm by re-reading position state. A request `transactionId` may be `null` when the
43
59
  gateway does not provide one.
44
60
 
61
+ ## Market data and leaderboard
62
+
63
+ Public reads, no signer needed: USD prices (`market.getPrices`, 1-500 tokens, split into requests
64
+ the backend accepts, each read under the
65
+ exact id it was asked for), price series (`market.getPriceSeries`, windows `1D` `1W` `1M` `1Y`
66
+ `ALL`), platform volume (`market.getVolumeSummary`) and the trading-competition seasons and
67
+ rankings (`leaderboard.getSeasons`, `getCurrentSeason`, `getLeaderboard`,
68
+ `getCurrentLeaderboard`). See [Market Data and Leaderboard](./docs/docs/tutorial-basics/market-data.md).
69
+
70
+ ```typescript
71
+ const gala = await gSwap.market.getPrice('GALA$Unit$none$none'); // undefined: no entry
72
+ const series = await gSwap.market.getPriceSeries('GALA$Unit$none$none', '1W');
73
+ const season = await gSwap.leaderboard.getCurrentSeason(); // null between seasons
74
+ ```
75
+
45
76
  ## Hosts and environment presets
46
77
 
47
78
  The SDK has one network boundary: the swap backend. It does not call public
@@ -75,6 +106,7 @@ See the [realtime stream guide](./docs/docs/tutorial-basics/realtime-stream.md).
75
106
  | `GalaWalletSigner` | Native `gala_signChainDto`; opt-in `personal-sign` needs a wallet build with fix 34ca4e4 (unreleased) | Selected account (`0x...`, `eth\|...`, `client\|...`) |
76
107
  | `BrowserWalletSigner` | EIP-1193 `personal_sign`; opt-in `{ scheme: 'eip712' }` (`eth_signTypedData_v4`) | Selected Ethereum account (`eip712` also resolves a `client\|` alias) |
77
108
 
109
+ The signers are exported by `@gala-chain/gala-core-sdk`, not by this package.
78
110
  Native signing is the default for server keys and current Gala Wallets.
79
111
  Browser wallet personal-sign signs the bare serialized DTO (the wallet applies
80
112
  the EIP-191 header) and sends that header as the DTO's `prefix`, which is what
@@ -98,7 +130,7 @@ server-side clients). See [App and Wallet Integration](./docs/docs/other/app-int
98
130
  Errors carry a stable `code` and flat `params` that an app localizes; `classifyFailure`,
99
131
  `pendingSwapFateFor`, `isNoMarket` and the other deciders answer retry and outcome questions from the
100
132
  code, never from message text ([Error Handling](./docs/docs/other/error-handling.md)). App-shell code
101
- that must not load the SDK imports its wallet helpers from `@gala-chain/gswap-sdk/wallet`
133
+ that must not load the SDK imports its wallet helpers from `@gala-chain/gala-core-sdk/wallet`
102
134
  ([Bundle size](./docs/docs/other/bundle-size.md)). Tick and price math, including the contract's
103
135
  in-range rule, is in [Tick and Price Math](./docs/docs/other/tick-and-price-math.md).
104
136
 
@@ -106,8 +138,10 @@ in-range rule, is in [Tick and Price Math](./docs/docs/other/tick-and-price-math
106
138
 
107
139
  Read the [gSwap SDK documentation](https://galachain.github.io/gswap-sdk/docs/intro)
108
140
  for setup, quoting, trading, liquidity, signing, migration, and API reference
109
- guides. Working examples are in [`examples/cli`](./examples/cli) and
110
- [`examples/full_dex`](./examples/full_dex).
141
+ guides. Working examples are in [`examples/cli`](./examples/cli),
142
+ [`examples/full_dex`](./examples/full_dex) and [`examples/demos`](./examples/demos) (runnable
143
+ scripts for swaps, quotes, pools, liquidity positions, fees, market data, leaderboards and pool
144
+ watching; moved here from launchpad-sdk, which has no DEX).
111
145
 
112
146
  ## License
113
147
 
@@ -1,2 +1,2 @@
1
- import{createConfirmationSchedule as e,throwIfAborted as t}from"../utils/confirmation_schedule.js";import{serverMessageOfBody as n}from"../utils/server_message.js";import{isValidUniqueKey as r}from"../utils/unique_key_syntax.js";import{GSwapSDKError as i,getStringProperty as a}from"./gswap_sdk_error.js";import{buildRequestHeaders as o,fetchRequestor as s,readBlockNumberHeader as c,readHeader as l,readResponseBody as u,readRetryAfter as d,requestWithTimeout as f}from"../utils/transport.js";var p=class extends i{constructor(e,t,n={}){super(e,t,n),this.name=`AppliedTradeError`}};async function m(i,a,c){let{uniqueKey:l}=a;if(!r(l))throw new p(`INVALID_UNIQUE_KEY`,{uniqueKey:String(l)},{uniqueKey:l});let m=i.httpRequestor??s,g=i.requestTimeoutMs??3e4,_=c?.signal,y=e=>new p(`CONFIRMATION_ABORTED`,{},{uniqueKey:l,cause:e}),b=`${i.dexBackendBaseUrl.replace(/\/$/u,``)}/v1/chain/apply-results/${encodeURIComponent(l)}?channel=asset&contract=dex-contract`,x=e(c,3e3,y);await x.waitForRead();let S;for(;;){t(_,y);let e,r;try{e=await f(m,b,{method:`GET`,headers:o(i.wire),..._===void 0?{}:{signal:_}},g),r=await u(e)}catch(e){if(t(_,y),S=e,!await x.waitForRead())break;continue}if(t(_,y),e.status===200)return h(a,e,r,b);if(e.status===404||e.status===429||v(e.status)){let t=e.status===429?d(e):void 0;if(!await x.waitForRead(t))break;continue}throw new p(`CONFIRMATION_FAILED`,{status:e.status,serverMessage:n(r)},{uniqueKey:l,status:e.status,body:r,url:b})}throw new p(`CONFIRMATION_TIMEOUT`,{},{uniqueKey:l,requestTransactionId:a.requestTransactionId,url:b,cause:S})}function h(e,t,n,r){let{uniqueKey:i}=e,o=y(n),s=o?.uniqueKey??o?.UniqueKey;if(typeof s==`string`&&s!==i)throw new p(`CONFIRMATION_KEY_MISMATCH`,{},{uniqueKey:i,status:t.status,body:n,url:r});let u=o?.Status,d=l(t,`x-apply-transaction-id`)??null,f=c(t,`x-apply-block-number`)??null;if(u===0)throw new p(`CHAIN_REJECTED`,{errorKey:a(o,`ErrorKey`)??`CHAIN_ERROR`,serverMessage:a(o,`Message`)??``},{uniqueKey:i,requestTransactionId:e.requestTransactionId,applyTransactionId:d,blockNumber:f,status:t.status,body:n,url:r});if(u!==1)throw g(e,t,n,r);let m=_(o?.Data);if(m===void 0)throw g(e,t,n,r);return{uniqueKey:i,transactionId:d,blockNumber:f,requestTransactionId:e.requestTransactionId,result:m}}function g(e,t,n,r){return new p(`CONFIRMATION_MALFORMED`,{},{uniqueKey:e.uniqueKey,status:t.status,body:n,url:r})}function _(e){let t=y(e);if(t===void 0||typeof t.token0!=`string`||typeof t.token1!=`string`||typeof t.fee!=`number`)return;let n=[`sell0Qty`,`sell1Qty`,`buy0Qty`,`buy1Qty`,`tradingFees`,`protocolFees`,`totalFees`];for(let e of n)if(e in t&&typeof t[e]!=`string`)return;return{token0:t.token0,token1:t.token1,fee:t.fee,...Object.fromEntries(n.flatMap(e=>typeof t[e]==`string`?[[e,t[e]]]:[]))}}function v(e){return e===500||e===502||e===503||e===504}function y(e){return typeof e==`object`&&e?e:void 0}export{p as AppliedTradeError,m as confirmAppliedTrade};
1
+ import{createConfirmationSchedule as e,throwIfAborted as t}from"../utils/confirmation_schedule.js";import{serverMessageOfBody as n}from"../utils/server_message.js";import{GSwapSDKError as r,getStringProperty as i}from"./gswap_sdk_error.js";import{buildRequestHeaders as a,fetchRequestor as o,isValidUniqueKey as s,readBlockNumberHeader as c,readHeader as l,readResponseBody as u,readRetryAfter as d,requestWithTimeout as f}from"@gala-chain/gala-core-sdk";var p=class extends r{constructor(e,t,n={}){super(e,t,n),this.name=`AppliedTradeError`}};async function m(r,i,c){let{uniqueKey:l}=i;if(!s(l))throw new p(`INVALID_UNIQUE_KEY`,{uniqueKey:String(l)},{uniqueKey:l});let m=r.httpRequestor??o,g=r.requestTimeoutMs??3e4,_=c?.signal,y=e=>new p(`CONFIRMATION_ABORTED`,{},{uniqueKey:l,cause:e}),b=`${r.dexBackendBaseUrl.replace(/\/$/u,``)}/v1/chain/apply-results/${encodeURIComponent(l)}?channel=asset&contract=dex-contract`,x=e(c,3e3,y);await x.waitForRead();let S;for(;;){t(_,y);let e,o;try{e=await f(m,b,{method:`GET`,headers:a(r.wire),..._===void 0?{}:{signal:_}},g),o=await u(e)}catch(e){if(t(_,y),S=e,!await x.waitForRead())break;continue}if(t(_,y),e.status===200)return h(i,e,o,b);if(e.status===404||e.status===429||v(e.status)){let t=e.status===429?d(e):void 0;if(!await x.waitForRead(t))break}else throw new p(`CONFIRMATION_FAILED`,{status:e.status,serverMessage:n(o)},{uniqueKey:l,status:e.status,body:o,url:b})}throw new p(`CONFIRMATION_TIMEOUT`,{},{uniqueKey:l,requestTransactionId:i.requestTransactionId,url:b,cause:S})}function h(e,t,n,r){let{uniqueKey:a}=e,o=y(n),s=o?.uniqueKey??o?.UniqueKey;if(typeof s==`string`&&s!==a)throw new p(`CONFIRMATION_KEY_MISMATCH`,{},{uniqueKey:a,status:t.status,body:n,url:r});let u=o?.Status,d=l(t,`x-apply-transaction-id`)??null,f=c(t,`x-apply-block-number`)??null;if(u===0)throw new p(`CHAIN_REJECTED`,{errorKey:i(o,`ErrorKey`)??`CHAIN_ERROR`,serverMessage:i(o,`Message`)??``},{uniqueKey:a,requestTransactionId:e.requestTransactionId,applyTransactionId:d,blockNumber:f,status:t.status,body:n,url:r});if(u!==1)throw g(e,t,n,r);let m=_(o?.Data);if(m===void 0)throw g(e,t,n,r);return{uniqueKey:a,transactionId:d,blockNumber:f,requestTransactionId:e.requestTransactionId,result:m}}function g(e,t,n,r){return new p(`CONFIRMATION_MALFORMED`,{},{uniqueKey:e.uniqueKey,status:t.status,body:n,url:r})}function _(e){let t=y(e);if(t===void 0||typeof t.token0!=`string`||typeof t.token1!=`string`||typeof t.fee!=`number`)return;let n=[`sell0Qty`,`sell1Qty`,`buy0Qty`,`buy1Qty`,`tradingFees`,`protocolFees`,`totalFees`];for(let e of n)if(e in t&&typeof t[e]!=`string`)return;return{token0:t.token0,token1:t.token1,fee:t.fee,...Object.fromEntries(n.flatMap(e=>typeof t[e]==`string`?[[e,t[e]]]:[]))}}function v(e){return e===500||e===502||e===503||e===504}function y(e){return typeof e==`object`&&e?e:void 0}export{p as AppliedTradeError,m as confirmAppliedTrade};
2
2
  //# sourceMappingURL=apply_results.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"apply_results.js","names":[],"sources":["../../../src/classes/apply_results.ts"],"sourcesContent":["import type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { HttpRequestor, HTTPResponse } from '../types/http_requestor.js';\nimport type { AppliedTrade, TradeExecution } from '../types/v2_results.js';\nimport { createConfirmationSchedule, throwIfAborted } from '../utils/confirmation_schedule.js';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport { isValidUniqueKey } from '../utils/unique_key_syntax.js';\nimport type { WireOptions } from '../types/wire.js';\nimport {\n buildRequestHeaders,\n fetchRequestor,\n readBlockNumberHeader,\n readHeader,\n readResponseBody,\n readRetryAfter,\n requestWithTimeout,\n} from '../utils/transport.js';\nimport type { GSwapErrorCode, GSwapErrorParams } from './error_catalog.js';\nimport { getStringProperty, GSwapSDKError, type GSwapErrorContext } from './gswap_sdk_error.js';\n\n/**\n * The AutoApplier waits at least 2 s before applying and the apply lands ~6-8 s after the\n * acknowledgement, so a read at t=0 is a guaranteed 404.\n */\nconst DEFAULT_INITIAL_DELAY_MS = 3_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n\n/**\n * The outcome of a queued RequestTrade that could not be delivered as an {@link AppliedTrade}.\n * `code` says why:\n *\n * - `CONFIRMATION_TIMEOUT`: no terminal result before the deadline. The trade may still apply;\n * confirm the same `uniqueKey` again later and never resubmit.\n * - `CONFIRMATION_ABORTED`: the caller's `signal` aborted. Nothing is known about the outcome.\n * - `CONFIRMATION_FAILED`: the apply-results read got a terminal HTTP status (`params.status`;\n * `params.serverMessage` is the failing body's own message, `''` when it had none: server\n * text is data, relay it or ignore it). The outcome is unknown.\n * - `CONFIRMATION_MALFORMED` / `CONFIRMATION_KEY_MISMATCH`: the apply result is not a usable\n * answer for this key. The outcome is unknown.\n * - `INVALID_UNIQUE_KEY`: the key is not a valid apply-results key; nothing was read. TERMINAL:\n * no retry can ever succeed (the SDK never signs such a key, so a stored one is corrupt), so a\n * resume loop must forget the swap. `PendingSwapStore.list` already prunes such entries.\n * - `CHAIN_REJECTED`: the chain REJECTED the trade; `params.errorKey` is the chain `ErrorKey` (or\n * `CHAIN_ERROR`) and `params.serverMessage` its English message.\n *\n * `uniqueKey` is always set and, where known, `requestTransactionId`, `applyTransactionId`,\n * `blockNumber`, `status`, `body`, `url` and the last transport `cause`.\n */\nexport class AppliedTradeError<C extends GSwapErrorCode = GSwapErrorCode> extends GSwapSDKError<C> {\n constructor(code: C, params: GSwapErrorParams<C>, context: GSwapErrorContext = {}) {\n super(code, params, context);\n this.name = 'AppliedTradeError';\n }\n}\n\n/** The transport and backend a confirmation reads from. */\nexport interface ApplyResultsClient {\n /** Swap backend origin, e.g. `https://dex-backend-prod1.defi.gala.com` (no trailing path). */\n dexBackendBaseUrl: string;\n /** Defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Per-read timeout in milliseconds (default 30 000). */\n requestTimeoutMs?: number | undefined;\n /** Request headers of the poll (`userAgent`, `headers`); see {@link WireOptions}. */\n wire?: WireOptions | undefined;\n}\n\n/** What identifies the queued trade to confirm. */\nexport interface AppliedTradeInput {\n uniqueKey: string;\n /** The transaction id of the queued request, carried through to the result; `null` if unknown. */\n requestTransactionId: string | null;\n}\n\n/**\n * Polls `GET /v1/chain/apply-results/{uniqueKey}?channel=asset&contract=dex-contract` until the\n * queued RequestTrade reaches a terminal state.\n *\n * Pacing: wait `initialDelayMs` (default 3 s), then read; on 404, 429, 500, 502, 503, 504 or a\n * transport error wait with jittered exponential backoff (`pollIntervalMs` doubling to 8 s,\n * `Retry-After` honored as seconds or an HTTP date) until `timeoutMs`. Any other status is\n * terminal. At least one read is always made.\n *\n * @returns The applied trade.\n * @throws AppliedTradeError - see its documentation for every `code`.\n * @example\n * ```ts\n * const applied = await confirmAppliedTrade(\n * { dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com' },\n * { uniqueKey, requestTransactionId: null },\n * { initialDelayMs: 0, timeoutMs: 60_000, signal: controller.signal },\n * );\n * ```\n */\nexport async function confirmAppliedTrade(\n client: ApplyResultsClient,\n input: AppliedTradeInput,\n options?: ConfirmOptions,\n): Promise<AppliedTrade> {\n const { uniqueKey } = input;\n if (!isValidUniqueKey(uniqueKey)) {\n throw new AppliedTradeError(\n 'INVALID_UNIQUE_KEY',\n { uniqueKey: String(uniqueKey) },\n { uniqueKey },\n );\n }\n const requestor = client.httpRequestor ?? fetchRequestor;\n const requestTimeoutMs = client.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const signal = options?.signal;\n const abortError = (cause?: unknown): Error =>\n new AppliedTradeError('CONFIRMATION_ABORTED', {}, { uniqueKey, cause });\n const url = `${client.dexBackendBaseUrl.replace(/\\/$/u, '')}/v1/chain/apply-results/${encodeURIComponent(uniqueKey)}?channel=asset&contract=dex-contract`;\n\n const schedule = createConfirmationSchedule(options, DEFAULT_INITIAL_DELAY_MS, abortError);\n await schedule.waitForRead();\n let lastError: unknown;\n\n while (true) {\n throwIfAborted(signal, abortError);\n let response: HTTPResponse;\n let body: unknown;\n try {\n response = await requestWithTimeout(\n requestor,\n url,\n {\n method: 'GET',\n headers: buildRequestHeaders(client.wire),\n ...(signal === undefined ? {} : { signal }),\n },\n requestTimeoutMs,\n );\n body = await readResponseBody(response);\n } catch (error: unknown) {\n throwIfAborted(signal, abortError);\n lastError = error;\n if (!(await schedule.waitForRead())) break;\n continue;\n }\n throwIfAborted(signal, abortError);\n\n if (response.status === 200) return readAppliedResult(input, response, body, url);\n\n if (response.status === 404 || response.status === 429 || isTransient(response.status)) {\n const retryAfter = response.status === 429 ? readRetryAfter(response) : undefined;\n if (!(await schedule.waitForRead(retryAfter))) break;\n continue;\n }\n\n throw new AppliedTradeError(\n 'CONFIRMATION_FAILED',\n { status: response.status, serverMessage: serverMessageOfBody(body) },\n { uniqueKey, status: response.status, body, url },\n );\n }\n\n throw new AppliedTradeError(\n 'CONFIRMATION_TIMEOUT',\n {},\n { uniqueKey, requestTransactionId: input.requestTransactionId, url, cause: lastError },\n );\n}\n\nfunction readAppliedResult(\n input: AppliedTradeInput,\n response: HTTPResponse,\n body: unknown,\n url: string,\n): AppliedTrade {\n const { uniqueKey } = input;\n const record = asRecord(body);\n const responseKey = record?.['uniqueKey'] ?? record?.['UniqueKey'];\n if (typeof responseKey === 'string' && responseKey !== uniqueKey) {\n throw new AppliedTradeError(\n 'CONFIRMATION_KEY_MISMATCH',\n {},\n { uniqueKey, status: response.status, body, url },\n );\n }\n const status = record?.['Status'];\n const applyTransactionId = readHeader(response, 'x-apply-transaction-id') ?? null;\n const blockNumber = readBlockNumberHeader(response, 'x-apply-block-number') ?? null;\n if (status === 0) {\n const errorKey = getStringProperty(record, 'ErrorKey') ?? 'CHAIN_ERROR';\n const chainMessage = getStringProperty(record, 'Message') ?? '';\n throw new AppliedTradeError(\n 'CHAIN_REJECTED',\n { errorKey, serverMessage: chainMessage },\n {\n uniqueKey,\n requestTransactionId: input.requestTransactionId,\n applyTransactionId,\n blockNumber,\n status: response.status,\n body,\n url,\n },\n );\n }\n if (status !== 1) throw malformed(input, response, body, url);\n const result = parseTradeExecution(record?.['Data']);\n if (result === undefined) throw malformed(input, response, body, url);\n return {\n uniqueKey,\n transactionId: applyTransactionId,\n blockNumber,\n requestTransactionId: input.requestTransactionId,\n result,\n };\n}\n\nfunction malformed(\n input: AppliedTradeInput,\n response: HTTPResponse,\n body: unknown,\n url: string,\n): AppliedTradeError<'CONFIRMATION_MALFORMED'> {\n return new AppliedTradeError(\n 'CONFIRMATION_MALFORMED',\n {},\n { uniqueKey: input.uniqueKey, status: response.status, body, url },\n );\n}\n\nfunction parseTradeExecution(value: unknown): TradeExecution | undefined {\n const record = asRecord(value);\n if (\n record === undefined ||\n typeof record['token0'] !== 'string' ||\n typeof record['token1'] !== 'string' ||\n typeof record['fee'] !== 'number'\n ) {\n return undefined;\n }\n const optionalFields = [\n 'sell0Qty',\n 'sell1Qty',\n 'buy0Qty',\n 'buy1Qty',\n 'tradingFees',\n 'protocolFees',\n 'totalFees',\n ] as const;\n for (const field of optionalFields) {\n if (field in record && typeof record[field] !== 'string') return undefined;\n }\n return {\n token0: record['token0'],\n token1: record['token1'],\n fee: record['fee'],\n ...Object.fromEntries(\n optionalFields.flatMap((field) =>\n typeof record[field] === 'string' ? [[field, record[field]]] : [],\n ),\n ),\n };\n}\n\nfunction isTransient(status: number): boolean {\n return status === 500 || status === 502 || status === 503 || status === 504;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"apply_results.js","names":["AppliedTradeError","GSwapSDKError","code","params","context","confirmAppliedTrade","input","isValidUniqueKey","uniqueKey","requestor","client","fetchRequestor","requestTimeoutMs","signal","options","abortError","url","schedule","createConfirmationSchedule","lastError","throwIfAborted","response","body","requestWithTimeout","buildRequestHeaders","readResponseBody","error","readAppliedResult","isTransient","retryAfter","readRetryAfter","serverMessageOfBody","record","asRecord","responseKey","\"uniqueKey\"","\"UniqueKey\"","status","\"Status\"","applyTransactionId","readHeader","blockNumber","readBlockNumberHeader","getStringProperty","malformed","result","parseTradeExecution","\"Data\"","value","\"token0\"","\"token1\"","\"fee\"","optionalFields","field"],"sources":["../../../src/classes/apply_results.ts"],"sourcesContent":["import {\n buildRequestHeaders,\n fetchRequestor,\n isValidUniqueKey,\n readBlockNumberHeader,\n readHeader,\n readResponseBody,\n readRetryAfter,\n requestWithTimeout,\n type GalaErrorContext,\n type HttpRequestor,\n type HTTPResponse,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { AppliedTrade, TradeExecution } from '../types/v2_results.js';\nimport { createConfirmationSchedule, throwIfAborted } from '../utils/confirmation_schedule.js';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport type { GSwapErrorCode, GSwapErrorParams } from './gswap_error_catalog.js';\nimport { getStringProperty, GSwapSDKError } from './gswap_sdk_error.js';\n\n/**\n * The AutoApplier waits at least 2 s before applying and the apply lands ~6-8 s after the\n * acknowledgement, so a read at t=0 is a guaranteed 404.\n */\nconst DEFAULT_INITIAL_DELAY_MS = 3_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n\n/**\n * The outcome of a queued RequestTrade that could not be delivered as an {@link AppliedTrade}.\n * `code` says why:\n *\n * - `CONFIRMATION_TIMEOUT`: no terminal result before the deadline. The trade may still apply;\n * confirm the same `uniqueKey` again later and never resubmit.\n * - `CONFIRMATION_ABORTED`: the caller's `signal` aborted. Nothing is known about the outcome.\n * - `CONFIRMATION_FAILED`: the apply-results read got a terminal HTTP status (`params.status`;\n * `params.serverMessage` is the failing body's own message, `''` when it had none: server\n * text is data, relay it or ignore it). The outcome is unknown.\n * - `CONFIRMATION_MALFORMED` / `CONFIRMATION_KEY_MISMATCH`: the apply result is not a usable\n * answer for this key. The outcome is unknown.\n * - `INVALID_UNIQUE_KEY`: the key is not a valid apply-results key; nothing was read. TERMINAL:\n * no retry can ever succeed (the SDK never signs such a key, so a stored one is corrupt), so a\n * resume loop must forget the swap. `PendingSwapStore.list` already prunes such entries.\n * - `CHAIN_REJECTED`: the chain REJECTED the trade; `params.errorKey` is the chain `ErrorKey` (or\n * `CHAIN_ERROR`) and `params.serverMessage` its English message.\n *\n * `uniqueKey` is always set and, where known, `requestTransactionId`, `applyTransactionId`,\n * `blockNumber`, `status`, `body`, `url` and the last transport `cause`.\n */\nexport class AppliedTradeError<C extends GSwapErrorCode = GSwapErrorCode> extends GSwapSDKError<C> {\n constructor(code: C, params: GSwapErrorParams<C>, context: GalaErrorContext = {}) {\n super(code, params, context);\n this.name = 'AppliedTradeError';\n }\n}\n\n/** The transport and backend a confirmation reads from. */\nexport interface ApplyResultsClient {\n /** Swap backend origin, e.g. `https://dex-backend-prod1.defi.gala.com` (no trailing path). */\n dexBackendBaseUrl: string;\n /** Defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Per-read timeout in milliseconds (default 30 000). */\n requestTimeoutMs?: number | undefined;\n /** Request headers of the poll (`userAgent`, `headers`); see {@link WireOptions}. */\n wire?: WireOptions | undefined;\n}\n\n/** What identifies the queued trade to confirm. */\nexport interface AppliedTradeInput {\n uniqueKey: string;\n /** The transaction id of the queued request, carried through to the result; `null` if unknown. */\n requestTransactionId: string | null;\n}\n\n/**\n * Polls `GET /v1/chain/apply-results/{uniqueKey}?channel=asset&contract=dex-contract` until the\n * queued RequestTrade reaches a terminal state.\n *\n * Pacing: wait `initialDelayMs` (default 3 s), then read; on 404, 429, 500, 502, 503, 504 or a\n * transport error wait with jittered exponential backoff (`pollIntervalMs` doubling to 8 s,\n * `Retry-After` honored as seconds or an HTTP date) until `timeoutMs`. Any other status is\n * terminal. At least one read is always made.\n *\n * @returns The applied trade.\n * @throws AppliedTradeError - see its documentation for every `code`.\n * @example\n * ```ts\n * const applied = await confirmAppliedTrade(\n * { dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com' },\n * { uniqueKey, requestTransactionId: null },\n * { initialDelayMs: 0, timeoutMs: 60_000, signal: controller.signal },\n * );\n * ```\n */\nexport async function confirmAppliedTrade(\n client: ApplyResultsClient,\n input: AppliedTradeInput,\n options?: ConfirmOptions,\n): Promise<AppliedTrade> {\n const { uniqueKey } = input;\n if (!isValidUniqueKey(uniqueKey)) {\n throw new AppliedTradeError(\n 'INVALID_UNIQUE_KEY',\n { uniqueKey: String(uniqueKey) },\n { uniqueKey },\n );\n }\n const requestor = client.httpRequestor ?? fetchRequestor;\n const requestTimeoutMs = client.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const signal = options?.signal;\n const abortError = (cause?: unknown): Error =>\n new AppliedTradeError('CONFIRMATION_ABORTED', {}, { uniqueKey, cause });\n const url = `${client.dexBackendBaseUrl.replace(/\\/$/u, '')}/v1/chain/apply-results/${encodeURIComponent(uniqueKey)}?channel=asset&contract=dex-contract`;\n\n const schedule = createConfirmationSchedule(options, DEFAULT_INITIAL_DELAY_MS, abortError);\n await schedule.waitForRead();\n let lastError: unknown;\n\n while (true) {\n throwIfAborted(signal, abortError);\n let response: HTTPResponse;\n let body: unknown;\n try {\n response = await requestWithTimeout(\n requestor,\n url,\n {\n method: 'GET',\n headers: buildRequestHeaders(client.wire),\n ...(signal === undefined ? {} : { signal }),\n },\n requestTimeoutMs,\n );\n body = await readResponseBody(response);\n } catch (error: unknown) {\n throwIfAborted(signal, abortError);\n lastError = error;\n if (!(await schedule.waitForRead())) break;\n continue;\n }\n throwIfAborted(signal, abortError);\n\n if (response.status === 200) return readAppliedResult(input, response, body, url);\n\n if (response.status === 404 || response.status === 429 || isTransient(response.status)) {\n const retryAfter = response.status === 429 ? readRetryAfter(response) : undefined;\n if (!(await schedule.waitForRead(retryAfter))) break;\n continue;\n }\n\n throw new AppliedTradeError(\n 'CONFIRMATION_FAILED',\n { status: response.status, serverMessage: serverMessageOfBody(body) },\n { uniqueKey, status: response.status, body, url },\n );\n }\n\n throw new AppliedTradeError(\n 'CONFIRMATION_TIMEOUT',\n {},\n { uniqueKey, requestTransactionId: input.requestTransactionId, url, cause: lastError },\n );\n}\n\nfunction readAppliedResult(\n input: AppliedTradeInput,\n response: HTTPResponse,\n body: unknown,\n url: string,\n): AppliedTrade {\n const { uniqueKey } = input;\n const record = asRecord(body);\n const responseKey = record?.['uniqueKey'] ?? record?.['UniqueKey'];\n if (typeof responseKey === 'string' && responseKey !== uniqueKey) {\n throw new AppliedTradeError(\n 'CONFIRMATION_KEY_MISMATCH',\n {},\n { uniqueKey, status: response.status, body, url },\n );\n }\n const status = record?.['Status'];\n const applyTransactionId = readHeader(response, 'x-apply-transaction-id') ?? null;\n const blockNumber = readBlockNumberHeader(response, 'x-apply-block-number') ?? null;\n if (status === 0) {\n const errorKey = getStringProperty(record, 'ErrorKey') ?? 'CHAIN_ERROR';\n const chainMessage = getStringProperty(record, 'Message') ?? '';\n throw new AppliedTradeError(\n 'CHAIN_REJECTED',\n { errorKey, serverMessage: chainMessage },\n {\n uniqueKey,\n requestTransactionId: input.requestTransactionId,\n applyTransactionId,\n blockNumber,\n status: response.status,\n body,\n url,\n },\n );\n }\n if (status !== 1) throw malformed(input, response, body, url);\n const result = parseTradeExecution(record?.['Data']);\n if (result === undefined) throw malformed(input, response, body, url);\n return {\n uniqueKey,\n transactionId: applyTransactionId,\n blockNumber,\n requestTransactionId: input.requestTransactionId,\n result,\n };\n}\n\nfunction malformed(\n input: AppliedTradeInput,\n response: HTTPResponse,\n body: unknown,\n url: string,\n): AppliedTradeError<'CONFIRMATION_MALFORMED'> {\n return new AppliedTradeError(\n 'CONFIRMATION_MALFORMED',\n {},\n { uniqueKey: input.uniqueKey, status: response.status, body, url },\n );\n}\n\nfunction parseTradeExecution(value: unknown): TradeExecution | undefined {\n const record = asRecord(value);\n if (\n record === undefined ||\n typeof record['token0'] !== 'string' ||\n typeof record['token1'] !== 'string' ||\n typeof record['fee'] !== 'number'\n ) {\n return undefined;\n }\n const optionalFields = [\n 'sell0Qty',\n 'sell1Qty',\n 'buy0Qty',\n 'buy1Qty',\n 'tradingFees',\n 'protocolFees',\n 'totalFees',\n ] as const;\n for (const field of optionalFields) {\n if (field in record && typeof record[field] !== 'string') return undefined;\n }\n return {\n token0: record['token0'],\n token1: record['token1'],\n fee: record['fee'],\n ...Object.fromEntries(\n optionalFields.flatMap((field) =>\n typeof record[field] === 'string' ? [[field, record[field]]] : [],\n ),\n ),\n };\n}\n\nfunction isTransient(status: number): boolean {\n return status === 500 || status === 502 || status === 503 || status === 504;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{GSwapSDKError as e,getObjectProperty as t}from"./gswap_sdk_error.js";import{validateWalletAddress as n}from"../utils/validation.js";var r=class{constructor(e,t){this.dexBackendBaseUrl=e,this.httpClient=t}async getUserAssets(t,r=1,a=10){if(n(t),!Number.isInteger(r)||r<1)throw new e(`INVALID_PAGE`,{value:r});if(!Number.isInteger(a)||a<1||a>100)throw new e(`INVALID_LIMIT`,{value:a,min:1,max:100});return i(await this.httpClient.sendGetRequest(this.dexBackendBaseUrl,`/user/assets`,``,{address:t,page:r.toString(),limit:a.toString()}))}};function i(n){let r=t(n,`data`),i=r?.token;if(!Array.isArray(i)||!i.every(a))throw new e(`INVALID_CHAIN_RESPONSE`,{resource:`user assets response`},{body:n});let o=r?.count;return{tokens:i.map(e=>({...e,decimals:parseInt(e.decimals,10)})),count:typeof o==`number`?o:0}}function a(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.image==`string`&&typeof t.name==`string`&&typeof t.decimals==`string`&&/^\d+$/u.test(t.decimals)&&typeof t.verify==`boolean`&&typeof t.symbol==`string`&&typeof t.quantity==`string`}export{r as Assets};
1
+ import{GSwapSDKError as e,getObjectProperty as t}from"./gswap_sdk_error.js";import{validateWalletAddress as n}from"../utils/validation.js";var r=class{constructor(e,t){this.dexBackendBaseUrl=e,this.httpClient=t}async getUserAssets(t,r=1,a=10){if(n(t),!Number.isInteger(r)||r<1)throw new e(`INVALID_PAGE`,{value:r});if(!Number.isInteger(a)||a<1||a>100)throw new e(`INVALID_LIMIT`,{value:a,min:1,max:100});return i(await this.httpClient.sendGetRequest(this.dexBackendBaseUrl,`/user/assets`,``,{address:t,page:r.toString(),limit:a.toString()}))}};function i(n){let r=t(n,`data`),i=r?.token;if(!Array.isArray(i)||!i.every(a))throw new e(`INVALID_CHAIN_RESPONSE`,{resource:`user assets response`},{body:n,write:!1});let o=r?.count;return{tokens:i.map(e=>({...e,decimals:parseInt(e.decimals,10)})),count:typeof o==`number`?o:0}}function a(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.image==`string`&&typeof t.name==`string`&&typeof t.decimals==`string`&&/^\d+$/u.test(t.decimals)&&typeof t.verify==`boolean`&&typeof t.symbol==`string`&&typeof t.quantity==`string`}export{r as Assets};
2
2
  //# sourceMappingURL=assets.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"assets.js","names":[],"sources":["../../../src/classes/assets.ts"],"sourcesContent":["import type { UserAsset, UserAssetsResult } from '../types/v2_results.js';\nimport { validateWalletAddress } from '../utils/validation.js';\nimport { getObjectProperty, GSwapSDKError } from './gswap_sdk_error.js';\nimport type { HttpClient } from './http_client.js';\n\n/**\n * Service for handling user asset operations.\n * Provides functionality to retrieve user token balances and asset information.\n */\nexport class Assets {\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n ) {}\n\n /**\n * Gets all token assets owned by a user with their balances.\n * @param ownerAddress - The wallet address to get assets for.\n * @param page - Page number for pagination (default: 1).\n * @param limit - Maximum number of assets to return per page (default: 10).\n * @returns User assets including token information and balances.\n * @example\n * ```typescript\n * const assets = await assetsService.getUserAssets('eth|123...abc', 1, 20);\n * console.log(`User has ${assets.count} different tokens`);\n * assets.tokens.forEach(token => {\n * console.log(`${token.symbol}: ${token.quantity}`);\n * });\n * ```\n */\n async getUserAssets(\n ownerAddress: string,\n page: number = 1,\n limit: number = 10,\n ): Promise<UserAssetsResult> {\n validateWalletAddress(ownerAddress);\n\n if (!Number.isInteger(page) || page < 1) {\n throw new GSwapSDKError('INVALID_PAGE', { value: page });\n }\n\n if (!Number.isInteger(limit) || limit < 1 || limit > 100) {\n throw new GSwapSDKError('INVALID_LIMIT', { value: limit, min: 1, max: 100 });\n }\n\n const json: unknown = await this.httpClient.sendGetRequest(\n this.dexBackendBaseUrl,\n '/user/assets',\n '',\n { address: ownerAddress, page: page.toString(), limit: limit.toString() },\n );\n return parseUserAssets(json);\n }\n}\n\nfunction parseUserAssets(value: unknown): UserAssetsResult {\n const data = getObjectProperty(value, 'data');\n // Not getObjectProperty — that's typed for object properties, and Array.isArray on its\n // Record<string, unknown> return type narrows to any[] instead of a real array type.\n const tokens: unknown = data?.['token'];\n if (!Array.isArray(tokens) || !tokens.every(isRawUserAsset)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'user assets response' },\n { body: value },\n );\n }\n const count = data?.['count'];\n return {\n tokens: tokens.map((token) => ({ ...token, decimals: parseInt(token.decimals, 10) })),\n count: typeof count === 'number' ? count : 0,\n };\n}\n\ntype RawUserAsset = Omit<UserAsset, 'decimals'> & { decimals: string };\n\nfunction isRawUserAsset(value: unknown): value is RawUserAsset {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Record<string, unknown>;\n return (\n typeof entry['image'] === 'string' &&\n typeof entry['name'] === 'string' &&\n typeof entry['decimals'] === 'string' &&\n /^\\d+$/u.test(entry['decimals']) &&\n typeof entry['verify'] === 'boolean' &&\n typeof entry['symbol'] === 'string' &&\n typeof entry['quantity'] === 'string'\n );\n}\n"],"mappings":"2IASA,IAAa,EAAb,KAAoB,CAClB,YACE,EACA,EACA,CAFiB,KAAA,kBAAA,EACA,KAAA,WAAA,CAChB,CAiBH,MAAM,cACJ,EACA,EAAe,EACf,EAAgB,GACW,CAG3B,GAFA,EAAsB,CAAY,EAE9B,CAAC,OAAO,UAAU,CAAI,GAAK,EAAO,EACpC,MAAM,IAAI,EAAc,eAAgB,CAAE,MAAO,CAAK,CAAC,EAGzD,GAAI,CAAC,OAAO,UAAU,CAAK,GAAK,EAAQ,GAAK,EAAQ,IACnD,MAAM,IAAI,EAAc,gBAAiB,CAAE,MAAO,EAAO,IAAK,EAAG,IAAK,GAAI,CAAC,EAS7E,OAAO,EAAgB,MANK,KAAK,WAAW,eAC1C,KAAK,kBACL,eACA,GACA,CAAE,QAAS,EAAc,KAAM,EAAK,SAAS,EAAG,MAAO,EAAM,SAAS,CAAE,CAC1E,CAC2B,CAC7B,CACF,EAEA,SAAS,EAAgB,EAAkC,CACzD,IAAM,EAAO,EAAkB,EAAO,MAAM,EAGtC,EAAkB,GAAO,MAC/B,GAAI,CAAC,MAAM,QAAQ,CAAM,GAAK,CAAC,EAAO,MAAM,CAAc,EACxD,MAAM,IAAI,EACR,yBACA,CAAE,SAAU,sBAAuB,EACnC,CAAE,KAAM,CAAM,CAChB,EAEF,IAAM,EAAQ,GAAO,MACrB,MAAO,CACL,OAAQ,EAAO,IAAK,IAAW,CAAE,GAAG,EAAO,SAAU,SAAS,EAAM,SAAU,EAAE,CAAE,EAAE,EACpF,MAAO,OAAO,GAAU,SAAW,EAAQ,CAC7C,CACF,CAIA,SAAS,EAAe,EAAuC,CAC7D,GAAI,OAAO,GAAU,WAAY,EAAgB,MAAO,GACxD,IAAM,EAAQ,EACd,OACE,OAAO,EAAM,OAAa,UAC1B,OAAO,EAAM,MAAY,UACzB,OAAO,EAAM,UAAgB,UAC7B,SAAS,KAAK,EAAM,QAAW,GAC/B,OAAO,EAAM,QAAc,WAC3B,OAAO,EAAM,QAAc,UAC3B,OAAO,EAAM,UAAgB,QAEjC"}
1
+ {"version":3,"file":"assets.js","names":["Assets","dexBackendBaseUrl","httpClient","validateWalletAddress","ownerAddress","page","GSwapSDKError","limit","parseUserAssets","data","getObjectProperty","value","tokens","\"token\"","isRawUserAsset","count","\"count\"","token","entry","\"image\"","\"name\"","\"decimals\"","\"verify\"","\"symbol\"","\"quantity\""],"sources":["../../../src/classes/assets.ts"],"sourcesContent":["import type { UserAsset, UserAssetsResult } from '../types/v2_results.js';\nimport { validateWalletAddress } from '../utils/validation.js';\nimport { getObjectProperty, GSwapSDKError } from './gswap_sdk_error.js';\nimport type { HttpClient } from './http_client.js';\n\n/**\n * Service for handling user asset operations.\n * Provides functionality to retrieve user token balances and asset information.\n */\nexport class Assets {\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n ) {}\n\n /**\n * Gets all token assets owned by a user with their balances.\n * @param ownerAddress - The wallet address to get assets for.\n * @param page - Page number for pagination (default: 1).\n * @param limit - Maximum number of assets to return per page (default: 10).\n * @returns User assets including token information and balances.\n * @example\n * ```typescript\n * const assets = await assetsService.getUserAssets('eth|123...abc', 1, 20);\n * console.log(`User has ${assets.count} different tokens`);\n * assets.tokens.forEach(token => {\n * console.log(`${token.symbol}: ${token.quantity}`);\n * });\n * ```\n */\n async getUserAssets(\n ownerAddress: string,\n page: number = 1,\n limit: number = 10,\n ): Promise<UserAssetsResult> {\n validateWalletAddress(ownerAddress);\n\n if (!Number.isInteger(page) || page < 1) {\n throw new GSwapSDKError('INVALID_PAGE', { value: page });\n }\n\n if (!Number.isInteger(limit) || limit < 1 || limit > 100) {\n throw new GSwapSDKError('INVALID_LIMIT', { value: limit, min: 1, max: 100 });\n }\n\n const json: unknown = await this.httpClient.sendGetRequest(\n this.dexBackendBaseUrl,\n '/user/assets',\n '',\n { address: ownerAddress, page: page.toString(), limit: limit.toString() },\n );\n return parseUserAssets(json);\n }\n}\n\nfunction parseUserAssets(value: unknown): UserAssetsResult {\n const data = getObjectProperty(value, 'data');\n // Not getObjectProperty — that's typed for object properties, and Array.isArray on its\n // Record<string, unknown> return type narrows to any[] instead of a real array type.\n const tokens: unknown = data?.['token'];\n if (!Array.isArray(tokens) || !tokens.every(isRawUserAsset)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'user assets response' },\n { body: value, write: false },\n );\n }\n const count = data?.['count'];\n return {\n tokens: tokens.map((token) => ({ ...token, decimals: parseInt(token.decimals, 10) })),\n count: typeof count === 'number' ? count : 0,\n };\n}\n\ntype RawUserAsset = Omit<UserAsset, 'decimals'> & { decimals: string };\n\nfunction isRawUserAsset(value: unknown): value is RawUserAsset {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Record<string, unknown>;\n return (\n typeof entry['image'] === 'string' &&\n typeof entry['name'] === 'string' &&\n typeof entry['decimals'] === 'string' &&\n /^\\d+$/u.test(entry['decimals']) &&\n typeof entry['verify'] === 'boolean' &&\n typeof entry['symbol'] === 'string' &&\n typeof entry['quantity'] === 'string'\n );\n}\n"],"mappings":"2IASA,IAAaA,EAAb,KAAoB,CAClB,YACE,EACA,EACA,CAFiB,KAAA,kBAAAC,EACA,KAAA,WAAAC,CAChB,CAiBH,MAAM,cACJ,EACA,EAAe,EACf,EAAgB,GACW,CAG3B,GAFAC,EAAsBC,CAAY,EAE9B,CAAC,OAAO,UAAUC,CAAI,GAAKA,EAAO,EACpC,MAAM,IAAIC,EAAc,eAAgB,CAAE,MAAOD,CAAK,CAAC,EAGzD,GAAI,CAAC,OAAO,UAAUE,CAAK,GAAKA,EAAQ,GAAKA,EAAQ,IACnD,MAAM,IAAID,EAAc,gBAAiB,CAAE,MAAOC,EAAO,IAAK,EAAG,IAAK,GAAI,CAAC,EAS7E,OAAOC,EAAgB,MANK,KAAK,WAAW,eAC1C,KAAK,kBACL,eACA,GACA,CAAE,QAASJ,EAAc,KAAMC,EAAK,SAAS,EAAG,MAAOE,EAAM,SAAS,CAAE,CAC1E,CAC2B,CAC7B,CACF,EAEA,SAASC,EAAgB,EAAkC,CACzD,IAAMC,EAAOC,EAAkBC,EAAO,MAAM,EAGtCC,EAAkBH,GAAOI,MAC/B,GAAI,CAAC,MAAM,QAAQD,CAAM,GAAK,CAACA,EAAO,MAAME,CAAc,EACxD,MAAM,IAAIR,EACR,yBACA,CAAE,SAAU,sBAAuB,EACnC,CAAE,KAAMK,EAAO,MAAO,EAAM,CAC9B,EAEF,IAAMI,EAAQN,GAAOO,MACrB,MAAO,CACL,OAAQJ,EAAO,IAAK,IAAW,CAAE,GAAGK,EAAO,SAAU,SAASA,EAAM,SAAU,EAAE,CAAE,EAAE,EACpF,MAAO,OAAOF,GAAU,SAAWA,EAAQ,CAC7C,CACF,CAIA,SAASD,EAAe,EAAuC,CAC7D,GAAI,OAAOH,GAAU,WAAYA,EAAgB,MAAO,GACxD,IAAMO,EAAQP,EACd,OACE,OAAOO,EAAMC,OAAa,UAC1B,OAAOD,EAAME,MAAY,UACzB,OAAOF,EAAMG,UAAgB,UAC7B,SAAS,KAAKH,EAAMG,QAAW,GAC/B,OAAOH,EAAMI,QAAc,WAC3B,OAAOJ,EAAMK,QAAc,UAC3B,OAAOL,EAAMM,UAAgB,QAEjC"}
@@ -1,2 +1,2 @@
1
- import e from"../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{buildRequestHeaders as n,fetchRequestor as r,readResponseBody as i,requestWithTimeout as a}from"../utils/transport.js";import{signPreSend as o}from"../utils/pre_send.js";const s=[`Swap`,`RequestTrade`,`AddLiquidity`,`RemoveLiquidity`,`CollectPositionFees`,`CreatePool`],c=`DryRun`,l=`galaconnect-operation-`;function u(e){return typeof e==`string`&&s.includes(e)}function d(e,t){return u(t)&&typeof e?.token0==`string`&&typeof e.token1==`string`}function f(e){let t={...e};for(let e of[`signature`,`prefix`,`types`,`domain`,`trace`])delete t[e];return t}function p(e,t,n,r,i=l){return o(e,c,{callerPublicKey:t,method:n,dto:r,uniqueKey:`${i}${globalThis.crypto.randomUUID()}`})}var m=class{constructor(t,n){this.signer=n,e(this,`requestor`,void 0),e(this,`baseUrl`,void 0),e(this,`requestTimeoutMs`,void 0),e(this,`wire`,void 0),this.requestor=t.httpRequestor??r,this.baseUrl=t.dexBackendBaseUrl.replace(/\/$/u,``),this.requestTimeoutMs=t.requestTimeoutMs??3e4,this.wire=t.wire}async quote(e,r,o,s={}){if(this.signer===void 0)throw t.noSignerError();let c=s.channel??`asset`,l=s.contract??`dexv3-contract`,u=await p(this.signer,e,r,f(o)),d=`${this.baseUrl}/wallet/connect/galachain/api/${encodeURIComponent(c)}/${encodeURIComponent(l)}/${encodeURIComponent(r)}/fee`,m,g,_;try{let e=await a(this.requestor,d,{method:`POST`,headers:n(this.wire,{json:!0,defaults:{Accept:`application/json`}}),body:JSON.stringify(u)},this.requestTimeoutMs);m=e.status,g=e.ok,_=g?await i(e):void 0}catch{return null}return g?h(_):l===`dex-contract`&&(m===403||m===404)?{source:`default`,fees:[{feeInGala:`0`}]}:null}};function h(e){if(typeof e!=`object`||!e)return null;let t=e.fees;return!Array.isArray(t)||typeof t[0]?.feeInGala!=`string`?null:e}export{s as DEX_FEE_METHODS,c as DRY_RUN_METHOD,l as DRY_RUN_UNIQUE_KEY_PREFIX,m as DexFees,p as buildDryRunWrapper,d as isCurrentContractDexMessage,u as isDexFeeMethod,f as toChainDto};
1
+ import e from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{buildRequestHeaders as n,createUniqueKey as r,fetchRequestor as i,readResponseBody as a,requestWithTimeout as o,signPreSend as s}from"@gala-chain/gala-core-sdk";const c=[`Swap`,`RequestTrade`,`AddLiquidity`,`RemoveLiquidity`,`CollectPositionFees`,`CreatePool`],l=`DryRun`,u=`galaconnect-operation-`;function d(e){return typeof e==`string`&&c.includes(e)}function f(e,t){return d(t)&&typeof e?.token0==`string`&&typeof e.token1==`string`}function p(e){let t={...e};for(let e of[`signature`,`prefix`,`types`,`domain`,`trace`])delete t[e];return t}function m(e,t,n,i,a=u){return s(e,l,{callerPublicKey:t,method:n,dto:i,uniqueKey:r(a)})}var h=class{constructor(t,n){this.signer=n,e(this,`requestor`,void 0),e(this,`baseUrl`,void 0),e(this,`requestTimeoutMs`,void 0),e(this,`wire`,void 0),this.requestor=t.httpRequestor??i,this.baseUrl=t.dexBackendBaseUrl.replace(/\/$/u,``),this.requestTimeoutMs=t.requestTimeoutMs??3e4,this.wire=t.wire}async quote(e,r,i,s={}){if(this.signer===void 0)throw t.noSignerError();let c=s.channel??`asset`,l=s.contract??`dexv3-contract`,u=await m(this.signer,e,r,p(i)),d=`${this.baseUrl}/wallet/connect/galachain/api/${encodeURIComponent(c)}/${encodeURIComponent(l)}/${encodeURIComponent(r)}/fee`,f,h,_;try{let e=await o(this.requestor,d,{method:`POST`,headers:n(this.wire,{json:!0,defaults:{Accept:`application/json`}}),body:JSON.stringify(u)},this.requestTimeoutMs);f=e.status,h=e.ok,_=h?await a(e):void 0}catch{return null}return h?g(_):l===`dex-contract`&&(f===403||f===404)?{source:`default`,fees:[{feeInGala:`0`}]}:null}};function g(e){if(typeof e!=`object`||!e)return null;let t=e.fees;return!Array.isArray(t)||typeof t[0]?.feeInGala!=`string`?null:e}export{c as DEX_FEE_METHODS,l as DRY_RUN_METHOD,u as DRY_RUN_UNIQUE_KEY_PREFIX,h as DexFees,m as buildDryRunWrapper,f as isCurrentContractDexMessage,d as isDexFeeMethod,p as toChainDto};
2
2
  //# sourceMappingURL=dex_fees.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dex_fees.js","names":[],"sources":["../../../src/classes/dex_fees.ts"],"sourcesContent":["import type { HttpRequestor } from '../types/http_requestor.js';\nimport type { WireOptions } from '../types/wire.js';\nimport {\n buildRequestHeaders,\n fetchRequestor,\n readResponseBody,\n requestWithTimeout,\n} from '../utils/transport.js';\nimport { signPreSend } from '../utils/pre_send.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport type { GalaChainSigner } from './signers.js';\n\n/** DEX methods the backend accepts a fee quote for (its allow-list enumerates the same six). */\nexport const DEX_FEE_METHODS = [\n 'Swap',\n 'RequestTrade',\n 'AddLiquidity',\n 'RemoveLiquidity',\n 'CollectPositionFees',\n 'CreatePool',\n] as const;\n/** A chain method whose network fee `DexFees.quote` can price (see `isDexFeeMethod`). */\nexport type DexFeeMethod = (typeof DEX_FEE_METHODS)[number];\n\n/** Which pool contract the DTO being quoted targets: legacy (V3) or current (GalaChainDex). */\nexport type DexFeeContract = 'dexv3-contract' | 'dex-contract';\n\n/** The chain method name the signed DryRun wrapper is signed under. */\nexport const DRY_RUN_METHOD = 'DryRun';\n\n/** `uniqueKey` prefix of the DryRun WRAPPER (distinct from the inner DTO's key). */\nexport const DRY_RUN_UNIQUE_KEY_PREFIX = 'galaconnect-operation-';\n\n/** True when `method` is a DEX method a fee can be quoted for. */\nexport function isDexFeeMethod(method: unknown): method is DexFeeMethod {\n return typeof method === 'string' && (DEX_FEE_METHODS as readonly string[]).includes(method);\n}\n\n/** Current-contract typed DEX messages use trading symbols instead of TokenClassKey objects. */\nexport function isCurrentContractDexMessage(\n message: Record<string, unknown> | null | undefined,\n method: unknown,\n): boolean {\n return (\n isDexFeeMethod(method) &&\n typeof message?.['token0'] === 'string' &&\n typeof message['token1'] === 'string'\n );\n}\n\n/**\n * The backend's response. It ALWAYS carries a usable `fees[0].feeInGala`: the backend decides what\n * to serve when the chain cannot price the operation, so the client never invents a fee.\n *\n * `source` is informational: `'dry-run'` is simulated on chain and authoritative (possibly a\n * legitimate `'0'`), `'default'` means the chain could not price it and the platform default was\n * served.\n */\nexport interface DexFeeQuote {\n fees: Array<{ feeInGala: string }>;\n source: 'dry-run' | 'default';\n}\n\n/**\n * Reduces an EIP-712 approval `message` to the DTO the chain actually receives: drops the signing\n * envelope (`signature`, `prefix`, `types`, `domain`) and transport metadata (`trace`).\n */\nexport function toChainDto(message: Record<string, unknown>): Record<string, unknown> {\n const chainDto: Record<string, unknown> = { ...message };\n for (const field of ['signature', 'prefix', 'types', 'domain', 'trace']) {\n delete chainDto[field];\n }\n return chainDto;\n}\n\n/**\n * Signs the DryRun WRAPPER the gateway accepts for every contract:\n * `{ callerPublicKey, method, dto: <inner DTO object>, uniqueKey, signature }`. The inner DTO\n * travels unsigned and as an object; no `signerPublicKey` is sent because the signature already\n * recovers it (the gateway rejects it as REDUNDANT_SIGNER_PUBLIC_KEY). The wrapper carries its own\n * `uniqueKey`, distinct from the DTO's.\n */\nexport function buildDryRunWrapper(\n signer: GalaChainSigner,\n callerPublicKey: string,\n method: string,\n dto: Record<string, unknown>,\n uniqueKeyPrefix: string = DRY_RUN_UNIQUE_KEY_PREFIX,\n): Promise<Record<string, unknown>> {\n return signPreSend(signer, DRY_RUN_METHOD, {\n callerPublicKey,\n method,\n dto,\n uniqueKey: `${uniqueKeyPrefix}${globalThis.crypto.randomUUID()}`,\n });\n}\n\n/** The transport and backend a fee quote reads from. */\nexport interface DexFeesClient {\n /** Swap backend origin, e.g. `https://dex-backend-prod1.defi.gala.com`. */\n dexBackendBaseUrl: string;\n /** Defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Per-request timeout in milliseconds (default 30 000). */\n requestTimeoutMs?: number | undefined;\n /**\n * Request headers of the fee POST (`userAgent`, `headers`); see {@link WireOptions}. The SDK's\n * `Accept: application/json` is a default that `wire.headers` may replace.\n */\n wire?: WireOptions | undefined;\n}\n\n/** Options for a single quote. */\nexport interface DexFeeQuoteOptions {\n /** GalaChain channel. Default `asset`. */\n channel?: string | undefined;\n /**\n * Contract the DTO targets. Default `dexv3-contract` (what every legacy caller quotes against);\n * a current-contract operation must pass `dex-contract` explicitly.\n */\n contract?: DexFeeContract | undefined;\n}\n\n/**\n * Network-fee quote for GalaChain DEX methods, derived from a server-side DryRun.\n *\n * The client only SIGNS the DryRun wrapper (with whatever {@link GalaChainSigner} it is given) and\n * the backend forwards it to the gateway, where the simulated writes carry the fee; the backend\n * never holds a key. Intended for wallets: the DTO quoted is the typed message a dApp handed over.\n *\n * @example\n * ```ts\n * const fees = new DexFees({ dexBackendBaseUrl }, new PrivateKeySigner(sessionKey));\n * const quote = await fees.quote(publicKey, 'RequestTrade', toChainDto(message), {\n * contract: 'dex-contract',\n * });\n * const feeInGala = quote?.fees[0]?.feeInGala;\n * ```\n */\nexport class DexFees {\n private readonly requestor: HttpRequestor;\n private readonly baseUrl: string;\n private readonly requestTimeoutMs: number;\n private readonly wire: WireOptions | undefined;\n\n constructor(\n client: DexFeesClient,\n private readonly signer: GalaChainSigner | undefined,\n ) {\n this.requestor = client.httpRequestor ?? fetchRequestor;\n this.baseUrl = client.dexBackendBaseUrl.replace(/\\/$/u, '');\n this.requestTimeoutMs = client.requestTimeoutMs ?? 30_000;\n this.wire = client.wire;\n }\n\n /**\n * Quotes the network fee for `method` applied to `message`. The message is reduced with\n * {@link toChainDto} first, so an EIP-712 approval message can be passed as is.\n *\n * Resolves `null` when the BACKEND could not be reached or answered unusably (offline, 4xx/5xx,\n * malformed body): a transport outcome, not a fee. Deciding what to charge when the chain is\n * silent is the backend's job (it serves `source: 'default'`), so the client never substitutes\n * a fee of its own, with ONE exception that mirrors the wallet: a `dex-contract` quote answered\n * 403 or 404 means the contract has no fee route yet and resolves `{ source: 'default', '0' }`.\n * Never throws on transport, so a fee lookup cannot block or break a signing screen.\n *\n * @throws GSwapSDKError NO_SIGNER when constructed without a signer; `SIGNING_FAILED` or\n * `KEY_PROVIDER_FAILED` (a pre-send error, the original as `cause`) when the signer fails, for\n * example a locked wallet.\n */\n public async quote(\n callerPublicKey: string,\n method: DexFeeMethod,\n message: Record<string, unknown>,\n options: DexFeeQuoteOptions = {},\n ): Promise<DexFeeQuote | null> {\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n const channel = options.channel ?? 'asset';\n const contract = options.contract ?? 'dexv3-contract';\n const wrapper = await buildDryRunWrapper(\n this.signer,\n callerPublicKey,\n method,\n toChainDto(message),\n );\n const url = `${this.baseUrl}/wallet/connect/galachain/api/${encodeURIComponent(channel)}/${encodeURIComponent(contract)}/${encodeURIComponent(method)}/fee`;\n\n let status: number;\n let ok: boolean;\n let body: unknown;\n try {\n const response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers: buildRequestHeaders(this.wire, {\n json: true,\n defaults: { Accept: 'application/json' },\n }),\n body: JSON.stringify(wrapper),\n },\n this.requestTimeoutMs,\n );\n status = response.status;\n ok = response.ok;\n body = ok ? await readResponseBody(response) : undefined;\n } catch {\n return null;\n }\n\n if (!ok) {\n if (contract === 'dex-contract' && (status === 403 || status === 404)) {\n return { source: 'default', fees: [{ feeInGala: '0' }] };\n }\n return null;\n }\n // Accept whatever fee the backend served: 'default' is as usable as 'dry-run'. Only a body\n // missing the fee outright is unusable.\n return readQuote(body);\n }\n}\n\nfunction readQuote(body: unknown): DexFeeQuote | null {\n if (typeof body !== 'object' || body === null) return null;\n const fees = (body as { fees?: unknown }).fees;\n if (\n !Array.isArray(fees) ||\n typeof (fees[0] as { feeInGala?: unknown } | undefined)?.feeInGala !== 'string'\n ) {\n return null;\n }\n return body as DexFeeQuote;\n}\n"],"mappings":"6TAaA,MAAa,EAAkB,CAC7B,OACA,eACA,eACA,kBACA,sBACA,YACF,EAQa,EAAiB,SAGjB,EAA4B,yBAGzC,SAAgB,EAAe,EAAyC,CACtE,OAAO,OAAO,GAAW,UAAa,EAAsC,SAAS,CAAM,CAC7F,CAGA,SAAgB,EACd,EACA,EACS,CACT,OACE,EAAe,CAAM,GACrB,OAAO,GAAU,QAAc,UAC/B,OAAO,EAAQ,QAAc,QAEjC,CAmBA,SAAgB,EAAW,EAA2D,CACpF,IAAM,EAAoC,CAAE,GAAG,CAAQ,EACvD,IAAK,IAAM,IAAS,CAAC,YAAa,SAAU,QAAS,SAAU,OAAO,EACpE,OAAO,EAAS,GAElB,OAAO,CACT,CASA,SAAgB,EACd,EACA,EACA,EACA,EACA,EAA0B,EACQ,CAClC,OAAO,EAAY,EAAQ,EAAgB,CACzC,kBACA,SACA,MACA,UAAW,GAAG,IAAkB,WAAW,OAAO,WAAW,GAC/D,CAAC,CACH,CA4CA,IAAa,EAAb,KAAqB,CAMnB,YACE,EACA,EACA,CADiB,KAAA,OAAA,EAPF,EAAA,KAAA,YAAA,IAAA,EAAA,EACA,EAAA,KAAA,UAAA,IAAA,EAAA,EACA,EAAA,KAAA,mBAAA,IAAA,EAAA,EACA,EAAA,KAAA,OAAA,IAAA,EAAA,EAMf,KAAK,UAAY,EAAO,eAAiB,EACzC,KAAK,QAAU,EAAO,kBAAkB,QAAQ,OAAQ,EAAE,EAC1D,KAAK,iBAAmB,EAAO,kBAAoB,IACnD,KAAK,KAAO,EAAO,IACrB,CAiBA,MAAa,MACX,EACA,EACA,EACA,EAA8B,CAAC,EACF,CAC7B,GAAI,KAAK,SAAW,IAAA,GAAW,MAAM,EAAc,cAAc,EACjE,IAAM,EAAU,EAAQ,SAAW,QAC7B,EAAW,EAAQ,UAAY,iBAC/B,EAAU,MAAM,EACpB,KAAK,OACL,EACA,EACA,EAAW,CAAO,CACpB,EACM,EAAM,GAAG,KAAK,QAAQ,gCAAgC,mBAAmB,CAAO,EAAE,GAAG,mBAAmB,CAAQ,EAAE,GAAG,mBAAmB,CAAM,EAAE,MAElJ,EACA,EACA,EACJ,GAAI,CACF,IAAM,EAAW,MAAM,EACrB,KAAK,UACL,EACA,CACE,OAAQ,OACR,QAAS,EAAoB,KAAK,KAAM,CACtC,KAAM,GACN,SAAU,CAAE,OAAQ,kBAAmB,CACzC,CAAC,EACD,KAAM,KAAK,UAAU,CAAO,CAC9B,EACA,KAAK,gBACP,EACA,EAAS,EAAS,OAClB,EAAK,EAAS,GACd,EAAO,EAAK,MAAM,EAAiB,CAAQ,EAAI,IAAA,EACjD,MAAQ,CACN,OAAO,IACT,CAUA,OARK,EAQE,EAAU,CAAI,EAPf,IAAa,iBAAmB,IAAW,KAAO,IAAW,KACxD,CAAE,OAAQ,UAAW,KAAM,CAAC,CAAE,UAAW,GAAI,CAAC,CAAE,EAElD,IAKX,CACF,EAEA,SAAS,EAAU,EAAmC,CACpD,GAAI,OAAO,GAAS,WAAY,EAAe,OAAO,KACtD,IAAM,EAAQ,EAA4B,KAO1C,MALE,CAAC,MAAM,QAAQ,CAAI,GACnB,OAAQ,EAAK,EAAE,EAA0C,WAAc,SAEhE,KAEF,CACT"}
1
+ {"version":3,"file":"dex_fees.js","names":["_defineProperty","DEX_FEE_METHODS","DRY_RUN_METHOD","DRY_RUN_UNIQUE_KEY_PREFIX","isDexFeeMethod","method","isCurrentContractDexMessage","message","\"token0\"","\"token1\"","toChainDto","chainDto","field","buildDryRunWrapper","signPreSend","signer","createUniqueKey","uniqueKeyPrefix","DexFees","client","fetchRequestor","GSwapSDKError","channel","options","contract","wrapper","callerPublicKey","url","status","ok","body","response","requestWithTimeout","buildRequestHeaders","readResponseBody","readQuote","fees"],"sources":["../../../src/classes/dex_fees.ts"],"sourcesContent":["import {\n buildRequestHeaders,\n createUniqueKey,\n fetchRequestor,\n readResponseBody,\n requestWithTimeout,\n signPreSend,\n type GalaChainSigner,\n type HttpRequestor,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\n/** DEX methods the backend accepts a fee quote for (its allow-list enumerates the same six). */\nexport const DEX_FEE_METHODS = [\n 'Swap',\n 'RequestTrade',\n 'AddLiquidity',\n 'RemoveLiquidity',\n 'CollectPositionFees',\n 'CreatePool',\n] as const;\n/** A chain method whose network fee `DexFees.quote` can price (see `isDexFeeMethod`). */\nexport type DexFeeMethod = (typeof DEX_FEE_METHODS)[number];\n\n/** Which pool contract the DTO being quoted targets: legacy (V3) or current (GalaChainDex). */\nexport type DexFeeContract = 'dexv3-contract' | 'dex-contract';\n\n/** The chain method name the signed DryRun wrapper is signed under. */\nexport const DRY_RUN_METHOD = 'DryRun';\n\n/** `uniqueKey` prefix of the DryRun WRAPPER (distinct from the inner DTO's key). */\nexport const DRY_RUN_UNIQUE_KEY_PREFIX = 'galaconnect-operation-';\n\n/** True when `method` is a DEX method a fee can be quoted for. */\nexport function isDexFeeMethod(method: unknown): method is DexFeeMethod {\n return typeof method === 'string' && (DEX_FEE_METHODS as readonly string[]).includes(method);\n}\n\n/** Current-contract typed DEX messages use trading symbols instead of TokenClassKey objects. */\nexport function isCurrentContractDexMessage(\n message: Record<string, unknown> | null | undefined,\n method: unknown,\n): boolean {\n return (\n isDexFeeMethod(method) &&\n typeof message?.['token0'] === 'string' &&\n typeof message['token1'] === 'string'\n );\n}\n\n/**\n * The backend's response. It ALWAYS carries a usable `fees[0].feeInGala`: the backend decides what\n * to serve when the chain cannot price the operation, so the client never invents a fee.\n *\n * `source` is informational: `'dry-run'` is simulated on chain and authoritative (possibly a\n * legitimate `'0'`), `'default'` means the chain could not price it and the platform default was\n * served.\n */\nexport interface DexFeeQuote {\n fees: Array<{ feeInGala: string }>;\n source: 'dry-run' | 'default';\n}\n\n/**\n * Reduces an EIP-712 approval `message` to the DTO the chain actually receives: drops the signing\n * envelope (`signature`, `prefix`, `types`, `domain`) and transport metadata (`trace`).\n */\nexport function toChainDto(message: Record<string, unknown>): Record<string, unknown> {\n const chainDto: Record<string, unknown> = { ...message };\n for (const field of ['signature', 'prefix', 'types', 'domain', 'trace']) {\n delete chainDto[field];\n }\n return chainDto;\n}\n\n/**\n * Signs the DryRun WRAPPER the gateway accepts for every contract:\n * `{ callerPublicKey, method, dto: <inner DTO object>, uniqueKey, signature }`. The inner DTO\n * travels unsigned and as an object; no `signerPublicKey` is sent because the signature already\n * recovers it (the gateway rejects it as REDUNDANT_SIGNER_PUBLIC_KEY). The wrapper carries its own\n * `uniqueKey`, distinct from the DTO's.\n */\nexport function buildDryRunWrapper(\n signer: GalaChainSigner,\n callerPublicKey: string,\n method: string,\n dto: Record<string, unknown>,\n uniqueKeyPrefix: string = DRY_RUN_UNIQUE_KEY_PREFIX,\n): Promise<Record<string, unknown>> {\n return signPreSend(signer, DRY_RUN_METHOD, {\n callerPublicKey,\n method,\n dto,\n // Core's RN-safe mint (`getRandomValues`, never `randomUUID`, which Hermes lacks).\n uniqueKey: createUniqueKey(uniqueKeyPrefix),\n });\n}\n\n/** The transport and backend a fee quote reads from. */\nexport interface DexFeesClient {\n /** Swap backend origin, e.g. `https://dex-backend-prod1.defi.gala.com`. */\n dexBackendBaseUrl: string;\n /** Defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Per-request timeout in milliseconds (default 30 000). */\n requestTimeoutMs?: number | undefined;\n /**\n * Request headers of the fee POST (`userAgent`, `headers`); see {@link WireOptions}. The SDK's\n * `Accept: application/json` is a default that `wire.headers` may replace.\n */\n wire?: WireOptions | undefined;\n}\n\n/** Options for a single quote. */\nexport interface DexFeeQuoteOptions {\n /** GalaChain channel. Default `asset`. */\n channel?: string | undefined;\n /**\n * Contract the DTO targets. Default `dexv3-contract` (what every legacy caller quotes against);\n * a current-contract operation must pass `dex-contract` explicitly.\n */\n contract?: DexFeeContract | undefined;\n}\n\n/**\n * Network-fee quote for GalaChain DEX methods, derived from a server-side DryRun.\n *\n * The client only SIGNS the DryRun wrapper (with whatever {@link GalaChainSigner} it is given) and\n * the backend forwards it to the gateway, where the simulated writes carry the fee; the backend\n * never holds a key. Intended for wallets: the DTO quoted is the typed message a dApp handed over.\n *\n * @example\n * ```ts\n * const fees = new DexFees({ dexBackendBaseUrl }, new PrivateKeySigner(sessionKey));\n * const quote = await fees.quote(publicKey, 'RequestTrade', toChainDto(message), {\n * contract: 'dex-contract',\n * });\n * const feeInGala = quote?.fees[0]?.feeInGala;\n * ```\n */\nexport class DexFees {\n private readonly requestor: HttpRequestor;\n private readonly baseUrl: string;\n private readonly requestTimeoutMs: number;\n private readonly wire: WireOptions | undefined;\n\n constructor(\n client: DexFeesClient,\n private readonly signer: GalaChainSigner | undefined,\n ) {\n this.requestor = client.httpRequestor ?? fetchRequestor;\n this.baseUrl = client.dexBackendBaseUrl.replace(/\\/$/u, '');\n this.requestTimeoutMs = client.requestTimeoutMs ?? 30_000;\n this.wire = client.wire;\n }\n\n /**\n * Quotes the network fee for `method` applied to `message`. The message is reduced with\n * {@link toChainDto} first, so an EIP-712 approval message can be passed as is.\n *\n * Resolves `null` when the BACKEND could not be reached or answered unusably (offline, 4xx/5xx,\n * malformed body): a transport outcome, not a fee. Deciding what to charge when the chain is\n * silent is the backend's job (it serves `source: 'default'`), so the client never substitutes\n * a fee of its own, with ONE exception that mirrors the wallet: a `dex-contract` quote answered\n * 403 or 404 means the contract has no fee route yet and resolves `{ source: 'default', '0' }`.\n * Never throws on transport, so a fee lookup cannot block or break a signing screen.\n *\n * @throws GSwapSDKError NO_SIGNER when constructed without a signer; `SIGNING_FAILED` or\n * `KEY_PROVIDER_FAILED` (a pre-send error, the original as `cause`) when the signer fails, for\n * example a locked wallet.\n */\n public async quote(\n callerPublicKey: string,\n method: DexFeeMethod,\n message: Record<string, unknown>,\n options: DexFeeQuoteOptions = {},\n ): Promise<DexFeeQuote | null> {\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n const channel = options.channel ?? 'asset';\n const contract = options.contract ?? 'dexv3-contract';\n const wrapper = await buildDryRunWrapper(\n this.signer,\n callerPublicKey,\n method,\n toChainDto(message),\n );\n const url = `${this.baseUrl}/wallet/connect/galachain/api/${encodeURIComponent(channel)}/${encodeURIComponent(contract)}/${encodeURIComponent(method)}/fee`;\n\n let status: number;\n let ok: boolean;\n let body: unknown;\n try {\n const response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers: buildRequestHeaders(this.wire, {\n json: true,\n defaults: { Accept: 'application/json' },\n }),\n body: JSON.stringify(wrapper),\n },\n this.requestTimeoutMs,\n );\n status = response.status;\n ok = response.ok;\n body = ok ? await readResponseBody(response) : undefined;\n } catch {\n return null;\n }\n\n if (!ok) {\n if (contract === 'dex-contract' && (status === 403 || status === 404)) {\n return { source: 'default', fees: [{ feeInGala: '0' }] };\n }\n return null;\n }\n // Accept whatever fee the backend served: 'default' is as usable as 'dry-run'. Only a body\n // missing the fee outright is unusable.\n return readQuote(body);\n }\n}\n\nfunction readQuote(body: unknown): DexFeeQuote | null {\n if (typeof body !== 'object' || body === null) return null;\n const fees = (body as { fees?: unknown }).fees;\n if (\n !Array.isArray(fees) ||\n typeof (fees[0] as { feeInGala?: unknown } | undefined)?.feeInGala !== 'string'\n ) {\n return null;\n }\n return body as DexFeeQuote;\n}\n"],"mappings":"oTAcA,MAAaC,EAAkB,CAC7B,OACA,eACA,eACA,kBACA,sBACA,YACF,EAQaC,EAAiB,SAGjBC,EAA4B,yBAGzC,SAAgBC,EAAe,EAAyC,CACtE,OAAO,OAAOC,GAAW,UAAaJ,EAAsC,SAASI,CAAM,CAC7F,CAGA,SAAgBC,EACd,EACA,EACS,CACT,OACEF,EAAeC,CAAM,GACrB,OAAOE,GAAUC,QAAc,UAC/B,OAAOD,EAAQE,QAAc,QAEjC,CAmBA,SAAgBC,EAAW,EAA2D,CACpF,IAAMC,EAAoC,CAAE,GAAGJ,CAAQ,EACvD,IAAK,IAAMK,IAAS,CAAC,YAAa,SAAU,QAAS,SAAU,OAAO,EACpE,OAAOD,EAASC,GAElB,OAAOD,CACT,CASA,SAAgBE,EACd,EACA,EACA,EACA,EACA,EAA0BV,EACQ,CAClC,OAAOW,EAAYC,EAAQb,EAAgB,CACzC,kBACA,SACA,MAEA,UAAWc,EAAgBC,CAAe,CAC5C,CAAC,CACH,CA4CA,IAAaC,EAAb,KAAqB,CAMnB,YACE,EACA,EACA,CADiB,KAAA,OAAAH,EAPFf,EAAA,KAAA,YAAA,IAAA,EAAA,EACAA,EAAA,KAAA,UAAA,IAAA,EAAA,EACAA,EAAA,KAAA,mBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,OAAA,IAAA,EAAA,EAMf,KAAK,UAAYmB,EAAO,eAAiBC,EACzC,KAAK,QAAUD,EAAO,kBAAkB,QAAQ,OAAQ,EAAE,EAC1D,KAAK,iBAAmBA,EAAO,kBAAoB,IACnD,KAAK,KAAOA,EAAO,IACrB,CAiBA,MAAa,MACX,EACA,EACA,EACA,EAA8B,CAAC,EACF,CAC7B,GAAI,KAAK,SAAW,IAAA,GAAW,MAAME,EAAc,cAAc,EACjE,IAAMC,EAAUC,EAAQ,SAAW,QAC7BC,EAAWD,EAAQ,UAAY,iBAC/BE,EAAU,MAAMZ,EACpB,KAAK,OACLa,EACArB,EACAK,EAAWH,CAAO,CACpB,EACMoB,EAAM,GAAG,KAAK,QAAQ,gCAAgC,mBAAmBL,CAAO,EAAE,GAAG,mBAAmBE,CAAQ,EAAE,GAAG,mBAAmBnB,CAAM,EAAE,MAElJuB,EACAC,EACAC,EACJ,GAAI,CACF,IAAMC,EAAW,MAAMC,EACrB,KAAK,UACLL,EACA,CACE,OAAQ,OACR,QAASM,EAAoB,KAAK,KAAM,CACtC,KAAM,GACN,SAAU,CAAE,OAAQ,kBAAmB,CACzC,CAAC,EACD,KAAM,KAAK,UAAUR,CAAO,CAC9B,EACA,KAAK,gBACP,EACA,EAASM,EAAS,OAClB,EAAKA,EAAS,GACd,EAAOF,EAAK,MAAMK,EAAiBH,CAAQ,EAAI,IAAA,EACjD,MAAQ,CACN,OAAO,IACT,CAUA,OARKF,EAQEM,EAAUL,CAAI,EAPfN,IAAa,iBAAmBI,IAAW,KAAOA,IAAW,KACxD,CAAE,OAAQ,UAAW,KAAM,CAAC,CAAE,UAAW,GAAI,CAAC,CAAE,EAElD,IAKX,CACF,EAEA,SAASO,EAAU,EAAmC,CACpD,GAAI,OAAOL,GAAS,WAAYA,EAAe,OAAO,KACtD,IAAMM,EAAQN,EAA4B,KAO1C,MALE,CAAC,MAAM,QAAQM,CAAI,GACnB,OAAQA,EAAK,EAAE,EAA0C,WAAc,SAEhE,KAEFN,CACT"}
@@ -1,2 +1,2 @@
1
- import{serverMessageOfBody as e}from"../utils/server_message.js";import t from"../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/defineProperty.js";import{GSwapSDKError as n,getObjectProperty as r,getStringProperty as i,isGSwapError as a}from"./gswap_sdk_error.js";import{buildRequestHeaders as o,fetchRequestor as s,readBlockNumberHeader as c,readHeader as l,readResponseBody as u,readRetryAfter as d,requestWithTimeout as f,validateTimeoutMs as p}from"../utils/transport.js";import{shadowFailures as m}from"../utils/shadow_errors.js";import{SubmittedTransaction as h}from"./submitted_transaction.js";var g=class{constructor(e){t(this,`requestor`,void 0),t(this,`walletAddress`,void 0),t(this,`chainCallTimeoutMs`,void 0),t(this,`isTransportFailure`,void 0),t(this,`answerOfRejectionHook`,void 0),t(this,`requestTimeoutMs`,void 0),t(this,`dexBackendBaseUrl`,void 0),t(this,`wire`,void 0),this.dexBackendBaseUrl=_(e.dexBackendBaseUrl),this.requestor=e.httpRequestor??s,this.walletAddress=e.walletAddress,this.chainCallTimeoutMs=p(e.chainCallTimeoutMs??3e4,`chainCallTimeoutMs`),this.requestTimeoutMs=this.chainCallTimeoutMs,this.wire=e.wire??{},this.isTransportFailure=e.isTransportFailure,this.answerOfRejectionHook=e.answerOfRejection}async submit(t,r,a){if(t===`Trade`)throw new n(`METHOD_NOT_SUPPORTED`,{method:t});let s=this.writeUrl(t),u=a?.walletAddress??this.walletAddress,d=o(this.wire,{json:!0,fixed:u===void 0?{}:{"X-Wallet-Address":u}}),{response:f,body:p}=await this.post(t,s,d,r),m=i(r,`uniqueKey`)??``,g=v(f,p,s,m);if(!f.ok)throw b(f,p,s,m);let _=x(p);if(_?.error===!0)throw new n(`GATEWAY_REPORTED_ERROR`,{serverMessage:e(_)},g);let C=x(_?.data??_?.Data);if(C===void 0)throw new n(`GATEWAY_DATA_MISSING`,{},g);let w=i(C,`transactionId`),T=i(C,`mode`),E=C.transactionId,D=C.blockNumber,O=()=>new n(`GATEWAY_MODE_INVALID`,{},g);if(T!==`sync`&&T!==`queued`||`transactionId`in C&&typeof E!=`string`||D!=null&&!S(D))throw O();if(t===`RequestTrade`&&T===`sync`)throw new n(`GATEWAY_SYNC_REQUEST_TRADE`,{},g);if(t===`RequestTrade`&&T===`queued`)y(f,p,s,C,r);else if(T===`queued`||!(`result`in C))throw O();if(T===`sync`){let e=x(C.result);if(e!==void 0){let t=e.Status;if(t!==void 0&&t!==1)throw n.fromChainError(i(e,`ErrorKey`)??`CHAIN_ERROR`,i(e,`Message`)??``,g)}}let k=l(f,`x-transaction-id`),A=w===void 0||w===``?k:w,j=D==null?c(f):S(D)?D:void 0;return new h({method:t,uniqueKey:m,transactionId:A===void 0||A===``?null:A,blockNumber:j??null,mode:T,result:T===`queued`?void 0:C.result,envelope:p,dexBackendBaseUrl:this.dexBackendBaseUrl,httpRequestor:this.requestor,requestTimeoutMs:this.chainCallTimeoutMs,wire:this.wire,...a?.positionConfirmation===void 0?{}:{positionConfirmation:a.positionConfirmation}})}async submitShadow(e,t,n){return m(()=>this.sendShadow(e,t,n))}async sendShadow(e,t,r){if(e===`Trade`)throw new n(`METHOD_NOT_SUPPORTED`,{method:e});let i=r?.walletAddress??this.walletAddress;if(i===void 0)throw new n(`SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS`,{});let a=o(this.wire,{json:!0,fixed:{"X-Wallet-Address":i,"X-Shadow":`true`}}),{response:s,body:c}=await this.post(e,this.writeUrl(e),a,t);return{httpStatus:s.status,body:c}}writeUrl(e){return`${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${e}`}async post(e,t,r,o){let s;try{s=JSON.stringify(o)}catch(t){throw new n(`SIGNING_FAILED`,{method:e,reason:`failed`},{cause:t})}let c=(e,r)=>new n(`SUBMISSION_OUTCOME_UNKNOWN`,{reason:e},{uniqueKey:i(o,`uniqueKey`)??``,url:t,cause:r}),l;try{l=await f(this.requestor,t,{method:`POST`,headers:r,body:s},this.chainCallTimeoutMs)}catch(e){if(a(e,`REQUEST_TIMEOUT`))throw c(`timeout`,e);if(a(e,`TRANSPORT_ERROR`)||this.isTransportRejection(e))throw c(`transport`,e);let t=this.answerOfRejection(e);if(t!==void 0)return t;throw e}try{return{response:l,body:await u(l)}}catch(e){throw c(`transport`,e)}}answerOfRejection(e){let t;try{t=this.answerOfRejectionHook?.(e)}catch{return}if(t===void 0)return;let{status:n,body:r,headers:i}=t;if(!Number.isInteger(n)||n<100||n>599)return;let a=typeof r==`string`?r:``;return{response:{ok:n>=200&&n<300,status:n,json:async()=>r,text:async()=>a,headers:i??{}},body:r}}isTransportRejection(e){try{return this.isTransportFailure?.(e)===!0}catch{return!1}}get httpRequestor(){return this.requestor}};function _(e){return e.replace(/\/$/u,``)}function v(e,t,n,r){return{status:e.status,body:t,url:n,...r===void 0||r===``?{}:{uniqueKey:r}}}function y(e,t,r,a,o){let s=i(o,`uniqueKey`)??``,c=a.uniqueKey;if(typeof c==`string`&&c!==``&&c===s)return;let l=c==null||c===``,u={...v(e,t,r),uniqueKey:s};throw l?new n(`MISSING_UNIQUE_KEY`,{},u):new n(`UNIQUE_KEY_MISMATCH`,{},u)}function b(t,a,o,s){if(t.status===426)return new n(`UPDATE_REQUIRED`,{status:t.status},v(t,a,o,s));let c=x(a),l=r(a,`error`),u=i(c,`code`)??i(l,`code`)??i(l,`ErrorKey`)??`HTTP_ERROR`,f=e(a),p=t.status===429?d(t):void 0;return u===`HTTP_ERROR`?new n(`HTTP_ERROR`,{status:t.status,url:o,serverMessage:f},v(t,a,o,s)):n.fromGatewayBounce(u,f,t.status,a,o,p,s===``?void 0:s)}function x(e){return typeof e==`object`&&e?e:void 0}function S(e){return typeof e==`number`&&Number.isInteger(e)&&e>=0}export{g as ChainGateway};
1
+ import{serverMessageOfBody as e}from"../utils/server_message.js";import t from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{GSwapSDKError as n,getObjectProperty as r,getStringProperty as i,isGSwapError as a}from"./gswap_sdk_error.js";import{shadowFailures as o}from"../utils/shadow_errors.js";import{SubmittedTransaction as s}from"./submitted_transaction.js";import{buildRequestHeaders as c,fetchRequestor as l,readBlockNumberHeader as u,readHeader as d,readResponseBody as f,readRetryAfter as p,requestWithTimeout as m,validateTimeoutMs as h}from"@gala-chain/gala-core-sdk";var g=class{constructor(e){t(this,`requestor`,void 0),t(this,`walletAddress`,void 0),t(this,`chainCallTimeoutMs`,void 0),t(this,`isTransportFailure`,void 0),t(this,`answerOfRejectionHook`,void 0),t(this,`requestTimeoutMs`,void 0),t(this,`dexBackendBaseUrl`,void 0),t(this,`wire`,void 0),this.dexBackendBaseUrl=_(e.dexBackendBaseUrl),this.requestor=e.httpRequestor??l,this.walletAddress=e.walletAddress,this.chainCallTimeoutMs=h(e.chainCallTimeoutMs??3e4,`chainCallTimeoutMs`),this.requestTimeoutMs=this.chainCallTimeoutMs,this.wire=e.wire??{},this.isTransportFailure=e.isTransportFailure,this.answerOfRejectionHook=e.answerOfRejection}async submit(t,r,a){if(t===`Trade`)throw new n(`METHOD_NOT_SUPPORTED`,{method:t});let o=this.writeUrl(t),l=a?.walletAddress??this.walletAddress,f=c(this.wire,{json:!0,fixed:l===void 0?{}:{"X-Wallet-Address":l}}),{response:p,body:m}=await this.post(t,o,f,r),h=i(r,`uniqueKey`)??``,g=v(p,m,o,h);if(!p.ok)throw b(p,m,o,h);let _=x(m);if(_?.error===!0)throw new n(`GATEWAY_REPORTED_ERROR`,{serverMessage:e(_)},g);let C=x(_?.data??_?.Data);if(C===void 0)throw new n(`GATEWAY_DATA_MISSING`,{},g);let w=i(C,`transactionId`),T=i(C,`mode`),E=C.transactionId,D=C.blockNumber,O=()=>new n(`GATEWAY_MODE_INVALID`,{},g);if(T!==`sync`&&T!==`queued`||`transactionId`in C&&typeof E!=`string`||D!=null&&!S(D))throw O();if(t===`RequestTrade`&&T===`sync`)throw new n(`GATEWAY_SYNC_REQUEST_TRADE`,{},g);if(t===`RequestTrade`&&T===`queued`)y(p,m,o,C,r);else if(T===`queued`||!(`result`in C))throw O();if(T===`sync`){let e=x(C.result);if(e!==void 0){let t=e.Status;if(t!==void 0&&t!==1)throw n.fromChainError(i(e,`ErrorKey`)??`CHAIN_ERROR`,i(e,`Message`)??``,g)}}let k=d(p,`x-transaction-id`),A=w===void 0||w===``?k:w,j=D==null?u(p):S(D)?D:void 0;return new s({method:t,uniqueKey:h,transactionId:A===void 0||A===``?null:A,blockNumber:j??null,mode:T,result:T===`queued`?void 0:C.result,envelope:m,dexBackendBaseUrl:this.dexBackendBaseUrl,httpRequestor:this.requestor,requestTimeoutMs:this.chainCallTimeoutMs,wire:this.wire,...a?.positionConfirmation===void 0?{}:{positionConfirmation:a.positionConfirmation}})}async submitShadow(e,t,n){return o(()=>this.sendShadow(e,t,n))}async sendShadow(e,t,r){if(e===`Trade`)throw new n(`METHOD_NOT_SUPPORTED`,{method:e});let i=r?.walletAddress??this.walletAddress;if(i===void 0)throw new n(`SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS`,{});let a=c(this.wire,{json:!0,fixed:{"X-Wallet-Address":i,"X-Shadow":`true`}}),{response:o,body:s}=await this.post(e,this.writeUrl(e),a,t);return{httpStatus:o.status,body:s}}writeUrl(e){return`${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${e}`}async post(e,t,r,o){let s;try{s=JSON.stringify(o)}catch(t){throw new n(`SIGNING_FAILED`,{method:e,reason:`failed`},{cause:t})}let c=(e,r)=>new n(`SUBMISSION_OUTCOME_UNKNOWN`,{reason:e},{uniqueKey:i(o,`uniqueKey`)??``,url:t,cause:r}),l;try{l=await m(this.requestor,t,{method:`POST`,headers:r,body:s},this.chainCallTimeoutMs)}catch(e){if(a(e,`REQUEST_TIMEOUT`))throw c(`timeout`,e);if(a(e,`TRANSPORT_ERROR`)||this.isTransportRejection(e))throw c(`transport`,e);let t=this.answerOfRejection(e);if(t!==void 0)return t;throw e}try{return{response:l,body:await f(l)}}catch(e){throw c(`transport`,e)}}answerOfRejection(e){let t;try{t=this.answerOfRejectionHook?.(e)}catch{return}if(t===void 0)return;let{status:n,body:r,headers:i}=t;if(!Number.isInteger(n)||n<100||n>599)return;let a=typeof r==`string`?r:``;return{response:{ok:n>=200&&n<300,status:n,json:async()=>r,text:async()=>a,headers:i??{}},body:r}}isTransportRejection(e){try{return this.isTransportFailure?.(e)===!0}catch{return!1}}get httpRequestor(){return this.requestor}};function _(e){return e.replace(/\/$/u,``)}function v(e,t,n,r){return{status:e.status,body:t,url:n,...r===void 0||r===``?{}:{uniqueKey:r}}}function y(e,t,r,a,o){let s=i(o,`uniqueKey`)??``,c=a.uniqueKey;if(typeof c==`string`&&c!==``&&c===s)return;let l=c==null||c===``,u={...v(e,t,r),uniqueKey:s};throw l?new n(`MISSING_UNIQUE_KEY`,{},u):new n(`UNIQUE_KEY_MISMATCH`,{},u)}function b(t,a,o,s){if(t.status===426)return new n(`UPDATE_REQUIRED`,{status:t.status},v(t,a,o,s));let c=x(a),l=r(a,`error`),u=i(c,`code`)??i(l,`code`)??i(l,`ErrorKey`)??`HTTP_ERROR`,d=e(a),f=t.status===429?p(t):void 0;return u===`HTTP_ERROR`?new n(`HTTP_ERROR`,{status:t.status,url:o,serverMessage:d},v(t,a,o,s)):n.fromGatewayBounce(u,d,t.status,a,o,f,s===``?void 0:s)}function x(e){return typeof e==`object`&&e?e:void 0}function S(e){return typeof e==`number`&&Number.isInteger(e)&&e>=0}export{g as ChainGateway};
2
2
  //# sourceMappingURL=gateway.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.js","names":[],"sources":["../../../src/classes/gateway.ts"],"sourcesContent":["import type { HttpRequestor, HTTPResponse } from '../types/http_requestor.js';\nimport type { WireOptions } from '../types/wire.js';\nimport {\n getObjectProperty,\n getStringProperty,\n GSwapSDKError,\n isGSwapError,\n UPDATE_REQUIRED_STATUS,\n type GSwapErrorContext,\n} from './gswap_sdk_error.js';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport { shadowFailures } from '../utils/shadow_errors.js';\nimport type { SubmissionOutcomeUnknownReason } from './error_catalog.js';\nimport type { ShadowSubmitResult } from './shadow_submit.js';\nimport { SubmittedTransaction, type PositionConfirmationResult } from './submitted_transaction.js';\nimport {\n buildRequestHeaders,\n fetchRequestor,\n readBlockNumberHeader,\n readHeader,\n readResponseBody,\n readRetryAfter,\n requestWithTimeout,\n validateTimeoutMs,\n} from '../utils/transport.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\n\n/** Options for a chain-gateway client. */\nexport interface ChainGatewayOptions {\n dexBackendBaseUrl: string;\n httpRequestor?: HttpRequestor | undefined;\n walletAddress?: string | undefined;\n /**\n * Timeout of every gateway request in milliseconds (default 30 000); also the per-read timeout\n * of the services built on this gateway and of `confirm()`. `Infinity` arms no timer, for an\n * app whose HTTP stack owns request lifetimes.\n */\n chainCallTimeoutMs?: number | undefined;\n /**\n * Wire format of every request of this gateway and of the services built on it: the headers\n * (`userAgent`, `headers`) of reads AND of the POSTs that submit writes, and the query encoding\n * of reads. `X-Wallet-Address` and `X-Shadow` always win over a same-named `wire.headers` entry.\n */\n wire?: WireOptions | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` mean \"no HTTP answer arrived\" (the\n * connection failed, was reset or dropped), as opposed to an answer your requestor turned into\n * an error (an interceptor that rejects on a 4xx, a version wall). Used only when submitting a\n * write: a rejection it accepts becomes `SUBMISSION_OUTCOME_UNKNOWN` with `reason: 'transport'`\n * (the request may have been queued; the original error is `cause`), and any other rejection\n * reaches the caller unchanged. The SDK's own `TRANSPORT_ERROR` (the default `fetch` requestor,\n * `httpRequestorFromAxios`) always counts, so this is only for requestors that reject with\n * their own errors. Never throw from it; a throw is treated as \"not a transport failure\".\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: galaFetch, // a fetch wrapper: its TypeError is the network failing\n * isTransportFailure: (error) => error instanceof TypeError,\n * });\n * ```\n */\n isTransportFailure?: ((error: unknown) => boolean) | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` are an HTTP ANSWER, and what the\n * answer was: a requestor built on an HTTP client that rejects every non-2xx (an interceptor\n * that throws on a 4xx, a version wall that throws on a 426) loses the answer the SDK reads\n * errors from. Return `{ status, body }` (the parsed JSON, or the raw text; `headers` for\n * `Retry-After`) for such a rejection and the write is handled exactly as if the requestor had\n * resolved that answer: the gateway's own code becomes its catalogued error\n * (`DTO_INVALID`, `RATE_LIMITED`, `CHAIN_DISPATCH_FAILED`, ...), an uncoded body `HTTP_ERROR`,\n * both carrying the signed `uniqueKey` and classified by `classifyFailure` as a write. Return\n * `undefined` for any other rejection: it reaches the caller unchanged. Used only when\n * submitting a write; `isTransportFailure` is asked first (no answer proves nothing, so\n * \"maybe queued\" wins), and a throw from this hook, or a `status` outside 100-599, means \"not an\n * answer\". Never throw from it.\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: httpRequestorFromAxios(instance, { rejectOnHttpError: true }),\n * answerOfRejection: (error) =>\n * error instanceof GatewayError && error.status !== undefined\n * ? { status: error.status, body: error.data }\n * : undefined,\n * });\n * ```\n */\n answerOfRejection?: ((error: unknown) => RejectedAnswer | undefined) | undefined;\n}\n\n/** The HTTP answer a rejection of the app's requestor stands for (see `ChainGatewayOptions.answerOfRejection`). */\nexport interface RejectedAnswer {\n /** The HTTP status of the answer (100-599). */\n status: number;\n /** The answer's body: parsed JSON when it was JSON, else the raw text. */\n body: unknown;\n /** The answer's headers, for `Retry-After`. */\n headers?: Record<string, string | undefined> | undefined;\n}\n\n/** Optional attribution and operation-specific confirmation hooks for a write. */\nexport interface ChainSubmitOptions {\n walletAddress?: string | undefined;\n positionConfirmation?: ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n}\n\n/** Thin client for backend-routed v2 writes: synchronous liquidity writes and queued RequestTrade. */\nexport class ChainGateway {\n private readonly requestor: HttpRequestor;\n private readonly walletAddress: string | undefined;\n private readonly chainCallTimeoutMs: number;\n private readonly isTransportFailure: ((error: unknown) => boolean) | undefined;\n private readonly answerOfRejectionHook:\n ((error: unknown) => RejectedAnswer | undefined) | undefined;\n /** The request timeout in milliseconds (`Infinity` when no timer is armed). */\n public readonly requestTimeoutMs: number;\n /** The swap backend base URL every request is sent to, without a trailing slash. */\n public readonly dexBackendBaseUrl: string;\n /** Wire format shared by the read services built on this gateway. */\n public readonly wire: WireOptions;\n\n /** Create a chain gateway client. */\n constructor(options: ChainGatewayOptions) {\n this.dexBackendBaseUrl = trimTrailingSlash(options.dexBackendBaseUrl);\n this.requestor = options.httpRequestor ?? fetchRequestor;\n this.walletAddress = options.walletAddress;\n this.chainCallTimeoutMs = validateTimeoutMs(\n options.chainCallTimeoutMs ?? 30_000,\n 'chainCallTimeoutMs',\n );\n this.requestTimeoutMs = this.chainCallTimeoutMs;\n this.wire = options.wire ?? {};\n this.isTransportFailure = options.isTransportFailure;\n this.answerOfRejectionHook = options.answerOfRejection;\n }\n\n /**\n * Submit a signed v2 DTO through the chain gateway.\n *\n * @throws GSwapSDKError `SUBMISSION_OUTCOME_UNKNOWN` when no answer was read: `params.reason` is\n * `'timeout'` (the POST exceeded `chainCallTimeoutMs`) or `'transport'` (the connection failed\n * or broke off). Either way the write MAY have been queued: keep `error.uniqueKey` and confirm\n * it. Whether to offer the user a Retry (a NEW request under a fresh key) is the app's policy;\n * the SDK states only that the outcome is unknown. Reads keep `TRANSPORT_ERROR`.\n */\n public async submit(\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<AppliedTrade>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<Position | null>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction> {\n // The synchronous swap was removed from the contract and from this SDK. This is the only\n // place the retired name may appear in the write path; the class guard in\n // tests/foundation.test.ts pins that nothing signs or submits it.\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const url = this.writeUrl(method);\n const walletAddress = options?.walletAddress ?? this.walletAddress;\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: walletAddress === undefined ? {} : { 'X-Wallet-Address': walletAddress },\n });\n const { response, body } = await this.post(method, url, headers, signedBody);\n // Every failure after an answer names the write it is about, so an app can confirm it and a\n // failure classifier can tell a write's HTTP failure from a read's.\n const uniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const context = responseContext(response, body, url, uniqueKey);\n\n if (!response.ok) {\n throw gatewayError(response, body, url, uniqueKey);\n }\n\n const envelope = asRecord(body);\n // `error: true` is the gateway refusing the write, even inside a 2xx. It is never a transaction.\n if (envelope?.['error'] === true) {\n throw new GSwapSDKError(\n 'GATEWAY_REPORTED_ERROR',\n { serverMessage: serverMessageOfBody(envelope) },\n context,\n );\n }\n const data = asRecord(envelope?.['data'] ?? envelope?.['Data']);\n if (data === undefined) {\n throw new GSwapSDKError('GATEWAY_DATA_MISSING', {}, context);\n }\n\n const transactionId = getStringProperty(data, 'transactionId');\n const mode = getStringProperty(data, 'mode');\n const rawTransactionId = data['transactionId'];\n const bodyBlockNumber = data['blockNumber'];\n const invalidMode = (): GSwapSDKError<'GATEWAY_MODE_INVALID'> =>\n new GSwapSDKError('GATEWAY_MODE_INVALID', {}, context);\n if (mode !== 'sync' && mode !== 'queued') {\n throw invalidMode();\n }\n if (\n ('transactionId' in data && typeof rawTransactionId !== 'string') ||\n (bodyBlockNumber !== undefined && bodyBlockNumber !== null && !isBlockNumber(bodyBlockNumber))\n ) {\n throw invalidMode();\n }\n if (method === 'RequestTrade' && mode === 'sync') {\n throw new GSwapSDKError('GATEWAY_SYNC_REQUEST_TRADE', {}, context);\n }\n if (method === 'RequestTrade' && mode === 'queued') {\n assertQueuedUnderSignedKey(response, body, url, data, signedBody);\n } else if (mode === 'queued' || !('result' in data)) {\n throw invalidMode();\n }\n\n // Only synchronous writes carry an executed chain result in the gateway response.\n if (mode === 'sync') {\n const embeddedResult = asRecord(data['result']);\n if (embeddedResult !== undefined) {\n const resultStatus = embeddedResult['Status'];\n if (resultStatus !== undefined && resultStatus !== 1) {\n throw GSwapSDKError.fromChainError(\n getStringProperty(embeddedResult, 'ErrorKey') ?? 'CHAIN_ERROR',\n getStringProperty(embeddedResult, 'Message') ?? '',\n context,\n );\n }\n }\n }\n\n const headerTransactionId = readHeader(response, 'x-transaction-id');\n const resolvedTransactionId =\n transactionId === undefined || transactionId === '' ? headerTransactionId : transactionId;\n const blockNumber: number | undefined =\n bodyBlockNumber === null || bodyBlockNumber === undefined\n ? readBlockNumberHeader(response)\n : isBlockNumber(bodyBlockNumber)\n ? bodyBlockNumber\n : undefined;\n return new SubmittedTransaction({\n method,\n uniqueKey,\n transactionId:\n resolvedTransactionId === undefined || resolvedTransactionId === ''\n ? null\n : resolvedTransactionId,\n blockNumber: blockNumber ?? null,\n mode,\n result: mode === 'queued' ? undefined : data['result'],\n envelope: body,\n dexBackendBaseUrl: this.dexBackendBaseUrl,\n httpRequestor: this.requestor,\n requestTimeoutMs: this.chainCallTimeoutMs,\n wire: this.wire,\n ...(options?.positionConfirmation === undefined\n ? {}\n : { positionConfirmation: options.positionConfirmation }),\n });\n }\n\n /**\n * Submit a signed v2 DTO as a SHADOW (dark) write: the same route and body as {@link submit},\n * plus `X-Wallet-Address` and `X-Shadow: true`, so defi-backend marks the transaction private\n * before it reaches the contract. The wallet address is required (the backend resolves the\n * owner from it).\n *\n * Unlike `submit`, EVERY HTTP status resolves: the result is the raw `{ httpStatus, body }`,\n * because shadow failures are classified from the status together with the body's `code`\n * (`SHADOW_UNAVAILABLE`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);\n * see `readShadowSubmitOutcome`. Only a failure to get an answer rejects, and it rejects with\n * `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` `'timeout'` or `'transport'`): the request may\n * have been accepted. Every error it throws has `error.shadow === true`, and a non-SDK object\n * that escapes (your requestor's own rejection) answers `isShadowError(error)`.\n *\n * @example\n * ```ts\n * const result = await gateway.submitShadow('RequestTrade', signedDto, { walletAddress });\n * const outcome = readShadowSubmitOutcome('RequestTrade', signedDto, result);\n * ```\n */\n public async submitShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n return shadowFailures(() => this.sendShadow(method, signedBody, options));\n }\n\n private async sendShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const walletAddress = options?.walletAddress ?? this.walletAddress;\n if (walletAddress === undefined) {\n throw new GSwapSDKError('SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS', {});\n }\n // Header order is frontend_v2's: X-Wallet-Address, then X-Shadow.\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: { 'X-Wallet-Address': walletAddress, 'X-Shadow': 'true' },\n });\n const { response, body } = await this.post(method, this.writeUrl(method), headers, signedBody);\n return { httpStatus: response.status, body };\n }\n\n private writeUrl(method: string): string {\n return `${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${method}`;\n }\n\n /**\n * POSTs a signed body and reads the answer. Neither a timeout nor a transport failure proves the\n * write was not submitted, so both are `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` says which),\n * never a retryable read failure. A rejection that is an answer (see `isTransportFailure`) is\n * rethrown unchanged.\n */\n private async post(\n method: string,\n url: string,\n headers: Record<string, string>,\n signedBody: Record<string, unknown>,\n ): Promise<{ response: HTTPResponse; body: unknown }> {\n // Serialized BEFORE the request is attempted and outside the try below: a body that cannot be\n // serialized (a cycle, a BigInt) was never sent, so it must not be mistaken for a transport\n // failure the app's `isTransportFailure` might claim, which would call it \"maybe queued\".\n let payload: string;\n try {\n payload = JSON.stringify(signedBody);\n } catch (cause: unknown) {\n throw new GSwapSDKError('SIGNING_FAILED', { method, reason: 'failed' }, { cause });\n }\n const outcomeUnknown = (\n reason: SubmissionOutcomeUnknownReason,\n cause: unknown,\n ): GSwapSDKError<'SUBMISSION_OUTCOME_UNKNOWN'> =>\n new GSwapSDKError(\n 'SUBMISSION_OUTCOME_UNKNOWN',\n { reason },\n { uniqueKey: getStringProperty(signedBody, 'uniqueKey') ?? '', url, cause },\n );\n let response: HTTPResponse;\n try {\n response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers,\n body: payload,\n },\n this.chainCallTimeoutMs,\n );\n } catch (error: unknown) {\n if (isGSwapError(error, 'REQUEST_TIMEOUT')) throw outcomeUnknown('timeout', error);\n if (isGSwapError(error, 'TRANSPORT_ERROR') || this.isTransportRejection(error)) {\n throw outcomeUnknown('transport', error);\n }\n // A rejection that IS an HTTP answer (the app's interceptor rejecting on a non-2xx, a\n // version wall) is handled exactly as the answer would have been, so the app does not\n // rebuild the SDK's error from it. Anything else the app's requestor threw reaches the\n // caller unchanged.\n const answered = this.answerOfRejection(error);\n if (answered !== undefined) return answered;\n throw error;\n }\n try {\n return { response, body: await readResponseBody(response) };\n } catch (error: unknown) {\n // The answer's headers arrived but its body broke off: the status alone does not say what\n // the gateway did with the write.\n throw outcomeUnknown('transport', error);\n }\n }\n\n /**\n * The HTTP answer a rejection of the app's requestor stands for, as the response the gateway\n * would have read. `undefined` when the app named none, when its hook throws, or when what it\n * returned is not an HTTP status; then the rejection is not an answer.\n */\n private answerOfRejection(error: unknown): { response: HTTPResponse; body: unknown } | undefined {\n let answer: RejectedAnswer | undefined;\n try {\n answer = this.answerOfRejectionHook?.(error);\n } catch {\n return undefined;\n }\n if (answer === undefined) return undefined;\n const { status, body, headers } = answer;\n if (!Number.isInteger(status) || status < 100 || status > 599) return undefined;\n const text = typeof body === 'string' ? body : '';\n const response: HTTPResponse = {\n ok: status >= 200 && status < 300,\n status,\n json: async () => body,\n text: async () => text,\n headers: headers ?? {},\n };\n return { response, body };\n }\n\n private isTransportRejection(error: unknown): boolean {\n try {\n return this.isTransportFailure?.(error) === true;\n } catch {\n return false;\n }\n }\n\n /** Expose the requestor for sibling read services that share this gateway transport. */\n public get httpRequestor(): HttpRequestor {\n return this.requestor;\n }\n}\n\nfunction trimTrailingSlash(value: string): string {\n return value.replace(/\\/$/u, '');\n}\n\nfunction responseContext(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey?: string,\n): GSwapErrorContext {\n return {\n status: response.status,\n body,\n url,\n ...(uniqueKey === undefined || uniqueKey === '' ? {} : { uniqueKey }),\n };\n}\n\n/**\n * A queued RequestTrade acknowledgement is a swap only if it names the exact key that was signed:\n * the key is the only handle `confirm()` and every recovery path have on the trade, so an\n * acknowledgement without it (or with another) proves nothing about THIS request. Fails closed:\n * an absent echo is as unacceptable as a wrong one. The code is `MISSING_UNIQUE_KEY` or\n * `UNIQUE_KEY_MISMATCH`, `error.uniqueKey` the signed key.\n *\n * Only RequestTrade is checked: a synchronous write is proven by its own executed chain result,\n * and the apps never required an echo for it.\n */\nfunction assertQueuedUnderSignedKey(\n response: HTTPResponse,\n body: unknown,\n url: string,\n data: Record<string, unknown>,\n signedBody: Record<string, unknown>,\n): void {\n const signedUniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const echoed = data['uniqueKey'];\n if (typeof echoed === 'string' && echoed !== '' && echoed === signedUniqueKey) return;\n const missing = echoed === undefined || echoed === null || echoed === '';\n const context: GSwapErrorContext = {\n ...responseContext(response, body, url),\n uniqueKey: signedUniqueKey,\n };\n throw missing\n ? new GSwapSDKError('MISSING_UNIQUE_KEY', {}, context)\n : new GSwapSDKError('UNIQUE_KEY_MISMATCH', {}, context);\n}\n\nfunction gatewayError(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey: string,\n): GSwapSDKError {\n // The version wall is decided by the status alone, whatever the body names: nothing was queued.\n if (response.status === UPDATE_REQUIRED_STATUS) {\n return new GSwapSDKError(\n 'UPDATE_REQUIRED',\n { status: response.status },\n responseContext(response, body, url, uniqueKey),\n );\n }\n const object = asRecord(body);\n const nested = getObjectProperty(body, 'error');\n const code =\n getStringProperty(object, 'code') ??\n getStringProperty(nested, 'code') ??\n getStringProperty(nested, 'ErrorKey') ??\n 'HTTP_ERROR';\n // Missing server text is an empty param, never SDK-written English standing in for it. A body\n // that is not JSON (an HTML 502 page, a WAF block) is kept as error.bodyText.\n const message = serverMessageOfBody(body);\n const retryAfterMs = response.status === 429 ? readRetryAfter(response) : undefined;\n if (code === 'HTTP_ERROR') {\n return new GSwapSDKError(\n 'HTTP_ERROR',\n { status: response.status, url, serverMessage: message },\n responseContext(response, body, url, uniqueKey),\n );\n }\n return GSwapSDKError.fromGatewayBounce(\n code,\n message,\n response.status,\n body,\n url,\n retryAfterMs,\n uniqueKey === '' ? undefined : uniqueKey,\n );\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction isBlockNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gateway.js","names":["_defineProperty","ChainGateway","trimTrailingSlash","options","fetchRequestor","validateTimeoutMs","method","GSwapSDKError","url","walletAddress","headers","buildRequestHeaders","signedBody","uniqueKey","getStringProperty","context","responseContext","response","body","gatewayError","envelope","asRecord","\"error\"","serverMessageOfBody","data","\"data\"","\"Data\"","transactionId","mode","rawTransactionId","\"transactionId\"","bodyBlockNumber","\"blockNumber\"","invalidMode","isBlockNumber","assertQueuedUnderSignedKey","embeddedResult","\"result\"","resultStatus","\"Status\"","headerTransactionId","readHeader","resolvedTransactionId","blockNumber","readBlockNumberHeader","SubmittedTransaction","shadowFailures","payload","cause","outcomeUnknown","requestWithTimeout","error","isGSwapError","answered","readResponseBody","answer","status","text","value","signedUniqueKey","echoed","\"uniqueKey\"","missing","object","nested","getObjectProperty","code","message","retryAfterMs","readRetryAfter"],"sources":["../../../src/classes/gateway.ts"],"sourcesContent":["import {\n buildRequestHeaders,\n fetchRequestor,\n readBlockNumberHeader,\n readHeader,\n readResponseBody,\n readRetryAfter,\n requestWithTimeout,\n validateTimeoutMs,\n type GalaErrorContext,\n type HttpRequestor,\n type HTTPResponse,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport {\n getObjectProperty,\n getStringProperty,\n GSwapSDKError,\n isGSwapError,\n UPDATE_REQUIRED_STATUS,\n} from './gswap_sdk_error.js';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport { shadowFailures } from '../utils/shadow_errors.js';\nimport type { SubmissionOutcomeUnknownReason } from './gswap_error_catalog.js';\nimport type { ShadowSubmitResult } from './shadow_submit.js';\nimport { SubmittedTransaction, type PositionConfirmationResult } from './submitted_transaction.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\n\n/** Options for a chain-gateway client. */\nexport interface ChainGatewayOptions {\n dexBackendBaseUrl: string;\n httpRequestor?: HttpRequestor | undefined;\n walletAddress?: string | undefined;\n /**\n * Timeout of every gateway request in milliseconds (default 30 000); also the per-read timeout\n * of the services built on this gateway and of `confirm()`. `Infinity` arms no timer, for an\n * app whose HTTP stack owns request lifetimes.\n */\n chainCallTimeoutMs?: number | undefined;\n /**\n * Wire format of every request of this gateway and of the services built on it: the headers\n * (`userAgent`, `headers`) of reads AND of the POSTs that submit writes, and the query encoding\n * of reads. `X-Wallet-Address` and `X-Shadow` always win over a same-named `wire.headers` entry.\n */\n wire?: WireOptions | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` mean \"no HTTP answer arrived\" (the\n * connection failed, was reset or dropped), as opposed to an answer your requestor turned into\n * an error (an interceptor that rejects on a 4xx, a version wall). Used only when submitting a\n * write: a rejection it accepts becomes `SUBMISSION_OUTCOME_UNKNOWN` with `reason: 'transport'`\n * (the request may have been queued; the original error is `cause`), and any other rejection\n * reaches the caller unchanged. The SDK's own `TRANSPORT_ERROR` (the default `fetch` requestor,\n * `httpRequestorFromAxios`) always counts, so this is only for requestors that reject with\n * their own errors. Never throw from it; a throw is treated as \"not a transport failure\".\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: galaFetch, // a fetch wrapper: its TypeError is the network failing\n * isTransportFailure: (error) => error instanceof TypeError,\n * });\n * ```\n */\n isTransportFailure?: ((error: unknown) => boolean) | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` are an HTTP ANSWER, and what the\n * answer was: a requestor built on an HTTP client that rejects every non-2xx (an interceptor\n * that throws on a 4xx, a version wall that throws on a 426) loses the answer the SDK reads\n * errors from. Return `{ status, body }` (the parsed JSON, or the raw text; `headers` for\n * `Retry-After`) for such a rejection and the write is handled exactly as if the requestor had\n * resolved that answer: the gateway's own code becomes its catalogued error\n * (`DTO_INVALID`, `RATE_LIMITED`, `CHAIN_DISPATCH_FAILED`, ...), an uncoded body `HTTP_ERROR`,\n * both carrying the signed `uniqueKey` and classified by `classifyFailure` as a write. Return\n * `undefined` for any other rejection: it reaches the caller unchanged. Used only when\n * submitting a write; `isTransportFailure` is asked first (no answer proves nothing, so\n * \"maybe queued\" wins), and a throw from this hook, or a `status` outside 100-599, means \"not an\n * answer\". Never throw from it.\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: httpRequestorFromAxios(instance, { rejectOnHttpError: true }),\n * answerOfRejection: (error) =>\n * error instanceof GatewayError && error.status !== undefined\n * ? { status: error.status, body: error.data }\n * : undefined,\n * });\n * ```\n */\n answerOfRejection?: ((error: unknown) => RejectedAnswer | undefined) | undefined;\n}\n\n/** The HTTP answer a rejection of the app's requestor stands for (see `ChainGatewayOptions.answerOfRejection`). */\nexport interface RejectedAnswer {\n /** The HTTP status of the answer (100-599). */\n status: number;\n /** The answer's body: parsed JSON when it was JSON, else the raw text. */\n body: unknown;\n /** The answer's headers, for `Retry-After`. */\n headers?: Record<string, string | undefined> | undefined;\n}\n\n/** Optional attribution and operation-specific confirmation hooks for a write. */\nexport interface ChainSubmitOptions {\n walletAddress?: string | undefined;\n positionConfirmation?: ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n}\n\n/** Thin client for backend-routed v2 writes: synchronous liquidity writes and queued RequestTrade. */\nexport class ChainGateway {\n private readonly requestor: HttpRequestor;\n private readonly walletAddress: string | undefined;\n private readonly chainCallTimeoutMs: number;\n private readonly isTransportFailure: ((error: unknown) => boolean) | undefined;\n private readonly answerOfRejectionHook:\n ((error: unknown) => RejectedAnswer | undefined) | undefined;\n /** The request timeout in milliseconds (`Infinity` when no timer is armed). */\n public readonly requestTimeoutMs: number;\n /** The swap backend base URL every request is sent to, without a trailing slash. */\n public readonly dexBackendBaseUrl: string;\n /** Wire format shared by the read services built on this gateway. */\n public readonly wire: WireOptions;\n\n /** Create a chain gateway client. */\n constructor(options: ChainGatewayOptions) {\n this.dexBackendBaseUrl = trimTrailingSlash(options.dexBackendBaseUrl);\n this.requestor = options.httpRequestor ?? fetchRequestor;\n this.walletAddress = options.walletAddress;\n this.chainCallTimeoutMs = validateTimeoutMs(\n options.chainCallTimeoutMs ?? 30_000,\n 'chainCallTimeoutMs',\n );\n this.requestTimeoutMs = this.chainCallTimeoutMs;\n this.wire = options.wire ?? {};\n this.isTransportFailure = options.isTransportFailure;\n this.answerOfRejectionHook = options.answerOfRejection;\n }\n\n /**\n * Submit a signed v2 DTO through the chain gateway.\n *\n * @throws GSwapSDKError `SUBMISSION_OUTCOME_UNKNOWN` when no answer was read: `params.reason` is\n * `'timeout'` (the POST exceeded `chainCallTimeoutMs`) or `'transport'` (the connection failed\n * or broke off). Either way the write MAY have been queued: keep `error.uniqueKey` and confirm\n * it. Whether to offer the user a Retry (a NEW request under a fresh key) is the app's policy;\n * the SDK states only that the outcome is unknown. Reads keep `TRANSPORT_ERROR`.\n */\n public async submit(\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<AppliedTrade>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<Position | null>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction> {\n // The synchronous swap was removed from the contract and from this SDK. This is the only\n // place the retired name may appear in the write path; the class guard in\n // tests/foundation.test.ts pins that nothing signs or submits it.\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const url = this.writeUrl(method);\n const walletAddress = options?.walletAddress ?? this.walletAddress;\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: walletAddress === undefined ? {} : { 'X-Wallet-Address': walletAddress },\n });\n const { response, body } = await this.post(method, url, headers, signedBody);\n // Every failure after an answer names the write it is about, so an app can confirm it and a\n // failure classifier can tell a write's HTTP failure from a read's.\n const uniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const context = responseContext(response, body, url, uniqueKey);\n\n if (!response.ok) {\n throw gatewayError(response, body, url, uniqueKey);\n }\n\n const envelope = asRecord(body);\n // `error: true` is the gateway refusing the write, even inside a 2xx. It is never a transaction.\n if (envelope?.['error'] === true) {\n throw new GSwapSDKError(\n 'GATEWAY_REPORTED_ERROR',\n { serverMessage: serverMessageOfBody(envelope) },\n context,\n );\n }\n const data = asRecord(envelope?.['data'] ?? envelope?.['Data']);\n if (data === undefined) {\n throw new GSwapSDKError('GATEWAY_DATA_MISSING', {}, context);\n }\n\n const transactionId = getStringProperty(data, 'transactionId');\n const mode = getStringProperty(data, 'mode');\n const rawTransactionId = data['transactionId'];\n const bodyBlockNumber = data['blockNumber'];\n const invalidMode = (): GSwapSDKError<'GATEWAY_MODE_INVALID'> =>\n new GSwapSDKError('GATEWAY_MODE_INVALID', {}, context);\n if (mode !== 'sync' && mode !== 'queued') {\n throw invalidMode();\n }\n if (\n ('transactionId' in data && typeof rawTransactionId !== 'string') ||\n (bodyBlockNumber !== undefined && bodyBlockNumber !== null && !isBlockNumber(bodyBlockNumber))\n ) {\n throw invalidMode();\n }\n if (method === 'RequestTrade' && mode === 'sync') {\n throw new GSwapSDKError('GATEWAY_SYNC_REQUEST_TRADE', {}, context);\n }\n if (method === 'RequestTrade' && mode === 'queued') {\n assertQueuedUnderSignedKey(response, body, url, data, signedBody);\n } else if (mode === 'queued' || !('result' in data)) {\n throw invalidMode();\n }\n\n // Only synchronous writes carry an executed chain result in the gateway response.\n if (mode === 'sync') {\n const embeddedResult = asRecord(data['result']);\n if (embeddedResult !== undefined) {\n const resultStatus = embeddedResult['Status'];\n if (resultStatus !== undefined && resultStatus !== 1) {\n throw GSwapSDKError.fromChainError(\n getStringProperty(embeddedResult, 'ErrorKey') ?? 'CHAIN_ERROR',\n getStringProperty(embeddedResult, 'Message') ?? '',\n context,\n );\n }\n }\n }\n\n const headerTransactionId = readHeader(response, 'x-transaction-id');\n const resolvedTransactionId =\n transactionId === undefined || transactionId === '' ? headerTransactionId : transactionId;\n const blockNumber: number | undefined =\n bodyBlockNumber === null || bodyBlockNumber === undefined\n ? readBlockNumberHeader(response)\n : isBlockNumber(bodyBlockNumber)\n ? bodyBlockNumber\n : undefined;\n return new SubmittedTransaction({\n method,\n uniqueKey,\n transactionId:\n resolvedTransactionId === undefined || resolvedTransactionId === ''\n ? null\n : resolvedTransactionId,\n blockNumber: blockNumber ?? null,\n mode,\n result: mode === 'queued' ? undefined : data['result'],\n envelope: body,\n dexBackendBaseUrl: this.dexBackendBaseUrl,\n httpRequestor: this.requestor,\n requestTimeoutMs: this.chainCallTimeoutMs,\n wire: this.wire,\n ...(options?.positionConfirmation === undefined\n ? {}\n : { positionConfirmation: options.positionConfirmation }),\n });\n }\n\n /**\n * Submit a signed v2 DTO as a SHADOW (dark) write: the same route and body as {@link submit},\n * plus `X-Wallet-Address` and `X-Shadow: true`, so defi-backend marks the transaction private\n * before it reaches the contract. The wallet address is required (the backend resolves the\n * owner from it).\n *\n * Unlike `submit`, EVERY HTTP status resolves: the result is the raw `{ httpStatus, body }`,\n * because shadow failures are classified from the status together with the body's `code`\n * (`SHADOW_UNAVAILABLE`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);\n * see `readShadowSubmitOutcome`. Only a failure to get an answer rejects, and it rejects with\n * `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` `'timeout'` or `'transport'`): the request may\n * have been accepted. Every error it throws has `error.shadow === true`, and a non-SDK object\n * that escapes (your requestor's own rejection) answers `isShadowError(error)`.\n *\n * @example\n * ```ts\n * const result = await gateway.submitShadow('RequestTrade', signedDto, { walletAddress });\n * const outcome = readShadowSubmitOutcome('RequestTrade', signedDto, result);\n * ```\n */\n public async submitShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n return shadowFailures(() => this.sendShadow(method, signedBody, options));\n }\n\n private async sendShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const walletAddress = options?.walletAddress ?? this.walletAddress;\n if (walletAddress === undefined) {\n throw new GSwapSDKError('SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS', {});\n }\n // Header order is frontend_v2's: X-Wallet-Address, then X-Shadow.\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: { 'X-Wallet-Address': walletAddress, 'X-Shadow': 'true' },\n });\n const { response, body } = await this.post(method, this.writeUrl(method), headers, signedBody);\n return { httpStatus: response.status, body };\n }\n\n private writeUrl(method: string): string {\n return `${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${method}`;\n }\n\n /**\n * POSTs a signed body and reads the answer. Neither a timeout nor a transport failure proves the\n * write was not submitted, so both are `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` says which),\n * never a retryable read failure. A rejection that is an answer (see `isTransportFailure`) is\n * rethrown unchanged.\n */\n private async post(\n method: string,\n url: string,\n headers: Record<string, string>,\n signedBody: Record<string, unknown>,\n ): Promise<{ response: HTTPResponse; body: unknown }> {\n // Serialized BEFORE the request is attempted and outside the try below: a body that cannot be\n // serialized (a cycle, a BigInt) was never sent, so it must not be mistaken for a transport\n // failure the app's `isTransportFailure` might claim, which would call it \"maybe queued\".\n let payload: string;\n try {\n payload = JSON.stringify(signedBody);\n } catch (cause: unknown) {\n throw new GSwapSDKError('SIGNING_FAILED', { method, reason: 'failed' }, { cause });\n }\n const outcomeUnknown = (\n reason: SubmissionOutcomeUnknownReason,\n cause: unknown,\n ): GSwapSDKError<'SUBMISSION_OUTCOME_UNKNOWN'> =>\n new GSwapSDKError(\n 'SUBMISSION_OUTCOME_UNKNOWN',\n { reason },\n { uniqueKey: getStringProperty(signedBody, 'uniqueKey') ?? '', url, cause },\n );\n let response: HTTPResponse;\n try {\n response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers,\n body: payload,\n },\n this.chainCallTimeoutMs,\n );\n } catch (error: unknown) {\n if (isGSwapError(error, 'REQUEST_TIMEOUT')) throw outcomeUnknown('timeout', error);\n if (isGSwapError(error, 'TRANSPORT_ERROR') || this.isTransportRejection(error)) {\n throw outcomeUnknown('transport', error);\n }\n // A rejection that IS an HTTP answer (the app's interceptor rejecting on a non-2xx, a\n // version wall) is handled exactly as the answer would have been, so the app does not\n // rebuild the SDK's error from it. Anything else the app's requestor threw reaches the\n // caller unchanged.\n const answered = this.answerOfRejection(error);\n if (answered !== undefined) return answered;\n throw error;\n }\n try {\n return { response, body: await readResponseBody(response) };\n } catch (error: unknown) {\n // The answer's headers arrived but its body broke off: the status alone does not say what\n // the gateway did with the write.\n throw outcomeUnknown('transport', error);\n }\n }\n\n /**\n * The HTTP answer a rejection of the app's requestor stands for, as the response the gateway\n * would have read. `undefined` when the app named none, when its hook throws, or when what it\n * returned is not an HTTP status; then the rejection is not an answer.\n */\n private answerOfRejection(error: unknown): { response: HTTPResponse; body: unknown } | undefined {\n let answer: RejectedAnswer | undefined;\n try {\n answer = this.answerOfRejectionHook?.(error);\n } catch {\n return undefined;\n }\n if (answer === undefined) return undefined;\n const { status, body, headers } = answer;\n if (!Number.isInteger(status) || status < 100 || status > 599) return undefined;\n const text = typeof body === 'string' ? body : '';\n const response: HTTPResponse = {\n ok: status >= 200 && status < 300,\n status,\n json: async () => body,\n text: async () => text,\n headers: headers ?? {},\n };\n return { response, body };\n }\n\n private isTransportRejection(error: unknown): boolean {\n try {\n return this.isTransportFailure?.(error) === true;\n } catch {\n return false;\n }\n }\n\n /** Expose the requestor for sibling read services that share this gateway transport. */\n public get httpRequestor(): HttpRequestor {\n return this.requestor;\n }\n}\n\nfunction trimTrailingSlash(value: string): string {\n return value.replace(/\\/$/u, '');\n}\n\nfunction responseContext(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey?: string,\n): GalaErrorContext {\n return {\n status: response.status,\n body,\n url,\n ...(uniqueKey === undefined || uniqueKey === '' ? {} : { uniqueKey }),\n };\n}\n\n/**\n * A queued RequestTrade acknowledgement is a swap only if it names the exact key that was signed:\n * the key is the only handle `confirm()` and every recovery path have on the trade, so an\n * acknowledgement without it (or with another) proves nothing about THIS request. Fails closed:\n * an absent echo is as unacceptable as a wrong one. The code is `MISSING_UNIQUE_KEY` or\n * `UNIQUE_KEY_MISMATCH`, `error.uniqueKey` the signed key.\n *\n * Only RequestTrade is checked: a synchronous write is proven by its own executed chain result,\n * and the apps never required an echo for it.\n */\nfunction assertQueuedUnderSignedKey(\n response: HTTPResponse,\n body: unknown,\n url: string,\n data: Record<string, unknown>,\n signedBody: Record<string, unknown>,\n): void {\n const signedUniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const echoed = data['uniqueKey'];\n if (typeof echoed === 'string' && echoed !== '' && echoed === signedUniqueKey) return;\n const missing = echoed === undefined || echoed === null || echoed === '';\n const context: GalaErrorContext = {\n ...responseContext(response, body, url),\n uniqueKey: signedUniqueKey,\n };\n throw missing\n ? new GSwapSDKError('MISSING_UNIQUE_KEY', {}, context)\n : new GSwapSDKError('UNIQUE_KEY_MISMATCH', {}, context);\n}\n\nfunction gatewayError(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey: string,\n): GSwapSDKError {\n // The version wall is decided by the status alone, whatever the body names: nothing was queued.\n if (response.status === UPDATE_REQUIRED_STATUS) {\n return new GSwapSDKError(\n 'UPDATE_REQUIRED',\n { status: response.status },\n responseContext(response, body, url, uniqueKey),\n );\n }\n const object = asRecord(body);\n const nested = getObjectProperty(body, 'error');\n const code =\n getStringProperty(object, 'code') ??\n getStringProperty(nested, 'code') ??\n getStringProperty(nested, 'ErrorKey') ??\n 'HTTP_ERROR';\n // Missing server text is an empty param, never SDK-written English standing in for it. A body\n // that is not JSON (an HTML 502 page, a WAF block) is kept as error.bodyText.\n const message = serverMessageOfBody(body);\n const retryAfterMs = response.status === 429 ? readRetryAfter(response) : undefined;\n if (code === 'HTTP_ERROR') {\n return new GSwapSDKError(\n 'HTTP_ERROR',\n { status: response.status, url, serverMessage: message },\n responseContext(response, body, url, uniqueKey),\n );\n }\n return GSwapSDKError.fromGatewayBounce(\n code,\n message,\n response.status,\n body,\n url,\n retryAfterMs,\n uniqueKey === '' ? undefined : uniqueKey,\n );\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction isBlockNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import e from"../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{GSWAP_ENVIRONMENTS as n}from"../types/env.js";import{debugLog as r}from"../utils/debug.js";import{ReconnectionBackoff as i}from"../utils/reconnection.js";const a=`gdex.jsonrpc.v1`,o=[`add`,`remove`,`collect`];function s(e){let{pool:t}=e;return(e.version===`v1`||e.version===`v2`)&&typeof t==`object`&&!!t&&typeof e.poolHash==`string`&&typeof e.transactionId==`string`&&o.includes(e.action)&&typeof e.owner==`string`&&typeof e.amount0==`string`&&typeof e.amount1==`string`&&typeof e.blockNumber==`number`&&typeof e.timestamp==`string`}var c=class extends Error{constructor(t,n,r){super(n),e(this,`code`,void 0),e(this,`data`,void 0),this.name=`GdexStreamError`,this.code=t,r!==void 0&&(this.data=r)}};function l(e){let t=typeof e==`object`&&e?e.subscriptionId:void 0;if(typeof t!=`string`)throw new c(-32603,`GDEX subscribe response is missing its subscriptionId`);return t}var u=class{constructor(r={}){e(this,`url`,void 0),e(this,`requestTimeoutMs`,void 0),e(this,`apiKey`,void 0),e(this,`webSocketConstructor`,void 0),e(this,`backoff`,void 0),e(this,`socket`,void 0),e(this,`connectPromise`,void 0),e(this,`nextRequestId`,0),e(this,`pending`,/* @__PURE__ */ new Map),e(this,`subscriptionsByServerId`,/* @__PURE__ */ new Map),e(this,`activeSubscriptions`,/* @__PURE__ */ new Set),e(this,`intentionalClose`,!1),e(this,`reconnecting`,!1),e(this,`reconnectTimer`,void 0),e(this,`reconnectDelayResolve`,void 0),this.url=r.url??n.prod.dexBackendWsUrl,this.requestTimeoutMs=r.requestTimeoutMs??15e3,this.backoff=new i({maxAttempts:r.reconnectAttempts??5,baseDelayMs:r.reconnectDelayMs??2e3});let a=r.webSocketImpl??globalThis.WebSocket;if(typeof a!=`function`)throw new t(`STREAM_WEBSOCKET_UNAVAILABLE`,{});if(this.webSocketConstructor=a,r.apiKey!==void 0){if(r.apiKey===``||r.webSocketImpl===void 0)throw new t(`STREAM_API_KEY_UNUSABLE`,{});this.apiKey=r.apiKey}}connect(){return this.isConnected()?Promise.resolve():this.connectPromise?this.connectPromise:(this.intentionalClose=!1,this.clearReconnectTimer(),this.connectPromise=this.openSocket(),this.connectPromise)}disconnect(){this.intentionalClose=!0,this.reconnecting=!1,this.clearReconnectTimer(),this.rejectPending(new t(`STREAM_DISCONNECTED`,{}));let e=this.socket;this.socket=void 0,this.connectPromise=void 0,e?.close(1e3,`client disconnect`)}isConnected(){return this.socket?.readyState===1}request(e,t){return this.send(e,t)}send(e,n,r){if(!this.isConnected()||!this.socket)return Promise.reject(new t(`STREAM_NOT_CONNECTED`,{}));let i=++this.nextRequestId,a={jsonrpc:`2.0`,id:i,method:e};return n!==void 0&&(a.params=n),new Promise((n,o)=>{let s=setTimeout(()=>{this.pending.delete(i),o(new t(`STREAM_REQUEST_TIMEOUT`,{method:e,timeoutMs:this.requestTimeoutMs}))},this.requestTimeoutMs);this.pending.set(i,{resolve:e=>n(e),reject:o,timeout:s,onResult:r});try{this.socket?.send(JSON.stringify(a))}catch(e){clearTimeout(s),this.pending.delete(i),o(e instanceof Error?e:Error(String(e)))}})}serverInfo(){return this.request(`gdex_serverInfo`)}ping(){return this.request(`gdex_ping`)}getPool(e){return this.request(`gdex_getPool`,e)}getBalance(e,t){return this.request(`gdex_getBalance`,t===void 0?{owner:e}:{owner:e,tokenClassKey:t})}getPositions(e){return this.request(`gdex_getPositions`,e)}getBlockHeight(){return this.request(`gdex_getBlockHeight`)}quote(e){return this.request(`gdex_quote`,e)}getToken(e){return this.request(`gdex_getToken`,{tokenClassKey:e})}subscribeSwaps(e,t={}){return this.subscribe(`swap`,e,t)}subscribePool(e,t,n={}){return this.subscribe(`pool`,t,{...e,...n})}subscribeBalances(e,t,n={}){return this.subscribe(`balance`,t,{owner:e,...n})}subscribePoolCreated(e,t={}){return this.subscribe(`poolCreated`,e,t)}subscribeLiquidity(e,t={}){return this.subscribe(`liquidity`,t=>{s(t)?e(t):r(`Ignoring a malformed liquidity event from the GDEX stream`)},t)}subscribeBlocks(e,t={}){return this.subscribe(`blocks`,e,t)}openSocket(){return new Promise((e,n)=>{let i=!1,o=this.apiKey===void 0?new this.webSocketConstructor(this.url,a):new this.webSocketConstructor(this.url,a,{headers:{"x-api-key":this.apiKey}});this.socket=o,o.onopen=()=>{this.socket===o&&(i=!0,this.connectPromise=void 0,this.reconnecting||this.backoff.reset(),r(`Connected to GDEX stream`),e())},o.onmessage=e=>this.handleMessage(e.data),o.onerror=()=>{i||n(new t(`STREAM_CONNECT_FAILED`,{url:this.url}))},o.onclose=e=>{this.socket===o&&(this.socket=void 0,this.connectPromise=void 0,i||n(new t(`STREAM_CLOSED_BEFORE_CONNECT`,{closeCode:e.code??0})),this.rejectPending(new t(`STREAM_CONNECTION_CLOSED`,{closeCode:e.code??0})),!this.intentionalClose&&!this.reconnecting&&this.startReconnectLoop())}})}handleMessage(e){if(typeof e!=`string`){r(`Ignoring non-text GDEX WebSocket frame`);return}let t;try{t=JSON.parse(e)}catch{r(`Ignoring invalid JSON from GDEX stream`);return}if(typeof t.id==`number`){let e=this.pending.get(t.id);if(!e)return;if(clearTimeout(e.timeout),this.pending.delete(t.id),t.error){let n=typeof t.error.code==`number`?t.error.code:-32603,r=typeof t.error.message==`string`?t.error.message:`GDEX request failed`;e.reject(new c(n,r,t.error.data))}else{try{e.onResult?.(t.result)}catch(t){e.reject(t instanceof Error?t:Error(String(t)));return}e.resolve(t.result)}return}if(t.method!==`gdex_subscription`||!this.isRecord(t.params))return;let n=t.params.subscription,i=t.params.result;if(typeof n!=`string`||!this.isRecord(i))return;let a=this.subscriptionsByServerId.get(n);if(a?.active)try{a.callback(i)}catch(e){r(`GDEX subscription callback failed`,e)}}async subscribe(e,t,n){let r={channel:e,...n},i={subscriptionId:``,unsubscribe:async()=>this.unsubscribe(a)},a={serverId:``,params:r,callback:t,handle:i,active:!0};return await this.send(`gdex_subscribe`,r,e=>{let t=l(e);a.serverId=t,i.subscriptionId=t,this.activeSubscriptions.add(a),this.subscriptionsByServerId.set(t,a)}),i}async unsubscribe(e){e.active&&(e.active=!1,this.activeSubscriptions.delete(e),this.subscriptionsByServerId.delete(e.serverId),this.isConnected()&&await this.request(`gdex_unsubscribe`,{subscriptionId:e.serverId}))}startReconnectLoop(){this.reconnecting||this.intentionalClose||(this.reconnecting=!0,this.reconnectLoop())}async reconnectLoop(){for(;!this.intentionalClose&&this.backoff.shouldRetry();){let e=this.backoff.nextDelayMs();if(this.backoff.recordAttempt(),r(`GDEX reconnect attempt ${this.backoff.attemptCount}/${this.backoff.maxAttempts} in ${e}ms`),await this.waitForReconnectDelay(e),this.intentionalClose)break;try{await this.openSocket(),await this.resubscribeAll(),this.backoff.reset(),this.reconnecting=!1;return}catch(e){r(`GDEX reconnect failed: ${e instanceof Error?e.message:String(e)}`)}}this.reconnecting=!1,this.intentionalClose||r(`GDEX reconnection attempts exhausted`)}async resubscribeAll(){this.subscriptionsByServerId.clear();for(let e of this.activeSubscriptions){if(!e.active)continue;let t={...e.params,snapshot:!0},n=await this.resubscribeWithRateLimitRetry(t,t=>{let n=l(t);e.active&&(e.serverId=n,e.handle.subscriptionId=n,this.subscriptionsByServerId.set(n,e))});e.active||await this.request(`gdex_unsubscribe`,{subscriptionId:n.subscriptionId})}}async resubscribeWithRateLimitRetry(e,t){for(let n=0;;n++)try{return await this.send(`gdex_subscribe`,e,t)}catch(e){if(!(e instanceof c)||e.code!==-32003||n>=5)throw e;let t=this.readRetryAfterMs(e.data);r(`GDEX resubscribe rate limited; retrying in ${t}ms`),await new Promise(e=>setTimeout(e,t))}}waitForReconnectDelay(e){return new Promise(t=>{this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=void 0,this.reconnectDelayResolve=void 0,t()},e),this.reconnectDelayResolve=t})}clearReconnectTimer(){this.reconnectTimer!==void 0&&clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0;let e=this.reconnectDelayResolve;this.reconnectDelayResolve=void 0,e?.()}rejectPending(e){for(let t of this.pending.values())clearTimeout(t.timeout),t.reject(e);this.pending.clear()}readRetryAfterMs(e){return!this.isRecord(e)||typeof e.retryAfterMs!=`number`||e.retryAfterMs<0?1e3:e.retryAfterMs}isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}};export{c as GdexStreamError,u as GdexStreamService,s as isGdexLiquidityEvent};
1
+ import e from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{GSWAP_ENVIRONMENTS as n}from"../types/env.js";import{debugLog as r}from"../utils/debug.js";import{ReconnectionBackoff as i}from"../utils/reconnection.js";const a=`gdex.jsonrpc.v1`,o=[`add`,`remove`,`collect`];function s(e){let{pool:t}=e;return(e.version===`v1`||e.version===`v2`)&&typeof t==`object`&&!!t&&typeof e.poolHash==`string`&&typeof e.transactionId==`string`&&o.includes(e.action)&&typeof e.owner==`string`&&typeof e.amount0==`string`&&typeof e.amount1==`string`&&typeof e.blockNumber==`number`&&typeof e.timestamp==`string`}var c=class extends Error{constructor(t,n,r){super(n),e(this,`code`,void 0),e(this,`data`,void 0),this.name=`GdexStreamError`,this.code=t,r!==void 0&&(this.data=r)}};function l(e){let t=typeof e==`object`&&e?e.subscriptionId:void 0;if(typeof t!=`string`)throw new c(-32603,`GDEX subscribe response is missing its subscriptionId`);return t}var u=class{constructor(r={}){e(this,`url`,void 0),e(this,`requestTimeoutMs`,void 0),e(this,`apiKey`,void 0),e(this,`webSocketConstructor`,void 0),e(this,`backoff`,void 0),e(this,`socket`,void 0),e(this,`connectPromise`,void 0),e(this,`nextRequestId`,0),e(this,`pending`,/* @__PURE__ */ new Map),e(this,`subscriptionsByServerId`,/* @__PURE__ */ new Map),e(this,`activeSubscriptions`,/* @__PURE__ */ new Set),e(this,`intentionalClose`,!1),e(this,`reconnecting`,!1),e(this,`reconnectTimer`,void 0),e(this,`reconnectDelayResolve`,void 0),this.url=r.url??n.prod.dexBackendWsUrl,this.requestTimeoutMs=r.requestTimeoutMs??15e3,this.backoff=new i({maxAttempts:r.reconnectAttempts??5,baseDelayMs:r.reconnectDelayMs??2e3});let a=r.webSocketImpl??globalThis.WebSocket;if(typeof a!=`function`)throw new t(`STREAM_WEBSOCKET_UNAVAILABLE`,{});if(this.webSocketConstructor=a,r.apiKey!==void 0){if(r.apiKey===``||r.webSocketImpl===void 0)throw new t(`STREAM_API_KEY_UNUSABLE`,{});this.apiKey=r.apiKey}}connect(){return this.isConnected()?Promise.resolve():(this.connectPromise||(this.intentionalClose=!1,this.clearReconnectTimer(),this.connectPromise=this.openSocket()),this.connectPromise)}disconnect(){this.intentionalClose=!0,this.reconnecting=!1,this.clearReconnectTimer(),this.rejectPending(new t(`STREAM_DISCONNECTED`,{}));let e=this.socket;this.socket=void 0,this.connectPromise=void 0,e?.close(1e3,`client disconnect`)}isConnected(){return this.socket?.readyState===1}request(e,t){return this.send(e,t)}send(e,n,r){if(!this.isConnected()||!this.socket)return Promise.reject(new t(`STREAM_NOT_CONNECTED`,{}));let i=++this.nextRequestId,a={jsonrpc:`2.0`,id:i,method:e};return n!==void 0&&(a.params=n),new Promise((n,o)=>{let s=setTimeout(()=>{this.pending.delete(i),o(new t(`STREAM_REQUEST_TIMEOUT`,{method:e,timeoutMs:this.requestTimeoutMs}))},this.requestTimeoutMs);this.pending.set(i,{resolve:e=>n(e),reject:o,timeout:s,onResult:r});try{this.socket?.send(JSON.stringify(a))}catch(e){clearTimeout(s),this.pending.delete(i),o(e instanceof Error?e:Error(String(e)))}})}serverInfo(){return this.request(`gdex_serverInfo`)}ping(){return this.request(`gdex_ping`)}getPool(e){return this.request(`gdex_getPool`,e)}getBalance(e,t){return this.request(`gdex_getBalance`,t===void 0?{owner:e}:{owner:e,tokenClassKey:t})}getPositions(e){return this.request(`gdex_getPositions`,e)}getBlockHeight(){return this.request(`gdex_getBlockHeight`)}quote(e){return this.request(`gdex_quote`,e)}getToken(e){return this.request(`gdex_getToken`,{tokenClassKey:e})}subscribeSwaps(e,t={}){return this.subscribe(`swap`,e,t)}subscribePool(e,t,n={}){return this.subscribe(`pool`,t,{...e,...n})}subscribeBalances(e,t,n={}){return this.subscribe(`balance`,t,{owner:e,...n})}subscribePoolCreated(e,t={}){return this.subscribe(`poolCreated`,e,t)}subscribeLiquidity(e,t={}){return this.subscribe(`liquidity`,t=>{s(t)?e(t):r(`Ignoring a malformed liquidity event from the GDEX stream`)},t)}subscribeBlocks(e,t={}){return this.subscribe(`blocks`,e,t)}openSocket(){return new Promise((e,n)=>{let i=!1,o=this.apiKey===void 0?new this.webSocketConstructor(this.url,a):new this.webSocketConstructor(this.url,a,{headers:{"x-api-key":this.apiKey}});this.socket=o,o.onopen=()=>{this.socket===o&&(i=!0,this.connectPromise=void 0,this.reconnecting||this.backoff.reset(),r(`Connected to GDEX stream`),e())},o.onmessage=e=>this.handleMessage(e.data),o.onerror=()=>{i||n(new t(`STREAM_CONNECT_FAILED`,{url:this.url}))},o.onclose=e=>{this.socket===o&&(this.socket=void 0,this.connectPromise=void 0,i||n(new t(`STREAM_CLOSED_BEFORE_CONNECT`,{closeCode:e.code??0})),this.rejectPending(new t(`STREAM_CONNECTION_CLOSED`,{closeCode:e.code??0})),!this.intentionalClose&&!this.reconnecting&&this.startReconnectLoop())}})}handleMessage(e){if(typeof e!=`string`){r(`Ignoring non-text GDEX WebSocket frame`);return}let t;try{t=JSON.parse(e)}catch{r(`Ignoring invalid JSON from GDEX stream`);return}if(typeof t.id==`number`){let e=this.pending.get(t.id);if(!e)return;if(clearTimeout(e.timeout),this.pending.delete(t.id),t.error){let n=typeof t.error.code==`number`?t.error.code:-32603,r=typeof t.error.message==`string`?t.error.message:`GDEX request failed`;e.reject(new c(n,r,t.error.data))}else{try{e.onResult?.(t.result)}catch(t){e.reject(t instanceof Error?t:Error(String(t)));return}e.resolve(t.result)}return}if(t.method!==`gdex_subscription`||!this.isRecord(t.params))return;let n=t.params.subscription,i=t.params.result;if(typeof n!=`string`||!this.isRecord(i))return;let a=this.subscriptionsByServerId.get(n);if(a?.active)try{a.callback(i)}catch(e){r(`GDEX subscription callback failed`,e)}}async subscribe(e,t,n){let r={channel:e,...n},i={subscriptionId:``,unsubscribe:async()=>this.unsubscribe(a)},a={serverId:``,params:r,callback:t,handle:i,active:!0};return await this.send(`gdex_subscribe`,r,e=>{let t=l(e);a.serverId=t,i.subscriptionId=t,this.activeSubscriptions.add(a),this.subscriptionsByServerId.set(t,a)}),i}async unsubscribe(e){e.active&&(e.active=!1,this.activeSubscriptions.delete(e),this.subscriptionsByServerId.delete(e.serverId),this.isConnected()&&await this.request(`gdex_unsubscribe`,{subscriptionId:e.serverId}))}startReconnectLoop(){this.reconnecting||this.intentionalClose||(this.reconnecting=!0,this.reconnectLoop())}async reconnectLoop(){for(;!this.intentionalClose&&this.backoff.shouldRetry();){let e=this.backoff.nextDelayMs();if(this.backoff.recordAttempt(),r(`GDEX reconnect attempt ${this.backoff.attemptCount}/${this.backoff.maxAttempts} in ${e}ms`),await this.waitForReconnectDelay(e),this.intentionalClose)break;try{await this.openSocket(),await this.resubscribeAll(),this.backoff.reset(),this.reconnecting=!1;return}catch(e){r(`GDEX reconnect failed: ${e instanceof Error?e.message:String(e)}`)}}this.reconnecting=!1,this.intentionalClose||r(`GDEX reconnection attempts exhausted`)}async resubscribeAll(){this.subscriptionsByServerId.clear();for(let e of this.activeSubscriptions){if(!e.active)continue;let t={...e.params,snapshot:!0},n=await this.resubscribeWithRateLimitRetry(t,t=>{let n=l(t);e.active&&(e.serverId=n,e.handle.subscriptionId=n,this.subscriptionsByServerId.set(n,e))});e.active||await this.request(`gdex_unsubscribe`,{subscriptionId:n.subscriptionId})}}async resubscribeWithRateLimitRetry(e,t){for(let n=0;;n++)try{return await this.send(`gdex_subscribe`,e,t)}catch(e){if(!(e instanceof c)||e.code!==-32003||n>=5)throw e;let t=this.readRetryAfterMs(e.data);r(`GDEX resubscribe rate limited; retrying in ${t}ms`),await new Promise(e=>setTimeout(e,t))}}waitForReconnectDelay(e){return new Promise(t=>{this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=void 0,this.reconnectDelayResolve=void 0,t()},e),this.reconnectDelayResolve=t})}clearReconnectTimer(){this.reconnectTimer!==void 0&&clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0;let e=this.reconnectDelayResolve;this.reconnectDelayResolve=void 0,e?.()}rejectPending(e){for(let t of this.pending.values())clearTimeout(t.timeout),t.reject(e);this.pending.clear()}readRetryAfterMs(e){return!this.isRecord(e)||typeof e.retryAfterMs!=`number`||e.retryAfterMs<0?1e3:e.retryAfterMs}isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}};export{c as GdexStreamError,u as GdexStreamService,s as isGdexLiquidityEvent};
2
2
  //# sourceMappingURL=gdex_stream.js.map