@hyperbridge/simplex 0.16.13 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,82 @@ 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 rundlerRequest(bundlerUrl, method, unsupported) {
235287
+ if (unsupported.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({ jsonrpc: "2.0", id: 1, method, params: [] })
235293
+ });
235294
+ const { result, error } = await response.json();
235295
+ if (error) {
235296
+ if (error.code !== void 0 && UNSUPPORTED_REQUEST_CODES.has(error.code)) {
235297
+ unsupported.add(bundlerUrl);
235298
+ }
235299
+ return null;
235300
+ }
235301
+ return result ?? null;
235302
+ } catch {
235303
+ return null;
235304
+ }
235305
+ }
235306
+ async function fetchRundlerPriorityFee(bundlerUrl) {
235307
+ const result = await rundlerRequest(
235308
+ bundlerUrl,
235309
+ BundlerMethod.RUNDLER_MAX_PRIORITY_FEE_PER_GAS,
235310
+ bundlersWithoutRundlerFees
235311
+ );
235312
+ try {
235313
+ return result == null ? null : BigInt(result);
235314
+ } catch {
235315
+ return null;
235316
+ }
235317
+ }
235318
+ async function fetchRundlerSuggestedFees(bundlerUrl) {
235319
+ const result = await rundlerRequest(
235320
+ bundlerUrl,
235321
+ BundlerMethod.RUNDLER_GET_USER_OPERATION_GAS_PRICE,
235322
+ bundlersWithoutRundlerGasPrice
235323
+ );
235324
+ const suggested = result?.suggested;
235325
+ if (suggested?.maxFeePerGas == null || suggested.maxPriorityFeePerGas == null) return null;
235326
+ try {
235327
+ return {
235328
+ maxFeePerGas: BigInt(suggested.maxFeePerGas),
235329
+ maxPriorityFeePerGas: BigInt(suggested.maxPriorityFeePerGas)
235330
+ };
235331
+ } catch {
235332
+ return null;
235333
+ }
235334
+ }
235335
+ async function rundlerUserOperationFees(bundlerUrl, fees4, params) {
235336
+ const { baseFeePerGas, priorityFeeBumpPercent, maxFeeBumpPercent } = params;
235337
+ const suggested = await fetchRundlerSuggestedFees(bundlerUrl);
235338
+ if (suggested) {
235339
+ return {
235340
+ maxFeePerGas: suggested.maxFeePerGas + suggested.maxFeePerGas * maxFeeBumpPercent / 100n,
235341
+ maxPriorityFeePerGas: suggested.maxPriorityFeePerGas + suggested.maxPriorityFeePerGas * priorityFeeBumpPercent / 100n
235342
+ };
235343
+ }
235344
+ const rundlerPriorityFee = await fetchRundlerPriorityFee(bundlerUrl);
235345
+ if (rundlerPriorityFee === null) return fees4;
235346
+ return applyRundlerPriorityFee(fees4, {
235347
+ rundlerPriorityFee,
235348
+ baseFeePerGas,
235349
+ priorityFeeBumpPercent,
235350
+ maxFeeBumpPercent
235351
+ });
235352
+ }
235353
+ function applyRundlerPriorityFee(fees4, params) {
235354
+ const { rundlerPriorityFee, baseFeePerGas, priorityFeeBumpPercent, maxFeeBumpPercent } = params;
235355
+ const priorityFloor = rundlerPriorityFee + rundlerPriorityFee * priorityFeeBumpPercent / 100n;
235356
+ const maxFeeFloor = baseFeePerGas + baseFeePerGas * maxFeeBumpPercent / 100n + priorityFloor;
235357
+ return {
235358
+ maxPriorityFeePerGas: fees4.maxPriorityFeePerGas > priorityFloor ? fees4.maxPriorityFeePerGas : priorityFloor,
235359
+ maxFeePerGas: fees4.maxFeePerGas > maxFeeFloor ? fees4.maxFeePerGas : maxFeeFloor
235360
+ };
235361
+ }
235240
235362
  function escrowSlot(commitment, leg) {
235241
235363
  const byCommitment = keccak2563(
235242
235364
  encodeAbiParameters2([{ type: "bytes32" }, { type: "uint256" }], [commitment, ESCROW_MAPPING_SLOT])
@@ -235422,7 +235544,7 @@ function encodePhantomBidDeclaration(declaration) {
235422
235544
  }
235423
235545
  return u8aToHex(new Uint8Array(bytes5));
235424
235546
  }
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;
235547
+ 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, bundlersWithoutRundlerGasPrice, 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
235548
  var init_node10 = __esm({
235427
235549
  "../sdk/dist/node/index.js"() {
235428
235550
  "use strict";
@@ -237775,6 +237897,9 @@ var init_node10 = __esm({
237775
237897
  default: { name: "Nile Tronscan", url: "https://nile.tronscan.org" }
237776
237898
  }
237777
237899
  });
237900
+ ENTRY_POINT_V08 = "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108";
237901
+ ENTRY_POINT_V09 = "0x433709009B8330FDa32311DF1C2AFA402eD8D009";
237902
+ KNOWN_ENTRY_POINTS = [ENTRY_POINT_V09, ENTRY_POINT_V08];
237778
237903
  chainConfigs = {
237779
237904
  97: {
237780
237905
  chainId: 97,
@@ -237807,11 +237932,14 @@ var init_node10 = __esm({
237807
237932
  UniversalRouter: "0xcc6d5ece3d4a57245bf5a2f64f3ed9179b81f714",
237808
237933
  UniswapV3Quoter: "0x0000000000000000000000000000000000000000",
237809
237934
  UniswapV4Quoter: "0x0000000000000000000000000000000000000000",
237810
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
237811
- SolverAccount: "0xf98E484858F59C30e31D2695ac18F92bc7C7b799"
237935
+ Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
237936
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
237937
+ SolverAccount: "0x7484C6Ff790b898bf7e6960Ffc82f63330445Dc2",
237938
+ SimplexPaymaster: "0x9f4a6F1254f27373C2aca5bDd0e48FbA45EA3aeC"
237812
237939
  },
237813
237940
  rpcEnvKey: "BSC_CHAPEL",
237814
237941
  defaultRpcUrl: "https://bnb-testnet.api.onfinality.io/public",
237942
+ bundlerUrl: "https://bundler.polytope.technology/bsc-chapel",
237815
237943
  consensusStateId: "BSC0",
237816
237944
  coingeckoId: "binance-smart-chain",
237817
237945
  popularTokens: [
@@ -237843,7 +237971,7 @@ var init_node10 = __esm({
237843
237971
  UniswapRouter02: "0x0000000000000000000000000000000000000000",
237844
237972
  UniswapV2Factory: "0x0000000000000000000000000000000000000000",
237845
237973
  UniswapV3Factory: "0x0000000000000000000000000000000000000000",
237846
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
237974
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
237847
237975
  },
237848
237976
  rpcEnvKey: "GNOSIS_CHIADO",
237849
237977
  defaultRpcUrl: "https://gnosis-chiado-rpc.publicnode.com",
@@ -237883,7 +238011,7 @@ var init_node10 = __esm({
237883
238011
  UniswapV2Factory: "0x0000000000000000000000000000000000000000",
237884
238012
  UniswapV3Factory: "0x0000000000000000000000000000000000000000",
237885
238013
  Calldispatcher: "0xC7f13b6D03A0A7F3239d38897503E90553ABe155",
237886
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238014
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
237887
238015
  },
237888
238016
  rpcEnvKey: "SEPOLIA",
237889
238017
  defaultRpcUrl: "https://1rpc.io/sepolia",
@@ -237934,7 +238062,7 @@ var init_node10 = __esm({
237934
238062
  },
237935
238063
  addresses: {
237936
238064
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
237937
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238065
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
237938
238066
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
237939
238067
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
237940
238068
  UniswapRouter02: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
@@ -237948,13 +238076,14 @@ var init_node10 = __esm({
237948
238076
  UniswapV4StateView: "0x7ffe42c4a5deea5b0fec41c94c136cf115597227",
237949
238077
  Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
237950
238078
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
237951
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238079
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
237952
238080
  CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
237953
238081
  SimplexPaymaster: "0xD4340d7466e040626383cb9cda9307ba8E081149",
237954
238082
  Usdt0Oft: "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee"
237955
238083
  },
237956
238084
  rpcEnvKey: "ETH_MAINNET",
237957
238085
  defaultRpcUrl: "https://eth-mainnet.g.alchemy.com/v2/demo",
238086
+ bundlerUrl: "https://bundler.polytope.technology/ethereum",
237958
238087
  consensusStateId: "ETH0",
237959
238088
  coingeckoId: "ethereum",
237960
238089
  layerZeroEid: 30101,
@@ -237980,7 +238109,8 @@ var init_node10 = __esm({
237980
238109
  USDC: "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d",
237981
238110
  USDT: "0x55d398326f99059ff775485246999027b3197955",
237982
238111
  EXT: "0x7C8c11ADb8EF7cd3CFa718008Ea048445C6E7209",
237983
- cNGN: "0xa8AEA66B361a8d53e8865c62D142167Af28Af058"
238112
+ cNGN: "0xa8AEA66B361a8d53e8865c62D142167Af28Af058",
238113
+ BRIDGE: "0x5b0c50fDd52ECC0d4c682c441eaBaD41FfDEABBB"
237984
238114
  },
237985
238115
  tokenDecimals: {
237986
238116
  USDC: 18,
@@ -237989,19 +238119,21 @@ var init_node10 = __esm({
237989
238119
  // Binance-pegged stables above. Every phantom standard_amount and pool rate divides
237990
238120
  // by this, so the divergence from its neighbours here is load-bearing, not a typo.
237991
238121
  cNGN: 6,
237992
- EXT: 18
238122
+ EXT: 18,
238123
+ BRIDGE: 18
237993
238124
  },
237994
238125
  tokenStorageSlots: {
237995
238126
  USDT: { balanceSlot: 1, allowanceSlot: 2 },
237996
238127
  USDC: { balanceSlot: 1, allowanceSlot: 2 },
237997
238128
  WETH: { balanceSlot: 3, allowanceSlot: 4 },
237998
238129
  DAI: { balanceSlot: 0, allowanceSlot: 0 },
237999
- cNGN: { balanceSlot: 201, allowanceSlot: 202 }
238130
+ cNGN: { balanceSlot: 201, allowanceSlot: 202 },
238000
238131
  // custom upgradeable layout, as on Base
238132
+ BRIDGE: { balanceSlot: 0, allowanceSlot: 1 }
238001
238133
  },
238002
238134
  addresses: {
238003
238135
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
238004
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238136
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
238005
238137
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
238006
238138
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238007
238139
  UniswapRouter02: "0x10ED43C718714eb63d5aA57B78B54704E256024E",
@@ -238015,12 +238147,13 @@ var init_node10 = __esm({
238015
238147
  UniswapV4StateView: "0xd13dd3d6e93f276fafc9db9e6bb47c1180aee0c4",
238016
238148
  Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
238017
238149
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238018
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238150
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
238019
238151
  SimplexPaymaster: "0xeD02f9f0df8F562B89cC5b25867Ad3C2d61252A9"
238020
238152
  // "Usdt0Oft": Not available on BSC
238021
238153
  },
238022
238154
  rpcEnvKey: "BSC_MAINNET",
238023
238155
  defaultRpcUrl: "https://bsc-rpc.publicnode.com",
238156
+ bundlerUrl: "https://bundler.polytope.technology/bsc",
238024
238157
  consensusStateId: "BSC0",
238025
238158
  coingeckoId: "binance-smart-chain",
238026
238159
  erc4626Vaults: [
@@ -238062,7 +238195,7 @@ var init_node10 = __esm({
238062
238195
  },
238063
238196
  addresses: {
238064
238197
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
238065
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238198
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
238066
238199
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
238067
238200
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238068
238201
  UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
@@ -238076,13 +238209,14 @@ var init_node10 = __esm({
238076
238209
  UniswapV4StateView: "0x76fd297e2d437cd7f76d50f01afe6160f86e9990",
238077
238210
  Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
238078
238211
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238079
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238212
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
238080
238213
  CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
238081
238214
  SimplexPaymaster: "0x7281Bccb4f0BCE44F3B8542d1fC5e51c2F5fC08C",
238082
238215
  Usdt0Oft: "0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92"
238083
238216
  },
238084
238217
  rpcEnvKey: "ARBITRUM_MAINNET",
238085
238218
  defaultRpcUrl: "https://arbitrum-one.public.blastapi.io",
238219
+ bundlerUrl: "https://bundler.polytope.technology/arbitrum",
238086
238220
  consensusStateId: "ETH0",
238087
238221
  coingeckoId: "arbitrum-one",
238088
238222
  layerZeroEid: 30110,
@@ -238136,7 +238270,7 @@ var init_node10 = __esm({
238136
238270
  },
238137
238271
  addresses: {
238138
238272
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
238139
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238273
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
238140
238274
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
238141
238275
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238142
238276
  UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
@@ -238147,7 +238281,7 @@ var init_node10 = __esm({
238147
238281
  UniswapV4Quoter: "0x0d5e0f971ed27fbff6c2837bf31316121532048d",
238148
238282
  Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
238149
238283
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238150
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238284
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
238151
238285
  CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
238152
238286
  SimplexPaymaster: "0x15b3B03C870c7ef252029c35A12d3b339F5c8d7f",
238153
238287
  AerodromeRouter: "0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43",
@@ -238158,6 +238292,7 @@ var init_node10 = __esm({
238158
238292
  },
238159
238293
  rpcEnvKey: "BASE_MAINNET",
238160
238294
  defaultRpcUrl: "https://base-mainnet.public.blastapi.io",
238295
+ bundlerUrl: "https://bundler.polytope.technology/base",
238161
238296
  consensusStateId: "ETH0",
238162
238297
  coingeckoId: "base",
238163
238298
  layerZeroEid: 30184,
@@ -238186,7 +238321,8 @@ var init_node10 = __esm({
238186
238321
  cNGN: "0x52828daa48C1a9A06F37500882b42daf0bE04C3B",
238187
238322
  ZARP: "0xb755506531786C8aC63B756BaB1ac387bACB0C04",
238188
238323
  XSGD: "0xDC3326e71D45186F113a2F448984CA0e8D201995",
238189
- USDR: "0x3B5F2810fB2168FfA9C73160F97BF9f2461fFa5c"
238324
+ USDR: "0x3B5F2810fB2168FfA9C73160F97BF9f2461fFa5c",
238325
+ BRIDGE: "0x5b0c50fDd52ECC0d4c682c441eaBaD41FfDEABBB"
238190
238326
  },
238191
238327
  tokenDecimals: {
238192
238328
  USDC: 6,
@@ -238195,7 +238331,8 @@ var init_node10 = __esm({
238195
238331
  cNGN: 6,
238196
238332
  ZARP: 18,
238197
238333
  XSGD: 6,
238198
- USDR: 6
238334
+ USDR: 6,
238335
+ BRIDGE: 18
238199
238336
  },
238200
238337
  tokenStorageSlots: {
238201
238338
  USDT: { balanceSlot: 0, allowanceSlot: 1 },
@@ -238206,11 +238343,12 @@ var init_node10 = __esm({
238206
238343
  // custom upgradeable layout
238207
238344
  ZARP: { balanceSlot: 51, allowanceSlot: 52 },
238208
238345
  XSGD: { balanceSlot: 7, allowanceSlot: 8 },
238209
- USDR: { balanceSlot: 51, allowanceSlot: 52 }
238346
+ USDR: { balanceSlot: 51, allowanceSlot: 52 },
238347
+ BRIDGE: { balanceSlot: 0, allowanceSlot: 1 }
238210
238348
  },
238211
238349
  addresses: {
238212
238350
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
238213
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238351
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
238214
238352
  TokenGateway: "0x8b536105b6Fae2aE9199f5146D3C57Dfe53b614E",
238215
238353
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238216
238354
  UniswapRouter02: "0xd2f9496824951D5237cC71245D659E48d0d5f9E8",
@@ -238224,13 +238362,14 @@ var init_node10 = __esm({
238224
238362
  UniswapV4StateView: "0x5ea1bd7974c8a611cbab0bdcafcb1d9cc9b3ba5a",
238225
238363
  Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
238226
238364
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238227
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238365
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
238228
238366
  CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
238229
238367
  SimplexPaymaster: "0xe99acFe0f5fC4C8ea54A187D8D3b05f136150095",
238230
238368
  Usdt0Oft: "0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13"
238231
238369
  },
238232
238370
  rpcEnvKey: "POLYGON_MAINNET",
238233
238371
  defaultRpcUrl: "https://polygon-bor-rpc.publicnode.com",
238372
+ bundlerUrl: "https://bundler.polytope.technology/polygon",
238234
238373
  consensusStateId: "POLY",
238235
238374
  coingeckoId: "polygon-pos",
238236
238375
  layerZeroEid: 30109,
@@ -238303,11 +238442,13 @@ var init_node10 = __esm({
238303
238442
  Host: "0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1",
238304
238443
  Calldispatcher: "0x876F1891982E260026630c233A4897160A281Fb8",
238305
238444
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238306
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238307
- SolverAccount: "0xf98E484858F59C30e31D2695ac18F92bc7C7b799"
238445
+ EntryPoint: "0x433709009B8330FDa32311DF1C2AFA402eD8D009",
238446
+ SolverAccount: "0x7484C6Ff790b898bf7e6960Ffc82f63330445Dc2",
238447
+ SimplexPaymaster: "0x6085a14078B7d26259145a894140f7C8361e02ae"
238308
238448
  },
238309
238449
  rpcEnvKey: "POLYGON_AMOY",
238310
238450
  defaultRpcUrl: "https://rpc-amoy.polygon.technology",
238451
+ bundlerUrl: "https://bundler.polytope.technology/polygon-amoy",
238311
238452
  consensusStateId: "POLY",
238312
238453
  coingeckoId: "polygon-pos"
238313
238454
  },
@@ -238336,7 +238477,7 @@ var init_node10 = __esm({
238336
238477
  UniswapV3Factory: "0x1F98431c8aD98523631AE4a59f267346ea31F984",
238337
238478
  Calldispatcher: "0xC71251c8b3e7B02697A84363Eef6DcE8DfBdF333",
238338
238479
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
238339
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238480
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238340
238481
  CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
238341
238482
  UniswapV4PositionManager: "0x3c3ea4b57a46241e54610e5f022e5c45859a1017",
238342
238483
  UniswapV4PoolManager: "0x9a13f98cb987694c9f086b1f5eb990eea8264ec3"
@@ -238370,7 +238511,7 @@ var init_node10 = __esm({
238370
238511
  // Mocked
238371
238512
  UniswapV2Factory: "0x0000000000000000000000000000000000000000",
238372
238513
  Calldispatcher: "0xC71251c8b3e7B02697A84363Eef6DcE8DfBdF333",
238373
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238514
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238374
238515
  },
238375
238516
  defaultRpcUrl: "https://rpc.gnosischain.com",
238376
238517
  consensusStateId: "GNO0",
@@ -238395,7 +238536,7 @@ var init_node10 = __esm({
238395
238536
  addresses: {
238396
238537
  TokenGateway: "0xCe304770236f39F9911BfCC51afBdfF3b8635718",
238397
238538
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238398
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238539
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
238399
238540
  UniswapV4PositionManager: "0x1b35d13a2e2528f192637f14b05f0dc0e7deb566",
238400
238541
  UniswapV4PoolManager: "0x360e68faccca8ca495c1b759fd9eee466db9fb32"
238401
238542
  },
@@ -238421,7 +238562,7 @@ var init_node10 = __esm({
238421
238562
  addresses: {
238422
238563
  TokenGateway: "0xFcDa26cA021d5535C3059547390E6cCd8De7acA6",
238423
238564
  Host: "0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1",
238424
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238565
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238425
238566
  },
238426
238567
  defaultRpcUrl: "https://sepolia-rollup.arbitrum.io/rpc",
238427
238568
  consensusStateId: "ETH0",
@@ -238445,7 +238586,7 @@ var init_node10 = __esm({
238445
238586
  addresses: {
238446
238587
  TokenGateway: "0xFcDa26cA021d5535C3059547390E6cCd8De7acA6",
238447
238588
  Host: "0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1",
238448
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238589
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238449
238590
  },
238450
238591
  defaultRpcUrl: "https://sepolia.optimism.io",
238451
238592
  consensusStateId: "ETH0",
@@ -238469,7 +238610,7 @@ var init_node10 = __esm({
238469
238610
  addresses: {
238470
238611
  TokenGateway: "0xFcDa26cA021d5535C3059547390E6cCd8De7acA6",
238471
238612
  Host: "0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1",
238472
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238613
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238473
238614
  },
238474
238615
  defaultRpcUrl: "https://sepolia.base.org",
238475
238616
  consensusStateId: "ETH0",
@@ -238495,7 +238636,7 @@ var init_node10 = __esm({
238495
238636
  IntentGateway: "0x606ba811aa6cb424ce2108e8977c5284686f0d1f",
238496
238637
  TokenGateway: "0x1c1e5be83df4a54c7a2230c337e4a3e8b7354b1c",
238497
238638
  Host: "0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1",
238498
- EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238639
+ EntryPoint: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
238499
238640
  },
238500
238641
  defaultRpcUrl: "https://testnet-asset-hub-eth-rpc.polkadot.io",
238501
238642
  consensusStateId: "PAS0",
@@ -238519,7 +238660,7 @@ var init_node10 = __esm({
238519
238660
  },
238520
238661
  addresses: {
238521
238662
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
238522
- SolverAccount: "0x77c3394CA5881A74f18139AC87D0c11F8Faa90cC",
238663
+ SolverAccount: "0xaAd062555800a97Af062795189e32a3CBd045612",
238523
238664
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
238524
238665
  Calldispatcher: "0xE2C7e576E26E0bE7aC97c6fE925bcDAbD87c4bEd"
238525
238666
  },
@@ -239924,9 +240065,9 @@ var init_node10 = __esm({
239924
240065
  internalType: "bytes32"
239925
240066
  },
239926
240067
  {
239927
- name: "solver",
239928
- type: "address",
239929
- internalType: "address"
240068
+ name: "userOpHash",
240069
+ type: "bytes32",
240070
+ internalType: "bytes32"
239930
240071
  },
239931
240072
  {
239932
240073
  name: "signature",
@@ -240972,8 +241113,8 @@ var init_node10 = __esm({
240972
241113
  getPopularTokens(chain2) {
240973
241114
  return this.getConfig(chain2)?.popularTokens ?? [];
240974
241115
  }
240975
- getEntryPointV08Address(chain2) {
240976
- return this.getConfig(chain2)?.addresses.EntryPointV08;
241116
+ getEntryPointAddress(chain2) {
241117
+ return this.getConfig(chain2)?.addresses.EntryPoint;
240977
241118
  }
240978
241119
  getCirclePaymasterAddress(chain2) {
240979
241120
  return this.getConfig(chain2)?.addresses.CirclePaymaster;
@@ -242053,7 +242194,7 @@ var init_node10 = __esm({
242053
242194
  * This is the only public way to construct an `EvmChain` — the constructor is private.
242054
242195
  *
242055
242196
  * @param rpcUrl - HTTP(S) RPC URL of the EVM node
242056
- * @param bundlerUrl - Optional ERC-4337 bundler URL for account abstraction support
242197
+ * @param bundlerUrl - Optional ERC-4337 bundler URL; defaults to Hyperbridge's bundler for the chain
242057
242198
  * @returns A fully initialised `EvmChain` ready for use
242058
242199
  * @throws If the chain ID returned by the RPC is not a known Hyperbridge deployment
242059
242200
  *
@@ -242079,8 +242220,12 @@ var init_node10 = __esm({
242079
242220
  get host() {
242080
242221
  return this.params.host;
242081
242222
  }
242223
+ /**
242224
+ * The bundler given to this chain, or else the one Hyperbridge runs for it.
242225
+ * Undefined on a chain Hyperbridge runs no bundler for.
242226
+ */
242082
242227
  get bundlerUrl() {
242083
- return this.params.bundlerUrl;
242228
+ return this.params.bundlerUrl ?? chainConfigs[this.params.chainId]?.bundlerUrl;
242084
242229
  }
242085
242230
  get config() {
242086
242231
  return {
@@ -243235,6 +243380,9 @@ Failed HTTP Request: ${JSON.stringify(
243235
243380
  * fails on-chain, and a second `retractBid` that pulls the bid just placed. When the signed nonce
243236
243381
  * cannot be read, the stalled result is returned rather than guessed at.
243237
243382
  *
243383
+ * A stall in `Future` first fills the missing nonce below it ({@link fillNonceGap}), so the
243384
+ * replacement can land.
243385
+ *
243238
243386
  * A rejection that bounced off a copy already pooled (1013/1014) is likewise left alone: that
243239
243387
  * copy is in flight and its outcome is unknown here, so the `pending` result goes back to the
243240
243388
  * caller to confirm later.
@@ -243259,6 +243407,7 @@ Failed HTTP Request: ${JSON.stringify(
243259
243407
  stalled = result;
243260
243408
  nonce ?? (nonce = this.signedNonce(extrinsic));
243261
243409
  if (nonce === void 0) return result;
243410
+ if (result.future) await this.fillNonceGap(keyPair, nonce, timeoutMs);
243262
243411
  continue;
243263
243412
  }
243264
243413
  if (result.pending) return stalled ?? result;
@@ -243298,19 +243447,6 @@ Failed HTTP Request: ${JSON.stringify(
243298
243447
  const inFlight = code === 1013 || code === 1014 || /already imported|already in the pool|priority is too low/i.test(err.message);
243299
243448
  return { success: false, pending: inFlight || void 0, error: err.message };
243300
243449
  }
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
243450
  /**
243315
243451
  * The nonce the next submission signs with, or undefined when the node cannot be asked.
243316
243452
  *
@@ -243327,6 +243463,7 @@ Failed HTTP Request: ${JSON.stringify(
243327
243463
  * queued as future, or simply not counted yet — is covered by `lastPooledNonce` instead, which
243328
243464
  * is the highest nonce this instance has put into the pool. The two are combined rather than
243329
243465
  * trusted separately, so a burst never reuses a nonce and a restart still picks up the chain's.
243466
+ * A nonce left missing by an extrinsic the node dropped is filled by {@link fillNonceGap}.
243330
243467
  */
243331
243468
  async nextNonce(api) {
243332
243469
  try {
@@ -243340,11 +243477,53 @@ Failed HTTP Request: ${JSON.stringify(
243340
243477
  return void 0;
243341
243478
  }
243342
243479
  }
243480
+ /**
243481
+ * A stall in `Future` means the node is missing a lower nonce of this account's, one whose
243482
+ * extrinsic it dropped, and everything signed above that nonce waits behind it. This fills the
243483
+ * lowest missing nonce, which `system_accountNextIndex` reports on the same node, with a
243484
+ * `system.remark` rather than the next call, so the calls already pooled above it land in the
243485
+ * order they were signed. One nonce per stall; a further gap shows up as the next `Future` stall.
243486
+ *
243487
+ * The remark carries no tip, so on any node or pool view that still holds a live call of ours at
243488
+ * that nonce, the call outranks it and the remark only ever fills a real gap.
243489
+ *
243490
+ * It runs inside the submission queue, so it submits directly rather than enqueueing, and gives
243491
+ * up after `timeoutMs` so a silent socket cannot hold the queue. A failure or timeout is logged
243492
+ * and left to the next stall.
243493
+ */
243494
+ async fillNonceGap(keyPair, nonce, timeoutMs) {
243495
+ const fill = async () => {
243496
+ const accountNextIndex = this.api.rpc?.system?.accountNextIndex;
243497
+ if (!accountNextIndex) return;
243498
+ const missing = Number((await accountNextIndex(keyPair.address)).toString());
243499
+ if (!Number.isFinite(missing) || missing >= nonce) return;
243500
+ await this.api.tx.system.remark("0x").signAndSend(keyPair, { tip: 0n, nonce: missing });
243501
+ };
243502
+ try {
243503
+ await Promise.race([fill(), rejectAfter(timeoutMs, `Timed out after ${timeoutMs}ms`)]);
243504
+ } catch (err) {
243505
+ console.warn(`Could not fill the nonce gap below ${nonce}:`, err);
243506
+ }
243507
+ }
243508
+ /**
243509
+ * Sends an extrinsic with a timeout.
243510
+ *
243511
+ * A timeout is only a failure when the extrinsic never made it into the transaction pool.
243512
+ * Once a pool-entry status (Future/Ready/Broadcast/Retracted) has been seen, the extrinsic is
243513
+ * in flight and may well execute after the watch is abandoned — the result is then `pending`
243514
+ * and `stalled`, telling the caller to replace it under the same nonce or confirm it later,
243515
+ * never to re-sign the same call under a fresh one.
243516
+ *
243517
+ * `nonce` pins the submission to a specific account nonce, which is what makes a retry a pool
243518
+ * replacement rather than a second extrinsic queued behind the first. Left undefined on the
243519
+ * first attempt, where the api's auto-nonce is correct.
243520
+ */
243343
243521
  async sendWithTimeout(extrinsic, keyPair, tip, timeoutMs, nonce) {
243344
243522
  return new Promise((resolve12) => {
243345
243523
  let resolved = false;
243346
243524
  let unsubscribe = null;
243347
243525
  let enteredPool = false;
243526
+ let inFuture = false;
243348
243527
  const timeoutId = setTimeout(() => {
243349
243528
  if (!resolved) {
243350
243529
  resolved = true;
@@ -243355,6 +243534,7 @@ Failed HTTP Request: ${JSON.stringify(
243355
243534
  success: false,
243356
243535
  pending: enteredPool || void 0,
243357
243536
  stalled: enteredPool || void 0,
243537
+ future: enteredPool && inFuture || void 0,
243358
243538
  extrinsicHash: enteredPool ? extrinsic.hash.toHex() : void 0,
243359
243539
  error: `Transaction timed out after ${timeoutMs}ms${enteredPool ? " while in the transaction pool" : ""}`
243360
243540
  });
@@ -243364,6 +243544,7 @@ Failed HTTP Request: ${JSON.stringify(
243364
243544
  if (resolved) return;
243365
243545
  if (result.status.isFuture || result.status.isReady || result.status.isBroadcast || result.status.isRetracted) {
243366
243546
  enteredPool = true;
243547
+ inFuture = result.status.isFuture;
243367
243548
  }
243368
243549
  if (result.dispatchError && (result.status.isInBlock || result.status.isFinalized)) {
243369
243550
  resolved = true;
@@ -246654,12 +246835,13 @@ query OrderStatus($commitment: String!) {
246654
246835
  ETH_GET_USER_OPERATION_RECEIPT: "eth_getUserOperationReceipt",
246655
246836
  /** Estimates gas limits for a UserOperation before submission. */
246656
246837
  ETH_ESTIMATE_USER_OPERATION_GAS: "eth_estimateUserOperationGas",
246657
- /** Pimlico-specific method to fetch recommended EIP-1559 gas prices for UserOperations. */
246658
- PIMLICO_GET_USER_OPERATION_GAS_PRICE: "pimlico_getUserOperationGasPrice",
246659
- /** Alchemy (Rundler) method to fetch recommended priority fee for UserOperations. */
246660
- RUNDLER_MAX_PRIORITY_FEE_PER_GAS: "rundler_maxPriorityFeePerGas"
246838
+ /** Rundler method returning the priority fee it requires of UserOperations. */
246839
+ RUNDLER_MAX_PRIORITY_FEE_PER_GAS: "rundler_maxPriorityFeePerGas",
246840
+ /** Rundler method returning the fees it requires and suggests for UserOperations. */
246841
+ RUNDLER_GET_USER_OPERATION_GAS_PRICE: "rundler_getUserOperationGasPrice"
246661
246842
  };
246662
- SELECT_SOLVER_TYPEHASH = keccak2563(toHex3("SelectSolver(bytes32 commitment,address solver)"));
246843
+ SELECT_SOLVER_TYPEHASH = keccak2563(toHex3("SelectSolver(bytes32 commitment,bytes32 userOpHash)"));
246844
+ LEGACY_SELECT_SOLVER_TYPEHASH = keccak2563(toHex3("SelectSolver(bytes32 commitment,address solver)"));
246663
246845
  PACKED_USEROP_TYPEHASH = keccak2563(
246664
246846
  toHex3(
246665
246847
  "PackedUserOperation(address sender,uint256 nonce,bytes initCode,bytes callData,bytes32 accountGasLimits,uint256 preVerificationGas,bytes32 gasFees,bytes paymasterAndData)"
@@ -246698,29 +246880,50 @@ query OrderStatus($commitment: String!) {
246698
246880
  );
246699
246881
  }
246700
246882
  /**
246701
- * Signs a `SelectSolver` EIP-712 message with a session key.
246883
+ * Signs `SelectSolver(bytes32 commitment,bytes32 userOpHash)` with the
246884
+ * order's session key, for gateways whose `SELECT_SOLVER_TYPEHASH` is
246885
+ * {@link SELECT_SOLVER_TYPEHASH}.
246702
246886
  *
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.
246887
+ * The signature selects one bid UserOperation for the order and is appended
246888
+ * to that operation's signature before it is sent to the bundler.
246706
246889
  *
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.
246890
+ * @param commitment - The order commitment.
246891
+ * @param userOpHash - EntryPoint userOpHash of the selected bid UserOperation.
246892
+ * @param domainSeparator - EIP-712 domain separator of the IntentGatewayV2 contract.
246893
+ * @param privateKey - Private key of the order's session key.
246894
+ * @returns The 65-byte ECDSA signature.
246712
246895
  */
246713
- static async signSolverSelection(commitment, solverAddress, domainSeparator2, privateKey) {
246714
- const account5 = privateKeyToAccount(privateKey);
246896
+ static async signUserOpHashSelection(commitment, userOpHash, domainSeparator2, privateKey) {
246897
+ const structHash = keccak2563(
246898
+ encodeAbiParameters2(
246899
+ [{ type: "bytes32" }, { type: "bytes32" }, { type: "bytes32" }],
246900
+ [SELECT_SOLVER_TYPEHASH, commitment, userOpHash]
246901
+ )
246902
+ );
246903
+ return signTypedDigest(domainSeparator2, structHash, privateKey);
246904
+ }
246905
+ /**
246906
+ * Signs `SelectSolver(bytes32 commitment,address solver)` with the order's
246907
+ * session key, for gateways whose `SELECT_SOLVER_TYPEHASH` is
246908
+ * {@link LEGACY_SELECT_SOLVER_TYPEHASH}.
246909
+ *
246910
+ * The signature selects a solver account for the order and is appended to
246911
+ * that solver's bid UserOperation signature before it is sent to the bundler.
246912
+ *
246913
+ * @param commitment - The order commitment.
246914
+ * @param solverAddress - Address of the selected solver account.
246915
+ * @param domainSeparator - EIP-712 domain separator of the IntentGatewayV2 contract.
246916
+ * @param privateKey - Private key of the order's session key.
246917
+ * @returns The 65-byte ECDSA signature.
246918
+ */
246919
+ static async signLegacySolverSelection(commitment, solverAddress, domainSeparator2, privateKey) {
246715
246920
  const structHash = keccak2563(
246716
246921
  encodeAbiParameters2(
246717
246922
  [{ type: "bytes32" }, { type: "bytes32" }, { type: "address" }],
246718
- [SELECT_SOLVER_TYPEHASH, commitment, solverAddress]
246923
+ [LEGACY_SELECT_SOLVER_TYPEHASH, commitment, solverAddress]
246719
246924
  )
246720
246925
  );
246721
- const digest = keccak2563(concat3(["0x1901", domainSeparator2, structHash]));
246722
- const signature = await account5.sign({ hash: digest });
246723
- return signature;
246926
+ return signTypedDigest(domainSeparator2, structHash, privateKey);
246724
246927
  }
246725
246928
  /**
246726
246929
  * Computes the EIP-712 hash of a `PackedUserOperation` as defined by
@@ -247247,16 +247450,13 @@ query OrderStatus($commitment: String!) {
247247
247450
  }
247248
247451
  /**
247249
247452
  * Creates a closure that computes the deduplication hash key for a
247250
- * UserOperation, pre-bound to the order's destination chain and entry point.
247453
+ * UserOperation, pre-bound to the destination chain.
247251
247454
  */
247252
- createUserOpHasher(order) {
247253
- const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(
247254
- normalizeStateMachineId(order.destination)
247255
- );
247455
+ createUserOpHasher() {
247256
247456
  const chainId = BigInt(
247257
247457
  this.ctx.dest.client.chain?.id ?? Number.parseInt(this.ctx.dest.config.stateMachineId.split("-")[1])
247258
247458
  );
247259
- return (userOp) => CryptoUtils.computeUserOpHash(userOp, entryPointAddress, chainId);
247459
+ return (userOp) => CryptoUtils.computeUserOpHash(userOp, ENTRY_POINT_V08, chainId);
247260
247460
  }
247261
247461
  /**
247262
247462
  * Fetches bids from the coprocessor for a given order commitment.
@@ -247372,7 +247572,7 @@ query OrderStatus($commitment: String!) {
247372
247572
  return;
247373
247573
  }
247374
247574
  const usedUserOps = await this.loadUsedUserOps(commitment);
247375
- const userOpHashKey = this.createUserOpHasher(order);
247575
+ const userOpHashKey = this.createUserOpHasher();
247376
247576
  const targetAssets = order.output.assets.map((a6) => ({ token: a6.token, amount: a6.amount }));
247377
247577
  let initial;
247378
247578
  try {
@@ -248236,7 +248436,8 @@ query OrderStatus($commitment: String!) {
248236
248436
  }, __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
248437
  __publicField(_a6, "SOURCE_GET_RESPONSE_GAS", 1000000n), __publicField(_a6, "REFUND_POST_GAS", 1000000n), _a6);
248238
248438
  FILL_ORDER_SELECTOR = "0x68ddf058";
248239
- SUPPORTED_INTENTS_VERSION = 3n;
248439
+ SUPPORTED_INTENTS_VERSION = 4n;
248440
+ TESTNET_INTENTS_VERSIONS = [3n, SUPPORTED_INTENTS_VERSION];
248240
248441
  CONTRACT_VERSION_ABI = [
248241
248442
  {
248242
248443
  type: "function",
@@ -248247,6 +248448,13 @@ query OrderStatus($commitment: String!) {
248247
248448
  }
248248
248449
  ];
248249
248450
  CANONICAL_EVM_TOKEN = /^0x0{24}[0-9a-fA-F]{40}$/;
248451
+ formats = /* @__PURE__ */ new Map();
248452
+ SELECTION_PARAMS_SLOT = pad4(toHex3(5n), { size: 32 });
248453
+ SOLVER_SELECTION_CLEARED = maxUint2563 ^ 0xffn << 160n;
248454
+ SELECTION_FORMAT_BY_ENTRY_POINT = /* @__PURE__ */ new Map([
248455
+ [ENTRY_POINT_V09.toLowerCase(), "userOpHash"],
248456
+ [ENTRY_POINT_V08.toLowerCase(), "address"]
248457
+ ]);
248250
248458
  ENTRY_POINT_EVENT_ABI = [
248251
248459
  { type: "event", name: "BeforeExecution", inputs: [] },
248252
248460
  {
@@ -248281,6 +248489,8 @@ query OrderStatus($commitment: String!) {
248281
248489
  __publicField(this, "domainSeparator");
248282
248490
  /** Cached session-key signature over the `SelectSolver` message. */
248283
248491
  __publicField(this, "cachedSignature");
248492
+ /** Cached result of {@link route}. */
248493
+ __publicField(this, "cachedRoute");
248284
248494
  this.ctx = params.ctx;
248285
248495
  this.crypto = params.crypto;
248286
248496
  this.order = params.order;
@@ -248310,69 +248520,117 @@ query OrderStatus($commitment: String!) {
248310
248520
  );
248311
248521
  }
248312
248522
  /**
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.
248523
+ * Finds the EntryPoint this bid's solver signed it for and checks that the
248524
+ * destination gateway's selection format pairs with it, reading the format
248525
+ * again before refusing a bid in case the gateway was upgraded since it was
248526
+ * cached. Caches the result.
248527
+ *
248528
+ * @throws If the solver's signature recovers under no known EntryPoint, the
248529
+ * EntryPoint does not pair with the gateway's selection format, or the
248530
+ * format cannot be read.
248531
+ */
248532
+ async route() {
248533
+ if (this.cachedRoute) return this.cachedRoute;
248534
+ const chainId = this.chainId();
248535
+ let signed;
248536
+ for (const entryPoint of KNOWN_ENTRY_POINTS) {
248537
+ const userOpHash = CryptoUtils.computeUserOpHash(this.userOp, entryPoint, chainId);
248538
+ if (await this.signedBySolver(userOpHash)) {
248539
+ signed = { entryPoint, userOpHash };
248540
+ break;
248541
+ }
248542
+ }
248543
+ if (!signed) {
248544
+ throw new Error(`Bid from solver=${this.solverAddress} is not signed for a known EntryPoint`);
248545
+ }
248546
+ const pairsWith = SELECTION_FORMAT_BY_ENTRY_POINT.get(signed.entryPoint.toLowerCase());
248547
+ const cached = readSelectionFormat(this.ctx.dest.client, chainId, this.intentGatewayV2Address);
248548
+ let format2 = await cached;
248549
+ if (pairsWith !== format2) {
248550
+ format2 = await refreshSelectionFormat(this.ctx.dest.client, chainId, this.intentGatewayV2Address, cached);
248551
+ }
248552
+ if (pairsWith !== format2) {
248553
+ throw new Error(
248554
+ `Bid from solver=${this.solverAddress} is signed for EntryPoint ${signed.entryPoint}, which the destination gateway's ${format2} selection does not pair with`
248555
+ );
248556
+ }
248557
+ this.cachedRoute = { ...signed, format: format2 };
248558
+ return this.cachedRoute;
248559
+ }
248560
+ /**
248561
+ * Whether the solver's signature in the bid, `signature[32:97]` after the order
248562
+ * commitment, recovers to the solver over `userOpHash`.
248563
+ */
248564
+ async signedBySolver(userOpHash) {
248565
+ try {
248566
+ const recovered = await recoverAddress3({
248567
+ hash: userOpHash,
248568
+ signature: slice4(this.userOp.signature, 32, 97)
248569
+ });
248570
+ return recovered.toLowerCase() === this.solverAddress.toLowerCase();
248571
+ } catch {
248572
+ return false;
248573
+ }
248574
+ }
248575
+ /**
248576
+ * Resolves the session key, signs the `SelectSolver` message for this bid in
248577
+ * the destination gateway's selection format, and caches the signature. Signs
248578
+ * at most once per bid.
248315
248579
  *
248316
- * @throws If the session key is missing or signing fails.
248580
+ * @throws If the bid cannot be routed, or the session key is missing.
248317
248581
  */
248318
248582
  async signSelection() {
248319
248583
  if (this.cachedSignature) return this.cachedSignature;
248584
+ const { format: format2, userOpHash } = await this.route();
248320
248585
  const commitment = this.order.id;
248321
248586
  const sessionKeyAddress = this.order.session;
248322
248587
  const sessionKeyData = this.sessionPrivateKey ? { privateKey: this.sessionPrivateKey } : await this.ctx.sessionKeyStorage.getSessionKeyByAddress(sessionKeyAddress);
248323
248588
  if (!sessionKeyData) {
248324
248589
  throw new Error(`SessionKey not found for commitment: ${commitment}`);
248325
248590
  }
248326
- const signature = await CryptoUtils.signSolverSelection(
248591
+ this.cachedSignature = format2 === "userOpHash" ? await CryptoUtils.signUserOpHashSelection(
248592
+ commitment,
248593
+ userOpHash,
248594
+ this.domainSeparator,
248595
+ sessionKeyData.privateKey
248596
+ ) : await CryptoUtils.signLegacySolverSelection(
248327
248597
  commitment,
248328
248598
  this.solverAddress,
248329
248599
  this.domainSeparator,
248330
248600
  sessionKeyData.privateKey
248331
248601
  );
248332
- if (!signature) {
248333
- throw new Error("Failed to sign solver selection");
248334
- }
248335
- this.cachedSignature = signature;
248336
- return signature;
248602
+ return this.cachedSignature;
248337
248603
  }
248338
248604
  /**
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.
248605
+ * Simulates this bid on-chain with an `eth_call` of its calldata from the
248606
+ * solver's account, after checking that the bid can be routed.
248607
+ *
248608
+ * The gateway's solver selection is turned off for the call with
248609
+ * {@link selectionOffStateDiff} and no `select` is made: a gateway that selects
248610
+ * by userOpHash checks the selection against the EntryPoint's current
248611
+ * operation, which only exists inside a bundle. The session's selection is
248612
+ * therefore not part of the simulation.
248342
248613
  *
248343
248614
  * The native value forwarded to the simulation is the sum of any native-token
248344
248615
  * (`address(0)`) output amounts plus the Hyperbridge dispatch fee.
248345
248616
  *
248346
- * @throws If the `eth_call` simulation reverts or errors.
248617
+ * @throws If the bid cannot be routed, or the `eth_call` simulation reverts or errors.
248347
248618
  */
248348
248619
  async simulate() {
248349
- const signature = await this.signSelection();
248350
- const selectOptions = {
248351
- commitment: this.order.id,
248352
- solver: this.solverAddress,
248353
- signature
248354
- };
248620
+ await this.route();
248355
248621
  const nativeOutputs = this.fillOptions.outputs.reduce(
248356
248622
  (acc, o6) => bytes32ToBytes20(o6.token) === ADDRESS_ZERO2 ? acc + o6.amount : acc,
248357
248623
  0n
248358
248624
  );
248359
248625
  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
248626
  try {
248627
+ const selectionOff = await selectionOffStateDiff(this.ctx.dest.client, this.intentGatewayV2Address);
248371
248628
  await this.ctx.dest.client.call({
248372
248629
  account: this.solverAddress,
248373
248630
  to: this.solverAddress,
248374
- data: batchedCalldata,
248375
- value: simulationValue
248631
+ data: this.userOp.callData,
248632
+ value: simulationValue,
248633
+ stateOverride: [{ address: this.intentGatewayV2Address, stateDiff: [selectionOff] }]
248376
248634
  });
248377
248635
  } catch (e4) {
248378
248636
  throw new Error(`Simulation failed: ${e4 instanceof Error ? e4.message : String(e4)}`);
@@ -248381,31 +248639,29 @@ query OrderStatus($commitment: String!) {
248381
248639
  /**
248382
248640
  * Signs the `SelectSolver` message with the session key, appends it to the
248383
248641
  * 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.
248642
+ * bundler on the EntryPoint the bid was signed for. Waits for the receipt and
248643
+ * reads `OrderFilled` / `PartialFill` logs to determine fill status.
248386
248644
  *
248387
248645
  * @returns A {@link SelectBidResult} with the submitted UserOperation, its hash,
248388
248646
  * 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.
248647
+ * @throws If the bundler is not configured, the bid cannot be routed, the
248648
+ * session key is missing, or the bundler rejects the UserOperation.
248391
248649
  */
248392
248650
  async execute() {
248393
248651
  const commitment = this.order.id;
248394
248652
  if (!this.ctx.bundlerUrl) {
248395
248653
  throw new Error("Bundler URL not configured");
248396
248654
  }
248655
+ const { entryPoint } = await this.route();
248397
248656
  const sessionSignature = await this.signSelection();
248398
248657
  const finalSignature = concat3([this.userOp.signature, sessionSignature]);
248399
248658
  const signedUserOp = {
248400
248659
  ...this.userOp,
248401
248660
  signature: finalSignature
248402
248661
  };
248403
- const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(
248404
- normalizeStateMachineId(this.order.destination)
248405
- );
248406
248662
  const userOpHash = await this.crypto.sendBundler(BundlerMethod.ETH_SEND_USER_OPERATION, [
248407
248663
  CryptoUtils.prepareBundlerCall(signedUserOp),
248408
- entryPointAddress
248664
+ entryPoint
248409
248665
  ]);
248410
248666
  let txnHash;
248411
248667
  let fillStatus;
@@ -248431,7 +248687,7 @@ query OrderStatus($commitment: String!) {
248431
248687
  );
248432
248688
  const fills = parseEventLogs2({
248433
248689
  abi: ABI3,
248434
- logs: userOperationLogs(chainReceipt.logs, entryPointAddress, userOpHash),
248690
+ logs: userOperationLogs(chainReceipt.logs, entryPoint, userOpHash),
248435
248691
  eventName: ["OrderFilled", "PartialFill"]
248436
248692
  }).filter(
248437
248693
  (event) => event.address.toLowerCase() === gateway.toLowerCase() && event.args.commitment.toLowerCase() === commitment.toLowerCase()
@@ -248483,12 +248739,15 @@ query OrderStatus($commitment: String!) {
248483
248739
  * Constructs a signed `PackedUserOperation` that a solver can submit to the
248484
248740
  * Hyperbridge coprocessor as a bid to fill an order.
248485
248741
  *
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.
248742
+ * The solver signs the operation as EIP-712 typed data for
248743
+ * `entryPointAddress`, whose digest is that EntryPoint's userOpHash. It must
248744
+ * be the EntryPoint the solver's `SolverAccount` accepts: the user's SDK
248745
+ * recovers it from this signature and executes the bid there. The binding
248746
+ * to the order lives in the operation itself: the 4337 nonce key must derive
248747
+ * from the order commitment, the session key and the calldata
248748
+ * (`SolverAccount` enforces this during validation), and the callData
248749
+ * carries the order. This keeps the signed payload fully transparent to
248750
+ * signing infrastructure instead of an opaque digest.
248492
248751
  *
248493
248752
  * @param options - Parameters describing the solver account, gas limits, fee
248494
248753
  * market values, and pre-built `callData` for the fill operation.
@@ -248521,7 +248780,7 @@ query OrderStatus($commitment: String!) {
248521
248780
  }
248522
248781
  const chain2 = normalizeStateMachineId(order.destination);
248523
248782
  const gateway = this.ctx.dest.configService.getIntentGatewayAddress(chain2);
248524
- if (!await supportsRateFills(this.ctx.dest.client, gateway)) {
248783
+ if (!await supportsRateFills(this.ctx.dest.client, gateway, chain2)) {
248525
248784
  throw new Error("Fills are not supported by the destination gateway");
248526
248785
  }
248527
248786
  const chainId = BigInt(
@@ -248561,6 +248820,11 @@ query OrderStatus($commitment: String!) {
248561
248820
  * silently dropped with a warning. The returned `Bid` instances are ready to
248562
248821
  * be ranked, simulated, and executed by the consumer.
248563
248822
  *
248823
+ * A bid signed for no known EntryPoint, or for one the destination gateway's
248824
+ * selection format does not pair with, is kept here and fails
248825
+ * {@link Bid.simulate} and {@link Bid.execute}, so {@link selectAndExecuteBest}
248826
+ * skips it.
248827
+ *
248564
248828
  * @param order - The placed order the bids are competing to fill.
248565
248829
  * @param bids - Raw filler bids fetched from the coprocessor.
248566
248830
  * @param sessionPrivateKey - Optional session-key override; looked up from
@@ -248853,12 +249117,16 @@ query OrderStatus($commitment: String!) {
248853
249117
  }
248854
249118
  }
248855
249119
  };
249120
+ UNSUPPORTED_REQUEST_CODES = /* @__PURE__ */ new Set([-32600, -32601, -32602]);
249121
+ bundlersWithoutRundlerFees = /* @__PURE__ */ new Set();
249122
+ bundlersWithoutRundlerGasPrice = /* @__PURE__ */ new Set();
248856
249123
  RELAYER_MESSAGE_GAS = 1000000n;
248857
249124
  NO_BUNDLER_FILL_GAS_BASE = 700000n;
248858
249125
  NO_BUNDLER_FILL_GAS_PER_OUTPUT = 150000n;
248859
249126
  NO_BUNDLER_PAYMASTER_VERIFICATION_GAS = 250000n;
248860
249127
  NO_BUNDLER_PAYMASTER_POST_OP_GAS = 100000n;
248861
249128
  BID_PVG_ESTIMATION_ACCOUNT_CODE = "0x60003560e01c631626ba7e1460145760206000f35b631626ba7e60e01b60005260206000f3";
249129
+ BID_PVG_ESTIMATION_PAYMASTER_CODE = "0x604060005260606000f3";
248862
249130
  SELECTED_BID_SIGNATURE_BYTES = 32 + 65 + 65;
248863
249131
  BID_PVG_HEADROOM_PERCENT = 10n;
248864
249132
  ESCROW_MAPPING_SLOT = 9n;
@@ -248872,8 +249140,6 @@ query OrderStatus($commitment: String!) {
248872
249140
  constructor(ctx, crypto10) {
248873
249141
  __publicField(this, "ctx");
248874
249142
  __publicField(this, "crypto");
248875
- /** Call dispatchers read from a gateway, for chains whose config carries none. */
248876
- __publicField(this, "dispatchers", /* @__PURE__ */ new Map());
248877
249143
  this.ctx = ctx;
248878
249144
  this.crypto = crypto10;
248879
249145
  }
@@ -248894,8 +249160,9 @@ query OrderStatus($commitment: String!) {
248894
249160
  * **Bundler path:** constructs a mock `PackedUserOperation` signed by an
248895
249161
  * ephemeral keypair, applies state overrides, and calls
248896
249162
  * `eth_estimateUserOperationGas`. Gas limits are bumped by 5-10% for
248897
- * headroom. If the bundler is Pimlico, gas prices are refined with
248898
- * `pimlico_getUserOperationGasPrice`. If the bundler rejects the estimate,
249163
+ * headroom. Fees are the rundler bundler's suggested fees raised by the bumps,
249164
+ * or the chain's gas price raised to the priority fee it requires where it
249165
+ * suggests none (see {@link rundlerUserOperationFees}). If the bundler rejects the estimate,
248899
249166
  * fixed gas limits are returned in its place, or the call throws when
248900
249167
  * `params.requireBundlerEstimate` is set.
248901
249168
  *
@@ -248930,7 +249197,7 @@ query OrderStatus($commitment: String!) {
248930
249197
  const souceStateMachineId = isHex3(order.source) ? hexToString2(order.source) : order.source;
248931
249198
  const destStateMachineId = isHex3(order.destination) ? hexToString2(order.destination) : order.destination;
248932
249199
  const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachineId);
248933
- const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(destStateMachineId);
249200
+ const entryPointAddress = this.ctx.dest.configService.getEntryPointAddress(destStateMachineId);
248934
249201
  const chainId = BigInt(Number.parseInt(destStateMachineId.split("-")[1]));
248935
249202
  const totalEthValue = quotedOutputs.filter((output3) => bytes32ToBytes20(output3.token) === ADDRESS_ZERO2).reduce((sum2, output3) => sum2 + output3.amount, 0n);
248936
249203
  const [sourceFeeToken, destFeeToken, gasPrice, latestBlock] = await Promise.all([
@@ -248992,7 +249259,7 @@ query OrderStatus($commitment: String!) {
248992
249259
  const maxFeeBumpPercent = params.maxFeePerGasBumpPercent ?? 10;
248993
249260
  let maxPriorityFeePerGas = gasPrice + gasPrice * BigInt(priorityFeeBumpPercent) / 100n;
248994
249261
  let maxFeePerGas = gasPrice + gasPrice * BigInt(maxFeeBumpPercent) / 100n;
248995
- await assertGatewayRelease(this.ctx.dest.client, intentGatewayV2Address);
249262
+ await assertGatewayRelease(this.ctx.dest.client, intentGatewayV2Address, destStateMachineId);
248996
249263
  const fillOrderCalldata = encodeFillOrder(transformOrderForContract(order), fillOptions);
248997
249264
  let callGasLimit = 500000n;
248998
249265
  let verificationGasLimit = 100000n;
@@ -249001,6 +249268,7 @@ query OrderStatus($commitment: String!) {
249001
249268
  let paymasterPostOpGasLimit = 0n;
249002
249269
  if (this.ctx.bundlerUrl) {
249003
249270
  try {
249271
+ if (!entryPointAddress) throw new Error(`No EntryPoint configured for ${destStateMachineId}`);
249004
249272
  const callData = this.crypto.encodeERC7821Execute([
249005
249273
  ...params.prependCalls ?? [],
249006
249274
  { target: intentGatewayV2Address, value: totalNativeValue, data: fillOrderCalldata }
@@ -249033,7 +249301,13 @@ query OrderStatus($commitment: String!) {
249033
249301
  chainId,
249034
249302
  intentGatewayV2Address
249035
249303
  );
249036
- const sessionSignature = await CryptoUtils.signSolverSelection(
249304
+ const selectionFormat = await readSelectionFormat(this.ctx.dest.client, chainId, intentGatewayV2Address);
249305
+ const sessionSignature = selectionFormat === "userOpHash" ? await CryptoUtils.signUserOpHashSelection(
249306
+ commitment,
249307
+ userOpHash,
249308
+ domainSeparator2,
249309
+ solverPrivateKey
249310
+ ) : await CryptoUtils.signLegacySolverSelection(
249037
249311
  commitment,
249038
249312
  solverAccountAddress,
249039
249313
  domainSeparator2,
@@ -249044,45 +249318,19 @@ query OrderStatus($commitment: String!) {
249044
249318
  sessionSignature
249045
249319
  ]);
249046
249320
  const bundlerUserOp = CryptoUtils.prepareBundlerCall(preliminaryUserOp);
249047
- const bundlerUrlLower = this.ctx.bundlerUrl.toLowerCase();
249048
- const isPimlico = bundlerUrlLower.includes("pimlico.io");
249049
- const isAlchemy = bundlerUrlLower.includes("alchemy.com");
249050
- const bundlerRequests = [
249321
+ const rundlerFeesRequest = rundlerUserOperationFees(
249322
+ this.ctx.bundlerUrl,
249323
+ { maxFeePerGas, maxPriorityFeePerGas },
249051
249324
  {
249052
- method: BundlerMethod.ETH_ESTIMATE_USER_OPERATION_GAS,
249053
- params: [bundlerUserOp, entryPointAddress, bundlerStateOverrides]
249054
- }
249055
- ];
249056
- if (isPimlico) {
249057
- bundlerRequests.push({
249058
- method: BundlerMethod.PIMLICO_GET_USER_OPERATION_GAS_PRICE,
249059
- params: []
249060
- });
249061
- }
249062
- if (isAlchemy) {
249063
- bundlerRequests.push({
249064
- method: BundlerMethod.RUNDLER_MAX_PRIORITY_FEE_PER_GAS,
249065
- params: []
249066
- });
249067
- }
249068
- let gasEstimate;
249069
- let pimlicoGasPrices = null;
249070
- let alchemyMaxPriorityFee = null;
249071
- try {
249072
- const batchResults = await this.crypto.sendBundlerBatch(bundlerRequests);
249073
- gasEstimate = batchResults[0];
249074
- if (isPimlico && batchResults.length > 1) {
249075
- pimlicoGasPrices = batchResults[1];
249076
- }
249077
- if (isAlchemy && batchResults.length > 1) {
249078
- alchemyMaxPriorityFee = batchResults[1];
249325
+ baseFeePerGas,
249326
+ priorityFeeBumpPercent: BigInt(priorityFeeBumpPercent),
249327
+ maxFeeBumpPercent: BigInt(maxFeeBumpPercent)
249079
249328
  }
249080
- } catch {
249081
- gasEstimate = await this.crypto.sendBundler(
249082
- BundlerMethod.ETH_ESTIMATE_USER_OPERATION_GAS,
249083
- [bundlerUserOp, entryPointAddress, bundlerStateOverrides]
249084
- );
249085
- }
249329
+ );
249330
+ const gasEstimate = await this.crypto.sendBundler(
249331
+ BundlerMethod.ETH_ESTIMATE_USER_OPERATION_GAS,
249332
+ [bundlerUserOp, entryPointAddress, bundlerStateOverrides]
249333
+ );
249086
249334
  callGasLimit = BigInt(gasEstimate.callGasLimit) * 160n / 100n;
249087
249335
  verificationGasLimit = BigInt(gasEstimate.verificationGasLimit) * 105n / 100n;
249088
249336
  preVerificationGas = BigInt(gasEstimate.preVerificationGas) * 105n / 100n;
@@ -249092,23 +249340,9 @@ query OrderStatus($commitment: String!) {
249092
249340
  if (gasEstimate.paymasterPostOpGasLimit) {
249093
249341
  paymasterPostOpGasLimit = BigInt(gasEstimate.paymasterPostOpGasLimit) * 105n / 100n;
249094
249342
  }
249095
- if (pimlicoGasPrices) {
249096
- const level = pimlicoGasPrices.fast ?? pimlicoGasPrices.standard ?? pimlicoGasPrices.slow ?? null;
249097
- if (level) {
249098
- const pimMaxFeePerGas = BigInt(level.maxFeePerGas);
249099
- const pimMaxPriorityFeePerGas = BigInt(level.maxPriorityFeePerGas);
249100
- maxFeePerGas = pimMaxFeePerGas + pimMaxFeePerGas * BigInt(maxFeeBumpPercent) / 100n;
249101
- maxPriorityFeePerGas = pimMaxPriorityFeePerGas + pimMaxPriorityFeePerGas * BigInt(priorityFeeBumpPercent) / 100n;
249102
- }
249103
- }
249104
- if (alchemyMaxPriorityFee) {
249105
- const rundlerPriorityFee = BigInt(alchemyMaxPriorityFee);
249106
- const isArbitrum = chainId === 42161n;
249107
- const alchemyPrioBump = isArbitrum ? 0n : 25n;
249108
- maxPriorityFeePerGas = rundlerPriorityFee + rundlerPriorityFee * alchemyPrioBump / 100n;
249109
- const bufferedBaseFee = baseFeePerGas + baseFeePerGas * 50n / 100n;
249110
- maxFeePerGas = bufferedBaseFee + maxPriorityFeePerGas;
249111
- }
249343
+ const rundlerFees = await rundlerFeesRequest;
249344
+ maxFeePerGas = rundlerFees.maxFeePerGas;
249345
+ maxPriorityFeePerGas = rundlerFees.maxPriorityFeePerGas;
249112
249346
  } catch (e4) {
249113
249347
  if (params.requireBundlerEstimate) {
249114
249348
  throw new Error(`Bundler gas estimation failed: ${e4 instanceof Error ? e4.message : String(e4)}`, {
@@ -249149,27 +249383,6 @@ query OrderStatus($commitment: String!) {
249149
249383
  inputs
249150
249384
  };
249151
249385
  }
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
249386
  /**
249174
249387
  * Asks the bundler for the `preVerificationGas` of the bid UserOperation that will
249175
249388
  * actually be signed, with every funding call, approval and signature byte in it.
@@ -249183,7 +249396,9 @@ query OrderStatus($commitment: String!) {
249183
249396
  * `maxFeePerGas`.
249184
249397
  *
249185
249398
  * 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.
249399
+ * and the paymaster's, if the bid has one, with {@link BID_PVG_ESTIMATION_PAYMASTER_CODE}
249400
+ * for the call, so only the bytes are priced and neither the fill nor the paymaster's
249401
+ * validation is simulated.
249187
249402
  *
249188
249403
  * @param params - The bid's fields as they will be signed.
249189
249404
  * @returns The `preVerificationGas` to sign, with {@link BID_PVG_HEADROOM_PERCENT} added.
@@ -249207,13 +249422,15 @@ query OrderStatus($commitment: String!) {
249207
249422
  paymasterAndData: params.paymasterAndData ?? "0x",
249208
249423
  signature: `0x${"ff".repeat(SELECTED_BID_SIGNATURE_BYTES)}`
249209
249424
  };
249425
+ const stateOverride = {
249426
+ [solverAccount]: { code: BID_PVG_ESTIMATION_ACCOUNT_CODE }
249427
+ };
249428
+ if (userOp.paymasterAndData.length >= 42) {
249429
+ stateOverride[userOp.paymasterAndData.slice(0, 42)] = { code: BID_PVG_ESTIMATION_PAYMASTER_CODE };
249430
+ }
249210
249431
  const estimate = await this.crypto.sendBundler(
249211
249432
  BundlerMethod.ETH_ESTIMATE_USER_OPERATION_GAS,
249212
- [
249213
- CryptoUtils.prepareBundlerCall(userOp),
249214
- params.entryPointAddress,
249215
- { [solverAccount]: { code: BID_PVG_ESTIMATION_ACCOUNT_CODE } }
249216
- ]
249433
+ [CryptoUtils.prepareBundlerCall(userOp), params.entryPointAddress, stateOverride]
249217
249434
  );
249218
249435
  return BigInt(estimate.preVerificationGas) * (100n + BID_PVG_HEADROOM_PERCENT) / 100n;
249219
249436
  }
@@ -249261,9 +249478,8 @@ query OrderStatus($commitment: String!) {
249261
249478
  * slots should be overridden.
249262
249479
  * @param params.spenderAddress - Address that needs allowance from the solver
249263
249480
  * 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.
249481
+ * @param params.intentGatewayV2Address - If provided, turns the gateway's
249482
+ * solver selection off with {@link selectionOffStateDiff}.
249267
249483
  * @param params.entryPointAddress - If provided, overrides the EntryPoint
249268
249484
  * deposit mapping to give the solver account a large deposit.
249269
249485
  * @returns An object with `viem` and `bundler` state-override collections.
@@ -249282,10 +249498,7 @@ query OrderStatus($commitment: String!) {
249282
249498
  const viemOverrides = [];
249283
249499
  const bundlerOverrides = {};
249284
249500
  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 }];
249501
+ const gatewayDiffs = [await selectionOffStateDiff(this.ctx.dest.client, intentGatewayV2Address)];
249289
249502
  for (const [leg, input] of (escrow?.inputs ?? []).entries()) {
249290
249503
  gatewayDiffs.push({
249291
249504
  slot: escrowSlot(escrow.commitment, leg),
@@ -249917,6 +250130,7 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
249917
250130
  *
249918
250131
  * The ERC-4337 bundler URL is read from `dest.bundlerUrl`, set when constructing
249919
250132
  * the destination chain via {@link EvmChain.create} or {@link EvmChainParams.bundlerUrl}.
250133
+ * An `EvmChain` given none uses the bundler Hyperbridge runs for it.
249920
250134
  *
249921
250135
  * @param source - Source chain for order placement
249922
250136
  * @param dest - Destination chain for order fulfillment
@@ -250606,6 +250820,27 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
250606
250820
  }
250607
250821
  });
250608
250822
 
250823
+ // src/config/bundlers.ts
250824
+ function hyperbridgeBundlerUrl(chainId) {
250825
+ return HYPERBRIDGE_BUNDLER_URLS[chainId];
250826
+ }
250827
+ var HYPERBRIDGE_BUNDLER_URLS;
250828
+ var init_bundlers = __esm({
250829
+ "src/config/bundlers.ts"() {
250830
+ "use strict";
250831
+ init_esm_shims();
250832
+ HYPERBRIDGE_BUNDLER_URLS = {
250833
+ 1: "https://bundler.polytope.technology/ethereum",
250834
+ 56: "https://bundler.polytope.technology/bsc",
250835
+ 97: "https://bundler.polytope.technology/bsc-chapel",
250836
+ 137: "https://bundler.polytope.technology/polygon",
250837
+ 8453: "https://bundler.polytope.technology/base",
250838
+ 42161: "https://bundler.polytope.technology/arbitrum",
250839
+ 80002: "https://bundler.polytope.technology/polygon-amoy"
250840
+ };
250841
+ }
250842
+ });
250843
+
250609
250844
  // src/services/FillerConfigService.ts
250610
250845
  function validateRpcUrls(rpcUrls) {
250611
250846
  if (rpcUrls.length === 0) {
@@ -250685,7 +250920,7 @@ async function resolveChainConfigs(chains2, options = {}) {
250685
250920
  "RPC endpoint could not report its chainId at startup; keeping it for the quorum to judge per call"
250686
250921
  );
250687
250922
  }
250688
- return { chainId: first3.chainId, rpcUrls, bundlerUrl: chain2.bundlerUrl };
250923
+ return { chainId: first3.chainId, rpcUrls, bundlerUrl: hyperbridgeBundlerUrl(first3.chainId) };
250689
250924
  })
250690
250925
  );
250691
250926
  }
@@ -250696,6 +250931,7 @@ var init_FillerConfigService = __esm({
250696
250931
  init_esm_shims();
250697
250932
  init_Logger();
250698
250933
  init_node10();
250934
+ init_bundlers();
250699
250935
  DEFAULT_BLOCK_SCAN_INTERVAL_SECONDS = 3;
250700
250936
  MIN_BLOCK_SCAN_INTERVAL_SECONDS = 0.1;
250701
250937
  DEFAULT_MIN_ORDER_SIZE_USD = 20;
@@ -250764,12 +251000,6 @@ var init_FillerConfigService = __esm({
250764
251000
  }
250765
251001
  this.rpcOverrides.set(chainId, validateRpcUrls(rpcUrls));
250766
251002
  }
250767
- setBundlerUrl(chainId, bundlerUrl) {
250768
- if (!this.rpcOverrides.has(chainId)) {
250769
- throw new Error(`Chain ${chainId} is not configured`);
250770
- }
250771
- this.bundlerUrls.set(chainId, bundlerUrl);
250772
- }
250773
251003
  /** Replaces the rebalancing config at runtime; trigger checks read it live. */
250774
251004
  setRebalancing(rebalancing) {
250775
251005
  if (this.fillerConfig) this.fillerConfig.rebalancing = rebalancing;
@@ -250946,7 +251176,7 @@ var init_FillerConfigService = __esm({
250946
251176
  return this.fillerConfig?.substratePrivateKey;
250947
251177
  }
250948
251178
  getEntryPointAddress(chain2) {
250949
- return this.chainConfigService.getEntryPointV08Address(chain2);
251179
+ return this.chainConfigService.getEntryPointAddress(chain2);
250950
251180
  }
250951
251181
  getSolverAccountContractAddress(chain2) {
250952
251182
  return this.chainConfigService.getSolverAccountAddress(chain2);
@@ -251140,9 +251370,6 @@ function validateConfig(config5, cliWatchOnly = false) {
251140
251370
  if (!Array.isArray(chain2.rpcUrls) || chain2.rpcUrls.length === 0 || chain2.rpcUrls.some((u6) => !u6)) {
251141
251371
  throw new Error("Each chain configuration must have rpcUrls (a non-empty array of strings)");
251142
251372
  }
251143
- if (!chain2.bundlerUrl) {
251144
- throw new Error("Each chain configuration must have bundlerUrl");
251145
- }
251146
251373
  }
251147
251374
  const concurrent = config5.simplex.maxConcurrentOrders;
251148
251375
  if (concurrent !== void 0) {
@@ -251390,7 +251617,7 @@ function nativeTokenSymbol(chainId) {
251390
251617
  return CHAIN_NATIVE_SYMBOLS[chainId] ?? "ETH";
251391
251618
  }
251392
251619
  function chainsForNetwork(network) {
251393
- return INIT_CHAINS.filter((chain2) => chain2.network === network);
251620
+ return INIT_CHAINS.filter((chain2) => chain2.network === network && chain2.hyperbridgeBundlerUrl);
251394
251621
  }
251395
251622
  function chainByChainId(chainId) {
251396
251623
  return INIT_CHAINS.find((chain2) => chain2.chainId === chainId);
@@ -251404,6 +251631,7 @@ var init_chains2 = __esm({
251404
251631
  "use strict";
251405
251632
  init_esm_shims();
251406
251633
  init_external_links();
251634
+ init_bundlers();
251407
251635
  FREE_RPC_URLS = {
251408
251636
  1: [
251409
251637
  "https://mainnet.gateway.tenderly.co",
@@ -251475,7 +251703,8 @@ var init_chains2 = __esm({
251475
251703
  network: "mainnet",
251476
251704
  alchemySubdomain: "eth-mainnet",
251477
251705
  explorerUrl: external_links_default.chainExplorers.ethereum,
251478
- defaultRpcUrls: FREE_RPC_URLS[1]
251706
+ defaultRpcUrls: FREE_RPC_URLS[1],
251707
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[1]
251479
251708
  },
251480
251709
  {
251481
251710
  chainId: 42161,
@@ -251484,7 +251713,8 @@ var init_chains2 = __esm({
251484
251713
  network: "mainnet",
251485
251714
  alchemySubdomain: "arb-mainnet",
251486
251715
  explorerUrl: external_links_default.chainExplorers.arbitrum,
251487
- defaultRpcUrls: FREE_RPC_URLS[42161]
251716
+ defaultRpcUrls: FREE_RPC_URLS[42161],
251717
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[42161]
251488
251718
  },
251489
251719
  {
251490
251720
  chainId: 8453,
@@ -251493,7 +251723,8 @@ var init_chains2 = __esm({
251493
251723
  network: "mainnet",
251494
251724
  alchemySubdomain: "base-mainnet",
251495
251725
  explorerUrl: external_links_default.chainExplorers.base,
251496
- defaultRpcUrls: FREE_RPC_URLS[8453]
251726
+ defaultRpcUrls: FREE_RPC_URLS[8453],
251727
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[8453]
251497
251728
  },
251498
251729
  {
251499
251730
  chainId: 137,
@@ -251502,7 +251733,8 @@ var init_chains2 = __esm({
251502
251733
  network: "mainnet",
251503
251734
  alchemySubdomain: "polygon-mainnet",
251504
251735
  explorerUrl: external_links_default.chainExplorers.polygon,
251505
- defaultRpcUrls: FREE_RPC_URLS[137]
251736
+ defaultRpcUrls: FREE_RPC_URLS[137],
251737
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[137]
251506
251738
  },
251507
251739
  {
251508
251740
  chainId: 56,
@@ -251511,7 +251743,8 @@ var init_chains2 = __esm({
251511
251743
  network: "mainnet",
251512
251744
  alchemySubdomain: "bnb-mainnet",
251513
251745
  explorerUrl: external_links_default.chainExplorers.bnb,
251514
- defaultRpcUrls: FREE_RPC_URLS[56]
251746
+ defaultRpcUrls: FREE_RPC_URLS[56],
251747
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[56]
251515
251748
  },
251516
251749
  {
251517
251750
  chainId: 11155111,
@@ -251543,7 +251776,8 @@ var init_chains2 = __esm({
251543
251776
  label: "Polygon Amoy",
251544
251777
  network: "testnet",
251545
251778
  alchemySubdomain: "polygon-amoy",
251546
- explorerUrl: external_links_default.chainExplorers.polygonAmoy
251779
+ explorerUrl: external_links_default.chainExplorers.polygonAmoy,
251780
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[80002]
251547
251781
  },
251548
251782
  {
251549
251783
  chainId: 97,
@@ -251551,7 +251785,8 @@ var init_chains2 = __esm({
251551
251785
  label: "BSC Chapel",
251552
251786
  network: "testnet",
251553
251787
  alchemySubdomain: "bnb-testnet",
251554
- explorerUrl: external_links_default.chainExplorers.bnbChapel
251788
+ explorerUrl: external_links_default.chainExplorers.bnbChapel,
251789
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[97]
251555
251790
  }
251556
251791
  ];
251557
251792
  HYPERBRIDGE_WS_DEFAULTS = {
@@ -251793,8 +252028,6 @@ function emitFillerToml(config5, options = {}) {
251793
252028
  push("[[chains]]");
251794
252029
  push("# List 2+ organisationally independent RPC providers to enable quorum log scanning.");
251795
252030
  push(kv("rpcUrls", chain2.rpcUrls));
251796
- push("# ERC-4337 bundler used to submit fill UserOperations on this chain.");
251797
- push(kv("bundlerUrl", chain2.bundlerUrl));
251798
252031
  push();
251799
252032
  });
251800
252033
  return `${out.join("\n").trimEnd()}
@@ -336725,9 +336958,6 @@ function parseAlchemyUrl(url2) {
336725
336958
  if (!match) return null;
336726
336959
  return { subdomain, apiKey: match[1] };
336727
336960
  }
336728
- function isAlchemyUrl(url2) {
336729
- return parseAlchemyUrl(url2) !== null;
336730
- }
336731
336961
  function deriveAlchemyRpc(apiKey, chainId) {
336732
336962
  const chain2 = chainByChainId(chainId);
336733
336963
  if (!chain2?.alchemySubdomain) return null;
@@ -337578,10 +337808,9 @@ var init_help_text = __esm({
337578
337808
  "use strict";
337579
337809
  init_esm_shims();
337580
337810
  WHY = {
337581
- 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).",
337811
+ chains: "Simplex listens for orders and fills only on the chains you pick. Each chain needs its own RPC and funded balances (native gas + stablecoins); fills go through Hyperbridge's bundler.",
337582
337812
  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
337813
  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.",
337585
337814
  signer: "This wallet signs every fill and holds your stablecoin float on each chain. It's the identity of your filler.",
337586
337815
  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
337816
  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.",
@@ -337643,8 +337872,7 @@ function detectPrefillNetwork(prefill) {
337643
337872
  if (!prefill) return void 0;
337644
337873
  for (const chainId of prefill.chainIds) {
337645
337874
  if (chainId === null) continue;
337646
- const meta = chainsForNetwork("testnet").find((c6) => c6.chainId === chainId);
337647
- if (meta) return "testnet";
337875
+ if (chainByChainId(chainId)?.network === "testnet") return "testnet";
337648
337876
  }
337649
337877
  return "mainnet";
337650
337878
  }
@@ -337838,118 +338066,6 @@ var init_chains3 = __esm({
337838
338066
  }
337839
338067
  });
337840
338068
 
337841
- // src/cli/init/derive/pimlico.ts
337842
- function parsePimlicoUrl(url2) {
337843
- let parsed;
337844
- try {
337845
- parsed = new URL(url2);
337846
- } catch {
337847
- return null;
337848
- }
337849
- if (parsed.protocol !== "https:") return null;
337850
- if (parsed.hostname !== "api.pimlico.io") return null;
337851
- const match = parsed.pathname.match(/^\/v2\/([^/]+)\/rpc$/);
337852
- if (!match) return null;
337853
- const chainId = Number(match[1]);
337854
- if (!Number.isInteger(chainId) || chainId <= 0) return null;
337855
- const apiKey = parsed.searchParams.get("apikey");
337856
- if (!apiKey) return null;
337857
- return { chainId, apiKey };
337858
- }
337859
- function derivePimlicoBundler(apiKey, chainId) {
337860
- return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${encodeURIComponent(apiKey)}`;
337861
- }
337862
- var init_pimlico = __esm({
337863
- "src/cli/init/derive/pimlico.ts"() {
337864
- "use strict";
337865
- init_esm_shims();
337866
- }
337867
- });
337868
-
337869
- // src/cli/init/steps/bundlers.ts
337870
- async function stepBundlers(state, prefill) {
337871
- why(WHY.bundler);
337872
- const alchemyChains = state.chains.filter((chain2) => {
337873
- if (chain2.bundlerUrl || !isAlchemyUrl(chain2.rpcUrls[0])) return false;
337874
- const existing = prefillBundlerFor(chain2.meta.chainId, prefill);
337875
- return !existing || existing === chain2.rpcUrls[0];
337876
- });
337877
- if (alchemyChains.length > 0) {
337878
- const reuse = guard(
337879
- await confirm({
337880
- message: `Reuse the Alchemy RPC as the ERC-4337 bundler for ${alchemyChains.map((c6) => c6.meta.label).join(", ")}?`,
337881
- initialValue: true
337882
- })
337883
- );
337884
- if (reuse) {
337885
- for (const chain2 of alchemyChains) chain2.bundlerUrl = chain2.rpcUrls[0];
337886
- }
337887
- }
337888
- const alchemyCapable = state.chains.filter((chain2) => !chain2.bundlerUrl && chain2.meta.alchemySubdomain);
337889
- if (alchemyCapable.length > 0) {
337890
- const useKey = guard(
337891
- await confirm({
337892
- message: `Configure the bundler for ${alchemyCapable.map((c6) => c6.meta.label).join(", ")} from one Alchemy API key?`,
337893
- initialValue: true
337894
- })
337895
- );
337896
- if (useKey) {
337897
- const apiKey = await askSecret("Alchemy API key");
337898
- for (const chain2 of alchemyCapable) {
337899
- const url2 = deriveAlchemyRpc(apiKey, chain2.meta.chainId);
337900
- if (url2) chain2.bundlerUrl = url2;
337901
- }
337902
- }
337903
- }
337904
- const pimlico = new ProviderDerivation({
337905
- detect: (url2) => parsePimlicoUrl(url2)?.apiKey ?? null,
337906
- derive: derivePimlicoBundler,
337907
- confirmMessage: (remaining) => `Pimlico key detected \u2014 derive bundler URLs for ${remaining} from the same key?`
337908
- });
337909
- for (const chain2 of state.chains) {
337910
- if (chain2.bundlerUrl) continue;
337911
- const existing = prefillBundlerFor(chain2.meta.chainId, prefill);
337912
- const derived2 = pimlico.candidate(chain2.meta.chainId);
337913
- const url2 = derived2 ? await askDerivedOrCustom(
337914
- `Bundler for ${chain2.meta.label}`,
337915
- derived2,
337916
- "Use the derived Pimlico URL",
337917
- () => askBundlerUrl(chain2.meta.label, existing)
337918
- ) : await askBundlerUrl(chain2.meta.label, existing);
337919
- chain2.bundlerUrl = url2;
337920
- const remaining = state.chains.filter((c6) => !c6.bundlerUrl);
337921
- await pimlico.offer(
337922
- url2,
337923
- remaining.map((c6) => c6.meta.label)
337924
- );
337925
- }
337926
- }
337927
- function prefillBundlerFor(chainId, prefill) {
337928
- if (!prefill) return void 0;
337929
- const index3 = prefill.chainIds.indexOf(chainId);
337930
- if (index3 === -1) return void 0;
337931
- return prefill.config.chains[index3]?.bundlerUrl || void 0;
337932
- }
337933
- function askBundlerUrl(label, initial) {
337934
- return askUrl(`ERC-4337 bundler URL for ${label}`, {
337935
- initial,
337936
- placeholder: "https://api.pimlico.io/v2/<chainId>/rpc?apikey=<your-key>",
337937
- required: "Bundler URL is required \u2014 fills are submitted through it"
337938
- });
337939
- }
337940
- var init_bundlers = __esm({
337941
- "src/cli/init/steps/bundlers.ts"() {
337942
- "use strict";
337943
- init_esm_shims();
337944
- init_dist11();
337945
- init_alchemy();
337946
- init_pimlico();
337947
- init_derive_flow();
337948
- init_prompt_utils();
337949
- init_help_text();
337950
- }
337951
- });
337952
-
337953
338069
  // src/cli/init/steps/signer.ts
337954
338070
  async function stepSigner(state, prefill) {
337955
338071
  why(WHY.signer);
@@ -338431,7 +338547,7 @@ function assembleConfig(state) {
338431
338547
  // would otherwise shadow the fresh entry (last [[chains]] wins at load).
338432
338548
  chains: [
338433
338549
  ...state.passthroughChains,
338434
- ...state.chains.map((chain2) => ({ rpcUrls: chain2.rpcUrls, bundlerUrl: chain2.bundlerUrl ?? "" }))
338550
+ ...state.chains.map((chain2) => ({ rpcUrls: chain2.rpcUrls }))
338435
338551
  ],
338436
338552
  rebalancing,
338437
338553
  vault: hasVault ? vault : void 0,
@@ -338453,10 +338569,7 @@ function chainComments(state) {
338453
338569
  function showSummary(state, outputPath) {
338454
338570
  const lines = [];
338455
338571
  for (const chain2 of state.chains) {
338456
- const bundlerHost = chain2.bundlerUrl ? new URL(chain2.bundlerUrl).hostname : "?";
338457
- lines.push(
338458
- `${chain2.meta.label}: ${chain2.rpcUrls.length} RPC${chain2.rpcUrls.length > 1 ? "s (quorum)" : ""}, bundler ${bundlerHost}`
338459
- );
338572
+ lines.push(`${chain2.meta.label}: ${chain2.rpcUrls.length} RPC${chain2.rpcUrls.length > 1 ? "s (quorum)" : ""}`);
338460
338573
  }
338461
338574
  if (state.passthroughChains.length > 0) {
338462
338575
  lines.push(`+ ${state.passthroughChains.length} unmanaged chain(s) kept from the previous config`);
@@ -338548,7 +338661,6 @@ async function runInit(options) {
338548
338661
  const state = newWizardState();
338549
338662
  state.prefillConfig = prefill?.config;
338550
338663
  await stepChains(state, prefill);
338551
- await stepBundlers(state, prefill);
338552
338664
  await stepSigner(state, prefill);
338553
338665
  await stepHyperbridge(state, prefill);
338554
338666
  for (; ; ) {
@@ -338648,7 +338760,6 @@ var init_init3 = __esm({
338648
338760
  init_migrate_legacy();
338649
338761
  init_state();
338650
338762
  init_chains3();
338651
- init_bundlers();
338652
338763
  init_signer2();
338653
338764
  init_hyperbridge();
338654
338765
  init_finetune();
@@ -338938,6 +339049,7 @@ init_dist4();
338938
339049
  // src/services/server/UiServer.ts
338939
339050
  init_esm_shims();
338940
339051
  init_interpolated_curve();
339052
+ init_bundlers();
338941
339053
  init_asset_registry();
338942
339054
  init_pairs();
338943
339055
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -340701,6 +340813,8 @@ var LimitOrderService = class {
340701
340813
  this.delegationService = delegationService;
340702
340814
  this.startingNonce = startingNonce;
340703
340815
  this.vaultBalances = vaultBalances;
340816
+ /** Re-signs in flight, by order id. A fill's resize waits one out rather than reposting alongside it. */
340817
+ this.resigning = /* @__PURE__ */ new Map();
340704
340818
  this.logger = loggers.get("limit-orders");
340705
340819
  }
340706
340820
  /**
@@ -340794,6 +340908,7 @@ var LimitOrderService = class {
340794
340908
  bookExpiresAt: null,
340795
340909
  bookPrice: null,
340796
340910
  orderNonce: order.orderNonce,
340911
+ entryPoint: null,
340797
340912
  status: "cancelled",
340798
340913
  lastError: null
340799
340914
  }),
@@ -341060,24 +341175,32 @@ var LimitOrderService = class {
341060
341175
  async resize(remaining, delivered) {
341061
341176
  const id2 = remaining.id;
341062
341177
  const floor2 = await this.dustFloor(remaining);
341063
- if (BigInt(remaining.remaining) < floor2) {
341178
+ for (let resigning = this.resigning.get(id2); resigning; resigning = this.resigning.get(id2)) await resigning;
341179
+ const order = await this.store.setStatus(id2, "resizing", null, POSTABLE);
341180
+ if (!order) return null;
341181
+ if (BigInt(order.remaining) < floor2) {
341064
341182
  this.logger.info(
341065
- { id: id2, remaining: remaining.remaining, floor: floor2.toString() },
341183
+ { id: id2, remaining: order.remaining, floor: floor2.toString() },
341066
341184
  "Limit order worked down past the dust floor; closing it"
341067
341185
  );
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
- });
341186
+ if (order.commitment) await this.withdraw(order.commitment);
341187
+ const closed = await this.store.setPosting(
341188
+ id2,
341189
+ {
341190
+ commitment: null,
341191
+ bookExpiresAt: null,
341192
+ bookPrice: null,
341193
+ orderNonce: order.orderNonce,
341194
+ entryPoint: null,
341195
+ status: "filled",
341196
+ lastError: null
341197
+ },
341198
+ POSTABLE
341199
+ );
341077
341200
  if (closed) this.report({ kind: "filled", order: closed });
341078
341201
  return closed;
341079
341202
  }
341080
- const resized = await this.repost(await this.store.setStatus(id2, "resizing"));
341203
+ const resized = await this.repost(order);
341081
341204
  if (resized) this.report({ kind: "resized", order: resized, delivered });
341082
341205
  return resized;
341083
341206
  }
@@ -341090,7 +341213,7 @@ var LimitOrderService = class {
341090
341213
  */
341091
341214
  async repost(order) {
341092
341215
  if (!order) return null;
341093
- if (isLocal(order)) return this.store.setStatus(order.id, "open");
341216
+ if (isLocal(order)) return this.store.setStatus(order.id, "open", null, POSTABLE);
341094
341217
  if (hasExpired(order.expiresAt, /* @__PURE__ */ new Date())) return this.retire(order);
341095
341218
  if (order.commitment) {
341096
341219
  const withdrawn = await this.withdraw(order.commitment);
@@ -341101,10 +341224,13 @@ var LimitOrderService = class {
341101
341224
  { id: order.id, commitment: order.commitment, err: message },
341102
341225
  "Could not clear the old entry; leaving the posting alone rather than adding a second"
341103
341226
  );
341104
- return this.store.setStatus(order.id, "open", message);
341227
+ return this.store.setStatus(order.id, "open", message, POSTABLE);
341105
341228
  }
341106
341229
  }
341107
- await this.store.setStatus(order.id, "resizing");
341230
+ if (!await this.store.setStatus(order.id, "resizing", null, POSTABLE)) {
341231
+ this.logger.info({ id: order.id }, "Limit order closed while it was being reposted; leaving it closed");
341232
+ return null;
341233
+ }
341108
341234
  const nonce = (BigInt(order.orderNonce) + 1n).toString();
341109
341235
  return (await this.post({ ...order, commitment: null, orderNonce: nonce })).order;
341110
341236
  }
@@ -341147,7 +341273,9 @@ var LimitOrderService = class {
341147
341273
  * They drift apart when a request never got an answer or the process died
341148
341274
  * between two of them: an entry the orderbook still lists that nothing here
341149
341275
  * 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.
341276
+ * down because the solver cannot cover what it quoted. A posted op is also
341277
+ * signed over one EntryPoint, so when the fill chain moves to another, every
341278
+ * entry signed before the move is withdrawn and posted again.
341151
341279
  */
341152
341280
  async reconcile(now = /* @__PURE__ */ new Date()) {
341153
341281
  const [entries, live] = await Promise.all([this.postedOrders(), this.live()]);
@@ -341174,7 +341302,17 @@ var LimitOrderService = class {
341174
341302
  }
341175
341303
  for (const order of live) {
341176
341304
  if (isLocal(order)) continue;
341177
- if (order.commitment && found.has(order.commitment.toLowerCase())) continue;
341305
+ if (order.commitment && found.has(order.commitment.toLowerCase())) {
341306
+ try {
341307
+ if (await this.resign(order)) report.reposted++;
341308
+ } catch (err) {
341309
+ this.logger.error(
341310
+ { id: order.id, err },
341311
+ "Could not sign the limit order again for its chain's EntryPoint"
341312
+ );
341313
+ }
341314
+ continue;
341315
+ }
341178
341316
  if (sinceMs(order.updatedAt, now) < POST_GRACE_MS) continue;
341179
341317
  this.logger.warn({ id: order.id }, "Limit order has no entry on the orderbook; posting it again");
341180
341318
  try {
@@ -341186,6 +341324,45 @@ var LimitOrderService = class {
341186
341324
  }
341187
341325
  return report;
341188
341326
  }
341327
+ /**
341328
+ * Withdraws a posting signed for an EntryPoint its fill chain no longer uses,
341329
+ * and posts it again signed for the one it uses now. Answers whether a new
341330
+ * posting landed.
341331
+ *
341332
+ * The row is read again and claimed out of `open` first: a fill can have worked
341333
+ * it down or started its own repost since reconciliation listed it, and that
341334
+ * write is the one to follow. A fill that lands once the claim is taken waits
341335
+ * in `resize` for this to finish. The EntryPoint is only written with a posting
341336
+ * that landed, so a pass cut short anywhere leaves a row the next pass still
341337
+ * reads as stale, or as having no entry, and finishes the job.
341338
+ */
341339
+ async resign(listed) {
341340
+ const entryPoint = this.configService.getEntryPointAddress(listed.fillChain);
341341
+ if (!entryPoint || sameAddress(signedFor(listed), entryPoint)) return false;
341342
+ const order = await this.store.get(listed.id);
341343
+ if (!order || order.status !== "open" || order.commitment !== listed.commitment) return false;
341344
+ if (sameAddress(signedFor(order), entryPoint) || this.resigning.has(order.id)) return false;
341345
+ const resigned = this.signAgain(order, entryPoint);
341346
+ this.resigning.set(
341347
+ order.id,
341348
+ resigned.catch(() => false)
341349
+ );
341350
+ try {
341351
+ return await resigned;
341352
+ } finally {
341353
+ this.resigning.delete(order.id);
341354
+ }
341355
+ }
341356
+ async signAgain(order, entryPoint) {
341357
+ const claimed = await this.store.setStatus(order.id, "resizing", null, ["open"]);
341358
+ if (!claimed) return false;
341359
+ this.logger.warn(
341360
+ { id: order.id, commitment: order.commitment, signedFor: signedFor(order), entryPoint },
341361
+ "Limit order was signed for an EntryPoint its chain no longer uses; signing it again"
341362
+ );
341363
+ const posted = await this.repost(claimed);
341364
+ return !!posted?.commitment && sameAddress(signedFor(posted), entryPoint);
341365
+ }
341189
341366
  /**
341190
341367
  * Lowers every open order's `remaining` to what the solver's account will still
341191
341368
  * pay for it, and puts the order back on the book at that size.
@@ -341267,6 +341444,7 @@ var LimitOrderService = class {
341267
341444
  bookExpiresAt: null,
341268
341445
  bookPrice: null,
341269
341446
  orderNonce: order.orderNonce,
341447
+ entryPoint: null,
341270
341448
  status: "expired",
341271
341449
  lastError: null
341272
341450
  });
@@ -341323,11 +341501,11 @@ var LimitOrderService = class {
341323
341501
  }
341324
341502
  /** Builds and submits the posting, then writes the orderbook's answer onto the row. */
341325
341503
  async post(order) {
341326
- const { result, orderNonce } = await this.submit(order);
341504
+ const { result, orderNonce, entryPoint } = await this.submit(order);
341327
341505
  if (result.kind === "accepted" || result.kind === "unchanged") {
341328
341506
  const posted = result.order;
341329
341507
  this.logger.info(
341330
- { id: order.id, commitment: posted.commitment, price: posted.price },
341508
+ { id: order.id, commitment: posted.commitment, price: posted.price, entryPoint },
341331
341509
  "Limit order posted to the orderbook"
341332
341510
  );
341333
341511
  const stored = await this.store.setPosting(
@@ -341337,6 +341515,10 @@ var LimitOrderService = class {
341337
341515
  bookExpiresAt: posted.expiresAt,
341338
341516
  bookPrice: posted.price,
341339
341517
  orderNonce: orderNonce.toString(),
341518
+ // An entry the orderbook already held was signed by an earlier attempt,
341519
+ // for whichever EntryPoint was current then. Recorded as unknown, which
341520
+ // reconciliation reads as v0.8 and signs again once the chain is past it.
341521
+ entryPoint: result.kind === "accepted" ? entryPoint : null,
341340
341522
  status: "open",
341341
341523
  lastError: null
341342
341524
  },
@@ -341366,6 +341548,7 @@ var LimitOrderService = class {
341366
341548
  bookExpiresAt: null,
341367
341549
  bookPrice: null,
341368
341550
  orderNonce: orderNonce.toString(),
341551
+ entryPoint: null,
341369
341552
  status: "open",
341370
341553
  lastError: message
341371
341554
  }),
@@ -341388,22 +341571,30 @@ var LimitOrderService = class {
341388
341571
  * only the second one.
341389
341572
  */
341390
341573
  async submit(order) {
341574
+ const entryPoint = this.entryPointFor(order.fillChain);
341391
341575
  const orderNonce = BigInt(order.orderNonce);
341392
- const attempt = await this.buildAndSubmit(order, orderNonce);
341576
+ const attempt = await this.buildAndSubmit(order, orderNonce, entryPoint);
341393
341577
  const first3 = attempt.result;
341394
341578
  if (first3.kind !== "rejected" || first3.code !== "REPLAYED" && first3.code !== "ORDER_EXISTS") {
341395
- return { result: first3, orderNonce };
341579
+ return { result: first3, orderNonce, entryPoint };
341396
341580
  }
341397
341581
  if (first3.code === "ORDER_EXISTS" && attempt.commitment) {
341398
341582
  const live = await this.entryAt(order, attempt.commitment);
341399
341583
  if (live) {
341400
341584
  this.logger.info({ id: order.id, commitment: live.commitment }, "This posting is already on the orderbook");
341401
- return { result: { kind: "unchanged", order: live }, orderNonce };
341585
+ return { result: { kind: "unchanged", order: live }, orderNonce, entryPoint };
341402
341586
  }
341403
341587
  }
341404
341588
  this.logger.warn({ id: order.id, code: first3.code }, "Orderbook has seen this op before; reposting on a new nonce");
341405
341589
  const retried = orderNonce + 1n;
341406
- return { result: (await this.buildAndSubmit(order, retried)).result, orderNonce: retried };
341590
+ const { result } = await this.buildAndSubmit(order, retried, entryPoint);
341591
+ return { result, orderNonce: retried, entryPoint };
341592
+ }
341593
+ /** The EntryPoint a posting on `chain` is signed for now. */
341594
+ entryPointFor(chain2) {
341595
+ const entryPoint = this.configService.getEntryPointAddress(chain2);
341596
+ if (!entryPoint) throw new LimitOrderValidationError(`No EntryPoint is configured for ${chain2}`);
341597
+ return entryPoint;
341407
341598
  }
341408
341599
  /**
341409
341600
  * The entry the orderbook holds at `commitment`, if it holds one. A lookup that
@@ -341419,8 +341610,8 @@ var LimitOrderService = class {
341419
341610
  }
341420
341611
  }
341421
341612
  /** 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);
341613
+ async buildAndSubmit(order, orderNonce, entryPoint) {
341614
+ const { commitment, userOp } = await this.buildUserOp(order, orderNonce, entryPoint);
341424
341615
  try {
341425
341616
  return { result: await this.client.submitOrder(userOp), commitment };
341426
341617
  } catch (err) {
@@ -341430,7 +341621,7 @@ var LimitOrderService = class {
341430
341621
  throw err;
341431
341622
  }
341432
341623
  }
341433
- async buildUserOp(order, orderNonce) {
341624
+ async buildUserOp(order, orderNonce, entryPointAddress) {
341434
341625
  const baseToken = this.assetRegistry.getAddress(order.base, order.fillChain);
341435
341626
  const quoteToken = this.assetRegistry.getAddress(order.quote, order.fillChain);
341436
341627
  const [baseDecimals, quoteDecimals] = await Promise.all([
@@ -341445,10 +341636,6 @@ var LimitOrderService = class {
341445
341636
  baseDecimals,
341446
341637
  quoteDecimals
341447
341638
  });
341448
- const entryPointAddress = this.configService.getEntryPointAddress(order.fillChain);
341449
- if (!entryPointAddress) {
341450
- throw new LimitOrderValidationError(`No EntryPoint is configured for ${order.fillChain}`);
341451
- }
341452
341639
  return this.contractService.prepareLimitOrderUserOp({
341453
341640
  fillChain: order.fillChain,
341454
341641
  entryPointAddress,
@@ -341479,6 +341666,12 @@ function hasExpired(expiresAt, now) {
341479
341666
  const at = Date.parse(expiresAt);
341480
341667
  return !Number.isNaN(at) && at <= now.getTime();
341481
341668
  }
341669
+ function signedFor(order) {
341670
+ return order.entryPoint ?? ENTRY_POINT_V08;
341671
+ }
341672
+ function sameAddress(a6, b5) {
341673
+ return a6.toLowerCase() === b5.toLowerCase();
341674
+ }
341482
341675
  function sinceMs(updatedAt, now) {
341483
341676
  const written = Date.parse(`${updatedAt.replace(" ", "T")}Z`);
341484
341677
  return Number.isNaN(written) ? Number.POSITIVE_INFINITY : now.getTime() - written;
@@ -343388,8 +343581,6 @@ async function handleSetupRequest(server, setup, req, res, path2, method) {
343388
343581
  return sendJson(res, 200, await validateAlchemyKey(body, deps));
343389
343582
  case "validate-rpc":
343390
343583
  return sendJson(res, 200, await validateRpc(body, deps));
343391
- case "validate-bundler":
343392
- return sendJson(res, 200, await validateBundler(body, deps));
343393
343584
  case "validate-token":
343394
343585
  return sendJson(res, 200, await validateToken(body));
343395
343586
  case "derive-evm-address":
@@ -343422,9 +343613,7 @@ async function validateAlchemyKey(body, deps) {
343422
343613
  stateMachineId: meta.stateMachineId,
343423
343614
  label: meta.label,
343424
343615
  note: meta.note,
343425
- rpcUrl,
343426
- // Alchemy serves ERC-4337 bundler methods on the same endpoint.
343427
- bundlerUrl: rpcUrl
343616
+ rpcUrl
343428
343617
  };
343429
343618
  });
343430
343619
  const probe = chains2.find((c6) => c6.rpcUrl);
@@ -343462,23 +343651,6 @@ async function validateRpc(body, deps) {
343462
343651
  );
343463
343652
  return { ok: results.every((r7) => !r7.error), results };
343464
343653
  }
343465
- async function validateBundler(body, deps) {
343466
- const url2 = String(body.url ?? "").trim();
343467
- if (!url2) return { ok: false, warning: "Bundler URL is empty" };
343468
- try {
343469
- const entryPoints = await withTimeout3(
343470
- deps.rpcRequest(url2, "eth_supportedEntryPoints", []),
343471
- PROBE_TIMEOUT_MS,
343472
- "Bundler probe"
343473
- );
343474
- return { ok: true, entryPoints };
343475
- } catch (err) {
343476
- return {
343477
- ok: true,
343478
- warning: `Bundler did not answer eth_supportedEntryPoints: ${err instanceof Error ? err.message : err}`
343479
- };
343480
- }
343481
- }
343482
343654
  async function validateToken(body) {
343483
343655
  const rpcUrl = String(body.rpcUrl ?? "").trim();
343484
343656
  const address = String(body.address ?? "").trim();
@@ -343616,7 +343788,6 @@ function maskToml(config5, chainLabels) {
343616
343788
  }
343617
343789
  for (const chain2 of masked.chains) {
343618
343790
  chain2.rpcUrls = chain2.rpcUrls.map(maskUrlKey);
343619
- chain2.bundlerUrl = maskUrlKey(chain2.bundlerUrl);
343620
343791
  }
343621
343792
  return emitFillerToml(masked, { chainComments: chainLabels });
343622
343793
  }
@@ -343690,12 +343861,7 @@ function openSseStream(req, res, clients) {
343690
343861
  res.once("close", cleanup);
343691
343862
  res.once("error", cleanup);
343692
343863
  }
343693
- var OPERATOR_PROBES = [
343694
- "/api/setup/validate-token",
343695
- "/api/setup/validate-rpc",
343696
- "/api/setup/validate-bundler",
343697
- "/api/setup/validate-alchemy-key"
343698
- ];
343864
+ var OPERATOR_PROBES = ["/api/setup/validate-token", "/api/setup/validate-rpc", "/api/setup/validate-alchemy-key"];
343699
343865
  var LOGS_UNAVAILABLE = "Log capture is not enabled for this filler";
343700
343866
  var MAX_LOG_STREAM_QUEUE = 5e3;
343701
343867
  var MAX_LOG_PAGE = 2e3;
@@ -344145,9 +344311,6 @@ var UiServer = class {
344145
344311
  const body = JSON.parse(await readBody(req));
344146
344312
  if (path2 === "/api/setup/validate-rpc")
344147
344313
  return sendJson(res, 200, await validateRpc(body, this.deps));
344148
- if (path2 === "/api/setup/validate-bundler") {
344149
- return sendJson(res, 200, await validateBundler(body, this.deps));
344150
- }
344151
344314
  if (path2 === "/api/setup/validate-alchemy-key") {
344152
344315
  return sendJson(res, 200, await validateAlchemyKey(body, this.deps));
344153
344316
  }
@@ -344863,7 +345026,7 @@ var UiServer = class {
344863
345026
  stateMachineId: formatChainKey(chainId),
344864
345027
  label: chainLabel(chainId),
344865
345028
  rpcUrls: chain2.rpcUrls,
344866
- bundlerUrl: chain2.bundlerUrl,
345029
+ bundlerUrl: hyperbridgeBundlerUrl(chainId) ?? "",
344867
345030
  watchOnly: globalWatchOnly ? watchOnly : Boolean(watchOnly?.[String(chainId)]),
344868
345031
  running: running.has(chainId)
344869
345032
  };
@@ -344910,11 +345073,11 @@ var UiServer = class {
344910
345073
  }
344911
345074
  const rpcUrls = (Array.isArray(row.rpcUrls) ? row.rpcUrls : []).map((url2) => String(url2).trim()).filter(Boolean);
344912
345075
  validateRpcUrls(rpcUrls);
344913
- const bundlerUrl = String(row.bundlerUrl ?? "").trim();
344914
- if (!bundlerUrl) {
344915
- throw new Error(`${chainLabel(chainId)} needs a bundler URL to submit fill UserOperations`);
345076
+ const watchOnly = row.watchOnly === true;
345077
+ if (!watchOnly && op.config.simplex.watchOnly !== true && !hyperbridgeBundlerUrl(chainId)) {
345078
+ throw new Error(`Hyperbridge runs no bundler for ${chainLabel(chainId)}, so it can only be watched`);
344916
345079
  }
344917
- rows.push({ chainId, rpcUrls, bundlerUrl, watchOnly: row.watchOnly === true });
345080
+ rows.push({ chainId, rpcUrls, watchOnly });
344918
345081
  }
344919
345082
  } catch (err) {
344920
345083
  return sendJson(res, 400, { error: err instanceof Error ? err.message : String(err) });
@@ -344946,7 +345109,7 @@ var UiServer = class {
344946
345109
  } catch (err) {
344947
345110
  return sendJson(res, 400, { error: err instanceof Error ? err.message : String(err) });
344948
345111
  }
344949
- op.config.chains = rows.map(({ rpcUrls, bundlerUrl }) => ({ rpcUrls, bundlerUrl }));
345112
+ op.config.chains = rows.map(({ rpcUrls }) => ({ rpcUrls }));
344950
345113
  if (Object.keys(confirmationPolicies).length > 0) op.config.confirmationPolicies = confirmationPolicies;
344951
345114
  if (typeof op.config.simplex.watchOnly !== "boolean") {
344952
345115
  const perChain = Object.fromEntries(rows.filter((r7) => r7.watchOnly).map((r7) => [String(r7.chainId), true]));
@@ -349514,9 +349677,9 @@ var INTENT_GATEWAY_V2_ABI = [
349514
349677
  internalType: "bytes32"
349515
349678
  },
349516
349679
  {
349517
- name: "solver",
349518
- type: "address",
349519
- internalType: "address"
349680
+ name: "userOpHash",
349681
+ type: "bytes32",
349682
+ internalType: "bytes32"
349520
349683
  },
349521
349684
  {
349522
349685
  name: "signature",
@@ -350904,10 +351067,13 @@ var LIMIT_ORDER_CALL_GAS_LIMIT = 500000n;
350904
351067
  var LIMIT_ORDER_VERIFICATION_GAS_LIMIT = 150000n;
350905
351068
  var LIMIT_ORDER_PRE_VERIFICATION_GAS = 50000n;
350906
351069
  var BID_DISCOVERY_PAD_SECONDS = 30;
351070
+ var BLOCK_TIME_SAMPLE_BLOCKS = 1000n;
351071
+ var FALLBACK_BLOCK_TIME_SECONDS = 2;
350907
351072
  var ContractInteractionService = class {
350908
351073
  constructor(clientManager, configService, signer, sharedCacheService) {
350909
351074
  this.clientManager = clientManager;
350910
351075
  this.sdkHelperCache = /* @__PURE__ */ new Map();
351076
+ this.blockTimes = /* @__PURE__ */ new Map();
350911
351077
  this.logger = moduleLogger(configService.loggers, "contract-service");
350912
351078
  this.configService = configService;
350913
351079
  this.cacheService = sharedCacheService || new CacheService();
@@ -350967,11 +351133,20 @@ var ContractInteractionService = class {
350967
351133
  try {
350968
351134
  const chainIds = this.configService.getConfiguredChainIds();
350969
351135
  const chainNames = chainIds.map((id2) => `EVM-${id2}`);
350970
- for (const chainName of chainNames) {
351136
+ await Promise.all(
351137
+ chainNames.map(async (chainName2) => {
351138
+ try {
351139
+ await this.blockTimeSeconds(chainName2);
351140
+ } catch (err) {
351141
+ this.logger.warn({ err, chain: chainName2 }, "Could not measure the block time at startup");
351142
+ }
351143
+ })
351144
+ );
351145
+ for (const chainName2 of chainNames) {
350971
351146
  try {
350972
- await this.getFeeTokenWithDecimals(chainName);
351147
+ await this.getFeeTokenWithDecimals(chainName2);
350973
351148
  } catch (err) {
350974
- this.logger.warn({ err, chain: chainName }, "Could not prewarm fee token decimals");
351149
+ this.logger.warn({ err, chain: chainName2 }, "Could not prewarm fee token decimals");
350975
351150
  }
350976
351151
  }
350977
351152
  for (const destChain of chainNames) {
@@ -351556,18 +351731,59 @@ var ContractInteractionService = class {
351556
351731
  *
351557
351732
  * Operators configure seconds because that is the unit the risk is actually in, but the
351558
351733
  * 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.
351734
+ * clock. The conversion uses the chain's block time from {@link blockTimeSeconds}; it is
351735
+ * deliberately rounded up, since erring long costs a slightly stale quote while erring
351736
+ * short silently drops winnable bids.
351562
351737
  */
351563
351738
  async bidValidUntilBlock(chain2) {
351564
351739
  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;
351740
+ const [currentBlock, blockTimeSec] = await Promise.all([client.getBlockNumber(), this.blockTimeSeconds(chain2)]);
351568
351741
  const windowSec = this.configService.getBidValiditySeconds() + BID_DISCOVERY_PAD_SECONDS;
351569
351742
  return currentBlock + BigInt(Math.ceil(windowSec / blockTimeSec));
351570
351743
  }
351744
+ /**
351745
+ * Seconds per block on `chain`. Measured once, when simplex starts ({@link initCache}), and
351746
+ * kept until it stops. A chain with no measurement yet, because it was added later or its
351747
+ * blocks could not be read at startup, is measured at its first bid.
351748
+ *
351749
+ * The nominal `Chain.blockTime` cannot be relied on alone: it goes stale when a chain
351750
+ * speeds up (BSC makes a block every 0.45s against a declared 0.75s) and some chains
351751
+ * declare none. Converting at a slower block time than the chain's ends a bid early, so
351752
+ * the faster of the measured and the declared figure is used, and a stalled or idle
351753
+ * stretch in the sample never shortens a bid.
351754
+ *
351755
+ * Blocks that cannot be read fall back to the declared figure, then to
351756
+ * {@link FALLBACK_BLOCK_TIME_SECONDS}. That answer is not kept.
351757
+ */
351758
+ blockTimeSeconds(chain2) {
351759
+ const known3 = this.blockTimes.get(chain2);
351760
+ if (known3) return known3;
351761
+ const client = this.clientManager.getPublicClient(chain2);
351762
+ const declaredMs = client.chain?.blockTime;
351763
+ const declared = declaredMs ? declaredMs / 1e3 : void 0;
351764
+ const seconds = this.measureBlockTimeSeconds(client).then((measured) => declared ? Math.min(measured, declared) : measured).catch((err) => {
351765
+ this.blockTimes.delete(chain2);
351766
+ const fallback2 = declared ?? FALLBACK_BLOCK_TIME_SECONDS;
351767
+ this.logger.warn(
351768
+ { err, chain: chain2, seconds: fallback2 },
351769
+ "Could not measure the block time; using the declared one"
351770
+ );
351771
+ return fallback2;
351772
+ });
351773
+ this.blockTimes.set(chain2, seconds);
351774
+ return seconds;
351775
+ }
351776
+ /** The average block time over the chain's last {@link BLOCK_TIME_SAMPLE_BLOCKS} blocks, in seconds. */
351777
+ async measureBlockTimeSeconds(client) {
351778
+ const head = await client.getBlock({ blockTag: "latest" });
351779
+ const span = head.number < BLOCK_TIME_SAMPLE_BLOCKS ? head.number : BLOCK_TIME_SAMPLE_BLOCKS;
351780
+ const tail = await client.getBlock({ blockNumber: head.number - span });
351781
+ const measured = Number(head.timestamp - tail.timestamp) / Number(span);
351782
+ if (!Number.isFinite(measured) || measured <= 0) {
351783
+ throw new Error(`${span} blocks span ${head.timestamp - tail.timestamp}s`);
351784
+ }
351785
+ return measured;
351786
+ }
351571
351787
  /**
351572
351788
  * Builds the signed, never-executed UserOperation that carries one limit order
351573
351789
  * to the HyperFX orderbook.
@@ -351751,6 +351967,8 @@ init_Logger();
351751
351967
  var FALLBACK_VERIFICATION_GAS_LIMIT = 250000n;
351752
351968
  var FALLBACK_CALL_GAS_LIMIT = 1500000n;
351753
351969
  var FALLBACK_PRE_VERIFICATION_GAS = 150000n;
351970
+ var PRIORITY_FEE_BUMP_PERCENT = 8n;
351971
+ var MAX_FEE_BUMP_PERCENT = 10n;
351754
351972
  var UserOpSender = class {
351755
351973
  constructor(clientManager, configService, signer) {
351756
351974
  this.clientManager = clientManager;
@@ -351777,7 +351995,7 @@ var UserOpSender = class {
351777
351995
  let auth;
351778
351996
  let fees4;
351779
351997
  try {
351780
- fees4 = await this.getGasPrice(bundlerUrl, publicClient, chainId);
351998
+ fees4 = await this.getGasPrice(bundlerUrl, publicClient);
351781
351999
  const gasForPrefund = gas ?? {
351782
352000
  verificationGasLimit: FALLBACK_VERIFICATION_GAS_LIMIT,
351783
352001
  callGasLimit: FALLBACK_CALL_GAS_LIMIT,
@@ -351931,31 +352149,27 @@ var UserOpSender = class {
351931
352149
  );
351932
352150
  return userOp;
351933
352151
  }
351934
- /** Mirrors the gas-price selection used by the delegation and fill paths. */
351935
- async getGasPrice(bundlerUrl, publicClient, chainId) {
351936
- const lower2 = bundlerUrl.toLowerCase();
351937
- if (lower2.includes("pimlico.io")) {
351938
- const res = await this.sendBundlerRpc(
351939
- bundlerUrl,
351940
- BundlerMethod.PIMLICO_GET_USER_OPERATION_GAS_PRICE,
351941
- []
351942
- );
351943
- return { maxFeePerGas: BigInt(res.fast.maxFeePerGas), maxPriorityFeePerGas: BigInt(res.fast.maxPriorityFeePerGas) };
351944
- }
351945
- if (lower2.includes("alchemy.com")) {
351946
- const [rundlerPriorityFee, latestBlock] = await Promise.all([
351947
- this.sendBundlerRpc(bundlerUrl, BundlerMethod.RUNDLER_MAX_PRIORITY_FEE_PER_GAS, []),
351948
- publicClient.getBlock({ blockTag: "latest" })
351949
- ]);
351950
- const baseFeePerGas = latestBlock.baseFeePerGas ?? await publicClient.getGasPrice();
351951
- const isArbitrum = BigInt(chainId) === 42161n;
351952
- const prioBump = isArbitrum ? 0n : 25n;
351953
- const maxPriorityFeePerGas = BigInt(rundlerPriorityFee) + BigInt(rundlerPriorityFee) * prioBump / 100n;
351954
- const bufferedBaseFee = baseFeePerGas + baseFeePerGas * 50n / 100n;
351955
- return { maxFeePerGas: bufferedBaseFee + maxPriorityFeePerGas, maxPriorityFeePerGas };
351956
- }
351957
- const gasPrice = await publicClient.getGasPrice();
351958
- return { maxFeePerGas: gasPrice + gasPrice * 10n / 100n, maxPriorityFeePerGas: gasPrice + gasPrice * 8n / 100n };
352152
+ /**
352153
+ * Prices the op for the rundler bundler, as the fill path does: its suggested fees, or the
352154
+ * chain's gas price raised to the priority fee it requires where it suggests none.
352155
+ */
352156
+ async getGasPrice(bundlerUrl, publicClient) {
352157
+ const [gasPrice, latestBlock] = await Promise.all([
352158
+ publicClient.getGasPrice(),
352159
+ publicClient.getBlock({ blockTag: "latest" })
352160
+ ]);
352161
+ return rundlerUserOperationFees(
352162
+ bundlerUrl,
352163
+ {
352164
+ maxFeePerGas: gasPrice + gasPrice * MAX_FEE_BUMP_PERCENT / 100n,
352165
+ maxPriorityFeePerGas: gasPrice + gasPrice * PRIORITY_FEE_BUMP_PERCENT / 100n
352166
+ },
352167
+ {
352168
+ baseFeePerGas: latestBlock.baseFeePerGas ?? gasPrice,
352169
+ priorityFeeBumpPercent: PRIORITY_FEE_BUMP_PERCENT,
352170
+ maxFeeBumpPercent: MAX_FEE_BUMP_PERCENT
352171
+ }
352172
+ );
351959
352173
  }
351960
352174
  async sendBundlerRpc(bundlerUrl, method, params) {
351961
352175
  const response = await fetch(bundlerUrl, {
@@ -367374,8 +367588,8 @@ var validateBalanceForTransaction = async (params) => {
367374
367588
  }, operationContext);
367375
367589
  const balance = await balancePrepared.execute();
367376
367590
  if (BigInt(balance) < BigInt(amount)) {
367377
- const chainName = extractChainInfo(operationContext.chain).name;
367378
- throw createInsufficientTokenBalanceError(chainName, token, {
367591
+ const chainName2 = extractChainInfo(operationContext.chain).name;
367592
+ throw createInsufficientTokenBalanceError(chainName2, token, {
367379
367593
  balance: balance.toString(),
367380
367594
  amount,
367381
367595
  tokenAddress,
@@ -367390,8 +367604,8 @@ var validateNativeBalanceForTransaction = async (params) => {
367390
367604
  }, operationContext);
367391
367605
  const balance = await balancePrepared.execute();
367392
367606
  if (BigInt(balance) === 0n) {
367393
- const chainName = extractChainInfo(operationContext.chain).name;
367394
- throw createInsufficientGasError(chainName, {
367607
+ const chainName2 = extractChainInfo(operationContext.chain).name;
367608
+ throw createInsufficientGasError(chainName2, {
367395
367609
  balance: "0",
367396
367610
  walletAddress: operationContext.address
367397
367611
  });
@@ -386353,6 +386567,86 @@ init_FillerConfigService();
386353
386567
  init_filler_toml();
386354
386568
  init_defaults8();
386355
386569
 
386570
+ // src/services/bundler-preflight.ts
386571
+ init_esm_shims();
386572
+ init_chains2();
386573
+ init_interpolated_curve();
386574
+ init_Logger();
386575
+ var BUNDLER_PREFLIGHT_TIMEOUT_MS = 1e4;
386576
+ async function assertBundlersServeEntryPoint(chains2, configService, options = {}) {
386577
+ const timeoutMs = options.timeoutMs ?? BUNDLER_PREFLIGHT_TIMEOUT_MS;
386578
+ const logger8 = moduleLogger(configService.loggers, "bundler-preflight");
386579
+ const failures = await Promise.all(
386580
+ chains2.map(async ({ chainId, bundlerUrl }) => {
386581
+ if (options.watchOnly?.[chainId] === true) return void 0;
386582
+ if (!bundlerUrl?.trim()) {
386583
+ return `Hyperbridge runs no bundler for ${chainName(chainId)}, so simplex cannot fill there; set it watch-only`;
386584
+ }
386585
+ const entryPoint = configService.getEntryPointAddress(formatChainKey(chainId));
386586
+ if (!entryPoint) return void 0;
386587
+ return checkBundler(chainId, bundlerUrl.trim(), entryPoint, timeoutMs, logger8);
386588
+ })
386589
+ );
386590
+ const messages = failures.filter((failure) => failure !== void 0);
386591
+ if (messages.length > 0) throw new Error(messages.join("; "));
386592
+ }
386593
+ function servesEntryPoint(listed, entryPoint) {
386594
+ return Array.isArray(listed) && listed.some((address) => String(address).toLowerCase() === entryPoint.toLowerCase());
386595
+ }
386596
+ function describeEntryPoints(listed) {
386597
+ return Array.isArray(listed) && listed.length > 0 ? listed.map(String).join(", ") : "none";
386598
+ }
386599
+ function bundlerHost(url2) {
386600
+ try {
386601
+ return new URL(url2).host || "an unparseable URL";
386602
+ } catch {
386603
+ return "an unparseable URL";
386604
+ }
386605
+ }
386606
+ function chainName(chainId) {
386607
+ const label = chainByChainId(chainId)?.label;
386608
+ return label ? `${label} (${formatChainKey(chainId)})` : formatChainKey(chainId);
386609
+ }
386610
+ async function checkBundler(chainId, bundlerUrl, entryPoint, timeoutMs, logger8) {
386611
+ const host = bundlerHost(bundlerUrl);
386612
+ const subject = `Bundler ${host} for ${chainName(chainId)}`;
386613
+ const signal = AbortSignal.timeout(timeoutMs);
386614
+ let listed;
386615
+ try {
386616
+ listed = await supportedEntryPoints(bundlerUrl, signal);
386617
+ } catch (err) {
386618
+ const reason = signal.aborted ? `timed out after ${timeoutMs}ms` : errorReason(err);
386619
+ logger8.warn(
386620
+ { chain: formatChainKey(chainId), bundler: host },
386621
+ `${subject} did not answer eth_supportedEntryPoints: ${reason.split(bundlerUrl).join(host)}. Continuing without confirming it serves EntryPoint ${entryPoint}`
386622
+ );
386623
+ return void 0;
386624
+ }
386625
+ if (servesEntryPoint(listed, entryPoint)) return void 0;
386626
+ return `${subject} does not support EntryPoint ${entryPoint}; it lists ${describeEntryPoints(listed)}`;
386627
+ }
386628
+ async function supportedEntryPoints(bundlerUrl, signal) {
386629
+ const response = await fetch(bundlerUrl, {
386630
+ method: "POST",
386631
+ headers: { "Content-Type": "application/json" },
386632
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_supportedEntryPoints", params: [] }),
386633
+ signal
386634
+ });
386635
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
386636
+ const json = await response.json();
386637
+ if (json.error) throw new Error(json.error.message ?? JSON.stringify(json.error));
386638
+ const { result } = json;
386639
+ if (!Array.isArray(result) || !result.every((address) => typeof address === "string")) {
386640
+ throw new Error("the result is not a list of addresses");
386641
+ }
386642
+ return result;
386643
+ }
386644
+ function errorReason(err) {
386645
+ if (!(err instanceof Error)) return String(err);
386646
+ const { cause } = err;
386647
+ return cause instanceof Error ? `${err.message} (${cause.message})` : err.message;
386648
+ }
386649
+
386356
386650
  // src/orderbook/lifecycle.ts
386357
386651
  init_esm_shims();
386358
386652
  init_Logger();
@@ -387178,8 +387472,8 @@ async function bootFiller(config5, options) {
387178
387472
  };
387179
387473
  const configService = new FillerConfigService(resolvedChains, fillerConfigForService, options.loggers);
387180
387474
  const chainConfigs2 = resolvedChains.map((chain2) => {
387181
- const chainName = `EVM-${chain2.chainId}`;
387182
- return configService.getChainConfig(chainName);
387475
+ const chainName2 = `EVM-${chain2.chainId}`;
387476
+ return configService.getChainConfig(chainName2);
387183
387477
  });
387184
387478
  let watchOnlyConfig;
387185
387479
  const globalWatchOnly = options.watchOnlyOverride === true || config5.simplex.watchOnly === true;
@@ -387217,6 +387511,8 @@ async function bootFiller(config5, options) {
387217
387511
  "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
387512
  );
387219
387513
  }
387514
+ logger8.info("Checking each bundler serves its chain's EntryPoint...");
387515
+ await assertBundlersServeEntryPoint(resolvedChains, configService, { watchOnly: watchOnlyConfig });
387220
387516
  const chainClientManager = new ChainClientManager(configService, options.signer);
387221
387517
  const runtimeSigner = chainClientManager.getSigner();
387222
387518
  if (options.signer) {
@@ -387407,10 +387703,10 @@ async function bootFiller(config5, options) {
387407
387703
  const token1 = {};
387408
387704
  for (const pair of config5.pairs ?? []) {
387409
387705
  if (normalizeSymbol(pair.token0) === normalizeSymbol(pair.token1)) continue;
387410
- for (const chainName of configuredChainNames) {
387411
- const address = assetRegistry.getAddress(pair.token1, chainName);
387706
+ for (const chainName2 of configuredChainNames) {
387707
+ const address = assetRegistry.getAddress(pair.token1, chainName2);
387412
387708
  if (!address) continue;
387413
- const list = token1[chainName] ?? (token1[chainName] = []);
387709
+ const list = token1[chainName2] ?? (token1[chainName2] = []);
387414
387710
  if (!list.includes(address)) list.push(address);
387415
387711
  }
387416
387712
  }
@@ -387815,6 +388111,7 @@ var MemoryLimitOrderStore = class {
387815
388111
  status: "open",
387816
388112
  commitment: null,
387817
388113
  orderNonce: order.orderNonce ?? "0",
388114
+ entryPoint: null,
387818
388115
  bookExpiresAt: null,
387819
388116
  bookPrice: null,
387820
388117
  lastError: null,
@@ -388457,7 +388754,7 @@ var OrderScanner = class _OrderScanner {
388457
388754
  async addChainNow(chain2) {
388458
388755
  if (this.closed) throw new Error("This OrderScanner is closed");
388459
388756
  const rpcUrls = validateRpcUrls(chain2.rpcUrls);
388460
- const chainId = chain2.chainId ?? (await resolveChainConfigs([{ rpcUrls, bundlerUrl: chain2.bundlerUrl ?? "" }], {
388757
+ const chainId = chain2.chainId ?? (await resolveChainConfigs([{ rpcUrls }], {
388461
388758
  loggers: this.loggers,
388462
388759
  tolerateUnreachable: true
388463
388760
  }))[0].chainId;
@@ -388808,10 +389105,10 @@ var PairController = class {
388808
389105
  if (assets && Object.keys(assets).length > 0) config5.assets = nextAssets;
388809
389106
  if (normalizeSymbol(pair.token0) !== normalizeSymbol(pair.token1)) {
388810
389107
  for (const chain2 of this.runtime.resolvedChains) {
388811
- const chainName = formatChainKey(chain2.chainId);
388812
- const address = assetRegistry.getAddress(pair.token1, chainName);
389108
+ const chainName2 = formatChainKey(chain2.chainId);
389109
+ const address = assetRegistry.getAddress(pair.token1, chainName2);
388813
389110
  if (!address) continue;
388814
- const list = balanceTokens[chainName] ?? (balanceTokens[chainName] = []);
389111
+ const list = balanceTokens[chainName2] ?? (balanceTokens[chainName2] = []);
388815
389112
  if (!list.includes(address)) list.push(address);
388816
389113
  }
388817
389114
  }
@@ -388890,10 +389187,7 @@ var ChainController = class {
388890
389187
  async add(chain2) {
388891
389188
  return this.serialise(async () => {
388892
389189
  validateRpcUrls(chain2.rpcUrls);
388893
- if (!chain2.bundlerUrl?.trim()) {
388894
- throw new Error("A bundler URL is required to submit fill UserOperations");
388895
- }
388896
- const [resolved] = await resolveChainConfigs([{ rpcUrls: chain2.rpcUrls, bundlerUrl: chain2.bundlerUrl }]);
389190
+ const [resolved] = await resolveChainConfigs([{ rpcUrls: chain2.rpcUrls }]);
388897
389191
  const { chainId } = resolved;
388898
389192
  const { configService, config: config5, intentFiller } = this.runtime;
388899
389193
  if (configService.getConfiguredChainIds().includes(chainId)) {
@@ -388916,12 +389210,13 @@ var ChainController = class {
388916
389210
  `Chain ${chainId} cannot be added as filling: this solver was started without a signer. Restart with \`signer\` to fill.`
388917
389211
  );
388918
389212
  }
388919
- configService.addChain(resolved);
388920
389213
  const watchOnly = chain2.watchOnly ?? (this.runtime.signerless || this.runtime.globalWatchOnly);
389214
+ await assertBundlersServeEntryPoint([resolved], configService, { watchOnly: { [chainId]: watchOnly } });
389215
+ configService.addChain(resolved);
388921
389216
  if (watchOnly) intentFiller.setWatchOnly(chainId, true);
388922
389217
  try {
388923
389218
  if (!inScanner) {
388924
- await this.scanner.addChain({ rpcUrls: chain2.rpcUrls, bundlerUrl: chain2.bundlerUrl, chainId });
389219
+ await this.scanner.addChain({ rpcUrls: chain2.rpcUrls, chainId });
388925
389220
  }
388926
389221
  this.runtime.chainClientManager.invalidate(formatChainKey(chainId));
388927
389222
  await intentFiller.addChain(configService.getChainConfig(formatChainKey(chainId)));
@@ -388938,7 +389233,7 @@ var ChainController = class {
388938
389233
  this.runtime.confirmationPolicy.adopt(chainId, resolvedPolicy);
388939
389234
  }
388940
389235
  this.runtime.resolvedChains.push(resolved);
388941
- config5.chains = [...config5.chains, { rpcUrls: chain2.rpcUrls, bundlerUrl: chain2.bundlerUrl }];
389236
+ config5.chains = [...config5.chains, { rpcUrls: chain2.rpcUrls }];
388942
389237
  if (Object.keys(confirmationPolicies).length > 0) config5.confirmationPolicies = confirmationPolicies;
388943
389238
  this.syncWatchOnlyToConfig();
388944
389239
  await this.persist();
@@ -388983,9 +389278,7 @@ var ChainController = class {
388983
389278
  validateRpcUrls(rpcUrls);
388984
389279
  const index3 = this.runtime.resolvedChains.findIndex((chain2) => chain2.chainId === chainId);
388985
389280
  if (index3 < 0) throw new Error(`Chain ${chainId} is not configured`);
388986
- const [probed] = await resolveChainConfigs([
388987
- { rpcUrls, bundlerUrl: this.runtime.resolvedChains[index3].bundlerUrl ?? "" }
388988
- ]);
389281
+ const [probed] = await resolveChainConfigs([{ rpcUrls }]);
388989
389282
  if (probed.chainId !== chainId) {
388990
389283
  throw new Error(`Those endpoints answer for chain ${probed.chainId}, not ${chainId}`);
388991
389284
  }
@@ -389004,17 +389297,6 @@ var ChainController = class {
389004
389297
  await this.persist();
389005
389298
  });
389006
389299
  }
389007
- async setBundlerUrl(chainId, bundlerUrl) {
389008
- return this.serialise(async () => {
389009
- if (!bundlerUrl?.trim()) throw new Error("A bundler URL is required");
389010
- const index3 = this.runtime.resolvedChains.findIndex((chain2) => chain2.chainId === chainId);
389011
- if (index3 < 0) throw new Error(`Chain ${chainId} is not configured`);
389012
- this.runtime.configService.setBundlerUrl(chainId, bundlerUrl);
389013
- this.runtime.resolvedChains[index3].bundlerUrl = bundlerUrl;
389014
- this.runtime.config.chains[index3].bundlerUrl = bundlerUrl;
389015
- await this.persist();
389016
- });
389017
- }
389018
389300
  /** Monitor without filling. Takes effect on the next order. */
389019
389301
  async setWatchOnly(chainId, watchOnly) {
389020
389302
  return this.serialise(async () => {
@@ -389023,6 +389305,10 @@ var ChainController = class {
389023
389305
  "Watch-only cannot be disabled: this solver was started without a signer. Restart with `signer` to fill."
389024
389306
  );
389025
389307
  }
389308
+ if (!watchOnly) {
389309
+ const chain2 = this.runtime.resolvedChains.find((resolved) => resolved.chainId === chainId);
389310
+ if (chain2) await assertBundlersServeEntryPoint([chain2], this.runtime.configService);
389311
+ }
389026
389312
  this.runtime.intentFiller.setWatchOnly(chainId, watchOnly);
389027
389313
  this.syncWatchOnlyToConfig();
389028
389314
  await this.persist();
@@ -389891,6 +390177,7 @@ var LIMIT_ORDER_COLUMNS = `
389891
390177
  status,
389892
390178
  commitment,
389893
390179
  order_nonce as orderNonce,
390180
+ entry_point as entryPoint,
389894
390181
  book_expires_at as bookExpiresAt,
389895
390182
  book_price as bookPrice,
389896
390183
  last_error as lastError,
@@ -389927,6 +390214,7 @@ var SqliteLimitOrderStore = class {
389927
390214
  status TEXT NOT NULL,
389928
390215
  commitment TEXT,
389929
390216
  order_nonce TEXT NOT NULL DEFAULT '0',
390217
+ entry_point TEXT,
389930
390218
  book_expires_at TEXT,
389931
390219
  book_price TEXT,
389932
390220
  last_error TEXT,
@@ -389951,6 +390239,10 @@ var SqliteLimitOrderStore = class {
389951
390239
 
389952
390240
  CREATE INDEX IF NOT EXISTS idx_limit_order_fills_order ON limit_order_fills(limit_order_id);
389953
390241
  `);
390242
+ if (!columnNames(this.db, "limit_orders").has("entry_point")) {
390243
+ this.db.exec("ALTER TABLE limit_orders ADD COLUMN entry_point TEXT");
390244
+ this.logger.info({ column: "entry_point" }, "Migrated limit order storage schema");
390245
+ }
389954
390246
  if (!columnNames(this.db, "limit_order_fills").has("amount_in")) {
389955
390247
  this.db.exec("ALTER TABLE limit_order_fills ADD COLUMN amount_in TEXT");
389956
390248
  this.logger.info({ column: "amount_in" }, "Migrated limit order fill schema");
@@ -390015,13 +390307,14 @@ var SqliteLimitOrderStore = class {
390015
390307
  const result = this.db.prepare(`
390016
390308
  UPDATE limit_orders
390017
390309
  SET commitment = ?, book_expires_at = ?, book_price = ?, order_nonce = ?,
390018
- status = ?, last_error = ?, updated_at = datetime('now')
390310
+ entry_point = ?, status = ?, last_error = ?, updated_at = datetime('now')
390019
390311
  WHERE id = ?${statusGuard(only)}
390020
390312
  `).run(
390021
390313
  posting.commitment,
390022
390314
  posting.bookExpiresAt,
390023
390315
  posting.bookPrice,
390024
390316
  posting.orderNonce,
390317
+ posting.entryPoint,
390025
390318
  posting.status,
390026
390319
  posting.lastError,
390027
390320
  id2,