@gala-chain/gswap-sdk 2.0.0 → 2.1.0-beta.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 +2 -2
- package/dist/browser/classes/apply_results.js.map +1 -1
- package/dist/browser/classes/assets.js.map +1 -1
- package/dist/browser/classes/dex_fees.js +1 -1
- package/dist/browser/classes/dex_fees.js.map +1 -1
- package/dist/browser/classes/gateway.js +1 -1
- package/dist/browser/classes/gateway.js.map +1 -1
- package/dist/browser/classes/gdex_stream.js +1 -1
- package/dist/browser/classes/gdex_stream.js.map +1 -1
- package/dist/browser/classes/gswap.js +1 -1
- package/dist/browser/classes/gswap.js.map +1 -1
- package/dist/browser/classes/gswap_error_catalog.js.map +1 -1
- package/dist/browser/classes/gswap_error_phase_table.js.map +1 -1
- package/dist/browser/classes/gswap_sdk_error.js +1 -1
- package/dist/browser/classes/gswap_sdk_error.js.map +1 -1
- package/dist/browser/classes/http_client.js.map +1 -1
- package/dist/browser/classes/leaderboard.js.map +1 -1
- package/dist/browser/classes/market.js.map +1 -1
- package/dist/browser/classes/onramper.js.map +1 -1
- package/dist/browser/classes/pending_swap_fate.js.map +1 -1
- package/dist/browser/classes/pending_swaps.js +1 -1
- package/dist/browser/classes/pending_swaps.js.map +1 -1
- package/dist/browser/classes/pools.js +1 -1
- package/dist/browser/classes/pools.js.map +1 -1
- package/dist/browser/classes/positions.js +1 -1
- package/dist/browser/classes/positions.js.map +1 -1
- package/dist/browser/classes/quoting.js +1 -1
- package/dist/browser/classes/quoting.js.map +1 -1
- package/dist/browser/classes/shadow_submit.js.map +1 -1
- package/dist/browser/classes/storage_adapters.js.map +1 -1
- package/dist/browser/classes/submitted_transaction.js +1 -1
- package/dist/browser/classes/submitted_transaction.js.map +1 -1
- package/dist/browser/classes/swaps.js +1 -1
- package/dist/browser/classes/swaps.js.map +1 -1
- package/dist/browser/classes/symbols.js +1 -1
- package/dist/browser/classes/symbols.js.map +1 -1
- package/dist/browser/types/env.js.map +1 -1
- package/dist/browser/types/fees.js.map +1 -1
- package/dist/browser/types/market.js.map +1 -1
- package/dist/browser/utils/chain_contract.js +2 -0
- package/dist/browser/utils/chain_contract.js.map +1 -0
- package/dist/browser/utils/classification.js.map +1 -1
- package/dist/browser/utils/confirmation_schedule.js.map +1 -1
- package/dist/browser/utils/confirmation_state.js.map +1 -1
- package/dist/browser/utils/debug.js.map +1 -1
- package/dist/browser/utils/dto_builders.js.map +1 -1
- package/dist/browser/utils/failure_classification.js.map +1 -1
- package/dist/browser/utils/failure_guards.js.map +1 -1
- package/dist/browser/utils/lenient.js.map +1 -1
- package/dist/browser/utils/ordering.js.map +1 -1
- package/dist/browser/utils/reconnection.js +1 -1
- package/dist/browser/utils/reconnection.js.map +1 -1
- package/dist/browser/utils/resolve_pre_send.js.map +1 -1
- package/dist/browser/utils/server_message.js.map +1 -1
- package/dist/browser/utils/shadow_errors.js.map +1 -1
- package/dist/browser/utils/submit_state.js.map +1 -1
- package/dist/browser/utils/tick_align.js.map +1 -1
- package/dist/browser/utils/tick_math.js.map +1 -1
- package/dist/browser/utils/tick_range.js.map +1 -1
- package/dist/browser/utils/ticks.js.map +1 -1
- package/dist/browser/utils/validation.js.map +1 -1
- package/dist/index.cjs +14 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +14 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/defineProperty.js +0 -0
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/toPrimitive.js +0 -0
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/toPropertyKey.js +0 -0
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/typeof.js +0 -0
|
@@ -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","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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"}
|
|
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","DEX_CONTRACT_PATH","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 { DEX_CONTRACT_PATH } from '../utils/chain_contract.js';\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, DEX_CONTRACT_PATH, 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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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{readServerMessage as e}from"../utils/server_message.js";import{ALLOWED_FEE_TIERS_TEXT as t}from"./gswap_error_catalog.js";import n from"../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import{readServerMessage as e}from"../utils/server_message.js";import{ALLOWED_FEE_TIERS_TEXT as t}from"./gswap_error_catalog.js";import n from"../_virtual/_@oxc-project_runtime@0.154.0/helpers/esm/defineProperty.js";import{GSwapSDKError as r,isGSwapError as i}from"./gswap_sdk_error.js";import{ALL_FEE_TIERS as a}from"../types/fees.js";import{validateNumericAmount as o}from"../utils/validation.js";import{HttpClient as s}from"./http_client.js";import{queryTokenOf as c}from"./symbols.js";import l from"bignumber.js";var u=class{constructor(e,t){this.gateway=e,this.symbols=t,n(this,`http`,void 0),this.http=new s(e.httpRequestor,e.requestTimeoutMs??3e4,e.wire)}async quoteExactInput(e,t,n,r){return o(n,`amountIn`),this.quote(e,t,{amountIn:x(n)},r)}async quoteExactOutput(e,t,n,r){return o(n,`amountOut`),this.quote(e,t,{amountOut:x(n)},r)}async quote(e,t,n,r){b(r);let i={tokenIn:await c(this.symbols,e),tokenOut:await c(this.symbols,t),...n};r!==void 0&&(i.fee=String(r));try{return d((await this.http.sendGetRequest(this.gateway.dexBackendBaseUrl,`/v2/trade`,`/quote`,i)).data)}catch(n){throw y(n,e,t,r,{tokenIn:i.tokenIn??``,tokenOut:i.tokenOut??``})}}};function d(e){if(!m(e))throw new r(`INVALID_CHAIN_RESPONSE`,{resource:`quote`},{body:e,write:!1});let t=e,n=t.currentPrice===void 0?p(t.currentSqrtPrice,t.tokenInIsToken0):new l(t.currentPrice),i=t.newPrice===void 0?p(t.newSqrtPrice,t.tokenInIsToken0):new l(t.newPrice),a=i.minus(n).dividedBy(n);return{contractVersion:t.contractVersion,fee:t.fee,amountIn:t.amountIn,amountOut:t.amountOut,...t.currentSqrtPrice===void 0?{}:{currentSqrtPrice:t.currentSqrtPrice},...t.newSqrtPrice===void 0?{}:{newSqrtPrice:t.newSqrtPrice},feeTier:t.fee,newTick:t.newTick,tradingFees:t.tradingFees,protocolFees:t.protocolFees,totalFees:t.totalFees,feeTokenSymbol:t.feeTokenSymbol,token0Symbol:t.token0Symbol,token1Symbol:t.token1Symbol,tokenInIsToken0:t.tokenInIsToken0,currentPrice:n,newPrice:i,priceImpact:a}}const f=l.clone({DECIMAL_PLACES:60});function p(e,t){let n=new f(e).pow(2);return t?n:new f(1).dividedBy(n)}function m(e){if(typeof e!=`object`||!e)return!1;let t=e;return t.contractVersion===`v2`&&typeof t.fee==`number`&&Number.isFinite(t.fee)&&[`amountIn`,`amountOut`,`tradingFees`,`protocolFees`,`totalFees`,`feeTokenSymbol`,`token0Symbol`,`token1Symbol`].every(e=>typeof t[e]==`string`)&&typeof t.newTick==`number`&&Number.isInteger(t.newTick)&&typeof t.tokenInIsToken0==`boolean`&&h(t.currentSqrtPrice)&&h(t.newSqrtPrice)&&h(t.currentPrice)&&h(t.newPrice)&&(t.currentSqrtPrice!==void 0||t.currentPrice!==void 0)&&(t.newSqrtPrice!==void 0||t.newPrice!==void 0)}function h(e){if(e===void 0)return!0;if(typeof e!=`string`)return!1;try{let t=new l(e);return t.isFinite()&&t.isGreaterThan(0)}catch{return!1}}const g=/no pool|no pools|pool does not exist/iu,_=/Token (\S+) has no trading symbol on the new DEX contract/u;function v(e,t,n,r){return e===t.tokenIn?n:e===t.tokenOut?r:e}function y(t,n,a,o,s){if(i(t)){let i=e(t)??``,c=_.exec(i)?.[1];return c===void 0?t.status===404||g.test(i)?r.noPoolAvailableError(n,a,o,t):t.status===400&&/insufficient liquidity/iu.test(i)?r.insufficientLiquidityError(n,a,o,t):t:r.unknownTokenError(v(c,s,n,a),t)}return new r(`REQUEST_FAILED`,{operation:`quote`},{cause:t,write:!1})}function b(e){if(e!==void 0&&!a.some(t=>Number(t)===Number(e)))throw new r(`INVALID_FEE`,{field:`fee`,value:Number(e),allowed:t})}function x(e){return new l(e).toFixed()}export{u as Quoting};
|
|
2
2
|
//# sourceMappingURL=quoting.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quoting.js","names":["_defineProperty","BigNumber","Quoting","gateway","symbols","HttpClient","validateNumericAmount","amountIn","tokenIn","tokenOut","toDecimalString","fee","amountOut","validateOptionalFee","params","queryTokenOf","amount","\"fee\"","mapQuote","error","mapQuoteError","\"tokenIn\"","\"tokenOut\"","isQuoteWire","value","GSwapSDKError","wire","currentPrice","orientPrice","newPrice","priceImpact","HighPrecision","poolPrice","sqrtPrice","tokenInIsToken0","\"contractVersion\"","key","\"newTick\"","\"tokenInIsToken0\"","optionalPositiveDecimal","\"currentSqrtPrice\"","\"newSqrtPrice\"","\"currentPrice\"","\"newPrice\"","decimal","NO_MARKET_MESSAGE","NO_SYMBOL_MESSAGE","unknownTokenOf","echoed","queried","isGSwapError","message","readServerMessage","unregistered","ALL_FEE_TIERS","tier","ALLOWED_FEE_TIERS_TEXT"],"sources":["../../../src/classes/quoting.ts"],"sourcesContent":["import BigNumber from 'bignumber.js';\nimport type { NumericAmount } from '../types/amounts.js';\nimport { ALL_FEE_TIERS } from '../types/fees.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport type { QuoteResult } from '../types/v2_results.js';\nimport type { TokenRef } from '../utils/ordering.js';\nimport { validateNumericAmount } from '../utils/validation.js';\nimport type { WireOptions } from '@gala-chain/gala-core-sdk';\nimport type { ChainGateway } from './gateway.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from './gswap_error_catalog.js';\nimport { readServerMessage } from '../utils/server_message.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport { HttpClient } from './http_client.js';\nimport { queryTokenOf, type TokenResolver } from './symbols.js';\n\ninterface QuoteWire {\n contractVersion: 'v2';\n fee: number;\n amountIn: string;\n amountOut: string;\n currentSqrtPrice?: string;\n newSqrtPrice?: string;\n currentPrice?: string;\n newPrice?: string;\n newTick: number;\n tradingFees: string;\n protocolFees: string;\n totalFees: string;\n feeTokenSymbol: string;\n token0Symbol: string;\n token1Symbol: string;\n tokenInIsToken0: boolean;\n}\n\ninterface BackendEnvelope<T> {\n data: T;\n}\n\n/** The transport a quote service reads through: the same shape `Pools` and `Symbols` take. */\ntype QuoteGateway = Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n};\n\n/** Read-only quote service backed by the v2 offline quote engine. */\nexport class Quoting {\n /**\n * Creates a quote service.\n *\n * @example\n * ```ts\n * const quoting = new Quoting(gateway, symbols); // a ChainGateway, or any { dexBackendBaseUrl, httpRequestor }\n * ```\n */\n constructor(\n private readonly gateway: QuoteGateway,\n private readonly symbols: TokenResolver,\n ) {\n this.http = new HttpClient(\n gateway.httpRequestor,\n gateway.requestTimeoutMs ?? 30_000,\n gateway.wire,\n );\n }\n\n private readonly http: HttpClient;\n\n /**\n * Quotes the output for a positive exact-input amount.\n *\n * @example\n * ```ts\n * const quote = await quoting.quoteExactInput('GALA', 'GUSDC', '100');\n * console.log(quote.amountOut);\n * ```\n */\n public async quoteExactInput(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amountIn: NumericAmount,\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateNumericAmount(amountIn, 'amountIn');\n return this.quote(tokenIn, tokenOut, { amountIn: toDecimalString(amountIn) }, fee);\n }\n\n /**\n * Quotes the input for a positive exact-output amount.\n *\n * @example\n * ```ts\n * const quote = await quoting.quoteExactOutput('GALA', 'GUSDC', '10', 3000);\n * console.log(quote.amountIn);\n * ```\n */\n public async quoteExactOutput(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amountOut: NumericAmount,\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateNumericAmount(amountOut, 'amountOut');\n return this.quote(tokenIn, tokenOut, { amountOut: toDecimalString(amountOut) }, fee);\n }\n\n private async quote(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amount: { amountIn: string } | { amountOut: string },\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateOptionalFee(fee);\n\n const params: Record<string, string> = {\n tokenIn: await queryTokenOf(this.symbols, tokenIn),\n tokenOut: await queryTokenOf(this.symbols, tokenOut),\n ...amount,\n };\n if (fee !== undefined) params['fee'] = String(fee);\n\n try {\n const response = await this.http.sendGetRequest<BackendEnvelope<QuoteWire>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n '/quote',\n params,\n );\n return mapQuote(response.data);\n } catch (error: unknown) {\n throw mapQuoteError(error, tokenIn, tokenOut, fee, {\n tokenIn: params['tokenIn'] ?? '',\n tokenOut: params['tokenOut'] ?? '',\n });\n }\n }\n}\n\nfunction mapQuote(value: unknown): QuoteResult {\n if (!isQuoteWire(value)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'quote' },\n { body: value, write: false },\n );\n }\n const wire = value;\n const currentPrice =\n wire.currentPrice !== undefined\n ? new BigNumber(wire.currentPrice)\n : orientPrice(wire.currentSqrtPrice!, wire.tokenInIsToken0);\n const newPrice =\n wire.newPrice !== undefined\n ? new BigNumber(wire.newPrice)\n : orientPrice(wire.newSqrtPrice!, wire.tokenInIsToken0);\n const priceImpact = newPrice.minus(currentPrice).dividedBy(currentPrice);\n\n return {\n contractVersion: wire.contractVersion,\n fee: wire.fee,\n amountIn: wire.amountIn,\n amountOut: wire.amountOut,\n ...(wire.currentSqrtPrice === undefined ? {} : { currentSqrtPrice: wire.currentSqrtPrice }),\n ...(wire.newSqrtPrice === undefined ? {} : { newSqrtPrice: wire.newSqrtPrice }),\n feeTier: wire.fee,\n newTick: wire.newTick,\n tradingFees: wire.tradingFees,\n protocolFees: wire.protocolFees,\n totalFees: wire.totalFees,\n feeTokenSymbol: wire.feeTokenSymbol,\n token0Symbol: wire.token0Symbol,\n token1Symbol: wire.token1Symbol,\n tokenInIsToken0: wire.tokenInIsToken0,\n currentPrice,\n newPrice,\n priceImpact,\n };\n}\n\n// The default BigNumber.DECIMAL_PLACES (20) underflows 1/poolPrice to exactly 0 for a\n// pool price above ~1e20 (a real, in-range price for a low-unit-value token quoted\n// against a high-value one) — 60dp matches the precision ticks.ts's DexMath already\n// uses for this same class of division.\nconst HighPrecision = BigNumber.clone({ DECIMAL_PLACES: 60 });\n\nfunction orientPrice(sqrtPrice: string, tokenInIsToken0: boolean): BigNumber {\n const poolPrice = new HighPrecision(sqrtPrice).pow(2);\n return tokenInIsToken0 ? poolPrice : new HighPrecision(1).dividedBy(poolPrice);\n}\n\nfunction isQuoteWire(value: unknown): value is QuoteWire {\n if (typeof value !== 'object' || value === null) return false;\n const wire = value as Record<string, unknown>;\n const requiredStrings = [\n 'amountIn',\n 'amountOut',\n 'tradingFees',\n 'protocolFees',\n 'totalFees',\n 'feeTokenSymbol',\n 'token0Symbol',\n 'token1Symbol',\n ];\n return (\n wire['contractVersion'] === 'v2' &&\n typeof wire['fee'] === 'number' &&\n Number.isFinite(wire['fee']) &&\n requiredStrings.every((key) => typeof wire[key] === 'string') &&\n typeof wire['newTick'] === 'number' &&\n Number.isInteger(wire['newTick']) &&\n typeof wire['tokenInIsToken0'] === 'boolean' &&\n optionalPositiveDecimal(wire['currentSqrtPrice']) &&\n optionalPositiveDecimal(wire['newSqrtPrice']) &&\n optionalPositiveDecimal(wire['currentPrice']) &&\n optionalPositiveDecimal(wire['newPrice']) &&\n (wire['currentSqrtPrice'] !== undefined || wire['currentPrice'] !== undefined) &&\n (wire['newSqrtPrice'] !== undefined || wire['newPrice'] !== undefined)\n );\n}\n\nfunction optionalPositiveDecimal(value: unknown): boolean {\n if (value === undefined) return true;\n if (typeof value !== 'string') return false;\n try {\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — this validates an untrusted backend field, so an unparseable value\n // must fail validation cleanly (INVALID_CHAIN_RESPONSE), not throw raw.\n const decimal = new BigNumber(value);\n return decimal.isFinite() && decimal.isGreaterThan(0);\n } catch {\n return false;\n }\n}\n\n/**\n * The ways the backend says a pair has no market at all: no pool at ANY fee tier (\"No pools found\n * with sufficient liquidity\") or a missing pool (\"Pool does not exist on the new DEX contract\").\n * A pool that exists but is too thin says \"Insufficient liquidity: ...\" instead.\n */\nconst NO_MARKET_MESSAGE = /no pool|no pools|pool does not exist/iu;\n\n/**\n * A token the DEX contract never registered: the backend's symbol registry answers\n * `Token <token> has no trading symbol on the new DEX contract (no gcdex pool includes it yet).`\n * with an HTTP 400, naming the token exactly as the quote request sent it. That is a different\n * fact from \"no pool for this pair\" (the token itself is unknown), so it is `UNKNOWN_TOKEN` with\n * the token, not `NO_POOL_AVAILABLE`. Token class keys and symbols contain no whitespace.\n */\nconst NO_SYMBOL_MESSAGE = /Token (\\S+) has no trading symbol on the new DEX contract/u;\n\n/** The token the quote request named in the form the caller gave it, else as the backend echoed it. */\nfunction unknownTokenOf(\n echoed: string,\n queried: { tokenIn: string; tokenOut: string },\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n): TokenRef {\n if (echoed === queried.tokenIn) return tokenIn;\n if (echoed === queried.tokenOut) return tokenOut;\n return echoed;\n}\n\nfunction mapQuoteError(\n error: unknown,\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n fee: FEE_TIER | undefined,\n queried: { tokenIn: string; tokenOut: string },\n): GSwapSDKError {\n if (isGSwapError(error)) {\n // The backend's own English is read ONLY to classify its answer; it is never surfaced. The\n // SDK's generated `message` is never matched: its templates are not a contract.\n const message = readServerMessage(error) ?? '';\n const unregistered = NO_SYMBOL_MESSAGE.exec(message)?.[1];\n if (unregistered !== undefined) {\n return GSwapSDKError.unknownTokenError(\n unknownTokenOf(unregistered, queried, tokenIn, tokenOut),\n error,\n );\n }\n if (error.status === 404 || NO_MARKET_MESSAGE.test(message)) {\n return GSwapSDKError.noPoolAvailableError(tokenIn, tokenOut, fee, error);\n }\n if (error.status === 400 && /insufficient liquidity/iu.test(message)) {\n return GSwapSDKError.insufficientLiquidityError(tokenIn, tokenOut, fee, error);\n }\n return error;\n }\n return new GSwapSDKError(\n 'REQUEST_FAILED',\n { operation: 'quote' },\n { cause: error, write: false },\n );\n}\n\nfunction validateOptionalFee(fee: FEE_TIER | undefined): void {\n if (fee !== undefined && !ALL_FEE_TIERS.some((tier) => Number(tier) === Number(fee))) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: Number(fee),\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n}\n\nfunction toDecimalString(amount: NumericAmount): string {\n return new BigNumber(amount).toFixed();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"quoting.js","names":["_defineProperty","BigNumber","Quoting","gateway","symbols","HttpClient","validateNumericAmount","amountIn","tokenIn","tokenOut","toDecimalString","fee","amountOut","validateOptionalFee","params","queryTokenOf","amount","\"fee\"","mapQuote","error","mapQuoteError","\"tokenIn\"","\"tokenOut\"","isQuoteWire","value","GSwapSDKError","wire","currentPrice","orientPrice","newPrice","priceImpact","HighPrecision","poolPrice","sqrtPrice","tokenInIsToken0","\"contractVersion\"","key","\"newTick\"","\"tokenInIsToken0\"","optionalPositiveDecimal","\"currentSqrtPrice\"","\"newSqrtPrice\"","\"currentPrice\"","\"newPrice\"","decimal","NO_MARKET_MESSAGE","NO_SYMBOL_MESSAGE","unknownTokenOf","echoed","queried","isGSwapError","message","readServerMessage","unregistered","ALL_FEE_TIERS","tier","ALLOWED_FEE_TIERS_TEXT"],"sources":["../../../src/classes/quoting.ts"],"sourcesContent":["import BigNumber from 'bignumber.js';\nimport type { NumericAmount } from '../types/amounts.js';\nimport { ALL_FEE_TIERS } from '../types/fees.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport type { QuoteResult } from '../types/v2_results.js';\nimport type { TokenRef } from '../utils/ordering.js';\nimport { validateNumericAmount } from '../utils/validation.js';\nimport type { WireOptions } from '@gala-chain/gala-core-sdk';\nimport type { ChainGateway } from './gateway.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from './gswap_error_catalog.js';\nimport { readServerMessage } from '../utils/server_message.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport { HttpClient } from './http_client.js';\nimport { queryTokenOf, type TokenResolver } from './symbols.js';\n\ninterface QuoteWire {\n contractVersion: 'v2';\n fee: number;\n amountIn: string;\n amountOut: string;\n currentSqrtPrice?: string;\n newSqrtPrice?: string;\n currentPrice?: string;\n newPrice?: string;\n newTick: number;\n tradingFees: string;\n protocolFees: string;\n totalFees: string;\n feeTokenSymbol: string;\n token0Symbol: string;\n token1Symbol: string;\n tokenInIsToken0: boolean;\n}\n\ninterface BackendEnvelope<T> {\n data: T;\n}\n\n/** The transport a quote service reads through: the same shape `Pools` and `Symbols` take. */\ntype QuoteGateway = Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n};\n\n/** Read-only quote service backed by the v2 offline quote engine. */\nexport class Quoting {\n /**\n * Creates a quote service.\n *\n * @example\n * ```ts\n * const quoting = new Quoting(gateway, symbols); // a ChainGateway, or any { dexBackendBaseUrl, httpRequestor }\n * ```\n */\n constructor(\n private readonly gateway: QuoteGateway,\n private readonly symbols: TokenResolver,\n ) {\n this.http = new HttpClient(\n gateway.httpRequestor,\n gateway.requestTimeoutMs ?? 30_000,\n gateway.wire,\n );\n }\n\n private readonly http: HttpClient;\n\n /**\n * Quotes the output for a positive exact-input amount.\n *\n * @example\n * ```ts\n * const quote = await quoting.quoteExactInput('GALA', 'GUSDC', '100');\n * console.log(quote.amountOut);\n * ```\n */\n public async quoteExactInput(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amountIn: NumericAmount,\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateNumericAmount(amountIn, 'amountIn');\n return this.quote(tokenIn, tokenOut, { amountIn: toDecimalString(amountIn) }, fee);\n }\n\n /**\n * Quotes the input for a positive exact-output amount.\n *\n * @example\n * ```ts\n * const quote = await quoting.quoteExactOutput('GALA', 'GUSDC', '10', 3000);\n * console.log(quote.amountIn);\n * ```\n */\n public async quoteExactOutput(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amountOut: NumericAmount,\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateNumericAmount(amountOut, 'amountOut');\n return this.quote(tokenIn, tokenOut, { amountOut: toDecimalString(amountOut) }, fee);\n }\n\n private async quote(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amount: { amountIn: string } | { amountOut: string },\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateOptionalFee(fee);\n\n const params: Record<string, string> = {\n tokenIn: await queryTokenOf(this.symbols, tokenIn),\n tokenOut: await queryTokenOf(this.symbols, tokenOut),\n ...amount,\n };\n if (fee !== undefined) params['fee'] = String(fee);\n\n try {\n const response = await this.http.sendGetRequest<BackendEnvelope<QuoteWire>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n '/quote',\n params,\n );\n return mapQuote(response.data);\n } catch (error: unknown) {\n throw mapQuoteError(error, tokenIn, tokenOut, fee, {\n tokenIn: params['tokenIn'] ?? '',\n tokenOut: params['tokenOut'] ?? '',\n });\n }\n }\n}\n\nfunction mapQuote(value: unknown): QuoteResult {\n if (!isQuoteWire(value)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'quote' },\n { body: value, write: false },\n );\n }\n const wire = value;\n const currentPrice =\n wire.currentPrice !== undefined\n ? new BigNumber(wire.currentPrice)\n : orientPrice(wire.currentSqrtPrice!, wire.tokenInIsToken0);\n const newPrice =\n wire.newPrice !== undefined\n ? new BigNumber(wire.newPrice)\n : orientPrice(wire.newSqrtPrice!, wire.tokenInIsToken0);\n const priceImpact = newPrice.minus(currentPrice).dividedBy(currentPrice);\n\n return {\n contractVersion: wire.contractVersion,\n fee: wire.fee,\n amountIn: wire.amountIn,\n amountOut: wire.amountOut,\n ...(wire.currentSqrtPrice === undefined ? {} : { currentSqrtPrice: wire.currentSqrtPrice }),\n ...(wire.newSqrtPrice === undefined ? {} : { newSqrtPrice: wire.newSqrtPrice }),\n feeTier: wire.fee,\n newTick: wire.newTick,\n tradingFees: wire.tradingFees,\n protocolFees: wire.protocolFees,\n totalFees: wire.totalFees,\n feeTokenSymbol: wire.feeTokenSymbol,\n token0Symbol: wire.token0Symbol,\n token1Symbol: wire.token1Symbol,\n tokenInIsToken0: wire.tokenInIsToken0,\n currentPrice,\n newPrice,\n priceImpact,\n };\n}\n\n// The default BigNumber.DECIMAL_PLACES (20) underflows 1/poolPrice to exactly 0 for a\n// pool price above ~1e20 (a real, in-range price for a low-unit-value token quoted\n// against a high-value one) — 60dp matches the precision ticks.ts's DexMath already\n// uses for this same class of division.\nconst HighPrecision = BigNumber.clone({ DECIMAL_PLACES: 60 });\n\nfunction orientPrice(sqrtPrice: string, tokenInIsToken0: boolean): BigNumber {\n const poolPrice = new HighPrecision(sqrtPrice).pow(2);\n return tokenInIsToken0 ? poolPrice : new HighPrecision(1).dividedBy(poolPrice);\n}\n\nfunction isQuoteWire(value: unknown): value is QuoteWire {\n if (typeof value !== 'object' || value === null) return false;\n const wire = value as Record<string, unknown>;\n const requiredStrings = [\n 'amountIn',\n 'amountOut',\n 'tradingFees',\n 'protocolFees',\n 'totalFees',\n 'feeTokenSymbol',\n 'token0Symbol',\n 'token1Symbol',\n ];\n return (\n wire['contractVersion'] === 'v2' &&\n typeof wire['fee'] === 'number' &&\n Number.isFinite(wire['fee']) &&\n requiredStrings.every((key) => typeof wire[key] === 'string') &&\n typeof wire['newTick'] === 'number' &&\n Number.isInteger(wire['newTick']) &&\n typeof wire['tokenInIsToken0'] === 'boolean' &&\n optionalPositiveDecimal(wire['currentSqrtPrice']) &&\n optionalPositiveDecimal(wire['newSqrtPrice']) &&\n optionalPositiveDecimal(wire['currentPrice']) &&\n optionalPositiveDecimal(wire['newPrice']) &&\n (wire['currentSqrtPrice'] !== undefined || wire['currentPrice'] !== undefined) &&\n (wire['newSqrtPrice'] !== undefined || wire['newPrice'] !== undefined)\n );\n}\n\nfunction optionalPositiveDecimal(value: unknown): boolean {\n if (value === undefined) return true;\n if (typeof value !== 'string') return false;\n try {\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — this validates an untrusted backend field, so an unparseable value\n // must fail validation cleanly (INVALID_CHAIN_RESPONSE), not throw raw.\n const decimal = new BigNumber(value);\n return decimal.isFinite() && decimal.isGreaterThan(0);\n } catch {\n return false;\n }\n}\n\n/**\n * The ways the backend says a pair has no market at all: no pool at ANY fee tier (\"No pools found\n * with sufficient liquidity\") or a missing pool (\"Pool does not exist on the new DEX contract\").\n * A pool that exists but is too thin says \"Insufficient liquidity: ...\" instead.\n */\nconst NO_MARKET_MESSAGE = /no pool|no pools|pool does not exist/iu;\n\n/**\n * A token the DEX contract never registered: the backend's symbol registry answers\n * `Token <token> has no trading symbol on the new DEX contract (no gcdex pool includes it yet).`\n * with an HTTP 400, naming the token exactly as the quote request sent it. That is a different\n * fact from \"no pool for this pair\" (the token itself is unknown), so it is `UNKNOWN_TOKEN` with\n * the token, not `NO_POOL_AVAILABLE`. Token class keys and symbols contain no whitespace.\n */\nconst NO_SYMBOL_MESSAGE = /Token (\\S+) has no trading symbol on the new DEX contract/u;\n\n/** The token the quote request named in the form the caller gave it, else as the backend echoed it. */\nfunction unknownTokenOf(\n echoed: string,\n queried: { tokenIn: string; tokenOut: string },\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n): TokenRef {\n if (echoed === queried.tokenIn) return tokenIn;\n if (echoed === queried.tokenOut) return tokenOut;\n return echoed;\n}\n\nfunction mapQuoteError(\n error: unknown,\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n fee: FEE_TIER | undefined,\n queried: { tokenIn: string; tokenOut: string },\n): GSwapSDKError {\n if (isGSwapError(error)) {\n // The backend's own English is read ONLY to classify its answer; it is never surfaced. The\n // SDK's generated `message` is never matched: its templates are not a contract.\n const message = readServerMessage(error) ?? '';\n const unregistered = NO_SYMBOL_MESSAGE.exec(message)?.[1];\n if (unregistered !== undefined) {\n return GSwapSDKError.unknownTokenError(\n unknownTokenOf(unregistered, queried, tokenIn, tokenOut),\n error,\n );\n }\n if (error.status === 404 || NO_MARKET_MESSAGE.test(message)) {\n return GSwapSDKError.noPoolAvailableError(tokenIn, tokenOut, fee, error);\n }\n if (error.status === 400 && /insufficient liquidity/iu.test(message)) {\n return GSwapSDKError.insufficientLiquidityError(tokenIn, tokenOut, fee, error);\n }\n return error;\n }\n return new GSwapSDKError(\n 'REQUEST_FAILED',\n { operation: 'quote' },\n { cause: error, write: false },\n );\n}\n\nfunction validateOptionalFee(fee: FEE_TIER | undefined): void {\n if (fee !== undefined && !ALL_FEE_TIERS.some((tier) => Number(tier) === Number(fee))) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: Number(fee),\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n}\n\nfunction toDecimalString(amount: NumericAmount): string {\n return new BigNumber(amount).toFixed();\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shadow_submit.js","names":["SHADOW_SUBMIT_CODES","SHADOW_FAILURE_KINDS","classifyShadowSubmitStatus","status","classifyShadowSubmitError","code","readShadowSubmitOutcome","result","envelope","asRecord","body","httpStatus","\"error\"","data","\"data\"","rawTransactionId","\"transactionId\"","method","requestedKey","signedBody","\"uniqueKey\"","\"mode\"","GSwapSDKError","kind","getStringProperty","value"],"sources":["../../../src/classes/shadow_submit.ts"],"sourcesContent":["import { getStringProperty, GSwapSDKError } from './gswap_sdk_error.js';\n\n/** The raw answer to a shadow (dark) write: every HTTP status resolves. */\nexport interface ShadowSubmitResult {\n httpStatus: number;\n /** Parsed JSON body, or the raw text when the body was not JSON. */\n body: unknown;\n}\n\n/**\n * Machine-readable codes the swap backend returns in a shadow failure body (`{ code, message }`, with\n * no `statusCode`; the HTTP status carries the number).\n *\n * - `SHADOW_UNAVAILABLE` (503): marking failed or infra not configured; retryable. Never fall back\n * silently to a public swap.\n * - `SHADOW_UNSUPPORTED_TYPE` (400): shadow requested on a non-swap method.\n * - `SHADOW_RELAY_REJECTED`: terminal business rejection (slippage, balance, ...), not retryable;\n * `message` is the gateway's verbatim string.\n */\nexport const SHADOW_SUBMIT_CODES = [\n 'SHADOW_UNAVAILABLE',\n 'SHADOW_UNSUPPORTED_TYPE',\n 'SHADOW_RELAY_REJECTED',\n] as const;\n\n/** One member of {@link SHADOW_SUBMIT_CODES}. */\nexport type ShadowSubmitCode = (typeof SHADOW_SUBMIT_CODES)[number];\n\n/**\n * Every `kind` of a failed {@link ShadowSubmitOutcome}, for an app that maps each to its own text\n * (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled` (the shadow route\n * answered 400: the request is not a dark-swappable one, e.g. `SHADOW_UNSUPPORTED_TYPE`; Shadow\n * Swaps themselves are enabled in every environment), `rejected` (carries the gateway's `message`)\n * and `unknown`.\n */\nexport const SHADOW_FAILURE_KINDS = ['unavailable', 'disabled', 'rejected', 'unknown'] as const;\n\n/** One member of {@link SHADOW_FAILURE_KINDS}. */\nexport type ShadowFailureKind = (typeof SHADOW_FAILURE_KINDS)[number];\n\n/** A RequestTrade the gateway queued: the handle to confirm it with `confirmAppliedTrade`. */\nexport interface ShadowQueuedRequest {\n uniqueKey: string;\n requestTransactionId: string | null;\n}\n\n/** A shadow write the gateway refused or did not answer: `kind` says why (see {@link SHADOW_FAILURE_KINDS}). */\nexport type ShadowSubmitFailure =\n | { ok: false; kind: 'unavailable'; retryable: true }\n | { ok: false; kind: 'disabled'; retryable: false }\n | { ok: false; kind: 'rejected'; retryable: false; message: string }\n | { ok: false; kind: 'unknown'; retryable: false };\n\n/**\n * The normalized outcome of a shadow RequestTrade (a dark swap). A success (`ok: true`) ALWAYS\n * carries `queued`, the exact key the gateway acknowledged: a RequestTrade answer that does not\n * queue the signed key is not an outcome but a thrown `SHADOW_NOT_QUEUED`. So after `if (outcome.ok)`\n * the app reads `outcome.queued` with no `undefined` branch.\n */\nexport type ShadowSubmitOutcome =\n | {\n ok: true;\n /** The request transaction id (`''` when the gateway gave none). */\n bundleId: string;\n /** Confirm with `confirmAppliedTrade`. */\n queued: ShadowQueuedRequest;\n }\n | ShadowSubmitFailure;\n\n/**\n * The success of a shadow write that is NOT a RequestTrade and executed synchronously\n * (`mode: 'sync'`, a liquidity write): there is nothing queued to confirm, so `queued` is absent.\n */\nexport interface ShadowSyncSuccess {\n ok: true;\n /** The transaction id (`''` when the gateway gave none). */\n bundleId: string;\n queued?: undefined;\n}\n\n/** Maps an HTTP status to a failure kind: 503 retryable, 400 disabled, anything else unknown. */\nexport function classifyShadowSubmitStatus(status: number): ShadowFailureKind {\n if (status === 503) return 'unavailable';\n if (status === 400) return 'disabled';\n return 'unknown';\n}\n\n/**\n * Prefers the body `code` (stable across status remaps) and falls back to the HTTP status.\n * `SHADOW_UNAVAILABLE` is the only retryable case; `SHADOW_RELAY_REJECTED` is a terminal gateway\n * rejection; `SHADOW_UNSUPPORTED_TYPE` and any other 400 map to \"disabled\".\n */\nexport function classifyShadowSubmitError(status: number, code?: string): ShadowFailureKind {\n if (code === 'SHADOW_UNAVAILABLE') return 'unavailable';\n if (code === 'SHADOW_RELAY_REJECTED') return 'rejected';\n if (code === 'SHADOW_UNSUPPORTED_TYPE') return 'disabled';\n return classifyShadowSubmitStatus(status);\n}\n\n/**\n * Normalizes a shadow write's raw answer. For `'RequestTrade'` the result is a\n * {@link ShadowSubmitOutcome}, whose success always has `queued`; any other method may also be a\n * {@link ShadowSyncSuccess} (no `queued`).\n *\n * A 2xx envelope with `error === false` is a success when it is a queued RequestTrade that\n * acknowledges the EXACT signed `uniqueKey`, or a synchronous (`mode: 'sync'`) liquidity write.\n * Everything else is classified as a failure from the status and the body's `code`.\n *\n * @throws GSwapSDKError SHADOW_NOT_QUEUED when a RequestTrade success does not queue the\n * signed `uniqueKey` (a synchronous or mismatched answer must never be accepted as a swap).\n */\nexport function readShadowSubmitOutcome(\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome;\nexport function readShadowSubmitOutcome(\n method: string,\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome | ShadowSyncSuccess;\nexport function readShadowSubmitOutcome(\n method: string,\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome | ShadowSyncSuccess {\n const { httpStatus, body } = result;\n const envelope = asRecord(body);\n if (httpStatus >= 200 && httpStatus < 300 && envelope?.['error'] === false) {\n const data = asRecord(envelope['data']);\n const rawTransactionId =\n typeof data?.['transactionId'] === 'string' ? data['transactionId'] : undefined;\n if (method === 'RequestTrade') {\n const requestedKey = signedBody['uniqueKey'];\n if (\n data?.['mode'] !== 'queued' ||\n typeof requestedKey !== 'string' ||\n data['uniqueKey'] !== requestedKey\n ) {\n throw new GSwapSDKError(\n 'SHADOW_NOT_QUEUED',\n {},\n {\n status: httpStatus,\n body,\n shadow: true,\n ...(typeof requestedKey === 'string' ? { uniqueKey: requestedKey } : {}),\n },\n );\n }\n return {\n ok: true,\n bundleId: rawTransactionId ?? '',\n queued: { uniqueKey: requestedKey, requestTransactionId: rawTransactionId ?? null },\n };\n }\n if (data?.['mode'] === 'sync') return { ok: true, bundleId: rawTransactionId ?? '' };\n }\n\n const kind = classifyShadowSubmitError(httpStatus, getStringProperty(body, 'code'));\n if (kind === 'rejected') {\n return {\n ok: false,\n kind: 'rejected',\n retryable: false,\n message: getStringProperty(body, 'message') ?? '',\n };\n }\n return kind === 'unavailable'\n ? { ok: false, kind, retryable: true }\n : { ok: false, kind, retryable: false };\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n"],"mappings":"4EAmBA,MAAaA,EAAsB,CACjC,qBACA,0BACA,uBACF,EAYaC,EAAuB,CAAC,cAAe,WAAY,WAAY,SAAS,EA8CrF,SAAgBC,EAA2B,EAAmC,CAG5E,OAFIC,IAAW,IAAY,cACvBA,IAAW,IAAY,WACpB,SACT,CAOA,SAAgBC,EAA0B,EAAgB,EAAkC,CAI1F,OAHIC,IAAS,qBAA6B,cACtCA,IAAS,wBAAgC,WACzCA,IAAS,0BAAkC,WACxCH,EAA2BC,CAAM,CAC1C,CAwBA,SAAgBG,EACd,EACA,EACA,EACyC,CACzC,GAAM,CAAE,aAAY,QAASC,EACvBC,EAAWC,EAASC,CAAI,EAC9B,GAAIC,GAAc,KAAOA,EAAa,KAAOH,GAAWI,QAAa,GAAO,CAC1E,IAAMC,EAAOJ,EAASD,EAASM,IAAO,EAChCC,EACJ,OAAOF,GAAOG,eAAqB,SAAWH,EAAKG,cAAmB,IAAA,GACxE,GAAIC,IAAW,eAAgB,CAC7B,IAAMC,EAAeC,EAAWC,UAChC,GACEP,GAAOQ,OAAY,UACnB,OAAOH,GAAiB,UACxBL,EAAKO,YAAiBF,EAEtB,MAAM,IAAII,EACR,oBACA,CAAC,EACD,CACE,OAAQX,EACR,OACA,OAAQ,GACR,GAAI,OAAOO,GAAiB,SAAW,CAAE,UAAWA,CAAa,EAAI,CAAC,CACxE,CACF,EAEF,MAAO,CACL,GAAI,GACJ,SAAUH,GAAoB,GAC9B,OAAQ,CAAE,UAAWG,EAAc,qBAAsBH,GAAoB,IAAK,CACpF,CACF,CACA,GAAIF,GAAOQ,OAAY,OAAQ,MAAO,CAAE,GAAI,GAAM,SAAUN,GAAoB,EAAG,CACrF,CAEA,IAAMQ,EAAOnB,EAA0BO,EAAYa,EAAkBd,EAAM,MAAM,CAAC,EASlF,OARIa,IAAS,WACJ,CACL,GAAI,GACJ,KAAM,WACN,UAAW,GACX,QAASC,EAAkBd,EAAM,SAAS,GAAK,EACjD,EAEKa,IAAS,cACZ,CAAE,GAAI,GAAO,OAAM,UAAW,EAAK,EACnC,CAAE,GAAI,GAAO,OAAM,UAAW,EAAM,CAC1C,CAEA,SAASd,EAAS,EAAqD,CACrE,OAAO,OAAOgB,GAAU,UAAYA,EAC/BA,EACD,IAAA,EACN"}
|
|
1
|
+
{"version":3,"file":"shadow_submit.js","names":["SHADOW_SUBMIT_CODES","SHADOW_FAILURE_KINDS","classifyShadowSubmitStatus","status","classifyShadowSubmitError","code","readShadowSubmitOutcome","result","envelope","asRecord","body","httpStatus","\"error\"","data","\"data\"","rawTransactionId","\"transactionId\"","method","requestedKey","signedBody","\"uniqueKey\"","\"mode\"","GSwapSDKError","kind","getStringProperty","value"],"sources":["../../../src/classes/shadow_submit.ts"],"sourcesContent":["import { getStringProperty, GSwapSDKError } from './gswap_sdk_error.js';\n\n/** The raw answer to a shadow (dark) write: every HTTP status resolves. */\nexport interface ShadowSubmitResult {\n httpStatus: number;\n /** Parsed JSON body, or the raw text when the body was not JSON. */\n body: unknown;\n}\n\n/**\n * Machine-readable codes the swap backend returns in a shadow failure body (`{ code, message }`, with\n * no `statusCode`; the HTTP status carries the number).\n *\n * - `SHADOW_UNAVAILABLE` (503): marking failed or infra not configured; retryable. Never fall back\n * silently to a public swap.\n * - `SHADOW_UNSUPPORTED_TYPE` (400): shadow requested on a non-swap method.\n * - `SHADOW_RELAY_REJECTED`: terminal business rejection (slippage, balance, ...), not retryable;\n * `message` is the gateway's verbatim string.\n */\nexport const SHADOW_SUBMIT_CODES = [\n 'SHADOW_UNAVAILABLE',\n 'SHADOW_UNSUPPORTED_TYPE',\n 'SHADOW_RELAY_REJECTED',\n] as const;\n\n/** One member of {@link SHADOW_SUBMIT_CODES}. */\nexport type ShadowSubmitCode = (typeof SHADOW_SUBMIT_CODES)[number];\n\n/**\n * Every `kind` of a failed {@link ShadowSubmitOutcome}, for an app that maps each to its own text\n * (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled` (the shadow route\n * answered 400: the request is not a dark-swappable one, e.g. `SHADOW_UNSUPPORTED_TYPE`; Shadow\n * Swaps themselves are enabled in every environment), `rejected` (carries the gateway's `message`)\n * and `unknown`.\n */\nexport const SHADOW_FAILURE_KINDS = ['unavailable', 'disabled', 'rejected', 'unknown'] as const;\n\n/** One member of {@link SHADOW_FAILURE_KINDS}. */\nexport type ShadowFailureKind = (typeof SHADOW_FAILURE_KINDS)[number];\n\n/** A RequestTrade the gateway queued: the handle to confirm it with `confirmAppliedTrade`. */\nexport interface ShadowQueuedRequest {\n uniqueKey: string;\n requestTransactionId: string | null;\n}\n\n/** A shadow write the gateway refused or did not answer: `kind` says why (see {@link SHADOW_FAILURE_KINDS}). */\nexport type ShadowSubmitFailure =\n | { ok: false; kind: 'unavailable'; retryable: true }\n | { ok: false; kind: 'disabled'; retryable: false }\n | { ok: false; kind: 'rejected'; retryable: false; message: string }\n | { ok: false; kind: 'unknown'; retryable: false };\n\n/**\n * The normalized outcome of a shadow RequestTrade (a dark swap). A success (`ok: true`) ALWAYS\n * carries `queued`, the exact key the gateway acknowledged: a RequestTrade answer that does not\n * queue the signed key is not an outcome but a thrown `SHADOW_NOT_QUEUED`. So after `if (outcome.ok)`\n * the app reads `outcome.queued` with no `undefined` branch.\n */\nexport type ShadowSubmitOutcome =\n | {\n ok: true;\n /** The request transaction id (`''` when the gateway gave none). */\n bundleId: string;\n /** Confirm with `confirmAppliedTrade`. */\n queued: ShadowQueuedRequest;\n }\n | ShadowSubmitFailure;\n\n/**\n * The success of a shadow write that is NOT a RequestTrade and executed synchronously\n * (`mode: 'sync'`, a liquidity write): there is nothing queued to confirm, so `queued` is absent.\n */\nexport interface ShadowSyncSuccess {\n ok: true;\n /** The transaction id (`''` when the gateway gave none). */\n bundleId: string;\n queued?: undefined;\n}\n\n/** Maps an HTTP status to a failure kind: 503 retryable, 400 disabled, anything else unknown. */\nexport function classifyShadowSubmitStatus(status: number): ShadowFailureKind {\n if (status === 503) return 'unavailable';\n if (status === 400) return 'disabled';\n return 'unknown';\n}\n\n/**\n * Prefers the body `code` (stable across status remaps) and falls back to the HTTP status.\n * `SHADOW_UNAVAILABLE` is the only retryable case; `SHADOW_RELAY_REJECTED` is a terminal gateway\n * rejection; `SHADOW_UNSUPPORTED_TYPE` and any other 400 map to \"disabled\".\n */\nexport function classifyShadowSubmitError(status: number, code?: string): ShadowFailureKind {\n if (code === 'SHADOW_UNAVAILABLE') return 'unavailable';\n if (code === 'SHADOW_RELAY_REJECTED') return 'rejected';\n if (code === 'SHADOW_UNSUPPORTED_TYPE') return 'disabled';\n return classifyShadowSubmitStatus(status);\n}\n\n/**\n * Normalizes a shadow write's raw answer. For `'RequestTrade'` the result is a\n * {@link ShadowSubmitOutcome}, whose success always has `queued`; any other method may also be a\n * {@link ShadowSyncSuccess} (no `queued`).\n *\n * A 2xx envelope with `error === false` is a success when it is a queued RequestTrade that\n * acknowledges the EXACT signed `uniqueKey`, or a synchronous (`mode: 'sync'`) liquidity write.\n * Everything else is classified as a failure from the status and the body's `code`.\n *\n * @throws GSwapSDKError SHADOW_NOT_QUEUED when a RequestTrade success does not queue the\n * signed `uniqueKey` (a synchronous or mismatched answer must never be accepted as a swap).\n */\nexport function readShadowSubmitOutcome(\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome;\nexport function readShadowSubmitOutcome(\n method: string,\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome | ShadowSyncSuccess;\nexport function readShadowSubmitOutcome(\n method: string,\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome | ShadowSyncSuccess {\n const { httpStatus, body } = result;\n const envelope = asRecord(body);\n if (httpStatus >= 200 && httpStatus < 300 && envelope?.['error'] === false) {\n const data = asRecord(envelope['data']);\n const rawTransactionId =\n typeof data?.['transactionId'] === 'string' ? data['transactionId'] : undefined;\n if (method === 'RequestTrade') {\n const requestedKey = signedBody['uniqueKey'];\n if (\n data?.['mode'] !== 'queued' ||\n typeof requestedKey !== 'string' ||\n data['uniqueKey'] !== requestedKey\n ) {\n throw new GSwapSDKError(\n 'SHADOW_NOT_QUEUED',\n {},\n {\n status: httpStatus,\n body,\n shadow: true,\n ...(typeof requestedKey === 'string' ? { uniqueKey: requestedKey } : {}),\n },\n );\n }\n return {\n ok: true,\n bundleId: rawTransactionId ?? '',\n queued: { uniqueKey: requestedKey, requestTransactionId: rawTransactionId ?? null },\n };\n }\n if (data?.['mode'] === 'sync') return { ok: true, bundleId: rawTransactionId ?? '' };\n }\n\n const kind = classifyShadowSubmitError(httpStatus, getStringProperty(body, 'code'));\n if (kind === 'rejected') {\n return {\n ok: false,\n kind: 'rejected',\n retryable: false,\n message: getStringProperty(body, 'message') ?? '',\n };\n }\n return kind === 'unavailable'\n ? { ok: false, kind, retryable: true }\n : { ok: false, kind, retryable: false };\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n"],"mappings":"A,4EAmBA,MAAaA,EAAsB,CACjC,qBACA,0BACA,uBACF,EAYaC,EAAuB,CAAC,cAAe,WAAY,WAAY,SAAS,EA8CrF,SAAgBC,EAA2B,EAAmC,CAG5E,OAFIC,IAAW,IAAY,cACvBA,IAAW,IAAY,WACpB,SACT,CAOA,SAAgBC,EAA0B,EAAgB,EAAkC,CAI1F,OAHIC,IAAS,qBAA6B,cACtCA,IAAS,wBAAgC,WACzCA,IAAS,0BAAkC,WACxCH,EAA2BC,CAAM,CAC1C,CAwBA,SAAgBG,EACd,EACA,EACA,EACyC,CACzC,GAAM,CAAE,aAAY,QAASC,EACvBC,EAAWC,EAASC,CAAI,EAC9B,GAAIC,GAAc,KAAOA,EAAa,KAAOH,GAAWI,QAAa,GAAO,CAC1E,IAAMC,EAAOJ,EAASD,EAASM,IAAO,EAChCC,EACJ,OAAOF,GAAOG,eAAqB,SAAWH,EAAKG,cAAmB,IAAA,GACxE,GAAIC,IAAW,eAAgB,CAC7B,IAAMC,EAAeC,EAAWC,UAChC,GACEP,GAAOQ,OAAY,UACnB,OAAOH,GAAiB,UACxBL,EAAKO,YAAiBF,EAEtB,MAAM,IAAII,EACR,oBACA,CAAC,EACD,CACE,OAAQX,EACR,OACA,OAAQ,GACR,GAAI,OAAOO,GAAiB,SAAW,CAAE,UAAWA,CAAa,EAAI,CAAC,CACxE,CACF,EAEF,MAAO,CACL,GAAI,GACJ,SAAUH,GAAoB,GAC9B,OAAQ,CAAE,UAAWG,EAAc,qBAAsBH,GAAoB,IAAK,CACpF,CACF,CACA,GAAIF,GAAOQ,OAAY,OAAQ,MAAO,CAAE,GAAI,GAAM,SAAUN,GAAoB,EAAG,CACrF,CAEA,IAAMQ,EAAOnB,EAA0BO,EAAYa,EAAkBd,EAAM,MAAM,CAAC,EASlF,OARIa,IAAS,WACJ,CACL,GAAI,GACJ,KAAM,WACN,UAAW,GACX,QAASC,EAAkBd,EAAM,SAAS,GAAK,EACjD,EAEKa,IAAS,cACZ,CAAE,GAAI,GAAO,OAAM,UAAW,EAAK,EACnC,CAAE,GAAI,GAAO,OAAM,UAAW,EAAM,CAC1C,CAEA,SAASd,EAAS,EAAqD,CACrE,OAAO,OAAOgB,GAAU,UAAYA,EAC/BA,EACD,IAAA,EACN,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage_adapters.js","names":["storageAdapterFromChromeStorage","areaNow","area","items","key","value","webStorageAdapter","raw"],"sources":["../../../src/classes/storage_adapters.ts"],"sourcesContent":["/**\n * Async key/value storage the pending-swap store persists through. It stores STRUCTURED VALUES\n * (the store never serializes), so each platform decides how a value lands on disk:\n *\n * - `chrome.storage.local`: `get: async (k) => (await chrome.storage.local.get(k))[k]`,\n * `set: (k, v) => chrome.storage.local.set({ [k]: v })`. This is the wallet's stored shape.\n * {@link storageAdapterFromChromeStorage} builds it.\n * - `localStorage` (a web app): JSON text under the key. {@link webStorageAdapter} builds it,\n * and returns CORRUPT JSON as a value (the raw string), not as a rejection: a value that is not\n * an array reads as \"no entries\" and the next write repairs it, whereas a `get` that rejects\n * forever makes every `remember` a no-op.\n * - React Native: AsyncStorage with the same JSON wrapping and the same corrupt-JSON rule.\n *\n * `get` resolves `undefined` for a missing key. Either method may reject; the store treats that\n * as \"storage unavailable\" and never lets it surface (see `PendingSwapStore`).\n *\n * This module imports nothing, so an app shell that only builds an adapter pays for the adapter.\n */\nexport interface StorageAdapter {\n get(key: string): Promise<unknown>;\n set(key: string, value: unknown): Promise<void>;\n}\n\n/**\n * The part of a `chrome.storage` area ({@link storageAdapterFromChromeStorage}) the adapter uses,\n * written structurally so the SDK needs no `chrome` types: `chrome.storage.local`,\n * `chrome.storage.session`, `browser.storage.local` (webextension-polyfill) and any object with\n * these two promise-returning methods satisfy it. It is the Manifest V3 promise form: the methods\n * are called WITHOUT a callback.\n */\nexport interface ChromeStorageAreaLike {\n get(key: string): Promise<Record<string, unknown>>;\n set(items: Record<string, unknown>): Promise<void>;\n}\n\n/**\n * A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps\n * in: the value lands under the key as the structured value it is (the browser clones it; nothing\n * is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the\n * store, which treats it as \"storage unavailable\".\n *\n * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is\n * built: a module that is imported where `chrome` does not exist yet (a test, a closing extension\n * context) then fails only when the store touches storage, and that failure (a throw inside the\n * function) is the same \"storage unavailable\" rejection.\n *\n * @example\n * ```ts\n * const store = new PendingSwapStore(storageAdapterFromChromeStorage(chrome.storage.local));\n * const lazy = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local));\n * ```\n */\nexport function storageAdapterFromChromeStorage(\n area: ChromeStorageAreaLike | (() => ChromeStorageAreaLike),\n): StorageAdapter {\n const areaNow = (): ChromeStorageAreaLike => (typeof area === 'function' ? area() : area);\n return {\n async get(key) {\n const items = await areaNow().get(key);\n return Object.hasOwn(items, key) ? items[key] : undefined;\n },\n async set(key, value) {\n await areaNow().set({ [key]: value });\n },\n };\n}\n\n/**\n * The part of a Web Storage area ({@link webStorageAdapter}) the adapter uses, written\n * structurally so the SDK needs no DOM types: `localStorage`, `sessionStorage` and any object with\n * these two synchronous methods (a React Native MMKV wrapper, a test double) satisfy it.\n */\nexport interface WebStorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\n/**\n * A {@link StorageAdapter} over a Web Storage area (`localStorage`, `sessionStorage`), the shape\n * a web app stores pending swaps in: the value lands under the key as JSON text. A missing key\n * resolves `undefined`. CORRUPT JSON resolves as the raw string, never a rejection (the store\n * reads a value that is not an array as \"no entries\" and the next write repairs it, whereas a\n * `get` that rejects forever would make every `remember` a no-op). A throwing area (storage blocked\n * by the browser, quota exceeded on `setItem`) rejects, which the store treats as \"storage\n * unavailable\".\n *\n * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is\n * built: where `localStorage` does not exist (server rendering, a test, a blocked context)\n * the access throws inside the function, which is the same \"storage unavailable\" rejection, and\n * the module that builds the adapter still loads.\n *\n * @example\n * ```ts\n * const store = new PendingSwapStore(webStorageAdapter(() => localStorage));\n * ```\n */\nexport function webStorageAdapter(area: WebStorageLike | (() => WebStorageLike)): StorageAdapter {\n const areaNow = (): WebStorageLike => (typeof area === 'function' ? area() : area);\n return {\n async get(key) {\n const raw = areaNow().getItem(key);\n if (raw === null) return undefined;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n },\n async set(key, value) {\n areaNow().setItem(key, JSON.stringify(value));\n },\n };\n}\n"],"mappings":"AAoDA,SAAgBA,EACd,EACgB,CAChB,IAAMC,MAAwC,OAAOC,GAAS,WAAaA,EAAK,EAAIA,EACpF,MAAO,CACL,MAAM,IAAI,EAAK,CACb,IAAMC,EAAQ,MAAMF,EAAQ,CAAC,CAAC,IAAIG,CAAG,EACrC,OAAO,OAAO,OAAOD,EAAOC,CAAG,EAAID,EAAMC,GAAO,IAAA,EAClD,EACA,MAAM,IAAI,EAAK,EAAO,CACpB,MAAMH,EAAQ,CAAC,CAAC,IAAI,EAAGG,GAAMC,CAAM,CAAC,CACtC,CACF,CACF,CA+BA,SAAgBC,EAAkB,EAA+D,CAC/F,IAAML,MAAiC,OAAOC,GAAS,WAAaA,EAAK,EAAIA,EAC7E,MAAO,CACL,MAAM,IAAI,EAAK,CACb,IAAMK,EAAMN,EAAQ,CAAC,CAAC,QAAQG,CAAG,EACjC,GAAIG,IAAQ,KACZ,GAAI,CACF,OAAO,KAAK,MAAMA,CAAG,CACvB,MAAQ,CACN,OAAOA,CACT,CACF,EACA,MAAM,IAAI,EAAK,EAAO,CACpBN,EAAQ,CAAC,CAAC,QAAQG,EAAK,KAAK,UAAUC,CAAK,CAAC,CAC9C,CACF,CACF"}
|
|
1
|
+
{"version":3,"file":"storage_adapters.js","names":["storageAdapterFromChromeStorage","areaNow","area","items","key","value","webStorageAdapter","raw"],"sources":["../../../src/classes/storage_adapters.ts"],"sourcesContent":["/**\n * Async key/value storage the pending-swap store persists through. It stores STRUCTURED VALUES\n * (the store never serializes), so each platform decides how a value lands on disk:\n *\n * - `chrome.storage.local`: `get: async (k) => (await chrome.storage.local.get(k))[k]`,\n * `set: (k, v) => chrome.storage.local.set({ [k]: v })`. This is the wallet's stored shape.\n * {@link storageAdapterFromChromeStorage} builds it.\n * - `localStorage` (a web app): JSON text under the key. {@link webStorageAdapter} builds it,\n * and returns CORRUPT JSON as a value (the raw string), not as a rejection: a value that is not\n * an array reads as \"no entries\" and the next write repairs it, whereas a `get` that rejects\n * forever makes every `remember` a no-op.\n * - React Native: AsyncStorage with the same JSON wrapping and the same corrupt-JSON rule.\n *\n * `get` resolves `undefined` for a missing key. Either method may reject; the store treats that\n * as \"storage unavailable\" and never lets it surface (see `PendingSwapStore`).\n *\n * This module imports nothing, so an app shell that only builds an adapter pays for the adapter.\n */\nexport interface StorageAdapter {\n get(key: string): Promise<unknown>;\n set(key: string, value: unknown): Promise<void>;\n}\n\n/**\n * The part of a `chrome.storage` area ({@link storageAdapterFromChromeStorage}) the adapter uses,\n * written structurally so the SDK needs no `chrome` types: `chrome.storage.local`,\n * `chrome.storage.session`, `browser.storage.local` (webextension-polyfill) and any object with\n * these two promise-returning methods satisfy it. It is the Manifest V3 promise form: the methods\n * are called WITHOUT a callback.\n */\nexport interface ChromeStorageAreaLike {\n get(key: string): Promise<Record<string, unknown>>;\n set(items: Record<string, unknown>): Promise<void>;\n}\n\n/**\n * A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps\n * in: the value lands under the key as the structured value it is (the browser clones it; nothing\n * is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the\n * store, which treats it as \"storage unavailable\".\n *\n * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is\n * built: a module that is imported where `chrome` does not exist yet (a test, a closing extension\n * context) then fails only when the store touches storage, and that failure (a throw inside the\n * function) is the same \"storage unavailable\" rejection.\n *\n * @example\n * ```ts\n * const store = new PendingSwapStore(storageAdapterFromChromeStorage(chrome.storage.local));\n * const lazy = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local));\n * ```\n */\nexport function storageAdapterFromChromeStorage(\n area: ChromeStorageAreaLike | (() => ChromeStorageAreaLike),\n): StorageAdapter {\n const areaNow = (): ChromeStorageAreaLike => (typeof area === 'function' ? area() : area);\n return {\n async get(key) {\n const items = await areaNow().get(key);\n return Object.hasOwn(items, key) ? items[key] : undefined;\n },\n async set(key, value) {\n await areaNow().set({ [key]: value });\n },\n };\n}\n\n/**\n * The part of a Web Storage area ({@link webStorageAdapter}) the adapter uses, written\n * structurally so the SDK needs no DOM types: `localStorage`, `sessionStorage` and any object with\n * these two synchronous methods (a React Native MMKV wrapper, a test double) satisfy it.\n */\nexport interface WebStorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\n/**\n * A {@link StorageAdapter} over a Web Storage area (`localStorage`, `sessionStorage`), the shape\n * a web app stores pending swaps in: the value lands under the key as JSON text. A missing key\n * resolves `undefined`. CORRUPT JSON resolves as the raw string, never a rejection (the store\n * reads a value that is not an array as \"no entries\" and the next write repairs it, whereas a\n * `get` that rejects forever would make every `remember` a no-op). A throwing area (storage blocked\n * by the browser, quota exceeded on `setItem`) rejects, which the store treats as \"storage\n * unavailable\".\n *\n * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is\n * built: where `localStorage` does not exist (server rendering, a test, a blocked context)\n * the access throws inside the function, which is the same \"storage unavailable\" rejection, and\n * the module that builds the adapter still loads.\n *\n * @example\n * ```ts\n * const store = new PendingSwapStore(webStorageAdapter(() => localStorage));\n * ```\n */\nexport function webStorageAdapter(area: WebStorageLike | (() => WebStorageLike)): StorageAdapter {\n const areaNow = (): WebStorageLike => (typeof area === 'function' ? area() : area);\n return {\n async get(key) {\n const raw = areaNow().getItem(key);\n if (raw === null) return undefined;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n },\n async set(key, value) {\n areaNow().setItem(key, JSON.stringify(value));\n },\n };\n}\n"],"mappings":"AAoDA,SAAgBA,EACd,EACgB,CAChB,IAAMC,MAAwC,OAAOC,GAAS,WAAaA,EAAK,EAAIA,EACpF,MAAO,CACL,MAAM,IAAI,EAAK,CACb,IAAMC,EAAQ,MAAMF,EAAQ,CAAC,CAAC,IAAIG,CAAG,EACrC,OAAO,OAAO,OAAOD,EAAOC,CAAG,EAAID,EAAMC,GAAO,IAAA,EAClD,EACA,MAAM,IAAI,EAAK,EAAO,CACpB,MAAMH,EAAQ,CAAC,CAAC,IAAI,EAAGG,GAAMC,CAAM,CAAC,CACtC,CACF,CACF,CA+BA,SAAgBC,EAAkB,EAA+D,CAC/F,IAAML,MAAiC,OAAOC,GAAS,WAAaA,EAAK,EAAIA,EAC7E,MAAO,CACL,MAAM,IAAI,EAAK,CACb,IAAMK,EAAMN,EAAQ,CAAC,CAAC,QAAQG,CAAG,EACjC,GAAIG,IAAQ,KACZ,GAAI,CACF,OAAO,KAAK,MAAMA,CAAG,CACvB,MAAQ,CACN,OAAOA,CACT,CACF,EACA,MAAM,IAAI,EAAK,EAAO,CACpBN,EAAQ,CAAC,CAAC,QAAQG,EAAK,KAAK,UAAUC,CAAK,CAAC,CAC9C,CACF,CACF,C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createConfirmationSchedule as e,throwIfAborted as t}from"../utils/confirmation_schedule.js";import n from"../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import{createConfirmationSchedule as e,throwIfAborted as t}from"../utils/confirmation_schedule.js";import n from"../_virtual/_@oxc-project_runtime@0.154.0/helpers/esm/defineProperty.js";import{GSwapSDKError as r,isGSwapError as i}from"./gswap_sdk_error.js";import{confirmAppliedTrade as a}from"./apply_results.js";import{armTimeout as o}from"@gala-chain/gala-core-sdk";var s=class{constructor(e){n(this,`method`,void 0),n(this,`uniqueKey`,void 0),n(this,`transactionId`,void 0),n(this,`blockNumber`,void 0),n(this,`mode`,void 0),n(this,`status`,void 0),n(this,`result`,void 0),n(this,`envelope`,void 0),n(this,`backendBaseUrl`,void 0),n(this,`requestor`,void 0),n(this,`requestTimeoutMs`,void 0),n(this,`wire`,void 0),n(this,`positionConfirmation`,void 0),this.method=e.method,this.uniqueKey=e.uniqueKey,this.transactionId=e.transactionId,this.blockNumber=e.blockNumber??null,this.mode=e.mode,this.status=e.mode===`queued`?`queued`:`executed`,this.result=e.result,this.envelope=e.envelope,this.backendBaseUrl=e.dexBackendBaseUrl.replace(/\/$/u,``),this.requestor=e.httpRequestor,this.requestTimeoutMs=e.requestTimeoutMs??3e4,this.wire=e.wire,this.positionConfirmation=e.positionConfirmation}async confirm(e){return this.method===`RequestTrade`?this.confirmApplied(e):this.confirmPosition(e)}confirmApplied(e){return a({dexBackendBaseUrl:this.backendBaseUrl,httpRequestor:this.requestor,requestTimeoutMs:this.requestTimeoutMs,wire:this.wire},{uniqueKey:this.uniqueKey,requestTransactionId:this.transactionId},e)}async confirmPosition(n){if(this.positionConfirmation===void 0)throw r.noWalletAddressError();let i=n?.signal,a=e=>new r(`CONFIRMATION_ABORTED`,{},{uniqueKey:this.uniqueKey,cause:e}),s=e(n,0,a);await s.waitForRead();let c;for(;;){let e=new AbortController,n=o(e,this.requestTimeoutMs),r=()=>e.abort();i?.addEventListener(`abort`,r,{once:!0});try{let t=await this.positionConfirmation(e.signal);if(t.confirmed)return t.position}catch(e){t(i,a);let n=l(this.uniqueKey,e);if(n!==void 0)throw n;c=e}finally{n(),i?.removeEventListener(`abort`,r)}if(!await s.waitForRead())break}throw r.confirmationTimeoutError(this.uniqueKey,c)}};function c(e){return e===404||e===408||e===429||e>=500}function l(e,t){if(!i(t))return;if(t.code===`INVALID_POSITION_RESPONSE`||t.code===`INVALID_CHAIN_RESPONSE`)return new r(`CONFIRMATION_MALFORMED`,{},{uniqueKey:e,url:t.url,body:t.body??t.bodyText,cause:t});let n=t.status;if((t.code===`HTTP_ERROR`||t.code===`UPDATE_REQUIRED`)&&n!==void 0&&!c(n)){let i=t.params.serverMessage;return new r(`CONFIRMATION_FAILED`,{status:n,serverMessage:typeof i==`string`?i:``},{uniqueKey:e,status:n,url:t.url,body:t.body??t.bodyText,cause:t})}}export{s as SubmittedTransaction};
|
|
2
2
|
//# sourceMappingURL=submitted_transaction.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submitted_transaction.js","names":["_defineProperty","SubmittedTransaction","options","confirmAppliedTrade","GSwapSDKError","callerSignal","abortError","schedule","createConfirmationSchedule","lastError","controller","disarm","armTimeout","forwardAbort","result","error","throwIfAborted","terminal","terminalPositionReadFailure","isRetriedStatus","status","isGSwapError","serverMessage","\"serverMessage\""],"sources":["../../../src/classes/submitted_transaction.ts"],"sourcesContent":["import { armTimeout, type HttpRequestor, type WireOptions } from '@gala-chain/gala-core-sdk';\nimport type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\nimport { createConfirmationSchedule, throwIfAborted } from '../utils/confirmation_schedule.js';\nimport type { SubmitStatus } from '../utils/submit_state.js';\nimport { confirmAppliedTrade } from './apply_results.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\n\n/** Result of one position-confirmation poll. */\nexport type PositionConfirmationResult =\n { confirmed: true; position: Position | null } | { confirmed: false; position?: Position | null };\n\n/** A submitted v2 transaction whose confirmation mode is explicit in the gateway response. */\nexport class SubmittedTransaction<TConfirmation = AppliedTrade | Position | null> {\n /** The chain method that was submitted (`RequestTrade`, `AddLiquidity`, ...). */\n public readonly method: string;\n /** The write's durable correlation key: persist it, and confirm from it alone later. */\n public readonly uniqueKey: string;\n /** The request transaction id the gateway reported, or `null` when it gave none. */\n public readonly transactionId: string | null;\n /** The block of the transaction, when the answer carried one; otherwise `null`. */\n public readonly blockNumber: number | null;\n /** The gateway's `data.mode`: `'sync'` (executed, `result` is the chain result) or `'queued'`. */\n public readonly mode: 'sync' | 'queued';\n /**\n * What the gateway's answer established: `'executed'` for `mode: 'sync'`, `'queued'` for\n * `mode: 'queued'` (accepted, NOT executed: `await confirm()` for the outcome). A refused answer\n * never becomes a transaction, so there is no `'rejected'` here; see {@link classifySubmitEnvelope}\n * for classifying a raw envelope.\n */\n public readonly status: SubmitStatus;\n /** The synchronous gateway result, or `undefined` when `mode === 'queued'`. */\n public readonly result: unknown;\n /**\n * The gateway's whole JSON answer as it came (`{ status, message, error, data }`), for an app\n * that hands the backend's own envelope to its callers; `undefined` for a transaction built from\n * a uniqueKey alone.\n */\n public readonly envelope: unknown;\n private readonly backendBaseUrl: string;\n private readonly requestor: HttpRequestor;\n private readonly requestTimeoutMs: number;\n private readonly wire: WireOptions | undefined;\n private readonly positionConfirmation:\n ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n\n /** Construct a submitted transaction from a successful gateway response.\n *\n * @example\n * ```ts\n * const transaction = new SubmittedTransaction({\n * method: 'RequestTrade', mode: 'queued', uniqueKey: 'swap-1',\n * transactionId: 'request-tx', result: undefined,\n * dexBackendBaseUrl: 'https://dex.example', httpRequestor,\n * });\n * ```\n */\n constructor(options: {\n method: string;\n uniqueKey: string;\n transactionId: string | null;\n mode: 'sync' | 'queued';\n result: unknown;\n dexBackendBaseUrl: string;\n httpRequestor: HttpRequestor;\n blockNumber?: number | null | undefined;\n envelope?: unknown;\n requestTimeoutMs?: number | undefined;\n /** Wire options of the apply-results polls `confirm()` makes. */\n wire?: WireOptions | undefined;\n positionConfirmation?:\n ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n }) {\n this.method = options.method;\n this.uniqueKey = options.uniqueKey;\n this.transactionId = options.transactionId;\n this.blockNumber = options.blockNumber ?? null;\n this.mode = options.mode;\n this.status = options.mode === 'queued' ? 'queued' : 'executed';\n this.result = options.result;\n this.envelope = options.envelope;\n this.backendBaseUrl = options.dexBackendBaseUrl.replace(/\\/$/u, '');\n this.requestor = options.httpRequestor;\n this.requestTimeoutMs = options.requestTimeoutMs ?? 30_000;\n this.wire = options.wire;\n this.positionConfirmation = options.positionConfirmation;\n }\n\n /** Confirm a queued RequestTrade or prove the affected position for a liquidity write.\n *\n * For RequestTrade, calling this method is required to learn the outcome: the queued\n * acknowledgement proves acceptance, not execution.\n *\n * Every failure is the write's (it carries `uniqueKey`, so `mayHaveBeenQueued` is true): a\n * re-read that cannot succeed is `CONFIRMATION_FAILED` (a terminal HTTP status) or\n * `CONFIRMATION_MALFORMED` (an unusable answer); one that may (no answer, a 5xx, 404, 408,\n * 429) is read again until the deadline, then `CONFIRMATION_TIMEOUT` with the last read error\n * as `cause`. Confirm the same transaction again; never resubmit the write.\n *\n * @example\n * ```ts\n * const applied = await submitted.confirm({ initialDelayMs: 3_000 });\n * ```\n */\n public async confirm(options?: ConfirmOptions): Promise<TConfirmation> {\n if (this.method === 'RequestTrade') {\n return this.confirmApplied(options) as Promise<TConfirmation>;\n }\n return this.confirmPosition(options) as Promise<TConfirmation>;\n }\n\n private confirmApplied(options?: ConfirmOptions): Promise<AppliedTrade> {\n return confirmAppliedTrade(\n {\n dexBackendBaseUrl: this.backendBaseUrl,\n httpRequestor: this.requestor,\n requestTimeoutMs: this.requestTimeoutMs,\n wire: this.wire,\n },\n { uniqueKey: this.uniqueKey, requestTransactionId: this.transactionId },\n options,\n );\n }\n\n /** Confirm a liquidity write against the position's observable effect.\n *\n * @returns The position after the write, or `null` for a confirmed full close.\n * @example\n * ```ts\n * const position = await submitted.confirm({ timeoutMs: 60_000 });\n * ```\n */\n private async confirmPosition(options?: ConfirmOptions): Promise<Position | null> {\n if (this.positionConfirmation === undefined) throw GSwapSDKError.noWalletAddressError();\n // A liquidity write has already executed when the gateway answers, so the first re-read\n // happens immediately unless the caller asks for a delay.\n const callerSignal = options?.signal;\n const abortError = (cause?: unknown): Error =>\n new GSwapSDKError('CONFIRMATION_ABORTED', {}, { uniqueKey: this.uniqueKey, cause });\n const schedule = createConfirmationSchedule(options, 0, abortError);\n await schedule.waitForRead();\n let lastError: unknown;\n while (true) {\n const controller = new AbortController();\n const disarm = armTimeout(controller, this.requestTimeoutMs);\n const forwardAbort = (): void => controller.abort();\n callerSignal?.addEventListener('abort', forwardAbort, { once: true });\n try {\n const result = await this.positionConfirmation(controller.signal);\n if (result.confirmed) return result.position;\n } catch (error: unknown) {\n throwIfAborted(callerSignal, abortError);\n // The write was accepted, so a failed re-read says nothing about it, and the read's own\n // error must never reach the caller: a read failure means \"retry the read\", and a\n // retried WRITE could apply twice. As on the trade path: a terminal answer is\n // CONFIRMATION_FAILED / CONFIRMATION_MALFORMED, anything else is read again until the\n // deadline, then CONFIRMATION_TIMEOUT. Each carries the write's uniqueKey (a write's).\n const terminal = terminalPositionReadFailure(this.uniqueKey, error);\n if (terminal !== undefined) throw terminal;\n lastError = error;\n } finally {\n disarm();\n callerSignal?.removeEventListener('abort', forwardAbort);\n }\n if (!(await schedule.waitForRead())) break;\n }\n throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey, lastError);\n }\n}\n\n/** HTTP answers a confirmation reads again (as the apply-results poll does), not terminal ones. */\nfunction isRetriedStatus(status: number): boolean {\n return status === 404 || status === 408 || status === 429 || status >= 500;\n}\n\n/**\n * The confirmation error for a position re-read that failed TERMINALLY (an answer that reading\n * again cannot change), or `undefined` when it is worth reading again.\n */\nfunction terminalPositionReadFailure(uniqueKey: string, error: unknown): GSwapSDKError | undefined {\n if (!isGSwapError(error)) return undefined;\n if (error.code === 'INVALID_POSITION_RESPONSE' || error.code === 'INVALID_CHAIN_RESPONSE') {\n return new GSwapSDKError(\n 'CONFIRMATION_MALFORMED',\n {},\n { uniqueKey, url: error.url, body: error.body ?? error.bodyText, cause: error },\n );\n }\n const status = error.status;\n if (\n (error.code === 'HTTP_ERROR' || error.code === 'UPDATE_REQUIRED') &&\n status !== undefined &&\n !isRetriedStatus(status)\n ) {\n const serverMessage = (error.params as Record<string, unknown>)['serverMessage'];\n return new GSwapSDKError(\n 'CONFIRMATION_FAILED',\n { status, serverMessage: typeof serverMessage === 'string' ? serverMessage : '' },\n { uniqueKey, status, url: error.url, body: error.body ?? error.bodyText, cause: error },\n );\n }\n return undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"submitted_transaction.js","names":["_defineProperty","SubmittedTransaction","options","confirmAppliedTrade","GSwapSDKError","callerSignal","abortError","schedule","createConfirmationSchedule","lastError","controller","disarm","armTimeout","forwardAbort","result","error","throwIfAborted","terminal","terminalPositionReadFailure","isRetriedStatus","status","isGSwapError","serverMessage","\"serverMessage\""],"sources":["../../../src/classes/submitted_transaction.ts"],"sourcesContent":["import { armTimeout, type HttpRequestor, type WireOptions } from '@gala-chain/gala-core-sdk';\nimport type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\nimport { createConfirmationSchedule, throwIfAborted } from '../utils/confirmation_schedule.js';\nimport type { SubmitStatus } from '../utils/submit_state.js';\nimport { confirmAppliedTrade } from './apply_results.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\n\n/** Result of one position-confirmation poll. */\nexport type PositionConfirmationResult =\n { confirmed: true; position: Position | null } | { confirmed: false; position?: Position | null };\n\n/** A submitted v2 transaction whose confirmation mode is explicit in the gateway response. */\nexport class SubmittedTransaction<TConfirmation = AppliedTrade | Position | null> {\n /** The chain method that was submitted (`RequestTrade`, `AddLiquidity`, ...). */\n public readonly method: string;\n /** The write's durable correlation key: persist it, and confirm from it alone later. */\n public readonly uniqueKey: string;\n /** The request transaction id the gateway reported, or `null` when it gave none. */\n public readonly transactionId: string | null;\n /** The block of the transaction, when the answer carried one; otherwise `null`. */\n public readonly blockNumber: number | null;\n /** The gateway's `data.mode`: `'sync'` (executed, `result` is the chain result) or `'queued'`. */\n public readonly mode: 'sync' | 'queued';\n /**\n * What the gateway's answer established: `'executed'` for `mode: 'sync'`, `'queued'` for\n * `mode: 'queued'` (accepted, NOT executed: `await confirm()` for the outcome). A refused answer\n * never becomes a transaction, so there is no `'rejected'` here; see {@link classifySubmitEnvelope}\n * for classifying a raw envelope.\n */\n public readonly status: SubmitStatus;\n /** The synchronous gateway result, or `undefined` when `mode === 'queued'`. */\n public readonly result: unknown;\n /**\n * The gateway's whole JSON answer as it came (`{ status, message, error, data }`), for an app\n * that hands the backend's own envelope to its callers; `undefined` for a transaction built from\n * a uniqueKey alone.\n */\n public readonly envelope: unknown;\n private readonly backendBaseUrl: string;\n private readonly requestor: HttpRequestor;\n private readonly requestTimeoutMs: number;\n private readonly wire: WireOptions | undefined;\n private readonly positionConfirmation:\n ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n\n /** Construct a submitted transaction from a successful gateway response.\n *\n * @example\n * ```ts\n * const transaction = new SubmittedTransaction({\n * method: 'RequestTrade', mode: 'queued', uniqueKey: 'swap-1',\n * transactionId: 'request-tx', result: undefined,\n * dexBackendBaseUrl: 'https://dex.example', httpRequestor,\n * });\n * ```\n */\n constructor(options: {\n method: string;\n uniqueKey: string;\n transactionId: string | null;\n mode: 'sync' | 'queued';\n result: unknown;\n dexBackendBaseUrl: string;\n httpRequestor: HttpRequestor;\n blockNumber?: number | null | undefined;\n envelope?: unknown;\n requestTimeoutMs?: number | undefined;\n /** Wire options of the apply-results polls `confirm()` makes. */\n wire?: WireOptions | undefined;\n positionConfirmation?:\n ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n }) {\n this.method = options.method;\n this.uniqueKey = options.uniqueKey;\n this.transactionId = options.transactionId;\n this.blockNumber = options.blockNumber ?? null;\n this.mode = options.mode;\n this.status = options.mode === 'queued' ? 'queued' : 'executed';\n this.result = options.result;\n this.envelope = options.envelope;\n this.backendBaseUrl = options.dexBackendBaseUrl.replace(/\\/$/u, '');\n this.requestor = options.httpRequestor;\n this.requestTimeoutMs = options.requestTimeoutMs ?? 30_000;\n this.wire = options.wire;\n this.positionConfirmation = options.positionConfirmation;\n }\n\n /** Confirm a queued RequestTrade or prove the affected position for a liquidity write.\n *\n * For RequestTrade, calling this method is required to learn the outcome: the queued\n * acknowledgement proves acceptance, not execution.\n *\n * Every failure is the write's (it carries `uniqueKey`, so `mayHaveBeenQueued` is true): a\n * re-read that cannot succeed is `CONFIRMATION_FAILED` (a terminal HTTP status) or\n * `CONFIRMATION_MALFORMED` (an unusable answer); one that may (no answer, a 5xx, 404, 408,\n * 429) is read again until the deadline, then `CONFIRMATION_TIMEOUT` with the last read error\n * as `cause`. Confirm the same transaction again; never resubmit the write.\n *\n * @example\n * ```ts\n * const applied = await submitted.confirm({ initialDelayMs: 3_000 });\n * ```\n */\n public async confirm(options?: ConfirmOptions): Promise<TConfirmation> {\n if (this.method === 'RequestTrade') {\n return this.confirmApplied(options) as Promise<TConfirmation>;\n }\n return this.confirmPosition(options) as Promise<TConfirmation>;\n }\n\n private confirmApplied(options?: ConfirmOptions): Promise<AppliedTrade> {\n return confirmAppliedTrade(\n {\n dexBackendBaseUrl: this.backendBaseUrl,\n httpRequestor: this.requestor,\n requestTimeoutMs: this.requestTimeoutMs,\n wire: this.wire,\n },\n { uniqueKey: this.uniqueKey, requestTransactionId: this.transactionId },\n options,\n );\n }\n\n /** Confirm a liquidity write against the position's observable effect.\n *\n * @returns The position after the write, or `null` for a confirmed full close.\n * @example\n * ```ts\n * const position = await submitted.confirm({ timeoutMs: 60_000 });\n * ```\n */\n private async confirmPosition(options?: ConfirmOptions): Promise<Position | null> {\n if (this.positionConfirmation === undefined) throw GSwapSDKError.noWalletAddressError();\n // A liquidity write has already executed when the gateway answers, so the first re-read\n // happens immediately unless the caller asks for a delay.\n const callerSignal = options?.signal;\n const abortError = (cause?: unknown): Error =>\n new GSwapSDKError('CONFIRMATION_ABORTED', {}, { uniqueKey: this.uniqueKey, cause });\n const schedule = createConfirmationSchedule(options, 0, abortError);\n await schedule.waitForRead();\n let lastError: unknown;\n while (true) {\n const controller = new AbortController();\n const disarm = armTimeout(controller, this.requestTimeoutMs);\n const forwardAbort = (): void => controller.abort();\n callerSignal?.addEventListener('abort', forwardAbort, { once: true });\n try {\n const result = await this.positionConfirmation(controller.signal);\n if (result.confirmed) return result.position;\n } catch (error: unknown) {\n throwIfAborted(callerSignal, abortError);\n // The write was accepted, so a failed re-read says nothing about it, and the read's own\n // error must never reach the caller: a read failure means \"retry the read\", and a\n // retried WRITE could apply twice. As on the trade path: a terminal answer is\n // CONFIRMATION_FAILED / CONFIRMATION_MALFORMED, anything else is read again until the\n // deadline, then CONFIRMATION_TIMEOUT. Each carries the write's uniqueKey (a write's).\n const terminal = terminalPositionReadFailure(this.uniqueKey, error);\n if (terminal !== undefined) throw terminal;\n lastError = error;\n } finally {\n disarm();\n callerSignal?.removeEventListener('abort', forwardAbort);\n }\n if (!(await schedule.waitForRead())) break;\n }\n throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey, lastError);\n }\n}\n\n/** HTTP answers a confirmation reads again (as the apply-results poll does), not terminal ones. */\nfunction isRetriedStatus(status: number): boolean {\n return status === 404 || status === 408 || status === 429 || status >= 500;\n}\n\n/**\n * The confirmation error for a position re-read that failed TERMINALLY (an answer that reading\n * again cannot change), or `undefined` when it is worth reading again.\n */\nfunction terminalPositionReadFailure(uniqueKey: string, error: unknown): GSwapSDKError | undefined {\n if (!isGSwapError(error)) return undefined;\n if (error.code === 'INVALID_POSITION_RESPONSE' || error.code === 'INVALID_CHAIN_RESPONSE') {\n return new GSwapSDKError(\n 'CONFIRMATION_MALFORMED',\n {},\n { uniqueKey, url: error.url, body: error.body ?? error.bodyText, cause: error },\n );\n }\n const status = error.status;\n if (\n (error.code === 'HTTP_ERROR' || error.code === 'UPDATE_REQUIRED') &&\n status !== undefined &&\n !isRetriedStatus(status)\n ) {\n const serverMessage = (error.params as Record<string, unknown>)['serverMessage'];\n return new GSwapSDKError(\n 'CONFIRMATION_FAILED',\n { status, serverMessage: typeof serverMessage === 'string' ? serverMessage : '' },\n { uniqueKey, status, url: error.url, body: error.body ?? error.bodyText, cause: error },\n );\n }\n return undefined;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from"../_virtual/_@oxc-project_runtime@0.154.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{assertCanonicalPair as n,userRef as r,validateFee as i}from"../utils/validation.js";import{DEX_CONTRACT_PATH as a}from"../utils/chain_contract.js";import{shadowFailures as o}from"../utils/shadow_errors.js";import{SubmittedTransaction as s}from"./submitted_transaction.js";import{orderSymbols as c,readOrderedSymbols as l}from"../utils/ordering.js";import{tradingSymbolOf as u}from"./symbols.js";import{assertCanonicalV2Dto as d,buildRequestTradeDto as f}from"../utils/dto_builders.js";import{readShadowSubmitOutcome as p}from"./shadow_submit.js";import{assertUniqueKey as m,createUniqueKey as h,resolveUniqueKeyPrefix as g,signPreSend as _}from"@gala-chain/gala-core-sdk";function v(e){i(e.fee),n(e.token0Symbol,e.token1Symbol);let[t,r]=e.tokenInIsToken0?[e.token0Symbol,e.token1Symbol]:[e.token1Symbol,e.token0Symbol];return{tokenIn:t,tokenOut:r,fee:e.fee,pool:{token0:e.token0Symbol,token1:e.token1Symbol}}}var y=class{constructor(t,n,i,a,o={}){this.gateway=t,this.symbols=n,this.signer=i,e(this,`walletAddress`,void 0),e(this,`uniqueKeyPrefix`,void 0),this.walletAddress=a===void 0?void 0:r(a,`walletAddress`),this.uniqueKeyPrefix=g(o.uniqueKeyPrefix)}async swap(e,t,n,r,i){return this.submitSwap(await this.buildSwap(e,t,n,r,i))}async swapShadow(e,t,n,r,i){return o(async()=>this.submitSwapShadow(await this.buildSwap(e,t,n,r,i)))}async buildSwap(e,t,n,r,a){i(n);let o=a?.uniqueKey??h(this.uniqueKeyPrefix);m(o);let s=await u(this.symbols,e),c=await u(this.symbols,t),l=this.orientPool(s,c,a?.pool);return f({token0:l.token0,token1:l.token1,fee:n,tokenInIsToken0:s===l.token0,uniqueKey:o,...r})}async submitSwap(e){let t=await this.signRequestTrade(e);return this.gateway.submit(`RequestTrade`,t,this.submitOptions())}async submitSwapShadow(e){return o(async()=>{let t=await this.signRequestTrade(e),n=await this.gateway.submitShadow(`RequestTrade`,t,this.submitOptions());return p(`RequestTrade`,t,n)})}submitOptions(){return this.walletAddress===void 0?{}:{walletAddress:this.walletAddress}}async signRequestTrade(e){if(d(`RequestTrade`,e),this.signer===void 0)throw t.noSignerError();return _(this.signer,a,`RequestTrade`,e)}orientPool(e,n,r){if(r===void 0)return l(c(e,n));if(!(e===r.token0&&n===r.token1||e===r.token1&&n===r.token0))throw new t(`POOL_MISMATCH`,{tokenIn:e,tokenOut:n,poolToken0:r.token0,poolToken1:r.token1});return{token0:r.token0,token1:r.token1}}async confirmSwap(e,t){return m(e),new s({method:`RequestTrade`,uniqueKey:e,transactionId:null,mode:`queued`,result:void 0,dexBackendBaseUrl:this.gateway.dexBackendBaseUrl,httpRequestor:this.gateway.httpRequestor,requestTimeoutMs:this.gateway.requestTimeoutMs,wire:this.gateway.wire}).confirm({initialDelayMs:0,...t})}};export{y as Swaps,v as swapRouteFromQuote};
|
|
2
2
|
//# sourceMappingURL=swaps.js.map
|