@hyperbridge/simplex 0.16.13 → 0.17.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.
@@ -30656,7 +30656,8 @@ var init_asset_registry = __esm({
30656
30656
  ZARP: { resolve: (r7, chain2) => r7.getAssetBySymbol(chain2, "ZARP") },
30657
30657
  EURC: { resolve: (r7, chain2) => r7.getAssetBySymbol(chain2, "EURC") },
30658
30658
  XSGD: { resolve: (r7, chain2) => r7.getAssetBySymbol(chain2, "XSGD") },
30659
- TRYB: { resolve: (r7, chain2) => r7.getAssetBySymbol(chain2, "TRYB") }
30659
+ TRYB: { resolve: (r7, chain2) => r7.getAssetBySymbol(chain2, "TRYB") },
30660
+ BRIDGE: { resolve: (r7, chain2) => r7.getAssetBySymbol(chain2, "BRIDGE") }
30660
30661
  };
30661
30662
  USD_STABLE_SYMBOLS = /* @__PURE__ */ new Set(["USDC", "USDT", "DAI"]);
30662
30663
  ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
@@ -30755,7 +30756,7 @@ function assertPairSymbolsResolve(pairs, registry, chainNames) {
30755
30756
  const pairSymbols = new Set(pairs.flatMap((pair) => [pair.token0, pair.token1]));
30756
30757
  for (const pair of pairs) {
30757
30758
  for (const symbol3 of [pair.token0, pair.token1]) {
30758
- const resolvesSomewhere = chainNames.some((chainName) => registry.getAddress(symbol3, chainName) !== null);
30759
+ const resolvesSomewhere = chainNames.some((chainName2) => registry.getAddress(symbol3, chainName2) !== null);
30759
30760
  if (!resolvesSomewhere) {
30760
30761
  throw new Error(
30761
30762
  `pairs.${pair.token0}/${pair.token1}: '${symbol3}' does not resolve to a deployed contract on any configured chain`
@@ -30763,15 +30764,15 @@ function assertPairSymbolsResolve(pairs, registry, chainNames) {
30763
30764
  }
30764
30765
  }
30765
30766
  }
30766
- for (const chainName of chainNames) {
30767
+ for (const chainName2 of chainNames) {
30767
30768
  const addressOwner = /* @__PURE__ */ new Map();
30768
30769
  for (const symbol3 of pairSymbols) {
30769
- const address = registry.getAddress(symbol3, chainName)?.toLowerCase();
30770
+ const address = registry.getAddress(symbol3, chainName2)?.toLowerCase();
30770
30771
  if (!address) continue;
30771
30772
  const owner = addressOwner.get(address);
30772
30773
  if (owner && normalizeSymbol(owner) !== normalizeSymbol(symbol3)) {
30773
30774
  throw new Error(
30774
- `assets: '${symbol3}' and '${owner}' both resolve to ${address} on ${chainName} \u2014 symbols must map to distinct contracts`
30775
+ `assets: '${symbol3}' and '${owner}' both resolve to ${address} on ${chainName2} \u2014 symbols must map to distinct contracts`
30775
30776
  );
30776
30777
  }
30777
30778
  addressOwner.set(address, symbol3);
@@ -48802,11 +48803,11 @@ var init_esm2 = __esm({
48802
48803
  init_encodeFunctionData2();
48803
48804
  init_encodePacked2();
48804
48805
  init_parseEventLogs2();
48805
- init_isAddress2();
48806
48806
  init_defineChain2();
48807
48807
  init_concat2();
48808
48808
  init_isHex2();
48809
48809
  init_pad2();
48810
+ init_slice2();
48810
48811
  init_fromBytes2();
48811
48812
  init_fromHex2();
48812
48813
  init_toBytes2();
@@ -48814,6 +48815,7 @@ var init_esm2 = __esm({
48814
48815
  init_keccak2562();
48815
48816
  init_toEventSelector2();
48816
48817
  init_toFunctionSelector2();
48818
+ init_recoverAddress2();
48817
48819
  init_formatUnits2();
48818
48820
  init_parseUnits2();
48819
48821
  }
@@ -135098,21 +135100,21 @@ var init_upgrades = __esm({
135098
135100
  });
135099
135101
 
135100
135102
  // ../../node_modules/.pnpm/@polkadot+types-known@16.5.6/node_modules/@polkadot/types-known/util.js
135101
- function withNames(chainName, specName, fn) {
135102
- return fn(chainName.toString(), specName.toString());
135103
+ function withNames(chainName2, specName, fn) {
135104
+ return fn(chainName2.toString(), specName.toString());
135103
135105
  }
135104
135106
  function filterVersions(versions = [], specVersion) {
135105
135107
  return versions.filter(({ minmax: [min2, max3] }) => (min2 === void 0 || min2 === null || specVersion >= min2) && (max3 === void 0 || max3 === null || specVersion <= max3)).reduce((result, { types: types4 }) => ({ ...result, ...types4 }), {});
135106
135108
  }
135107
- function getSpecExtensions({ knownTypes: knownTypes2 }, chainName, specName) {
135108
- return withNames(chainName, specName, (c6, s4) => ({
135109
+ function getSpecExtensions({ knownTypes: knownTypes2 }, chainName2, specName) {
135110
+ return withNames(chainName2, specName, (c6, s4) => ({
135109
135111
  ...knownTypes2.typesBundle?.spec?.[s4]?.signedExtensions ?? {},
135110
135112
  ...knownTypes2.typesBundle?.chain?.[c6]?.signedExtensions ?? {}
135111
135113
  }));
135112
135114
  }
135113
- function getSpecTypes({ knownTypes: knownTypes2 }, chainName, specName, specVersion) {
135115
+ function getSpecTypes({ knownTypes: knownTypes2 }, chainName2, specName, specVersion) {
135114
135116
  const _specVersion = bnToBn(specVersion).toNumber();
135115
- return withNames(chainName, specName, (c6, s4) => ({
135117
+ return withNames(chainName2, specName, (c6, s4) => ({
135116
135118
  // The order here is always, based on -
135117
135119
  // - spec then chain
135118
135120
  // - typesBundle takes higher precedence
@@ -135126,23 +135128,23 @@ function getSpecTypes({ knownTypes: knownTypes2 }, chainName, specName, specVers
135126
135128
  ...knownTypes2.types ?? {}
135127
135129
  }));
135128
135130
  }
135129
- function getSpecHasher({ knownTypes: knownTypes2 }, chainName, specName) {
135130
- return withNames(chainName, specName, (c6, s4) => knownTypes2.hasher || knownTypes2.typesBundle?.chain?.[c6]?.hasher || knownTypes2.typesBundle?.spec?.[s4]?.hasher || null);
135131
+ function getSpecHasher({ knownTypes: knownTypes2 }, chainName2, specName) {
135132
+ return withNames(chainName2, specName, (c6, s4) => knownTypes2.hasher || knownTypes2.typesBundle?.chain?.[c6]?.hasher || knownTypes2.typesBundle?.spec?.[s4]?.hasher || null);
135131
135133
  }
135132
- function getSpecRpc({ knownTypes: knownTypes2 }, chainName, specName) {
135133
- return withNames(chainName, specName, (c6, s4) => ({
135134
+ function getSpecRpc({ knownTypes: knownTypes2 }, chainName2, specName) {
135135
+ return withNames(chainName2, specName, (c6, s4) => ({
135134
135136
  ...knownTypes2.typesBundle?.spec?.[s4]?.rpc ?? {},
135135
135137
  ...knownTypes2.typesBundle?.chain?.[c6]?.rpc ?? {}
135136
135138
  }));
135137
135139
  }
135138
- function getSpecRuntime({ knownTypes: knownTypes2 }, chainName, specName) {
135139
- return withNames(chainName, specName, (c6, s4) => ({
135140
+ function getSpecRuntime({ knownTypes: knownTypes2 }, chainName2, specName) {
135141
+ return withNames(chainName2, specName, (c6, s4) => ({
135140
135142
  ...knownTypes2.typesBundle?.spec?.[s4]?.runtime ?? {},
135141
135143
  ...knownTypes2.typesBundle?.chain?.[c6]?.runtime ?? {}
135142
135144
  }));
135143
135145
  }
135144
- function getSpecAlias({ knownTypes: knownTypes2 }, chainName, specName) {
135145
- return withNames(chainName, specName, (c6, s4) => ({
135146
+ function getSpecAlias({ knownTypes: knownTypes2 }, chainName2, specName) {
135147
+ return withNames(chainName2, specName, (c6, s4) => ({
135146
135148
  // as per versions, first spec, then chain then finally non-versioned
135147
135149
  ...knownTypes2.typesBundle?.spec?.[s4]?.alias ?? {},
135148
135150
  ...knownTypes2.typesBundle?.chain?.[c6]?.alias ?? {},
@@ -156390,7 +156392,7 @@ var require_isTime = __commonJS({
156390
156392
  hourFormat: "hour24",
156391
156393
  mode: "default"
156392
156394
  };
156393
- var formats = {
156395
+ var formats2 = {
156394
156396
  hour24: {
156395
156397
  default: /^([01]?[0-9]|2[0-3]):([0-5][0-9])$/,
156396
156398
  withSeconds: /^([01]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/,
@@ -156405,7 +156407,7 @@ var require_isTime = __commonJS({
156405
156407
  function isTime(input, options) {
156406
156408
  options = (0, _merge.default)(options, default_time_options);
156407
156409
  if (typeof input !== "string") return false;
156408
- return formats[options.hourFormat][options.mode].test(input);
156410
+ return formats2[options.hourFormat][options.mode].test(input);
156409
156411
  }
156410
156412
  module2.exports = exports2.default;
156411
156413
  module2.exports.default = exports2.default;
@@ -234901,6 +234903,10 @@ function createSessionKeyStorage(options = {}) {
234901
234903
  listSessionKeys
234902
234904
  });
234903
234905
  }
234906
+ async function signTypedDigest(domainSeparator2, structHash, privateKey) {
234907
+ const digest = keccak2563(concat3(["0x1901", domainSeparator2, structHash]));
234908
+ return privateKeyToAccount(privateKey).sign({ hash: digest });
234909
+ }
234904
234910
  function encodeERC7821ExecuteBatch(calls) {
234905
234911
  const executionData = encodeAbiParameters2(
234906
234912
  [{ type: "tuple[]", components: erc7281_default.ABI[1].components }],
@@ -235162,6 +235168,9 @@ function cancelFromSourceContext(order, commitment) {
235162
235168
  ]
235163
235169
  );
235164
235170
  }
235171
+ function supportedReleases(stateMachineId) {
235172
+ return TESTNET_CHAINS.has(stateMachineId) ? TESTNET_INTENTS_VERSIONS : [SUPPORTED_INTENTS_VERSION];
235173
+ }
235165
235174
  async function readContractVersion(client, address) {
235166
235175
  try {
235167
235176
  return await client.readContract({ address, abi: CONTRACT_VERSION_ABI, functionName: "version" });
@@ -235170,14 +235179,17 @@ async function readContractVersion(client, address) {
235170
235179
  throw error;
235171
235180
  }
235172
235181
  }
235173
- async function supportsRateFills(client, gateway) {
235174
- return await readContractVersion(client, gateway) === SUPPORTED_INTENTS_VERSION;
235182
+ async function supportsRateFills(client, gateway, stateMachineId) {
235183
+ const version17 = await readContractVersion(client, gateway);
235184
+ return supportedReleases(stateMachineId).some((release) => release === version17);
235175
235185
  }
235176
- async function assertGatewayRelease(client, gateway) {
235186
+ async function assertGatewayRelease(client, gateway, stateMachineId) {
235187
+ const supported = supportedReleases(stateMachineId);
235177
235188
  const version17 = await readContractVersion(client, gateway);
235178
- if (version17 === SUPPORTED_INTENTS_VERSION) return;
235189
+ if (supported.some((release) => release === version17)) return;
235190
+ const required2 = supported.join(" or ");
235179
235191
  throw new Error(
235180
- version17 === void 0 ? `IntentGateway ${gateway} reports no version(); this SDK requires release ${SUPPORTED_INTENTS_VERSION}` : `IntentGateway ${gateway} reports release ${String(version17)}; this SDK requires release ${SUPPORTED_INTENTS_VERSION}`
235192
+ version17 === void 0 ? `IntentGateway ${gateway} reports no version(); this SDK requires release ${required2}` : `IntentGateway ${gateway} reports release ${String(version17)}; this SDK requires release ${required2}`
235181
235193
  );
235182
235194
  }
235183
235195
  function isCanonicalEvmToken(token) {
@@ -235219,6 +235231,40 @@ function decodeFillOrder(data4) {
235219
235231
  return null;
235220
235232
  }
235221
235233
  }
235234
+ function readSelectionFormat(client, chainId, gateway) {
235235
+ const key = `${chainId}:${gateway.toLowerCase()}`;
235236
+ const cached = formats.get(key);
235237
+ if (cached) return cached;
235238
+ const format2 = client.readContract({ address: gateway, abi: ABI3, functionName: "SELECT_SOLVER_TYPEHASH" }).then((typehash) => {
235239
+ switch (typehash.toLowerCase()) {
235240
+ case SELECT_SOLVER_TYPEHASH:
235241
+ return "userOpHash";
235242
+ case LEGACY_SELECT_SOLVER_TYPEHASH:
235243
+ return "address";
235244
+ default:
235245
+ throw new Error(
235246
+ `IntentGatewayV2 ${gateway} on chain ${chainId} has unknown SELECT_SOLVER_TYPEHASH ${typehash}`
235247
+ );
235248
+ }
235249
+ });
235250
+ formats.set(key, format2);
235251
+ format2.catch(() => {
235252
+ if (formats.get(key) === format2) formats.delete(key);
235253
+ });
235254
+ return format2;
235255
+ }
235256
+ function refreshSelectionFormat(client, chainId, gateway, stale) {
235257
+ const key = `${chainId}:${gateway.toLowerCase()}`;
235258
+ if (formats.get(key) === stale) formats.delete(key);
235259
+ return readSelectionFormat(client, chainId, gateway);
235260
+ }
235261
+ async function selectionOffStateDiff(client, gateway) {
235262
+ const word = await client.getStorageAt({ address: gateway, slot: SELECTION_PARAMS_SLOT });
235263
+ return {
235264
+ slot: SELECTION_PARAMS_SLOT,
235265
+ value: toHex3(hexToBigInt2(word ?? "0x0") & SOLVER_SELECTION_CLEARED, { size: 32 })
235266
+ };
235267
+ }
235222
235268
  function userOperationLogs(logs, entryPoint, userOpHash) {
235223
235269
  const [beforeExecution, userOperationEvent] = ENTRY_POINT_EVENT_ABI.map((event) => toEventSelector2(event));
235224
235270
  const isBoundary = (log4) => log4.address.toLowerCase() === entryPoint.toLowerCase() && (log4.topics[0] === beforeExecution || log4.topics[0] === userOperationEvent);
@@ -235237,6 +235283,40 @@ function userOperationLogs(logs, entryPoint, userOpHash) {
235237
235283
  while (start >= 0 && !isBoundary(logs[start])) start--;
235238
235284
  return logs.slice(start + 1, end);
235239
235285
  }
235286
+ async function fetchRundlerPriorityFee(bundlerUrl) {
235287
+ if (bundlersWithoutRundlerFees.has(bundlerUrl)) return null;
235288
+ try {
235289
+ const response = await fetch(bundlerUrl, {
235290
+ method: "POST",
235291
+ headers: { "Content-Type": "application/json" },
235292
+ body: JSON.stringify({
235293
+ jsonrpc: "2.0",
235294
+ id: 1,
235295
+ method: BundlerMethod.RUNDLER_MAX_PRIORITY_FEE_PER_GAS,
235296
+ params: []
235297
+ })
235298
+ });
235299
+ const { result, error } = await response.json();
235300
+ if (error) {
235301
+ if (error.code !== void 0 && UNSUPPORTED_REQUEST_CODES.has(error.code)) {
235302
+ bundlersWithoutRundlerFees.add(bundlerUrl);
235303
+ }
235304
+ return null;
235305
+ }
235306
+ return result == null ? null : BigInt(result);
235307
+ } catch {
235308
+ return null;
235309
+ }
235310
+ }
235311
+ function applyRundlerPriorityFee(fees4, params) {
235312
+ const { rundlerPriorityFee, baseFeePerGas, priorityFeeBumpPercent, maxFeeBumpPercent } = params;
235313
+ const priorityFloor = rundlerPriorityFee + rundlerPriorityFee * priorityFeeBumpPercent / 100n;
235314
+ const maxFeeFloor = baseFeePerGas + baseFeePerGas * maxFeeBumpPercent / 100n + priorityFloor;
235315
+ return {
235316
+ maxPriorityFeePerGas: fees4.maxPriorityFeePerGas > priorityFloor ? fees4.maxPriorityFeePerGas : priorityFloor,
235317
+ maxFeePerGas: fees4.maxFeePerGas > maxFeeFloor ? fees4.maxFeePerGas : maxFeeFloor
235318
+ };
235319
+ }
235240
235320
  function escrowSlot(commitment, leg) {
235241
235321
  const byCommitment = keccak2563(
235242
235322
  encodeAbiParameters2([{ type: "bytes32" }, { type: "uint256" }], [commitment, ESCROW_MAPPING_SLOT])
@@ -235422,7 +235502,7 @@ function encodePhantomBidDeclaration(declaration) {
235422
235502
  }
235423
235503
  return u8aToHex(new Uint8Array(bytes5));
235424
235504
  }
235425
- var import_merge_race, __defProp3, __getOwnPropNames2, __esm2, __export2, node_exports, wasm, full_path, __dirname$1, cachedTextDecoder, cachedUint8ArrayMemory0, WASM_VECTOR_LEN, cachedTextEncoder, encodeString5, cachedDataViewMemory0, KeccakMergeFinalization, KeccakMerge, wasmPath, wasmBytes2, bindings, wasmModule, wasmInstance, __wasm, init_node11, RequestStatus, TimeoutStatus, IntentOrderStatus, ABI, evmHost_default, ABI2, handlerV2_default, polkadotAssetHubPaseo, polkadotHubMainnet, pharosMainnet, pharosAtlantic, tronNile, chainConfigs, configsByStateMachineId, getConfigByStateMachineId, getChainId3, getViemChain, hyperbridgeAddress, ABI3, IntentGatewayV2_default, ChainConfigService, ABI4, uniswapRouterV2_default, chains, DEFAULT_ADDRESS, EvmChain, REQUEST_COMMITMENTS_SLOT, RESPONSE_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, STATE_COMMITMENTS_SLOT, MISSING_CONSENSUS_UPDATE_TIME_MESSAGE, MissingConsensusUpdateTimeError, TokenBucket, BATCHES_NOT_SUPPORTED_CODE, TOO_BIG_BATCH_REQUEST_CODE, DEFAULT_MAX_BATCH_SIZE, _endpoint2, _headers3, _limiter, _maxBatchSize, _batchingSupported, _pending2, _flushTimer, _flushing, _nextId, __BatchingHttpProvider_instances, scheduleFlush_fn, flushNow_fn, flush_fn, post_fn, settleBatch_fn, settle_fn, handleBatchRefusal_fn, requeue_fn, _a5, BatchingHttpProvider, OFFCHAIN_BID_PREFIX, HYPERBRIDGE_TYPES_BUNDLE, BASE_TIP, HTTP_CONNECT_TIMEOUT_MS, INCLUSION_TIMEOUT_MS, DEFAULT_RPC_MAX_RPS, rpcLimiters, BidCodec, PackedUserOperationCodec, IntentsCoprocessor, ReviveContractInfo, ReviveAccountType, ReviveAccountInfo, H256, EvmStateProof, SubstrateHashing, SubstrateStateMachineProof, BasicProof, LeafIndexAndPos, MmrProof, ConsensusStateId, ConsensusMessage, FraudProofMessage, StateMachine, StateMachineId, StateMachineHeight, Proof, PostRequest, PostResponse, GetRequest, StorageValue, GetResponse, Request3, Response2, RequestMessage, RequestResponse, ResponseMessage, TimeoutMessage, GetRequestsWithProof, Message, DEFAULT_CHILD_STORAGE_PREFIX, PharosProofNodeCodec, SiblingLeftmostLeafProofCodec, NonExistenceProofCodec, AccountProofDataCodec, PharosStateProof, DEFAULT_POLL_INTERVAL, ADDRESS_ZERO2, DEFAULT_GRAFFITI, DEFAULT_LOGGER, REQUEST_STATUS_WEIGHTS, TIMEOUT_STATUS_WEIGHTS, COMBINED_STATUS_WEIGHTS, CHAIN_ID_TO_COINGECKO_NATIVE, TESTNET_CHAINS, ORDER_STATUS, loadDriver, detectEnvironment, STORAGE_KEYS, LEGACY_STORAGE_KEYS, ABI5, uniswapV3Quoter_default, UNISWAP_V4_QUOTER_ABI, ABI6, universalRouter_default, PERMIT2_ABI, UniswapQuoteEngine, COMMON_FEE_TIERS, Swap, ABI7, erc7281_default, DEFAULT_GRAFFITI2, ERC7821_BATCH_MODE, BundlerMethod, SELECT_SOLVER_TYPEHASH, PACKED_USEROP_TYPEHASH, DOMAIN_TYPEHASH, CryptoUtils, FEE_TOKEN_CACHE_TTL_MS, OrderPlacer, TOKEN_KEYED_GATEWAY_ABI, keyingByClient, PARTIAL_FILLS_SLOT, USED_USEROPS_STORAGE_KEY, OrderExecutor, _a6, OrderCanceller, FILL_ORDER_SELECTOR, SUPPORTED_INTENTS_VERSION, CONTRACT_VERSION_ABI, CANONICAL_EVM_TOKEN, ENTRY_POINT_EVENT_ABI, BidImpl, BidManager, RELAYER_MESSAGE_GAS, NO_BUNDLER_FILL_GAS_BASE, NO_BUNDLER_FILL_GAS_PER_OUTPUT, NO_BUNDLER_PAYMASTER_VERIFICATION_GAS, NO_BUNDLER_PAYMASTER_POST_OP_GAS, BID_PVG_ESTIMATION_ACCOUNT_CODE, SELECTED_BID_SIGNATURE_BYTES, BID_PVG_HEADROOM_PERCENT, ESCROW_MAPPING_SLOT, GasEstimator, OrderStatusChecker, ORDERBOOK_URLS, ORDERBOOK_DECIMALS, ORDERBOOK_SCALE, OrderbookRequestError, RATE_FIELDS, TOP_OF_BOOK_QUERY, ROUTE_LIQUIDITY_QUERY, QUOTE_QUERY, QUOTE_PESSIMISTIC_QUERY, HyperFxOrderbook, UnsupportedLiquidityAssetError, UnsupportedLiquidityChainError, OrderbookQuoteNotConvergedError, MAX_EXACT_OUTPUT_ROUNDS, OrderbookMarket, ETHEREUM_ORDER_FEE_GAS_PRICE_BUMP_PERCENT, DEFAULT_ORDER_FEE_GAS_PRICE_BUMP_PERCENT, IntentGateway, DECLARATION_V1, DECLARATION_V2, PAYMASTER_ADDRESS_BYTES, PAYMASTER_GAS_LIMIT_BYTES, PAYMASTER_DATA_OFFSET, PERMIT2_DATA_BYTES, PERMIT2_SPONSORSHIP_BYTES, MAX_DECLARED_ENTRIES, MAX_TOKEN_ID_BYTES, TeleportParams, MultiAccount;
235505
+ var import_merge_race, __defProp3, __getOwnPropNames2, __esm2, __export2, node_exports, wasm, full_path, __dirname$1, cachedTextDecoder, cachedUint8ArrayMemory0, WASM_VECTOR_LEN, cachedTextEncoder, encodeString5, cachedDataViewMemory0, KeccakMergeFinalization, KeccakMerge, wasmPath, wasmBytes2, bindings, wasmModule, wasmInstance, __wasm, init_node11, RequestStatus, TimeoutStatus, IntentOrderStatus, ABI, evmHost_default, ABI2, handlerV2_default, polkadotAssetHubPaseo, polkadotHubMainnet, pharosMainnet, pharosAtlantic, tronNile, ENTRY_POINT_V08, ENTRY_POINT_V09, KNOWN_ENTRY_POINTS, chainConfigs, configsByStateMachineId, getConfigByStateMachineId, getChainId3, getViemChain, hyperbridgeAddress, ABI3, IntentGatewayV2_default, ChainConfigService, ABI4, uniswapRouterV2_default, chains, DEFAULT_ADDRESS, EvmChain, REQUEST_COMMITMENTS_SLOT, RESPONSE_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, STATE_COMMITMENTS_SLOT, MISSING_CONSENSUS_UPDATE_TIME_MESSAGE, MissingConsensusUpdateTimeError, TokenBucket, BATCHES_NOT_SUPPORTED_CODE, TOO_BIG_BATCH_REQUEST_CODE, DEFAULT_MAX_BATCH_SIZE, _endpoint2, _headers3, _limiter, _maxBatchSize, _batchingSupported, _pending2, _flushTimer, _flushing, _nextId, __BatchingHttpProvider_instances, scheduleFlush_fn, flushNow_fn, flush_fn, post_fn, settleBatch_fn, settle_fn, handleBatchRefusal_fn, requeue_fn, _a5, BatchingHttpProvider, OFFCHAIN_BID_PREFIX, HYPERBRIDGE_TYPES_BUNDLE, BASE_TIP, HTTP_CONNECT_TIMEOUT_MS, INCLUSION_TIMEOUT_MS, DEFAULT_RPC_MAX_RPS, rpcLimiters, BidCodec, PackedUserOperationCodec, IntentsCoprocessor, ReviveContractInfo, ReviveAccountType, ReviveAccountInfo, H256, EvmStateProof, SubstrateHashing, SubstrateStateMachineProof, BasicProof, LeafIndexAndPos, MmrProof, ConsensusStateId, ConsensusMessage, FraudProofMessage, StateMachine, StateMachineId, StateMachineHeight, Proof, PostRequest, PostResponse, GetRequest, StorageValue, GetResponse, Request3, Response2, RequestMessage, RequestResponse, ResponseMessage, TimeoutMessage, GetRequestsWithProof, Message, DEFAULT_CHILD_STORAGE_PREFIX, PharosProofNodeCodec, SiblingLeftmostLeafProofCodec, NonExistenceProofCodec, AccountProofDataCodec, PharosStateProof, DEFAULT_POLL_INTERVAL, ADDRESS_ZERO2, DEFAULT_GRAFFITI, DEFAULT_LOGGER, REQUEST_STATUS_WEIGHTS, TIMEOUT_STATUS_WEIGHTS, COMBINED_STATUS_WEIGHTS, CHAIN_ID_TO_COINGECKO_NATIVE, TESTNET_CHAINS, ORDER_STATUS, loadDriver, detectEnvironment, STORAGE_KEYS, LEGACY_STORAGE_KEYS, ABI5, uniswapV3Quoter_default, UNISWAP_V4_QUOTER_ABI, ABI6, universalRouter_default, PERMIT2_ABI, UniswapQuoteEngine, COMMON_FEE_TIERS, Swap, ABI7, erc7281_default, DEFAULT_GRAFFITI2, ERC7821_BATCH_MODE, BundlerMethod, SELECT_SOLVER_TYPEHASH, LEGACY_SELECT_SOLVER_TYPEHASH, PACKED_USEROP_TYPEHASH, DOMAIN_TYPEHASH, CryptoUtils, FEE_TOKEN_CACHE_TTL_MS, OrderPlacer, TOKEN_KEYED_GATEWAY_ABI, keyingByClient, PARTIAL_FILLS_SLOT, USED_USEROPS_STORAGE_KEY, OrderExecutor, _a6, OrderCanceller, FILL_ORDER_SELECTOR, SUPPORTED_INTENTS_VERSION, TESTNET_INTENTS_VERSIONS, CONTRACT_VERSION_ABI, CANONICAL_EVM_TOKEN, formats, SELECTION_PARAMS_SLOT, SOLVER_SELECTION_CLEARED, SELECTION_FORMAT_BY_ENTRY_POINT, ENTRY_POINT_EVENT_ABI, BidImpl, BidManager, UNSUPPORTED_REQUEST_CODES, bundlersWithoutRundlerFees, RELAYER_MESSAGE_GAS, NO_BUNDLER_FILL_GAS_BASE, NO_BUNDLER_FILL_GAS_PER_OUTPUT, NO_BUNDLER_PAYMASTER_VERIFICATION_GAS, NO_BUNDLER_PAYMASTER_POST_OP_GAS, BID_PVG_ESTIMATION_ACCOUNT_CODE, BID_PVG_ESTIMATION_PAYMASTER_CODE, SELECTED_BID_SIGNATURE_BYTES, BID_PVG_HEADROOM_PERCENT, ESCROW_MAPPING_SLOT, GasEstimator, OrderStatusChecker, ORDERBOOK_URLS, ORDERBOOK_DECIMALS, ORDERBOOK_SCALE, OrderbookRequestError, RATE_FIELDS, TOP_OF_BOOK_QUERY, ROUTE_LIQUIDITY_QUERY, QUOTE_QUERY, QUOTE_PESSIMISTIC_QUERY, HyperFxOrderbook, UnsupportedLiquidityAssetError, UnsupportedLiquidityChainError, OrderbookQuoteNotConvergedError, MAX_EXACT_OUTPUT_ROUNDS, OrderbookMarket, ETHEREUM_ORDER_FEE_GAS_PRICE_BUMP_PERCENT, DEFAULT_ORDER_FEE_GAS_PRICE_BUMP_PERCENT, IntentGateway, DECLARATION_V1, DECLARATION_V2, PAYMASTER_ADDRESS_BYTES, PAYMASTER_GAS_LIMIT_BYTES, PAYMASTER_DATA_OFFSET, PERMIT2_DATA_BYTES, PERMIT2_SPONSORSHIP_BYTES, MAX_DECLARED_ENTRIES, MAX_TOKEN_ID_BYTES, TeleportParams, MultiAccount;
235426
235506
  var init_node10 = __esm({
235427
235507
  "../sdk/dist/node/index.js"() {
235428
235508
  "use strict";
@@ -237775,6 +237855,9 @@ var init_node10 = __esm({
237775
237855
  default: { name: "Nile Tronscan", url: "https://nile.tronscan.org" }
237776
237856
  }
237777
237857
  });
237858
+ ENTRY_POINT_V08 = "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108";
237859
+ ENTRY_POINT_V09 = "0x433709009B8330FDa32311DF1C2AFA402eD8D009";
237860
+ KNOWN_ENTRY_POINTS = [ENTRY_POINT_V09, ENTRY_POINT_V08];
237778
237861
  chainConfigs = {
237779
237862
  97: {
237780
237863
  chainId: 97,
@@ -237807,8 +237890,10 @@ var init_node10 = __esm({
237807
237890
  UniversalRouter: "0xcc6d5ece3d4a57245bf5a2f64f3ed9179b81f714",
237808
237891
  UniswapV3Quoter: "0x0000000000000000000000000000000000000000",
237809
237892
  UniswapV4Quoter: "0x0000000000000000000000000000000000000000",
237810
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
237811
- SolverAccount: "0xf98E484858F59C30e31D2695ac18F92bc7C7b799"
237893
+ Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
237894
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
237895
+ SolverAccount: "0x7484C6Ff790b898bf7e6960Ffc82f63330445Dc2",
237896
+ SimplexPaymaster: "0x9f4a6F1254f27373C2aca5bDd0e48FbA45EA3aeC"
237812
237897
  },
237813
237898
  rpcEnvKey: "BSC_CHAPEL",
237814
237899
  defaultRpcUrl: "https://bnb-testnet.api.onfinality.io/public",
@@ -237843,7 +237928,7 @@ var init_node10 = __esm({
237843
237928
  UniswapRouter02: "0x0000000000000000000000000000000000000000",
237844
237929
  UniswapV2Factory: "0x0000000000000000000000000000000000000000",
237845
237930
  UniswapV3Factory: "0x0000000000000000000000000000000000000000",
237846
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
237931
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
237847
237932
  },
237848
237933
  rpcEnvKey: "GNOSIS_CHIADO",
237849
237934
  defaultRpcUrl: "https://gnosis-chiado-rpc.publicnode.com",
@@ -237883,7 +237968,7 @@ var init_node10 = __esm({
237883
237968
  UniswapV2Factory: "0x0000000000000000000000000000000000000000",
237884
237969
  UniswapV3Factory: "0x0000000000000000000000000000000000000000",
237885
237970
  Calldispatcher: "0xC7f13b6D03A0A7F3239d38897503E90553ABe155",
237886
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
237971
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
237887
237972
  },
237888
237973
  rpcEnvKey: "SEPOLIA",
237889
237974
  defaultRpcUrl: "https://1rpc.io/sepolia",
@@ -237934,7 +238019,7 @@ var init_node10 = __esm({
237934
238019
  },
237935
238020
  addresses: {
237936
238021
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
237937
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238022
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
237938
238023
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
237939
238024
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
237940
238025
  UniswapRouter02: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
@@ -237948,7 +238033,7 @@ var init_node10 = __esm({
237948
238033
  UniswapV4StateView: "0x7ffe42c4a5deea5b0fec41c94c136cf115597227",
237949
238034
  Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
237950
238035
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
237951
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238036
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
237952
238037
  CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
237953
238038
  SimplexPaymaster: "0xD4340d7466e040626383cb9cda9307ba8E081149",
237954
238039
  Usdt0Oft: "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee"
@@ -237980,7 +238065,8 @@ var init_node10 = __esm({
237980
238065
  USDC: "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d",
237981
238066
  USDT: "0x55d398326f99059ff775485246999027b3197955",
237982
238067
  EXT: "0x7C8c11ADb8EF7cd3CFa718008Ea048445C6E7209",
237983
- cNGN: "0xa8AEA66B361a8d53e8865c62D142167Af28Af058"
238068
+ cNGN: "0xa8AEA66B361a8d53e8865c62D142167Af28Af058",
238069
+ BRIDGE: "0x5b0c50fDd52ECC0d4c682c441eaBaD41FfDEABBB"
237984
238070
  },
237985
238071
  tokenDecimals: {
237986
238072
  USDC: 18,
@@ -237989,19 +238075,21 @@ var init_node10 = __esm({
237989
238075
  // Binance-pegged stables above. Every phantom standard_amount and pool rate divides
237990
238076
  // by this, so the divergence from its neighbours here is load-bearing, not a typo.
237991
238077
  cNGN: 6,
237992
- EXT: 18
238078
+ EXT: 18,
238079
+ BRIDGE: 18
237993
238080
  },
237994
238081
  tokenStorageSlots: {
237995
238082
  USDT: { balanceSlot: 1, allowanceSlot: 2 },
237996
238083
  USDC: { balanceSlot: 1, allowanceSlot: 2 },
237997
238084
  WETH: { balanceSlot: 3, allowanceSlot: 4 },
237998
238085
  DAI: { balanceSlot: 0, allowanceSlot: 0 },
237999
- cNGN: { balanceSlot: 201, allowanceSlot: 202 }
238086
+ cNGN: { balanceSlot: 201, allowanceSlot: 202 },
238000
238087
  // custom upgradeable layout, as on Base
238088
+ BRIDGE: { balanceSlot: 0, allowanceSlot: 1 }
238001
238089
  },
238002
238090
  addresses: {
238003
238091
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
238004
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238092
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
238005
238093
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
238006
238094
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238007
238095
  UniswapRouter02: "0x10ED43C718714eb63d5aA57B78B54704E256024E",
@@ -238015,7 +238103,7 @@ var init_node10 = __esm({
238015
238103
  UniswapV4StateView: "0xd13dd3d6e93f276fafc9db9e6bb47c1180aee0c4",
238016
238104
  Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
238017
238105
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238018
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238106
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
238019
238107
  SimplexPaymaster: "0xeD02f9f0df8F562B89cC5b25867Ad3C2d61252A9"
238020
238108
  // "Usdt0Oft": Not available on BSC
238021
238109
  },
@@ -238062,7 +238150,7 @@ var init_node10 = __esm({
238062
238150
  },
238063
238151
  addresses: {
238064
238152
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
238065
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238153
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
238066
238154
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
238067
238155
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238068
238156
  UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
@@ -238076,7 +238164,7 @@ var init_node10 = __esm({
238076
238164
  UniswapV4StateView: "0x76fd297e2d437cd7f76d50f01afe6160f86e9990",
238077
238165
  Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
238078
238166
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238079
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238167
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
238080
238168
  CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
238081
238169
  SimplexPaymaster: "0x7281Bccb4f0BCE44F3B8542d1fC5e51c2F5fC08C",
238082
238170
  Usdt0Oft: "0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92"
@@ -238136,7 +238224,7 @@ var init_node10 = __esm({
238136
238224
  },
238137
238225
  addresses: {
238138
238226
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
238139
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238227
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
238140
238228
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
238141
238229
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238142
238230
  UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
@@ -238147,7 +238235,7 @@ var init_node10 = __esm({
238147
238235
  UniswapV4Quoter: "0x0d5e0f971ed27fbff6c2837bf31316121532048d",
238148
238236
  Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
238149
238237
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238150
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238238
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
238151
238239
  CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
238152
238240
  SimplexPaymaster: "0x15b3B03C870c7ef252029c35A12d3b339F5c8d7f",
238153
238241
  AerodromeRouter: "0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43",
@@ -238186,7 +238274,8 @@ var init_node10 = __esm({
238186
238274
  cNGN: "0x52828daa48C1a9A06F37500882b42daf0bE04C3B",
238187
238275
  ZARP: "0xb755506531786C8aC63B756BaB1ac387bACB0C04",
238188
238276
  XSGD: "0xDC3326e71D45186F113a2F448984CA0e8D201995",
238189
- USDR: "0x3B5F2810fB2168FfA9C73160F97BF9f2461fFa5c"
238277
+ USDR: "0x3B5F2810fB2168FfA9C73160F97BF9f2461fFa5c",
238278
+ BRIDGE: "0x5b0c50fDd52ECC0d4c682c441eaBaD41FfDEABBB"
238190
238279
  },
238191
238280
  tokenDecimals: {
238192
238281
  USDC: 6,
@@ -238195,7 +238284,8 @@ var init_node10 = __esm({
238195
238284
  cNGN: 6,
238196
238285
  ZARP: 18,
238197
238286
  XSGD: 6,
238198
- USDR: 6
238287
+ USDR: 6,
238288
+ BRIDGE: 18
238199
238289
  },
238200
238290
  tokenStorageSlots: {
238201
238291
  USDT: { balanceSlot: 0, allowanceSlot: 1 },
@@ -238206,11 +238296,12 @@ var init_node10 = __esm({
238206
238296
  // custom upgradeable layout
238207
238297
  ZARP: { balanceSlot: 51, allowanceSlot: 52 },
238208
238298
  XSGD: { balanceSlot: 7, allowanceSlot: 8 },
238209
- USDR: { balanceSlot: 51, allowanceSlot: 52 }
238299
+ USDR: { balanceSlot: 51, allowanceSlot: 52 },
238300
+ BRIDGE: { balanceSlot: 0, allowanceSlot: 1 }
238210
238301
  },
238211
238302
  addresses: {
238212
238303
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
238213
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238304
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
238214
238305
  TokenGateway: "0x8b536105b6Fae2aE9199f5146D3C57Dfe53b614E",
238215
238306
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238216
238307
  UniswapRouter02: "0xd2f9496824951D5237cC71245D659E48d0d5f9E8",
@@ -238224,7 +238315,7 @@ var init_node10 = __esm({
238224
238315
  UniswapV4StateView: "0x5ea1bd7974c8a611cbab0bdcafcb1d9cc9b3ba5a",
238225
238316
  Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
238226
238317
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238227
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238318
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
238228
238319
  CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
238229
238320
  SimplexPaymaster: "0xe99acFe0f5fC4C8ea54A187D8D3b05f136150095",
238230
238321
  Usdt0Oft: "0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13"
@@ -238303,8 +238394,9 @@ var init_node10 = __esm({
238303
238394
  Host: "0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1",
238304
238395
  Calldispatcher: "0x876F1891982E260026630c233A4897160A281Fb8",
238305
238396
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238306
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238307
- SolverAccount: "0xf98E484858F59C30e31D2695ac18F92bc7C7b799"
238397
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
238398
+ SolverAccount: "0x7484C6Ff790b898bf7e6960Ffc82f63330445Dc2",
238399
+ SimplexPaymaster: "0x6085a14078B7d26259145a894140f7C8361e02ae"
238308
238400
  },
238309
238401
  rpcEnvKey: "POLYGON_AMOY",
238310
238402
  defaultRpcUrl: "https://rpc-amoy.polygon.technology",
@@ -238336,7 +238428,7 @@ var init_node10 = __esm({
238336
238428
  UniswapV3Factory: "0x1F98431c8aD98523631AE4a59f267346ea31F984",
238337
238429
  Calldispatcher: "0xC71251c8b3e7B02697A84363Eef6DcE8DfBdF333",
238338
238430
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238339
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238431
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238340
238432
  CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
238341
238433
  UniswapV4PositionManager: "0x3c3ea4b57a46241e54610e5f022e5c45859a1017",
238342
238434
  UniswapV4PoolManager: "0x9a13f98cb987694c9f086b1f5eb990eea8264ec3"
@@ -238370,7 +238462,7 @@ var init_node10 = __esm({
238370
238462
  // Mocked
238371
238463
  UniswapV2Factory: "0x0000000000000000000000000000000000000000",
238372
238464
  Calldispatcher: "0xC71251c8b3e7B02697A84363Eef6DcE8DfBdF333",
238373
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238465
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238374
238466
  },
238375
238467
  defaultRpcUrl: "https://rpc.gnosischain.com",
238376
238468
  consensusStateId: "GNO0",
@@ -238395,7 +238487,7 @@ var init_node10 = __esm({
238395
238487
  addresses: {
238396
238488
  TokenGateway: "0xCe304770236f39F9911BfCC51afBdfF3b8635718",
238397
238489
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238398
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238490
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238399
238491
  UniswapV4PositionManager: "0x1b35d13a2e2528f192637f14b05f0dc0e7deb566",
238400
238492
  UniswapV4PoolManager: "0x360e68faccca8ca495c1b759fd9eee466db9fb32"
238401
238493
  },
@@ -238421,7 +238513,7 @@ var init_node10 = __esm({
238421
238513
  addresses: {
238422
238514
  TokenGateway: "0xFcDa26cA021d5535C3059547390E6cCd8De7acA6",
238423
238515
  Host: "0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1",
238424
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238516
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238425
238517
  },
238426
238518
  defaultRpcUrl: "https://sepolia-rollup.arbitrum.io/rpc",
238427
238519
  consensusStateId: "ETH0",
@@ -238445,7 +238537,7 @@ var init_node10 = __esm({
238445
238537
  addresses: {
238446
238538
  TokenGateway: "0xFcDa26cA021d5535C3059547390E6cCd8De7acA6",
238447
238539
  Host: "0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1",
238448
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238540
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238449
238541
  },
238450
238542
  defaultRpcUrl: "https://sepolia.optimism.io",
238451
238543
  consensusStateId: "ETH0",
@@ -238469,7 +238561,7 @@ var init_node10 = __esm({
238469
238561
  addresses: {
238470
238562
  TokenGateway: "0xFcDa26cA021d5535C3059547390E6cCd8De7acA6",
238471
238563
  Host: "0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1",
238472
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238564
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238473
238565
  },
238474
238566
  defaultRpcUrl: "https://sepolia.base.org",
238475
238567
  consensusStateId: "ETH0",
@@ -238495,7 +238587,7 @@ var init_node10 = __esm({
238495
238587
  IntentGateway: "0x606ba811aa6cb424ce2108e8977c5284686f0d1f",
238496
238588
  TokenGateway: "0x1c1e5be83df4a54c7a2230c337e4a3e8b7354b1c",
238497
238589
  Host: "0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1",
238498
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238590
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238499
238591
  },
238500
238592
  defaultRpcUrl: "https://testnet-asset-hub-eth-rpc.polkadot.io",
238501
238593
  consensusStateId: "PAS0",
@@ -238519,7 +238611,7 @@ var init_node10 = __esm({
238519
238611
  },
238520
238612
  addresses: {
238521
238613
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
238522
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238614
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
238523
238615
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238524
238616
  Calldispatcher: "0xE2C7e576E26E0bE7aC97c6fE925bcDAbD87c4bEd"
238525
238617
  },
@@ -239924,9 +240016,9 @@ var init_node10 = __esm({
239924
240016
  internalType: "bytes32"
239925
240017
  },
239926
240018
  {
239927
- name: "solver",
239928
- type: "address",
239929
- internalType: "address"
240019
+ name: "userOpHash",
240020
+ type: "bytes32",
240021
+ internalType: "bytes32"
239930
240022
  },
239931
240023
  {
239932
240024
  name: "signature",
@@ -240972,8 +241064,8 @@ var init_node10 = __esm({
240972
241064
  getPopularTokens(chain2) {
240973
241065
  return this.getConfig(chain2)?.popularTokens ?? [];
240974
241066
  }
240975
- getEntryPointV08Address(chain2) {
240976
- return this.getConfig(chain2)?.addresses.EntryPointV08;
241067
+ getEntryPointAddress(chain2) {
241068
+ return this.getConfig(chain2)?.addresses.EntryPoint;
240977
241069
  }
240978
241070
  getCirclePaymasterAddress(chain2) {
240979
241071
  return this.getConfig(chain2)?.addresses.CirclePaymaster;
@@ -243235,6 +243327,9 @@ Failed HTTP Request: ${JSON.stringify(
243235
243327
  * fails on-chain, and a second `retractBid` that pulls the bid just placed. When the signed nonce
243236
243328
  * cannot be read, the stalled result is returned rather than guessed at.
243237
243329
  *
243330
+ * A stall in `Future` first fills the missing nonce below it ({@link fillNonceGap}), so the
243331
+ * replacement can land.
243332
+ *
243238
243333
  * A rejection that bounced off a copy already pooled (1013/1014) is likewise left alone: that
243239
243334
  * copy is in flight and its outcome is unknown here, so the `pending` result goes back to the
243240
243335
  * caller to confirm later.
@@ -243259,6 +243354,7 @@ Failed HTTP Request: ${JSON.stringify(
243259
243354
  stalled = result;
243260
243355
  nonce ?? (nonce = this.signedNonce(extrinsic));
243261
243356
  if (nonce === void 0) return result;
243357
+ if (result.future) await this.fillNonceGap(keyPair, nonce, timeoutMs);
243262
243358
  continue;
243263
243359
  }
243264
243360
  if (result.pending) return stalled ?? result;
@@ -243298,19 +243394,6 @@ Failed HTTP Request: ${JSON.stringify(
243298
243394
  const inFlight = code === 1013 || code === 1014 || /already imported|already in the pool|priority is too low/i.test(err.message);
243299
243395
  return { success: false, pending: inFlight || void 0, error: err.message };
243300
243396
  }
243301
- /**
243302
- * Sends an extrinsic with a timeout.
243303
- *
243304
- * A timeout is only a failure when the extrinsic never made it into the transaction pool.
243305
- * Once a pool-entry status (Future/Ready/Broadcast/Retracted) has been seen, the extrinsic is
243306
- * in flight and may well execute after the watch is abandoned — the result is then `pending`
243307
- * and `stalled`, telling the caller to replace it under the same nonce or confirm it later,
243308
- * never to re-sign the same call under a fresh one.
243309
- *
243310
- * `nonce` pins the submission to a specific account nonce, which is what makes a retry a pool
243311
- * replacement rather than a second extrinsic queued behind the first. Left undefined on the
243312
- * first attempt, where the api's auto-nonce is correct.
243313
- */
243314
243397
  /**
243315
243398
  * The nonce the next submission signs with, or undefined when the node cannot be asked.
243316
243399
  *
@@ -243327,6 +243410,7 @@ Failed HTTP Request: ${JSON.stringify(
243327
243410
  * queued as future, or simply not counted yet — is covered by `lastPooledNonce` instead, which
243328
243411
  * is the highest nonce this instance has put into the pool. The two are combined rather than
243329
243412
  * trusted separately, so a burst never reuses a nonce and a restart still picks up the chain's.
243413
+ * A nonce left missing by an extrinsic the node dropped is filled by {@link fillNonceGap}.
243330
243414
  */
243331
243415
  async nextNonce(api) {
243332
243416
  try {
@@ -243340,11 +243424,53 @@ Failed HTTP Request: ${JSON.stringify(
243340
243424
  return void 0;
243341
243425
  }
243342
243426
  }
243427
+ /**
243428
+ * A stall in `Future` means the node is missing a lower nonce of this account's, one whose
243429
+ * extrinsic it dropped, and everything signed above that nonce waits behind it. This fills the
243430
+ * lowest missing nonce, which `system_accountNextIndex` reports on the same node, with a
243431
+ * `system.remark` rather than the next call, so the calls already pooled above it land in the
243432
+ * order they were signed. One nonce per stall; a further gap shows up as the next `Future` stall.
243433
+ *
243434
+ * The remark carries no tip, so on any node or pool view that still holds a live call of ours at
243435
+ * that nonce, the call outranks it and the remark only ever fills a real gap.
243436
+ *
243437
+ * It runs inside the submission queue, so it submits directly rather than enqueueing, and gives
243438
+ * up after `timeoutMs` so a silent socket cannot hold the queue. A failure or timeout is logged
243439
+ * and left to the next stall.
243440
+ */
243441
+ async fillNonceGap(keyPair, nonce, timeoutMs) {
243442
+ const fill = async () => {
243443
+ const accountNextIndex = this.api.rpc?.system?.accountNextIndex;
243444
+ if (!accountNextIndex) return;
243445
+ const missing = Number((await accountNextIndex(keyPair.address)).toString());
243446
+ if (!Number.isFinite(missing) || missing >= nonce) return;
243447
+ await this.api.tx.system.remark("0x").signAndSend(keyPair, { tip: 0n, nonce: missing });
243448
+ };
243449
+ try {
243450
+ await Promise.race([fill(), rejectAfter(timeoutMs, `Timed out after ${timeoutMs}ms`)]);
243451
+ } catch (err) {
243452
+ console.warn(`Could not fill the nonce gap below ${nonce}:`, err);
243453
+ }
243454
+ }
243455
+ /**
243456
+ * Sends an extrinsic with a timeout.
243457
+ *
243458
+ * A timeout is only a failure when the extrinsic never made it into the transaction pool.
243459
+ * Once a pool-entry status (Future/Ready/Broadcast/Retracted) has been seen, the extrinsic is
243460
+ * in flight and may well execute after the watch is abandoned — the result is then `pending`
243461
+ * and `stalled`, telling the caller to replace it under the same nonce or confirm it later,
243462
+ * never to re-sign the same call under a fresh one.
243463
+ *
243464
+ * `nonce` pins the submission to a specific account nonce, which is what makes a retry a pool
243465
+ * replacement rather than a second extrinsic queued behind the first. Left undefined on the
243466
+ * first attempt, where the api's auto-nonce is correct.
243467
+ */
243343
243468
  async sendWithTimeout(extrinsic, keyPair, tip, timeoutMs, nonce) {
243344
243469
  return new Promise((resolve12) => {
243345
243470
  let resolved = false;
243346
243471
  let unsubscribe = null;
243347
243472
  let enteredPool = false;
243473
+ let inFuture = false;
243348
243474
  const timeoutId = setTimeout(() => {
243349
243475
  if (!resolved) {
243350
243476
  resolved = true;
@@ -243355,6 +243481,7 @@ Failed HTTP Request: ${JSON.stringify(
243355
243481
  success: false,
243356
243482
  pending: enteredPool || void 0,
243357
243483
  stalled: enteredPool || void 0,
243484
+ future: enteredPool && inFuture || void 0,
243358
243485
  extrinsicHash: enteredPool ? extrinsic.hash.toHex() : void 0,
243359
243486
  error: `Transaction timed out after ${timeoutMs}ms${enteredPool ? " while in the transaction pool" : ""}`
243360
243487
  });
@@ -243364,6 +243491,7 @@ Failed HTTP Request: ${JSON.stringify(
243364
243491
  if (resolved) return;
243365
243492
  if (result.status.isFuture || result.status.isReady || result.status.isBroadcast || result.status.isRetracted) {
243366
243493
  enteredPool = true;
243494
+ inFuture = result.status.isFuture;
243367
243495
  }
243368
243496
  if (result.dispatchError && (result.status.isInBlock || result.status.isFinalized)) {
243369
243497
  resolved = true;
@@ -246659,7 +246787,8 @@ query OrderStatus($commitment: String!) {
246659
246787
  /** Alchemy (Rundler) method to fetch recommended priority fee for UserOperations. */
246660
246788
  RUNDLER_MAX_PRIORITY_FEE_PER_GAS: "rundler_maxPriorityFeePerGas"
246661
246789
  };
246662
- SELECT_SOLVER_TYPEHASH = keccak2563(toHex3("SelectSolver(bytes32 commitment,address solver)"));
246790
+ SELECT_SOLVER_TYPEHASH = keccak2563(toHex3("SelectSolver(bytes32 commitment,bytes32 userOpHash)"));
246791
+ LEGACY_SELECT_SOLVER_TYPEHASH = keccak2563(toHex3("SelectSolver(bytes32 commitment,address solver)"));
246663
246792
  PACKED_USEROP_TYPEHASH = keccak2563(
246664
246793
  toHex3(
246665
246794
  "PackedUserOperation(address sender,uint256 nonce,bytes initCode,bytes callData,bytes32 accountGasLimits,uint256 preVerificationGas,bytes32 gasFees,bytes paymasterAndData)"
@@ -246698,29 +246827,50 @@ query OrderStatus($commitment: String!) {
246698
246827
  );
246699
246828
  }
246700
246829
  /**
246701
- * Signs a `SelectSolver` EIP-712 message with a session key.
246830
+ * Signs `SelectSolver(bytes32 commitment,bytes32 userOpHash)` with the
246831
+ * order's session key, for gateways whose `SELECT_SOLVER_TYPEHASH` is
246832
+ * {@link SELECT_SOLVER_TYPEHASH}.
246702
246833
  *
246703
- * The session key authorises the selection of a specific solver for the
246704
- * given order commitment. The resulting signature is appended to the
246705
- * solver's UserOperation signature before bundle submission.
246834
+ * The signature selects one bid UserOperation for the order and is appended
246835
+ * to that operation's signature before it is sent to the bundler.
246706
246836
  *
246707
- * @param commitment - The order commitment (bytes32) being fulfilled.
246708
- * @param solverAddress - Address of the solver account selected to fill the order.
246709
- * @param domainSeparator - EIP-712 domain separator for the IntentGatewayV2 contract.
246710
- * @param privateKey - Hex-encoded private key of the session key that signs the message.
246711
- * @returns The ECDSA signature as a hex string, or `null` if signing fails.
246837
+ * @param commitment - The order commitment.
246838
+ * @param userOpHash - EntryPoint userOpHash of the selected bid UserOperation.
246839
+ * @param domainSeparator - EIP-712 domain separator of the IntentGatewayV2 contract.
246840
+ * @param privateKey - Private key of the order's session key.
246841
+ * @returns The 65-byte ECDSA signature.
246712
246842
  */
246713
- static async signSolverSelection(commitment, solverAddress, domainSeparator2, privateKey) {
246714
- const account5 = privateKeyToAccount(privateKey);
246843
+ static async signUserOpHashSelection(commitment, userOpHash, domainSeparator2, privateKey) {
246844
+ const structHash = keccak2563(
246845
+ encodeAbiParameters2(
246846
+ [{ type: "bytes32" }, { type: "bytes32" }, { type: "bytes32" }],
246847
+ [SELECT_SOLVER_TYPEHASH, commitment, userOpHash]
246848
+ )
246849
+ );
246850
+ return signTypedDigest(domainSeparator2, structHash, privateKey);
246851
+ }
246852
+ /**
246853
+ * Signs `SelectSolver(bytes32 commitment,address solver)` with the order's
246854
+ * session key, for gateways whose `SELECT_SOLVER_TYPEHASH` is
246855
+ * {@link LEGACY_SELECT_SOLVER_TYPEHASH}.
246856
+ *
246857
+ * The signature selects a solver account for the order and is appended to
246858
+ * that solver's bid UserOperation signature before it is sent to the bundler.
246859
+ *
246860
+ * @param commitment - The order commitment.
246861
+ * @param solverAddress - Address of the selected solver account.
246862
+ * @param domainSeparator - EIP-712 domain separator of the IntentGatewayV2 contract.
246863
+ * @param privateKey - Private key of the order's session key.
246864
+ * @returns The 65-byte ECDSA signature.
246865
+ */
246866
+ static async signLegacySolverSelection(commitment, solverAddress, domainSeparator2, privateKey) {
246715
246867
  const structHash = keccak2563(
246716
246868
  encodeAbiParameters2(
246717
246869
  [{ type: "bytes32" }, { type: "bytes32" }, { type: "address" }],
246718
- [SELECT_SOLVER_TYPEHASH, commitment, solverAddress]
246870
+ [LEGACY_SELECT_SOLVER_TYPEHASH, commitment, solverAddress]
246719
246871
  )
246720
246872
  );
246721
- const digest = keccak2563(concat3(["0x1901", domainSeparator2, structHash]));
246722
- const signature = await account5.sign({ hash: digest });
246723
- return signature;
246873
+ return signTypedDigest(domainSeparator2, structHash, privateKey);
246724
246874
  }
246725
246875
  /**
246726
246876
  * Computes the EIP-712 hash of a `PackedUserOperation` as defined by
@@ -247247,16 +247397,13 @@ query OrderStatus($commitment: String!) {
247247
247397
  }
247248
247398
  /**
247249
247399
  * Creates a closure that computes the deduplication hash key for a
247250
- * UserOperation, pre-bound to the order's destination chain and entry point.
247400
+ * UserOperation, pre-bound to the destination chain.
247251
247401
  */
247252
- createUserOpHasher(order) {
247253
- const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(
247254
- normalizeStateMachineId(order.destination)
247255
- );
247402
+ createUserOpHasher() {
247256
247403
  const chainId = BigInt(
247257
247404
  this.ctx.dest.client.chain?.id ?? Number.parseInt(this.ctx.dest.config.stateMachineId.split("-")[1])
247258
247405
  );
247259
- return (userOp) => CryptoUtils.computeUserOpHash(userOp, entryPointAddress, chainId);
247406
+ return (userOp) => CryptoUtils.computeUserOpHash(userOp, ENTRY_POINT_V08, chainId);
247260
247407
  }
247261
247408
  /**
247262
247409
  * Fetches bids from the coprocessor for a given order commitment.
@@ -247372,7 +247519,7 @@ query OrderStatus($commitment: String!) {
247372
247519
  return;
247373
247520
  }
247374
247521
  const usedUserOps = await this.loadUsedUserOps(commitment);
247375
- const userOpHashKey = this.createUserOpHasher(order);
247522
+ const userOpHashKey = this.createUserOpHasher();
247376
247523
  const targetAssets = order.output.assets.map((a6) => ({ token: a6.token, amount: a6.amount }));
247377
247524
  let initial;
247378
247525
  try {
@@ -248236,7 +248383,8 @@ query OrderStatus($commitment: String!) {
248236
248383
  }, __publicField(_a6, "DEFAULT_MAX_RECOVERY_RESTARTS", 1), __publicField(_a6, "PROOF_FRESHNESS_MAX_RETRIES", 3), __publicField(_a6, "PROOF_FRESHNESS_BACKOFF_MS", 500), /** Gas budgets used to price cancellation delivery on the source chain. */
248237
248384
  __publicField(_a6, "SOURCE_GET_RESPONSE_GAS", 1000000n), __publicField(_a6, "REFUND_POST_GAS", 1000000n), _a6);
248238
248385
  FILL_ORDER_SELECTOR = "0x68ddf058";
248239
- SUPPORTED_INTENTS_VERSION = 3n;
248386
+ SUPPORTED_INTENTS_VERSION = 4n;
248387
+ TESTNET_INTENTS_VERSIONS = [3n, SUPPORTED_INTENTS_VERSION];
248240
248388
  CONTRACT_VERSION_ABI = [
248241
248389
  {
248242
248390
  type: "function",
@@ -248247,6 +248395,13 @@ query OrderStatus($commitment: String!) {
248247
248395
  }
248248
248396
  ];
248249
248397
  CANONICAL_EVM_TOKEN = /^0x0{24}[0-9a-fA-F]{40}$/;
248398
+ formats = /* @__PURE__ */ new Map();
248399
+ SELECTION_PARAMS_SLOT = pad4(toHex3(5n), { size: 32 });
248400
+ SOLVER_SELECTION_CLEARED = maxUint2563 ^ 0xffn << 160n;
248401
+ SELECTION_FORMAT_BY_ENTRY_POINT = /* @__PURE__ */ new Map([
248402
+ [ENTRY_POINT_V09.toLowerCase(), "userOpHash"],
248403
+ [ENTRY_POINT_V08.toLowerCase(), "address"]
248404
+ ]);
248250
248405
  ENTRY_POINT_EVENT_ABI = [
248251
248406
  { type: "event", name: "BeforeExecution", inputs: [] },
248252
248407
  {
@@ -248281,6 +248436,8 @@ query OrderStatus($commitment: String!) {
248281
248436
  __publicField(this, "domainSeparator");
248282
248437
  /** Cached session-key signature over the `SelectSolver` message. */
248283
248438
  __publicField(this, "cachedSignature");
248439
+ /** Cached result of {@link route}. */
248440
+ __publicField(this, "cachedRoute");
248284
248441
  this.ctx = params.ctx;
248285
248442
  this.crypto = params.crypto;
248286
248443
  this.order = params.order;
@@ -248310,69 +248467,117 @@ query OrderStatus($commitment: String!) {
248310
248467
  );
248311
248468
  }
248312
248469
  /**
248313
- * Resolves the session key, signs the `SelectSolver` message for this bid's
248314
- * solver, and caches the signature. Signs at most once per bid.
248470
+ * Finds the EntryPoint this bid's solver signed it for and checks that the
248471
+ * destination gateway's selection format pairs with it, reading the format
248472
+ * again before refusing a bid in case the gateway was upgraded since it was
248473
+ * cached. Caches the result.
248315
248474
  *
248316
- * @throws If the session key is missing or signing fails.
248475
+ * @throws If the solver's signature recovers under no known EntryPoint, the
248476
+ * EntryPoint does not pair with the gateway's selection format, or the
248477
+ * format cannot be read.
248478
+ */
248479
+ async route() {
248480
+ if (this.cachedRoute) return this.cachedRoute;
248481
+ const chainId = this.chainId();
248482
+ let signed;
248483
+ for (const entryPoint of KNOWN_ENTRY_POINTS) {
248484
+ const userOpHash = CryptoUtils.computeUserOpHash(this.userOp, entryPoint, chainId);
248485
+ if (await this.signedBySolver(userOpHash)) {
248486
+ signed = { entryPoint, userOpHash };
248487
+ break;
248488
+ }
248489
+ }
248490
+ if (!signed) {
248491
+ throw new Error(`Bid from solver=${this.solverAddress} is not signed for a known EntryPoint`);
248492
+ }
248493
+ const pairsWith = SELECTION_FORMAT_BY_ENTRY_POINT.get(signed.entryPoint.toLowerCase());
248494
+ const cached = readSelectionFormat(this.ctx.dest.client, chainId, this.intentGatewayV2Address);
248495
+ let format2 = await cached;
248496
+ if (pairsWith !== format2) {
248497
+ format2 = await refreshSelectionFormat(this.ctx.dest.client, chainId, this.intentGatewayV2Address, cached);
248498
+ }
248499
+ if (pairsWith !== format2) {
248500
+ throw new Error(
248501
+ `Bid from solver=${this.solverAddress} is signed for EntryPoint ${signed.entryPoint}, which the destination gateway's ${format2} selection does not pair with`
248502
+ );
248503
+ }
248504
+ this.cachedRoute = { ...signed, format: format2 };
248505
+ return this.cachedRoute;
248506
+ }
248507
+ /**
248508
+ * Whether the solver's signature in the bid, `signature[32:97]` after the order
248509
+ * commitment, recovers to the solver over `userOpHash`.
248510
+ */
248511
+ async signedBySolver(userOpHash) {
248512
+ try {
248513
+ const recovered = await recoverAddress3({
248514
+ hash: userOpHash,
248515
+ signature: slice4(this.userOp.signature, 32, 97)
248516
+ });
248517
+ return recovered.toLowerCase() === this.solverAddress.toLowerCase();
248518
+ } catch {
248519
+ return false;
248520
+ }
248521
+ }
248522
+ /**
248523
+ * Resolves the session key, signs the `SelectSolver` message for this bid in
248524
+ * the destination gateway's selection format, and caches the signature. Signs
248525
+ * at most once per bid.
248526
+ *
248527
+ * @throws If the bid cannot be routed, or the session key is missing.
248317
248528
  */
248318
248529
  async signSelection() {
248319
248530
  if (this.cachedSignature) return this.cachedSignature;
248531
+ const { format: format2, userOpHash } = await this.route();
248320
248532
  const commitment = this.order.id;
248321
248533
  const sessionKeyAddress = this.order.session;
248322
248534
  const sessionKeyData = this.sessionPrivateKey ? { privateKey: this.sessionPrivateKey } : await this.ctx.sessionKeyStorage.getSessionKeyByAddress(sessionKeyAddress);
248323
248535
  if (!sessionKeyData) {
248324
248536
  throw new Error(`SessionKey not found for commitment: ${commitment}`);
248325
248537
  }
248326
- const signature = await CryptoUtils.signSolverSelection(
248538
+ this.cachedSignature = format2 === "userOpHash" ? await CryptoUtils.signUserOpHashSelection(
248539
+ commitment,
248540
+ userOpHash,
248541
+ this.domainSeparator,
248542
+ sessionKeyData.privateKey
248543
+ ) : await CryptoUtils.signLegacySolverSelection(
248327
248544
  commitment,
248328
248545
  this.solverAddress,
248329
248546
  this.domainSeparator,
248330
248547
  sessionKeyData.privateKey
248331
248548
  );
248332
- if (!signature) {
248333
- throw new Error("Failed to sign solver selection");
248334
- }
248335
- this.cachedSignature = signature;
248336
- return signature;
248549
+ return this.cachedSignature;
248337
248550
  }
248338
248551
  /**
248339
- * Simulates this bid on-chain by batching the `select` and `fillOrder` calls
248340
- * via `eth_call` from the solver's account, using the IntentGatewayV2 ERC-7821
248341
- * batch-execute pattern.
248552
+ * Simulates this bid on-chain with an `eth_call` of its calldata from the
248553
+ * solver's account, after checking that the bid can be routed.
248554
+ *
248555
+ * The gateway's solver selection is turned off for the call with
248556
+ * {@link selectionOffStateDiff} and no `select` is made: a gateway that selects
248557
+ * by userOpHash checks the selection against the EntryPoint's current
248558
+ * operation, which only exists inside a bundle. The session's selection is
248559
+ * therefore not part of the simulation.
248342
248560
  *
248343
248561
  * The native value forwarded to the simulation is the sum of any native-token
248344
248562
  * (`address(0)`) output amounts plus the Hyperbridge dispatch fee.
248345
248563
  *
248346
- * @throws If the `eth_call` simulation reverts or errors.
248564
+ * @throws If the bid cannot be routed, or the `eth_call` simulation reverts or errors.
248347
248565
  */
248348
248566
  async simulate() {
248349
- const signature = await this.signSelection();
248350
- const selectOptions = {
248351
- commitment: this.order.id,
248352
- solver: this.solverAddress,
248353
- signature
248354
- };
248567
+ await this.route();
248355
248568
  const nativeOutputs = this.fillOptions.outputs.reduce(
248356
248569
  (acc, o6) => bytes32ToBytes20(o6.token) === ADDRESS_ZERO2 ? acc + o6.amount : acc,
248357
248570
  0n
248358
248571
  );
248359
248572
  const simulationValue = nativeOutputs + this.fillOptions.nativeDispatchFee;
248360
- const selectCalldata = encodeFunctionData2({
248361
- abi: ABI3,
248362
- functionName: "select",
248363
- args: [selectOptions]
248364
- });
248365
- const calls = [
248366
- { target: this.intentGatewayV2Address, value: 0n, data: selectCalldata },
248367
- { target: this.solverAddress, value: simulationValue, data: this.userOp.callData }
248368
- ];
248369
- const batchedCalldata = this.crypto.encodeERC7821Execute(calls);
248370
248573
  try {
248574
+ const selectionOff = await selectionOffStateDiff(this.ctx.dest.client, this.intentGatewayV2Address);
248371
248575
  await this.ctx.dest.client.call({
248372
248576
  account: this.solverAddress,
248373
248577
  to: this.solverAddress,
248374
- data: batchedCalldata,
248375
- value: simulationValue
248578
+ data: this.userOp.callData,
248579
+ value: simulationValue,
248580
+ stateOverride: [{ address: this.intentGatewayV2Address, stateDiff: [selectionOff] }]
248376
248581
  });
248377
248582
  } catch (e4) {
248378
248583
  throw new Error(`Simulation failed: ${e4 instanceof Error ? e4.message : String(e4)}`);
@@ -248381,31 +248586,29 @@ query OrderStatus($commitment: String!) {
248381
248586
  /**
248382
248587
  * Signs the `SelectSolver` message with the session key, appends it to the
248383
248588
  * solver's existing UserOp signature, and submits the UserOperation to the
248384
- * bundler. Waits for the receipt and reads `OrderFilled` / `PartialFill`
248385
- * logs to determine fill status.
248589
+ * bundler on the EntryPoint the bid was signed for. Waits for the receipt and
248590
+ * reads `OrderFilled` / `PartialFill` logs to determine fill status.
248386
248591
  *
248387
248592
  * @returns A {@link SelectBidResult} with the submitted UserOperation, its hash,
248388
248593
  * the solver address, transaction hash, and fill status.
248389
- * @throws If the bundler is not configured, the session key is missing, or the
248390
- * bundler rejects the UserOperation.
248594
+ * @throws If the bundler is not configured, the bid cannot be routed, the
248595
+ * session key is missing, or the bundler rejects the UserOperation.
248391
248596
  */
248392
248597
  async execute() {
248393
248598
  const commitment = this.order.id;
248394
248599
  if (!this.ctx.bundlerUrl) {
248395
248600
  throw new Error("Bundler URL not configured");
248396
248601
  }
248602
+ const { entryPoint } = await this.route();
248397
248603
  const sessionSignature = await this.signSelection();
248398
248604
  const finalSignature = concat3([this.userOp.signature, sessionSignature]);
248399
248605
  const signedUserOp = {
248400
248606
  ...this.userOp,
248401
248607
  signature: finalSignature
248402
248608
  };
248403
- const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(
248404
- normalizeStateMachineId(this.order.destination)
248405
- );
248406
248609
  const userOpHash = await this.crypto.sendBundler(BundlerMethod.ETH_SEND_USER_OPERATION, [
248407
248610
  CryptoUtils.prepareBundlerCall(signedUserOp),
248408
- entryPointAddress
248611
+ entryPoint
248409
248612
  ]);
248410
248613
  let txnHash;
248411
248614
  let fillStatus;
@@ -248431,7 +248634,7 @@ query OrderStatus($commitment: String!) {
248431
248634
  );
248432
248635
  const fills = parseEventLogs2({
248433
248636
  abi: ABI3,
248434
- logs: userOperationLogs(chainReceipt.logs, entryPointAddress, userOpHash),
248637
+ logs: userOperationLogs(chainReceipt.logs, entryPoint, userOpHash),
248435
248638
  eventName: ["OrderFilled", "PartialFill"]
248436
248639
  }).filter(
248437
248640
  (event) => event.address.toLowerCase() === gateway.toLowerCase() && event.args.commitment.toLowerCase() === commitment.toLowerCase()
@@ -248483,12 +248686,15 @@ query OrderStatus($commitment: String!) {
248483
248686
  * Constructs a signed `PackedUserOperation` that a solver can submit to the
248484
248687
  * Hyperbridge coprocessor as a bid to fill an order.
248485
248688
  *
248486
- * The solver signs the operation as EntryPoint v0.8 EIP-712 typed data,
248487
- * whose digest is the plain userOpHash. The binding to the order lives in
248488
- * the operation itself: the 4337 nonce key must be the lower 192 bits of
248489
- * the order commitment (`SolverAccount` enforces this during validation),
248490
- * and the callData carries the order. This keeps the signed payload fully
248491
- * transparent to signing infrastructure instead of an opaque digest.
248689
+ * The solver signs the operation as EIP-712 typed data for
248690
+ * `entryPointAddress`, whose digest is that EntryPoint's userOpHash. It must
248691
+ * be the EntryPoint the solver's `SolverAccount` accepts: the user's SDK
248692
+ * recovers it from this signature and executes the bid there. The binding
248693
+ * to the order lives in the operation itself: the 4337 nonce key must derive
248694
+ * from the order commitment, the session key and the calldata
248695
+ * (`SolverAccount` enforces this during validation), and the callData
248696
+ * carries the order. This keeps the signed payload fully transparent to
248697
+ * signing infrastructure instead of an opaque digest.
248492
248698
  *
248493
248699
  * @param options - Parameters describing the solver account, gas limits, fee
248494
248700
  * market values, and pre-built `callData` for the fill operation.
@@ -248521,7 +248727,7 @@ query OrderStatus($commitment: String!) {
248521
248727
  }
248522
248728
  const chain2 = normalizeStateMachineId(order.destination);
248523
248729
  const gateway = this.ctx.dest.configService.getIntentGatewayAddress(chain2);
248524
- if (!await supportsRateFills(this.ctx.dest.client, gateway)) {
248730
+ if (!await supportsRateFills(this.ctx.dest.client, gateway, chain2)) {
248525
248731
  throw new Error("Fills are not supported by the destination gateway");
248526
248732
  }
248527
248733
  const chainId = BigInt(
@@ -248561,6 +248767,11 @@ query OrderStatus($commitment: String!) {
248561
248767
  * silently dropped with a warning. The returned `Bid` instances are ready to
248562
248768
  * be ranked, simulated, and executed by the consumer.
248563
248769
  *
248770
+ * A bid signed for no known EntryPoint, or for one the destination gateway's
248771
+ * selection format does not pair with, is kept here and fails
248772
+ * {@link Bid.simulate} and {@link Bid.execute}, so {@link selectAndExecuteBest}
248773
+ * skips it.
248774
+ *
248564
248775
  * @param order - The placed order the bids are competing to fill.
248565
248776
  * @param bids - Raw filler bids fetched from the coprocessor.
248566
248777
  * @param sessionPrivateKey - Optional session-key override; looked up from
@@ -248853,12 +249064,15 @@ query OrderStatus($commitment: String!) {
248853
249064
  }
248854
249065
  }
248855
249066
  };
249067
+ UNSUPPORTED_REQUEST_CODES = /* @__PURE__ */ new Set([-32600, -32601, -32602]);
249068
+ bundlersWithoutRundlerFees = /* @__PURE__ */ new Set();
248856
249069
  RELAYER_MESSAGE_GAS = 1000000n;
248857
249070
  NO_BUNDLER_FILL_GAS_BASE = 700000n;
248858
249071
  NO_BUNDLER_FILL_GAS_PER_OUTPUT = 150000n;
248859
249072
  NO_BUNDLER_PAYMASTER_VERIFICATION_GAS = 250000n;
248860
249073
  NO_BUNDLER_PAYMASTER_POST_OP_GAS = 100000n;
248861
249074
  BID_PVG_ESTIMATION_ACCOUNT_CODE = "0x60003560e01c631626ba7e1460145760206000f35b631626ba7e60e01b60005260206000f3";
249075
+ BID_PVG_ESTIMATION_PAYMASTER_CODE = "0x604060005260606000f3";
248862
249076
  SELECTED_BID_SIGNATURE_BYTES = 32 + 65 + 65;
248863
249077
  BID_PVG_HEADROOM_PERCENT = 10n;
248864
249078
  ESCROW_MAPPING_SLOT = 9n;
@@ -248872,8 +249086,6 @@ query OrderStatus($commitment: String!) {
248872
249086
  constructor(ctx, crypto10) {
248873
249087
  __publicField(this, "ctx");
248874
249088
  __publicField(this, "crypto");
248875
- /** Call dispatchers read from a gateway, for chains whose config carries none. */
248876
- __publicField(this, "dispatchers", /* @__PURE__ */ new Map());
248877
249089
  this.ctx = ctx;
248878
249090
  this.crypto = crypto10;
248879
249091
  }
@@ -248895,7 +249107,10 @@ query OrderStatus($commitment: String!) {
248895
249107
  * ephemeral keypair, applies state overrides, and calls
248896
249108
  * `eth_estimateUserOperationGas`. Gas limits are bumped by 5-10% for
248897
249109
  * headroom. If the bundler is Pimlico, gas prices are refined with
248898
- * `pimlico_getUserOperationGasPrice`. If the bundler rejects the estimate,
249110
+ * `pimlico_getUserOperationGasPrice`, and if it is Alchemy, with
249111
+ * `rundler_maxPriorityFeePerGas`. For any other bundler that answers
249112
+ * `rundler_maxPriorityFeePerGas`, the fees are raised to at least that
249113
+ * priority fee (see {@link applyRundlerPriorityFee}). If the bundler rejects the estimate,
248899
249114
  * fixed gas limits are returned in its place, or the call throws when
248900
249115
  * `params.requireBundlerEstimate` is set.
248901
249116
  *
@@ -248930,7 +249145,7 @@ query OrderStatus($commitment: String!) {
248930
249145
  const souceStateMachineId = isHex3(order.source) ? hexToString2(order.source) : order.source;
248931
249146
  const destStateMachineId = isHex3(order.destination) ? hexToString2(order.destination) : order.destination;
248932
249147
  const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachineId);
248933
- const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(destStateMachineId);
249148
+ const entryPointAddress = this.ctx.dest.configService.getEntryPointAddress(destStateMachineId);
248934
249149
  const chainId = BigInt(Number.parseInt(destStateMachineId.split("-")[1]));
248935
249150
  const totalEthValue = quotedOutputs.filter((output3) => bytes32ToBytes20(output3.token) === ADDRESS_ZERO2).reduce((sum2, output3) => sum2 + output3.amount, 0n);
248936
249151
  const [sourceFeeToken, destFeeToken, gasPrice, latestBlock] = await Promise.all([
@@ -248992,7 +249207,7 @@ query OrderStatus($commitment: String!) {
248992
249207
  const maxFeeBumpPercent = params.maxFeePerGasBumpPercent ?? 10;
248993
249208
  let maxPriorityFeePerGas = gasPrice + gasPrice * BigInt(priorityFeeBumpPercent) / 100n;
248994
249209
  let maxFeePerGas = gasPrice + gasPrice * BigInt(maxFeeBumpPercent) / 100n;
248995
- await assertGatewayRelease(this.ctx.dest.client, intentGatewayV2Address);
249210
+ await assertGatewayRelease(this.ctx.dest.client, intentGatewayV2Address, destStateMachineId);
248996
249211
  const fillOrderCalldata = encodeFillOrder(transformOrderForContract(order), fillOptions);
248997
249212
  let callGasLimit = 500000n;
248998
249213
  let verificationGasLimit = 100000n;
@@ -249001,6 +249216,7 @@ query OrderStatus($commitment: String!) {
249001
249216
  let paymasterPostOpGasLimit = 0n;
249002
249217
  if (this.ctx.bundlerUrl) {
249003
249218
  try {
249219
+ if (!entryPointAddress) throw new Error(`No EntryPoint configured for ${destStateMachineId}`);
249004
249220
  const callData = this.crypto.encodeERC7821Execute([
249005
249221
  ...params.prependCalls ?? [],
249006
249222
  { target: intentGatewayV2Address, value: totalNativeValue, data: fillOrderCalldata }
@@ -249033,7 +249249,13 @@ query OrderStatus($commitment: String!) {
249033
249249
  chainId,
249034
249250
  intentGatewayV2Address
249035
249251
  );
249036
- const sessionSignature = await CryptoUtils.signSolverSelection(
249252
+ const selectionFormat = await readSelectionFormat(this.ctx.dest.client, chainId, intentGatewayV2Address);
249253
+ const sessionSignature = selectionFormat === "userOpHash" ? await CryptoUtils.signUserOpHashSelection(
249254
+ commitment,
249255
+ userOpHash,
249256
+ domainSeparator2,
249257
+ solverPrivateKey
249258
+ ) : await CryptoUtils.signLegacySolverSelection(
249037
249259
  commitment,
249038
249260
  solverAccountAddress,
249039
249261
  domainSeparator2,
@@ -249047,6 +249269,7 @@ query OrderStatus($commitment: String!) {
249047
249269
  const bundlerUrlLower = this.ctx.bundlerUrl.toLowerCase();
249048
249270
  const isPimlico = bundlerUrlLower.includes("pimlico.io");
249049
249271
  const isAlchemy = bundlerUrlLower.includes("alchemy.com");
249272
+ const rundlerPriorityFeeRequest = isPimlico || isAlchemy ? Promise.resolve(null) : fetchRundlerPriorityFee(this.ctx.bundlerUrl);
249050
249273
  const bundlerRequests = [
249051
249274
  {
249052
249275
  method: BundlerMethod.ETH_ESTIMATE_USER_OPERATION_GAS,
@@ -249102,13 +249325,27 @@ query OrderStatus($commitment: String!) {
249102
249325
  }
249103
249326
  }
249104
249327
  if (alchemyMaxPriorityFee) {
249105
- const rundlerPriorityFee = BigInt(alchemyMaxPriorityFee);
249328
+ const rundlerPriorityFee2 = BigInt(alchemyMaxPriorityFee);
249106
249329
  const isArbitrum = chainId === 42161n;
249107
249330
  const alchemyPrioBump = isArbitrum ? 0n : 25n;
249108
- maxPriorityFeePerGas = rundlerPriorityFee + rundlerPriorityFee * alchemyPrioBump / 100n;
249331
+ maxPriorityFeePerGas = rundlerPriorityFee2 + rundlerPriorityFee2 * alchemyPrioBump / 100n;
249109
249332
  const bufferedBaseFee = baseFeePerGas + baseFeePerGas * 50n / 100n;
249110
249333
  maxFeePerGas = bufferedBaseFee + maxPriorityFeePerGas;
249111
249334
  }
249335
+ const rundlerPriorityFee = await rundlerPriorityFeeRequest;
249336
+ if (rundlerPriorityFee !== null) {
249337
+ const rundlerFees = applyRundlerPriorityFee(
249338
+ { maxFeePerGas, maxPriorityFeePerGas },
249339
+ {
249340
+ rundlerPriorityFee,
249341
+ baseFeePerGas,
249342
+ priorityFeeBumpPercent: BigInt(priorityFeeBumpPercent),
249343
+ maxFeeBumpPercent: BigInt(maxFeeBumpPercent)
249344
+ }
249345
+ );
249346
+ maxFeePerGas = rundlerFees.maxFeePerGas;
249347
+ maxPriorityFeePerGas = rundlerFees.maxPriorityFeePerGas;
249348
+ }
249112
249349
  } catch (e4) {
249113
249350
  if (params.requireBundlerEstimate) {
249114
249351
  throw new Error(`Bundler gas estimation failed: ${e4 instanceof Error ? e4.message : String(e4)}`, {
@@ -249149,27 +249386,6 @@ query OrderStatus($commitment: String!) {
249149
249386
  inputs
249150
249387
  };
249151
249388
  }
249152
- /**
249153
- * The call dispatcher the gateway on `chain` uses: the configured address, or the one
249154
- * the gateway reports when the chain's config carries none.
249155
- *
249156
- * {@link buildStateOverride} writes it back into the gateway's params slot. Without an
249157
- * address that value is 12 bytes instead of 32, and the bundler rejects the whole
249158
- * estimate as `Invalid params`.
249159
- */
249160
- async callDispatcher(chain2, gateway) {
249161
- const configured = this.ctx.dest.configService.getCalldispatcherAddress(chain2);
249162
- if (isAddress2(configured)) return configured;
249163
- const known3 = this.dispatchers.get(chain2);
249164
- if (known3) return known3;
249165
- const params = await this.ctx.dest.client.readContract({
249166
- abi: ABI3,
249167
- address: gateway,
249168
- functionName: "params"
249169
- });
249170
- this.dispatchers.set(chain2, params.dispatcher);
249171
- return params.dispatcher;
249172
- }
249173
249389
  /**
249174
249390
  * Asks the bundler for the `preVerificationGas` of the bid UserOperation that will
249175
249391
  * actually be signed, with every funding call, approval and signature byte in it.
@@ -249183,7 +249399,9 @@ query OrderStatus($commitment: String!) {
249183
249399
  * `maxFeePerGas`.
249184
249400
  *
249185
249401
  * The solver account's code is overridden with {@link BID_PVG_ESTIMATION_ACCOUNT_CODE}
249186
- * for the call, so only the bytes are priced and the fill itself is not simulated.
249402
+ * and the paymaster's, if the bid has one, with {@link BID_PVG_ESTIMATION_PAYMASTER_CODE}
249403
+ * for the call, so only the bytes are priced and neither the fill nor the paymaster's
249404
+ * validation is simulated.
249187
249405
  *
249188
249406
  * @param params - The bid's fields as they will be signed.
249189
249407
  * @returns The `preVerificationGas` to sign, with {@link BID_PVG_HEADROOM_PERCENT} added.
@@ -249207,13 +249425,15 @@ query OrderStatus($commitment: String!) {
249207
249425
  paymasterAndData: params.paymasterAndData ?? "0x",
249208
249426
  signature: `0x${"ff".repeat(SELECTED_BID_SIGNATURE_BYTES)}`
249209
249427
  };
249428
+ const stateOverride = {
249429
+ [solverAccount]: { code: BID_PVG_ESTIMATION_ACCOUNT_CODE }
249430
+ };
249431
+ if (userOp.paymasterAndData.length >= 42) {
249432
+ stateOverride[userOp.paymasterAndData.slice(0, 42)] = { code: BID_PVG_ESTIMATION_PAYMASTER_CODE };
249433
+ }
249210
249434
  const estimate = await this.crypto.sendBundler(
249211
249435
  BundlerMethod.ETH_ESTIMATE_USER_OPERATION_GAS,
249212
- [
249213
- CryptoUtils.prepareBundlerCall(userOp),
249214
- params.entryPointAddress,
249215
- { [solverAccount]: { code: BID_PVG_ESTIMATION_ACCOUNT_CODE } }
249216
- ]
249436
+ [CryptoUtils.prepareBundlerCall(userOp), params.entryPointAddress, stateOverride]
249217
249437
  );
249218
249438
  return BigInt(estimate.preVerificationGas) * (100n + BID_PVG_HEADROOM_PERCENT) / 100n;
249219
249439
  }
@@ -249261,9 +249481,8 @@ query OrderStatus($commitment: String!) {
249261
249481
  * slots should be overridden.
249262
249482
  * @param params.spenderAddress - Address that needs allowance from the solver
249263
249483
  * account (i.e. the IntentGatewayV2 contract).
249264
- * @param params.intentGatewayV2Address - If provided, overrides slot 5 of
249265
- * IntentGatewayV2 with the call-dispatcher address so dispatch calls
249266
- * succeed during estimation.
249484
+ * @param params.intentGatewayV2Address - If provided, turns the gateway's
249485
+ * solver selection off with {@link selectionOffStateDiff}.
249267
249486
  * @param params.entryPointAddress - If provided, overrides the EntryPoint
249268
249487
  * deposit mapping to give the solver account a large deposit.
249269
249488
  * @returns An object with `viem` and `bundler` state-override collections.
@@ -249282,10 +249501,7 @@ query OrderStatus($commitment: String!) {
249282
249501
  const viemOverrides = [];
249283
249502
  const bundlerOverrides = {};
249284
249503
  if (intentGatewayV2Address) {
249285
- const paramsSlot5 = pad4(toHex3(5n), { size: 32 });
249286
- const dispatcherAddress = await this.callDispatcher(chain2, intentGatewayV2Address);
249287
- const newSlot5Value = "0x" + "0".repeat(22) + "00" + dispatcherAddress.slice(2).toLowerCase();
249288
- const gatewayDiffs = [{ slot: paramsSlot5, value: newSlot5Value }];
249504
+ const gatewayDiffs = [await selectionOffStateDiff(this.ctx.dest.client, intentGatewayV2Address)];
249289
249505
  for (const [leg, input] of (escrow?.inputs ?? []).entries()) {
249290
249506
  gatewayDiffs.push({
249291
249507
  slot: escrowSlot(escrow.commitment, leg),
@@ -250946,7 +251162,7 @@ var init_FillerConfigService = __esm({
250946
251162
  return this.fillerConfig?.substratePrivateKey;
250947
251163
  }
250948
251164
  getEntryPointAddress(chain2) {
250949
- return this.chainConfigService.getEntryPointV08Address(chain2);
251165
+ return this.chainConfigService.getEntryPointAddress(chain2);
250950
251166
  }
250951
251167
  getSolverAccountContractAddress(chain2) {
250952
251168
  return this.chainConfigService.getSolverAccountAddress(chain2);
@@ -251398,7 +251614,7 @@ function chainByChainId(chainId) {
251398
251614
  function chainByAlchemySubdomain(subdomain) {
251399
251615
  return INIT_CHAINS.find((chain2) => chain2.alchemySubdomain === subdomain);
251400
251616
  }
251401
- var FREE_RPC_URLS, CHAIN_NATIVE_SYMBOLS, INIT_CHAINS, HYPERBRIDGE_WS_DEFAULTS;
251617
+ var FREE_RPC_URLS, HYPERBRIDGE_BUNDLER_URLS, CHAIN_NATIVE_SYMBOLS, INIT_CHAINS, HYPERBRIDGE_WS_DEFAULTS;
251402
251618
  var init_chains2 = __esm({
251403
251619
  "src/cli/init/chains.ts"() {
251404
251620
  "use strict";
@@ -251450,6 +251666,13 @@ var init_chains2 = __esm({
251450
251666
  "https://arb1.arbitrum.io/rpc"
251451
251667
  ]
251452
251668
  };
251669
+ HYPERBRIDGE_BUNDLER_URLS = {
251670
+ 1: "https://bundler.polytope.technology/ethereum",
251671
+ 56: "https://bundler.polytope.technology/bsc",
251672
+ 137: "https://bundler.polytope.technology/polygon",
251673
+ 8453: "https://bundler.polytope.technology/base",
251674
+ 42161: "https://bundler.polytope.technology/arbitrum"
251675
+ };
251453
251676
  CHAIN_NATIVE_SYMBOLS = {
251454
251677
  1: "ETH",
251455
251678
  56: "BNB",
@@ -251475,7 +251698,8 @@ var init_chains2 = __esm({
251475
251698
  network: "mainnet",
251476
251699
  alchemySubdomain: "eth-mainnet",
251477
251700
  explorerUrl: external_links_default.chainExplorers.ethereum,
251478
- defaultRpcUrls: FREE_RPC_URLS[1]
251701
+ defaultRpcUrls: FREE_RPC_URLS[1],
251702
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[1]
251479
251703
  },
251480
251704
  {
251481
251705
  chainId: 42161,
@@ -251484,7 +251708,8 @@ var init_chains2 = __esm({
251484
251708
  network: "mainnet",
251485
251709
  alchemySubdomain: "arb-mainnet",
251486
251710
  explorerUrl: external_links_default.chainExplorers.arbitrum,
251487
- defaultRpcUrls: FREE_RPC_URLS[42161]
251711
+ defaultRpcUrls: FREE_RPC_URLS[42161],
251712
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[42161]
251488
251713
  },
251489
251714
  {
251490
251715
  chainId: 8453,
@@ -251493,7 +251718,8 @@ var init_chains2 = __esm({
251493
251718
  network: "mainnet",
251494
251719
  alchemySubdomain: "base-mainnet",
251495
251720
  explorerUrl: external_links_default.chainExplorers.base,
251496
- defaultRpcUrls: FREE_RPC_URLS[8453]
251721
+ defaultRpcUrls: FREE_RPC_URLS[8453],
251722
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[8453]
251497
251723
  },
251498
251724
  {
251499
251725
  chainId: 137,
@@ -251502,7 +251728,8 @@ var init_chains2 = __esm({
251502
251728
  network: "mainnet",
251503
251729
  alchemySubdomain: "polygon-mainnet",
251504
251730
  explorerUrl: external_links_default.chainExplorers.polygon,
251505
- defaultRpcUrls: FREE_RPC_URLS[137]
251731
+ defaultRpcUrls: FREE_RPC_URLS[137],
251732
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[137]
251506
251733
  },
251507
251734
  {
251508
251735
  chainId: 56,
@@ -251511,7 +251738,8 @@ var init_chains2 = __esm({
251511
251738
  network: "mainnet",
251512
251739
  alchemySubdomain: "bnb-mainnet",
251513
251740
  explorerUrl: external_links_default.chainExplorers.bnb,
251514
- defaultRpcUrls: FREE_RPC_URLS[56]
251741
+ defaultRpcUrls: FREE_RPC_URLS[56],
251742
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[56]
251515
251743
  },
251516
251744
  {
251517
251745
  chainId: 11155111,
@@ -337581,7 +337809,7 @@ var init_help_text = __esm({
337581
337809
  chains: "Simplex listens for orders and fills only on the chains you pick. Each chain needs its own RPC, an ERC-4337 bundler, and funded balances (native gas + stablecoins).",
337582
337810
  rpc: "The RPC is used to scan order events, read balances and simulate fills. Use a premium endpoint with archive access (Alchemy, Infura, QuickNode) \u2014 free tiers rate-limit and break event scanning.",
337583
337811
  quorum: "Listing a second, organisationally independent RPC enables quorum log scanning: every event batch must match across providers, so one lying or compromised RPC can't feed you fake orders.",
337584
- bundler: "Fills execute as ERC-4337 UserOperations; the bundler submits them on-chain. Alchemy RPC endpoints double as bundlers, or use a dedicated provider like Pimlico.",
337812
+ bundler: "Fills execute as ERC-4337 UserOperations; the bundler submits them on-chain. Hyperbridge runs no bundler for these chains, so use a provider such as Pimlico.",
337585
337813
  signer: "This wallet signs every fill and holds your stablecoin float on each chain. It's the identity of your filler.",
337586
337814
  secretPhrase: "A secret phrase is a BIP-39 mnemonic of 12 to 24 English words. The filler signs with the wallet at m/44'/60'/0'/0/0 unless you pick another account index. The phrase is written to the config file in plain text, protected only by the file's permissions, the same as a private key.",
337587
337815
  substrateKey: "Solver-selection orders are won by submitting signed bids to Hyperbridge. This Substrate account signs those bid extrinsics and must hold BRIDGE tokens for fees \u2014 the fees are claimed back automatically after fills.",
@@ -337868,6 +338096,10 @@ var init_pimlico = __esm({
337868
338096
 
337869
338097
  // src/cli/init/steps/bundlers.ts
337870
338098
  async function stepBundlers(state, prefill) {
338099
+ for (const chain2 of state.chains) {
338100
+ if (chain2.meta.hyperbridgeBundlerUrl) chain2.bundlerUrl = chain2.meta.hyperbridgeBundlerUrl;
338101
+ }
338102
+ if (state.chains.every((chain2) => chain2.bundlerUrl)) return;
337871
338103
  why(WHY.bundler);
337872
338104
  const alchemyChains = state.chains.filter((chain2) => {
337873
338105
  if (chain2.bundlerUrl || !isAlchemyUrl(chain2.rpcUrls[0])) return false;
@@ -338453,9 +338685,9 @@ function chainComments(state) {
338453
338685
  function showSummary(state, outputPath) {
338454
338686
  const lines = [];
338455
338687
  for (const chain2 of state.chains) {
338456
- const bundlerHost = chain2.bundlerUrl ? new URL(chain2.bundlerUrl).hostname : "?";
338688
+ const bundlerHost2 = chain2.bundlerUrl ? new URL(chain2.bundlerUrl).hostname : "?";
338457
338689
  lines.push(
338458
- `${chain2.meta.label}: ${chain2.rpcUrls.length} RPC${chain2.rpcUrls.length > 1 ? "s (quorum)" : ""}, bundler ${bundlerHost}`
338690
+ `${chain2.meta.label}: ${chain2.rpcUrls.length} RPC${chain2.rpcUrls.length > 1 ? "s (quorum)" : ""}, bundler ${bundlerHost2}`
338459
338691
  );
338460
338692
  }
338461
338693
  if (state.passthroughChains.length > 0) {
@@ -340701,6 +340933,8 @@ var LimitOrderService = class {
340701
340933
  this.delegationService = delegationService;
340702
340934
  this.startingNonce = startingNonce;
340703
340935
  this.vaultBalances = vaultBalances;
340936
+ /** Re-signs in flight, by order id. A fill's resize waits one out rather than reposting alongside it. */
340937
+ this.resigning = /* @__PURE__ */ new Map();
340704
340938
  this.logger = loggers.get("limit-orders");
340705
340939
  }
340706
340940
  /**
@@ -340794,6 +341028,7 @@ var LimitOrderService = class {
340794
341028
  bookExpiresAt: null,
340795
341029
  bookPrice: null,
340796
341030
  orderNonce: order.orderNonce,
341031
+ entryPoint: null,
340797
341032
  status: "cancelled",
340798
341033
  lastError: null
340799
341034
  }),
@@ -341060,24 +341295,32 @@ var LimitOrderService = class {
341060
341295
  async resize(remaining, delivered) {
341061
341296
  const id2 = remaining.id;
341062
341297
  const floor2 = await this.dustFloor(remaining);
341063
- if (BigInt(remaining.remaining) < floor2) {
341298
+ for (let resigning = this.resigning.get(id2); resigning; resigning = this.resigning.get(id2)) await resigning;
341299
+ const order = await this.store.setStatus(id2, "resizing", null, POSTABLE);
341300
+ if (!order) return null;
341301
+ if (BigInt(order.remaining) < floor2) {
341064
341302
  this.logger.info(
341065
- { id: id2, remaining: remaining.remaining, floor: floor2.toString() },
341303
+ { id: id2, remaining: order.remaining, floor: floor2.toString() },
341066
341304
  "Limit order worked down past the dust floor; closing it"
341067
341305
  );
341068
- if (remaining.commitment) await this.withdraw(remaining.commitment);
341069
- const closed = await this.store.setPosting(id2, {
341070
- commitment: null,
341071
- bookExpiresAt: null,
341072
- bookPrice: null,
341073
- orderNonce: remaining.orderNonce,
341074
- status: "filled",
341075
- lastError: null
341076
- });
341306
+ if (order.commitment) await this.withdraw(order.commitment);
341307
+ const closed = await this.store.setPosting(
341308
+ id2,
341309
+ {
341310
+ commitment: null,
341311
+ bookExpiresAt: null,
341312
+ bookPrice: null,
341313
+ orderNonce: order.orderNonce,
341314
+ entryPoint: null,
341315
+ status: "filled",
341316
+ lastError: null
341317
+ },
341318
+ POSTABLE
341319
+ );
341077
341320
  if (closed) this.report({ kind: "filled", order: closed });
341078
341321
  return closed;
341079
341322
  }
341080
- const resized = await this.repost(await this.store.setStatus(id2, "resizing"));
341323
+ const resized = await this.repost(order);
341081
341324
  if (resized) this.report({ kind: "resized", order: resized, delivered });
341082
341325
  return resized;
341083
341326
  }
@@ -341090,7 +341333,7 @@ var LimitOrderService = class {
341090
341333
  */
341091
341334
  async repost(order) {
341092
341335
  if (!order) return null;
341093
- if (isLocal(order)) return this.store.setStatus(order.id, "open");
341336
+ if (isLocal(order)) return this.store.setStatus(order.id, "open", null, POSTABLE);
341094
341337
  if (hasExpired(order.expiresAt, /* @__PURE__ */ new Date())) return this.retire(order);
341095
341338
  if (order.commitment) {
341096
341339
  const withdrawn = await this.withdraw(order.commitment);
@@ -341101,10 +341344,13 @@ var LimitOrderService = class {
341101
341344
  { id: order.id, commitment: order.commitment, err: message },
341102
341345
  "Could not clear the old entry; leaving the posting alone rather than adding a second"
341103
341346
  );
341104
- return this.store.setStatus(order.id, "open", message);
341347
+ return this.store.setStatus(order.id, "open", message, POSTABLE);
341105
341348
  }
341106
341349
  }
341107
- await this.store.setStatus(order.id, "resizing");
341350
+ if (!await this.store.setStatus(order.id, "resizing", null, POSTABLE)) {
341351
+ this.logger.info({ id: order.id }, "Limit order closed while it was being reposted; leaving it closed");
341352
+ return null;
341353
+ }
341108
341354
  const nonce = (BigInt(order.orderNonce) + 1n).toString();
341109
341355
  return (await this.post({ ...order, commitment: null, orderNonce: nonce })).order;
341110
341356
  }
@@ -341147,7 +341393,9 @@ var LimitOrderService = class {
341147
341393
  * They drift apart when a request never got an answer or the process died
341148
341394
  * between two of them: an entry the orderbook still lists that nothing here
341149
341395
  * owns, an order here whose entry has gone, or an entry the orderbook has cut
341150
- * down because the solver cannot cover what it quoted.
341396
+ * down because the solver cannot cover what it quoted. A posted op is also
341397
+ * signed over one EntryPoint, so when the fill chain moves to another, every
341398
+ * entry signed before the move is withdrawn and posted again.
341151
341399
  */
341152
341400
  async reconcile(now = /* @__PURE__ */ new Date()) {
341153
341401
  const [entries, live] = await Promise.all([this.postedOrders(), this.live()]);
@@ -341174,7 +341422,17 @@ var LimitOrderService = class {
341174
341422
  }
341175
341423
  for (const order of live) {
341176
341424
  if (isLocal(order)) continue;
341177
- if (order.commitment && found.has(order.commitment.toLowerCase())) continue;
341425
+ if (order.commitment && found.has(order.commitment.toLowerCase())) {
341426
+ try {
341427
+ if (await this.resign(order)) report.reposted++;
341428
+ } catch (err) {
341429
+ this.logger.error(
341430
+ { id: order.id, err },
341431
+ "Could not sign the limit order again for its chain's EntryPoint"
341432
+ );
341433
+ }
341434
+ continue;
341435
+ }
341178
341436
  if (sinceMs(order.updatedAt, now) < POST_GRACE_MS) continue;
341179
341437
  this.logger.warn({ id: order.id }, "Limit order has no entry on the orderbook; posting it again");
341180
341438
  try {
@@ -341186,6 +341444,45 @@ var LimitOrderService = class {
341186
341444
  }
341187
341445
  return report;
341188
341446
  }
341447
+ /**
341448
+ * Withdraws a posting signed for an EntryPoint its fill chain no longer uses,
341449
+ * and posts it again signed for the one it uses now. Answers whether a new
341450
+ * posting landed.
341451
+ *
341452
+ * The row is read again and claimed out of `open` first: a fill can have worked
341453
+ * it down or started its own repost since reconciliation listed it, and that
341454
+ * write is the one to follow. A fill that lands once the claim is taken waits
341455
+ * in `resize` for this to finish. The EntryPoint is only written with a posting
341456
+ * that landed, so a pass cut short anywhere leaves a row the next pass still
341457
+ * reads as stale, or as having no entry, and finishes the job.
341458
+ */
341459
+ async resign(listed) {
341460
+ const entryPoint = this.configService.getEntryPointAddress(listed.fillChain);
341461
+ if (!entryPoint || sameAddress(signedFor(listed), entryPoint)) return false;
341462
+ const order = await this.store.get(listed.id);
341463
+ if (!order || order.status !== "open" || order.commitment !== listed.commitment) return false;
341464
+ if (sameAddress(signedFor(order), entryPoint) || this.resigning.has(order.id)) return false;
341465
+ const resigned = this.signAgain(order, entryPoint);
341466
+ this.resigning.set(
341467
+ order.id,
341468
+ resigned.catch(() => false)
341469
+ );
341470
+ try {
341471
+ return await resigned;
341472
+ } finally {
341473
+ this.resigning.delete(order.id);
341474
+ }
341475
+ }
341476
+ async signAgain(order, entryPoint) {
341477
+ const claimed = await this.store.setStatus(order.id, "resizing", null, ["open"]);
341478
+ if (!claimed) return false;
341479
+ this.logger.warn(
341480
+ { id: order.id, commitment: order.commitment, signedFor: signedFor(order), entryPoint },
341481
+ "Limit order was signed for an EntryPoint its chain no longer uses; signing it again"
341482
+ );
341483
+ const posted = await this.repost(claimed);
341484
+ return !!posted?.commitment && sameAddress(signedFor(posted), entryPoint);
341485
+ }
341189
341486
  /**
341190
341487
  * Lowers every open order's `remaining` to what the solver's account will still
341191
341488
  * pay for it, and puts the order back on the book at that size.
@@ -341267,6 +341564,7 @@ var LimitOrderService = class {
341267
341564
  bookExpiresAt: null,
341268
341565
  bookPrice: null,
341269
341566
  orderNonce: order.orderNonce,
341567
+ entryPoint: null,
341270
341568
  status: "expired",
341271
341569
  lastError: null
341272
341570
  });
@@ -341323,11 +341621,11 @@ var LimitOrderService = class {
341323
341621
  }
341324
341622
  /** Builds and submits the posting, then writes the orderbook's answer onto the row. */
341325
341623
  async post(order) {
341326
- const { result, orderNonce } = await this.submit(order);
341624
+ const { result, orderNonce, entryPoint } = await this.submit(order);
341327
341625
  if (result.kind === "accepted" || result.kind === "unchanged") {
341328
341626
  const posted = result.order;
341329
341627
  this.logger.info(
341330
- { id: order.id, commitment: posted.commitment, price: posted.price },
341628
+ { id: order.id, commitment: posted.commitment, price: posted.price, entryPoint },
341331
341629
  "Limit order posted to the orderbook"
341332
341630
  );
341333
341631
  const stored = await this.store.setPosting(
@@ -341337,6 +341635,10 @@ var LimitOrderService = class {
341337
341635
  bookExpiresAt: posted.expiresAt,
341338
341636
  bookPrice: posted.price,
341339
341637
  orderNonce: orderNonce.toString(),
341638
+ // An entry the orderbook already held was signed by an earlier attempt,
341639
+ // for whichever EntryPoint was current then. Recorded as unknown, which
341640
+ // reconciliation reads as v0.8 and signs again once the chain is past it.
341641
+ entryPoint: result.kind === "accepted" ? entryPoint : null,
341340
341642
  status: "open",
341341
341643
  lastError: null
341342
341644
  },
@@ -341366,6 +341668,7 @@ var LimitOrderService = class {
341366
341668
  bookExpiresAt: null,
341367
341669
  bookPrice: null,
341368
341670
  orderNonce: orderNonce.toString(),
341671
+ entryPoint: null,
341369
341672
  status: "open",
341370
341673
  lastError: message
341371
341674
  }),
@@ -341388,22 +341691,30 @@ var LimitOrderService = class {
341388
341691
  * only the second one.
341389
341692
  */
341390
341693
  async submit(order) {
341694
+ const entryPoint = this.entryPointFor(order.fillChain);
341391
341695
  const orderNonce = BigInt(order.orderNonce);
341392
- const attempt = await this.buildAndSubmit(order, orderNonce);
341696
+ const attempt = await this.buildAndSubmit(order, orderNonce, entryPoint);
341393
341697
  const first3 = attempt.result;
341394
341698
  if (first3.kind !== "rejected" || first3.code !== "REPLAYED" && first3.code !== "ORDER_EXISTS") {
341395
- return { result: first3, orderNonce };
341699
+ return { result: first3, orderNonce, entryPoint };
341396
341700
  }
341397
341701
  if (first3.code === "ORDER_EXISTS" && attempt.commitment) {
341398
341702
  const live = await this.entryAt(order, attempt.commitment);
341399
341703
  if (live) {
341400
341704
  this.logger.info({ id: order.id, commitment: live.commitment }, "This posting is already on the orderbook");
341401
- return { result: { kind: "unchanged", order: live }, orderNonce };
341705
+ return { result: { kind: "unchanged", order: live }, orderNonce, entryPoint };
341402
341706
  }
341403
341707
  }
341404
341708
  this.logger.warn({ id: order.id, code: first3.code }, "Orderbook has seen this op before; reposting on a new nonce");
341405
341709
  const retried = orderNonce + 1n;
341406
- return { result: (await this.buildAndSubmit(order, retried)).result, orderNonce: retried };
341710
+ const { result } = await this.buildAndSubmit(order, retried, entryPoint);
341711
+ return { result, orderNonce: retried, entryPoint };
341712
+ }
341713
+ /** The EntryPoint a posting on `chain` is signed for now. */
341714
+ entryPointFor(chain2) {
341715
+ const entryPoint = this.configService.getEntryPointAddress(chain2);
341716
+ if (!entryPoint) throw new LimitOrderValidationError(`No EntryPoint is configured for ${chain2}`);
341717
+ return entryPoint;
341407
341718
  }
341408
341719
  /**
341409
341720
  * The entry the orderbook holds at `commitment`, if it holds one. A lookup that
@@ -341419,8 +341730,8 @@ var LimitOrderService = class {
341419
341730
  }
341420
341731
  }
341421
341732
  /** The orderbook's answer, and the commitment the op we sent hashes to. */
341422
- async buildAndSubmit(order, orderNonce) {
341423
- const { commitment, userOp } = await this.buildUserOp(order, orderNonce);
341733
+ async buildAndSubmit(order, orderNonce, entryPoint) {
341734
+ const { commitment, userOp } = await this.buildUserOp(order, orderNonce, entryPoint);
341424
341735
  try {
341425
341736
  return { result: await this.client.submitOrder(userOp), commitment };
341426
341737
  } catch (err) {
@@ -341430,7 +341741,7 @@ var LimitOrderService = class {
341430
341741
  throw err;
341431
341742
  }
341432
341743
  }
341433
- async buildUserOp(order, orderNonce) {
341744
+ async buildUserOp(order, orderNonce, entryPointAddress) {
341434
341745
  const baseToken = this.assetRegistry.getAddress(order.base, order.fillChain);
341435
341746
  const quoteToken = this.assetRegistry.getAddress(order.quote, order.fillChain);
341436
341747
  const [baseDecimals, quoteDecimals] = await Promise.all([
@@ -341445,10 +341756,6 @@ var LimitOrderService = class {
341445
341756
  baseDecimals,
341446
341757
  quoteDecimals
341447
341758
  });
341448
- const entryPointAddress = this.configService.getEntryPointAddress(order.fillChain);
341449
- if (!entryPointAddress) {
341450
- throw new LimitOrderValidationError(`No EntryPoint is configured for ${order.fillChain}`);
341451
- }
341452
341759
  return this.contractService.prepareLimitOrderUserOp({
341453
341760
  fillChain: order.fillChain,
341454
341761
  entryPointAddress,
@@ -341479,6 +341786,12 @@ function hasExpired(expiresAt, now) {
341479
341786
  const at = Date.parse(expiresAt);
341480
341787
  return !Number.isNaN(at) && at <= now.getTime();
341481
341788
  }
341789
+ function signedFor(order) {
341790
+ return order.entryPoint ?? ENTRY_POINT_V08;
341791
+ }
341792
+ function sameAddress(a6, b5) {
341793
+ return a6.toLowerCase() === b5.toLowerCase();
341794
+ }
341482
341795
  function sinceMs(updatedAt, now) {
341483
341796
  const written = Date.parse(`${updatedAt.replace(" ", "T")}Z`);
341484
341797
  return Number.isNaN(written) ? Number.POSITIVE_INFINITY : now.getTime() - written;
@@ -343273,6 +343586,86 @@ init_pairs();
343273
343586
  init_interpolated_curve();
343274
343587
  init_asset_registry();
343275
343588
  init_FillerConfigService();
343589
+
343590
+ // src/services/bundler-preflight.ts
343591
+ init_esm_shims();
343592
+ init_chains2();
343593
+ init_interpolated_curve();
343594
+ init_Logger();
343595
+ var BUNDLER_PREFLIGHT_TIMEOUT_MS = 1e4;
343596
+ async function assertBundlersServeEntryPoint(chains2, configService, options = {}) {
343597
+ const timeoutMs = options.timeoutMs ?? BUNDLER_PREFLIGHT_TIMEOUT_MS;
343598
+ const logger8 = moduleLogger(configService.loggers, "bundler-preflight");
343599
+ const failures = await Promise.all(
343600
+ chains2.map(async ({ chainId, bundlerUrl }) => {
343601
+ if (options.watchOnly?.[chainId] === true) return void 0;
343602
+ if (!bundlerUrl?.trim()) return void 0;
343603
+ const entryPoint = configService.getEntryPointAddress(formatChainKey(chainId));
343604
+ if (!entryPoint) return void 0;
343605
+ return checkBundler(chainId, bundlerUrl.trim(), entryPoint, timeoutMs, logger8);
343606
+ })
343607
+ );
343608
+ const messages = failures.filter((failure) => failure !== void 0);
343609
+ if (messages.length > 0) throw new Error(messages.join("; "));
343610
+ }
343611
+ function servesEntryPoint(listed, entryPoint) {
343612
+ return Array.isArray(listed) && listed.some((address) => String(address).toLowerCase() === entryPoint.toLowerCase());
343613
+ }
343614
+ function describeEntryPoints(listed) {
343615
+ return Array.isArray(listed) && listed.length > 0 ? listed.map(String).join(", ") : "none";
343616
+ }
343617
+ function bundlerHost(url2) {
343618
+ try {
343619
+ return new URL(url2).host || "an unparseable URL";
343620
+ } catch {
343621
+ return "an unparseable URL";
343622
+ }
343623
+ }
343624
+ function chainName(chainId) {
343625
+ const label = chainByChainId(chainId)?.label;
343626
+ return label ? `${label} (${formatChainKey(chainId)})` : formatChainKey(chainId);
343627
+ }
343628
+ async function checkBundler(chainId, bundlerUrl, entryPoint, timeoutMs, logger8) {
343629
+ const host = bundlerHost(bundlerUrl);
343630
+ const subject = `Bundler ${host} for ${chainName(chainId)}`;
343631
+ const signal = AbortSignal.timeout(timeoutMs);
343632
+ let listed;
343633
+ try {
343634
+ listed = await supportedEntryPoints(bundlerUrl, signal);
343635
+ } catch (err) {
343636
+ const reason = signal.aborted ? `timed out after ${timeoutMs}ms` : errorReason(err);
343637
+ logger8.warn(
343638
+ { chain: formatChainKey(chainId), bundler: host },
343639
+ `${subject} did not answer eth_supportedEntryPoints: ${reason.split(bundlerUrl).join(host)}. Continuing without confirming it serves EntryPoint ${entryPoint}`
343640
+ );
343641
+ return void 0;
343642
+ }
343643
+ if (servesEntryPoint(listed, entryPoint)) return void 0;
343644
+ return `${subject} does not support EntryPoint ${entryPoint}; it lists ${describeEntryPoints(listed)}`;
343645
+ }
343646
+ async function supportedEntryPoints(bundlerUrl, signal) {
343647
+ const response = await fetch(bundlerUrl, {
343648
+ method: "POST",
343649
+ headers: { "Content-Type": "application/json" },
343650
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_supportedEntryPoints", params: [] }),
343651
+ signal
343652
+ });
343653
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
343654
+ const json = await response.json();
343655
+ if (json.error) throw new Error(json.error.message ?? JSON.stringify(json.error));
343656
+ const { result } = json;
343657
+ if (!Array.isArray(result) || !result.every((address) => typeof address === "string")) {
343658
+ throw new Error("the result is not a list of addresses");
343659
+ }
343660
+ return result;
343661
+ }
343662
+ function errorReason(err) {
343663
+ if (!(err instanceof Error)) return String(err);
343664
+ const { cause } = err;
343665
+ return cause instanceof Error ? `${err.message} (${cause.message})` : err.message;
343666
+ }
343667
+
343668
+ // src/services/server/setup-api.ts
343276
343669
  init_wallet3();
343277
343670
 
343278
343671
  // src/services/substrate-key.ts
@@ -343471,6 +343864,23 @@ async function validateBundler(body, deps) {
343471
343864
  PROBE_TIMEOUT_MS,
343472
343865
  "Bundler probe"
343473
343866
  );
343867
+ const chainId = Number(body.chainId);
343868
+ const required2 = Number.isInteger(chainId) ? new ChainConfigService({}).getEntryPointAddress(formatChainKey(chainId)) : void 0;
343869
+ if (!required2) return { ok: true, entryPoints };
343870
+ if (!Array.isArray(entryPoints) || !entryPoints.every((address) => typeof address === "string")) {
343871
+ return {
343872
+ ok: true,
343873
+ entryPoints,
343874
+ warning: `Bundler's eth_supportedEntryPoints answer is not a list of addresses, so it could not be confirmed to support EntryPoint ${required2}, which this chain's solver account uses. Simplex will use it and warn.`
343875
+ };
343876
+ }
343877
+ if (!servesEntryPoint(entryPoints, required2)) {
343878
+ return {
343879
+ ok: true,
343880
+ entryPoints,
343881
+ warning: `Bundler does not support EntryPoint ${required2}, which this chain's solver account uses; it lists ${describeEntryPoints(entryPoints)}. Simplex will refuse to use it.`
343882
+ };
343883
+ }
343474
343884
  return { ok: true, entryPoints };
343475
343885
  } catch (err) {
343476
343886
  return {
@@ -349514,9 +349924,9 @@ var INTENT_GATEWAY_V2_ABI = [
349514
349924
  internalType: "bytes32"
349515
349925
  },
349516
349926
  {
349517
- name: "solver",
349518
- type: "address",
349519
- internalType: "address"
349927
+ name: "userOpHash",
349928
+ type: "bytes32",
349929
+ internalType: "bytes32"
349520
349930
  },
349521
349931
  {
349522
349932
  name: "signature",
@@ -350904,10 +351314,13 @@ var LIMIT_ORDER_CALL_GAS_LIMIT = 500000n;
350904
351314
  var LIMIT_ORDER_VERIFICATION_GAS_LIMIT = 150000n;
350905
351315
  var LIMIT_ORDER_PRE_VERIFICATION_GAS = 50000n;
350906
351316
  var BID_DISCOVERY_PAD_SECONDS = 30;
351317
+ var BLOCK_TIME_SAMPLE_BLOCKS = 1000n;
351318
+ var FALLBACK_BLOCK_TIME_SECONDS = 2;
350907
351319
  var ContractInteractionService = class {
350908
351320
  constructor(clientManager, configService, signer, sharedCacheService) {
350909
351321
  this.clientManager = clientManager;
350910
351322
  this.sdkHelperCache = /* @__PURE__ */ new Map();
351323
+ this.blockTimes = /* @__PURE__ */ new Map();
350911
351324
  this.logger = moduleLogger(configService.loggers, "contract-service");
350912
351325
  this.configService = configService;
350913
351326
  this.cacheService = sharedCacheService || new CacheService();
@@ -350967,11 +351380,20 @@ var ContractInteractionService = class {
350967
351380
  try {
350968
351381
  const chainIds = this.configService.getConfiguredChainIds();
350969
351382
  const chainNames = chainIds.map((id2) => `EVM-${id2}`);
350970
- for (const chainName of chainNames) {
351383
+ await Promise.all(
351384
+ chainNames.map(async (chainName2) => {
351385
+ try {
351386
+ await this.blockTimeSeconds(chainName2);
351387
+ } catch (err) {
351388
+ this.logger.warn({ err, chain: chainName2 }, "Could not measure the block time at startup");
351389
+ }
351390
+ })
351391
+ );
351392
+ for (const chainName2 of chainNames) {
350971
351393
  try {
350972
- await this.getFeeTokenWithDecimals(chainName);
351394
+ await this.getFeeTokenWithDecimals(chainName2);
350973
351395
  } catch (err) {
350974
- this.logger.warn({ err, chain: chainName }, "Could not prewarm fee token decimals");
351396
+ this.logger.warn({ err, chain: chainName2 }, "Could not prewarm fee token decimals");
350975
351397
  }
350976
351398
  }
350977
351399
  for (const destChain of chainNames) {
@@ -351556,18 +351978,59 @@ var ContractInteractionService = class {
351556
351978
  *
351557
351979
  * Operators configure seconds because that is the unit the risk is actually in, but the
351558
351980
  * contract compares against block numbers so `order.deadline` and this read the same
351559
- * clock. The conversion uses the chain's nominal block time; it is deliberately rounded
351560
- * up, since erring long costs a slightly stale quote while erring short silently drops
351561
- * winnable bids.
351981
+ * clock. The conversion uses the chain's block time from {@link blockTimeSeconds}; it is
351982
+ * deliberately rounded up, since erring long costs a slightly stale quote while erring
351983
+ * short silently drops winnable bids.
351562
351984
  */
351563
351985
  async bidValidUntilBlock(chain2) {
351564
351986
  const client = this.clientManager.getPublicClient(chain2);
351565
- const currentBlock = await client.getBlockNumber();
351566
- const blockTimeMs = client.chain?.blockTime;
351567
- const blockTimeSec = blockTimeMs ? blockTimeMs / 1e3 : 2;
351987
+ const [currentBlock, blockTimeSec] = await Promise.all([client.getBlockNumber(), this.blockTimeSeconds(chain2)]);
351568
351988
  const windowSec = this.configService.getBidValiditySeconds() + BID_DISCOVERY_PAD_SECONDS;
351569
351989
  return currentBlock + BigInt(Math.ceil(windowSec / blockTimeSec));
351570
351990
  }
351991
+ /**
351992
+ * Seconds per block on `chain`. Measured once, when simplex starts ({@link initCache}), and
351993
+ * kept until it stops. A chain with no measurement yet, because it was added later or its
351994
+ * blocks could not be read at startup, is measured at its first bid.
351995
+ *
351996
+ * The nominal `Chain.blockTime` cannot be relied on alone: it goes stale when a chain
351997
+ * speeds up (BSC makes a block every 0.45s against a declared 0.75s) and some chains
351998
+ * declare none. Converting at a slower block time than the chain's ends a bid early, so
351999
+ * the faster of the measured and the declared figure is used, and a stalled or idle
352000
+ * stretch in the sample never shortens a bid.
352001
+ *
352002
+ * Blocks that cannot be read fall back to the declared figure, then to
352003
+ * {@link FALLBACK_BLOCK_TIME_SECONDS}. That answer is not kept.
352004
+ */
352005
+ blockTimeSeconds(chain2) {
352006
+ const known3 = this.blockTimes.get(chain2);
352007
+ if (known3) return known3;
352008
+ const client = this.clientManager.getPublicClient(chain2);
352009
+ const declaredMs = client.chain?.blockTime;
352010
+ const declared = declaredMs ? declaredMs / 1e3 : void 0;
352011
+ const seconds = this.measureBlockTimeSeconds(client).then((measured) => declared ? Math.min(measured, declared) : measured).catch((err) => {
352012
+ this.blockTimes.delete(chain2);
352013
+ const fallback2 = declared ?? FALLBACK_BLOCK_TIME_SECONDS;
352014
+ this.logger.warn(
352015
+ { err, chain: chain2, seconds: fallback2 },
352016
+ "Could not measure the block time; using the declared one"
352017
+ );
352018
+ return fallback2;
352019
+ });
352020
+ this.blockTimes.set(chain2, seconds);
352021
+ return seconds;
352022
+ }
352023
+ /** The average block time over the chain's last {@link BLOCK_TIME_SAMPLE_BLOCKS} blocks, in seconds. */
352024
+ async measureBlockTimeSeconds(client) {
352025
+ const head = await client.getBlock({ blockTag: "latest" });
352026
+ const span = head.number < BLOCK_TIME_SAMPLE_BLOCKS ? head.number : BLOCK_TIME_SAMPLE_BLOCKS;
352027
+ const tail = await client.getBlock({ blockNumber: head.number - span });
352028
+ const measured = Number(head.timestamp - tail.timestamp) / Number(span);
352029
+ if (!Number.isFinite(measured) || measured <= 0) {
352030
+ throw new Error(`${span} blocks span ${head.timestamp - tail.timestamp}s`);
352031
+ }
352032
+ return measured;
352033
+ }
351571
352034
  /**
351572
352035
  * Builds the signed, never-executed UserOperation that carries one limit order
351573
352036
  * to the HyperFX orderbook.
@@ -351751,6 +352214,8 @@ init_Logger();
351751
352214
  var FALLBACK_VERIFICATION_GAS_LIMIT = 250000n;
351752
352215
  var FALLBACK_CALL_GAS_LIMIT = 1500000n;
351753
352216
  var FALLBACK_PRE_VERIFICATION_GAS = 150000n;
352217
+ var PRIORITY_FEE_BUMP_PERCENT = 8n;
352218
+ var MAX_FEE_BUMP_PERCENT = 10n;
351754
352219
  var UserOpSender = class {
351755
352220
  constructor(clientManager, configService, signer) {
351756
352221
  this.clientManager = clientManager;
@@ -351931,7 +352396,11 @@ var UserOpSender = class {
351931
352396
  );
351932
352397
  return userOp;
351933
352398
  }
351934
- /** Mirrors the gas-price selection used by the delegation and fill paths. */
352399
+ /**
352400
+ * Mirrors the gas-price selection used by the delegation and fill paths: Pimlico's and
352401
+ * Alchemy's own pricing, otherwise the chain's gas price raised to the priority fee a
352402
+ * rundler bundler requires, when the bundler gives one.
352403
+ */
351935
352404
  async getGasPrice(bundlerUrl, publicClient, chainId) {
351936
352405
  const lower2 = bundlerUrl.toLowerCase();
351937
352406
  if (lower2.includes("pimlico.io")) {
@@ -351943,19 +352412,33 @@ var UserOpSender = class {
351943
352412
  return { maxFeePerGas: BigInt(res.fast.maxFeePerGas), maxPriorityFeePerGas: BigInt(res.fast.maxPriorityFeePerGas) };
351944
352413
  }
351945
352414
  if (lower2.includes("alchemy.com")) {
351946
- const [rundlerPriorityFee, latestBlock] = await Promise.all([
352415
+ const [rundlerPriorityFee2, latestBlock2] = await Promise.all([
351947
352416
  this.sendBundlerRpc(bundlerUrl, BundlerMethod.RUNDLER_MAX_PRIORITY_FEE_PER_GAS, []),
351948
352417
  publicClient.getBlock({ blockTag: "latest" })
351949
352418
  ]);
351950
- const baseFeePerGas = latestBlock.baseFeePerGas ?? await publicClient.getGasPrice();
352419
+ const baseFeePerGas = latestBlock2.baseFeePerGas ?? await publicClient.getGasPrice();
351951
352420
  const isArbitrum = BigInt(chainId) === 42161n;
351952
352421
  const prioBump = isArbitrum ? 0n : 25n;
351953
- const maxPriorityFeePerGas = BigInt(rundlerPriorityFee) + BigInt(rundlerPriorityFee) * prioBump / 100n;
352422
+ const maxPriorityFeePerGas = BigInt(rundlerPriorityFee2) + BigInt(rundlerPriorityFee2) * prioBump / 100n;
351954
352423
  const bufferedBaseFee = baseFeePerGas + baseFeePerGas * 50n / 100n;
351955
352424
  return { maxFeePerGas: bufferedBaseFee + maxPriorityFeePerGas, maxPriorityFeePerGas };
351956
352425
  }
351957
- const gasPrice = await publicClient.getGasPrice();
351958
- return { maxFeePerGas: gasPrice + gasPrice * 10n / 100n, maxPriorityFeePerGas: gasPrice + gasPrice * 8n / 100n };
352426
+ const [gasPrice, rundlerPriorityFee] = await Promise.all([
352427
+ publicClient.getGasPrice(),
352428
+ fetchRundlerPriorityFee(bundlerUrl)
352429
+ ]);
352430
+ const fees4 = {
352431
+ maxFeePerGas: gasPrice + gasPrice * MAX_FEE_BUMP_PERCENT / 100n,
352432
+ maxPriorityFeePerGas: gasPrice + gasPrice * PRIORITY_FEE_BUMP_PERCENT / 100n
352433
+ };
352434
+ if (rundlerPriorityFee === null) return fees4;
352435
+ const latestBlock = await publicClient.getBlock({ blockTag: "latest" });
352436
+ return applyRundlerPriorityFee(fees4, {
352437
+ rundlerPriorityFee,
352438
+ baseFeePerGas: latestBlock.baseFeePerGas ?? gasPrice,
352439
+ priorityFeeBumpPercent: PRIORITY_FEE_BUMP_PERCENT,
352440
+ maxFeeBumpPercent: MAX_FEE_BUMP_PERCENT
352441
+ });
351959
352442
  }
351960
352443
  async sendBundlerRpc(bundlerUrl, method, params) {
351961
352444
  const response = await fetch(bundlerUrl, {
@@ -367374,8 +367857,8 @@ var validateBalanceForTransaction = async (params) => {
367374
367857
  }, operationContext);
367375
367858
  const balance = await balancePrepared.execute();
367376
367859
  if (BigInt(balance) < BigInt(amount)) {
367377
- const chainName = extractChainInfo(operationContext.chain).name;
367378
- throw createInsufficientTokenBalanceError(chainName, token, {
367860
+ const chainName2 = extractChainInfo(operationContext.chain).name;
367861
+ throw createInsufficientTokenBalanceError(chainName2, token, {
367379
367862
  balance: balance.toString(),
367380
367863
  amount,
367381
367864
  tokenAddress,
@@ -367390,8 +367873,8 @@ var validateNativeBalanceForTransaction = async (params) => {
367390
367873
  }, operationContext);
367391
367874
  const balance = await balancePrepared.execute();
367392
367875
  if (BigInt(balance) === 0n) {
367393
- const chainName = extractChainInfo(operationContext.chain).name;
367394
- throw createInsufficientGasError(chainName, {
367876
+ const chainName2 = extractChainInfo(operationContext.chain).name;
367877
+ throw createInsufficientGasError(chainName2, {
367395
367878
  balance: "0",
367396
367879
  walletAddress: operationContext.address
367397
367880
  });
@@ -387178,8 +387661,8 @@ async function bootFiller(config5, options) {
387178
387661
  };
387179
387662
  const configService = new FillerConfigService(resolvedChains, fillerConfigForService, options.loggers);
387180
387663
  const chainConfigs2 = resolvedChains.map((chain2) => {
387181
- const chainName = `EVM-${chain2.chainId}`;
387182
- return configService.getChainConfig(chainName);
387664
+ const chainName2 = `EVM-${chain2.chainId}`;
387665
+ return configService.getChainConfig(chainName2);
387183
387666
  });
387184
387667
  let watchOnlyConfig;
387185
387668
  const globalWatchOnly = options.watchOnlyOverride === true || config5.simplex.watchOnly === true;
@@ -387217,6 +387700,8 @@ async function bootFiller(config5, options) {
387217
387700
  "A signer is required unless every chain is watch-only: pass `signer` to Simplex.start (privateKeySigner, secretPhraseSigner, turnkeySigner, mpcVaultSigner, viemSigner, or your own Signer implementation). Running the binary? Configure it under [simplex.signer]."
387218
387701
  );
387219
387702
  }
387703
+ logger8.info("Checking each bundler serves its chain's EntryPoint...");
387704
+ await assertBundlersServeEntryPoint(resolvedChains, configService, { watchOnly: watchOnlyConfig });
387220
387705
  const chainClientManager = new ChainClientManager(configService, options.signer);
387221
387706
  const runtimeSigner = chainClientManager.getSigner();
387222
387707
  if (options.signer) {
@@ -387407,10 +387892,10 @@ async function bootFiller(config5, options) {
387407
387892
  const token1 = {};
387408
387893
  for (const pair of config5.pairs ?? []) {
387409
387894
  if (normalizeSymbol(pair.token0) === normalizeSymbol(pair.token1)) continue;
387410
- for (const chainName of configuredChainNames) {
387411
- const address = assetRegistry.getAddress(pair.token1, chainName);
387895
+ for (const chainName2 of configuredChainNames) {
387896
+ const address = assetRegistry.getAddress(pair.token1, chainName2);
387412
387897
  if (!address) continue;
387413
- const list = token1[chainName] ?? (token1[chainName] = []);
387898
+ const list = token1[chainName2] ?? (token1[chainName2] = []);
387414
387899
  if (!list.includes(address)) list.push(address);
387415
387900
  }
387416
387901
  }
@@ -387815,6 +388300,7 @@ var MemoryLimitOrderStore = class {
387815
388300
  status: "open",
387816
388301
  commitment: null,
387817
388302
  orderNonce: order.orderNonce ?? "0",
388303
+ entryPoint: null,
387818
388304
  bookExpiresAt: null,
387819
388305
  bookPrice: null,
387820
388306
  lastError: null,
@@ -388808,10 +389294,10 @@ var PairController = class {
388808
389294
  if (assets && Object.keys(assets).length > 0) config5.assets = nextAssets;
388809
389295
  if (normalizeSymbol(pair.token0) !== normalizeSymbol(pair.token1)) {
388810
389296
  for (const chain2 of this.runtime.resolvedChains) {
388811
- const chainName = formatChainKey(chain2.chainId);
388812
- const address = assetRegistry.getAddress(pair.token1, chainName);
389297
+ const chainName2 = formatChainKey(chain2.chainId);
389298
+ const address = assetRegistry.getAddress(pair.token1, chainName2);
388813
389299
  if (!address) continue;
388814
- const list = balanceTokens[chainName] ?? (balanceTokens[chainName] = []);
389300
+ const list = balanceTokens[chainName2] ?? (balanceTokens[chainName2] = []);
388815
389301
  if (!list.includes(address)) list.push(address);
388816
389302
  }
388817
389303
  }
@@ -388916,8 +389402,9 @@ var ChainController = class {
388916
389402
  `Chain ${chainId} cannot be added as filling: this solver was started without a signer. Restart with \`signer\` to fill.`
388917
389403
  );
388918
389404
  }
388919
- configService.addChain(resolved);
388920
389405
  const watchOnly = chain2.watchOnly ?? (this.runtime.signerless || this.runtime.globalWatchOnly);
389406
+ await assertBundlersServeEntryPoint([resolved], configService, { watchOnly: { [chainId]: watchOnly } });
389407
+ configService.addChain(resolved);
388921
389408
  if (watchOnly) intentFiller.setWatchOnly(chainId, true);
388922
389409
  try {
388923
389410
  if (!inScanner) {
@@ -389009,6 +389496,9 @@ var ChainController = class {
389009
389496
  if (!bundlerUrl?.trim()) throw new Error("A bundler URL is required");
389010
389497
  const index3 = this.runtime.resolvedChains.findIndex((chain2) => chain2.chainId === chainId);
389011
389498
  if (index3 < 0) throw new Error(`Chain ${chainId} is not configured`);
389499
+ await assertBundlersServeEntryPoint([{ chainId, bundlerUrl }], this.runtime.configService, {
389500
+ watchOnly: this.runtime.intentFiller.getWatchOnly()
389501
+ });
389012
389502
  this.runtime.configService.setBundlerUrl(chainId, bundlerUrl);
389013
389503
  this.runtime.resolvedChains[index3].bundlerUrl = bundlerUrl;
389014
389504
  this.runtime.config.chains[index3].bundlerUrl = bundlerUrl;
@@ -389023,6 +389513,10 @@ var ChainController = class {
389023
389513
  "Watch-only cannot be disabled: this solver was started without a signer. Restart with `signer` to fill."
389024
389514
  );
389025
389515
  }
389516
+ if (!watchOnly) {
389517
+ const chain2 = this.runtime.resolvedChains.find((resolved) => resolved.chainId === chainId);
389518
+ if (chain2) await assertBundlersServeEntryPoint([chain2], this.runtime.configService);
389519
+ }
389026
389520
  this.runtime.intentFiller.setWatchOnly(chainId, watchOnly);
389027
389521
  this.syncWatchOnlyToConfig();
389028
389522
  await this.persist();
@@ -389891,6 +390385,7 @@ var LIMIT_ORDER_COLUMNS = `
389891
390385
  status,
389892
390386
  commitment,
389893
390387
  order_nonce as orderNonce,
390388
+ entry_point as entryPoint,
389894
390389
  book_expires_at as bookExpiresAt,
389895
390390
  book_price as bookPrice,
389896
390391
  last_error as lastError,
@@ -389927,6 +390422,7 @@ var SqliteLimitOrderStore = class {
389927
390422
  status TEXT NOT NULL,
389928
390423
  commitment TEXT,
389929
390424
  order_nonce TEXT NOT NULL DEFAULT '0',
390425
+ entry_point TEXT,
389930
390426
  book_expires_at TEXT,
389931
390427
  book_price TEXT,
389932
390428
  last_error TEXT,
@@ -389951,6 +390447,10 @@ var SqliteLimitOrderStore = class {
389951
390447
 
389952
390448
  CREATE INDEX IF NOT EXISTS idx_limit_order_fills_order ON limit_order_fills(limit_order_id);
389953
390449
  `);
390450
+ if (!columnNames(this.db, "limit_orders").has("entry_point")) {
390451
+ this.db.exec("ALTER TABLE limit_orders ADD COLUMN entry_point TEXT");
390452
+ this.logger.info({ column: "entry_point" }, "Migrated limit order storage schema");
390453
+ }
389954
390454
  if (!columnNames(this.db, "limit_order_fills").has("amount_in")) {
389955
390455
  this.db.exec("ALTER TABLE limit_order_fills ADD COLUMN amount_in TEXT");
389956
390456
  this.logger.info({ column: "amount_in" }, "Migrated limit order fill schema");
@@ -390015,13 +390515,14 @@ var SqliteLimitOrderStore = class {
390015
390515
  const result = this.db.prepare(`
390016
390516
  UPDATE limit_orders
390017
390517
  SET commitment = ?, book_expires_at = ?, book_price = ?, order_nonce = ?,
390018
- status = ?, last_error = ?, updated_at = datetime('now')
390518
+ entry_point = ?, status = ?, last_error = ?, updated_at = datetime('now')
390019
390519
  WHERE id = ?${statusGuard(only)}
390020
390520
  `).run(
390021
390521
  posting.commitment,
390022
390522
  posting.bookExpiresAt,
390023
390523
  posting.bookPrice,
390024
390524
  posting.orderNonce,
390525
+ posting.entryPoint,
390025
390526
  posting.status,
390026
390527
  posting.lastError,
390027
390528
  id2,