@hyperbridge/sdk 2.8.7 → 2.8.10

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.
@@ -4,10 +4,10 @@ import { baseSepolia, optimismSepolia, arbitrumSepolia, soneium, gnosis, optimis
4
4
  import { TronWeb } from 'tronweb';
5
5
  import { flatten, zip, capitalize, maxBy, isNil } from 'lodash-es';
6
6
  import { match } from 'ts-pattern';
7
- import { WsProvider, ApiPromise, HttpProvider, Keyring } from '@polkadot/api';
7
+ import { WsProvider, ApiPromise, Keyring, HttpProvider } from '@polkadot/api';
8
8
  import { Struct, Vector, u8, Bytes, Enum, Tuple, _void, u64, u32, Option, bool, u128 } from 'scale-ts';
9
- import { keccakAsU8a, decodeAddress, keccakAsHex, xxhashAsU8a, blake2AsU8a } from '@polkadot/util-crypto';
10
- import { hexToU8a, u8aToHex, u8aConcat, stringToU8a, isHex as isHex$1, u8aToString } from '@polkadot/util';
9
+ import { xxhashAsU8a, keccakAsU8a, decodeAddress, keccakAsHex, blake2AsU8a } from '@polkadot/util-crypto';
10
+ import { u8aToHex, u8aConcat, hexToU8a, stringToU8a, isHex as isHex$1, u8aToString } from '@polkadot/util';
11
11
  import PQueue from 'p-queue';
12
12
  import { hasWindow, isNode, env } from 'std-env';
13
13
  import mergeRace from '@async-generator/merge-race';
@@ -2847,7 +2847,7 @@ var chainConfigs = {
2847
2847
  // "Usdt0Oft": Not available on BSC
2848
2848
  },
2849
2849
  rpcEnvKey: "BSC_MAINNET",
2850
- defaultRpcUrl: "https://binance.llamarpc.com",
2850
+ defaultRpcUrl: "https://bsc-rpc.publicnode.com",
2851
2851
  consensusStateId: "BSC0",
2852
2852
  coingeckoId: "binance-smart-chain",
2853
2853
  erc4626Vaults: [
@@ -3897,6 +3897,11 @@ var ABI3 = [
3897
3897
  type: "uint256",
3898
3898
  internalType: "uint256"
3899
3899
  },
3900
+ {
3901
+ name: "validUntil",
3902
+ type: "uint256",
3903
+ internalType: "uint256"
3904
+ },
3900
3905
  {
3901
3906
  name: "outputs",
3902
3907
  type: "tuple[]",
@@ -7864,6 +7869,255 @@ function encodeISMPMessage(message) {
7864
7869
  throw new Error("Failed to encode ISMP message", { cause: error });
7865
7870
  }
7866
7871
  }
7872
+
7873
+ // src/utils/rateLimiter.ts
7874
+ var TokenBucket = class {
7875
+ /**
7876
+ * @param ratePerSecond - sustained requests per second.
7877
+ * @param burst - how many requests may go out back-to-back before pacing starts. Defaults to
7878
+ * one second's worth, which is the shape most limiters police.
7879
+ */
7880
+ constructor(ratePerSecond, burst = ratePerSecond) {
7881
+ this.ratePerSecond = ratePerSecond;
7882
+ this.burst = burst;
7883
+ if (ratePerSecond <= 0) throw new Error(`TokenBucket rate must be positive, got ${ratePerSecond}`);
7884
+ this.tokens = burst;
7885
+ this.lastRefill = Date.now();
7886
+ }
7887
+ ratePerSecond;
7888
+ burst;
7889
+ /** Fractional on purpose: a partial token is real capacity, just not yet a whole request. */
7890
+ tokens;
7891
+ lastRefill;
7892
+ waiting = [];
7893
+ drainTimer = null;
7894
+ /** Resolves once this caller may send. */
7895
+ async acquire() {
7896
+ if (this.waiting.length === 0 && this.take()) return;
7897
+ return new Promise((resolve) => {
7898
+ this.waiting.push(resolve);
7899
+ this.scheduleDrain();
7900
+ });
7901
+ }
7902
+ /** Requests currently waiting on a token. Exposed for tests and diagnostics. */
7903
+ get queued() {
7904
+ return this.waiting.length;
7905
+ }
7906
+ refill() {
7907
+ const now = Date.now();
7908
+ const elapsed = now - this.lastRefill;
7909
+ if (elapsed <= 0) {
7910
+ if (elapsed < 0) this.lastRefill = now;
7911
+ return;
7912
+ }
7913
+ this.tokens = Math.min(this.burst, this.tokens + elapsed * this.ratePerSecond / 1e3);
7914
+ this.lastRefill = now;
7915
+ }
7916
+ take() {
7917
+ this.refill();
7918
+ if (this.tokens < 1) return false;
7919
+ this.tokens -= 1;
7920
+ return true;
7921
+ }
7922
+ scheduleDrain() {
7923
+ if (this.drainTimer) return;
7924
+ this.refill();
7925
+ const deficit = 1 - this.tokens;
7926
+ const waitMs = deficit <= 0 ? 0 : Math.ceil(deficit * 1e3 / this.ratePerSecond);
7927
+ const timer = setTimeout(() => {
7928
+ this.drainTimer = null;
7929
+ this.drain();
7930
+ }, waitMs);
7931
+ timer.unref?.();
7932
+ this.drainTimer = timer;
7933
+ }
7934
+ drain() {
7935
+ while (this.waiting.length > 0 && this.take()) {
7936
+ this.waiting.shift()?.();
7937
+ }
7938
+ if (this.waiting.length > 0) this.scheduleDrain();
7939
+ }
7940
+ };
7941
+ var BATCHES_NOT_SUPPORTED_CODE = -32005;
7942
+ var TOO_BIG_BATCH_REQUEST_CODE = -32010;
7943
+ var DEFAULT_MAX_BATCH_SIZE = 32;
7944
+ function rpcError({ code, message, data }) {
7945
+ const suffix = data === void 0 ? "" : `: ${typeof data === "string" ? data : JSON.stringify(data)}`;
7946
+ const error = new Error(`${code}: ${message}${suffix}`);
7947
+ error.code = code;
7948
+ error.data = data;
7949
+ return error;
7950
+ }
7951
+ var BatchingHttpProvider = class _BatchingHttpProvider extends HttpProvider {
7952
+ #endpoint;
7953
+ #headers;
7954
+ #limiter;
7955
+ #maxBatchSize;
7956
+ #batchingSupported = true;
7957
+ #pending = [];
7958
+ #flushTimer = null;
7959
+ #flushing = false;
7960
+ #nextId = 1;
7961
+ constructor(endpoint, headers, limiter, maxBatchSize = DEFAULT_MAX_BATCH_SIZE) {
7962
+ super(endpoint, headers, 0);
7963
+ this.#endpoint = endpoint;
7964
+ this.#headers = headers;
7965
+ this.#limiter = limiter;
7966
+ this.#maxBatchSize = maxBatchSize;
7967
+ }
7968
+ /**
7969
+ * `isCacheable` is accepted for interface compatibility and ignored: this provider has no
7970
+ * response cache, which is deliberate — see the note in `IntentsCoprocessor.http`.
7971
+ */
7972
+ async send(method, params, _isCacheable) {
7973
+ return new Promise((resolve, reject) => {
7974
+ this.#pending.push({
7975
+ id: this.#nextId++,
7976
+ method,
7977
+ params,
7978
+ resolve,
7979
+ reject
7980
+ });
7981
+ if (this.#pending.length >= this.#maxBatchSize) this.#flushNow();
7982
+ else this.#scheduleFlush();
7983
+ });
7984
+ }
7985
+ clone() {
7986
+ return new _BatchingHttpProvider(this.#endpoint, this.#headers, this.#limiter, this.#maxBatchSize);
7987
+ }
7988
+ /** Calls waiting for a flush. Exposed for tests and diagnostics. */
7989
+ get queued() {
7990
+ return this.#pending.length;
7991
+ }
7992
+ /**
7993
+ * Collect for the rest of this macrotask, then send.
7994
+ *
7995
+ * A macrotask rather than a microtask because the bursts worth catching are not synchronous:
7996
+ * `Promise.all` over a set of reads starts them in one synchronous run, but each then advances
7997
+ * through several microtask turns of its own before reaching the provider. A microtask flush
7998
+ * would fire between those turns and split one burst across several requests.
7999
+ */
8000
+ #scheduleFlush() {
8001
+ if (this.#flushTimer || this.#flushing) return;
8002
+ const timer = setTimeout(() => {
8003
+ this.#flushTimer = null;
8004
+ void this.#flush();
8005
+ }, 0);
8006
+ timer.unref?.();
8007
+ this.#flushTimer = timer;
8008
+ }
8009
+ #flushNow() {
8010
+ if (this.#flushing) return;
8011
+ if (this.#flushTimer) {
8012
+ clearTimeout(this.#flushTimer);
8013
+ this.#flushTimer = null;
8014
+ }
8015
+ void this.#flush();
8016
+ }
8017
+ async #flush() {
8018
+ if (this.#flushing) return;
8019
+ const calls = this.#pending.splice(0, this.#maxBatchSize);
8020
+ if (calls.length === 0) return;
8021
+ this.#flushing = true;
8022
+ try {
8023
+ await this.#limiter.acquire();
8024
+ await this.#post(calls);
8025
+ } finally {
8026
+ this.#flushing = false;
8027
+ if (this.#pending.length > 0) this.#scheduleFlush();
8028
+ }
8029
+ }
8030
+ async #post(calls) {
8031
+ const single = calls.length === 1;
8032
+ const payload = calls.map(({ id, method, params }) => ({ id, jsonrpc: "2.0", method, params }));
8033
+ const body = JSON.stringify(single ? payload[0] : payload);
8034
+ let parsed;
8035
+ try {
8036
+ const response = await fetch(this.#endpoint, {
8037
+ body,
8038
+ headers: {
8039
+ Accept: "application/json",
8040
+ "Content-Type": "application/json",
8041
+ ...this.#headers
8042
+ },
8043
+ method: "POST"
8044
+ });
8045
+ if (!response.ok) throw new Error(`[${response.status}]: ${response.statusText}`);
8046
+ parsed = JSON.parse(await response.text());
8047
+ } catch (err) {
8048
+ const error = err instanceof Error ? err : new Error(String(err));
8049
+ error.message = `${error.message}
8050
+ Failed HTTP Request: ${JSON.stringify(
8051
+ calls.map(({ method, params }) => ({ method, params }))
8052
+ )}`;
8053
+ for (const call of calls) call.reject(error);
8054
+ return;
8055
+ }
8056
+ if (Array.isArray(parsed)) {
8057
+ this.#settleBatch(calls, parsed);
8058
+ return;
8059
+ }
8060
+ if (!single) {
8061
+ this.#handleBatchRefusal(calls, parsed);
8062
+ return;
8063
+ }
8064
+ this.#settle(calls[0], parsed);
8065
+ }
8066
+ #settleBatch(calls, responses) {
8067
+ const byId = /* @__PURE__ */ new Map();
8068
+ for (const response of responses) {
8069
+ if (typeof response?.id === "number") byId.set(response.id, response);
8070
+ }
8071
+ for (const call of calls) {
8072
+ const response = byId.get(call.id);
8073
+ if (response) this.#settle(call, response);
8074
+ else call.reject(new Error(`No response for ${call.method} in batch reply`));
8075
+ }
8076
+ }
8077
+ #settle(call, response) {
8078
+ if (response?.error) {
8079
+ call.reject(rpcError(response.error));
8080
+ return;
8081
+ }
8082
+ if (!response || response.result === void 0) {
8083
+ call.reject(new Error("No result found in jsonrpc response"));
8084
+ return;
8085
+ }
8086
+ call.resolve(response.result);
8087
+ }
8088
+ /**
8089
+ * The server rejected the batch itself rather than any call in it. Both forms are recoverable
8090
+ * without losing a call, and neither should ever surface to a caller as a failure.
8091
+ */
8092
+ #handleBatchRefusal(calls, response) {
8093
+ const code = response?.error?.code;
8094
+ if (code === BATCHES_NOT_SUPPORTED_CODE) {
8095
+ this.#batchingSupported = false;
8096
+ this.#maxBatchSize = 1;
8097
+ this.#requeue(calls);
8098
+ return;
8099
+ }
8100
+ if (code === TOO_BIG_BATCH_REQUEST_CODE) {
8101
+ this.#maxBatchSize = Math.max(1, Math.floor(this.#maxBatchSize / 2));
8102
+ this.#requeue(calls);
8103
+ return;
8104
+ }
8105
+ const error = response?.error ? rpcError(response.error) : new Error("Malformed batch reply: neither an array nor an error");
8106
+ for (const call of calls) call.reject(error);
8107
+ }
8108
+ /** Puts calls back at the head of the queue, so a refused batch keeps its place in line. */
8109
+ #requeue(calls) {
8110
+ this.#pending.unshift(...calls);
8111
+ this.#scheduleFlush();
8112
+ }
8113
+ /** Whether batches are still being attempted. Exposed for tests and diagnostics. */
8114
+ get batchingSupported() {
8115
+ return this.#batchingSupported;
8116
+ }
8117
+ };
8118
+
8119
+ // src/chains/intentsCoprocessor.ts
8120
+ var SYSTEM_EVENTS_KEY = u8aToHex(u8aConcat(xxhashAsU8a("System", 128), xxhashAsU8a("Events", 128)));
7867
8121
  var OFFCHAIN_BID_PREFIX = new TextEncoder().encode("intents::bid::");
7868
8122
  var OFFCHAIN_PHANTOM_PREFIX = new TextEncoder().encode("intents::phantom::order::");
7869
8123
  var HYPERBRIDGE_TYPES_BUNDLE = {
@@ -7877,6 +8131,63 @@ var HTTP_CONNECT_TIMEOUT_MS = 2e4;
7877
8131
  var INCLUSION_TIMEOUT_MS = 2e4;
7878
8132
  var PHANTOM_POLL_INTERVAL_MS = 15e3;
7879
8133
  var GARGANTUA_PHANTOM_POLL_INTERVAL_MS = 6e3;
8134
+ var DEFAULT_RPC_MAX_RPS = 8;
8135
+ var DEFAULT_MAX_BLOCKS_PER_POLL = 10;
8136
+ var MAX_RATE_LIMIT_BACKOFF_TICKS = 8;
8137
+ var rpcLimiters = /* @__PURE__ */ new Map();
8138
+ function limiterFor(httpUrl) {
8139
+ const key = new URL(httpUrl).origin;
8140
+ let limiter = rpcLimiters.get(key);
8141
+ if (!limiter) {
8142
+ limiter = new TokenBucket(configuredRpcMaxRps());
8143
+ rpcLimiters.set(key, limiter);
8144
+ }
8145
+ return limiter;
8146
+ }
8147
+ function configuredRpcMaxRps() {
8148
+ const raw = typeof process !== "undefined" ? process.env?.HYPERBRIDGE_RPC_MAX_RPS : void 0;
8149
+ const parsed = raw === void 0 ? Number.NaN : Number(raw);
8150
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_RPC_MAX_RPS;
8151
+ }
8152
+ function isRateLimited(err) {
8153
+ const message = err instanceof Error ? err.message : String(err);
8154
+ return message.includes("[429]") || /too many requests/i.test(message);
8155
+ }
8156
+ function isMethodUnavailable(err) {
8157
+ const message = err instanceof Error ? err.message : String(err);
8158
+ const code = err?.code;
8159
+ return code === -32601 || /method not found|unsafe to be called externally/i.test(message);
8160
+ }
8161
+ var EventDecodeError = class extends Error {
8162
+ };
8163
+ function phantomOrdersFrom(records) {
8164
+ if (records == null || typeof records[Symbol.iterator] !== "function") {
8165
+ throw new EventDecodeError(`Expected a decoded event vector, got ${typeof records}`);
8166
+ }
8167
+ const orders = [];
8168
+ for (const record of records) {
8169
+ if (typeof record !== "object" || record === null || !("event" in record)) {
8170
+ throw new EventDecodeError(
8171
+ "system.events did not decode to event records \u2014 the storage entry's metadata was probably not carried through, leaving the value as raw bytes"
8172
+ );
8173
+ }
8174
+ const { event } = record;
8175
+ if (event.section !== "intentsCoprocessor" || event.method !== "PhantomOrderRegistered") continue;
8176
+ const [commitment, chain, createdAt, legs] = event.data;
8177
+ orders.push({
8178
+ commitment: commitment.toHex(),
8179
+ chain: new TextDecoder().decode(hexToU8a(chain.toHex())),
8180
+ createdAt: createdAt.toNumber(),
8181
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8182
+ legs: legs.map((leg) => ({
8183
+ tokenA: leg.tokenA.toHex(),
8184
+ tokenB: leg.tokenB.toHex(),
8185
+ standardAmount: BigInt(leg.standardAmount.toString())
8186
+ }))
8187
+ });
8188
+ }
8189
+ return orders;
8190
+ }
7880
8191
  function rejectAfter(ms, message) {
7881
8192
  return new Promise((_resolve, reject) => {
7882
8193
  const timer = setTimeout(() => reject(new Error(message)), ms);
@@ -7948,8 +8259,14 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
7948
8259
  ownsConnection;
7949
8260
  /** Cached result of whether the node exposes intents_* RPC methods */
7950
8261
  hasIntentsRpc = null;
8262
+ /** The pallet's phantom timings, read once. Cleared on failure so the read retries. */
8263
+ phantomTimingsRead = null;
7951
8264
  /** The HTTP-backed api, connected on first use. Cleared after a failed attempt so it retries. */
7952
8265
  httpApi = null;
8266
+ /** Last runtime version read from the node, for {@link confirmedRuntimeVersion} to compare against. */
8267
+ lastRuntimeVersion;
8268
+ /** Set once the node refuses `state_queryStorage`, so the poll stops asking for it. */
8269
+ rangeQueryUnavailable = false;
7953
8270
  // Serialises every extrinsic submission on this instance's substrate account. All submit/retract
7954
8271
  // methods funnel through signAndSendExtrinsic, each using the API's auto-nonce; fired in parallel
7955
8272
  // (bids for orders on different chains, or several phantom orders in one interval) they would grab
@@ -8049,7 +8366,11 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8049
8366
  // replayed from memory on every tick, faster than the TTL could lapse, and the node never
8050
8367
  // saw a second request. The cache bought nothing here anyway: the poll reads each block
8051
8368
  // once, and `api.at(hash)` reuses registries at the api layer regardless.
8052
- provider: new HttpProvider(httpUrl, {}, 0),
8369
+ // Concurrent calls are coalesced into one JSON-RPC batch request, and every request
8370
+ // to this endpoint is paced by a bucket shared with any other coprocessor in this
8371
+ // process pointed at the same host — the limit is the server's, and it counts
8372
+ // requests per address rather than per connection.
8373
+ provider: new BatchingHttpProvider(httpUrl, {}, limiterFor(httpUrl)),
8053
8374
  typesBundle: HYPERBRIDGE_TYPES_BUNDLE,
8054
8375
  // A second connection to the node the ws api already reported on; its init warnings
8055
8376
  // would just be duplicates.
@@ -8617,29 +8938,77 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8617
8938
  }
8618
8939
  /**
8619
8940
  * Reads the PhantomOrderRegistered events emitted in a single block.
8941
+ *
8942
+ * Costs two RPCs per block when `knownVersion` is supplied and four without it, which is why the
8943
+ * poll goes to the trouble of establishing one. `api.at(hash)` has to work out which metadata to
8944
+ * decode the block against, and with nothing to go on it fetches the header and then the runtime
8945
+ * version at its parent — every block, forever. Its cheaper paths are a registry already pinned
8946
+ * to this exact hash (only ever the previous block's) or one matching a version the caller
8947
+ * names, so naming the version is the only way out. See `getBlockRegistry` in
8948
+ * `@polkadot/api/base/Init`; the `getUpgradeVersion` shortcut that would otherwise skip the
8949
+ * lookup only covers chains hardcoded in `@polkadot/types-known`, which Hyperbridge is not.
8950
+ *
8951
+ * @param knownVersion - the runtime version this block is known to run, if the caller has
8952
+ * established one. Passing a version the block does not actually run decodes it against the
8953
+ * wrong metadata, so this is for callers that have checked, not a place to pass a guess.
8620
8954
  */
8621
- async getPhantomOrdersInBlock(blockNumber) {
8955
+ async getPhantomOrdersInBlock(blockNumber, knownVersion) {
8622
8956
  const api = await this.http();
8623
8957
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
8624
- const apiAt = await api.at(blockHash);
8625
- const records = await apiAt.query.system.events();
8626
- const orders = [];
8627
- for (const { event } of records) {
8628
- if (event.section !== "intentsCoprocessor" || event.method !== "PhantomOrderRegistered") continue;
8629
- const [commitment, chain, createdAt, legs] = event.data;
8630
- orders.push({
8631
- commitment: commitment.toHex(),
8632
- chain: new TextDecoder().decode(hexToU8a(chain.toHex())),
8633
- createdAt: createdAt.toNumber(),
8634
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8635
- legs: legs.map((leg) => ({
8636
- tokenA: leg.tokenA.toHex(),
8637
- tokenB: leg.tokenB.toHex(),
8638
- standardAmount: BigInt(leg.standardAmount.toString())
8639
- }))
8640
- });
8641
- }
8642
- return orders;
8958
+ return await this.getPhantomOrdersAtHash(blockHash.toHex(), knownVersion);
8959
+ }
8960
+ /**
8961
+ * The same read, for a caller that already holds the block's hash.
8962
+ *
8963
+ * Split out so the poll can fetch a whole range's hashes in one concurrent wave — which the
8964
+ * provider coalesces into a single batched request — and then read each block's events knowing
8965
+ * its hash. `chain_getBlockHash` is the half of the pair that parallelises safely: it takes no
8966
+ * historic block hash, so it never triggers polkadot-js's per-hash registry resolution, and
8967
+ * concurrent calls cannot race each other's registry state.
8968
+ */
8969
+ async getPhantomOrdersAtHash(blockHash, knownVersion) {
8970
+ const api = await this.http();
8971
+ const apiAt = await api.at(blockHash, knownVersion);
8972
+ return phantomOrdersFrom(await apiAt.query.system.events());
8973
+ }
8974
+ /**
8975
+ * Every block's phantom orders across a whole range, in one `state_queryStorage` call.
8976
+ *
8977
+ * This is the cheap path: the request cost of a scan stops depending on how many blocks it
8978
+ * covers. The events key is the only key queried, and both bounds are block hashes the caller
8979
+ * already holds.
8980
+ *
8981
+ * Two properties of the RPC shape the result.
8982
+ *
8983
+ * It returns *diffs*: `query_storage_unfiltered` in `sc-rpc` pushes a change set for a block only
8984
+ * when the value differs from the previous block in the range (`has_changed`, and the set is
8985
+ * dropped when empty), so a block whose events encode byte-for-byte identically to its
8986
+ * predecessor's is simply absent. That happens on a quiet chain, where consecutive blocks carry
8987
+ * nothing but the timestamp inherent's `ExtrinsicSuccess`. It is safe here because an absent
8988
+ * block provably carries no phantom orders: a `PhantomOrderRegistered` commitment is derived from
8989
+ * the block number (`phantom_order_commitment`), so a block that registered orders can never
8990
+ * encode identically to any other block. Absent therefore means "same as the previous block",
8991
+ * and the previous block having orders would contradict that.
8992
+ *
8993
+ * And it is gated by `--rpc-methods` (`check_if_safe` in `sc-rpc`), which answers a denied call
8994
+ * with `Method not found`. The node this reads from must already run unsafe RPC to serve
8995
+ * `offchain_localStorageGet` for the orders themselves, so this is normally available; the poll
8996
+ * falls back to reading block by block when it is not.
8997
+ *
8998
+ * @returns one entry per block the node reported a change for, in ascending block order.
8999
+ */
9000
+ async getPhantomOrdersInRange(fromBlockHash, toBlockHash) {
9001
+ const api = await this.http();
9002
+ const changeSets = await api.rpc.state.queryStorage.raw(
9003
+ [SYSTEM_EVENTS_KEY],
9004
+ fromBlockHash,
9005
+ toBlockHash
9006
+ );
9007
+ return changeSets.map((changeSet) => {
9008
+ const value = changeSet?.changes?.find(([key]) => key === SYSTEM_EVENTS_KEY)?.[1];
9009
+ if (!value) return [];
9010
+ return phantomOrdersFrom(api.registry.createType("Vec<EventRecord>", value));
9011
+ });
8643
9012
  }
8644
9013
  /**
8645
9014
  * Polls for newly registered phantom orders, invoking the callback once per block that carries
@@ -8667,30 +9036,85 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8667
9036
  * socket that looks alive while delivering nothing. It also means a websocket outage does not
8668
9037
  * pause phantom bidding at all — the two transports fail independently.
8669
9038
  *
9039
+ * What the cadence does *not* describe is the request rate, which is what rate limiters police.
9040
+ * A tick costs four requests whatever the range covers — the head, the runtime version, the two
9041
+ * bounding block hashes as one batched request, and one `state_queryStorage` for every block's
9042
+ * events — and they go out back-to-back, so an interval well under any per-second limit could
9043
+ * still arrive as a burst over it. Three things keep that in bounds: the provider coalesces
9044
+ * concurrent calls into one request and paces requests through the endpoint's token bucket (see
9045
+ * `http`), and `maxBlocksPerPoll` bounds the range. A 429 that gets through anyway backs the
9046
+ * poll off for a doubling number of ticks, so a limiter that is already shedding load is not
9047
+ * handed the next window's budget in rejections too.
9048
+ *
9049
+ * Where the node will not serve `state_queryStorage` the poll reads block by block instead, at
9050
+ * three requests plus one per block; see {@link scanRangeAtOnce}.
9051
+ *
8670
9052
  * Returns a function that stops polling.
8671
9053
  */
8672
9054
  pollPhantomOrders(callback, options = {}) {
8673
- const { intervalMs, maxBlocksPerPoll = 500, lookbackBlocks = 0, onError } = options;
9055
+ const {
9056
+ intervalMs,
9057
+ maxBlocksPerPoll = DEFAULT_MAX_BLOCKS_PER_POLL,
9058
+ onError,
9059
+ onSkip
9060
+ } = options;
8674
9061
  let cursor = null;
8675
9062
  let inFlight = false;
8676
9063
  let stopped = false;
9064
+ let backoffTicks = 0;
9065
+ let backoffLength = 0;
8677
9066
  const tick = async () => {
8678
9067
  if (inFlight || stopped) return;
9068
+ if (backoffTicks > 0) {
9069
+ backoffTicks -= 1;
9070
+ return;
9071
+ }
8679
9072
  inFlight = true;
8680
9073
  try {
8681
- const head = (await (await this.http()).rpc.chain.getHeader()).number.toNumber();
9074
+ const api = await this.http();
9075
+ const head = (await api.rpc.chain.getHeader()).number.toNumber();
8682
9076
  if (cursor === null) {
8683
- cursor = Math.max(head - 1 - lookbackBlocks, -1);
9077
+ cursor = Math.max(head - 1, -1);
9078
+ } else {
9079
+ const { bidWindowBlocks, intervalBlocks } = await this.phantomTimings();
9080
+ if (head - cursor > bidWindowBlocks + Math.max(intervalBlocks, bidWindowBlocks)) {
9081
+ const from = cursor + 1;
9082
+ cursor = Math.max(head - 1 - bidWindowBlocks, -1);
9083
+ onSkip?.({ from, to: cursor, head });
9084
+ }
8684
9085
  }
8685
9086
  if (head <= cursor) return;
9087
+ const knownVersion = await this.confirmedRuntimeVersion();
8686
9088
  const to = Math.min(head, cursor + maxBlocksPerPoll);
8687
- for (let blockNumber = cursor + 1; blockNumber <= to; blockNumber++) {
9089
+ const ranged = await this.scanRangeAtOnce(api, cursor + 1, to, knownVersion, onError);
9090
+ if (ranged) {
9091
+ for (const orders of ranged) {
9092
+ if (stopped) return;
9093
+ if (orders.length > 0) callback(orders);
9094
+ }
9095
+ cursor = to;
9096
+ backoffLength = 0;
9097
+ return;
9098
+ }
9099
+ const numbers = [];
9100
+ for (let blockNumber = cursor + 1; blockNumber <= to; blockNumber++) numbers.push(blockNumber);
9101
+ const hashes = await Promise.allSettled(
9102
+ numbers.map((blockNumber) => api.rpc.chain.getBlockHash(blockNumber))
9103
+ );
9104
+ for (let index = 0; index < numbers.length; index++) {
8688
9105
  if (stopped) return;
8689
- const orders = await this.getPhantomOrdersInBlock(blockNumber);
9106
+ const hash = hashes[index];
9107
+ if (hash.status === "rejected") throw hash.reason;
9108
+ const orders = await this.getPhantomOrdersAtHash(hash.value.toHex(), knownVersion);
8690
9109
  if (orders.length > 0) callback(orders);
8691
- cursor = blockNumber;
9110
+ cursor = numbers[index];
8692
9111
  }
9112
+ backoffLength = 0;
8693
9113
  } catch (err) {
9114
+ if (isRateLimited(err)) {
9115
+ backoffLength = Math.min(backoffLength === 0 ? 1 : backoffLength * 2, MAX_RATE_LIMIT_BACKOFF_TICKS);
9116
+ backoffTicks = backoffLength;
9117
+ }
8694
9118
  onError?.(err);
8695
9119
  } finally {
8696
9120
  inFlight = false;
@@ -8709,6 +9133,125 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8709
9133
  if (timer) clearInterval(timer);
8710
9134
  };
8711
9135
  }
9136
+ /**
9137
+ * The Hyperbridge head, over HTTP like every other read here.
9138
+ *
9139
+ * Exposed for callers that have to know how old something is: a phantom order carries the block
9140
+ * it was registered at, and only against the head does that become "still biddable" or "long
9141
+ * expired".
9142
+ */
9143
+ async latestBlockNumber() {
9144
+ const api = await this.http();
9145
+ return (await api.rpc.chain.getHeader()).number.toNumber();
9146
+ }
9147
+ /**
9148
+ * The pallet's phantom timings, read from chain state.
9149
+ *
9150
+ * Both are governance-settable and neither is derivable: on Nexus today the window is 15 while
9151
+ * the runtime constant behind it is 25, so anything hard-coded is wrong in one direction or the
9152
+ * other — too tight and live orders are dropped, too loose and bids are sent into a closed
9153
+ * window for the pallet to reject.
9154
+ *
9155
+ * Read once per instance and cached, because a governance change to either is rare and a read
9156
+ * per poll tick would be a request per tick forever. The cost is that a change is picked up on
9157
+ * the next restart rather than immediately. A failed read is not cached, so it retries.
9158
+ */
9159
+ async phantomTimings() {
9160
+ if (!this.phantomTimingsRead) {
9161
+ this.phantomTimingsRead = this.readPhantomTimings().catch((err) => {
9162
+ this.phantomTimingsRead = null;
9163
+ throw err;
9164
+ });
9165
+ }
9166
+ return this.phantomTimingsRead;
9167
+ }
9168
+ async readPhantomTimings() {
9169
+ const api = await this.http();
9170
+ const [window, interval] = await Promise.all([
9171
+ api.query.intentsCoprocessor.phantomBidWindow(),
9172
+ api.query.intentsCoprocessor.phantomOrderInterval()
9173
+ ]);
9174
+ const stored = Number(window.toString());
9175
+ return {
9176
+ bidWindowBlocks: stored === 0 ? Number(api.consts.intentsCoprocessor.phantomOrderBidWindowBlocks.toString()) : stored,
9177
+ intervalBlocks: Number(interval.toString())
9178
+ };
9179
+ }
9180
+ /**
9181
+ * A whole range of blocks in one `state_queryStorage` call, or `null` when that is not available
9182
+ * and the caller should read block by block.
9183
+ *
9184
+ * Two conditions have to hold, and both are about decoding rather than the range itself.
9185
+ *
9186
+ * The version must be confirmed for this tick — an upgrade inside the range means blocks decode
9187
+ * against different metadata, and one call cannot do that.
9188
+ *
9189
+ * And that confirmed version must still be the one the api's own registry was built for.
9190
+ * `state_queryStorage` declares no historic block hash, so rpc-core skips its registry swap and
9191
+ * decodes the reply against the default registry — fixed at connect, with no
9192
+ * `subscribeRuntimeVersion` on an HTTP api to refresh it. After an upgrade the two diverge, and
9193
+ * the per-block path takes over for good: `api.at(hash, version)` resolves, and builds, the right
9194
+ * registry. That costs a restart to get the cheap path back, which is the correct direction to
9195
+ * fail in.
9196
+ */
9197
+ async scanRangeAtOnce(api, from, to, knownVersion, onError) {
9198
+ if (this.rangeQueryUnavailable || !knownVersion) return null;
9199
+ const registryVersion = api.runtimeVersion?.specVersion;
9200
+ if (!registryVersion || !knownVersion.specVersion.eq(registryVersion)) return null;
9201
+ const [fromHash, toHash] = from === to ? await Promise.all([api.rpc.chain.getBlockHash(from)]).then(([only]) => [only, only]) : await Promise.all([api.rpc.chain.getBlockHash(from), api.rpc.chain.getBlockHash(to)]);
9202
+ try {
9203
+ return await this.getPhantomOrdersInRange(fromHash.toHex(), toHash.toHex());
9204
+ } catch (err) {
9205
+ if (isMethodUnavailable(err)) {
9206
+ this.rangeQueryUnavailable = true;
9207
+ return null;
9208
+ }
9209
+ if (err instanceof EventDecodeError) {
9210
+ this.rangeQueryUnavailable = true;
9211
+ onError?.(err);
9212
+ return null;
9213
+ }
9214
+ throw err;
9215
+ }
9216
+ }
9217
+ /**
9218
+ * The runtime version this tick's blocks may be decoded against, or `undefined` when that cannot
9219
+ * be established and each block must resolve its own.
9220
+ *
9221
+ * Naming a version to `api.at` is what removes two of the four RPCs a block scan costs, and it
9222
+ * is only sound while the version is actually the block's. Getting that wrong is not a loud
9223
+ * failure: events decoded against the wrong metadata come back as a shape the scan does not
9224
+ * recognise, so the block reads as carrying no phantom orders and the cursor advances past it —
9225
+ * exactly the silent miss the block cursor exists to rule out.
9226
+ *
9227
+ * So the version is read fresh each tick and only used when it matches the previous reading.
9228
+ * `specVersion` only ever increases, and this read happens *after* the head read, so two equal
9229
+ * readings mean no upgrade landed anywhere in between — and therefore none in the range about to
9230
+ * be scanned. A reading that differs means an upgrade landed inside the range: that tick falls
9231
+ * back to per-block resolution, which is exact, and the version is used from the next tick on
9232
+ * once it has been seen twice.
9233
+ *
9234
+ * The gap this leaves is a backlog reaching back past an upgrade, whose oldest blocks predate
9235
+ * even the previous reading. Recovering from an outage that long means those bid windows closed
9236
+ * many upgrades ago, so nothing is lost that was still winnable.
9237
+ *
9238
+ * A version that cannot be read at all yields `undefined` rather than an error: the scan is
9239
+ * about to make the same request against the same endpoint and is the better place to report it.
9240
+ */
9241
+ async confirmedRuntimeVersion() {
9242
+ let api;
9243
+ let current;
9244
+ try {
9245
+ api = await this.http();
9246
+ current = await api.rpc.state.getRuntimeVersion();
9247
+ } catch {
9248
+ return void 0;
9249
+ }
9250
+ const previous = this.lastRuntimeVersion ?? api.runtimeVersion;
9251
+ this.lastRuntimeVersion = current;
9252
+ if (!previous?.specVersion || !previous?.specName) return void 0;
9253
+ return current.specVersion.eq(previous.specVersion) && current.specName.eq(previous.specName) ? current : void 0;
9254
+ }
8712
9255
  /**
8713
9256
  * The poll cadence for the runtime this instance is connected to: Gargantua polls every block,
8714
9257
  * everything else every 15s. Falls back to the slower cadence if the runtime cannot be read,
@@ -12140,40 +12683,17 @@ query AvailableLiquidity(
12140
12683
  }
12141
12684
  }`;
12142
12685
  var BUY_AND_SELL_RATES = `
12143
- query BuyAndSellRates(
12144
- $poolId: String!
12145
- $directChain: String!
12146
- $directDirection: String!
12147
- $reverseChain: String!
12148
- $reverseDirection: String!
12149
- ) {
12150
- direct: poolChainLiquidities(
12151
- filter: {
12152
- and: [
12153
- { poolId: { equalToInsensitive: $poolId } }
12154
- { chain: { equalTo: $directChain } }
12155
- { direction: { equalTo: $directDirection } }
12156
- ]
12157
- }
12686
+ query GetLiquidityPoolRate($poolId: String!) {
12687
+ liquidityPools(
12158
12688
  first: 1
12689
+ filter: { id: { equalToInsensitive: $poolId } }
12159
12690
  ) {
12160
12691
  nodes {
12161
- rate
12162
- lastUpdatedAt
12163
- }
12164
- }
12165
- reverse: poolChainLiquidities(
12166
- filter: {
12167
- and: [
12168
- { poolId: { equalToInsensitive: $poolId } }
12169
- { chain: { equalTo: $reverseChain } }
12170
- { direction: { equalTo: $reverseDirection } }
12171
- ]
12172
- }
12173
- first: 1
12174
- ) {
12175
- nodes {
12176
- rate
12692
+ id
12693
+ token0Symbol
12694
+ token1Symbol
12695
+ sellRate
12696
+ buyRate
12177
12697
  lastUpdatedAt
12178
12698
  }
12179
12699
  }
@@ -17119,6 +17639,115 @@ var OrderCanceller = class _OrderCanceller {
17119
17639
  return feeInDestFeeToken * 1005n / 1000n;
17120
17640
  }
17121
17641
  };
17642
+ var FILL_ORDER_V1_ABI = [
17643
+ {
17644
+ type: "function",
17645
+ name: "fillOrder",
17646
+ stateMutability: "payable",
17647
+ outputs: [],
17648
+ inputs: [
17649
+ ABI3.find((e) => e.type === "function" && e.name === "fillOrder").inputs[0],
17650
+ {
17651
+ name: "options",
17652
+ type: "tuple",
17653
+ internalType: "struct FillOptions",
17654
+ components: [
17655
+ { name: "relayerFee", type: "uint256", internalType: "uint256" },
17656
+ { name: "nativeDispatchFee", type: "uint256", internalType: "uint256" },
17657
+ {
17658
+ name: "outputs",
17659
+ type: "tuple[]",
17660
+ internalType: "struct TokenInfo[]",
17661
+ components: [
17662
+ { name: "token", type: "bytes32", internalType: "bytes32" },
17663
+ { name: "amount", type: "uint256", internalType: "uint256" }
17664
+ ]
17665
+ }
17666
+ ]
17667
+ }
17668
+ ]
17669
+ }
17670
+ ];
17671
+ var ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
17672
+ var LEGACY_FILL_OPTIONS_IMPLEMENTATIONS = /* @__PURE__ */ new Set([
17673
+ // The pre-validUntil IntentGatewayV2 implementation. One entry covers every chain: the
17674
+ // protocol contracts are CREATE2-deployed, so this is the implementation address on all
17675
+ // of them (confirmed with the maintainers).
17676
+ "0x976b268b06f545c4a2bf44866aa2465bd8b3c67d"
17677
+ ]);
17678
+ var CHAINS_WITHOUT_VALID_UNTIL = /* @__PURE__ */ new Set([
17679
+ 97,
17680
+ // BNB testnet
17681
+ 10200,
17682
+ // Gnosis Chiado
17683
+ 80002,
17684
+ // Polygon Amoy
17685
+ 84532,
17686
+ // Base Sepolia
17687
+ 421614,
17688
+ // Arbitrum Sepolia
17689
+ 688689,
17690
+ // Pharos testnet
17691
+ 11155111,
17692
+ // Sepolia
17693
+ 11155420,
17694
+ // Optimism Sepolia
17695
+ 420420417
17696
+ // Polkadot Hub Paseo
17697
+ ]);
17698
+ var knownV2Gateways = /* @__PURE__ */ new Set();
17699
+ function resetFillOptionsVersionCache() {
17700
+ knownV2Gateways.clear();
17701
+ }
17702
+ async function resolveImplementation(client, gateway) {
17703
+ const slot = await client.getStorageAt({ address: gateway, slot: ERC1967_IMPLEMENTATION_SLOT });
17704
+ if (!slot || slot.length < 66) return gateway;
17705
+ const addr = `0x${slot.slice(-40)}`;
17706
+ return /^0x0{40}$/.test(addr) ? gateway : addr;
17707
+ }
17708
+ async function getFillOptionsVersion(client, gateway) {
17709
+ const chainId = client.chain?.id;
17710
+ if (chainId !== void 0 && CHAINS_WITHOUT_VALID_UNTIL.has(chainId)) return 1;
17711
+ const key = gateway.toLowerCase();
17712
+ if (knownV2Gateways.has(key)) return 2;
17713
+ const implementation = await resolveImplementation(client, gateway);
17714
+ if (LEGACY_FILL_OPTIONS_IMPLEMENTATIONS.has(implementation.toLowerCase())) return 1;
17715
+ knownV2Gateways.add(key);
17716
+ return 2;
17717
+ }
17718
+ function encodeFillOrder(order, options, version) {
17719
+ if (version === 2) {
17720
+ return encodeFunctionData({
17721
+ abi: ABI3,
17722
+ functionName: "fillOrder",
17723
+ args: [order, options]
17724
+ });
17725
+ }
17726
+ const { relayerFee, nativeDispatchFee, outputs } = options;
17727
+ return encodeFunctionData({
17728
+ abi: FILL_ORDER_V1_ABI,
17729
+ functionName: "fillOrder",
17730
+ args: [order, { relayerFee, nativeDispatchFee, outputs }]
17731
+ });
17732
+ }
17733
+ function decodeFillOrder(data) {
17734
+ try {
17735
+ const decoded = decodeFunctionData({ abi: ABI3, data });
17736
+ if (decoded.functionName === "fillOrder" && decoded.args && decoded.args.length >= 2) {
17737
+ return { order: decoded.args[0], options: decoded.args[1] };
17738
+ }
17739
+ } catch {
17740
+ }
17741
+ try {
17742
+ const decoded = decodeFunctionData({ abi: FILL_ORDER_V1_ABI, data });
17743
+ if (decoded.functionName === "fillOrder" && decoded.args && decoded.args.length >= 2) {
17744
+ const legacy = decoded.args[1];
17745
+ return { order: decoded.args[0], options: { ...legacy, validUntil: 0n } };
17746
+ }
17747
+ } catch {
17748
+ }
17749
+ return null;
17750
+ }
17122
17751
  var BidImpl = class {
17123
17752
  solverAddress;
17124
17753
  outputs;
@@ -17549,19 +18178,9 @@ var BidManager = class {
17549
18178
  const innerCalls = this.crypto.decodeERC7821Execute(bid.userOp.callData);
17550
18179
  if (!innerCalls || innerCalls.length === 0) return null;
17551
18180
  for (const call of innerCalls) {
17552
- try {
17553
- const decoded = decodeFunctionData({
17554
- abi: ABI3,
17555
- data: call.data
17556
- });
17557
- if (decoded?.functionName === "fillOrder" && decoded.args && decoded.args.length >= 2) {
17558
- const fillOptions = decoded.args[1];
17559
- if (fillOptions?.outputs?.length > 0) {
17560
- return fillOptions;
17561
- }
17562
- }
17563
- } catch {
17564
- continue;
18181
+ const decoded = decodeFillOrder(call.data);
18182
+ if (decoded && decoded.options?.outputs?.length > 0) {
18183
+ return decoded.options;
17565
18184
  }
17566
18185
  }
17567
18186
  } catch {
@@ -17939,6 +18558,10 @@ var GasEstimator = class {
17939
18558
  relayerFee: crossChainFees.postRequestFee,
17940
18559
  // Always dispatch with the fee token (see the method docs).
17941
18560
  nativeDispatchFee: 0n,
18561
+ // Unbounded for estimation: this call is simulated, never submitted, and a real
18562
+ // bound here would only risk the estimate reverting on a slow bundler round trip.
18563
+ // The caller sets the real one on the options it actually signs.
18564
+ validUntil: 0n,
17942
18565
  outputs: order.output.assets.map((asset) => ({
17943
18566
  ...asset,
17944
18567
  token: normalizeAddressForEvmBytes32(asset.token)
@@ -17951,11 +18574,12 @@ var GasEstimator = class {
17951
18574
  let maxFeePerGas = gasPrice + gasPrice * BigInt(maxFeeBumpPercent) / 100n;
17952
18575
  const orderForEstimation = { ...order, session: solverAccountAddress };
17953
18576
  const commitment = orderCommitment(orderForEstimation);
17954
- const fillOrderCalldata = encodeFunctionData({
17955
- abi: ABI3,
17956
- functionName: "fillOrder",
17957
- args: [transformOrderForContract(orderForEstimation), fillOptions]
17958
- });
18577
+ const fillOptionsVersion = await getFillOptionsVersion(this.ctx.dest.client, intentGatewayV2Address);
18578
+ const fillOrderCalldata = encodeFillOrder(
18579
+ transformOrderForContract(orderForEstimation),
18580
+ fillOptions,
18581
+ fillOptionsVersion
18582
+ );
17959
18583
  let callGasLimit = 500000n;
17960
18584
  let verificationGasLimit = 100000n;
17961
18585
  let preVerificationGas = 100000n;
@@ -18395,29 +19019,29 @@ var LiquidityEngine = class {
18395
19019
  };
18396
19020
  }
18397
19021
  /**
18398
- * Returns chain-specific buy and sell rates in less-valued quote-token units
18399
- * per one base token.
19022
+ * Returns the indexed pool's aggregate buy and sell rates in less-valued
19023
+ * quote-token units per one base token.
18400
19024
  *
18401
- * The requested direction is read on the destination chain; its reverse is
18402
- * read on the source chain. This mirrors where each direction's output token
18403
- * must be delivered for a cross-chain trade.
19025
+ * The indexer depth-weights fresh per-chain samples into the pool rates. The
19026
+ * source and destination chains remain part of the result because they define
19027
+ * the cross-chain route whose configured token symbols were resolved.
18404
19028
  */
18405
19029
  async getBuyAndSellRates(params) {
18406
19030
  const pool = resolveLiquidityPool(params.tokenInSymbol, params.tokenOutSymbol);
18407
- const directDirection = params.tokenInSymbol.toLowerCase() === pool.token0Symbol.toLowerCase() ? SELL : BUY;
18408
- const reverseDirection = directDirection === SELL ? BUY : SELL;
18409
19031
  const response = await this.queryClient.request(BUY_AND_SELL_RATES, {
18410
- poolId: pool.poolId,
18411
- directChain: params.destinationChain,
18412
- directDirection,
18413
- reverseChain: params.sourceChain,
18414
- reverseDirection
19032
+ poolId: pool.poolId
18415
19033
  });
18416
- if (!response?.direct?.nodes || !response?.reverse?.nodes) {
18417
- throw new InvalidLiquidityIndexerResponseError("rate connections are missing");
18418
- }
18419
- const direct = readIndexedRate(response.direct.nodes[0], "direct rate");
18420
- const reverse = readIndexedRate(response.reverse.nodes[0], "reverse rate");
19034
+ if (!response?.liquidityPools?.nodes) {
19035
+ throw new InvalidLiquidityIndexerResponseError("liquidity pool connection is missing");
19036
+ }
19037
+ const indexedPool = response.liquidityPools.nodes[0];
19038
+ if (!indexedPool) return void 0;
19039
+ validateIndexedPool(indexedPool, pool);
19040
+ const sell = readIndexedRate(indexedPool.sellRate, indexedPool.lastUpdatedAt, "pool sell rate");
19041
+ const buy = readIndexedRate(indexedPool.buyRate, indexedPool.lastUpdatedAt, "pool buy rate");
19042
+ const inputIsToken0 = params.tokenInSymbol.toLowerCase() === pool.token0Symbol.toLowerCase();
19043
+ const direct = inputIsToken0 ? sell : buy;
19044
+ const reverse = inputIsToken0 ? buy : sell;
18421
19045
  if (!direct && !reverse) return void 0;
18422
19046
  const quoteTokenSymbol = resolveQuoteTokenSymbol(
18423
19047
  params.tokenInSymbol,
@@ -18426,17 +19050,17 @@ var LiquidityEngine = class {
18426
19050
  reverse?.scaledRate
18427
19051
  );
18428
19052
  const quoteIsTokenOut = quoteTokenSymbol === params.tokenOutSymbol;
18429
- const buy = quoteIsTokenOut ? direct : reverse;
18430
- const sell = quoteIsTokenOut ? reverse : direct;
19053
+ const orientedBuy = quoteIsTokenOut ? direct : reverse;
19054
+ const orientedSell = quoteIsTokenOut ? reverse : direct;
18431
19055
  return {
18432
19056
  baseTokenSymbol: quoteIsTokenOut ? params.tokenInSymbol : params.tokenOutSymbol,
18433
19057
  quoteTokenSymbol,
18434
19058
  sourceChain: params.sourceChain,
18435
19059
  destinationChain: params.destinationChain,
18436
- buyRate: buy ? formatUnits(buy.scaledRate, INDEXER_FIXED_POINT_DECIMALS) : null,
18437
- sellRate: sell ? formatUnits(reciprocalRate(sell.scaledRate, "sell rate"), INDEXER_FIXED_POINT_DECIMALS) : null,
18438
- buyRateUpdatedAt: buy?.updatedAt ?? null,
18439
- sellRateUpdatedAt: sell?.updatedAt ?? null
19060
+ buyRate: orientedBuy ? formatUnits(orientedBuy.scaledRate, INDEXER_FIXED_POINT_DECIMALS) : null,
19061
+ sellRate: orientedSell ? formatUnits(reciprocalRate(orientedSell.scaledRate, "sell rate"), INDEXER_FIXED_POINT_DECIMALS) : null,
19062
+ buyRateUpdatedAt: orientedBuy?.updatedAt ?? null,
19063
+ sellRateUpdatedAt: orientedSell?.updatedAt ?? null
18440
19064
  };
18441
19065
  }
18442
19066
  };
@@ -18478,20 +19102,25 @@ function readIndexerDate(value, label) {
18478
19102
  if (Number.isNaN(date.getTime())) throw new InvalidLiquidityIndexerResponseError(`${label} is invalid`);
18479
19103
  return date;
18480
19104
  }
18481
- function readIndexedRate(node, label) {
18482
- if (!node) return void 0;
19105
+ function readIndexedRate(value, lastUpdatedAt, label) {
19106
+ if (value === null) return void 0;
18483
19107
  try {
18484
- const scaledRate = BigInt(node.rate);
19108
+ const scaledRate = BigInt(value);
18485
19109
  if (scaledRate <= 0n) throw new Error();
18486
19110
  return {
18487
19111
  scaledRate,
18488
- updatedAt: readIndexerDate(node.lastUpdatedAt, `${label} lastUpdatedAt`)
19112
+ updatedAt: readIndexerDate(lastUpdatedAt, `${label} lastUpdatedAt`)
18489
19113
  };
18490
19114
  } catch (error) {
18491
19115
  if (error instanceof InvalidLiquidityIndexerResponseError) throw error;
18492
19116
  throw new InvalidLiquidityIndexerResponseError(`${label} is not a positive integer`);
18493
19117
  }
18494
19118
  }
19119
+ function validateIndexedPool(indexedPool, expected) {
19120
+ if (indexedPool.id.toLowerCase() !== expected.poolId.toLowerCase() || indexedPool.token0Symbol.toLowerCase() !== expected.token0Symbol.toLowerCase() || indexedPool.token1Symbol.toLowerCase() !== expected.token1Symbol.toLowerCase()) {
19121
+ throw new InvalidLiquidityIndexerResponseError(`pool identity does not match ${expected.poolId}`);
19122
+ }
19123
+ }
18495
19124
  function resolveQuoteTokenSymbol(tokenInSymbol, tokenOutSymbol, directRate, reverseRate) {
18496
19125
  const inputIsUsdStable = USD_STABLE_SYMBOLS.has(tokenInSymbol);
18497
19126
  const outputIsUsdStable = USD_STABLE_SYMBOLS.has(tokenOutSymbol);
@@ -18501,7 +19130,8 @@ function resolveQuoteTokenSymbol(tokenInSymbol, tokenOutSymbol, directRate, reve
18501
19130
  throw new InvalidLiquidityIndexerResponseError("cannot orient an empty rate pair");
18502
19131
  }
18503
19132
  function reciprocalRate(rate, label) {
18504
- const reciprocal = POOL_RATE_SCALE * POOL_RATE_SCALE / rate;
19133
+ const numerator = POOL_RATE_SCALE * POOL_RATE_SCALE;
19134
+ const reciprocal = (numerator + rate - 1n) / rate;
18505
19135
  if (reciprocal <= 0n) throw new InvalidLiquidityIndexerResponseError(`${label} reciprocal underflowed`);
18506
19136
  return reciprocal;
18507
19137
  }
@@ -18533,6 +19163,20 @@ var InvalidPhantomSnapshotError = class extends Error {
18533
19163
  this.name = "InvalidPhantomSnapshotError";
18534
19164
  }
18535
19165
  };
19166
+ var IndexedRateUnavailableError = class extends Error {
19167
+ constructor(params) {
19168
+ const route = params.source && params.destination && params.tokenIn && params.tokenOut ? ` for ${params.tokenIn} -> ${params.tokenOut} on ${params.source} -> ${params.destination}` : "";
19169
+ const side = params.side ? ` ${params.side}` : "";
19170
+ super(`No indexed${side} rate available${route}`);
19171
+ this.name = "IndexedRateUnavailableError";
19172
+ }
19173
+ };
19174
+ var InvalidIndexedRateError = class extends Error {
19175
+ constructor(reason) {
19176
+ super(`Invalid indexed intent rate: ${reason}`);
19177
+ this.name = "InvalidIndexedRateError";
19178
+ }
19179
+ };
18536
19180
  var BPS_DENOMINATOR = 10000n;
18537
19181
  function validateQuoteParams(params) {
18538
19182
  const hasAmountIn = params.amountIn !== void 0;
@@ -18899,9 +19543,142 @@ function isSupportedSnapshotPair(tokenA, tokenB) {
18899
19543
  function isConfiguredAddress(address) {
18900
19544
  return Boolean(address && address !== "0x" && !/^0x0{40}$/i.test(address));
18901
19545
  }
19546
+ var INDEXED_RATE_DECIMALS = 18;
19547
+ var INDEXED_RATE_SCALE = 10n ** BigInt(INDEXED_RATE_DECIMALS);
19548
+ var IndexedRateIntentQuoteStrategy = class {
19549
+ constructor(chainConfigService, getQueryClient) {
19550
+ this.chainConfigService = chainConfigService;
19551
+ this.getQueryClient = getQueryClient;
19552
+ }
19553
+ chainConfigService;
19554
+ getQueryClient;
19555
+ async quote(params, source, destination) {
19556
+ validateQuoteParams(params);
19557
+ const sourceConfig = getConfigByStateMachineId(source.stateMachineId);
19558
+ const destinationConfig = getConfigByStateMachineId(destination.stateMachineId);
19559
+ if (!sourceConfig) throw new UnsupportedLiquidityChainError(source.stateMachineId);
19560
+ if (!destinationConfig) throw new UnsupportedLiquidityChainError(destination.stateMachineId);
19561
+ const tokenIn = this.resolveAsset(sourceConfig.stateMachineId, params.tokenIn);
19562
+ const tokenOut = this.resolveAsset(destinationConfig.stateMachineId, params.tokenOut);
19563
+ const [protocolFeeBps, rates] = await Promise.all([
19564
+ readProtocolFeeBps(this.chainConfigService, source),
19565
+ new LiquidityEngine(this.getQueryClient()).getBuyAndSellRates({
19566
+ sourceChain: sourceConfig.stateMachineId,
19567
+ destinationChain: destinationConfig.stateMachineId,
19568
+ tokenInSymbol: tokenIn.symbol,
19569
+ tokenOutSymbol: tokenOut.symbol
19570
+ })
19571
+ ]);
19572
+ if (!rates) {
19573
+ throw new IndexedRateUnavailableError({
19574
+ source: sourceConfig.stateMachineId,
19575
+ destination: destinationConfig.stateMachineId,
19576
+ tokenIn: tokenIn.symbol,
19577
+ tokenOut: tokenOut.symbol
19578
+ });
19579
+ }
19580
+ const selectedRate = selectIndexedRate(rates, tokenIn.symbol, tokenOut.symbol);
19581
+ return quoteWithIndexedRate(params, tokenIn, tokenOut, selectedRate, rates, protocolFeeBps);
19582
+ }
19583
+ resolveAsset(chain, address) {
19584
+ const asset = this.chainConfigService.getAssetMetadataByAddress(chain, address);
19585
+ if (!asset) throw new UnsupportedLiquidityAssetError(chain, address);
19586
+ const { decimals } = asset;
19587
+ if (decimals === void 0 || !Number.isSafeInteger(decimals) || decimals < 0) {
19588
+ throw new InvalidIndexedRateError(`decimals are not configured for ${asset.symbol} on ${chain}`);
19589
+ }
19590
+ return { ...asset, decimals };
19591
+ }
19592
+ };
19593
+ function selectIndexedRate(rates, tokenInSymbol, tokenOutSymbol) {
19594
+ if (tokenInSymbol === rates.baseTokenSymbol && tokenOutSymbol === rates.quoteTokenSymbol) {
19595
+ return readIndexedRate2(
19596
+ "buy",
19597
+ rates.buyRate,
19598
+ rates.buyRateUpdatedAt,
19599
+ rates,
19600
+ tokenInSymbol,
19601
+ tokenOutSymbol
19602
+ );
19603
+ }
19604
+ if (tokenInSymbol === rates.quoteTokenSymbol && tokenOutSymbol === rates.baseTokenSymbol) {
19605
+ return readIndexedRate2(
19606
+ "sell",
19607
+ rates.sellRate,
19608
+ rates.sellRateUpdatedAt,
19609
+ rates,
19610
+ tokenInSymbol,
19611
+ tokenOutSymbol
19612
+ );
19613
+ }
19614
+ throw new InvalidIndexedRateError(
19615
+ `indexed pair ${rates.baseTokenSymbol}/${rates.quoteTokenSymbol} does not match ${tokenInSymbol}/${tokenOutSymbol}`
19616
+ );
19617
+ }
19618
+ function readIndexedRate2(side, rate, updatedAt, rates, tokenInSymbol, tokenOutSymbol) {
19619
+ if (!rate || !updatedAt) {
19620
+ throw new IndexedRateUnavailableError({
19621
+ source: rates.sourceChain,
19622
+ destination: rates.destinationChain,
19623
+ tokenIn: tokenInSymbol,
19624
+ tokenOut: tokenOutSymbol,
19625
+ side
19626
+ });
19627
+ }
19628
+ try {
19629
+ const scaledRate = parseUnits(rate, INDEXED_RATE_DECIMALS);
19630
+ if (scaledRate <= 0n || Number.isNaN(updatedAt.getTime())) throw new Error();
19631
+ return { side, rate, scaledRate, updatedAt };
19632
+ } catch {
19633
+ throw new InvalidIndexedRateError(`${side} rate or timestamp is invalid`);
19634
+ }
19635
+ }
19636
+ function quoteWithIndexedRate(params, tokenIn, tokenOut, selectedRate, rates, protocolFeeBps) {
19637
+ const inputUnit = 10n ** BigInt(tokenIn.decimals);
19638
+ const outputUnit = 10n ** BigInt(tokenOut.decimals);
19639
+ if (params.amountIn !== void 0) {
19640
+ const netAmountIn2 = deductProtocolFee(params.amountIn, protocolFeeBps);
19641
+ const amountOut = selectedRate.side === "buy" ? netAmountIn2 * selectedRate.scaledRate * outputUnit / (inputUnit * INDEXED_RATE_SCALE) : netAmountIn2 * outputUnit * INDEXED_RATE_SCALE / (inputUnit * selectedRate.scaledRate);
19642
+ if (amountOut <= 0n) throw new InvalidIndexedRateError("quote rounds down to zero output");
19643
+ return buildResult("EXACT_INPUT", params.amountIn, amountOut, selectedRate, rates, protocolFeeBps);
19644
+ }
19645
+ if (params.amountOut === void 0) throw new Error("Quote amount is missing after validation");
19646
+ const netAmountIn = selectedRate.side === "buy" ? divCeil(params.amountOut * inputUnit * INDEXED_RATE_SCALE, selectedRate.scaledRate * outputUnit) : divCeil(params.amountOut * inputUnit * selectedRate.scaledRate, outputUnit * INDEXED_RATE_SCALE);
19647
+ const amountIn = grossUpForProtocolFee(netAmountIn, protocolFeeBps);
19648
+ return buildResult("EXACT_OUTPUT", amountIn, params.amountOut, selectedRate, rates, protocolFeeBps);
19649
+ }
19650
+ function buildResult(tradeType, amountIn, amountOut, selectedRate, rates, protocolFeeBps) {
19651
+ return {
19652
+ strategy: "indexed_rates",
19653
+ tradeType,
19654
+ amountIn,
19655
+ amountOut,
19656
+ quoteMetadata: {
19657
+ sourceChain: rates.sourceChain,
19658
+ destinationChain: rates.destinationChain,
19659
+ baseTokenSymbol: rates.baseTokenSymbol,
19660
+ quoteTokenSymbol: rates.quoteTokenSymbol,
19661
+ rateSide: selectedRate.side,
19662
+ rate: selectedRate.rate,
19663
+ rateUpdatedAt: selectedRate.updatedAt,
19664
+ protocolFeeBps
19665
+ }
19666
+ };
19667
+ }
18902
19668
 
18903
19669
  // src/protocols/intents/IntentGateway.ts
18904
- var CROSS_CHAIN_ORDER_FEE_GAS_PRICE_BUMP_PERCENT = 10n;
19670
+ var ORDER_FEE_GAS_PRICE_BUMP_POLICY = {
19671
+ defaultPercent: 10n,
19672
+ bySourceStateMachineId: {
19673
+ ["EVM-1" /* MAINNET */]: 50n
19674
+ }
19675
+ };
19676
+ function resolveOrderFeeGasPriceBump(sourceStateMachineId, isSameChain) {
19677
+ if (isSameChain) {
19678
+ return 0n;
19679
+ }
19680
+ return ORDER_FEE_GAS_PRICE_BUMP_POLICY.bySourceStateMachineId[sourceStateMachineId] ?? ORDER_FEE_GAS_PRICE_BUMP_POLICY.defaultPercent;
19681
+ }
18905
19682
  var IntentGateway = class _IntentGateway {
18906
19683
  /** EVM chain on which orders are placed and escrowed. */
18907
19684
  source;
@@ -18973,6 +19750,10 @@ var IntentGateway = class _IntentGateway {
18973
19750
  this.gasEstimator = gasEstimator;
18974
19751
  this._crypto = crypto;
18975
19752
  this.quoteStrategies = {
19753
+ indexed_rates: new IndexedRateIntentQuoteStrategy(
19754
+ dest.configService,
19755
+ () => this.requireIndexer().queryClient
19756
+ ),
18976
19757
  phantom_snapshot: new PhantomSnapshotIntentQuoteStrategy(
18977
19758
  dest.configService,
18978
19759
  () => this.requireIndexer().queryClient
@@ -19026,26 +19807,26 @@ var IntentGateway = class _IntentGateway {
19026
19807
  /**
19027
19808
  * Quotes an intent between this gateway's source and destination chains.
19028
19809
  *
19029
- * Uses the latest directional Phantom order price snapshot from the attached
19030
- * indexer by default. Pass `strategy: "uniswap_v4"` only when explicitly
19031
- * requesting a Uniswap quote. Provide exactly one of `amountIn` or `amountOut`.
19810
+ * Uses the indexer's latest aggregate directional pool rate by default. Pass
19811
+ * `strategy: "phantom_snapshot"` or `strategy: "uniswap_v4"` only when
19812
+ * explicitly requesting a legacy quote source. Provide exactly one of
19813
+ * `amountIn` or `amountOut`.
19032
19814
  *
19033
- * Both built-in strategies resolve their canonical market on Base,
19034
- * regardless of this gateway's destination chain. Returned
19815
+ * The gateway's source and destination chains resolve the configured order
19816
+ * tokens; the indexer supplies the depth-weighted pool rate. Returned
19035
19817
  * `amountIn`/`amountOut` already account for the gateway's protocol fee
19036
- * (`quoteMetadata.protocolFeeBps`), which the gateway deducts from order
19037
- * inputs; use the returned amounts directly when placing the order.
19818
+ * (`quoteMetadata.protocolFeeBps`), which the gateway deducts from order inputs.
19038
19819
  *
19039
19820
  * @param params - Token pair, amount, and optional strategy/pool overrides.
19040
19821
  * @returns The quoted amounts plus strategy-specific metadata.
19041
19822
  * @throws {UnsupportedIntentQuoteStrategyError} For unknown strategies.
19042
19823
  * @throws {UnsupportedIntentQuotePairError} When the selected strategy does not support the pair.
19043
- * @throws {PhantomSnapshotUnavailableError} When an eligible cNGN pair has no snapshot.
19824
+ * @throws {IndexedRateUnavailableError} When the requested direction has no indexed rate.
19044
19825
  */
19045
19826
  async quoteIntent(params) {
19046
19827
  const source = { stateMachineId: this.source.config.stateMachineId, client: this.source.client };
19047
19828
  const destination = { stateMachineId: this.dest.config.stateMachineId, client: this.dest.client };
19048
- const strategy = params.strategy ?? "phantom_snapshot";
19829
+ const strategy = params.strategy ?? "indexed_rates";
19049
19830
  const handler = this.quoteStrategies[strategy];
19050
19831
  if (!handler) throw new UnsupportedIntentQuoteStrategyError(strategy);
19051
19832
  return handler.quote({ ...params, strategy }, source, destination);
@@ -19085,9 +19866,9 @@ var IntentGateway = class _IntentGateway {
19085
19866
  });
19086
19867
  }
19087
19868
  /**
19088
- * Returns chain-specific buy and sell rates in less-valued quote-token units
19089
- * without requiring token addresses. Symbols are matched case-insensitively;
19090
- * chain IDs are numeric IDs for chains configured in the SDK.
19869
+ * Returns aggregate indexed pool buy and sell rates in less-valued quote-token
19870
+ * units without requiring token addresses. Symbols are matched
19871
+ * case-insensitively; chain IDs resolve configured token deployments.
19091
19872
  */
19092
19873
  async queryBuyAndSellRates(params) {
19093
19874
  const { queryClient } = this.requireIndexer();
@@ -19116,8 +19897,9 @@ var IntentGateway = class _IntentGateway {
19116
19897
  * **Yield/receive protocol:**
19117
19898
  * 1. If `order.fees` is unset or zero, prices the fee on an internal copy
19118
19899
  * via {@link quoteOrderFees}: same-chain fees are twice the fill-gas
19119
- * estimate without a gas-price bump; cross-chain gas is priced 10% above
19120
- * the live price before attaching (fill gas + the settlement relayer fee)
19900
+ * estimate without a gas-price bump; cross-chain order fees originating on
19901
+ * Ethereum price gas 50% above the live price, while other source chains use
19902
+ * 10%, before attaching (fill gas + the settlement relayer fee)
19121
19903
  * with a further 5% buffer over the whole sum — strictly above the solver's
19122
19904
  * unpadded requirement. Direct solver estimates remain unbumped. The wei
19123
19905
  * cost used for the `value` field receives a 2% buffer.
@@ -19487,7 +20269,8 @@ var IntentGateway = class _IntentGateway {
19487
20269
  * transaction (check the native balance).
19488
20270
  *
19489
20271
  * @param order - The order to quote. `order.fees` is ignored and not mutated.
19490
- * Gas prices used to derive cross-chain `fees` receive 10% SDK-only headroom.
20272
+ * Gas prices used to derive cross-chain `fees` receive 50% SDK-only headroom
20273
+ * when the source chain is Ethereum mainnet and 10% for other source chains.
19491
20274
  * Same-chain quotes and direct calls to {@link estimateFillOrder}, including
19492
20275
  * Simplex solver estimates, remain unbumped.
19493
20276
  *
@@ -19498,15 +20281,14 @@ var IntentGateway = class _IntentGateway {
19498
20281
  */
19499
20282
  async quoteOrderFees(order, options) {
19500
20283
  const isSameChain = this.source.config.stateMachineId === this.dest.config.stateMachineId;
20284
+ const orderFeeGasPriceBumpPercent = resolveOrderFeeGasPriceBump(this.source.config.stateMachineId, isSameChain);
19501
20285
  const estimate = await this.gasEstimator.estimateFillOrder(
19502
20286
  {
19503
20287
  order,
19504
20288
  maxPriorityFeePerGasBumpPercent: options?.maxPriorityFeePerGasBumpPercent,
19505
20289
  maxFeePerGasBumpPercent: options?.maxFeePerGasBumpPercent
19506
20290
  },
19507
- {
19508
- orderFeeGasPriceBumpPercent: isSameChain ? 0n : CROSS_CHAIN_ORDER_FEE_GAS_PRICE_BUMP_PERCENT
19509
- }
20291
+ { orderFeeGasPriceBumpPercent }
19510
20292
  );
19511
20293
  if (estimate.totalGasCostWei === 0n || estimate.totalGasInFeeToken === 0n) {
19512
20294
  throw new Error("Gas estimation failed");
@@ -19735,6 +20517,17 @@ function encodeAcceptedSourceChains(chains2) {
19735
20517
  function decodeAcceptedSourceChains(paymasterAndData) {
19736
20518
  return decodePhantomBidDeclaration(paymasterAndData).acceptedSources;
19737
20519
  }
20520
+ var UNISWAP_QUOTE_HAIRCUT_BPS = 10n;
20521
+ var PHANTOM_QUOTE_HAIRCUT_BPS = 5n;
20522
+ function haircut(amount, bps) {
20523
+ return amount * (10000n - bps) / 10000n;
20524
+ }
20525
+ function applyUniswapQuoteHaircut(amount) {
20526
+ return haircut(amount, UNISWAP_QUOTE_HAIRCUT_BPS);
20527
+ }
20528
+ function applyPhantomQuoteHaircut(amount) {
20529
+ return haircut(amount, PHANTOM_QUOTE_HAIRCUT_BPS);
20530
+ }
19738
20531
  FILL_ORDER_ABI.find(
19739
20532
  (item) => item?.type === "function" && item?.name === "fillOrder"
19740
20533
  )?.inputs?.[0];
@@ -24208,6 +25001,6 @@ async function teleportDot(param_) {
24208
25001
  return stream;
24209
25002
  }
24210
25003
 
24211
- export { ADDRESS_ZERO2 as ADDRESS_ZERO, BundlerMethod, ChainConfigService, Chains, CryptoUtils, DEFAULT_ADDRESS, DEFAULT_GRAFFITI, DOMAIN_TYPEHASH, DUMMY_PRIVATE_KEY, ERC20Method, ERC7821_BATCH_MODE, EvmChain, ABI as EvmHostABI, EvmLanguage, HyperClientStatus, HyperFungibleToken, HyperFungibleTokenABI, INCLUSION_TIMEOUT_MS, IntentGateway, ABI3 as IntentGatewayABI, IntentOrderStatus, IntentsCoprocessor, InvalidLiquidityIndexerResponseError, InvalidPhantomSnapshotError, IsmpClient, MOCK_ADDRESS, ORDER_V2_PARAM_TYPE, OrderStatus, OrderStatusChecker, PACKED_USEROP_TYPEHASH, PLACE_ORDER_SELECTOR, PhantomSnapshotUnavailableError, PharosChain, PolkadotHubChain, REQUEST_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, RESPONSE_COMMITMENTS_SLOT, RESPONSE_RECEIPTS_SLOT, RequestKind, RequestStatus, SELECT_SOLVER_TYPEHASH, STATE_COMMITMENTS_SLOT, SubstrateChain, Swap, TESTNET_CHAINS, TeleportStatus, TimeoutStatus, TokenGateway, TronChain, USE_ETHERSCAN_CHAINS, UnsupportedIntentQuotePairError, UnsupportedIntentQuoteStrategyError, UnsupportedLiquidityAssetError, UnsupportedLiquidityChainError, WrappedHyperFungibleTokenABI, __test, adjustDecimals, bytes20ToBytes32, bytes32ToBytes20, calculateAllowanceMappingLocation, calculateBalanceMappingLocation, chainConfigs, constructRedeemEscrowRequestBody, constructRefundEscrowRequestBody, convertCodecToIGetRequest, convertCodecToIProof, convertIGetRequestToCodec, convertIProofToCodec, convertStateIdToStateMachineId, convertStateMachineEnumToString, convertStateMachineIdToEnum, createEvmChain, createQueryClient, decodeAcceptedSourceChains, decodeERC7821ExecuteBatch, decodePhantomBidDeclaration, decodeUserOpScale, deriveHttpUrl, encodeAcceptedSourceChains, encodeERC7821ExecuteBatch, encodeISMPMessage, encodePhantomBidDeclaration, encodeStateMachineId, encodeUserOpScale, encodeWithdrawalRequest, estimateGasForPost, fetchPrice, fetchSourceProof, generateRootWithProof, getChainId, getConfigByStateMachineId, getContractCallInput, getContractCallInputs, getGasPriceFromEtherscan, getOrFetchStorageSlot, getOrderPlacedFromTx, getPostRequestEventFromTx, getPostResponseEventFromTx, getRequestCommitment, getStateCommitmentFieldSlot, getStateCommitmentSlot, getStorageSlot, getViemChain, hexToString, hyperbridgeAddress, maxBigInt, normalizeAddressForEvmBytes32, normalizeAddressForStateMachine, normalizeEvmAddress, normalizeEvmChainId, normalizeStateMachineId, orderCommitment, parseStateMachineId, pharosAtlantic, pharosMainnet, polkadotAssetHubPaseo, polkadotHubMainnet, poolSlug, postRequestCommitment, queryAssetTeleported, queryGetRequest, queryPostRequest, quoteUniswap, requestCommitmentKey, responseCommitmentKey, retryPromise, sortPoolSymbols, teleport, teleportDot, transformOrderForContract, tronChainIds, tronNile };
25004
+ export { ADDRESS_ZERO2 as ADDRESS_ZERO, BundlerMethod, CHAINS_WITHOUT_VALID_UNTIL, ChainConfigService, Chains, CryptoUtils, DEFAULT_ADDRESS, DEFAULT_GRAFFITI, DOMAIN_TYPEHASH, DUMMY_PRIVATE_KEY, ERC20Method, ERC7821_BATCH_MODE, EvmChain, ABI as EvmHostABI, EvmLanguage, FILL_ORDER_V1_ABI, HyperClientStatus, HyperFungibleToken, HyperFungibleTokenABI, INCLUSION_TIMEOUT_MS, IndexedRateUnavailableError, IntentGateway, ABI3 as IntentGatewayABI, IntentOrderStatus, IntentsCoprocessor, InvalidIndexedRateError, InvalidLiquidityIndexerResponseError, InvalidPhantomSnapshotError, IsmpClient, LEGACY_FILL_OPTIONS_IMPLEMENTATIONS, MOCK_ADDRESS, ORDER_V2_PARAM_TYPE, OrderStatus, OrderStatusChecker, PACKED_USEROP_TYPEHASH, PHANTOM_QUOTE_HAIRCUT_BPS, PLACE_ORDER_SELECTOR, PhantomSnapshotUnavailableError, PharosChain, PolkadotHubChain, REQUEST_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, RESPONSE_COMMITMENTS_SLOT, RESPONSE_RECEIPTS_SLOT, RequestKind, RequestStatus, SELECT_SOLVER_TYPEHASH, STATE_COMMITMENTS_SLOT, SubstrateChain, Swap, TESTNET_CHAINS, TeleportStatus, TimeoutStatus, TokenGateway, TronChain, UNISWAP_QUOTE_HAIRCUT_BPS, USE_ETHERSCAN_CHAINS, UnsupportedIntentQuotePairError, UnsupportedIntentQuoteStrategyError, UnsupportedLiquidityAssetError, UnsupportedLiquidityChainError, WrappedHyperFungibleTokenABI, __test, adjustDecimals, applyPhantomQuoteHaircut, applyUniswapQuoteHaircut, bytes20ToBytes32, bytes32ToBytes20, calculateAllowanceMappingLocation, calculateBalanceMappingLocation, chainConfigs, constructRedeemEscrowRequestBody, constructRefundEscrowRequestBody, convertCodecToIGetRequest, convertCodecToIProof, convertIGetRequestToCodec, convertIProofToCodec, convertStateIdToStateMachineId, convertStateMachineEnumToString, convertStateMachineIdToEnum, createEvmChain, createQueryClient, decodeAcceptedSourceChains, decodeERC7821ExecuteBatch, decodeFillOrder, decodePhantomBidDeclaration, decodeUserOpScale, deriveHttpUrl, encodeAcceptedSourceChains, encodeERC7821ExecuteBatch, encodeFillOrder, encodeISMPMessage, encodePhantomBidDeclaration, encodeStateMachineId, encodeUserOpScale, encodeWithdrawalRequest, estimateGasForPost, fetchPrice, fetchSourceProof, generateRootWithProof, getChainId, getConfigByStateMachineId, getContractCallInput, getContractCallInputs, getFillOptionsVersion, getGasPriceFromEtherscan, getOrFetchStorageSlot, getOrderPlacedFromTx, getPostRequestEventFromTx, getPostResponseEventFromTx, getRequestCommitment, getStateCommitmentFieldSlot, getStateCommitmentSlot, getStorageSlot, getViemChain, hexToString, hyperbridgeAddress, maxBigInt, normalizeAddressForEvmBytes32, normalizeAddressForStateMachine, normalizeEvmAddress, normalizeEvmChainId, normalizeStateMachineId, orderCommitment, parseStateMachineId, pharosAtlantic, pharosMainnet, polkadotAssetHubPaseo, polkadotHubMainnet, poolSlug, postRequestCommitment, queryAssetTeleported, queryGetRequest, queryPostRequest, quoteUniswap, requestCommitmentKey, resetFillOptionsVersionCache, responseCommitmentKey, retryPromise, sortPoolSymbols, teleport, teleportDot, transformOrderForContract, tronChainIds, tronNile };
24212
25005
  //# sourceMappingURL=index.js.map
24213
25006
  //# sourceMappingURL=index.js.map