@hyperbridge/simplex 0.16.11 → 0.16.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/simplex.js +168 -34
- package/dist/bin/simplex.js.map +1 -1
- package/dist/index.cjs +120 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -1
- package/dist/index.d.ts +46 -1
- package/dist/index.js +120 -16
- package/dist/index.js.map +1 -1
- package/dist/ui/assets/{index-CD2NZXpG.js → index-QU1Ik7IX.js} +20 -20
- package/dist/ui/assets/{index-B_p2oQkc.css → index-XKHMOpY2.css} +1 -1
- package/dist/ui/index.html +2 -2
- package/package.json +4 -3
package/dist/bin/simplex.js
CHANGED
|
@@ -48802,6 +48802,7 @@ var init_esm2 = __esm({
|
|
|
48802
48802
|
init_encodeFunctionData2();
|
|
48803
48803
|
init_encodePacked2();
|
|
48804
48804
|
init_parseEventLogs2();
|
|
48805
|
+
init_isAddress2();
|
|
48805
48806
|
init_defineChain2();
|
|
48806
48807
|
init_concat2();
|
|
48807
48808
|
init_isHex2();
|
|
@@ -235360,7 +235361,7 @@ function resolveOrderFeeGasPriceBump(sourceStateMachineId, isSameChain) {
|
|
|
235360
235361
|
if (isSameChain) {
|
|
235361
235362
|
return 0n;
|
|
235362
235363
|
}
|
|
235363
|
-
return
|
|
235364
|
+
return sourceStateMachineId === "EVM-1" ? ETHEREUM_ORDER_FEE_GAS_PRICE_BUMP_PERCENT : DEFAULT_ORDER_FEE_GAS_PRICE_BUMP_PERCENT;
|
|
235364
235365
|
}
|
|
235365
235366
|
function utf8Encode(text2) {
|
|
235366
235367
|
const bytes5 = [];
|
|
@@ -235421,7 +235422,7 @@ function encodePhantomBidDeclaration(declaration) {
|
|
|
235421
235422
|
}
|
|
235422
235423
|
return u8aToHex(new Uint8Array(bytes5));
|
|
235423
235424
|
}
|
|
235424
|
-
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,
|
|
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;
|
|
235425
235426
|
var init_node10 = __esm({
|
|
235426
235427
|
"../sdk/dist/node/index.js"() {
|
|
235427
235428
|
"use strict";
|
|
@@ -248855,6 +248856,8 @@ query OrderStatus($commitment: String!) {
|
|
|
248855
248856
|
constructor(ctx, crypto10) {
|
|
248856
248857
|
__publicField(this, "ctx");
|
|
248857
248858
|
__publicField(this, "crypto");
|
|
248859
|
+
/** Call dispatchers read from a gateway, for chains whose config carries none. */
|
|
248860
|
+
__publicField(this, "dispatchers", /* @__PURE__ */ new Map());
|
|
248858
248861
|
this.ctx = ctx;
|
|
248859
248862
|
this.crypto = crypto10;
|
|
248860
248863
|
}
|
|
@@ -248876,7 +248879,9 @@ query OrderStatus($commitment: String!) {
|
|
|
248876
248879
|
* ephemeral keypair, applies state overrides, and calls
|
|
248877
248880
|
* `eth_estimateUserOperationGas`. Gas limits are bumped by 5-10% for
|
|
248878
248881
|
* headroom. If the bundler is Pimlico, gas prices are refined with
|
|
248879
|
-
* `pimlico_getUserOperationGasPrice`.
|
|
248882
|
+
* `pimlico_getUserOperationGasPrice`. If the bundler rejects the estimate,
|
|
248883
|
+
* fixed gas limits are returned in its place, or the call throws when
|
|
248884
|
+
* `params.requireBundlerEstimate` is set.
|
|
248880
248885
|
*
|
|
248881
248886
|
* **Fallback path (no bundler):** uses a fixed budget
|
|
248882
248887
|
* ({@link NO_BUNDLER_FILL_GAS_BASE} plus {@link NO_BUNDLER_FILL_GAS_PER_OUTPUT}
|
|
@@ -248890,6 +248895,8 @@ query OrderStatus($commitment: String!) {
|
|
|
248890
248895
|
* @returns A {@link FillOrderEstimate} containing all gas components,
|
|
248891
248896
|
* EIP-1559 fee values, total cost in wei, and total cost in the source
|
|
248892
248897
|
* chain's fee token.
|
|
248898
|
+
* @throws If `params.requireBundlerEstimate` is set and the bundler fails to
|
|
248899
|
+
* estimate the fill.
|
|
248893
248900
|
*/
|
|
248894
248901
|
async estimateFillOrder(params, pricingOptions = {}) {
|
|
248895
248902
|
const { order } = params;
|
|
@@ -249087,6 +249094,11 @@ query OrderStatus($commitment: String!) {
|
|
|
249087
249094
|
maxFeePerGas = bufferedBaseFee + maxPriorityFeePerGas;
|
|
249088
249095
|
}
|
|
249089
249096
|
} catch (e4) {
|
|
249097
|
+
if (params.requireBundlerEstimate) {
|
|
249098
|
+
throw new Error(`Bundler gas estimation failed: ${e4 instanceof Error ? e4.message : String(e4)}`, {
|
|
249099
|
+
cause: e4
|
|
249100
|
+
});
|
|
249101
|
+
}
|
|
249090
249102
|
console.warn("Bundler gas estimation failed, using fallback values:", e4);
|
|
249091
249103
|
}
|
|
249092
249104
|
} else {
|
|
@@ -249121,6 +249133,27 @@ query OrderStatus($commitment: String!) {
|
|
|
249121
249133
|
inputs
|
|
249122
249134
|
};
|
|
249123
249135
|
}
|
|
249136
|
+
/**
|
|
249137
|
+
* The call dispatcher the gateway on `chain` uses: the configured address, or the one
|
|
249138
|
+
* the gateway reports when the chain's config carries none.
|
|
249139
|
+
*
|
|
249140
|
+
* {@link buildStateOverride} writes it back into the gateway's params slot. Without an
|
|
249141
|
+
* address that value is 12 bytes instead of 32, and the bundler rejects the whole
|
|
249142
|
+
* estimate as `Invalid params`.
|
|
249143
|
+
*/
|
|
249144
|
+
async callDispatcher(chain2, gateway) {
|
|
249145
|
+
const configured = this.ctx.dest.configService.getCalldispatcherAddress(chain2);
|
|
249146
|
+
if (isAddress2(configured)) return configured;
|
|
249147
|
+
const known3 = this.dispatchers.get(chain2);
|
|
249148
|
+
if (known3) return known3;
|
|
249149
|
+
const params = await this.ctx.dest.client.readContract({
|
|
249150
|
+
abi: ABI3,
|
|
249151
|
+
address: gateway,
|
|
249152
|
+
functionName: "params"
|
|
249153
|
+
});
|
|
249154
|
+
this.dispatchers.set(chain2, params.dispatcher);
|
|
249155
|
+
return params.dispatcher;
|
|
249156
|
+
}
|
|
249124
249157
|
/**
|
|
249125
249158
|
* Asks the bundler for the `preVerificationGas` of the bid UserOperation that will
|
|
249126
249159
|
* actually be signed, with every funding call, approval and signature byte in it.
|
|
@@ -249234,7 +249267,7 @@ query OrderStatus($commitment: String!) {
|
|
|
249234
249267
|
const bundlerOverrides = {};
|
|
249235
249268
|
if (intentGatewayV2Address) {
|
|
249236
249269
|
const paramsSlot5 = pad4(toHex3(5n), { size: 32 });
|
|
249237
|
-
const dispatcherAddress = this.
|
|
249270
|
+
const dispatcherAddress = await this.callDispatcher(chain2, intentGatewayV2Address);
|
|
249238
249271
|
const newSlot5Value = "0x" + "0".repeat(22) + "00" + dispatcherAddress.slice(2).toLowerCase();
|
|
249239
249272
|
const gatewayDiffs = [{ slot: paramsSlot5, value: newSlot5Value }];
|
|
249240
249273
|
for (const [leg, input] of (escrow?.inputs ?? []).entries()) {
|
|
@@ -249775,15 +249808,8 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
249775
249808
|
return withDecimals(resolvedChain, symbol3, this.configService.getAssetMetadataBySymbol(resolvedChain, symbol3));
|
|
249776
249809
|
}
|
|
249777
249810
|
};
|
|
249778
|
-
|
|
249779
|
-
|
|
249780
|
-
bySourceStateMachineId: {
|
|
249781
|
-
[
|
|
249782
|
-
"EVM-1"
|
|
249783
|
-
/* MAINNET */
|
|
249784
|
-
]: 50n
|
|
249785
|
-
}
|
|
249786
|
-
};
|
|
249811
|
+
ETHEREUM_ORDER_FEE_GAS_PRICE_BUMP_PERCENT = 50n;
|
|
249812
|
+
DEFAULT_ORDER_FEE_GAS_PRICE_BUMP_PERCENT = 100n;
|
|
249787
249813
|
IntentGateway = class _IntentGateway {
|
|
249788
249814
|
/**
|
|
249789
249815
|
* Private constructor — use {@link IntentGateway.create} instead.
|
|
@@ -249964,9 +249990,9 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
249964
249990
|
* 1. If `order.fees` is unset or zero, prices the fee on an internal copy
|
|
249965
249991
|
* via {@link quoteOrderFees}: same-chain fees are twice the fill-gas
|
|
249966
249992
|
* estimate without a gas-price bump; cross-chain order fees originating on
|
|
249967
|
-
* Ethereum price gas 50% above the live price, while other source
|
|
249968
|
-
*
|
|
249969
|
-
* with a further 5% buffer over the whole sum — strictly above the solver's
|
|
249993
|
+
* Ethereum mainnet price gas 50% above the live price, while other source
|
|
249994
|
+
* chains use 100%, before attaching (fill gas + the settlement relayer
|
|
249995
|
+
* fee) with a further 5% buffer over the whole sum — strictly above the solver's
|
|
249970
249996
|
* unpadded requirement. Direct solver estimates remain unbumped. The wei
|
|
249971
249997
|
* cost used for the `value` field receives a 2% buffer.
|
|
249972
249998
|
* 2. Yields `AWAITING_PLACE_ORDER` with `{ to, data, value, nativeFee,
|
|
@@ -250356,7 +250382,7 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
250356
250382
|
*
|
|
250357
250383
|
* @param order - The order to quote. `order.fees` is ignored and not mutated.
|
|
250358
250384
|
* Gas prices used to derive cross-chain `fees` receive 50% SDK-only headroom
|
|
250359
|
-
* when the source chain is Ethereum mainnet and
|
|
250385
|
+
* when the source chain is Ethereum mainnet and 100% for other source chains.
|
|
250360
250386
|
* Same-chain quotes and direct calls to {@link estimateFillOrder}, including
|
|
250361
250387
|
* Simplex solver estimates, remain unbumped.
|
|
250362
250388
|
*
|
|
@@ -250645,7 +250671,7 @@ async function resolveChainConfigs(chains2, options = {}) {
|
|
|
250645
250671
|
})
|
|
250646
250672
|
);
|
|
250647
250673
|
}
|
|
250648
|
-
var DEFAULT_BLOCK_SCAN_INTERVAL_SECONDS, MIN_BLOCK_SCAN_INTERVAL_SECONDS, FillerConfigService;
|
|
250674
|
+
var DEFAULT_BLOCK_SCAN_INTERVAL_SECONDS, MIN_BLOCK_SCAN_INTERVAL_SECONDS, DEFAULT_MIN_ORDER_SIZE_USD, FillerConfigService;
|
|
250649
250675
|
var init_FillerConfigService = __esm({
|
|
250650
250676
|
"src/services/FillerConfigService.ts"() {
|
|
250651
250677
|
"use strict";
|
|
@@ -250654,6 +250680,7 @@ var init_FillerConfigService = __esm({
|
|
|
250654
250680
|
init_node10();
|
|
250655
250681
|
DEFAULT_BLOCK_SCAN_INTERVAL_SECONDS = 3;
|
|
250656
250682
|
MIN_BLOCK_SCAN_INTERVAL_SECONDS = 0.1;
|
|
250683
|
+
DEFAULT_MIN_ORDER_SIZE_USD = 20;
|
|
250657
250684
|
FillerConfigService = class {
|
|
250658
250685
|
constructor(chainConfigs2, fillerConfig, loggers) {
|
|
250659
250686
|
this.rpcOverrides = /* @__PURE__ */ new Map();
|
|
@@ -250994,6 +251021,13 @@ var init_FillerConfigService = __esm({
|
|
|
250994
251021
|
getBidValiditySeconds() {
|
|
250995
251022
|
return this.fillerConfig?.bidValiditySeconds ?? 300;
|
|
250996
251023
|
}
|
|
251024
|
+
/**
|
|
251025
|
+
* The order size, in USD, below which `order.fees` must cover the execution cost.
|
|
251026
|
+
* Defaults to 20. An order at or above it is filled whatever fees it carries.
|
|
251027
|
+
*/
|
|
251028
|
+
getMinOrderSizeUsd() {
|
|
251029
|
+
return this.fillerConfig?.minOrderSizeUsd ?? DEFAULT_MIN_ORDER_SIZE_USD;
|
|
251030
|
+
}
|
|
250997
251031
|
/** Ceiling bps above user-requested output. Default 500 (5%). */
|
|
250998
251032
|
getMaxOverfillBps() {
|
|
250999
251033
|
return BigInt(this.fillerConfig?.overfillProtection?.maxOverfillBps ?? 500);
|
|
@@ -251106,6 +251140,12 @@ function validateConfig(config5, cliWatchOnly = false) {
|
|
|
251106
251140
|
);
|
|
251107
251141
|
}
|
|
251108
251142
|
}
|
|
251143
|
+
const minOrderSize = config5.simplex.minOrderSizeUsd;
|
|
251144
|
+
if (minOrderSize !== void 0) {
|
|
251145
|
+
if (!Number.isFinite(minOrderSize) || minOrderSize < 0) {
|
|
251146
|
+
throw new Error(`simplex.minOrderSizeUsd must be a number >= 0 (USD); got ${minOrderSize}`);
|
|
251147
|
+
}
|
|
251148
|
+
}
|
|
251109
251149
|
if (config5.allowlist) {
|
|
251110
251150
|
for (const user of config5.allowlist.users ?? []) {
|
|
251111
251151
|
if (!isAddress(user)) {
|
|
@@ -251591,6 +251631,10 @@ function emitFillerToml(config5, options = {}) {
|
|
|
251591
251631
|
push("# Gas units to keep deposited at the ERC-4337 EntryPoint on chains without a paymaster.");
|
|
251592
251632
|
push(kv("targetGasUnits", config5.simplex.targetGasUnits));
|
|
251593
251633
|
}
|
|
251634
|
+
if (config5.simplex.minOrderSizeUsd !== void 0) {
|
|
251635
|
+
push("# Order size in USD below which an order's fees must cover gas. Default 20.");
|
|
251636
|
+
push(kv("minOrderSizeUsd", config5.simplex.minOrderSizeUsd));
|
|
251637
|
+
}
|
|
251594
251638
|
push();
|
|
251595
251639
|
if (config5.simplex.signer) {
|
|
251596
251640
|
push("# Wallet that signs fills and holds the stablecoin float on every chain.");
|
|
@@ -344731,6 +344775,7 @@ var CacheService = class {
|
|
|
344731
344775
|
matchedLimitOrders: {},
|
|
344732
344776
|
bidPlans: {},
|
|
344733
344777
|
partialFills: {},
|
|
344778
|
+
feeChecksWaived: {},
|
|
344734
344779
|
feeTokens: {},
|
|
344735
344780
|
tokenDecimals: {},
|
|
344736
344781
|
solverSelection: {}
|
|
@@ -344770,6 +344815,10 @@ var CacheService = class {
|
|
|
344770
344815
|
stalePartialIds.forEach((orderId) => {
|
|
344771
344816
|
delete this.cacheData.partialFills[orderId];
|
|
344772
344817
|
});
|
|
344818
|
+
const staleWaivedIds = Object.entries(this.cacheData.feeChecksWaived).filter(([_5, data4]) => !this.isCacheValid(data4.timestamp)).map(([orderId]) => orderId);
|
|
344819
|
+
staleWaivedIds.forEach((orderId) => {
|
|
344820
|
+
delete this.cacheData.feeChecksWaived[orderId];
|
|
344821
|
+
});
|
|
344773
344822
|
}
|
|
344774
344823
|
getGasEstimate(orderId) {
|
|
344775
344824
|
try {
|
|
@@ -345082,6 +345131,24 @@ var CacheService = class {
|
|
|
345082
345131
|
clearPartialFill(orderId) {
|
|
345083
345132
|
delete this.cacheData.partialFills[orderId];
|
|
345084
345133
|
}
|
|
345134
|
+
/**
|
|
345135
|
+
* Whether the strategy's completed evaluation let a bid through without holding
|
|
345136
|
+
* `order.fees` to the execution cost, because the order is at or above the
|
|
345137
|
+
* operator's minimum size.
|
|
345138
|
+
*
|
|
345139
|
+
* Written and cleared the way {@link isPartialFill} is, for the same reason: the
|
|
345140
|
+
* caller exempts such an order from its profit floor.
|
|
345141
|
+
*/
|
|
345142
|
+
isFeeCheckWaived(orderId) {
|
|
345143
|
+
const cache = this.cacheData.feeChecksWaived[orderId];
|
|
345144
|
+
return cache !== void 0 && this.isCacheValid(cache.timestamp) && cache.waived;
|
|
345145
|
+
}
|
|
345146
|
+
setFeeCheckWaived(orderId, waived) {
|
|
345147
|
+
this.cacheData.feeChecksWaived[orderId] = { waived, timestamp: Date.now() };
|
|
345148
|
+
}
|
|
345149
|
+
clearFeeCheckWaived(orderId) {
|
|
345150
|
+
delete this.cacheData.feeChecksWaived[orderId];
|
|
345151
|
+
}
|
|
345085
345152
|
getFeeTokenWithDecimals(chain2) {
|
|
345086
345153
|
try {
|
|
345087
345154
|
const cache = this.cacheData.feeTokens[chain2];
|
|
@@ -350396,7 +350463,10 @@ var ContractInteractionService = class {
|
|
|
350396
350463
|
order,
|
|
350397
350464
|
prependCalls: void 0,
|
|
350398
350465
|
maxPriorityFeePerGasBumpPercent: gasFeeBumpConfig?.maxPriorityFeePerGasBumpPercent,
|
|
350399
|
-
maxFeePerGasBumpPercent: gasFeeBumpConfig?.maxFeePerGasBumpPercent
|
|
350466
|
+
maxFeePerGasBumpPercent: gasFeeBumpConfig?.maxFeePerGasBumpPercent,
|
|
350467
|
+
// No bid without the bundler's own figures: an op signed with the SDK's
|
|
350468
|
+
// fixed fallback limits does not execute, so a failed estimate skips the order.
|
|
350469
|
+
requireBundlerEstimate: true
|
|
350400
350470
|
});
|
|
350401
350471
|
this.logger.info({ orderId: order.id }, "Caching gas estimate");
|
|
350402
350472
|
this.logger.info({ estimate }, "Estimate");
|
|
@@ -350419,7 +350489,7 @@ var ContractInteractionService = class {
|
|
|
350419
350489
|
callGasLimit: estimate.callGasLimit
|
|
350420
350490
|
};
|
|
350421
350491
|
} catch (error) {
|
|
350422
|
-
this.logger.error({ err: error }, "Error estimating gas,
|
|
350492
|
+
this.logger.error({ err: error, orderId: order.id }, "Error estimating gas, not bidding on this order");
|
|
350423
350493
|
throw new Error(`Failed to estimate gas: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
350424
350494
|
}
|
|
350425
350495
|
}
|
|
@@ -384242,6 +384312,23 @@ var IntentFiller = class {
|
|
|
384242
384312
|
this.monitor.emit("orderSkipped", { orderId: order.id, reason: "watch-only" });
|
|
384243
384313
|
return null;
|
|
384244
384314
|
}
|
|
384315
|
+
const destinationHead = await this.destinationHead(order);
|
|
384316
|
+
if (destinationHead !== null && order.deadline <= destinationHead) {
|
|
384317
|
+
this.logger.info(
|
|
384318
|
+
{
|
|
384319
|
+
orderId: order.id,
|
|
384320
|
+
destChain: order.destination,
|
|
384321
|
+
deadline: order.deadline.toString(),
|
|
384322
|
+
head: destinationHead.toString()
|
|
384323
|
+
},
|
|
384324
|
+
"Skipping order: its deadline has passed on the destination chain"
|
|
384325
|
+
);
|
|
384326
|
+
this.monitor.emit("orderSkipped", {
|
|
384327
|
+
orderId: order.id,
|
|
384328
|
+
reason: "Order deadline has passed on the destination chain"
|
|
384329
|
+
});
|
|
384330
|
+
return null;
|
|
384331
|
+
}
|
|
384245
384332
|
const evalStartMs = Date.now();
|
|
384246
384333
|
const eligibleStrategies = await Promise.all(
|
|
384247
384334
|
this.strategies.map(async (strategy) => {
|
|
@@ -384251,7 +384338,10 @@ var IntentFiller = class {
|
|
|
384251
384338
|
})
|
|
384252
384339
|
);
|
|
384253
384340
|
const fillsPartially = this.fillsPartially(order);
|
|
384254
|
-
const
|
|
384341
|
+
const feeCheckWaived = this.feeCheckWaived(order);
|
|
384342
|
+
const validStrategies = eligibleStrategies.filter(
|
|
384343
|
+
(s4) => s4 !== null && (s4.profitability > 0 || fillsPartially || feeCheckWaived)
|
|
384344
|
+
).sort((a6, b5) => b5.profitability - a6.profitability);
|
|
384255
384345
|
const evalDurationSec = (Date.now() - evalStartMs) / 1e3;
|
|
384256
384346
|
this.monitor.emit("orderTiming", { orderId: order.id, phase: "evaluation", durationSec: evalDurationSec });
|
|
384257
384347
|
if (validStrategies.length === 0) {
|
|
@@ -384276,6 +384366,23 @@ var IntentFiller = class {
|
|
|
384276
384366
|
);
|
|
384277
384367
|
return validStrategies[0];
|
|
384278
384368
|
}
|
|
384369
|
+
/**
|
|
384370
|
+
* The destination chain's latest block number, the clock `order.deadline` is read on.
|
|
384371
|
+
*
|
|
384372
|
+
* Null when the read fails. That is not an answer about the order, so evaluation goes
|
|
384373
|
+
* on: the gas estimate simulates the same deadline check and refuses an expired order.
|
|
384374
|
+
*/
|
|
384375
|
+
async destinationHead(order) {
|
|
384376
|
+
try {
|
|
384377
|
+
return await this.chainClientManager.getPublicClient(order.destination).getBlockNumber();
|
|
384378
|
+
} catch (err) {
|
|
384379
|
+
this.logger.warn(
|
|
384380
|
+
{ orderId: order.id, destChain: order.destination, err },
|
|
384381
|
+
"Could not read the destination head to check the order's deadline"
|
|
384382
|
+
);
|
|
384383
|
+
return null;
|
|
384384
|
+
}
|
|
384385
|
+
}
|
|
384279
384386
|
/**
|
|
384280
384387
|
* Whether the strategy's evaluation concluded in a deliberate partial fill.
|
|
384281
384388
|
*
|
|
@@ -384289,6 +384396,15 @@ var IntentFiller = class {
|
|
|
384289
384396
|
if (!order.id) return false;
|
|
384290
384397
|
return this.contractService.cacheService.isPartialFill(order.id);
|
|
384291
384398
|
}
|
|
384399
|
+
/**
|
|
384400
|
+
* Whether the strategy's evaluation let a bid through without the fee check, because
|
|
384401
|
+
* the order is at or above the operator's minimum size. Read from a flag the strategy
|
|
384402
|
+
* sets only once it has an answer, as {@link fillsPartially} is.
|
|
384403
|
+
*/
|
|
384404
|
+
feeCheckWaived(order) {
|
|
384405
|
+
if (!order.id) return false;
|
|
384406
|
+
return this.contractService.cacheService.isFeeCheckWaived(order.id);
|
|
384407
|
+
}
|
|
384292
384408
|
executeOrder(order, bestStrategy, solverSelectionActive, inputUsdValue, profitUsd) {
|
|
384293
384409
|
const chainQueue = this.chainQueues.get(getChainId3(order.destination));
|
|
384294
384410
|
if (!chainQueue) {
|
|
@@ -384865,11 +384981,13 @@ var FXFiller = class _FXFiller {
|
|
|
384865
384981
|
* - Treat a payout below the ask as a partial fill, which only orders
|
|
384866
384982
|
* without output calldata and without an earlier partial fill allow.
|
|
384867
384983
|
* - Cap each payout by the filler's balance plus funding-venue withdrawals,
|
|
384868
|
-
* then gate it on fees (full fills) and the
|
|
384984
|
+
* then gate it on fees (full fills of orders below `minOrderSizeUsd`) and the
|
|
384985
|
+
* same-asset spread.
|
|
384869
384986
|
* - Cache the resulting bids for later use in `executeOrder`.
|
|
384870
384987
|
*/
|
|
384871
384988
|
async calculateProfitability(order) {
|
|
384872
384989
|
if (order.id) this.contractService.cacheService.clearPartialFill(order.id);
|
|
384990
|
+
if (order.id) this.contractService.cacheService.clearFeeCheckWaived(order.id);
|
|
384873
384991
|
if (this.halted) {
|
|
384874
384992
|
this.logger.warn({ orderId: order.id }, "FXFiller halted \u2014 rejecting order");
|
|
384875
384993
|
return 0;
|
|
@@ -384885,6 +385003,15 @@ var FXFiller = class _FXFiller {
|
|
|
384885
385003
|
const plans = [];
|
|
384886
385004
|
const plannedOn = /* @__PURE__ */ new Map();
|
|
384887
385005
|
const spentOn = /* @__PURE__ */ new Map();
|
|
385006
|
+
let atOrAboveMinSize;
|
|
385007
|
+
const feeCheckWaived = async () => {
|
|
385008
|
+
if (atOrAboveMinSize === void 0) {
|
|
385009
|
+
const usd = await this.getOrderUsdValue(order);
|
|
385010
|
+
atOrAboveMinSize = usd !== null && usd.inputUsd.gte(this.configService.getMinOrderSizeUsd());
|
|
385011
|
+
}
|
|
385012
|
+
return atOrAboveMinSize;
|
|
385013
|
+
};
|
|
385014
|
+
let feesWaived = false;
|
|
384888
385015
|
for (let leg = 0; leg < order.inputs.length; leg++) {
|
|
384889
385016
|
const input = order.inputs[leg];
|
|
384890
385017
|
const output3 = order.output.assets[leg];
|
|
@@ -385128,17 +385255,21 @@ var FXFiller = class _FXFiller {
|
|
|
385128
385255
|
const executionCost = totalCostInSourceFeeToken + relayerFeeInSourceFeeToken;
|
|
385129
385256
|
const partialEdgeUsd = sameAssetEdgeUsd.plus(payoutSurplusUsd);
|
|
385130
385257
|
if (!partialFill && order.fees < executionCost) {
|
|
385131
|
-
|
|
385132
|
-
|
|
385133
|
-
|
|
385134
|
-
|
|
385135
|
-
|
|
385136
|
-
|
|
385137
|
-
|
|
385138
|
-
|
|
385139
|
-
|
|
385140
|
-
|
|
385141
|
-
|
|
385258
|
+
if (!await feeCheckWaived()) {
|
|
385259
|
+
this.logger.info(
|
|
385260
|
+
{
|
|
385261
|
+
orderId: order.id,
|
|
385262
|
+
orderFees: formatUnits(order.fees, feeTokenDecimals),
|
|
385263
|
+
fillGas: formatUnits(totalCostInSourceFeeToken, feeTokenDecimals),
|
|
385264
|
+
relayerFee: formatUnits(relayerFeeInSourceFeeToken, feeTokenDecimals),
|
|
385265
|
+
executionCost: formatUnits(executionCost, feeTokenDecimals),
|
|
385266
|
+
minOrderSizeUsd: this.configService.getMinOrderSizeUsd()
|
|
385267
|
+
},
|
|
385268
|
+
"Skipping order: attached fees do not cover execution cost (fill gas + relayer fee)"
|
|
385269
|
+
);
|
|
385270
|
+
continue;
|
|
385271
|
+
}
|
|
385272
|
+
feesWaived = true;
|
|
385142
385273
|
}
|
|
385143
385274
|
if (sameAsset && !sameAssetProfitable) {
|
|
385144
385275
|
this.logger.info(
|
|
@@ -385172,7 +385303,8 @@ var FXFiller = class _FXFiller {
|
|
|
385172
385303
|
realizedSpreadProfit: formatUnits(realizedSpreadProfit, feeTokenDecimals),
|
|
385173
385304
|
payoutSurplusUsd: payoutSurplusUsd.toString(),
|
|
385174
385305
|
totalProfit,
|
|
385175
|
-
profitable: totalProfit > 0
|
|
385306
|
+
profitable: totalProfit > 0,
|
|
385307
|
+
feeCheckWaived: !partialFill && order.fees < executionCost
|
|
385176
385308
|
},
|
|
385177
385309
|
"FX swap profitability evaluation"
|
|
385178
385310
|
);
|
|
@@ -385204,6 +385336,7 @@ var FXFiller = class _FXFiller {
|
|
|
385204
385336
|
plans[0].budget
|
|
385205
385337
|
);
|
|
385206
385338
|
this.contractService.cacheService.setPartialFill(order.id, plans[0].partialFill);
|
|
385339
|
+
this.contractService.cacheService.setFeeCheckWaived(order.id, feesWaived);
|
|
385207
385340
|
this.contractService.cacheService.setMatchedLimitOrder(order.id, [
|
|
385208
385341
|
{ limitOrderId: plans[0].limitOrderId, payout: plans[0].payout }
|
|
385209
385342
|
]);
|
|
@@ -386470,6 +386603,7 @@ async function bootFiller(config5, options) {
|
|
|
386470
386603
|
rebalancing: config5.rebalancing,
|
|
386471
386604
|
targetGasUnits: config5.simplex.targetGasUnits,
|
|
386472
386605
|
bidValiditySeconds: config5.simplex.bidValiditySeconds,
|
|
386606
|
+
minOrderSizeUsd: config5.simplex.minOrderSizeUsd,
|
|
386473
386607
|
blockScanIntervalSeconds: config5.simplex.blockScanIntervalSeconds,
|
|
386474
386608
|
gasFeeBump: config5.simplex.gasFeeBump,
|
|
386475
386609
|
overfillProtection: config5.simplex.overfillProtection,
|