@gala-chain/gswap-sdk 2.0.0 → 2.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/browser/classes/apply_results.js.map +1 -1
- package/dist/browser/classes/assets.js.map +1 -1
- package/dist/browser/classes/dex_fees.js +1 -1
- package/dist/browser/classes/dex_fees.js.map +1 -1
- package/dist/browser/classes/gateway.js +1 -1
- package/dist/browser/classes/gateway.js.map +1 -1
- package/dist/browser/classes/gdex_stream.js +1 -1
- package/dist/browser/classes/gdex_stream.js.map +1 -1
- package/dist/browser/classes/gswap.js +1 -1
- package/dist/browser/classes/gswap.js.map +1 -1
- package/dist/browser/classes/gswap_error_catalog.js +1 -1
- package/dist/browser/classes/gswap_error_catalog.js.map +1 -1
- package/dist/browser/classes/gswap_error_phase_table.js +1 -1
- package/dist/browser/classes/gswap_error_phase_table.js.map +1 -1
- package/dist/browser/classes/gswap_sdk_error.js +1 -1
- package/dist/browser/classes/gswap_sdk_error.js.map +1 -1
- package/dist/browser/classes/http_client.js.map +1 -1
- package/dist/browser/classes/leaderboard.js.map +1 -1
- package/dist/browser/classes/market.js.map +1 -1
- package/dist/browser/classes/onramper.js.map +1 -1
- package/dist/browser/classes/pending_swap_fate.js.map +1 -1
- package/dist/browser/classes/pending_swaps.js +1 -1
- package/dist/browser/classes/pending_swaps.js.map +1 -1
- package/dist/browser/classes/pools.js +1 -1
- package/dist/browser/classes/pools.js.map +1 -1
- package/dist/browser/classes/positions.js +1 -1
- package/dist/browser/classes/positions.js.map +1 -1
- package/dist/browser/classes/quoting.js +1 -1
- package/dist/browser/classes/quoting.js.map +1 -1
- package/dist/browser/classes/shadow_submit.js.map +1 -1
- package/dist/browser/classes/storage_adapters.js.map +1 -1
- package/dist/browser/classes/submitted_transaction.js +1 -1
- package/dist/browser/classes/submitted_transaction.js.map +1 -1
- package/dist/browser/classes/swaps.js +1 -1
- package/dist/browser/classes/swaps.js.map +1 -1
- package/dist/browser/classes/symbols.js +1 -1
- package/dist/browser/classes/symbols.js.map +1 -1
- package/dist/browser/types/env.js.map +1 -1
- package/dist/browser/types/fees.js.map +1 -1
- package/dist/browser/types/market.js.map +1 -1
- package/dist/browser/utils/chain_contract.js +2 -0
- package/dist/browser/utils/chain_contract.js.map +1 -0
- package/dist/browser/utils/classification.js.map +1 -1
- package/dist/browser/utils/confirmation_schedule.js.map +1 -1
- package/dist/browser/utils/confirmation_state.js.map +1 -1
- package/dist/browser/utils/debug.js.map +1 -1
- package/dist/browser/utils/dto_builders.js.map +1 -1
- package/dist/browser/utils/failure_classification.js +1 -1
- package/dist/browser/utils/failure_classification.js.map +1 -1
- package/dist/browser/utils/failure_guards.js +1 -1
- package/dist/browser/utils/failure_guards.js.map +1 -1
- package/dist/browser/utils/lenient.js.map +1 -1
- package/dist/browser/utils/ordering.js.map +1 -1
- package/dist/browser/utils/reconnection.js +1 -1
- package/dist/browser/utils/reconnection.js.map +1 -1
- package/dist/browser/utils/resolve_pre_send.js.map +1 -1
- package/dist/browser/utils/server_message.js.map +1 -1
- package/dist/browser/utils/shadow_errors.js.map +1 -1
- package/dist/browser/utils/submit_state.js.map +1 -1
- package/dist/browser/utils/tick_align.js.map +1 -1
- package/dist/browser/utils/tick_math.js.map +1 -1
- package/dist/browser/utils/tick_range.js.map +1 -1
- package/dist/browser/utils/ticks.js.map +1 -1
- package/dist/browser/utils/validation.js.map +1 -1
- package/dist/index.cjs +23 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.mjs +23 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/defineProperty.js +0 -0
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/toPrimitive.js +0 -0
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/toPropertyKey.js +0 -0
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/typeof.js +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{isCatalogCode as e}from"../classes/gswap_error_phase_table.js";import{NOT_QUEUED_FINAL as t,classification as n}from"./classification.js";import{isWriteView as r,numberParamOf as i,stringParamOf as a,toFailureView as o}from"@gala-chain/gala-core-sdk";const s=n(`rejected`),c=n(`unknown`),l=n(`not_queued`),u=n(`not_sent`),d=n(`invalid_input`),f=n(`transient`),p={REQUEST_TIMEOUT:f,TRANSPORT_ERROR:f,REQUEST_FAILED:f,SUBMISSION_OUTCOME_UNKNOWN:c,GATEWAY_REPORTED_ERROR:c,GATEWAY_DATA_MISSING:c,GATEWAY_MODE_INVALID:c,GATEWAY_SYNC_REQUEST_TRADE:c,MISSING_UNIQUE_KEY:c,UNIQUE_KEY_MISMATCH:c,GATEWAY_WRITE_OUTCOME_UNKNOWN:c,GATEWAY_RESPONSE_INVALID:c,BRIDGE_RESPONSE_INVALID:c,BRIDGE_WRITE_OUTCOME_UNKNOWN:c,BRIDGE_OUT_OUTCOME_UNKNOWN:c,BRIDGE_DEPOSIT_OUTCOME_UNKNOWN:c,BRIDGE_STATUS_TIMEOUT:c,SHADOW_NOT_QUEUED:t,METHOD_NOT_ALLOWED:l,SIGNATURE_INVALID:l,SIGNER_MISMATCH:l,DTO_INVALID:l,BOUNDS_VIOLATION:l,SYMBOL_CONFLICT:l,RATE_LIMITED:l,GATEWAY_REJECTED:l,CHAIN_REJECTED:s,INVALID_CHAIN_RESPONSE:f,INVALID_POSITION_RESPONSE:f,GATEWAY_READ_REJECTED:f,GATEWAY_READ_RESPONSE_INVALID:f,BRIDGE_READ_RESPONSE_INVALID:f,BRIDGE_TOKEN_NOT_FOUND:d,TOKEN_NOT_WRAPPABLE:d,BRIDGE_CHAIN_READ_FAILED:f,TOKEN_CLASS_NOT_FOUND:d,PAGINATION_LIMIT_EXCEEDED:d,CONFIRMATION_TIMEOUT:c,CONFIRMATION_ABORTED:c,CONFIRMATION_FAILED:c,CONFIRMATION_MALFORMED:c,CONFIRMATION_KEY_MISMATCH:c,STREAM_DISCONNECTED:f,STREAM_REQUEST_TIMEOUT:f,STREAM_CONNECT_FAILED:f,STREAM_CLOSED_BEFORE_CONNECT:f,STREAM_CONNECTION_CLOSED:f,SIGNING_FAILED:u,KEY_PROVIDER_FAILED:u,TOKEN_RESOLUTION_FAILED:u,TOKEN_NAME_RESOLUTION_FAILED:u,NO_WALLET_ADDRESS:d,NO_POOL_AVAILABLE:d,INSUFFICIENT_LIQUIDITY:d};function m(e){return a(e,`reason`)===`no_key_provided`?u:d}function h(e){return e.status??i(e,`status`)}function g(e){let n=h(e);return n===void 0?c:r(e)?n===429?l:n===408||n>=500?c:t:n===408||n===429||n>=500?f:d}function _(e){return r(e)&&h(e)===409?c:g(e)}function v(e){return r(e)?t:d}function y(e){let t=e.status;return t===void 0||t===409||t>=500?c:t===422?s:l}function b(e){let t=e.status;return t===void 0||t===409||t>=500?c:s}function x(e,t={}){let n=S(o(e));return t.afterQueued===!0&&n.outcome!==`rejected`?{...n,retryable:!1}:n}function S(t){if(t===void 0)return{...c};if(!e(t.code))return t.outcome===void 0?{...c}:t.retryable===!1?n(t.outcome,{retryable:!1}):n(t.outcome);let{code:r}=t;return r===`HTTP_ERROR`||r===`GATEWAY_HTTP_ERROR`?{...g(t)}:r===`GALACONNECT_HTTP_ERROR`?{..._(t)}:r===`GATEWAY_WRITE_REJECTED`||r===`BRIDGE_REQUEST_REJECTED`?{...b(t)}:r===`UPDATE_REQUIRED`?{...v(t)}:r===`CHAIN_DISPATCH_FAILED`?{...y(t)}:r===`INVALID_PRIVATE_KEY`?{...m(t)}:{...p[r]??d}}function C(e){return x(e).outcome===`unknown`}export{x as classifyFailure,C as mayHaveBeenQueued};
|
|
1
|
+
import{isCatalogCode as e}from"../classes/gswap_error_phase_table.js";import{NOT_QUEUED_FINAL as t,classification as n}from"./classification.js";import{isWriteView as r,numberParamOf as i,stringParamOf as a,toFailureView as o}from"@gala-chain/gala-core-sdk";const s=n(`rejected`),c=n(`unknown`),l=n(`not_queued`),u=n(`not_sent`),d=n(`invalid_input`),f=n(`transient`),p={REQUEST_TIMEOUT:f,TRANSPORT_ERROR:f,REQUEST_FAILED:f,SUBMISSION_OUTCOME_UNKNOWN:c,GATEWAY_REPORTED_ERROR:c,GATEWAY_DATA_MISSING:c,GATEWAY_MODE_INVALID:c,GATEWAY_SYNC_REQUEST_TRADE:c,MISSING_UNIQUE_KEY:c,UNIQUE_KEY_MISMATCH:c,GATEWAY_WRITE_OUTCOME_UNKNOWN:c,GATEWAY_RESPONSE_INVALID:c,BRIDGE_RESPONSE_INVALID:c,BRIDGE_WRITE_OUTCOME_UNKNOWN:c,BRIDGE_OUT_OUTCOME_UNKNOWN:c,BRIDGE_DEPOSIT_OUTCOME_UNKNOWN:c,BRIDGE_STATUS_TIMEOUT:c,SHADOW_NOT_QUEUED:t,METHOD_NOT_ALLOWED:l,SIGNATURE_INVALID:l,SIGNER_MISMATCH:l,DTO_INVALID:l,DTO_OPERATION_MISMATCH:l,BOUNDS_VIOLATION:l,SYMBOL_CONFLICT:l,RATE_LIMITED:l,GATEWAY_REJECTED:l,CHAIN_REJECTED:s,INVALID_CHAIN_RESPONSE:f,INVALID_POSITION_RESPONSE:f,GATEWAY_READ_REJECTED:f,GATEWAY_READ_RESPONSE_INVALID:f,BRIDGE_READ_RESPONSE_INVALID:f,BRIDGE_TOKEN_NOT_FOUND:d,TOKEN_NOT_WRAPPABLE:d,BRIDGE_CHAIN_READ_FAILED:f,TOKEN_CLASS_NOT_FOUND:d,PAGINATION_LIMIT_EXCEEDED:d,CONFIRMATION_TIMEOUT:c,CONFIRMATION_ABORTED:c,CONFIRMATION_FAILED:c,CONFIRMATION_MALFORMED:c,CONFIRMATION_KEY_MISMATCH:c,STREAM_DISCONNECTED:f,STREAM_REQUEST_TIMEOUT:f,STREAM_CONNECT_FAILED:f,STREAM_CLOSED_BEFORE_CONNECT:f,STREAM_CONNECTION_CLOSED:f,SIGNING_FAILED:u,KEY_PROVIDER_FAILED:u,TOKEN_RESOLUTION_FAILED:u,TOKEN_NAME_RESOLUTION_FAILED:u,NO_WALLET_ADDRESS:d,NO_POOL_AVAILABLE:d,INSUFFICIENT_LIQUIDITY:d};function m(e){return a(e,`reason`)===`no_key_provided`?u:d}function h(e){return e.status??i(e,`status`)}function g(e){let n=h(e);return n===void 0?c:r(e)?n===429?l:n===408||n>=500?c:t:n===408||n===429||n>=500?f:d}function _(e){return r(e)&&h(e)===409?c:g(e)}function v(e){return r(e)?t:d}function y(e){let t=e.status;return t===void 0||t===409||t>=500?c:t===422?s:l}function b(e){let t=e.status;return t===void 0||t===409||t>=500?c:s}function x(e,t={}){let n=S(o(e));return t.afterQueued===!0&&n.outcome!==`rejected`?{...n,retryable:!1}:n}function S(t){if(t===void 0)return{...c};if(!e(t.code))return t.outcome===void 0?{...c}:t.retryable===!1?n(t.outcome,{retryable:!1}):n(t.outcome);let{code:r}=t;return r===`HTTP_ERROR`||r===`GATEWAY_HTTP_ERROR`?{...g(t)}:r===`GALACONNECT_HTTP_ERROR`?{..._(t)}:r===`GATEWAY_WRITE_REJECTED`||r===`BRIDGE_REQUEST_REJECTED`?{...b(t)}:r===`UPDATE_REQUIRED`?{...v(t)}:r===`CHAIN_DISPATCH_FAILED`?{...y(t)}:r===`INVALID_PRIVATE_KEY`?{...m(t)}:{...p[r]??d}}function C(e){return x(e).outcome===`unknown`}export{x as classifyFailure,C as mayHaveBeenQueued};
|
|
2
2
|
//# sourceMappingURL=failure_classification.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failure_classification.js","names":["REJECTED","classification","UNKNOWN","NOT_QUEUED","NOT_SENT","INVALID_INPUT","TRANSIENT","BY_CODE","NOT_QUEUED_FINAL","classifyInvalidPrivateKey","stringParamOf","view","statusOfView","numberParamOf","classifyHttpError","status","isWriteView","classifyGalaConnectHttpError","classifyUpdateRequired","classifyChainDispatchFailed","classifyGatewayWriteRejected","classifyFailure","result","classifyView","toFailureView","error","options","isCatalogCode","code","mayHaveBeenQueued"],"sources":["../../../src/utils/failure_classification.ts"],"sourcesContent":["import {\n isWriteView,\n numberParamOf,\n stringParamOf,\n toFailureView,\n type FailureView,\n type GALA_ERROR_CATALOG,\n} from '@gala-chain/gala-core-sdk';\nimport type { GSWAP_ERROR_CATALOG, GSwapErrorCode } from '../classes/gswap_error_catalog.js';\nimport { isCatalogCode } from '../classes/gswap_error_phase_table.js';\nimport { classification, NOT_QUEUED_FINAL, type FailureClassification } from './classification.js';\n\n/**\n * `classifyFailure` and `mayHaveBeenQueued`: the one module that holds the decision for every\n * catalog code (~135 names, a floor no minifier can remove). It needs the code table and nothing\n * else: the classification values live in `classification.ts`, the yes/no guards in\n * `failure_guards.ts`, and the error class and catalog are only named as types.\n */\n\nconst REJECTED: FailureClassification = classification('rejected');\nconst UNKNOWN: FailureClassification = classification('unknown');\nconst NOT_QUEUED: FailureClassification = classification('not_queued');\nconst NOT_SENT: FailureClassification = classification('not_sent');\nconst INVALID_INPUT: FailureClassification = classification('invalid_input');\nconst TRANSIENT: FailureClassification = classification('transient');\n\n/**\n * The classification of every code whose meaning does not depend on the failing answer. A code\n * missing here is a compile error (unless it is `pre_send`, see {@link CodeTable}), so adding a\n * catalog code forces a decision.\n */\nconst BY_CODE = {\n // ----------------------------------------------------------------------------------- transport\n REQUEST_TIMEOUT: TRANSIENT,\n TRANSPORT_ERROR: TRANSIENT,\n REQUEST_FAILED: TRANSIENT,\n\n // ------------------------------------------------------------------------------- write: unknown\n // No answer was read, or a 2xx answer that does not prove the write was queued under the signed\n // key: it may have been applied.\n SUBMISSION_OUTCOME_UNKNOWN: UNKNOWN,\n GATEWAY_REPORTED_ERROR: UNKNOWN,\n GATEWAY_DATA_MISSING: UNKNOWN,\n GATEWAY_MODE_INVALID: UNKNOWN,\n GATEWAY_SYNC_REQUEST_TRADE: UNKNOWN,\n MISSING_UNIQUE_KEY: UNKNOWN,\n UNIQUE_KEY_MISMATCH: UNKNOWN,\n // Core `GatewayWrites` (token-contract writes): no answer read, or a 2xx that proves nothing.\n GATEWAY_WRITE_OUTCOME_UNKNOWN: UNKNOWN,\n GATEWAY_RESPONSE_INVALID: UNKNOWN,\n // Core `./bridge` (GalaConnect bridge writes): a 2xx without the id or hash the next step needs,\n // or no answer read after the request left.\n BRIDGE_RESPONSE_INVALID: UNKNOWN,\n BRIDGE_WRITE_OUTCOME_UNKNOWN: UNKNOWN,\n // Any failure after GalaConnect accepted a bridge-out request: the tokens may be locked, so\n // never a retry under a fresh key, whatever the inner failure (a BridgeTokenOut 429 included).\n BRIDGE_OUT_OUTCOME_UNKNOWN: UNKNOWN,\n // A bridge-in deposit that failed once it was being sent (sending, confirming, registering): the\n // funds may have left the wallet. A status wait that timed out: the bridge may still complete.\n BRIDGE_DEPOSIT_OUTCOME_UNKNOWN: UNKNOWN,\n BRIDGE_STATUS_TIMEOUT: UNKNOWN,\n\n // --------------------------------------------------------------------- write: refused, not queued\n SHADOW_NOT_QUEUED: NOT_QUEUED_FINAL,\n METHOD_NOT_ALLOWED: NOT_QUEUED,\n SIGNATURE_INVALID: NOT_QUEUED,\n SIGNER_MISMATCH: NOT_QUEUED,\n DTO_INVALID: NOT_QUEUED,\n BOUNDS_VIOLATION: NOT_QUEUED,\n SYMBOL_CONFLICT: NOT_QUEUED,\n RATE_LIMITED: NOT_QUEUED,\n GATEWAY_REJECTED: NOT_QUEUED,\n\n // ----------------------------------------------------------------------- the chain's own verdict\n CHAIN_REJECTED: REJECTED,\n\n // ----------------------------------------------------------------------- reads of backend data\n INVALID_CHAIN_RESPONSE: TRANSIENT,\n INVALID_POSITION_RESPONSE: TRANSIENT,\n // Core `GatewayReads` (unsigned token-contract reads): nothing is applied, so a refusal or an\n // unusable answer is worth another try; a class that does not exist, or a data set larger than\n // the caller allowed, needs a different request.\n GATEWAY_READ_REJECTED: TRANSIENT,\n GATEWAY_READ_RESPONSE_INVALID: TRANSIENT,\n // Core `./bridge` GalaConnect reads (configurations, fee, status): the same as a gateway read;\n // a symbol GalaConnect has no verified configuration for needs a different request.\n BRIDGE_READ_RESPONSE_INVALID: TRANSIENT,\n BRIDGE_TOKEN_NOT_FOUND: INVALID_INPUT,\n // A token the wrappable list does not have (or its counterpart, or a channel a wrap does not\n // move between): a different request is needed.\n TOKEN_NOT_WRAPPABLE: INVALID_INPUT,\n // A failed or unusable read of the external chain before a bridge-in deposit: nothing was sent.\n BRIDGE_CHAIN_READ_FAILED: TRANSIENT,\n TOKEN_CLASS_NOT_FOUND: INVALID_INPUT,\n PAGINATION_LIMIT_EXCEEDED: INVALID_INPUT,\n\n // -------------------------------------------------------------------------------- confirmation\n CONFIRMATION_TIMEOUT: UNKNOWN,\n CONFIRMATION_ABORTED: UNKNOWN,\n CONFIRMATION_FAILED: UNKNOWN,\n CONFIRMATION_MALFORMED: UNKNOWN,\n CONFIRMATION_KEY_MISMATCH: UNKNOWN,\n\n // ------------------------------------------------------------------------------ the realtime stream\n STREAM_DISCONNECTED: TRANSIENT,\n STREAM_REQUEST_TIMEOUT: TRANSIENT,\n STREAM_CONNECT_FAILED: TRANSIENT,\n STREAM_CLOSED_BEFORE_CONNECT: TRANSIENT,\n STREAM_CONNECTION_CLOSED: TRANSIENT,\n\n // ----------------------------------------------- pre-send: an app-supplied callback failed\n // The signer, the key provider or the token resolver threw before anything was transmitted. The\n // original error is `cause`. A repeat cannot apply anything twice.\n SIGNING_FAILED: NOT_SENT,\n KEY_PROVIDER_FAILED: NOT_SENT,\n TOKEN_RESOLUTION_FAILED: NOT_SENT,\n TOKEN_NAME_RESOLUTION_FAILED: NOT_SENT,\n\n // ------------------------------------------- the call cannot work as written, found AFTER an answer\n // (a pre_send code needs no row: it is `invalid_input` by default, see `CodeTable`)\n NO_WALLET_ADDRESS: INVALID_INPUT,\n NO_POOL_AVAILABLE: INVALID_INPUT,\n INSUFFICIENT_LIQUIDITY: INVALID_INPUT,\n} as const satisfies CodeTable;\n\n/** Both catalogs as one type: every code a `GSwapSDKError` can carry reads its entry here. */\ntype Catalogs = typeof GALA_ERROR_CATALOG & typeof GSWAP_ERROR_CATALOG;\n\n/** A code (core or DEX) whose catalog phase is `pre_send`. */\ntype PreSendCode = {\n [C in GSwapErrorCode]: Catalogs[C]['phase'] extends 'pre_send' ? C : never;\n}[GSwapErrorCode];\n\n/** The codes whose classification depends on the failing answer, not on a table row. */\ntype AnswerDependentCode =\n | 'HTTP_ERROR'\n | 'UPDATE_REQUIRED'\n | 'CHAIN_DISPATCH_FAILED'\n | 'INVALID_PRIVATE_KEY'\n | 'GATEWAY_HTTP_ERROR'\n | 'GALACONNECT_HTTP_ERROR'\n | 'GATEWAY_WRITE_REJECTED'\n | 'BRIDGE_REQUEST_REJECTED';\n\n/**\n * Every code that is NOT `pre_send` needs a row (a new one is a compile error until it has one);\n * a `pre_send` code may have one (`SIGNING_FAILED` is `not_sent`). A `pre_send` code without a row\n * is `invalid_input`: nothing was transmitted, so it cannot be `unknown`, and it is not a\n * condition a repeat clears. That keeps the 90-odd validation codes out of the table, which is\n * what keeps `classifyFailure` small enough for an app shell.\n */\ntype CodeTable = {\n readonly [C in Exclude<GSwapErrorCode, PreSendCode | AnswerDependentCode>]: FailureClassification;\n} & {\n readonly [C in Exclude<PreSendCode, AnswerDependentCode>]?: FailureClassification;\n};\n\n/**\n * A key that is not valid is the input's fault (`invalid_input`), except `no_key_provided`: the\n * provider had nothing to give right now (a locked wallet, an empty slot). That is the same\n * situation as a provider that throws (`KEY_PROVIDER_FAILED`), and it clears once a key exists, so\n * it is `not_sent` and Retry is safe.\n */\nfunction classifyInvalidPrivateKey(view: FailureView): FailureClassification {\n return stringParamOf(view, 'reason') === 'no_key_provided' ? NOT_SENT : INVALID_INPUT;\n}\n\n/** The status of an HTTP failure: the one it carries, else its `status` param. */\nfunction statusOfView(view: FailureView): number | undefined {\n return view.status ?? numberParamOf(view, 'status');\n}\n\n/**\n * An HTTP failure with no gateway or chain code: its meaning depends on the status and on read vs\n * write. A view that states no status at all cannot be judged: `unknown`.\n */\nfunction classifyHttpError(view: FailureView): FailureClassification {\n const status = statusOfView(view);\n if (status === undefined) return UNKNOWN;\n if (isWriteView(view)) {\n // A gateway that answered 5xx or 408 may still have queued the write; 429 and 4xx did not.\n if (status === 429) return NOT_QUEUED;\n if (status === 408 || status >= 500) return UNKNOWN;\n return NOT_QUEUED_FINAL;\n }\n return status === 408 || status === 429 || status >= 500 ? TRANSIENT : INVALID_INPUT;\n}\n\n/**\n * A core `./bridge` GalaConnect HTTP failure: like {@link classifyHttpError}, except that a\n * WRITE answered 409 is `unknown`: GalaChain's \"this uniqueKey was already consumed\", after which\n * an earlier attempt under the key may be applied (a bridge-out that locked the tokens).\n */\nfunction classifyGalaConnectHttpError(view: FailureView): FailureClassification {\n return isWriteView(view) && statusOfView(view) === 409 ? UNKNOWN : classifyHttpError(view);\n}\n\n/**\n * The version wall (HTTP 426). On a write the gateway refused it before queueing anything, and a\n * repeat of the same app version is refused the same way, so it is `not_queued` with no Retry. On a\n * read nothing changed either, and only an update helps: `invalid_input`, no Retry. Both say \"show\n * the update screen\", not \"try again\".\n */\nfunction classifyUpdateRequired(view: FailureView): FailureClassification {\n return isWriteView(view) ? NOT_QUEUED_FINAL : INVALID_INPUT;\n}\n\n/**\n * The chain dispatch failed. The gateway echoes the upstream status: 409 is \"this uniqueKey was\n * already consumed\" (the first attempt may be applied), 422 is the chain evaluating the write and\n * refusing it (definite), another 5xx is an upstream outage after which the write may have landed,\n * and a 4xx is a refusal before anything was queued.\n */\nfunction classifyChainDispatchFailed(view: FailureView): FailureClassification {\n const status = view.status;\n if (status === undefined || status === 409 || status >= 500) return UNKNOWN;\n return status === 422 ? REJECTED : NOT_QUEUED;\n}\n\n/**\n * GalaChain answered a core `GatewayWrites` token-contract write with a `Status` other than 1: the\n * chain's verdict, so the write was not applied (`rejected`), except where the verdict does not\n * prove that: a 409 is \"this uniqueKey was already consumed\" (an earlier attempt under it may be\n * applied), and a 5xx, or no status at all, cannot be judged.\n */\nfunction classifyGatewayWriteRejected(view: FailureView): FailureClassification {\n const status = view.status;\n return status === undefined || status === 409 || status >= 500 ? UNKNOWN : REJECTED;\n}\n\n/**\n * Classifies any thrown value from its code (and, for a few codes, its HTTP status), never from\n * message text, so an app does not have to re-derive \"may I offer Retry?\" and \"is the outcome\n * unknown?\" for every code. The decision for each code is in this module's table; a new catalog\n * code cannot be added without one.\n *\n * A failure BEFORE the request left (`error.phase === 'pre_send'`, `isPreSendError`) can never be\n * `unknown` or `rejected`: it is `invalid_input` (the input has to change) or `not_sent` (nothing\n * was transmitted; a repeat is safe). Every app-supplied callback the SDK calls before it sends\n * (the signer, the key provider, a token resolver) has its failure wrapped into such an error\n * (`SIGNING_FAILED`, `KEY_PROVIDER_FAILED`, `TOKEN_RESOLUTION_FAILED`, the original as `cause`),\n * so an app NEVER needs an error class of its own to say \"nothing was sent\": a locked wallet,\n * a declined signature and a failed lookup all arrive as `not_sent`, retryable.\n *\n * It accepts a `GSwapSDKError` or a plain-object VIEW of one ({@link FailureView}: `{ code,\n * params?, status?, uniqueKey?, ... }`, the shape of the wrapper an app builds from an SDK error;\n * `toFailureView` reads any value), and decides from the same fields, so an app does not need to\n * keep the original error to ask. `{ afterQueued: true }` says the write is already queued (the\n * step being classified is a confirmation): `retryable` is then always `false`.\n *\n * Anything that is not an SDK error or such a view, or a view whose `code` the catalog does not\n * define, is `{ outcome: 'unknown', retryable: false }`: the SDK\n * cannot say what happened, and refusing Retry is the safe answer. That is only what escapes AFTER\n * the request left (an app requestor that rejects with its own error, a callback of yours that\n * throws once bytes were sent). An error your own code raises BEFORE it calls the SDK says so\n * itself: give it a code of its own and `outcome` (`{ code: 'POSITION_STALE', outcome: 'not_sent'\n * }`), and the SDK answers with that outcome's classification and `mayHaveBeenQueued` is `false`.\n * The declared `outcome` is read only for a code the catalog does not define.\n *\n * A failure is a WRITE's unless it states `write: false` (`GSwapSDKError.write`, set for every\n * SDK read): see {@link FailureView}. A view that lost its `uniqueKey` is therefore still judged as\n * a write (a 5xx stays `unknown`), never as a retryable read.\n *\n * To learn that a failure came from the dark (shadow) path, read `error.shadow` (a typed field of\n * every `GSwapSDKError`) or call `isShadowError(error)`, which also covers a non-SDK object that\n * escaped `swapShadow` / `submitSwapShadow` / `ChainGateway.submitShadow`. The classification is\n * the same as on the public path; an app that withholds Retry or a public fallback after a dark\n * swap applies that policy on top of `retryable`.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * const { outcome, retryable } = classifyFailure(error);\n * if (outcome === 'unknown') keepPendingAndConfirm(error); // never a second swap\n * else if (retryable) offerRetry(); // a new request under a fresh key\n * }\n * ```\n */\nexport function classifyFailure(\n error: unknown,\n options: ClassifyFailureOptions = {},\n): FailureClassification {\n const result = classifyView(toFailureView(error));\n // A `rejected` outcome is the chain's definite no: the queued write was evaluated and NOT\n // applied, so a new request under a fresh key cannot double-apply it and Retry stays as it is.\n return options.afterQueued === true && result.outcome !== 'rejected'\n ? { ...result, retryable: false }\n : result;\n}\n\n/** Options of {@link classifyFailure}. */\nexport interface ClassifyFailureOptions {\n /**\n * The write is ALREADY queued (the gateway acknowledged it with this `uniqueKey`), and what is\n * being classified is a later step: confirming it, reading its apply result. Whatever the\n * outcome, `retryable` is then `false`: a NEW request would be a second trade, so the app\n * confirms the same key (or forgets it) and never offers \"Try again\". `outcome` is unchanged.\n *\n * The one exception is `rejected`: the chain evaluated the queued write and refused it (an\n * apply result of `Status: 0`, `CHAIN_REJECTED`; a 422 dispatch). That PROVES it was not\n * applied, so a new request under a fresh key cannot make a second trade, and `retryable`\n * keeps the answer it has without this option (`true`). Every outcome that does not prove\n * \"not applied\" (`unknown`, `transient`, `not_queued`, ...) is `false`.\n */\n afterQueued?: boolean | undefined;\n}\n\n/**\n * The classification of a failure view: the table decision for its code, the status-dependent\n * decision for the codes whose meaning needs it, and for a code the catalog does not define\n * (a wallet error, an ethers `ACTION_REJECTED`, a typo, an app's own error): `unknown` unless the\n * view DECLARES its `outcome` (an app's error, `{ code: 'POSITION_STALE', outcome: 'not_sent' }`),\n * then the SDK's own classification of that outcome. A value with no view is `unknown`.\n */\nfunction classifyView(view: FailureView | undefined): FailureClassification {\n if (view === undefined) return { ...UNKNOWN };\n if (!isCatalogCode(view.code)) {\n if (view.outcome === undefined) return { ...UNKNOWN };\n // Withhold-only: `retryable: false` removes Retry from the declared outcome, never adds it.\n return view.retryable === false\n ? classification(view.outcome, { retryable: false })\n : classification(view.outcome);\n }\n const { code } = view;\n // A core gateway HTTP failure without a chain envelope reads exactly like HTTP_ERROR (by its\n // status, and read vs write); so does a GalaConnect one, except a write's 409.\n if (code === 'HTTP_ERROR' || code === 'GATEWAY_HTTP_ERROR') {\n return { ...classifyHttpError(view) };\n }\n if (code === 'GALACONNECT_HTTP_ERROR') return { ...classifyGalaConnectHttpError(view) };\n // GalaChain's refusal of a core gateway or GalaConnect bridge write: by the chain's code.\n if (code === 'GATEWAY_WRITE_REJECTED' || code === 'BRIDGE_REQUEST_REJECTED') {\n return { ...classifyGatewayWriteRejected(view) };\n }\n if (code === 'UPDATE_REQUIRED') return { ...classifyUpdateRequired(view) };\n if (code === 'CHAIN_DISPATCH_FAILED') return { ...classifyChainDispatchFailed(view) };\n if (code === 'INVALID_PRIVATE_KEY') return { ...classifyInvalidPrivateKey(view) };\n const row: FailureClassification | undefined = (\n BY_CODE as Readonly<Partial<Record<GSwapErrorCode, FailureClassification>>>\n )[code];\n return { ...(row ?? INVALID_INPUT) };\n}\n\n/**\n * True when the failed call was a WRITE that may nevertheless have been queued: its outcome is\n * `unknown` (`classifyFailure(error).outcome === 'unknown'`: a timeout or broken connection after\n * the request left, an acknowledgement that proves nothing, a gateway 409 or 5xx, a failed\n * confirmation). The app must keep `error.uniqueKey` and confirm it, and must NOT submit again\n * under a fresh key. Every other outcome (`rejected`, `not_queued`, `not_sent`, `invalid_input`,\n * `transient`) proves the write is not pending.\n *\n * A value the SDK cannot judge (an app requestor's own rejection after the request left) is\n * `unknown` too, so it is `true`; handle errors your own code raised BEFORE calling the SDK first.\n * Meant for the catch of a write; a read never has a pending key to keep.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * if (mayHaveBeenQueued(error)) keepPendingAndConfirm(error);\n * }\n * ```\n */\nexport function mayHaveBeenQueued(error: unknown): boolean {\n return classifyFailure(error).outcome === 'unknown';\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"failure_classification.js","names":["REJECTED","classification","UNKNOWN","NOT_QUEUED","NOT_SENT","INVALID_INPUT","TRANSIENT","BY_CODE","NOT_QUEUED_FINAL","classifyInvalidPrivateKey","stringParamOf","view","statusOfView","numberParamOf","classifyHttpError","status","isWriteView","classifyGalaConnectHttpError","classifyUpdateRequired","classifyChainDispatchFailed","classifyGatewayWriteRejected","classifyFailure","result","classifyView","toFailureView","error","options","isCatalogCode","code","mayHaveBeenQueued"],"sources":["../../../src/utils/failure_classification.ts"],"sourcesContent":["import {\n isWriteView,\n numberParamOf,\n stringParamOf,\n toFailureView,\n type FailureView,\n type GALA_ERROR_CATALOG,\n} from '@gala-chain/gala-core-sdk';\nimport type { GSWAP_ERROR_CATALOG, GSwapErrorCode } from '../classes/gswap_error_catalog.js';\nimport { isCatalogCode } from '../classes/gswap_error_phase_table.js';\nimport { classification, NOT_QUEUED_FINAL, type FailureClassification } from './classification.js';\n\n/**\n * `classifyFailure` and `mayHaveBeenQueued`: the one module that holds the decision for every\n * catalog code (~135 names, a floor no minifier can remove). It needs the code table and nothing\n * else: the classification values live in `classification.ts`, the yes/no guards in\n * `failure_guards.ts`, and the error class and catalog are only named as types.\n */\n\nconst REJECTED: FailureClassification = classification('rejected');\nconst UNKNOWN: FailureClassification = classification('unknown');\nconst NOT_QUEUED: FailureClassification = classification('not_queued');\nconst NOT_SENT: FailureClassification = classification('not_sent');\nconst INVALID_INPUT: FailureClassification = classification('invalid_input');\nconst TRANSIENT: FailureClassification = classification('transient');\n\n/**\n * The classification of every code whose meaning does not depend on the failing answer. A code\n * missing here is a compile error (unless it is `pre_send`, see {@link CodeTable}), so adding a\n * catalog code forces a decision.\n */\nconst BY_CODE = {\n // ----------------------------------------------------------------------------------- transport\n REQUEST_TIMEOUT: TRANSIENT,\n TRANSPORT_ERROR: TRANSIENT,\n REQUEST_FAILED: TRANSIENT,\n\n // ------------------------------------------------------------------------------- write: unknown\n // No answer was read, or a 2xx answer that does not prove the write was queued under the signed\n // key: it may have been applied.\n SUBMISSION_OUTCOME_UNKNOWN: UNKNOWN,\n GATEWAY_REPORTED_ERROR: UNKNOWN,\n GATEWAY_DATA_MISSING: UNKNOWN,\n GATEWAY_MODE_INVALID: UNKNOWN,\n GATEWAY_SYNC_REQUEST_TRADE: UNKNOWN,\n MISSING_UNIQUE_KEY: UNKNOWN,\n UNIQUE_KEY_MISMATCH: UNKNOWN,\n // Core `GatewayWrites` (token-contract writes): no answer read, or a 2xx that proves nothing.\n GATEWAY_WRITE_OUTCOME_UNKNOWN: UNKNOWN,\n GATEWAY_RESPONSE_INVALID: UNKNOWN,\n // Core `./bridge` (GalaConnect bridge writes): a 2xx without the id or hash the next step needs,\n // or no answer read after the request left.\n BRIDGE_RESPONSE_INVALID: UNKNOWN,\n BRIDGE_WRITE_OUTCOME_UNKNOWN: UNKNOWN,\n // Any failure after GalaConnect accepted a bridge-out request: the tokens may be locked, so\n // never a retry under a fresh key, whatever the inner failure (a BridgeTokenOut 429 included).\n BRIDGE_OUT_OUTCOME_UNKNOWN: UNKNOWN,\n // A bridge-in deposit that failed once it was being sent (sending, confirming, registering): the\n // funds may have left the wallet. A status wait that timed out: the bridge may still complete.\n BRIDGE_DEPOSIT_OUTCOME_UNKNOWN: UNKNOWN,\n BRIDGE_STATUS_TIMEOUT: UNKNOWN,\n\n // --------------------------------------------------------------------- write: refused, not queued\n SHADOW_NOT_QUEUED: NOT_QUEUED_FINAL,\n METHOD_NOT_ALLOWED: NOT_QUEUED,\n SIGNATURE_INVALID: NOT_QUEUED,\n SIGNER_MISMATCH: NOT_QUEUED,\n DTO_INVALID: NOT_QUEUED,\n DTO_OPERATION_MISMATCH: NOT_QUEUED,\n BOUNDS_VIOLATION: NOT_QUEUED,\n SYMBOL_CONFLICT: NOT_QUEUED,\n RATE_LIMITED: NOT_QUEUED,\n GATEWAY_REJECTED: NOT_QUEUED,\n\n // ----------------------------------------------------------------------- the chain's own verdict\n CHAIN_REJECTED: REJECTED,\n\n // ----------------------------------------------------------------------- reads of backend data\n INVALID_CHAIN_RESPONSE: TRANSIENT,\n INVALID_POSITION_RESPONSE: TRANSIENT,\n // Core `GatewayReads` (unsigned token-contract reads): nothing is applied, so a refusal or an\n // unusable answer is worth another try; a class that does not exist, or a data set larger than\n // the caller allowed, needs a different request.\n GATEWAY_READ_REJECTED: TRANSIENT,\n GATEWAY_READ_RESPONSE_INVALID: TRANSIENT,\n // Core `./bridge` GalaConnect reads (configurations, fee, status): the same as a gateway read;\n // a symbol GalaConnect has no verified configuration for needs a different request.\n BRIDGE_READ_RESPONSE_INVALID: TRANSIENT,\n BRIDGE_TOKEN_NOT_FOUND: INVALID_INPUT,\n // A token the wrappable list does not have (or its counterpart, or a channel a wrap does not\n // move between): a different request is needed.\n TOKEN_NOT_WRAPPABLE: INVALID_INPUT,\n // A failed or unusable read of the external chain before a bridge-in deposit: nothing was sent.\n BRIDGE_CHAIN_READ_FAILED: TRANSIENT,\n TOKEN_CLASS_NOT_FOUND: INVALID_INPUT,\n PAGINATION_LIMIT_EXCEEDED: INVALID_INPUT,\n\n // -------------------------------------------------------------------------------- confirmation\n CONFIRMATION_TIMEOUT: UNKNOWN,\n CONFIRMATION_ABORTED: UNKNOWN,\n CONFIRMATION_FAILED: UNKNOWN,\n CONFIRMATION_MALFORMED: UNKNOWN,\n CONFIRMATION_KEY_MISMATCH: UNKNOWN,\n\n // ------------------------------------------------------------------------------ the realtime stream\n STREAM_DISCONNECTED: TRANSIENT,\n STREAM_REQUEST_TIMEOUT: TRANSIENT,\n STREAM_CONNECT_FAILED: TRANSIENT,\n STREAM_CLOSED_BEFORE_CONNECT: TRANSIENT,\n STREAM_CONNECTION_CLOSED: TRANSIENT,\n\n // ----------------------------------------------- pre-send: an app-supplied callback failed\n // The signer, the key provider or the token resolver threw before anything was transmitted. The\n // original error is `cause`. A repeat cannot apply anything twice.\n SIGNING_FAILED: NOT_SENT,\n KEY_PROVIDER_FAILED: NOT_SENT,\n TOKEN_RESOLUTION_FAILED: NOT_SENT,\n TOKEN_NAME_RESOLUTION_FAILED: NOT_SENT,\n\n // ------------------------------------------- the call cannot work as written, found AFTER an answer\n // (a pre_send code needs no row: it is `invalid_input` by default, see `CodeTable`)\n NO_WALLET_ADDRESS: INVALID_INPUT,\n NO_POOL_AVAILABLE: INVALID_INPUT,\n INSUFFICIENT_LIQUIDITY: INVALID_INPUT,\n} as const satisfies CodeTable;\n\n/** Both catalogs as one type: every code a `GSwapSDKError` can carry reads its entry here. */\ntype Catalogs = typeof GALA_ERROR_CATALOG & typeof GSWAP_ERROR_CATALOG;\n\n/** A code (core or DEX) whose catalog phase is `pre_send`. */\ntype PreSendCode = {\n [C in GSwapErrorCode]: Catalogs[C]['phase'] extends 'pre_send' ? C : never;\n}[GSwapErrorCode];\n\n/** The codes whose classification depends on the failing answer, not on a table row. */\ntype AnswerDependentCode =\n | 'HTTP_ERROR'\n | 'UPDATE_REQUIRED'\n | 'CHAIN_DISPATCH_FAILED'\n | 'INVALID_PRIVATE_KEY'\n | 'GATEWAY_HTTP_ERROR'\n | 'GALACONNECT_HTTP_ERROR'\n | 'GATEWAY_WRITE_REJECTED'\n | 'BRIDGE_REQUEST_REJECTED';\n\n/**\n * Every code that is NOT `pre_send` needs a row (a new one is a compile error until it has one);\n * a `pre_send` code may have one (`SIGNING_FAILED` is `not_sent`). A `pre_send` code without a row\n * is `invalid_input`: nothing was transmitted, so it cannot be `unknown`, and it is not a\n * condition a repeat clears. That keeps the 90-odd validation codes out of the table, which is\n * what keeps `classifyFailure` small enough for an app shell.\n */\ntype CodeTable = {\n readonly [C in Exclude<GSwapErrorCode, PreSendCode | AnswerDependentCode>]: FailureClassification;\n} & {\n readonly [C in Exclude<PreSendCode, AnswerDependentCode>]?: FailureClassification;\n};\n\n/**\n * A key that is not valid is the input's fault (`invalid_input`), except `no_key_provided`: the\n * provider had nothing to give right now (a locked wallet, an empty slot). That is the same\n * situation as a provider that throws (`KEY_PROVIDER_FAILED`), and it clears once a key exists, so\n * it is `not_sent` and Retry is safe.\n */\nfunction classifyInvalidPrivateKey(view: FailureView): FailureClassification {\n return stringParamOf(view, 'reason') === 'no_key_provided' ? NOT_SENT : INVALID_INPUT;\n}\n\n/** The status of an HTTP failure: the one it carries, else its `status` param. */\nfunction statusOfView(view: FailureView): number | undefined {\n return view.status ?? numberParamOf(view, 'status');\n}\n\n/**\n * An HTTP failure with no gateway or chain code: its meaning depends on the status and on read vs\n * write. A view that states no status at all cannot be judged: `unknown`.\n */\nfunction classifyHttpError(view: FailureView): FailureClassification {\n const status = statusOfView(view);\n if (status === undefined) return UNKNOWN;\n if (isWriteView(view)) {\n // A gateway that answered 5xx or 408 may still have queued the write; 429 and 4xx did not.\n if (status === 429) return NOT_QUEUED;\n if (status === 408 || status >= 500) return UNKNOWN;\n return NOT_QUEUED_FINAL;\n }\n return status === 408 || status === 429 || status >= 500 ? TRANSIENT : INVALID_INPUT;\n}\n\n/**\n * A core `./bridge` GalaConnect HTTP failure: like {@link classifyHttpError}, except that a\n * WRITE answered 409 is `unknown`: GalaChain's \"this uniqueKey was already consumed\", after which\n * an earlier attempt under the key may be applied (a bridge-out that locked the tokens).\n */\nfunction classifyGalaConnectHttpError(view: FailureView): FailureClassification {\n return isWriteView(view) && statusOfView(view) === 409 ? UNKNOWN : classifyHttpError(view);\n}\n\n/**\n * The version wall (HTTP 426). On a write the gateway refused it before queueing anything, and a\n * repeat of the same app version is refused the same way, so it is `not_queued` with no Retry. On a\n * read nothing changed either, and only an update helps: `invalid_input`, no Retry. Both say \"show\n * the update screen\", not \"try again\".\n */\nfunction classifyUpdateRequired(view: FailureView): FailureClassification {\n return isWriteView(view) ? NOT_QUEUED_FINAL : INVALID_INPUT;\n}\n\n/**\n * The chain dispatch failed. The gateway echoes the upstream status: 409 is \"this uniqueKey was\n * already consumed\" (the first attempt may be applied), 422 is the chain evaluating the write and\n * refusing it (definite), another 5xx is an upstream outage after which the write may have landed,\n * and a 4xx is a refusal before anything was queued.\n */\nfunction classifyChainDispatchFailed(view: FailureView): FailureClassification {\n const status = view.status;\n if (status === undefined || status === 409 || status >= 500) return UNKNOWN;\n return status === 422 ? REJECTED : NOT_QUEUED;\n}\n\n/**\n * GalaChain answered a core `GatewayWrites` token-contract write with a `Status` other than 1: the\n * chain's verdict, so the write was not applied (`rejected`), except where the verdict does not\n * prove that: a 409 is \"this uniqueKey was already consumed\" (an earlier attempt under it may be\n * applied), and a 5xx, or no status at all, cannot be judged.\n */\nfunction classifyGatewayWriteRejected(view: FailureView): FailureClassification {\n const status = view.status;\n return status === undefined || status === 409 || status >= 500 ? UNKNOWN : REJECTED;\n}\n\n/**\n * Classifies any thrown value from its code (and, for a few codes, its HTTP status), never from\n * message text, so an app does not have to re-derive \"may I offer Retry?\" and \"is the outcome\n * unknown?\" for every code. The decision for each code is in this module's table; a new catalog\n * code cannot be added without one.\n *\n * A failure BEFORE the request left (`error.phase === 'pre_send'`, `isPreSendError`) can never be\n * `unknown` or `rejected`: it is `invalid_input` (the input has to change) or `not_sent` (nothing\n * was transmitted; a repeat is safe). Every app-supplied callback the SDK calls before it sends\n * (the signer, the key provider, a token resolver) has its failure wrapped into such an error\n * (`SIGNING_FAILED`, `KEY_PROVIDER_FAILED`, `TOKEN_RESOLUTION_FAILED`, the original as `cause`),\n * so an app NEVER needs an error class of its own to say \"nothing was sent\": a locked wallet,\n * a declined signature and a failed lookup all arrive as `not_sent`, retryable.\n *\n * It accepts a `GSwapSDKError` or a plain-object VIEW of one ({@link FailureView}: `{ code,\n * params?, status?, uniqueKey?, ... }`, the shape of the wrapper an app builds from an SDK error;\n * `toFailureView` reads any value), and decides from the same fields, so an app does not need to\n * keep the original error to ask. `{ afterQueued: true }` says the write is already queued (the\n * step being classified is a confirmation): `retryable` is then always `false`.\n *\n * Anything that is not an SDK error or such a view, or a view whose `code` the catalog does not\n * define, is `{ outcome: 'unknown', retryable: false }`: the SDK\n * cannot say what happened, and refusing Retry is the safe answer. That is only what escapes AFTER\n * the request left (an app requestor that rejects with its own error, a callback of yours that\n * throws once bytes were sent). An error your own code raises BEFORE it calls the SDK says so\n * itself: give it a code of its own and `outcome` (`{ code: 'POSITION_STALE', outcome: 'not_sent'\n * }`), and the SDK answers with that outcome's classification and `mayHaveBeenQueued` is `false`.\n * The declared `outcome` is read only for a code the catalog does not define.\n *\n * A failure is a WRITE's unless it states `write: false` (`GSwapSDKError.write`, set for every\n * SDK read): see {@link FailureView}. A view that lost its `uniqueKey` is therefore still judged as\n * a write (a 5xx stays `unknown`), never as a retryable read.\n *\n * To learn that a failure came from the dark (shadow) path, read `error.shadow` (a typed field of\n * every `GSwapSDKError`) or call `isShadowError(error)`, which also covers a non-SDK object that\n * escaped `swapShadow` / `submitSwapShadow` / `ChainGateway.submitShadow`. The classification is\n * the same as on the public path; an app that withholds Retry or a public fallback after a dark\n * swap applies that policy on top of `retryable`.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * const { outcome, retryable } = classifyFailure(error);\n * if (outcome === 'unknown') keepPendingAndConfirm(error); // never a second swap\n * else if (retryable) offerRetry(); // a new request under a fresh key\n * }\n * ```\n */\nexport function classifyFailure(\n error: unknown,\n options: ClassifyFailureOptions = {},\n): FailureClassification {\n const result = classifyView(toFailureView(error));\n // A `rejected` outcome is the chain's definite no: the queued write was evaluated and NOT\n // applied, so a new request under a fresh key cannot double-apply it and Retry stays as it is.\n return options.afterQueued === true && result.outcome !== 'rejected'\n ? { ...result, retryable: false }\n : result;\n}\n\n/** Options of {@link classifyFailure}. */\nexport interface ClassifyFailureOptions {\n /**\n * The write is ALREADY queued (the gateway acknowledged it with this `uniqueKey`), and what is\n * being classified is a later step: confirming it, reading its apply result. Whatever the\n * outcome, `retryable` is then `false`: a NEW request would be a second trade, so the app\n * confirms the same key (or forgets it) and never offers \"Try again\". `outcome` is unchanged.\n *\n * The one exception is `rejected`: the chain evaluated the queued write and refused it (an\n * apply result of `Status: 0`, `CHAIN_REJECTED`; a 422 dispatch). That PROVES it was not\n * applied, so a new request under a fresh key cannot make a second trade, and `retryable`\n * keeps the answer it has without this option (`true`). Every outcome that does not prove\n * \"not applied\" (`unknown`, `transient`, `not_queued`, ...) is `false`.\n */\n afterQueued?: boolean | undefined;\n}\n\n/**\n * The classification of a failure view: the table decision for its code, the status-dependent\n * decision for the codes whose meaning needs it, and for a code the catalog does not define\n * (a wallet error, an ethers `ACTION_REJECTED`, a typo, an app's own error): `unknown` unless the\n * view DECLARES its `outcome` (an app's error, `{ code: 'POSITION_STALE', outcome: 'not_sent' }`),\n * then the SDK's own classification of that outcome. A value with no view is `unknown`.\n */\nfunction classifyView(view: FailureView | undefined): FailureClassification {\n if (view === undefined) return { ...UNKNOWN };\n if (!isCatalogCode(view.code)) {\n if (view.outcome === undefined) return { ...UNKNOWN };\n // Withhold-only: `retryable: false` removes Retry from the declared outcome, never adds it.\n return view.retryable === false\n ? classification(view.outcome, { retryable: false })\n : classification(view.outcome);\n }\n const { code } = view;\n // A core gateway HTTP failure without a chain envelope reads exactly like HTTP_ERROR (by its\n // status, and read vs write); so does a GalaConnect one, except a write's 409.\n if (code === 'HTTP_ERROR' || code === 'GATEWAY_HTTP_ERROR') {\n return { ...classifyHttpError(view) };\n }\n if (code === 'GALACONNECT_HTTP_ERROR') return { ...classifyGalaConnectHttpError(view) };\n // GalaChain's refusal of a core gateway or GalaConnect bridge write: by the chain's code.\n if (code === 'GATEWAY_WRITE_REJECTED' || code === 'BRIDGE_REQUEST_REJECTED') {\n return { ...classifyGatewayWriteRejected(view) };\n }\n if (code === 'UPDATE_REQUIRED') return { ...classifyUpdateRequired(view) };\n if (code === 'CHAIN_DISPATCH_FAILED') return { ...classifyChainDispatchFailed(view) };\n if (code === 'INVALID_PRIVATE_KEY') return { ...classifyInvalidPrivateKey(view) };\n const row: FailureClassification | undefined = (\n BY_CODE as Readonly<Partial<Record<GSwapErrorCode, FailureClassification>>>\n )[code];\n return { ...(row ?? INVALID_INPUT) };\n}\n\n/**\n * True when the failed call was a WRITE that may nevertheless have been queued: its outcome is\n * `unknown` (`classifyFailure(error).outcome === 'unknown'`: a timeout or broken connection after\n * the request left, an acknowledgement that proves nothing, a gateway 409 or 5xx, a failed\n * confirmation). The app must keep `error.uniqueKey` and confirm it, and must NOT submit again\n * under a fresh key. Every other outcome (`rejected`, `not_queued`, `not_sent`, `invalid_input`,\n * `transient`) proves the write is not pending.\n *\n * A value the SDK cannot judge (an app requestor's own rejection after the request left) is\n * `unknown` too, so it is `true`; handle errors your own code raised BEFORE calling the SDK first.\n * Meant for the catch of a write; a read never has a pending key to keep.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * if (mayHaveBeenQueued(error)) keepPendingAndConfirm(error);\n * }\n * ```\n */\nexport function mayHaveBeenQueued(error: unknown): boolean {\n return classifyFailure(error).outcome === 'unknown';\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{isWriteView as e,stringParamOf as t,toFailureView as n}from"@gala-chain/gala-core-sdk";function r(e){let t=n(e);return t?.code===`CHAIN_DISPATCH_FAILED`&&t.status===409}const i=[`GATEWAY_DATA_MISSING`,`GATEWAY_MODE_INVALID`,`GATEWAY_SYNC_REQUEST_TRADE`,`MISSING_UNIQUE_KEY`,`UNIQUE_KEY_MISMATCH`];function a(e){return s(e,i)}function o(e,t){return t.some(t=>t===e)}function s(e,t){let r=n(e);return r!==void 0&&o(r.code,t)}const c=[`GATEWAY_REPORTED_ERROR`,`METHOD_NOT_ALLOWED`,`SIGNATURE_INVALID`,`SIGNER_MISMATCH`,`DTO_INVALID`,`BOUNDS_VIOLATION`,`SYMBOL_CONFLICT`,`RATE_LIMITED`,`CHAIN_DISPATCH_FAILED`,`GATEWAY_REJECTED`];function l(e){return s(e,c)}function u(e){return a(e)||s(e,[`GATEWAY_REPORTED_ERROR`])}function d(e){let r=n(e);if(r===void 0||r.code!==`CHAIN_REJECTED`&&r.code!==`CHAIN_DISPATCH_FAILED`)return;let i=t(r,`errorKey`);return i===void 0||i===``?void 0:i}const f=[`NO_POOL_AVAILABLE`,`INSUFFICIENT_LIQUIDITY`,`UNKNOWN_TOKEN`];function p(t){let r=n(t);return r===void 0?!1:o(r.code,f)?!0:!e(r)&&(r.notFound===!0||r.status===404)}export{d as chainErrorKeyOf,p as isNoMarket,l as isRelayableRefusal,u as isUninterpretedAnswer,r as isUniqueKeyConsumed,a as isUnprovenAcknowledgement};
|
|
1
|
+
import{isWriteView as e,stringParamOf as t,toFailureView as n}from"@gala-chain/gala-core-sdk";function r(e){let t=n(e);return t?.code===`CHAIN_DISPATCH_FAILED`&&t.status===409}const i=[`GATEWAY_DATA_MISSING`,`GATEWAY_MODE_INVALID`,`GATEWAY_SYNC_REQUEST_TRADE`,`MISSING_UNIQUE_KEY`,`UNIQUE_KEY_MISMATCH`];function a(e){return s(e,i)}function o(e,t){return t.some(t=>t===e)}function s(e,t){let r=n(e);return r!==void 0&&o(r.code,t)}const c=[`GATEWAY_REPORTED_ERROR`,`METHOD_NOT_ALLOWED`,`SIGNATURE_INVALID`,`SIGNER_MISMATCH`,`DTO_INVALID`,`DTO_OPERATION_MISMATCH`,`BOUNDS_VIOLATION`,`SYMBOL_CONFLICT`,`RATE_LIMITED`,`CHAIN_DISPATCH_FAILED`,`GATEWAY_REJECTED`];function l(e){return s(e,c)}function u(e){return a(e)||s(e,[`GATEWAY_REPORTED_ERROR`])}function d(e){let r=n(e);if(r===void 0||r.code!==`CHAIN_REJECTED`&&r.code!==`CHAIN_DISPATCH_FAILED`)return;let i=t(r,`errorKey`);return i===void 0||i===``?void 0:i}const f=[`NO_POOL_AVAILABLE`,`INSUFFICIENT_LIQUIDITY`,`UNKNOWN_TOKEN`];function p(t){let r=n(t);return r===void 0?!1:o(r.code,f)?!0:!e(r)&&(r.notFound===!0||r.status===404)}export{d as chainErrorKeyOf,p as isNoMarket,l as isRelayableRefusal,u as isUninterpretedAnswer,r as isUniqueKeyConsumed,a as isUnprovenAcknowledgement};
|
|
2
2
|
//# sourceMappingURL=failure_guards.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failure_guards.js","names":["isUniqueKeyConsumed","view","toFailureView","error","UNPROVEN_ACKNOWLEDGEMENT_CODES","isUnprovenAcknowledgement","hasCodeIn","isCodeIn","codes","known","code","RELAYABLE_REFUSAL_CODES","isRelayableRefusal","isUninterpretedAnswer","chainErrorKeyOf","errorKey","stringParamOf","NO_MARKET_CODES","isNoMarket","isWriteView"],"sources":["../../../src/utils/failure_guards.ts"],"sourcesContent":["import { isWriteView, stringParamOf, toFailureView } from '@gala-chain/gala-core-sdk';\nimport type { GSwapErrorCode } from '../classes/gswap_error_catalog.js';\nimport type { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/**\n * The yes/no questions an app asks about a failure from its CODE alone. They read only the failure\n * view and a short list of codes: no table of every code (that is `classifyFailure`'s, in\n * `failure_classification.ts`), no error class and no catalog (the imports above are types, erased\n * at build time). An app shell that imports one of them pays for this module and nothing else.\n */\n\n/**\n * True when the gateway answered that the write's `uniqueKey` was ALREADY CONSUMED: a\n * `CHAIN_DISPATCH_FAILED` with HTTP status 409. The first attempt under that key may be applied\n * (`classifyFailure` says `unknown`), so the app confirms the key it holds instead of submitting\n * again or showing the server's text. It replaces `error.code === 'CHAIN_DISPATCH_FAILED' &&\n * error.status === 409` and the regex on \"already saved\". Accepts an SDK error or a plain-object\n * view ({@link FailureView}: `code` and `status`); every other value is `false`.\n *\n * @example\n * ```ts\n * if (isUniqueKeyConsumed(error)) return confirmAndShowResult(error.uniqueKey);\n * ```\n */\nexport function isUniqueKeyConsumed(error: unknown): boolean {\n const view = toFailureView(error);\n return view?.code === 'CHAIN_DISPATCH_FAILED' && view.status === 409;\n}\n\nconst UNPROVEN_ACKNOWLEDGEMENT_CODES: readonly GSwapErrorCode[] = [\n 'GATEWAY_DATA_MISSING',\n 'GATEWAY_MODE_INVALID',\n 'GATEWAY_SYNC_REQUEST_TRADE',\n 'MISSING_UNIQUE_KEY',\n 'UNIQUE_KEY_MISMATCH',\n];\n\n/**\n * True when a write got a 2xx answer that does NOT prove it was queued under the signed key: no\n * `data`, an unreadable `mode`, a synchronous RequestTrade, or a missing or foreign `uniqueKey`.\n * The outcome is `unknown` (it may have been queued: confirm `error.uniqueKey`), and the copy an\n * app shows is one line for all five (\"the backend did not confirm it queued the request\"), so\n * the app asks this instead of keeping its own list of the codes. A gateway that says\n * `error: true` (`GATEWAY_REPORTED_ERROR`) is a refusal with its own message, not in this set.\n *\n * @example\n * ```ts\n * if (isUnprovenAcknowledgement(error)) keepPendingAndConfirm(error.uniqueKey);\n * ```\n */\nexport function isUnprovenAcknowledgement(error: unknown): boolean {\n return hasCodeIn(error, UNPROVEN_ACKNOWLEDGEMENT_CODES);\n}\n\n/** True when `code` is one of `codes` (a list of catalog codes), by exact spelling. */\nfunction isCodeIn(code: string, codes: readonly GSwapErrorCode[]): boolean {\n return codes.some((known) => known === code);\n}\n\n/**\n * True when `error` is an SDK error OR a plain-object view of one (see {@link FailureView}) whose\n * `code` is one of `codes`. The code is compared with the catalog's own spelling, so a wallet\n * error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.\n */\nfunction hasCodeIn(error: unknown, codes: readonly GSwapErrorCode[]): boolean {\n const view = toFailureView(error);\n // `codes` holds catalog codes only, so membership already means \"a catalog code\": no table needed.\n return view !== undefined && isCodeIn(view.code, codes);\n}\n\n/**\n * The codes whose `params.serverMessage` is the gateway's own answer to THIS write, which an app\n * may show as it is (and falls back to its own line when it is empty): a refusal the gateway made\n * (`GATEWAY_REPORTED_ERROR`, a 2xx with `error: true`) or a bounce it named (the gateway codes the\n * SDK knows, and `GATEWAY_REJECTED` for one it does not).\n */\nconst RELAYABLE_REFUSAL_CODES: readonly GSwapErrorCode[] = [\n 'GATEWAY_REPORTED_ERROR',\n 'METHOD_NOT_ALLOWED',\n 'SIGNATURE_INVALID',\n 'SIGNER_MISMATCH',\n 'DTO_INVALID',\n 'BOUNDS_VIOLATION',\n 'SYMBOL_CONFLICT',\n 'RATE_LIMITED',\n 'CHAIN_DISPATCH_FAILED',\n 'GATEWAY_REJECTED',\n];\n\n/**\n * True when the error is a gateway refusal whose `params.serverMessage` an app may relay to the\n * person as the gateway sent it: `GATEWAY_REPORTED_ERROR`, the gateway bounces (`METHOD_NOT_ALLOWED`,\n * `SIGNATURE_INVALID`, `SIGNER_MISMATCH`, `DTO_INVALID`, `BOUNDS_VIOLATION`, `SYMBOL_CONFLICT`,\n * `RATE_LIMITED`, `GATEWAY_REJECTED`) and `CHAIN_DISPATCH_FAILED`. The app shows `serverMessage` when\n * it is not empty and its own line when it is; the SDK's English `message` is never what to show.\n *\n * It accepts a plain-object view of an SDK error too ({@link FailureView}: an app's wrapper with a\n * `code`), and decides from the code in the same way. It narrows to `GSwapSDKError<...>` ONLY when\n * called with an SDK error; with an `unknown` or a view it answers `boolean` (narrow with\n * `isGSwapError` first, or read the view's own `params`).\n *\n * It is a test on the code alone, so it also holds for `CHAIN_DISPATCH_FAILED` with HTTP 409\n * (the `uniqueKey` was already consumed; `classifyFailure` says `unknown`): an app that words that\n * case itself (\"already submitted\", then confirm the key) checks `error.status === 409` BEFORE\n * relaying. It is false for `CHAIN_REJECTED` (the chain's verdict, worded by where it is shown: the\n * submit and confirm screens differ), for `HTTP_ERROR` (a proxy's page, not an answer to this\n * write) and for the five unproven acknowledgements (`isUnprovenAcknowledgement`: they carry no\n * server text).\n *\n * @example\n * ```ts\n * if (isRelayableRefusal(error)) show(error.params.serverMessage || t('swap.requestFailed'));\n * ```\n */\nexport function isRelayableRefusal(error: GSwapSDKError): error is GSwapSDKError<RelayableCode>;\nexport function isRelayableRefusal(error: unknown): boolean;\nexport function isRelayableRefusal(error: unknown): boolean {\n return hasCodeIn(error, RELAYABLE_REFUSAL_CODES);\n}\n\n/** The codes {@link isRelayableRefusal} is true for. */\nexport type RelayableCode =\n | 'GATEWAY_REPORTED_ERROR'\n | 'METHOD_NOT_ALLOWED'\n | 'SIGNATURE_INVALID'\n | 'SIGNER_MISMATCH'\n | 'DTO_INVALID'\n | 'BOUNDS_VIOLATION'\n | 'SYMBOL_CONFLICT'\n | 'RATE_LIMITED'\n | 'CHAIN_DISPATCH_FAILED'\n | 'GATEWAY_REJECTED';\n\n/**\n * True when a write got a 2xx answer the SDK refused to interpret, so the answer itself is in\n * `error.body` (or `error.bodyText`) for the app to read: the five unproven acknowledgements\n * (`isUnprovenAcknowledgement`) and `GATEWAY_REPORTED_ERROR` (a gateway that says `error: true`).\n * The outcome is `unknown` for all six. It replaces the app's own\n * `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')` pair.\n */\nexport function isUninterpretedAnswer(error: unknown): boolean {\n return isUnprovenAcknowledgement(error) || hasCodeIn(error, ['GATEWAY_REPORTED_ERROR']);\n}\n\n/**\n * The chain's own machine-readable `ErrorKey` of a failure (`'TOKEN_NOT_FOUND'`,\n * `'NOT_ENOUGH_LIQUIDITY'`, ...), for an app that maps a chain refusal to its own copy: the\n * `params.errorKey` of a `CHAIN_REJECTED` (an apply result, or a body that carries the chain's\n * error) and of a `CHAIN_DISPATCH_FAILED` (the gateway adds the chain's key to the body it\n * answered). `undefined` when the failure is neither, or when it carries no key (the gateway sent\n * none: the SDK writes `''`, which is not a key). Map the KEY, never the message text.\n *\n * Accepts an SDK error or a plain-object view ({@link FailureView}: `code` and `params`); every\n * other value is `undefined`. Other codes are `undefined` even when they have an `errorKey`-named\n * param, so a stray field cannot pass for a chain verdict.\n *\n * @example\n * ```ts\n * const key = chainErrorKeyOf(error);\n * if (key === 'NOT_ENOUGH_LIQUIDITY') showTooThin(); else showGeneric(error);\n * ```\n */\nexport function chainErrorKeyOf(error: unknown): string | undefined {\n const view = toFailureView(error);\n if (view === undefined) return undefined;\n if (view.code !== 'CHAIN_REJECTED' && view.code !== 'CHAIN_DISPATCH_FAILED') return undefined;\n const errorKey = stringParamOf(view, 'errorKey');\n return errorKey === undefined || errorKey === '' ? undefined : errorKey;\n}\n\n/** Codes that mean \"there is no market for this\" however the app reached them. */\nconst NO_MARKET_CODES: readonly GSwapErrorCode[] = [\n 'NO_POOL_AVAILABLE',\n 'INSUFFICIENT_LIQUIDITY',\n 'UNKNOWN_TOKEN',\n];\n\n/**\n * True when a failure means \"there is no market to trade this pair\": `NO_POOL_AVAILABLE` (no pool\n * at any fee tier), `INSUFFICIENT_LIQUIDITY` (a pool too thin to quote), `UNKNOWN_TOKEN` (the DEX\n * has no trading symbol for the token), or a READ that was answered 404 (a quote the backend\n * cannot find, `error.notFound`). It replaces an app's own `code === ... || code === ... ||\n * notFound` list, so the empty-state (\"No market for this pair\") has one definition.\n *\n * A write that was answered 404 (it carries a `uniqueKey`) is a missing route, not a missing\n * market, and is not this. Accepts an SDK error or a plain-object view ({@link FailureView}); every\n * other value is `false`.\n *\n * @example\n * ```ts\n * if (isNoMarket(error)) showEmptyState(t('swap.noMarket')); else showError(error);\n * ```\n */\nexport function isNoMarket(error: unknown): boolean {\n const view = toFailureView(error);\n if (view === undefined) return false;\n if (isCodeIn(view.code, NO_MARKET_CODES)) return true;\n return !isWriteView(view) && (view.notFound === true || view.status === 404);\n}\n"],"mappings":"8FAwBA,SAAgBA,EAAoB,EAAyB,CAC3D,IAAMC,EAAOC,EAAcC,CAAK,EAChC,OAAOF,GAAM,OAAS,yBAA2BA,EAAK,SAAW,GACnE,CAEA,MAAMG,EAA4D,CAChE,uBACA,uBACA,6BACA,qBACA,qBACF,EAeA,SAAgBC,EAA0B,EAAyB,CACjE,OAAOC,EAAUH,EAAOC,CAA8B,CACxD,CAGA,SAASG,EAAS,EAAc,EAA2C,CACzE,OAAOC,EAAM,KAAM,GAAUC,IAAUC,CAAI,CAC7C,CAOA,SAASJ,EAAU,EAAgB,EAA2C,CAC5E,IAAML,EAAOC,EAAcC,CAAK,EAEhC,OAAOF,IAAS,IAAA,IAAaM,EAASN,EAAK,KAAMO,CAAK,CACxD,CAQA,MAAMG,EAAqD,CACzD,yBACA,qBACA,oBACA,kBACA,cACA,mBACA,kBACA,eACA,wBACA,kBACF,EA6BA,SAAgBC,EAAmB,EAAyB,CAC1D,OAAON,EAAUH,EAAOQ,CAAuB,CACjD,CAsBA,SAAgBE,EAAsB,EAAyB,CAC7D,OAAOR,EAA0BF,CAAK,GAAKG,EAAUH,EAAO,CAAC,wBAAwB,CAAC,CACxF,CAoBA,SAAgBW,EAAgB,EAAoC,CAClE,IAAMb,EAAOC,EAAcC,CAAK,EAEhC,GADIF,IAAS,IAAA,IACTA,EAAK,OAAS,kBAAoBA,EAAK,OAAS,wBAAyB,OAC7E,IAAMc,EAAWC,EAAcf,EAAM,UAAU,EAC/C,OAAOc,IAAa,IAAA,IAAaA,IAAa,GAAK,IAAA,GAAYA,CACjE,CAGA,MAAME,EAA6C,CACjD,oBACA,yBACA,eACF,EAkBA,SAAgBC,EAAW,EAAyB,CAClD,IAAMjB,EAAOC,EAAcC,CAAK,EAGhC,OAFIF,IAAS,IAAA,GAAkB,GAC3BM,EAASN,EAAK,KAAMgB,CAAe,EAAU,GAC1C,CAACE,EAAYlB,CAAI,IAAMA,EAAK,WAAa,IAAQA,EAAK,SAAW,IAC1E"}
|
|
1
|
+
{"version":3,"file":"failure_guards.js","names":["isUniqueKeyConsumed","view","toFailureView","error","UNPROVEN_ACKNOWLEDGEMENT_CODES","isUnprovenAcknowledgement","hasCodeIn","isCodeIn","codes","known","code","RELAYABLE_REFUSAL_CODES","isRelayableRefusal","isUninterpretedAnswer","chainErrorKeyOf","errorKey","stringParamOf","NO_MARKET_CODES","isNoMarket","isWriteView"],"sources":["../../../src/utils/failure_guards.ts"],"sourcesContent":["import { isWriteView, stringParamOf, toFailureView } from '@gala-chain/gala-core-sdk';\nimport type { GSwapErrorCode } from '../classes/gswap_error_catalog.js';\nimport type { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/**\n * The yes/no questions an app asks about a failure from its CODE alone. They read only the failure\n * view and a short list of codes: no table of every code (that is `classifyFailure`'s, in\n * `failure_classification.ts`), no error class and no catalog (the imports above are types, erased\n * at build time). An app shell that imports one of them pays for this module and nothing else.\n */\n\n/**\n * True when the gateway answered that the write's `uniqueKey` was ALREADY CONSUMED: a\n * `CHAIN_DISPATCH_FAILED` with HTTP status 409. The first attempt under that key may be applied\n * (`classifyFailure` says `unknown`), so the app confirms the key it holds instead of submitting\n * again or showing the server's text. It replaces `error.code === 'CHAIN_DISPATCH_FAILED' &&\n * error.status === 409` and the regex on \"already saved\". Accepts an SDK error or a plain-object\n * view ({@link FailureView}: `code` and `status`); every other value is `false`.\n *\n * @example\n * ```ts\n * if (isUniqueKeyConsumed(error)) return confirmAndShowResult(error.uniqueKey);\n * ```\n */\nexport function isUniqueKeyConsumed(error: unknown): boolean {\n const view = toFailureView(error);\n return view?.code === 'CHAIN_DISPATCH_FAILED' && view.status === 409;\n}\n\nconst UNPROVEN_ACKNOWLEDGEMENT_CODES: readonly GSwapErrorCode[] = [\n 'GATEWAY_DATA_MISSING',\n 'GATEWAY_MODE_INVALID',\n 'GATEWAY_SYNC_REQUEST_TRADE',\n 'MISSING_UNIQUE_KEY',\n 'UNIQUE_KEY_MISMATCH',\n];\n\n/**\n * True when a write got a 2xx answer that does NOT prove it was queued under the signed key: no\n * `data`, an unreadable `mode`, a synchronous RequestTrade, or a missing or foreign `uniqueKey`.\n * The outcome is `unknown` (it may have been queued: confirm `error.uniqueKey`), and the copy an\n * app shows is one line for all five (\"the backend did not confirm it queued the request\"), so\n * the app asks this instead of keeping its own list of the codes. A gateway that says\n * `error: true` (`GATEWAY_REPORTED_ERROR`) is a refusal with its own message, not in this set.\n *\n * @example\n * ```ts\n * if (isUnprovenAcknowledgement(error)) keepPendingAndConfirm(error.uniqueKey);\n * ```\n */\nexport function isUnprovenAcknowledgement(error: unknown): boolean {\n return hasCodeIn(error, UNPROVEN_ACKNOWLEDGEMENT_CODES);\n}\n\n/** True when `code` is one of `codes` (a list of catalog codes), by exact spelling. */\nfunction isCodeIn(code: string, codes: readonly GSwapErrorCode[]): boolean {\n return codes.some((known) => known === code);\n}\n\n/**\n * True when `error` is an SDK error OR a plain-object view of one (see {@link FailureView}) whose\n * `code` is one of `codes`. The code is compared with the catalog's own spelling, so a wallet\n * error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.\n */\nfunction hasCodeIn(error: unknown, codes: readonly GSwapErrorCode[]): boolean {\n const view = toFailureView(error);\n // `codes` holds catalog codes only, so membership already means \"a catalog code\": no table needed.\n return view !== undefined && isCodeIn(view.code, codes);\n}\n\n/**\n * The codes whose `params.serverMessage` is the gateway's own answer to THIS write, which an app\n * may show as it is (and falls back to its own line when it is empty): a refusal the gateway made\n * (`GATEWAY_REPORTED_ERROR`, a 2xx with `error: true`) or a bounce it named (the gateway codes the\n * SDK knows, and `GATEWAY_REJECTED` for one it does not).\n */\nconst RELAYABLE_REFUSAL_CODES: readonly GSwapErrorCode[] = [\n 'GATEWAY_REPORTED_ERROR',\n 'METHOD_NOT_ALLOWED',\n 'SIGNATURE_INVALID',\n 'SIGNER_MISMATCH',\n 'DTO_INVALID',\n 'DTO_OPERATION_MISMATCH',\n 'BOUNDS_VIOLATION',\n 'SYMBOL_CONFLICT',\n 'RATE_LIMITED',\n 'CHAIN_DISPATCH_FAILED',\n 'GATEWAY_REJECTED',\n];\n\n/**\n * True when the error is a gateway refusal whose `params.serverMessage` an app may relay to the\n * person as the gateway sent it: `GATEWAY_REPORTED_ERROR`, the gateway bounces (`METHOD_NOT_ALLOWED`,\n * `SIGNATURE_INVALID`, `SIGNER_MISMATCH`, `DTO_INVALID`, `DTO_OPERATION_MISMATCH`, `BOUNDS_VIOLATION`,\n * `SYMBOL_CONFLICT`, `RATE_LIMITED`, `GATEWAY_REJECTED`) and `CHAIN_DISPATCH_FAILED`. The app shows `serverMessage` when\n * it is not empty and its own line when it is; the SDK's English `message` is never what to show.\n *\n * It accepts a plain-object view of an SDK error too ({@link FailureView}: an app's wrapper with a\n * `code`), and decides from the code in the same way. It narrows to `GSwapSDKError<...>` ONLY when\n * called with an SDK error; with an `unknown` or a view it answers `boolean` (narrow with\n * `isGSwapError` first, or read the view's own `params`).\n *\n * It is a test on the code alone, so it also holds for `CHAIN_DISPATCH_FAILED` with HTTP 409\n * (the `uniqueKey` was already consumed; `classifyFailure` says `unknown`): an app that words that\n * case itself (\"already submitted\", then confirm the key) checks `error.status === 409` BEFORE\n * relaying. It is false for `CHAIN_REJECTED` (the chain's verdict, worded by where it is shown: the\n * submit and confirm screens differ), for `HTTP_ERROR` (a proxy's page, not an answer to this\n * write) and for the five unproven acknowledgements (`isUnprovenAcknowledgement`: they carry no\n * server text).\n *\n * @example\n * ```ts\n * if (isRelayableRefusal(error)) show(error.params.serverMessage || t('swap.requestFailed'));\n * ```\n */\nexport function isRelayableRefusal(error: GSwapSDKError): error is GSwapSDKError<RelayableCode>;\nexport function isRelayableRefusal(error: unknown): boolean;\nexport function isRelayableRefusal(error: unknown): boolean {\n return hasCodeIn(error, RELAYABLE_REFUSAL_CODES);\n}\n\n/** The codes {@link isRelayableRefusal} is true for. */\nexport type RelayableCode =\n | 'GATEWAY_REPORTED_ERROR'\n | 'METHOD_NOT_ALLOWED'\n | 'SIGNATURE_INVALID'\n | 'SIGNER_MISMATCH'\n | 'DTO_INVALID'\n | 'DTO_OPERATION_MISMATCH'\n | 'BOUNDS_VIOLATION'\n | 'SYMBOL_CONFLICT'\n | 'RATE_LIMITED'\n | 'CHAIN_DISPATCH_FAILED'\n | 'GATEWAY_REJECTED';\n\n/**\n * True when a write got a 2xx answer the SDK refused to interpret, so the answer itself is in\n * `error.body` (or `error.bodyText`) for the app to read: the five unproven acknowledgements\n * (`isUnprovenAcknowledgement`) and `GATEWAY_REPORTED_ERROR` (a gateway that says `error: true`).\n * The outcome is `unknown` for all six. It replaces the app's own\n * `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')` pair.\n */\nexport function isUninterpretedAnswer(error: unknown): boolean {\n return isUnprovenAcknowledgement(error) || hasCodeIn(error, ['GATEWAY_REPORTED_ERROR']);\n}\n\n/**\n * The chain's own machine-readable `ErrorKey` of a failure (`'TOKEN_NOT_FOUND'`,\n * `'NOT_ENOUGH_LIQUIDITY'`, ...), for an app that maps a chain refusal to its own copy: the\n * `params.errorKey` of a `CHAIN_REJECTED` (an apply result, or a body that carries the chain's\n * error) and of a `CHAIN_DISPATCH_FAILED` (the gateway adds the chain's key to the body it\n * answered). `undefined` when the failure is neither, or when it carries no key (the gateway sent\n * none: the SDK writes `''`, which is not a key). Map the KEY, never the message text.\n *\n * Accepts an SDK error or a plain-object view ({@link FailureView}: `code` and `params`); every\n * other value is `undefined`. Other codes are `undefined` even when they have an `errorKey`-named\n * param, so a stray field cannot pass for a chain verdict.\n *\n * @example\n * ```ts\n * const key = chainErrorKeyOf(error);\n * if (key === 'NOT_ENOUGH_LIQUIDITY') showTooThin(); else showGeneric(error);\n * ```\n */\nexport function chainErrorKeyOf(error: unknown): string | undefined {\n const view = toFailureView(error);\n if (view === undefined) return undefined;\n if (view.code !== 'CHAIN_REJECTED' && view.code !== 'CHAIN_DISPATCH_FAILED') return undefined;\n const errorKey = stringParamOf(view, 'errorKey');\n return errorKey === undefined || errorKey === '' ? undefined : errorKey;\n}\n\n/** Codes that mean \"there is no market for this\" however the app reached them. */\nconst NO_MARKET_CODES: readonly GSwapErrorCode[] = [\n 'NO_POOL_AVAILABLE',\n 'INSUFFICIENT_LIQUIDITY',\n 'UNKNOWN_TOKEN',\n];\n\n/**\n * True when a failure means \"there is no market to trade this pair\": `NO_POOL_AVAILABLE` (no pool\n * at any fee tier), `INSUFFICIENT_LIQUIDITY` (a pool too thin to quote), `UNKNOWN_TOKEN` (the DEX\n * has no trading symbol for the token), or a READ that was answered 404 (a quote the backend\n * cannot find, `error.notFound`). It replaces an app's own `code === ... || code === ... ||\n * notFound` list, so the empty-state (\"No market for this pair\") has one definition.\n *\n * A write that was answered 404 (it carries a `uniqueKey`) is a missing route, not a missing\n * market, and is not this. Accepts an SDK error or a plain-object view ({@link FailureView}); every\n * other value is `false`.\n *\n * @example\n * ```ts\n * if (isNoMarket(error)) showEmptyState(t('swap.noMarket')); else showError(error);\n * ```\n */\nexport function isNoMarket(error: unknown): boolean {\n const view = toFailureView(error);\n if (view === undefined) return false;\n if (isCodeIn(view.code, NO_MARKET_CODES)) return true;\n return !isWriteView(view) && (view.notFound === true || view.status === 404);\n}\n"],"mappings":"A,8FAwBA,SAAgBA,EAAoB,EAAyB,CAC3D,IAAMC,EAAOC,EAAcC,CAAK,EAChC,OAAOF,GAAM,OAAS,yBAA2BA,EAAK,SAAW,GACnE,CAEA,MAAMG,EAA4D,CAChE,uBACA,uBACA,6BACA,qBACA,qBACF,EAeA,SAAgBC,EAA0B,EAAyB,CACjE,OAAOC,EAAUH,EAAOC,CAA8B,CACxD,CAGA,SAASG,EAAS,EAAc,EAA2C,CACzE,OAAOC,EAAM,KAAM,GAAUC,IAAUC,CAAI,CAC7C,CAOA,SAASJ,EAAU,EAAgB,EAA2C,CAC5E,IAAML,EAAOC,EAAcC,CAAK,EAEhC,OAAOF,IAAS,IAAA,IAAaM,EAASN,EAAK,KAAMO,CAAK,CACxD,CAQA,MAAMG,EAAqD,CACzD,yBACA,qBACA,oBACA,kBACA,cACA,yBACA,mBACA,kBACA,eACA,wBACA,kBACF,EA6BA,SAAgBC,EAAmB,EAAyB,CAC1D,OAAON,EAAUH,EAAOQ,CAAuB,CACjD,CAuBA,SAAgBE,EAAsB,EAAyB,CAC7D,OAAOR,EAA0BF,CAAK,GAAKG,EAAUH,EAAO,CAAC,wBAAwB,CAAC,CACxF,CAoBA,SAAgBW,EAAgB,EAAoC,CAClE,IAAMb,EAAOC,EAAcC,CAAK,EAEhC,GADIF,IAAS,IAAA,IACTA,EAAK,OAAS,kBAAoBA,EAAK,OAAS,wBAAyB,OAC7E,IAAMc,EAAWC,EAAcf,EAAM,UAAU,EAC/C,OAAOc,IAAa,IAAA,IAAaA,IAAa,GAAK,IAAA,GAAYA,CACjE,CAGA,MAAME,EAA6C,CACjD,oBACA,yBACA,eACF,EAkBA,SAAgBC,EAAW,EAAyB,CAClD,IAAMjB,EAAOC,EAAcC,CAAK,EAGhC,OAFIF,IAAS,IAAA,GAAkB,GAC3BM,EAASN,EAAK,KAAMgB,CAAe,EAAU,GAC1C,CAACE,EAAYlB,CAAI,IAAMA,EAAK,WAAa,IAAQA,EAAK,SAAW,IAC1E,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lenient.js","names":["entryOk","entryRejected","readEntries","data","GSwapSDKError","source","rows","parsed","parse","entry","onInvalidEntry","asEntryRecord","value","finiteNumberOf"],"sources":["../../../src/utils/lenient.ts"],"sourcesContent":["import { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/** One row of a list answer that the SDK skipped because it was not usable. */\nexport interface InvalidEntry {\n /** Which read the row came from. */\n source: 'pools' | 'symbols' | 'positions' | 'prices' | 'priceSeries' | 'seasons' | 'leaderboard';\n /**\n * Position of the row in the answer's array; for `prices` (an answer keyed by token), the\n * position of the token in the list asked for.\n */\n index: number;\n /** The row exactly as the backend sent it. */\n entry: unknown;\n /** Why it was skipped, in words. */\n reason: string;\n}\n\n/**\n * Called once per skipped row, in order, before the read resolves. It is a diagnostics hook: what it\n * does, or throws, never changes the result of the read.\n */\nexport type InvalidEntryHandler = (invalid: InvalidEntry) => void;\n\n/** The outcome of reading one row. */\nexport type EntryParse<T> = { ok: true; value: T } | { ok: false; reason: string };\n\n/** A usable row. */\nexport function entryOk<T>(value: T): EntryParse<T> {\n return { ok: true, value };\n}\n\n/** An unusable row, with the reason it is reported under. */\nexport function entryRejected<T>(reason: string): EntryParse<T> {\n return { ok: false, reason };\n}\n\n/**\n * Reads a list answer row by row: a row that cannot be used is skipped and reported, instead of\n * rejecting the whole list because of one bad row. An answer that is not a list at all is still\n * `INVALID_CHAIN_RESPONSE` (a read's: `write: false`): nothing in it can be trusted.\n */\nexport function readEntries<T>(\n source: InvalidEntry['source'],\n data: unknown,\n parse: (entry: unknown) => EntryParse<T>,\n onInvalidEntry?: InvalidEntryHandler,\n): T[] {\n if (!Array.isArray(data)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: `${source} list` },\n { body: data, write: false },\n );\n }\n const rows: T[] = [];\n (data as unknown[]).forEach((entry, index) => {\n const parsed = parse(entry);\n if (parsed.ok) {\n rows.push(parsed.value);\n return;\n }\n try {\n onInvalidEntry?.({ source, index, entry, reason: parsed.reason });\n } catch {\n // A diagnostics hook must not turn a lenient read into a failed one.\n }\n });\n return rows;\n}\n\n/** A plain JSON object (not null, not an array). */\nexport function asEntryRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** A finite number, or a non-empty numeric string, as a number; otherwise `undefined`. */\nexport function finiteNumberOf(value: unknown): number | undefined {\n if (typeof value === 'number') return Number.isFinite(value) ? value : undefined;\n if (typeof value === 'string' && value.trim() !== '') {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n"],"mappings":"8DA2BA,SAAgBA,EAAW,EAAyB,CAClD,MAAO,CAAE,GAAI,GAAM,OAAM,CAC3B,CAGA,SAAgBC,EAAiB,EAA+B,CAC9D,MAAO,CAAE,GAAI,GAAO,QAAO,CAC7B,CAOA,SAAgBC,EACd,EACA,EACA,EACA,EACK,CACL,GAAI,CAAC,MAAM,QAAQC,CAAI,EACrB,MAAM,IAAIC,EACR,yBACA,CAAE,SAAU,GAAGC,EAAO,MAAO,EAC7B,CAAE,KAAMF,EAAM,MAAO,EAAM,CAC7B,EAEF,IAAMG,EAAY,CAAC,EAanB,OAZAH,EAAoB,SAAS,EAAO,IAAU,CAC5C,IAAMI,EAASC,EAAMC,CAAK,EAC1B,GAAIF,EAAO,GACTD,EAAK,KAAKC,EAAO,KAAK,OAGxB,GAAI,CACFG,IAAiB,CAAE,SAAQ,QAAO,QAAO,OAAQH,EAAO,MAAO,CAAC,CAClE,MAAQ,CAER,CACF,CAAC,EACMD,CACT,CAGA,SAAgBK,EAAc,EAAqD,CACjF,OAAO,OAAOC,GAAU,UAAYA,GAAkB,CAAC,MAAM,QAAQA,CAAK,EACrEA,EACD,IAAA,EACN,CAGA,SAAgBC,EAAe,EAAoC,CACjE,GAAI,OAAOD,GAAU,SAAU,OAAO,OAAO,SAASA,CAAK,EAAIA,EAAQ,IAAA,GACvE,GAAI,OAAOA,GAAU,UAAYA,EAAM,KAAK,IAAM,GAAI,CACpD,IAAML,EAAS,OAAOK,CAAK,EAC3B,OAAO,OAAO,SAASL,CAAM,EAAIA,EAAS,IAAA,EAC5C,CAEF"}
|
|
1
|
+
{"version":3,"file":"lenient.js","names":["entryOk","entryRejected","readEntries","data","GSwapSDKError","source","rows","parsed","parse","entry","onInvalidEntry","asEntryRecord","value","finiteNumberOf"],"sources":["../../../src/utils/lenient.ts"],"sourcesContent":["import { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/** One row of a list answer that the SDK skipped because it was not usable. */\nexport interface InvalidEntry {\n /** Which read the row came from. */\n source: 'pools' | 'symbols' | 'positions' | 'prices' | 'priceSeries' | 'seasons' | 'leaderboard';\n /**\n * Position of the row in the answer's array; for `prices` (an answer keyed by token), the\n * position of the token in the list asked for.\n */\n index: number;\n /** The row exactly as the backend sent it. */\n entry: unknown;\n /** Why it was skipped, in words. */\n reason: string;\n}\n\n/**\n * Called once per skipped row, in order, before the read resolves. It is a diagnostics hook: what it\n * does, or throws, never changes the result of the read.\n */\nexport type InvalidEntryHandler = (invalid: InvalidEntry) => void;\n\n/** The outcome of reading one row. */\nexport type EntryParse<T> = { ok: true; value: T } | { ok: false; reason: string };\n\n/** A usable row. */\nexport function entryOk<T>(value: T): EntryParse<T> {\n return { ok: true, value };\n}\n\n/** An unusable row, with the reason it is reported under. */\nexport function entryRejected<T>(reason: string): EntryParse<T> {\n return { ok: false, reason };\n}\n\n/**\n * Reads a list answer row by row: a row that cannot be used is skipped and reported, instead of\n * rejecting the whole list because of one bad row. An answer that is not a list at all is still\n * `INVALID_CHAIN_RESPONSE` (a read's: `write: false`): nothing in it can be trusted.\n */\nexport function readEntries<T>(\n source: InvalidEntry['source'],\n data: unknown,\n parse: (entry: unknown) => EntryParse<T>,\n onInvalidEntry?: InvalidEntryHandler,\n): T[] {\n if (!Array.isArray(data)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: `${source} list` },\n { body: data, write: false },\n );\n }\n const rows: T[] = [];\n (data as unknown[]).forEach((entry, index) => {\n const parsed = parse(entry);\n if (parsed.ok) {\n rows.push(parsed.value);\n return;\n }\n try {\n onInvalidEntry?.({ source, index, entry, reason: parsed.reason });\n } catch {\n // A diagnostics hook must not turn a lenient read into a failed one.\n }\n });\n return rows;\n}\n\n/** A plain JSON object (not null, not an array). */\nexport function asEntryRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** A finite number, or a non-empty numeric string, as a number; otherwise `undefined`. */\nexport function finiteNumberOf(value: unknown): number | undefined {\n if (typeof value === 'number') return Number.isFinite(value) ? value : undefined;\n if (typeof value === 'string' && value.trim() !== '') {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n"],"mappings":"A,8DA2BA,SAAgBA,EAAW,EAAyB,CAClD,MAAO,CAAE,GAAI,GAAM,OAAM,CAC3B,CAGA,SAAgBC,EAAiB,EAA+B,CAC9D,MAAO,CAAE,GAAI,GAAO,QAAO,CAC7B,CAOA,SAAgBC,EACd,EACA,EACA,EACA,EACK,CACL,GAAI,CAAC,MAAM,QAAQC,CAAI,EACrB,MAAM,IAAIC,EACR,yBACA,CAAE,SAAU,GAAGC,EAAO,MAAO,EAC7B,CAAE,KAAMF,EAAM,MAAO,EAAM,CAC7B,EAEF,IAAMG,EAAY,CAAC,EAanB,OAZAH,EAAoB,SAAS,EAAO,IAAU,CAC5C,IAAMI,EAASC,EAAMC,CAAK,EAC1B,GAAIF,EAAO,GACTD,EAAK,KAAKC,EAAO,KAAK,OAGxB,GAAI,CACFG,IAAiB,CAAE,SAAQ,QAAO,QAAO,OAAQH,EAAO,MAAO,CAAC,CAClE,MAAQ,CAER,CACF,CAAC,EACMD,CACT,CAGA,SAAgBK,EAAc,EAAqD,CACjF,OAAO,OAAOC,GAAU,UAAYA,GAAkB,CAAC,MAAM,QAAQA,CAAK,EACrEA,EACD,IAAA,EACN,CAGA,SAAgBC,EAAe,EAAoC,CACjE,GAAI,OAAOD,GAAU,SAAU,OAAO,OAAO,SAASA,CAAK,EAAIA,EAAQ,IAAA,GACvE,GAAI,OAAOA,GAAU,UAAYA,EAAM,KAAK,IAAM,GAAI,CACpD,IAAML,EAAS,OAAOK,CAAK,EAC3B,OAAO,OAAO,SAASL,CAAM,EAAIA,EAAS,IAAA,EAC5C,CAEF,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ordering.js","names":["orderSymbols","a","b","readOrderedSymbols","value","token0","token1","record","\"token0\"","\"token1\"","GSwapSDKError","parseTokenClassKey","tokenClassKey","parsed","splitClassKey"],"sources":["../../../src/utils/ordering.ts"],"sourcesContent":["import { splitClassKey, type GalaChainTokenClassKey } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/** A symbol or a GalaChain token class key accepted by v2 operations. */\nexport type TokenRef = string | GalaChainTokenClassKey;\n\n/** Return two trading symbols in the contract's plain-string order. */\nexport function orderSymbols(a: string, b: string): [string, string] {\n return a < b ? [a, b] : [b, a];\n}\n\n/** Read an ordered symbol pair from a tuple or object returned by a boundary helper.\n *\n * @example\n * ```ts\n * const pair = readOrderedSymbols(['GALA', 'GUSDC']);\n * console.log(pair.token0);\n * ```\n */\nexport function readOrderedSymbols(value: unknown): { token0: string; token1: string } {\n if (Array.isArray(value) && value.length >= 2) {\n const token0 = (value as unknown[])[0];\n const token1 = (value as unknown[])[1];\n if (typeof token0 === 'string' && typeof token1 === 'string') return { token0, token1 };\n }\n if (typeof value === 'object' && value !== null) {\n const record = value as Record<string, unknown>;\n const token0 = record['token0'];\n const token1 = record['token1'];\n if (typeof token0 === 'string' && typeof token1 === 'string') return { token0, token1 };\n }\n throw new GSwapSDKError('UNORDERABLE_SYMBOLS', {\n received: Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value,\n });\n}\n\n/**\n * Parse a pipe- or dollar-separated token class key.\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. Nothing here says anything about the token's symbol: a class key carries\n * no symbol, which must come from the token class or trading-symbol registry.\n *\n * @example\n * ```ts\n * parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'\n * ```\n */\nexport function parseTokenClassKey(tokenClassKey: TokenRef): GalaChainTokenClassKey {\n if (typeof tokenClassKey === 'object') {\n return {\n collection: tokenClassKey.collection,\n category: tokenClassKey.category,\n type: tokenClassKey.type,\n additionalKey: tokenClassKey.additionalKey,\n };\n }\n\n const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes('|') ? '|' : '$');\n if (parsed === undefined) throw new GSwapSDKError('INVALID_TOKEN_CLASS_KEY', { tokenClassKey });\n return parsed;\n}\n"],"mappings":"wHAOA,SAAgBA,EAAa,EAAW,EAA6B,CACnE,OAAOC,EAAIC,EAAI,CAACD,EAAGC,CAAC,EAAI,CAACA,EAAGD,CAAC,CAC/B,CAUA,SAAgBE,EAAmB,EAAoD,CACrF,GAAI,MAAM,QAAQC,CAAK,GAAKA,EAAM,QAAU,EAAG,CAC7C,IAAMC,EAAUD,EAAoB,GAC9BE,EAAUF,EAAoB,GACpC,GAAI,OAAOC,GAAW,UAAY,OAAOC,GAAW,SAAU,MAAO,CAAE,SAAQ,QAAO,CACxF,CACA,GAAI,OAAOF,GAAU,UAAYA,EAAgB,CAC/C,IAAMG,EAASH,EACTC,EAASE,EAAOC,OAChBF,EAASC,EAAOE,OACtB,GAAI,OAAOJ,GAAW,UAAY,OAAOC,GAAW,SAAU,MAAO,CAAE,SAAQ,QAAO,CACxF,CACA,MAAM,IAAII,EAAc,sBAAuB,CAC7C,SAAU,MAAM,QAAQN,CAAK,EAAI,QAAUA,IAAU,KAAO,OAAS,OAAOA,CAC9E,CAAC,CACH,CAgBA,SAAgBO,EAAmB,EAAiD,CAClF,GAAI,OAAOC,GAAkB,SAC3B,MAAO,CACL,WAAYA,EAAc,WAC1B,SAAUA,EAAc,SACxB,KAAMA,EAAc,KACpB,cAAeA,EAAc,aAC/B,EAGF,IAAMC,EAASC,EAAcF,EAAeA,EAAc,SAAS,GAAG,EAAI,IAAM,GAAG,EACnF,GAAIC,IAAW,IAAA,GAAW,MAAM,IAAIH,EAAc,0BAA2B,CAAE,eAAc,CAAC,EAC9F,OAAOG,CACT"}
|
|
1
|
+
{"version":3,"file":"ordering.js","names":["orderSymbols","a","b","readOrderedSymbols","value","token0","token1","record","\"token0\"","\"token1\"","GSwapSDKError","parseTokenClassKey","tokenClassKey","parsed","splitClassKey"],"sources":["../../../src/utils/ordering.ts"],"sourcesContent":["import { splitClassKey, type GalaChainTokenClassKey } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/** A symbol or a GalaChain token class key accepted by v2 operations. */\nexport type TokenRef = string | GalaChainTokenClassKey;\n\n/** Return two trading symbols in the contract's plain-string order. */\nexport function orderSymbols(a: string, b: string): [string, string] {\n return a < b ? [a, b] : [b, a];\n}\n\n/** Read an ordered symbol pair from a tuple or object returned by a boundary helper.\n *\n * @example\n * ```ts\n * const pair = readOrderedSymbols(['GALA', 'GUSDC']);\n * console.log(pair.token0);\n * ```\n */\nexport function readOrderedSymbols(value: unknown): { token0: string; token1: string } {\n if (Array.isArray(value) && value.length >= 2) {\n const token0 = (value as unknown[])[0];\n const token1 = (value as unknown[])[1];\n if (typeof token0 === 'string' && typeof token1 === 'string') return { token0, token1 };\n }\n if (typeof value === 'object' && value !== null) {\n const record = value as Record<string, unknown>;\n const token0 = record['token0'];\n const token1 = record['token1'];\n if (typeof token0 === 'string' && typeof token1 === 'string') return { token0, token1 };\n }\n throw new GSwapSDKError('UNORDERABLE_SYMBOLS', {\n received: Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value,\n });\n}\n\n/**\n * Parse a pipe- or dollar-separated token class key.\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. Nothing here says anything about the token's symbol: a class key carries\n * no symbol, which must come from the token class or trading-symbol registry.\n *\n * @example\n * ```ts\n * parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'\n * ```\n */\nexport function parseTokenClassKey(tokenClassKey: TokenRef): GalaChainTokenClassKey {\n if (typeof tokenClassKey === 'object') {\n return {\n collection: tokenClassKey.collection,\n category: tokenClassKey.category,\n type: tokenClassKey.type,\n additionalKey: tokenClassKey.additionalKey,\n };\n }\n\n const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes('|') ? '|' : '$');\n if (parsed === undefined) throw new GSwapSDKError('INVALID_TOKEN_CLASS_KEY', { tokenClassKey });\n return parsed;\n}\n"],"mappings":"A,wHAOA,SAAgBA,EAAa,EAAW,EAA6B,CACnE,OAAOC,EAAIC,EAAI,CAACD,EAAGC,CAAC,EAAI,CAACA,EAAGD,CAAC,CAC/B,CAUA,SAAgBE,EAAmB,EAAoD,CACrF,GAAI,MAAM,QAAQC,CAAK,GAAKA,EAAM,QAAU,EAAG,CAC7C,IAAMC,EAAUD,EAAoB,GAC9BE,EAAUF,EAAoB,GACpC,GAAI,OAAOC,GAAW,UAAY,OAAOC,GAAW,SAAU,MAAO,CAAE,SAAQ,QAAO,CACxF,CACA,GAAI,OAAOF,GAAU,UAAYA,EAAgB,CAC/C,IAAMG,EAASH,EACTC,EAASE,EAAOC,OAChBF,EAASC,EAAOE,OACtB,GAAI,OAAOJ,GAAW,UAAY,OAAOC,GAAW,SAAU,MAAO,CAAE,SAAQ,QAAO,CACxF,CACA,MAAM,IAAII,EAAc,sBAAuB,CAC7C,SAAU,MAAM,QAAQN,CAAK,EAAI,QAAUA,IAAU,KAAO,OAAS,OAAOA,CAC9E,CAAC,CACH,CAgBA,SAAgBO,EAAmB,EAAiD,CAClF,GAAI,OAAOC,GAAkB,SAC3B,MAAO,CACL,WAAYA,EAAc,WAC1B,SAAUA,EAAc,SACxB,KAAMA,EAAc,KACpB,cAAeA,EAAc,aAC/B,EAGF,IAAMC,EAASC,EAAcF,EAAeA,EAAc,SAAS,GAAG,EAAI,IAAM,GAAG,EACnF,GAAIC,IAAW,IAAA,GAAW,MAAM,IAAIH,EAAc,0BAA2B,CAAE,eAAc,CAAC,EAC9F,OAAOG,CACT,C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from"../_virtual/_@oxc-project_runtime@0.154.0/helpers/esm/defineProperty.js";var t=class{constructor(t){this.options=t,e(this,`attempts`,0),e(this,`delayMs`,void 0),e(this,`maxDelayMs`,void 0),this.delayMs=t.baseDelayMs,this.maxDelayMs=t.maxDelayMs??3e4}shouldRetry(){return this.attempts<this.options.maxAttempts}nextDelayMs(){return this.delayMs}recordAttempt(){this.attempts+=1,this.delayMs=Math.min(this.delayMs*2,this.maxDelayMs)}reset(){this.attempts=0,this.delayMs=this.options.baseDelayMs}get attemptCount(){return this.attempts}get maxAttempts(){return this.options.maxAttempts}};export{t as ReconnectionBackoff};
|
|
2
2
|
//# sourceMappingURL=reconnection.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconnection.js","names":["_defineProperty","ReconnectionBackoff","options"],"sources":["../../../src/utils/reconnection.ts"],"sourcesContent":["/** Options for {@link ReconnectionBackoff}. */\nexport interface ReconnectionBackoffOptions {\n /** Attempts allowed before giving up. */\n maxAttempts: number;\n /** Delay before the first attempt, in milliseconds. */\n baseDelayMs: number;\n /** Ceiling the doubling delay never exceeds, in milliseconds. */\n maxDelayMs?: number;\n}\n\n/** Counts reconnect attempts and doubles the delay between them, up to a ceiling. */\nexport class ReconnectionBackoff {\n private attempts = 0;\n private delayMs: number;\n private readonly maxDelayMs: number;\n\n constructor(private readonly options: ReconnectionBackoffOptions) {\n this.delayMs = options.baseDelayMs;\n this.maxDelayMs = options.maxDelayMs ?? 30_000;\n }\n\n /** Whether another attempt is allowed. */\n shouldRetry(): boolean {\n return this.attempts < this.options.maxAttempts;\n }\n\n /** The delay to wait before the next attempt. */\n nextDelayMs(): number {\n return this.delayMs;\n }\n\n /** Record that an attempt is being made, and double the next delay. */\n recordAttempt(): void {\n this.attempts += 1;\n this.delayMs = Math.min(this.delayMs * 2, this.maxDelayMs);\n }\n\n /** Forget every attempt: the connection is healthy again. */\n reset(): void {\n this.attempts = 0;\n this.delayMs = this.options.baseDelayMs;\n }\n\n get attemptCount(): number {\n return this.attempts;\n }\n\n get maxAttempts(): number {\n return this.options.maxAttempts;\n }\n}\n"],"mappings":"uFAWA,IAAaC,EAAb,KAAiC,CAK/B,YAAY,EAAsD,CAArC,KAAA,QAAAC,EAJrBF,EAAA,KAAA,WAAW,CAAA,EACXA,EAAA,KAAA,UAAA,IAAA,EAAA,EACSA,EAAA,KAAA,aAAA,IAAA,EAAA,EAGf,KAAK,QAAUE,EAAQ,YACvB,KAAK,WAAaA,EAAQ,YAAc,GAC1C,CAGA,aAAuB,CACrB,OAAO,KAAK,SAAW,KAAK,QAAQ,WACtC,CAGA,aAAsB,CACpB,OAAO,KAAK,OACd,CAGA,eAAsB,CACpB,KAAK,UAAY,EACjB,KAAK,QAAU,KAAK,IAAI,KAAK,QAAU,EAAG,KAAK,UAAU,CAC3D,CAGA,OAAc,CACZ,KAAK,SAAW,EAChB,KAAK,QAAU,KAAK,QAAQ,WAC9B,CAEA,IAAI,cAAuB,CACzB,OAAO,KAAK,QACd,CAEA,IAAI,aAAsB,CACxB,OAAO,KAAK,QAAQ,WACtB,CACF"}
|
|
1
|
+
{"version":3,"file":"reconnection.js","names":["_defineProperty","ReconnectionBackoff","options"],"sources":["../../../src/utils/reconnection.ts"],"sourcesContent":["/** Options for {@link ReconnectionBackoff}. */\nexport interface ReconnectionBackoffOptions {\n /** Attempts allowed before giving up. */\n maxAttempts: number;\n /** Delay before the first attempt, in milliseconds. */\n baseDelayMs: number;\n /** Ceiling the doubling delay never exceeds, in milliseconds. */\n maxDelayMs?: number;\n}\n\n/** Counts reconnect attempts and doubles the delay between them, up to a ceiling. */\nexport class ReconnectionBackoff {\n private attempts = 0;\n private delayMs: number;\n private readonly maxDelayMs: number;\n\n constructor(private readonly options: ReconnectionBackoffOptions) {\n this.delayMs = options.baseDelayMs;\n this.maxDelayMs = options.maxDelayMs ?? 30_000;\n }\n\n /** Whether another attempt is allowed. */\n shouldRetry(): boolean {\n return this.attempts < this.options.maxAttempts;\n }\n\n /** The delay to wait before the next attempt. */\n nextDelayMs(): number {\n return this.delayMs;\n }\n\n /** Record that an attempt is being made, and double the next delay. */\n recordAttempt(): void {\n this.attempts += 1;\n this.delayMs = Math.min(this.delayMs * 2, this.maxDelayMs);\n }\n\n /** Forget every attempt: the connection is healthy again. */\n reset(): void {\n this.attempts = 0;\n this.delayMs = this.options.baseDelayMs;\n }\n\n get attemptCount(): number {\n return this.attempts;\n }\n\n get maxAttempts(): number {\n return this.options.maxAttempts;\n }\n}\n"],"mappings":"A,uFAWA,IAAaC,EAAb,KAAiC,CAK/B,YAAY,EAAsD,CAArC,KAAA,QAAAC,EAJrBF,EAAA,KAAA,WAAW,CAAA,EACXA,EAAA,KAAA,UAAA,IAAA,EAAA,EACSA,EAAA,KAAA,aAAA,IAAA,EAAA,EAGf,KAAK,QAAUE,EAAQ,YACvB,KAAK,WAAaA,EAAQ,YAAc,GAC1C,CAGA,aAAuB,CACrB,OAAO,KAAK,SAAW,KAAK,QAAQ,WACtC,CAGA,aAAsB,CACpB,OAAO,KAAK,OACd,CAGA,eAAsB,CACpB,KAAK,UAAY,EACjB,KAAK,QAAU,KAAK,IAAI,KAAK,QAAU,EAAG,KAAK,UAAU,CAC3D,CAGA,OAAc,CACZ,KAAK,SAAW,EAChB,KAAK,QAAU,KAAK,QAAQ,WAC9B,CAEA,IAAI,cAAuB,CACzB,OAAO,KAAK,QACd,CAEA,IAAI,aAAsB,CACxB,OAAO,KAAK,QAAQ,WACtB,CACF,E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve_pre_send.js","names":["resolvePreSend","run","cause","isGalaError","GSwapSDKError"],"sources":["../../../src/utils/resolve_pre_send.ts"],"sourcesContent":["import { isGalaError } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/**\n * Runs a token-resolution step (a resolver's `resolve` / `orderPair`, which may read the registry\n * through the app's HTTP stack) on the \"nothing was sent\" boundary, like core's `signPreSend` does\n * for the signer. A failure that is not an SDK error is `TOKEN_RESOLUTION_FAILED` (`token` names\n * what was being resolved, the original is `cause`); an SDK error of any product (every one is a\n * `GalaSDKError`, core's transport errors included) passes through.\n *\n * @throws GSwapSDKError TOKEN_RESOLUTION_FAILED, or the SDK error the step itself threw.\n */\nexport async function resolvePreSend<T>(token: string, run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (cause: unknown) {\n throw isGalaError(cause)\n ? cause\n : new GSwapSDKError('TOKEN_RESOLUTION_FAILED', { token }, { cause });\n }\n}\n"],"mappings":"sHAYA,eAAsBA,EAAkB,EAAe,EAAmC,CACxF,GAAI,CACF,OAAO,MAAMC,EAAI,CACnB,OAASC,EAAgB,CACvB,MAAMC,EAAYD,CAAK,EACnBA,EACA,IAAIE,EAAc,0BAA2B,CAAE,OAAM,EAAG,CAAE,OAAM,CAAC,CACvE,CACF"}
|
|
1
|
+
{"version":3,"file":"resolve_pre_send.js","names":["resolvePreSend","run","cause","isGalaError","GSwapSDKError"],"sources":["../../../src/utils/resolve_pre_send.ts"],"sourcesContent":["import { isGalaError } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/**\n * Runs a token-resolution step (a resolver's `resolve` / `orderPair`, which may read the registry\n * through the app's HTTP stack) on the \"nothing was sent\" boundary, like core's `signPreSend` does\n * for the signer. A failure that is not an SDK error is `TOKEN_RESOLUTION_FAILED` (`token` names\n * what was being resolved, the original is `cause`); an SDK error of any product (every one is a\n * `GalaSDKError`, core's transport errors included) passes through.\n *\n * @throws GSwapSDKError TOKEN_RESOLUTION_FAILED, or the SDK error the step itself threw.\n */\nexport async function resolvePreSend<T>(token: string, run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (cause: unknown) {\n throw isGalaError(cause)\n ? cause\n : new GSwapSDKError('TOKEN_RESOLUTION_FAILED', { token }, { cause });\n }\n}\n"],"mappings":"A,sHAYA,eAAsBA,EAAkB,EAAe,EAAmC,CACxF,GAAI,CACF,OAAO,MAAMC,EAAI,CACnB,OAASC,EAAgB,CACvB,MAAMC,EAAYD,CAAK,EACnBA,EACA,IAAIE,EAAc,0BAA2B,CAAE,OAAM,EAAG,CAAE,OAAM,CAAC,CACvE,CACF,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server_message.js","names":["nonEmptyString","value","field","property","serverMessageOfBody","nested","body","\"error\"","readServerMessage","fromParams","error","\"serverMessage\"","fromBody"],"sources":["../../../src/utils/server_message.ts"],"sourcesContent":["import type { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\nfunction nonEmptyString(value: unknown, property: string): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const field = (value as Record<string, unknown>)[property];\n return typeof field === 'string' && field !== '' ? field : undefined;\n}\n\n/**\n * The human message a failing JSON body carries, as the server wrote it: the first non-empty\n * string of `message`, `Message`, `error.message`, `error.Message` (NestJS, the gateway filter\n * and the chain each use one of these shapes), else `''`. A body that is not JSON (an HTML 502\n * page, an empty body), or whose `message` is not a string (a validation error's list), has no\n * message. This is the single reader behind every `serverMessage` param.\n *\n * The text is DATA from the server, not SDK text: it is English, unstable, and may be empty. The\n * SDK exposes it so an app can relay it or ignore it; it is never part of `error.message`.\n */\nexport function serverMessageOfBody(body: unknown): string {\n const nested =\n typeof body === 'object' && body !== null\n ? (body as Record<string, unknown>)['error']\n : undefined;\n return (\n nonEmptyString(body, 'message') ??\n nonEmptyString(body, 'Message') ??\n nonEmptyString(nested, 'message') ??\n nonEmptyString(nested, 'Message') ??\n ''\n );\n}\n\n/**\n * The message the server put in a failing answer: the `serverMessage` param of a code that relays\n * it, else the message of the JSON body ({@link serverMessageOfBody}). Internal: the SDK reads it\n * ONLY to classify a failure (a quote that says \"no pools\"); it is English from the server, never\n * part of the SDK's own `message`, and not exported from the package.\n */\nexport function readServerMessage(error: GSwapSDKError): string | undefined {\n const params: Readonly<Record<string, string | number | boolean>> = error.params;\n const fromParams = params['serverMessage'];\n if (typeof fromParams === 'string' && fromParams !== '') return fromParams;\n const fromBody = serverMessageOfBody(error.body);\n return fromBody === '' ? undefined : fromBody;\n}\n"],"mappings":"AAEA,SAASA,EAAe,EAAgB,EAAsC,CAC5E,GAAI,OAAOC,GAAU,WAAYA,EAAgB,OACjD,IAAMC,EAASD,EAAkCE,GACjD,OAAO,OAAOD,GAAU,UAAYA,IAAU,GAAKA,EAAQ,IAAA,EAC7D,CAYA,SAAgBE,EAAoB,EAAuB,CACzD,IAAMC,EACJ,OAAOC,GAAS,UAAYA,EACvBA,EAAiCC,MAClC,IAAA,GACN,OACEP,EAAeM,EAAM,SAAS,GAC9BN,EAAeM,EAAM,SAAS,GAC9BN,EAAeK,EAAQ,SAAS,GAChCL,EAAeK,EAAQ,SAAS,GAChC,EAEJ,CAQA,SAAgBG,EAAkB,EAA0C,CAE1E,IAAMC,EAD8DC,EAAM,OAChDC,cAC1B,GAAI,OAAOF,GAAe,UAAYA,IAAe,GAAI,OAAOA,EAChE,IAAMG,EAAWR,EAAoBM,EAAM,IAAI,EAC/C,OAAOE,IAAa,GAAK,IAAA,GAAYA,CACvC"}
|
|
1
|
+
{"version":3,"file":"server_message.js","names":["nonEmptyString","value","field","property","serverMessageOfBody","nested","body","\"error\"","readServerMessage","fromParams","error","\"serverMessage\"","fromBody"],"sources":["../../../src/utils/server_message.ts"],"sourcesContent":["import type { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\nfunction nonEmptyString(value: unknown, property: string): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const field = (value as Record<string, unknown>)[property];\n return typeof field === 'string' && field !== '' ? field : undefined;\n}\n\n/**\n * The human message a failing JSON body carries, as the server wrote it: the first non-empty\n * string of `message`, `Message`, `error.message`, `error.Message` (NestJS, the gateway filter\n * and the chain each use one of these shapes), else `''`. A body that is not JSON (an HTML 502\n * page, an empty body), or whose `message` is not a string (a validation error's list), has no\n * message. This is the single reader behind every `serverMessage` param.\n *\n * The text is DATA from the server, not SDK text: it is English, unstable, and may be empty. The\n * SDK exposes it so an app can relay it or ignore it; it is never part of `error.message`.\n */\nexport function serverMessageOfBody(body: unknown): string {\n const nested =\n typeof body === 'object' && body !== null\n ? (body as Record<string, unknown>)['error']\n : undefined;\n return (\n nonEmptyString(body, 'message') ??\n nonEmptyString(body, 'Message') ??\n nonEmptyString(nested, 'message') ??\n nonEmptyString(nested, 'Message') ??\n ''\n );\n}\n\n/**\n * The message the server put in a failing answer: the `serverMessage` param of a code that relays\n * it, else the message of the JSON body ({@link serverMessageOfBody}). Internal: the SDK reads it\n * ONLY to classify a failure (a quote that says \"no pools\"); it is English from the server, never\n * part of the SDK's own `message`, and not exported from the package.\n */\nexport function readServerMessage(error: GSwapSDKError): string | undefined {\n const params: Readonly<Record<string, string | number | boolean>> = error.params;\n const fromParams = params['serverMessage'];\n if (typeof fromParams === 'string' && fromParams !== '') return fromParams;\n const fromBody = serverMessageOfBody(error.body);\n return fromBody === '' ? undefined : fromBody;\n}\n"],"mappings":"AAEA,SAASA,EAAe,EAAgB,EAAsC,CAC5E,GAAI,OAAOC,GAAU,WAAYA,EAAgB,OACjD,IAAMC,EAASD,EAAkCE,GACjD,OAAO,OAAOD,GAAU,UAAYA,IAAU,GAAKA,EAAQ,IAAA,EAC7D,CAYA,SAAgBE,EAAoB,EAAuB,CACzD,IAAMC,EACJ,OAAOC,GAAS,UAAYA,EACvBA,EAAiCC,MAClC,IAAA,GACN,OACEP,EAAeM,EAAM,SAAS,GAC9BN,EAAeM,EAAM,SAAS,GAC9BN,EAAeK,EAAQ,SAAS,GAChCL,EAAeK,EAAQ,SAAS,GAChC,EAEJ,CAQA,SAAgBG,EAAkB,EAA0C,CAE1E,IAAMC,EAD8DC,EAAM,OAChDC,cAC1B,GAAI,OAAOF,GAAe,UAAYA,IAAe,GAAI,OAAOA,EAChE,IAAMG,EAAWR,EAAoBM,EAAM,IAAI,EAC/C,OAAOE,IAAa,GAAK,IAAA,GAAYA,CACvC,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shadow_errors.js","names":["shadowRejections","isShadowError","isGSwapError","value","toFailureView","asShadowError","error","copy","GSwapSDKError","shadowFailures","run"],"sources":["../../../src/utils/shadow_errors.ts"],"sourcesContent":["import { toFailureView } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError, isGSwapError } from '../classes/gswap_sdk_error.js';\n\n/**\n * Failures of the shadow (dark) path carry that fact, so an app can apply its own policy (no\n * Retry, no public fallback) without tracking which call it made. An SDK error gets `shadow: true`;\n * a non-SDK object that escapes the path (an app requestor's own rejection) is remembered in a\n * WeakSet, which `isShadowError` reads. Nothing here changes what an error means, only where it\n * came from.\n */\nconst shadowRejections = new WeakSet<object>();\n\n/**\n * True when `value` is a failure of the shadow (dark) path: an SDK error with `shadow: true`, a\n * plain-object view of one (`{ code, shadow: true }`, see `FailureView`), or a non-SDK object (a requestor's own rejection) that escaped `swapShadow`, `submitSwapShadow` or\n * `ChainGateway.submitShadow`. A primitive that was thrown (`throw 'x'`) cannot be remembered, so\n * it is never shadow; an app that cares tracks the call it made.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swapShadow('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * const { retryable } = classifyFailure(error);\n * offerRetry(retryable && !isShadowError(error)); // never retry a dark swap in public\n * }\n * ```\n */\nexport function isShadowError(value: unknown): boolean {\n if (isGSwapError(value)) return value.shadow;\n if (toFailureView(value)?.shadow === true) return true;\n return typeof value === 'object' && value !== null && shadowRejections.has(value);\n}\n\n/**\n * The same failure, marked as shadow. An SDK error is COPIED (same code, params, status, body,\n * url, ids, cause, phase, read/write, wallet code and stack), never mutated: one error object can\n * be shared by several callers (a registry read many swaps wait on), and only the shadow caller's\n * copy is shadow. Everything the deciders read is carried over, so the copy classifies exactly as\n * the original (a failed READ stays a read, never a \"maybe queued\" write).\n */\nfunction asShadowError(error: unknown): unknown {\n if (isGSwapError(error)) {\n if (error.shadow) return error;\n const copy = new GSwapSDKError(error.code, error.params, {\n status: error.status,\n body: error.body ?? error.bodyText,\n url: error.url,\n uniqueKey: error.uniqueKey,\n requestTransactionId: error.requestTransactionId,\n applyTransactionId: error.applyTransactionId,\n blockNumber: error.blockNumber,\n retryAfterMs: error.retryAfterMs,\n cause: error.cause,\n phase: error.phase,\n write: error.write,\n walletCode: error.walletCode,\n shadow: true,\n });\n if (error.stack !== undefined) copy.stack = error.stack;\n return copy;\n }\n if (typeof error === 'object' && error !== null) shadowRejections.add(error);\n return error;\n}\n\n/** Runs one shadow operation and marks whatever it throws as shadow (see {@link isShadowError}). */\nexport async function shadowFailures<T>(run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (error: unknown) {\n throw asShadowError(error);\n }\n}\n"],"mappings":"0IAUA,MAAMA,kBAAmB,IAAI,QAkB7B,SAAgBC,EAAc,EAAyB,CAGrD,OAFIC,EAAaC,CAAK,EAAUA,EAAM,OAClCC,EAAcD,CAAK,CAAC,EAAE,SAAW,IAC9B,OAAOA,GAAU,YAAYA,GAAkBH,EAAiB,IAAIG,CAAK,CAClF,CASA,SAASE,EAAc,EAAyB,CAC9C,GAAIH,EAAaI,CAAK,EAAG,CACvB,GAAIA,EAAM,OAAQ,OAAOA,EACzB,IAAMC,EAAO,IAAIC,EAAcF,EAAM,KAAMA,EAAM,OAAQ,CACvD,OAAQA,EAAM,OACd,KAAMA,EAAM,MAAQA,EAAM,SAC1B,IAAKA,EAAM,IACX,UAAWA,EAAM,UACjB,qBAAsBA,EAAM,qBAC5B,mBAAoBA,EAAM,mBAC1B,YAAaA,EAAM,YACnB,aAAcA,EAAM,aACpB,MAAOA,EAAM,MACb,MAAOA,EAAM,MACb,MAAOA,EAAM,MACb,WAAYA,EAAM,WAClB,OAAQ,EACV,CAAC,EAED,OADIA,EAAM,QAAU,IAAA,KAAW,EAAK,MAAQA,EAAM,OAC3CC,CACT,CAEA,OADI,OAAOD,GAAU,UAAYA,GAAgBN,EAAiB,IAAIM,CAAK,EACpEA,CACT,CAGA,eAAsBG,EAAkB,EAAmC,CACzE,GAAI,CACF,OAAO,MAAMC,EAAI,CACnB,OAASJ,EAAgB,CACvB,MAAMD,EAAcC,CAAK,CAC3B,CACF"}
|
|
1
|
+
{"version":3,"file":"shadow_errors.js","names":["shadowRejections","isShadowError","isGSwapError","value","toFailureView","asShadowError","error","copy","GSwapSDKError","shadowFailures","run"],"sources":["../../../src/utils/shadow_errors.ts"],"sourcesContent":["import { toFailureView } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError, isGSwapError } from '../classes/gswap_sdk_error.js';\n\n/**\n * Failures of the shadow (dark) path carry that fact, so an app can apply its own policy (no\n * Retry, no public fallback) without tracking which call it made. An SDK error gets `shadow: true`;\n * a non-SDK object that escapes the path (an app requestor's own rejection) is remembered in a\n * WeakSet, which `isShadowError` reads. Nothing here changes what an error means, only where it\n * came from.\n */\nconst shadowRejections = new WeakSet<object>();\n\n/**\n * True when `value` is a failure of the shadow (dark) path: an SDK error with `shadow: true`, a\n * plain-object view of one (`{ code, shadow: true }`, see `FailureView`), or a non-SDK object (a requestor's own rejection) that escaped `swapShadow`, `submitSwapShadow` or\n * `ChainGateway.submitShadow`. A primitive that was thrown (`throw 'x'`) cannot be remembered, so\n * it is never shadow; an app that cares tracks the call it made.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swapShadow('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * const { retryable } = classifyFailure(error);\n * offerRetry(retryable && !isShadowError(error)); // never retry a dark swap in public\n * }\n * ```\n */\nexport function isShadowError(value: unknown): boolean {\n if (isGSwapError(value)) return value.shadow;\n if (toFailureView(value)?.shadow === true) return true;\n return typeof value === 'object' && value !== null && shadowRejections.has(value);\n}\n\n/**\n * The same failure, marked as shadow. An SDK error is COPIED (same code, params, status, body,\n * url, ids, cause, phase, read/write, wallet code and stack), never mutated: one error object can\n * be shared by several callers (a registry read many swaps wait on), and only the shadow caller's\n * copy is shadow. Everything the deciders read is carried over, so the copy classifies exactly as\n * the original (a failed READ stays a read, never a \"maybe queued\" write).\n */\nfunction asShadowError(error: unknown): unknown {\n if (isGSwapError(error)) {\n if (error.shadow) return error;\n const copy = new GSwapSDKError(error.code, error.params, {\n status: error.status,\n body: error.body ?? error.bodyText,\n url: error.url,\n uniqueKey: error.uniqueKey,\n requestTransactionId: error.requestTransactionId,\n applyTransactionId: error.applyTransactionId,\n blockNumber: error.blockNumber,\n retryAfterMs: error.retryAfterMs,\n cause: error.cause,\n phase: error.phase,\n write: error.write,\n walletCode: error.walletCode,\n shadow: true,\n });\n if (error.stack !== undefined) copy.stack = error.stack;\n return copy;\n }\n if (typeof error === 'object' && error !== null) shadowRejections.add(error);\n return error;\n}\n\n/** Runs one shadow operation and marks whatever it throws as shadow (see {@link isShadowError}). */\nexport async function shadowFailures<T>(run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (error: unknown) {\n throw asShadowError(error);\n }\n}\n"],"mappings":"A,0IAUA,MAAMA,kBAAmB,IAAI,QAkB7B,SAAgBC,EAAc,EAAyB,CAGrD,OAFIC,EAAaC,CAAK,EAAUA,EAAM,OAClCC,EAAcD,CAAK,CAAC,EAAE,SAAW,IAC9B,OAAOA,GAAU,YAAYA,GAAkBH,EAAiB,IAAIG,CAAK,CAClF,CASA,SAASE,EAAc,EAAyB,CAC9C,GAAIH,EAAaI,CAAK,EAAG,CACvB,GAAIA,EAAM,OAAQ,OAAOA,EACzB,IAAMC,EAAO,IAAIC,EAAcF,EAAM,KAAMA,EAAM,OAAQ,CACvD,OAAQA,EAAM,OACd,KAAMA,EAAM,MAAQA,EAAM,SAC1B,IAAKA,EAAM,IACX,UAAWA,EAAM,UACjB,qBAAsBA,EAAM,qBAC5B,mBAAoBA,EAAM,mBAC1B,YAAaA,EAAM,YACnB,aAAcA,EAAM,aACpB,MAAOA,EAAM,MACb,MAAOA,EAAM,MACb,MAAOA,EAAM,MACb,WAAYA,EAAM,WAClB,OAAQ,EACV,CAAC,EAED,OADIA,EAAM,QAAU,IAAA,KAAW,EAAK,MAAQA,EAAM,OAC3CC,CACT,CAEA,OADI,OAAOD,GAAU,UAAYA,GAAgBN,EAAiB,IAAIM,CAAK,EACpEA,CACT,CAGA,eAAsBG,EAAkB,EAAmC,CACzE,GAAI,CACF,OAAO,MAAMC,EAAI,CACnB,OAASJ,EAAgB,CACvB,MAAMD,EAAcC,CAAK,CAC3B,CACF,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submit_state.js","names":["modeOf","data","envelope","\"data\"","\"mode\"","recordOf","value","isSubmitRejected","\"error\"","isSubmitExecuted","record","isSubmitQueued","\"uniqueKey\"","classifySubmitEnvelope"],"sources":["../../../src/utils/submit_state.ts"],"sourcesContent":["/**\n * What a write's gateway answer says about the write, as one vocabulary for every app.\n *\n * The gateway answers `{ status, message, error, data }`. `data.mode` is `'sync'` for a liquidity\n * write (its executed chain result is in `data.result`) and `'queued'` for a RequestTrade\n * acknowledgement (accepted, NOT executed: the outcome is read from apply-results with\n * `confirm()`). `error: true` is the gateway refusing the write.\n *\n * A {@link SubmittedTransaction} only exists for an answer the SDK accepted, so its\n * {@link SubmitStatus} is `'executed'` or `'queued'`; a refused answer is a thrown\n * {@link GSwapSDKError}. The predicates below classify a RAW envelope instead, for an app that\n * holds one (`SubmittedTransaction.envelope`, `GSwapSDKError.body`, a stored answer) and for the\n * answers that never became a transaction, so an app does not need its own copies of the\n * success, queued and rejected checks.\n */\n\n/** The state of an accepted write: executed on chain (`mode: 'sync'`) or queued (`mode: 'queued'`). */\nexport type SubmitStatus = 'executed' | 'queued';\n\n/**\n * How a raw gateway envelope classifies:\n *\n * - `'executed'`: `error === false` and `data.mode === 'sync'` (the executed result came back).\n * - `'queued'`: `error === false`, `data.mode === 'queued'` and `data.uniqueKey` is a string.\n * - `'rejected'`: no envelope at all, or `error === true`: a DEFINITE failure.\n * - `'unconfirmed'`: anything else (`error: false` with another or no `mode`, a queued answer\n * with no `uniqueKey`, an envelope with no boolean `error`): accepted, outcome not known. It is\n * NOT a rejection and must not be shown as one.\n *\n * The four are mutually exclusive and exhaustive.\n */\nexport type SubmitClassification = SubmitStatus | 'rejected' | 'unconfirmed';\n\n/** The `mode` of `envelope.data`, or `undefined` when there is no such field. */\nfunction modeOf(envelope: Record<string, unknown>): unknown {\n const data = envelope['data'];\n return typeof data === 'object' && data !== null\n ? (data as Record<string, unknown>)['mode']\n : undefined;\n}\n\nfunction recordOf(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** True when the envelope is a definite failure: absent, or `error === true`. */\nexport function isSubmitRejected(envelope: unknown): boolean {\n if (!envelope) return true;\n return recordOf(envelope)?.['error'] === true;\n}\n\n/**\n * True when the envelope carries an executed result: `error === false` and `data.mode === 'sync'`.\n * A queued RequestTrade acknowledgement is deliberately NOT executed: its outcome is not known\n * until apply-results resolves.\n */\nexport function isSubmitExecuted(envelope: unknown): boolean {\n const record = recordOf(envelope);\n return record?.['error'] === false && modeOf(record) === 'sync';\n}\n\n/** True when the envelope acknowledges a `uniqueKey` as queued (`data.mode === 'queued'`). */\nexport function isSubmitQueued(envelope: unknown): boolean {\n const record = recordOf(envelope);\n if (record?.['error'] !== false || modeOf(record) !== 'queued') return false;\n return typeof recordOf(record['data'])?.['uniqueKey'] === 'string';\n}\n\n/** Classifies a raw gateway envelope; see {@link SubmitClassification}. */\nexport function classifySubmitEnvelope(envelope: unknown): SubmitClassification {\n if (isSubmitRejected(envelope)) return 'rejected';\n if (isSubmitExecuted(envelope)) return 'executed';\n if (isSubmitQueued(envelope)) return 'queued';\n return 'unconfirmed';\n}\n"],"mappings":"AAkCA,SAASA,EAAO,EAA4C,CAC1D,IAAMC,EAAOC,EAASC,KACtB,OAAO,OAAOF,GAAS,UAAYA,EAC9BA,EAAiCG,KAClC,IAAA,EACN,CAEA,SAASC,EAAS,EAAqD,CACrE,OAAO,OAAOC,GAAU,UAAYA,EAC/BA,EACD,IAAA,EACN,CAGA,SAAgBC,EAAiB,EAA4B,CAE3D,MADA,CAAKL,GACEG,EAASH,CAAQ,CAAC,EAAGM,QAAa,EAC3C,CAOA,SAAgBC,EAAiB,EAA4B,CAC3D,IAAMC,EAASL,EAASH,CAAQ,EAChC,OAAOQ,GAASF,QAAa,IAASR,EAAOU,CAAM,IAAM,MAC3D,CAGA,SAAgBC,EAAe,EAA4B,CACzD,IAAMD,EAASL,EAASH,CAAQ,EAEhC,OADIQ,GAASF,QAAa,IAASR,EAAOU,CAAM,IAAM,SAAiB,GAChE,OAAOL,EAASK,EAAOP,IAAO,CAAC,EAAGS,WAAiB,QAC5D,CAGA,SAAgBC,EAAuB,EAAyC,CAI9E,OAHIN,EAAiBL,CAAQ,EAAU,WACnCO,EAAiBP,CAAQ,EAAU,WACnCS,EAAeT,CAAQ,EAAU,SAC9B,aACT"}
|
|
1
|
+
{"version":3,"file":"submit_state.js","names":["modeOf","data","envelope","\"data\"","\"mode\"","recordOf","value","isSubmitRejected","\"error\"","isSubmitExecuted","record","isSubmitQueued","\"uniqueKey\"","classifySubmitEnvelope"],"sources":["../../../src/utils/submit_state.ts"],"sourcesContent":["/**\n * What a write's gateway answer says about the write, as one vocabulary for every app.\n *\n * The gateway answers `{ status, message, error, data }`. `data.mode` is `'sync'` for a liquidity\n * write (its executed chain result is in `data.result`) and `'queued'` for a RequestTrade\n * acknowledgement (accepted, NOT executed: the outcome is read from apply-results with\n * `confirm()`). `error: true` is the gateway refusing the write.\n *\n * A {@link SubmittedTransaction} only exists for an answer the SDK accepted, so its\n * {@link SubmitStatus} is `'executed'` or `'queued'`; a refused answer is a thrown\n * {@link GSwapSDKError}. The predicates below classify a RAW envelope instead, for an app that\n * holds one (`SubmittedTransaction.envelope`, `GSwapSDKError.body`, a stored answer) and for the\n * answers that never became a transaction, so an app does not need its own copies of the\n * success, queued and rejected checks.\n */\n\n/** The state of an accepted write: executed on chain (`mode: 'sync'`) or queued (`mode: 'queued'`). */\nexport type SubmitStatus = 'executed' | 'queued';\n\n/**\n * How a raw gateway envelope classifies:\n *\n * - `'executed'`: `error === false` and `data.mode === 'sync'` (the executed result came back).\n * - `'queued'`: `error === false`, `data.mode === 'queued'` and `data.uniqueKey` is a string.\n * - `'rejected'`: no envelope at all, or `error === true`: a DEFINITE failure.\n * - `'unconfirmed'`: anything else (`error: false` with another or no `mode`, a queued answer\n * with no `uniqueKey`, an envelope with no boolean `error`): accepted, outcome not known. It is\n * NOT a rejection and must not be shown as one.\n *\n * The four are mutually exclusive and exhaustive.\n */\nexport type SubmitClassification = SubmitStatus | 'rejected' | 'unconfirmed';\n\n/** The `mode` of `envelope.data`, or `undefined` when there is no such field. */\nfunction modeOf(envelope: Record<string, unknown>): unknown {\n const data = envelope['data'];\n return typeof data === 'object' && data !== null\n ? (data as Record<string, unknown>)['mode']\n : undefined;\n}\n\nfunction recordOf(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** True when the envelope is a definite failure: absent, or `error === true`. */\nexport function isSubmitRejected(envelope: unknown): boolean {\n if (!envelope) return true;\n return recordOf(envelope)?.['error'] === true;\n}\n\n/**\n * True when the envelope carries an executed result: `error === false` and `data.mode === 'sync'`.\n * A queued RequestTrade acknowledgement is deliberately NOT executed: its outcome is not known\n * until apply-results resolves.\n */\nexport function isSubmitExecuted(envelope: unknown): boolean {\n const record = recordOf(envelope);\n return record?.['error'] === false && modeOf(record) === 'sync';\n}\n\n/** True when the envelope acknowledges a `uniqueKey` as queued (`data.mode === 'queued'`). */\nexport function isSubmitQueued(envelope: unknown): boolean {\n const record = recordOf(envelope);\n if (record?.['error'] !== false || modeOf(record) !== 'queued') return false;\n return typeof recordOf(record['data'])?.['uniqueKey'] === 'string';\n}\n\n/** Classifies a raw gateway envelope; see {@link SubmitClassification}. */\nexport function classifySubmitEnvelope(envelope: unknown): SubmitClassification {\n if (isSubmitRejected(envelope)) return 'rejected';\n if (isSubmitExecuted(envelope)) return 'executed';\n if (isSubmitQueued(envelope)) return 'queued';\n return 'unconfirmed';\n}\n"],"mappings":"AAkCA,SAASA,EAAO,EAA4C,CAC1D,IAAMC,EAAOC,EAASC,KACtB,OAAO,OAAOF,GAAS,UAAYA,EAC9BA,EAAiCG,KAClC,IAAA,EACN,CAEA,SAASC,EAAS,EAAqD,CACrE,OAAO,OAAOC,GAAU,UAAYA,EAC/BA,EACD,IAAA,EACN,CAGA,SAAgBC,EAAiB,EAA4B,CAE3D,MADA,CAAKL,GACEG,EAASH,CAAQ,CAAC,EAAGM,QAAa,EAC3C,CAOA,SAAgBC,EAAiB,EAA4B,CAC3D,IAAMC,EAASL,EAASH,CAAQ,EAChC,OAAOQ,GAASF,QAAa,IAASR,EAAOU,CAAM,IAAM,MAC3D,CAGA,SAAgBC,EAAe,EAA4B,CACzD,IAAMD,EAASL,EAASH,CAAQ,EAEhC,OADIQ,GAASF,QAAa,IAASR,EAAOU,CAAM,IAAM,SAAiB,GAChE,OAAOL,EAASK,EAAOP,IAAO,CAAC,EAAGS,WAAiB,QAC5D,CAGA,SAAgBC,EAAuB,EAAyC,CAI9E,OAHIN,EAAiBL,CAAQ,EAAU,WACnCO,EAAiBP,CAAQ,EAAU,WACnCS,EAAeT,CAAQ,EAAU,SAC9B,aACT,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tick_align.js","names":["hasValidSpacing","spacing","alignTickDownOrNaN","tick","alignTickUpOrNaN"],"sources":["../../../src/utils/tick_align.ts"],"sourcesContent":["/**\n * Aligning a tick to a pool's tick spacing without throwing. This module imports nothing, so an\n * app shell (a price input that snaps to a tick) pays for a few dozen bytes, not for the error\n * class and catalog that `alignTickDown` and `alignTickUp` (in `ticks.ts`) carry because they\n * throw `INVALID_TICK_SPACING` for a spacing that is not a positive integer.\n */\n\n/** True for a tick spacing the contract can use: a positive integer. The one definition. */\nexport function hasValidSpacing(spacing: number): boolean {\n return Number.isInteger(spacing) && spacing > 0;\n}\n\n/**\n * {@link alignTickDown} that answers `NaN` instead of throwing: the greatest multiple of `spacing`\n * that is no greater than `tick`, or `NaN` when `spacing` is not a positive integer (a pool whose\n * spacing has not loaded yet) or `tick` is not a number. For an app shell and for a drag handler,\n * which must not throw while the spacing is missing. `alignTickDown` (the SDK's own call sites use\n * it) gives the same value and throws for the bad spacing.\n *\n * @example\n * ```ts\n * alignTickDownOrNaN(-61, 60); // -120: it floors, it does not truncate toward zero\n * alignTickDownOrNaN(100, 0); // NaN\n * ```\n */\nexport function alignTickDownOrNaN(tick: number, spacing: number): number {\n return hasValidSpacing(spacing) ? Math.floor(tick / spacing) * spacing : Number.NaN;\n}\n\n/**\n * {@link alignTickUp} that answers `NaN` instead of throwing: the least multiple of `spacing` that\n * is no less than `tick`, or `NaN` for a spacing that is not a positive integer. See\n * {@link alignTickDownOrNaN}.\n */\nexport function alignTickUpOrNaN(tick: number, spacing: number): number {\n return hasValidSpacing(spacing) ? Math.ceil(tick / spacing) * spacing : Number.NaN;\n}\n"],"mappings":"AAQA,SAAgBA,EAAgB,EAA0B,CACxD,OAAO,OAAO,UAAUC,CAAO,GAAKA,EAAU,CAChD,CAeA,SAAgBC,EAAmB,EAAc,EAAyB,CACxE,OAAOF,EAAgBC,CAAO,EAAI,KAAK,MAAME,EAAOF,CAAO,EAAIA,EAAU,GAC3E,CAOA,SAAgBG,EAAiB,EAAc,EAAyB,CACtE,OAAOJ,EAAgBC,CAAO,EAAI,KAAK,KAAKE,EAAOF,CAAO,EAAIA,EAAU,GAC1E"}
|
|
1
|
+
{"version":3,"file":"tick_align.js","names":["hasValidSpacing","spacing","alignTickDownOrNaN","tick","alignTickUpOrNaN"],"sources":["../../../src/utils/tick_align.ts"],"sourcesContent":["/**\n * Aligning a tick to a pool's tick spacing without throwing. This module imports nothing, so an\n * app shell (a price input that snaps to a tick) pays for a few dozen bytes, not for the error\n * class and catalog that `alignTickDown` and `alignTickUp` (in `ticks.ts`) carry because they\n * throw `INVALID_TICK_SPACING` for a spacing that is not a positive integer.\n */\n\n/** True for a tick spacing the contract can use: a positive integer. The one definition. */\nexport function hasValidSpacing(spacing: number): boolean {\n return Number.isInteger(spacing) && spacing > 0;\n}\n\n/**\n * {@link alignTickDown} that answers `NaN` instead of throwing: the greatest multiple of `spacing`\n * that is no greater than `tick`, or `NaN` when `spacing` is not a positive integer (a pool whose\n * spacing has not loaded yet) or `tick` is not a number. For an app shell and for a drag handler,\n * which must not throw while the spacing is missing. `alignTickDown` (the SDK's own call sites use\n * it) gives the same value and throws for the bad spacing.\n *\n * @example\n * ```ts\n * alignTickDownOrNaN(-61, 60); // -120: it floors, it does not truncate toward zero\n * alignTickDownOrNaN(100, 0); // NaN\n * ```\n */\nexport function alignTickDownOrNaN(tick: number, spacing: number): number {\n return hasValidSpacing(spacing) ? Math.floor(tick / spacing) * spacing : Number.NaN;\n}\n\n/**\n * {@link alignTickUp} that answers `NaN` instead of throwing: the least multiple of `spacing` that\n * is no less than `tick`, or `NaN` for a spacing that is not a positive integer. See\n * {@link alignTickDownOrNaN}.\n */\nexport function alignTickUpOrNaN(tick: number, spacing: number): number {\n return hasValidSpacing(spacing) ? Math.ceil(tick / spacing) * spacing : Number.NaN;\n}\n"],"mappings":"AAQA,SAAgBA,EAAgB,EAA0B,CACxD,OAAO,OAAO,UAAUC,CAAO,GAAKA,EAAU,CAChD,CAeA,SAAgBC,EAAmB,EAAc,EAAyB,CACxE,OAAOF,EAAgBC,CAAO,EAAI,KAAK,MAAME,EAAOF,CAAO,EAAIA,EAAU,GAC3E,CAOA,SAAgBG,EAAiB,EAAc,EAAyB,CACtE,OAAOJ,EAAgBC,CAAO,EAAI,KAAK,KAAKE,EAAOF,CAAO,EAAIA,EAAU,GAC1E,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tick_math.js","names":["BigNumber","GC_MIN_TICK","GC_MAX_TICK","DexMath","DexDecimal","Decimal","tickToSqrtPrice","tick","sqrtPriceToTick","value","sqrtPrice","approximate","tickToPrice","isSqrtPriceInRange","isTickInRange","tickLower","tickUpper","tickFromPrice","priceText","price","exact","options"],"sources":["../../../src/utils/tick_math.ts"],"sourcesContent":["import BigNumber from 'bignumber.js';\nimport { Decimal } from 'decimal.js';\nimport { isTickInRange, type TickInput } from './tick_range.js';\n\n/**\n * Tick and price arithmetic that never throws an SDK error: the contract's tick bounds, the\n * conversions between ticks and prices, and nothing that validates a range. It imports only the\n * two number libraries it computes with, never the `GSwapSDKError` class or the error catalog\n * (functions that must throw, `alignTickDown` and `assertTickRange`, are in `ticks.ts`), so an\n * app shell that prices a tick pays for the libraries and these few functions, not for ~25 kB of\n * error templates. A value that cannot be computed is `NaN`, never an exception.\n */\n\n/** Minimum tick supported by GalaChainDex. */\nexport const GC_MIN_TICK = -887272;\n/** Maximum tick supported by GalaChainDex. */\nexport const GC_MAX_TICK = 887272;\n\nconst DexMath = BigNumber.clone({\n DECIMAL_PLACES: 60,\n ROUNDING_MODE: BigNumber.ROUND_DOWN,\n});\n/** `decimal.js` at the 60 significant digits the contract's price math is exact to. */\nexport const DexDecimal = Decimal.clone({ precision: 60 });\n\n/** Convert a tick to the corresponding square-root price. */\nexport function tickToSqrtPrice(tick: number): BigNumber {\n return new BigNumber(new DexDecimal(1.0001).pow(tick / 2).toString());\n}\n\n/** Return the greatest tick whose square-root price is no greater than the input. */\nexport function sqrtPriceToTick(sqrtPrice: BigNumber.Value): number {\n let value: BigNumber;\n try {\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — this function's contract is to signal an invalid input via NaN, not\n // to throw, so an unparseable value is just another case for the guard below.\n value = new DexMath(sqrtPrice);\n } catch {\n return Number.NaN;\n }\n if (!value.isFinite() || value.isLessThanOrEqualTo(0)) return Number.NaN;\n\n const approximate = Math.log(value.toNumber() ** 2) / Math.log(1.0001);\n if (!Number.isFinite(approximate)) return Number.NaN;\n // Clamp the seed before the correction loops below — an unclamped seed derived from an\n // out-of-range sqrtPrice (extreme but finite, e.g. 1e20) leaves the loops running past\n // GC_MIN_TICK/GC_MAX_TICK for a long time; an infinite (overflowed) seed would never\n // enter the increasing loop and never terminate the decreasing one.\n let tick = Math.min(GC_MAX_TICK, Math.max(GC_MIN_TICK, Math.floor(approximate)));\n while (tick < GC_MAX_TICK && tickToSqrtPrice(tick + 1).isLessThanOrEqualTo(value)) tick += 1;\n while (tick > GC_MIN_TICK && tickToSqrtPrice(tick).isGreaterThan(value)) tick -= 1;\n return tick;\n}\n\n/**\n * The token1/token0 price at `tick`: `1.0001 ** tick`, exact to 60 significant digits (the lower\n * edge of the tick's price range; `tickToSqrtPrice(tick) ** 2`). A tick outside the contract's\n * bounds is still computed; ask `assertTickRange` first when that matters. A non-integer tick is\n * computed as given.\n *\n * Use `.toNumber()` for a display value (it differs from `Math.exp(tick * Math.log(1.0001))` in\n * the last digits of a double: that expression multiplies in floating point first).\n */\nexport function tickToPrice(tick: number): BigNumber {\n return new BigNumber(new DexDecimal(1.0001).pow(tick).toString());\n}\n\n/**\n * {@link isTickInRange} for a pool's square-root price instead of its tick (a position row that\n * carries `sqrtPrice`, `tickLower` and `tickUpper`). The tick is derived from the price exactly as\n * the contract does (`sqrtPriceToTick`: the greatest tick whose square-root price is no greater\n * than the price, exact to 60 digits), then the contract's rule applies: lower tick inclusive,\n * upper tick exclusive. So a pool sitting exactly on `tickLower`'s price is in range, and exactly\n * on `tickUpper`'s price is not, and no float rounding can flip either.\n *\n * `false` for a price that is not positive and finite (not loaded, zero, `NaN`): it says nothing\n * about the position, so an app that must show a neutral state checks for the missing price\n * itself first. `tickLower` and `tickUpper` follow {@link isTickInRange}.\n *\n * @example\n * ```ts\n * const inRange = isSqrtPriceInRange(position.sqrtPrice, position.tickLower, position.tickUpper);\n * ```\n */\nexport function isSqrtPriceInRange(\n sqrtPrice: BigNumber.Value,\n tickLower: TickInput,\n tickUpper: TickInput,\n): boolean {\n return isTickInRange(sqrtPriceToTick(sqrtPrice), tickLower, tickUpper);\n}\n\n/** How {@link tickFromPrice} turns the exact logarithm into an integer tick. */\nexport interface TickFromPriceOptions {\n /**\n * `'floor'` (default): the greatest tick whose price is no greater than `price`, which is how\n * the contract places a price. `'nearest'`: the closest tick, a half rounding away from zero.\n * That is what a price INPUT wants (a person types a price, the field snaps to the nearest\n * tick), and it differs from `'floor'` for any price in the upper half of a tick's range.\n */\n rounding?: 'floor' | 'nearest' | undefined;\n}\n\n/**\n * Return the integer tick for a token1/token0 `price`: by default the greatest tick whose price\n * is no greater than `price`; `{ rounding: 'nearest' }` the closest tick. `NaN` for a price that\n * is not positive and finite.\n */\nexport function tickFromPrice(price: BigNumber.Value, options: TickFromPriceOptions = {}): number {\n const priceText =\n typeof price === 'string'\n ? price\n : typeof price === 'number'\n ? price.toString()\n : BigNumber.isBigNumber(price)\n ? price.toString()\n : 'NaN';\n const value = new DexDecimal(priceText);\n if (!value.isFinite() || value.lessThanOrEqualTo(0)) return Number.NaN;\n if (!Number.isFinite(value.toNumber())) return Number.NaN;\n const exact = value.ln().dividedBy(new DexDecimal(1.0001).ln());\n const tick = (options.rounding === 'nearest' ? exact.round() : exact.floor()).toNumber();\n return Number.isFinite(tick) ? tick : Number.NaN;\n}\n"],"mappings":"iHAcA,MAAaC,EAAc,QAEdC,EAAc,OAErBC,EAAUH,EAAU,MAAM,CAC9B,eAAgB,GAChB,cAAeA,EAAU,UAC3B,CAAC,EAEYI,EAAaC,EAAQ,MAAM,CAAE,UAAW,EAAG,CAAC,EAGzD,SAAgBC,EAAgB,EAAyB,CACvD,OAAO,IAAIN,EAAU,IAAII,EAAW,MAAM,CAAC,CAAC,IAAIG,EAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CACtE,CAGA,SAAgBC,EAAgB,EAAoC,CAClE,IAAIC,EACJ,GAAI,CAIF,EAAQ,IAAIN,EAAQO,CAAS,CAC/B,MAAQ,CACN,MAAO,IACT,CACA,GAAI,CAACD,EAAM,SAAS,GAAKA,EAAM,oBAAoB,CAAC,EAAG,MAAO,KAE9D,IAAME,EAAc,KAAK,IAAIF,EAAM,SAAS,GAAK,CAAC,EAAI,KAAK,IAAI,MAAM,EACrE,GAAI,CAAC,OAAO,SAASE,CAAW,EAAG,MAAO,KAK1C,IAAIJ,EAAO,KAAK,IAAIL,EAAa,KAAK,IAAID,EAAa,KAAK,MAAMU,CAAW,CAAC,CAAC,EAC/E,KAAOJ,EAAA,QAAsBD,EAAgBC,EAAO,CAAC,CAAC,CAAC,oBAAoBE,CAAK,GAAG,GAAQ,EAC3F,KAAOF,EAAA,SAAsBD,EAAgBC,CAAI,CAAC,CAAC,cAAcE,CAAK,GAAG,IACzE,OAAOF,CACT,CAWA,SAAgBK,EAAY,EAAyB,CACnD,OAAO,IAAIZ,EAAU,IAAII,EAAW,MAAM,CAAC,CAAC,IAAIG,CAAI,CAAC,CAAC,SAAS,CAAC,CAClE,CAmBA,SAAgBM,EACd,EACA,EACA,EACS,CACT,OAAOC,EAAcN,EAAgBE,CAAS,EAAGK,EAAWC,CAAS,CACvE,CAkBA,SAAgBC,EAAc,EAAwB,EAAgC,CAAC,EAAW,CAChG,IAAMC,EACJ,OAAOC,GAAU,SACbA,EACA,OAAOA,GAAU,UAEfnB,EAAU,YAAYmB,CAAK,EAD3BA,EAAM,SAAS,EAGb,MACJV,EAAQ,IAAIL,EAAWc,CAAS,EAEtC,GADI,CAACT,EAAM,SAAS,GAAKA,EAAM,kBAAkB,CAAC,GAC9C,CAAC,OAAO,SAASA,EAAM,SAAS,CAAC,EAAG,MAAO,KAC/C,IAAMW,EAAQX,EAAM,GAAG,CAAC,CAAC,UAAU,IAAIL,EAAW,MAAM,CAAC,CAAC,GAAG,CAAC,EACxDG,GAAQc,EAAQ,WAAa,UAAYD,EAAM,MAAM,EAAIA,EAAM,MAAM,EAAA,CAAG,SAAS,EACvF,OAAO,OAAO,SAASb,CAAI,EAAIA,EAAO,GACxC"}
|
|
1
|
+
{"version":3,"file":"tick_math.js","names":["BigNumber","GC_MIN_TICK","GC_MAX_TICK","DexMath","DexDecimal","Decimal","tickToSqrtPrice","tick","sqrtPriceToTick","value","sqrtPrice","approximate","tickToPrice","isSqrtPriceInRange","isTickInRange","tickLower","tickUpper","tickFromPrice","priceText","price","exact","options"],"sources":["../../../src/utils/tick_math.ts"],"sourcesContent":["import BigNumber from 'bignumber.js';\nimport { Decimal } from 'decimal.js';\nimport { isTickInRange, type TickInput } from './tick_range.js';\n\n/**\n * Tick and price arithmetic that never throws an SDK error: the contract's tick bounds, the\n * conversions between ticks and prices, and nothing that validates a range. It imports only the\n * two number libraries it computes with, never the `GSwapSDKError` class or the error catalog\n * (functions that must throw, `alignTickDown` and `assertTickRange`, are in `ticks.ts`), so an\n * app shell that prices a tick pays for the libraries and these few functions, not for ~25 kB of\n * error templates. A value that cannot be computed is `NaN`, never an exception.\n */\n\n/** Minimum tick supported by GalaChainDex. */\nexport const GC_MIN_TICK = -887272;\n/** Maximum tick supported by GalaChainDex. */\nexport const GC_MAX_TICK = 887272;\n\nconst DexMath = BigNumber.clone({\n DECIMAL_PLACES: 60,\n ROUNDING_MODE: BigNumber.ROUND_DOWN,\n});\n/** `decimal.js` at the 60 significant digits the contract's price math is exact to. */\nexport const DexDecimal = Decimal.clone({ precision: 60 });\n\n/** Convert a tick to the corresponding square-root price. */\nexport function tickToSqrtPrice(tick: number): BigNumber {\n return new BigNumber(new DexDecimal(1.0001).pow(tick / 2).toString());\n}\n\n/** Return the greatest tick whose square-root price is no greater than the input. */\nexport function sqrtPriceToTick(sqrtPrice: BigNumber.Value): number {\n let value: BigNumber;\n try {\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — this function's contract is to signal an invalid input via NaN, not\n // to throw, so an unparseable value is just another case for the guard below.\n value = new DexMath(sqrtPrice);\n } catch {\n return Number.NaN;\n }\n if (!value.isFinite() || value.isLessThanOrEqualTo(0)) return Number.NaN;\n\n const approximate = Math.log(value.toNumber() ** 2) / Math.log(1.0001);\n if (!Number.isFinite(approximate)) return Number.NaN;\n // Clamp the seed before the correction loops below — an unclamped seed derived from an\n // out-of-range sqrtPrice (extreme but finite, e.g. 1e20) leaves the loops running past\n // GC_MIN_TICK/GC_MAX_TICK for a long time; an infinite (overflowed) seed would never\n // enter the increasing loop and never terminate the decreasing one.\n let tick = Math.min(GC_MAX_TICK, Math.max(GC_MIN_TICK, Math.floor(approximate)));\n while (tick < GC_MAX_TICK && tickToSqrtPrice(tick + 1).isLessThanOrEqualTo(value)) tick += 1;\n while (tick > GC_MIN_TICK && tickToSqrtPrice(tick).isGreaterThan(value)) tick -= 1;\n return tick;\n}\n\n/**\n * The token1/token0 price at `tick`: `1.0001 ** tick`, exact to 60 significant digits (the lower\n * edge of the tick's price range; `tickToSqrtPrice(tick) ** 2`). A tick outside the contract's\n * bounds is still computed; ask `assertTickRange` first when that matters. A non-integer tick is\n * computed as given.\n *\n * Use `.toNumber()` for a display value (it differs from `Math.exp(tick * Math.log(1.0001))` in\n * the last digits of a double: that expression multiplies in floating point first).\n */\nexport function tickToPrice(tick: number): BigNumber {\n return new BigNumber(new DexDecimal(1.0001).pow(tick).toString());\n}\n\n/**\n * {@link isTickInRange} for a pool's square-root price instead of its tick (a position row that\n * carries `sqrtPrice`, `tickLower` and `tickUpper`). The tick is derived from the price exactly as\n * the contract does (`sqrtPriceToTick`: the greatest tick whose square-root price is no greater\n * than the price, exact to 60 digits), then the contract's rule applies: lower tick inclusive,\n * upper tick exclusive. So a pool sitting exactly on `tickLower`'s price is in range, and exactly\n * on `tickUpper`'s price is not, and no float rounding can flip either.\n *\n * `false` for a price that is not positive and finite (not loaded, zero, `NaN`): it says nothing\n * about the position, so an app that must show a neutral state checks for the missing price\n * itself first. `tickLower` and `tickUpper` follow {@link isTickInRange}.\n *\n * @example\n * ```ts\n * const inRange = isSqrtPriceInRange(position.sqrtPrice, position.tickLower, position.tickUpper);\n * ```\n */\nexport function isSqrtPriceInRange(\n sqrtPrice: BigNumber.Value,\n tickLower: TickInput,\n tickUpper: TickInput,\n): boolean {\n return isTickInRange(sqrtPriceToTick(sqrtPrice), tickLower, tickUpper);\n}\n\n/** How {@link tickFromPrice} turns the exact logarithm into an integer tick. */\nexport interface TickFromPriceOptions {\n /**\n * `'floor'` (default): the greatest tick whose price is no greater than `price`, which is how\n * the contract places a price. `'nearest'`: the closest tick, a half rounding away from zero.\n * That is what a price INPUT wants (a person types a price, the field snaps to the nearest\n * tick), and it differs from `'floor'` for any price in the upper half of a tick's range.\n */\n rounding?: 'floor' | 'nearest' | undefined;\n}\n\n/**\n * Return the integer tick for a token1/token0 `price`: by default the greatest tick whose price\n * is no greater than `price`; `{ rounding: 'nearest' }` the closest tick. `NaN` for a price that\n * is not positive and finite.\n */\nexport function tickFromPrice(price: BigNumber.Value, options: TickFromPriceOptions = {}): number {\n const priceText =\n typeof price === 'string'\n ? price\n : typeof price === 'number'\n ? price.toString()\n : BigNumber.isBigNumber(price)\n ? price.toString()\n : 'NaN';\n const value = new DexDecimal(priceText);\n if (!value.isFinite() || value.lessThanOrEqualTo(0)) return Number.NaN;\n if (!Number.isFinite(value.toNumber())) return Number.NaN;\n const exact = value.ln().dividedBy(new DexDecimal(1.0001).ln());\n const tick = (options.rounding === 'nearest' ? exact.round() : exact.floor()).toNumber();\n return Number.isFinite(tick) ? tick : Number.NaN;\n}\n"],"mappings":"A,iHAcA,MAAaC,EAAc,QAEdC,EAAc,OAErBC,EAAUH,EAAU,MAAM,CAC9B,eAAgB,GAChB,cAAeA,EAAU,UAC3B,CAAC,EAEYI,EAAaC,EAAQ,MAAM,CAAE,UAAW,EAAG,CAAC,EAGzD,SAAgBC,EAAgB,EAAyB,CACvD,OAAO,IAAIN,EAAU,IAAII,EAAW,MAAM,CAAC,CAAC,IAAIG,EAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CACtE,CAGA,SAAgBC,EAAgB,EAAoC,CAClE,IAAIC,EACJ,GAAI,CAIF,EAAQ,IAAIN,EAAQO,CAAS,CAC/B,MAAQ,CACN,MAAO,IACT,CACA,GAAI,CAACD,EAAM,SAAS,GAAKA,EAAM,oBAAoB,CAAC,EAAG,MAAO,KAE9D,IAAME,EAAc,KAAK,IAAIF,EAAM,SAAS,GAAK,CAAC,EAAI,KAAK,IAAI,MAAM,EACrE,GAAI,CAAC,OAAO,SAASE,CAAW,EAAG,MAAO,KAK1C,IAAIJ,EAAO,KAAK,IAAIL,EAAa,KAAK,IAAID,EAAa,KAAK,MAAMU,CAAW,CAAC,CAAC,EAC/E,KAAOJ,EAAA,QAAsBD,EAAgBC,EAAO,CAAC,CAAC,CAAC,oBAAoBE,CAAK,GAAG,GAAQ,EAC3F,KAAOF,EAAA,SAAsBD,EAAgBC,CAAI,CAAC,CAAC,cAAcE,CAAK,GAAG,IACzE,OAAOF,CACT,CAWA,SAAgBK,EAAY,EAAyB,CACnD,OAAO,IAAIZ,EAAU,IAAII,EAAW,MAAM,CAAC,CAAC,IAAIG,CAAI,CAAC,CAAC,SAAS,CAAC,CAClE,CAmBA,SAAgBM,EACd,EACA,EACA,EACS,CACT,OAAOC,EAAcN,EAAgBE,CAAS,EAAGK,EAAWC,CAAS,CACvE,CAkBA,SAAgBC,EAAc,EAAwB,EAAgC,CAAC,EAAW,CAChG,IAAMC,EACJ,OAAOC,GAAU,SACbA,EACA,OAAOA,GAAU,UAEfnB,EAAU,YAAYmB,CAAK,EAD3BA,EAAM,SAAS,EAGb,MACJV,EAAQ,IAAIL,EAAWc,CAAS,EAEtC,GADI,CAACT,EAAM,SAAS,GAAKA,EAAM,kBAAkB,CAAC,GAC9C,CAAC,OAAO,SAASA,EAAM,SAAS,CAAC,EAAG,MAAO,KAC/C,IAAMW,EAAQX,EAAM,GAAG,CAAC,CAAC,UAAU,IAAIL,EAAW,MAAM,CAAC,CAAC,GAAG,CAAC,EACxDG,GAAQc,EAAQ,WAAa,UAAYD,EAAM,MAAM,EAAIA,EAAM,MAAM,EAAA,CAAG,SAAS,EACvF,OAAO,OAAO,SAASb,CAAI,EAAIA,EAAO,GACxC,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tick_range.js","names":["integerTickOf","tick","isTickInRange","current","currentTick","lower","tickLower","upper","tickUpper"],"sources":["../../../src/utils/tick_range.ts"],"sourcesContent":["/**\n * Whether a pool's current tick lies inside a position's range, by the contract's own rule. This\n * module imports nothing, so an app shell (a position badge, a filter) pays for a few dozen bytes.\n */\n\n/** A tick as the chain and the backends write it: a number, or the decimal string of one. */\nexport type TickInput = number | string;\n\nfunction integerTickOf(tick: TickInput): number {\n if (typeof tick === 'string') return tick.trim() === '' ? Number.NaN : Number(tick);\n return tick;\n}\n\n/**\n * True when a position over `[tickLower, tickUpper)` is IN RANGE at `currentTick`: the lower tick\n * is INCLUSIVE and the upper tick is EXCLUSIVE. That is the GalaChainDex contract's rule\n * (`DexV3Pool`: `tickCurrent >= tickLower && tickCurrent < tickUpper` is the case in which a\n * position holds both tokens and earns fees). A pool whose tick equals `tickUpper` is already out\n * of range: the position is entirely token1 there, and a swap through the tick has crossed it.\n *\n * `currentTick` is the pool's tick (`slot0.tick`, the greatest tick whose price is no greater than\n * the pool's price), not a rounded display value. A tick may be a number or the decimal string a\n * backend returns. Anything that is not an integer (`NaN`, `undefined`-like, an empty string, a\n * fraction) makes the answer `false`: an app that must tell \"not loaded yet\" from \"out of range\"\n * checks for the missing value itself first.\n *\n * Do NOT decide range by comparing a price with a tick's price (`tickToPrice`) using `<=` on both\n * ends, or by mixing a square-root price with a price. A price exactly on a tick's boundary is\n * then in range at the upper edge (the contract says it is not), and two representations of the\n * same boundary can round to opposite sides. For a pool price use {@link isSqrtPriceInRange}, which\n * derives the tick the way the contract does and then applies this rule.\n *\n * @example\n * ```ts\n * isTickInRange(-60, -60, 60); // true: the lower tick is inclusive\n * isTickInRange(60, -60, 60); // false: the upper tick is exclusive\n * ```\n */\nexport function isTickInRange(\n currentTick: TickInput,\n tickLower: TickInput,\n tickUpper: TickInput,\n): boolean {\n const current = integerTickOf(currentTick);\n const lower = integerTickOf(tickLower);\n const upper = integerTickOf(tickUpper);\n if (!Number.isInteger(current) || !Number.isInteger(lower) || !Number.isInteger(upper)) {\n return false;\n }\n return current >= lower && current < upper;\n}\n"],"mappings":"AAQA,SAASA,EAAc,EAAyB,CAE9C,OADI,OAAOC,GAAS,SAAiBA,EAAK,KAAK,IAAM,GAAK,IAAa,OAAOA,CAAI,EAC3EA,CACT,CA2BA,SAAgBC,EACd,EACA,EACA,EACS,CACT,IAAMC,EAAUH,EAAcI,CAAW,EACnCC,EAAQL,EAAcM,CAAS,EAC/BC,EAAQP,EAAcQ,CAAS,EAIrC,MAHI,CAAC,OAAO,UAAUL,CAAO,GAAK,CAAC,OAAO,UAAUE,CAAK,GAAK,CAAC,OAAO,UAAUE,CAAK,EAC5E,GAEFJ,GAAWE,GAASF,EAAUI,CACvC"}
|
|
1
|
+
{"version":3,"file":"tick_range.js","names":["integerTickOf","tick","isTickInRange","current","currentTick","lower","tickLower","upper","tickUpper"],"sources":["../../../src/utils/tick_range.ts"],"sourcesContent":["/**\n * Whether a pool's current tick lies inside a position's range, by the contract's own rule. This\n * module imports nothing, so an app shell (a position badge, a filter) pays for a few dozen bytes.\n */\n\n/** A tick as the chain and the backends write it: a number, or the decimal string of one. */\nexport type TickInput = number | string;\n\nfunction integerTickOf(tick: TickInput): number {\n if (typeof tick === 'string') return tick.trim() === '' ? Number.NaN : Number(tick);\n return tick;\n}\n\n/**\n * True when a position over `[tickLower, tickUpper)` is IN RANGE at `currentTick`: the lower tick\n * is INCLUSIVE and the upper tick is EXCLUSIVE. That is the GalaChainDex contract's rule\n * (`DexV3Pool`: `tickCurrent >= tickLower && tickCurrent < tickUpper` is the case in which a\n * position holds both tokens and earns fees). A pool whose tick equals `tickUpper` is already out\n * of range: the position is entirely token1 there, and a swap through the tick has crossed it.\n *\n * `currentTick` is the pool's tick (`slot0.tick`, the greatest tick whose price is no greater than\n * the pool's price), not a rounded display value. A tick may be a number or the decimal string a\n * backend returns. Anything that is not an integer (`NaN`, `undefined`-like, an empty string, a\n * fraction) makes the answer `false`: an app that must tell \"not loaded yet\" from \"out of range\"\n * checks for the missing value itself first.\n *\n * Do NOT decide range by comparing a price with a tick's price (`tickToPrice`) using `<=` on both\n * ends, or by mixing a square-root price with a price. A price exactly on a tick's boundary is\n * then in range at the upper edge (the contract says it is not), and two representations of the\n * same boundary can round to opposite sides. For a pool price use {@link isSqrtPriceInRange}, which\n * derives the tick the way the contract does and then applies this rule.\n *\n * @example\n * ```ts\n * isTickInRange(-60, -60, 60); // true: the lower tick is inclusive\n * isTickInRange(60, -60, 60); // false: the upper tick is exclusive\n * ```\n */\nexport function isTickInRange(\n currentTick: TickInput,\n tickLower: TickInput,\n tickUpper: TickInput,\n): boolean {\n const current = integerTickOf(currentTick);\n const lower = integerTickOf(tickLower);\n const upper = integerTickOf(tickUpper);\n if (!Number.isInteger(current) || !Number.isInteger(lower) || !Number.isInteger(upper)) {\n return false;\n }\n return current >= lower && current < upper;\n}\n"],"mappings":"AAQA,SAASA,EAAc,EAAyB,CAE9C,OADI,OAAOC,GAAS,SAAiBA,EAAK,KAAK,IAAM,GAAK,IAAa,OAAOA,CAAI,EAC3EA,CACT,CA2BA,SAAgBC,EACd,EACA,EACA,EACS,CACT,IAAMC,EAAUH,EAAcI,CAAW,EACnCC,EAAQL,EAAcM,CAAS,EAC/BC,EAAQP,EAAcQ,CAAS,EAIrC,MAHI,CAAC,OAAO,UAAUL,CAAO,GAAK,CAAC,OAAO,UAAUE,CAAK,GAAK,CAAC,OAAO,UAAUE,CAAK,EAC5E,GAEFJ,GAAWE,GAASF,EAAUI,CACvC,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ticks.js","names":["alignTickDown","assertSpacing","spacing","alignTickDownOrNaN","tick","alignTickUp","alignTickUpOrNaN","assertTickRange","TICK_SPACING_BY_FEE","fee","GSwapSDKError","ALLOWED_FEE_TIERS_TEXT","lower","upper","GC_MIN_TICK","GC_MAX_TICK","hasValidSpacing","frameSlot0","slot0","inverted","DexDecimal","sqrtPrice","sqrtPriceToTick"],"sources":["../../../src/utils/ticks.ts"],"sourcesContent":["import { ALLOWED_FEE_TIERS_TEXT } from '../classes/gswap_error_catalog.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { TICK_SPACING_BY_FEE } from '../types/fees.js';\nimport { alignTickDownOrNaN, alignTickUpOrNaN, hasValidSpacing } from './tick_align.js';\nimport { DexDecimal, GC_MAX_TICK, GC_MIN_TICK, sqrtPriceToTick } from './tick_math.js';\n\n/**\n * The tick functions that THROW an SDK error on a bad input (`alignTickDown`, `alignTickUp`,\n * `assertTickRange`, `frameSlot0`). The arithmetic that never throws (`tickToPrice`,\n * `tickFromPrice`, `tickToSqrtPrice`, `sqrtPriceToTick`, the bounds) is in `tick_math.ts`, which\n * does not import the error class or the catalog; import it from the package entry as usual.\n */\n\n/** Align a tick down to the nearest multiple of a positive spacing. */\nexport function alignTickDown(tick: number, spacing: number): number {\n assertSpacing(spacing);\n return alignTickDownOrNaN(tick, spacing);\n}\n\n/** Align a tick up to the nearest multiple of a positive spacing. */\nexport function alignTickUp(tick: number, spacing: number): number {\n assertSpacing(spacing);\n return alignTickUpOrNaN(tick, spacing);\n}\n\n/** Validate a position range against the global tick bounds and fee-tier spacing. */\nexport function assertTickRange(lower: number, upper: number, fee: FEE_TIER): void {\n const spacing = TICK_SPACING_BY_FEE[fee];\n if (spacing === undefined) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n if (!Number.isInteger(lower) || !Number.isInteger(upper)) {\n throw new GSwapSDKError('TICKS_NOT_INTEGERS', { tickLower: lower, tickUpper: upper });\n }\n if (lower >= upper) {\n throw new GSwapSDKError('INVALID_TICK_RANGE', { tickLower: lower, tickUpper: upper });\n }\n if (lower < GC_MIN_TICK || upper > GC_MAX_TICK) {\n throw new GSwapSDKError('TICKS_OUT_OF_BOUNDS', {\n tickLower: lower,\n tickUpper: upper,\n minTick: GC_MIN_TICK,\n maxTick: GC_MAX_TICK,\n });\n }\n if (lower % spacing !== 0 || upper % spacing !== 0) {\n throw new GSwapSDKError('TICKS_NOT_ALIGNED', {\n tickLower: lower,\n tickUpper: upper,\n spacing,\n });\n }\n}\n\nfunction assertSpacing(spacing: number): void {\n if (!hasValidSpacing(spacing)) {\n throw new GSwapSDKError('INVALID_TICK_SPACING', { value: spacing });\n }\n}\n\n/** A pool's current price in the frame of the request that asked for it. */\nexport interface FramedSlot0 {\n /** The square-root price, token1 per token0 in the REQUESTED order. */\n sqrtPrice: string;\n /** The greatest tick whose square-root price is no greater than `sqrtPrice`. */\n tick: number;\n}\n\n/**\n * Puts a `slot0` answer into the frame of the request. The backend always answers in the pool's\n * canonical order and says so with `flippedFromRequest`; when the caller asked for the reverse\n * order the price is inverted here (at 60 significant digits, so a very large or very small\n * reciprocal keeps its precision) and the tick is re-derived from the inverted price with the\n * contract's greatest-tick rule. Negating the tick instead is wrong for a price between ticks\n * (and `-t - 1` is wrong for a price exactly on a tick: sqrtPrice 1 / tick 0 stays 1 / 0).\n *\n * @example\n * ```ts\n * const slot0 = await gSwap.pools.getSlot0('A', 'B', 500);\n * const { sqrtPrice, tick } = frameSlot0(slot0);\n * ```\n */\nexport function frameSlot0(slot0: {\n sqrtPrice: string;\n tick: number;\n flippedFromRequest?: boolean | undefined;\n}): FramedSlot0 {\n if (slot0.flippedFromRequest !== true) return { sqrtPrice: slot0.sqrtPrice, tick: slot0.tick };\n const inverted = new DexDecimal(1).dividedBy(new DexDecimal(slot0.sqrtPrice));\n if (!inverted.isFinite() || inverted.lessThanOrEqualTo(0)) {\n throw new GSwapSDKError('INVALID_SQRT_PRICE', { sqrtPrice: slot0.sqrtPrice });\n }\n const sqrtPrice = inverted.toString();\n return { sqrtPrice, tick: sqrtPriceToTick(sqrtPrice) };\n}\n"],"mappings":"mYAeA,SAAgBA,EAAc,EAAc,EAAyB,CAEnE,OADAC,EAAcC,CAAO,EACdC,EAAmBC,EAAMF,CAAO,CACzC,CAGA,SAAgBG,EAAY,EAAc,EAAyB,CAEjE,OADAJ,EAAcC,CAAO,EACdI,EAAiBF,EAAMF,CAAO,CACvC,CAGA,SAAgBK,EAAgB,EAAe,EAAe,EAAqB,CACjF,IAAML,EAAUM,EAAoBC,GACpC,GAAIP,IAAY,IAAA,GACd,MAAM,IAAIQ,EAAc,cAAe,CACrC,MAAO,MACP,MAAOD,EACP,QAASE,CACX,CAAC,EAEH,GAAI,CAAC,OAAO,UAAUC,CAAK,GAAK,CAAC,OAAO,UAAUC,CAAK,EACrD,MAAM,IAAIH,EAAc,qBAAsB,CAAE,UAAWE,EAAO,UAAWC,CAAM,CAAC,EAEtF,GAAID,GAASC,EACX,MAAM,IAAIH,EAAc,qBAAsB,CAAE,UAAWE,EAAO,UAAWC,CAAM,CAAC,EAEtF,GAAID,EAAA,SAAuBC,EAAA,OACzB,MAAM,IAAIH,EAAc,sBAAuB,CAC7C,UAAWE,EACX,UAAWC,EACX,QAASC,EACT,QAASC,CACX,CAAC,EAEH,GAAIH,EAAQV,IAAY,GAAKW,EAAQX,IAAY,EAC/C,MAAM,IAAIQ,EAAc,oBAAqB,CAC3C,UAAWE,EACX,UAAWC,EACX,SACF,CAAC,CAEL,CAEA,SAASZ,EAAc,EAAuB,CAC5C,GAAI,CAACe,EAAgBd,CAAO,EAC1B,MAAM,IAAIQ,EAAc,uBAAwB,CAAE,MAAOR,CAAQ,CAAC,CAEtE,CAwBA,SAAgBe,EAAW,EAIX,CACd,GAAIC,EAAM,qBAAuB,GAAM,MAAO,CAAE,UAAWA,EAAM,UAAW,KAAMA,EAAM,IAAK,EAC7F,IAAMC,EAAW,IAAIC,EAAW,CAAC,CAAC,CAAC,UAAU,IAAIA,EAAWF,EAAM,SAAS,CAAC,EAC5E,GAAI,CAACC,EAAS,SAAS,GAAKA,EAAS,kBAAkB,CAAC,EACtD,MAAM,IAAIT,EAAc,qBAAsB,CAAE,UAAWQ,EAAM,SAAU,CAAC,EAE9E,IAAMG,EAAYF,EAAS,SAAS,EACpC,MAAO,CAAE,YAAW,KAAMG,EAAgBD,CAAS,CAAE,CACvD"}
|
|
1
|
+
{"version":3,"file":"ticks.js","names":["alignTickDown","assertSpacing","spacing","alignTickDownOrNaN","tick","alignTickUp","alignTickUpOrNaN","assertTickRange","TICK_SPACING_BY_FEE","fee","GSwapSDKError","ALLOWED_FEE_TIERS_TEXT","lower","upper","GC_MIN_TICK","GC_MAX_TICK","hasValidSpacing","frameSlot0","slot0","inverted","DexDecimal","sqrtPrice","sqrtPriceToTick"],"sources":["../../../src/utils/ticks.ts"],"sourcesContent":["import { ALLOWED_FEE_TIERS_TEXT } from '../classes/gswap_error_catalog.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { TICK_SPACING_BY_FEE } from '../types/fees.js';\nimport { alignTickDownOrNaN, alignTickUpOrNaN, hasValidSpacing } from './tick_align.js';\nimport { DexDecimal, GC_MAX_TICK, GC_MIN_TICK, sqrtPriceToTick } from './tick_math.js';\n\n/**\n * The tick functions that THROW an SDK error on a bad input (`alignTickDown`, `alignTickUp`,\n * `assertTickRange`, `frameSlot0`). The arithmetic that never throws (`tickToPrice`,\n * `tickFromPrice`, `tickToSqrtPrice`, `sqrtPriceToTick`, the bounds) is in `tick_math.ts`, which\n * does not import the error class or the catalog; import it from the package entry as usual.\n */\n\n/** Align a tick down to the nearest multiple of a positive spacing. */\nexport function alignTickDown(tick: number, spacing: number): number {\n assertSpacing(spacing);\n return alignTickDownOrNaN(tick, spacing);\n}\n\n/** Align a tick up to the nearest multiple of a positive spacing. */\nexport function alignTickUp(tick: number, spacing: number): number {\n assertSpacing(spacing);\n return alignTickUpOrNaN(tick, spacing);\n}\n\n/** Validate a position range against the global tick bounds and fee-tier spacing. */\nexport function assertTickRange(lower: number, upper: number, fee: FEE_TIER): void {\n const spacing = TICK_SPACING_BY_FEE[fee];\n if (spacing === undefined) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n if (!Number.isInteger(lower) || !Number.isInteger(upper)) {\n throw new GSwapSDKError('TICKS_NOT_INTEGERS', { tickLower: lower, tickUpper: upper });\n }\n if (lower >= upper) {\n throw new GSwapSDKError('INVALID_TICK_RANGE', { tickLower: lower, tickUpper: upper });\n }\n if (lower < GC_MIN_TICK || upper > GC_MAX_TICK) {\n throw new GSwapSDKError('TICKS_OUT_OF_BOUNDS', {\n tickLower: lower,\n tickUpper: upper,\n minTick: GC_MIN_TICK,\n maxTick: GC_MAX_TICK,\n });\n }\n if (lower % spacing !== 0 || upper % spacing !== 0) {\n throw new GSwapSDKError('TICKS_NOT_ALIGNED', {\n tickLower: lower,\n tickUpper: upper,\n spacing,\n });\n }\n}\n\nfunction assertSpacing(spacing: number): void {\n if (!hasValidSpacing(spacing)) {\n throw new GSwapSDKError('INVALID_TICK_SPACING', { value: spacing });\n }\n}\n\n/** A pool's current price in the frame of the request that asked for it. */\nexport interface FramedSlot0 {\n /** The square-root price, token1 per token0 in the REQUESTED order. */\n sqrtPrice: string;\n /** The greatest tick whose square-root price is no greater than `sqrtPrice`. */\n tick: number;\n}\n\n/**\n * Puts a `slot0` answer into the frame of the request. The backend always answers in the pool's\n * canonical order and says so with `flippedFromRequest`; when the caller asked for the reverse\n * order the price is inverted here (at 60 significant digits, so a very large or very small\n * reciprocal keeps its precision) and the tick is re-derived from the inverted price with the\n * contract's greatest-tick rule. Negating the tick instead is wrong for a price between ticks\n * (and `-t - 1` is wrong for a price exactly on a tick: sqrtPrice 1 / tick 0 stays 1 / 0).\n *\n * @example\n * ```ts\n * const slot0 = await gSwap.pools.getSlot0('A', 'B', 500);\n * const { sqrtPrice, tick } = frameSlot0(slot0);\n * ```\n */\nexport function frameSlot0(slot0: {\n sqrtPrice: string;\n tick: number;\n flippedFromRequest?: boolean | undefined;\n}): FramedSlot0 {\n if (slot0.flippedFromRequest !== true) return { sqrtPrice: slot0.sqrtPrice, tick: slot0.tick };\n const inverted = new DexDecimal(1).dividedBy(new DexDecimal(slot0.sqrtPrice));\n if (!inverted.isFinite() || inverted.lessThanOrEqualTo(0)) {\n throw new GSwapSDKError('INVALID_SQRT_PRICE', { sqrtPrice: slot0.sqrtPrice });\n }\n const sqrtPrice = inverted.toString();\n return { sqrtPrice, tick: sqrtPriceToTick(sqrtPrice) };\n}\n"],"mappings":"A,mYAeA,SAAgBA,EAAc,EAAc,EAAyB,CAEnE,OADAC,EAAcC,CAAO,EACdC,EAAmBC,EAAMF,CAAO,CACzC,CAGA,SAAgBG,EAAY,EAAc,EAAyB,CAEjE,OADAJ,EAAcC,CAAO,EACdI,EAAiBF,EAAMF,CAAO,CACvC,CAGA,SAAgBK,EAAgB,EAAe,EAAe,EAAqB,CACjF,IAAML,EAAUM,EAAoBC,GACpC,GAAIP,IAAY,IAAA,GACd,MAAM,IAAIQ,EAAc,cAAe,CACrC,MAAO,MACP,MAAOD,EACP,QAASE,CACX,CAAC,EAEH,GAAI,CAAC,OAAO,UAAUC,CAAK,GAAK,CAAC,OAAO,UAAUC,CAAK,EACrD,MAAM,IAAIH,EAAc,qBAAsB,CAAE,UAAWE,EAAO,UAAWC,CAAM,CAAC,EAEtF,GAAID,GAASC,EACX,MAAM,IAAIH,EAAc,qBAAsB,CAAE,UAAWE,EAAO,UAAWC,CAAM,CAAC,EAEtF,GAAID,EAAA,SAAuBC,EAAA,OACzB,MAAM,IAAIH,EAAc,sBAAuB,CAC7C,UAAWE,EACX,UAAWC,EACX,QAASC,EACT,QAASC,CACX,CAAC,EAEH,GAAIH,EAAQV,IAAY,GAAKW,EAAQX,IAAY,EAC/C,MAAM,IAAIQ,EAAc,oBAAqB,CAC3C,UAAWE,EACX,UAAWC,EACX,SACF,CAAC,CAEL,CAEA,SAASZ,EAAc,EAAuB,CAC5C,GAAI,CAACe,EAAgBd,CAAO,EAC1B,MAAM,IAAIQ,EAAc,uBAAwB,CAAE,MAAOR,CAAQ,CAAC,CAEtE,CAwBA,SAAgBe,EAAW,EAIX,CACd,GAAIC,EAAM,qBAAuB,GAAM,MAAO,CAAE,UAAWA,EAAM,UAAW,KAAMA,EAAM,IAAK,EAC7F,IAAMC,EAAW,IAAIC,EAAW,CAAC,CAAC,CAAC,UAAU,IAAIA,EAAWF,EAAM,SAAS,CAAC,EAC5E,GAAI,CAACC,EAAS,SAAS,GAAKA,EAAS,kBAAkB,CAAC,EACtD,MAAM,IAAIT,EAAc,qBAAsB,CAAE,UAAWQ,EAAM,SAAU,CAAC,EAE9E,IAAMG,EAAYF,EAAS,SAAS,EACpC,MAAO,CAAE,YAAW,KAAMG,EAAgBD,CAAS,CAAE,CACvD,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","names":["BigNumber","validateNumericAmount","amount","GSwapSDKError","parameterName","bnAmount","allowZero","validatePriceValues","spotPrice","lowerPrice","upperPrice","value","parse","bnSpotPrice","bnLowerPrice","bnUpperPrice","validateTokenDecimals","decimals","validateTickRange","tickLower","tickUpper","GC_MIN_TICK","GC_MAX_TICK","validateFee","ALL_FEE_TIERS","tier","fee","ALLOWED_FEE_TIERS_TEXT","validateTickSpacing","tickSpacing","userRef","galaChainUserRef","field","cause","isGalaError","requireUserRef","address","RESERVED_TRADING_SYMBOLS","TRADING_SYMBOL_PATTERN","isProposableTradingSymbol","symbol","assertCanonicalPair","token0","token1"],"sources":["../../../src/utils/validation.ts"],"sourcesContent":["import { galaChainUserRef, isGalaError } from '@gala-chain/gala-core-sdk';\nimport BigNumber from 'bignumber.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from '../classes/gswap_error_catalog.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { NumericAmount } from '../types/amounts.js';\nimport { ALL_FEE_TIERS } from '../types/fees.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { GC_MAX_TICK, GC_MIN_TICK } from './tick_math.js';\n\n/**\n * Validates a decimal amount: a string or `BigNumber`, never a JavaScript number.\n *\n * @param amount - The amount to check.\n * @param parameterName - The field name reported in the error's `params.field`.\n * @param allowZero - Accept zero (default `false`).\n * @throws GSwapSDKError `AMOUNT_IS_JS_NUMBER`, `AMOUNT_NOT_FINITE`, `AMOUNT_NOT_POSITIVE` (zero\n * when `allowZero` is false) or `AMOUNT_NEGATIVE`.\n */\nexport function validateNumericAmount(\n amount: NumericAmount,\n parameterName: string,\n allowZero = false,\n): void {\n if (typeof amount === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: parameterName });\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite() check below still catches\n // it and raises the same typed error, instead of a raw exception escaping.\n let bnAmount: BigNumber;\n try {\n bnAmount = BigNumber(amount);\n } catch {\n bnAmount = BigNumber(NaN);\n }\n\n if (!bnAmount.isFinite()) {\n throw new GSwapSDKError('AMOUNT_NOT_FINITE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (!allowZero && bnAmount.isZero()) {\n throw new GSwapSDKError('AMOUNT_NOT_POSITIVE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (bnAmount.isNegative()) {\n throw new GSwapSDKError('AMOUNT_NEGATIVE', { field: parameterName, value: String(amount) });\n }\n}\n\n/**\n * Validates a spot price and a lower/upper price range: none a JavaScript number, all positive and\n * finite (a non-finite upper bound counts as an unbounded `1e18`), and `lowerPrice <= upperPrice`.\n *\n * @throws GSwapSDKError `PRICE_VALUES_IS_JS_NUMBER`, `INVALID_PRICE_VALUES` or `INVALID_PRICE_RANGE`.\n */\nexport function validatePriceValues(\n spotPrice: NumericAmount,\n lowerPrice: NumericAmount,\n upperPrice: NumericAmount,\n): void {\n if ([spotPrice, lowerPrice, upperPrice].some((value) => typeof value === 'number')) {\n throw new GSwapSDKError('PRICE_VALUES_IS_JS_NUMBER', {});\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite()/isPositive() checks below\n // still catch it and raise the same typed error, instead of a raw exception escaping.\n const parse = (value: NumericAmount): BigNumber => {\n try {\n return BigNumber(value);\n } catch {\n return BigNumber(NaN);\n }\n };\n const bnSpotPrice = parse(spotPrice);\n const bnLowerPrice = parse(lowerPrice);\n let bnUpperPrice = parse(upperPrice);\n\n bnUpperPrice = bnUpperPrice.isFinite() ? bnUpperPrice : BigNumber(1e18);\n\n if (\n !bnSpotPrice.isFinite() ||\n !bnLowerPrice.isFinite() ||\n !bnUpperPrice.isFinite() ||\n !bnSpotPrice.isPositive() ||\n !bnLowerPrice.isPositive() ||\n !bnUpperPrice.isPositive()\n ) {\n throw new GSwapSDKError('INVALID_PRICE_VALUES', {\n spotPrice: String(spotPrice),\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n\n if (bnLowerPrice.isGreaterThan(bnUpperPrice)) {\n throw new GSwapSDKError('INVALID_PRICE_RANGE', {\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n}\n\n/**\n * Validates a token's decimals: a non-negative integer.\n *\n * @throws GSwapSDKError `INVALID_TOKEN_DECIMALS` (`params.field` is `parameterName`).\n */\nexport function validateTokenDecimals(decimals: number, parameterName: string): void {\n if (decimals < 0 || !Number.isInteger(decimals)) {\n throw new GSwapSDKError('INVALID_TOKEN_DECIMALS', { field: parameterName, value: decimals });\n }\n}\n\n/**\n * Validates a position's tick range: two integers with `tickLower < tickUpper`, both within\n * `GC_MIN_TICK`..`GC_MAX_TICK`. It does not check alignment to a fee tier's spacing (see\n * `assertTickRange`).\n *\n * @throws GSwapSDKError `TICKS_NOT_INTEGERS`, `INVALID_TICK_RANGE` or `TICKS_OUT_OF_BOUNDS`.\n */\nexport function validateTickRange(tickLower: number, tickUpper: number): void {\n if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) {\n throw new GSwapSDKError('TICKS_NOT_INTEGERS', { tickLower, tickUpper });\n }\n\n if (tickLower >= tickUpper) {\n throw new GSwapSDKError('INVALID_TICK_RANGE', { tickLower, tickUpper });\n }\n\n if (tickLower < GC_MIN_TICK || tickUpper > GC_MAX_TICK) {\n throw new GSwapSDKError('TICKS_OUT_OF_BOUNDS', {\n tickLower,\n tickUpper,\n minTick: GC_MIN_TICK,\n maxTick: GC_MAX_TICK,\n });\n }\n}\n\n/**\n * Asserts that `fee` is one of the fee tiers in `ALL_FEE_TIERS` (`0`, `500`, `3000`, `10000`).\n *\n * @throws GSwapSDKError `INVALID_FEE` (`params.field` `'fee'`, `params.allowed` the tiers).\n */\nexport function validateFee(fee: number): asserts fee is FEE_TIER {\n if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n}\n\n/**\n * Validates a tick spacing: a positive integer.\n *\n * @throws GSwapSDKError `INVALID_TICK_SPACING`.\n */\nexport function validateTickSpacing(tickSpacing: number): void {\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {\n throw new GSwapSDKError('INVALID_TICK_SPACING', { value: tickSpacing });\n }\n}\n\n/**\n * The GalaChain user reference an owner, user or wallet address names, in the one spelling the\n * gateway and the swap backend accept: `eth|<EIP-55 checksummed digits>` for an Ethereum account\n * (given as `eth|<40 hex>` in any casing, `0x<40 hex>` or bare hex), `client|<id>` as written.\n * `eth|0x<hex>` is not an address form. This is `galaChainUserRef` of\n * `@gala-chain/gala-core-sdk`, the one implementation; only the error for a spelling that is no\n * address at all is this package's. Every place this SDK puts a user identity on the wire goes\n * through it, so what is signed, sent and compared on the backend (`owner === position.owner`,\n * strict) is always the chain's own spelling.\n *\n * @param value - The identity the caller gave.\n * @param field - The field name reported in the error's `params.field`.\n * @throws GalaSDKError core's `INVALID_ETH_USER_REF_PREFIX` (passed through as it is: its message\n * says an `eth|` reference takes the 40 hex digits with no `0x` and names the correct spelling,\n * `params.expected`) for `eth|0x...`; GSwapSDKError `INVALID_WALLET_ADDRESS` for anything else, a\n * mixed-case spelling whose casing is not the EIP-55 checksum included (a typo); nothing is\n * signed or sent.\n */\nexport function userRef(value: unknown, field: string): string {\n try {\n return galaChainUserRef(value, field);\n } catch (cause: unknown) {\n if (isGalaError(cause) && cause.code === 'INVALID_ETH_USER_REF_PREFIX') throw cause;\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', { field, value: String(value) });\n }\n}\n\n/**\n * {@link userRef} of an address that must be there.\n *\n * @throws GSwapSDKError `MISSING_WALLET_ADDRESS` (undefined) or `INVALID_WALLET_ADDRESS`; core's\n * `INVALID_ETH_USER_REF_PREFIX` for `eth|0x...` (see {@link userRef}).\n */\nexport function requireUserRef(address: string | undefined, field: string): string {\n if (address === undefined) {\n throw new GSwapSDKError('MISSING_WALLET_ADDRESS', {});\n }\n return userRef(address, field);\n}\n\n/** Words the chain gateway refuses as a trading symbol. */\nconst RESERVED_TRADING_SYMBOLS = new Set(['Token', 'Unit', 'none']);\nconst TRADING_SYMBOL_PATTERN = /^[A-Za-z0-9]+$/u;\nconst MAX_TRADING_SYMBOL_LENGTH = 32;\n\n/**\n * True when `symbol` is acceptable to propose into the trading-symbol registry: ASCII letters and\n * digits only, 1 to 32 characters, and not a reserved word (`Token`, `Unit`, `none`) — the rules\n * the chain gateway enforces on a CreatePool symbol.\n */\nexport function isProposableTradingSymbol(symbol: string): boolean {\n return (\n TRADING_SYMBOL_PATTERN.test(symbol) &&\n symbol.length <= MAX_TRADING_SYMBOL_LENGTH &&\n !RESERVED_TRADING_SYMBOLS.has(symbol)\n );\n}\n\n/**\n * Asserts that a pair is in the contract's canonical order (`token0 < token1` by plain string\n * comparison), which every write DTO requires. A pair a caller took from a stale quote or\n * position can be reversed; signing it would sign something other than what was priced.\n *\n * @throws GSwapSDKError `NON_CANONICAL_PAIR` (`params.token0`, `params.token1`) otherwise.\n */\nexport function assertCanonicalPair(token0: string, token1: string): void {\n if (!(token0 < token1)) {\n throw new GSwapSDKError('NON_CANONICAL_PAIR', { token0, token1 });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validation.js","names":["BigNumber","validateNumericAmount","amount","GSwapSDKError","parameterName","bnAmount","allowZero","validatePriceValues","spotPrice","lowerPrice","upperPrice","value","parse","bnSpotPrice","bnLowerPrice","bnUpperPrice","validateTokenDecimals","decimals","validateTickRange","tickLower","tickUpper","GC_MIN_TICK","GC_MAX_TICK","validateFee","ALL_FEE_TIERS","tier","fee","ALLOWED_FEE_TIERS_TEXT","validateTickSpacing","tickSpacing","userRef","galaChainUserRef","field","cause","isGalaError","requireUserRef","address","RESERVED_TRADING_SYMBOLS","TRADING_SYMBOL_PATTERN","isProposableTradingSymbol","symbol","assertCanonicalPair","token0","token1"],"sources":["../../../src/utils/validation.ts"],"sourcesContent":["import { galaChainUserRef, isGalaError } from '@gala-chain/gala-core-sdk';\nimport BigNumber from 'bignumber.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from '../classes/gswap_error_catalog.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { NumericAmount } from '../types/amounts.js';\nimport { ALL_FEE_TIERS } from '../types/fees.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { GC_MAX_TICK, GC_MIN_TICK } from './tick_math.js';\n\n/**\n * Validates a decimal amount: a string or `BigNumber`, never a JavaScript number.\n *\n * @param amount - The amount to check.\n * @param parameterName - The field name reported in the error's `params.field`.\n * @param allowZero - Accept zero (default `false`).\n * @throws GSwapSDKError `AMOUNT_IS_JS_NUMBER`, `AMOUNT_NOT_FINITE`, `AMOUNT_NOT_POSITIVE` (zero\n * when `allowZero` is false) or `AMOUNT_NEGATIVE`.\n */\nexport function validateNumericAmount(\n amount: NumericAmount,\n parameterName: string,\n allowZero = false,\n): void {\n if (typeof amount === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: parameterName });\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite() check below still catches\n // it and raises the same typed error, instead of a raw exception escaping.\n let bnAmount: BigNumber;\n try {\n bnAmount = BigNumber(amount);\n } catch {\n bnAmount = BigNumber(NaN);\n }\n\n if (!bnAmount.isFinite()) {\n throw new GSwapSDKError('AMOUNT_NOT_FINITE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (!allowZero && bnAmount.isZero()) {\n throw new GSwapSDKError('AMOUNT_NOT_POSITIVE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (bnAmount.isNegative()) {\n throw new GSwapSDKError('AMOUNT_NEGATIVE', { field: parameterName, value: String(amount) });\n }\n}\n\n/**\n * Validates a spot price and a lower/upper price range: none a JavaScript number, all positive and\n * finite (a non-finite upper bound counts as an unbounded `1e18`), and `lowerPrice <= upperPrice`.\n *\n * @throws GSwapSDKError `PRICE_VALUES_IS_JS_NUMBER`, `INVALID_PRICE_VALUES` or `INVALID_PRICE_RANGE`.\n */\nexport function validatePriceValues(\n spotPrice: NumericAmount,\n lowerPrice: NumericAmount,\n upperPrice: NumericAmount,\n): void {\n if ([spotPrice, lowerPrice, upperPrice].some((value) => typeof value === 'number')) {\n throw new GSwapSDKError('PRICE_VALUES_IS_JS_NUMBER', {});\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite()/isPositive() checks below\n // still catch it and raise the same typed error, instead of a raw exception escaping.\n const parse = (value: NumericAmount): BigNumber => {\n try {\n return BigNumber(value);\n } catch {\n return BigNumber(NaN);\n }\n };\n const bnSpotPrice = parse(spotPrice);\n const bnLowerPrice = parse(lowerPrice);\n let bnUpperPrice = parse(upperPrice);\n\n bnUpperPrice = bnUpperPrice.isFinite() ? bnUpperPrice : BigNumber(1e18);\n\n if (\n !bnSpotPrice.isFinite() ||\n !bnLowerPrice.isFinite() ||\n !bnUpperPrice.isFinite() ||\n !bnSpotPrice.isPositive() ||\n !bnLowerPrice.isPositive() ||\n !bnUpperPrice.isPositive()\n ) {\n throw new GSwapSDKError('INVALID_PRICE_VALUES', {\n spotPrice: String(spotPrice),\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n\n if (bnLowerPrice.isGreaterThan(bnUpperPrice)) {\n throw new GSwapSDKError('INVALID_PRICE_RANGE', {\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n}\n\n/**\n * Validates a token's decimals: a non-negative integer.\n *\n * @throws GSwapSDKError `INVALID_TOKEN_DECIMALS` (`params.field` is `parameterName`).\n */\nexport function validateTokenDecimals(decimals: number, parameterName: string): void {\n if (decimals < 0 || !Number.isInteger(decimals)) {\n throw new GSwapSDKError('INVALID_TOKEN_DECIMALS', { field: parameterName, value: decimals });\n }\n}\n\n/**\n * Validates a position's tick range: two integers with `tickLower < tickUpper`, both within\n * `GC_MIN_TICK`..`GC_MAX_TICK`. It does not check alignment to a fee tier's spacing (see\n * `assertTickRange`).\n *\n * @throws GSwapSDKError `TICKS_NOT_INTEGERS`, `INVALID_TICK_RANGE` or `TICKS_OUT_OF_BOUNDS`.\n */\nexport function validateTickRange(tickLower: number, tickUpper: number): void {\n if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) {\n throw new GSwapSDKError('TICKS_NOT_INTEGERS', { tickLower, tickUpper });\n }\n\n if (tickLower >= tickUpper) {\n throw new GSwapSDKError('INVALID_TICK_RANGE', { tickLower, tickUpper });\n }\n\n if (tickLower < GC_MIN_TICK || tickUpper > GC_MAX_TICK) {\n throw new GSwapSDKError('TICKS_OUT_OF_BOUNDS', {\n tickLower,\n tickUpper,\n minTick: GC_MIN_TICK,\n maxTick: GC_MAX_TICK,\n });\n }\n}\n\n/**\n * Asserts that `fee` is one of the fee tiers in `ALL_FEE_TIERS` (`0`, `500`, `3000`, `10000`).\n *\n * @throws GSwapSDKError `INVALID_FEE` (`params.field` `'fee'`, `params.allowed` the tiers).\n */\nexport function validateFee(fee: number): asserts fee is FEE_TIER {\n if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n}\n\n/**\n * Validates a tick spacing: a positive integer.\n *\n * @throws GSwapSDKError `INVALID_TICK_SPACING`.\n */\nexport function validateTickSpacing(tickSpacing: number): void {\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {\n throw new GSwapSDKError('INVALID_TICK_SPACING', { value: tickSpacing });\n }\n}\n\n/**\n * The GalaChain user reference an owner, user or wallet address names, in the one spelling the\n * gateway and the swap backend accept: `eth|<EIP-55 checksummed digits>` for an Ethereum account\n * (given as `eth|<40 hex>` in any casing, `0x<40 hex>` or bare hex), `client|<id>` as written.\n * `eth|0x<hex>` is not an address form. This is `galaChainUserRef` of\n * `@gala-chain/gala-core-sdk`, the one implementation; only the error for a spelling that is no\n * address at all is this package's. Every place this SDK puts a user identity on the wire goes\n * through it, so what is signed, sent and compared on the backend (`owner === position.owner`,\n * strict) is always the chain's own spelling.\n *\n * @param value - The identity the caller gave.\n * @param field - The field name reported in the error's `params.field`.\n * @throws GalaSDKError core's `INVALID_ETH_USER_REF_PREFIX` (passed through as it is: its message\n * says an `eth|` reference takes the 40 hex digits with no `0x` and names the correct spelling,\n * `params.expected`) for `eth|0x...`; GSwapSDKError `INVALID_WALLET_ADDRESS` for anything else, a\n * mixed-case spelling whose casing is not the EIP-55 checksum included (a typo); nothing is\n * signed or sent.\n */\nexport function userRef(value: unknown, field: string): string {\n try {\n return galaChainUserRef(value, field);\n } catch (cause: unknown) {\n if (isGalaError(cause) && cause.code === 'INVALID_ETH_USER_REF_PREFIX') throw cause;\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', { field, value: String(value) });\n }\n}\n\n/**\n * {@link userRef} of an address that must be there.\n *\n * @throws GSwapSDKError `MISSING_WALLET_ADDRESS` (undefined) or `INVALID_WALLET_ADDRESS`; core's\n * `INVALID_ETH_USER_REF_PREFIX` for `eth|0x...` (see {@link userRef}).\n */\nexport function requireUserRef(address: string | undefined, field: string): string {\n if (address === undefined) {\n throw new GSwapSDKError('MISSING_WALLET_ADDRESS', {});\n }\n return userRef(address, field);\n}\n\n/** Words the chain gateway refuses as a trading symbol. */\nconst RESERVED_TRADING_SYMBOLS = new Set(['Token', 'Unit', 'none']);\nconst TRADING_SYMBOL_PATTERN = /^[A-Za-z0-9]+$/u;\nconst MAX_TRADING_SYMBOL_LENGTH = 32;\n\n/**\n * True when `symbol` is acceptable to propose into the trading-symbol registry: ASCII letters and\n * digits only, 1 to 32 characters, and not a reserved word (`Token`, `Unit`, `none`) — the rules\n * the chain gateway enforces on a CreatePool symbol.\n */\nexport function isProposableTradingSymbol(symbol: string): boolean {\n return (\n TRADING_SYMBOL_PATTERN.test(symbol) &&\n symbol.length <= MAX_TRADING_SYMBOL_LENGTH &&\n !RESERVED_TRADING_SYMBOLS.has(symbol)\n );\n}\n\n/**\n * Asserts that a pair is in the contract's canonical order (`token0 < token1` by plain string\n * comparison), which every write DTO requires. A pair a caller took from a stale quote or\n * position can be reversed; signing it would sign something other than what was priced.\n *\n * @throws GSwapSDKError `NON_CANONICAL_PAIR` (`params.token0`, `params.token1`) otherwise.\n */\nexport function assertCanonicalPair(token0: string, token1: string): void {\n if (!(token0 < token1)) {\n throw new GSwapSDKError('NON_CANONICAL_PAIR', { token0, token1 });\n }\n}\n"],"mappings":"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"}
|