@gala-chain/gswap-sdk 1.2.0-rc.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +25 -10
  2. package/dist/browser/classes/dex_fees.js.map +1 -1
  3. package/dist/browser/classes/gateway.js.map +1 -1
  4. package/dist/browser/classes/gdex_stream.js.map +1 -1
  5. package/dist/browser/classes/gswap.js.map +1 -1
  6. package/dist/browser/classes/gswap_sdk_error.js.map +1 -1
  7. package/dist/browser/classes/pending_swap_fate.js +2 -0
  8. package/dist/browser/classes/pending_swap_fate.js.map +1 -0
  9. package/dist/browser/classes/pending_swaps.js +1 -1
  10. package/dist/browser/classes/pending_swaps.js.map +1 -1
  11. package/dist/browser/classes/positions.js +1 -1
  12. package/dist/browser/classes/positions.js.map +1 -1
  13. package/dist/browser/classes/shadow_submit.js +1 -1
  14. package/dist/browser/classes/shadow_submit.js.map +1 -1
  15. package/dist/browser/classes/signers.js.map +1 -1
  16. package/dist/browser/classes/storage_adapters.js +2 -0
  17. package/dist/browser/classes/storage_adapters.js.map +1 -0
  18. package/dist/browser/classes/submitted_transaction.js.map +1 -1
  19. package/dist/browser/classes/symbols.js +1 -1
  20. package/dist/browser/classes/symbols.js.map +1 -1
  21. package/dist/browser/index.js +1 -1
  22. package/dist/browser/utils/chain_dto_signing.js.map +1 -1
  23. package/dist/browser/utils/class_key.js +2 -0
  24. package/dist/browser/utils/class_key.js.map +1 -0
  25. package/dist/browser/utils/classification.js +2 -0
  26. package/dist/browser/utils/classification.js.map +1 -0
  27. package/dist/browser/utils/dto_builders.js +1 -1
  28. package/dist/browser/utils/dto_builders.js.map +1 -1
  29. package/dist/browser/utils/eip712.js.map +1 -1
  30. package/dist/browser/utils/failure_classification.js +1 -1
  31. package/dist/browser/utils/failure_classification.js.map +1 -1
  32. package/dist/browser/utils/failure_guards.js +2 -0
  33. package/dist/browser/utils/failure_guards.js.map +1 -0
  34. package/dist/browser/utils/ordering.js +1 -1
  35. package/dist/browser/utils/ordering.js.map +1 -1
  36. package/dist/browser/utils/tick_align.js +2 -0
  37. package/dist/browser/utils/tick_align.js.map +1 -0
  38. package/dist/browser/utils/tick_math.js +2 -0
  39. package/dist/browser/utils/tick_math.js.map +1 -0
  40. package/dist/browser/utils/tick_range.js +2 -0
  41. package/dist/browser/utils/tick_range.js.map +1 -0
  42. package/dist/browser/utils/ticks.js +1 -1
  43. package/dist/browser/utils/ticks.js.map +1 -1
  44. package/dist/browser/utils/transport.js +1 -1
  45. package/dist/browser/utils/transport.js.map +1 -1
  46. package/dist/browser/utils/validation.js +1 -1
  47. package/dist/browser/utils/validation.js.map +1 -1
  48. package/dist/browser/version.js +1 -1
  49. package/dist/browser/version.js.map +1 -1
  50. package/dist/index.cjs +641 -336
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +470 -186
  53. package/dist/index.d.ts +470 -186
  54. package/dist/index.mjs +636 -337
  55. package/dist/index.mjs.map +1 -1
  56. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- import{GSwapSDKError as e,getStringProperty as t}from"./gswap_sdk_error.js";const n=[`SHADOW_UNAVAILABLE`,`SHADOW_DISABLED`,`SHADOW_UNSUPPORTED_TYPE`,`SHADOW_RELAY_REJECTED`],r=[`unavailable`,`disabled`,`rejected`,`unknown`];function i(e){return e===503?`unavailable`:e===400?`disabled`:`unknown`}function a(e,t){return t===`SHADOW_UNAVAILABLE`?`unavailable`:t===`SHADOW_RELAY_REJECTED`?`rejected`:t===`SHADOW_DISABLED`||t===`SHADOW_UNSUPPORTED_TYPE`?`disabled`:i(e)}function o(n,r,i){let{httpStatus:o,body:c}=i,l=s(c);if(o>=200&&o<300&&l?.error===!1){let t=s(l.data),i=typeof t?.transactionId==`string`?t.transactionId:void 0;if(n===`RequestTrade`){let n=r.uniqueKey;if(t?.mode!==`queued`||typeof n!=`string`||t.uniqueKey!==n)throw new e(`SHADOW_NOT_QUEUED`,{},{status:o,body:c,shadow:!0,...typeof n==`string`?{uniqueKey:n}:{}});return{ok:!0,bundleId:i??``,queued:{uniqueKey:n,requestTransactionId:i??null}}}if(t?.mode===`sync`)return{ok:!0,bundleId:i??``}}let u=a(o,t(c,`code`));return u===`rejected`?{ok:!1,kind:`rejected`,retryable:!1,message:t(c,`message`)??``}:u===`unavailable`?{ok:!1,kind:u,retryable:!0}:{ok:!1,kind:u,retryable:!1}}function s(e){return typeof e==`object`&&e?e:void 0}export{r as SHADOW_FAILURE_KINDS,n as SHADOW_SUBMIT_CODES,a as classifyShadowSubmitError,i as classifyShadowSubmitStatus,o as readShadowSubmitOutcome};
1
+ import{GSwapSDKError as e,getStringProperty as t}from"./gswap_sdk_error.js";const n=[`SHADOW_UNAVAILABLE`,`SHADOW_UNSUPPORTED_TYPE`,`SHADOW_RELAY_REJECTED`],r=[`unavailable`,`disabled`,`rejected`,`unknown`];function i(e){return e===503?`unavailable`:e===400?`disabled`:`unknown`}function a(e,t){return t===`SHADOW_UNAVAILABLE`?`unavailable`:t===`SHADOW_RELAY_REJECTED`?`rejected`:t===`SHADOW_UNSUPPORTED_TYPE`?`disabled`:i(e)}function o(n,r,i){let{httpStatus:o,body:c}=i,l=s(c);if(o>=200&&o<300&&l?.error===!1){let t=s(l.data),i=typeof t?.transactionId==`string`?t.transactionId:void 0;if(n===`RequestTrade`){let n=r.uniqueKey;if(t?.mode!==`queued`||typeof n!=`string`||t.uniqueKey!==n)throw new e(`SHADOW_NOT_QUEUED`,{},{status:o,body:c,shadow:!0,...typeof n==`string`?{uniqueKey:n}:{}});return{ok:!0,bundleId:i??``,queued:{uniqueKey:n,requestTransactionId:i??null}}}if(t?.mode===`sync`)return{ok:!0,bundleId:i??``}}let u=a(o,t(c,`code`));return u===`rejected`?{ok:!1,kind:`rejected`,retryable:!1,message:t(c,`message`)??``}:u===`unavailable`?{ok:!1,kind:u,retryable:!0}:{ok:!1,kind:u,retryable:!1}}function s(e){return typeof e==`object`&&e?e:void 0}export{r as SHADOW_FAILURE_KINDS,n as SHADOW_SUBMIT_CODES,a as classifyShadowSubmitError,i as classifyShadowSubmitStatus,o as readShadowSubmitOutcome};
2
2
  //# sourceMappingURL=shadow_submit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shadow_submit.js","names":[],"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 defi-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_DISABLED` (400): the feature is off for this environment.\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_DISABLED',\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`, `rejected` (carries\n * the gateway's `message`) 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; the two other 400 codes and any unknown 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_DISABLED' || 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":"4EAoBA,MAAa,EAAsB,CACjC,qBACA,kBACA,0BACA,uBACF,EAUa,EAAuB,CAAC,cAAe,WAAY,WAAY,SAAS,EA8CrF,SAAgB,EAA2B,EAAmC,CAG5E,OAFI,IAAW,IAAY,cACvB,IAAW,IAAY,WACpB,SACT,CAOA,SAAgB,EAA0B,EAAgB,EAAkC,CAI1F,OAHI,IAAS,qBAA6B,cACtC,IAAS,wBAAgC,WACzC,IAAS,mBAAqB,IAAS,0BAAkC,WACtE,EAA2B,CAAM,CAC1C,CAwBA,SAAgB,EACd,EACA,EACA,EACyC,CACzC,GAAM,CAAE,aAAY,QAAS,EACvB,EAAW,EAAS,CAAI,EAC9B,GAAI,GAAc,KAAO,EAAa,KAAO,GAAW,QAAa,GAAO,CAC1E,IAAM,EAAO,EAAS,EAAS,IAAO,EAChC,EACJ,OAAO,GAAO,eAAqB,SAAW,EAAK,cAAmB,IAAA,GACxE,GAAI,IAAW,eAAgB,CAC7B,IAAM,EAAe,EAAW,UAChC,GACE,GAAO,OAAY,UACnB,OAAO,GAAiB,UACxB,EAAK,YAAiB,EAEtB,MAAM,IAAI,EACR,oBACA,CAAC,EACD,CACE,OAAQ,EACR,OACA,OAAQ,GACR,GAAI,OAAO,GAAiB,SAAW,CAAE,UAAW,CAAa,EAAI,CAAC,CACxE,CACF,EAEF,MAAO,CACL,GAAI,GACJ,SAAU,GAAoB,GAC9B,OAAQ,CAAE,UAAW,EAAc,qBAAsB,GAAoB,IAAK,CACpF,CACF,CACA,GAAI,GAAO,OAAY,OAAQ,MAAO,CAAE,GAAI,GAAM,SAAU,GAAoB,EAAG,CACrF,CAEA,IAAM,EAAO,EAA0B,EAAY,EAAkB,EAAM,MAAM,CAAC,EASlF,OARI,IAAS,WACJ,CACL,GAAI,GACJ,KAAM,WACN,UAAW,GACX,QAAS,EAAkB,EAAM,SAAS,GAAK,EACjD,EAEK,IAAS,cACZ,CAAE,GAAI,GAAO,OAAM,UAAW,EAAK,EACnC,CAAE,GAAI,GAAO,OAAM,UAAW,EAAM,CAC1C,CAEA,SAAS,EAAS,EAAqD,CACrE,OAAO,OAAO,GAAU,UAAY,EAC/B,EACD,IAAA,EACN"}
1
+ {"version":3,"file":"shadow_submit.js","names":[],"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 defi-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,MAAa,EAAsB,CACjC,qBACA,0BACA,uBACF,EAYa,EAAuB,CAAC,cAAe,WAAY,WAAY,SAAS,EA8CrF,SAAgB,EAA2B,EAAmC,CAG5E,OAFI,IAAW,IAAY,cACvB,IAAW,IAAY,WACpB,SACT,CAOA,SAAgB,EAA0B,EAAgB,EAAkC,CAI1F,OAHI,IAAS,qBAA6B,cACtC,IAAS,wBAAgC,WACzC,IAAS,0BAAkC,WACxC,EAA2B,CAAM,CAC1C,CAwBA,SAAgB,EACd,EACA,EACA,EACyC,CACzC,GAAM,CAAE,aAAY,QAAS,EACvB,EAAW,EAAS,CAAI,EAC9B,GAAI,GAAc,KAAO,EAAa,KAAO,GAAW,QAAa,GAAO,CAC1E,IAAM,EAAO,EAAS,EAAS,IAAO,EAChC,EACJ,OAAO,GAAO,eAAqB,SAAW,EAAK,cAAmB,IAAA,GACxE,GAAI,IAAW,eAAgB,CAC7B,IAAM,EAAe,EAAW,UAChC,GACE,GAAO,OAAY,UACnB,OAAO,GAAiB,UACxB,EAAK,YAAiB,EAEtB,MAAM,IAAI,EACR,oBACA,CAAC,EACD,CACE,OAAQ,EACR,OACA,OAAQ,GACR,GAAI,OAAO,GAAiB,SAAW,CAAE,UAAW,CAAa,EAAI,CAAC,CACxE,CACF,EAEF,MAAO,CACL,GAAI,GACJ,SAAU,GAAoB,GAC9B,OAAQ,CAAE,UAAW,EAAc,qBAAsB,GAAoB,IAAK,CACpF,CACF,CACA,GAAI,GAAO,OAAY,OAAQ,MAAO,CAAE,GAAI,GAAM,SAAU,GAAoB,EAAG,CACrF,CAEA,IAAM,EAAO,EAA0B,EAAY,EAAkB,EAAM,MAAM,CAAC,EASlF,OARI,IAAS,WACJ,CACL,GAAI,GACJ,KAAM,WACN,UAAW,GACX,QAAS,EAAkB,EAAM,SAAS,GAAK,EACjD,EAEK,IAAS,cACZ,CAAE,GAAI,GAAO,OAAM,UAAW,EAAK,EACnC,CAAE,GAAI,GAAO,OAAM,UAAW,EAAM,CAC1C,CAEA,SAAS,EAAS,EAAqD,CACrE,OAAO,OAAO,GAAU,UAAY,EAC/B,EACD,IAAA,EACN"}
@@ -1 +1 @@
1
- {"version":3,"file":"signers.js","names":["globalObject"],"sources":["../../../src/classes/signers.ts"],"sourcesContent":["import { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport {\n buildEIP712Payload,\n EIP712_CAPABLE_METHODS,\n eip712DomainFor,\n type EIP712DomainValue,\n type EIP712Types,\n} from '../utils/eip712.js';\nimport {\n ethAddressOfPrivateKey,\n fixpointPrefixFor,\n normalizePrivateKey,\n personalSignPrefixFor,\n serialize,\n signNative,\n} from '../utils/signing.js';\n\n// Personal-sign prefix, computed the way THE CHAIN verifies it.\n//\n// GalaChain (SDK 3.x) recovers a personal-signed DTO from\n// keccak256(<prefix field> + <canonical JSON of the DTO WITHOUT the prefix field>)\n// and a browser wallet's `personal_sign` (EIP-191) hashes\n// \"\\u0019Ethereum Signed Message:\\n\" + <byte length of message> + <message>.\n// They agree exactly when the wallet signs the bare canonical DTO and `prefix` is the EIP-191\n// header for that message's UTF-8 BYTE length. Any other message still yields a valid-looking\n// signature — it just recovers to an address nobody holds. This SDK used to embed `prefix` in\n// the signed message (the SDK 1.10 client recipe): observed on stage 2026-09-23, such a\n// MetaMask-signed CreatePool executed on chain under a phantom creator, and defi-backend's\n// bouncer now rejects that shape outright.\n//\n// `@gala-chain/connect`'s prefix helper must NOT be used for wallet `personal_sign`: its\n// fixpoint counts the prefix itself and targets the SDK's raw-payload signer. The same header\n// is also what Gala Wallet's `gala_signChainDto` (personal-sign scheme) prepends before hashing,\n// so one value serves both paths.\n//\n// The header itself is computed by `personalSignPrefixFor` in ../utils/signing.ts.\n\n/** The signing schemes supported by the Gala Wallet signer. */\nexport type GalaWalletScheme = 'native' | 'personal-sign';\n\n/** The request surface used by an EIP-1193 browser wallet. */\nexport interface BrowserWalletProvider {\n request(args: { method: string; params?: unknown[] }): Promise<unknown>;\n}\n\ninterface GalaWalletProvider {\n request(args: { method: string; params?: unknown[] }): Promise<unknown>;\n /** Gala Wallet's \"act as this account\" switch; absent on other providers. */\n setAddress?: (address: string) => Promise<void>;\n}\n\ninterface WindowWithGala {\n gala?: GalaWalletProvider;\n}\n\ninterface GlobalWithWindow {\n window?: WindowWithGala;\n}\n\n/** A DTO together with the signature that belongs in the gateway request body. */\nexport type SignedDto<T extends Record<string, unknown>> = T & { signature: string };\n\n/**\n * A signer for complete GalaChain write bodies.\n *\n * Implementations return the DTO fields together with the signature that belongs in the\n * gateway request body. Signer identity is recovered from that signature; implementations do\n * not add signer hints, typed-data metadata, or a domain.\n */\nexport interface GalaChainSigner {\n /**\n * Signs a DTO for a named GalaChain contract method.\n *\n * @example\n * ```typescript\n * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });\n * ```\n */\n signObject<T extends Record<string, unknown>>(methodName: string, dto: T): Promise<SignedDto<T>>;\n}\n\nfunction getWalletProvider(): GalaWalletProvider {\n const globalObject = globalThis as GlobalWithWindow;\n const wallet = globalObject.window?.gala;\n if (!wallet) {\n throw new GSwapSDKError('GALA_WALLET_NOT_AVAILABLE', {});\n }\n return wallet;\n}\n\nfunction getNativeSignature(value: unknown): string {\n if (typeof value !== 'string') {\n throw new GSwapSDKError('INVALID_SIGNATURE', { scheme: 'native' });\n }\n // 130 hex digits (r || s || v), bare as Gala Wallet returns it or `0x`-prefixed; passed on\n // verbatim, because the backend recovers the signer from either spelling.\n if (!/^(?:0x)?[0-9a-fA-F]{130}$/u.test(value)) {\n throw new GSwapSDKError('INVALID_SIGNATURE', { scheme: 'native' });\n }\n return value;\n}\n\nfunction getPersonalSignature(value: unknown): string {\n if (typeof value !== 'string' || !/^(?:0x)?[0-9a-fA-F]{130}$/u.test(value)) {\n throw new GSwapSDKError('INVALID_SIGNATURE', { scheme: 'personal-sign' });\n }\n return value;\n}\n\n/**\n * The `0x`-prefixed Ethereum address a Gala account is signed by, or `undefined` when the account\n * names no key (a `client|` alias or a bare GalaChain id is not derivable from a key). Accepts\n * `0x` plus 40 hex digits and `eth|` plus 40 hex digits, with or without `0x`; the caller's casing\n * is kept. For {@link LazyPrivateKeySignerOptions.expectedAddress}, which should only be set for\n * an account whose key can be checked.\n *\n * @example\n * ```ts\n * createLazyPrivateKeySigner(getKey, { expectedAddress: ethereumAddressOfAccount(account) });\n * ```\n */\nexport function ethereumAddressOfAccount(account: string): string | undefined {\n const match = /^(?:eth\\|(?:0x)?|0x)([0-9a-fA-F]{40})$/u.exec(account);\n return match?.[1] === undefined ? undefined : `0x${match[1]}`;\n}\n\nfunction normalizeEthereumAccount(address: string, allowGalaPrefix: boolean): string {\n const normalized = allowGalaPrefix ? (ethereumAddressOfAccount(address) ?? address) : address;\n if (!/^0x[0-9a-fA-F]{40}$/u.test(normalized)) {\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', { field: 'walletAddress', value: address });\n }\n // The caller's casing is kept on purpose: frontend_v2 and the wallet hand the wallet the\n // checksummed account, and EIP-1193 / Gala Wallet accept any case, so passing the value through\n // unchanged is the only choice that cannot differ from what they send.\n return normalized;\n}\n\n/**\n * The account handed to Gala Wallet as the signer address. An Ethereum account is held to the\n * same strict check as ever (`0x` plus 40 hex digits; `eth|` plus 40 hex digits, with or without\n * `0x`, is normalized to it). A GalaChain id the wallet can also be asked to sign for is passed\n * through verbatim: `client|` plus 24 hex digits, or the bare 24 hex digits that frontend_v2 keeps\n * in `state.user.wallet` after a direct `client|` login. Nothing else is accepted.\n */\nfunction normalizeGalaWalletAccount(address: string): string {\n const eth = /^eth\\|(?:0x)?([0-9a-fA-F]{40})$/u.exec(address);\n if (eth?.[1] !== undefined) return `0x${eth[1]}`;\n if (/^0x[0-9a-fA-F]{40}$/u.test(address) || /^(?:client\\|)?[0-9a-fA-F]{24}$/u.test(address)) {\n return address;\n }\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', { field: 'walletAddress', value: address });\n}\n\n/** An identity Gala Wallet can act as: an account form above, any `eth|`/`client|` alias, verbatim. */\nfunction assertWalletIdentity(identity: string): void {\n if (\n !/^(?:eth\\|(?:0x)?[0-9a-fA-F]{40}|0x[0-9a-fA-F]{40}|(?:client\\|)?[0-9a-fA-F]{24})$/u.test(\n identity,\n )\n ) {\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', { field: 'selectAddress', value: identity });\n }\n}\n\n/** Provider-wide queue: `setAddress` + the signature request must not interleave across signers. */\nconst walletIdentityQueue = new WeakMap<object, Promise<unknown>>();\n\n/**\n * Runs `signWith` with `identity` selected on a Gala Wallet that supports `setAddress`. Gala\n * Wallet holds ONE current account, so two signatures for different identities in flight at once\n * would sign as whichever selection came last; the pair (select, sign) is therefore serialized\n * per provider. A failed selection fails the signature (nothing is requested).\n */\nfunction withSelectedIdentity<T>(\n wallet: GalaWalletProvider,\n identity: string | undefined,\n signWith: () => Promise<T>,\n): Promise<T> {\n const { setAddress } = wallet;\n if (identity === undefined || typeof setAddress !== 'function') return signWith();\n const previous = walletIdentityQueue.get(wallet) ?? Promise.resolve();\n const run = previous\n .catch(() => undefined)\n .then(async () => {\n await setAddress.call(wallet, identity);\n return signWith();\n });\n walletIdentityQueue.set(wallet, run);\n return run;\n}\n\nfunction personalSign<T extends Record<string, unknown>>(\n provider: GalaWalletProvider | BrowserWalletProvider,\n dto: T,\n walletAddress: string,\n methodName?: string,\n): Promise<T & { prefix: string; signature: string }> {\n const prefix = personalSignPrefixFor(dto);\n const payload = { ...dto, prefix };\n // A browser wallet's `personal_sign` applies the EIP-191 header ITSELF, so it must sign the\n // bare DTO; Gala Wallet's `gala_signChainDto` (personal-sign scheme) instead extracts the\n // `prefix` field from what it is handed and prepends it before hashing, so it is handed the\n // prefixed payload. Both submit `{ ...dto, prefix, signature }`.\n const params =\n methodName !== undefined\n ? [serialize(payload), walletAddress, methodName]\n : [serialize(dto), walletAddress];\n\n return provider\n .request({ method: methodName !== undefined ? 'gala_signChainDto' : 'personal_sign', params })\n .then((value) => ({ ...payload, signature: getPersonalSignature(value) }));\n}\n\n/**\n * Signs a DTO via genuine EIP-712 (`eth_signTypedData_v4`) — correctly resolves the `client|`\n * identity, unlike `personal_sign`, for the operations in `EIP712_CAPABLE_METHODS`.\n *\n * Constructs the raw JSON-RPC payload by hand (`{domain, types: {...types, EIP712Domain},\n * primaryType, message}`) rather than depending on ethers.js, matching exactly what\n * `ethers.TypedDataEncoder.getPayload`/`Wallet.signTypedData` produce internally — verified\n * byte-for-byte equivalent (same recovered address from the same signature against both\n * constructions) before this shipped, since gswap-sdk deliberately has no ethers dependency.\n */\nasync function signEIP712<T extends Record<string, unknown>>(\n provider: BrowserWalletProvider,\n methodName: string,\n dto: T,\n walletAddress: string,\n): Promise<T & { types: EIP712Types; domain: EIP712DomainValue; signature: string }> {\n const { completedDto, types } = buildEIP712Payload(methodName, dto);\n // The wallet's LIVE chain id, read on every signature: a user can switch networks after\n // connecting, and a cached or hardcoded id would sign a domain MetaMask itself rejects.\n const domain = eip712DomainFor(await provider.request({ method: 'eth_chainId', params: [] }));\n // The body `prefix` is not part of the EIP-712 `types`, so it is never hashed; it carries the\n // connect-style fixpoint value only to keep the submitted body byte-identical to frontend_v2's.\n const prefix = fixpointPrefixFor(completedDto);\n const message = { ...completedDto, prefix };\n const eip712Domain = [\n { name: 'name', type: 'string' },\n { name: 'chainId', type: 'uint256' },\n ];\n const payload = {\n domain,\n types: { ...types, EIP712Domain: eip712Domain },\n primaryType: methodName,\n message,\n };\n\n const value = await provider.request({\n method: 'eth_signTypedData_v4',\n params: [walletAddress, JSON.stringify(payload)],\n });\n // Key order matches frontend_v2's submitted body: ..., prefix, signature, types, domain.\n return {\n ...(message as T & { prefix: string }),\n signature: getPersonalSignature(value),\n types,\n domain,\n };\n}\n\n/**\n * A GalaChain native signer backed by a secp256k1 private key.\n *\n * Native signing produces the bare GalaChain signature format, without a personal-sign prefix\n * or EIP-712 metadata. The private-key identity is recovered by the chain.\n */\nexport class PrivateKeySigner implements GalaChainSigner {\n private readonly privateKey: Uint8Array;\n\n /**\n * Creates a native signer from a hex or base64 secp256k1 private key.\n *\n * @example\n * ```typescript\n * const signer = new PrivateKeySigner('1'.padStart(64, '0'));\n * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });\n * ```\n */\n constructor(privateKey: string) {\n this.privateKey = normalizePrivateKey(privateKey);\n }\n\n /**\n * Signs the DTO with GalaChain native signing.\n *\n * @example\n * ```typescript\n * const signed = await signer.signObject('RequestTrade', {\n * token0: 'GALA',\n * token1: 'GUSDC',\n * fee: 3000,\n * });\n * ```\n */\n public signObject<T extends Record<string, unknown>>(\n _methodName: string,\n dto: T,\n ): Promise<SignedDto<T>> {\n const signature = signNative(this.privateKey, dto);\n return Promise.resolve({ ...dto, signature });\n }\n}\n\n/** Supplies a private key at sign time: a hex/base64 string, possibly fetched asynchronously. */\nexport type PrivateKeyProvider = () => Promise<string> | string;\n\n/** Options for {@link createLazyPrivateKeySigner}. */\nexport interface LazyPrivateKeySignerOptions {\n /**\n * When set, every signature first checks that the fetched key belongs to this account (`0x...`\n * or the Gala `eth|0x...` / `eth|<40 hex>` form, case-insensitive) and refuses to sign otherwise\n * (`SIGNER_ADDRESS_MISMATCH`). Use it when the key lives in a slot another surface can switch\n * between the moment a request was approved and the moment it is signed.\n */\n expectedAddress?: string | undefined;\n}\n\n/**\n * Calls the app's key provider. Whatever it throws or rejects with is the app's own failure to\n * produce a key before anything was signed or sent, so it becomes `KEY_PROVIDER_FAILED` (the\n * original is `cause`); an SDK error is already catalogued and passes through.\n */\nasync function keyFrom(getPrivateKey: PrivateKeyProvider): Promise<unknown> {\n try {\n return await getPrivateKey();\n } catch (cause: unknown) {\n throw isGSwapError(cause) ? cause : new GSwapSDKError('KEY_PROVIDER_FAILED', {}, { cause });\n }\n}\n\n/**\n * Creates the native-signing equivalent of {@link PrivateKeySigner} for apps that must not hold a\n * key in a long-lived object (an extension that reads its session key at sign time).\n *\n * `getPrivateKey` is called once per `signObject` call, never cached, never shared between calls\n * (concurrent signatures each fetch their own key), and the normalized key bytes are zeroed\n * before `signObject` settles, also on failure. A rejection or exception from `getPrivateKey` (the\n * app's \"wallet is locked\", a storage read that failed) is a `KEY_PROVIDER_FAILED` error with the\n * original error as `cause`: nothing has been sent, so `classifyFailure` says `not_sent` and Retry\n * is safe, and the app needs no error class of its own to tell this apart. A provider that returns\n * no usable string (`''`, `undefined`) is `INVALID_PRIVATE_KEY` with `reason: 'no_key_provided'`,\n * classified the same way; any other key that is not a valid secp256k1 key string is an\n * `INVALID_PRIVATE_KEY` error. An SDK error the provider throws itself is passed through.\n * Signatures are byte-identical to `new PrivateKeySigner(key).signObject(...)`.\n *\n * A JavaScript string cannot be wiped; the provider owns the lifetime of the string it returns.\n *\n * @example\n * ```typescript\n * const signer = createLazyPrivateKeySigner(\n * () => SecurityHelper.getSessionSecret(SecurityHelper.SESSION_PRIVATE_KEY_KEY),\n * { expectedAddress: account.address },\n * );\n * const gswap = new GSwap({ signer });\n * ```\n */\nexport function createLazyPrivateKeySigner(\n getPrivateKey: PrivateKeyProvider,\n options: LazyPrivateKeySignerOptions = {},\n): GalaChainSigner {\n const expected = options.expectedAddress;\n const expectedLower =\n expected === undefined ? undefined : normalizeEthereumAccount(expected, true).toLowerCase();\n\n return {\n async signObject<T extends Record<string, unknown>>(\n _methodName: string,\n dto: T,\n ): Promise<SignedDto<T>> {\n const provided: unknown = await keyFrom(getPrivateKey);\n if (typeof provided !== 'string' || provided === '') {\n throw new GSwapSDKError('INVALID_PRIVATE_KEY', { reason: 'no_key_provided' });\n }\n const key = normalizePrivateKey(provided);\n try {\n if (expectedLower !== undefined && ethAddressOfPrivateKey(key) !== expectedLower) {\n throw new GSwapSDKError('SIGNER_ADDRESS_MISMATCH', {});\n }\n return { ...dto, signature: signNative(key, dto) };\n } finally {\n key.fill(0);\n }\n },\n };\n}\n\n/**\n * A Gala Wallet signer using native GalaChain signing, with an opt-in personal-sign mode.\n *\n * The selected Ethereum account is passed to Gala Wallet. There is NO automatic fallback: a\n * wallet that rejects `native` surfaces its error to the caller, because the only alternative,\n * `personal-sign`, silently recovers a phantom signer on every released Gala Wallet.\n *\n * `scheme: 'personal-sign'` calls\n * `gala_signChainDto([serialize({ ...dto, prefix }), walletAddress, methodName])` and REQUIRES\n * a wallet build that contains wallet_extension commit 3ad7ae6 (strips the embedded `prefix`\n * field and hashes `prefix` + the prefix-less canonical body, the chain's scheme). Wallets\n * released before that fix hash the string with the `prefix` field still inside it and the\n * signature recovers to an address nobody holds, so only opt in once the fixed wallet is\n * released. See SIGNING-PARITY.md.\n */\nexport class GalaWalletSigner implements GalaChainSigner {\n /** The wallet address supplied to Gala Wallet for each signing request. */\n public readonly walletAddress: string;\n\n /** The signing scheme used for every request; it never changes after construction. */\n public readonly scheme: GalaWalletScheme;\n\n /**\n * Creates a Gala Wallet signer.\n *\n * @example\n * ```typescript\n * const signer = new GalaWalletSigner('0x0123456789012345678901234567890123456789');\n * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });\n * ```\n *\n * @param walletAddress - The account passed to Gala Wallet as the signer address. An Ethereum\n * account is `0x` plus 40 hex digits (Gala Wallet's `eth|...` form is normalized to it and held\n * to the same check); a GalaChain id is `client|` plus 24 hex digits, or the bare 24 hex digits\n * frontend_v2 keeps for a direct `client|` login, and is passed through unchanged.\n * @param options - Select native signing (default) or personal-sign explicitly.\n * `'personal-sign'` requires a Gala Wallet build with wallet_extension commit 3ad7ae6.\n * `selectAddress` is the identity (`client|...` / `eth|...`) Gala Wallet is switched to with\n * `window.gala.setAddress` before every signature, when the wallet offers it.\n */\n constructor(\n walletAddress: string,\n options: { scheme?: GalaWalletScheme | undefined; selectAddress?: string | undefined } = {},\n ) {\n this.walletAddress = normalizeGalaWalletAccount(walletAddress);\n this.scheme = options.scheme ?? 'native';\n if (options.selectAddress !== undefined) assertWalletIdentity(options.selectAddress);\n this.selectAddress = options.selectAddress;\n }\n\n /** The identity Gala Wallet is switched to before each signature, if one was given. */\n public readonly selectAddress: string | undefined;\n\n /**\n * Signs a DTO through `gala_signChainDto`.\n *\n * @example\n * ```typescript\n * const signed = await signer.signObject('AddLiquidity', {\n * token0: 'GALA',\n * token1: 'GUSDC',\n * tickLower: -60,\n * tickUpper: 60,\n * });\n * ```\n */\n public async signObject<T extends Record<string, unknown>>(\n methodName: string,\n dto: T,\n ): Promise<SignedDto<T>> {\n const wallet = getWalletProvider();\n\n return withSelectedIdentity(wallet, this.selectAddress, async () => {\n if (this.scheme === 'personal-sign') {\n return personalSign(wallet, dto, this.walletAddress, methodName);\n }\n const signature = await wallet.request({\n method: 'gala_signChainDto',\n params: [serialize(dto), this.walletAddress, methodName, 'native'],\n });\n return { ...dto, signature: getNativeSignature(signature) };\n });\n }\n}\n\n/**\n * A personal-sign signer for MetaMask and other EIP-1193 browser wallets.\n *\n * The chain recovers this signature using the EIP-191 wrap applied by the wallet to\n * `personal_sign`. This is the browser-wallet path used by the v2 frontend and resolves the\n * bare `eth|` identity.\n */\nexport class BrowserWalletSigner implements GalaChainSigner {\n /**\n * Creates a browser-wallet signer.\n *\n * Defaults to `personal_sign` — unchanged from every existing integration, since it only ever\n * resolves the bare `eth|` identity and changing that silently would be a real behavior\n * break for anyone already depending on it. Pass `{ scheme: 'eip712' }` to correctly resolve\n * a registered `client|` alias instead, for `RequestTrade`/`AddLiquidity`/`RemoveLiquidity`/\n * `CollectPositionFees` (`EIP712_CAPABLE_METHODS`) — `CreatePool` and any other method still\n * falls back to `personal_sign` even in `'eip712'` mode, since its EIP-712 signing is a\n * separate, unsolved chain-side problem.\n *\n * @example\n * ```typescript\n * const signer = new BrowserWalletSigner(window.ethereum, '0x0123456789012345678901234567890123456789');\n * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });\n * ```\n * @example\n * ```typescript\n * // Correctly resolves a registered client| alias instead of the bare eth| address.\n * const signer = new BrowserWalletSigner(window.ethereum, walletAddress, { scheme: 'eip712' });\n * ```\n */\n constructor(\n private readonly provider: BrowserWalletProvider,\n walletAddress: string,\n options: { scheme?: 'personal-sign' | 'eip712' } = {},\n ) {\n this.walletAddress = normalizeEthereumAccount(walletAddress, false);\n this.scheme = options.scheme ?? 'personal-sign';\n }\n\n public readonly walletAddress: string;\n private readonly scheme: 'personal-sign' | 'eip712';\n\n /**\n * Signs the DTO with `eth_signTypedData_v4` (when constructed with `{ scheme: 'eip712' }` and\n * `methodName` is in `EIP712_CAPABLE_METHODS`) or the EIP-1193 `personal_sign` method\n * (otherwise — the default).\n *\n * @example\n * ```typescript\n * const signed = await signer.signObject('RequestTrade', {\n * token0: 'GALA',\n * token1: 'GUSDC',\n * fee: 3000,\n * });\n * ```\n */\n public signObject<T extends Record<string, unknown>>(\n methodName: string,\n dto: T,\n ): Promise<SignedDto<T>> {\n if (this.scheme === 'eip712' && EIP712_CAPABLE_METHODS.has(methodName)) {\n return signEIP712(this.provider, methodName, dto, this.walletAddress);\n }\n return personalSign(this.provider, dto, this.walletAddress);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"signers.js","names":["globalObject"],"sources":["../../../src/classes/signers.ts"],"sourcesContent":["import { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport {\n buildEIP712Payload,\n EIP712_CAPABLE_METHODS,\n eip712DomainFor,\n type EIP712DomainValue,\n type EIP712Types,\n} from '../utils/eip712.js';\nimport {\n ethAddressOfPrivateKey,\n fixpointPrefixFor,\n normalizePrivateKey,\n personalSignPrefixFor,\n serialize,\n signNative,\n} from '../utils/signing.js';\n\n// Personal-sign prefix, computed the way THE CHAIN verifies it.\n//\n// GalaChain (SDK 3.x) recovers a personal-signed DTO from\n// keccak256(<prefix field> + <canonical JSON of the DTO WITHOUT the prefix field>)\n// and a browser wallet's `personal_sign` (EIP-191) hashes\n// \"\\u0019Ethereum Signed Message:\\n\" + <byte length of message> + <message>.\n// They agree exactly when the wallet signs the bare canonical DTO and `prefix` is the EIP-191\n// header for that message's UTF-8 BYTE length. Any other message still yields a valid-looking\n// signature — it just recovers to an address nobody holds. This SDK used to embed `prefix` in\n// the signed message (the SDK 1.10 client recipe): observed on stage 2026-09-23, such a\n// MetaMask-signed CreatePool executed on chain under a phantom creator, and defi-backend's\n// bouncer now rejects that shape outright.\n//\n// `@gala-chain/connect`'s prefix helper must NOT be used for wallet `personal_sign`: its\n// fixpoint counts the prefix itself and targets the SDK's raw-payload signer. The same header\n// is also what Gala Wallet's `gala_signChainDto` (personal-sign scheme) prepends before hashing,\n// so one value serves both paths.\n//\n// The header itself is computed by `personalSignPrefixFor` in ../utils/signing.ts.\n\n/** The signing schemes supported by the Gala Wallet signer. */\nexport type GalaWalletScheme = 'native' | 'personal-sign';\n\n/** The request surface used by an EIP-1193 browser wallet. */\nexport interface BrowserWalletProvider {\n request(args: { method: string; params?: unknown[] }): Promise<unknown>;\n}\n\ninterface GalaWalletProvider {\n request(args: { method: string; params?: unknown[] }): Promise<unknown>;\n /** Gala Wallet's \"act as this account\" switch; absent on other providers. */\n setAddress?: (address: string) => Promise<void>;\n}\n\ninterface WindowWithGala {\n gala?: GalaWalletProvider;\n}\n\ninterface GlobalWithWindow {\n window?: WindowWithGala;\n}\n\n/** A DTO together with the signature that belongs in the gateway request body. */\nexport type SignedDto<T extends Record<string, unknown>> = T & { signature: string };\n\n/**\n * A signer for complete GalaChain write bodies.\n *\n * Implementations return the DTO fields together with the signature that belongs in the\n * gateway request body. Signer identity is recovered from that signature; implementations do\n * not add signer hints, typed-data metadata, or a domain.\n */\nexport interface GalaChainSigner {\n /**\n * Signs a DTO for a named GalaChain contract method.\n *\n * @example\n * ```typescript\n * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });\n * ```\n */\n signObject<T extends Record<string, unknown>>(methodName: string, dto: T): Promise<SignedDto<T>>;\n}\n\nfunction getWalletProvider(): GalaWalletProvider {\n const globalObject = globalThis as GlobalWithWindow;\n const wallet = globalObject.window?.gala;\n if (!wallet) {\n throw new GSwapSDKError('GALA_WALLET_NOT_AVAILABLE', {});\n }\n return wallet;\n}\n\nfunction getNativeSignature(value: unknown): string {\n if (typeof value !== 'string') {\n throw new GSwapSDKError('INVALID_SIGNATURE', { scheme: 'native' });\n }\n // 130 hex digits (r || s || v), bare as Gala Wallet returns it or `0x`-prefixed; passed on\n // verbatim, because the backend recovers the signer from either spelling.\n if (!/^(?:0x)?[0-9a-fA-F]{130}$/u.test(value)) {\n throw new GSwapSDKError('INVALID_SIGNATURE', { scheme: 'native' });\n }\n return value;\n}\n\nfunction getPersonalSignature(value: unknown): string {\n if (typeof value !== 'string' || !/^(?:0x)?[0-9a-fA-F]{130}$/u.test(value)) {\n throw new GSwapSDKError('INVALID_SIGNATURE', { scheme: 'personal-sign' });\n }\n return value;\n}\n\n/**\n * The `0x`-prefixed Ethereum address a Gala account is signed by, or `undefined` when the account\n * names no key (a `client|` alias or a bare GalaChain id is not derivable from a key). Accepts\n * `0x` plus 40 hex digits and `eth|` plus 40 hex digits, with or without `0x`; the caller's casing\n * is kept. For {@link LazyPrivateKeySignerOptions.expectedAddress}, which should only be set for\n * an account whose key can be checked.\n *\n * @example\n * ```ts\n * createLazyPrivateKeySigner(getKey, { expectedAddress: ethereumAddressOfAccount(account) });\n * ```\n */\nexport function ethereumAddressOfAccount(account: string): string | undefined {\n const match = /^(?:eth\\|(?:0x)?|0x)([0-9a-fA-F]{40})$/u.exec(account);\n return match?.[1] === undefined ? undefined : `0x${match[1]}`;\n}\n\nfunction normalizeEthereumAccount(address: string, allowGalaPrefix: boolean): string {\n const normalized = allowGalaPrefix ? (ethereumAddressOfAccount(address) ?? address) : address;\n if (!/^0x[0-9a-fA-F]{40}$/u.test(normalized)) {\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', { field: 'walletAddress', value: address });\n }\n // The caller's casing is kept on purpose: frontend_v2 and the wallet hand the wallet the\n // checksummed account, and EIP-1193 / Gala Wallet accept any case, so passing the value through\n // unchanged is the only choice that cannot differ from what they send.\n return normalized;\n}\n\n/**\n * The account handed to Gala Wallet as the signer address. An Ethereum account is held to the\n * same strict check as ever (`0x` plus 40 hex digits; `eth|` plus 40 hex digits, with or without\n * `0x`, is normalized to it). A GalaChain id the wallet can also be asked to sign for is passed\n * through verbatim: `client|` plus 24 hex digits, or the bare 24 hex digits that frontend_v2 keeps\n * in `state.user.wallet` after a direct `client|` login. Nothing else is accepted.\n */\nfunction normalizeGalaWalletAccount(address: string): string {\n const eth = /^eth\\|(?:0x)?([0-9a-fA-F]{40})$/u.exec(address);\n if (eth?.[1] !== undefined) return `0x${eth[1]}`;\n if (/^0x[0-9a-fA-F]{40}$/u.test(address) || /^(?:client\\|)?[0-9a-fA-F]{24}$/u.test(address)) {\n return address;\n }\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', { field: 'walletAddress', value: address });\n}\n\n/** An identity Gala Wallet can act as: an account form above, any `eth|`/`client|` alias, verbatim. */\nfunction assertWalletIdentity(identity: string): void {\n if (\n !/^(?:eth\\|(?:0x)?[0-9a-fA-F]{40}|0x[0-9a-fA-F]{40}|(?:client\\|)?[0-9a-fA-F]{24})$/u.test(\n identity,\n )\n ) {\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', { field: 'selectAddress', value: identity });\n }\n}\n\n/** Provider-wide queue: `setAddress` + the signature request must not interleave across signers. */\nconst walletIdentityQueue = new WeakMap<object, Promise<unknown>>();\n\n/**\n * Runs `signWith` with `identity` selected on a Gala Wallet that supports `setAddress`. Gala\n * Wallet holds ONE current account, so two signatures for different identities in flight at once\n * would sign as whichever selection came last; the pair (select, sign) is therefore serialized\n * per provider. A failed selection fails the signature (nothing is requested).\n */\nfunction withSelectedIdentity<T>(\n wallet: GalaWalletProvider,\n identity: string | undefined,\n signWith: () => Promise<T>,\n): Promise<T> {\n const { setAddress } = wallet;\n if (identity === undefined || typeof setAddress !== 'function') return signWith();\n const previous = walletIdentityQueue.get(wallet) ?? Promise.resolve();\n const run = previous\n .catch(() => undefined)\n .then(async () => {\n await setAddress.call(wallet, identity);\n return signWith();\n });\n walletIdentityQueue.set(wallet, run);\n return run;\n}\n\nfunction personalSign<T extends Record<string, unknown>>(\n provider: GalaWalletProvider | BrowserWalletProvider,\n dto: T,\n walletAddress: string,\n methodName?: string,\n): Promise<T & { prefix: string; signature: string }> {\n const prefix = personalSignPrefixFor(dto);\n const payload = { ...dto, prefix };\n // A browser wallet's `personal_sign` applies the EIP-191 header ITSELF, so it must sign the\n // bare DTO; Gala Wallet's `gala_signChainDto` (personal-sign scheme) instead extracts the\n // `prefix` field from what it is handed and prepends it before hashing, so it is handed the\n // prefixed payload. Both submit `{ ...dto, prefix, signature }`.\n const params =\n methodName !== undefined\n ? [serialize(payload), walletAddress, methodName]\n : [serialize(dto), walletAddress];\n\n return provider\n .request({ method: methodName !== undefined ? 'gala_signChainDto' : 'personal_sign', params })\n .then((value) => ({ ...payload, signature: getPersonalSignature(value) }));\n}\n\n/**\n * Signs a DTO via genuine EIP-712 (`eth_signTypedData_v4`) — correctly resolves the `client|`\n * identity, unlike `personal_sign`, for the operations in `EIP712_CAPABLE_METHODS`.\n *\n * Constructs the raw JSON-RPC payload by hand (`{domain, types: {...types, EIP712Domain},\n * primaryType, message}`) rather than depending on ethers.js, matching exactly what\n * `ethers.TypedDataEncoder.getPayload`/`Wallet.signTypedData` produce internally — verified\n * byte-for-byte equivalent (same recovered address from the same signature against both\n * constructions) before this shipped, since gswap-sdk deliberately has no ethers dependency.\n */\nasync function signEIP712<T extends Record<string, unknown>>(\n provider: BrowserWalletProvider,\n methodName: string,\n dto: T,\n walletAddress: string,\n): Promise<T & { types: EIP712Types; domain: EIP712DomainValue; signature: string }> {\n const { completedDto, types } = buildEIP712Payload(methodName, dto);\n // The wallet's LIVE chain id, read on every signature: a user can switch networks after\n // connecting, and a cached or hardcoded id would sign a domain MetaMask itself rejects.\n const domain = eip712DomainFor(await provider.request({ method: 'eth_chainId', params: [] }));\n // The body `prefix` is not part of the EIP-712 `types`, so it is never hashed; it carries the\n // connect-style fixpoint value only to keep the submitted body byte-identical to frontend_v2's.\n const prefix = fixpointPrefixFor(completedDto);\n const message = { ...completedDto, prefix };\n const eip712Domain = [\n { name: 'name', type: 'string' },\n { name: 'chainId', type: 'uint256' },\n ];\n const payload = {\n domain,\n types: { ...types, EIP712Domain: eip712Domain },\n primaryType: methodName,\n message,\n };\n\n const value = await provider.request({\n method: 'eth_signTypedData_v4',\n params: [walletAddress, JSON.stringify(payload)],\n });\n // Key order matches frontend_v2's submitted body: ..., prefix, signature, types, domain.\n return {\n ...(message as T & { prefix: string }),\n signature: getPersonalSignature(value),\n types,\n domain,\n };\n}\n\n/**\n * A GalaChain native signer backed by a secp256k1 private key.\n *\n * Native signing produces the bare GalaChain signature format, without a personal-sign prefix\n * or EIP-712 metadata. The private-key identity is recovered by the chain.\n */\nexport class PrivateKeySigner implements GalaChainSigner {\n private readonly privateKey: Uint8Array;\n\n /**\n * Creates a native signer from a hex or base64 secp256k1 private key.\n *\n * @example\n * ```typescript\n * const signer = new PrivateKeySigner('1'.padStart(64, '0'));\n * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });\n * ```\n */\n constructor(privateKey: string) {\n this.privateKey = normalizePrivateKey(privateKey);\n }\n\n /**\n * Signs the DTO with GalaChain native signing.\n *\n * @example\n * ```typescript\n * const signed = await signer.signObject('RequestTrade', {\n * token0: 'GALA',\n * token1: 'GUSDC',\n * fee: 3000,\n * });\n * ```\n */\n public signObject<T extends Record<string, unknown>>(\n _methodName: string,\n dto: T,\n ): Promise<SignedDto<T>> {\n const signature = signNative(this.privateKey, dto);\n return Promise.resolve({ ...dto, signature });\n }\n}\n\n/** Supplies a private key at sign time: a hex/base64 string, possibly fetched asynchronously. */\nexport type PrivateKeyProvider = () => Promise<string> | string;\n\n/** Options for {@link createLazyPrivateKeySigner}. */\nexport interface LazyPrivateKeySignerOptions {\n /**\n * When set, every signature first checks that the fetched key belongs to this account (`0x...`\n * or the Gala `eth|0x...` / `eth|<40 hex>` form, case-insensitive) and refuses to sign otherwise\n * (`SIGNER_ADDRESS_MISMATCH`). Use it when the key lives in a slot another surface can switch\n * between the moment a request was approved and the moment it is signed.\n */\n expectedAddress?: string | undefined;\n}\n\n/**\n * Calls the app's key provider. Whatever it throws or rejects with is the app's own failure to\n * produce a key before anything was signed or sent, so it becomes `KEY_PROVIDER_FAILED` (the\n * original is `cause`); an SDK error is already catalogued and passes through.\n */\nasync function keyFrom(getPrivateKey: PrivateKeyProvider): Promise<unknown> {\n try {\n return await getPrivateKey();\n } catch (cause: unknown) {\n throw isGSwapError(cause) ? cause : new GSwapSDKError('KEY_PROVIDER_FAILED', {}, { cause });\n }\n}\n\n/**\n * Creates the native-signing equivalent of {@link PrivateKeySigner} for apps that must not hold a\n * key in a long-lived object (an extension that reads its session key at sign time).\n *\n * `getPrivateKey` is called once per `signObject` call, never cached, never shared between calls\n * (concurrent signatures each fetch their own key), and the normalized key bytes are zeroed\n * before `signObject` settles, also on failure. A rejection or exception from `getPrivateKey` (the\n * app's \"wallet is locked\", a storage read that failed) is a `KEY_PROVIDER_FAILED` error with the\n * original error as `cause`: nothing has been sent, so `classifyFailure` says `not_sent` and Retry\n * is safe, and the app needs no error class of its own to tell this apart. A provider that returns\n * no usable string (`''`, `undefined`) is `INVALID_PRIVATE_KEY` with `reason: 'no_key_provided'`,\n * classified the same way; any other key that is not a valid secp256k1 key string is an\n * `INVALID_PRIVATE_KEY` error. An SDK error the provider throws itself is passed through.\n * Signatures are byte-identical to `new PrivateKeySigner(key).signObject(...)`.\n *\n * A JavaScript string cannot be wiped; the provider owns the lifetime of the string it returns.\n *\n * @example\n * ```typescript\n * const signer = createLazyPrivateKeySigner(\n * () => SecurityHelper.getSessionSecret(SecurityHelper.SESSION_PRIVATE_KEY_KEY),\n * { expectedAddress: account.address },\n * );\n * const gswap = new GSwap({ signer });\n * ```\n */\nexport function createLazyPrivateKeySigner(\n getPrivateKey: PrivateKeyProvider,\n options: LazyPrivateKeySignerOptions = {},\n): GalaChainSigner {\n const expected = options.expectedAddress;\n const expectedLower =\n expected === undefined ? undefined : normalizeEthereumAccount(expected, true).toLowerCase();\n\n return {\n async signObject<T extends Record<string, unknown>>(\n _methodName: string,\n dto: T,\n ): Promise<SignedDto<T>> {\n const provided: unknown = await keyFrom(getPrivateKey);\n if (typeof provided !== 'string' || provided === '') {\n throw new GSwapSDKError('INVALID_PRIVATE_KEY', { reason: 'no_key_provided' });\n }\n const key = normalizePrivateKey(provided);\n try {\n if (expectedLower !== undefined && ethAddressOfPrivateKey(key) !== expectedLower) {\n throw new GSwapSDKError('SIGNER_ADDRESS_MISMATCH', {});\n }\n return { ...dto, signature: signNative(key, dto) };\n } finally {\n key.fill(0);\n }\n },\n };\n}\n\n/**\n * A Gala Wallet signer using native GalaChain signing, with an opt-in personal-sign mode.\n *\n * The selected Ethereum account is passed to Gala Wallet. There is NO automatic fallback: a\n * wallet that rejects `native` surfaces its error to the caller, because the only alternative,\n * `personal-sign`, silently recovers a phantom signer on every released Gala Wallet.\n *\n * `scheme: 'personal-sign'` calls\n * `gala_signChainDto([serialize({ ...dto, prefix }), walletAddress, methodName])` and REQUIRES\n * a wallet build that contains wallet_extension commit 34ca4e4 (strips the embedded `prefix`\n * field and hashes `prefix` + the prefix-less canonical body, the chain's scheme). Wallets\n * released before that fix hash the string with the `prefix` field still inside it and the\n * signature recovers to an address nobody holds, so only opt in once the fixed wallet is\n * released. See SIGNING-PARITY.md.\n */\nexport class GalaWalletSigner implements GalaChainSigner {\n /** The wallet address supplied to Gala Wallet for each signing request. */\n public readonly walletAddress: string;\n\n /** The signing scheme used for every request; it never changes after construction. */\n public readonly scheme: GalaWalletScheme;\n\n /**\n * Creates a Gala Wallet signer.\n *\n * @example\n * ```typescript\n * const signer = new GalaWalletSigner('0x0123456789012345678901234567890123456789');\n * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });\n * ```\n *\n * @param walletAddress - The account passed to Gala Wallet as the signer address. An Ethereum\n * account is `0x` plus 40 hex digits (Gala Wallet's `eth|...` form is normalized to it and held\n * to the same check); a GalaChain id is `client|` plus 24 hex digits, or the bare 24 hex digits\n * frontend_v2 keeps for a direct `client|` login, and is passed through unchanged.\n * @param options - Select native signing (default) or personal-sign explicitly.\n * `'personal-sign'` requires a Gala Wallet build with wallet_extension commit 34ca4e4.\n * `selectAddress` is the identity (`client|...` / `eth|...`) Gala Wallet is switched to with\n * `window.gala.setAddress` before every signature, when the wallet offers it.\n */\n constructor(\n walletAddress: string,\n options: { scheme?: GalaWalletScheme | undefined; selectAddress?: string | undefined } = {},\n ) {\n this.walletAddress = normalizeGalaWalletAccount(walletAddress);\n this.scheme = options.scheme ?? 'native';\n if (options.selectAddress !== undefined) assertWalletIdentity(options.selectAddress);\n this.selectAddress = options.selectAddress;\n }\n\n /** The identity Gala Wallet is switched to before each signature, if one was given. */\n public readonly selectAddress: string | undefined;\n\n /**\n * Signs a DTO through `gala_signChainDto`.\n *\n * @example\n * ```typescript\n * const signed = await signer.signObject('AddLiquidity', {\n * token0: 'GALA',\n * token1: 'GUSDC',\n * tickLower: -60,\n * tickUpper: 60,\n * });\n * ```\n */\n public async signObject<T extends Record<string, unknown>>(\n methodName: string,\n dto: T,\n ): Promise<SignedDto<T>> {\n const wallet = getWalletProvider();\n\n return withSelectedIdentity(wallet, this.selectAddress, async () => {\n if (this.scheme === 'personal-sign') {\n return personalSign(wallet, dto, this.walletAddress, methodName);\n }\n const signature = await wallet.request({\n method: 'gala_signChainDto',\n params: [serialize(dto), this.walletAddress, methodName, 'native'],\n });\n return { ...dto, signature: getNativeSignature(signature) };\n });\n }\n}\n\n/**\n * A personal-sign signer for MetaMask and other EIP-1193 browser wallets.\n *\n * The chain recovers this signature using the EIP-191 wrap applied by the wallet to\n * `personal_sign`. This is the browser-wallet path used by the v2 frontend and resolves the\n * bare `eth|` identity.\n */\nexport class BrowserWalletSigner implements GalaChainSigner {\n /**\n * Creates a browser-wallet signer.\n *\n * Defaults to `personal_sign` — unchanged from every existing integration, since it only ever\n * resolves the bare `eth|` identity and changing that silently would be a real behavior\n * break for anyone already depending on it. Pass `{ scheme: 'eip712' }` to correctly resolve\n * a registered `client|` alias instead, for `RequestTrade`/`AddLiquidity`/`RemoveLiquidity`/\n * `CollectPositionFees` (`EIP712_CAPABLE_METHODS`) — `CreatePool` and any other method still\n * falls back to `personal_sign` even in `'eip712'` mode, since its EIP-712 signing is a\n * separate, unsolved chain-side problem.\n *\n * @example\n * ```typescript\n * const signer = new BrowserWalletSigner(window.ethereum, '0x0123456789012345678901234567890123456789');\n * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });\n * ```\n * @example\n * ```typescript\n * // Correctly resolves a registered client| alias instead of the bare eth| address.\n * const signer = new BrowserWalletSigner(window.ethereum, walletAddress, { scheme: 'eip712' });\n * ```\n */\n constructor(\n private readonly provider: BrowserWalletProvider,\n walletAddress: string,\n options: { scheme?: 'personal-sign' | 'eip712' } = {},\n ) {\n this.walletAddress = normalizeEthereumAccount(walletAddress, false);\n this.scheme = options.scheme ?? 'personal-sign';\n }\n\n /** The selected `0x` Ethereum account every signature is requested for. */\n public readonly walletAddress: string;\n private readonly scheme: 'personal-sign' | 'eip712';\n\n /**\n * Signs the DTO with `eth_signTypedData_v4` (when constructed with `{ scheme: 'eip712' }` and\n * `methodName` is in `EIP712_CAPABLE_METHODS`) or the EIP-1193 `personal_sign` method\n * (otherwise — the default).\n *\n * @example\n * ```typescript\n * const signed = await signer.signObject('RequestTrade', {\n * token0: 'GALA',\n * token1: 'GUSDC',\n * fee: 3000,\n * });\n * ```\n */\n public signObject<T extends Record<string, unknown>>(\n methodName: string,\n dto: T,\n ): Promise<SignedDto<T>> {\n if (this.scheme === 'eip712' && EIP712_CAPABLE_METHODS.has(methodName)) {\n return signEIP712(this.provider, methodName, dto, this.walletAddress);\n }\n return personalSign(this.provider, dto, this.walletAddress);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ function e(e){let t=()=>typeof e==`function`?e():e;return{async get(e){let n=await t().get(e);return Object.hasOwn(n,e)?n[e]:void 0},async set(e,n){await t().set({[e]:n})}}}function t(e){let t=()=>typeof e==`function`?e():e;return{async get(e){let n=t().getItem(e);if(n!==null)try{return JSON.parse(n)}catch{return n}},async set(e,n){t().setItem(e,JSON.stringify(n))}}}export{e as storageAdapterFromChromeStorage,t as webStorageAdapter};
2
+ //# sourceMappingURL=storage_adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage_adapters.js","names":[],"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` (frontend_v2): 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 * frontend_v2 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,SAAgB,EACd,EACgB,CAChB,IAAM,MAAwC,OAAO,GAAS,WAAa,EAAK,EAAI,EACpF,MAAO,CACL,MAAM,IAAI,EAAK,CACb,IAAM,EAAQ,MAAM,EAAQ,CAAC,CAAC,IAAI,CAAG,EACrC,OAAO,OAAO,OAAO,EAAO,CAAG,EAAI,EAAM,GAAO,IAAA,EAClD,EACA,MAAM,IAAI,EAAK,EAAO,CACpB,MAAM,EAAQ,CAAC,CAAC,IAAI,EAAG,GAAM,CAAM,CAAC,CACtC,CACF,CACF,CA+BA,SAAgB,EAAkB,EAA+D,CAC/F,IAAM,MAAiC,OAAO,GAAS,WAAa,EAAK,EAAI,EAC7E,MAAO,CACL,MAAM,IAAI,EAAK,CACb,IAAM,EAAM,EAAQ,CAAC,CAAC,QAAQ,CAAG,EACjC,GAAI,IAAQ,KACZ,GAAI,CACF,OAAO,KAAK,MAAM,CAAG,CACvB,MAAQ,CACN,OAAO,CACT,CACF,EACA,MAAM,IAAI,EAAK,EAAO,CACpB,EAAQ,CAAC,CAAC,QAAQ,EAAK,KAAK,UAAU,CAAK,CAAC,CAC9C,CACF,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"submitted_transaction.js","names":[],"sources":["../../../src/classes/submitted_transaction.ts"],"sourcesContent":["import type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { HttpRequestor } from '../types/http_requestor.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\nimport type { WireOptions } from '../types/wire.js';\nimport { createConfirmationSchedule, throwIfAborted } from '../utils/confirmation_schedule.js';\nimport type { SubmitStatus } from '../utils/submit_state.js';\nimport { armTimeout } from '../utils/transport.js';\nimport { confirmAppliedTrade } from './apply_results.js';\nimport { GSwapSDKError } 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 public readonly method: string;\n public readonly uniqueKey: string;\n public readonly transactionId: string | 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 * @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 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 throw error;\n } finally {\n disarm();\n callerSignal?.removeEventListener('abort', forwardAbort);\n }\n if (!(await schedule.waitForRead())) break;\n }\n throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey);\n }\n}\n"],"mappings":"2VAeA,IAAa,EAAb,KAAkF,CAwChF,YAAY,EAeT,CAtDa,EAAA,KAAA,SAAA,IAAA,EAAA,EACA,EAAA,KAAA,YAAA,IAAA,EAAA,EACA,EAAA,KAAA,gBAAA,IAAA,EAAA,EACA,EAAA,KAAA,cAAA,IAAA,EAAA,EAEA,EAAA,KAAA,OAAA,IAAA,EAAA,EAOA,EAAA,KAAA,SAAA,IAAA,EAAA,EAEA,EAAA,KAAA,SAAA,IAAA,EAAA,EAMA,EAAA,KAAA,WAAA,IAAA,EAAA,EACC,EAAA,KAAA,iBAAA,IAAA,EAAA,EACA,EAAA,KAAA,YAAA,IAAA,EAAA,EACA,EAAA,KAAA,mBAAA,IAAA,EAAA,EACA,EAAA,KAAA,OAAA,IAAA,EAAA,EACA,EAAA,KAAA,uBAAA,IAAA,EAAA,EA8Bf,KAAK,OAAS,EAAQ,OACtB,KAAK,UAAY,EAAQ,UACzB,KAAK,cAAgB,EAAQ,cAC7B,KAAK,YAAc,EAAQ,aAAe,KAC1C,KAAK,KAAO,EAAQ,KACpB,KAAK,OAAS,EAAQ,OAAS,SAAW,SAAW,WACrD,KAAK,OAAS,EAAQ,OACtB,KAAK,SAAW,EAAQ,SACxB,KAAK,eAAiB,EAAQ,kBAAkB,QAAQ,OAAQ,EAAE,EAClE,KAAK,UAAY,EAAQ,cACzB,KAAK,iBAAmB,EAAQ,kBAAoB,IACpD,KAAK,KAAO,EAAQ,KACpB,KAAK,qBAAuB,EAAQ,oBACtC,CAYA,MAAa,QAAQ,EAAkD,CAIrE,OAHI,KAAK,SAAW,eACX,KAAK,eAAe,CAAO,EAE7B,KAAK,gBAAgB,CAAO,CACrC,CAEA,eAAuB,EAAiD,CACtE,OAAO,EACL,CACE,kBAAmB,KAAK,eACxB,cAAe,KAAK,UACpB,iBAAkB,KAAK,iBACvB,KAAM,KAAK,IACb,EACA,CAAE,UAAW,KAAK,UAAW,qBAAsB,KAAK,aAAc,EACtE,CACF,CACF,CAUA,MAAc,gBAAgB,EAAoD,CAChF,GAAI,KAAK,uBAAyB,IAAA,GAAW,MAAM,EAAc,qBAAqB,EAGtF,IAAM,EAAe,GAAS,OACxB,EAAc,GAClB,IAAI,EAAc,uBAAwB,CAAC,EAAG,CAAE,UAAW,KAAK,UAAW,OAAM,CAAC,EAC9E,EAAW,EAA2B,EAAS,EAAG,CAAU,EAElE,IADA,MAAM,EAAS,YAAY,IACd,CACX,IAAM,EAAa,IAAI,gBACjB,EAAS,EAAW,EAAY,KAAK,gBAAgB,EACrD,MAA2B,EAAW,MAAM,EAClD,GAAc,iBAAiB,QAAS,EAAc,CAAE,KAAM,EAAK,CAAC,EACpE,GAAI,CACF,IAAM,EAAS,MAAM,KAAK,qBAAqB,EAAW,MAAM,EAChE,GAAI,EAAO,UAAW,OAAO,EAAO,QACtC,OAAS,EAAgB,CAEvB,MADA,EAAe,EAAc,CAAU,EACjC,CACR,QAAU,CACR,EAAO,EACP,GAAc,oBAAoB,QAAS,CAAY,CACzD,CACA,GAAI,CAAE,MAAM,EAAS,YAAY,EAAI,KACvC,CACA,MAAM,EAAc,yBAAyB,KAAK,SAAS,CAC7D,CACF"}
1
+ {"version":3,"file":"submitted_transaction.js","names":[],"sources":["../../../src/classes/submitted_transaction.ts"],"sourcesContent":["import type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { HttpRequestor } from '../types/http_requestor.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\nimport type { WireOptions } from '../types/wire.js';\nimport { createConfirmationSchedule, throwIfAborted } from '../utils/confirmation_schedule.js';\nimport type { SubmitStatus } from '../utils/submit_state.js';\nimport { armTimeout } from '../utils/transport.js';\nimport { confirmAppliedTrade } from './apply_results.js';\nimport { GSwapSDKError } 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 * @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 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 throw error;\n } finally {\n disarm();\n callerSignal?.removeEventListener('abort', forwardAbort);\n }\n if (!(await schedule.waitForRead())) break;\n }\n throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey);\n }\n}\n"],"mappings":"2VAeA,IAAa,EAAb,KAAkF,CA4ChF,YAAY,EAeT,CAzDa,EAAA,KAAA,SAAA,IAAA,EAAA,EAEA,EAAA,KAAA,YAAA,IAAA,EAAA,EAEA,EAAA,KAAA,gBAAA,IAAA,EAAA,EAEA,EAAA,KAAA,cAAA,IAAA,EAAA,EAEA,EAAA,KAAA,OAAA,IAAA,EAAA,EAOA,EAAA,KAAA,SAAA,IAAA,EAAA,EAEA,EAAA,KAAA,SAAA,IAAA,EAAA,EAMA,EAAA,KAAA,WAAA,IAAA,EAAA,EACC,EAAA,KAAA,iBAAA,IAAA,EAAA,EACA,EAAA,KAAA,YAAA,IAAA,EAAA,EACA,EAAA,KAAA,mBAAA,IAAA,EAAA,EACA,EAAA,KAAA,OAAA,IAAA,EAAA,EACA,EAAA,KAAA,uBAAA,IAAA,EAAA,EA8Bf,KAAK,OAAS,EAAQ,OACtB,KAAK,UAAY,EAAQ,UACzB,KAAK,cAAgB,EAAQ,cAC7B,KAAK,YAAc,EAAQ,aAAe,KAC1C,KAAK,KAAO,EAAQ,KACpB,KAAK,OAAS,EAAQ,OAAS,SAAW,SAAW,WACrD,KAAK,OAAS,EAAQ,OACtB,KAAK,SAAW,EAAQ,SACxB,KAAK,eAAiB,EAAQ,kBAAkB,QAAQ,OAAQ,EAAE,EAClE,KAAK,UAAY,EAAQ,cACzB,KAAK,iBAAmB,EAAQ,kBAAoB,IACpD,KAAK,KAAO,EAAQ,KACpB,KAAK,qBAAuB,EAAQ,oBACtC,CAYA,MAAa,QAAQ,EAAkD,CAIrE,OAHI,KAAK,SAAW,eACX,KAAK,eAAe,CAAO,EAE7B,KAAK,gBAAgB,CAAO,CACrC,CAEA,eAAuB,EAAiD,CACtE,OAAO,EACL,CACE,kBAAmB,KAAK,eACxB,cAAe,KAAK,UACpB,iBAAkB,KAAK,iBACvB,KAAM,KAAK,IACb,EACA,CAAE,UAAW,KAAK,UAAW,qBAAsB,KAAK,aAAc,EACtE,CACF,CACF,CAUA,MAAc,gBAAgB,EAAoD,CAChF,GAAI,KAAK,uBAAyB,IAAA,GAAW,MAAM,EAAc,qBAAqB,EAGtF,IAAM,EAAe,GAAS,OACxB,EAAc,GAClB,IAAI,EAAc,uBAAwB,CAAC,EAAG,CAAE,UAAW,KAAK,UAAW,OAAM,CAAC,EAC9E,EAAW,EAA2B,EAAS,EAAG,CAAU,EAElE,IADA,MAAM,EAAS,YAAY,IACd,CACX,IAAM,EAAa,IAAI,gBACjB,EAAS,EAAW,EAAY,KAAK,gBAAgB,EACrD,MAA2B,EAAW,MAAM,EAClD,GAAc,iBAAiB,QAAS,EAAc,CAAE,KAAM,EAAK,CAAC,EACpE,GAAI,CACF,IAAM,EAAS,MAAM,KAAK,qBAAqB,EAAW,MAAM,EAChE,GAAI,EAAO,UAAW,OAAO,EAAO,QACtC,OAAS,EAAgB,CAEvB,MADA,EAAe,EAAc,CAAU,EACjC,CACR,QAAU,CACR,EAAO,EACP,GAAc,oBAAoB,QAAS,CAAY,CACzD,CACA,GAAI,CAAE,MAAM,EAAS,YAAY,EAAI,KACvC,CACA,MAAM,EAAc,yBAAyB,KAAK,SAAS,CAC7D,CACF"}
@@ -1,2 +1,2 @@
1
- import e from"../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{isProposableTradingSymbol as n}from"../utils/validation.js";import{resolvePreSend as r}from"../utils/pre_send.js";import{HttpClient as i}from"./http_client.js";import{asEntryRecord as a,entryOk as o,entryRejected as s,readEntries as c}from"../utils/lenient.js";import{compositeKeyOf as l,orderSymbols as u,parseTokenClassKey as d}from"../utils/ordering.js";var f=class{constructor(t,n={}){this.gateway=t,this.options=n,e(this,`cachedSymbols`,void 0),e(this,`cachedAt`,0),e(this,`refreshInFlight`,void 0),e(this,`http`,void 0),this.http=new i(t.httpRequestor,t.requestTimeoutMs,t.wire)}async list(){return this.cachedSymbols!==void 0&&Date.now()-this.cachedAt<6e4?this.cachedSymbols:(this.refreshInFlight===void 0&&(this.refreshInFlight=this.http.sendGetRequest(this.gateway.dexBackendBaseUrl,`/v2/trade`,`/symbols`).then(e=>c(`symbols`,e.data,p,this.options.onInvalidEntry)).then(e=>(this.cachedSymbols=e,this.cachedAt=Date.now(),e)).finally(()=>{this.refreshInFlight=void 0})),this.refreshInFlight)}invalidate(){this.cachedSymbols=void 0,this.cachedAt=0}async refresh(){return this.invalidate(),this.refreshInFlight=void 0,this.list()}async resolve(e){let n=await this.list(),r=typeof e==`string`?m(e)?l(d(e)):void 0:l(e),i=n.find(t=>t.symbol===e||r!==void 0&&l(t)===r);if(i===void 0){n=await this.refresh();let i=n.find(t=>t.symbol===e||r!==void 0&&l(t)===r);if(i===void 0)throw t.unknownTokenError(e);return i}return i}async proposeSymbol(e,r,i={}){let a=[];try{a=await this.list()}catch(e){if(i.registryFailure!==`ignore`)throw e}let o=l(e),s=a.find(t=>t.collection===e.collection&&t.category===e.category&&t.type===e.type&&t.additionalKey===e.additionalKey);if(s!==void 0)return s.symbol;if(n(r))return r;throw new t(`NO_VALID_TRADING_SYMBOL`,{classKey:o,displaySymbol:r})}async orderPair(e,t){let[n,r]=await Promise.all([this.resolve(e),this.resolve(t)]),[i,a]=u(n.symbol,r.symbol);return{token0:i===n.symbol?n:r,token1:a===r.symbol?r:n,flipped:i!==n.symbol}}};function p(e){let t=a(e);if(t===void 0)return s(`the row is not an object`);let{symbol:n,collection:r,category:i,type:c,additionalKey:l,decimals:u}=t;return typeof n==`string`?n.length===0?s(`symbol is empty`):typeof r==`string`?typeof i==`string`?typeof c==`string`?typeof l==`string`?typeof u!=`number`||!Number.isInteger(u)||u<0?s(`decimals is not a non-negative integer`):o({symbol:n,collection:r,category:i,type:c,additionalKey:l,decimals:u}):s(`additionalKey is not a string`):s(`type is not a string`):s(`category is not a string`):s(`collection is not a string`):s(`symbol is not a string`)}function m(e){return e.includes(`|`)||e.includes(`$`)}function h(e){return typeof e==`string`?e:l(e)}async function g(e,n){let i=await r(h(n),()=>e.resolve(n));if(i.symbol.length>0)return i.symbol;throw new t(`SYMBOL_NOT_FOUND`,{token:h(n)})}async function _(e,t){return e.passthrough===!0?h(t):g(e,t)}var v=class{constructor(){e(this,`passthrough`,!0)}resolve(e){return typeof e==`string`&&!m(e)?Promise.resolve({symbol:e,collection:``,category:``,type:``,additionalKey:``,decimals:0}):Promise.reject(t.unknownTokenError(e))}async orderPair(e,t){let[n,r]=await Promise.all([this.resolve(e),this.resolve(t)]),[i]=u(n.symbol,r.symbol),a=i!==n.symbol;return{token0:a?r:n,token1:a?n:r,flipped:a}}invalidate(){}};export{v as CanonicalSymbols,f as Symbols,_ as queryTokenOf,h as rawTokenOf,g as tradingSymbolOf};
1
+ import e from"../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{isProposableTradingSymbol as n}from"../utils/validation.js";import{resolvePreSend as r}from"../utils/pre_send.js";import{HttpClient as i}from"./http_client.js";import{asEntryRecord as a,entryOk as o,entryRejected as s,readEntries as c}from"../utils/lenient.js";import{compositeKeyOf as l}from"../utils/class_key.js";import{orderSymbols as u,parseTokenClassKey as d}from"../utils/ordering.js";var f=class{constructor(t,n={}){this.gateway=t,this.options=n,e(this,`cachedSymbols`,void 0),e(this,`cachedAt`,0),e(this,`refreshInFlight`,void 0),e(this,`http`,void 0),this.http=new i(t.httpRequestor,t.requestTimeoutMs,t.wire)}async list(){return this.cachedSymbols!==void 0&&Date.now()-this.cachedAt<6e4?this.cachedSymbols:(this.refreshInFlight===void 0&&(this.refreshInFlight=this.http.sendGetRequest(this.gateway.dexBackendBaseUrl,`/v2/trade`,`/symbols`).then(e=>c(`symbols`,e.data,p,this.options.onInvalidEntry)).then(e=>(this.cachedSymbols=e,this.cachedAt=Date.now(),e)).finally(()=>{this.refreshInFlight=void 0})),this.refreshInFlight)}invalidate(){this.cachedSymbols=void 0,this.cachedAt=0}async refresh(){return this.invalidate(),this.refreshInFlight=void 0,this.list()}async resolve(e){let n=await this.list(),r=typeof e==`string`?m(e)?l(d(e)):void 0:l(e),i=n.find(t=>t.symbol===e||r!==void 0&&l(t)===r);if(i===void 0){n=await this.refresh();let i=n.find(t=>t.symbol===e||r!==void 0&&l(t)===r);if(i===void 0)throw t.unknownTokenError(e);return i}return i}async proposeSymbol(e,r,i={}){let a=[];try{a=await this.list()}catch(e){if(i.registryFailure!==`ignore`)throw e}let o=l(e),s=a.find(t=>t.collection===e.collection&&t.category===e.category&&t.type===e.type&&t.additionalKey===e.additionalKey);if(s!==void 0)return s.symbol;if(n(r))return r;throw new t(`NO_VALID_TRADING_SYMBOL`,{classKey:o,displaySymbol:r})}async orderPair(e,t){let[n,r]=await Promise.all([this.resolve(e),this.resolve(t)]),[i,a]=u(n.symbol,r.symbol);return{token0:i===n.symbol?n:r,token1:a===r.symbol?r:n,flipped:i!==n.symbol}}};function p(e){let t=a(e);if(t===void 0)return s(`the row is not an object`);let{symbol:n,collection:r,category:i,type:c,additionalKey:l,decimals:u}=t;return typeof n==`string`?n.length===0?s(`symbol is empty`):typeof r==`string`?typeof i==`string`?typeof c==`string`?typeof l==`string`?typeof u!=`number`||!Number.isInteger(u)||u<0?s(`decimals is not a non-negative integer`):o({symbol:n,collection:r,category:i,type:c,additionalKey:l,decimals:u}):s(`additionalKey is not a string`):s(`type is not a string`):s(`category is not a string`):s(`collection is not a string`):s(`symbol is not a string`)}function m(e){return e.includes(`|`)||e.includes(`$`)}function h(e){return typeof e==`string`?e:l(e)}async function g(e,n){let i=await r(h(n),()=>e.resolve(n));if(i.symbol.length>0)return i.symbol;throw new t(`SYMBOL_NOT_FOUND`,{token:h(n)})}async function _(e,t){return e.passthrough===!0?h(t):g(e,t)}var v=class{constructor(){e(this,`passthrough`,!0)}resolve(e){return typeof e==`string`&&!m(e)?Promise.resolve({symbol:e,collection:``,category:``,type:``,additionalKey:``,decimals:0}):Promise.reject(t.unknownTokenError(e))}async orderPair(e,t){let[n,r]=await Promise.all([this.resolve(e),this.resolve(t)]),[i]=u(n.symbol,r.symbol),a=i!==n.symbol;return{token0:a?r:n,token1:a?n:r,flipped:a}}invalidate(){}};export{v as CanonicalSymbols,f as Symbols,_ as queryTokenOf,h as rawTokenOf,g as tradingSymbolOf};
2
2
  //# sourceMappingURL=symbols.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"symbols.js","names":[],"sources":["../../../src/classes/symbols.ts"],"sourcesContent":["import type { GalaChainTokenClassKey } from '../types/token.js';\nimport type { TradingSymbol } from '../types/v2_results.js';\nimport type { WireOptions } from '../types/wire.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport type { TokenRef } from '../utils/ordering.js';\nimport { compositeKeyOf, orderSymbols, parseTokenClassKey } from '../utils/ordering.js';\nimport { resolvePreSend } from '../utils/pre_send.js';\nimport { isProposableTradingSymbol } from '../utils/validation.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport type { ChainGateway } from './gateway.js';\nimport { HttpClient } from './http_client.js';\n\nconst SYMBOL_CACHE_TTL_MS = 60_000;\n\n/** Symbol registry client for the current GalaChainDex contract. */\nexport class Symbols {\n private cachedSymbols: TradingSymbol[] | undefined;\n private cachedAt = 0;\n private refreshInFlight: Promise<TradingSymbol[]> | undefined;\n\n private readonly http: HttpClient;\n\n /**\n * Create a symbol service backed by the swap backend. `onInvalidEntry` is told about every\n * registry row that was skipped as unusable (see {@link InvalidEntryHandler}).\n */\n constructor(\n private readonly gateway: Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n },\n private readonly options: { onInvalidEntry?: InvalidEntryHandler | undefined } = {},\n ) {\n this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs, gateway.wire);\n }\n\n /**\n * List all registered GalaChainDex trading symbols, cached for 60 seconds. A registry row that\n * is not a usable symbol is skipped (and reported to `onInvalidEntry`) instead of failing the\n * whole list.\n */\n public async list(): Promise<TradingSymbol[]> {\n if (this.cachedSymbols !== undefined && Date.now() - this.cachedAt < SYMBOL_CACHE_TTL_MS) {\n return this.cachedSymbols;\n }\n if (this.refreshInFlight !== undefined) return this.refreshInFlight;\n this.refreshInFlight = this.http\n .sendGetRequest<{ data: unknown }>(this.gateway.dexBackendBaseUrl, '/v2/trade', '/symbols')\n .then((response) =>\n readEntries('symbols', response.data, parseTradingSymbol, this.options.onInvalidEntry),\n )\n .then((symbols) => {\n this.cachedSymbols = symbols;\n this.cachedAt = Date.now();\n return symbols;\n })\n .finally(() => {\n this.refreshInFlight = undefined;\n });\n return this.refreshInFlight;\n }\n\n /** Invalidate the cached symbol registry after a write changes registration state.\n *\n * @example\n * ```ts\n * gSwap.symbols.invalidate();\n * ```\n */\n public invalidate(): void {\n this.cachedSymbols = undefined;\n this.cachedAt = 0;\n }\n\n /** Force one registry refresh, bypassing the cache.\n *\n * @example\n * ```ts\n * const symbols = await gSwap.symbols.refresh();\n * ```\n */\n public async refresh(): Promise<TradingSymbol[]> {\n this.invalidate();\n // list() would otherwise return an ALREADY in-flight refresh that started before this\n // call (built from pre-invalidation state) — bypassing it too is what makes this\n // actually force a fresh fetch, not just satisfy the cache-freshness check.\n this.refreshInFlight = undefined;\n return this.list();\n }\n\n /** Resolve a symbol or token class key to its registered symbol metadata. */\n public async resolve(ref: TokenRef): Promise<TradingSymbol> {\n let symbols = await this.list();\n const composite =\n typeof ref === 'string'\n ? isCompositeKey(ref)\n ? compositeKeyOf(parseTokenClassKey(ref))\n : undefined\n : compositeKeyOf(ref);\n const resolved = symbols.find(\n (entry) =>\n entry.symbol === ref || (composite !== undefined && compositeKeyOf(entry) === composite),\n );\n if (resolved === undefined) {\n symbols = await this.refresh();\n const refreshed = symbols.find(\n (entry) =>\n entry.symbol === ref || (composite !== undefined && compositeKeyOf(entry) === composite),\n );\n if (refreshed === undefined) throw GSwapSDKError.unknownTokenError(ref);\n return refreshed;\n }\n return resolved;\n }\n\n /**\n * The trading symbol to put in a token's first CreatePool.\n *\n * 1. The symbol ALREADY registered for exactly this class key, if any: proposing another one\n * fails the gateway's registry-conflict check.\n * 2. Otherwise `displaySymbol` (the token's curated symbol), when it is proposable\n * ({@link isProposableTradingSymbol}).\n * 3. Otherwise a `NO_VALID_TRADING_SYMBOL` error: a symbol is never derived from the key (BNB's collection is\n * `GBNB`, a launchpad token's is the reserved word `Token`).\n *\n * `registryFailure: 'ignore'` treats an unreachable registry as an empty one and falls through\n * to step 2 (the gateway still rejects a conflicting symbol); the default `'throw'` propagates\n * the failure.\n *\n * @example\n * ```ts\n * const symbol = await gSwap.symbols.proposeSymbol(\n * { collection: 'GALA_TEST1', category: 'Unit', type: 'none', additionalKey: 'none' },\n * 'GALATEST',\n * );\n * ```\n */\n public async proposeSymbol(\n classKey: GalaChainTokenClassKey,\n displaySymbol: string,\n options: { registryFailure?: 'throw' | 'ignore' | undefined } = {},\n ): Promise<string> {\n let registry: TradingSymbol[] = [];\n try {\n registry = await this.list();\n } catch (error: unknown) {\n if (options.registryFailure !== 'ignore') throw error;\n }\n const wanted = compositeKeyOf(classKey);\n const registered = registry.find(\n (entry) =>\n entry.collection === classKey.collection &&\n entry.category === classKey.category &&\n entry.type === classKey.type &&\n entry.additionalKey === classKey.additionalKey,\n );\n if (registered !== undefined) return registered.symbol;\n if (isProposableTradingSymbol(displaySymbol)) return displaySymbol;\n throw new GSwapSDKError('NO_VALID_TRADING_SYMBOL', { classKey: wanted, displaySymbol });\n }\n\n /** Resolve and put two token references in canonical trading-symbol order. */\n public async orderPair(\n a: TokenRef,\n b: TokenRef,\n ): Promise<{\n token0: TradingSymbol;\n token1: TradingSymbol;\n flipped: boolean;\n }> {\n const [resolvedA, resolvedB] = await Promise.all([this.resolve(a), this.resolve(b)]);\n const [token0Symbol, token1Symbol] = orderSymbols(resolvedA.symbol, resolvedB.symbol);\n return {\n token0: token0Symbol === resolvedA.symbol ? resolvedA : resolvedB,\n token1: token1Symbol === resolvedB.symbol ? resolvedB : resolvedA,\n flipped: token0Symbol !== resolvedA.symbol,\n };\n }\n}\n\n/** Reads one registry row: all four class-key parts, a symbol and non-negative integer decimals. */\nfunction parseTradingSymbol(value: unknown): EntryParse<TradingSymbol> {\n const entry = asEntryRecord(value);\n if (entry === undefined) return entryRejected('the row is not an object');\n const { symbol, collection, category, type, additionalKey, decimals } = entry;\n if (typeof symbol !== 'string') return entryRejected('symbol is not a string');\n if (symbol.length === 0) return entryRejected('symbol is empty');\n if (typeof collection !== 'string') return entryRejected('collection is not a string');\n if (typeof category !== 'string') return entryRejected('category is not a string');\n if (typeof type !== 'string') return entryRejected('type is not a string');\n if (typeof additionalKey !== 'string') return entryRejected('additionalKey is not a string');\n if (typeof decimals !== 'number' || !Number.isInteger(decimals) || decimals < 0) {\n return entryRejected('decimals is not a non-negative integer');\n }\n return entryOk({ symbol, collection, category, type, additionalKey, decimals });\n}\n\nfunction isCompositeKey(ref: string): boolean {\n return ref.includes('|') || ref.includes('$');\n}\n\n/** Alias exported for callers that use the contract's shorter type name. */\nexport type TokenClassKey = GalaChainTokenClassKey;\n\n/**\n * What the services need from a token resolver: how a token reference becomes a trading symbol,\n * and whether requests carry the caller's references untouched. {@link Symbols} is the registry\n * resolver (one `GET /v2/trade/symbols`, cached); {@link CanonicalSymbols} is the offline one.\n */\nexport interface TokenResolver {\n resolve(ref: TokenRef): Promise<TradingSymbol>;\n /**\n * True when reads send the caller's token references verbatim (a symbol, or a composite key as\n * the caller wrote it) and let the backend resolve and orient the pair — no registry request\n * and no client-side ordering or tick flip.\n */\n readonly passthrough?: boolean | undefined;\n}\n\n/** A token reference as the caller wrote it: a string verbatim, a class key as its `$` composite. */\nexport function rawTokenOf(ref: TokenRef): string {\n return typeof ref === 'string' ? ref : compositeKeyOf(ref);\n}\n\n/** The trading symbol of a reference, or `SYMBOL_NOT_FOUND` when the resolver has none. */\nexport async function tradingSymbolOf(resolver: TokenResolver, ref: TokenRef): Promise<string> {\n const resolved = await resolvePreSend(rawTokenOf(ref), () => resolver.resolve(ref));\n if (resolved.symbol.length > 0) return resolved.symbol;\n throw new GSwapSDKError('SYMBOL_NOT_FOUND', { token: rawTokenOf(ref) });\n}\n\n/** What a read request names a token by: the reference itself in pass-through mode, else its symbol. */\nexport async function queryTokenOf(resolver: TokenResolver, ref: TokenRef): Promise<string> {\n return resolver.passthrough === true ? rawTokenOf(ref) : tradingSymbolOf(resolver, ref);\n}\n\n/**\n * The offline resolver for apps that already hold the backend's canonical trading symbols (from\n * `/quote`, `/add-liq-estimate`, a position row) and must not make a registry request of their own.\n *\n * - `resolve` accepts a bare trading symbol and returns it as is; a class key (object, `$` or `|`\n * form) is not a symbol and is refused as `UNKNOWN_TOKEN`. `createPool` relies on that refusal to\n * fall back to the symbols its caller supplies.\n * - `orderPair` orders two symbols by plain string comparison, as the contract does.\n * - Reads are pass-through (see {@link TokenResolver.passthrough}): the caller's references go on\n * the wire verbatim, composite keys included, and the backend orients the pair.\n *\n * @example\n * ```ts\n * const swaps = new Swaps(gateway, new CanonicalSymbols(), signer, walletAddress);\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '10' });\n * ```\n */\nexport class CanonicalSymbols implements TokenResolver {\n public readonly passthrough = true;\n\n /** Resolve a bare trading symbol to itself. */\n public resolve(ref: TokenRef): Promise<TradingSymbol> {\n if (typeof ref === 'string' && !isCompositeKey(ref)) {\n return Promise.resolve({\n symbol: ref,\n collection: '',\n category: '',\n type: '',\n additionalKey: '',\n decimals: 0,\n });\n }\n return Promise.reject(GSwapSDKError.unknownTokenError(ref));\n }\n\n /** Put two symbols in canonical (string) order. */\n public async orderPair(\n a: TokenRef,\n b: TokenRef,\n ): Promise<{ token0: TradingSymbol; token1: TradingSymbol; flipped: boolean }> {\n const [resolvedA, resolvedB] = await Promise.all([this.resolve(a), this.resolve(b)]);\n const [first] = orderSymbols(resolvedA.symbol, resolvedB.symbol);\n const flipped = first !== resolvedA.symbol;\n return {\n token0: flipped ? resolvedB : resolvedA,\n token1: flipped ? resolvedA : resolvedB,\n flipped,\n };\n }\n\n /** There is no registry state to drop. */\n public invalidate(): void {\n // Nothing is cached: every answer is derived from the reference itself.\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"symbols.js","names":[],"sources":["../../../src/classes/symbols.ts"],"sourcesContent":["import type { GalaChainTokenClassKey } from '../types/token.js';\nimport type { TradingSymbol } from '../types/v2_results.js';\nimport type { WireOptions } from '../types/wire.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport type { TokenRef } from '../utils/ordering.js';\nimport { compositeKeyOf } from '../utils/class_key.js';\nimport { orderSymbols, parseTokenClassKey } from '../utils/ordering.js';\nimport { resolvePreSend } from '../utils/pre_send.js';\nimport { isProposableTradingSymbol } from '../utils/validation.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport type { ChainGateway } from './gateway.js';\nimport { HttpClient } from './http_client.js';\n\nconst SYMBOL_CACHE_TTL_MS = 60_000;\n\n/** Symbol registry client for the current GalaChainDex contract. */\nexport class Symbols {\n private cachedSymbols: TradingSymbol[] | undefined;\n private cachedAt = 0;\n private refreshInFlight: Promise<TradingSymbol[]> | undefined;\n\n private readonly http: HttpClient;\n\n /**\n * Create a symbol service backed by the swap backend. `onInvalidEntry` is told about every\n * registry row that was skipped as unusable (see {@link InvalidEntryHandler}).\n */\n constructor(\n private readonly gateway: Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n },\n private readonly options: { onInvalidEntry?: InvalidEntryHandler | undefined } = {},\n ) {\n this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs, gateway.wire);\n }\n\n /**\n * List all registered GalaChainDex trading symbols, cached for 60 seconds. A registry row that\n * is not a usable symbol is skipped (and reported to `onInvalidEntry`) instead of failing the\n * whole list.\n */\n public async list(): Promise<TradingSymbol[]> {\n if (this.cachedSymbols !== undefined && Date.now() - this.cachedAt < SYMBOL_CACHE_TTL_MS) {\n return this.cachedSymbols;\n }\n if (this.refreshInFlight !== undefined) return this.refreshInFlight;\n this.refreshInFlight = this.http\n .sendGetRequest<{ data: unknown }>(this.gateway.dexBackendBaseUrl, '/v2/trade', '/symbols')\n .then((response) =>\n readEntries('symbols', response.data, parseTradingSymbol, this.options.onInvalidEntry),\n )\n .then((symbols) => {\n this.cachedSymbols = symbols;\n this.cachedAt = Date.now();\n return symbols;\n })\n .finally(() => {\n this.refreshInFlight = undefined;\n });\n return this.refreshInFlight;\n }\n\n /** Invalidate the cached symbol registry after a write changes registration state.\n *\n * @example\n * ```ts\n * gSwap.symbols.invalidate();\n * ```\n */\n public invalidate(): void {\n this.cachedSymbols = undefined;\n this.cachedAt = 0;\n }\n\n /** Force one registry refresh, bypassing the cache.\n *\n * @example\n * ```ts\n * const symbols = await gSwap.symbols.refresh();\n * ```\n */\n public async refresh(): Promise<TradingSymbol[]> {\n this.invalidate();\n // list() would otherwise return an ALREADY in-flight refresh that started before this\n // call (built from pre-invalidation state) — bypassing it too is what makes this\n // actually force a fresh fetch, not just satisfy the cache-freshness check.\n this.refreshInFlight = undefined;\n return this.list();\n }\n\n /** Resolve a symbol or token class key to its registered symbol metadata. */\n public async resolve(ref: TokenRef): Promise<TradingSymbol> {\n let symbols = await this.list();\n const composite =\n typeof ref === 'string'\n ? isCompositeKey(ref)\n ? compositeKeyOf(parseTokenClassKey(ref))\n : undefined\n : compositeKeyOf(ref);\n const resolved = symbols.find(\n (entry) =>\n entry.symbol === ref || (composite !== undefined && compositeKeyOf(entry) === composite),\n );\n if (resolved === undefined) {\n symbols = await this.refresh();\n const refreshed = symbols.find(\n (entry) =>\n entry.symbol === ref || (composite !== undefined && compositeKeyOf(entry) === composite),\n );\n if (refreshed === undefined) throw GSwapSDKError.unknownTokenError(ref);\n return refreshed;\n }\n return resolved;\n }\n\n /**\n * The trading symbol to put in a token's first CreatePool.\n *\n * 1. The symbol ALREADY registered for exactly this class key, if any: proposing another one\n * fails the gateway's registry-conflict check.\n * 2. Otherwise `displaySymbol` (the token's curated symbol), when it is proposable\n * ({@link isProposableTradingSymbol}).\n * 3. Otherwise a `NO_VALID_TRADING_SYMBOL` error: a symbol is never derived from the key (BNB's collection is\n * `GBNB`, a launchpad token's is the reserved word `Token`).\n *\n * `registryFailure: 'ignore'` treats an unreachable registry as an empty one and falls through\n * to step 2 (the gateway still rejects a conflicting symbol); the default `'throw'` propagates\n * the failure.\n *\n * @example\n * ```ts\n * const symbol = await gSwap.symbols.proposeSymbol(\n * { collection: 'GALA_TEST1', category: 'Unit', type: 'none', additionalKey: 'none' },\n * 'GALATEST',\n * );\n * ```\n */\n public async proposeSymbol(\n classKey: GalaChainTokenClassKey,\n displaySymbol: string,\n options: { registryFailure?: 'throw' | 'ignore' | undefined } = {},\n ): Promise<string> {\n let registry: TradingSymbol[] = [];\n try {\n registry = await this.list();\n } catch (error: unknown) {\n if (options.registryFailure !== 'ignore') throw error;\n }\n const wanted = compositeKeyOf(classKey);\n const registered = registry.find(\n (entry) =>\n entry.collection === classKey.collection &&\n entry.category === classKey.category &&\n entry.type === classKey.type &&\n entry.additionalKey === classKey.additionalKey,\n );\n if (registered !== undefined) return registered.symbol;\n if (isProposableTradingSymbol(displaySymbol)) return displaySymbol;\n throw new GSwapSDKError('NO_VALID_TRADING_SYMBOL', { classKey: wanted, displaySymbol });\n }\n\n /** Resolve and put two token references in canonical trading-symbol order. */\n public async orderPair(\n a: TokenRef,\n b: TokenRef,\n ): Promise<{\n token0: TradingSymbol;\n token1: TradingSymbol;\n flipped: boolean;\n }> {\n const [resolvedA, resolvedB] = await Promise.all([this.resolve(a), this.resolve(b)]);\n const [token0Symbol, token1Symbol] = orderSymbols(resolvedA.symbol, resolvedB.symbol);\n return {\n token0: token0Symbol === resolvedA.symbol ? resolvedA : resolvedB,\n token1: token1Symbol === resolvedB.symbol ? resolvedB : resolvedA,\n flipped: token0Symbol !== resolvedA.symbol,\n };\n }\n}\n\n/** Reads one registry row: all four class-key parts, a symbol and non-negative integer decimals. */\nfunction parseTradingSymbol(value: unknown): EntryParse<TradingSymbol> {\n const entry = asEntryRecord(value);\n if (entry === undefined) return entryRejected('the row is not an object');\n const { symbol, collection, category, type, additionalKey, decimals } = entry;\n if (typeof symbol !== 'string') return entryRejected('symbol is not a string');\n if (symbol.length === 0) return entryRejected('symbol is empty');\n if (typeof collection !== 'string') return entryRejected('collection is not a string');\n if (typeof category !== 'string') return entryRejected('category is not a string');\n if (typeof type !== 'string') return entryRejected('type is not a string');\n if (typeof additionalKey !== 'string') return entryRejected('additionalKey is not a string');\n if (typeof decimals !== 'number' || !Number.isInteger(decimals) || decimals < 0) {\n return entryRejected('decimals is not a non-negative integer');\n }\n return entryOk({ symbol, collection, category, type, additionalKey, decimals });\n}\n\nfunction isCompositeKey(ref: string): boolean {\n return ref.includes('|') || ref.includes('$');\n}\n\n/** Alias exported for callers that use the contract's shorter type name. */\nexport type TokenClassKey = GalaChainTokenClassKey;\n\n/**\n * What the services need from a token resolver: how a token reference becomes a trading symbol,\n * and whether requests carry the caller's references untouched. {@link Symbols} is the registry\n * resolver (one `GET /v2/trade/symbols`, cached); {@link CanonicalSymbols} is the offline one.\n */\nexport interface TokenResolver {\n resolve(ref: TokenRef): Promise<TradingSymbol>;\n /**\n * True when reads send the caller's token references verbatim (a symbol, or a composite key as\n * the caller wrote it) and let the backend resolve and orient the pair — no registry request\n * and no client-side ordering or tick flip.\n */\n readonly passthrough?: boolean | undefined;\n}\n\n/** A token reference as the caller wrote it: a string verbatim, a class key as its `$` composite. */\nexport function rawTokenOf(ref: TokenRef): string {\n return typeof ref === 'string' ? ref : compositeKeyOf(ref);\n}\n\n/** The trading symbol of a reference, or `SYMBOL_NOT_FOUND` when the resolver has none. */\nexport async function tradingSymbolOf(resolver: TokenResolver, ref: TokenRef): Promise<string> {\n const resolved = await resolvePreSend(rawTokenOf(ref), () => resolver.resolve(ref));\n if (resolved.symbol.length > 0) return resolved.symbol;\n throw new GSwapSDKError('SYMBOL_NOT_FOUND', { token: rawTokenOf(ref) });\n}\n\n/** What a read request names a token by: the reference itself in pass-through mode, else its symbol. */\nexport async function queryTokenOf(resolver: TokenResolver, ref: TokenRef): Promise<string> {\n return resolver.passthrough === true ? rawTokenOf(ref) : tradingSymbolOf(resolver, ref);\n}\n\n/**\n * The offline resolver for apps that already hold the backend's canonical trading symbols (from\n * `/quote`, `/add-liq-estimate`, a position row) and must not make a registry request of their own.\n *\n * - `resolve` accepts a bare trading symbol and returns it as is; a class key (object, `$` or `|`\n * form) is not a symbol and is refused as `UNKNOWN_TOKEN`. `createPool` relies on that refusal to\n * fall back to the symbols its caller supplies.\n * - `orderPair` orders two symbols by plain string comparison, as the contract does.\n * - Reads are pass-through (see {@link TokenResolver.passthrough}): the caller's references go on\n * the wire verbatim, composite keys included, and the backend orients the pair.\n *\n * @example\n * ```ts\n * const swaps = new Swaps(gateway, new CanonicalSymbols(), signer, walletAddress);\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '10' });\n * ```\n */\nexport class CanonicalSymbols implements TokenResolver {\n public readonly passthrough = true;\n\n /** Resolve a bare trading symbol to itself. */\n public resolve(ref: TokenRef): Promise<TradingSymbol> {\n if (typeof ref === 'string' && !isCompositeKey(ref)) {\n return Promise.resolve({\n symbol: ref,\n collection: '',\n category: '',\n type: '',\n additionalKey: '',\n decimals: 0,\n });\n }\n return Promise.reject(GSwapSDKError.unknownTokenError(ref));\n }\n\n /** Put two symbols in canonical (string) order. */\n public async orderPair(\n a: TokenRef,\n b: TokenRef,\n ): Promise<{ token0: TradingSymbol; token1: TradingSymbol; flipped: boolean }> {\n const [resolvedA, resolvedB] = await Promise.all([this.resolve(a), this.resolve(b)]);\n const [first] = orderSymbols(resolvedA.symbol, resolvedB.symbol);\n const flipped = first !== resolvedA.symbol;\n return {\n token0: flipped ? resolvedB : resolvedA,\n token1: flipped ? resolvedA : resolvedB,\n flipped,\n };\n }\n\n /** There is no registry state to drop. */\n public invalidate(): void {\n // Nothing is cached: every answer is derived from the reference itself.\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- import{isValidUniqueKey as e}from"./utils/unique_key_syntax.js";import{isGSwapErrorLike as t}from"./utils/error_brand.js";import{GSWAP_ERROR_PHASES as n}from"./classes/error_phases.js";import{FAILURE_OUTCOMES as r}from"./utils/failure_outcomes.js";import{isWriteView as i,toFailureView as a}from"./utils/failure_view.js";import{GSWAP_ERROR_PHASE_BY_CODE as o}from"./classes/error_phase_table.js";import{GSWAP_ERROR_CATALOG as s,INVALID_PRIVATE_KEY_REASONS as c,SIGNING_FAILURE_REASONS as l,SUBMISSION_OUTCOME_UNKNOWN_REASONS as u,gswapErrorTemplates as d,renderGSwapErrorTemplate as f}from"./classes/error_catalog.js";import{GSwapSDKError as p,UPDATE_REQUIRED_STATUS as m,getObjectProperty as h,getStringProperty as g,isGSwapError as _,isPreSendError as v,parseJson as y}from"./classes/gswap_sdk_error.js";import{AppliedTradeError as b,confirmAppliedTrade as x}from"./classes/apply_results.js";import{ALL_FEE_TIERS as S,FEE_TIER as C,TICK_SPACING_BY_FEE as w}from"./types/fees.js";import{GC_MAX_TICK as T,GC_MIN_TICK as E,alignTickDown as D,alignTickUp as O,assertTickRange as k,frameSlot0 as A,sqrtPriceToTick as j,tickFromPrice as M,tickToPrice as N,tickToSqrtPrice as P}from"./utils/ticks.js";import{assertCanonicalPair as F,isProposableTradingSymbol as I,validateFee as L,validateNumericAmount as R,validatePriceValues as z,validateTickRange as B,validateTickSpacing as V,validateTokenDecimals as H,validateWalletAddress as U}from"./utils/validation.js";import{Assets as W}from"./classes/assets.js";import{isWalletUserRejection as G,walletDeclineCode as K}from"./utils/wallet_rejection.js";import{DEX_FEE_METHODS as q,DRY_RUN_METHOD as J,DRY_RUN_UNIQUE_KEY_PREFIX as Y,DexFees as X,buildDryRunWrapper as Z,isCurrentContractDexMessage as Q,isDexFeeMethod as $,toChainDto as ee}from"./classes/dex_fees.js";import{isShadowError as te}from"./utils/shadow_errors.js";import{SubmittedTransaction as ne}from"./classes/submitted_transaction.js";import{ChainGateway as re}from"./classes/gateway.js";import{GSWAP_ENVIRONMENTS as ie}from"./types/env.js";import{GdexStreamError as ae,GdexStreamService as oe,isGdexLiquidityEvent as se}from"./classes/gdex_stream.js";import{compositeKeyOf as ce,orderSymbols as le,parseTokenClassKey as ue,readOrderedSymbols as de,tryParseCompositeKey as fe,tryParseTokenClassKey as pe}from"./utils/ordering.js";import{CanonicalSymbols as me,Symbols as he,queryTokenOf as ge,rawTokenOf as _e,tradingSymbolOf as ve}from"./classes/symbols.js";import{Pools as ye}from"./classes/pools.js";import{DEFAULT_UNIQUE_KEY_PREFIX as be,assertUniqueKey as xe,createUniqueKey as Se,resolveUniqueKeyPrefix as Ce}from"./utils/unique_key.js";import{assertCanonicalV2Dto as we,buildAddLiquidityDto as Te,buildCollectPositionFeesDto as Ee,buildCreatePoolDto as De,buildRemoveLiquidityDto as Oe,buildRequestTradeDto as ke}from"./utils/dto_builders.js";import{Positions as Ae}from"./classes/positions.js";import{Quoting as je}from"./classes/quoting.js";import{SHADOW_FAILURE_KINDS as Me,SHADOW_SUBMIT_CODES as Ne,classifyShadowSubmitError as Pe,classifyShadowSubmitStatus as Fe,readShadowSubmitOutcome as Ie}from"./classes/shadow_submit.js";import{Swaps as Le,swapRouteFromQuote as Re}from"./classes/swaps.js";import{GSwap as ze}from"./classes/gswap.js";import{NOT_QUEUED_FINAL as Be,classification as Ve,classifyFailure as He,isNoMarket as Ue,isRelayableRefusal as We,isUninterpretedAnswer as Ge,isUniqueKeyConsumed as Ke,isUnprovenAcknowledgement as qe,mayHaveBeenQueued as Je,notSentClassification as Ye}from"./utils/failure_classification.js";import{PENDING_SWAPS_STORAGE_KEY as Xe,PENDING_SWAP_EXPIRY_MS as Ze,PENDING_SWAP_FATES as Qe,PENDING_SWAP_PRUNE_REASONS as $e,PendingSwapStore as et,pendingSwapFateFor as tt,pendingSwapFateOfOutcome as nt,storageAdapterFromChromeStorage as rt}from"./classes/pending_swaps.js";import{EIP712_CAPABLE_METHODS as it,buildEIP712Payload as at,eip712DomainFor as ot,generateEIP712Types as st}from"./utils/eip712.js";import{calculatePersonalSignPrefix as ct,ethAddressOfPrivateKey as lt,fixpointPrefixFor as ut,getPayloadToSign as dt,normalizePrivateKey as ft,personalSignPrefixFor as pt,serialize as mt,signNative as ht,signPersonalMessage as gt,signSerializedNative as _t}from"./utils/signing.js";import{BrowserWalletSigner as vt,GalaWalletSigner as yt,PrivateKeySigner as bt,createLazyPrivateKeySigner as xt,ethereumAddressOfAccount as St}from"./classes/signers.js";import{canonicalDecimalString as Ct,resolvePersonalSignChainDtoPayload as wt,signChainDtoHash as Tt,signChainDtoNative as Et,signChainDtoPersonalSign as Dt,signRawObject as Ot,stripEip712DomainType as kt,tokenClassDollarKey as At,withPrivateKey as jt}from"./utils/chain_dto_signing.js";import{hashTypedData as Mt,signTypedDataPayload as Nt}from"./utils/typed_data.js";import{httpRequestorFromAxios as Pt}from"./utils/axios_requestor.js";import{eip1193ProviderFromEthers as Ft}from"./utils/ethers_provider.js";import{confirmationStateOf as It,isConfirmationAborted as Lt,isConfirmationTimeout as Rt}from"./utils/confirmation_state.js";import{isFetchTransportFailure as zt}from"./utils/fetch_failure.js";import{classifySubmitEnvelope as Bt,isSubmitExecuted as Vt,isSubmitQueued as Ht,isSubmitRejected as Ut}from"./utils/submit_state.js";export{S as ALL_FEE_TIERS,b as AppliedTradeError,W as Assets,vt as BrowserWalletSigner,me as CanonicalSymbols,re as ChainGateway,be as DEFAULT_UNIQUE_KEY_PREFIX,q as DEX_FEE_METHODS,J as DRY_RUN_METHOD,Y as DRY_RUN_UNIQUE_KEY_PREFIX,X as DexFees,it as EIP712_CAPABLE_METHODS,r as FAILURE_OUTCOMES,C as FEE_TIER,T as GC_MAX_TICK,E as GC_MIN_TICK,ie as GSWAP_ENVIRONMENTS,s as GSWAP_ERROR_CATALOG,n as GSWAP_ERROR_PHASES,o as GSWAP_ERROR_PHASE_BY_CODE,ze as GSwap,p as GSwapSDKError,yt as GalaWalletSigner,ae as GdexStreamError,oe as GdexStreamService,c as INVALID_PRIVATE_KEY_REASONS,Be as NOT_QUEUED_FINAL,Xe as PENDING_SWAPS_STORAGE_KEY,Ze as PENDING_SWAP_EXPIRY_MS,Qe as PENDING_SWAP_FATES,$e as PENDING_SWAP_PRUNE_REASONS,et as PendingSwapStore,ye as Pools,Ae as Positions,bt as PrivateKeySigner,je as Quoting,Me as SHADOW_FAILURE_KINDS,Ne as SHADOW_SUBMIT_CODES,l as SIGNING_FAILURE_REASONS,u as SUBMISSION_OUTCOME_UNKNOWN_REASONS,ne as SubmittedTransaction,Le as Swaps,he as Symbols,w as TICK_SPACING_BY_FEE,m as UPDATE_REQUIRED_STATUS,D as alignTickDown,O as alignTickUp,F as assertCanonicalPair,we as assertCanonicalV2Dto,k as assertTickRange,xe as assertUniqueKey,Te as buildAddLiquidityDto,Ee as buildCollectPositionFeesDto,De as buildCreatePoolDto,Z as buildDryRunWrapper,at as buildEIP712Payload,Oe as buildRemoveLiquidityDto,ke as buildRequestTradeDto,ct as calculatePersonalSignPrefix,Ct as canonicalDecimalString,Ve as classification,He as classifyFailure,Pe as classifyShadowSubmitError,Fe as classifyShadowSubmitStatus,Bt as classifySubmitEnvelope,ce as compositeKeyOf,x as confirmAppliedTrade,It as confirmationStateOf,xt as createLazyPrivateKeySigner,Se as createUniqueKey,Ft as eip1193ProviderFromEthers,ot as eip712DomainFor,lt as ethAddressOfPrivateKey,St as ethereumAddressOfAccount,ut as fixpointPrefixFor,A as frameSlot0,st as generateEIP712Types,h as getObjectProperty,dt as getPayloadToSign,g as getStringProperty,d as gswapErrorTemplates,Mt as hashTypedData,Pt as httpRequestorFromAxios,Lt as isConfirmationAborted,Rt as isConfirmationTimeout,Q as isCurrentContractDexMessage,$ as isDexFeeMethod,zt as isFetchTransportFailure,_ as isGSwapError,t as isGSwapErrorLike,se as isGdexLiquidityEvent,Ue as isNoMarket,v as isPreSendError,I as isProposableTradingSymbol,We as isRelayableRefusal,te as isShadowError,Vt as isSubmitExecuted,Ht as isSubmitQueued,Ut as isSubmitRejected,Ge as isUninterpretedAnswer,Ke as isUniqueKeyConsumed,qe as isUnprovenAcknowledgement,e as isValidUniqueKey,G as isWalletUserRejection,i as isWriteView,Je as mayHaveBeenQueued,ft as normalizePrivateKey,Ye as notSentClassification,le as orderSymbols,y as parseJson,ue as parseTokenClassKey,tt as pendingSwapFateFor,nt as pendingSwapFateOfOutcome,pt as personalSignPrefixFor,ge as queryTokenOf,_e as rawTokenOf,de as readOrderedSymbols,Ie as readShadowSubmitOutcome,f as renderGSwapErrorTemplate,wt as resolvePersonalSignChainDtoPayload,Ce as resolveUniqueKeyPrefix,mt as serialize,Tt as signChainDtoHash,Et as signChainDtoNative,Dt as signChainDtoPersonalSign,ht as signNative,gt as signPersonalMessage,Ot as signRawObject,_t as signSerializedNative,Nt as signTypedDataPayload,j as sqrtPriceToTick,rt as storageAdapterFromChromeStorage,kt as stripEip712DomainType,Re as swapRouteFromQuote,M as tickFromPrice,N as tickToPrice,P as tickToSqrtPrice,ee as toChainDto,a as toFailureView,At as tokenClassDollarKey,ve as tradingSymbolOf,fe as tryParseCompositeKey,pe as tryParseTokenClassKey,L as validateFee,R as validateNumericAmount,z as validatePriceValues,B as validateTickRange,V as validateTickSpacing,H as validateTokenDecimals,U as validateWalletAddress,K as walletDeclineCode,jt as withPrivateKey};
1
+ import{isValidUniqueKey as e}from"./utils/unique_key_syntax.js";import{isGSwapErrorLike as t}from"./utils/error_brand.js";import{GSWAP_ERROR_PHASES as n}from"./classes/error_phases.js";import{FAILURE_OUTCOMES as r}from"./utils/failure_outcomes.js";import{isWriteView as i,toFailureView as a}from"./utils/failure_view.js";import{GSWAP_ERROR_PHASE_BY_CODE as o}from"./classes/error_phase_table.js";import{GSWAP_ERROR_CATALOG as s,INVALID_PRIVATE_KEY_REASONS as c,SIGNING_FAILURE_REASONS as l,SUBMISSION_OUTCOME_UNKNOWN_REASONS as u,gswapErrorTemplates as d,renderGSwapErrorTemplate as f}from"./classes/error_catalog.js";import{GSwapSDKError as p,UPDATE_REQUIRED_STATUS as m,getObjectProperty as h,getStringProperty as g,isGSwapError as _,isPreSendError as v,parseJson as y}from"./classes/gswap_sdk_error.js";import{AppliedTradeError as b,confirmAppliedTrade as x}from"./classes/apply_results.js";import{ALL_FEE_TIERS as S,FEE_TIER as C,TICK_SPACING_BY_FEE as w}from"./types/fees.js";import{isTickInRange as T}from"./utils/tick_range.js";import{GC_MAX_TICK as E,GC_MIN_TICK as D,isSqrtPriceInRange as O,sqrtPriceToTick as k,tickFromPrice as A,tickToPrice as j,tickToSqrtPrice as M}from"./utils/tick_math.js";import{assertCanonicalPair as N,isProposableTradingSymbol as P,validateFee as F,validateNumericAmount as I,validatePriceValues as L,validateTickRange as R,validateTickSpacing as z,validateTokenDecimals as B,validateWalletAddress as V}from"./utils/validation.js";import{Assets as H}from"./classes/assets.js";import{isWalletUserRejection as U,walletDeclineCode as W}from"./utils/wallet_rejection.js";import{DEX_FEE_METHODS as G,DRY_RUN_METHOD as K,DRY_RUN_UNIQUE_KEY_PREFIX as q,DexFees as J,buildDryRunWrapper as Y,isCurrentContractDexMessage as X,isDexFeeMethod as Z,toChainDto as Q}from"./classes/dex_fees.js";import{isShadowError as $}from"./utils/shadow_errors.js";import{SubmittedTransaction as ee}from"./classes/submitted_transaction.js";import{ChainGateway as te}from"./classes/gateway.js";import{GSWAP_ENVIRONMENTS as ne}from"./types/env.js";import{GdexStreamError as re,GdexStreamService as ie,isGdexLiquidityEvent as ae}from"./classes/gdex_stream.js";import{compositeKeyOf as oe,tryParseCompositeKey as se,tryParseTokenClassKey as ce}from"./utils/class_key.js";import{orderSymbols as le,parseTokenClassKey as ue,readOrderedSymbols as de}from"./utils/ordering.js";import{CanonicalSymbols as fe,Symbols as pe,queryTokenOf as me,rawTokenOf as he,tradingSymbolOf as ge}from"./classes/symbols.js";import{Pools as _e}from"./classes/pools.js";import{alignTickDownOrNaN as ve,alignTickUpOrNaN as ye}from"./utils/tick_align.js";import{alignTickDown as be,alignTickUp as xe,assertTickRange as Se,frameSlot0 as Ce}from"./utils/ticks.js";import{DEFAULT_UNIQUE_KEY_PREFIX as we,assertUniqueKey as Te,createUniqueKey as Ee,resolveUniqueKeyPrefix as De}from"./utils/unique_key.js";import{assertCanonicalV2Dto as Oe,buildAddLiquidityDto as ke,buildCollectPositionFeesDto as Ae,buildCreatePoolDto as je,buildRemoveLiquidityDto as Me,buildRequestTradeDto as Ne}from"./utils/dto_builders.js";import{Positions as Pe}from"./classes/positions.js";import{Quoting as Fe}from"./classes/quoting.js";import{SHADOW_FAILURE_KINDS as Ie,SHADOW_SUBMIT_CODES as Le,classifyShadowSubmitError as Re,classifyShadowSubmitStatus as ze,readShadowSubmitOutcome as Be}from"./classes/shadow_submit.js";import{Swaps as Ve,swapRouteFromQuote as He}from"./classes/swaps.js";import{GSwap as Ue}from"./classes/gswap.js";import{NOT_QUEUED_FINAL as We,classification as Ge,notSentClassification as Ke}from"./utils/classification.js";import{classifyFailure as qe,mayHaveBeenQueued as Je}from"./utils/failure_classification.js";import{PENDING_SWAP_FATES as Ye,pendingSwapFateFor as Xe,pendingSwapFateOfOutcome as Ze}from"./classes/pending_swap_fate.js";import{PENDING_SWAPS_STORAGE_KEY as Qe,PENDING_SWAP_EXPIRY_MS as $e,PENDING_SWAP_PRUNE_REASONS as et,PendingSwapStore as tt}from"./classes/pending_swaps.js";import{EIP712_CAPABLE_METHODS as nt,buildEIP712Payload as rt,eip712DomainFor as it,generateEIP712Types as at}from"./utils/eip712.js";import{calculatePersonalSignPrefix as ot,ethAddressOfPrivateKey as st,fixpointPrefixFor as ct,getPayloadToSign as lt,normalizePrivateKey as ut,personalSignPrefixFor as dt,serialize as ft,signNative as pt,signPersonalMessage as mt,signSerializedNative as ht}from"./utils/signing.js";import{BrowserWalletSigner as gt,GalaWalletSigner as _t,PrivateKeySigner as vt,createLazyPrivateKeySigner as yt,ethereumAddressOfAccount as bt}from"./classes/signers.js";import{storageAdapterFromChromeStorage as xt,webStorageAdapter as St}from"./classes/storage_adapters.js";import{canonicalDecimalString as Ct,resolvePersonalSignChainDtoPayload as wt,signChainDtoHash as Tt,signChainDtoNative as Et,signChainDtoPersonalSign as Dt,signRawObject as Ot,stripEip712DomainType as kt,tokenClassDollarKey as At,withPrivateKey as jt}from"./utils/chain_dto_signing.js";import{hashTypedData as Mt,signTypedDataPayload as Nt}from"./utils/typed_data.js";import{httpRequestorFromAxios as Pt}from"./utils/axios_requestor.js";import{eip1193ProviderFromEthers as Ft}from"./utils/ethers_provider.js";import{confirmationStateOf as It,isConfirmationAborted as Lt,isConfirmationTimeout as Rt}from"./utils/confirmation_state.js";import{isFetchTransportFailure as zt}from"./utils/fetch_failure.js";import{chainErrorKeyOf as Bt,isNoMarket as Vt,isRelayableRefusal as Ht,isUninterpretedAnswer as Ut,isUniqueKeyConsumed as Wt,isUnprovenAcknowledgement as Gt}from"./utils/failure_guards.js";import{classifySubmitEnvelope as Kt,isSubmitExecuted as qt,isSubmitQueued as Jt,isSubmitRejected as Yt}from"./utils/submit_state.js";export{S as ALL_FEE_TIERS,b as AppliedTradeError,H as Assets,gt as BrowserWalletSigner,fe as CanonicalSymbols,te as ChainGateway,we as DEFAULT_UNIQUE_KEY_PREFIX,G as DEX_FEE_METHODS,K as DRY_RUN_METHOD,q as DRY_RUN_UNIQUE_KEY_PREFIX,J as DexFees,nt as EIP712_CAPABLE_METHODS,r as FAILURE_OUTCOMES,C as FEE_TIER,E as GC_MAX_TICK,D as GC_MIN_TICK,ne as GSWAP_ENVIRONMENTS,s as GSWAP_ERROR_CATALOG,n as GSWAP_ERROR_PHASES,o as GSWAP_ERROR_PHASE_BY_CODE,Ue as GSwap,p as GSwapSDKError,_t as GalaWalletSigner,re as GdexStreamError,ie as GdexStreamService,c as INVALID_PRIVATE_KEY_REASONS,We as NOT_QUEUED_FINAL,Qe as PENDING_SWAPS_STORAGE_KEY,$e as PENDING_SWAP_EXPIRY_MS,Ye as PENDING_SWAP_FATES,et as PENDING_SWAP_PRUNE_REASONS,tt as PendingSwapStore,_e as Pools,Pe as Positions,vt as PrivateKeySigner,Fe as Quoting,Ie as SHADOW_FAILURE_KINDS,Le as SHADOW_SUBMIT_CODES,l as SIGNING_FAILURE_REASONS,u as SUBMISSION_OUTCOME_UNKNOWN_REASONS,ee as SubmittedTransaction,Ve as Swaps,pe as Symbols,w as TICK_SPACING_BY_FEE,m as UPDATE_REQUIRED_STATUS,be as alignTickDown,ve as alignTickDownOrNaN,xe as alignTickUp,ye as alignTickUpOrNaN,N as assertCanonicalPair,Oe as assertCanonicalV2Dto,Se as assertTickRange,Te as assertUniqueKey,ke as buildAddLiquidityDto,Ae as buildCollectPositionFeesDto,je as buildCreatePoolDto,Y as buildDryRunWrapper,rt as buildEIP712Payload,Me as buildRemoveLiquidityDto,Ne as buildRequestTradeDto,ot as calculatePersonalSignPrefix,Ct as canonicalDecimalString,Bt as chainErrorKeyOf,Ge as classification,qe as classifyFailure,Re as classifyShadowSubmitError,ze as classifyShadowSubmitStatus,Kt as classifySubmitEnvelope,oe as compositeKeyOf,x as confirmAppliedTrade,It as confirmationStateOf,yt as createLazyPrivateKeySigner,Ee as createUniqueKey,Ft as eip1193ProviderFromEthers,it as eip712DomainFor,st as ethAddressOfPrivateKey,bt as ethereumAddressOfAccount,ct as fixpointPrefixFor,Ce as frameSlot0,at as generateEIP712Types,h as getObjectProperty,lt as getPayloadToSign,g as getStringProperty,d as gswapErrorTemplates,Mt as hashTypedData,Pt as httpRequestorFromAxios,Lt as isConfirmationAborted,Rt as isConfirmationTimeout,X as isCurrentContractDexMessage,Z as isDexFeeMethod,zt as isFetchTransportFailure,_ as isGSwapError,t as isGSwapErrorLike,ae as isGdexLiquidityEvent,Vt as isNoMarket,v as isPreSendError,P as isProposableTradingSymbol,Ht as isRelayableRefusal,$ as isShadowError,O as isSqrtPriceInRange,qt as isSubmitExecuted,Jt as isSubmitQueued,Yt as isSubmitRejected,T as isTickInRange,Ut as isUninterpretedAnswer,Wt as isUniqueKeyConsumed,Gt as isUnprovenAcknowledgement,e as isValidUniqueKey,U as isWalletUserRejection,i as isWriteView,Je as mayHaveBeenQueued,ut as normalizePrivateKey,Ke as notSentClassification,le as orderSymbols,y as parseJson,ue as parseTokenClassKey,Xe as pendingSwapFateFor,Ze as pendingSwapFateOfOutcome,dt as personalSignPrefixFor,me as queryTokenOf,he as rawTokenOf,de as readOrderedSymbols,Be as readShadowSubmitOutcome,f as renderGSwapErrorTemplate,wt as resolvePersonalSignChainDtoPayload,De as resolveUniqueKeyPrefix,ft as serialize,Tt as signChainDtoHash,Et as signChainDtoNative,Dt as signChainDtoPersonalSign,pt as signNative,mt as signPersonalMessage,Ot as signRawObject,ht as signSerializedNative,Nt as signTypedDataPayload,k as sqrtPriceToTick,xt as storageAdapterFromChromeStorage,kt as stripEip712DomainType,He as swapRouteFromQuote,A as tickFromPrice,j as tickToPrice,M as tickToSqrtPrice,Q as toChainDto,a as toFailureView,At as tokenClassDollarKey,ge as tradingSymbolOf,se as tryParseCompositeKey,ce as tryParseTokenClassKey,F as validateFee,I as validateNumericAmount,L as validatePriceValues,R as validateTickRange,z as validateTickSpacing,B as validateTokenDecimals,V as validateWalletAddress,W as walletDeclineCode,St as webStorageAdapter,jt as withPrivateKey};
@@ -1 +1 @@
1
- {"version":3,"file":"chain_dto_signing.js","names":[],"sources":["../../../src/utils/chain_dto_signing.ts"],"sourcesContent":["/**\n * String-key signing entry points for apps that hold a private key only briefly (the Gala Wallet\n * extension reads its session key at sign time and must not keep it in a long-lived object).\n *\n * These are thin, byte-exact ports of the functions the wallet shipped in\n * `wallet_extension/src/helpers/wallet/signing.ts` (including the fail-closed personal-sign\n * payload resolver from its commit 3ad7ae6), re-expressed over the SDK's own primitives. Every\n * function takes the key as a string (`0x`-optional hex, or base64) or as bytes, normalizes it per\n * call, and zeroes the normalized copy before returning, so nothing in this module retains a key.\n * A JavaScript string cannot be wiped; the caller owns the lifetime of the string it passes in.\n */\nimport BigNumber from 'bignumber.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport {\n normalizePrivateKey,\n serialize,\n signPersonalMessage,\n signSerializedNative,\n} from './signing.js';\n\n/** A secp256k1 private key as a hex/base64 string or as raw 32 bytes. */\nexport type PrivateKeyInput = string | Uint8Array;\n\n/**\n * Runs `action` with a private normalized copy of the key, zeroed afterwards (also when `action`\n * throws). Bytes given by the caller are copied, never modified: the caller owns them.\n */\nexport function withPrivateKey<T>(privateKey: PrivateKeyInput, action: (key: Uint8Array) => T): T {\n const key = normalizePrivateKey(privateKey);\n try {\n return action(key);\n } finally {\n key.fill(0);\n }\n}\n\n/**\n * GalaChain NATIVE signature over an already-serialized DTO: keccak256 of the exact bytes with no\n * prefix and no envelope (wallet `signChainDtoNative`). The caller owns serialization, so the\n * bytes a user reviewed and the bytes signed cannot diverge.\n *\n * @returns 130 lowercase hex characters, `r || s || v` with `v` = `1b`/`1c`, no `0x`.\n */\nexport function signChainDtoNative(privateKey: PrivateKeyInput, serializedDto: string): string {\n return withPrivateKey(privateKey, (key) => signSerializedNative(key, serializedDto));\n}\n\n/**\n * The personal-sign hash primitive (wallet `signChainDtoHash`): keccak256(`prefix` + `message`),\n * both verbatim, with no further EIP-191 wrap. `message` must be the DTO's serialization WITHOUT\n * its `prefix` field; callers holding a dApp-supplied string go through `signChainDtoPersonalSign`,\n * which derives both inputs from it.\n */\nexport function signChainDtoHash(\n privateKey: PrivateKeyInput,\n prefix: string,\n message: string,\n): string {\n return withPrivateKey(privateKey, (key) => signPersonalMessage(key, prefix, message));\n}\n\nconst PERSONAL_SIGN_HEADER = String.fromCharCode(0x19) + 'Ethereum Signed Message:\\n';\nconst PERSONAL_SIGN_LENGTH_PATTERN = /^(?:0|[1-9][0-9]*)$/u;\n\n// A header with a body starting `{` can never collide with another EIP-191 message's hash, and\n// anything that is not a header (arbitrary bytes the user cannot see on an approval card) is\n// refused. The number is NOT required to equal the byte length: the chain hashes whatever prefix\n// the submitted DTO carries, and defi-backend's bouncer rejects a mismatched header loudly.\nfunction isPersonalSignHeader(prefix: string): boolean {\n return (\n prefix.startsWith(PERSONAL_SIGN_HEADER) &&\n PERSONAL_SIGN_LENGTH_PATTERN.test(prefix.slice(PERSONAL_SIGN_HEADER.length))\n );\n}\n\n/**\n * Top-level fields that would make the chain (`getPayloadToSign`) or defi-backend's personal-sign\n * verifier hash something other than `prefix + serialize(dto minus prefix)`. An unsigned DTO from\n * a dApp never legitimately carries any of them, so they fail closed. Order is part of the error\n * message the wallet shows its user.\n */\nconst PERSONAL_SIGN_FORBIDDEN_FIELDS = [\n 'signature',\n 'multisig',\n 'trace',\n 'types',\n 'domain',\n 'stringsInstructions',\n] as const;\n\n/** What a `gala_signChainDto` personal-sign request hashes. */\nexport interface PersonalSignChainDtoPayload {\n /** The `prefix` the chain prepends: the DTO's own `prefix` field, or `''` when it has none. */\n prefix: string;\n /** The exact message hashed after `prefix`. */\n message: string;\n}\n\n/**\n * Derives what to hash for a `gala_signChainDto` personal-sign request from the exact string the\n * dApp sent (and the approval card displayed): wallet `resolvePersonalSignChainDtoPayload`.\n *\n * The dApp submits `{ ...dto, prefix, signature }`, which the chain recovers from\n * `keccak256(prefix + serialize(dto WITHOUT prefix))`. So when the string embeds a `prefix`\n * field, that field is removed and the remainder re-serialized; the prefix used is the dApp's own\n * value byte for byte. A string with no `prefix` field is hashed verbatim with an empty prefix\n * (chain-equivalent to a native signature of that exact string).\n *\n * Fails closed (throws `GSwapSDKError` `PERSONAL_SIGN_NOT_JSON`, `PERSONAL_SIGN_NOT_OBJECT`,\n * `PERSONAL_SIGN_BAD_PREFIX`, `PERSONAL_SIGN_ENVELOPE_FIELDS` or `PERSONAL_SIGN_NOT_CANONICAL`) on:\n * malformed JSON; JSON that is not a plain object; a `prefix` that is not an EIP-191\n * \"Ethereum Signed Message\" header; any signing-envelope field (`signature`, `multisig`, `trace`,\n * `types`, `domain`, `stringsInstructions`); and a string that is not already the canonical\n * serialization of what it parses to (duplicate keys, lossy numbers, key-order tricks the card\n * would render differently). Stripping `prefix` is therefore the ONLY byte change between the\n * reviewed string and the signed message.\n */\nexport function resolvePersonalSignChainDtoPayload(data: string): PersonalSignChainDtoPayload {\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch {\n throw new GSwapSDKError('PERSONAL_SIGN_NOT_JSON', {});\n }\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new GSwapSDKError('PERSONAL_SIGN_NOT_OBJECT', {});\n }\n const dto = parsed as Record<string, unknown>;\n if (!Object.prototype.hasOwnProperty.call(dto, 'prefix')) {\n return { prefix: '', message: data };\n }\n\n const { prefix, ...withoutPrefix } = dto;\n if (typeof prefix !== 'string' || !isPersonalSignHeader(prefix)) {\n throw new GSwapSDKError('PERSONAL_SIGN_BAD_PREFIX', {});\n }\n const forbidden = PERSONAL_SIGN_FORBIDDEN_FIELDS.filter((field) =>\n Object.prototype.hasOwnProperty.call(withoutPrefix, field),\n );\n if (forbidden.length > 0) {\n throw new GSwapSDKError('PERSONAL_SIGN_ENVELOPE_FIELDS', { fields: forbidden.join(', ') });\n }\n if (serialize(dto) !== data) {\n throw new GSwapSDKError('PERSONAL_SIGN_NOT_CANONICAL', {});\n }\n return { prefix, message: serialize(withoutPrefix) };\n}\n\n/**\n * Signs a GalaChain personal-sign scheme DTO from the exact string a dApp sent through\n * `gala_signChainDto` (wallet `signChainDtoPersonalSign`). See\n * `resolvePersonalSignChainDtoPayload` for what is signed and what is refused; the signature\n * recovers, under the chain's `getPayloadToSign`, to this key for the DTO the dApp submits with\n * its `prefix`, and equals a `personal_sign` of the bare body when that prefix is the EIP-191\n * header of the bare body's byte length.\n *\n * @throws GSwapSDKError (`PERSONAL_SIGN_*`, see `resolvePersonalSignChainDtoPayload`) before any\n * signing when the input is refused.\n */\nexport function signChainDtoPersonalSign(privateKey: PrivateKeyInput, data: string): string {\n const { prefix, message } = resolvePersonalSignChainDtoPayload(data);\n return signChainDtoHash(privateKey, prefix, message);\n}\n\n/**\n * Raw object signing (wallet `signObject`), used for transfers, bridge and fee-dry-run DTOs the\n * wallet signs itself. Removes ONLY `signature`, signs `keccak256(serialize(rest))` natively\n * (no `prefix` handling, and `trace` / `multisig` stay in the signed bytes, unlike\n * `signNative`), and returns `{ signature, ...rest }` with the signature as the FIRST key, exactly\n * like the wallet. Callers that must not sign extra fields strip them first.\n */\nexport function signRawObject(\n privateKey: PrivateKeyInput,\n obj: Record<string, unknown>,\n): { signature: string } & Record<string, unknown> {\n const rest = { ...obj };\n delete rest['signature'];\n return {\n signature: signChainDtoNative(privateKey, serialize(rest)),\n ...rest,\n };\n}\n\n/**\n * Drops the `EIP712Domain` entry from a dApp-supplied types map (a typed-data encoder derives the\n * domain type itself and rejects an explicit one). The order of the remaining types is preserved.\n */\nexport function stripEip712DomainType<T>(types: Record<string, T>): Record<string, T> {\n const stripped: Record<string, T> = {};\n for (const typeName of Object.keys(types)) {\n if (typeName !== 'EIP712Domain') stripped[typeName] = types[typeName] as T;\n }\n return stripped;\n}\n\n/**\n * `collection$category$type$additionalKey` for a token-class object (wallet `decodeTokenData`).\n * Lenient on purpose: any missing or non-string part becomes `''`, so a display layer never\n * throws on odd input.\n */\nexport function tokenClassDollarKey(token: Record<string, unknown> | null | undefined): string {\n const part = (field: string): string => {\n const value = token?.[field];\n return typeof value === 'string' ? value : '';\n };\n return `${part('collection')}$${part('category')}$${part('type')}$${part('additionalKey')}`;\n}\n\n/**\n * A quantity in the form GalaChain's `IsBigNumber` validator accepts: FIXED notation, no leading\n * zeros, no trailing decimal zeros (`BigNumber#toFixed()`; never `toString()`, which turns\n * `0.00000001` into `1e-8`, and never a JS number in between).\n *\n * @throws GSwapSDKError (`INVALID_DECIMAL`) for a value that is not a finite number. The wallet's\n * `cleanNumber` returned the string `'NaN'` there; signing that text can only fail on chain.\n */\nexport function canonicalDecimalString(value: string | number): string {\n let parsed = new BigNumber(Number.NaN);\n try {\n parsed = new BigNumber(value);\n } catch {\n // BigNumber throws instead of returning NaN when its DEBUG flag is on; both mean \"invalid\".\n }\n if (!parsed.isFinite()) {\n throw new GSwapSDKError('INVALID_DECIMAL', { value: String(value) });\n }\n return parsed.toFixed();\n}\n"],"mappings":"+MA2BA,SAAgB,EAAkB,EAA6B,EAAmC,CAChG,IAAM,EAAM,EAAoB,CAAU,EAC1C,GAAI,CACF,OAAO,EAAO,CAAG,CACnB,QAAU,CACR,EAAI,KAAK,CAAC,CACZ,CACF,CASA,SAAgB,EAAmB,EAA6B,EAA+B,CAC7F,OAAO,EAAe,EAAa,GAAQ,EAAqB,EAAK,CAAa,CAAC,CACrF,CAQA,SAAgB,EACd,EACA,EACA,EACQ,CACR,OAAO,EAAe,EAAa,GAAQ,EAAoB,EAAK,EAAQ,CAAO,CAAC,CACtF,CAEA,MACM,EAA+B,uBAMrC,SAAS,EAAqB,EAAyB,CACrD,OACE,EAAO,WAAW;CAAoB,GACtC,EAA6B,KAAK,EAAO,MAAM,EAA2B,CAAC,CAE/E,CAQA,MAAM,EAAiC,CACrC,YACA,WACA,QACA,QACA,SACA,qBACF,EA6BA,SAAgB,EAAmC,EAA2C,CAC5F,IAAI,EACJ,GAAI,CACF,EAAS,KAAK,MAAM,CAAI,CAC1B,MAAQ,CACN,MAAM,IAAI,EAAc,yBAA0B,CAAC,CAAC,CACtD,CACA,GAAuB,OAAO,GAAW,WAArC,GAAiD,MAAM,QAAQ,CAAM,EACvE,MAAM,IAAI,EAAc,2BAA4B,CAAC,CAAC,EAExD,IAAM,EAAM,EACZ,GAAI,CAAC,OAAO,UAAU,eAAe,KAAK,EAAK,QAAQ,EACrD,MAAO,CAAE,OAAQ,GAAI,QAAS,CAAK,EAGrC,GAAM,CAAE,SAAQ,GAAG,GAAkB,EACrC,GAAI,OAAO,GAAW,UAAY,CAAC,EAAqB,CAAM,EAC5D,MAAM,IAAI,EAAc,2BAA4B,CAAC,CAAC,EAExD,IAAM,EAAY,EAA+B,OAAQ,GACvD,OAAO,UAAU,eAAe,KAAK,EAAe,CAAK,CAC3D,EACA,GAAI,EAAU,OAAS,EACrB,MAAM,IAAI,EAAc,gCAAiC,CAAE,OAAQ,EAAU,KAAK,IAAI,CAAE,CAAC,EAE3F,GAAI,EAAU,CAAG,IAAM,EACrB,MAAM,IAAI,EAAc,8BAA+B,CAAC,CAAC,EAE3D,MAAO,CAAE,SAAQ,QAAS,EAAU,CAAa,CAAE,CACrD,CAaA,SAAgB,EAAyB,EAA6B,EAAsB,CAC1F,GAAM,CAAE,SAAQ,WAAY,EAAmC,CAAI,EACnE,OAAO,EAAiB,EAAY,EAAQ,CAAO,CACrD,CASA,SAAgB,EACd,EACA,EACiD,CACjD,IAAM,EAAO,CAAE,GAAG,CAAI,EAEtB,OADA,OAAO,EAAK,UACL,CACL,UAAW,EAAmB,EAAY,EAAU,CAAI,CAAC,EACzD,GAAG,CACL,CACF,CAMA,SAAgB,EAAyB,EAA6C,CACpF,IAAM,EAA8B,CAAC,EACrC,IAAK,IAAM,KAAY,OAAO,KAAK,CAAK,EAClC,IAAa,iBAAgB,EAAS,GAAY,EAAM,IAE9D,OAAO,CACT,CAOA,SAAgB,EAAoB,EAA2D,CAC7F,IAAM,EAAQ,GAA0B,CACtC,IAAM,EAAQ,IAAQ,GACtB,OAAO,OAAO,GAAU,SAAW,EAAQ,EAC7C,EACA,MAAO,GAAG,EAAK,YAAY,EAAE,GAAG,EAAK,UAAU,EAAE,GAAG,EAAK,MAAM,EAAE,GAAG,EAAK,eAAe,GAC1F,CAUA,SAAgB,EAAuB,EAAgC,CACrE,IAAI,EAAS,IAAI,EAAU,GAAU,EACrC,GAAI,CACF,EAAS,IAAI,EAAU,CAAK,CAC9B,MAAQ,CAER,CACA,GAAI,CAAC,EAAO,SAAS,EACnB,MAAM,IAAI,EAAc,kBAAmB,CAAE,MAAO,OAAO,CAAK,CAAE,CAAC,EAErE,OAAO,EAAO,QAAQ,CACxB"}
1
+ {"version":3,"file":"chain_dto_signing.js","names":[],"sources":["../../../src/utils/chain_dto_signing.ts"],"sourcesContent":["/**\n * String-key signing entry points for apps that hold a private key only briefly (the Gala Wallet\n * extension reads its session key at sign time and must not keep it in a long-lived object).\n *\n * These are thin, byte-exact ports of the functions the wallet shipped in\n * `wallet_extension/src/helpers/wallet/signing.ts` (including the fail-closed personal-sign\n * payload resolver from its commit 34ca4e4), re-expressed over the SDK's own primitives. Every\n * function takes the key as a string (`0x`-optional hex, or base64) or as bytes, normalizes it per\n * call, and zeroes the normalized copy before returning, so nothing in this module retains a key.\n * A JavaScript string cannot be wiped; the caller owns the lifetime of the string it passes in.\n */\nimport BigNumber from 'bignumber.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport {\n normalizePrivateKey,\n serialize,\n signPersonalMessage,\n signSerializedNative,\n} from './signing.js';\n\n/** A secp256k1 private key as a hex/base64 string or as raw 32 bytes. */\nexport type PrivateKeyInput = string | Uint8Array;\n\n/**\n * Runs `action` with a private normalized copy of the key, zeroed afterwards (also when `action`\n * throws). Bytes given by the caller are copied, never modified: the caller owns them.\n */\nexport function withPrivateKey<T>(privateKey: PrivateKeyInput, action: (key: Uint8Array) => T): T {\n const key = normalizePrivateKey(privateKey);\n try {\n return action(key);\n } finally {\n key.fill(0);\n }\n}\n\n/**\n * GalaChain NATIVE signature over an already-serialized DTO: keccak256 of the exact bytes with no\n * prefix and no envelope (wallet `signChainDtoNative`). The caller owns serialization, so the\n * bytes a user reviewed and the bytes signed cannot diverge.\n *\n * @returns 130 lowercase hex characters, `r || s || v` with `v` = `1b`/`1c`, no `0x`.\n */\nexport function signChainDtoNative(privateKey: PrivateKeyInput, serializedDto: string): string {\n return withPrivateKey(privateKey, (key) => signSerializedNative(key, serializedDto));\n}\n\n/**\n * The personal-sign hash primitive (wallet `signChainDtoHash`): keccak256(`prefix` + `message`),\n * both verbatim, with no further EIP-191 wrap. `message` must be the DTO's serialization WITHOUT\n * its `prefix` field; callers holding a dApp-supplied string go through `signChainDtoPersonalSign`,\n * which derives both inputs from it.\n */\nexport function signChainDtoHash(\n privateKey: PrivateKeyInput,\n prefix: string,\n message: string,\n): string {\n return withPrivateKey(privateKey, (key) => signPersonalMessage(key, prefix, message));\n}\n\nconst PERSONAL_SIGN_HEADER = String.fromCharCode(0x19) + 'Ethereum Signed Message:\\n';\nconst PERSONAL_SIGN_LENGTH_PATTERN = /^(?:0|[1-9][0-9]*)$/u;\n\n// A header with a body starting `{` can never collide with another EIP-191 message's hash, and\n// anything that is not a header (arbitrary bytes the user cannot see on an approval card) is\n// refused. The number is NOT required to equal the byte length: the chain hashes whatever prefix\n// the submitted DTO carries, and defi-backend's bouncer rejects a mismatched header loudly.\nfunction isPersonalSignHeader(prefix: string): boolean {\n return (\n prefix.startsWith(PERSONAL_SIGN_HEADER) &&\n PERSONAL_SIGN_LENGTH_PATTERN.test(prefix.slice(PERSONAL_SIGN_HEADER.length))\n );\n}\n\n/**\n * Top-level fields that would make the chain (`getPayloadToSign`) or defi-backend's personal-sign\n * verifier hash something other than `prefix + serialize(dto minus prefix)`. An unsigned DTO from\n * a dApp never legitimately carries any of them, so they fail closed. Order is part of the error\n * message the wallet shows its user.\n */\nconst PERSONAL_SIGN_FORBIDDEN_FIELDS = [\n 'signature',\n 'multisig',\n 'trace',\n 'types',\n 'domain',\n 'stringsInstructions',\n] as const;\n\n/** What a `gala_signChainDto` personal-sign request hashes. */\nexport interface PersonalSignChainDtoPayload {\n /** The `prefix` the chain prepends: the DTO's own `prefix` field, or `''` when it has none. */\n prefix: string;\n /** The exact message hashed after `prefix`. */\n message: string;\n}\n\n/**\n * Derives what to hash for a `gala_signChainDto` personal-sign request from the exact string the\n * dApp sent (and the approval card displayed): wallet `resolvePersonalSignChainDtoPayload`.\n *\n * The dApp submits `{ ...dto, prefix, signature }`, which the chain recovers from\n * `keccak256(prefix + serialize(dto WITHOUT prefix))`. So when the string embeds a `prefix`\n * field, that field is removed and the remainder re-serialized; the prefix used is the dApp's own\n * value byte for byte. A string with no `prefix` field is hashed verbatim with an empty prefix\n * (chain-equivalent to a native signature of that exact string).\n *\n * Fails closed (throws `GSwapSDKError` `PERSONAL_SIGN_NOT_JSON`, `PERSONAL_SIGN_NOT_OBJECT`,\n * `PERSONAL_SIGN_BAD_PREFIX`, `PERSONAL_SIGN_ENVELOPE_FIELDS` or `PERSONAL_SIGN_NOT_CANONICAL`) on:\n * malformed JSON; JSON that is not a plain object; a `prefix` that is not an EIP-191\n * \"Ethereum Signed Message\" header; any signing-envelope field (`signature`, `multisig`, `trace`,\n * `types`, `domain`, `stringsInstructions`); and a string that is not already the canonical\n * serialization of what it parses to (duplicate keys, lossy numbers, key-order tricks the card\n * would render differently). Stripping `prefix` is therefore the ONLY byte change between the\n * reviewed string and the signed message.\n */\nexport function resolvePersonalSignChainDtoPayload(data: string): PersonalSignChainDtoPayload {\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch {\n throw new GSwapSDKError('PERSONAL_SIGN_NOT_JSON', {});\n }\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new GSwapSDKError('PERSONAL_SIGN_NOT_OBJECT', {});\n }\n const dto = parsed as Record<string, unknown>;\n if (!Object.prototype.hasOwnProperty.call(dto, 'prefix')) {\n return { prefix: '', message: data };\n }\n\n const { prefix, ...withoutPrefix } = dto;\n if (typeof prefix !== 'string' || !isPersonalSignHeader(prefix)) {\n throw new GSwapSDKError('PERSONAL_SIGN_BAD_PREFIX', {});\n }\n const forbidden = PERSONAL_SIGN_FORBIDDEN_FIELDS.filter((field) =>\n Object.prototype.hasOwnProperty.call(withoutPrefix, field),\n );\n if (forbidden.length > 0) {\n throw new GSwapSDKError('PERSONAL_SIGN_ENVELOPE_FIELDS', { fields: forbidden.join(', ') });\n }\n if (serialize(dto) !== data) {\n throw new GSwapSDKError('PERSONAL_SIGN_NOT_CANONICAL', {});\n }\n return { prefix, message: serialize(withoutPrefix) };\n}\n\n/**\n * Signs a GalaChain personal-sign scheme DTO from the exact string a dApp sent through\n * `gala_signChainDto` (wallet `signChainDtoPersonalSign`). See\n * `resolvePersonalSignChainDtoPayload` for what is signed and what is refused; the signature\n * recovers, under the chain's `getPayloadToSign`, to this key for the DTO the dApp submits with\n * its `prefix`, and equals a `personal_sign` of the bare body when that prefix is the EIP-191\n * header of the bare body's byte length.\n *\n * @throws GSwapSDKError (`PERSONAL_SIGN_*`, see `resolvePersonalSignChainDtoPayload`) before any\n * signing when the input is refused.\n */\nexport function signChainDtoPersonalSign(privateKey: PrivateKeyInput, data: string): string {\n const { prefix, message } = resolvePersonalSignChainDtoPayload(data);\n return signChainDtoHash(privateKey, prefix, message);\n}\n\n/**\n * Raw object signing (wallet `signObject`), used for transfers, bridge and fee-dry-run DTOs the\n * wallet signs itself. Removes ONLY `signature`, signs `keccak256(serialize(rest))` natively\n * (no `prefix` handling, and `trace` / `multisig` stay in the signed bytes, unlike\n * `signNative`), and returns `{ signature, ...rest }` with the signature as the FIRST key, exactly\n * like the wallet. Callers that must not sign extra fields strip them first.\n */\nexport function signRawObject(\n privateKey: PrivateKeyInput,\n obj: Record<string, unknown>,\n): { signature: string } & Record<string, unknown> {\n const rest = { ...obj };\n delete rest['signature'];\n return {\n signature: signChainDtoNative(privateKey, serialize(rest)),\n ...rest,\n };\n}\n\n/**\n * Drops the `EIP712Domain` entry from a dApp-supplied types map (a typed-data encoder derives the\n * domain type itself and rejects an explicit one). The order of the remaining types is preserved.\n */\nexport function stripEip712DomainType<T>(types: Record<string, T>): Record<string, T> {\n const stripped: Record<string, T> = {};\n for (const typeName of Object.keys(types)) {\n if (typeName !== 'EIP712Domain') stripped[typeName] = types[typeName] as T;\n }\n return stripped;\n}\n\n/**\n * `collection$category$type$additionalKey` for a token-class object (wallet `decodeTokenData`).\n * Lenient on purpose: any missing or non-string part becomes `''`, so a display layer never\n * throws on odd input.\n */\nexport function tokenClassDollarKey(token: Record<string, unknown> | null | undefined): string {\n const part = (field: string): string => {\n const value = token?.[field];\n return typeof value === 'string' ? value : '';\n };\n return `${part('collection')}$${part('category')}$${part('type')}$${part('additionalKey')}`;\n}\n\n/**\n * A quantity in the form GalaChain's `IsBigNumber` validator accepts: FIXED notation, no leading\n * zeros, no trailing decimal zeros (`BigNumber#toFixed()`; never `toString()`, which turns\n * `0.00000001` into `1e-8`, and never a JS number in between).\n *\n * @throws GSwapSDKError (`INVALID_DECIMAL`) for a value that is not a finite number. The wallet's\n * `cleanNumber` returned the string `'NaN'` there; signing that text can only fail on chain.\n */\nexport function canonicalDecimalString(value: string | number): string {\n let parsed = new BigNumber(Number.NaN);\n try {\n parsed = new BigNumber(value);\n } catch {\n // BigNumber throws instead of returning NaN when its DEBUG flag is on; both mean \"invalid\".\n }\n if (!parsed.isFinite()) {\n throw new GSwapSDKError('INVALID_DECIMAL', { value: String(value) });\n }\n return parsed.toFixed();\n}\n"],"mappings":"+MA2BA,SAAgB,EAAkB,EAA6B,EAAmC,CAChG,IAAM,EAAM,EAAoB,CAAU,EAC1C,GAAI,CACF,OAAO,EAAO,CAAG,CACnB,QAAU,CACR,EAAI,KAAK,CAAC,CACZ,CACF,CASA,SAAgB,EAAmB,EAA6B,EAA+B,CAC7F,OAAO,EAAe,EAAa,GAAQ,EAAqB,EAAK,CAAa,CAAC,CACrF,CAQA,SAAgB,EACd,EACA,EACA,EACQ,CACR,OAAO,EAAe,EAAa,GAAQ,EAAoB,EAAK,EAAQ,CAAO,CAAC,CACtF,CAEA,MACM,EAA+B,uBAMrC,SAAS,EAAqB,EAAyB,CACrD,OACE,EAAO,WAAW;CAAoB,GACtC,EAA6B,KAAK,EAAO,MAAM,EAA2B,CAAC,CAE/E,CAQA,MAAM,EAAiC,CACrC,YACA,WACA,QACA,QACA,SACA,qBACF,EA6BA,SAAgB,EAAmC,EAA2C,CAC5F,IAAI,EACJ,GAAI,CACF,EAAS,KAAK,MAAM,CAAI,CAC1B,MAAQ,CACN,MAAM,IAAI,EAAc,yBAA0B,CAAC,CAAC,CACtD,CACA,GAAuB,OAAO,GAAW,WAArC,GAAiD,MAAM,QAAQ,CAAM,EACvE,MAAM,IAAI,EAAc,2BAA4B,CAAC,CAAC,EAExD,IAAM,EAAM,EACZ,GAAI,CAAC,OAAO,UAAU,eAAe,KAAK,EAAK,QAAQ,EACrD,MAAO,CAAE,OAAQ,GAAI,QAAS,CAAK,EAGrC,GAAM,CAAE,SAAQ,GAAG,GAAkB,EACrC,GAAI,OAAO,GAAW,UAAY,CAAC,EAAqB,CAAM,EAC5D,MAAM,IAAI,EAAc,2BAA4B,CAAC,CAAC,EAExD,IAAM,EAAY,EAA+B,OAAQ,GACvD,OAAO,UAAU,eAAe,KAAK,EAAe,CAAK,CAC3D,EACA,GAAI,EAAU,OAAS,EACrB,MAAM,IAAI,EAAc,gCAAiC,CAAE,OAAQ,EAAU,KAAK,IAAI,CAAE,CAAC,EAE3F,GAAI,EAAU,CAAG,IAAM,EACrB,MAAM,IAAI,EAAc,8BAA+B,CAAC,CAAC,EAE3D,MAAO,CAAE,SAAQ,QAAS,EAAU,CAAa,CAAE,CACrD,CAaA,SAAgB,EAAyB,EAA6B,EAAsB,CAC1F,GAAM,CAAE,SAAQ,WAAY,EAAmC,CAAI,EACnE,OAAO,EAAiB,EAAY,EAAQ,CAAO,CACrD,CASA,SAAgB,EACd,EACA,EACiD,CACjD,IAAM,EAAO,CAAE,GAAG,CAAI,EAEtB,OADA,OAAO,EAAK,UACL,CACL,UAAW,EAAmB,EAAY,EAAU,CAAI,CAAC,EACzD,GAAG,CACL,CACF,CAMA,SAAgB,EAAyB,EAA6C,CACpF,IAAM,EAA8B,CAAC,EACrC,IAAK,IAAM,KAAY,OAAO,KAAK,CAAK,EAClC,IAAa,iBAAgB,EAAS,GAAY,EAAM,IAE9D,OAAO,CACT,CAOA,SAAgB,EAAoB,EAA2D,CAC7F,IAAM,EAAQ,GAA0B,CACtC,IAAM,EAAQ,IAAQ,GACtB,OAAO,OAAO,GAAU,SAAW,EAAQ,EAC7C,EACA,MAAO,GAAG,EAAK,YAAY,EAAE,GAAG,EAAK,UAAU,EAAE,GAAG,EAAK,MAAM,EAAE,GAAG,EAAK,eAAe,GAC1F,CAUA,SAAgB,EAAuB,EAAgC,CACrE,IAAI,EAAS,IAAI,EAAU,GAAU,EACrC,GAAI,CACF,EAAS,IAAI,EAAU,CAAK,CAC9B,MAAQ,CAER,CACA,GAAI,CAAC,EAAO,SAAS,EACnB,MAAM,IAAI,EAAc,kBAAmB,CAAE,MAAO,OAAO,CAAK,CAAE,CAAC,EAErE,OAAO,EAAO,QAAQ,CACxB"}
@@ -0,0 +1,2 @@
1
+ function e(e){return[e.collection,e.category,e.type,e.additionalKey].join(`$`)}function t(e,t){let n=e.split(t),r=n.slice(-3),i=n.slice(0,-3).join(t);if(n.length<4||i.length===0||r.some(e=>e.length===0))return;let[a,o,s]=r;return{collection:i,category:a,type:o,additionalKey:s}}function n(e){if(typeof e==`string`)return t(e,e.includes(`|`)?`|`:`$`);if(typeof e==`object`&&e)try{let{collection:t,category:n,type:r,additionalKey:i}=e;return typeof t!=`string`||typeof n!=`string`||typeof r!=`string`||typeof i!=`string`||t===``||n===``||r===``||i===``?void 0:{collection:t,category:n,type:r,additionalKey:i}}catch{return}}function r(e){return typeof e==`string`?t(e,`$`):void 0}export{e as compositeKeyOf,t as splitClassKey,r as tryParseCompositeKey,n as tryParseTokenClassKey};
2
+ //# sourceMappingURL=class_key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class_key.js","names":[],"sources":["../../../src/utils/class_key.ts"],"sourcesContent":["import type { GalaChainTokenClassKey } from '../types/token.js';\n\n/**\n * Token class keys that never throw: the `$`-joined composite key and the non-throwing parsers.\n * This module imports nothing at run time (the key type is erased), so an app shell that reads a\n * stored key pays for a few hundred bytes, never for the error class or the catalog. The parser\n * that THROWS an SDK error on a bad key (`parseTokenClassKey`) lives in `ordering.ts`.\n */\n\n/** Return the `$`-joined composite key used by GalaChain object identities. */\nexport function compositeKeyOf(token: GalaChainTokenClassKey): string {\n return [token.collection, token.category, token.type, token.additionalKey].join('$');\n}\n\n/**\n * Splits `collection<d>category<d>type<d>additionalKey` from the right, or `undefined` when there\n * are fewer than four segments or any of the four is empty. The one place the split is written;\n * the strict `parseTokenClassKey` calls it too.\n *\n * The LAST three segments are always `category`, `type` and `additionalKey`; everything before\n * them is the `collection`. Parsing from the right is required because real collections contain\n * the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`\n * shifts every field.\n */\nexport function splitClassKey(\n key: string,\n delimiter: '|' | '$',\n): GalaChainTokenClassKey | undefined {\n const segments = key.split(delimiter);\n const tail = segments.slice(-3);\n const collection = segments.slice(0, -3).join(delimiter);\n if (segments.length < 4 || collection.length === 0 || tail.some((part) => part.length === 0)) {\n return undefined;\n }\n const [category, type, additionalKey] = tail;\n return {\n collection,\n category: category as string,\n type: type as string,\n additionalKey: additionalKey as string,\n };\n}\n\n/**\n * The non-throwing `parseTokenClassKey`: the class key, or `undefined` when `value` is not\n * one. A string is split exactly as `parseTokenClassKey` splits it (`|` form when it contains a\n * `|`, else `$`, from the right, all four parts non-empty). Unlike `parseTokenClassKey`, an\n * object is VALIDATED, not just copied: all four fields must be non-empty strings. Anything else\n * (`undefined`, `null`, a number, an array) is `undefined`, so it is safe on untrusted input (a\n * stored token, a URL parameter, a wallet row) without a `try`/`catch`.\n *\n * Use {@link tryParseCompositeKey} instead when only the `$` form is valid input.\n *\n * @example\n * ```ts\n * const key = tryParseTokenClassKey(row.compositeKey);\n * if (key === undefined) return failClosed(); // no class is known: never invent one from a symbol\n * ```\n */\nexport function tryParseTokenClassKey(value: unknown): GalaChainTokenClassKey | undefined {\n if (typeof value === 'string') return splitClassKey(value, value.includes('|') ? '|' : '$');\n if (typeof value !== 'object' || value === null) return undefined;\n try {\n const { collection, category, type, additionalKey } = value as Record<string, unknown>;\n if (\n typeof collection !== 'string' ||\n typeof category !== 'string' ||\n typeof type !== 'string' ||\n typeof additionalKey !== 'string' ||\n collection === '' ||\n category === '' ||\n type === '' ||\n additionalKey === ''\n ) {\n return undefined;\n }\n return { collection, category, type, additionalKey };\n } catch {\n // A getter or proxy that throws is not a token class key.\n return undefined;\n }\n}\n\n/**\n * Parses a `$`-joined composite key (`Collection$Category$Type$AdditionalKey`, what\n * {@link compositeKeyOf} writes) and nothing else, or `undefined`. It is {@link tryParseTokenClassKey}\n * for a string that may ONLY be in the `$` form: a key that contains `|` is NOT read as the pipe\n * form here (it stays part of a segment), and only a string is accepted. The split is from the\n * right, so a collection that itself contains `$` (production's `$GMUSIC`, stage's\n * `$GMUSIC_TEST1`) stays whole; `'GALA'`, `'GALA$Unit$none'`, `'ETIME$$$'`, `'GALA$Unit$none$'` and\n * `'$$$$'` are `undefined`.\n *\n * It replaces an app's own `parseCompositeKey(key): Components | null` (`?? null`), which had\n * exactly these semantics.\n *\n * @example\n * ```ts\n * tryParseCompositeKey('$GMUSIC_TEST1$Unit$none$none')?.collection; // '$GMUSIC_TEST1'\n * tryParseCompositeKey('GALA$Unit$none'); // undefined\n * ```\n */\nexport function tryParseCompositeKey(value: unknown): GalaChainTokenClassKey | undefined {\n return typeof value === 'string' ? splitClassKey(value, '$') : undefined;\n}\n"],"mappings":"AAUA,SAAgB,EAAe,EAAuC,CACpE,MAAO,CAAC,EAAM,WAAY,EAAM,SAAU,EAAM,KAAM,EAAM,aAAa,CAAC,CAAC,KAAK,GAAG,CACrF,CAYA,SAAgB,EACd,EACA,EACoC,CACpC,IAAM,EAAW,EAAI,MAAM,CAAS,EAC9B,EAAO,EAAS,MAAM,EAAE,EACxB,EAAa,EAAS,MAAM,EAAG,EAAE,CAAC,CAAC,KAAK,CAAS,EACvD,GAAI,EAAS,OAAS,GAAK,EAAW,SAAW,GAAK,EAAK,KAAM,GAAS,EAAK,SAAW,CAAC,EACzF,OAEF,GAAM,CAAC,EAAU,EAAM,GAAiB,EACxC,MAAO,CACL,aACU,WACJ,OACS,eACjB,CACF,CAkBA,SAAgB,EAAsB,EAAoD,CACxF,GAAI,OAAO,GAAU,SAAU,OAAO,EAAc,EAAO,EAAM,SAAS,GAAG,EAAI,IAAM,GAAG,EAC1F,GAAI,OAAO,GAAU,UAAY,EACjC,GAAI,CACF,GAAM,CAAE,aAAY,WAAU,OAAM,iBAAkB,EAatD,OAXE,OAAO,GAAe,UACtB,OAAO,GAAa,UACpB,OAAO,GAAS,UAChB,OAAO,GAAkB,UACzB,IAAe,IACf,IAAa,IACb,IAAS,IACT,IAAkB,GAElB,OAEK,CAAE,aAAY,WAAU,OAAM,eAAc,CACrD,MAAQ,CAEN,MACF,CACF,CAoBA,SAAgB,EAAqB,EAAoD,CACvF,OAAO,OAAO,GAAU,SAAW,EAAc,EAAO,GAAG,EAAI,IAAA,EACjE"}
@@ -0,0 +1,2 @@
1
+ const e={rejected:!0,unknown:!1,not_queued:!0,not_sent:!0,invalid_input:!1,transient:!0};function t(t,n={}){return{outcome:t,retryable:n.retryable!==!1&&e[t]}}const n=Object.freeze(t(`not_queued`,{retryable:!1}));function r(){return t(`not_sent`)}export{n as NOT_QUEUED_FINAL,t as classification,r as notSentClassification};
2
+ //# sourceMappingURL=classification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classification.js","names":[],"sources":["../../../src/utils/classification.ts"],"sourcesContent":["import type { FailureOutcome } from './failure_outcomes.js';\n\n/**\n * The classification values an app shell may need on their own: what an outcome allows. This module\n * is deliberately tiny and imports nothing at run time (the outcome type is erased), so an app\n * shell that builds `classification('not_sent')` or reads `NOT_QUEUED_FINAL` loads a few hundred\n * bytes, not the table of error codes that lives with `classifyFailure`.\n */\n\n/** The result of `classifyFailure`. */\nexport interface FailureClassification {\n readonly outcome: FailureOutcome;\n /**\n * May the app offer the user Retry: repeat the operation as a NEW request (a fresh key for a\n * write) without any risk of applying it twice? Always `false` for `unknown` (confirm the same\n * key instead) and `invalid_input` (the same call fails again). It says a repeat is SAFE, not\n * that it will succeed, and it is the SDK's floor: an app may still withhold Retry (the\n * wallet and frontend_v2 do after a Dark swap: see `isShadowError`).\n */\n readonly retryable: boolean;\n}\n\n/**\n * The SDK's default Retry answer for each outcome. A decision that departs from it (a refusal the\n * gateway will repeat, `SHADOW_NOT_QUEUED`) is written out in the table of `classifyFailure`.\n */\nconst DEFAULT_RETRYABLE = {\n rejected: true,\n unknown: false,\n not_queued: true,\n not_sent: true,\n invalid_input: false,\n transient: true,\n} as const satisfies Record<FailureOutcome, boolean>;\n\n/**\n * Builds the classification the SDK itself gives an outcome, so an app that classifies a step of\n * its OWN (one that is not an SDK call) uses the SDK's type and its values instead of a\n * hard-coded `{ outcome, retryable }` literal. `retryable` is the SDK's default for that outcome\n * (`false` for `unknown` and `invalid_input`, `true` for the rest). Each call returns a new\n * object, safe to mutate or freeze.\n *\n * `options.retryable: false` WITHHOLDS Retry from an outcome that would otherwise allow it: the\n * SDK's own `not_queued` for a refusal the gateway will repeat is\n * `classification('not_queued', { retryable: false })` (also exported, frozen, as\n * {@link NOT_QUEUED_FINAL}). An app may take Retry away from an outcome but never grant it to one\n * that cannot have it, so only `false` is accepted.\n *\n * @example\n * ```ts\n * // The app refreshes a quote before it asks the SDK to sign; the refresh failed.\n * throw new AppSwapError(text, classification('not_sent'));\n * // The app refuses a request for a reason a repeat cannot fix.\n * throw new AppSwapError(text, classification('not_queued', { retryable: false }));\n * ```\n */\nexport function classification(\n outcome: FailureOutcome,\n options: { readonly retryable?: false } = {},\n): FailureClassification {\n return { outcome, retryable: options.retryable === false ? false : DEFAULT_RETRYABLE[outcome] };\n}\n\n/**\n * `classification('not_queued', { retryable: false })`: the gateway refused the write before\n * queueing it AND will refuse a repeat the same way (the version wall, a dark swap that did not\n * queue, an HTTP 4xx). Nothing is pending and Retry is not offered. It is frozen: use it as it is\n * (`classification: NOT_QUEUED_FINAL`) instead of spreading `classification('not_queued')` and\n * overriding `retryable`; `{ ...NOT_QUEUED_FINAL }` is a mutable copy.\n */\nexport const NOT_QUEUED_FINAL: Readonly<FailureClassification> = Object.freeze(\n classification('not_queued', { retryable: false }),\n);\n\n/**\n * `classification('not_sent')`: a step of the app's own failed before anything was signed or\n * sent (a quote refresh, a balance read), so nothing is pending and a repeat is safe.\n */\nexport function notSentClassification(): FailureClassification {\n return classification('not_sent');\n}\n"],"mappings":"AA0BA,MAAM,EAAoB,CACxB,SAAU,GACV,QAAS,GACT,WAAY,GACZ,SAAU,GACV,cAAe,GACf,UAAW,EACb,EAuBA,SAAgB,EACd,EACA,EAA0C,CAAC,EACpB,CACvB,MAAO,CAAE,UAAS,UAAW,EAAQ,YAAc,IAAgB,EAAkB,EAAS,CAChG,CASA,MAAa,EAAoD,OAAO,OACtE,EAAe,aAAc,CAAE,UAAW,EAAM,CAAC,CACnD,EAMA,SAAgB,GAA+C,CAC7D,OAAO,EAAe,UAAU,CAClC"}
@@ -1,2 +1,2 @@
1
- import{GSwapSDKError as e}from"../classes/gswap_sdk_error.js";import{assertTickRange as t}from"./ticks.js";import{assertCanonicalPair as n,isProposableTradingSymbol as r,validateFee as i,validateNumericAmount as a}from"./validation.js";import{assertUniqueKey as o}from"./unique_key.js";import s from"bignumber.js";const c=e=>new s(e).toFixed();function l(t){i(t.fee),n(t.token0,t.token1),o(t.uniqueKey);let r={token0:t.token0,token1:t.token1,fee:t.fee,uniqueKey:t.uniqueKey};if(`exactIn`in t){let n=t.exactIn;if(n===void 0)throw new e(`EXACT_AMOUNT_REQUIRED`,{field:`exactIn`});a(n,`exactIn`),r[t.tokenInIsToken0?`sell0Qty`:`sell1Qty`]=c(n),t.amountOutMinimum!==void 0&&(a(t.amountOutMinimum,`amountOutMinimum`,!0),r.amountOutMinimum=c(t.amountOutMinimum))}else{let n=t.exactOut;if(n===void 0)throw new e(`EXACT_AMOUNT_REQUIRED`,{field:`exactOut`});a(n,`exactOut`),r[t.tokenInIsToken0?`buy1Qty`:`buy0Qty`]=c(n),t.amountInMaximum!==void 0&&(a(t.amountInMaximum,`amountInMaximum`,!0),r.amountInMaximum=c(t.amountInMaximum))}return t.priceLimit!==void 0&&(a(t.priceLimit,`priceLimit`),r.priceLimit=c(t.priceLimit)),r}function u(e){i(e.fee),n(e.token0,e.token1),t(e.tickLower,e.tickUpper,e.fee),o(e.uniqueKey)}function d(t){u(t);let n=g(t.depositQuantityToken0,t.depositQuantityToken1,`depositQuantityToken0`,`depositQuantityToken1`);if(n===void 0)throw new e(`EXACTLY_ONE_OF_REQUIRED`,{first:`depositQuantityToken0`,second:`depositQuantityToken1`});return a(n.amount,n.name),{token0:t.token0,token1:t.token1,fee:t.fee,tickLower:t.tickLower,tickUpper:t.tickUpper,uniqueKey:t.uniqueKey,[n.name]:c(n.amount)}}function f(e){u(e);let t=g(e.withdrawalQuantityToken0,e.withdrawalQuantityToken1,`withdrawalQuantityToken0`,`withdrawalQuantityToken1`,!0);return t!==void 0&&a(t.amount,t.name),{token0:e.token0,token1:e.token1,fee:e.fee,tickLower:e.tickLower,tickUpper:e.tickUpper,uniqueKey:e.uniqueKey,...t===void 0?{}:{[t.name]:c(t.amount)}}}function p(e){return u(e),{token0:e.token0,token1:e.token1,fee:e.fee,tickLower:e.tickLower,tickUpper:e.tickUpper,uniqueKey:e.uniqueKey}}function m(t){i(t.fee),o(t.uniqueKey),n(t.token0Symbol,t.token1Symbol);for(let n of[t.token0Symbol,t.token1Symbol])if(!r(n))throw new e(`INVALID_TRADING_SYMBOL`,{symbol:n});for(let e of[t.token0Key,t.token1Key])h(e);let a=g(t.startingPrice,t.startingSqrtPrice,`startingPrice`,`startingSqrtPrice`);if(a===void 0)throw new e(`EXACTLY_ONE_OF_REQUIRED`,{first:`startingPrice`,second:`startingSqrtPrice`});if(typeof a.amount==`number`)throw new e(`AMOUNT_IS_JS_NUMBER`,{field:a.name});let c=new s(a.amount);if(!c.isFinite()||c.isLessThanOrEqualTo(0))throw new e(`INVALID_STARTING_PRICE`,{value:String(a.amount)});return{token0Key:t.token0Key,token1Key:t.token1Key,fee:t.fee,[a.name]:c.toFixed(),token0Symbol:t.token0Symbol,token1Symbol:t.token1Symbol,uniqueKey:t.uniqueKey,...t.name===void 0||t.name===``?{}:{name:t.name},...t.isPrivate===void 0?{}:{isPrivate:t.isPrivate},...t.privateAccess===void 0?{}:{privateAccess:t.privateAccess}}}function h(t){for(let n of[`collection`,`category`,`type`,`additionalKey`])if(typeof t[n]!=`string`||t[n].length===0)throw new e(`INCOMPLETE_TOKEN_CLASS_KEY`,{compositeKey:[t.collection,t.category,t.type,t.additionalKey].join(`$`),part:n})}function g(t,n,r,i,a=!1){if(t!==void 0&&n!==void 0)throw a?new e(`AT_MOST_ONE_OF_ALLOWED`,{first:r,second:i}):new e(`EXACTLY_ONE_OF_REQUIRED`,{first:r,second:i});if(t!==void 0)return{name:r,amount:t};if(n!==void 0)return{name:i,amount:n}}function _(t,n,r){return new e(`INVALID_DTO`,{method:t,field:n,expected:r})}function v(e,t){let n=n=>{let r=t[n];if(typeof r!=`string`)throw _(e,n,`string`);return r},r=n=>{let r=t[n];if(typeof r!=`number`)throw _(e,n,`number`);return r},i=e=>t[e]===void 0?void 0:n(e),a=n=>{let r=t[n];if(typeof r!=`object`||!r)throw _(e,n,`class_key`);let i=r,a=t=>{if(typeof i[t]!=`string`)throw _(e,`${n}.${t}`,`string`);return i[t]};return{collection:a(`collection`),category:a(`category`),type:a(`type`),additionalKey:a(`additionalKey`)}},o=()=>({token0:n(`token0`),token1:n(`token1`),fee:r(`fee`)}),s=n(`uniqueKey`),c=()=>({...o(),uniqueKey:s,tickLower:r(`tickLower`),tickUpper:r(`tickUpper`)});switch(e){case`RequestTrade`:{let r=[`sell0Qty`,`sell1Qty`,`buy0Qty`,`buy1Qty`].filter(e=>t[e]!==void 0),[a]=r;if(r.length!==1||a===void 0)throw _(e,`sell0Qty|sell1Qty|buy0Qty|buy1Qty`,`exactly_once`);let c=a===`sell0Qty`||a===`buy1Qty`,u={...o(),uniqueKey:s,tokenInIsToken0:c},d=i(`priceLimit`);return a.startsWith(`sell`)?l({...u,exactIn:n(a),amountOutMinimum:i(`amountOutMinimum`),priceLimit:d}):l({...u,exactOut:n(a),amountInMaximum:i(`amountInMaximum`),priceLimit:d})}case`AddLiquidity`:{let e=i(`depositQuantityToken0`),t=i(`depositQuantityToken1`);return d({...c(),...e===void 0?{depositQuantityToken1:t}:{depositQuantityToken0:e}})}case`RemoveLiquidity`:return f({...c(),withdrawalQuantityToken0:i(`withdrawalQuantityToken0`),withdrawalQuantityToken1:i(`withdrawalQuantityToken1`)});case`CollectPositionFees`:return p(c());case`CreatePool`:{let o=i(`startingPrice`),c=i(`startingSqrtPrice`),l=t.privateAccess;if(l!==void 0&&(!Array.isArray(l)||l.some(e=>typeof e!=`string`)))throw _(e,`privateAccess`,`string_array`);if(t.isPrivate!==void 0&&typeof t.isPrivate!=`boolean`)throw _(e,`isPrivate`,`boolean`);return m({token0Key:a(`token0Key`),token1Key:a(`token1Key`),token0Symbol:n(`token0Symbol`),token1Symbol:n(`token1Symbol`),fee:r(`fee`),uniqueKey:s,name:i(`name`),isPrivate:t.isPrivate,privateAccess:l,...o===void 0?{startingSqrtPrice:c}:{startingPrice:o}})}}}function y(t,n){let r=v(t,n);if(JSON.stringify(r)!==JSON.stringify(n))throw new e(`DTO_NOT_CANONICAL`,{method:t})}export{y as assertCanonicalV2Dto,d as buildAddLiquidityDto,p as buildCollectPositionFeesDto,m as buildCreatePoolDto,f as buildRemoveLiquidityDto,l as buildRequestTradeDto};
1
+ import{GSwapSDKError as e}from"../classes/gswap_sdk_error.js";import{assertCanonicalPair as t,isProposableTradingSymbol as n,validateFee as r,validateNumericAmount as i}from"./validation.js";import{assertTickRange as a}from"./ticks.js";import{assertUniqueKey as o}from"./unique_key.js";import s from"bignumber.js";const c=e=>new s(e).toFixed();function l(n){r(n.fee),t(n.token0,n.token1),o(n.uniqueKey);let a={token0:n.token0,token1:n.token1,fee:n.fee,uniqueKey:n.uniqueKey};if(`exactIn`in n){let t=n.exactIn;if(t===void 0)throw new e(`EXACT_AMOUNT_REQUIRED`,{field:`exactIn`});i(t,`exactIn`),a[n.tokenInIsToken0?`sell0Qty`:`sell1Qty`]=c(t),n.amountOutMinimum!==void 0&&(i(n.amountOutMinimum,`amountOutMinimum`,!0),a.amountOutMinimum=c(n.amountOutMinimum))}else{let t=n.exactOut;if(t===void 0)throw new e(`EXACT_AMOUNT_REQUIRED`,{field:`exactOut`});i(t,`exactOut`),a[n.tokenInIsToken0?`buy1Qty`:`buy0Qty`]=c(t),n.amountInMaximum!==void 0&&(i(n.amountInMaximum,`amountInMaximum`,!0),a.amountInMaximum=c(n.amountInMaximum))}return n.priceLimit!==void 0&&(i(n.priceLimit,`priceLimit`),a.priceLimit=c(n.priceLimit)),a}function u(e){r(e.fee),t(e.token0,e.token1),a(e.tickLower,e.tickUpper,e.fee),o(e.uniqueKey)}function d(t){u(t);let n=g(t.depositQuantityToken0,t.depositQuantityToken1,`depositQuantityToken0`,`depositQuantityToken1`);if(n===void 0)throw new e(`EXACTLY_ONE_OF_REQUIRED`,{first:`depositQuantityToken0`,second:`depositQuantityToken1`});return i(n.amount,n.name),{token0:t.token0,token1:t.token1,fee:t.fee,tickLower:t.tickLower,tickUpper:t.tickUpper,uniqueKey:t.uniqueKey,[n.name]:c(n.amount)}}function f(e){u(e);let t=g(e.withdrawalQuantityToken0,e.withdrawalQuantityToken1,`withdrawalQuantityToken0`,`withdrawalQuantityToken1`,!0);return t!==void 0&&i(t.amount,t.name),{token0:e.token0,token1:e.token1,fee:e.fee,tickLower:e.tickLower,tickUpper:e.tickUpper,uniqueKey:e.uniqueKey,...t===void 0?{}:{[t.name]:c(t.amount)}}}function p(e){return u(e),{token0:e.token0,token1:e.token1,fee:e.fee,tickLower:e.tickLower,tickUpper:e.tickUpper,uniqueKey:e.uniqueKey}}function m(i){r(i.fee),o(i.uniqueKey),t(i.token0Symbol,i.token1Symbol);for(let t of[i.token0Symbol,i.token1Symbol])if(!n(t))throw new e(`INVALID_TRADING_SYMBOL`,{symbol:t});for(let e of[i.token0Key,i.token1Key])h(e);let a=g(i.startingPrice,i.startingSqrtPrice,`startingPrice`,`startingSqrtPrice`);if(a===void 0)throw new e(`EXACTLY_ONE_OF_REQUIRED`,{first:`startingPrice`,second:`startingSqrtPrice`});if(typeof a.amount==`number`)throw new e(`AMOUNT_IS_JS_NUMBER`,{field:a.name});let c=new s(a.amount);if(!c.isFinite()||c.isLessThanOrEqualTo(0))throw new e(`INVALID_STARTING_PRICE`,{value:String(a.amount)});return{token0Key:i.token0Key,token1Key:i.token1Key,fee:i.fee,[a.name]:c.toFixed(),token0Symbol:i.token0Symbol,token1Symbol:i.token1Symbol,uniqueKey:i.uniqueKey,...i.name===void 0||i.name===``?{}:{name:i.name},...i.isPrivate===void 0?{}:{isPrivate:i.isPrivate},...i.privateAccess===void 0?{}:{privateAccess:i.privateAccess}}}function h(t){for(let n of[`collection`,`category`,`type`,`additionalKey`])if(typeof t[n]!=`string`||t[n].length===0)throw new e(`INCOMPLETE_TOKEN_CLASS_KEY`,{compositeKey:[t.collection,t.category,t.type,t.additionalKey].join(`$`),part:n})}function g(t,n,r,i,a=!1){if(t!==void 0&&n!==void 0)throw a?new e(`AT_MOST_ONE_OF_ALLOWED`,{first:r,second:i}):new e(`EXACTLY_ONE_OF_REQUIRED`,{first:r,second:i});if(t!==void 0)return{name:r,amount:t};if(n!==void 0)return{name:i,amount:n}}function _(t,n,r){return new e(`INVALID_DTO`,{method:t,field:n,expected:r})}function v(e,t){let n=n=>{let r=t[n];if(typeof r!=`string`)throw _(e,n,`string`);return r},r=n=>{let r=t[n];if(typeof r!=`number`)throw _(e,n,`number`);return r},i=e=>t[e]===void 0?void 0:n(e),a=n=>{let r=t[n];if(typeof r!=`object`||!r)throw _(e,n,`class_key`);let i=r,a=t=>{if(typeof i[t]!=`string`)throw _(e,`${n}.${t}`,`string`);return i[t]};return{collection:a(`collection`),category:a(`category`),type:a(`type`),additionalKey:a(`additionalKey`)}},o=()=>({token0:n(`token0`),token1:n(`token1`),fee:r(`fee`)}),s=n(`uniqueKey`),c=()=>({...o(),uniqueKey:s,tickLower:r(`tickLower`),tickUpper:r(`tickUpper`)});switch(e){case`RequestTrade`:{let r=[`sell0Qty`,`sell1Qty`,`buy0Qty`,`buy1Qty`].filter(e=>t[e]!==void 0),[a]=r;if(r.length!==1||a===void 0)throw _(e,`sell0Qty|sell1Qty|buy0Qty|buy1Qty`,`exactly_once`);let c=a===`sell0Qty`||a===`buy1Qty`,u={...o(),uniqueKey:s,tokenInIsToken0:c},d=i(`priceLimit`);return a.startsWith(`sell`)?l({...u,exactIn:n(a),amountOutMinimum:i(`amountOutMinimum`),priceLimit:d}):l({...u,exactOut:n(a),amountInMaximum:i(`amountInMaximum`),priceLimit:d})}case`AddLiquidity`:{let e=i(`depositQuantityToken0`),t=i(`depositQuantityToken1`);return d({...c(),...e===void 0?{depositQuantityToken1:t}:{depositQuantityToken0:e}})}case`RemoveLiquidity`:return f({...c(),withdrawalQuantityToken0:i(`withdrawalQuantityToken0`),withdrawalQuantityToken1:i(`withdrawalQuantityToken1`)});case`CollectPositionFees`:return p(c());case`CreatePool`:{let o=i(`startingPrice`),c=i(`startingSqrtPrice`),l=t.privateAccess;if(l!==void 0&&(!Array.isArray(l)||l.some(e=>typeof e!=`string`)))throw _(e,`privateAccess`,`string_array`);if(t.isPrivate!==void 0&&typeof t.isPrivate!=`boolean`)throw _(e,`isPrivate`,`boolean`);return m({token0Key:a(`token0Key`),token1Key:a(`token1Key`),token0Symbol:n(`token0Symbol`),token1Symbol:n(`token1Symbol`),fee:r(`fee`),uniqueKey:s,name:i(`name`),isPrivate:t.isPrivate,privateAccess:l,...o===void 0?{startingSqrtPrice:c}:{startingPrice:o}})}}}function y(t,n){let r=v(t,n);if(JSON.stringify(r)!==JSON.stringify(n))throw new e(`DTO_NOT_CANONICAL`,{method:t})}export{y as assertCanonicalV2Dto,d as buildAddLiquidityDto,p as buildCollectPositionFeesDto,m as buildCreatePoolDto,f as buildRemoveLiquidityDto,l as buildRequestTradeDto};
2
2
  //# sourceMappingURL=dto_builders.js.map