@hyperbridge/simplex 0.16.6 → 0.16.8
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 +729 -250
- package/dist/bin/simplex.js.map +1 -1
- package/dist/index.cjs +380 -132
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -56
- package/dist/index.d.ts +74 -56
- package/dist/index.js +380 -132
- package/dist/index.js.map +1 -1
- package/dist/sqlite.cjs +1 -1
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.d.cts +1 -1
- package/dist/sqlite.d.ts +1 -1
- package/dist/sqlite.js +1 -1
- package/dist/sqlite.js.map +1 -1
- package/dist/{types-DUDABLPI.d.cts → types-C7rnnKWn.d.cts} +6 -4
- package/dist/{types-DUDABLPI.d.ts → types-C7rnnKWn.d.ts} +6 -4
- package/dist/ui/assets/index-BQu6BMxc.js +106 -0
- package/dist/ui/assets/index-C3T-gubp.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +2 -2
- package/dist/ui/assets/index-CsBo6xg3.js +0 -106
- package/dist/ui/assets/index-PIGVK8XG.css +0 -1
package/dist/bin/simplex.js
CHANGED
|
@@ -70714,13 +70714,13 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
70714
70714
|
}
|
|
70715
70715
|
function convertReadableWritablePair(pair, context) {
|
|
70716
70716
|
assertDictionary(pair, context);
|
|
70717
|
-
const
|
|
70718
|
-
assertRequiredField(
|
|
70719
|
-
assertReadableStream(
|
|
70717
|
+
const readable2 = pair === null || pair === void 0 ? void 0 : pair.readable;
|
|
70718
|
+
assertRequiredField(readable2, "readable", "ReadableWritablePair");
|
|
70719
|
+
assertReadableStream(readable2, `${context} has member 'readable' that`);
|
|
70720
70720
|
const writable = pair === null || pair === void 0 ? void 0 : pair.writable;
|
|
70721
70721
|
assertRequiredField(writable, "writable", "ReadableWritablePair");
|
|
70722
70722
|
assertWritableStream(writable, `${context} has member 'writable' that`);
|
|
70723
|
-
return { readable, writable };
|
|
70723
|
+
return { readable: readable2, writable };
|
|
70724
70724
|
}
|
|
70725
70725
|
class ReadableStream2 {
|
|
70726
70726
|
constructor(rawUnderlyingSource = {}, rawStrategy = {}) {
|
|
@@ -71399,7 +71399,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
71399
71399
|
if (controller._finishPromise !== void 0) {
|
|
71400
71400
|
return controller._finishPromise;
|
|
71401
71401
|
}
|
|
71402
|
-
const
|
|
71402
|
+
const readable2 = stream4._readable;
|
|
71403
71403
|
controller._finishPromise = newPromise((resolve11, reject) => {
|
|
71404
71404
|
controller._finishPromise_resolve = resolve11;
|
|
71405
71405
|
controller._finishPromise_reject = reject;
|
|
@@ -71407,15 +71407,15 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
71407
71407
|
const cancelPromise = controller._cancelAlgorithm(reason);
|
|
71408
71408
|
TransformStreamDefaultControllerClearAlgorithms(controller);
|
|
71409
71409
|
uponPromise(cancelPromise, () => {
|
|
71410
|
-
if (
|
|
71411
|
-
defaultControllerFinishPromiseReject(controller,
|
|
71410
|
+
if (readable2._state === "errored") {
|
|
71411
|
+
defaultControllerFinishPromiseReject(controller, readable2._storedError);
|
|
71412
71412
|
} else {
|
|
71413
|
-
ReadableStreamDefaultControllerError(
|
|
71413
|
+
ReadableStreamDefaultControllerError(readable2._readableStreamController, reason);
|
|
71414
71414
|
defaultControllerFinishPromiseResolve(controller);
|
|
71415
71415
|
}
|
|
71416
71416
|
return null;
|
|
71417
71417
|
}, (r7) => {
|
|
71418
|
-
ReadableStreamDefaultControllerError(
|
|
71418
|
+
ReadableStreamDefaultControllerError(readable2._readableStreamController, r7);
|
|
71419
71419
|
defaultControllerFinishPromiseReject(controller, r7);
|
|
71420
71420
|
return null;
|
|
71421
71421
|
});
|
|
@@ -71426,7 +71426,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
71426
71426
|
if (controller._finishPromise !== void 0) {
|
|
71427
71427
|
return controller._finishPromise;
|
|
71428
71428
|
}
|
|
71429
|
-
const
|
|
71429
|
+
const readable2 = stream4._readable;
|
|
71430
71430
|
controller._finishPromise = newPromise((resolve11, reject) => {
|
|
71431
71431
|
controller._finishPromise_resolve = resolve11;
|
|
71432
71432
|
controller._finishPromise_reject = reject;
|
|
@@ -71434,15 +71434,15 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
71434
71434
|
const flushPromise = controller._flushAlgorithm();
|
|
71435
71435
|
TransformStreamDefaultControllerClearAlgorithms(controller);
|
|
71436
71436
|
uponPromise(flushPromise, () => {
|
|
71437
|
-
if (
|
|
71438
|
-
defaultControllerFinishPromiseReject(controller,
|
|
71437
|
+
if (readable2._state === "errored") {
|
|
71438
|
+
defaultControllerFinishPromiseReject(controller, readable2._storedError);
|
|
71439
71439
|
} else {
|
|
71440
|
-
ReadableStreamDefaultControllerClose(
|
|
71440
|
+
ReadableStreamDefaultControllerClose(readable2._readableStreamController);
|
|
71441
71441
|
defaultControllerFinishPromiseResolve(controller);
|
|
71442
71442
|
}
|
|
71443
71443
|
return null;
|
|
71444
71444
|
}, (r7) => {
|
|
71445
|
-
ReadableStreamDefaultControllerError(
|
|
71445
|
+
ReadableStreamDefaultControllerError(readable2._readableStreamController, r7);
|
|
71446
71446
|
defaultControllerFinishPromiseReject(controller, r7);
|
|
71447
71447
|
return null;
|
|
71448
71448
|
});
|
|
@@ -214220,6 +214220,12 @@ function userOperationLogs(logs, entryPoint, userOpHash) {
|
|
|
214220
214220
|
while (start >= 0 && !isBoundary(logs[start])) start--;
|
|
214221
214221
|
return logs.slice(start + 1, end);
|
|
214222
214222
|
}
|
|
214223
|
+
function escrowSlot(commitment, leg) {
|
|
214224
|
+
const byCommitment = keccak2563(
|
|
214225
|
+
encodeAbiParameters2([{ type: "bytes32" }, { type: "uint256" }], [commitment, ESCROW_MAPPING_SLOT])
|
|
214226
|
+
);
|
|
214227
|
+
return keccak2563(encodeAbiParameters2([{ type: "uint256" }, { type: "bytes32" }], [BigInt(leg), byCommitment]));
|
|
214228
|
+
}
|
|
214223
214229
|
function destinationStateMachine(order) {
|
|
214224
214230
|
return isHex3(order.destination) ? hexToString2(order.destination) : order.destination;
|
|
214225
214231
|
}
|
|
@@ -214231,13 +214237,19 @@ function describeError(error) {
|
|
|
214231
214237
|
if (graphqlErrors?.length) return graphqlErrors.map((e4) => e4.message).join("; ");
|
|
214232
214238
|
return error instanceof Error ? error.message : String(error);
|
|
214233
214239
|
}
|
|
214240
|
+
function sameSymbol(a6, b5) {
|
|
214241
|
+
return a6.toLowerCase() === b5.toLowerCase();
|
|
214242
|
+
}
|
|
214234
214243
|
function findBook(books, tokenA, tokenB) {
|
|
214235
214244
|
const book = books.find(
|
|
214236
|
-
(b5) => b5.base
|
|
214245
|
+
(b5) => sameSymbol(b5.base, tokenA) && sameSymbol(b5.quote, tokenB) || sameSymbol(b5.base, tokenB) && sameSymbol(b5.quote, tokenA)
|
|
214237
214246
|
);
|
|
214238
214247
|
if (!book) throw new OrderbookRequestError(`no book trades ${tokenA} for ${tokenB}`);
|
|
214239
214248
|
return book;
|
|
214240
214249
|
}
|
|
214250
|
+
function optionalBigInt(value) {
|
|
214251
|
+
return value === null ? null : BigInt(value);
|
|
214252
|
+
}
|
|
214241
214253
|
function parseRate(raw) {
|
|
214242
214254
|
return {
|
|
214243
214255
|
side: raw.side,
|
|
@@ -214282,24 +214294,32 @@ function toRoute(tokenIn, tokenOut) {
|
|
|
214282
214294
|
function requiredInput(side, amountOut, rate) {
|
|
214283
214295
|
return side === "BID" ? divCeil(amountOut * ORDERBOOK_SCALE, rate) : divCeil(amountOut * rate, ORDERBOOK_SCALE);
|
|
214284
214296
|
}
|
|
214285
|
-
function
|
|
214286
|
-
|
|
214287
|
-
|
|
214297
|
+
function swapQuoteTotals(quote) {
|
|
214298
|
+
const worstFill = quote.fills.at(-1);
|
|
214299
|
+
if (quote.fillable && !worstFill)
|
|
214300
|
+
throw new OrderbookRequestError("the orderbook served a fillable quote with no fills");
|
|
214288
214301
|
return {
|
|
214289
|
-
|
|
214290
|
-
amountIn,
|
|
214291
|
-
amountOut,
|
|
214292
|
-
|
|
214293
|
-
|
|
214294
|
-
|
|
214295
|
-
|
|
214296
|
-
|
|
214297
|
-
|
|
214298
|
-
|
|
214299
|
-
|
|
214300
|
-
|
|
214301
|
-
|
|
214302
|
-
|
|
214302
|
+
side: quote.side,
|
|
214303
|
+
amountIn: quote.amountIn,
|
|
214304
|
+
amountOut: quote.fills.reduce((total, fill) => total + fill.amountOut, 0n),
|
|
214305
|
+
fillable: quote.fillable,
|
|
214306
|
+
maxFillableIn: quote.maxFillableIn,
|
|
214307
|
+
worstIn: worstFill?.amountIn ?? 0n,
|
|
214308
|
+
worstOut: worstFill?.amountOut ?? 0n
|
|
214309
|
+
};
|
|
214310
|
+
}
|
|
214311
|
+
function levelQuoteTotals(quote) {
|
|
214312
|
+
if (quote.fillable && quote.rate === null) {
|
|
214313
|
+
throw new OrderbookRequestError("the orderbook served a fillable quote with no rate");
|
|
214314
|
+
}
|
|
214315
|
+
return {
|
|
214316
|
+
side: quote.side,
|
|
214317
|
+
amountIn: quote.amountIn,
|
|
214318
|
+
amountOut: quote.amountOut,
|
|
214319
|
+
fillable: quote.fillable,
|
|
214320
|
+
maxFillableIn: quote.maxFillableIn,
|
|
214321
|
+
worstIn: quote.amountIn,
|
|
214322
|
+
worstOut: quote.amountOut
|
|
214303
214323
|
};
|
|
214304
214324
|
}
|
|
214305
214325
|
function toOrderbookAmount(amount, decimals) {
|
|
@@ -214385,7 +214405,7 @@ function encodePhantomBidDeclaration(declaration) {
|
|
|
214385
214405
|
}
|
|
214386
214406
|
return u8aToHex(new Uint8Array(bytes4));
|
|
214387
214407
|
}
|
|
214388
|
-
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, GasEstimator, OrderStatusChecker, ORDERBOOK_URLS, ORDERBOOK_DECIMALS, ORDERBOOK_SCALE, OrderbookRequestError, RATE_FIELDS, TOP_OF_BOOK_QUERY, ROUTE_LIQUIDITY_QUERY, QUOTE_QUERY, HyperFxOrderbook, UnsupportedLiquidityAssetError, UnsupportedLiquidityChainError, OrderbookQuoteNotConvergedError,
|
|
214408
|
+
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, ORDER_FEE_GAS_PRICE_BUMP_POLICY, 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;
|
|
214389
214409
|
var init_node10 = __esm({
|
|
214390
214410
|
"../sdk/dist/node/index.js"() {
|
|
214391
214411
|
"use strict";
|
|
@@ -227805,6 +227825,10 @@ query OrderStatus($commitment: String!) {
|
|
|
227805
227825
|
NO_BUNDLER_FILL_GAS_PER_OUTPUT = 150000n;
|
|
227806
227826
|
NO_BUNDLER_PAYMASTER_VERIFICATION_GAS = 250000n;
|
|
227807
227827
|
NO_BUNDLER_PAYMASTER_POST_OP_GAS = 100000n;
|
|
227828
|
+
BID_PVG_ESTIMATION_ACCOUNT_CODE = "0x60003560e01c631626ba7e1460145760206000f35b631626ba7e60e01b60005260206000f3";
|
|
227829
|
+
SELECTED_BID_SIGNATURE_BYTES = 32 + 65 + 65;
|
|
227830
|
+
BID_PVG_HEADROOM_PERCENT = 10n;
|
|
227831
|
+
ESCROW_MAPPING_SLOT = 9n;
|
|
227808
227832
|
GasEstimator = class {
|
|
227809
227833
|
/**
|
|
227810
227834
|
* @param ctx - Shared IntentsV2 context providing the source and destination
|
|
@@ -227883,6 +227907,7 @@ query OrderStatus($commitment: String!) {
|
|
|
227883
227907
|
assetsForOverrides.push({ token: feeTokenAsBytes32, amount: 0n });
|
|
227884
227908
|
}
|
|
227885
227909
|
const isSameChain = souceStateMachineId === destStateMachineId;
|
|
227910
|
+
const commitment = orderCommitment(order);
|
|
227886
227911
|
const [stateOverridesResult, crossChainFees] = await Promise.all([
|
|
227887
227912
|
this.ctx.bundlerUrl ? this.buildStateOverride({
|
|
227888
227913
|
accountAddress: solverAccountAddress,
|
|
@@ -227890,7 +227915,16 @@ query OrderStatus($commitment: String!) {
|
|
|
227890
227915
|
outputAssets: assetsForOverrides,
|
|
227891
227916
|
spenderAddress: intentGatewayV2Address,
|
|
227892
227917
|
intentGatewayV2Address,
|
|
227893
|
-
entryPointAddress
|
|
227918
|
+
entryPointAddress,
|
|
227919
|
+
// A fee quote runs before the order is placed, so nothing is escrowed under
|
|
227920
|
+
// its commitment yet. Cross-chain fills release escrow on the source chain.
|
|
227921
|
+
escrow: isSameChain ? {
|
|
227922
|
+
commitment,
|
|
227923
|
+
inputs: order.inputs.map((input) => ({
|
|
227924
|
+
token: normalizeAddressForEvmBytes32(input.token),
|
|
227925
|
+
amount: input.amount
|
|
227926
|
+
}))
|
|
227927
|
+
} : void 0
|
|
227894
227928
|
}) : Promise.resolve({ viem: [], bundler: {} }),
|
|
227895
227929
|
isSameChain ? Promise.resolve({ postRequestFee: 0n, relayerFeeInSourceFeeToken: 0n }) : this.estimateCrossChainFees(
|
|
227896
227930
|
sourceFeeToken,
|
|
@@ -227919,10 +227953,8 @@ query OrderStatus($commitment: String!) {
|
|
|
227919
227953
|
const maxFeeBumpPercent = params.maxFeePerGasBumpPercent ?? 10;
|
|
227920
227954
|
let maxPriorityFeePerGas = gasPrice + gasPrice * BigInt(priorityFeeBumpPercent) / 100n;
|
|
227921
227955
|
let maxFeePerGas = gasPrice + gasPrice * BigInt(maxFeeBumpPercent) / 100n;
|
|
227922
|
-
const orderForEstimation = { ...order, session: solverAccountAddress };
|
|
227923
|
-
const commitment = orderCommitment(orderForEstimation);
|
|
227924
227956
|
await assertGatewayRelease(this.ctx.dest.client, intentGatewayV2Address);
|
|
227925
|
-
const fillOrderCalldata = encodeFillOrder(transformOrderForContract(
|
|
227957
|
+
const fillOrderCalldata = encodeFillOrder(transformOrderForContract(order), fillOptions);
|
|
227926
227958
|
let callGasLimit = 500000n;
|
|
227927
227959
|
let verificationGasLimit = 100000n;
|
|
227928
227960
|
let preVerificationGas = 100000n;
|
|
@@ -227934,7 +227966,7 @@ query OrderStatus($commitment: String!) {
|
|
|
227934
227966
|
...params.prependCalls ?? [],
|
|
227935
227967
|
{ target: intentGatewayV2Address, value: totalNativeValue, data: fillOrderCalldata }
|
|
227936
227968
|
]);
|
|
227937
|
-
const accountGasLimits = CryptoUtils.packGasLimits(
|
|
227969
|
+
const accountGasLimits = CryptoUtils.packGasLimits(0n, 0n);
|
|
227938
227970
|
const gasFees = CryptoUtils.packGasFees(maxPriorityFeePerGas, maxFeePerGas);
|
|
227939
227971
|
const nonce = 0n;
|
|
227940
227972
|
const preliminaryUserOp = {
|
|
@@ -227943,7 +227975,7 @@ query OrderStatus($commitment: String!) {
|
|
|
227943
227975
|
initCode: "0x",
|
|
227944
227976
|
callData,
|
|
227945
227977
|
accountGasLimits,
|
|
227946
|
-
preVerificationGas:
|
|
227978
|
+
preVerificationGas: 0n,
|
|
227947
227979
|
gasFees,
|
|
227948
227980
|
paymasterAndData: "0x",
|
|
227949
227981
|
signature: "0x"
|
|
@@ -228073,6 +228105,53 @@ query OrderStatus($commitment: String!) {
|
|
|
228073
228105
|
inputs
|
|
228074
228106
|
};
|
|
228075
228107
|
}
|
|
228108
|
+
/**
|
|
228109
|
+
* Asks the bundler for the `preVerificationGas` of the bid UserOperation that will
|
|
228110
|
+
* actually be signed, with every funding call, approval and signature byte in it.
|
|
228111
|
+
*
|
|
228112
|
+
* On an L2, `preVerificationGas` also pays the L1 data fee for the op's bytes, a fixed
|
|
228113
|
+
* amount of wei that the bundler converts to gas at the price the op pays. A bundler
|
|
228114
|
+
* admits an op priced at its `maxFeePerGas`, but bundles it at the base fee plus its
|
|
228115
|
+
* priority fee, where the same wei costs more gas. An op sized only for admission is
|
|
228116
|
+
* accepted and then skipped in every bundle until it expires. The estimate is taken
|
|
228117
|
+
* at the bundle's price: the latest base fee plus the op's priority fee, capped at its
|
|
228118
|
+
* `maxFeePerGas`.
|
|
228119
|
+
*
|
|
228120
|
+
* The solver account's code is overridden with {@link BID_PVG_ESTIMATION_ACCOUNT_CODE}
|
|
228121
|
+
* for the call, so only the bytes are priced and the fill itself is not simulated.
|
|
228122
|
+
*
|
|
228123
|
+
* @param params - The bid's fields as they will be signed.
|
|
228124
|
+
* @returns The `preVerificationGas` to sign, with {@link BID_PVG_HEADROOM_PERCENT} added.
|
|
228125
|
+
* @throws If no bundler is configured or the bundler rejects the estimate.
|
|
228126
|
+
*/
|
|
228127
|
+
async estimateBidPreVerificationGas(params) {
|
|
228128
|
+
const { solverAccount, maxFeePerGas, maxPriorityFeePerGas } = params;
|
|
228129
|
+
const latestBlock = await this.ctx.dest.client.getBlock({ blockTag: "latest" });
|
|
228130
|
+
const baseFeePerGas = latestBlock.baseFeePerGas;
|
|
228131
|
+
const bundlePrice = baseFeePerGas == null || baseFeePerGas + maxPriorityFeePerGas > maxFeePerGas ? maxFeePerGas : baseFeePerGas + maxPriorityFeePerGas;
|
|
228132
|
+
const priorityFee = maxPriorityFeePerGas < bundlePrice ? maxPriorityFeePerGas : bundlePrice;
|
|
228133
|
+
const userOp = {
|
|
228134
|
+
sender: solverAccount,
|
|
228135
|
+
nonce: params.nonce,
|
|
228136
|
+
initCode: "0x",
|
|
228137
|
+
callData: params.callData,
|
|
228138
|
+
accountGasLimits: CryptoUtils.packGasLimits(params.verificationGasLimit, params.callGasLimit),
|
|
228139
|
+
// Bundlers return a non-zero preVerificationGas as given rather than estimating it.
|
|
228140
|
+
preVerificationGas: 0n,
|
|
228141
|
+
gasFees: CryptoUtils.packGasFees(priorityFee, bundlePrice),
|
|
228142
|
+
paymasterAndData: params.paymasterAndData ?? "0x",
|
|
228143
|
+
signature: `0x${"ff".repeat(SELECTED_BID_SIGNATURE_BYTES)}`
|
|
228144
|
+
};
|
|
228145
|
+
const estimate = await this.crypto.sendBundler(
|
|
228146
|
+
BundlerMethod.ETH_ESTIMATE_USER_OPERATION_GAS,
|
|
228147
|
+
[
|
|
228148
|
+
CryptoUtils.prepareBundlerCall(userOp),
|
|
228149
|
+
params.entryPointAddress,
|
|
228150
|
+
{ [solverAccount]: { code: BID_PVG_ESTIMATION_ACCOUNT_CODE } }
|
|
228151
|
+
]
|
|
228152
|
+
);
|
|
228153
|
+
return BigInt(estimate.preVerificationGas) * (100n + BID_PVG_HEADROOM_PERCENT) / 100n;
|
|
228154
|
+
}
|
|
228076
228155
|
/**
|
|
228077
228156
|
* Estimates the cross-chain ISMP POST request fee (the relayer fee for the
|
|
228078
228157
|
* RedeemEscrow message), in both the source and destination fee tokens.
|
|
@@ -228125,20 +228204,38 @@ query OrderStatus($commitment: String!) {
|
|
|
228125
228204
|
* @returns An object with `viem` and `bundler` state-override collections.
|
|
228126
228205
|
*/
|
|
228127
228206
|
async buildStateOverride(params) {
|
|
228128
|
-
const {
|
|
228129
|
-
|
|
228207
|
+
const {
|
|
228208
|
+
accountAddress,
|
|
228209
|
+
chain: chain2,
|
|
228210
|
+
outputAssets,
|
|
228211
|
+
spenderAddress,
|
|
228212
|
+
intentGatewayV2Address,
|
|
228213
|
+
entryPointAddress,
|
|
228214
|
+
escrow
|
|
228215
|
+
} = params;
|
|
228216
|
+
const testValue = toHex3(2n ** 128n, { size: 32 });
|
|
228130
228217
|
const viemOverrides = [];
|
|
228131
228218
|
const bundlerOverrides = {};
|
|
228132
228219
|
if (intentGatewayV2Address) {
|
|
228133
228220
|
const paramsSlot5 = pad4(toHex3(5n), { size: 32 });
|
|
228134
228221
|
const dispatcherAddress = this.ctx.dest.configService.getCalldispatcherAddress(chain2);
|
|
228135
228222
|
const newSlot5Value = "0x" + "0".repeat(22) + "00" + dispatcherAddress.slice(2).toLowerCase();
|
|
228223
|
+
const gatewayDiffs = [{ slot: paramsSlot5, value: newSlot5Value }];
|
|
228224
|
+
for (const [leg, input] of (escrow?.inputs ?? []).entries()) {
|
|
228225
|
+
gatewayDiffs.push({
|
|
228226
|
+
slot: escrowSlot(escrow.commitment, leg),
|
|
228227
|
+
value: toHex3(input.amount, { size: 32 })
|
|
228228
|
+
});
|
|
228229
|
+
}
|
|
228230
|
+
const releasesNative = escrow?.inputs.some((input) => bytes32ToBytes20(input.token) === ADDRESS_ZERO2);
|
|
228136
228231
|
viemOverrides.push({
|
|
228137
228232
|
address: intentGatewayV2Address,
|
|
228138
|
-
|
|
228233
|
+
...releasesNative ? { balance: 2n ** 128n } : {},
|
|
228234
|
+
stateDiff: gatewayDiffs
|
|
228139
228235
|
});
|
|
228140
228236
|
bundlerOverrides[intentGatewayV2Address] = {
|
|
228141
|
-
|
|
228237
|
+
...releasesNative ? { balance: testValue } : {},
|
|
228238
|
+
stateDiff: Object.fromEntries(gatewayDiffs.map(({ slot, value }) => [slot, value]))
|
|
228142
228239
|
};
|
|
228143
228240
|
}
|
|
228144
228241
|
if (entryPointAddress) {
|
|
@@ -228174,6 +228271,25 @@ query OrderStatus($commitment: String!) {
|
|
|
228174
228271
|
bundlerOverrides[result.address] = { stateDiff: result.bundlerStateDiffs };
|
|
228175
228272
|
}
|
|
228176
228273
|
}
|
|
228274
|
+
if (intentGatewayV2Address && escrow) {
|
|
228275
|
+
const gatewayBalances = await Promise.all(
|
|
228276
|
+
escrow.inputs.map((input) => this.tokenBalanceSlot(input.token, intentGatewayV2Address, chain2))
|
|
228277
|
+
);
|
|
228278
|
+
for (const override of gatewayBalances) {
|
|
228279
|
+
if (!override) continue;
|
|
228280
|
+
const existing = viemOverrides.find((entry) => entry.address === override.address && entry.stateDiff);
|
|
228281
|
+
if (existing) existing.stateDiff.push({ slot: override.slot, value: testValue });
|
|
228282
|
+
else
|
|
228283
|
+
viemOverrides.push({
|
|
228284
|
+
address: override.address,
|
|
228285
|
+
stateDiff: [{ slot: override.slot, value: testValue }]
|
|
228286
|
+
});
|
|
228287
|
+
bundlerOverrides[override.address] = {
|
|
228288
|
+
...bundlerOverrides[override.address],
|
|
228289
|
+
stateDiff: { ...bundlerOverrides[override.address]?.stateDiff, [override.slot]: testValue }
|
|
228290
|
+
};
|
|
228291
|
+
}
|
|
228292
|
+
}
|
|
228177
228293
|
const solverAccountContract = this.ctx.dest.configService.getSolverAccountAddress(chain2);
|
|
228178
228294
|
if (solverAccountContract) {
|
|
228179
228295
|
try {
|
|
@@ -228196,6 +228312,21 @@ query OrderStatus($commitment: String!) {
|
|
|
228196
228312
|
}
|
|
228197
228313
|
return { viem: viemOverrides, bundler: bundlerOverrides };
|
|
228198
228314
|
}
|
|
228315
|
+
/**
|
|
228316
|
+
* The balance slot of `holder` in an ERC-20 token, for overriding. `null` for the native
|
|
228317
|
+
* token or when the slot cannot be discovered.
|
|
228318
|
+
*/
|
|
228319
|
+
async tokenBalanceSlot(tokenHex, holder, chain2) {
|
|
228320
|
+
const tokenAddress = bytes32ToBytes20(tokenHex);
|
|
228321
|
+
if (tokenAddress === ADDRESS_ZERO2) return null;
|
|
228322
|
+
try {
|
|
228323
|
+
const balanceData = "0x70a08231" + bytes20ToBytes32(holder).slice(2);
|
|
228324
|
+
const slot = await getOrFetchStorageSlot(this.ctx.dest.client, chain2, tokenAddress, balanceData);
|
|
228325
|
+
return slot ? { address: tokenAddress, slot } : null;
|
|
228326
|
+
} catch {
|
|
228327
|
+
return null;
|
|
228328
|
+
}
|
|
228329
|
+
}
|
|
228199
228330
|
/**
|
|
228200
228331
|
* Resolves the balance and allowance storage slot overrides for a single
|
|
228201
228332
|
* ERC-20 token in parallel. Returns `null` for native-ETH tokens or when
|
|
@@ -228328,14 +228459,20 @@ query TopOfBook($tokenA: String!, $tokenB: String!, $fillChain: String!, $source
|
|
|
228328
228459
|
query RouteLiquidity($route: RouteInput!) {
|
|
228329
228460
|
books { id base quote }
|
|
228330
228461
|
routeLiquidity(route: $route) {
|
|
228331
|
-
route bestRate depthIn depthOut availableLiquidity maxFillableIn orderCount solverCount
|
|
228462
|
+
route bestRate slippageBps depthIn depthOut availableLiquidity maxFillableIn orderCount solverCount
|
|
228332
228463
|
}
|
|
228333
228464
|
}`;
|
|
228334
228465
|
QUOTE_QUERY = `
|
|
228335
228466
|
query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
228336
228467
|
quote(route: $route, amountIn: $amountIn) {
|
|
228337
|
-
route side amountIn
|
|
228338
|
-
fills { orderRate amountOut
|
|
228468
|
+
route side amountIn slippageBps fillable maxFillableIn
|
|
228469
|
+
fills { advertisedSize orderRate amountIn amountOut }
|
|
228470
|
+
}
|
|
228471
|
+
}`;
|
|
228472
|
+
QUOTE_PESSIMISTIC_QUERY = `
|
|
228473
|
+
query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
|
|
228474
|
+
quotePessimistic(route: $route, amountIn: $amountIn) {
|
|
228475
|
+
route side amountIn amountOut rate priceBucket slippageBps fillable maxFillableIn
|
|
228339
228476
|
}
|
|
228340
228477
|
}`;
|
|
228341
228478
|
HyperFxOrderbook = class {
|
|
@@ -228365,8 +228502,9 @@ query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
228365
228502
|
return {
|
|
228366
228503
|
route: raw.route,
|
|
228367
228504
|
book,
|
|
228368
|
-
side: book.base
|
|
228369
|
-
bestRate:
|
|
228505
|
+
side: sameSymbol(book.base, route.tokenIn) ? "BID" : "ASK",
|
|
228506
|
+
bestRate: optionalBigInt(raw.bestRate),
|
|
228507
|
+
slippageBps: raw.slippageBps,
|
|
228370
228508
|
depthIn: BigInt(raw.depthIn),
|
|
228371
228509
|
depthOut: BigInt(raw.depthOut),
|
|
228372
228510
|
availableLiquidity: BigInt(raw.availableLiquidity),
|
|
@@ -228375,7 +228513,10 @@ query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
228375
228513
|
solverCount: raw.solverCount
|
|
228376
228514
|
};
|
|
228377
228515
|
}
|
|
228378
|
-
/**
|
|
228516
|
+
/**
|
|
228517
|
+
* The optimistic quote for `amountIn` (1e18 tokenIn) on a route: the route's orders, best price
|
|
228518
|
+
* first, each taking what it can at its own price. The fills' `amountOut`s sum to the output.
|
|
228519
|
+
*/
|
|
228379
228520
|
async quote(route, amountIn) {
|
|
228380
228521
|
const { quote: raw } = await this.request(QUOTE_QUERY, {
|
|
228381
228522
|
route,
|
|
@@ -228385,18 +228526,39 @@ query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
228385
228526
|
route: raw.route,
|
|
228386
228527
|
side: raw.side,
|
|
228387
228528
|
amountIn: BigInt(raw.amountIn),
|
|
228388
|
-
|
|
228389
|
-
rate: raw.rate === null ? null : BigInt(raw.rate),
|
|
228529
|
+
slippageBps: raw.slippageBps,
|
|
228390
228530
|
fillable: raw.fillable,
|
|
228391
|
-
depth: BigInt(raw.depth),
|
|
228392
228531
|
maxFillableIn: BigInt(raw.maxFillableIn),
|
|
228393
228532
|
fills: raw.fills.map((fill) => ({
|
|
228533
|
+
advertisedSize: BigInt(fill.advertisedSize),
|
|
228394
228534
|
orderRate: BigInt(fill.orderRate),
|
|
228395
|
-
|
|
228396
|
-
|
|
228535
|
+
amountIn: BigInt(fill.amountIn),
|
|
228536
|
+
amountOut: BigInt(fill.amountOut)
|
|
228397
228537
|
}))
|
|
228398
228538
|
};
|
|
228399
228539
|
}
|
|
228540
|
+
/**
|
|
228541
|
+
* The pessimistic quote for `amountIn` (1e18 tokenIn) on a route: one price, from the first level
|
|
228542
|
+
* deep enough to fill the whole trade by itself, at which every order in it fills; the route's
|
|
228543
|
+
* worst price when no one level can but its levels together can.
|
|
228544
|
+
*/
|
|
228545
|
+
async quotePessimistic(route, amountIn) {
|
|
228546
|
+
const { quotePessimistic: raw } = await this.request(
|
|
228547
|
+
QUOTE_PESSIMISTIC_QUERY,
|
|
228548
|
+
{ route, amountIn: amountIn.toString() }
|
|
228549
|
+
);
|
|
228550
|
+
return {
|
|
228551
|
+
route: raw.route,
|
|
228552
|
+
side: raw.side,
|
|
228553
|
+
amountIn: BigInt(raw.amountIn),
|
|
228554
|
+
amountOut: BigInt(raw.amountOut),
|
|
228555
|
+
rate: optionalBigInt(raw.rate),
|
|
228556
|
+
priceBucket: optionalBigInt(raw.priceBucket),
|
|
228557
|
+
slippageBps: raw.slippageBps,
|
|
228558
|
+
fillable: raw.fillable,
|
|
228559
|
+
maxFillableIn: BigInt(raw.maxFillableIn)
|
|
228560
|
+
};
|
|
228561
|
+
}
|
|
228400
228562
|
async request(query3, variables) {
|
|
228401
228563
|
try {
|
|
228402
228564
|
return await this.client.request(query3, variables);
|
|
@@ -228431,18 +228593,6 @@ query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
228431
228593
|
this.name = "OrderbookQuoteNotConvergedError";
|
|
228432
228594
|
}
|
|
228433
228595
|
};
|
|
228434
|
-
InsufficientOrderbookLiquidityError = class extends Error {
|
|
228435
|
-
constructor(route, maxFillableIn) {
|
|
228436
|
-
super(
|
|
228437
|
-
`The HyperFX orderbook cannot fill ${route.tokenIn} -> ${route.tokenOut} on ${route.sourceChain} -> ${route.destinationChain}; max fillable input is ${maxFillableIn} raw units`
|
|
228438
|
-
);
|
|
228439
|
-
__publicField(this, "route");
|
|
228440
|
-
__publicField(this, "maxFillableIn");
|
|
228441
|
-
this.route = route;
|
|
228442
|
-
this.maxFillableIn = maxFillableIn;
|
|
228443
|
-
this.name = "InsufficientOrderbookLiquidityError";
|
|
228444
|
-
}
|
|
228445
|
-
};
|
|
228446
228596
|
MAX_EXACT_OUTPUT_ROUNDS = 16;
|
|
228447
228597
|
OrderbookMarket = class {
|
|
228448
228598
|
constructor(configService, orderbook) {
|
|
@@ -228452,26 +228602,67 @@ query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
228452
228602
|
this.orderbook = orderbook;
|
|
228453
228603
|
}
|
|
228454
228604
|
async quoteIntent(params, sourceChain, destinationChain) {
|
|
228605
|
+
const orderbook = this.orderbook();
|
|
228606
|
+
if (!params.optimistic) {
|
|
228607
|
+
const { quote: quote2, tokenIn: tokenIn2, tokenOut: tokenOut2 } = await this.priceIntent(
|
|
228608
|
+
params,
|
|
228609
|
+
sourceChain,
|
|
228610
|
+
destinationChain,
|
|
228611
|
+
(route, amountIn) => orderbook.quotePessimistic(route, amountIn),
|
|
228612
|
+
levelQuoteTotals
|
|
228613
|
+
);
|
|
228614
|
+
return {
|
|
228615
|
+
route: quote2.route,
|
|
228616
|
+
side: quote2.side,
|
|
228617
|
+
amountIn: fromOrderbookAmount(quote2.amountIn, tokenIn2.decimals),
|
|
228618
|
+
amountOut: fromOrderbookAmount(quote2.amountOut, tokenOut2.decimals),
|
|
228619
|
+
rate: quote2.rate,
|
|
228620
|
+
priceBucket: quote2.priceBucket,
|
|
228621
|
+
slippageBps: quote2.slippageBps,
|
|
228622
|
+
fillable: quote2.fillable,
|
|
228623
|
+
maxFillableIn: fromOrderbookAmount(quote2.maxFillableIn, tokenIn2.decimals)
|
|
228624
|
+
};
|
|
228625
|
+
}
|
|
228626
|
+
const { quote, tokenIn, tokenOut } = await this.priceIntent(
|
|
228627
|
+
params,
|
|
228628
|
+
sourceChain,
|
|
228629
|
+
destinationChain,
|
|
228630
|
+
(route, amountIn) => orderbook.quote(route, amountIn),
|
|
228631
|
+
swapQuoteTotals
|
|
228632
|
+
);
|
|
228633
|
+
return {
|
|
228634
|
+
route: quote.route,
|
|
228635
|
+
side: quote.side,
|
|
228636
|
+
amountIn: fromOrderbookAmount(quote.amountIn, tokenIn.decimals),
|
|
228637
|
+
slippageBps: quote.slippageBps,
|
|
228638
|
+
fillable: quote.fillable,
|
|
228639
|
+
maxFillableIn: fromOrderbookAmount(quote.maxFillableIn, tokenIn.decimals),
|
|
228640
|
+
legs: quote.fills.map((fill) => ({
|
|
228641
|
+
advertisedSize: fromOrderbookAmount(fill.advertisedSize, tokenOut.decimals),
|
|
228642
|
+
orderRate: fill.orderRate,
|
|
228643
|
+
amountIn: fromOrderbookAmount(fill.amountIn, tokenIn.decimals),
|
|
228644
|
+
amountOut: fromOrderbookAmount(fill.amountOut, tokenOut.decimals)
|
|
228645
|
+
}))
|
|
228646
|
+
};
|
|
228647
|
+
}
|
|
228648
|
+
/**
|
|
228649
|
+
* The orderbook's quote for an exact input, or for the input found to deliver
|
|
228650
|
+
* an exact output, with the assets it trades. A route that cannot fill the
|
|
228651
|
+
* trade answers with an unfillable quote rather than an error.
|
|
228652
|
+
*/
|
|
228653
|
+
async priceIntent(params, sourceChain, destinationChain, price, totals) {
|
|
228455
228654
|
validateQuoteParams(params);
|
|
228456
228655
|
const tokenIn = this.assetByAddress(sourceChain, params.tokenIn);
|
|
228457
228656
|
const tokenOut = this.assetByAddress(destinationChain, params.tokenOut);
|
|
228458
228657
|
const route = toRoute(tokenIn, tokenOut);
|
|
228459
228658
|
if (params.amountIn !== void 0) {
|
|
228460
|
-
const quote2 = await
|
|
228461
|
-
|
|
228462
|
-
|
|
228463
|
-
return buildQuote("EXACT_INPUT", params.amountIn, amountOut2, quote2, tokenIn, tokenOut);
|
|
228659
|
+
const quote2 = await price(route, toOrderbookAmount(params.amountIn, tokenIn.decimals));
|
|
228660
|
+
totals(quote2);
|
|
228661
|
+
return { quote: quote2, tokenIn, tokenOut };
|
|
228464
228662
|
}
|
|
228465
|
-
const
|
|
228466
|
-
const quote = await this.quoteExactOutput(route,
|
|
228467
|
-
return
|
|
228468
|
-
"EXACT_OUTPUT",
|
|
228469
|
-
fromOrderbookAmount(quote.amountIn, tokenIn.decimals),
|
|
228470
|
-
amountOut,
|
|
228471
|
-
quote,
|
|
228472
|
-
tokenIn,
|
|
228473
|
-
tokenOut
|
|
228474
|
-
);
|
|
228663
|
+
const targetOut = toOrderbookAmount(params.amountOut, tokenOut.decimals);
|
|
228664
|
+
const quote = await this.quoteExactOutput(route, targetOut, tokenIn, price, totals);
|
|
228665
|
+
return { quote, tokenIn, tokenOut };
|
|
228475
228666
|
}
|
|
228476
228667
|
async availableLiquidity(params, sourceChain, destinationChain) {
|
|
228477
228668
|
const tokenIn = this.assetByAddress(sourceChain, params.tokenIn);
|
|
@@ -228524,22 +228715,29 @@ query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
228524
228715
|
}
|
|
228525
228716
|
/**
|
|
228526
228717
|
* The orderbook only quotes an input amount, so an output is priced by
|
|
228527
|
-
* guessing the input from the best rate
|
|
228528
|
-
*
|
|
228718
|
+
* guessing the input from the best rate, then keeping the part of each quote
|
|
228719
|
+
* filled better than its worst rate and re-pricing the rest of `targetOut` at
|
|
228720
|
+
* the input-to-output ratio that part filled at, until a quote delivers it.
|
|
228721
|
+
* That ratio is the orderbook's own, with the protocol fee already taken off.
|
|
228722
|
+
*
|
|
228723
|
+
* An output the route cannot deliver is answered by quoting an input past its
|
|
228724
|
+
* `maxFillableIn`, which the orderbook serves as unfillable: the smallest such
|
|
228725
|
+
* input guessed from the best rate, or one raw unit when no order serves it.
|
|
228529
228726
|
*/
|
|
228530
|
-
async quoteExactOutput(route, targetOut, tokenIn) {
|
|
228531
|
-
const
|
|
228532
|
-
const liquidity = await orderbook.routeLiquidity(route);
|
|
228533
|
-
if (liquidity.bestRate === null) throw this.insufficient(route, 0n, tokenIn);
|
|
228727
|
+
async quoteExactOutput(route, targetOut, tokenIn, price, totals) {
|
|
228728
|
+
const liquidity = await this.orderbook().routeLiquidity(route);
|
|
228534
228729
|
const inputUnit = toOrderbookAmount(1n, tokenIn.decimals);
|
|
228535
|
-
let amountIn = roundUpTo(requiredInput(liquidity.side, targetOut, liquidity.bestRate), inputUnit);
|
|
228730
|
+
let amountIn = liquidity.bestRate === null ? inputUnit : roundUpTo(requiredInput(liquidity.side, targetOut, liquidity.bestRate), inputUnit);
|
|
228536
228731
|
let lastAmountIn = amountIn;
|
|
228537
228732
|
for (let round2 = 0; round2 < MAX_EXACT_OUTPUT_ROUNDS; round2++) {
|
|
228538
|
-
|
|
228539
|
-
const quote =
|
|
228540
|
-
if (quote.fillable && quote.amountOut >= targetOut) return
|
|
228733
|
+
const served = await price(route, amountIn);
|
|
228734
|
+
const quote = totals(served);
|
|
228735
|
+
if (quote.fillable && quote.amountOut >= targetOut) return served;
|
|
228736
|
+
if (!quote.fillable && amountIn > liquidity.maxFillableIn) return served;
|
|
228541
228737
|
lastAmountIn = amountIn;
|
|
228542
|
-
const
|
|
228738
|
+
const betterIn = quote.amountIn - quote.worstIn;
|
|
228739
|
+
const betterOut = quote.amountOut - quote.worstOut;
|
|
228740
|
+
const next = quote.fillable && quote.worstOut > 0n ? betterIn + roundUpTo(divCeil((targetOut - betterOut) * quote.worstIn, quote.worstOut), inputUnit) : amountIn;
|
|
228543
228741
|
amountIn = next > amountIn ? next : amountIn + inputUnit;
|
|
228544
228742
|
}
|
|
228545
228743
|
throw new OrderbookQuoteNotConvergedError(
|
|
@@ -228548,9 +228746,6 @@ query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
228548
228746
|
fromOrderbookAmount(lastAmountIn, tokenIn.decimals)
|
|
228549
228747
|
);
|
|
228550
228748
|
}
|
|
228551
|
-
insufficient(route, maxFillableIn, tokenIn) {
|
|
228552
|
-
return new InsufficientOrderbookLiquidityError(route, fromOrderbookAmount(maxFillableIn, tokenIn.decimals));
|
|
228553
|
-
}
|
|
228554
228749
|
assetByAddress(chain2, address) {
|
|
228555
228750
|
const resolvedChain = resolveChain(chain2);
|
|
228556
228751
|
return withDecimals(
|
|
@@ -228709,22 +228904,6 @@ query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
228709
228904
|
this.orderbook = typeof orderbook === "string" ? new HyperFxOrderbook(orderbook) : orderbook;
|
|
228710
228905
|
return this;
|
|
228711
228906
|
}
|
|
228712
|
-
/**
|
|
228713
|
-
* Quotes an intent between this gateway's source and destination chains from
|
|
228714
|
-
* the HyperFX orderbook. Provide exactly one of `amountIn` or `amountOut`, in
|
|
228715
|
-
* raw token units.
|
|
228716
|
-
*
|
|
228717
|
-
* An exact-input quote is the orderbook's clearing price for `amountIn`,
|
|
228718
|
-
* which may combine several solvers' orders. An exact-output quote finds the
|
|
228719
|
-
* smallest input whose clearing price delivers `amountOut`. A cross-chain
|
|
228720
|
-
* route only counts orders whose solvers accept the source chain.
|
|
228721
|
-
*
|
|
228722
|
-
* The orderbook's rates already carry the gateway protocol fee, so the
|
|
228723
|
-
* returned amounts can be placed as the order's inputs and outputs directly.
|
|
228724
|
-
*
|
|
228725
|
-
* @throws {InsufficientOrderbookLiquidityError} When the route cannot fill the amount.
|
|
228726
|
-
* @throws {OrderbookRequestError} When the orderbook is unreachable or trades no book for the pair.
|
|
228727
|
-
*/
|
|
228728
228907
|
async quoteIntent(params) {
|
|
228729
228908
|
return this.market.quoteIntent(params, this.source.config.stateMachineId, this.dest.config.stateMachineId);
|
|
228730
228909
|
}
|
|
@@ -229139,6 +229318,16 @@ query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
229139
229318
|
async estimateFillOrder(params) {
|
|
229140
229319
|
return this.gasEstimator.estimateFillOrder(params);
|
|
229141
229320
|
}
|
|
229321
|
+
/**
|
|
229322
|
+
* Asks the bundler for the `preVerificationGas` of a bid as it will be signed, priced at
|
|
229323
|
+
* the gas price its bundle pays. Call it with the final calldata and `paymasterAndData`,
|
|
229324
|
+
* before {@link prepareSubmitBid} signs the op.
|
|
229325
|
+
*
|
|
229326
|
+
* Delegates to {@link GasEstimator.estimateBidPreVerificationGas}.
|
|
229327
|
+
*/
|
|
229328
|
+
async estimateBidPreVerificationGas(params) {
|
|
229329
|
+
return this.gasEstimator.estimateBidPreVerificationGas(params);
|
|
229330
|
+
}
|
|
229142
229331
|
/**
|
|
229143
229332
|
* Quotes the solver fee for an order using the same policy {@link execute} /
|
|
229144
229333
|
* {@link executeBest} apply when `order.fees` is `0n`.
|
|
@@ -229954,6 +230143,7 @@ var init_external_links = __esm({
|
|
|
229954
230143
|
"src/config/external-links.json"() {
|
|
229955
230144
|
external_links_default = {
|
|
229956
230145
|
hyperfxApp: "https://app.hyperfx.finance",
|
|
230146
|
+
alchemyDashboard: "https://dashboard.alchemy.com/",
|
|
229957
230147
|
hyperbridgeExplorers: {
|
|
229958
230148
|
mainnet: "https://nexus.statescan.io",
|
|
229959
230149
|
testnet: "https://gargantua.statescan.io"
|
|
@@ -229987,12 +230177,58 @@ function chainByChainId(chainId) {
|
|
|
229987
230177
|
function chainByAlchemySubdomain(subdomain) {
|
|
229988
230178
|
return INIT_CHAINS.find((chain2) => chain2.alchemySubdomain === subdomain);
|
|
229989
230179
|
}
|
|
229990
|
-
var CHAIN_NATIVE_SYMBOLS, INIT_CHAINS, HYPERBRIDGE_WS_DEFAULTS;
|
|
230180
|
+
var FREE_RPC_URLS, CHAIN_NATIVE_SYMBOLS, INIT_CHAINS, HYPERBRIDGE_WS_DEFAULTS;
|
|
229991
230181
|
var init_chains2 = __esm({
|
|
229992
230182
|
"src/cli/init/chains.ts"() {
|
|
229993
230183
|
"use strict";
|
|
229994
230184
|
init_esm_shims();
|
|
229995
230185
|
init_external_links();
|
|
230186
|
+
FREE_RPC_URLS = {
|
|
230187
|
+
1: [
|
|
230188
|
+
"https://mainnet.gateway.tenderly.co",
|
|
230189
|
+
"https://rpc.mevblocker.io",
|
|
230190
|
+
"https://ethereum-rpc.publicnode.com",
|
|
230191
|
+
"https://ethereum.public.blockpi.network/v1/rpc/public",
|
|
230192
|
+
"https://eth.blockrazor.xyz",
|
|
230193
|
+
"https://eth.api.pocket.network",
|
|
230194
|
+
"https://ethereum-public.nodies.app",
|
|
230195
|
+
"https://eth-mainnet.public.blastapi.io",
|
|
230196
|
+
"https://public-eth.nownodes.io"
|
|
230197
|
+
],
|
|
230198
|
+
56: [
|
|
230199
|
+
"https://bsc-rpc.publicnode.com",
|
|
230200
|
+
"https://public-bsc-mainnet.fastnode.io",
|
|
230201
|
+
"https://public-bsc.nownodes.io",
|
|
230202
|
+
"https://bsc.blockrazor.xyz",
|
|
230203
|
+
"https://rpc-bsc.48.club",
|
|
230204
|
+
"https://bsc.api.pocket.network"
|
|
230205
|
+
],
|
|
230206
|
+
137: [
|
|
230207
|
+
"https://polygon-bor-rpc.publicnode.com",
|
|
230208
|
+
"https://polygon.drpc.org",
|
|
230209
|
+
"https://polygon.gateway.tenderly.co",
|
|
230210
|
+
"https://rpc.private.mev-x.com/polygon",
|
|
230211
|
+
"https://poly.api.pocket.network"
|
|
230212
|
+
],
|
|
230213
|
+
8453: [
|
|
230214
|
+
"https://base-rpc.publicnode.com",
|
|
230215
|
+
"https://base.gateway.tenderly.co",
|
|
230216
|
+
"https://base.public.blockpi.network/v1/rpc/public",
|
|
230217
|
+
"https://base.rpc.blxrbdn.com",
|
|
230218
|
+
"https://rpc.baseazul.dev",
|
|
230219
|
+
"https://mainnet.base.org",
|
|
230220
|
+
"https://base-public.nodies.app"
|
|
230221
|
+
],
|
|
230222
|
+
42161: [
|
|
230223
|
+
"https://arbitrum-one-rpc.publicnode.com",
|
|
230224
|
+
"https://arbitrum.gateway.tenderly.co",
|
|
230225
|
+
"https://arbitrum.drpc.org",
|
|
230226
|
+
"https://public-arb-mainnet.fastnode.io",
|
|
230227
|
+
"https://arb-one.api.pocket.network",
|
|
230228
|
+
"https://arbitrum-one-public.nodies.app",
|
|
230229
|
+
"https://arb1.arbitrum.io/rpc"
|
|
230230
|
+
]
|
|
230231
|
+
};
|
|
229996
230232
|
CHAIN_NATIVE_SYMBOLS = {
|
|
229997
230233
|
1: "ETH",
|
|
229998
230234
|
56: "BNB",
|
|
@@ -230017,7 +230253,8 @@ var init_chains2 = __esm({
|
|
|
230017
230253
|
label: "Ethereum",
|
|
230018
230254
|
network: "mainnet",
|
|
230019
230255
|
alchemySubdomain: "eth-mainnet",
|
|
230020
|
-
explorerUrl: external_links_default.chainExplorers.ethereum
|
|
230256
|
+
explorerUrl: external_links_default.chainExplorers.ethereum,
|
|
230257
|
+
defaultRpcUrls: FREE_RPC_URLS[1]
|
|
230021
230258
|
},
|
|
230022
230259
|
{
|
|
230023
230260
|
chainId: 42161,
|
|
@@ -230025,7 +230262,8 @@ var init_chains2 = __esm({
|
|
|
230025
230262
|
label: "Arbitrum",
|
|
230026
230263
|
network: "mainnet",
|
|
230027
230264
|
alchemySubdomain: "arb-mainnet",
|
|
230028
|
-
explorerUrl: external_links_default.chainExplorers.arbitrum
|
|
230265
|
+
explorerUrl: external_links_default.chainExplorers.arbitrum,
|
|
230266
|
+
defaultRpcUrls: FREE_RPC_URLS[42161]
|
|
230029
230267
|
},
|
|
230030
230268
|
{
|
|
230031
230269
|
chainId: 8453,
|
|
@@ -230033,7 +230271,8 @@ var init_chains2 = __esm({
|
|
|
230033
230271
|
label: "Base",
|
|
230034
230272
|
network: "mainnet",
|
|
230035
230273
|
alchemySubdomain: "base-mainnet",
|
|
230036
|
-
explorerUrl: external_links_default.chainExplorers.base
|
|
230274
|
+
explorerUrl: external_links_default.chainExplorers.base,
|
|
230275
|
+
defaultRpcUrls: FREE_RPC_URLS[8453]
|
|
230037
230276
|
},
|
|
230038
230277
|
{
|
|
230039
230278
|
chainId: 137,
|
|
@@ -230041,7 +230280,8 @@ var init_chains2 = __esm({
|
|
|
230041
230280
|
label: "Polygon",
|
|
230042
230281
|
network: "mainnet",
|
|
230043
230282
|
alchemySubdomain: "polygon-mainnet",
|
|
230044
|
-
explorerUrl: external_links_default.chainExplorers.polygon
|
|
230283
|
+
explorerUrl: external_links_default.chainExplorers.polygon,
|
|
230284
|
+
defaultRpcUrls: FREE_RPC_URLS[137]
|
|
230045
230285
|
},
|
|
230046
230286
|
{
|
|
230047
230287
|
chainId: 56,
|
|
@@ -230049,7 +230289,8 @@ var init_chains2 = __esm({
|
|
|
230049
230289
|
label: "BNB Chain",
|
|
230050
230290
|
network: "mainnet",
|
|
230051
230291
|
alchemySubdomain: "bnb-mainnet",
|
|
230052
|
-
explorerUrl: external_links_default.chainExplorers.bnb
|
|
230292
|
+
explorerUrl: external_links_default.chainExplorers.bnb,
|
|
230293
|
+
defaultRpcUrls: FREE_RPC_URLS[56]
|
|
230053
230294
|
},
|
|
230054
230295
|
{
|
|
230055
230296
|
chainId: 11155111,
|
|
@@ -295054,12 +295295,12 @@ var init_lib3 = __esm({
|
|
|
295054
295295
|
return Promise.resolve(ab);
|
|
295055
295296
|
}
|
|
295056
295297
|
stream() {
|
|
295057
|
-
const
|
|
295058
|
-
|
|
295298
|
+
const readable2 = new Readable3();
|
|
295299
|
+
readable2._read = function() {
|
|
295059
295300
|
};
|
|
295060
|
-
|
|
295061
|
-
|
|
295062
|
-
return
|
|
295301
|
+
readable2.push(this[BUFFER]);
|
|
295302
|
+
readable2.push(null);
|
|
295303
|
+
return readable2;
|
|
295063
295304
|
}
|
|
295064
295305
|
toString() {
|
|
295065
295306
|
return "[object Blob]";
|
|
@@ -316113,6 +316354,19 @@ async function collectRpcUrls(state, prefill) {
|
|
|
316113
316354
|
for (const chain2 of state.chains) {
|
|
316114
316355
|
const existing = prefillRpcFor(chain2.meta.chainId, prefill);
|
|
316115
316356
|
const derived2 = alchemy.candidate(chain2.meta.chainId);
|
|
316357
|
+
const bundled = chain2.meta.defaultRpcUrls;
|
|
316358
|
+
if (!existing?.length && !derived2 && bundled?.length) {
|
|
316359
|
+
const usePublic = guard(
|
|
316360
|
+
await confirm({
|
|
316361
|
+
message: `Use ${bundled.length} public RPC endpoints for ${chain2.meta.label}?`,
|
|
316362
|
+
initialValue: true
|
|
316363
|
+
})
|
|
316364
|
+
);
|
|
316365
|
+
if (usePublic) {
|
|
316366
|
+
chain2.rpcUrls = [...bundled];
|
|
316367
|
+
continue;
|
|
316368
|
+
}
|
|
316369
|
+
}
|
|
316116
316370
|
let url2;
|
|
316117
316371
|
if (existing?.length) {
|
|
316118
316372
|
url2 = await askRpcUrl(chain2.meta, existing[0]);
|
|
@@ -316290,6 +316544,22 @@ async function stepBundlers(state, prefill) {
|
|
|
316290
316544
|
for (const chain2 of alchemyChains) chain2.bundlerUrl = chain2.rpcUrls[0];
|
|
316291
316545
|
}
|
|
316292
316546
|
}
|
|
316547
|
+
const alchemyCapable = state.chains.filter((chain2) => !chain2.bundlerUrl && chain2.meta.alchemySubdomain);
|
|
316548
|
+
if (alchemyCapable.length > 0) {
|
|
316549
|
+
const useKey = guard(
|
|
316550
|
+
await confirm({
|
|
316551
|
+
message: `Configure the bundler for ${alchemyCapable.map((c6) => c6.meta.label).join(", ")} from one Alchemy API key?`,
|
|
316552
|
+
initialValue: true
|
|
316553
|
+
})
|
|
316554
|
+
);
|
|
316555
|
+
if (useKey) {
|
|
316556
|
+
const apiKey = await askSecret("Alchemy API key");
|
|
316557
|
+
for (const chain2 of alchemyCapable) {
|
|
316558
|
+
const url2 = deriveAlchemyRpc(apiKey, chain2.meta.chainId);
|
|
316559
|
+
if (url2) chain2.bundlerUrl = url2;
|
|
316560
|
+
}
|
|
316561
|
+
}
|
|
316562
|
+
}
|
|
316293
316563
|
const pimlico = new ProviderDerivation({
|
|
316294
316564
|
detect: (url2) => parsePimlicoUrl(url2)?.apiKey ?? null,
|
|
316295
316565
|
derive: derivePimlicoBundler,
|
|
@@ -319025,14 +319295,16 @@ var LimitOrderService = class {
|
|
|
319025
319295
|
}
|
|
319026
319296
|
}
|
|
319027
319297
|
/**
|
|
319028
|
-
* The pairs an order can be written against,
|
|
319298
|
+
* The pairs an order can be written against, the smallest payout each token may carry, and
|
|
319299
|
+
* the tokens the orderbook registers on each chain.
|
|
319029
319300
|
*
|
|
319030
319301
|
* The orderbook lists the books; `resolveBook` refuses a request naming anything else, so the
|
|
319031
|
-
* operator is offered exactly these and no combination of symbols they could not post.
|
|
319302
|
+
* operator is offered exactly these and no combination of symbols they could not post. The
|
|
319303
|
+
* chains do the same for the source chains an order can accept.
|
|
319032
319304
|
*/
|
|
319033
319305
|
async books() {
|
|
319034
319306
|
const limits = await this.limits();
|
|
319035
|
-
return { books: limits.books, minOrderSizes: limits.serverInfo.minOrderSizes };
|
|
319307
|
+
return { books: limits.books, minOrderSizes: limits.serverInfo.minOrderSizes, chains: limits.chains ?? [] };
|
|
319036
319308
|
}
|
|
319037
319309
|
/**
|
|
319038
319310
|
* Reads `serverInfo` and `books`, reusing the last read for {@link LIMITS_TTL_MS}.
|
|
@@ -319114,6 +319386,18 @@ var LimitOrderService = class {
|
|
|
319114
319386
|
);
|
|
319115
319387
|
}
|
|
319116
319388
|
}
|
|
319389
|
+
if (book.base !== book.quote) {
|
|
319390
|
+
const input = normalizeSymbol(request3.tokenIn);
|
|
319391
|
+
const lacking = sources.filter((source) => {
|
|
319392
|
+
const listed = limits.chains?.find((chain2) => chain2.id === source);
|
|
319393
|
+
return listed && !listed.tokens.some((token) => normalizeSymbol(token.symbol) === input);
|
|
319394
|
+
});
|
|
319395
|
+
if (lacking.length > 0) {
|
|
319396
|
+
throw new LimitOrderValidationError(
|
|
319397
|
+
`The orderbook has no ${request3.tokenIn} on ${lacking.join(", ")}, so swaps from there cannot pay this order`
|
|
319398
|
+
);
|
|
319399
|
+
}
|
|
319400
|
+
}
|
|
319117
319401
|
if (ttlSecs < limits.serverInfo.minOrderTtlSecs) {
|
|
319118
319402
|
throw new LimitOrderValidationError(
|
|
319119
319403
|
`ttlSecs must be at least the orderbook's minimum of ${limits.serverInfo.minOrderTtlSecs}; got ${ttlSecs}`
|
|
@@ -320776,7 +321060,7 @@ var NotificationService = class extends EventEmitter6 {
|
|
|
320776
321060
|
title: "Swap filled",
|
|
320777
321061
|
body: swapBody(event),
|
|
320778
321062
|
tag: `simplex-swap-${id2}`,
|
|
320779
|
-
url: "./
|
|
321063
|
+
url: "./history"
|
|
320780
321064
|
}).catch((error) => this.logger.error({ err: error }, "Could not publish swap notification"));
|
|
320781
321065
|
}
|
|
320782
321066
|
};
|
|
@@ -320969,6 +321253,7 @@ init_chains2();
|
|
|
320969
321253
|
init_alchemy();
|
|
320970
321254
|
init_prompt_utils();
|
|
320971
321255
|
init_state();
|
|
321256
|
+
init_defaults8();
|
|
320972
321257
|
init_Logger();
|
|
320973
321258
|
var logger2 = getLogger("setup");
|
|
320974
321259
|
async function defaultRpcRequest(url2, method, params) {
|
|
@@ -321015,6 +321300,18 @@ async function handleSetupRequest(server, setup, req, res, path2, method) {
|
|
|
321015
321300
|
};
|
|
321016
321301
|
return sendJson(res, 200, defaults3);
|
|
321017
321302
|
}
|
|
321303
|
+
if (endpoint === "orderbook") {
|
|
321304
|
+
if (method !== "GET") return sendJson(res, 405, { error: "Method not allowed" });
|
|
321305
|
+
const url2 = DEFAULT_ORDERBOOK_URLS.mainnet;
|
|
321306
|
+
try {
|
|
321307
|
+
const { books } = await new OrderbookClient(url2, DEFAULT_ORDERBOOK_TIMEOUT_MS).limits();
|
|
321308
|
+
const orderbook = { url: url2, books };
|
|
321309
|
+
return sendJson(res, 200, orderbook);
|
|
321310
|
+
} catch (err) {
|
|
321311
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
321312
|
+
return sendJson(res, 502, { error: `Could not read the orderbook's markets: ${reason}` });
|
|
321313
|
+
}
|
|
321314
|
+
}
|
|
321018
321315
|
if (method !== "POST") return sendJson(res, 405, { error: "Method not allowed" });
|
|
321019
321316
|
let body;
|
|
321020
321317
|
try {
|
|
@@ -323326,14 +323623,10 @@ var RATE_LIMIT_RPC_CODES = /* @__PURE__ */ new Set([-32005, -32097, -32016, 429]
|
|
|
323326
323623
|
var RATE_LIMIT_SUSPENSION_MS = 5 * 6e4;
|
|
323327
323624
|
var SCAN_BUDGET = {
|
|
323328
323625
|
timeoutMs: 5e3,
|
|
323329
|
-
retryCount: 1,
|
|
323330
|
-
retryDelayMs: 500,
|
|
323331
323626
|
deadlineMs: 12e3
|
|
323332
323627
|
};
|
|
323333
323628
|
var CONFIRMATION_BUDGET = {
|
|
323334
323629
|
timeoutMs: 1e4,
|
|
323335
|
-
retryCount: 1,
|
|
323336
|
-
retryDelayMs: 500,
|
|
323337
323630
|
deadlineMs: 3e4
|
|
323338
323631
|
};
|
|
323339
323632
|
var MALFORMED_RESPONSE_SUSPENSION_MS = 3e4;
|
|
@@ -323425,8 +323718,14 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323425
323718
|
chain: chain2,
|
|
323426
323719
|
transport: http(url2, {
|
|
323427
323720
|
timeout: budget.timeoutMs,
|
|
323428
|
-
|
|
323429
|
-
|
|
323721
|
+
// No transport-level retry. viem's retry sleeps for the provider's
|
|
323722
|
+
// `Retry-After` verbatim and uncapped, which reaches the socket
|
|
323723
|
+
// before {@link suspensionMsFor} can apply its clamp — and even
|
|
323724
|
+
// without that header, retrying inside the task is what makes a
|
|
323725
|
+
// task's worst case (timeout, backoff, timeout) approach the
|
|
323726
|
+
// deadline that is supposed to bound it. One attempt per endpoint
|
|
323727
|
+
// per call; `retryPromise` above the quorum owns the retry policy.
|
|
323728
|
+
retryCount: 0
|
|
323430
323729
|
})
|
|
323431
323730
|
})
|
|
323432
323731
|
);
|
|
@@ -323440,11 +323739,10 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323440
323739
|
return this.rpcUrls.filter((url2) => (_QuorumPublicClient.benchedUntil.get(url2) ?? 0) > now);
|
|
323441
323740
|
}
|
|
323442
323741
|
/**
|
|
323443
|
-
* The endpoints this call queries
|
|
323444
|
-
*
|
|
323445
|
-
*
|
|
323446
|
-
*
|
|
323447
|
-
* queried again; there is nobody left to prefer.
|
|
323742
|
+
* The endpoints this call queries: everyone not benched. A benched endpoint is
|
|
323743
|
+
* dropped outright: it answers nothing while throttled, so asking it could only
|
|
323744
|
+
* cost a request. With every endpoint benched, everyone is queried again; there
|
|
323745
|
+
* is nobody left to prefer.
|
|
323448
323746
|
*/
|
|
323449
323747
|
participants() {
|
|
323450
323748
|
const now = Date.now();
|
|
@@ -323452,12 +323750,7 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323452
323750
|
const active = all7.filter(({ idx }) => (_QuorumPublicClient.benchedUntil.get(this.rpcUrls[idx]) ?? 0) <= now);
|
|
323453
323751
|
const allBenched = active.length === 0;
|
|
323454
323752
|
const queried = allBenched ? all7 : active;
|
|
323455
|
-
return {
|
|
323456
|
-
queried,
|
|
323457
|
-
skipped: all7.length - queried.length,
|
|
323458
|
-
threshold: quorumThreshold(queried.length),
|
|
323459
|
-
allBenched
|
|
323460
|
-
};
|
|
323753
|
+
return { queried, skipped: all7.length - queried.length, allBenched };
|
|
323461
323754
|
}
|
|
323462
323755
|
/**
|
|
323463
323756
|
* Records a task failure against its endpoint. Only the failures
|
|
@@ -323502,17 +323795,21 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323502
323795
|
* retries would otherwise stall every confirmation poll). Stragglers settle
|
|
323503
323796
|
* out of band and are ignored. `tryDecide` returns undefined to keep
|
|
323504
323797
|
* waiting; once every task has settled, `finalize` must decide (it throws
|
|
323505
|
-
* the QuorumError when the full response set still has no quorum).
|
|
323506
|
-
*
|
|
323507
|
-
*
|
|
323798
|
+
* the QuorumError when the full response set still has no quorum).
|
|
323799
|
+
*
|
|
323800
|
+
* Both are handed the bar: the BFT threshold over the endpoints that have not
|
|
323801
|
+
* failed, answered or still out. A failure lowers it rather than counting
|
|
323802
|
+
* against it. Counting the pending endpoints keeps an early decision to a bar
|
|
323803
|
+
* no lower than the full response set would get, so a vote it did not wait for
|
|
323804
|
+
* could never have reversed it.
|
|
323508
323805
|
*
|
|
323509
323806
|
* `deadlineMs` bounds the other direction: when the bar is NOT reachable
|
|
323510
323807
|
* from the fast responders, the call used to wait out every straggler, and
|
|
323511
323808
|
* the caller's own retry loop multiplied that into minutes of a chain not
|
|
323512
323809
|
* being scanned at all, silently. At the deadline the outstanding endpoints
|
|
323513
323810
|
* are treated as failures — named in the QuorumError, so the operator sees
|
|
323514
|
-
* which ones held the call up — and `finalize` decides
|
|
323515
|
-
*
|
|
323811
|
+
* which ones held the call up — and `finalize` decides over the endpoints
|
|
323812
|
+
* that answered.
|
|
323516
323813
|
*/
|
|
323517
323814
|
settleUntilQuorum(tasks, tryDecide, finalize) {
|
|
323518
323815
|
return new Promise((resolve11, reject) => {
|
|
@@ -323530,13 +323827,14 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323530
323827
|
const evaluate = () => {
|
|
323531
323828
|
if (done) return;
|
|
323532
323829
|
try {
|
|
323533
|
-
const
|
|
323830
|
+
const threshold = quorumThreshold(tasks.length - failures.length);
|
|
323831
|
+
const early = tryDecide(fulfilled, threshold);
|
|
323534
323832
|
if (early !== void 0) {
|
|
323535
323833
|
finish(() => resolve11(early));
|
|
323536
323834
|
return;
|
|
323537
323835
|
}
|
|
323538
323836
|
if (outstanding === 0) {
|
|
323539
|
-
const value = finalize(fulfilled, failures);
|
|
323837
|
+
const value = finalize(fulfilled, failures, threshold);
|
|
323540
323838
|
finish(() => resolve11(value));
|
|
323541
323839
|
}
|
|
323542
323840
|
} catch (error) {
|
|
@@ -323554,7 +323852,7 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323554
323852
|
error: new Error(`no answer within the ${this.deadlineMs}ms quorum deadline`)
|
|
323555
323853
|
}));
|
|
323556
323854
|
try {
|
|
323557
|
-
const value = finalize(fulfilled, [...failures, ...stragglers]);
|
|
323855
|
+
const value = finalize(fulfilled, [...failures, ...stragglers], quorumThreshold(fulfilled.length));
|
|
323558
323856
|
finish(() => resolve11(value));
|
|
323559
323857
|
} catch (error) {
|
|
323560
323858
|
finish(() => reject(error));
|
|
@@ -323581,22 +323879,22 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323581
323879
|
});
|
|
323582
323880
|
}
|
|
323583
323881
|
/**
|
|
323584
|
-
* Highest block head backed by a
|
|
323585
|
-
*
|
|
323882
|
+
* Highest block head backed by a quorum of the endpoints that answer. Throws
|
|
323883
|
+
* {@link QuorumError} when none do.
|
|
323586
323884
|
*/
|
|
323587
323885
|
async getBlockNumber() {
|
|
323588
|
-
const { queried, skipped,
|
|
323886
|
+
const { queried, skipped, allBenched } = this.participants();
|
|
323589
323887
|
return this.settleUntilQuorum(
|
|
323590
323888
|
queried.map(({ idx, client }) => ({ idx, task: client.getBlockNumber() })),
|
|
323591
323889
|
// Early exit as soon as a quorum is satisfiable. Late voters could
|
|
323592
323890
|
// only raise the reported head; the earlier (lower) head is
|
|
323593
323891
|
// conservative for every consumer (fewer confirmations counted,
|
|
323594
323892
|
// smaller scan windows).
|
|
323595
|
-
(fulfilled) => this.quorumHead(
|
|
323893
|
+
(fulfilled, threshold) => this.quorumHead(
|
|
323596
323894
|
fulfilled.map((f7) => f7.value),
|
|
323597
323895
|
threshold
|
|
323598
323896
|
) ?? void 0,
|
|
323599
|
-
(fulfilled, failures) => {
|
|
323897
|
+
(fulfilled, failures, threshold) => {
|
|
323600
323898
|
const head = this.quorumHead(
|
|
323601
323899
|
fulfilled.map((f7) => f7.value),
|
|
323602
323900
|
threshold
|
|
@@ -323637,7 +323935,7 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323637
323935
|
}
|
|
323638
323936
|
return views;
|
|
323639
323937
|
};
|
|
323640
|
-
const { queried, skipped,
|
|
323938
|
+
const { queried, skipped, allBenched } = this.participants();
|
|
323641
323939
|
return this.settleUntilQuorum(
|
|
323642
323940
|
queried.map(({ idx, client }) => ({
|
|
323643
323941
|
idx,
|
|
@@ -323656,8 +323954,8 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323656
323954
|
// Early exit only on a POSITIVE quorum: an agreeing inclusion group can
|
|
323657
323955
|
// only grow, so the first satisfiable quorum is final. Not-found votes
|
|
323658
323956
|
// never decide early — "not confirmed" needs the full response set.
|
|
323659
|
-
(fulfilled) => aggregateConfirmations(toViews(fulfilled), threshold) ?? void 0,
|
|
323660
|
-
(fulfilled, failures) => {
|
|
323957
|
+
(fulfilled, threshold) => aggregateConfirmations(toViews(fulfilled), threshold) ?? void 0,
|
|
323958
|
+
(fulfilled, failures, threshold) => {
|
|
323661
323959
|
const confirmations = aggregateConfirmations(toViews(fulfilled), threshold);
|
|
323662
323960
|
if (confirmations === null) {
|
|
323663
323961
|
throw new QuorumError(
|
|
@@ -323686,7 +323984,7 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323686
323984
|
}
|
|
323687
323985
|
return groups;
|
|
323688
323986
|
};
|
|
323689
|
-
const { queried, skipped,
|
|
323987
|
+
const { queried, skipped, allBenched } = this.participants();
|
|
323690
323988
|
return this.settleUntilQuorum(
|
|
323691
323989
|
queried.map(({ idx, client }) => ({
|
|
323692
323990
|
idx,
|
|
@@ -323698,13 +323996,13 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
323698
323996
|
// two disjoint groups can't both hold one), so the first satisfiable
|
|
323699
323997
|
// agreement is final — no need to wait out stragglers that could
|
|
323700
323998
|
// only join or lose.
|
|
323701
|
-
(fulfilled) => {
|
|
323999
|
+
(fulfilled, threshold) => {
|
|
323702
324000
|
for (const group of groupOf(fulfilled).values()) {
|
|
323703
324001
|
if (group.providerIdxs.length >= threshold) return group.result;
|
|
323704
324002
|
}
|
|
323705
324003
|
return void 0;
|
|
323706
324004
|
},
|
|
323707
|
-
(fulfilled, failures) => {
|
|
324005
|
+
(fulfilled, failures, threshold) => {
|
|
323708
324006
|
const groups = groupOf(fulfilled);
|
|
323709
324007
|
for (const group of groups.values()) {
|
|
323710
324008
|
if (group.providerIdxs.length >= threshold) return group.result;
|
|
@@ -328936,20 +329234,32 @@ var ContractInteractionService = class {
|
|
|
328936
329234
|
} else {
|
|
328937
329235
|
this.logger.warn({ reason: pmResult.reason }, "No paymaster for bid UserOp; relying on EntryPoint deposit");
|
|
328938
329236
|
}
|
|
328939
|
-
const
|
|
328940
|
-
order,
|
|
328941
|
-
fillOptions,
|
|
329237
|
+
const bidGas = {
|
|
328942
329238
|
solverAccount: solverAccountAddress,
|
|
328943
|
-
solverSigner: sdkSigningAccount(this.signer),
|
|
328944
329239
|
nonce,
|
|
328945
329240
|
entryPointAddress,
|
|
328946
329241
|
callGasLimit,
|
|
328947
329242
|
verificationGasLimit: cachedEstimate.verificationGasLimit,
|
|
328948
|
-
preVerificationGas: cachedEstimate.preVerificationGas,
|
|
328949
329243
|
maxFeePerGas: cachedEstimate.maxFeePerGas,
|
|
328950
329244
|
maxPriorityFeePerGas: cachedEstimate.maxPriorityFeePerGas,
|
|
328951
329245
|
callData,
|
|
328952
329246
|
paymasterAndData
|
|
329247
|
+
};
|
|
329248
|
+
let preVerificationGas = cachedEstimate.preVerificationGas;
|
|
329249
|
+
try {
|
|
329250
|
+
preVerificationGas = await sdkHelper.estimateBidPreVerificationGas(bidGas);
|
|
329251
|
+
} catch (err) {
|
|
329252
|
+
this.logger.warn(
|
|
329253
|
+
{ orderId: order.id, err, preVerificationGas: preVerificationGas.toString() },
|
|
329254
|
+
"Could not estimate the bid's preVerificationGas; using the fill estimate's"
|
|
329255
|
+
);
|
|
329256
|
+
}
|
|
329257
|
+
const userOp = await sdkHelper.prepareSubmitBid({
|
|
329258
|
+
...bidGas,
|
|
329259
|
+
order,
|
|
329260
|
+
fillOptions,
|
|
329261
|
+
solverSigner: sdkSigningAccount(this.signer),
|
|
329262
|
+
preVerificationGas
|
|
328953
329263
|
});
|
|
328954
329264
|
const encodedUserOp = encodeUserOpScale(userOp);
|
|
328955
329265
|
this.logger.info(
|
|
@@ -328958,6 +329268,7 @@ var ContractInteractionService = class {
|
|
|
328958
329268
|
solverAccount: solverAccountAddress,
|
|
328959
329269
|
nonce: nonce.toString(),
|
|
328960
329270
|
callGasLimit: callGasLimit.toString(),
|
|
329271
|
+
preVerificationGas: preVerificationGas.toString(),
|
|
328961
329272
|
maxFeePerGas: cachedEstimate.maxFeePerGas.toString()
|
|
328962
329273
|
},
|
|
328963
329274
|
"Prepared bid UserOp"
|
|
@@ -362304,8 +362615,15 @@ var IntentFiller = class {
|
|
|
362304
362615
|
const evalDurationSec = (Date.now() - evalStartMs) / 1e3;
|
|
362305
362616
|
this.monitor.emit("orderTiming", { orderId: order.id, phase: "evaluation", durationSec: evalDurationSec });
|
|
362306
362617
|
if (validStrategies.length === 0) {
|
|
362307
|
-
|
|
362308
|
-
this.
|
|
362618
|
+
const priced = eligibleStrategies.some((s4) => s4 !== null);
|
|
362619
|
+
this.logger.warn(
|
|
362620
|
+
{ orderId: order.id },
|
|
362621
|
+
priced ? "No profitable strategy found for order" : "No strategy can fill this order"
|
|
362622
|
+
);
|
|
362623
|
+
this.monitor.emit("orderSkipped", {
|
|
362624
|
+
orderId: order.id,
|
|
362625
|
+
reason: priced ? "No profitable strategy" : "No strategy can fill this order"
|
|
362626
|
+
});
|
|
362309
362627
|
return null;
|
|
362310
362628
|
}
|
|
362311
362629
|
this.logger.info(
|
|
@@ -362732,10 +363050,6 @@ init_asset_registry();
|
|
|
362732
363050
|
function limitOrderLegs(order) {
|
|
362733
363051
|
return order.side === "BID" ? { input: order.base, output: order.quote } : { input: order.quote, output: order.base };
|
|
362734
363052
|
}
|
|
362735
|
-
function availableOn(order) {
|
|
362736
|
-
const available = BigInt(order.remaining) - BigInt(order.reserved);
|
|
362737
|
-
return available > 0n ? available : 0n;
|
|
362738
|
-
}
|
|
362739
363053
|
function matchLimitOrders(orders, incoming, resolve11, now = /* @__PURE__ */ new Date()) {
|
|
362740
363054
|
const qualifying = orders.filter((order) => serves(order, incoming, resolve11, now)).map((order) => {
|
|
362741
363055
|
const offer = offerFor({
|
|
@@ -362744,7 +363058,7 @@ function matchLimitOrders(orders, incoming, resolve11, now = /* @__PURE__ */ new
|
|
|
362744
363058
|
price: BigInt(order.price),
|
|
362745
363059
|
outputDecimals: incoming.outputDecimals
|
|
362746
363060
|
});
|
|
362747
|
-
const available =
|
|
363061
|
+
const available = BigInt(order.remaining);
|
|
362748
363062
|
return { order, offer, available, payout: offer < available ? offer : available };
|
|
362749
363063
|
}).filter((candidate) => candidate.offer >= incoming.requestedOutput && candidate.payout > 0n).sort(byBestOfferFirst);
|
|
362750
363064
|
return qualifying;
|
|
@@ -362754,16 +363068,63 @@ function byBestOfferFirst(a6, b5) {
|
|
|
362754
363068
|
if (a6.available !== b5.available) return a6.available > b5.available ? -1 : 1;
|
|
362755
363069
|
return a6.order.id < b5.order.id ? -1 : 1;
|
|
362756
363070
|
}
|
|
363071
|
+
function whyUnmatched(orders, incoming, resolve11, now = /* @__PURE__ */ new Date()) {
|
|
363072
|
+
let furthest = -1;
|
|
363073
|
+
for (const order of orders) {
|
|
363074
|
+
const failed = firstFailed(order, incoming, resolve11, now);
|
|
363075
|
+
furthest = Math.max(furthest, failed === null ? CHECKS.length : CHECKS.indexOf(failed));
|
|
363076
|
+
}
|
|
363077
|
+
const { source, destination, inputSymbol } = incoming;
|
|
363078
|
+
if (furthest < CHECKS.length) {
|
|
363079
|
+
switch (CHECKS[Math.max(furthest, 0)]) {
|
|
363080
|
+
case "open":
|
|
363081
|
+
return "no limit order is open";
|
|
363082
|
+
case "chain":
|
|
363083
|
+
return `no open limit order fills on ${destination}`;
|
|
363084
|
+
case "input":
|
|
363085
|
+
return `no limit order on ${destination} takes ${inputSymbol} in`;
|
|
363086
|
+
case "output":
|
|
363087
|
+
return `no limit order on ${destination} taking ${inputSymbol} in pays out the token this order asks for`;
|
|
363088
|
+
case "source":
|
|
363089
|
+
return `no limit order for this pair on ${destination} accepts swaps from ${source}`;
|
|
363090
|
+
}
|
|
363091
|
+
}
|
|
363092
|
+
const priced = orders.filter((order) => firstFailed(order, incoming, resolve11, now) === null).map((order) => ({
|
|
363093
|
+
order,
|
|
363094
|
+
offer: offerFor({
|
|
363095
|
+
side: order.side,
|
|
363096
|
+
inputAmount: incoming.inputNet,
|
|
363097
|
+
price: BigInt(order.price),
|
|
363098
|
+
outputDecimals: incoming.outputDecimals
|
|
363099
|
+
})
|
|
363100
|
+
}));
|
|
363101
|
+
if (priced.some(({ offer }) => offer >= incoming.requestedOutput)) {
|
|
363102
|
+
return "the limit orders that meet its rate have nothing left to pay out";
|
|
363103
|
+
}
|
|
363104
|
+
const best = priced.reduce((a6, b5) => b5.offer > a6.offer ? b5 : a6);
|
|
363105
|
+
const symbol3 = limitOrderLegs(best.order).output;
|
|
363106
|
+
return `it asks for ${readable(incoming.requestedOutput)} ${symbol3}; the best limit order offers ${readable(best.offer)} ${symbol3}`;
|
|
363107
|
+
}
|
|
363108
|
+
var CHECKS = ["open", "chain", "input", "output", "source"];
|
|
362757
363109
|
function serves(order, incoming, resolve11, now) {
|
|
362758
|
-
|
|
362759
|
-
|
|
362760
|
-
|
|
363110
|
+
return firstFailed(order, incoming, resolve11, now) === null;
|
|
363111
|
+
}
|
|
363112
|
+
function firstFailed(order, incoming, resolve11, now) {
|
|
363113
|
+
if (order.status !== "open") return "open";
|
|
363114
|
+
if (order.expiresAt !== null && new Date(order.expiresAt) <= now) return "open";
|
|
363115
|
+
if (order.fillChain !== incoming.destination) return "chain";
|
|
362761
363116
|
const legs = limitOrderLegs(order);
|
|
362762
|
-
if (normalizeSymbol(legs.input) !== normalizeSymbol(incoming.inputSymbol)) return
|
|
363117
|
+
if (normalizeSymbol(legs.input) !== normalizeSymbol(incoming.inputSymbol)) return "input";
|
|
362763
363118
|
const outputToken = resolve11(legs.output, order.fillChain);
|
|
362764
|
-
if (!outputToken || outputToken.toLowerCase() !== incoming.outputToken.toLowerCase()) return
|
|
362765
|
-
if (incoming.source === incoming.destination) return
|
|
362766
|
-
return order.acceptedSources.includes(incoming.source);
|
|
363119
|
+
if (!outputToken || outputToken.toLowerCase() !== incoming.outputToken.toLowerCase()) return "output";
|
|
363120
|
+
if (incoming.source === incoming.destination) return null;
|
|
363121
|
+
return order.acceptedSources.includes(incoming.source) ? null : "source";
|
|
363122
|
+
}
|
|
363123
|
+
function readable(amount) {
|
|
363124
|
+
const [whole, fraction] = toHuman(amount).split(".");
|
|
363125
|
+
const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
363126
|
+
const cut = fraction?.slice(0, 6).replace(/0+$/, "");
|
|
363127
|
+
return cut ? `${grouped}.${cut}` : grouped;
|
|
362767
363128
|
}
|
|
362768
363129
|
|
|
362769
363130
|
// src/orderbook/usd.ts
|
|
@@ -362907,15 +363268,20 @@ var FXFiller = class _FXFiller {
|
|
|
362907
363268
|
}
|
|
362908
363269
|
try {
|
|
362909
363270
|
if (order.inputs.length !== order.output.assets.length) {
|
|
362910
|
-
this.logger.
|
|
362911
|
-
{ inputs: order.inputs.length, outputs: order.output.assets.length },
|
|
363271
|
+
this.logger.info(
|
|
363272
|
+
{ orderId: order.id, inputs: order.inputs.length, outputs: order.output.assets.length },
|
|
362912
363273
|
"Order input/output length mismatch or empty"
|
|
362913
363274
|
);
|
|
362914
363275
|
return false;
|
|
362915
363276
|
}
|
|
362916
363277
|
if ((await this.matchOrder(order)).length === 0) {
|
|
362917
|
-
this.logger.
|
|
362918
|
-
{
|
|
363278
|
+
this.logger.info(
|
|
363279
|
+
{
|
|
363280
|
+
orderId: order.id,
|
|
363281
|
+
sourceChain: order.source,
|
|
363282
|
+
destChain: order.destination,
|
|
363283
|
+
reason: await this.explainUnmatched(order)
|
|
363284
|
+
},
|
|
362919
363285
|
"No limit order matches this order"
|
|
362920
363286
|
);
|
|
362921
363287
|
return false;
|
|
@@ -363457,30 +363823,53 @@ var FXFiller = class _FXFiller {
|
|
|
363457
363823
|
*/
|
|
363458
363824
|
async matchLeg(order, leg) {
|
|
363459
363825
|
if (!this.limitOrders) return [];
|
|
363826
|
+
const incoming = await this.incomingFor(order, leg);
|
|
363827
|
+
if (!incoming) return [];
|
|
363828
|
+
return matchLimitOrders(
|
|
363829
|
+
await this.limitOrders.open(),
|
|
363830
|
+
incoming,
|
|
363831
|
+
(symbol3, chain2) => this.registry.getAddress(symbol3, chain2)
|
|
363832
|
+
);
|
|
363833
|
+
}
|
|
363834
|
+
/** Why no limit order serves the order, leg by leg, for the line that says it was passed over. */
|
|
363835
|
+
async explainUnmatched(order) {
|
|
363836
|
+
if (!this.limitOrders) return "limit orders are not loaded";
|
|
363837
|
+
const open2 = await this.limitOrders.open();
|
|
363838
|
+
const reasons = [];
|
|
363839
|
+
for (let leg = 0; leg < order.inputs.length; leg++) {
|
|
363840
|
+
const incoming = await this.incomingFor(order, leg);
|
|
363841
|
+
const reason = incoming ? whyUnmatched(open2, incoming, (symbol3, chain2) => this.registry.getAddress(symbol3, chain2)) : `its input token is not in the asset registry on ${order.source}`;
|
|
363842
|
+
reasons.push(order.inputs.length > 1 ? `leg ${leg}: ${reason}` : reason);
|
|
363843
|
+
}
|
|
363844
|
+
return reasons.join("; ");
|
|
363845
|
+
}
|
|
363846
|
+
/**
|
|
363847
|
+
* One leg as the matcher sees it, or null when its input token is not one the asset
|
|
363848
|
+
* registry knows on the source chain.
|
|
363849
|
+
*
|
|
363850
|
+
* Amounts cross into the matcher at 1e18, the unit limit orders are kept in.
|
|
363851
|
+
*/
|
|
363852
|
+
async incomingFor(order, leg) {
|
|
363460
363853
|
const input = order.inputs[leg];
|
|
363461
363854
|
const output3 = order.output.assets[leg];
|
|
363462
|
-
if (!input || !output3) return
|
|
363855
|
+
if (!input || !output3) return null;
|
|
363463
363856
|
const inputToken = bytes32ToBytes20(input.token);
|
|
363464
363857
|
const outputToken = bytes32ToBytes20(output3.token);
|
|
363465
363858
|
const inputSymbol = this.registry.symbolFor(inputToken, order.source);
|
|
363466
|
-
if (!inputSymbol) return
|
|
363859
|
+
if (!inputSymbol) return null;
|
|
363467
363860
|
const [inputDecimals, outputDecimals] = await Promise.all([
|
|
363468
363861
|
this.contractService.getTokenDecimals(inputToken, order.source),
|
|
363469
363862
|
this.contractService.getTokenDecimals(outputToken, order.destination)
|
|
363470
363863
|
]);
|
|
363471
|
-
return
|
|
363472
|
-
|
|
363473
|
-
|
|
363474
|
-
|
|
363475
|
-
|
|
363476
|
-
|
|
363477
|
-
|
|
363478
|
-
|
|
363479
|
-
|
|
363480
|
-
outputDecimals
|
|
363481
|
-
},
|
|
363482
|
-
(symbol3, chain2) => this.registry.getAddress(symbol3, chain2)
|
|
363483
|
-
);
|
|
363864
|
+
return {
|
|
363865
|
+
source: order.source,
|
|
363866
|
+
destination: order.destination,
|
|
363867
|
+
inputSymbol,
|
|
363868
|
+
outputToken,
|
|
363869
|
+
inputNet: toScaled(input.amount, inputDecimals),
|
|
363870
|
+
requestedOutput: toScaled(output3.amount, outputDecimals),
|
|
363871
|
+
outputDecimals
|
|
363872
|
+
};
|
|
363484
363873
|
}
|
|
363485
363874
|
/**
|
|
363486
363875
|
* The order's input in **USD**, or null when no limit order connects its input
|
|
@@ -364583,48 +364972,42 @@ async function bootFiller(config5, options) {
|
|
|
364583
364972
|
assertPairSymbolsResolve(config5.pairs, assetRegistry, configuredChainNames);
|
|
364584
364973
|
}
|
|
364585
364974
|
const adminStrategies = [];
|
|
364586
|
-
const
|
|
364587
|
-
|
|
364588
|
-
|
|
364589
|
-
|
|
364590
|
-
|
|
364591
|
-
|
|
364592
|
-
|
|
364593
|
-
|
|
364594
|
-
|
|
364595
|
-
|
|
364596
|
-
|
|
364597
|
-
|
|
364598
|
-
token1: pair.token1,
|
|
364599
|
-
sameToken: normalizeSymbol(pair.token0) === normalizeSymbol(pair.token1)
|
|
364600
|
-
});
|
|
364975
|
+
const tradingPairs = (config5.pairs ?? []).map((pair) => ({
|
|
364976
|
+
token0: pair.token0,
|
|
364977
|
+
token1: pair.token1
|
|
364978
|
+
}));
|
|
364979
|
+
tradingPairs.forEach((pair, pairIndex) => {
|
|
364980
|
+
adminStrategies.push({
|
|
364981
|
+
index: pairIndex,
|
|
364982
|
+
pairIndex,
|
|
364983
|
+
exotic: `${pair.token0}/${pair.token1}`,
|
|
364984
|
+
token0: pair.token0,
|
|
364985
|
+
token1: pair.token1,
|
|
364986
|
+
sameToken: normalizeSymbol(pair.token0) === normalizeSymbol(pair.token1)
|
|
364601
364987
|
});
|
|
364602
|
-
|
|
364603
|
-
|
|
364604
|
-
|
|
364605
|
-
)
|
|
364606
|
-
|
|
364607
|
-
|
|
364608
|
-
|
|
364609
|
-
|
|
364610
|
-
|
|
364611
|
-
|
|
364612
|
-
|
|
364613
|
-
|
|
364614
|
-
|
|
364615
|
-
|
|
364616
|
-
|
|
364617
|
-
|
|
364618
|
-
|
|
364619
|
-
|
|
364988
|
+
});
|
|
364989
|
+
const confirmationPolicy = assertConfirmationCoverage(
|
|
364990
|
+
config5.confirmationPolicies,
|
|
364991
|
+
resolvedChains.map((c6) => c6.chainId)
|
|
364992
|
+
);
|
|
364993
|
+
const fundingVenues = vaultVenue ? [vaultVenue] : [];
|
|
364994
|
+
const engine = new FXFiller(
|
|
364995
|
+
runtimeSigner,
|
|
364996
|
+
configService,
|
|
364997
|
+
chainClientManager,
|
|
364998
|
+
contractService,
|
|
364999
|
+
tradingPairs,
|
|
365000
|
+
assetRegistry,
|
|
365001
|
+
{ confirmationPolicy, fundingVenues, limitOrders: options.data.limitOrders }
|
|
365002
|
+
);
|
|
365003
|
+
logger8.info("Hydrating funding venue state...");
|
|
365004
|
+
await engine.initialise();
|
|
365005
|
+
const strategies = [engine];
|
|
364620
365006
|
const haltControls = strategies.map((engine2, index3) => ({
|
|
364621
365007
|
index: index3,
|
|
364622
365008
|
isHalted: () => engine2.isHalted(),
|
|
364623
365009
|
resetHalt: () => engine2.resetHalt()
|
|
364624
365010
|
}));
|
|
364625
|
-
if (vaultVenue) {
|
|
364626
|
-
await vaultVenue.initialise(runtimeSigner.address);
|
|
364627
|
-
}
|
|
364628
365011
|
let rebalancingService;
|
|
364629
365012
|
const rebalancingConfig = configService.getRebalancingConfig();
|
|
364630
365013
|
if (rebalancingConfig?.triggerPercentage !== void 0 && rebalancingConfig?.baseBalances) {
|
|
@@ -365150,8 +365533,8 @@ var MemoryLimitOrderStore = class {
|
|
|
365150
365533
|
async reserve(id2, amount) {
|
|
365151
365534
|
const order = this.orders.get(id2);
|
|
365152
365535
|
if (!order || order.status !== "open") return false;
|
|
365536
|
+
if (BigInt(amount) > BigInt(order.remaining)) return false;
|
|
365153
365537
|
const reserved = BigInt(order.reserved) + BigInt(amount);
|
|
365154
|
-
if (reserved > BigInt(order.remaining)) return false;
|
|
365155
365538
|
this.patch(id2, { reserved: reserved.toString() });
|
|
365156
365539
|
return true;
|
|
365157
365540
|
}
|
|
@@ -365232,6 +365615,8 @@ var MAX_BLOCK_RANGE = 1000n;
|
|
|
365232
365615
|
var PUBLISH_CHUNK = 250;
|
|
365233
365616
|
var yieldToConsumers = () => new Promise((resolve11) => setImmediate(resolve11));
|
|
365234
365617
|
var STOP_DRAIN_TIMEOUT_MS = 5e3;
|
|
365618
|
+
var STALL_THRESHOLD_MS = 45e3;
|
|
365619
|
+
var STALL_REPORT_INTERVAL_MS = 6e4;
|
|
365235
365620
|
var ChainScanner = class {
|
|
365236
365621
|
constructor(target, loggers = defaultLoggerContext(), scanIntervalMs = DEFAULT_SCAN_INTERVAL_MS) {
|
|
365237
365622
|
this.target = target;
|
|
@@ -365245,6 +365630,18 @@ var ChainScanner = class {
|
|
|
365245
365630
|
this.errorHandler = () => {
|
|
365246
365631
|
};
|
|
365247
365632
|
this.stopped = false;
|
|
365633
|
+
/**
|
|
365634
|
+
* How far past the cursor the next pass reads, as `toBlock - fromBlock`:
|
|
365635
|
+
* halved after a failed read, doubled after a good one, between 0 (one block)
|
|
365636
|
+
* and {@link MAX_BLOCK_RANGE}.
|
|
365637
|
+
*
|
|
365638
|
+
* Free endpoints cap `eth_getLogs` ranges far below the full span — on
|
|
365639
|
+
* Arbitrum three of seven refused 100 blocks — and the cursor never moves
|
|
365640
|
+
* past a range it failed to read. At a fixed span a catch-up that outgrew
|
|
365641
|
+
* those caps was stuck for good: the range only grew, so the capped endpoints
|
|
365642
|
+
* never rejoined and the quorum never formed.
|
|
365643
|
+
*/
|
|
365644
|
+
this.span = MAX_BLOCK_RANGE;
|
|
365248
365645
|
this.logger = loggers.get("chain-scanner");
|
|
365249
365646
|
this.quorumClient = new QuorumPublicClient(target.chainId, target.rpcUrls, loggers);
|
|
365250
365647
|
if (this.quorumClient.size > 1) {
|
|
@@ -365287,8 +365684,9 @@ var ChainScanner = class {
|
|
|
365287
365684
|
if (this.timer || this.stopped) return;
|
|
365288
365685
|
this.logger.info({ chainId: this.target.chainId }, "Block scanner started");
|
|
365289
365686
|
this.timer = setInterval(() => {
|
|
365290
|
-
if (this.mutex.isLocked()) return;
|
|
365687
|
+
if (this.mutex.isLocked()) return this.reportStall();
|
|
365291
365688
|
void this.mutex.runExclusive(async () => {
|
|
365689
|
+
this.pass = { phase: "head", startedAt: Date.now(), reportedAt: 0 };
|
|
365292
365690
|
try {
|
|
365293
365691
|
await this.scan();
|
|
365294
365692
|
} catch (error) {
|
|
@@ -365302,10 +365700,66 @@ var ChainScanner = class {
|
|
|
365302
365700
|
"Error in block scanner"
|
|
365303
365701
|
);
|
|
365304
365702
|
this.errorHandler(error);
|
|
365703
|
+
} finally {
|
|
365704
|
+
this.notePassEnd();
|
|
365305
365705
|
}
|
|
365306
365706
|
});
|
|
365307
365707
|
}, this.scanIntervalMs);
|
|
365308
365708
|
}
|
|
365709
|
+
/**
|
|
365710
|
+
* Records which await the current pass is sitting on, for the watchdog.
|
|
365711
|
+
*
|
|
365712
|
+
* A no-op when no pass is registered — `scan()` is driven directly by tests
|
|
365713
|
+
* and by nothing else, so there is no watchdog to inform.
|
|
365714
|
+
*/
|
|
365715
|
+
enter(phase) {
|
|
365716
|
+
if (this.pass) this.pass.phase = phase;
|
|
365717
|
+
}
|
|
365718
|
+
/**
|
|
365719
|
+
* Says that a pass has outlived the quorum budgets and names the phase it is
|
|
365720
|
+
* stuck in, then repeats every {@link STALL_REPORT_INTERVAL_MS} until it ends.
|
|
365721
|
+
*
|
|
365722
|
+
* Observation only: the pass is left alone. Aborting it would need a cancel
|
|
365723
|
+
* path through the quorum client that does not exist, and the cursor is safe
|
|
365724
|
+
* either way — a pass that never completes never advances it.
|
|
365725
|
+
*/
|
|
365726
|
+
reportStall() {
|
|
365727
|
+
const pass = this.pass;
|
|
365728
|
+
if (!pass) return;
|
|
365729
|
+
const now = Date.now();
|
|
365730
|
+
const heldMs = now - pass.startedAt;
|
|
365731
|
+
if (heldMs < STALL_THRESHOLD_MS) return;
|
|
365732
|
+
if (pass.reportedAt !== 0 && now - pass.reportedAt < STALL_REPORT_INTERVAL_MS) return;
|
|
365733
|
+
pass.reportedAt = now;
|
|
365734
|
+
this.logger.warn(
|
|
365735
|
+
{
|
|
365736
|
+
chainId: this.target.chainId,
|
|
365737
|
+
phase: pass.phase,
|
|
365738
|
+
heldMs,
|
|
365739
|
+
cursor: this.cursor?.toString(),
|
|
365740
|
+
rpcUrls: this.target.rpcUrls
|
|
365741
|
+
},
|
|
365742
|
+
"Block scan pass has outlived its budget \u2014 this chain is not being scanned"
|
|
365743
|
+
);
|
|
365744
|
+
}
|
|
365745
|
+
/**
|
|
365746
|
+
* Closes out a pass, and says so if the watchdog complained about it — without
|
|
365747
|
+
* this the log shows a chain going quiet and never shows it coming back.
|
|
365748
|
+
*/
|
|
365749
|
+
notePassEnd() {
|
|
365750
|
+
const pass = this.pass;
|
|
365751
|
+
this.pass = void 0;
|
|
365752
|
+
if (!pass || pass.reportedAt === 0) return;
|
|
365753
|
+
this.logger.warn(
|
|
365754
|
+
{
|
|
365755
|
+
chainId: this.target.chainId,
|
|
365756
|
+
phase: pass.phase,
|
|
365757
|
+
heldMs: Date.now() - pass.startedAt,
|
|
365758
|
+
cursor: this.cursor?.toString()
|
|
365759
|
+
},
|
|
365760
|
+
"Block scan pass finished after outliving its budget \u2014 scanning has resumed"
|
|
365761
|
+
);
|
|
365762
|
+
}
|
|
365309
365763
|
/**
|
|
365310
365764
|
* Points this loop at different endpoints, keeping the cursor.
|
|
365311
365765
|
*
|
|
@@ -365347,11 +365801,12 @@ var ChainScanner = class {
|
|
|
365347
365801
|
}
|
|
365348
365802
|
if (currentBlock <= this.cursor) return;
|
|
365349
365803
|
const fromBlock = this.cursor + 1n;
|
|
365350
|
-
const toBlock = fromBlock +
|
|
365804
|
+
const toBlock = fromBlock + this.span > currentBlock ? currentBlock : fromBlock + this.span;
|
|
365351
365805
|
this.logger.debug(
|
|
365352
365806
|
{ chainId: this.target.chainId, fromBlock, toBlock, gap: Number(toBlock - fromBlock) },
|
|
365353
365807
|
"Scanning blocks"
|
|
365354
365808
|
);
|
|
365809
|
+
this.enter("logs");
|
|
365355
365810
|
let logs;
|
|
365356
365811
|
try {
|
|
365357
365812
|
logs = await retryPromise(
|
|
@@ -365373,6 +365828,7 @@ var ChainScanner = class {
|
|
|
365373
365828
|
);
|
|
365374
365829
|
} catch (error) {
|
|
365375
365830
|
if (isBlockRangeError(error)) return;
|
|
365831
|
+
this.narrow(toBlock - fromBlock);
|
|
365376
365832
|
throw error;
|
|
365377
365833
|
}
|
|
365378
365834
|
if (this.stopped) return;
|
|
@@ -365383,6 +365839,7 @@ var ChainScanner = class {
|
|
|
365383
365839
|
{ chainId: this.target.chainId, fromBlock, toBlock, eventCount: placed.length },
|
|
365384
365840
|
"Found OrderPlaced events in block scan"
|
|
365385
365841
|
);
|
|
365842
|
+
this.enter("publish-orders");
|
|
365386
365843
|
await this.publishOrders(placed);
|
|
365387
365844
|
}
|
|
365388
365845
|
if (filled.length > 0) {
|
|
@@ -365390,10 +365847,36 @@ var ChainScanner = class {
|
|
|
365390
365847
|
{ chainId: this.target.chainId, fromBlock, toBlock, eventCount: filled.length },
|
|
365391
365848
|
"Found OrderFilled events in block scan"
|
|
365392
365849
|
);
|
|
365850
|
+
this.enter("publish-fills");
|
|
365393
365851
|
await this.publishFills(filled);
|
|
365394
365852
|
}
|
|
365395
365853
|
if (this.stopped) return;
|
|
365396
365854
|
this.cursor = toBlock;
|
|
365855
|
+
this.widen();
|
|
365856
|
+
}
|
|
365857
|
+
/**
|
|
365858
|
+
* Halves the span below the range that just failed, so the next pass asks
|
|
365859
|
+
* for something a range-capped endpoint will answer. Halving the attempted
|
|
365860
|
+
* range rather than the span matters near the head, where a pass reads fewer
|
|
365861
|
+
* blocks than the span allows.
|
|
365862
|
+
*/
|
|
365863
|
+
narrow(attempted) {
|
|
365864
|
+
const next = attempted / 2n;
|
|
365865
|
+
if (next >= this.span) return;
|
|
365866
|
+
this.span = next;
|
|
365867
|
+
this.logger.warn(
|
|
365868
|
+
{ chainId: this.target.chainId, span: Number(next) },
|
|
365869
|
+
"Narrowing the block scan range after a failed read"
|
|
365870
|
+
);
|
|
365871
|
+
}
|
|
365872
|
+
/** Doubles the span back toward {@link MAX_BLOCK_RANGE} after a good read. */
|
|
365873
|
+
widen() {
|
|
365874
|
+
if (this.span >= MAX_BLOCK_RANGE) return;
|
|
365875
|
+
const next = this.span === 0n ? 1n : this.span * 2n;
|
|
365876
|
+
this.span = next > MAX_BLOCK_RANGE ? MAX_BLOCK_RANGE : next;
|
|
365877
|
+
if (this.span === MAX_BLOCK_RANGE) {
|
|
365878
|
+
this.logger.info({ chainId: this.target.chainId }, "Block scan range back to full");
|
|
365879
|
+
}
|
|
365397
365880
|
}
|
|
365398
365881
|
async publishOrders(logs) {
|
|
365399
365882
|
const rebuilt = reconstructOrdersFromLogs(logs, {
|
|
@@ -365762,7 +366245,7 @@ var LimitOrderController = class {
|
|
|
365762
366245
|
]);
|
|
365763
366246
|
return { order, fills, bids };
|
|
365764
366247
|
}
|
|
365765
|
-
/** The pairs the orderbook lists,
|
|
366248
|
+
/** The pairs the orderbook lists, the smallest payout each token may carry, and its tokens per chain. */
|
|
365766
366249
|
books() {
|
|
365767
366250
|
return this.service.books();
|
|
365768
366251
|
}
|
|
@@ -365810,10 +366293,7 @@ var PairController = class {
|
|
|
365810
366293
|
* the pair's symbols have to resolve before the market can be hydrated.
|
|
365811
366294
|
*/
|
|
365812
366295
|
async add(pair, options) {
|
|
365813
|
-
const { engine,
|
|
365814
|
-
if (!engine || !tradingPairs) {
|
|
365815
|
-
throw new Error("No trading engine is running \u2014 this filler was started without pairs");
|
|
365816
|
-
}
|
|
366296
|
+
const { engine, assetRegistry, adminStrategies, balanceTokens, config: config5 } = this.runtime;
|
|
365817
366297
|
const assets = options?.assets;
|
|
365818
366298
|
const nextAssets = { ...config5.assets ?? {}, ...assets ?? {} };
|
|
365819
366299
|
const nextPairs = [...this.pairs, pair];
|
|
@@ -365852,7 +366332,6 @@ var PairController = class {
|
|
|
365852
366332
|
/** Closes a market. Orders already in flight against it still complete. */
|
|
365853
366333
|
async remove(index3) {
|
|
365854
366334
|
const { engine, tradingPairs, adminStrategies, config: config5 } = this.runtime;
|
|
365855
|
-
if (!engine || !tradingPairs) throw new Error("No trading engine is running");
|
|
365856
366335
|
if (index3 < 0 || index3 >= this.pairs.length) throw new Error(`Unknown pair ${index3}`);
|
|
365857
366336
|
engine.removePair(tradingPairs[index3]);
|
|
365858
366337
|
config5.pairs = this.pairs.filter((_5, i6) => i6 !== index3);
|
|
@@ -365864,7 +366343,7 @@ var PairController = class {
|
|
|
365864
366343
|
await this.persist();
|
|
365865
366344
|
}
|
|
365866
366345
|
livePair(index3) {
|
|
365867
|
-
const pair = this.runtime.tradingPairs
|
|
366346
|
+
const pair = this.runtime.tradingPairs[index3];
|
|
365868
366347
|
if (!pair) throw new Error(`Unknown pair ${index3}`);
|
|
365869
366348
|
return pair;
|
|
365870
366349
|
}
|
|
@@ -365956,9 +366435,9 @@ var ChainController = class {
|
|
|
365956
366435
|
throw error;
|
|
365957
366436
|
}
|
|
365958
366437
|
const curve = confirmationPolicies[String(chainId)];
|
|
365959
|
-
if (curve) this.runtime.confirmationPolicy
|
|
365960
|
-
else if (!this.runtime.confirmationPolicy
|
|
365961
|
-
this.runtime.confirmationPolicy
|
|
366438
|
+
if (curve) this.runtime.confirmationPolicy.add(chainId, curve);
|
|
366439
|
+
else if (!this.runtime.confirmationPolicy.has(chainId)) {
|
|
366440
|
+
this.runtime.confirmationPolicy.adopt(chainId, resolvedPolicy);
|
|
365962
366441
|
}
|
|
365963
366442
|
this.runtime.resolvedChains.push(resolved);
|
|
365964
366443
|
config5.chains = [...config5.chains, { rpcUrls: chain2.rpcUrls, bundlerUrl: chain2.bundlerUrl }];
|
|
@@ -365986,7 +366465,7 @@ var ChainController = class {
|
|
|
365986
366465
|
await intentFiller.removeChain(chainId);
|
|
365987
366466
|
if (this.ownsScanner) await this.scanner.removeChain(chainId);
|
|
365988
366467
|
configService.removeChain(chainId);
|
|
365989
|
-
this.runtime.confirmationPolicy
|
|
366468
|
+
this.runtime.confirmationPolicy.remove(chainId);
|
|
365990
366469
|
this.runtime.chainClientManager.invalidate(chainKey);
|
|
365991
366470
|
this.runtime.resolvedChains.splice(index3, 1);
|
|
365992
366471
|
config5.chains = config5.chains.filter((_5, i6) => i6 !== index3);
|
|
@@ -367022,8 +367501,8 @@ var SqliteLimitOrderStore = class {
|
|
|
367022
367501
|
async reserve(id2, amount) {
|
|
367023
367502
|
const order = this.read(id2);
|
|
367024
367503
|
if (!order || order.status !== "open") return false;
|
|
367504
|
+
if (BigInt(amount) > BigInt(order.remaining)) return false;
|
|
367025
367505
|
const reserved = BigInt(order.reserved) + BigInt(amount);
|
|
367026
|
-
if (reserved > BigInt(order.remaining)) return false;
|
|
367027
367506
|
const result = this.db.prepare(`
|
|
367028
367507
|
UPDATE limit_orders SET reserved = ?, updated_at = datetime('now')
|
|
367029
367508
|
WHERE id = ? AND reserved = ? AND status = 'open'
|