@hyperbridge/simplex 0.17.0 → 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.
@@ -235283,31 +235283,73 @@ function userOperationLogs(logs, entryPoint, userOpHash) {
235283
235283
  while (start >= 0 && !isBoundary(logs[start])) start--;
235284
235284
  return logs.slice(start + 1, end);
235285
235285
  }
235286
- async function fetchRundlerPriorityFee(bundlerUrl) {
235287
- if (bundlersWithoutRundlerFees.has(bundlerUrl)) return null;
235286
+ async function rundlerRequest(bundlerUrl, method, unsupported) {
235287
+ if (unsupported.has(bundlerUrl)) return null;
235288
235288
  try {
235289
235289
  const response = await fetch(bundlerUrl, {
235290
235290
  method: "POST",
235291
235291
  headers: { "Content-Type": "application/json" },
235292
- body: JSON.stringify({
235293
- jsonrpc: "2.0",
235294
- id: 1,
235295
- method: BundlerMethod.RUNDLER_MAX_PRIORITY_FEE_PER_GAS,
235296
- params: []
235297
- })
235292
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params: [] })
235298
235293
  });
235299
235294
  const { result, error } = await response.json();
235300
235295
  if (error) {
235301
235296
  if (error.code !== void 0 && UNSUPPORTED_REQUEST_CODES.has(error.code)) {
235302
- bundlersWithoutRundlerFees.add(bundlerUrl);
235297
+ unsupported.add(bundlerUrl);
235303
235298
  }
235304
235299
  return null;
235305
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 {
235306
235313
  return result == null ? null : BigInt(result);
235307
235314
  } catch {
235308
235315
  return null;
235309
235316
  }
235310
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
+ }
235311
235353
  function applyRundlerPriorityFee(fees4, params) {
235312
235354
  const { rundlerPriorityFee, baseFeePerGas, priorityFeeBumpPercent, maxFeeBumpPercent } = params;
235313
235355
  const priorityFloor = rundlerPriorityFee + rundlerPriorityFee * priorityFeeBumpPercent / 100n;
@@ -235502,7 +235544,7 @@ function encodePhantomBidDeclaration(declaration) {
235502
235544
  }
235503
235545
  return u8aToHex(new Uint8Array(bytes5));
235504
235546
  }
235505
- var import_merge_race, __defProp3, __getOwnPropNames2, __esm2, __export2, node_exports, wasm, full_path, __dirname$1, cachedTextDecoder, cachedUint8ArrayMemory0, WASM_VECTOR_LEN, cachedTextEncoder, encodeString5, cachedDataViewMemory0, KeccakMergeFinalization, KeccakMerge, wasmPath, wasmBytes2, bindings, wasmModule, wasmInstance, __wasm, init_node11, RequestStatus, TimeoutStatus, IntentOrderStatus, ABI, evmHost_default, ABI2, handlerV2_default, polkadotAssetHubPaseo, polkadotHubMainnet, pharosMainnet, pharosAtlantic, tronNile, ENTRY_POINT_V08, ENTRY_POINT_V09, KNOWN_ENTRY_POINTS, chainConfigs, configsByStateMachineId, getConfigByStateMachineId, getChainId3, getViemChain, hyperbridgeAddress, ABI3, IntentGatewayV2_default, ChainConfigService, ABI4, uniswapRouterV2_default, chains, DEFAULT_ADDRESS, EvmChain, REQUEST_COMMITMENTS_SLOT, RESPONSE_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, STATE_COMMITMENTS_SLOT, MISSING_CONSENSUS_UPDATE_TIME_MESSAGE, MissingConsensusUpdateTimeError, TokenBucket, BATCHES_NOT_SUPPORTED_CODE, TOO_BIG_BATCH_REQUEST_CODE, DEFAULT_MAX_BATCH_SIZE, _endpoint2, _headers3, _limiter, _maxBatchSize, _batchingSupported, _pending2, _flushTimer, _flushing, _nextId, __BatchingHttpProvider_instances, scheduleFlush_fn, flushNow_fn, flush_fn, post_fn, settleBatch_fn, settle_fn, handleBatchRefusal_fn, requeue_fn, _a5, BatchingHttpProvider, OFFCHAIN_BID_PREFIX, HYPERBRIDGE_TYPES_BUNDLE, BASE_TIP, HTTP_CONNECT_TIMEOUT_MS, INCLUSION_TIMEOUT_MS, DEFAULT_RPC_MAX_RPS, rpcLimiters, BidCodec, PackedUserOperationCodec, IntentsCoprocessor, ReviveContractInfo, ReviveAccountType, ReviveAccountInfo, H256, EvmStateProof, SubstrateHashing, SubstrateStateMachineProof, BasicProof, LeafIndexAndPos, MmrProof, ConsensusStateId, ConsensusMessage, FraudProofMessage, StateMachine, StateMachineId, StateMachineHeight, Proof, PostRequest, PostResponse, GetRequest, StorageValue, GetResponse, Request3, Response2, RequestMessage, RequestResponse, ResponseMessage, TimeoutMessage, GetRequestsWithProof, Message, DEFAULT_CHILD_STORAGE_PREFIX, PharosProofNodeCodec, SiblingLeftmostLeafProofCodec, NonExistenceProofCodec, AccountProofDataCodec, PharosStateProof, DEFAULT_POLL_INTERVAL, ADDRESS_ZERO2, DEFAULT_GRAFFITI, DEFAULT_LOGGER, REQUEST_STATUS_WEIGHTS, TIMEOUT_STATUS_WEIGHTS, COMBINED_STATUS_WEIGHTS, CHAIN_ID_TO_COINGECKO_NATIVE, TESTNET_CHAINS, ORDER_STATUS, loadDriver, detectEnvironment, STORAGE_KEYS, LEGACY_STORAGE_KEYS, ABI5, uniswapV3Quoter_default, UNISWAP_V4_QUOTER_ABI, ABI6, universalRouter_default, PERMIT2_ABI, UniswapQuoteEngine, COMMON_FEE_TIERS, Swap, ABI7, erc7281_default, DEFAULT_GRAFFITI2, ERC7821_BATCH_MODE, BundlerMethod, SELECT_SOLVER_TYPEHASH, LEGACY_SELECT_SOLVER_TYPEHASH, PACKED_USEROP_TYPEHASH, DOMAIN_TYPEHASH, CryptoUtils, FEE_TOKEN_CACHE_TTL_MS, OrderPlacer, TOKEN_KEYED_GATEWAY_ABI, keyingByClient, PARTIAL_FILLS_SLOT, USED_USEROPS_STORAGE_KEY, OrderExecutor, _a6, OrderCanceller, FILL_ORDER_SELECTOR, SUPPORTED_INTENTS_VERSION, TESTNET_INTENTS_VERSIONS, CONTRACT_VERSION_ABI, CANONICAL_EVM_TOKEN, formats, SELECTION_PARAMS_SLOT, SOLVER_SELECTION_CLEARED, SELECTION_FORMAT_BY_ENTRY_POINT, ENTRY_POINT_EVENT_ABI, BidImpl, BidManager, UNSUPPORTED_REQUEST_CODES, bundlersWithoutRundlerFees, RELAYER_MESSAGE_GAS, NO_BUNDLER_FILL_GAS_BASE, NO_BUNDLER_FILL_GAS_PER_OUTPUT, NO_BUNDLER_PAYMASTER_VERIFICATION_GAS, NO_BUNDLER_PAYMASTER_POST_OP_GAS, BID_PVG_ESTIMATION_ACCOUNT_CODE, BID_PVG_ESTIMATION_PAYMASTER_CODE, SELECTED_BID_SIGNATURE_BYTES, BID_PVG_HEADROOM_PERCENT, ESCROW_MAPPING_SLOT, GasEstimator, OrderStatusChecker, ORDERBOOK_URLS, ORDERBOOK_DECIMALS, ORDERBOOK_SCALE, OrderbookRequestError, RATE_FIELDS, TOP_OF_BOOK_QUERY, ROUTE_LIQUIDITY_QUERY, QUOTE_QUERY, QUOTE_PESSIMISTIC_QUERY, HyperFxOrderbook, UnsupportedLiquidityAssetError, UnsupportedLiquidityChainError, OrderbookQuoteNotConvergedError, MAX_EXACT_OUTPUT_ROUNDS, OrderbookMarket, ETHEREUM_ORDER_FEE_GAS_PRICE_BUMP_PERCENT, DEFAULT_ORDER_FEE_GAS_PRICE_BUMP_PERCENT, IntentGateway, DECLARATION_V1, DECLARATION_V2, PAYMASTER_ADDRESS_BYTES, PAYMASTER_GAS_LIMIT_BYTES, PAYMASTER_DATA_OFFSET, PERMIT2_DATA_BYTES, PERMIT2_SPONSORSHIP_BYTES, MAX_DECLARED_ENTRIES, MAX_TOKEN_ID_BYTES, TeleportParams, MultiAccount;
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;
235506
235548
  var init_node10 = __esm({
235507
235549
  "../sdk/dist/node/index.js"() {
235508
235550
  "use strict";
@@ -237897,6 +237939,7 @@ var init_node10 = __esm({
237897
237939
  },
237898
237940
  rpcEnvKey: "BSC_CHAPEL",
237899
237941
  defaultRpcUrl: "https://bnb-testnet.api.onfinality.io/public",
237942
+ bundlerUrl: "https://bundler.polytope.technology/bsc-chapel",
237900
237943
  consensusStateId: "BSC0",
237901
237944
  coingeckoId: "binance-smart-chain",
237902
237945
  popularTokens: [
@@ -238040,6 +238083,7 @@ var init_node10 = __esm({
238040
238083
  },
238041
238084
  rpcEnvKey: "ETH_MAINNET",
238042
238085
  defaultRpcUrl: "https://eth-mainnet.g.alchemy.com/v2/demo",
238086
+ bundlerUrl: "https://bundler.polytope.technology/ethereum",
238043
238087
  consensusStateId: "ETH0",
238044
238088
  coingeckoId: "ethereum",
238045
238089
  layerZeroEid: 30101,
@@ -238109,6 +238153,7 @@ var init_node10 = __esm({
238109
238153
  },
238110
238154
  rpcEnvKey: "BSC_MAINNET",
238111
238155
  defaultRpcUrl: "https://bsc-rpc.publicnode.com",
238156
+ bundlerUrl: "https://bundler.polytope.technology/bsc",
238112
238157
  consensusStateId: "BSC0",
238113
238158
  coingeckoId: "binance-smart-chain",
238114
238159
  erc4626Vaults: [
@@ -238171,6 +238216,7 @@ var init_node10 = __esm({
238171
238216
  },
238172
238217
  rpcEnvKey: "ARBITRUM_MAINNET",
238173
238218
  defaultRpcUrl: "https://arbitrum-one.public.blastapi.io",
238219
+ bundlerUrl: "https://bundler.polytope.technology/arbitrum",
238174
238220
  consensusStateId: "ETH0",
238175
238221
  coingeckoId: "arbitrum-one",
238176
238222
  layerZeroEid: 30110,
@@ -238246,6 +238292,7 @@ var init_node10 = __esm({
238246
238292
  },
238247
238293
  rpcEnvKey: "BASE_MAINNET",
238248
238294
  defaultRpcUrl: "https://base-mainnet.public.blastapi.io",
238295
+ bundlerUrl: "https://bundler.polytope.technology/base",
238249
238296
  consensusStateId: "ETH0",
238250
238297
  coingeckoId: "base",
238251
238298
  layerZeroEid: 30184,
@@ -238322,6 +238369,7 @@ var init_node10 = __esm({
238322
238369
  },
238323
238370
  rpcEnvKey: "POLYGON_MAINNET",
238324
238371
  defaultRpcUrl: "https://polygon-bor-rpc.publicnode.com",
238372
+ bundlerUrl: "https://bundler.polytope.technology/polygon",
238325
238373
  consensusStateId: "POLY",
238326
238374
  coingeckoId: "polygon-pos",
238327
238375
  layerZeroEid: 30109,
@@ -238400,6 +238448,7 @@ var init_node10 = __esm({
238400
238448
  },
238401
238449
  rpcEnvKey: "POLYGON_AMOY",
238402
238450
  defaultRpcUrl: "https://rpc-amoy.polygon.technology",
238451
+ bundlerUrl: "https://bundler.polytope.technology/polygon-amoy",
238403
238452
  consensusStateId: "POLY",
238404
238453
  coingeckoId: "polygon-pos"
238405
238454
  },
@@ -242145,7 +242194,7 @@ var init_node10 = __esm({
242145
242194
  * This is the only public way to construct an `EvmChain` — the constructor is private.
242146
242195
  *
242147
242196
  * @param rpcUrl - HTTP(S) RPC URL of the EVM node
242148
- * @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
242149
242198
  * @returns A fully initialised `EvmChain` ready for use
242150
242199
  * @throws If the chain ID returned by the RPC is not a known Hyperbridge deployment
242151
242200
  *
@@ -242171,8 +242220,12 @@ var init_node10 = __esm({
242171
242220
  get host() {
242172
242221
  return this.params.host;
242173
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
+ */
242174
242227
  get bundlerUrl() {
242175
- return this.params.bundlerUrl;
242228
+ return this.params.bundlerUrl ?? chainConfigs[this.params.chainId]?.bundlerUrl;
242176
242229
  }
242177
242230
  get config() {
242178
242231
  return {
@@ -246782,10 +246835,10 @@ query OrderStatus($commitment: String!) {
246782
246835
  ETH_GET_USER_OPERATION_RECEIPT: "eth_getUserOperationReceipt",
246783
246836
  /** Estimates gas limits for a UserOperation before submission. */
246784
246837
  ETH_ESTIMATE_USER_OPERATION_GAS: "eth_estimateUserOperationGas",
246785
- /** Pimlico-specific method to fetch recommended EIP-1559 gas prices for UserOperations. */
246786
- PIMLICO_GET_USER_OPERATION_GAS_PRICE: "pimlico_getUserOperationGasPrice",
246787
- /** Alchemy (Rundler) method to fetch recommended priority fee for UserOperations. */
246788
- 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"
246789
246842
  };
246790
246843
  SELECT_SOLVER_TYPEHASH = keccak2563(toHex3("SelectSolver(bytes32 commitment,bytes32 userOpHash)"));
246791
246844
  LEGACY_SELECT_SOLVER_TYPEHASH = keccak2563(toHex3("SelectSolver(bytes32 commitment,address solver)"));
@@ -249066,6 +249119,7 @@ query OrderStatus($commitment: String!) {
249066
249119
  };
249067
249120
  UNSUPPORTED_REQUEST_CODES = /* @__PURE__ */ new Set([-32600, -32601, -32602]);
249068
249121
  bundlersWithoutRundlerFees = /* @__PURE__ */ new Set();
249122
+ bundlersWithoutRundlerGasPrice = /* @__PURE__ */ new Set();
249069
249123
  RELAYER_MESSAGE_GAS = 1000000n;
249070
249124
  NO_BUNDLER_FILL_GAS_BASE = 700000n;
249071
249125
  NO_BUNDLER_FILL_GAS_PER_OUTPUT = 150000n;
@@ -249106,11 +249160,9 @@ query OrderStatus($commitment: String!) {
249106
249160
  * **Bundler path:** constructs a mock `PackedUserOperation` signed by an
249107
249161
  * ephemeral keypair, applies state overrides, and calls
249108
249162
  * `eth_estimateUserOperationGas`. Gas limits are bumped by 5-10% for
249109
- * headroom. If the bundler is Pimlico, gas prices are refined with
249110
- * `pimlico_getUserOperationGasPrice`, and if it is Alchemy, with
249111
- * `rundler_maxPriorityFeePerGas`. For any other bundler that answers
249112
- * `rundler_maxPriorityFeePerGas`, the fees are raised to at least that
249113
- * priority fee (see {@link applyRundlerPriorityFee}). If the bundler rejects the estimate,
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,
249114
249166
  * fixed gas limits are returned in its place, or the call throws when
249115
249167
  * `params.requireBundlerEstimate` is set.
249116
249168
  *
@@ -249266,46 +249318,19 @@ query OrderStatus($commitment: String!) {
249266
249318
  sessionSignature
249267
249319
  ]);
249268
249320
  const bundlerUserOp = CryptoUtils.prepareBundlerCall(preliminaryUserOp);
249269
- const bundlerUrlLower = this.ctx.bundlerUrl.toLowerCase();
249270
- const isPimlico = bundlerUrlLower.includes("pimlico.io");
249271
- const isAlchemy = bundlerUrlLower.includes("alchemy.com");
249272
- const rundlerPriorityFeeRequest = isPimlico || isAlchemy ? Promise.resolve(null) : fetchRundlerPriorityFee(this.ctx.bundlerUrl);
249273
- const bundlerRequests = [
249321
+ const rundlerFeesRequest = rundlerUserOperationFees(
249322
+ this.ctx.bundlerUrl,
249323
+ { maxFeePerGas, maxPriorityFeePerGas },
249274
249324
  {
249275
- method: BundlerMethod.ETH_ESTIMATE_USER_OPERATION_GAS,
249276
- params: [bundlerUserOp, entryPointAddress, bundlerStateOverrides]
249277
- }
249278
- ];
249279
- if (isPimlico) {
249280
- bundlerRequests.push({
249281
- method: BundlerMethod.PIMLICO_GET_USER_OPERATION_GAS_PRICE,
249282
- params: []
249283
- });
249284
- }
249285
- if (isAlchemy) {
249286
- bundlerRequests.push({
249287
- method: BundlerMethod.RUNDLER_MAX_PRIORITY_FEE_PER_GAS,
249288
- params: []
249289
- });
249290
- }
249291
- let gasEstimate;
249292
- let pimlicoGasPrices = null;
249293
- let alchemyMaxPriorityFee = null;
249294
- try {
249295
- const batchResults = await this.crypto.sendBundlerBatch(bundlerRequests);
249296
- gasEstimate = batchResults[0];
249297
- if (isPimlico && batchResults.length > 1) {
249298
- pimlicoGasPrices = batchResults[1];
249325
+ baseFeePerGas,
249326
+ priorityFeeBumpPercent: BigInt(priorityFeeBumpPercent),
249327
+ maxFeeBumpPercent: BigInt(maxFeeBumpPercent)
249299
249328
  }
249300
- if (isAlchemy && batchResults.length > 1) {
249301
- alchemyMaxPriorityFee = batchResults[1];
249302
- }
249303
- } catch {
249304
- gasEstimate = await this.crypto.sendBundler(
249305
- BundlerMethod.ETH_ESTIMATE_USER_OPERATION_GAS,
249306
- [bundlerUserOp, entryPointAddress, bundlerStateOverrides]
249307
- );
249308
- }
249329
+ );
249330
+ const gasEstimate = await this.crypto.sendBundler(
249331
+ BundlerMethod.ETH_ESTIMATE_USER_OPERATION_GAS,
249332
+ [bundlerUserOp, entryPointAddress, bundlerStateOverrides]
249333
+ );
249309
249334
  callGasLimit = BigInt(gasEstimate.callGasLimit) * 160n / 100n;
249310
249335
  verificationGasLimit = BigInt(gasEstimate.verificationGasLimit) * 105n / 100n;
249311
249336
  preVerificationGas = BigInt(gasEstimate.preVerificationGas) * 105n / 100n;
@@ -249315,37 +249340,9 @@ query OrderStatus($commitment: String!) {
249315
249340
  if (gasEstimate.paymasterPostOpGasLimit) {
249316
249341
  paymasterPostOpGasLimit = BigInt(gasEstimate.paymasterPostOpGasLimit) * 105n / 100n;
249317
249342
  }
249318
- if (pimlicoGasPrices) {
249319
- const level = pimlicoGasPrices.fast ?? pimlicoGasPrices.standard ?? pimlicoGasPrices.slow ?? null;
249320
- if (level) {
249321
- const pimMaxFeePerGas = BigInt(level.maxFeePerGas);
249322
- const pimMaxPriorityFeePerGas = BigInt(level.maxPriorityFeePerGas);
249323
- maxFeePerGas = pimMaxFeePerGas + pimMaxFeePerGas * BigInt(maxFeeBumpPercent) / 100n;
249324
- maxPriorityFeePerGas = pimMaxPriorityFeePerGas + pimMaxPriorityFeePerGas * BigInt(priorityFeeBumpPercent) / 100n;
249325
- }
249326
- }
249327
- if (alchemyMaxPriorityFee) {
249328
- const rundlerPriorityFee2 = BigInt(alchemyMaxPriorityFee);
249329
- const isArbitrum = chainId === 42161n;
249330
- const alchemyPrioBump = isArbitrum ? 0n : 25n;
249331
- maxPriorityFeePerGas = rundlerPriorityFee2 + rundlerPriorityFee2 * alchemyPrioBump / 100n;
249332
- const bufferedBaseFee = baseFeePerGas + baseFeePerGas * 50n / 100n;
249333
- maxFeePerGas = bufferedBaseFee + maxPriorityFeePerGas;
249334
- }
249335
- const rundlerPriorityFee = await rundlerPriorityFeeRequest;
249336
- if (rundlerPriorityFee !== null) {
249337
- const rundlerFees = applyRundlerPriorityFee(
249338
- { maxFeePerGas, maxPriorityFeePerGas },
249339
- {
249340
- rundlerPriorityFee,
249341
- baseFeePerGas,
249342
- priorityFeeBumpPercent: BigInt(priorityFeeBumpPercent),
249343
- maxFeeBumpPercent: BigInt(maxFeeBumpPercent)
249344
- }
249345
- );
249346
- maxFeePerGas = rundlerFees.maxFeePerGas;
249347
- maxPriorityFeePerGas = rundlerFees.maxPriorityFeePerGas;
249348
- }
249343
+ const rundlerFees = await rundlerFeesRequest;
249344
+ maxFeePerGas = rundlerFees.maxFeePerGas;
249345
+ maxPriorityFeePerGas = rundlerFees.maxPriorityFeePerGas;
249349
249346
  } catch (e4) {
249350
249347
  if (params.requireBundlerEstimate) {
249351
249348
  throw new Error(`Bundler gas estimation failed: ${e4 instanceof Error ? e4.message : String(e4)}`, {
@@ -250133,6 +250130,7 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
250133
250130
  *
250134
250131
  * The ERC-4337 bundler URL is read from `dest.bundlerUrl`, set when constructing
250135
250132
  * the destination chain via {@link EvmChain.create} or {@link EvmChainParams.bundlerUrl}.
250133
+ * An `EvmChain` given none uses the bundler Hyperbridge runs for it.
250136
250134
  *
250137
250135
  * @param source - Source chain for order placement
250138
250136
  * @param dest - Destination chain for order fulfillment
@@ -250822,6 +250820,27 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
250822
250820
  }
250823
250821
  });
250824
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
+
250825
250844
  // src/services/FillerConfigService.ts
250826
250845
  function validateRpcUrls(rpcUrls) {
250827
250846
  if (rpcUrls.length === 0) {
@@ -250901,7 +250920,7 @@ async function resolveChainConfigs(chains2, options = {}) {
250901
250920
  "RPC endpoint could not report its chainId at startup; keeping it for the quorum to judge per call"
250902
250921
  );
250903
250922
  }
250904
- return { chainId: first3.chainId, rpcUrls, bundlerUrl: chain2.bundlerUrl };
250923
+ return { chainId: first3.chainId, rpcUrls, bundlerUrl: hyperbridgeBundlerUrl(first3.chainId) };
250905
250924
  })
250906
250925
  );
250907
250926
  }
@@ -250912,6 +250931,7 @@ var init_FillerConfigService = __esm({
250912
250931
  init_esm_shims();
250913
250932
  init_Logger();
250914
250933
  init_node10();
250934
+ init_bundlers();
250915
250935
  DEFAULT_BLOCK_SCAN_INTERVAL_SECONDS = 3;
250916
250936
  MIN_BLOCK_SCAN_INTERVAL_SECONDS = 0.1;
250917
250937
  DEFAULT_MIN_ORDER_SIZE_USD = 20;
@@ -250980,12 +251000,6 @@ var init_FillerConfigService = __esm({
250980
251000
  }
250981
251001
  this.rpcOverrides.set(chainId, validateRpcUrls(rpcUrls));
250982
251002
  }
250983
- setBundlerUrl(chainId, bundlerUrl) {
250984
- if (!this.rpcOverrides.has(chainId)) {
250985
- throw new Error(`Chain ${chainId} is not configured`);
250986
- }
250987
- this.bundlerUrls.set(chainId, bundlerUrl);
250988
- }
250989
251003
  /** Replaces the rebalancing config at runtime; trigger checks read it live. */
250990
251004
  setRebalancing(rebalancing) {
250991
251005
  if (this.fillerConfig) this.fillerConfig.rebalancing = rebalancing;
@@ -251356,9 +251370,6 @@ function validateConfig(config5, cliWatchOnly = false) {
251356
251370
  if (!Array.isArray(chain2.rpcUrls) || chain2.rpcUrls.length === 0 || chain2.rpcUrls.some((u6) => !u6)) {
251357
251371
  throw new Error("Each chain configuration must have rpcUrls (a non-empty array of strings)");
251358
251372
  }
251359
- if (!chain2.bundlerUrl) {
251360
- throw new Error("Each chain configuration must have bundlerUrl");
251361
- }
251362
251373
  }
251363
251374
  const concurrent = config5.simplex.maxConcurrentOrders;
251364
251375
  if (concurrent !== void 0) {
@@ -251606,7 +251617,7 @@ function nativeTokenSymbol(chainId) {
251606
251617
  return CHAIN_NATIVE_SYMBOLS[chainId] ?? "ETH";
251607
251618
  }
251608
251619
  function chainsForNetwork(network) {
251609
- return INIT_CHAINS.filter((chain2) => chain2.network === network);
251620
+ return INIT_CHAINS.filter((chain2) => chain2.network === network && chain2.hyperbridgeBundlerUrl);
251610
251621
  }
251611
251622
  function chainByChainId(chainId) {
251612
251623
  return INIT_CHAINS.find((chain2) => chain2.chainId === chainId);
@@ -251614,12 +251625,13 @@ function chainByChainId(chainId) {
251614
251625
  function chainByAlchemySubdomain(subdomain) {
251615
251626
  return INIT_CHAINS.find((chain2) => chain2.alchemySubdomain === subdomain);
251616
251627
  }
251617
- var FREE_RPC_URLS, HYPERBRIDGE_BUNDLER_URLS, CHAIN_NATIVE_SYMBOLS, INIT_CHAINS, HYPERBRIDGE_WS_DEFAULTS;
251628
+ var FREE_RPC_URLS, CHAIN_NATIVE_SYMBOLS, INIT_CHAINS, HYPERBRIDGE_WS_DEFAULTS;
251618
251629
  var init_chains2 = __esm({
251619
251630
  "src/cli/init/chains.ts"() {
251620
251631
  "use strict";
251621
251632
  init_esm_shims();
251622
251633
  init_external_links();
251634
+ init_bundlers();
251623
251635
  FREE_RPC_URLS = {
251624
251636
  1: [
251625
251637
  "https://mainnet.gateway.tenderly.co",
@@ -251666,13 +251678,6 @@ var init_chains2 = __esm({
251666
251678
  "https://arb1.arbitrum.io/rpc"
251667
251679
  ]
251668
251680
  };
251669
- HYPERBRIDGE_BUNDLER_URLS = {
251670
- 1: "https://bundler.polytope.technology/ethereum",
251671
- 56: "https://bundler.polytope.technology/bsc",
251672
- 137: "https://bundler.polytope.technology/polygon",
251673
- 8453: "https://bundler.polytope.technology/base",
251674
- 42161: "https://bundler.polytope.technology/arbitrum"
251675
- };
251676
251681
  CHAIN_NATIVE_SYMBOLS = {
251677
251682
  1: "ETH",
251678
251683
  56: "BNB",
@@ -251771,7 +251776,8 @@ var init_chains2 = __esm({
251771
251776
  label: "Polygon Amoy",
251772
251777
  network: "testnet",
251773
251778
  alchemySubdomain: "polygon-amoy",
251774
- explorerUrl: external_links_default.chainExplorers.polygonAmoy
251779
+ explorerUrl: external_links_default.chainExplorers.polygonAmoy,
251780
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[80002]
251775
251781
  },
251776
251782
  {
251777
251783
  chainId: 97,
@@ -251779,7 +251785,8 @@ var init_chains2 = __esm({
251779
251785
  label: "BSC Chapel",
251780
251786
  network: "testnet",
251781
251787
  alchemySubdomain: "bnb-testnet",
251782
- explorerUrl: external_links_default.chainExplorers.bnbChapel
251788
+ explorerUrl: external_links_default.chainExplorers.bnbChapel,
251789
+ hyperbridgeBundlerUrl: HYPERBRIDGE_BUNDLER_URLS[97]
251783
251790
  }
251784
251791
  ];
251785
251792
  HYPERBRIDGE_WS_DEFAULTS = {
@@ -252021,8 +252028,6 @@ function emitFillerToml(config5, options = {}) {
252021
252028
  push("[[chains]]");
252022
252029
  push("# List 2+ organisationally independent RPC providers to enable quorum log scanning.");
252023
252030
  push(kv("rpcUrls", chain2.rpcUrls));
252024
- push("# ERC-4337 bundler used to submit fill UserOperations on this chain.");
252025
- push(kv("bundlerUrl", chain2.bundlerUrl));
252026
252031
  push();
252027
252032
  });
252028
252033
  return `${out.join("\n").trimEnd()}
@@ -336953,9 +336958,6 @@ function parseAlchemyUrl(url2) {
336953
336958
  if (!match) return null;
336954
336959
  return { subdomain, apiKey: match[1] };
336955
336960
  }
336956
- function isAlchemyUrl(url2) {
336957
- return parseAlchemyUrl(url2) !== null;
336958
- }
336959
336961
  function deriveAlchemyRpc(apiKey, chainId) {
336960
336962
  const chain2 = chainByChainId(chainId);
336961
336963
  if (!chain2?.alchemySubdomain) return null;
@@ -337806,10 +337808,9 @@ var init_help_text = __esm({
337806
337808
  "use strict";
337807
337809
  init_esm_shims();
337808
337810
  WHY = {
337809
- chains: "Simplex listens for orders and fills only on the chains you pick. Each chain needs its own RPC, an ERC-4337 bundler, and funded balances (native gas + stablecoins).",
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.",
337810
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.",
337811
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.",
337812
- bundler: "Fills execute as ERC-4337 UserOperations; the bundler submits them on-chain. Hyperbridge runs no bundler for these chains, so use a provider such as Pimlico.",
337813
337814
  signer: "This wallet signs every fill and holds your stablecoin float on each chain. It's the identity of your filler.",
337814
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.",
337815
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.",
@@ -337871,8 +337872,7 @@ function detectPrefillNetwork(prefill) {
337871
337872
  if (!prefill) return void 0;
337872
337873
  for (const chainId of prefill.chainIds) {
337873
337874
  if (chainId === null) continue;
337874
- const meta = chainsForNetwork("testnet").find((c6) => c6.chainId === chainId);
337875
- if (meta) return "testnet";
337875
+ if (chainByChainId(chainId)?.network === "testnet") return "testnet";
337876
337876
  }
337877
337877
  return "mainnet";
337878
337878
  }
@@ -338066,122 +338066,6 @@ var init_chains3 = __esm({
338066
338066
  }
338067
338067
  });
338068
338068
 
338069
- // src/cli/init/derive/pimlico.ts
338070
- function parsePimlicoUrl(url2) {
338071
- let parsed;
338072
- try {
338073
- parsed = new URL(url2);
338074
- } catch {
338075
- return null;
338076
- }
338077
- if (parsed.protocol !== "https:") return null;
338078
- if (parsed.hostname !== "api.pimlico.io") return null;
338079
- const match = parsed.pathname.match(/^\/v2\/([^/]+)\/rpc$/);
338080
- if (!match) return null;
338081
- const chainId = Number(match[1]);
338082
- if (!Number.isInteger(chainId) || chainId <= 0) return null;
338083
- const apiKey = parsed.searchParams.get("apikey");
338084
- if (!apiKey) return null;
338085
- return { chainId, apiKey };
338086
- }
338087
- function derivePimlicoBundler(apiKey, chainId) {
338088
- return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${encodeURIComponent(apiKey)}`;
338089
- }
338090
- var init_pimlico = __esm({
338091
- "src/cli/init/derive/pimlico.ts"() {
338092
- "use strict";
338093
- init_esm_shims();
338094
- }
338095
- });
338096
-
338097
- // src/cli/init/steps/bundlers.ts
338098
- async function stepBundlers(state, prefill) {
338099
- for (const chain2 of state.chains) {
338100
- if (chain2.meta.hyperbridgeBundlerUrl) chain2.bundlerUrl = chain2.meta.hyperbridgeBundlerUrl;
338101
- }
338102
- if (state.chains.every((chain2) => chain2.bundlerUrl)) return;
338103
- why(WHY.bundler);
338104
- const alchemyChains = state.chains.filter((chain2) => {
338105
- if (chain2.bundlerUrl || !isAlchemyUrl(chain2.rpcUrls[0])) return false;
338106
- const existing = prefillBundlerFor(chain2.meta.chainId, prefill);
338107
- return !existing || existing === chain2.rpcUrls[0];
338108
- });
338109
- if (alchemyChains.length > 0) {
338110
- const reuse = guard(
338111
- await confirm({
338112
- message: `Reuse the Alchemy RPC as the ERC-4337 bundler for ${alchemyChains.map((c6) => c6.meta.label).join(", ")}?`,
338113
- initialValue: true
338114
- })
338115
- );
338116
- if (reuse) {
338117
- for (const chain2 of alchemyChains) chain2.bundlerUrl = chain2.rpcUrls[0];
338118
- }
338119
- }
338120
- const alchemyCapable = state.chains.filter((chain2) => !chain2.bundlerUrl && chain2.meta.alchemySubdomain);
338121
- if (alchemyCapable.length > 0) {
338122
- const useKey = guard(
338123
- await confirm({
338124
- message: `Configure the bundler for ${alchemyCapable.map((c6) => c6.meta.label).join(", ")} from one Alchemy API key?`,
338125
- initialValue: true
338126
- })
338127
- );
338128
- if (useKey) {
338129
- const apiKey = await askSecret("Alchemy API key");
338130
- for (const chain2 of alchemyCapable) {
338131
- const url2 = deriveAlchemyRpc(apiKey, chain2.meta.chainId);
338132
- if (url2) chain2.bundlerUrl = url2;
338133
- }
338134
- }
338135
- }
338136
- const pimlico = new ProviderDerivation({
338137
- detect: (url2) => parsePimlicoUrl(url2)?.apiKey ?? null,
338138
- derive: derivePimlicoBundler,
338139
- confirmMessage: (remaining) => `Pimlico key detected \u2014 derive bundler URLs for ${remaining} from the same key?`
338140
- });
338141
- for (const chain2 of state.chains) {
338142
- if (chain2.bundlerUrl) continue;
338143
- const existing = prefillBundlerFor(chain2.meta.chainId, prefill);
338144
- const derived2 = pimlico.candidate(chain2.meta.chainId);
338145
- const url2 = derived2 ? await askDerivedOrCustom(
338146
- `Bundler for ${chain2.meta.label}`,
338147
- derived2,
338148
- "Use the derived Pimlico URL",
338149
- () => askBundlerUrl(chain2.meta.label, existing)
338150
- ) : await askBundlerUrl(chain2.meta.label, existing);
338151
- chain2.bundlerUrl = url2;
338152
- const remaining = state.chains.filter((c6) => !c6.bundlerUrl);
338153
- await pimlico.offer(
338154
- url2,
338155
- remaining.map((c6) => c6.meta.label)
338156
- );
338157
- }
338158
- }
338159
- function prefillBundlerFor(chainId, prefill) {
338160
- if (!prefill) return void 0;
338161
- const index3 = prefill.chainIds.indexOf(chainId);
338162
- if (index3 === -1) return void 0;
338163
- return prefill.config.chains[index3]?.bundlerUrl || void 0;
338164
- }
338165
- function askBundlerUrl(label, initial) {
338166
- return askUrl(`ERC-4337 bundler URL for ${label}`, {
338167
- initial,
338168
- placeholder: "https://api.pimlico.io/v2/<chainId>/rpc?apikey=<your-key>",
338169
- required: "Bundler URL is required \u2014 fills are submitted through it"
338170
- });
338171
- }
338172
- var init_bundlers = __esm({
338173
- "src/cli/init/steps/bundlers.ts"() {
338174
- "use strict";
338175
- init_esm_shims();
338176
- init_dist11();
338177
- init_alchemy();
338178
- init_pimlico();
338179
- init_derive_flow();
338180
- init_prompt_utils();
338181
- init_help_text();
338182
- }
338183
- });
338184
-
338185
338069
  // src/cli/init/steps/signer.ts
338186
338070
  async function stepSigner(state, prefill) {
338187
338071
  why(WHY.signer);
@@ -338663,7 +338547,7 @@ function assembleConfig(state) {
338663
338547
  // would otherwise shadow the fresh entry (last [[chains]] wins at load).
338664
338548
  chains: [
338665
338549
  ...state.passthroughChains,
338666
- ...state.chains.map((chain2) => ({ rpcUrls: chain2.rpcUrls, bundlerUrl: chain2.bundlerUrl ?? "" }))
338550
+ ...state.chains.map((chain2) => ({ rpcUrls: chain2.rpcUrls }))
338667
338551
  ],
338668
338552
  rebalancing,
338669
338553
  vault: hasVault ? vault : void 0,
@@ -338685,10 +338569,7 @@ function chainComments(state) {
338685
338569
  function showSummary(state, outputPath) {
338686
338570
  const lines = [];
338687
338571
  for (const chain2 of state.chains) {
338688
- const bundlerHost2 = chain2.bundlerUrl ? new URL(chain2.bundlerUrl).hostname : "?";
338689
- lines.push(
338690
- `${chain2.meta.label}: ${chain2.rpcUrls.length} RPC${chain2.rpcUrls.length > 1 ? "s (quorum)" : ""}, bundler ${bundlerHost2}`
338691
- );
338572
+ lines.push(`${chain2.meta.label}: ${chain2.rpcUrls.length} RPC${chain2.rpcUrls.length > 1 ? "s (quorum)" : ""}`);
338692
338573
  }
338693
338574
  if (state.passthroughChains.length > 0) {
338694
338575
  lines.push(`+ ${state.passthroughChains.length} unmanaged chain(s) kept from the previous config`);
@@ -338780,7 +338661,6 @@ async function runInit(options) {
338780
338661
  const state = newWizardState();
338781
338662
  state.prefillConfig = prefill?.config;
338782
338663
  await stepChains(state, prefill);
338783
- await stepBundlers(state, prefill);
338784
338664
  await stepSigner(state, prefill);
338785
338665
  await stepHyperbridge(state, prefill);
338786
338666
  for (; ; ) {
@@ -338880,7 +338760,6 @@ var init_init3 = __esm({
338880
338760
  init_migrate_legacy();
338881
338761
  init_state();
338882
338762
  init_chains3();
338883
- init_bundlers();
338884
338763
  init_signer2();
338885
338764
  init_hyperbridge();
338886
338765
  init_finetune();
@@ -339170,6 +339049,7 @@ init_dist4();
339170
339049
  // src/services/server/UiServer.ts
339171
339050
  init_esm_shims();
339172
339051
  init_interpolated_curve();
339052
+ init_bundlers();
339173
339053
  init_asset_registry();
339174
339054
  init_pairs();
339175
339055
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -343586,86 +343466,6 @@ init_pairs();
343586
343466
  init_interpolated_curve();
343587
343467
  init_asset_registry();
343588
343468
  init_FillerConfigService();
343589
-
343590
- // src/services/bundler-preflight.ts
343591
- init_esm_shims();
343592
- init_chains2();
343593
- init_interpolated_curve();
343594
- init_Logger();
343595
- var BUNDLER_PREFLIGHT_TIMEOUT_MS = 1e4;
343596
- async function assertBundlersServeEntryPoint(chains2, configService, options = {}) {
343597
- const timeoutMs = options.timeoutMs ?? BUNDLER_PREFLIGHT_TIMEOUT_MS;
343598
- const logger8 = moduleLogger(configService.loggers, "bundler-preflight");
343599
- const failures = await Promise.all(
343600
- chains2.map(async ({ chainId, bundlerUrl }) => {
343601
- if (options.watchOnly?.[chainId] === true) return void 0;
343602
- if (!bundlerUrl?.trim()) return void 0;
343603
- const entryPoint = configService.getEntryPointAddress(formatChainKey(chainId));
343604
- if (!entryPoint) return void 0;
343605
- return checkBundler(chainId, bundlerUrl.trim(), entryPoint, timeoutMs, logger8);
343606
- })
343607
- );
343608
- const messages = failures.filter((failure) => failure !== void 0);
343609
- if (messages.length > 0) throw new Error(messages.join("; "));
343610
- }
343611
- function servesEntryPoint(listed, entryPoint) {
343612
- return Array.isArray(listed) && listed.some((address) => String(address).toLowerCase() === entryPoint.toLowerCase());
343613
- }
343614
- function describeEntryPoints(listed) {
343615
- return Array.isArray(listed) && listed.length > 0 ? listed.map(String).join(", ") : "none";
343616
- }
343617
- function bundlerHost(url2) {
343618
- try {
343619
- return new URL(url2).host || "an unparseable URL";
343620
- } catch {
343621
- return "an unparseable URL";
343622
- }
343623
- }
343624
- function chainName(chainId) {
343625
- const label = chainByChainId(chainId)?.label;
343626
- return label ? `${label} (${formatChainKey(chainId)})` : formatChainKey(chainId);
343627
- }
343628
- async function checkBundler(chainId, bundlerUrl, entryPoint, timeoutMs, logger8) {
343629
- const host = bundlerHost(bundlerUrl);
343630
- const subject = `Bundler ${host} for ${chainName(chainId)}`;
343631
- const signal = AbortSignal.timeout(timeoutMs);
343632
- let listed;
343633
- try {
343634
- listed = await supportedEntryPoints(bundlerUrl, signal);
343635
- } catch (err) {
343636
- const reason = signal.aborted ? `timed out after ${timeoutMs}ms` : errorReason(err);
343637
- logger8.warn(
343638
- { chain: formatChainKey(chainId), bundler: host },
343639
- `${subject} did not answer eth_supportedEntryPoints: ${reason.split(bundlerUrl).join(host)}. Continuing without confirming it serves EntryPoint ${entryPoint}`
343640
- );
343641
- return void 0;
343642
- }
343643
- if (servesEntryPoint(listed, entryPoint)) return void 0;
343644
- return `${subject} does not support EntryPoint ${entryPoint}; it lists ${describeEntryPoints(listed)}`;
343645
- }
343646
- async function supportedEntryPoints(bundlerUrl, signal) {
343647
- const response = await fetch(bundlerUrl, {
343648
- method: "POST",
343649
- headers: { "Content-Type": "application/json" },
343650
- body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_supportedEntryPoints", params: [] }),
343651
- signal
343652
- });
343653
- if (!response.ok) throw new Error(`HTTP ${response.status}`);
343654
- const json = await response.json();
343655
- if (json.error) throw new Error(json.error.message ?? JSON.stringify(json.error));
343656
- const { result } = json;
343657
- if (!Array.isArray(result) || !result.every((address) => typeof address === "string")) {
343658
- throw new Error("the result is not a list of addresses");
343659
- }
343660
- return result;
343661
- }
343662
- function errorReason(err) {
343663
- if (!(err instanceof Error)) return String(err);
343664
- const { cause } = err;
343665
- return cause instanceof Error ? `${err.message} (${cause.message})` : err.message;
343666
- }
343667
-
343668
- // src/services/server/setup-api.ts
343669
343469
  init_wallet3();
343670
343470
 
343671
343471
  // src/services/substrate-key.ts
@@ -343781,8 +343581,6 @@ async function handleSetupRequest(server, setup, req, res, path2, method) {
343781
343581
  return sendJson(res, 200, await validateAlchemyKey(body, deps));
343782
343582
  case "validate-rpc":
343783
343583
  return sendJson(res, 200, await validateRpc(body, deps));
343784
- case "validate-bundler":
343785
- return sendJson(res, 200, await validateBundler(body, deps));
343786
343584
  case "validate-token":
343787
343585
  return sendJson(res, 200, await validateToken(body));
343788
343586
  case "derive-evm-address":
@@ -343815,9 +343613,7 @@ async function validateAlchemyKey(body, deps) {
343815
343613
  stateMachineId: meta.stateMachineId,
343816
343614
  label: meta.label,
343817
343615
  note: meta.note,
343818
- rpcUrl,
343819
- // Alchemy serves ERC-4337 bundler methods on the same endpoint.
343820
- bundlerUrl: rpcUrl
343616
+ rpcUrl
343821
343617
  };
343822
343618
  });
343823
343619
  const probe = chains2.find((c6) => c6.rpcUrl);
@@ -343855,40 +343651,6 @@ async function validateRpc(body, deps) {
343855
343651
  );
343856
343652
  return { ok: results.every((r7) => !r7.error), results };
343857
343653
  }
343858
- async function validateBundler(body, deps) {
343859
- const url2 = String(body.url ?? "").trim();
343860
- if (!url2) return { ok: false, warning: "Bundler URL is empty" };
343861
- try {
343862
- const entryPoints = await withTimeout3(
343863
- deps.rpcRequest(url2, "eth_supportedEntryPoints", []),
343864
- PROBE_TIMEOUT_MS,
343865
- "Bundler probe"
343866
- );
343867
- const chainId = Number(body.chainId);
343868
- const required2 = Number.isInteger(chainId) ? new ChainConfigService({}).getEntryPointAddress(formatChainKey(chainId)) : void 0;
343869
- if (!required2) return { ok: true, entryPoints };
343870
- if (!Array.isArray(entryPoints) || !entryPoints.every((address) => typeof address === "string")) {
343871
- return {
343872
- ok: true,
343873
- entryPoints,
343874
- warning: `Bundler's eth_supportedEntryPoints answer is not a list of addresses, so it could not be confirmed to support EntryPoint ${required2}, which this chain's solver account uses. Simplex will use it and warn.`
343875
- };
343876
- }
343877
- if (!servesEntryPoint(entryPoints, required2)) {
343878
- return {
343879
- ok: true,
343880
- entryPoints,
343881
- warning: `Bundler does not support EntryPoint ${required2}, which this chain's solver account uses; it lists ${describeEntryPoints(entryPoints)}. Simplex will refuse to use it.`
343882
- };
343883
- }
343884
- return { ok: true, entryPoints };
343885
- } catch (err) {
343886
- return {
343887
- ok: true,
343888
- warning: `Bundler did not answer eth_supportedEntryPoints: ${err instanceof Error ? err.message : err}`
343889
- };
343890
- }
343891
- }
343892
343654
  async function validateToken(body) {
343893
343655
  const rpcUrl = String(body.rpcUrl ?? "").trim();
343894
343656
  const address = String(body.address ?? "").trim();
@@ -344026,7 +343788,6 @@ function maskToml(config5, chainLabels) {
344026
343788
  }
344027
343789
  for (const chain2 of masked.chains) {
344028
343790
  chain2.rpcUrls = chain2.rpcUrls.map(maskUrlKey);
344029
- chain2.bundlerUrl = maskUrlKey(chain2.bundlerUrl);
344030
343791
  }
344031
343792
  return emitFillerToml(masked, { chainComments: chainLabels });
344032
343793
  }
@@ -344100,12 +343861,7 @@ function openSseStream(req, res, clients) {
344100
343861
  res.once("close", cleanup);
344101
343862
  res.once("error", cleanup);
344102
343863
  }
344103
- var OPERATOR_PROBES = [
344104
- "/api/setup/validate-token",
344105
- "/api/setup/validate-rpc",
344106
- "/api/setup/validate-bundler",
344107
- "/api/setup/validate-alchemy-key"
344108
- ];
343864
+ var OPERATOR_PROBES = ["/api/setup/validate-token", "/api/setup/validate-rpc", "/api/setup/validate-alchemy-key"];
344109
343865
  var LOGS_UNAVAILABLE = "Log capture is not enabled for this filler";
344110
343866
  var MAX_LOG_STREAM_QUEUE = 5e3;
344111
343867
  var MAX_LOG_PAGE = 2e3;
@@ -344555,9 +344311,6 @@ var UiServer = class {
344555
344311
  const body = JSON.parse(await readBody(req));
344556
344312
  if (path2 === "/api/setup/validate-rpc")
344557
344313
  return sendJson(res, 200, await validateRpc(body, this.deps));
344558
- if (path2 === "/api/setup/validate-bundler") {
344559
- return sendJson(res, 200, await validateBundler(body, this.deps));
344560
- }
344561
344314
  if (path2 === "/api/setup/validate-alchemy-key") {
344562
344315
  return sendJson(res, 200, await validateAlchemyKey(body, this.deps));
344563
344316
  }
@@ -345273,7 +345026,7 @@ var UiServer = class {
345273
345026
  stateMachineId: formatChainKey(chainId),
345274
345027
  label: chainLabel(chainId),
345275
345028
  rpcUrls: chain2.rpcUrls,
345276
- bundlerUrl: chain2.bundlerUrl,
345029
+ bundlerUrl: hyperbridgeBundlerUrl(chainId) ?? "",
345277
345030
  watchOnly: globalWatchOnly ? watchOnly : Boolean(watchOnly?.[String(chainId)]),
345278
345031
  running: running.has(chainId)
345279
345032
  };
@@ -345320,11 +345073,11 @@ var UiServer = class {
345320
345073
  }
345321
345074
  const rpcUrls = (Array.isArray(row.rpcUrls) ? row.rpcUrls : []).map((url2) => String(url2).trim()).filter(Boolean);
345322
345075
  validateRpcUrls(rpcUrls);
345323
- const bundlerUrl = String(row.bundlerUrl ?? "").trim();
345324
- if (!bundlerUrl) {
345325
- 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`);
345326
345079
  }
345327
- rows.push({ chainId, rpcUrls, bundlerUrl, watchOnly: row.watchOnly === true });
345080
+ rows.push({ chainId, rpcUrls, watchOnly });
345328
345081
  }
345329
345082
  } catch (err) {
345330
345083
  return sendJson(res, 400, { error: err instanceof Error ? err.message : String(err) });
@@ -345356,7 +345109,7 @@ var UiServer = class {
345356
345109
  } catch (err) {
345357
345110
  return sendJson(res, 400, { error: err instanceof Error ? err.message : String(err) });
345358
345111
  }
345359
- op.config.chains = rows.map(({ rpcUrls, bundlerUrl }) => ({ rpcUrls, bundlerUrl }));
345112
+ op.config.chains = rows.map(({ rpcUrls }) => ({ rpcUrls }));
345360
345113
  if (Object.keys(confirmationPolicies).length > 0) op.config.confirmationPolicies = confirmationPolicies;
345361
345114
  if (typeof op.config.simplex.watchOnly !== "boolean") {
345362
345115
  const perChain = Object.fromEntries(rows.filter((r7) => r7.watchOnly).map((r7) => [String(r7.chainId), true]));
@@ -352242,7 +351995,7 @@ var UserOpSender = class {
352242
351995
  let auth;
352243
351996
  let fees4;
352244
351997
  try {
352245
- fees4 = await this.getGasPrice(bundlerUrl, publicClient, chainId);
351998
+ fees4 = await this.getGasPrice(bundlerUrl, publicClient);
352246
351999
  const gasForPrefund = gas ?? {
352247
352000
  verificationGasLimit: FALLBACK_VERIFICATION_GAS_LIMIT,
352248
352001
  callGasLimit: FALLBACK_CALL_GAS_LIMIT,
@@ -352397,48 +352150,26 @@ var UserOpSender = class {
352397
352150
  return userOp;
352398
352151
  }
352399
352152
  /**
352400
- * Mirrors the gas-price selection used by the delegation and fill paths: Pimlico's and
352401
- * Alchemy's own pricing, otherwise the chain's gas price raised to the priority fee a
352402
- * rundler bundler requires, when the bundler gives one.
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.
352403
352155
  */
352404
- async getGasPrice(bundlerUrl, publicClient, chainId) {
352405
- const lower2 = bundlerUrl.toLowerCase();
352406
- if (lower2.includes("pimlico.io")) {
352407
- const res = await this.sendBundlerRpc(
352408
- bundlerUrl,
352409
- BundlerMethod.PIMLICO_GET_USER_OPERATION_GAS_PRICE,
352410
- []
352411
- );
352412
- return { maxFeePerGas: BigInt(res.fast.maxFeePerGas), maxPriorityFeePerGas: BigInt(res.fast.maxPriorityFeePerGas) };
352413
- }
352414
- if (lower2.includes("alchemy.com")) {
352415
- const [rundlerPriorityFee2, latestBlock2] = await Promise.all([
352416
- this.sendBundlerRpc(bundlerUrl, BundlerMethod.RUNDLER_MAX_PRIORITY_FEE_PER_GAS, []),
352417
- publicClient.getBlock({ blockTag: "latest" })
352418
- ]);
352419
- const baseFeePerGas = latestBlock2.baseFeePerGas ?? await publicClient.getGasPrice();
352420
- const isArbitrum = BigInt(chainId) === 42161n;
352421
- const prioBump = isArbitrum ? 0n : 25n;
352422
- const maxPriorityFeePerGas = BigInt(rundlerPriorityFee2) + BigInt(rundlerPriorityFee2) * prioBump / 100n;
352423
- const bufferedBaseFee = baseFeePerGas + baseFeePerGas * 50n / 100n;
352424
- return { maxFeePerGas: bufferedBaseFee + maxPriorityFeePerGas, maxPriorityFeePerGas };
352425
- }
352426
- const [gasPrice, rundlerPriorityFee] = await Promise.all([
352156
+ async getGasPrice(bundlerUrl, publicClient) {
352157
+ const [gasPrice, latestBlock] = await Promise.all([
352427
352158
  publicClient.getGasPrice(),
352428
- fetchRundlerPriorityFee(bundlerUrl)
352159
+ publicClient.getBlock({ blockTag: "latest" })
352429
352160
  ]);
352430
- const fees4 = {
352431
- maxFeePerGas: gasPrice + gasPrice * MAX_FEE_BUMP_PERCENT / 100n,
352432
- maxPriorityFeePerGas: gasPrice + gasPrice * PRIORITY_FEE_BUMP_PERCENT / 100n
352433
- };
352434
- if (rundlerPriorityFee === null) return fees4;
352435
- const latestBlock = await publicClient.getBlock({ blockTag: "latest" });
352436
- return applyRundlerPriorityFee(fees4, {
352437
- rundlerPriorityFee,
352438
- baseFeePerGas: latestBlock.baseFeePerGas ?? gasPrice,
352439
- priorityFeeBumpPercent: PRIORITY_FEE_BUMP_PERCENT,
352440
- maxFeeBumpPercent: MAX_FEE_BUMP_PERCENT
352441
- });
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
+ );
352442
352173
  }
352443
352174
  async sendBundlerRpc(bundlerUrl, method, params) {
352444
352175
  const response = await fetch(bundlerUrl, {
@@ -386836,6 +386567,86 @@ init_FillerConfigService();
386836
386567
  init_filler_toml();
386837
386568
  init_defaults8();
386838
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
+
386839
386650
  // src/orderbook/lifecycle.ts
386840
386651
  init_esm_shims();
386841
386652
  init_Logger();
@@ -388943,7 +388754,7 @@ var OrderScanner = class _OrderScanner {
388943
388754
  async addChainNow(chain2) {
388944
388755
  if (this.closed) throw new Error("This OrderScanner is closed");
388945
388756
  const rpcUrls = validateRpcUrls(chain2.rpcUrls);
388946
- const chainId = chain2.chainId ?? (await resolveChainConfigs([{ rpcUrls, bundlerUrl: chain2.bundlerUrl ?? "" }], {
388757
+ const chainId = chain2.chainId ?? (await resolveChainConfigs([{ rpcUrls }], {
388947
388758
  loggers: this.loggers,
388948
388759
  tolerateUnreachable: true
388949
388760
  }))[0].chainId;
@@ -389376,10 +389187,7 @@ var ChainController = class {
389376
389187
  async add(chain2) {
389377
389188
  return this.serialise(async () => {
389378
389189
  validateRpcUrls(chain2.rpcUrls);
389379
- if (!chain2.bundlerUrl?.trim()) {
389380
- throw new Error("A bundler URL is required to submit fill UserOperations");
389381
- }
389382
- const [resolved] = await resolveChainConfigs([{ rpcUrls: chain2.rpcUrls, bundlerUrl: chain2.bundlerUrl }]);
389190
+ const [resolved] = await resolveChainConfigs([{ rpcUrls: chain2.rpcUrls }]);
389383
389191
  const { chainId } = resolved;
389384
389192
  const { configService, config: config5, intentFiller } = this.runtime;
389385
389193
  if (configService.getConfiguredChainIds().includes(chainId)) {
@@ -389408,7 +389216,7 @@ var ChainController = class {
389408
389216
  if (watchOnly) intentFiller.setWatchOnly(chainId, true);
389409
389217
  try {
389410
389218
  if (!inScanner) {
389411
- await this.scanner.addChain({ rpcUrls: chain2.rpcUrls, bundlerUrl: chain2.bundlerUrl, chainId });
389219
+ await this.scanner.addChain({ rpcUrls: chain2.rpcUrls, chainId });
389412
389220
  }
389413
389221
  this.runtime.chainClientManager.invalidate(formatChainKey(chainId));
389414
389222
  await intentFiller.addChain(configService.getChainConfig(formatChainKey(chainId)));
@@ -389425,7 +389233,7 @@ var ChainController = class {
389425
389233
  this.runtime.confirmationPolicy.adopt(chainId, resolvedPolicy);
389426
389234
  }
389427
389235
  this.runtime.resolvedChains.push(resolved);
389428
- config5.chains = [...config5.chains, { rpcUrls: chain2.rpcUrls, bundlerUrl: chain2.bundlerUrl }];
389236
+ config5.chains = [...config5.chains, { rpcUrls: chain2.rpcUrls }];
389429
389237
  if (Object.keys(confirmationPolicies).length > 0) config5.confirmationPolicies = confirmationPolicies;
389430
389238
  this.syncWatchOnlyToConfig();
389431
389239
  await this.persist();
@@ -389470,9 +389278,7 @@ var ChainController = class {
389470
389278
  validateRpcUrls(rpcUrls);
389471
389279
  const index3 = this.runtime.resolvedChains.findIndex((chain2) => chain2.chainId === chainId);
389472
389280
  if (index3 < 0) throw new Error(`Chain ${chainId} is not configured`);
389473
- const [probed] = await resolveChainConfigs([
389474
- { rpcUrls, bundlerUrl: this.runtime.resolvedChains[index3].bundlerUrl ?? "" }
389475
- ]);
389281
+ const [probed] = await resolveChainConfigs([{ rpcUrls }]);
389476
389282
  if (probed.chainId !== chainId) {
389477
389283
  throw new Error(`Those endpoints answer for chain ${probed.chainId}, not ${chainId}`);
389478
389284
  }
@@ -389491,20 +389297,6 @@ var ChainController = class {
389491
389297
  await this.persist();
389492
389298
  });
389493
389299
  }
389494
- async setBundlerUrl(chainId, bundlerUrl) {
389495
- return this.serialise(async () => {
389496
- if (!bundlerUrl?.trim()) throw new Error("A bundler URL is required");
389497
- const index3 = this.runtime.resolvedChains.findIndex((chain2) => chain2.chainId === chainId);
389498
- if (index3 < 0) throw new Error(`Chain ${chainId} is not configured`);
389499
- await assertBundlersServeEntryPoint([{ chainId, bundlerUrl }], this.runtime.configService, {
389500
- watchOnly: this.runtime.intentFiller.getWatchOnly()
389501
- });
389502
- this.runtime.configService.setBundlerUrl(chainId, bundlerUrl);
389503
- this.runtime.resolvedChains[index3].bundlerUrl = bundlerUrl;
389504
- this.runtime.config.chains[index3].bundlerUrl = bundlerUrl;
389505
- await this.persist();
389506
- });
389507
- }
389508
389300
  /** Monitor without filling. Takes effect on the next order. */
389509
389301
  async setWatchOnly(chainId, watchOnly) {
389510
389302
  return this.serialise(async () => {