@gala-chain/gswap-sdk 1.2.0-rc.8 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -10
- package/dist/browser/classes/dex_fees.js.map +1 -1
- package/dist/browser/classes/gateway.js.map +1 -1
- package/dist/browser/classes/gdex_stream.js.map +1 -1
- package/dist/browser/classes/gswap.js.map +1 -1
- package/dist/browser/classes/gswap_sdk_error.js.map +1 -1
- package/dist/browser/classes/pending_swap_fate.js +2 -0
- package/dist/browser/classes/pending_swap_fate.js.map +1 -0
- package/dist/browser/classes/pending_swaps.js +1 -1
- package/dist/browser/classes/pending_swaps.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/shadow_submit.js +1 -1
- package/dist/browser/classes/shadow_submit.js.map +1 -1
- package/dist/browser/classes/signers.js.map +1 -1
- package/dist/browser/classes/storage_adapters.js +2 -0
- package/dist/browser/classes/storage_adapters.js.map +1 -0
- package/dist/browser/classes/submitted_transaction.js.map +1 -1
- package/dist/browser/classes/symbols.js +1 -1
- package/dist/browser/classes/symbols.js.map +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/utils/chain_dto_signing.js.map +1 -1
- package/dist/browser/utils/class_key.js +2 -0
- package/dist/browser/utils/class_key.js.map +1 -0
- package/dist/browser/utils/classification.js +2 -0
- package/dist/browser/utils/classification.js.map +1 -0
- package/dist/browser/utils/dto_builders.js +1 -1
- package/dist/browser/utils/dto_builders.js.map +1 -1
- package/dist/browser/utils/eip712.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 +2 -0
- package/dist/browser/utils/failure_guards.js.map +1 -0
- package/dist/browser/utils/ordering.js +1 -1
- package/dist/browser/utils/ordering.js.map +1 -1
- package/dist/browser/utils/tick_align.js +2 -0
- package/dist/browser/utils/tick_align.js.map +1 -0
- package/dist/browser/utils/tick_math.js +2 -0
- package/dist/browser/utils/tick_math.js.map +1 -0
- package/dist/browser/utils/tick_range.js +2 -0
- package/dist/browser/utils/tick_range.js.map +1 -0
- package/dist/browser/utils/ticks.js +1 -1
- package/dist/browser/utils/ticks.js.map +1 -1
- package/dist/browser/utils/transport.js +1 -1
- package/dist/browser/utils/transport.js.map +1 -1
- package/dist/browser/utils/validation.js +1 -1
- package/dist/browser/utils/validation.js.map +1 -1
- package/dist/browser/version.js +1 -1
- package/dist/browser/version.js.map +1 -1
- package/dist/index.cjs +641 -336
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +470 -186
- package/dist/index.d.ts +470 -186
- package/dist/index.mjs +636 -337
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1345,6 +1345,7 @@ var GSwapSDKError = class GSwapSDKError extends Error {
|
|
|
1345
1345
|
code;
|
|
1346
1346
|
/** The named placeholders of the error: a flat object of primitives, safe to localize with. */
|
|
1347
1347
|
params;
|
|
1348
|
+
/** The server's `Retry-After` in milliseconds (a `RATE_LIMITED` answer), when it sent one. */
|
|
1348
1349
|
retryAfterMs;
|
|
1349
1350
|
/** The HTTP status of the response that caused this error, when there was one. */
|
|
1350
1351
|
status;
|
|
@@ -1670,7 +1671,7 @@ function parseJson(text) {
|
|
|
1670
1671
|
//#endregion
|
|
1671
1672
|
//#region src/version.ts
|
|
1672
1673
|
/** Package version embedded by the bundler, with a source-test fallback. */
|
|
1673
|
-
const SDK_VERSION = "1.2.0
|
|
1674
|
+
const SDK_VERSION = "1.2.0";
|
|
1674
1675
|
|
|
1675
1676
|
//#endregion
|
|
1676
1677
|
//#region src/utils/transport.ts
|
|
@@ -1731,7 +1732,7 @@ function buildRequestHeaders(wire, parts = {}) {
|
|
|
1731
1732
|
entries.set(name.toLowerCase(), [name, value]);
|
|
1732
1733
|
}
|
|
1733
1734
|
};
|
|
1734
|
-
if ((wire === null || wire === void 0 ? void 0 : wire.userAgent) !== false) put({ "User-Agent": (wire === null || wire === void 0 ? void 0 : wire.userAgent) ?? `GalaChain-SDK/${"1.2.0
|
|
1735
|
+
if ((wire === null || wire === void 0 ? void 0 : wire.userAgent) !== false) put({ "User-Agent": (wire === null || wire === void 0 ? void 0 : wire.userAgent) ?? `GalaChain-SDK/${"1.2.0"}` });
|
|
1735
1736
|
put(parts.defaults);
|
|
1736
1737
|
put(wire === null || wire === void 0 ? void 0 : wire.headers);
|
|
1737
1738
|
if (parts.json === true && !entries.has("content-type")) put({ "Content-Type": "application/json" });
|
|
@@ -2035,7 +2036,54 @@ const ALL_FEE_TIERS = [
|
|
|
2035
2036
|
];
|
|
2036
2037
|
|
|
2037
2038
|
//#endregion
|
|
2038
|
-
//#region src/utils/
|
|
2039
|
+
//#region src/utils/tick_range.ts
|
|
2040
|
+
function integerTickOf(tick) {
|
|
2041
|
+
if (typeof tick === "string") return tick.trim() === "" ? NaN : Number(tick);
|
|
2042
|
+
return tick;
|
|
2043
|
+
}
|
|
2044
|
+
/**
|
|
2045
|
+
* True when a position over `[tickLower, tickUpper)` is IN RANGE at `currentTick`: the lower tick
|
|
2046
|
+
* is INCLUSIVE and the upper tick is EXCLUSIVE. That is the GalaChainDex contract's rule
|
|
2047
|
+
* (`DexV3Pool`: `tickCurrent >= tickLower && tickCurrent < tickUpper` is the case in which a
|
|
2048
|
+
* position holds both tokens and earns fees). A pool whose tick equals `tickUpper` is already out
|
|
2049
|
+
* of range: the position is entirely token1 there, and a swap through the tick has crossed it.
|
|
2050
|
+
*
|
|
2051
|
+
* `currentTick` is the pool's tick (`slot0.tick`, the greatest tick whose price is no greater than
|
|
2052
|
+
* the pool's price), not a rounded display value. A tick may be a number or the decimal string a
|
|
2053
|
+
* backend returns. Anything that is not an integer (`NaN`, `undefined`-like, an empty string, a
|
|
2054
|
+
* fraction) makes the answer `false`: an app that must tell "not loaded yet" from "out of range"
|
|
2055
|
+
* checks for the missing value itself first.
|
|
2056
|
+
*
|
|
2057
|
+
* Do NOT decide range by comparing a price with a tick's price (`tickToPrice`) using `<=` on both
|
|
2058
|
+
* ends, or by mixing a square-root price with a price. A price exactly on a tick's boundary is
|
|
2059
|
+
* then in range at the upper edge (the contract says it is not), and two representations of the
|
|
2060
|
+
* same boundary can round to opposite sides. For a pool price use {@link isSqrtPriceInRange}, which
|
|
2061
|
+
* derives the tick the way the contract does and then applies this rule.
|
|
2062
|
+
*
|
|
2063
|
+
* @example
|
|
2064
|
+
* ```ts
|
|
2065
|
+
* isTickInRange(-60, -60, 60); // true: the lower tick is inclusive
|
|
2066
|
+
* isTickInRange(60, -60, 60); // false: the upper tick is exclusive
|
|
2067
|
+
* ```
|
|
2068
|
+
*/
|
|
2069
|
+
function isTickInRange(currentTick, tickLower, tickUpper) {
|
|
2070
|
+
const current = integerTickOf(currentTick);
|
|
2071
|
+
const lower = integerTickOf(tickLower);
|
|
2072
|
+
const upper = integerTickOf(tickUpper);
|
|
2073
|
+
if (!Number.isInteger(current) || !Number.isInteger(lower) || !Number.isInteger(upper)) return false;
|
|
2074
|
+
return current >= lower && current < upper;
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
//#endregion
|
|
2078
|
+
//#region src/utils/tick_math.ts
|
|
2079
|
+
/**
|
|
2080
|
+
* Tick and price arithmetic that never throws an SDK error: the contract's tick bounds, the
|
|
2081
|
+
* conversions between ticks and prices, and nothing that validates a range. It imports only the
|
|
2082
|
+
* two number libraries it computes with, never the `GSwapSDKError` class or the error catalog
|
|
2083
|
+
* (functions that must throw, `alignTickDown` and `assertTickRange`, are in `ticks.ts`), so an
|
|
2084
|
+
* app shell that prices a tick pays for the libraries and these few functions, not for ~25 kB of
|
|
2085
|
+
* error templates. A value that cannot be computed is `NaN`, never an exception.
|
|
2086
|
+
*/
|
|
2039
2087
|
/** Minimum tick supported by GalaChainDex. */
|
|
2040
2088
|
const GC_MIN_TICK = -887272;
|
|
2041
2089
|
/** Maximum tick supported by GalaChainDex. */
|
|
@@ -2044,6 +2092,7 @@ const DexMath = bignumber_js.default.clone({
|
|
|
2044
2092
|
DECIMAL_PLACES: 60,
|
|
2045
2093
|
ROUNDING_MODE: bignumber_js.default.ROUND_DOWN
|
|
2046
2094
|
});
|
|
2095
|
+
/** `decimal.js` at the 60 significant digits the contract's price math is exact to. */
|
|
2047
2096
|
const DexDecimal = decimal_js.Decimal.clone({ precision: 60 });
|
|
2048
2097
|
/** Convert a tick to the corresponding square-root price. */
|
|
2049
2098
|
function tickToSqrtPrice(tick) {
|
|
@@ -2078,6 +2127,26 @@ function tickToPrice(tick) {
|
|
|
2078
2127
|
return new bignumber_js.default(new DexDecimal(1.0001).pow(tick).toString());
|
|
2079
2128
|
}
|
|
2080
2129
|
/**
|
|
2130
|
+
* {@link isTickInRange} for a pool's square-root price instead of its tick (a position row that
|
|
2131
|
+
* carries `sqrtPrice`, `tickLower` and `tickUpper`). The tick is derived from the price exactly as
|
|
2132
|
+
* the contract does (`sqrtPriceToTick`: the greatest tick whose square-root price is no greater
|
|
2133
|
+
* than the price, exact to 60 digits), then the contract's rule applies: lower tick inclusive,
|
|
2134
|
+
* upper tick exclusive. So a pool sitting exactly on `tickLower`'s price is in range, and exactly
|
|
2135
|
+
* on `tickUpper`'s price is not, and no float rounding can flip either.
|
|
2136
|
+
*
|
|
2137
|
+
* `false` for a price that is not positive and finite (not loaded, zero, `NaN`): it says nothing
|
|
2138
|
+
* about the position, so an app that must show a neutral state checks for the missing price
|
|
2139
|
+
* itself first. `tickLower` and `tickUpper` follow {@link isTickInRange}.
|
|
2140
|
+
*
|
|
2141
|
+
* @example
|
|
2142
|
+
* ```ts
|
|
2143
|
+
* const inRange = isSqrtPriceInRange(position.sqrtPrice, position.tickLower, position.tickUpper);
|
|
2144
|
+
* ```
|
|
2145
|
+
*/
|
|
2146
|
+
function isSqrtPriceInRange(sqrtPrice, tickLower, tickUpper) {
|
|
2147
|
+
return isTickInRange(sqrtPriceToTick(sqrtPrice), tickLower, tickUpper);
|
|
2148
|
+
}
|
|
2149
|
+
/**
|
|
2081
2150
|
* Return the integer tick for a token1/token0 `price`: by default the greatest tick whose price
|
|
2082
2151
|
* is no greater than `price`; `{ rounding: 'nearest' }` the closest tick. `NaN` for a price that
|
|
2083
2152
|
* is not positive and finite.
|
|
@@ -2091,77 +2160,18 @@ function tickFromPrice(price, options = {}) {
|
|
|
2091
2160
|
const tick = (options.rounding === "nearest" ? exact.round() : exact.floor()).toNumber();
|
|
2092
2161
|
return Number.isFinite(tick) ? tick : NaN;
|
|
2093
2162
|
}
|
|
2094
|
-
/** Align a tick down to the nearest multiple of a positive spacing. */
|
|
2095
|
-
function alignTickDown(tick, spacing) {
|
|
2096
|
-
assertSpacing(spacing);
|
|
2097
|
-
return Math.floor(tick / spacing) * spacing;
|
|
2098
|
-
}
|
|
2099
|
-
/** Align a tick up to the nearest multiple of a positive spacing. */
|
|
2100
|
-
function alignTickUp(tick, spacing) {
|
|
2101
|
-
assertSpacing(spacing);
|
|
2102
|
-
return Math.ceil(tick / spacing) * spacing;
|
|
2103
|
-
}
|
|
2104
|
-
/** Validate a position range against the global tick bounds and fee-tier spacing. */
|
|
2105
|
-
function assertTickRange(lower, upper, fee) {
|
|
2106
|
-
const spacing = TICK_SPACING_BY_FEE[fee];
|
|
2107
|
-
if (spacing === void 0) throw new GSwapSDKError("INVALID_FEE", {
|
|
2108
|
-
field: "fee",
|
|
2109
|
-
value: fee,
|
|
2110
|
-
allowed: ALLOWED_FEE_TIERS_TEXT
|
|
2111
|
-
});
|
|
2112
|
-
if (!Number.isInteger(lower) || !Number.isInteger(upper)) throw new GSwapSDKError("TICKS_NOT_INTEGERS", {
|
|
2113
|
-
tickLower: lower,
|
|
2114
|
-
tickUpper: upper
|
|
2115
|
-
});
|
|
2116
|
-
if (lower >= upper) throw new GSwapSDKError("INVALID_TICK_RANGE", {
|
|
2117
|
-
tickLower: lower,
|
|
2118
|
-
tickUpper: upper
|
|
2119
|
-
});
|
|
2120
|
-
if (lower < -887272 || upper > 887272) throw new GSwapSDKError("TICKS_OUT_OF_BOUNDS", {
|
|
2121
|
-
tickLower: lower,
|
|
2122
|
-
tickUpper: upper,
|
|
2123
|
-
minTick: GC_MIN_TICK,
|
|
2124
|
-
maxTick: GC_MAX_TICK
|
|
2125
|
-
});
|
|
2126
|
-
if (lower % spacing !== 0 || upper % spacing !== 0) throw new GSwapSDKError("TICKS_NOT_ALIGNED", {
|
|
2127
|
-
tickLower: lower,
|
|
2128
|
-
tickUpper: upper,
|
|
2129
|
-
spacing
|
|
2130
|
-
});
|
|
2131
|
-
}
|
|
2132
|
-
function assertSpacing(spacing) {
|
|
2133
|
-
if (!Number.isInteger(spacing) || spacing <= 0) throw new GSwapSDKError("INVALID_TICK_SPACING", { value: spacing });
|
|
2134
|
-
}
|
|
2135
|
-
/**
|
|
2136
|
-
* Puts a `slot0` answer into the frame of the request. The backend always answers in the pool's
|
|
2137
|
-
* canonical order and says so with `flippedFromRequest`; when the caller asked for the reverse
|
|
2138
|
-
* order the price is inverted here (at 60 significant digits, so a very large or very small
|
|
2139
|
-
* reciprocal keeps its precision) and the tick is re-derived from the inverted price with the
|
|
2140
|
-
* contract's greatest-tick rule. Negating the tick instead is wrong for a price between ticks
|
|
2141
|
-
* (and `-t - 1` is wrong for a price exactly on a tick: sqrtPrice 1 / tick 0 stays 1 / 0).
|
|
2142
|
-
*
|
|
2143
|
-
* @example
|
|
2144
|
-
* ```ts
|
|
2145
|
-
* const slot0 = await gSwap.pools.getSlot0('A', 'B', 500);
|
|
2146
|
-
* const { sqrtPrice, tick } = frameSlot0(slot0);
|
|
2147
|
-
* ```
|
|
2148
|
-
*/
|
|
2149
|
-
function frameSlot0(slot0) {
|
|
2150
|
-
if (slot0.flippedFromRequest !== true) return {
|
|
2151
|
-
sqrtPrice: slot0.sqrtPrice,
|
|
2152
|
-
tick: slot0.tick
|
|
2153
|
-
};
|
|
2154
|
-
const inverted = new DexDecimal(1).dividedBy(new DexDecimal(slot0.sqrtPrice));
|
|
2155
|
-
if (!inverted.isFinite() || inverted.lessThanOrEqualTo(0)) throw new GSwapSDKError("INVALID_SQRT_PRICE", { sqrtPrice: slot0.sqrtPrice });
|
|
2156
|
-
const sqrtPrice = inverted.toString();
|
|
2157
|
-
return {
|
|
2158
|
-
sqrtPrice,
|
|
2159
|
-
tick: sqrtPriceToTick(sqrtPrice)
|
|
2160
|
-
};
|
|
2161
|
-
}
|
|
2162
2163
|
|
|
2163
2164
|
//#endregion
|
|
2164
2165
|
//#region src/utils/validation.ts
|
|
2166
|
+
/**
|
|
2167
|
+
* Validates a decimal amount: a string or `BigNumber`, never a JavaScript number.
|
|
2168
|
+
*
|
|
2169
|
+
* @param amount - The amount to check.
|
|
2170
|
+
* @param parameterName - The field name reported in the error's `params.field`.
|
|
2171
|
+
* @param allowZero - Accept zero (default `false`).
|
|
2172
|
+
* @throws GSwapSDKError `AMOUNT_IS_JS_NUMBER`, `AMOUNT_NOT_FINITE`, `AMOUNT_NOT_POSITIVE` (zero
|
|
2173
|
+
* when `allowZero` is false) or `AMOUNT_NEGATIVE`.
|
|
2174
|
+
*/
|
|
2165
2175
|
function validateNumericAmount(amount, parameterName, allowZero = false) {
|
|
2166
2176
|
if (typeof amount === "number") throw new GSwapSDKError("AMOUNT_IS_JS_NUMBER", { field: parameterName });
|
|
2167
2177
|
let bnAmount;
|
|
@@ -2183,6 +2193,12 @@ function validateNumericAmount(amount, parameterName, allowZero = false) {
|
|
|
2183
2193
|
value: String(amount)
|
|
2184
2194
|
});
|
|
2185
2195
|
}
|
|
2196
|
+
/**
|
|
2197
|
+
* Validates a spot price and a lower/upper price range: none a JavaScript number, all positive and
|
|
2198
|
+
* finite (a non-finite upper bound counts as an unbounded `1e18`), and `lowerPrice <= upperPrice`.
|
|
2199
|
+
*
|
|
2200
|
+
* @throws GSwapSDKError `PRICE_VALUES_IS_JS_NUMBER`, `INVALID_PRICE_VALUES` or `INVALID_PRICE_RANGE`.
|
|
2201
|
+
*/
|
|
2186
2202
|
function validatePriceValues(spotPrice, lowerPrice, upperPrice) {
|
|
2187
2203
|
if ([
|
|
2188
2204
|
spotPrice,
|
|
@@ -2210,12 +2226,24 @@ function validatePriceValues(spotPrice, lowerPrice, upperPrice) {
|
|
|
2210
2226
|
upperPrice: String(upperPrice)
|
|
2211
2227
|
});
|
|
2212
2228
|
}
|
|
2229
|
+
/**
|
|
2230
|
+
* Validates a token's decimals: a non-negative integer.
|
|
2231
|
+
*
|
|
2232
|
+
* @throws GSwapSDKError `INVALID_TOKEN_DECIMALS` (`params.field` is `parameterName`).
|
|
2233
|
+
*/
|
|
2213
2234
|
function validateTokenDecimals(decimals, parameterName) {
|
|
2214
2235
|
if (decimals < 0 || !Number.isInteger(decimals)) throw new GSwapSDKError("INVALID_TOKEN_DECIMALS", {
|
|
2215
2236
|
field: parameterName,
|
|
2216
2237
|
value: decimals
|
|
2217
2238
|
});
|
|
2218
2239
|
}
|
|
2240
|
+
/**
|
|
2241
|
+
* Validates a position's tick range: two integers with `tickLower < tickUpper`, both within
|
|
2242
|
+
* `GC_MIN_TICK`..`GC_MAX_TICK`. It does not check alignment to a fee tier's spacing (see
|
|
2243
|
+
* `assertTickRange`).
|
|
2244
|
+
*
|
|
2245
|
+
* @throws GSwapSDKError `TICKS_NOT_INTEGERS`, `INVALID_TICK_RANGE` or `TICKS_OUT_OF_BOUNDS`.
|
|
2246
|
+
*/
|
|
2219
2247
|
function validateTickRange(tickLower, tickUpper) {
|
|
2220
2248
|
if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) throw new GSwapSDKError("TICKS_NOT_INTEGERS", {
|
|
2221
2249
|
tickLower,
|
|
@@ -2232,6 +2260,11 @@ function validateTickRange(tickLower, tickUpper) {
|
|
|
2232
2260
|
maxTick: GC_MAX_TICK
|
|
2233
2261
|
});
|
|
2234
2262
|
}
|
|
2263
|
+
/**
|
|
2264
|
+
* Asserts that `fee` is one of the fee tiers in `ALL_FEE_TIERS` (`0`, `500`, `3000`, `10000`).
|
|
2265
|
+
*
|
|
2266
|
+
* @throws GSwapSDKError `INVALID_FEE` (`params.field` `'fee'`, `params.allowed` the tiers).
|
|
2267
|
+
*/
|
|
2235
2268
|
function validateFee(fee) {
|
|
2236
2269
|
if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) throw new GSwapSDKError("INVALID_FEE", {
|
|
2237
2270
|
field: "fee",
|
|
@@ -2239,9 +2272,20 @@ function validateFee(fee) {
|
|
|
2239
2272
|
allowed: ALLOWED_FEE_TIERS_TEXT
|
|
2240
2273
|
});
|
|
2241
2274
|
}
|
|
2275
|
+
/**
|
|
2276
|
+
* Validates a tick spacing: a positive integer.
|
|
2277
|
+
*
|
|
2278
|
+
* @throws GSwapSDKError `INVALID_TICK_SPACING`.
|
|
2279
|
+
*/
|
|
2242
2280
|
function validateTickSpacing(tickSpacing) {
|
|
2243
2281
|
if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) throw new GSwapSDKError("INVALID_TICK_SPACING", { value: tickSpacing });
|
|
2244
2282
|
}
|
|
2283
|
+
/**
|
|
2284
|
+
* Asserts that a wallet address was given and is a non-blank string. It does not check the address
|
|
2285
|
+
* format.
|
|
2286
|
+
*
|
|
2287
|
+
* @throws GSwapSDKError `MISSING_WALLET_ADDRESS` (undefined) or `INVALID_WALLET_ADDRESS` (blank).
|
|
2288
|
+
*/
|
|
2245
2289
|
function validateWalletAddress(address) {
|
|
2246
2290
|
if (address === void 0) throw new GSwapSDKError("MISSING_WALLET_ADDRESS", {});
|
|
2247
2291
|
if (!address || typeof address !== "string" || address.trim().length === 0) throw new GSwapSDKError("INVALID_WALLET_ADDRESS", {
|
|
@@ -2724,9 +2768,13 @@ async function shadowFailures(run) {
|
|
|
2724
2768
|
//#region src/classes/submitted_transaction.ts
|
|
2725
2769
|
/** A submitted v2 transaction whose confirmation mode is explicit in the gateway response. */
|
|
2726
2770
|
var SubmittedTransaction = class {
|
|
2771
|
+
/** The chain method that was submitted (`RequestTrade`, `AddLiquidity`, ...). */
|
|
2727
2772
|
method;
|
|
2773
|
+
/** The write's durable correlation key: persist it, and confirm from it alone later. */
|
|
2728
2774
|
uniqueKey;
|
|
2775
|
+
/** The request transaction id the gateway reported, or `null` when it gave none. */
|
|
2729
2776
|
transactionId;
|
|
2777
|
+
/** The block of the transaction, when the answer carried one; otherwise `null`. */
|
|
2730
2778
|
blockNumber;
|
|
2731
2779
|
/** The gateway's `data.mode`: `'sync'` (executed, `result` is the chain result) or `'queued'`. */
|
|
2732
2780
|
mode;
|
|
@@ -2848,7 +2896,9 @@ var ChainGateway = class {
|
|
|
2848
2896
|
chainCallTimeoutMs;
|
|
2849
2897
|
isTransportFailure;
|
|
2850
2898
|
answerOfRejectionHook;
|
|
2899
|
+
/** The request timeout in milliseconds (`Infinity` when no timer is armed). */
|
|
2851
2900
|
requestTimeoutMs;
|
|
2901
|
+
/** The swap backend base URL every request is sent to, without a trailing slash. */
|
|
2852
2902
|
dexBackendBaseUrl;
|
|
2853
2903
|
/** Wire format shared by the read services built on this gateway. */
|
|
2854
2904
|
wire;
|
|
@@ -2922,7 +2972,7 @@ var ChainGateway = class {
|
|
|
2922
2972
|
*
|
|
2923
2973
|
* Unlike `submit`, EVERY HTTP status resolves: the result is the raw `{ httpStatus, body }`,
|
|
2924
2974
|
* because shadow failures are classified from the status together with the body's `code`
|
|
2925
|
-
* (`SHADOW_UNAVAILABLE`, `
|
|
2975
|
+
* (`SHADOW_UNAVAILABLE`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);
|
|
2926
2976
|
* see `readShadowSubmitOutcome`. Only a failure to get an answer rejects, and it rejects with
|
|
2927
2977
|
* `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` `'timeout'` or `'transport'`): the request may
|
|
2928
2978
|
* have been accepted. Every error it throws has `error.shadow === true`, and a non-SDK object
|
|
@@ -3170,7 +3220,9 @@ function isGdexLiquidityEvent(value) {
|
|
|
3170
3220
|
}
|
|
3171
3221
|
/** A JSON-RPC error answered by the stream. */
|
|
3172
3222
|
var GdexStreamError = class extends Error {
|
|
3223
|
+
/** The JSON-RPC error code. */
|
|
3173
3224
|
code;
|
|
3225
|
+
/** The error's optional `data` member, as the server sent it. */
|
|
3174
3226
|
data;
|
|
3175
3227
|
constructor(code, message, data) {
|
|
3176
3228
|
super(message);
|
|
@@ -3248,6 +3300,7 @@ var GdexStreamService = class {
|
|
|
3248
3300
|
this.connectPromise = void 0;
|
|
3249
3301
|
socket === null || socket === void 0 || socket.close(1e3, "client disconnect");
|
|
3250
3302
|
}
|
|
3303
|
+
/** `true` while the socket is open (false while connecting, reconnecting or after `disconnect()`). */
|
|
3251
3304
|
isConnected() {
|
|
3252
3305
|
var _this$socket;
|
|
3253
3306
|
return ((_this$socket = this.socket) === null || _this$socket === void 0 ? void 0 : _this$socket.readyState) === WEBSOCKET_OPEN;
|
|
@@ -3289,30 +3342,41 @@ var GdexStreamService = class {
|
|
|
3289
3342
|
}
|
|
3290
3343
|
});
|
|
3291
3344
|
}
|
|
3345
|
+
/** `gdex_serverInfo`: the server's own description of itself, as it sends it. */
|
|
3292
3346
|
serverInfo() {
|
|
3293
3347
|
return this.request("gdex_serverInfo");
|
|
3294
3348
|
}
|
|
3349
|
+
/** `gdex_ping`: a round trip that answers `{ pong, serverTime }`. */
|
|
3295
3350
|
ping() {
|
|
3296
3351
|
return this.request("gdex_ping");
|
|
3297
3352
|
}
|
|
3353
|
+
/** `gdex_getPool`: the current state of one pool, selected by its key or hash. */
|
|
3298
3354
|
getPool(selector) {
|
|
3299
3355
|
return this.request("gdex_getPool", selector);
|
|
3300
3356
|
}
|
|
3357
|
+
/** `gdex_getBalance`: an owner's balances, or only the one of `tokenClassKey` when given. */
|
|
3301
3358
|
getBalance(owner, tokenClassKey) {
|
|
3302
3359
|
return this.request("gdex_getBalance", tokenClassKey === void 0 ? { owner } : {
|
|
3303
3360
|
owner,
|
|
3304
3361
|
tokenClassKey
|
|
3305
3362
|
});
|
|
3306
3363
|
}
|
|
3364
|
+
/**
|
|
3365
|
+
* `gdex_getPositions`: an owner's positions, optionally in one pool, a page at a time. Pass the
|
|
3366
|
+
* returned `bookmark` back in as `bookmark` for the next page.
|
|
3367
|
+
*/
|
|
3307
3368
|
getPositions(opts) {
|
|
3308
3369
|
return this.request("gdex_getPositions", opts);
|
|
3309
3370
|
}
|
|
3371
|
+
/** `gdex_getBlockHeight`: the block number the server reports, with its timestamp. */
|
|
3310
3372
|
getBlockHeight() {
|
|
3311
3373
|
return this.request("gdex_getBlockHeight");
|
|
3312
3374
|
}
|
|
3375
|
+
/** `gdex_quote`: a quote over the stream; give exactly one of `amountIn` or `amountOut`. */
|
|
3313
3376
|
quote(params) {
|
|
3314
3377
|
return this.request("gdex_quote", params);
|
|
3315
3378
|
}
|
|
3379
|
+
/** `gdex_getToken`: the server's record of one token class, as it sends it. */
|
|
3316
3380
|
getToken(tokenClassKey) {
|
|
3317
3381
|
return this.request("gdex_getToken", { tokenClassKey });
|
|
3318
3382
|
}
|
|
@@ -3645,39 +3709,13 @@ function finiteNumberOf(value) {
|
|
|
3645
3709
|
}
|
|
3646
3710
|
|
|
3647
3711
|
//#endregion
|
|
3648
|
-
//#region src/utils/
|
|
3649
|
-
/**
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
*
|
|
3655
|
-
* @example
|
|
3656
|
-
* ```ts
|
|
3657
|
-
* const pair = readOrderedSymbols(['GALA', 'GUSDC']);
|
|
3658
|
-
* console.log(pair.token0);
|
|
3659
|
-
* ```
|
|
3712
|
+
//#region src/utils/class_key.ts
|
|
3713
|
+
/**
|
|
3714
|
+
* Token class keys that never throw: the `$`-joined composite key and the non-throwing parsers.
|
|
3715
|
+
* This module imports nothing at run time (the key type is erased), so an app shell that reads a
|
|
3716
|
+
* stored key pays for a few hundred bytes, never for the error class or the catalog. The parser
|
|
3717
|
+
* that THROWS an SDK error on a bad key (`parseTokenClassKey`) lives in `ordering.ts`.
|
|
3660
3718
|
*/
|
|
3661
|
-
function readOrderedSymbols(value) {
|
|
3662
|
-
if (Array.isArray(value) && value.length >= 2) {
|
|
3663
|
-
const token0 = value[0];
|
|
3664
|
-
const token1 = value[1];
|
|
3665
|
-
if (typeof token0 === "string" && typeof token1 === "string") return {
|
|
3666
|
-
token0,
|
|
3667
|
-
token1
|
|
3668
|
-
};
|
|
3669
|
-
}
|
|
3670
|
-
if (typeof value === "object" && value !== null) {
|
|
3671
|
-
const record = value;
|
|
3672
|
-
const token0 = record["token0"];
|
|
3673
|
-
const token1 = record["token1"];
|
|
3674
|
-
if (typeof token0 === "string" && typeof token1 === "string") return {
|
|
3675
|
-
token0,
|
|
3676
|
-
token1
|
|
3677
|
-
};
|
|
3678
|
-
}
|
|
3679
|
-
throw new GSwapSDKError("UNORDERABLE_SYMBOLS", { received: Array.isArray(value) ? "array" : value === null ? "null" : typeof value });
|
|
3680
|
-
}
|
|
3681
3719
|
/** Return the `$`-joined composite key used by GalaChain object identities. */
|
|
3682
3720
|
function compositeKeyOf(token) {
|
|
3683
3721
|
return [
|
|
@@ -3688,33 +3726,14 @@ function compositeKeyOf(token) {
|
|
|
3688
3726
|
].join("$");
|
|
3689
3727
|
}
|
|
3690
3728
|
/**
|
|
3691
|
-
*
|
|
3729
|
+
* Splits `collection<d>category<d>type<d>additionalKey` from the right, or `undefined` when there
|
|
3730
|
+
* are fewer than four segments or any of the four is empty. The one place the split is written;
|
|
3731
|
+
* the strict `parseTokenClassKey` calls it too.
|
|
3692
3732
|
*
|
|
3693
3733
|
* The LAST three segments are always `category`, `type` and `additionalKey`; everything before
|
|
3694
3734
|
* them is the `collection`. Parsing from the right is required because real collections contain
|
|
3695
3735
|
* the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`
|
|
3696
|
-
* shifts every field.
|
|
3697
|
-
* no symbol, which must come from the token class or trading-symbol registry.
|
|
3698
|
-
*
|
|
3699
|
-
* @example
|
|
3700
|
-
* ```ts
|
|
3701
|
-
* parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'
|
|
3702
|
-
* ```
|
|
3703
|
-
*/
|
|
3704
|
-
function parseTokenClassKey(tokenClassKey) {
|
|
3705
|
-
if (typeof tokenClassKey === "object") return {
|
|
3706
|
-
collection: tokenClassKey.collection,
|
|
3707
|
-
category: tokenClassKey.category,
|
|
3708
|
-
type: tokenClassKey.type,
|
|
3709
|
-
additionalKey: tokenClassKey.additionalKey
|
|
3710
|
-
};
|
|
3711
|
-
const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes("|") ? "|" : "$");
|
|
3712
|
-
if (parsed === void 0) throw new GSwapSDKError("INVALID_TOKEN_CLASS_KEY", { tokenClassKey });
|
|
3713
|
-
return parsed;
|
|
3714
|
-
}
|
|
3715
|
-
/**
|
|
3716
|
-
* Splits `collection<d>category<d>type<d>additionalKey` from the right, or `undefined` when there
|
|
3717
|
-
* are fewer than four segments or any of the four is empty. The one place the split is written.
|
|
3736
|
+
* shifts every field.
|
|
3718
3737
|
*/
|
|
3719
3738
|
function splitClassKey(key, delimiter) {
|
|
3720
3739
|
const segments = key.split(delimiter);
|
|
@@ -3730,7 +3749,7 @@ function splitClassKey(key, delimiter) {
|
|
|
3730
3749
|
};
|
|
3731
3750
|
}
|
|
3732
3751
|
/**
|
|
3733
|
-
* The non-throwing
|
|
3752
|
+
* The non-throwing `parseTokenClassKey`: the class key, or `undefined` when `value` is not
|
|
3734
3753
|
* one. A string is split exactly as `parseTokenClassKey` splits it (`|` form when it contains a
|
|
3735
3754
|
* `|`, else `$`, from the right, all four parts non-empty). Unlike `parseTokenClassKey`, an
|
|
3736
3755
|
* object is VALIDATED, not just copied: all four fields must be non-empty strings. Anything else
|
|
@@ -3783,6 +3802,66 @@ function tryParseCompositeKey(value) {
|
|
|
3783
3802
|
return typeof value === "string" ? splitClassKey(value, "$") : void 0;
|
|
3784
3803
|
}
|
|
3785
3804
|
|
|
3805
|
+
//#endregion
|
|
3806
|
+
//#region src/utils/ordering.ts
|
|
3807
|
+
/** Return two trading symbols in the contract's plain-string order. */
|
|
3808
|
+
function orderSymbols(a, b) {
|
|
3809
|
+
return a < b ? [a, b] : [b, a];
|
|
3810
|
+
}
|
|
3811
|
+
/** Read an ordered symbol pair from a tuple or object returned by a boundary helper.
|
|
3812
|
+
*
|
|
3813
|
+
* @example
|
|
3814
|
+
* ```ts
|
|
3815
|
+
* const pair = readOrderedSymbols(['GALA', 'GUSDC']);
|
|
3816
|
+
* console.log(pair.token0);
|
|
3817
|
+
* ```
|
|
3818
|
+
*/
|
|
3819
|
+
function readOrderedSymbols(value) {
|
|
3820
|
+
if (Array.isArray(value) && value.length >= 2) {
|
|
3821
|
+
const token0 = value[0];
|
|
3822
|
+
const token1 = value[1];
|
|
3823
|
+
if (typeof token0 === "string" && typeof token1 === "string") return {
|
|
3824
|
+
token0,
|
|
3825
|
+
token1
|
|
3826
|
+
};
|
|
3827
|
+
}
|
|
3828
|
+
if (typeof value === "object" && value !== null) {
|
|
3829
|
+
const record = value;
|
|
3830
|
+
const token0 = record["token0"];
|
|
3831
|
+
const token1 = record["token1"];
|
|
3832
|
+
if (typeof token0 === "string" && typeof token1 === "string") return {
|
|
3833
|
+
token0,
|
|
3834
|
+
token1
|
|
3835
|
+
};
|
|
3836
|
+
}
|
|
3837
|
+
throw new GSwapSDKError("UNORDERABLE_SYMBOLS", { received: Array.isArray(value) ? "array" : value === null ? "null" : typeof value });
|
|
3838
|
+
}
|
|
3839
|
+
/**
|
|
3840
|
+
* Parse a pipe- or dollar-separated token class key.
|
|
3841
|
+
*
|
|
3842
|
+
* The LAST three segments are always `category`, `type` and `additionalKey`; everything before
|
|
3843
|
+
* them is the `collection`. Parsing from the right is required because real collections contain
|
|
3844
|
+
* the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`
|
|
3845
|
+
* shifts every field. Nothing here says anything about the token's symbol: a class key carries
|
|
3846
|
+
* no symbol, which must come from the token class or trading-symbol registry.
|
|
3847
|
+
*
|
|
3848
|
+
* @example
|
|
3849
|
+
* ```ts
|
|
3850
|
+
* parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'
|
|
3851
|
+
* ```
|
|
3852
|
+
*/
|
|
3853
|
+
function parseTokenClassKey(tokenClassKey) {
|
|
3854
|
+
if (typeof tokenClassKey === "object") return {
|
|
3855
|
+
collection: tokenClassKey.collection,
|
|
3856
|
+
category: tokenClassKey.category,
|
|
3857
|
+
type: tokenClassKey.type,
|
|
3858
|
+
additionalKey: tokenClassKey.additionalKey
|
|
3859
|
+
};
|
|
3860
|
+
const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes("|") ? "|" : "$");
|
|
3861
|
+
if (parsed === void 0) throw new GSwapSDKError("INVALID_TOKEN_CLASS_KEY", { tokenClassKey });
|
|
3862
|
+
return parsed;
|
|
3863
|
+
}
|
|
3864
|
+
|
|
3786
3865
|
//#endregion
|
|
3787
3866
|
//#region src/classes/symbols.ts
|
|
3788
3867
|
const SYMBOL_CACHE_TTL_MS = 6e4;
|
|
@@ -4201,37 +4280,151 @@ function parsePoolListInfo(entry) {
|
|
|
4201
4280
|
}
|
|
4202
4281
|
|
|
4203
4282
|
//#endregion
|
|
4204
|
-
//#region src/utils/
|
|
4283
|
+
//#region src/utils/tick_align.ts
|
|
4205
4284
|
/**
|
|
4206
|
-
*
|
|
4207
|
-
* (
|
|
4208
|
-
*
|
|
4209
|
-
* `
|
|
4210
|
-
* trade builder, which nothing reads back by prefix.
|
|
4285
|
+
* Aligning a tick to a pool's tick spacing without throwing. This module imports nothing, so an
|
|
4286
|
+
* app shell (a price input that snaps to a tick) pays for a few dozen bytes, not for the error
|
|
4287
|
+
* class and catalog that `alignTickDown` and `alignTickUp` (in `ticks.ts`) carry because they
|
|
4288
|
+
* throw `INVALID_TICK_SPACING` for a spacing that is not a positive integer.
|
|
4211
4289
|
*/
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4290
|
+
/** True for a tick spacing the contract can use: a positive integer. The one definition. */
|
|
4291
|
+
function hasValidSpacing(spacing) {
|
|
4292
|
+
return Number.isInteger(spacing) && spacing > 0;
|
|
4293
|
+
}
|
|
4216
4294
|
/**
|
|
4217
|
-
*
|
|
4218
|
-
*
|
|
4295
|
+
* {@link alignTickDown} that answers `NaN` instead of throwing: the greatest multiple of `spacing`
|
|
4296
|
+
* that is no greater than `tick`, or `NaN` when `spacing` is not a positive integer (a pool whose
|
|
4297
|
+
* spacing has not loaded yet) or `tick` is not a number. For an app shell and for a drag handler,
|
|
4298
|
+
* which must not throw while the spacing is missing. `alignTickDown` (the SDK's own call sites use
|
|
4299
|
+
* it) gives the same value and throws for the bad spacing.
|
|
4219
4300
|
*
|
|
4220
|
-
* @
|
|
4221
|
-
*
|
|
4301
|
+
* @example
|
|
4302
|
+
* ```ts
|
|
4303
|
+
* alignTickDownOrNaN(-61, 60); // -120: it floors, it does not truncate toward zero
|
|
4304
|
+
* alignTickDownOrNaN(100, 0); // NaN
|
|
4305
|
+
* ```
|
|
4222
4306
|
*/
|
|
4223
|
-
function
|
|
4224
|
-
|
|
4225
|
-
if (!UNIQUE_KEY_PREFIX_PATTERN.test(prefix) || prefix.length > MAX_UNIQUE_KEY_PREFIX_LENGTH) throw new GSwapSDKError("INVALID_UNIQUE_KEY_PREFIX", {
|
|
4226
|
-
uniqueKeyPrefix: prefix,
|
|
4227
|
-
maxLength: MAX_UNIQUE_KEY_PREFIX_LENGTH
|
|
4228
|
-
});
|
|
4229
|
-
return prefix;
|
|
4307
|
+
function alignTickDownOrNaN(tick, spacing) {
|
|
4308
|
+
return hasValidSpacing(spacing) ? Math.floor(tick / spacing) * spacing : NaN;
|
|
4230
4309
|
}
|
|
4231
4310
|
/**
|
|
4232
|
-
*
|
|
4233
|
-
*
|
|
4234
|
-
*
|
|
4311
|
+
* {@link alignTickUp} that answers `NaN` instead of throwing: the least multiple of `spacing` that
|
|
4312
|
+
* is no less than `tick`, or `NaN` for a spacing that is not a positive integer. See
|
|
4313
|
+
* {@link alignTickDownOrNaN}.
|
|
4314
|
+
*/
|
|
4315
|
+
function alignTickUpOrNaN(tick, spacing) {
|
|
4316
|
+
return hasValidSpacing(spacing) ? Math.ceil(tick / spacing) * spacing : NaN;
|
|
4317
|
+
}
|
|
4318
|
+
|
|
4319
|
+
//#endregion
|
|
4320
|
+
//#region src/utils/ticks.ts
|
|
4321
|
+
/**
|
|
4322
|
+
* The tick functions that THROW an SDK error on a bad input (`alignTickDown`, `alignTickUp`,
|
|
4323
|
+
* `assertTickRange`, `frameSlot0`). The arithmetic that never throws (`tickToPrice`,
|
|
4324
|
+
* `tickFromPrice`, `tickToSqrtPrice`, `sqrtPriceToTick`, the bounds) is in `tick_math.ts`, which
|
|
4325
|
+
* does not import the error class or the catalog; import it from the package entry as usual.
|
|
4326
|
+
*/
|
|
4327
|
+
/** Align a tick down to the nearest multiple of a positive spacing. */
|
|
4328
|
+
function alignTickDown(tick, spacing) {
|
|
4329
|
+
assertSpacing(spacing);
|
|
4330
|
+
return alignTickDownOrNaN(tick, spacing);
|
|
4331
|
+
}
|
|
4332
|
+
/** Align a tick up to the nearest multiple of a positive spacing. */
|
|
4333
|
+
function alignTickUp(tick, spacing) {
|
|
4334
|
+
assertSpacing(spacing);
|
|
4335
|
+
return alignTickUpOrNaN(tick, spacing);
|
|
4336
|
+
}
|
|
4337
|
+
/** Validate a position range against the global tick bounds and fee-tier spacing. */
|
|
4338
|
+
function assertTickRange(lower, upper, fee) {
|
|
4339
|
+
const spacing = TICK_SPACING_BY_FEE[fee];
|
|
4340
|
+
if (spacing === void 0) throw new GSwapSDKError("INVALID_FEE", {
|
|
4341
|
+
field: "fee",
|
|
4342
|
+
value: fee,
|
|
4343
|
+
allowed: ALLOWED_FEE_TIERS_TEXT
|
|
4344
|
+
});
|
|
4345
|
+
if (!Number.isInteger(lower) || !Number.isInteger(upper)) throw new GSwapSDKError("TICKS_NOT_INTEGERS", {
|
|
4346
|
+
tickLower: lower,
|
|
4347
|
+
tickUpper: upper
|
|
4348
|
+
});
|
|
4349
|
+
if (lower >= upper) throw new GSwapSDKError("INVALID_TICK_RANGE", {
|
|
4350
|
+
tickLower: lower,
|
|
4351
|
+
tickUpper: upper
|
|
4352
|
+
});
|
|
4353
|
+
if (lower < -887272 || upper > 887272) throw new GSwapSDKError("TICKS_OUT_OF_BOUNDS", {
|
|
4354
|
+
tickLower: lower,
|
|
4355
|
+
tickUpper: upper,
|
|
4356
|
+
minTick: GC_MIN_TICK,
|
|
4357
|
+
maxTick: GC_MAX_TICK
|
|
4358
|
+
});
|
|
4359
|
+
if (lower % spacing !== 0 || upper % spacing !== 0) throw new GSwapSDKError("TICKS_NOT_ALIGNED", {
|
|
4360
|
+
tickLower: lower,
|
|
4361
|
+
tickUpper: upper,
|
|
4362
|
+
spacing
|
|
4363
|
+
});
|
|
4364
|
+
}
|
|
4365
|
+
function assertSpacing(spacing) {
|
|
4366
|
+
if (!hasValidSpacing(spacing)) throw new GSwapSDKError("INVALID_TICK_SPACING", { value: spacing });
|
|
4367
|
+
}
|
|
4368
|
+
/**
|
|
4369
|
+
* Puts a `slot0` answer into the frame of the request. The backend always answers in the pool's
|
|
4370
|
+
* canonical order and says so with `flippedFromRequest`; when the caller asked for the reverse
|
|
4371
|
+
* order the price is inverted here (at 60 significant digits, so a very large or very small
|
|
4372
|
+
* reciprocal keeps its precision) and the tick is re-derived from the inverted price with the
|
|
4373
|
+
* contract's greatest-tick rule. Negating the tick instead is wrong for a price between ticks
|
|
4374
|
+
* (and `-t - 1` is wrong for a price exactly on a tick: sqrtPrice 1 / tick 0 stays 1 / 0).
|
|
4375
|
+
*
|
|
4376
|
+
* @example
|
|
4377
|
+
* ```ts
|
|
4378
|
+
* const slot0 = await gSwap.pools.getSlot0('A', 'B', 500);
|
|
4379
|
+
* const { sqrtPrice, tick } = frameSlot0(slot0);
|
|
4380
|
+
* ```
|
|
4381
|
+
*/
|
|
4382
|
+
function frameSlot0(slot0) {
|
|
4383
|
+
if (slot0.flippedFromRequest !== true) return {
|
|
4384
|
+
sqrtPrice: slot0.sqrtPrice,
|
|
4385
|
+
tick: slot0.tick
|
|
4386
|
+
};
|
|
4387
|
+
const inverted = new DexDecimal(1).dividedBy(new DexDecimal(slot0.sqrtPrice));
|
|
4388
|
+
if (!inverted.isFinite() || inverted.lessThanOrEqualTo(0)) throw new GSwapSDKError("INVALID_SQRT_PRICE", { sqrtPrice: slot0.sqrtPrice });
|
|
4389
|
+
const sqrtPrice = inverted.toString();
|
|
4390
|
+
return {
|
|
4391
|
+
sqrtPrice,
|
|
4392
|
+
tick: sqrtPriceToTick(sqrtPrice)
|
|
4393
|
+
};
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
//#endregion
|
|
4397
|
+
//#region src/utils/unique_key.ts
|
|
4398
|
+
/**
|
|
4399
|
+
* The `uniqueKey` prefix frontend_v2 and wallet_extension have always sent
|
|
4400
|
+
* (`galaswap-operation-<uuid>`). defi-backend does not depend on it: the chain-write verifier
|
|
4401
|
+
* only requires a non-empty key of at most 256 characters, and apply-results accepts
|
|
4402
|
+
* `[A-Za-z0-9._:-]{1,128}`; the only code that mints a prefixed key itself is the server-side v1
|
|
4403
|
+
* trade builder, which nothing reads back by prefix.
|
|
4404
|
+
*/
|
|
4405
|
+
const DEFAULT_UNIQUE_KEY_PREFIX = "galaswap-operation-";
|
|
4406
|
+
/** A canonical UUID is 36 characters; the apply-results key limit is 128. */
|
|
4407
|
+
const MAX_UNIQUE_KEY_PREFIX_LENGTH = 92;
|
|
4408
|
+
const UNIQUE_KEY_PREFIX_PATTERN = /^[A-Za-z0-9._:-]*$/u;
|
|
4409
|
+
/**
|
|
4410
|
+
* Validates a caller-supplied `uniqueKey` prefix. The whole key (`<prefix><uuid>`) must stay a
|
|
4411
|
+
* valid apply-results key, otherwise `confirm()` could never read the outcome of the write.
|
|
4412
|
+
*
|
|
4413
|
+
* @throws GSwapSDKError `INVALID_UNIQUE_KEY_PREFIX` when the prefix has characters outside
|
|
4414
|
+
* `A-Za-z0-9._:-` or is longer than 92 characters.
|
|
4415
|
+
*/
|
|
4416
|
+
function resolveUniqueKeyPrefix(prefix) {
|
|
4417
|
+
if (prefix === void 0) return DEFAULT_UNIQUE_KEY_PREFIX;
|
|
4418
|
+
if (!UNIQUE_KEY_PREFIX_PATTERN.test(prefix) || prefix.length > MAX_UNIQUE_KEY_PREFIX_LENGTH) throw new GSwapSDKError("INVALID_UNIQUE_KEY_PREFIX", {
|
|
4419
|
+
uniqueKeyPrefix: prefix,
|
|
4420
|
+
maxLength: MAX_UNIQUE_KEY_PREFIX_LENGTH
|
|
4421
|
+
});
|
|
4422
|
+
return prefix;
|
|
4423
|
+
}
|
|
4424
|
+
/**
|
|
4425
|
+
* Validates a caller-supplied write `uniqueKey`: 1 to 128 characters of `A-Za-z0-9._:-`, the
|
|
4426
|
+
* shape the apply-results route accepts, so the write's outcome can always be read back with
|
|
4427
|
+
* `confirm()`. A key is one attempt's identity: reuse it only to retry that same attempt.
|
|
4235
4428
|
*
|
|
4236
4429
|
* @throws GSwapSDKError `INVALID_UNIQUE_KEY` otherwise.
|
|
4237
4430
|
*/
|
|
@@ -4249,8 +4442,9 @@ const decimalString = (amount) => new bignumber_js.default(amount).toFixed();
|
|
|
4249
4442
|
/**
|
|
4250
4443
|
* Builds the RequestTrade DTO: `exactIn` sells that much of the input token (`sell0Qty` or
|
|
4251
4444
|
* `sell1Qty`), `exactOut` buys that much of the output token (`buy1Qty` or `buy0Qty`), plus the
|
|
4252
|
-
* side's slippage bound and an optional `priceLimit`. Key order
|
|
4253
|
-
*
|
|
4445
|
+
* side's slippage bound and an optional `priceLimit`. Key order is
|
|
4446
|
+
* `token0, token1, fee, uniqueKey`, then the one quantity, then the slippage bound, then
|
|
4447
|
+
* `priceLimit`.
|
|
4254
4448
|
*
|
|
4255
4449
|
* @example
|
|
4256
4450
|
* ```ts
|
|
@@ -5438,21 +5632,21 @@ function toDecimalString(amount) {
|
|
|
5438
5632
|
*
|
|
5439
5633
|
* - `SHADOW_UNAVAILABLE` (503): marking failed or infra not configured; retryable. Never fall back
|
|
5440
5634
|
* silently to a public swap.
|
|
5441
|
-
* - `SHADOW_DISABLED` (400): the feature is off for this environment.
|
|
5442
5635
|
* - `SHADOW_UNSUPPORTED_TYPE` (400): shadow requested on a non-swap method.
|
|
5443
5636
|
* - `SHADOW_RELAY_REJECTED`: terminal business rejection (slippage, balance, ...), not retryable;
|
|
5444
5637
|
* `message` is the gateway's verbatim string.
|
|
5445
5638
|
*/
|
|
5446
5639
|
const SHADOW_SUBMIT_CODES = [
|
|
5447
5640
|
"SHADOW_UNAVAILABLE",
|
|
5448
|
-
"SHADOW_DISABLED",
|
|
5449
5641
|
"SHADOW_UNSUPPORTED_TYPE",
|
|
5450
5642
|
"SHADOW_RELAY_REJECTED"
|
|
5451
5643
|
];
|
|
5452
5644
|
/**
|
|
5453
5645
|
* Every `kind` of a failed {@link ShadowSubmitOutcome}, for an app that maps each to its own text
|
|
5454
|
-
* (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled
|
|
5455
|
-
* the
|
|
5646
|
+
* (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled` (the shadow route
|
|
5647
|
+
* answered 400: the request is not a dark-swappable one, e.g. `SHADOW_UNSUPPORTED_TYPE`; Shadow
|
|
5648
|
+
* Swaps themselves are enabled in every environment), `rejected` (carries the gateway's `message`)
|
|
5649
|
+
* and `unknown`.
|
|
5456
5650
|
*/
|
|
5457
5651
|
const SHADOW_FAILURE_KINDS = [
|
|
5458
5652
|
"unavailable",
|
|
@@ -5469,12 +5663,12 @@ function classifyShadowSubmitStatus(status) {
|
|
|
5469
5663
|
/**
|
|
5470
5664
|
* Prefers the body `code` (stable across status remaps) and falls back to the HTTP status.
|
|
5471
5665
|
* `SHADOW_UNAVAILABLE` is the only retryable case; `SHADOW_RELAY_REJECTED` is a terminal gateway
|
|
5472
|
-
* rejection;
|
|
5666
|
+
* rejection; `SHADOW_UNSUPPORTED_TYPE` and any other 400 map to "disabled".
|
|
5473
5667
|
*/
|
|
5474
5668
|
function classifyShadowSubmitError(status, code) {
|
|
5475
5669
|
if (code === "SHADOW_UNAVAILABLE") return "unavailable";
|
|
5476
5670
|
if (code === "SHADOW_RELAY_REJECTED") return "rejected";
|
|
5477
|
-
if (code === "
|
|
5671
|
+
if (code === "SHADOW_UNSUPPORTED_TYPE") return "disabled";
|
|
5478
5672
|
return classifyShadowSubmitStatus(status);
|
|
5479
5673
|
}
|
|
5480
5674
|
function readShadowSubmitOutcome(method, signedBody, result) {
|
|
@@ -5716,27 +5910,43 @@ var Swaps = class {
|
|
|
5716
5910
|
|
|
5717
5911
|
//#endregion
|
|
5718
5912
|
//#region src/classes/gswap.ts
|
|
5719
|
-
/**
|
|
5913
|
+
/**
|
|
5914
|
+
* Main entry point for the current GalaChainDex SDK: one client bundling the services that read
|
|
5915
|
+
* and write through the swap backend (`quoting`, `swaps`, `pools`, `positions`, `assets`,
|
|
5916
|
+
* `symbols`, `fees`, `stream`). See {@link GSwapOptions} for configuration.
|
|
5917
|
+
*/
|
|
5720
5918
|
var GSwap = class {
|
|
5919
|
+
/** The swap backend base URL every request goes to, without a trailing slash. */
|
|
5721
5920
|
dexBackendBaseUrl;
|
|
5921
|
+
/** The request timeout in milliseconds (default 30 000; `Infinity` arms no timer). */
|
|
5722
5922
|
chainCallTimeoutMs;
|
|
5923
|
+
/** The signer given at construction, if any. */
|
|
5723
5924
|
signer;
|
|
5925
|
+
/** The account given at construction, if any. */
|
|
5724
5926
|
walletAddress;
|
|
5927
|
+
/** The chain-gateway client every other service reads and writes through. */
|
|
5725
5928
|
gateway;
|
|
5929
|
+
/** The trading-symbol registry. */
|
|
5726
5930
|
symbols;
|
|
5931
|
+
/** Read-only exact-input and exact-output quotes. */
|
|
5727
5932
|
quoting;
|
|
5933
|
+
/** Pool, slot0 and composite-pool reads. */
|
|
5728
5934
|
pools;
|
|
5935
|
+
/** Position reads, liquidity estimates and liquidity / pool-creation writes. */
|
|
5729
5936
|
positions;
|
|
5937
|
+
/** Queued swaps (`RequestTrade`), dark swaps and swap confirmation. */
|
|
5730
5938
|
swaps;
|
|
5939
|
+
/** User token balances. */
|
|
5731
5940
|
assets;
|
|
5732
5941
|
/** Network-fee quotes (DryRun) signed with this client's signer. */
|
|
5733
5942
|
fees;
|
|
5943
|
+
/** The realtime stream endpoint {@link GSwap.stream} connects to. */
|
|
5734
5944
|
dexBackendWsUrl;
|
|
5735
5945
|
webSocketImpl;
|
|
5736
5946
|
streamApiKey;
|
|
5737
5947
|
streamClient;
|
|
5738
5948
|
/**
|
|
5739
|
-
* Create an SDK client for prod or stage.
|
|
5949
|
+
* Create an SDK client for prod (the default) or stage, or for a `dexBackendBaseUrl` of your own.
|
|
5740
5950
|
*
|
|
5741
5951
|
* @example
|
|
5742
5952
|
* ```typescript
|
|
@@ -5800,10 +6010,10 @@ function trimTrailingSlash(value) {
|
|
|
5800
6010
|
}
|
|
5801
6011
|
|
|
5802
6012
|
//#endregion
|
|
5803
|
-
//#region src/utils/
|
|
6013
|
+
//#region src/utils/classification.ts
|
|
5804
6014
|
/**
|
|
5805
6015
|
* The SDK's default Retry answer for each outcome. A decision that departs from it (a refusal the
|
|
5806
|
-
* gateway will repeat, `SHADOW_NOT_QUEUED`) is written out in the table
|
|
6016
|
+
* gateway will repeat, `SHADOW_NOT_QUEUED`) is written out in the table of `classifyFailure`.
|
|
5807
6017
|
*/
|
|
5808
6018
|
const DEFAULT_RETRYABLE = {
|
|
5809
6019
|
rejected: true,
|
|
@@ -5821,10 +6031,10 @@ const DEFAULT_RETRYABLE = {
|
|
|
5821
6031
|
* object, safe to mutate or freeze.
|
|
5822
6032
|
*
|
|
5823
6033
|
* `options.retryable: false` WITHHOLDS Retry from an outcome that would otherwise allow it: the
|
|
5824
|
-
* SDK's own `not_queued` for a refusal the gateway will repeat is
|
|
5825
|
-
* { retryable: false })` (also exported, frozen, as
|
|
5826
|
-
* Retry away from an outcome but never grant it to one
|
|
5827
|
-
* accepted.
|
|
6034
|
+
* SDK's own `not_queued` for a refusal the gateway will repeat is
|
|
6035
|
+
* `classification('not_queued', { retryable: false })` (also exported, frozen, as
|
|
6036
|
+
* {@link NOT_QUEUED_FINAL}). An app may take Retry away from an outcome but never grant it to one
|
|
6037
|
+
* that cannot have it, so only `false` is accepted.
|
|
5828
6038
|
*
|
|
5829
6039
|
* @example
|
|
5830
6040
|
* ```ts
|
|
@@ -5855,6 +6065,15 @@ const NOT_QUEUED_FINAL = Object.freeze(classification("not_queued", { retryable:
|
|
|
5855
6065
|
function notSentClassification() {
|
|
5856
6066
|
return classification("not_sent");
|
|
5857
6067
|
}
|
|
6068
|
+
|
|
6069
|
+
//#endregion
|
|
6070
|
+
//#region src/utils/failure_classification.ts
|
|
6071
|
+
/**
|
|
6072
|
+
* `classifyFailure` and `mayHaveBeenQueued`: the one module that holds the decision for every
|
|
6073
|
+
* catalog code (~135 names, a floor no minifier can remove). It needs the code table and nothing
|
|
6074
|
+
* else: the classification values live in `classification.ts`, the yes/no guards in
|
|
6075
|
+
* `failure_guards.ts`, and the error class and catalog are only named as types.
|
|
6076
|
+
*/
|
|
5858
6077
|
const REJECTED = classification("rejected");
|
|
5859
6078
|
const UNKNOWN = classification("unknown");
|
|
5860
6079
|
const NOT_QUEUED = classification("not_queued");
|
|
@@ -5954,90 +6173,6 @@ function classifyChainDispatchFailed(view) {
|
|
|
5954
6173
|
return status === 422 ? REJECTED : NOT_QUEUED;
|
|
5955
6174
|
}
|
|
5956
6175
|
/**
|
|
5957
|
-
* True when the gateway answered that the write's `uniqueKey` was ALREADY CONSUMED: a
|
|
5958
|
-
* `CHAIN_DISPATCH_FAILED` with HTTP status 409. The first attempt under that key may be applied
|
|
5959
|
-
* (`classifyFailure` says `unknown`), so the app confirms the key it holds instead of submitting
|
|
5960
|
-
* again or showing the server's text. It replaces `error.code === 'CHAIN_DISPATCH_FAILED' &&
|
|
5961
|
-
* error.status === 409` and the regex on "already saved". Accepts an SDK error or a plain-object
|
|
5962
|
-
* view ({@link FailureView}: `code` and `status`); every other value is `false`.
|
|
5963
|
-
*
|
|
5964
|
-
* @example
|
|
5965
|
-
* ```ts
|
|
5966
|
-
* if (isUniqueKeyConsumed(error)) return confirmAndShowResult(error.uniqueKey);
|
|
5967
|
-
* ```
|
|
5968
|
-
*/
|
|
5969
|
-
function isUniqueKeyConsumed(error) {
|
|
5970
|
-
const view = toFailureView(error);
|
|
5971
|
-
return (view === null || view === void 0 ? void 0 : view.code) === "CHAIN_DISPATCH_FAILED" && view.status === 409;
|
|
5972
|
-
}
|
|
5973
|
-
const UNPROVEN_ACKNOWLEDGEMENT_CODES = [
|
|
5974
|
-
"GATEWAY_DATA_MISSING",
|
|
5975
|
-
"GATEWAY_MODE_INVALID",
|
|
5976
|
-
"GATEWAY_SYNC_REQUEST_TRADE",
|
|
5977
|
-
"MISSING_UNIQUE_KEY",
|
|
5978
|
-
"UNIQUE_KEY_MISMATCH"
|
|
5979
|
-
];
|
|
5980
|
-
/**
|
|
5981
|
-
* True when a write got a 2xx answer that does NOT prove it was queued under the signed key: no
|
|
5982
|
-
* `data`, an unreadable `mode`, a synchronous RequestTrade, or a missing or foreign `uniqueKey`.
|
|
5983
|
-
* The outcome is `unknown` (it may have been queued: confirm `error.uniqueKey`), and the copy an
|
|
5984
|
-
* app shows is one line for all five ("the backend did not confirm it queued the request"), so
|
|
5985
|
-
* the app asks this instead of keeping its own list of the codes. A gateway that says
|
|
5986
|
-
* `error: true` (`GATEWAY_REPORTED_ERROR`) is a refusal with its own message, not in this set.
|
|
5987
|
-
*
|
|
5988
|
-
* @example
|
|
5989
|
-
* ```ts
|
|
5990
|
-
* if (isUnprovenAcknowledgement(error)) keepPendingAndConfirm(error.uniqueKey);
|
|
5991
|
-
* ```
|
|
5992
|
-
*/
|
|
5993
|
-
function isUnprovenAcknowledgement(error) {
|
|
5994
|
-
return hasCodeIn(error, UNPROVEN_ACKNOWLEDGEMENT_CODES);
|
|
5995
|
-
}
|
|
5996
|
-
/** True when `code` is one of `codes` (a list of catalog codes), by exact spelling. */
|
|
5997
|
-
function isCodeIn(code, codes) {
|
|
5998
|
-
return codes.some((known) => known === code);
|
|
5999
|
-
}
|
|
6000
|
-
/**
|
|
6001
|
-
* True when `error` is an SDK error OR a plain-object view of one (see {@link FailureView}) whose
|
|
6002
|
-
* `code` is one of `codes`. The code is compared with the catalog's own spelling, so a wallet
|
|
6003
|
-
* error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.
|
|
6004
|
-
*/
|
|
6005
|
-
function hasCodeIn(error, codes) {
|
|
6006
|
-
const view = toFailureView(error);
|
|
6007
|
-
return view !== void 0 && isCodeIn(view.code, codes);
|
|
6008
|
-
}
|
|
6009
|
-
/**
|
|
6010
|
-
* The codes whose `params.serverMessage` is the gateway's own answer to THIS write, which an app
|
|
6011
|
-
* may show as it is (and falls back to its own line when it is empty): a refusal the gateway made
|
|
6012
|
-
* (`GATEWAY_REPORTED_ERROR`, a 2xx with `error: true`) or a bounce it named (the gateway codes the
|
|
6013
|
-
* SDK knows, and `GATEWAY_REJECTED` for one it does not).
|
|
6014
|
-
*/
|
|
6015
|
-
const RELAYABLE_REFUSAL_CODES = [
|
|
6016
|
-
"GATEWAY_REPORTED_ERROR",
|
|
6017
|
-
"METHOD_NOT_ALLOWED",
|
|
6018
|
-
"SIGNATURE_INVALID",
|
|
6019
|
-
"SIGNER_MISMATCH",
|
|
6020
|
-
"DTO_INVALID",
|
|
6021
|
-
"BOUNDS_VIOLATION",
|
|
6022
|
-
"SYMBOL_CONFLICT",
|
|
6023
|
-
"RATE_LIMITED",
|
|
6024
|
-
"CHAIN_DISPATCH_FAILED",
|
|
6025
|
-
"GATEWAY_REJECTED"
|
|
6026
|
-
];
|
|
6027
|
-
function isRelayableRefusal(error) {
|
|
6028
|
-
return hasCodeIn(error, RELAYABLE_REFUSAL_CODES);
|
|
6029
|
-
}
|
|
6030
|
-
/**
|
|
6031
|
-
* True when a write got a 2xx answer the SDK refused to interpret, so the answer itself is in
|
|
6032
|
-
* `error.body` (or `error.bodyText`) for the app to read: the five unproven acknowledgements
|
|
6033
|
-
* (`isUnprovenAcknowledgement`) and `GATEWAY_REPORTED_ERROR` (a gateway that says `error: true`).
|
|
6034
|
-
* The outcome is `unknown` for all six. It replaces the app's own
|
|
6035
|
-
* `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')` pair.
|
|
6036
|
-
*/
|
|
6037
|
-
function isUninterpretedAnswer(error) {
|
|
6038
|
-
return isUnprovenAcknowledgement(error) || hasCodeIn(error, ["GATEWAY_REPORTED_ERROR"]);
|
|
6039
|
-
}
|
|
6040
|
-
/**
|
|
6041
6176
|
* Classifies any thrown value from its code (and, for two codes, its HTTP status), never from
|
|
6042
6177
|
* message text, so an app does not have to re-derive "may I offer Retry?" and "is the outcome
|
|
6043
6178
|
* unknown?" for every code. The decision for each code is in this module's table; a new catalog
|
|
@@ -6114,34 +6249,6 @@ function classifyView(view) {
|
|
|
6114
6249
|
if (code === "INVALID_PRIVATE_KEY") return { ...classifyInvalidPrivateKey(view) };
|
|
6115
6250
|
return { ...BY_CODE[code] ?? INVALID_INPUT };
|
|
6116
6251
|
}
|
|
6117
|
-
/** Codes that mean "there is no market for this" however the app reached them. */
|
|
6118
|
-
const NO_MARKET_CODES = [
|
|
6119
|
-
"NO_POOL_AVAILABLE",
|
|
6120
|
-
"INSUFFICIENT_LIQUIDITY",
|
|
6121
|
-
"UNKNOWN_TOKEN"
|
|
6122
|
-
];
|
|
6123
|
-
/**
|
|
6124
|
-
* True when a failure means "there is no market to trade this pair": `NO_POOL_AVAILABLE` (no pool
|
|
6125
|
-
* at any fee tier), `INSUFFICIENT_LIQUIDITY` (a pool too thin to quote), `UNKNOWN_TOKEN` (the DEX
|
|
6126
|
-
* has no trading symbol for the token), or a READ that was answered 404 (a quote the backend
|
|
6127
|
-
* cannot find, `error.notFound`). It replaces an app's own `code === ... || code === ... ||
|
|
6128
|
-
* notFound` list, so the empty-state ("No market for this pair") has one definition.
|
|
6129
|
-
*
|
|
6130
|
-
* A write that was answered 404 (it carries a `uniqueKey`) is a missing route, not a missing
|
|
6131
|
-
* market, and is not this. Accepts an SDK error or a plain-object view ({@link FailureView}); every
|
|
6132
|
-
* other value is `false`.
|
|
6133
|
-
*
|
|
6134
|
-
* @example
|
|
6135
|
-
* ```ts
|
|
6136
|
-
* if (isNoMarket(error)) showEmptyState(t('swap.noMarket')); else showError(error);
|
|
6137
|
-
* ```
|
|
6138
|
-
*/
|
|
6139
|
-
function isNoMarket(error) {
|
|
6140
|
-
const view = toFailureView(error);
|
|
6141
|
-
if (view === void 0) return false;
|
|
6142
|
-
if (isCodeIn(view.code, NO_MARKET_CODES)) return true;
|
|
6143
|
-
return !isWriteView(view) && (view.notFound === true || view.status === 404);
|
|
6144
|
-
}
|
|
6145
6252
|
/**
|
|
6146
6253
|
* True when the failed call was a WRITE that may nevertheless have been queued: its outcome is
|
|
6147
6254
|
* `unknown` (`classifyFailure(error).outcome === 'unknown'`: a timeout or broken connection after
|
|
@@ -6168,59 +6275,7 @@ function mayHaveBeenQueued(error) {
|
|
|
6168
6275
|
}
|
|
6169
6276
|
|
|
6170
6277
|
//#endregion
|
|
6171
|
-
//#region src/classes/
|
|
6172
|
-
/** Key the wallet_extension has always used; its storage value is a plain array of entries. */
|
|
6173
|
-
const PENDING_SWAPS_STORAGE_KEY = "pendingSwaps.v1";
|
|
6174
|
-
/** Entries older than this are dropped the next time a wallet's swaps are listed. */
|
|
6175
|
-
const PENDING_SWAP_EXPIRY_MS = 6048e5;
|
|
6176
|
-
/**
|
|
6177
|
-
* A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps
|
|
6178
|
-
* in: the value lands under the key as the structured value it is (the browser clones it; nothing
|
|
6179
|
-
* is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the
|
|
6180
|
-
* store, which treats it as "storage unavailable".
|
|
6181
|
-
*
|
|
6182
|
-
* Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is
|
|
6183
|
-
* built: a module that is imported where `chrome` does not exist yet (a test, a closing extension
|
|
6184
|
-
* context) then fails only when the store touches storage, and that failure (a throw inside the
|
|
6185
|
-
* function) is the same "storage unavailable" rejection.
|
|
6186
|
-
*
|
|
6187
|
-
* @example
|
|
6188
|
-
* ```ts
|
|
6189
|
-
* const store = new PendingSwapStore(storageAdapterFromChromeStorage(chrome.storage.local));
|
|
6190
|
-
* const lazy = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local));
|
|
6191
|
-
* ```
|
|
6192
|
-
*/
|
|
6193
|
-
function storageAdapterFromChromeStorage(area) {
|
|
6194
|
-
const areaNow = () => typeof area === "function" ? area() : area;
|
|
6195
|
-
return {
|
|
6196
|
-
async get(key) {
|
|
6197
|
-
const items = await areaNow().get(key);
|
|
6198
|
-
return Object.hasOwn(items, key) ? items[key] : void 0;
|
|
6199
|
-
},
|
|
6200
|
-
async set(key, value) {
|
|
6201
|
-
await areaNow().set({ [key]: value });
|
|
6202
|
-
}
|
|
6203
|
-
};
|
|
6204
|
-
}
|
|
6205
|
-
/**
|
|
6206
|
-
* Why the store dropped a pending swap (the `reason` of {@link PrunedPendingSwap}).
|
|
6207
|
-
*
|
|
6208
|
-
* - `expired`: older than {@link PENDING_SWAP_EXPIRY_MS}.
|
|
6209
|
-
* - `invalid_unique_key`: its `uniqueKey` is not a valid apply-results key (1 to 128 characters
|
|
6210
|
-
* of `A-Za-z0-9._:-`). `confirmAppliedTrade` refuses such a key with `INVALID_UNIQUE_KEY`
|
|
6211
|
-
* before reading anything and always will, so keeping the entry would retry it forever. The
|
|
6212
|
-
* SDK never signs such a key; an entry like this is corrupt or foreign.
|
|
6213
|
-
* - `chain_rejected`: {@link PendingSwapStore.settle} dropped it because a confirmation proved the
|
|
6214
|
-
* chain REFUSED the trade (`pendingSwapFateFor` is `forget`): it did not happen.
|
|
6215
|
-
* - `unconfirmable`: {@link PendingSwapStore.settle} dropped it because a confirmation failed in a
|
|
6216
|
-
* way that never changes (`forget_quietly`: the key itself is refused): nothing can be learned.
|
|
6217
|
-
*/
|
|
6218
|
-
const PENDING_SWAP_PRUNE_REASONS = [
|
|
6219
|
-
"expired",
|
|
6220
|
-
"invalid_unique_key",
|
|
6221
|
-
"chain_rejected",
|
|
6222
|
-
"unconfirmable"
|
|
6223
|
-
];
|
|
6278
|
+
//#region src/classes/pending_swap_fate.ts
|
|
6224
6279
|
/**
|
|
6225
6280
|
* What to do with a pending swap after confirming it failed (the answer of
|
|
6226
6281
|
* {@link pendingSwapFateFor}).
|
|
@@ -6230,6 +6285,9 @@ const PENDING_SWAP_PRUNE_REASONS = [
|
|
|
6230
6285
|
* Drop it without claiming anything about the trade.
|
|
6231
6286
|
* - `keep`: the trade may still have been applied (a timeout, a broken connection, a gateway
|
|
6232
6287
|
* hiccup, anything not proven). Leave it pending and look again later.
|
|
6288
|
+
*
|
|
6289
|
+
* This module holds the decision and nothing of the store, so an app shell that only needs the
|
|
6290
|
+
* fate pays for `classifyFailure` and this table, not for `PendingSwapStore`.
|
|
6233
6291
|
*/
|
|
6234
6292
|
const PENDING_SWAP_FATES = [
|
|
6235
6293
|
"forget",
|
|
@@ -6278,6 +6336,32 @@ function pendingSwapFateOfOutcome(outcome) {
|
|
|
6278
6336
|
function pendingSwapFateFor(error) {
|
|
6279
6337
|
return pendingSwapFateOfOutcome(classifyFailure(error, { afterQueued: true }).outcome);
|
|
6280
6338
|
}
|
|
6339
|
+
|
|
6340
|
+
//#endregion
|
|
6341
|
+
//#region src/classes/pending_swaps.ts
|
|
6342
|
+
/** Key the wallet_extension has always used; its storage value is a plain array of entries. */
|
|
6343
|
+
const PENDING_SWAPS_STORAGE_KEY = "pendingSwaps.v1";
|
|
6344
|
+
/** Entries older than this are dropped the next time a wallet's swaps are listed. */
|
|
6345
|
+
const PENDING_SWAP_EXPIRY_MS = 6048e5;
|
|
6346
|
+
/**
|
|
6347
|
+
* Why the store dropped a pending swap (the `reason` of {@link PrunedPendingSwap}).
|
|
6348
|
+
*
|
|
6349
|
+
* - `expired`: older than {@link PENDING_SWAP_EXPIRY_MS}.
|
|
6350
|
+
* - `invalid_unique_key`: its `uniqueKey` is not a valid apply-results key (1 to 128 characters
|
|
6351
|
+
* of `A-Za-z0-9._:-`). `confirmAppliedTrade` refuses such a key with `INVALID_UNIQUE_KEY`
|
|
6352
|
+
* before reading anything and always will, so keeping the entry would retry it forever. The
|
|
6353
|
+
* SDK never signs such a key; an entry like this is corrupt or foreign.
|
|
6354
|
+
* - `chain_rejected`: {@link PendingSwapStore.settle} dropped it because a confirmation proved the
|
|
6355
|
+
* chain REFUSED the trade (`pendingSwapFateFor` is `forget`): it did not happen.
|
|
6356
|
+
* - `unconfirmable`: {@link PendingSwapStore.settle} dropped it because a confirmation failed in a
|
|
6357
|
+
* way that never changes (`forget_quietly`: the key itself is refused): nothing can be learned.
|
|
6358
|
+
*/
|
|
6359
|
+
const PENDING_SWAP_PRUNE_REASONS = [
|
|
6360
|
+
"expired",
|
|
6361
|
+
"invalid_unique_key",
|
|
6362
|
+
"chain_rejected",
|
|
6363
|
+
"unconfirmable"
|
|
6364
|
+
];
|
|
6281
6365
|
/**
|
|
6282
6366
|
* Remembers queued swaps so their outcome can be confirmed after the UI, popup or service worker
|
|
6283
6367
|
* that submitted them is gone (`confirmAppliedTrade` with the stored `uniqueKey`).
|
|
@@ -7131,7 +7215,7 @@ function createLazyPrivateKeySigner(getPrivateKey, options = {}) {
|
|
|
7131
7215
|
*
|
|
7132
7216
|
* `scheme: 'personal-sign'` calls
|
|
7133
7217
|
* `gala_signChainDto([serialize({ ...dto, prefix }), walletAddress, methodName])` and REQUIRES
|
|
7134
|
-
* a wallet build that contains wallet_extension commit
|
|
7218
|
+
* a wallet build that contains wallet_extension commit 34ca4e4 (strips the embedded `prefix`
|
|
7135
7219
|
* field and hashes `prefix` + the prefix-less canonical body, the chain's scheme). Wallets
|
|
7136
7220
|
* released before that fix hash the string with the `prefix` field still inside it and the
|
|
7137
7221
|
* signature recovers to an address nobody holds, so only opt in once the fixed wallet is
|
|
@@ -7156,7 +7240,7 @@ var GalaWalletSigner = class {
|
|
|
7156
7240
|
* to the same check); a GalaChain id is `client|` plus 24 hex digits, or the bare 24 hex digits
|
|
7157
7241
|
* frontend_v2 keeps for a direct `client|` login, and is passed through unchanged.
|
|
7158
7242
|
* @param options - Select native signing (default) or personal-sign explicitly.
|
|
7159
|
-
* `'personal-sign'` requires a Gala Wallet build with wallet_extension commit
|
|
7243
|
+
* `'personal-sign'` requires a Gala Wallet build with wallet_extension commit 34ca4e4.
|
|
7160
7244
|
* `selectAddress` is the identity (`client|...` / `eth|...`) Gala Wallet is switched to with
|
|
7161
7245
|
* `window.gala.setAddress` before every signature, when the wallet offers it.
|
|
7162
7246
|
*/
|
|
@@ -7237,6 +7321,7 @@ var BrowserWalletSigner = class {
|
|
|
7237
7321
|
this.walletAddress = normalizeEthereumAccount(walletAddress, false);
|
|
7238
7322
|
this.scheme = options.scheme ?? "personal-sign";
|
|
7239
7323
|
}
|
|
7324
|
+
/** The selected `0x` Ethereum account every signature is requested for. */
|
|
7240
7325
|
walletAddress;
|
|
7241
7326
|
scheme;
|
|
7242
7327
|
/**
|
|
@@ -7259,6 +7344,74 @@ var BrowserWalletSigner = class {
|
|
|
7259
7344
|
}
|
|
7260
7345
|
};
|
|
7261
7346
|
|
|
7347
|
+
//#endregion
|
|
7348
|
+
//#region src/classes/storage_adapters.ts
|
|
7349
|
+
/**
|
|
7350
|
+
* A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps
|
|
7351
|
+
* in: the value lands under the key as the structured value it is (the browser clones it; nothing
|
|
7352
|
+
* is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the
|
|
7353
|
+
* store, which treats it as "storage unavailable".
|
|
7354
|
+
*
|
|
7355
|
+
* Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is
|
|
7356
|
+
* built: a module that is imported where `chrome` does not exist yet (a test, a closing extension
|
|
7357
|
+
* context) then fails only when the store touches storage, and that failure (a throw inside the
|
|
7358
|
+
* function) is the same "storage unavailable" rejection.
|
|
7359
|
+
*
|
|
7360
|
+
* @example
|
|
7361
|
+
* ```ts
|
|
7362
|
+
* const store = new PendingSwapStore(storageAdapterFromChromeStorage(chrome.storage.local));
|
|
7363
|
+
* const lazy = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local));
|
|
7364
|
+
* ```
|
|
7365
|
+
*/
|
|
7366
|
+
function storageAdapterFromChromeStorage(area) {
|
|
7367
|
+
const areaNow = () => typeof area === "function" ? area() : area;
|
|
7368
|
+
return {
|
|
7369
|
+
async get(key) {
|
|
7370
|
+
const items = await areaNow().get(key);
|
|
7371
|
+
return Object.hasOwn(items, key) ? items[key] : void 0;
|
|
7372
|
+
},
|
|
7373
|
+
async set(key, value) {
|
|
7374
|
+
await areaNow().set({ [key]: value });
|
|
7375
|
+
}
|
|
7376
|
+
};
|
|
7377
|
+
}
|
|
7378
|
+
/**
|
|
7379
|
+
* A {@link StorageAdapter} over a Web Storage area (`localStorage`, `sessionStorage`), the shape
|
|
7380
|
+
* frontend_v2 stores pending swaps in: the value lands under the key as JSON text. A missing key
|
|
7381
|
+
* resolves `undefined`. CORRUPT JSON resolves as the raw string, never a rejection (the store
|
|
7382
|
+
* reads a value that is not an array as "no entries" and the next write repairs it, whereas a
|
|
7383
|
+
* `get` that rejects forever would make every `remember` a no-op). A throwing area (storage blocked
|
|
7384
|
+
* by the browser, quota exceeded on `setItem`) rejects, which the store treats as "storage
|
|
7385
|
+
* unavailable".
|
|
7386
|
+
*
|
|
7387
|
+
* Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is
|
|
7388
|
+
* built: where `localStorage` does not exist (server rendering, a test, a blocked context)
|
|
7389
|
+
* the access throws inside the function, which is the same "storage unavailable" rejection, and
|
|
7390
|
+
* the module that builds the adapter still loads.
|
|
7391
|
+
*
|
|
7392
|
+
* @example
|
|
7393
|
+
* ```ts
|
|
7394
|
+
* const store = new PendingSwapStore(webStorageAdapter(() => localStorage));
|
|
7395
|
+
* ```
|
|
7396
|
+
*/
|
|
7397
|
+
function webStorageAdapter(area) {
|
|
7398
|
+
const areaNow = () => typeof area === "function" ? area() : area;
|
|
7399
|
+
return {
|
|
7400
|
+
async get(key) {
|
|
7401
|
+
const raw = areaNow().getItem(key);
|
|
7402
|
+
if (raw === null) return void 0;
|
|
7403
|
+
try {
|
|
7404
|
+
return JSON.parse(raw);
|
|
7405
|
+
} catch {
|
|
7406
|
+
return raw;
|
|
7407
|
+
}
|
|
7408
|
+
},
|
|
7409
|
+
async set(key, value) {
|
|
7410
|
+
areaNow().setItem(key, JSON.stringify(value));
|
|
7411
|
+
}
|
|
7412
|
+
};
|
|
7413
|
+
}
|
|
7414
|
+
|
|
7262
7415
|
//#endregion
|
|
7263
7416
|
//#region src/utils/chain_dto_signing.ts
|
|
7264
7417
|
/**
|
|
@@ -7267,7 +7420,7 @@ var BrowserWalletSigner = class {
|
|
|
7267
7420
|
*
|
|
7268
7421
|
* These are thin, byte-exact ports of the functions the wallet shipped in
|
|
7269
7422
|
* `wallet_extension/src/helpers/wallet/signing.ts` (including the fail-closed personal-sign
|
|
7270
|
-
* payload resolver from its commit
|
|
7423
|
+
* payload resolver from its commit 34ca4e4), re-expressed over the SDK's own primitives. Every
|
|
7271
7424
|
* function takes the key as a string (`0x`-optional hex, or base64) or as bytes, normalizes it per
|
|
7272
7425
|
* call, and zeroes the normalized copy before returning, so nothing in this module retains a key.
|
|
7273
7426
|
* A JavaScript string cannot be wiped; the caller owns the lifetime of the string it passes in.
|
|
@@ -7988,6 +8141,152 @@ function isFetchTransportFailure(error) {
|
|
|
7988
8141
|
}
|
|
7989
8142
|
}
|
|
7990
8143
|
|
|
8144
|
+
//#endregion
|
|
8145
|
+
//#region src/utils/failure_guards.ts
|
|
8146
|
+
/**
|
|
8147
|
+
* The yes/no questions an app asks about a failure from its CODE alone. They read only the failure
|
|
8148
|
+
* view and a short list of codes: no table of every code (that is `classifyFailure`'s, in
|
|
8149
|
+
* `failure_classification.ts`), no error class and no catalog (the imports above are types, erased
|
|
8150
|
+
* at build time). An app shell that imports one of them pays for this module and nothing else.
|
|
8151
|
+
*/
|
|
8152
|
+
/**
|
|
8153
|
+
* True when the gateway answered that the write's `uniqueKey` was ALREADY CONSUMED: a
|
|
8154
|
+
* `CHAIN_DISPATCH_FAILED` with HTTP status 409. The first attempt under that key may be applied
|
|
8155
|
+
* (`classifyFailure` says `unknown`), so the app confirms the key it holds instead of submitting
|
|
8156
|
+
* again or showing the server's text. It replaces `error.code === 'CHAIN_DISPATCH_FAILED' &&
|
|
8157
|
+
* error.status === 409` and the regex on "already saved". Accepts an SDK error or a plain-object
|
|
8158
|
+
* view ({@link FailureView}: `code` and `status`); every other value is `false`.
|
|
8159
|
+
*
|
|
8160
|
+
* @example
|
|
8161
|
+
* ```ts
|
|
8162
|
+
* if (isUniqueKeyConsumed(error)) return confirmAndShowResult(error.uniqueKey);
|
|
8163
|
+
* ```
|
|
8164
|
+
*/
|
|
8165
|
+
function isUniqueKeyConsumed(error) {
|
|
8166
|
+
const view = toFailureView(error);
|
|
8167
|
+
return (view === null || view === void 0 ? void 0 : view.code) === "CHAIN_DISPATCH_FAILED" && view.status === 409;
|
|
8168
|
+
}
|
|
8169
|
+
const UNPROVEN_ACKNOWLEDGEMENT_CODES = [
|
|
8170
|
+
"GATEWAY_DATA_MISSING",
|
|
8171
|
+
"GATEWAY_MODE_INVALID",
|
|
8172
|
+
"GATEWAY_SYNC_REQUEST_TRADE",
|
|
8173
|
+
"MISSING_UNIQUE_KEY",
|
|
8174
|
+
"UNIQUE_KEY_MISMATCH"
|
|
8175
|
+
];
|
|
8176
|
+
/**
|
|
8177
|
+
* True when a write got a 2xx answer that does NOT prove it was queued under the signed key: no
|
|
8178
|
+
* `data`, an unreadable `mode`, a synchronous RequestTrade, or a missing or foreign `uniqueKey`.
|
|
8179
|
+
* The outcome is `unknown` (it may have been queued: confirm `error.uniqueKey`), and the copy an
|
|
8180
|
+
* app shows is one line for all five ("the backend did not confirm it queued the request"), so
|
|
8181
|
+
* the app asks this instead of keeping its own list of the codes. A gateway that says
|
|
8182
|
+
* `error: true` (`GATEWAY_REPORTED_ERROR`) is a refusal with its own message, not in this set.
|
|
8183
|
+
*
|
|
8184
|
+
* @example
|
|
8185
|
+
* ```ts
|
|
8186
|
+
* if (isUnprovenAcknowledgement(error)) keepPendingAndConfirm(error.uniqueKey);
|
|
8187
|
+
* ```
|
|
8188
|
+
*/
|
|
8189
|
+
function isUnprovenAcknowledgement(error) {
|
|
8190
|
+
return hasCodeIn(error, UNPROVEN_ACKNOWLEDGEMENT_CODES);
|
|
8191
|
+
}
|
|
8192
|
+
/** True when `code` is one of `codes` (a list of catalog codes), by exact spelling. */
|
|
8193
|
+
function isCodeIn(code, codes) {
|
|
8194
|
+
return codes.some((known) => known === code);
|
|
8195
|
+
}
|
|
8196
|
+
/**
|
|
8197
|
+
* True when `error` is an SDK error OR a plain-object view of one (see {@link FailureView}) whose
|
|
8198
|
+
* `code` is one of `codes`. The code is compared with the catalog's own spelling, so a wallet
|
|
8199
|
+
* error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.
|
|
8200
|
+
*/
|
|
8201
|
+
function hasCodeIn(error, codes) {
|
|
8202
|
+
const view = toFailureView(error);
|
|
8203
|
+
return view !== void 0 && isCodeIn(view.code, codes);
|
|
8204
|
+
}
|
|
8205
|
+
/**
|
|
8206
|
+
* The codes whose `params.serverMessage` is the gateway's own answer to THIS write, which an app
|
|
8207
|
+
* may show as it is (and falls back to its own line when it is empty): a refusal the gateway made
|
|
8208
|
+
* (`GATEWAY_REPORTED_ERROR`, a 2xx with `error: true`) or a bounce it named (the gateway codes the
|
|
8209
|
+
* SDK knows, and `GATEWAY_REJECTED` for one it does not).
|
|
8210
|
+
*/
|
|
8211
|
+
const RELAYABLE_REFUSAL_CODES = [
|
|
8212
|
+
"GATEWAY_REPORTED_ERROR",
|
|
8213
|
+
"METHOD_NOT_ALLOWED",
|
|
8214
|
+
"SIGNATURE_INVALID",
|
|
8215
|
+
"SIGNER_MISMATCH",
|
|
8216
|
+
"DTO_INVALID",
|
|
8217
|
+
"BOUNDS_VIOLATION",
|
|
8218
|
+
"SYMBOL_CONFLICT",
|
|
8219
|
+
"RATE_LIMITED",
|
|
8220
|
+
"CHAIN_DISPATCH_FAILED",
|
|
8221
|
+
"GATEWAY_REJECTED"
|
|
8222
|
+
];
|
|
8223
|
+
function isRelayableRefusal(error) {
|
|
8224
|
+
return hasCodeIn(error, RELAYABLE_REFUSAL_CODES);
|
|
8225
|
+
}
|
|
8226
|
+
/**
|
|
8227
|
+
* True when a write got a 2xx answer the SDK refused to interpret, so the answer itself is in
|
|
8228
|
+
* `error.body` (or `error.bodyText`) for the app to read: the five unproven acknowledgements
|
|
8229
|
+
* (`isUnprovenAcknowledgement`) and `GATEWAY_REPORTED_ERROR` (a gateway that says `error: true`).
|
|
8230
|
+
* The outcome is `unknown` for all six. It replaces the app's own
|
|
8231
|
+
* `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')` pair.
|
|
8232
|
+
*/
|
|
8233
|
+
function isUninterpretedAnswer(error) {
|
|
8234
|
+
return isUnprovenAcknowledgement(error) || hasCodeIn(error, ["GATEWAY_REPORTED_ERROR"]);
|
|
8235
|
+
}
|
|
8236
|
+
/**
|
|
8237
|
+
* The chain's own machine-readable `ErrorKey` of a failure (`'TOKEN_NOT_FOUND'`,
|
|
8238
|
+
* `'NOT_ENOUGH_LIQUIDITY'`, ...), for an app that maps a chain refusal to its own copy: the
|
|
8239
|
+
* `params.errorKey` of a `CHAIN_REJECTED` (an apply result, or a body that carries the chain's
|
|
8240
|
+
* error) and of a `CHAIN_DISPATCH_FAILED` (the gateway adds the chain's key to the body it
|
|
8241
|
+
* answered). `undefined` when the failure is neither, or when it carries no key (the gateway sent
|
|
8242
|
+
* none: the SDK writes `''`, which is not a key). Map the KEY, never the message text.
|
|
8243
|
+
*
|
|
8244
|
+
* Accepts an SDK error or a plain-object view ({@link FailureView}: `code` and `params`); every
|
|
8245
|
+
* other value is `undefined`. Other codes are `undefined` even when they have an `errorKey`-named
|
|
8246
|
+
* param, so a stray field cannot pass for a chain verdict.
|
|
8247
|
+
*
|
|
8248
|
+
* @example
|
|
8249
|
+
* ```ts
|
|
8250
|
+
* const key = chainErrorKeyOf(error);
|
|
8251
|
+
* if (key === 'NOT_ENOUGH_LIQUIDITY') showTooThin(); else showGeneric(error);
|
|
8252
|
+
* ```
|
|
8253
|
+
*/
|
|
8254
|
+
function chainErrorKeyOf(error) {
|
|
8255
|
+
const view = toFailureView(error);
|
|
8256
|
+
if (view === void 0) return void 0;
|
|
8257
|
+
if (view.code !== "CHAIN_REJECTED" && view.code !== "CHAIN_DISPATCH_FAILED") return void 0;
|
|
8258
|
+
const errorKey = stringParamOf(view, "errorKey");
|
|
8259
|
+
return errorKey === void 0 || errorKey === "" ? void 0 : errorKey;
|
|
8260
|
+
}
|
|
8261
|
+
/** Codes that mean "there is no market for this" however the app reached them. */
|
|
8262
|
+
const NO_MARKET_CODES = [
|
|
8263
|
+
"NO_POOL_AVAILABLE",
|
|
8264
|
+
"INSUFFICIENT_LIQUIDITY",
|
|
8265
|
+
"UNKNOWN_TOKEN"
|
|
8266
|
+
];
|
|
8267
|
+
/**
|
|
8268
|
+
* True when a failure means "there is no market to trade this pair": `NO_POOL_AVAILABLE` (no pool
|
|
8269
|
+
* at any fee tier), `INSUFFICIENT_LIQUIDITY` (a pool too thin to quote), `UNKNOWN_TOKEN` (the DEX
|
|
8270
|
+
* has no trading symbol for the token), or a READ that was answered 404 (a quote the backend
|
|
8271
|
+
* cannot find, `error.notFound`). It replaces an app's own `code === ... || code === ... ||
|
|
8272
|
+
* notFound` list, so the empty-state ("No market for this pair") has one definition.
|
|
8273
|
+
*
|
|
8274
|
+
* A write that was answered 404 (it carries a `uniqueKey`) is a missing route, not a missing
|
|
8275
|
+
* market, and is not this. Accepts an SDK error or a plain-object view ({@link FailureView}); every
|
|
8276
|
+
* other value is `false`.
|
|
8277
|
+
*
|
|
8278
|
+
* @example
|
|
8279
|
+
* ```ts
|
|
8280
|
+
* if (isNoMarket(error)) showEmptyState(t('swap.noMarket')); else showError(error);
|
|
8281
|
+
* ```
|
|
8282
|
+
*/
|
|
8283
|
+
function isNoMarket(error) {
|
|
8284
|
+
const view = toFailureView(error);
|
|
8285
|
+
if (view === void 0) return false;
|
|
8286
|
+
if (isCodeIn(view.code, NO_MARKET_CODES)) return true;
|
|
8287
|
+
return !isWriteView(view) && (view.notFound === true || view.status === 404);
|
|
8288
|
+
}
|
|
8289
|
+
|
|
7991
8290
|
//#endregion
|
|
7992
8291
|
//#region src/utils/submit_state.ts
|
|
7993
8292
|
/** The `mode` of `envelope.data`, or `undefined` when there is no such field. */
|
|
@@ -8075,7 +8374,9 @@ exports.Symbols = Symbols;
|
|
|
8075
8374
|
exports.TICK_SPACING_BY_FEE = TICK_SPACING_BY_FEE;
|
|
8076
8375
|
exports.UPDATE_REQUIRED_STATUS = UPDATE_REQUIRED_STATUS;
|
|
8077
8376
|
exports.alignTickDown = alignTickDown;
|
|
8377
|
+
exports.alignTickDownOrNaN = alignTickDownOrNaN;
|
|
8078
8378
|
exports.alignTickUp = alignTickUp;
|
|
8379
|
+
exports.alignTickUpOrNaN = alignTickUpOrNaN;
|
|
8079
8380
|
exports.assertCanonicalPair = assertCanonicalPair;
|
|
8080
8381
|
exports.assertCanonicalV2Dto = assertCanonicalV2Dto;
|
|
8081
8382
|
exports.assertTickRange = assertTickRange;
|
|
@@ -8089,6 +8390,7 @@ exports.buildRemoveLiquidityDto = buildRemoveLiquidityDto;
|
|
|
8089
8390
|
exports.buildRequestTradeDto = buildRequestTradeDto;
|
|
8090
8391
|
exports.calculatePersonalSignPrefix = calculatePersonalSignPrefix;
|
|
8091
8392
|
exports.canonicalDecimalString = canonicalDecimalString;
|
|
8393
|
+
exports.chainErrorKeyOf = chainErrorKeyOf;
|
|
8092
8394
|
exports.classification = classification;
|
|
8093
8395
|
exports.classifyFailure = classifyFailure;
|
|
8094
8396
|
exports.classifyShadowSubmitError = classifyShadowSubmitError;
|
|
@@ -8125,9 +8427,11 @@ exports.isPreSendError = isPreSendError;
|
|
|
8125
8427
|
exports.isProposableTradingSymbol = isProposableTradingSymbol;
|
|
8126
8428
|
exports.isRelayableRefusal = isRelayableRefusal;
|
|
8127
8429
|
exports.isShadowError = isShadowError;
|
|
8430
|
+
exports.isSqrtPriceInRange = isSqrtPriceInRange;
|
|
8128
8431
|
exports.isSubmitExecuted = isSubmitExecuted;
|
|
8129
8432
|
exports.isSubmitQueued = isSubmitQueued;
|
|
8130
8433
|
exports.isSubmitRejected = isSubmitRejected;
|
|
8434
|
+
exports.isTickInRange = isTickInRange;
|
|
8131
8435
|
exports.isUninterpretedAnswer = isUninterpretedAnswer;
|
|
8132
8436
|
exports.isUniqueKeyConsumed = isUniqueKeyConsumed;
|
|
8133
8437
|
exports.isUnprovenAcknowledgement = isUnprovenAcknowledgement;
|
|
@@ -8180,5 +8484,6 @@ exports.validateTickSpacing = validateTickSpacing;
|
|
|
8180
8484
|
exports.validateTokenDecimals = validateTokenDecimals;
|
|
8181
8485
|
exports.validateWalletAddress = validateWalletAddress;
|
|
8182
8486
|
exports.walletDeclineCode = walletDeclineCode;
|
|
8487
|
+
exports.webStorageAdapter = webStorageAdapter;
|
|
8183
8488
|
exports.withPrivateKey = withPrivateKey;
|
|
8184
8489
|
//# sourceMappingURL=index.cjs.map
|