@gala-chain/gswap-sdk 2.0.0-rc.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,13 +24,11 @@ waiter, and EIP-712 is only an opt-in scheme of `BrowserWalletSigner`.
24
24
  ## Install
25
25
 
26
26
  ```bash
27
- npm install @gala-chain/gswap-sdk@next @gala-chain/gala-core-sdk@next
27
+ npm install @gala-chain/gswap-sdk @gala-chain/gala-core-sdk
28
28
  ```
29
29
 
30
- `@gala-chain/gala-core-sdk` is a peer dependency (range <!-- docs:var peer:@gala-chain/gala-core-sdk -->>=1.0.0-rc.7 <2<!-- /docs:var -->):
31
- install it next to the SDK. 2.0 is a release candidate under the `next`
32
- dist-tag; `latest` is still 1.2.0, so an install without `@next` gets 1.x.
33
- Pin exact versions for a wallet or app build.
30
+ `@gala-chain/gala-core-sdk` is a peer dependency (range <!-- docs:var peer:@gala-chain/gala-core-sdk -->^1.0.0<!-- /docs:var -->):
31
+ install it next to the SDK. Pin exact versions for a wallet or app build.
34
32
 
35
33
  ## 2.0: signing moved to @gala-chain/gala-core-sdk
36
34
 
@@ -49,6 +47,7 @@ see also [Migration from 0.x](./docs/other/migration-from-0.x.md).
49
47
  ## Quick start
50
48
 
51
49
  ```typescript
50
+ import BigNumber from 'bignumber.js'; // a dependency of the SDK; install it in your own app too
52
51
  import { GSwap } from '@gala-chain/gswap-sdk';
53
52
  import { PrivateKeySigner } from '@gala-chain/gala-core-sdk';
54
53
 
@@ -57,7 +56,9 @@ const gSwap = new GSwap({ signer, walletAddress: process.env.GALACHAIN_ADDRESS,
57
56
  const quote = await gSwap.quoting.quoteExactInput('GALA', 'GUSDC', '100');
58
57
  const tx = await gSwap.swaps.swap('GALA', 'GUSDC', quote.feeTier, {
59
58
  exactIn: '100',
60
- amountOutMinimum: quote.amountOut,
59
+ // The least you accept (1% under the quote), not the quote itself: the swap is applied a few
60
+ // seconds later and a bound equal to the quote is rejected whenever the price moves in between.
61
+ amountOutMinimum: new BigNumber(quote.amountOut).multipliedBy('0.99').toFixed(),
61
62
  });
62
63
  console.log({ mode: tx.mode, uniqueKey: tx.uniqueKey, transactionId: tx.transactionId });
63
64
  const applied = await tx.confirm();
@@ -65,7 +66,7 @@ console.log(applied.result);
65
66
  ```
66
67
 
67
68
  The `env: 'stage'` preset targets the staging swap backend, and `prod` targets
68
- the production swap backend. All SDK traffic uses the swap backend. Use class keys such as `GALA|Unit|none|none` when a symbol is not
69
+ the production swap backend (`prod` is also the default when `env` is omitted). All SDK traffic uses the swap backend. Use class keys such as `GALA|Unit|none|none` when a symbol is not
69
70
  available; the SDK resolves registered symbols and orders pool tokens for you.
70
71
  Every write returns a `SubmittedTransaction`. A swap acknowledgement has
71
72
  `mode === 'queued'`, `result === undefined`, and a durable `uniqueKey`; call
@@ -1 +1 @@
1
- {"version":3,"file":"onramper.js","names":["ONRAMPER_MODES","TEXT_FIELDS","AMOUNT_FIELDS","invalidField","GSwapSDKError","widgetBody","request","body","\"mode\"","field","value","widgetUrlOf","url","asEntryRecord","response","\"data\"","\"url\"","Onramper","dexBackendBaseUrl","httpClient","createOnramper","options","HttpClient"],"sources":["../../../src/classes/onramper.ts"],"sourcesContent":["import type { HttpRequestor, WireOptions } from '@gala-chain/gala-core-sdk';\nimport { asEntryRecord } from '../utils/lenient.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport { HttpClient } from './http_client.js';\n\n/** What the Onramper widget does. */\nexport const ONRAMPER_MODES = ['buy', 'sell', 'swap'] as const;\n\n/** One of {@link ONRAMPER_MODES}. */\nexport type OnramperMode = (typeof ONRAMPER_MODES)[number];\n\n/**\n * The request of {@link Onramper.generateWidgetUrl}: the fields of the swap backend's\n * `GenerateWidgetUrlDto`, no others (the backend refuses a field it does not know). A field left\n * out is the backend's default (`mode` `buy`, `defaultFiat` `USD`, `defaultAmount` 100,\n * `sellDefaultAmount` 1, `onlyCryptoNetworks` `gala`, `defaultPaymentMethod` `creditcard`,\n * `networkPrefix` `gala_gala`).\n */\nexport interface OnramperWidgetRequest {\n /** The wallet that receives the crypto, sent as given (the backend wants an `0x` Ethereum address). */\n walletAddress: string;\n mode?: OnramperMode | undefined;\n defaultFiat?: string | undefined;\n /** The fiat amount the widget opens with (the backend accepts 15 to 15 000, at most 2 decimals). */\n defaultAmount?: number | undefined;\n /** The crypto amount a sell opens with (0.000001 to 1 000 000, at most 18 decimals). */\n sellDefaultAmount?: number | undefined;\n onlyCryptoNetworks?: string | undefined;\n defaultPaymentMethod?: string | undefined;\n defaultCrypto?: string | undefined;\n onlyPaymentMethods?: string | undefined;\n excludePaymentMethods?: string | undefined;\n onlyFiat?: string | undefined;\n excludeFiat?: string | undefined;\n isAddressEditable?: string | undefined;\n networkPrefix?: string | undefined;\n}\n\n/** The request fields that are text, besides `walletAddress` and `mode`. */\nconst TEXT_FIELDS = [\n 'defaultFiat',\n 'onlyCryptoNetworks',\n 'defaultPaymentMethod',\n 'defaultCrypto',\n 'onlyPaymentMethods',\n 'excludePaymentMethods',\n 'onlyFiat',\n 'excludeFiat',\n 'isAddressEditable',\n 'networkPrefix',\n] as const;\n\n/** The request fields that are amounts. */\nconst AMOUNT_FIELDS = ['defaultAmount', 'sellDefaultAmount'] as const;\n\nconst METHOD = 'onramper.generateWidgetUrl';\n\nfunction invalidField(field: string, expected: string): GSwapSDKError {\n return new GSwapSDKError('INVALID_DTO', { method: METHOD, field, expected });\n}\n\n/**\n * The body to send: the fields the caller gave, checked. A field left out (or `undefined`) is not\n * sent, so the backend's default applies. An amount that is not a finite number is refused here:\n * `JSON.stringify` would turn `NaN` into `null`, which the backend reads as \"not given\" and\n * silently replaces with its default amount.\n */\nfunction widgetBody(request: OnramperWidgetRequest): Record<string, string | number> {\n if (typeof request !== 'object' || request === null) {\n throw invalidField('request', 'an object');\n }\n if (typeof request.walletAddress !== 'string' || request.walletAddress.trim() === '') {\n throw invalidField('walletAddress', 'a non-empty string');\n }\n const body: Record<string, string | number> = { walletAddress: request.walletAddress };\n if (request.mode !== undefined) {\n if (!(ONRAMPER_MODES as readonly unknown[]).includes(request.mode)) {\n throw invalidField('mode', ONRAMPER_MODES.join(', '));\n }\n body['mode'] = request.mode;\n }\n for (const field of TEXT_FIELDS) {\n const value: unknown = request[field];\n if (value === undefined) continue;\n if (typeof value !== 'string') throw invalidField(field, 'a string');\n body[field] = value;\n }\n for (const field of AMOUNT_FIELDS) {\n const value: unknown = request[field];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {\n throw invalidField(field, 'a finite number, 0 or more');\n }\n body[field] = value;\n }\n return body;\n}\n\n/** The widget URL of the backend's `{ status, error, message, data: { url } }` answer. */\nfunction widgetUrlOf(response: unknown): string {\n const data = asEntryRecord(asEntryRecord(response)?.['data']);\n const url = data?.['url'];\n if (typeof url === 'string' && url !== '') {\n try {\n // Only to know it is an absolute URL; the backend's text is returned as it is.\n void new URL(url);\n return url;\n } catch {\n // Falls through to the invalid-answer error below.\n }\n }\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'onramper widget url' },\n { body: response, write: false },\n );\n}\n\n/**\n * The swap backend's Onramper (fiat on-ramp) widget URL. The route is PUBLIC: the request carries\n * no `Authorization` header and no signature, whatever session the app has, so no token can leak to\n * it. The backend signs the wallet into the URL; the app adds its own look (theme query parameters)\n * to the returned URL.\n */\nexport class Onramper {\n /**\n * Creates the service. To get one without building a whole {@link GSwap} client, use\n * {@link createOnramper}.\n *\n * @example\n * ```ts\n * const onramper = new Onramper('https://dex-backend-prod1.defi.gala.com', httpClient);\n * ```\n */\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n ) {}\n\n /**\n * Asks the backend for a signed Onramper widget URL for `request.walletAddress`.\n *\n * @returns The widget URL.\n * @throws GSwapSDKError `INVALID_DTO` (before anything is sent: no wallet address, an unknown\n * `mode`, a text field that is not text, an amount that is not a finite number of 0 or more),\n * `HTTP_ERROR` (the backend refused: `serverMessage` is its message, e.g. \"Failed to generate\n * widget URL. Check server configuration.\" for a 500, its validation message for a 400, the\n * throttle for a 429), `REQUEST_FAILED` (no answer), `INVALID_CHAIN_RESPONSE` (an answer without\n * a usable `data.url`).\n *\n * @example\n * ```ts\n * const url = await gSwap.onramper.generateWidgetUrl({\n * walletAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',\n * defaultCrypto: 'gala',\n * onlyCryptoNetworks: 'gala',\n * mode: 'buy',\n * });\n * window.open(url);\n * ```\n */\n public async generateWidgetUrl(request: OnramperWidgetRequest): Promise<string> {\n const body = widgetBody(request);\n const response = await this.httpClient.sendPostRequest<unknown>(\n this.dexBackendBaseUrl,\n '/api/v1/onramper',\n '/generate-widget-url',\n body,\n );\n return widgetUrlOf(response);\n }\n}\n\n/** Options of {@link createOnramper}. */\nexport interface OnramperOptions {\n /** The swap backend's base URL (no trailing slash needed). */\n dexBackendBaseUrl: string;\n /** Your own HTTP requestor instead of `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Request timeout in milliseconds (default 30 000). */\n timeoutMs?: number | undefined;\n /** Query encoding and `User-Agent` of the requests. */\n wire?: WireOptions | undefined;\n}\n\n/**\n * An {@link Onramper} for a swap backend, without building a {@link GSwap} client (no signer, no\n * wallet, no pool or stream services): the call for an app that only needs the widget URL.\n *\n * @example\n * ```ts\n * import { createOnramper } from '@gala-chain/gswap-sdk';\n *\n * const onramper = createOnramper({ dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com' });\n * const url = await onramper.generateWidgetUrl({ walletAddress, mode: 'buy' });\n * ```\n */\nexport function createOnramper(options: OnramperOptions): Onramper {\n return new Onramper(\n options.dexBackendBaseUrl.replace(/\\/$/u, ''),\n new HttpClient(options.httpRequestor, options.timeoutMs, options.wire),\n );\n}\n"],"mappings":"uJAMA,MAAaA,EAAiB,CAAC,MAAO,OAAQ,MAAM,EAiC9CC,EAAc,CAClB,cACA,qBACA,uBACA,gBACA,qBACA,wBACA,WACA,cACA,oBACA,eACF,EAGMC,EAAgB,CAAC,gBAAiB,mBAAmB,EAI3D,SAASC,EAAa,EAAe,EAAiC,CACpE,OAAO,IAAIC,EAAc,cAAe,CAAE,OAAQ,6BAAQ,QAAO,UAAS,CAAC,CAC7E,CAQA,SAASC,EAAW,EAAiE,CACnF,GAAI,OAAOC,GAAY,WAAYA,EACjC,MAAMH,EAAa,UAAW,WAAW,EAE3C,GAAI,OAAOG,EAAQ,eAAkB,UAAYA,EAAQ,cAAc,KAAK,IAAM,GAChF,MAAMH,EAAa,gBAAiB,oBAAoB,EAE1D,IAAMI,EAAwC,CAAE,cAAeD,EAAQ,aAAc,EACrF,GAAIA,EAAQ,OAAS,IAAA,GAAW,CAC9B,GAAI,CAAEN,EAAsC,SAASM,EAAQ,IAAI,EAC/D,MAAMH,EAAa,OAAQH,EAAe,KAAK,IAAI,CAAC,EAEtD,EAAKQ,KAAUF,EAAQ,IACzB,CACA,IAAK,IAAMG,KAASR,EAAa,CAC/B,IAAMS,EAAiBJ,EAAQG,GAC/B,GAAIC,IAAU,IAAA,GACd,IAAI,OAAOA,GAAU,SAAU,MAAMP,EAAaM,EAAO,UAAU,EACnE,EAAKA,GAASC,CADqD,CAErE,CACA,IAAK,IAAMD,KAASP,EAAe,CACjC,IAAMQ,EAAiBJ,EAAQG,GAC/B,GAAIC,IAAU,IAAA,GACd,IAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,GAAKA,EAAQ,EAClE,MAAMP,EAAaM,EAAO,4BAA4B,EAExD,EAAKA,GAASC,CAF0C,CAG1D,CACA,OAAOH,CACT,CAGA,SAASI,EAAY,EAA2B,CAE9C,IAAMC,EADOC,EAAcA,EAAcC,CAAQ,CAAC,EAAGC,IACtC,CAAC,EAAGC,IACnB,GAAI,OAAOJ,GAAQ,UAAYA,IAAQ,GACrC,GAAI,CAGF,OADA,IAAS,IAAIA,CAAG,EACTA,CACT,MAAQ,CAER,CAEF,MAAM,IAAIR,EACR,yBACA,CAAE,SAAU,qBAAsB,EAClC,CAAE,KAAMU,EAAU,MAAO,EAAM,CACjC,CACF,CAQA,IAAaG,EAAb,KAAsB,CAUpB,YACE,EACA,EACA,CAFiB,KAAA,kBAAAC,EACA,KAAA,WAAAC,CAChB,CAwBH,MAAa,kBAAkB,EAAiD,CAC9E,IAAMZ,EAAOF,EAAWC,CAAO,EAO/B,OAAOK,EAAY,MANI,KAAK,WAAW,gBACrC,KAAK,kBACL,mBACA,uBACAJ,CACF,CAC2B,CAC7B,CACF,EA0BA,SAAgBa,EAAe,EAAoC,CACjE,OAAO,IAAIH,EACTI,EAAQ,kBAAkB,QAAQ,OAAQ,EAAE,EAC5C,IAAIC,EAAWD,EAAQ,cAAeA,EAAQ,UAAWA,EAAQ,IAAI,CACvE,CACF"}
1
+ {"version":3,"file":"onramper.js","names":["ONRAMPER_MODES","TEXT_FIELDS","AMOUNT_FIELDS","invalidField","GSwapSDKError","widgetBody","request","body","\"mode\"","field","value","widgetUrlOf","url","asEntryRecord","response","\"data\"","\"url\"","Onramper","dexBackendBaseUrl","httpClient","createOnramper","options","HttpClient"],"sources":["../../../src/classes/onramper.ts"],"sourcesContent":["import type { HttpRequestor, WireOptions } from '@gala-chain/gala-core-sdk';\nimport { asEntryRecord } from '../utils/lenient.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport { HttpClient } from './http_client.js';\n\n/** What the Onramper widget does. */\nexport const ONRAMPER_MODES = ['buy', 'sell', 'swap'] as const;\n\n/** One of {@link ONRAMPER_MODES}. */\nexport type OnramperMode = (typeof ONRAMPER_MODES)[number];\n\n/**\n * The request of {@link Onramper.generateWidgetUrl}: the fields of the swap backend's\n * `GenerateWidgetUrlDto`, no others (the backend refuses a field it does not know). A field left\n * out is the backend's default (`mode` `buy`, `defaultFiat` `USD`, `defaultAmount` 100,\n * `sellDefaultAmount` 1, `onlyCryptoNetworks` `gala`, `defaultPaymentMethod` `creditcard`,\n * `networkPrefix` `gala_gala`).\n */\nexport interface OnramperWidgetRequest {\n /** The wallet that receives the crypto, sent as given (the backend accepts `0x…` or `eth|…` Ethereum addresses and `client|…` aliases, and canonicalizes them). */\n walletAddress: string;\n mode?: OnramperMode | undefined;\n defaultFiat?: string | undefined;\n /** The fiat amount the widget opens with (the backend accepts 15 to 15 000, at most 2 decimals). */\n defaultAmount?: number | undefined;\n /** The crypto amount a sell opens with (0.000001 to 1 000 000, at most 18 decimals). */\n sellDefaultAmount?: number | undefined;\n onlyCryptoNetworks?: string | undefined;\n defaultPaymentMethod?: string | undefined;\n defaultCrypto?: string | undefined;\n onlyPaymentMethods?: string | undefined;\n excludePaymentMethods?: string | undefined;\n onlyFiat?: string | undefined;\n excludeFiat?: string | undefined;\n isAddressEditable?: string | undefined;\n networkPrefix?: string | undefined;\n}\n\n/** The request fields that are text, besides `walletAddress` and `mode`. */\nconst TEXT_FIELDS = [\n 'defaultFiat',\n 'onlyCryptoNetworks',\n 'defaultPaymentMethod',\n 'defaultCrypto',\n 'onlyPaymentMethods',\n 'excludePaymentMethods',\n 'onlyFiat',\n 'excludeFiat',\n 'isAddressEditable',\n 'networkPrefix',\n] as const;\n\n/** The request fields that are amounts. */\nconst AMOUNT_FIELDS = ['defaultAmount', 'sellDefaultAmount'] as const;\n\nconst METHOD = 'onramper.generateWidgetUrl';\n\nfunction invalidField(field: string, expected: string): GSwapSDKError {\n return new GSwapSDKError('INVALID_DTO', { method: METHOD, field, expected });\n}\n\n/**\n * The body to send: the fields the caller gave, checked. A field left out (or `undefined`) is not\n * sent, so the backend's default applies. An amount that is not a finite number is refused here:\n * `JSON.stringify` would turn `NaN` into `null`, which the backend reads as \"not given\" and\n * silently replaces with its default amount.\n */\nfunction widgetBody(request: OnramperWidgetRequest): Record<string, string | number> {\n if (typeof request !== 'object' || request === null) {\n throw invalidField('request', 'an object');\n }\n if (typeof request.walletAddress !== 'string' || request.walletAddress.trim() === '') {\n throw invalidField('walletAddress', 'a non-empty string');\n }\n const body: Record<string, string | number> = { walletAddress: request.walletAddress };\n if (request.mode !== undefined) {\n if (!(ONRAMPER_MODES as readonly unknown[]).includes(request.mode)) {\n throw invalidField('mode', ONRAMPER_MODES.join(', '));\n }\n body['mode'] = request.mode;\n }\n for (const field of TEXT_FIELDS) {\n const value: unknown = request[field];\n if (value === undefined) continue;\n if (typeof value !== 'string') throw invalidField(field, 'a string');\n body[field] = value;\n }\n for (const field of AMOUNT_FIELDS) {\n const value: unknown = request[field];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {\n throw invalidField(field, 'a finite number, 0 or more');\n }\n body[field] = value;\n }\n return body;\n}\n\n/** The widget URL of the backend's `{ status, error, message, data: { url } }` answer. */\nfunction widgetUrlOf(response: unknown): string {\n const data = asEntryRecord(asEntryRecord(response)?.['data']);\n const url = data?.['url'];\n if (typeof url === 'string' && url !== '') {\n try {\n // Only to know it is an absolute URL; the backend's text is returned as it is.\n void new URL(url);\n return url;\n } catch {\n // Falls through to the invalid-answer error below.\n }\n }\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'onramper widget url' },\n { body: response, write: false },\n );\n}\n\n/**\n * The swap backend's Onramper (fiat on-ramp) widget URL. The route is PUBLIC: the request carries\n * no `Authorization` header and no signature, whatever session the app has, so no token can leak to\n * it. The backend signs the wallet into the URL; the app adds its own look (theme query parameters)\n * to the returned URL.\n */\nexport class Onramper {\n /**\n * Creates the service. To get one without building a whole {@link GSwap} client, use\n * {@link createOnramper}.\n *\n * @example\n * ```ts\n * const onramper = new Onramper('https://dex-backend-prod1.defi.gala.com', httpClient);\n * ```\n */\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n ) {}\n\n /**\n * Asks the backend for a signed Onramper widget URL for `request.walletAddress`.\n *\n * @returns The widget URL.\n * @throws GSwapSDKError `INVALID_DTO` (before anything is sent: no wallet address, an unknown\n * `mode`, a text field that is not text, an amount that is not a finite number of 0 or more),\n * `HTTP_ERROR` (the backend refused: `serverMessage` is its message, e.g. \"Failed to generate\n * widget URL. Check server configuration.\" for a 500, its validation message for a 400, the\n * throttle for a 429), `REQUEST_FAILED` (no answer), `INVALID_CHAIN_RESPONSE` (an answer without\n * a usable `data.url`).\n *\n * @example\n * ```ts\n * const url = await gSwap.onramper.generateWidgetUrl({\n * walletAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',\n * defaultCrypto: 'gala',\n * onlyCryptoNetworks: 'gala',\n * mode: 'buy',\n * });\n * window.open(url);\n * ```\n */\n public async generateWidgetUrl(request: OnramperWidgetRequest): Promise<string> {\n const body = widgetBody(request);\n const response = await this.httpClient.sendPostRequest<unknown>(\n this.dexBackendBaseUrl,\n '/api/v1/onramper',\n '/generate-widget-url',\n body,\n );\n return widgetUrlOf(response);\n }\n}\n\n/** Options of {@link createOnramper}. */\nexport interface OnramperOptions {\n /** The swap backend's base URL (no trailing slash needed). */\n dexBackendBaseUrl: string;\n /** Your own HTTP requestor instead of `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Request timeout in milliseconds (default 30 000). */\n timeoutMs?: number | undefined;\n /** Query encoding and `User-Agent` of the requests. */\n wire?: WireOptions | undefined;\n}\n\n/**\n * An {@link Onramper} for a swap backend, without building a {@link GSwap} client (no signer, no\n * wallet, no pool or stream services): the call for an app that only needs the widget URL.\n *\n * @example\n * ```ts\n * import { createOnramper } from '@gala-chain/gswap-sdk';\n *\n * const onramper = createOnramper({ dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com' });\n * const url = await onramper.generateWidgetUrl({ walletAddress, mode: 'buy' });\n * ```\n */\nexport function createOnramper(options: OnramperOptions): Onramper {\n return new Onramper(\n options.dexBackendBaseUrl.replace(/\\/$/u, ''),\n new HttpClient(options.httpRequestor, options.timeoutMs, options.wire),\n );\n}\n"],"mappings":"uJAMA,MAAaA,EAAiB,CAAC,MAAO,OAAQ,MAAM,EAiC9CC,EAAc,CAClB,cACA,qBACA,uBACA,gBACA,qBACA,wBACA,WACA,cACA,oBACA,eACF,EAGMC,EAAgB,CAAC,gBAAiB,mBAAmB,EAI3D,SAASC,EAAa,EAAe,EAAiC,CACpE,OAAO,IAAIC,EAAc,cAAe,CAAE,OAAQ,6BAAQ,QAAO,UAAS,CAAC,CAC7E,CAQA,SAASC,EAAW,EAAiE,CACnF,GAAI,OAAOC,GAAY,WAAYA,EACjC,MAAMH,EAAa,UAAW,WAAW,EAE3C,GAAI,OAAOG,EAAQ,eAAkB,UAAYA,EAAQ,cAAc,KAAK,IAAM,GAChF,MAAMH,EAAa,gBAAiB,oBAAoB,EAE1D,IAAMI,EAAwC,CAAE,cAAeD,EAAQ,aAAc,EACrF,GAAIA,EAAQ,OAAS,IAAA,GAAW,CAC9B,GAAI,CAAEN,EAAsC,SAASM,EAAQ,IAAI,EAC/D,MAAMH,EAAa,OAAQH,EAAe,KAAK,IAAI,CAAC,EAEtD,EAAKQ,KAAUF,EAAQ,IACzB,CACA,IAAK,IAAMG,KAASR,EAAa,CAC/B,IAAMS,EAAiBJ,EAAQG,GAC/B,GAAIC,IAAU,IAAA,GACd,IAAI,OAAOA,GAAU,SAAU,MAAMP,EAAaM,EAAO,UAAU,EACnE,EAAKA,GAASC,CADqD,CAErE,CACA,IAAK,IAAMD,KAASP,EAAe,CACjC,IAAMQ,EAAiBJ,EAAQG,GAC/B,GAAIC,IAAU,IAAA,GACd,IAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,GAAKA,EAAQ,EAClE,MAAMP,EAAaM,EAAO,4BAA4B,EAExD,EAAKA,GAASC,CAF0C,CAG1D,CACA,OAAOH,CACT,CAGA,SAASI,EAAY,EAA2B,CAE9C,IAAMC,EADOC,EAAcA,EAAcC,CAAQ,CAAC,EAAGC,IACtC,CAAC,EAAGC,IACnB,GAAI,OAAOJ,GAAQ,UAAYA,IAAQ,GACrC,GAAI,CAGF,OADA,IAAS,IAAIA,CAAG,EACTA,CACT,MAAQ,CAER,CAEF,MAAM,IAAIR,EACR,yBACA,CAAE,SAAU,qBAAsB,EAClC,CAAE,KAAMU,EAAU,MAAO,EAAM,CACjC,CACF,CAQA,IAAaG,EAAb,KAAsB,CAUpB,YACE,EACA,EACA,CAFiB,KAAA,kBAAAC,EACA,KAAA,WAAAC,CAChB,CAwBH,MAAa,kBAAkB,EAAiD,CAC9E,IAAMZ,EAAOF,EAAWC,CAAO,EAO/B,OAAOK,EAAY,MANI,KAAK,WAAW,gBACrC,KAAK,kBACL,mBACA,uBACAJ,CACF,CAC2B,CAC7B,CACF,EA0BA,SAAgBa,EAAe,EAAoC,CACjE,OAAO,IAAIH,EACTI,EAAQ,kBAAkB,QAAQ,OAAQ,EAAE,EAC5C,IAAIC,EAAWD,EAAQ,cAAeA,EAAQ,UAAWA,EAAQ,IAAI,CACvE,CACF"}
@@ -1,2 +1,2 @@
1
- import{ALLOWED_FEE_TIERS_TEXT as e}from"./gswap_error_catalog.js";import t from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{GSwapSDKError as n,isGSwapError as r}from"./gswap_sdk_error.js";import{TICK_SPACING_BY_FEE as i}from"../types/fees.js";import{tickFromPrice as a}from"../utils/tick_math.js";import{isProposableTradingSymbol as o,userRef as s,validateFee as c,validateNumericAmount as l}from"../utils/validation.js";import{HttpClient as u}from"./http_client.js";import{asEntryRecord as d,entryOk as f,entryRejected as p,readEntries as m}from"../utils/lenient.js";import{parseTokenClassKey as h}from"../utils/ordering.js";import{resolvePreSend as g}from"../utils/resolve_pre_send.js";import{rawTokenOf as _}from"./symbols.js";import{alignTickDown as v,alignTickUp as y,assertTickRange as b}from"../utils/ticks.js";import{assertCanonicalV2Dto as x,buildAddLiquidityDto as S,buildCollectPositionFeesDto as C,buildCreatePoolDto as w,buildRemoveLiquidityDto as T}from"../utils/dto_builders.js";import{assertUniqueKey as E,compositeKeyOf as D,createUniqueKey as O,resolveUniqueKeyPrefix as k,signPreSend as A}from"@gala-chain/gala-core-sdk";import j from"bignumber.js";function M(e){return{token0:e.token0,token1:e.token1,fee:e.fee,tickLower:e.tickLower,tickUpper:e.tickUpper}}var N=class{constructor(e,n,r,i,a={}){this.gateway=e,this.symbols=n,this.signer=r,t(this,`walletAddress`,void 0),t(this,`http`,void 0),t(this,`uniqueKeyPrefix`,void 0),t(this,`onInvalidEntry`,void 0),this.walletAddress=i===void 0?void 0:s(i,`walletAddress`),this.http=new u(e.httpRequestor,e.requestTimeoutMs??3e4,e.wire),this.uniqueKeyPrefix=k(a.uniqueKeyPrefix),this.onInvalidEntry=a.onInvalidEntry}async getUserPositions(e){let t=await this.get(`/positions`,{user:s(e,`owner`)});return m(`positions`,t.data,L,this.onInvalidEntry)}async getPosition(e,t){let n=await this.getNullable(`/position`,await this.positionParams(e),t);return n===null?null:R(n.data)}async readPosition(e,t){try{let n=await this.getPosition(e,t);return n===null?{kind:`not_found`}:{kind:`found`,data:n}}catch(e){if(t?.aborted===!0)throw e;return{kind:`unknown`,error:r(e)?e:new n(`REQUEST_FAILED`,{operation:`position`},{cause:e,write:!1})}}}async positionParams(e){let t=s(e.owner,`owner`);if(this.symbols.passthrough===!0)return{token0:_(e.token0),token1:_(e.token1),fee:`${e.fee}`,owner:t,tickLower:`${e.tickLower}`,tickUpper:`${e.tickUpper}`};let n=await this.orderPair(e.token0,e.token1),r=this.canonicalTicks(e.tickLower,e.tickUpper,n.flipped);return{token0:n.token0.symbol,token1:n.token1.symbol,fee:`${e.fee}`,owner:t,tickLower:`${r.tickLower}`,tickUpper:`${r.tickUpper}`}}async estimateAddLiquidity(e){return l(e.amount,`amount`),(await this.get(`/add-liq-estimate`,{token0:_(e.token0),token1:_(e.token1),fee:`${e.fee}`,tickLower:`${e.tickLower}`,tickUpper:`${e.tickUpper}`,amount:new j(e.amount).toFixed(),amountIsToken0:String(e.amountIsToken0)})).data}async estimateRemoveLiquidity(e){return l(e.liquidity,`liquidity`),(await this.get(`/remove-liq-estimate`,{token0:_(e.token0),token1:_(e.token1),fee:`${e.fee}`,tickLower:`${e.tickLower}`,tickUpper:`${e.tickUpper}`,liquidity:new j(e.liquidity).toFixed()})).data}async addLiquidityByTicks(e){return this.submitAddLiquidity(await this.buildAddLiquidity(e))}async buildAddLiquidity(e){c(e.fee);let t=await this.orderPair(e.token0,e.token1),n=this.canonicalTicks(e.tickLower,e.tickUpper,t.flipped);b(n.tickLower,n.tickUpper,e.fee),l(e.amount,`amount`);let r={token0:t.token0.symbol,token1:t.token1.symbol,fee:e.fee,tickLower:n.tickLower,tickUpper:n.tickUpper,uniqueKey:this.uniqueKeyFor(e.uniqueKey)};return t.flipped===e.amountIsToken0?S({...r,depositQuantityToken1:e.amount}):S({...r,depositQuantityToken0:e.amount})}async submitAddLiquidity(e){return x(`AddLiquidity`,e),this.submit(`AddLiquidity`,e,{kind:`add`,identity:M(e)})}async addLiquidityByPrice(e){c(e.fee),this.rejectNumber(e.minPrice,`minPrice`),this.rejectNumber(e.maxPrice,`maxPrice`);let t=new j(e.minPrice),r=new j(e.maxPrice);if(!t.isFinite()||!r.isFinite()||t.isLessThanOrEqualTo(0)||r.isLessThanOrEqualTo(0))throw new n(`INVALID_PRICE_BOUNDS`,{minPrice:String(e.minPrice),maxPrice:String(e.maxPrice)});if(t.isGreaterThan(r))throw new n(`PRICE_BOUNDS_ORDER`,{minPrice:String(e.minPrice),maxPrice:String(e.maxPrice)});let i=this.tickSpacing(e.fee),o=v(a(t),i),s=y(a(r),i);return this.addLiquidityByTicks({token0:e.token0,token1:e.token1,fee:e.fee,tickLower:o,tickUpper:s,amount:e.amount,amountIsToken0:e.amountIsToken0,uniqueKey:e.uniqueKey})}async removeLiquidity(e){return this.submitRemoveLiquidity(await this.buildRemoveLiquidity(e))}async buildRemoveLiquidity(e){c(e.fee);let t=await this.orderPair(e.token0,e.token1),r=this.canonicalTicks(e.tickLower,e.tickUpper,t.flipped);if(b(r.tickLower,r.tickUpper,e.fee),e.amount0!==void 0&&e.amount1!==void 0)throw new n(`AT_MOST_ONE_OF_ALLOWED`,{first:`amount0`,second:`amount1`});e.amount0!==void 0&&l(e.amount0,`amount0`),e.amount1!==void 0&&l(e.amount1,`amount1`);let[i,a]=t.flipped?[e.amount1,e.amount0]:[e.amount0,e.amount1];return T({token0:t.token0.symbol,token1:t.token1.symbol,fee:e.fee,tickLower:r.tickLower,tickUpper:r.tickUpper,uniqueKey:this.uniqueKeyFor(e.uniqueKey),withdrawalQuantityToken0:i,withdrawalQuantityToken1:a})}async submitRemoveLiquidity(e){x(`RemoveLiquidity`,e);let t=e.withdrawalQuantityToken0===void 0&&e.withdrawalQuantityToken1===void 0;return this.submit(`RemoveLiquidity`,e,{kind:t?`removeFull`:`removePartial`,identity:M(e)})}async collectPositionFees(e){return this.submitCollectPositionFees(await this.buildCollectPositionFees(e))}async buildCollectPositionFees(e){c(e.fee);let t=await this.orderPair(e.token0,e.token1),n=this.canonicalTicks(e.tickLower,e.tickUpper,t.flipped);return b(n.tickLower,n.tickUpper,e.fee),C({token0:t.token0.symbol,token1:t.token1.symbol,fee:e.fee,tickLower:n.tickLower,tickUpper:n.tickUpper,uniqueKey:this.uniqueKeyFor(e.uniqueKey)})}async submitCollectPositionFees(e){return x(`CollectPositionFees`,e),this.submit(`CollectPositionFees`,e,{kind:`collect`,identity:M(e)})}async createPool(e){return this.submitCreatePool(await this.buildCreatePool(e))}async buildCreatePool(e){let t=e.startingPrice!==void 0;if(t===(e.startingSqrtPrice!==void 0))throw new n(`EXACTLY_ONE_OF_REQUIRED`,{first:`startingPrice`,second:`startingSqrtPrice`});c(e.fee);let[r,i]=await Promise.all([this.resolveCreateToken(e.token0,e.token0Symbol),this.resolveCreateToken(e.token1,e.token1Symbol)]),a=r.symbol>i.symbol,[o,s]=a?[i,r]:[r,i],l=t?e.startingPrice:e.startingSqrtPrice;this.rejectNumber(l,t?`startingPrice`:`startingSqrtPrice`);let u=new j(l);if(!u.isFinite()||u.isLessThanOrEqualTo(0))throw new n(`INVALID_STARTING_PRICE`,{value:String(l)});let d=a?new j(1).dividedBy(u):u,f={token0Key:o.classKey,token1Key:s.classKey,token0Symbol:o.symbol,token1Symbol:s.symbol,fee:e.fee,uniqueKey:this.uniqueKeyFor(e.uniqueKey),name:e.name,isPrivate:e.isPrivate,privateAccess:e.privateAccess};return w(t?{...f,startingPrice:d}:{...f,startingSqrtPrice:d})}async submitCreatePool(e){x(`CreatePool`,e);let t=await this.submit(`CreatePool`,e,{kind:`createPool`,token0:e.token0Symbol,token1:e.token1Symbol,fee:e.fee});return this.symbols.invalidate?.(),t}async submit(e,t,r){if(this.signer===void 0)throw n.noSignerError();let i=await A(this.signer,e,t),a=this.walletAddress===void 0?{}:{walletAddress:this.walletAddress},o=this.walletAddress,s=this.buildPositionConfirmation(r,o),c={...a,...s===void 0?{}:{positionConfirmation:s}};return this.gateway.submit(e,i,c)}buildPositionConfirmation(e,t){if(e===void 0)return;if(e.kind===`createPool`){let{token0:t,token1:n,fee:r}=e;return async e=>await this.getNullable(`/pool`,{token0:t,token1:n,fee:`${r}`},e)===null?{confirmed:!1}:{confirmed:!0,position:null}}if(t===void 0)return;let{kind:n,identity:r}=e,i;return async e=>{let a=await this.getPosition({...r,owner:t},e);if(i===void 0)return i={liquidity:new j(a?.liquidity??0),fees:new j(a?.fees0??0).plus(new j(a?.fees1??0))},n===`removeFull`&&a===null?{confirmed:!0,position:null}:{confirmed:!1};switch(n){case`add`:return a!==null&&new j(a.liquidity).isGreaterThan(i.liquidity)?{confirmed:!0,position:a}:{confirmed:!1};case`removePartial`:return a!==null&&new j(a.liquidity).isLessThan(i.liquidity)?{confirmed:!0,position:a}:{confirmed:!1};case`removeFull`:return a===null?{confirmed:!0,position:null}:{confirmed:!1};case`collect`:{if(a===null)return{confirmed:!1};let e=new j(a.fees0??0).plus(new j(a.fees1??0));return e.isLessThan(i.fees)||i.fees.isZero()&&e.isZero()?{confirmed:!0,position:a}:{confirmed:!1}}}}}async get(e,t,n){return this.http.sendGetRequest(this.gateway.dexBackendBaseUrl,`/v2/trade`,e,t,n===void 0?void 0:{signal:n})}async getNullable(e,t,n){try{return await this.get(e,t,n)}catch(e){if(this.isNotFound(e))return null;throw e}}isNotFound(e){return r(e)&&e.status===404}canonicalTicks(e,t,n){return n?{tickLower:-t,tickUpper:-e}:{tickLower:e,tickUpper:t}}tickSpacing(t){let r=i[t];if(r===void 0)throw new n(`INVALID_FEE`,{field:`fee`,value:t,allowed:e});return r}rejectNumber(e,t){if(typeof e==`number`)throw new n(`AMOUNT_IS_JS_NUMBER`,{field:t})}uniqueKeyFor(e){return e===void 0?O(this.uniqueKeyPrefix):(E(e),e)}orderPair(e,t){return g(`${_(e)}/${_(t)}`,()=>this.symbols.orderPair(e,t))}async resolveCreateToken(e,t){try{let r=typeof e==`object`?D(e):e,i=await g(_(e),()=>this.symbols.resolve(r));if(t!==void 0&&t!==``&&t!==i.symbol)throw new n(`SYMBOL_DISAGREES_WITH_REGISTRY`,{token:_(e),suppliedSymbol:t,registeredSymbol:i.symbol});let a=this.tryParseClassKey(e);if(a===void 0&&i.collection===``)throw new n(`CREATE_POOL_NEEDS_CLASS_KEY`,{token:_(e)});return{symbol:i.symbol,classKey:a??h({collection:i.collection,category:i.category,type:i.type,additionalKey:i.additionalKey})}}catch(i){if(!r(i,`UNKNOWN_TOKEN`))throw i;let a;try{a=h(e)}catch{throw i}if(t===void 0||t===``)throw new n(`TOKEN_SYMBOL_NOT_REGISTERED`,{token:_(e)});if(!o(t))throw new n(`INVALID_TRADING_SYMBOL`,{symbol:t});return{symbol:t,classKey:a}}}tryParseClassKey(e){try{return h(e)}catch{return}}};const P=[`token0Symbol`,`token1Symbol`,`owner`,`liquidity`,`amount0`,`amount1`],F=[`fee`,`tickLower`,`tickUpper`],I=[`token0CompositeKey`,`token1CompositeKey`,`token0Image`,`token1Image`,`sqrtPrice`,`fees0`,`fees1`];function L(e){let t=d(e);if(t===void 0)return p(`the row is not an object`);for(let e of P)if(typeof t[e]!=`string`)return p(`${e} is not a string`);for(let e of F){let n=t[e];if(typeof n!=`number`||!Number.isFinite(n))return p(`${e} is not a number`)}if(typeof t.inRange!=`boolean`)return p(`inRange is not a boolean`);for(let e of I)if(t[e]!==void 0&&typeof t[e]!=`string`)return p(`${e} is not a string`);let n=t.currentTick;if(n!==void 0&&(typeof n!=`number`||!Number.isFinite(n)))return p(`currentTick is not a number`);let r=t.poolRef??t.pool??``;if(typeof r!=`string`)return p(`pool is not a string`);let i=Object.fromEntries([...I,`currentTick`].flatMap(e=>t[e]===void 0?[]:[[e,t[e]]]));return f({token0Symbol:t.token0Symbol,token1Symbol:t.token1Symbol,fee:t.fee,tickLower:t.tickLower,tickUpper:t.tickUpper,liquidity:t.liquidity,amount0:t.amount0,amount1:t.amount1,inRange:t.inRange,pool:r,owner:t.owner,...i})}function R(e){let t=L(e);if(t.ok)return t.value;throw new n(`INVALID_POSITION_RESPONSE`,{reason:t.reason},{body:e,write:!1})}export{N as Positions};
1
+ import{ALLOWED_FEE_TIERS_TEXT as e}from"./gswap_error_catalog.js";import t from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{GSwapSDKError as n,isGSwapError as r}from"./gswap_sdk_error.js";import{TICK_SPACING_BY_FEE as i}from"../types/fees.js";import{tickFromPrice as a}from"../utils/tick_math.js";import{isProposableTradingSymbol as o,userRef as s,validateFee as c,validateNumericAmount as l}from"../utils/validation.js";import{HttpClient as u}from"./http_client.js";import{asEntryRecord as d,entryOk as f,entryRejected as p,readEntries as m}from"../utils/lenient.js";import{parseTokenClassKey as h}from"../utils/ordering.js";import{resolvePreSend as g}from"../utils/resolve_pre_send.js";import{rawTokenOf as _}from"./symbols.js";import{alignTickDown as v,alignTickUp as y,assertTickRange as b}from"../utils/ticks.js";import{assertCanonicalV2Dto as x,buildAddLiquidityDto as S,buildCollectPositionFeesDto as C,buildCreatePoolDto as w,buildRemoveLiquidityDto as T}from"../utils/dto_builders.js";import{assertUniqueKey as E,compositeKeyOf as D,createUniqueKey as O,resolveUniqueKeyPrefix as k,signPreSend as A}from"@gala-chain/gala-core-sdk";import j from"bignumber.js";function M(e){return{token0:e.token0,token1:e.token1,fee:e.fee,tickLower:e.tickLower,tickUpper:e.tickUpper}}var N=class{constructor(e,n,r,i,a={}){this.gateway=e,this.symbols=n,this.signer=r,t(this,`walletAddress`,void 0),t(this,`http`,void 0),t(this,`uniqueKeyPrefix`,void 0),t(this,`onInvalidEntry`,void 0),this.walletAddress=i===void 0?void 0:s(i,`walletAddress`),this.http=new u(e.httpRequestor,e.requestTimeoutMs??3e4,e.wire),this.uniqueKeyPrefix=k(a.uniqueKeyPrefix),this.onInvalidEntry=a.onInvalidEntry}async getUserPositions(e){let t=await this.get(`/positions`,{user:s(e,`owner`)});return m(`positions`,t.data,L,this.onInvalidEntry)}async getPosition(e,t){let n=await this.getNullable(`/position`,await this.positionParams(e),t);return n===null?null:R(n.data)}async readPosition(e,t){try{let n=await this.getPosition(e,t);return n===null?{kind:`not_found`}:{kind:`found`,data:n}}catch(e){if(t?.aborted===!0)throw e;return{kind:`unknown`,error:r(e)?e:new n(`REQUEST_FAILED`,{operation:`position`},{cause:e,write:!1})}}}async positionParams(e){let t=s(e.owner,`owner`);if(this.symbols.passthrough===!0)return{token0:_(e.token0),token1:_(e.token1),fee:`${e.fee}`,owner:t,tickLower:`${e.tickLower}`,tickUpper:`${e.tickUpper}`};let n=await this.orderPair(e.token0,e.token1),r=this.canonicalTicks(e.tickLower,e.tickUpper,n.flipped);return{token0:n.token0.symbol,token1:n.token1.symbol,fee:`${e.fee}`,owner:t,tickLower:`${r.tickLower}`,tickUpper:`${r.tickUpper}`}}async estimateAddLiquidity(e){return l(e.amount,`amount`),(await this.get(`/add-liq-estimate`,{token0:_(e.token0),token1:_(e.token1),fee:`${e.fee}`,tickLower:`${e.tickLower}`,tickUpper:`${e.tickUpper}`,amount:new j(e.amount).toFixed(),amountIsToken0:String(e.amountIsToken0)})).data}async estimateRemoveLiquidity(e){return l(e.liquidity,`liquidity`),(await this.get(`/remove-liq-estimate`,{token0:_(e.token0),token1:_(e.token1),fee:`${e.fee}`,tickLower:`${e.tickLower}`,tickUpper:`${e.tickUpper}`,liquidity:new j(e.liquidity).toFixed()})).data}async addLiquidityByTicks(e){return this.submitAddLiquidity(await this.buildAddLiquidity(e))}async buildAddLiquidity(e){c(e.fee);let t=await this.orderPair(e.token0,e.token1),n=this.canonicalTicks(e.tickLower,e.tickUpper,t.flipped);b(n.tickLower,n.tickUpper,e.fee),l(e.amount,`amount`);let r={token0:t.token0.symbol,token1:t.token1.symbol,fee:e.fee,tickLower:n.tickLower,tickUpper:n.tickUpper,uniqueKey:this.uniqueKeyFor(e.uniqueKey)};return t.flipped===e.amountIsToken0?S({...r,depositQuantityToken1:e.amount}):S({...r,depositQuantityToken0:e.amount})}async submitAddLiquidity(e){return x(`AddLiquidity`,e),this.submit(`AddLiquidity`,e,{kind:`add`,identity:M(e)})}async addLiquidityByPrice(e){c(e.fee),this.rejectNumber(e.minPrice,`minPrice`),this.rejectNumber(e.maxPrice,`maxPrice`);let t=new j(e.minPrice),r=new j(e.maxPrice);if(!t.isFinite()||!r.isFinite()||t.isLessThanOrEqualTo(0)||r.isLessThanOrEqualTo(0))throw new n(`INVALID_PRICE_BOUNDS`,{minPrice:String(e.minPrice),maxPrice:String(e.maxPrice)});if(t.isGreaterThan(r))throw new n(`PRICE_BOUNDS_ORDER`,{minPrice:String(e.minPrice),maxPrice:String(e.maxPrice)});let i=this.tickSpacing(e.fee),o=v(a(t),i),s=y(a(r),i);return this.addLiquidityByTicks({token0:e.token0,token1:e.token1,fee:e.fee,tickLower:o,tickUpper:s,amount:e.amount,amountIsToken0:e.amountIsToken0,uniqueKey:e.uniqueKey})}async removeLiquidity(e){return this.submitRemoveLiquidity(await this.buildRemoveLiquidity(e))}async buildRemoveLiquidity(e){c(e.fee);let t=await this.orderPair(e.token0,e.token1),r=this.canonicalTicks(e.tickLower,e.tickUpper,t.flipped);if(b(r.tickLower,r.tickUpper,e.fee),e.amount0!==void 0&&e.amount1!==void 0)throw new n(`AT_MOST_ONE_OF_ALLOWED`,{first:`amount0`,second:`amount1`});e.amount0!==void 0&&l(e.amount0,`amount0`),e.amount1!==void 0&&l(e.amount1,`amount1`);let[i,a]=t.flipped?[e.amount1,e.amount0]:[e.amount0,e.amount1];return T({token0:t.token0.symbol,token1:t.token1.symbol,fee:e.fee,tickLower:r.tickLower,tickUpper:r.tickUpper,uniqueKey:this.uniqueKeyFor(e.uniqueKey),withdrawalQuantityToken0:i,withdrawalQuantityToken1:a})}async submitRemoveLiquidity(e){x(`RemoveLiquidity`,e);let t=e.withdrawalQuantityToken0===void 0&&e.withdrawalQuantityToken1===void 0;return this.submit(`RemoveLiquidity`,e,{kind:t?`removeFull`:`removePartial`,identity:M(e)})}async collectPositionFees(e){return this.submitCollectPositionFees(await this.buildCollectPositionFees(e))}async buildCollectPositionFees(e){c(e.fee);let t=await this.orderPair(e.token0,e.token1),n=this.canonicalTicks(e.tickLower,e.tickUpper,t.flipped);return b(n.tickLower,n.tickUpper,e.fee),C({token0:t.token0.symbol,token1:t.token1.symbol,fee:e.fee,tickLower:n.tickLower,tickUpper:n.tickUpper,uniqueKey:this.uniqueKeyFor(e.uniqueKey)})}async submitCollectPositionFees(e){return x(`CollectPositionFees`,e),this.submit(`CollectPositionFees`,e,{kind:`collect`,identity:M(e)})}async createPool(e){return this.submitCreatePool(await this.buildCreatePool(e))}async buildCreatePool(e){let t=e.startingPrice!==void 0;if(t===(e.startingSqrtPrice!==void 0))throw new n(`EXACTLY_ONE_OF_REQUIRED`,{first:`startingPrice`,second:`startingSqrtPrice`});c(e.fee);let[r,i]=await Promise.all([this.resolveCreateToken(e.token0,e.token0Symbol),this.resolveCreateToken(e.token1,e.token1Symbol)]),a=r.symbol>i.symbol,[o,s]=a?[i,r]:[r,i],l=t?e.startingPrice:e.startingSqrtPrice;this.rejectNumber(l,t?`startingPrice`:`startingSqrtPrice`);let u=new j(l);if(!u.isFinite()||u.isLessThanOrEqualTo(0))throw new n(`INVALID_STARTING_PRICE`,{value:String(l)});let d=a?new j(1).dividedBy(u):u,f={token0Key:o.classKey,token1Key:s.classKey,token0Symbol:o.symbol,token1Symbol:s.symbol,fee:e.fee,uniqueKey:this.uniqueKeyFor(e.uniqueKey),name:e.name,isPrivate:e.isPrivate,privateAccess:e.privateAccess};return w(t?{...f,startingPrice:d}:{...f,startingSqrtPrice:d})}async submitCreatePool(e){x(`CreatePool`,e);let t=await this.submit(`CreatePool`,e,{kind:`createPool`,token0:e.token0Symbol,token1:e.token1Symbol,fee:e.fee});return this.symbols.invalidate?.(),t}async submit(e,t,r){if(this.signer===void 0)throw n.noSignerError();let i=await A(this.signer,e,t),a=this.walletAddress===void 0?{}:{walletAddress:this.walletAddress},o=this.walletAddress,s=await this.buildPositionConfirmation(r,o),c={...a,...s===void 0?{}:{positionConfirmation:s}};return this.gateway.submit(e,i,c)}async buildPositionConfirmation(e,t){if(e===void 0)return;if(e.kind===`createPool`){let{token0:t,token1:n,fee:r}=e;return async e=>await this.getNullable(`/pool`,{token0:t,token1:n,fee:`${r}`},e)===null?{confirmed:!1}:{confirmed:!0,position:null}}if(t===void 0)return;let{kind:n,identity:r}=e,i=e=>({liquidity:new j(e?.liquidity??0),fees:new j(e?.fees0??0).plus(new j(e?.fees1??0))}),a;if(n!==`removeFull`)try{a=i(await this.getPosition({...r,owner:t}))}catch{a=void 0}return async e=>{let o=await this.getPosition({...r,owner:t},e);if(a===void 0)return a=i(o),n===`removeFull`&&o===null?{confirmed:!0,position:null}:{confirmed:!1};switch(n){case`add`:return o!==null&&new j(o.liquidity).isGreaterThan(a.liquidity)?{confirmed:!0,position:o}:{confirmed:!1};case`removePartial`:return o!==null&&new j(o.liquidity).isLessThan(a.liquidity)?{confirmed:!0,position:o}:{confirmed:!1};case`removeFull`:return o===null?{confirmed:!0,position:null}:{confirmed:!1};case`collect`:{if(o===null)return{confirmed:!1};let e=new j(o.fees0??0).plus(new j(o.fees1??0));return e.isLessThan(a.fees)||a.fees.isZero()&&e.isZero()?{confirmed:!0,position:o}:{confirmed:!1}}}}}async get(e,t,n){return this.http.sendGetRequest(this.gateway.dexBackendBaseUrl,`/v2/trade`,e,t,n===void 0?void 0:{signal:n})}async getNullable(e,t,n){try{return await this.get(e,t,n)}catch(e){if(this.isNotFound(e))return null;throw e}}isNotFound(e){return r(e)&&e.status===404}canonicalTicks(e,t,n){return n?{tickLower:-t,tickUpper:-e}:{tickLower:e,tickUpper:t}}tickSpacing(t){let r=i[t];if(r===void 0)throw new n(`INVALID_FEE`,{field:`fee`,value:t,allowed:e});return r}rejectNumber(e,t){if(typeof e==`number`)throw new n(`AMOUNT_IS_JS_NUMBER`,{field:t})}uniqueKeyFor(e){return e===void 0?O(this.uniqueKeyPrefix):(E(e),e)}orderPair(e,t){return g(`${_(e)}/${_(t)}`,()=>this.symbols.orderPair(e,t))}async resolveCreateToken(e,t){try{let r=typeof e==`object`?D(e):e,i=await g(_(e),()=>this.symbols.resolve(r));if(t!==void 0&&t!==``&&t!==i.symbol)throw new n(`SYMBOL_DISAGREES_WITH_REGISTRY`,{token:_(e),suppliedSymbol:t,registeredSymbol:i.symbol});let a=this.tryParseClassKey(e);if(a===void 0&&i.collection===``)throw new n(`CREATE_POOL_NEEDS_CLASS_KEY`,{token:_(e)});return{symbol:i.symbol,classKey:a??h({collection:i.collection,category:i.category,type:i.type,additionalKey:i.additionalKey})}}catch(i){if(!r(i,`UNKNOWN_TOKEN`))throw i;let a;try{a=h(e)}catch{throw i}if(t===void 0||t===``)throw new n(`TOKEN_SYMBOL_NOT_REGISTERED`,{token:_(e)});if(!o(t))throw new n(`INVALID_TRADING_SYMBOL`,{symbol:t});return{symbol:t,classKey:a}}}tryParseClassKey(e){try{return h(e)}catch{return}}};const P=[`token0Symbol`,`token1Symbol`,`owner`,`liquidity`,`amount0`,`amount1`],F=[`fee`,`tickLower`,`tickUpper`],I=[`token0CompositeKey`,`token1CompositeKey`,`token0Image`,`token1Image`,`sqrtPrice`,`fees0`,`fees1`];function L(e){let t=d(e);if(t===void 0)return p(`the row is not an object`);for(let e of P)if(typeof t[e]!=`string`)return p(`${e} is not a string`);for(let e of F){let n=t[e];if(typeof n!=`number`||!Number.isFinite(n))return p(`${e} is not a number`)}if(typeof t.inRange!=`boolean`)return p(`inRange is not a boolean`);for(let e of I)if(t[e]!==void 0&&typeof t[e]!=`string`)return p(`${e} is not a string`);let n=t.currentTick;if(n!==void 0&&(typeof n!=`number`||!Number.isFinite(n)))return p(`currentTick is not a number`);let r=t.poolRef??t.pool??``;if(typeof r!=`string`)return p(`pool is not a string`);let i=Object.fromEntries([...I,`currentTick`].flatMap(e=>t[e]===void 0?[]:[[e,t[e]]]));return f({token0Symbol:t.token0Symbol,token1Symbol:t.token1Symbol,fee:t.fee,tickLower:t.tickLower,tickUpper:t.tickUpper,liquidity:t.liquidity,amount0:t.amount0,amount1:t.amount1,inRange:t.inRange,pool:r,owner:t.owner,...i})}function R(e){let t=L(e);if(t.ok)return t.value;throw new n(`INVALID_POSITION_RESPONSE`,{reason:t.reason},{body:e,write:!1})}export{N as Positions};
2
2
  //# sourceMappingURL=positions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"positions.js","names":["_defineProperty","BigNumber","identityOf","dto","Positions","gateway","symbols","signer","walletAddress","userRef","HttpClient","resolveUniqueKeyPrefix","options","response","owner","readEntries","parsePosition","args","signal","readPositionBody","position","error","isGSwapError","GSwapSDKError","rawTokenOf","pair","ticks","validateNumericAmount","validateFee","assertTickRange","base","buildAddLiquidityDto","assertCanonicalV2Dto","minPrice","maxPrice","spacing","tickLower","alignTickDown","tickFromPrice","tickUpper","alignTickUp","canonical0","canonical1","buildRemoveLiquidityDto","isFullClose","buildCollectPositionFeesDto","hasPrice","tokenA","tokenB","flipped","token0","token1","sourcePriceInput","sourcePrice","canonicalPrice","shared","buildCreatePoolDto","transaction","signed","signPreSend","method","submitOptions","positionConfirmation","confirmation","fee","baseline","current","identity","kind","currentFees","endpoint","params","TICK_SPACING_BY_FEE","ALLOWED_FEE_TIERS_TEXT","value","parameterName","supplied","createUniqueKey","assertUniqueKey","resolvePreSend","a","b","lookupRef","ref","compositeKeyOf","resolved","symbolOverride","suppliedClassKey","parseTokenClassKey","classKey","isProposableTradingSymbol","REQUIRED_POSITION_STRINGS","REQUIRED_POSITION_NUMBERS","OPTIONAL_POSITION_STRINGS","wire","asEntryRecord","entryRejected","key","number","\"inRange\"","currentTick","\"currentTick\"","pool","\"poolRef\"","\"pool\"","optional","entryOk","\"token0Symbol\"","\"token1Symbol\"","\"fee\"","\"tickLower\"","\"tickUpper\"","\"liquidity\"","\"amount0\"","\"amount1\"","\"owner\"","parsed","data"],"sources":["../../../src/classes/positions.ts"],"sourcesContent":["import {\n assertUniqueKey,\n compositeKeyOf,\n createUniqueKey,\n resolveUniqueKeyPrefix,\n signPreSend,\n type GalaChainSigner,\n type UniqueKeyOptions,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport BigNumber from 'bignumber.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from './gswap_error_catalog.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport type { ChainGateway, ChainSubmitOptions } from './gateway.js';\nimport type { PositionConfirmationResult, SubmittedTransaction } from './submitted_transaction.js';\nimport { HttpClient } from './http_client.js';\nimport { rawTokenOf, type Symbols, type TokenResolver } from './symbols.js';\nimport type { NumericAmount, PriceIn } from '../types/amounts.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { TICK_SPACING_BY_FEE } from '../types/fees.js';\nimport type {\n AddLiquidityDTO,\n CollectPositionFeesDTO,\n CreatePoolDTO,\n RemoveLiquidityDTO,\n} from '../types/v2_dtos.js';\nimport type {\n AddLiquidityEstimate,\n Position,\n RemoveLiquidityEstimate,\n} from '../types/v2_results.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport { type TokenRef, parseTokenClassKey } from '../utils/ordering.js';\nimport { resolvePreSend } from '../utils/resolve_pre_send.js';\nimport {\n isProposableTradingSymbol,\n validateFee,\n userRef,\n validateNumericAmount,\n} from '../utils/validation.js';\nimport { tickFromPrice } from '../utils/tick_math.js';\nimport { alignTickDown, alignTickUp, assertTickRange } from '../utils/ticks.js';\nimport {\n assertCanonicalV2Dto,\n buildAddLiquidityDto,\n buildCollectPositionFeesDto,\n buildCreatePoolDto,\n buildRemoveLiquidityDto,\n} from '../utils/dto_builders.js';\n\ntype PositionGateway = Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n submit: (\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ) => Promise<SubmittedTransaction<Position | null>>;\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n};\ntype PositionSymbols = TokenResolver & Pick<Symbols, 'orderPair'> & { invalidate?: () => void };\n\n/** Options of {@link Positions}: the `uniqueKey` prefix and a handler for skipped list rows. */\nexport interface PositionsOptions extends UniqueKeyOptions {\n /** Told about every position row of a list that was skipped as unusable. */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n}\n\n/** A write's optional attempt identity. */\ninterface UniqueKeyArg {\n /**\n * The attempt's `uniqueKey` (1-128 characters of `A-Za-z0-9._:-`). Default: a fresh\n * `<uniqueKeyPrefix><uuid>`. Supply one to know the key before signing, or to retry the SAME\n * attempt after a lost response; never reuse it for another write.\n */\n uniqueKey?: string | undefined;\n}\n\n/** Arguments of {@link Positions.addLiquidityByTicks} and {@link Positions.buildAddLiquidity}. */\nexport interface AddLiquidityArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n amount: NumericAmount;\n /** Whether `amount` is of `token0` as the caller passed it (not of the canonical token0). */\n amountIsToken0: boolean;\n}\n\n/** Arguments of {@link Positions.removeLiquidity} and {@link Positions.buildRemoveLiquidity}. */\nexport interface RemoveLiquidityArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n /** Withdraw this much of the caller's `token0`; give at most one of `amount0` / `amount1`. */\n amount0?: NumericAmount | undefined;\n amount1?: NumericAmount | undefined;\n}\n\n/** Arguments of {@link Positions.collectPositionFees} and {@link Positions.buildCollectPositionFees}. */\nexport interface CollectPositionFeesArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n}\n\n/** Arguments of {@link Positions.createPool} and {@link Positions.buildCreatePool}. */\nexport interface CreatePoolArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n token0Symbol?: string | undefined;\n token1Symbol?: string | undefined;\n fee: FEE_TIER;\n startingPrice?: NumericAmount | undefined;\n startingSqrtPrice?: NumericAmount | undefined;\n /** Optional pool display name, sent as the DTO's `name`; omitted when undefined or empty. */\n name?: string | undefined;\n isPrivate?: boolean | undefined;\n privateAccess?: string[] | undefined;\n}\n\n/** The pool position a liquidity DTO names, as its confirmation needs it. */\nfunction identityOf(\n dto: Pick<CollectPositionFeesDTO, 'token0' | 'token1' | 'fee' | 'tickLower' | 'tickUpper'>,\n): PositionIdentity {\n return {\n token0: dto.token0,\n token1: dto.token1,\n fee: dto.fee,\n tickLower: dto.tickLower,\n tickUpper: dto.tickUpper,\n };\n}\n\n/**\n * The outcome of {@link Positions.readPosition}. Only `not_found` is chain-confirmed absence (the\n * backend answers HTTP 404 only when the chain itself found no such position); `unknown` is \"no\n * evidence either way\" — a transport failure, a gateway timeout, any other error status or an\n * answer that is not a position — and must never be read as a removal.\n */\nexport type PositionRead =\n | { kind: 'found'; data: Position }\n | { kind: 'not_found' }\n | { kind: 'unknown'; error: GSwapSDKError };\n\ninterface BackendEnvelope<TData> {\n data: TData;\n}\n\ninterface AddLiquidityEstimateWire {\n amount0: string;\n amount1: string;\n liquidity: string;\n token0Symbol: string;\n token1Symbol: string;\n tickLower: number;\n tickUpper: number;\n amountIsCanonicalToken0: boolean;\n}\n\ninterface RemoveLiquidityEstimateWire {\n amount0: string;\n amount1: string;\n}\n\ninterface ResolvedCreateToken {\n symbol: string;\n classKey: ReturnType<typeof parseTokenClassKey>;\n}\n\ninterface PositionIdentity {\n token0: string;\n token1: string;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n}\n\n/** Tells `submit()` how to prove a write's own effect for `SubmittedTransaction.confirm()`. */\ntype PositionSubmitConfirmation =\n | { kind: 'add' | 'removePartial' | 'removeFull' | 'collect'; identity: PositionIdentity }\n | { kind: 'createPool'; token0: string; token1: string; fee: FEE_TIER };\n\n/**\n * Manages current-contract concentrated-liquidity positions.\n *\n * @example\n * ```typescript\n * const positions = gSwap.positions;\n * const mine = await positions.getUserPositions('client|012345678901234567890123');\n * console.log(mine.length);\n * ```\n */\nexport class Positions {\n constructor(\n private readonly gateway: PositionGateway,\n private readonly symbols: PositionSymbols,\n private readonly signer?: GalaChainSigner,\n walletAddress?: string,\n options: PositionsOptions = {},\n ) {\n this.walletAddress =\n walletAddress === undefined ? undefined : userRef(walletAddress, 'walletAddress');\n this.http = new HttpClient(\n gateway.httpRequestor,\n gateway.requestTimeoutMs ?? 30_000,\n gateway.wire,\n );\n this.uniqueKeyPrefix = resolveUniqueKeyPrefix(options.uniqueKeyPrefix);\n this.onInvalidEntry = options.onInvalidEntry;\n }\n\n /** The signing wallet in the gateway's spelling (`eth|<EIP-55>` or `client|<id>`). */\n private readonly walletAddress: string | undefined;\n private readonly http: HttpClient;\n private readonly uniqueKeyPrefix: string;\n private readonly onInvalidEntry: InvalidEntryHandler | undefined;\n\n /**\n * Gets all current-contract positions owned by an address.\n *\n * @param owner - GalaChain owner identity.\n * @returns Enriched positions from the v2 trade backend, token images included. A row that is\n * not a usable position is skipped and reported to `onInvalidEntry`.\n * @example\n * ```typescript\n * const positions = await gSwap.positions.getUserPositions('client|012345678901234567890123');\n * ```\n */\n async getUserPositions(owner: string): Promise<Position[]> {\n const response = await this.get<unknown>('/positions', { user: userRef(owner, 'owner') });\n return readEntries('positions', response.data, parsePosition, this.onInvalidEntry);\n }\n\n /**\n * Gets one position, normalizing a caller-supplied reversed pair to canonical symbol order.\n * Reversed pairs also invert the price axis, so `[lower, upper]` becomes `[-upper, -lower]`.\n *\n * @param args - Pair, owner, fee, and position tick range.\n * @returns The position, or `null` when the backend returns 404.\n * @example\n * ```typescript\n * const position = await gSwap.positions.getPosition({\n * token0: 'GALA', token1: 'GUSDC', owner: 'client|012345678901234567890123',\n * fee: 3000, tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async getPosition(\n args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n },\n signal?: AbortSignal,\n ): Promise<Position | null> {\n const response = await this.getNullable<unknown>(\n '/position',\n await this.positionParams(args),\n signal,\n );\n return response === null ? null : readPositionBody(response.data);\n }\n\n /**\n * Reads one position and classifies the outcome instead of throwing: `found` with the position\n * (fees included), `not_found` (the backend's HTTP 404, which it sends only when the chain\n * itself has no such position) or `unknown` (any other failure, carried as `error`). Use it\n * to confirm a write: `unknown` is \"no evidence either way\", never a confirmed absence.\n *\n * Only the caller's own abort rethrows. With a pass-through resolver ({@link CanonicalSymbols})\n * the pair and ticks go to the backend exactly as given and the backend orients them.\n *\n * @example\n * ```typescript\n * const read = await gSwap.positions.readPosition({\n * token0: 'GALA', token1: 'GUSDC', owner: 'client|012345678901234567890123',\n * fee: 3000, tickLower: -19200, tickUpper: 12000,\n * });\n * if (read.kind === 'found') console.log(read.data.fees0);\n * ```\n */\n async readPosition(\n args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n },\n signal?: AbortSignal,\n ): Promise<PositionRead> {\n try {\n const position = await this.getPosition(args, signal);\n return position === null ? { kind: 'not_found' } : { kind: 'found', data: position };\n } catch (error: unknown) {\n if (signal?.aborted === true) throw error;\n return {\n kind: 'unknown',\n error: isGSwapError(error)\n ? error\n : new GSwapSDKError(\n 'REQUEST_FAILED',\n { operation: 'position' },\n { cause: error, write: false },\n ),\n };\n }\n }\n\n /**\n * The `/position` query: canonical symbols and canonical ticks after a client-side flip, or,\n * for a pass-through resolver, the caller's references and ticks untouched.\n */\n private async positionParams(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n }): Promise<Record<string, string>> {\n // The backend matches `owner` against the chain's position owner with strict equality, so\n // only the chain's own spelling (`eth|<EIP-55>`) finds a position.\n const owner = userRef(args.owner, 'owner');\n if (this.symbols.passthrough === true) {\n return {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n owner,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n };\n }\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n return {\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: `${args.fee}`,\n owner,\n tickLower: `${ticks.tickLower}`,\n tickUpper: `${ticks.tickUpper}`,\n };\n }\n\n /**\n * Estimates the other token amount and resulting liquidity for a deposit.\n *\n * @param args - Pair, tick range, deposit amount, and the amount's caller-side token index.\n * @returns Backend liquidity estimate.\n * @example\n * ```typescript\n * const estimate = await gSwap.positions.estimateAddLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async estimateAddLiquidity(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n amount: NumericAmount;\n amountIsToken0: boolean;\n }): Promise<AddLiquidityEstimate> {\n validateNumericAmount(args.amount, 'amount');\n const response = await this.get<AddLiquidityEstimateWire>('/add-liq-estimate', {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n amount: new BigNumber(args.amount).toFixed(),\n amountIsToken0: String(args.amountIsToken0),\n });\n return response.data;\n }\n\n /**\n * Estimates token amounts released by burning liquidity.\n *\n * @param args - Pair, tick range, fee tier, and liquidity quantity.\n * @returns Estimated token0 and token1 quantities.\n * @example\n * ```typescript\n * const estimate = await gSwap.positions.estimateRemoveLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, liquidity: '1000',\n * });\n * ```\n */\n async estimateRemoveLiquidity(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n liquidity: NumericAmount;\n }): Promise<RemoveLiquidityEstimate> {\n validateNumericAmount(args.liquidity, 'liquidity');\n const response = await this.get<RemoveLiquidityEstimateWire>('/remove-liq-estimate', {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n liquidity: new BigNumber(args.liquidity).toFixed(),\n });\n return response.data;\n }\n\n /**\n * Adds liquidity using an explicit tick range. Exactly one canonical deposit field is emitted.\n *\n * @param args - Pair, fee, range, deposit amount, and caller-side token index.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.addLiquidityByTicks({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * await tx.confirm();\n * ```\n */\n async addLiquidityByTicks(args: AddLiquidityArgs) {\n return this.submitAddLiquidity(await this.buildAddLiquidity(args));\n }\n\n /**\n * Builds the AddLiquidity DTO that {@link addLiquidityByTicks} would sign, without signing or\n * sending it: to show in an approval popup, or to sign elsewhere. Submit exactly this DTO with\n * {@link submitAddLiquidity}. The pure counterpart, with canonical inputs and no resolution,\n * is `buildAddLiquidityDto`.\n *\n * @example\n * ```typescript\n * const dto = await gSwap.positions.buildAddLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async buildAddLiquidity(args: AddLiquidityArgs): Promise<AddLiquidityDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n // Caller-facing checks first, so a refusal names the caller's own argument (`amount`).\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n validateNumericAmount(args.amount, 'amount');\n const base = {\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n };\n return pair.flipped !== args.amountIsToken0\n ? buildAddLiquidityDto({ ...base, depositQuantityToken0: args.amount })\n : buildAddLiquidityDto({ ...base, depositQuantityToken1: args.amount });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildAddLiquidity} or `buildAddLiquidityDto`; it must\n * be exactly what the builder produces. The returned transaction confirms by proving the\n * position's liquidity grew.\n */\n async submitAddLiquidity(dto: AddLiquidityDTO) {\n assertCanonicalV2Dto('AddLiquidity', dto);\n return this.submit('AddLiquidity', dto, { kind: 'add', identity: identityOf(dto) });\n }\n\n /**\n * Adds liquidity from prices, flooring the lower tick and ceiling the upper tick to fee spacing.\n * The resulting range is therefore no narrower than the requested price interval.\n *\n * @param args - Pair, fee, price range, deposit amount, and caller-side token index.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.addLiquidityByPrice({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * minPrice: '0.14', maxPrice: '0.16', amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async addLiquidityByPrice(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n minPrice: PriceIn;\n maxPrice: PriceIn;\n amount: NumericAmount;\n amountIsToken0: boolean;\n /** The attempt's `uniqueKey`; default a fresh one (see {@link AddLiquidityArgs.uniqueKey}). */\n uniqueKey?: string | undefined;\n }) {\n validateFee(args.fee);\n this.rejectNumber(args.minPrice, 'minPrice');\n this.rejectNumber(args.maxPrice, 'maxPrice');\n const minPrice = new BigNumber(args.minPrice);\n const maxPrice = new BigNumber(args.maxPrice);\n if (\n !minPrice.isFinite() ||\n !maxPrice.isFinite() ||\n minPrice.isLessThanOrEqualTo(0) ||\n maxPrice.isLessThanOrEqualTo(0)\n ) {\n throw new GSwapSDKError('INVALID_PRICE_BOUNDS', {\n minPrice: String(args.minPrice),\n maxPrice: String(args.maxPrice),\n });\n }\n if (minPrice.isGreaterThan(maxPrice)) {\n throw new GSwapSDKError('PRICE_BOUNDS_ORDER', {\n minPrice: String(args.minPrice),\n maxPrice: String(args.maxPrice),\n });\n }\n const spacing = this.tickSpacing(args.fee);\n const tickLower = alignTickDown(tickFromPrice(minPrice), spacing);\n const tickUpper = alignTickUp(tickFromPrice(maxPrice), spacing);\n return this.addLiquidityByTicks({\n token0: args.token0,\n token1: args.token1,\n fee: args.fee,\n tickLower,\n tickUpper,\n amount: args.amount,\n amountIsToken0: args.amountIsToken0,\n uniqueKey: args.uniqueKey,\n });\n }\n\n /**\n * Removes liquidity by withdrawing at most one canonical token quantity.\n * Omitting both amounts closes the position and sweeps all accrued fees.\n *\n * @param args - Pair, fee, range, and optional caller-side withdrawal amount.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.removeLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async removeLiquidity(args: RemoveLiquidityArgs) {\n return this.submitRemoveLiquidity(await this.buildRemoveLiquidity(args));\n }\n\n /**\n * Builds the RemoveLiquidity DTO that {@link removeLiquidity} would sign, without signing or\n * sending it. Submit exactly this DTO with {@link submitRemoveLiquidity}. The pure counterpart\n * is `buildRemoveLiquidityDto`.\n */\n async buildRemoveLiquidity(args: RemoveLiquidityArgs): Promise<RemoveLiquidityDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n if (args.amount0 !== undefined && args.amount1 !== undefined) {\n throw new GSwapSDKError('AT_MOST_ONE_OF_ALLOWED', { first: 'amount0', second: 'amount1' });\n }\n if (args.amount0 !== undefined) validateNumericAmount(args.amount0, 'amount0');\n if (args.amount1 !== undefined) validateNumericAmount(args.amount1, 'amount1');\n // The caller's amount0 / amount1 follow the caller's pair; the DTO's follow the canonical one.\n const [canonical0, canonical1] = pair.flipped\n ? [args.amount1, args.amount0]\n : [args.amount0, args.amount1];\n return buildRemoveLiquidityDto({\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n withdrawalQuantityToken0: canonical0,\n withdrawalQuantityToken1: canonical1,\n });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildRemoveLiquidity} or `buildRemoveLiquidityDto`;\n * it must be exactly what the builder produces. A DTO with no withdrawal quantity closes the\n * position, and the returned transaction then confirms by proving the position is gone.\n */\n async submitRemoveLiquidity(dto: RemoveLiquidityDTO) {\n assertCanonicalV2Dto('RemoveLiquidity', dto);\n const isFullClose =\n dto.withdrawalQuantityToken0 === undefined && dto.withdrawalQuantityToken1 === undefined;\n return this.submit('RemoveLiquidity', dto, {\n kind: isFullClose ? 'removeFull' : 'removePartial',\n identity: identityOf(dto),\n });\n }\n\n /**\n * Collects all accrued fees for a position; the contract does not support partial collection.\n *\n * @param args - Pair, fee, and tick range identifying the position.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.collectPositionFees({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async collectPositionFees(args: CollectPositionFeesArgs) {\n return this.submitCollectPositionFees(await this.buildCollectPositionFees(args));\n }\n\n /**\n * Builds the CollectPositionFees DTO that {@link collectPositionFees} would sign, without\n * signing or sending it. Submit exactly this DTO with {@link submitCollectPositionFees}. The\n * pure counterpart is `buildCollectPositionFeesDto`.\n */\n async buildCollectPositionFees(args: CollectPositionFeesArgs): Promise<CollectPositionFeesDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n return buildCollectPositionFeesDto({\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildCollectPositionFees} or\n * `buildCollectPositionFeesDto`; it must be exactly what the builder produces.\n */\n async submitCollectPositionFees(dto: CollectPositionFeesDTO) {\n assertCanonicalV2Dto('CollectPositionFees', dto);\n return this.submit('CollectPositionFees', dto, { kind: 'collect', identity: identityOf(dto) });\n }\n\n /**\n * Creates a pool, resolving registered trading symbols.\n * Reversed symbol order inverts the supplied starting price or square-root price.\n *\n * A token class key carries no symbol, so for a token being proposed into the v2\n * trading-symbol registry for the first time (no existing pool has registered it yet) the\n * caller MUST pass `token0Symbol`/`token1Symbol` (the token class's symbol, from the token\n * list or FetchTokenClasses). The SDK never derives a symbol from the key, and throws a\n * TOKEN_SYMBOL_NOT_REGISTERED error when an unregistered token has none. For an already-registered token a\n * supplied symbol must match the registered one.\n *\n * @param args - Token class keys or references, fee, exactly one starting price field, and privacy options.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.createPool({\n * token0: 'GALA|Unit|none|none', token1: 'GUSDC|Unit|none|none', fee: 3000,\n * startingPrice: '0.15',\n * });\n * ```\n */\n async createPool(args: CreatePoolArgs) {\n return this.submitCreatePool(await this.buildCreatePool(args));\n }\n\n /**\n * Builds the CreatePool DTO that {@link createPool} would sign, without signing or sending it:\n * symbols resolved or proposed, the pair put in canonical order and the price inverted when it\n * was reversed. Submit exactly this DTO with {@link submitCreatePool}. The pure counterpart,\n * with canonical inputs, is `buildCreatePoolDto`.\n */\n async buildCreatePool(args: CreatePoolArgs): Promise<CreatePoolDTO> {\n const hasPrice = args.startingPrice !== undefined;\n const hasSqrtPrice = args.startingSqrtPrice !== undefined;\n if (hasPrice === hasSqrtPrice) {\n throw new GSwapSDKError('EXACTLY_ONE_OF_REQUIRED', {\n first: 'startingPrice',\n second: 'startingSqrtPrice',\n });\n }\n validateFee(args.fee);\n const [tokenA, tokenB] = await Promise.all([\n this.resolveCreateToken(args.token0, args.token0Symbol),\n this.resolveCreateToken(args.token1, args.token1Symbol),\n ]);\n const flipped = tokenA.symbol > tokenB.symbol;\n const [token0, token1] = flipped ? [tokenB, tokenA] : [tokenA, tokenB];\n const sourcePriceInput = hasPrice\n ? (args.startingPrice as NumericAmount)\n : (args.startingSqrtPrice as NumericAmount);\n this.rejectNumber(sourcePriceInput, hasPrice ? 'startingPrice' : 'startingSqrtPrice');\n const sourcePrice = new BigNumber(sourcePriceInput);\n if (!sourcePrice.isFinite() || sourcePrice.isLessThanOrEqualTo(0)) {\n throw new GSwapSDKError('INVALID_STARTING_PRICE', { value: String(sourcePriceInput) });\n }\n const canonicalPrice = flipped ? new BigNumber(1).dividedBy(sourcePrice) : sourcePrice;\n const shared = {\n token0Key: token0.classKey,\n token1Key: token1.classKey,\n token0Symbol: token0.symbol,\n token1Symbol: token1.symbol,\n fee: args.fee,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n name: args.name,\n isPrivate: args.isPrivate,\n privateAccess: args.privateAccess,\n };\n return hasPrice\n ? buildCreatePoolDto({ ...shared, startingPrice: canonicalPrice })\n : buildCreatePoolDto({ ...shared, startingSqrtPrice: canonicalPrice });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildCreatePool} or `buildCreatePoolDto`; it must be\n * exactly what the builder produces. The returned transaction confirms by the pool existing, and\n * the cached symbol registry is dropped, since the pool may have registered new symbols.\n */\n async submitCreatePool(dto: CreatePoolDTO) {\n assertCanonicalV2Dto('CreatePool', dto);\n const transaction = await this.submit('CreatePool', dto, {\n kind: 'createPool',\n token0: dto.token0Symbol,\n token1: dto.token1Symbol,\n fee: dto.fee,\n });\n this.symbols.invalidate?.();\n return transaction;\n }\n\n private async submit(\n method: string,\n dto: Record<string, unknown>,\n confirmation?: PositionSubmitConfirmation,\n ) {\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n const signed = await signPreSend(this.signer, method, dto);\n const submitOptions =\n this.walletAddress === undefined ? {} : { walletAddress: this.walletAddress };\n const owner = this.walletAddress;\n const positionConfirmation = this.buildPositionConfirmation(confirmation, owner);\n const options: ChainSubmitOptions = {\n ...submitOptions,\n ...(positionConfirmation === undefined ? {} : { positionConfirmation }),\n };\n return this.gateway.submit(method, signed, options);\n }\n\n /**\n * Builds a confirmation closure that proves the write's own effect, not just that a\n * position row exists (true before most of these writes run too, for any operation on a\n * pre-existing position — existence alone would false-confirm before the write executes,\n * and would never confirm a full close, whose whole point is that the position stops\n * existing).\n *\n * The \"before\" state is captured lazily, on the confirmation closure's own first poll —\n * not eagerly here in `submit()` — so confirming a write never adds an extra round-trip to\n * the write itself; the cost of establishing the baseline is paid by `confirm()`, only if\n * and when the caller actually asks to confirm.\n */\n private buildPositionConfirmation(\n confirmation: PositionSubmitConfirmation | undefined,\n owner: string | undefined,\n ): ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined {\n if (confirmation === undefined) return undefined;\n\n if (confirmation.kind === 'createPool') {\n const { token0, token1, fee } = confirmation;\n return async (signal) => {\n const pool = await this.getNullable<unknown>(\n '/pool',\n { token0, token1, fee: `${fee}` },\n signal,\n );\n return pool === null ? { confirmed: false } : { confirmed: true, position: null };\n };\n }\n\n if (owner === undefined) return undefined;\n const { kind, identity } = confirmation;\n let baseline: { liquidity: BigNumber; fees: BigNumber } | undefined;\n\n return async (signal) => {\n const current = await this.getPosition({ ...identity, owner }, signal);\n\n if (baseline === undefined) {\n // First poll only establishes the baseline to compare future polls against — it can\n // never itself be the confirmed outcome (nothing has been observed to change yet).\n baseline = {\n liquidity: new BigNumber(current?.liquidity ?? 0),\n fees: new BigNumber(current?.fees0 ?? 0).plus(new BigNumber(current?.fees1 ?? 0)),\n };\n // A full close starting from \"already gone\" (e.g. a retried confirm after the position\n // was already swept) is confirmed immediately rather than waiting for a change that\n // already happened.\n return kind === 'removeFull' && current === null\n ? { confirmed: true, position: null }\n : { confirmed: false };\n }\n\n switch (kind) {\n case 'add':\n return current !== null &&\n new BigNumber(current.liquidity).isGreaterThan(baseline.liquidity)\n ? { confirmed: true, position: current }\n : { confirmed: false };\n case 'removePartial':\n return current !== null && new BigNumber(current.liquidity).isLessThan(baseline.liquidity)\n ? { confirmed: true, position: current }\n : { confirmed: false };\n case 'removeFull':\n return current === null ? { confirmed: true, position: null } : { confirmed: false };\n case 'collect': {\n if (current === null) return { confirmed: false };\n const currentFees = new BigNumber(current.fees0 ?? 0).plus(\n new BigNumber(current.fees1 ?? 0),\n );\n if (currentFees.isLessThan(baseline.fees)) return { confirmed: true, position: current };\n // Nothing to sweep in the first place — a legitimate no-op collect never moves\n // fees, so \"still zero\" is the confirmed outcome, not an unconfirmed one.\n if (baseline.fees.isZero() && currentFees.isZero())\n return { confirmed: true, position: current };\n return { confirmed: false };\n }\n }\n };\n }\n\n private async get<TData>(\n endpoint: string,\n params: Record<string, string>,\n signal?: AbortSignal,\n ): Promise<BackendEnvelope<TData>> {\n return this.http.sendGetRequest<BackendEnvelope<TData>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n endpoint,\n params,\n signal === undefined ? undefined : { signal },\n );\n }\n\n private async getNullable<TData>(\n endpoint: string,\n params: Record<string, string>,\n signal?: AbortSignal,\n ): Promise<BackendEnvelope<TData> | null> {\n try {\n return await this.get<TData>(endpoint, params, signal);\n } catch (error: unknown) {\n if (this.isNotFound(error)) return null;\n throw error;\n }\n }\n\n private isNotFound(error: unknown): boolean {\n return isGSwapError(error) && error.status === 404;\n }\n\n private canonicalTicks(tickLower: number, tickUpper: number, flipped: boolean) {\n return flipped ? { tickLower: -tickUpper, tickUpper: -tickLower } : { tickLower, tickUpper };\n }\n\n private tickSpacing(fee: number): number {\n const spacing = (TICK_SPACING_BY_FEE as Record<number, number>)[fee];\n if (spacing === undefined) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n return spacing;\n }\n\n private rejectNumber(value: unknown, parameterName: string): void {\n if (typeof value === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: parameterName });\n }\n }\n\n /** The caller's `uniqueKey` (validated), else a fresh one. */\n private uniqueKeyFor(supplied: string | undefined): string {\n if (supplied === undefined) return createUniqueKey(this.uniqueKeyPrefix);\n assertUniqueKey(supplied);\n return supplied;\n }\n\n /**\n * The pair in canonical order. A resolver failure that is not an SDK error (an app's own\n * resolver, an app requestor's rejection during the registry read) is `TOKEN_RESOLUTION_FAILED`.\n */\n private orderPair(a: TokenRef, b: TokenRef) {\n return resolvePreSend(`${rawTokenOf(a)}/${rawTokenOf(b)}`, () => this.symbols.orderPair(a, b));\n }\n\n private async resolveCreateToken(\n ref: TokenRef,\n symbolOverride?: string,\n ): Promise<ResolvedCreateToken> {\n try {\n const lookupRef = typeof ref === 'object' ? compositeKeyOf(ref) : ref;\n const resolved = await resolvePreSend(rawTokenOf(ref), () => this.symbols.resolve(lookupRef));\n if (\n symbolOverride !== undefined &&\n symbolOverride !== '' &&\n symbolOverride !== resolved.symbol\n ) {\n throw new GSwapSDKError('SYMBOL_DISAGREES_WITH_REGISTRY', {\n token: rawTokenOf(ref),\n suppliedSymbol: symbolOverride,\n registeredSymbol: resolved.symbol,\n });\n }\n const suppliedClassKey = this.tryParseClassKey(ref);\n if (suppliedClassKey === undefined && resolved.collection === '') {\n // An offline resolver knows a bare symbol but not its class key; a pool needs the key.\n throw new GSwapSDKError('CREATE_POOL_NEEDS_CLASS_KEY', { token: rawTokenOf(ref) });\n }\n return {\n symbol: resolved.symbol,\n classKey:\n suppliedClassKey ??\n parseTokenClassKey({\n collection: resolved.collection,\n category: resolved.category,\n type: resolved.type,\n additionalKey: resolved.additionalKey,\n }),\n };\n } catch (error: unknown) {\n if (!isGSwapError(error, 'UNKNOWN_TOKEN')) {\n throw error;\n }\n let classKey: ReturnType<typeof parseTokenClassKey>;\n try {\n classKey = parseTokenClassKey(ref);\n } catch {\n throw error;\n }\n // First-time registration: a class key carries NO symbol (collection and symbol disagree\n // for many tokens, launchpad tokens all share collection `Token`, and some collections\n // contain `$`), so the symbol to propose must be supplied by the caller from the token\n // class / registry. Never derive it from the key.\n if (symbolOverride === undefined || symbolOverride === '') {\n throw new GSwapSDKError('TOKEN_SYMBOL_NOT_REGISTERED', { token: rawTokenOf(ref) });\n }\n if (!isProposableTradingSymbol(symbolOverride)) {\n throw new GSwapSDKError('INVALID_TRADING_SYMBOL', { symbol: symbolOverride });\n }\n return { symbol: symbolOverride, classKey };\n }\n }\n\n private tryParseClassKey(ref: TokenRef): ReturnType<typeof parseTokenClassKey> | undefined {\n try {\n return parseTokenClassKey(ref);\n } catch {\n return undefined;\n }\n }\n}\n\nconst REQUIRED_POSITION_STRINGS = [\n 'token0Symbol',\n 'token1Symbol',\n 'owner',\n 'liquidity',\n 'amount0',\n 'amount1',\n] as const;\nconst REQUIRED_POSITION_NUMBERS = ['fee', 'tickLower', 'tickUpper'] as const;\nconst OPTIONAL_POSITION_STRINGS = [\n 'token0CompositeKey',\n 'token1CompositeKey',\n 'token0Image',\n 'token1Image',\n 'sqrtPrice',\n 'fees0',\n 'fees1',\n] as const;\n\n/**\n * Reads one position row of `/positions` or `/position`: the pair, owner, range, liquidity and\n * amounts must be usable; the composite keys, token images, current tick and price, and the\n * escrowed fees are carried when present. `pool` is the pool reference (`poolRef` wins over\n * `pool`; `''` when the row names neither).\n */\nfunction parsePosition(value: unknown): EntryParse<Position> {\n const wire = asEntryRecord(value);\n if (wire === undefined) return entryRejected('the row is not an object');\n for (const key of REQUIRED_POSITION_STRINGS) {\n if (typeof wire[key] !== 'string') return entryRejected(`${key} is not a string`);\n }\n for (const key of REQUIRED_POSITION_NUMBERS) {\n const number = wire[key];\n if (typeof number !== 'number' || !Number.isFinite(number)) {\n return entryRejected(`${key} is not a number`);\n }\n }\n if (typeof wire['inRange'] !== 'boolean') return entryRejected('inRange is not a boolean');\n for (const key of OPTIONAL_POSITION_STRINGS) {\n if (wire[key] !== undefined && typeof wire[key] !== 'string') {\n return entryRejected(`${key} is not a string`);\n }\n }\n const currentTick = wire['currentTick'];\n if (\n currentTick !== undefined &&\n (typeof currentTick !== 'number' || !Number.isFinite(currentTick))\n ) {\n return entryRejected('currentTick is not a number');\n }\n const pool = wire['poolRef'] ?? wire['pool'] ?? '';\n if (typeof pool !== 'string') return entryRejected('pool is not a string');\n const optional = Object.fromEntries(\n [...OPTIONAL_POSITION_STRINGS, 'currentTick' as const].flatMap((key) =>\n wire[key] === undefined ? [] : [[key, wire[key]]],\n ),\n );\n return entryOk({\n token0Symbol: wire['token0Symbol'] as string,\n token1Symbol: wire['token1Symbol'] as string,\n fee: wire['fee'] as number,\n tickLower: wire['tickLower'] as number,\n tickUpper: wire['tickUpper'] as number,\n liquidity: wire['liquidity'] as string,\n amount0: wire['amount0'] as string,\n amount1: wire['amount1'] as string,\n inRange: wire['inRange'],\n pool,\n owner: wire['owner'] as string,\n ...optional,\n });\n}\n\n/** The position inside a `/position` answer, or `INVALID_CHAIN_RESPONSE` when it is not one. */\nfunction readPositionBody(data: unknown): Position {\n const parsed = parsePosition(data);\n if (parsed.ok) return parsed.value;\n throw new GSwapSDKError(\n 'INVALID_POSITION_RESPONSE',\n { reason: parsed.reason },\n { body: data, write: false },\n );\n}\n"],"mappings":"orCAqIA,SAASE,EACP,EACkB,CAClB,MAAO,CACL,OAAQC,EAAI,OACZ,OAAQA,EAAI,OACZ,IAAKA,EAAI,IACT,UAAWA,EAAI,UACf,UAAWA,EAAI,SACjB,CACF,CA6DA,IAAaC,EAAb,KAAuB,CACrB,YACE,EACA,EACA,EACA,EACA,EAA4B,CAAC,EAC7B,CALiB,KAAA,QAAAC,EACA,KAAA,QAAAC,EACA,KAAA,OAAAC,EAgBFP,EAAA,KAAA,gBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,OAAA,IAAA,EAAA,EACAA,EAAA,KAAA,kBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,iBAAA,IAAA,EAAA,EAff,KAAK,cACHQ,IAAkB,IAAA,GAAY,IAAA,GAAYC,EAAQD,EAAe,eAAe,EAClF,KAAK,KAAO,IAAIE,EACdL,EAAQ,cACRA,EAAQ,kBAAoB,IAC5BA,EAAQ,IACV,EACA,KAAK,gBAAkBM,EAAuBC,EAAQ,eAAe,EACrE,KAAK,eAAiBA,EAAQ,cAChC,CAmBA,MAAM,iBAAiB,EAAoC,CACzD,IAAMC,EAAW,MAAM,KAAK,IAAa,aAAc,CAAE,KAAMJ,EAAQK,EAAO,OAAO,CAAE,CAAC,EACxF,OAAOC,EAAY,YAAaF,EAAS,KAAMG,EAAe,KAAK,cAAc,CACnF,CAgBA,MAAM,YACJ,EAQA,EAC0B,CAC1B,IAAMH,EAAW,MAAM,KAAK,YAC1B,YACA,MAAM,KAAK,eAAeI,CAAI,EAC9BC,CACF,EACA,OAAOL,IAAa,KAAO,KAAOM,EAAiBN,EAAS,IAAI,CAClE,CAoBA,MAAM,aACJ,EAQA,EACuB,CACvB,GAAI,CACF,IAAMO,EAAW,MAAM,KAAK,YAAYH,EAAMC,CAAM,EACpD,OAAOE,IAAa,KAAO,CAAE,KAAM,WAAY,EAAI,CAAE,KAAM,QAAS,KAAMA,CAAS,CACrF,OAASC,EAAgB,CACvB,GAAIH,GAAQ,UAAY,GAAM,MAAMG,EACpC,MAAO,CACL,KAAM,UACN,MAAOC,EAAaD,CAAK,EACrBA,EACA,IAAIE,EACF,iBACA,CAAE,UAAW,UAAW,EACxB,CAAE,MAAOF,EAAO,MAAO,EAAM,CAC/B,CACN,CACF,CACF,CAMA,MAAc,eAAe,EAOO,CAGlC,IAAMP,EAAQL,EAAQQ,EAAK,MAAO,OAAO,EACzC,GAAI,KAAK,QAAQ,cAAgB,GAC/B,MAAO,CACL,OAAQO,EAAWP,EAAK,MAAM,EAC9B,OAAQO,EAAWP,EAAK,MAAM,EAC9B,IAAK,GAAGA,EAAK,MACb,QACA,UAAW,GAAGA,EAAK,YACnB,UAAW,GAAGA,EAAK,WACrB,EAEF,IAAMQ,EAAO,MAAM,KAAK,UAAUR,EAAK,OAAQA,EAAK,MAAM,EACpDS,EAAQ,KAAK,eAAeT,EAAK,UAAWA,EAAK,UAAWQ,EAAK,OAAO,EAC9E,MAAO,CACL,OAAQA,EAAK,OAAO,OACpB,OAAQA,EAAK,OAAO,OACpB,IAAK,GAAGR,EAAK,MACb,QACA,UAAW,GAAGS,EAAM,YACpB,UAAW,GAAGA,EAAM,WACtB,CACF,CAeA,MAAM,qBAAqB,EAQO,CAWhC,OAVAC,EAAsBV,EAAK,OAAQ,QAAQ,GAUpC,MATgB,KAAK,IAA8B,oBAAqB,CAC7E,OAAQO,EAAWP,EAAK,MAAM,EAC9B,OAAQO,EAAWP,EAAK,MAAM,EAC9B,IAAK,GAAGA,EAAK,MACb,UAAW,GAAGA,EAAK,YACnB,UAAW,GAAGA,EAAK,YACnB,OAAQ,IAAIhB,EAAUgB,EAAK,MAAM,CAAC,CAAC,QAAQ,EAC3C,eAAgB,OAAOA,EAAK,cAAc,CAC5C,CAAC,EAAA,CACe,IAClB,CAeA,MAAM,wBAAwB,EAOO,CAUnC,OATAU,EAAsBV,EAAK,UAAW,WAAW,GAS1C,MARgB,KAAK,IAAiC,uBAAwB,CACnF,OAAQO,EAAWP,EAAK,MAAM,EAC9B,OAAQO,EAAWP,EAAK,MAAM,EAC9B,IAAK,GAAGA,EAAK,MACb,UAAW,GAAGA,EAAK,YACnB,UAAW,GAAGA,EAAK,YACnB,UAAW,IAAIhB,EAAUgB,EAAK,SAAS,CAAC,CAAC,QAAQ,CACnD,CAAC,EAAA,CACe,IAClB,CAgBA,MAAM,oBAAoB,EAAwB,CAChD,OAAO,KAAK,mBAAmB,MAAM,KAAK,kBAAkBA,CAAI,CAAC,CACnE,CAgBA,MAAM,kBAAkB,EAAkD,CACxEW,EAAYX,EAAK,GAAG,EACpB,IAAMQ,EAAO,MAAM,KAAK,UAAUR,EAAK,OAAQA,EAAK,MAAM,EACpDS,EAAQ,KAAK,eAAeT,EAAK,UAAWA,EAAK,UAAWQ,EAAK,OAAO,EAE9EI,EAAgBH,EAAM,UAAWA,EAAM,UAAWT,EAAK,GAAG,EAC1DU,EAAsBV,EAAK,OAAQ,QAAQ,EAC3C,IAAMa,EAAO,CACX,OAAQL,EAAK,OAAO,OACpB,OAAQA,EAAK,OAAO,OACpB,IAAKR,EAAK,IACV,UAAWS,EAAM,UACjB,UAAWA,EAAM,UACjB,UAAW,KAAK,aAAaT,EAAK,SAAS,CAC7C,EACA,OAAOQ,EAAK,UAAYR,EAAK,eAEzBc,EAAqB,CAAE,GAAGD,EAAM,sBAAuBb,EAAK,MAAO,CAAC,EADpEc,EAAqB,CAAE,GAAGD,EAAM,sBAAuBb,EAAK,MAAO,CAAC,CAE1E,CAOA,MAAM,mBAAmB,EAAsB,CAE7C,OADAe,EAAqB,eAAgB7B,CAAG,EACjC,KAAK,OAAO,eAAgBA,EAAK,CAAE,KAAM,MAAO,SAAUD,EAAWC,CAAG,CAAE,CAAC,CACpF,CAgBA,MAAM,oBAAoB,EAUvB,CACDyB,EAAYX,EAAK,GAAG,EACpB,KAAK,aAAaA,EAAK,SAAU,UAAU,EAC3C,KAAK,aAAaA,EAAK,SAAU,UAAU,EAC3C,IAAMgB,EAAW,IAAIhC,EAAUgB,EAAK,QAAQ,EACtCiB,EAAW,IAAIjC,EAAUgB,EAAK,QAAQ,EAC5C,GACE,CAACgB,EAAS,SAAS,GACnB,CAACC,EAAS,SAAS,GACnBD,EAAS,oBAAoB,CAAC,GAC9BC,EAAS,oBAAoB,CAAC,EAE9B,MAAM,IAAIX,EAAc,uBAAwB,CAC9C,SAAU,OAAON,EAAK,QAAQ,EAC9B,SAAU,OAAOA,EAAK,QAAQ,CAChC,CAAC,EAEH,GAAIgB,EAAS,cAAcC,CAAQ,EACjC,MAAM,IAAIX,EAAc,qBAAsB,CAC5C,SAAU,OAAON,EAAK,QAAQ,EAC9B,SAAU,OAAOA,EAAK,QAAQ,CAChC,CAAC,EAEH,IAAMkB,EAAU,KAAK,YAAYlB,EAAK,GAAG,EACnCmB,EAAYC,EAAcC,EAAcL,CAAQ,EAAGE,CAAO,EAC1DI,EAAYC,EAAYF,EAAcJ,CAAQ,EAAGC,CAAO,EAC9D,OAAO,KAAK,oBAAoB,CAC9B,OAAQlB,EAAK,OACb,OAAQA,EAAK,OACb,IAAKA,EAAK,IACV,YACA,YACA,OAAQA,EAAK,OACb,eAAgBA,EAAK,eACrB,UAAWA,EAAK,SAClB,CAAC,CACH,CAgBA,MAAM,gBAAgB,EAA2B,CAC/C,OAAO,KAAK,sBAAsB,MAAM,KAAK,qBAAqBA,CAAI,CAAC,CACzE,CAOA,MAAM,qBAAqB,EAAwD,CACjFW,EAAYX,EAAK,GAAG,EACpB,IAAMQ,EAAO,MAAM,KAAK,UAAUR,EAAK,OAAQA,EAAK,MAAM,EACpDS,EAAQ,KAAK,eAAeT,EAAK,UAAWA,EAAK,UAAWQ,EAAK,OAAO,EAE9E,GADAI,EAAgBH,EAAM,UAAWA,EAAM,UAAWT,EAAK,GAAG,EACtDA,EAAK,UAAY,IAAA,IAAaA,EAAK,UAAY,IAAA,GACjD,MAAM,IAAIM,EAAc,yBAA0B,CAAE,MAAO,UAAW,OAAQ,SAAU,CAAC,EAEvFN,EAAK,UAAY,IAAA,IAAWU,EAAsBV,EAAK,QAAS,SAAS,EACzEA,EAAK,UAAY,IAAA,IAAWU,EAAsBV,EAAK,QAAS,SAAS,EAE7E,GAAM,CAACwB,EAAYC,GAAcjB,EAAK,QAClC,CAACR,EAAK,QAASA,EAAK,OAAO,EAC3B,CAACA,EAAK,QAASA,EAAK,OAAO,EAC/B,OAAO0B,EAAwB,CAC7B,OAAQlB,EAAK,OAAO,OACpB,OAAQA,EAAK,OAAO,OACpB,IAAKR,EAAK,IACV,UAAWS,EAAM,UACjB,UAAWA,EAAM,UACjB,UAAW,KAAK,aAAaT,EAAK,SAAS,EAC3C,yBAA0BwB,EAC1B,yBAA0BC,CAC5B,CAAC,CACH,CAOA,MAAM,sBAAsB,EAAyB,CACnDV,EAAqB,kBAAmB7B,CAAG,EAC3C,IAAMyC,EACJzC,EAAI,2BAA6B,IAAA,IAAaA,EAAI,2BAA6B,IAAA,GACjF,OAAO,KAAK,OAAO,kBAAmBA,EAAK,CACzC,KAAMyC,EAAc,aAAe,gBACnC,SAAU1C,EAAWC,CAAG,CAC1B,CAAC,CACH,CAeA,MAAM,oBAAoB,EAA+B,CACvD,OAAO,KAAK,0BAA0B,MAAM,KAAK,yBAAyBc,CAAI,CAAC,CACjF,CAOA,MAAM,yBAAyB,EAAgE,CAC7FW,EAAYX,EAAK,GAAG,EACpB,IAAMQ,EAAO,MAAM,KAAK,UAAUR,EAAK,OAAQA,EAAK,MAAM,EACpDS,EAAQ,KAAK,eAAeT,EAAK,UAAWA,EAAK,UAAWQ,EAAK,OAAO,EAE9E,OADAI,EAAgBH,EAAM,UAAWA,EAAM,UAAWT,EAAK,GAAG,EACnD4B,EAA4B,CACjC,OAAQpB,EAAK,OAAO,OACpB,OAAQA,EAAK,OAAO,OACpB,IAAKR,EAAK,IACV,UAAWS,EAAM,UACjB,UAAWA,EAAM,UACjB,UAAW,KAAK,aAAaT,EAAK,SAAS,CAC7C,CAAC,CACH,CAMA,MAAM,0BAA0B,EAA6B,CAE3D,OADAe,EAAqB,sBAAuB7B,CAAG,EACxC,KAAK,OAAO,sBAAuBA,EAAK,CAAE,KAAM,UAAW,SAAUD,EAAWC,CAAG,CAAE,CAAC,CAC/F,CAuBA,MAAM,WAAW,EAAsB,CACrC,OAAO,KAAK,iBAAiB,MAAM,KAAK,gBAAgBc,CAAI,CAAC,CAC/D,CAQA,MAAM,gBAAgB,EAA8C,CAClE,IAAM6B,EAAW7B,EAAK,gBAAkB,IAAA,GAExC,GAAI6B,KADiB7B,EAAK,oBAAsB,IAAA,IAE9C,MAAM,IAAIM,EAAc,0BAA2B,CACjD,MAAO,gBACP,OAAQ,mBACV,CAAC,EAEHK,EAAYX,EAAK,GAAG,EACpB,GAAM,CAAC8B,EAAQC,GAAU,MAAM,QAAQ,IAAI,CACzC,KAAK,mBAAmB/B,EAAK,OAAQA,EAAK,YAAY,EACtD,KAAK,mBAAmBA,EAAK,OAAQA,EAAK,YAAY,CACxD,CAAC,EACKgC,EAAUF,EAAO,OAASC,EAAO,OACjC,CAACE,EAAQC,GAAUF,EAAU,CAACD,EAAQD,CAAM,EAAI,CAACA,EAAQC,CAAM,EAC/DI,EAAmBN,EACpB7B,EAAK,cACLA,EAAK,kBACV,KAAK,aAAamC,EAAkBN,EAAW,gBAAkB,mBAAmB,EACpF,IAAMO,EAAc,IAAIpD,EAAUmD,CAAgB,EAClD,GAAI,CAACC,EAAY,SAAS,GAAKA,EAAY,oBAAoB,CAAC,EAC9D,MAAM,IAAI9B,EAAc,yBAA0B,CAAE,MAAO,OAAO6B,CAAgB,CAAE,CAAC,EAEvF,IAAME,EAAiBL,EAAU,IAAIhD,EAAU,CAAC,CAAC,CAAC,UAAUoD,CAAW,EAAIA,EACrEE,EAAS,CACb,UAAWL,EAAO,SAClB,UAAWC,EAAO,SAClB,aAAcD,EAAO,OACrB,aAAcC,EAAO,OACrB,IAAKlC,EAAK,IACV,UAAW,KAAK,aAAaA,EAAK,SAAS,EAC3C,KAAMA,EAAK,KACX,UAAWA,EAAK,UAChB,cAAeA,EAAK,aACtB,EACA,OACIuC,EADGV,EACgB,CAAE,GAAGS,EAAQ,cAAeD,CAAe,EAC3C,CAAE,GAAGC,EAAQ,kBAAmBD,CAAe,CAAC,CACzE,CAOA,MAAM,iBAAiB,EAAoB,CACzCtB,EAAqB,aAAc7B,CAAG,EACtC,IAAMsD,EAAc,MAAM,KAAK,OAAO,aAActD,EAAK,CACvD,KAAM,aACN,OAAQA,EAAI,aACZ,OAAQA,EAAI,aACZ,IAAKA,EAAI,GACX,CAAC,EAED,OADA,KAAK,QAAQ,aAAa,EACnBsD,CACT,CAEA,MAAc,OACZ,EACA,EACA,EACA,CACA,GAAI,KAAK,SAAW,IAAA,GAAW,MAAMlC,EAAc,cAAc,EACjE,IAAMmC,EAAS,MAAMC,EAAY,KAAK,OAAQC,EAAQzD,CAAG,EACnD0D,EACJ,KAAK,gBAAkB,IAAA,GAAY,CAAC,EAAI,CAAE,cAAe,KAAK,aAAc,EACxE/C,EAAQ,KAAK,cACbgD,EAAuB,KAAK,0BAA0BC,EAAcjD,CAAK,EACzEF,EAA8B,CAClC,GAAGiD,EACH,GAAIC,IAAyB,IAAA,GAAY,CAAC,EAAI,CAAE,sBAAqB,CACvE,EACA,OAAO,KAAK,QAAQ,OAAOF,EAAQF,EAAQ9C,CAAO,CACpD,CAcA,0BACE,EACA,EAC4E,CAC5E,GAAImD,IAAiB,IAAA,GAAW,OAEhC,GAAIA,EAAa,OAAS,aAAc,CACtC,GAAM,CAAE,SAAQ,SAAQ,OAAQA,EAChC,OAAO,KAAO,IAML,MALY,KAAK,YACtB,QACA,CAAE,SAAQ,SAAQ,IAAK,GAAGC,GAAM,EAChC9C,CACF,IACgB,KAAO,CAAE,UAAW,EAAM,EAAI,CAAE,UAAW,GAAM,SAAU,IAAK,CAEpF,CAEA,GAAIJ,IAAU,IAAA,GAAW,OACzB,GAAM,CAAE,OAAM,YAAaiD,EACvBE,EAEJ,OAAO,KAAO,IAAW,CACvB,IAAMC,EAAU,MAAM,KAAK,YAAY,CAAE,GAAGC,EAAU,OAAM,EAAGjD,CAAM,EAErE,GAAI+C,IAAa,IAAA,GAUf,MAPA,GAAW,CACT,UAAW,IAAIhE,EAAUiE,GAAS,WAAa,CAAC,EAChD,KAAM,IAAIjE,EAAUiE,GAAS,OAAS,CAAC,CAAC,CAAC,KAAK,IAAIjE,EAAUiE,GAAS,OAAS,CAAC,CAAC,CAClF,EAIOE,IAAS,cAAgBF,IAAY,KACxC,CAAE,UAAW,GAAM,SAAU,IAAK,EAClC,CAAE,UAAW,EAAM,EAGzB,OAAQE,EAAR,CACE,IAAK,MACH,OAAOF,IAAY,MACjB,IAAIjE,EAAUiE,EAAQ,SAAS,CAAC,CAAC,cAAcD,EAAS,SAAS,EAC/D,CAAE,UAAW,GAAM,SAAUC,CAAQ,EACrC,CAAE,UAAW,EAAM,EACzB,IAAK,gBACH,OAAOA,IAAY,MAAQ,IAAIjE,EAAUiE,EAAQ,SAAS,CAAC,CAAC,WAAWD,EAAS,SAAS,EACrF,CAAE,UAAW,GAAM,SAAUC,CAAQ,EACrC,CAAE,UAAW,EAAM,EACzB,IAAK,aACH,OAAOA,IAAY,KAAO,CAAE,UAAW,GAAM,SAAU,IAAK,EAAI,CAAE,UAAW,EAAM,EACrF,IAAK,UAAW,CACd,GAAIA,IAAY,KAAM,MAAO,CAAE,UAAW,EAAM,EAChD,IAAMG,EAAc,IAAIpE,EAAUiE,EAAQ,OAAS,CAAC,CAAC,CAAC,KACpD,IAAIjE,EAAUiE,EAAQ,OAAS,CAAC,CAClC,EAMA,OALIG,EAAY,WAAWJ,EAAS,IAAI,GAGpCA,EAAS,KAAK,OAAO,GAAKI,EAAY,OAAO,EACxC,CAAE,UAAW,GAAM,SAAUH,CAAQ,EACvC,CAAE,UAAW,EAAM,CAC5B,CACF,CACF,CACF,CAEA,MAAc,IACZ,EACA,EACA,EACiC,CACjC,OAAO,KAAK,KAAK,eACf,KAAK,QAAQ,kBACb,YACAI,EACAC,EACArD,IAAW,IAAA,GAAY,IAAA,GAAY,CAAE,QAAO,CAC9C,CACF,CAEA,MAAc,YACZ,EACA,EACA,EACwC,CACxC,GAAI,CACF,OAAO,MAAM,KAAK,IAAWoD,EAAUC,EAAQrD,CAAM,CACvD,OAASG,EAAgB,CACvB,GAAI,KAAK,WAAWA,CAAK,EAAG,OAAO,KACnC,MAAMA,CACR,CACF,CAEA,WAAmB,EAAyB,CAC1C,OAAOC,EAAaD,CAAK,GAAKA,EAAM,SAAW,GACjD,CAEA,eAAuB,EAAmB,EAAmB,EAAkB,CAC7E,OAAO4B,EAAU,CAAE,UAAW,CAACV,EAAW,UAAW,CAACH,CAAU,EAAI,CAAE,YAAW,WAAU,CAC7F,CAEA,YAAoB,EAAqB,CACvC,IAAMD,EAAWqC,EAA+CR,GAChE,GAAI7B,IAAY,IAAA,GACd,MAAM,IAAIZ,EAAc,cAAe,CACrC,MAAO,MACP,MAAOyC,EACP,QAASS,CACX,CAAC,EAEH,OAAOtC,CACT,CAEA,aAAqB,EAAgB,EAA6B,CAChE,GAAI,OAAOuC,GAAU,SACnB,MAAM,IAAInD,EAAc,sBAAuB,CAAE,MAAOoD,CAAc,CAAC,CAE3E,CAGA,aAAqB,EAAsC,CAGzD,OAFIC,IAAa,IAAA,GAAkBC,EAAgB,KAAK,eAAe,GACvEC,EAAgBF,CAAQ,EACjBA,EACT,CAMA,UAAkB,EAAa,EAAa,CAC1C,OAAOG,EAAe,GAAGvD,EAAWwD,CAAC,EAAE,GAAGxD,EAAWyD,CAAC,QAAW,KAAK,QAAQ,UAAUD,EAAGC,CAAC,CAAC,CAC/F,CAEA,MAAc,mBACZ,EACA,EAC8B,CAC9B,GAAI,CACF,IAAMC,EAAY,OAAOC,GAAQ,SAAWC,EAAeD,CAAG,EAAIA,EAC5DE,EAAW,MAAMN,EAAevD,EAAW2D,CAAG,MAAS,KAAK,QAAQ,QAAQD,CAAS,CAAC,EAC5F,GACEI,IAAmB,IAAA,IACnBA,IAAmB,IACnBA,IAAmBD,EAAS,OAE5B,MAAM,IAAI9D,EAAc,iCAAkC,CACxD,MAAOC,EAAW2D,CAAG,EACrB,eAAgBG,EAChB,iBAAkBD,EAAS,MAC7B,CAAC,EAEH,IAAME,EAAmB,KAAK,iBAAiBJ,CAAG,EAClD,GAAII,IAAqB,IAAA,IAAaF,EAAS,aAAe,GAE5D,MAAM,IAAI9D,EAAc,8BAA+B,CAAE,MAAOC,EAAW2D,CAAG,CAAE,CAAC,EAEnF,MAAO,CACL,OAAQE,EAAS,OACjB,SACEE,GACAC,EAAmB,CACjB,WAAYH,EAAS,WACrB,SAAUA,EAAS,SACnB,KAAMA,EAAS,KACf,cAAeA,EAAS,aAC1B,CAAC,CACL,CACF,OAAShE,EAAgB,CACvB,GAAI,CAACC,EAAaD,EAAO,eAAe,EACtC,MAAMA,EAER,IAAIoE,EACJ,GAAI,CACF,EAAWD,EAAmBL,CAAG,CACnC,MAAQ,CACN,MAAM9D,CACR,CAKA,GAAIiE,IAAmB,IAAA,IAAaA,IAAmB,GACrD,MAAM,IAAI/D,EAAc,8BAA+B,CAAE,MAAOC,EAAW2D,CAAG,CAAE,CAAC,EAEnF,GAAI,CAACO,EAA0BJ,CAAc,EAC3C,MAAM,IAAI/D,EAAc,yBAA0B,CAAE,OAAQ+D,CAAe,CAAC,EAE9E,MAAO,CAAE,OAAQA,EAAgB,UAAS,CAC5C,CACF,CAEA,iBAAyB,EAAkE,CACzF,GAAI,CACF,OAAOE,EAAmBL,CAAG,CAC/B,MAAQ,CACN,MACF,CACF,CACF,EAEA,MAAMQ,EAA4B,CAChC,eACA,eACA,QACA,YACA,UACA,SACF,EACMC,EAA4B,CAAC,MAAO,YAAa,WAAW,EAC5DC,EAA4B,CAChC,qBACA,qBACA,cACA,cACA,YACA,QACA,OACF,EAQA,SAAS7E,EAAc,EAAsC,CAC3D,IAAM8E,EAAOC,EAAcrB,CAAK,EAChC,GAAIoB,IAAS,IAAA,GAAW,OAAOE,EAAc,0BAA0B,EACvE,IAAK,IAAMC,KAAON,EAChB,GAAI,OAAOG,EAAKG,IAAS,SAAU,OAAOD,EAAc,GAAGC,EAAI,iBAAiB,EAElF,IAAK,IAAMA,KAAOL,EAA2B,CAC3C,IAAMM,EAASJ,EAAKG,GACpB,GAAI,OAAOC,GAAW,UAAY,CAAC,OAAO,SAASA,CAAM,EACvD,OAAOF,EAAc,GAAGC,EAAI,iBAAiB,CAEjD,CACA,GAAI,OAAOH,EAAKK,SAAe,UAAW,OAAOH,EAAc,0BAA0B,EACzF,IAAK,IAAMC,KAAOJ,EAChB,GAAIC,EAAKG,KAAS,IAAA,IAAa,OAAOH,EAAKG,IAAS,SAClD,OAAOD,EAAc,GAAGC,EAAI,iBAAiB,EAGjD,IAAMG,EAAcN,EAAKO,YACzB,GACED,IAAgB,IAAA,KACf,OAAOA,GAAgB,UAAY,CAAC,OAAO,SAASA,CAAW,GAEhE,OAAOJ,EAAc,6BAA6B,EAEpD,IAAMM,EAAOR,EAAKS,SAAcT,EAAKU,MAAW,GAChD,GAAI,OAAOF,GAAS,SAAU,OAAON,EAAc,sBAAsB,EACzE,IAAMS,EAAW,OAAO,YACtB,CAAC,GAAGZ,EAA2B,aAAsB,CAAC,CAAC,QAAS,GAC9DC,EAAKG,KAAS,IAAA,GAAY,CAAC,EAAI,CAAC,CAACA,EAAKH,EAAKG,EAAI,CAAC,CAClD,CACF,EACA,OAAOS,EAAQ,CACb,aAAcZ,EAAKa,aACnB,aAAcb,EAAKc,aACnB,IAAKd,EAAKe,IACV,UAAWf,EAAKgB,UAChB,UAAWhB,EAAKiB,UAChB,UAAWjB,EAAKkB,UAChB,QAASlB,EAAKmB,QACd,QAASnB,EAAKoB,QACd,QAASpB,EAAKK,QACd,OACA,MAAOL,EAAKqB,MACZ,GAAGV,CACL,CAAC,CACH,CAGA,SAAStF,EAAiB,EAAyB,CACjD,IAAMiG,EAASpG,EAAcqG,CAAI,EACjC,GAAID,EAAO,GAAI,OAAOA,EAAO,MAC7B,MAAM,IAAI7F,EACR,4BACA,CAAE,OAAQ6F,EAAO,MAAO,EACxB,CAAE,KAAMC,EAAM,MAAO,EAAM,CAC7B,CACF"}
1
+ {"version":3,"file":"positions.js","names":["_defineProperty","BigNumber","identityOf","dto","Positions","gateway","symbols","signer","walletAddress","userRef","HttpClient","resolveUniqueKeyPrefix","options","response","owner","readEntries","parsePosition","args","signal","readPositionBody","position","error","isGSwapError","GSwapSDKError","rawTokenOf","pair","ticks","validateNumericAmount","validateFee","assertTickRange","base","buildAddLiquidityDto","assertCanonicalV2Dto","minPrice","maxPrice","spacing","tickLower","alignTickDown","tickFromPrice","tickUpper","alignTickUp","canonical0","canonical1","buildRemoveLiquidityDto","isFullClose","buildCollectPositionFeesDto","hasPrice","tokenA","tokenB","flipped","token0","token1","sourcePriceInput","sourcePrice","canonicalPrice","shared","buildCreatePoolDto","transaction","signed","signPreSend","method","submitOptions","positionConfirmation","confirmation","fee","toBaseline","current","baseline","kind","identity","currentFees","endpoint","params","TICK_SPACING_BY_FEE","ALLOWED_FEE_TIERS_TEXT","value","parameterName","supplied","createUniqueKey","assertUniqueKey","resolvePreSend","a","b","lookupRef","ref","compositeKeyOf","resolved","symbolOverride","suppliedClassKey","parseTokenClassKey","classKey","isProposableTradingSymbol","REQUIRED_POSITION_STRINGS","REQUIRED_POSITION_NUMBERS","OPTIONAL_POSITION_STRINGS","wire","asEntryRecord","entryRejected","key","number","\"inRange\"","currentTick","\"currentTick\"","pool","\"poolRef\"","\"pool\"","optional","entryOk","\"token0Symbol\"","\"token1Symbol\"","\"fee\"","\"tickLower\"","\"tickUpper\"","\"liquidity\"","\"amount0\"","\"amount1\"","\"owner\"","parsed","data"],"sources":["../../../src/classes/positions.ts"],"sourcesContent":["import {\n assertUniqueKey,\n compositeKeyOf,\n createUniqueKey,\n resolveUniqueKeyPrefix,\n signPreSend,\n type GalaChainSigner,\n type UniqueKeyOptions,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport BigNumber from 'bignumber.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from './gswap_error_catalog.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport type { ChainGateway, ChainSubmitOptions } from './gateway.js';\nimport type { PositionConfirmationResult, SubmittedTransaction } from './submitted_transaction.js';\nimport { HttpClient } from './http_client.js';\nimport { rawTokenOf, type Symbols, type TokenResolver } from './symbols.js';\nimport type { NumericAmount, PriceIn } from '../types/amounts.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { TICK_SPACING_BY_FEE } from '../types/fees.js';\nimport type {\n AddLiquidityDTO,\n CollectPositionFeesDTO,\n CreatePoolDTO,\n RemoveLiquidityDTO,\n} from '../types/v2_dtos.js';\nimport type {\n AddLiquidityEstimate,\n Position,\n RemoveLiquidityEstimate,\n} from '../types/v2_results.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport { type TokenRef, parseTokenClassKey } from '../utils/ordering.js';\nimport { resolvePreSend } from '../utils/resolve_pre_send.js';\nimport {\n isProposableTradingSymbol,\n validateFee,\n userRef,\n validateNumericAmount,\n} from '../utils/validation.js';\nimport { tickFromPrice } from '../utils/tick_math.js';\nimport { alignTickDown, alignTickUp, assertTickRange } from '../utils/ticks.js';\nimport {\n assertCanonicalV2Dto,\n buildAddLiquidityDto,\n buildCollectPositionFeesDto,\n buildCreatePoolDto,\n buildRemoveLiquidityDto,\n} from '../utils/dto_builders.js';\n\ntype PositionGateway = Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n submit: (\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ) => Promise<SubmittedTransaction<Position | null>>;\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n};\ntype PositionSymbols = TokenResolver & Pick<Symbols, 'orderPair'> & { invalidate?: () => void };\n\n/** Options of {@link Positions}: the `uniqueKey` prefix and a handler for skipped list rows. */\nexport interface PositionsOptions extends UniqueKeyOptions {\n /** Told about every position row of a list that was skipped as unusable. */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n}\n\n/** A write's optional attempt identity. */\ninterface UniqueKeyArg {\n /**\n * The attempt's `uniqueKey` (1-128 characters of `A-Za-z0-9._:-`). Default: a fresh\n * `<uniqueKeyPrefix><uuid>`. Supply one to know the key before signing, or to retry the SAME\n * attempt after a lost response; never reuse it for another write.\n */\n uniqueKey?: string | undefined;\n}\n\n/** Arguments of {@link Positions.addLiquidityByTicks} and {@link Positions.buildAddLiquidity}. */\nexport interface AddLiquidityArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n amount: NumericAmount;\n /** Whether `amount` is of `token0` as the caller passed it (not of the canonical token0). */\n amountIsToken0: boolean;\n}\n\n/** Arguments of {@link Positions.removeLiquidity} and {@link Positions.buildRemoveLiquidity}. */\nexport interface RemoveLiquidityArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n /** Withdraw this much of the caller's `token0`; give at most one of `amount0` / `amount1`. */\n amount0?: NumericAmount | undefined;\n amount1?: NumericAmount | undefined;\n}\n\n/** Arguments of {@link Positions.collectPositionFees} and {@link Positions.buildCollectPositionFees}. */\nexport interface CollectPositionFeesArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n}\n\n/** Arguments of {@link Positions.createPool} and {@link Positions.buildCreatePool}. */\nexport interface CreatePoolArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n token0Symbol?: string | undefined;\n token1Symbol?: string | undefined;\n fee: FEE_TIER;\n startingPrice?: NumericAmount | undefined;\n startingSqrtPrice?: NumericAmount | undefined;\n /** Optional pool display name, sent as the DTO's `name`; omitted when undefined or empty. */\n name?: string | undefined;\n isPrivate?: boolean | undefined;\n privateAccess?: string[] | undefined;\n}\n\n/** The pool position a liquidity DTO names, as its confirmation needs it. */\nfunction identityOf(\n dto: Pick<CollectPositionFeesDTO, 'token0' | 'token1' | 'fee' | 'tickLower' | 'tickUpper'>,\n): PositionIdentity {\n return {\n token0: dto.token0,\n token1: dto.token1,\n fee: dto.fee,\n tickLower: dto.tickLower,\n tickUpper: dto.tickUpper,\n };\n}\n\n/**\n * The outcome of {@link Positions.readPosition}. Only `not_found` is chain-confirmed absence (the\n * backend answers HTTP 404 only when the chain itself found no such position); `unknown` is \"no\n * evidence either way\" — a transport failure, a gateway timeout, any other error status or an\n * answer that is not a position — and must never be read as a removal.\n */\nexport type PositionRead =\n | { kind: 'found'; data: Position }\n | { kind: 'not_found' }\n | { kind: 'unknown'; error: GSwapSDKError };\n\ninterface BackendEnvelope<TData> {\n data: TData;\n}\n\ninterface AddLiquidityEstimateWire {\n amount0: string;\n amount1: string;\n liquidity: string;\n token0Symbol: string;\n token1Symbol: string;\n tickLower: number;\n tickUpper: number;\n amountIsCanonicalToken0: boolean;\n}\n\ninterface RemoveLiquidityEstimateWire {\n amount0: string;\n amount1: string;\n}\n\ninterface ResolvedCreateToken {\n symbol: string;\n classKey: ReturnType<typeof parseTokenClassKey>;\n}\n\ninterface PositionIdentity {\n token0: string;\n token1: string;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n}\n\n/** Tells `submit()` how to prove a write's own effect for `SubmittedTransaction.confirm()`. */\ntype PositionSubmitConfirmation =\n | { kind: 'add' | 'removePartial' | 'removeFull' | 'collect'; identity: PositionIdentity }\n | { kind: 'createPool'; token0: string; token1: string; fee: FEE_TIER };\n\n/**\n * Manages current-contract concentrated-liquidity positions.\n *\n * @example\n * ```typescript\n * const positions = gSwap.positions;\n * const mine = await positions.getUserPositions('client|012345678901234567890123');\n * console.log(mine.length);\n * ```\n */\nexport class Positions {\n constructor(\n private readonly gateway: PositionGateway,\n private readonly symbols: PositionSymbols,\n private readonly signer?: GalaChainSigner,\n walletAddress?: string,\n options: PositionsOptions = {},\n ) {\n this.walletAddress =\n walletAddress === undefined ? undefined : userRef(walletAddress, 'walletAddress');\n this.http = new HttpClient(\n gateway.httpRequestor,\n gateway.requestTimeoutMs ?? 30_000,\n gateway.wire,\n );\n this.uniqueKeyPrefix = resolveUniqueKeyPrefix(options.uniqueKeyPrefix);\n this.onInvalidEntry = options.onInvalidEntry;\n }\n\n /** The signing wallet in the gateway's spelling (`eth|<EIP-55>` or `client|<id>`). */\n private readonly walletAddress: string | undefined;\n private readonly http: HttpClient;\n private readonly uniqueKeyPrefix: string;\n private readonly onInvalidEntry: InvalidEntryHandler | undefined;\n\n /**\n * Gets all current-contract positions owned by an address.\n *\n * @param owner - GalaChain owner identity.\n * @returns Enriched positions from the v2 trade backend, token images included. A row that is\n * not a usable position is skipped and reported to `onInvalidEntry`.\n * @example\n * ```typescript\n * const positions = await gSwap.positions.getUserPositions('client|012345678901234567890123');\n * ```\n */\n async getUserPositions(owner: string): Promise<Position[]> {\n const response = await this.get<unknown>('/positions', { user: userRef(owner, 'owner') });\n return readEntries('positions', response.data, parsePosition, this.onInvalidEntry);\n }\n\n /**\n * Gets one position, normalizing a caller-supplied reversed pair to canonical symbol order.\n * Reversed pairs also invert the price axis, so `[lower, upper]` becomes `[-upper, -lower]`.\n *\n * @param args - Pair, owner, fee, and position tick range.\n * @returns The position, or `null` when the backend returns 404.\n * @example\n * ```typescript\n * const position = await gSwap.positions.getPosition({\n * token0: 'GALA', token1: 'GUSDC', owner: 'client|012345678901234567890123',\n * fee: 3000, tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async getPosition(\n args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n },\n signal?: AbortSignal,\n ): Promise<Position | null> {\n const response = await this.getNullable<unknown>(\n '/position',\n await this.positionParams(args),\n signal,\n );\n return response === null ? null : readPositionBody(response.data);\n }\n\n /**\n * Reads one position and classifies the outcome instead of throwing: `found` with the position\n * (fees included), `not_found` (the backend's HTTP 404, which it sends only when the chain\n * itself has no such position) or `unknown` (any other failure, carried as `error`). Use it\n * to confirm a write: `unknown` is \"no evidence either way\", never a confirmed absence.\n *\n * Only the caller's own abort rethrows. With a pass-through resolver ({@link CanonicalSymbols})\n * the pair and ticks go to the backend exactly as given and the backend orients them.\n *\n * @example\n * ```typescript\n * const read = await gSwap.positions.readPosition({\n * token0: 'GALA', token1: 'GUSDC', owner: 'client|012345678901234567890123',\n * fee: 3000, tickLower: -19200, tickUpper: 12000,\n * });\n * if (read.kind === 'found') console.log(read.data.fees0);\n * ```\n */\n async readPosition(\n args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n },\n signal?: AbortSignal,\n ): Promise<PositionRead> {\n try {\n const position = await this.getPosition(args, signal);\n return position === null ? { kind: 'not_found' } : { kind: 'found', data: position };\n } catch (error: unknown) {\n if (signal?.aborted === true) throw error;\n return {\n kind: 'unknown',\n error: isGSwapError(error)\n ? error\n : new GSwapSDKError(\n 'REQUEST_FAILED',\n { operation: 'position' },\n { cause: error, write: false },\n ),\n };\n }\n }\n\n /**\n * The `/position` query: canonical symbols and canonical ticks after a client-side flip, or,\n * for a pass-through resolver, the caller's references and ticks untouched.\n */\n private async positionParams(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n }): Promise<Record<string, string>> {\n // The backend matches `owner` against the chain's position owner with strict equality, so\n // only the chain's own spelling (`eth|<EIP-55>`) finds a position.\n const owner = userRef(args.owner, 'owner');\n if (this.symbols.passthrough === true) {\n return {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n owner,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n };\n }\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n return {\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: `${args.fee}`,\n owner,\n tickLower: `${ticks.tickLower}`,\n tickUpper: `${ticks.tickUpper}`,\n };\n }\n\n /**\n * Estimates the other token amount and resulting liquidity for a deposit.\n *\n * @param args - Pair, tick range, deposit amount, and the amount's caller-side token index.\n * @returns Backend liquidity estimate.\n * @example\n * ```typescript\n * const estimate = await gSwap.positions.estimateAddLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async estimateAddLiquidity(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n amount: NumericAmount;\n amountIsToken0: boolean;\n }): Promise<AddLiquidityEstimate> {\n validateNumericAmount(args.amount, 'amount');\n const response = await this.get<AddLiquidityEstimateWire>('/add-liq-estimate', {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n amount: new BigNumber(args.amount).toFixed(),\n amountIsToken0: String(args.amountIsToken0),\n });\n return response.data;\n }\n\n /**\n * Estimates token amounts released by burning liquidity.\n *\n * @param args - Pair, tick range, fee tier, and liquidity quantity.\n * @returns Estimated token0 and token1 quantities.\n * @example\n * ```typescript\n * const estimate = await gSwap.positions.estimateRemoveLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, liquidity: '1000',\n * });\n * ```\n */\n async estimateRemoveLiquidity(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n liquidity: NumericAmount;\n }): Promise<RemoveLiquidityEstimate> {\n validateNumericAmount(args.liquidity, 'liquidity');\n const response = await this.get<RemoveLiquidityEstimateWire>('/remove-liq-estimate', {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n liquidity: new BigNumber(args.liquidity).toFixed(),\n });\n return response.data;\n }\n\n /**\n * Adds liquidity using an explicit tick range. Exactly one canonical deposit field is emitted.\n *\n * @param args - Pair, fee, range, deposit amount, and caller-side token index.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.addLiquidityByTicks({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * await tx.confirm();\n * ```\n */\n async addLiquidityByTicks(args: AddLiquidityArgs) {\n return this.submitAddLiquidity(await this.buildAddLiquidity(args));\n }\n\n /**\n * Builds the AddLiquidity DTO that {@link addLiquidityByTicks} would sign, without signing or\n * sending it: to show in an approval popup, or to sign elsewhere. Submit exactly this DTO with\n * {@link submitAddLiquidity}. The pure counterpart, with canonical inputs and no resolution,\n * is `buildAddLiquidityDto`.\n *\n * @example\n * ```typescript\n * const dto = await gSwap.positions.buildAddLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async buildAddLiquidity(args: AddLiquidityArgs): Promise<AddLiquidityDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n // Caller-facing checks first, so a refusal names the caller's own argument (`amount`).\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n validateNumericAmount(args.amount, 'amount');\n const base = {\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n };\n return pair.flipped !== args.amountIsToken0\n ? buildAddLiquidityDto({ ...base, depositQuantityToken0: args.amount })\n : buildAddLiquidityDto({ ...base, depositQuantityToken1: args.amount });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildAddLiquidity} or `buildAddLiquidityDto`; it must\n * be exactly what the builder produces. The returned transaction confirms by proving the\n * position's liquidity grew.\n */\n async submitAddLiquidity(dto: AddLiquidityDTO) {\n assertCanonicalV2Dto('AddLiquidity', dto);\n return this.submit('AddLiquidity', dto, { kind: 'add', identity: identityOf(dto) });\n }\n\n /**\n * Adds liquidity from prices, flooring the lower tick and ceiling the upper tick to fee spacing.\n * The resulting range is therefore no narrower than the requested price interval.\n *\n * @param args - Pair, fee, price range, deposit amount, and caller-side token index.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.addLiquidityByPrice({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * minPrice: '0.14', maxPrice: '0.16', amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async addLiquidityByPrice(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n minPrice: PriceIn;\n maxPrice: PriceIn;\n amount: NumericAmount;\n amountIsToken0: boolean;\n /** The attempt's `uniqueKey`; default a fresh one (see {@link AddLiquidityArgs.uniqueKey}). */\n uniqueKey?: string | undefined;\n }) {\n validateFee(args.fee);\n this.rejectNumber(args.minPrice, 'minPrice');\n this.rejectNumber(args.maxPrice, 'maxPrice');\n const minPrice = new BigNumber(args.minPrice);\n const maxPrice = new BigNumber(args.maxPrice);\n if (\n !minPrice.isFinite() ||\n !maxPrice.isFinite() ||\n minPrice.isLessThanOrEqualTo(0) ||\n maxPrice.isLessThanOrEqualTo(0)\n ) {\n throw new GSwapSDKError('INVALID_PRICE_BOUNDS', {\n minPrice: String(args.minPrice),\n maxPrice: String(args.maxPrice),\n });\n }\n if (minPrice.isGreaterThan(maxPrice)) {\n throw new GSwapSDKError('PRICE_BOUNDS_ORDER', {\n minPrice: String(args.minPrice),\n maxPrice: String(args.maxPrice),\n });\n }\n const spacing = this.tickSpacing(args.fee);\n const tickLower = alignTickDown(tickFromPrice(minPrice), spacing);\n const tickUpper = alignTickUp(tickFromPrice(maxPrice), spacing);\n return this.addLiquidityByTicks({\n token0: args.token0,\n token1: args.token1,\n fee: args.fee,\n tickLower,\n tickUpper,\n amount: args.amount,\n amountIsToken0: args.amountIsToken0,\n uniqueKey: args.uniqueKey,\n });\n }\n\n /**\n * Removes liquidity by withdrawing at most one canonical token quantity.\n * Omitting both amounts closes the position and sweeps all accrued fees.\n *\n * @param args - Pair, fee, range, and optional caller-side withdrawal amount.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.removeLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async removeLiquidity(args: RemoveLiquidityArgs) {\n return this.submitRemoveLiquidity(await this.buildRemoveLiquidity(args));\n }\n\n /**\n * Builds the RemoveLiquidity DTO that {@link removeLiquidity} would sign, without signing or\n * sending it. Submit exactly this DTO with {@link submitRemoveLiquidity}. The pure counterpart\n * is `buildRemoveLiquidityDto`.\n */\n async buildRemoveLiquidity(args: RemoveLiquidityArgs): Promise<RemoveLiquidityDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n if (args.amount0 !== undefined && args.amount1 !== undefined) {\n throw new GSwapSDKError('AT_MOST_ONE_OF_ALLOWED', { first: 'amount0', second: 'amount1' });\n }\n if (args.amount0 !== undefined) validateNumericAmount(args.amount0, 'amount0');\n if (args.amount1 !== undefined) validateNumericAmount(args.amount1, 'amount1');\n // The caller's amount0 / amount1 follow the caller's pair; the DTO's follow the canonical one.\n const [canonical0, canonical1] = pair.flipped\n ? [args.amount1, args.amount0]\n : [args.amount0, args.amount1];\n return buildRemoveLiquidityDto({\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n withdrawalQuantityToken0: canonical0,\n withdrawalQuantityToken1: canonical1,\n });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildRemoveLiquidity} or `buildRemoveLiquidityDto`;\n * it must be exactly what the builder produces. A DTO with no withdrawal quantity closes the\n * position, and the returned transaction then confirms by proving the position is gone.\n */\n async submitRemoveLiquidity(dto: RemoveLiquidityDTO) {\n assertCanonicalV2Dto('RemoveLiquidity', dto);\n const isFullClose =\n dto.withdrawalQuantityToken0 === undefined && dto.withdrawalQuantityToken1 === undefined;\n return this.submit('RemoveLiquidity', dto, {\n kind: isFullClose ? 'removeFull' : 'removePartial',\n identity: identityOf(dto),\n });\n }\n\n /**\n * Collects all accrued fees for a position; the contract does not support partial collection.\n *\n * @param args - Pair, fee, and tick range identifying the position.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.collectPositionFees({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async collectPositionFees(args: CollectPositionFeesArgs) {\n return this.submitCollectPositionFees(await this.buildCollectPositionFees(args));\n }\n\n /**\n * Builds the CollectPositionFees DTO that {@link collectPositionFees} would sign, without\n * signing or sending it. Submit exactly this DTO with {@link submitCollectPositionFees}. The\n * pure counterpart is `buildCollectPositionFeesDto`.\n */\n async buildCollectPositionFees(args: CollectPositionFeesArgs): Promise<CollectPositionFeesDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n return buildCollectPositionFeesDto({\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildCollectPositionFees} or\n * `buildCollectPositionFeesDto`; it must be exactly what the builder produces.\n */\n async submitCollectPositionFees(dto: CollectPositionFeesDTO) {\n assertCanonicalV2Dto('CollectPositionFees', dto);\n return this.submit('CollectPositionFees', dto, { kind: 'collect', identity: identityOf(dto) });\n }\n\n /**\n * Creates a pool, resolving registered trading symbols.\n * Reversed symbol order inverts the supplied starting price or square-root price.\n *\n * A token class key carries no symbol, so for a token being proposed into the v2\n * trading-symbol registry for the first time (no existing pool has registered it yet) the\n * caller MUST pass `token0Symbol`/`token1Symbol` (the token class's symbol, from the token\n * list or FetchTokenClasses). The SDK never derives a symbol from the key, and throws a\n * TOKEN_SYMBOL_NOT_REGISTERED error when an unregistered token has none. For an already-registered token a\n * supplied symbol must match the registered one.\n *\n * @param args - Token class keys or references, fee, exactly one starting price field, and privacy options.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.createPool({\n * token0: 'GALA|Unit|none|none', token1: 'GUSDC|Unit|none|none', fee: 3000,\n * startingPrice: '0.15',\n * });\n * ```\n */\n async createPool(args: CreatePoolArgs) {\n return this.submitCreatePool(await this.buildCreatePool(args));\n }\n\n /**\n * Builds the CreatePool DTO that {@link createPool} would sign, without signing or sending it:\n * symbols resolved or proposed, the pair put in canonical order and the price inverted when it\n * was reversed. Submit exactly this DTO with {@link submitCreatePool}. The pure counterpart,\n * with canonical inputs, is `buildCreatePoolDto`.\n */\n async buildCreatePool(args: CreatePoolArgs): Promise<CreatePoolDTO> {\n const hasPrice = args.startingPrice !== undefined;\n const hasSqrtPrice = args.startingSqrtPrice !== undefined;\n if (hasPrice === hasSqrtPrice) {\n throw new GSwapSDKError('EXACTLY_ONE_OF_REQUIRED', {\n first: 'startingPrice',\n second: 'startingSqrtPrice',\n });\n }\n validateFee(args.fee);\n const [tokenA, tokenB] = await Promise.all([\n this.resolveCreateToken(args.token0, args.token0Symbol),\n this.resolveCreateToken(args.token1, args.token1Symbol),\n ]);\n const flipped = tokenA.symbol > tokenB.symbol;\n const [token0, token1] = flipped ? [tokenB, tokenA] : [tokenA, tokenB];\n const sourcePriceInput = hasPrice\n ? (args.startingPrice as NumericAmount)\n : (args.startingSqrtPrice as NumericAmount);\n this.rejectNumber(sourcePriceInput, hasPrice ? 'startingPrice' : 'startingSqrtPrice');\n const sourcePrice = new BigNumber(sourcePriceInput);\n if (!sourcePrice.isFinite() || sourcePrice.isLessThanOrEqualTo(0)) {\n throw new GSwapSDKError('INVALID_STARTING_PRICE', { value: String(sourcePriceInput) });\n }\n const canonicalPrice = flipped ? new BigNumber(1).dividedBy(sourcePrice) : sourcePrice;\n const shared = {\n token0Key: token0.classKey,\n token1Key: token1.classKey,\n token0Symbol: token0.symbol,\n token1Symbol: token1.symbol,\n fee: args.fee,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n name: args.name,\n isPrivate: args.isPrivate,\n privateAccess: args.privateAccess,\n };\n return hasPrice\n ? buildCreatePoolDto({ ...shared, startingPrice: canonicalPrice })\n : buildCreatePoolDto({ ...shared, startingSqrtPrice: canonicalPrice });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildCreatePool} or `buildCreatePoolDto`; it must be\n * exactly what the builder produces. The returned transaction confirms by the pool existing, and\n * the cached symbol registry is dropped, since the pool may have registered new symbols.\n */\n async submitCreatePool(dto: CreatePoolDTO) {\n assertCanonicalV2Dto('CreatePool', dto);\n const transaction = await this.submit('CreatePool', dto, {\n kind: 'createPool',\n token0: dto.token0Symbol,\n token1: dto.token1Symbol,\n fee: dto.fee,\n });\n this.symbols.invalidate?.();\n return transaction;\n }\n\n private async submit(\n method: string,\n dto: Record<string, unknown>,\n confirmation?: PositionSubmitConfirmation,\n ) {\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n const signed = await signPreSend(this.signer, method, dto);\n const submitOptions =\n this.walletAddress === undefined ? {} : { walletAddress: this.walletAddress };\n const owner = this.walletAddress;\n const positionConfirmation = await this.buildPositionConfirmation(confirmation, owner);\n const options: ChainSubmitOptions = {\n ...submitOptions,\n ...(positionConfirmation === undefined ? {} : { positionConfirmation }),\n };\n return this.gateway.submit(method, signed, options);\n }\n\n /**\n * Builds a confirmation closure that proves the write's own effect, not just that a\n * position row exists (true before most of these writes run too, for any operation on a\n * pre-existing position — existence alone would false-confirm before the write executes,\n * and would never confirm a full close, whose whole point is that the position stops\n * existing).\n *\n * The \"before\" state is read here, before the write is sent. Liquidity writes execute\n * synchronously, so by the time `confirm()` first polls the effect has already landed: a\n * baseline taken on that first poll would already include it, and an add or partial remove\n * would never be seen to change and would time out. Only a full close needs no baseline\n * (it waits for the position to disappear). If the baseline read fails the write is still\n * sent and the closure falls back to taking the baseline on its first poll.\n */\n private async buildPositionConfirmation(\n confirmation: PositionSubmitConfirmation | undefined,\n owner: string | undefined,\n ): Promise<((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined> {\n if (confirmation === undefined) return undefined;\n\n if (confirmation.kind === 'createPool') {\n const { token0, token1, fee } = confirmation;\n return async (signal) => {\n const pool = await this.getNullable<unknown>(\n '/pool',\n { token0, token1, fee: `${fee}` },\n signal,\n );\n return pool === null ? { confirmed: false } : { confirmed: true, position: null };\n };\n }\n\n if (owner === undefined) return undefined;\n const { kind, identity } = confirmation;\n const toBaseline = (current: Position | null) => ({\n liquidity: new BigNumber(current?.liquidity ?? 0),\n fees: new BigNumber(current?.fees0 ?? 0).plus(new BigNumber(current?.fees1 ?? 0)),\n });\n let baseline: { liquidity: BigNumber; fees: BigNumber } | undefined;\n if (kind !== 'removeFull') {\n try {\n baseline = toBaseline(await this.getPosition({ ...identity, owner }));\n } catch {\n baseline = undefined;\n }\n }\n\n return async (signal) => {\n const current = await this.getPosition({ ...identity, owner }, signal);\n\n if (baseline === undefined) {\n // First poll only establishes the baseline to compare future polls against — it can\n // never itself be the confirmed outcome (nothing has been observed to change yet).\n baseline = toBaseline(current);\n // A full close starting from \"already gone\" (e.g. a retried confirm after the position\n // was already swept) is confirmed immediately rather than waiting for a change that\n // already happened.\n return kind === 'removeFull' && current === null\n ? { confirmed: true, position: null }\n : { confirmed: false };\n }\n\n switch (kind) {\n case 'add':\n return current !== null &&\n new BigNumber(current.liquidity).isGreaterThan(baseline.liquidity)\n ? { confirmed: true, position: current }\n : { confirmed: false };\n case 'removePartial':\n return current !== null && new BigNumber(current.liquidity).isLessThan(baseline.liquidity)\n ? { confirmed: true, position: current }\n : { confirmed: false };\n case 'removeFull':\n return current === null ? { confirmed: true, position: null } : { confirmed: false };\n case 'collect': {\n if (current === null) return { confirmed: false };\n const currentFees = new BigNumber(current.fees0 ?? 0).plus(\n new BigNumber(current.fees1 ?? 0),\n );\n if (currentFees.isLessThan(baseline.fees)) return { confirmed: true, position: current };\n // Nothing to sweep in the first place — a legitimate no-op collect never moves\n // fees, so \"still zero\" is the confirmed outcome, not an unconfirmed one.\n if (baseline.fees.isZero() && currentFees.isZero())\n return { confirmed: true, position: current };\n return { confirmed: false };\n }\n }\n };\n }\n\n private async get<TData>(\n endpoint: string,\n params: Record<string, string>,\n signal?: AbortSignal,\n ): Promise<BackendEnvelope<TData>> {\n return this.http.sendGetRequest<BackendEnvelope<TData>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n endpoint,\n params,\n signal === undefined ? undefined : { signal },\n );\n }\n\n private async getNullable<TData>(\n endpoint: string,\n params: Record<string, string>,\n signal?: AbortSignal,\n ): Promise<BackendEnvelope<TData> | null> {\n try {\n return await this.get<TData>(endpoint, params, signal);\n } catch (error: unknown) {\n if (this.isNotFound(error)) return null;\n throw error;\n }\n }\n\n private isNotFound(error: unknown): boolean {\n return isGSwapError(error) && error.status === 404;\n }\n\n private canonicalTicks(tickLower: number, tickUpper: number, flipped: boolean) {\n return flipped ? { tickLower: -tickUpper, tickUpper: -tickLower } : { tickLower, tickUpper };\n }\n\n private tickSpacing(fee: number): number {\n const spacing = (TICK_SPACING_BY_FEE as Record<number, number>)[fee];\n if (spacing === undefined) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n return spacing;\n }\n\n private rejectNumber(value: unknown, parameterName: string): void {\n if (typeof value === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: parameterName });\n }\n }\n\n /** The caller's `uniqueKey` (validated), else a fresh one. */\n private uniqueKeyFor(supplied: string | undefined): string {\n if (supplied === undefined) return createUniqueKey(this.uniqueKeyPrefix);\n assertUniqueKey(supplied);\n return supplied;\n }\n\n /**\n * The pair in canonical order. A resolver failure that is not an SDK error (an app's own\n * resolver, an app requestor's rejection during the registry read) is `TOKEN_RESOLUTION_FAILED`.\n */\n private orderPair(a: TokenRef, b: TokenRef) {\n return resolvePreSend(`${rawTokenOf(a)}/${rawTokenOf(b)}`, () => this.symbols.orderPair(a, b));\n }\n\n private async resolveCreateToken(\n ref: TokenRef,\n symbolOverride?: string,\n ): Promise<ResolvedCreateToken> {\n try {\n const lookupRef = typeof ref === 'object' ? compositeKeyOf(ref) : ref;\n const resolved = await resolvePreSend(rawTokenOf(ref), () => this.symbols.resolve(lookupRef));\n if (\n symbolOverride !== undefined &&\n symbolOverride !== '' &&\n symbolOverride !== resolved.symbol\n ) {\n throw new GSwapSDKError('SYMBOL_DISAGREES_WITH_REGISTRY', {\n token: rawTokenOf(ref),\n suppliedSymbol: symbolOverride,\n registeredSymbol: resolved.symbol,\n });\n }\n const suppliedClassKey = this.tryParseClassKey(ref);\n if (suppliedClassKey === undefined && resolved.collection === '') {\n // An offline resolver knows a bare symbol but not its class key; a pool needs the key.\n throw new GSwapSDKError('CREATE_POOL_NEEDS_CLASS_KEY', { token: rawTokenOf(ref) });\n }\n return {\n symbol: resolved.symbol,\n classKey:\n suppliedClassKey ??\n parseTokenClassKey({\n collection: resolved.collection,\n category: resolved.category,\n type: resolved.type,\n additionalKey: resolved.additionalKey,\n }),\n };\n } catch (error: unknown) {\n if (!isGSwapError(error, 'UNKNOWN_TOKEN')) {\n throw error;\n }\n let classKey: ReturnType<typeof parseTokenClassKey>;\n try {\n classKey = parseTokenClassKey(ref);\n } catch {\n throw error;\n }\n // First-time registration: a class key carries NO symbol (collection and symbol disagree\n // for many tokens, launchpad tokens all share collection `Token`, and some collections\n // contain `$`), so the symbol to propose must be supplied by the caller from the token\n // class / registry. Never derive it from the key.\n if (symbolOverride === undefined || symbolOverride === '') {\n throw new GSwapSDKError('TOKEN_SYMBOL_NOT_REGISTERED', { token: rawTokenOf(ref) });\n }\n if (!isProposableTradingSymbol(symbolOverride)) {\n throw new GSwapSDKError('INVALID_TRADING_SYMBOL', { symbol: symbolOverride });\n }\n return { symbol: symbolOverride, classKey };\n }\n }\n\n private tryParseClassKey(ref: TokenRef): ReturnType<typeof parseTokenClassKey> | undefined {\n try {\n return parseTokenClassKey(ref);\n } catch {\n return undefined;\n }\n }\n}\n\nconst REQUIRED_POSITION_STRINGS = [\n 'token0Symbol',\n 'token1Symbol',\n 'owner',\n 'liquidity',\n 'amount0',\n 'amount1',\n] as const;\nconst REQUIRED_POSITION_NUMBERS = ['fee', 'tickLower', 'tickUpper'] as const;\nconst OPTIONAL_POSITION_STRINGS = [\n 'token0CompositeKey',\n 'token1CompositeKey',\n 'token0Image',\n 'token1Image',\n 'sqrtPrice',\n 'fees0',\n 'fees1',\n] as const;\n\n/**\n * Reads one position row of `/positions` or `/position`: the pair, owner, range, liquidity and\n * amounts must be usable; the composite keys, token images, current tick and price, and the\n * escrowed fees are carried when present. `pool` is the pool reference (`poolRef` wins over\n * `pool`; `''` when the row names neither).\n */\nfunction parsePosition(value: unknown): EntryParse<Position> {\n const wire = asEntryRecord(value);\n if (wire === undefined) return entryRejected('the row is not an object');\n for (const key of REQUIRED_POSITION_STRINGS) {\n if (typeof wire[key] !== 'string') return entryRejected(`${key} is not a string`);\n }\n for (const key of REQUIRED_POSITION_NUMBERS) {\n const number = wire[key];\n if (typeof number !== 'number' || !Number.isFinite(number)) {\n return entryRejected(`${key} is not a number`);\n }\n }\n if (typeof wire['inRange'] !== 'boolean') return entryRejected('inRange is not a boolean');\n for (const key of OPTIONAL_POSITION_STRINGS) {\n if (wire[key] !== undefined && typeof wire[key] !== 'string') {\n return entryRejected(`${key} is not a string`);\n }\n }\n const currentTick = wire['currentTick'];\n if (\n currentTick !== undefined &&\n (typeof currentTick !== 'number' || !Number.isFinite(currentTick))\n ) {\n return entryRejected('currentTick is not a number');\n }\n const pool = wire['poolRef'] ?? wire['pool'] ?? '';\n if (typeof pool !== 'string') return entryRejected('pool is not a string');\n const optional = Object.fromEntries(\n [...OPTIONAL_POSITION_STRINGS, 'currentTick' as const].flatMap((key) =>\n wire[key] === undefined ? [] : [[key, wire[key]]],\n ),\n );\n return entryOk({\n token0Symbol: wire['token0Symbol'] as string,\n token1Symbol: wire['token1Symbol'] as string,\n fee: wire['fee'] as number,\n tickLower: wire['tickLower'] as number,\n tickUpper: wire['tickUpper'] as number,\n liquidity: wire['liquidity'] as string,\n amount0: wire['amount0'] as string,\n amount1: wire['amount1'] as string,\n inRange: wire['inRange'],\n pool,\n owner: wire['owner'] as string,\n ...optional,\n });\n}\n\n/** The position inside a `/position` answer, or `INVALID_CHAIN_RESPONSE` when it is not one. */\nfunction readPositionBody(data: unknown): Position {\n const parsed = parsePosition(data);\n if (parsed.ok) return parsed.value;\n throw new GSwapSDKError(\n 'INVALID_POSITION_RESPONSE',\n { reason: parsed.reason },\n { body: data, write: false },\n );\n}\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -4980,7 +4980,7 @@ var Positions = class {
4980
4980
  const signed = await (0, _gala_chain_gala_core_sdk.signPreSend)(this.signer, method, dto);
4981
4981
  const submitOptions = this.walletAddress === void 0 ? {} : { walletAddress: this.walletAddress };
4982
4982
  const owner = this.walletAddress;
4983
- const positionConfirmation = this.buildPositionConfirmation(confirmation, owner);
4983
+ const positionConfirmation = await this.buildPositionConfirmation(confirmation, owner);
4984
4984
  const options = {
4985
4985
  ...submitOptions,
4986
4986
  ...positionConfirmation === void 0 ? {} : { positionConfirmation }
@@ -4994,12 +4994,14 @@ var Positions = class {
4994
4994
  * and would never confirm a full close, whose whole point is that the position stops
4995
4995
  * existing).
4996
4996
  *
4997
- * The "before" state is captured lazily, on the confirmation closure's own first poll —
4998
- * not eagerly here in `submit()` — so confirming a write never adds an extra round-trip to
4999
- * the write itself; the cost of establishing the baseline is paid by `confirm()`, only if
5000
- * and when the caller actually asks to confirm.
4997
+ * The "before" state is read here, before the write is sent. Liquidity writes execute
4998
+ * synchronously, so by the time `confirm()` first polls the effect has already landed: a
4999
+ * baseline taken on that first poll would already include it, and an add or partial remove
5000
+ * would never be seen to change and would time out. Only a full close needs no baseline
5001
+ * (it waits for the position to disappear). If the baseline read fails the write is still
5002
+ * sent and the closure falls back to taking the baseline on its first poll.
5001
5003
  */
5002
- buildPositionConfirmation(confirmation, owner) {
5004
+ async buildPositionConfirmation(confirmation, owner) {
5003
5005
  if (confirmation === void 0) return void 0;
5004
5006
  if (confirmation.kind === "createPool") {
5005
5007
  const { token0, token1, fee } = confirmation;
@@ -5016,17 +5018,26 @@ var Positions = class {
5016
5018
  }
5017
5019
  if (owner === void 0) return void 0;
5018
5020
  const { kind, identity } = confirmation;
5021
+ const toBaseline = (current) => ({
5022
+ liquidity: new bignumber_js.default((current === null || current === void 0 ? void 0 : current.liquidity) ?? 0),
5023
+ fees: new bignumber_js.default((current === null || current === void 0 ? void 0 : current.fees0) ?? 0).plus(new bignumber_js.default((current === null || current === void 0 ? void 0 : current.fees1) ?? 0))
5024
+ });
5019
5025
  let baseline;
5026
+ if (kind !== "removeFull") try {
5027
+ baseline = toBaseline(await this.getPosition({
5028
+ ...identity,
5029
+ owner
5030
+ }));
5031
+ } catch {
5032
+ baseline = void 0;
5033
+ }
5020
5034
  return async (signal) => {
5021
5035
  const current = await this.getPosition({
5022
5036
  ...identity,
5023
5037
  owner
5024
5038
  }, signal);
5025
5039
  if (baseline === void 0) {
5026
- baseline = {
5027
- liquidity: new bignumber_js.default((current === null || current === void 0 ? void 0 : current.liquidity) ?? 0),
5028
- fees: new bignumber_js.default((current === null || current === void 0 ? void 0 : current.fees0) ?? 0).plus(new bignumber_js.default((current === null || current === void 0 ? void 0 : current.fees1) ?? 0))
5029
- };
5040
+ baseline = toBaseline(current);
5030
5041
  return kind === "removeFull" && current === null ? {
5031
5042
  confirmed: true,
5032
5043
  position: null