@hyperbridge/simplex 0.16.11 → 0.16.13
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 +1134 -182
- package/dist/bin/simplex.js.map +1 -1
- package/dist/index.cjs +873 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +214 -13
- package/dist/index.d.ts +214 -13
- package/dist/index.js +873 -80
- package/dist/index.js.map +1 -1
- package/dist/sqlite.cjs +59 -3
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.d.cts +21 -2
- package/dist/sqlite.d.ts +21 -2
- package/dist/sqlite.js +58 -3
- package/dist/sqlite.js.map +1 -1
- package/dist/{types-B5zkFhxR.d.cts → types-BISgqJhM.d.cts} +57 -1
- package/dist/{types-B5zkFhxR.d.ts → types-BISgqJhM.d.ts} +57 -1
- package/dist/ui/assets/Novatica-Medium-CjNgGPEL.ttf +0 -0
- package/dist/ui/assets/index-CK8E6aPx.css +1 -0
- package/dist/ui/assets/index-DShjZe_c.js +106 -0
- package/dist/ui/index.html +2 -2
- package/package.json +5 -4
- package/dist/ui/assets/index-B_p2oQkc.css +0 -1
- package/dist/ui/assets/index-CD2NZXpG.js +0 -106
package/dist/bin/simplex.js
CHANGED
|
@@ -29007,17 +29007,17 @@ function cosh(x4) {
|
|
|
29007
29007
|
}
|
|
29008
29008
|
function clone(obj) {
|
|
29009
29009
|
var i6, p3, ps;
|
|
29010
|
-
function
|
|
29010
|
+
function Decimal3(v7) {
|
|
29011
29011
|
var e4, i7, t6, x4 = this;
|
|
29012
|
-
if (!(x4 instanceof
|
|
29013
|
-
x4.constructor =
|
|
29012
|
+
if (!(x4 instanceof Decimal3)) return new Decimal3(v7);
|
|
29013
|
+
x4.constructor = Decimal3;
|
|
29014
29014
|
if (isDecimalInstance(v7)) {
|
|
29015
29015
|
x4.s = v7.s;
|
|
29016
29016
|
if (external) {
|
|
29017
|
-
if (!v7.d || v7.e >
|
|
29017
|
+
if (!v7.d || v7.e > Decimal3.maxE) {
|
|
29018
29018
|
x4.e = NaN;
|
|
29019
29019
|
x4.d = null;
|
|
29020
|
-
} else if (v7.e <
|
|
29020
|
+
} else if (v7.e < Decimal3.minE) {
|
|
29021
29021
|
x4.e = 0;
|
|
29022
29022
|
x4.d = [0];
|
|
29023
29023
|
} else {
|
|
@@ -29047,10 +29047,10 @@ function clone(obj) {
|
|
|
29047
29047
|
if (v7 === ~~v7 && v7 < 1e7) {
|
|
29048
29048
|
for (e4 = 0, i7 = v7; i7 >= 10; i7 /= 10) e4++;
|
|
29049
29049
|
if (external) {
|
|
29050
|
-
if (e4 >
|
|
29050
|
+
if (e4 > Decimal3.maxE) {
|
|
29051
29051
|
x4.e = NaN;
|
|
29052
29052
|
x4.d = null;
|
|
29053
|
-
} else if (e4 <
|
|
29053
|
+
} else if (e4 < Decimal3.minE) {
|
|
29054
29054
|
x4.e = 0;
|
|
29055
29055
|
x4.d = [0];
|
|
29056
29056
|
} else {
|
|
@@ -29092,58 +29092,58 @@ function clone(obj) {
|
|
|
29092
29092
|
}
|
|
29093
29093
|
throw Error(invalidArgument + v7);
|
|
29094
29094
|
}
|
|
29095
|
-
|
|
29096
|
-
|
|
29097
|
-
|
|
29098
|
-
|
|
29099
|
-
|
|
29100
|
-
|
|
29101
|
-
|
|
29102
|
-
|
|
29103
|
-
|
|
29104
|
-
|
|
29105
|
-
|
|
29106
|
-
|
|
29107
|
-
|
|
29108
|
-
|
|
29109
|
-
|
|
29110
|
-
|
|
29111
|
-
|
|
29112
|
-
|
|
29113
|
-
|
|
29114
|
-
|
|
29115
|
-
|
|
29116
|
-
|
|
29117
|
-
|
|
29118
|
-
|
|
29119
|
-
|
|
29120
|
-
|
|
29121
|
-
|
|
29122
|
-
|
|
29123
|
-
|
|
29124
|
-
|
|
29125
|
-
|
|
29126
|
-
|
|
29127
|
-
|
|
29128
|
-
|
|
29129
|
-
|
|
29130
|
-
|
|
29131
|
-
|
|
29132
|
-
|
|
29133
|
-
|
|
29134
|
-
|
|
29135
|
-
|
|
29136
|
-
|
|
29137
|
-
|
|
29138
|
-
|
|
29139
|
-
|
|
29140
|
-
|
|
29141
|
-
|
|
29142
|
-
|
|
29143
|
-
|
|
29144
|
-
|
|
29145
|
-
|
|
29146
|
-
|
|
29095
|
+
Decimal3.prototype = P;
|
|
29096
|
+
Decimal3.ROUND_UP = 0;
|
|
29097
|
+
Decimal3.ROUND_DOWN = 1;
|
|
29098
|
+
Decimal3.ROUND_CEIL = 2;
|
|
29099
|
+
Decimal3.ROUND_FLOOR = 3;
|
|
29100
|
+
Decimal3.ROUND_HALF_UP = 4;
|
|
29101
|
+
Decimal3.ROUND_HALF_DOWN = 5;
|
|
29102
|
+
Decimal3.ROUND_HALF_EVEN = 6;
|
|
29103
|
+
Decimal3.ROUND_HALF_CEIL = 7;
|
|
29104
|
+
Decimal3.ROUND_HALF_FLOOR = 8;
|
|
29105
|
+
Decimal3.EUCLID = 9;
|
|
29106
|
+
Decimal3.config = Decimal3.set = config;
|
|
29107
|
+
Decimal3.clone = clone;
|
|
29108
|
+
Decimal3.isDecimal = isDecimalInstance;
|
|
29109
|
+
Decimal3.abs = abs;
|
|
29110
|
+
Decimal3.acos = acos;
|
|
29111
|
+
Decimal3.acosh = acosh;
|
|
29112
|
+
Decimal3.add = add2;
|
|
29113
|
+
Decimal3.asin = asin;
|
|
29114
|
+
Decimal3.asinh = asinh;
|
|
29115
|
+
Decimal3.atan = atan;
|
|
29116
|
+
Decimal3.atanh = atanh;
|
|
29117
|
+
Decimal3.atan2 = atan2;
|
|
29118
|
+
Decimal3.cbrt = cbrt;
|
|
29119
|
+
Decimal3.ceil = ceil;
|
|
29120
|
+
Decimal3.clamp = clamp;
|
|
29121
|
+
Decimal3.cos = cos;
|
|
29122
|
+
Decimal3.cosh = cosh;
|
|
29123
|
+
Decimal3.div = div;
|
|
29124
|
+
Decimal3.exp = exp;
|
|
29125
|
+
Decimal3.floor = floor;
|
|
29126
|
+
Decimal3.hypot = hypot;
|
|
29127
|
+
Decimal3.ln = ln;
|
|
29128
|
+
Decimal3.log = log;
|
|
29129
|
+
Decimal3.log10 = log10;
|
|
29130
|
+
Decimal3.log2 = log2;
|
|
29131
|
+
Decimal3.max = max;
|
|
29132
|
+
Decimal3.min = min;
|
|
29133
|
+
Decimal3.mod = mod3;
|
|
29134
|
+
Decimal3.mul = mul;
|
|
29135
|
+
Decimal3.pow = pow;
|
|
29136
|
+
Decimal3.random = random;
|
|
29137
|
+
Decimal3.round = round;
|
|
29138
|
+
Decimal3.sign = sign;
|
|
29139
|
+
Decimal3.sin = sin;
|
|
29140
|
+
Decimal3.sinh = sinh;
|
|
29141
|
+
Decimal3.sqrt = sqrt;
|
|
29142
|
+
Decimal3.sub = sub;
|
|
29143
|
+
Decimal3.sum = sum;
|
|
29144
|
+
Decimal3.tan = tan;
|
|
29145
|
+
Decimal3.tanh = tanh;
|
|
29146
|
+
Decimal3.trunc = trunc;
|
|
29147
29147
|
if (obj === void 0) obj = {};
|
|
29148
29148
|
if (obj) {
|
|
29149
29149
|
if (obj.defaults !== true) {
|
|
@@ -29151,8 +29151,8 @@ function clone(obj) {
|
|
|
29151
29151
|
for (i6 = 0; i6 < ps.length; ) if (!obj.hasOwnProperty(p3 = ps[i6++])) obj[p3] = this[p3];
|
|
29152
29152
|
}
|
|
29153
29153
|
}
|
|
29154
|
-
|
|
29155
|
-
return
|
|
29154
|
+
Decimal3.config(obj);
|
|
29155
|
+
return Decimal3;
|
|
29156
29156
|
}
|
|
29157
29157
|
function div(x4, y5) {
|
|
29158
29158
|
return new this(x4).div(y5);
|
|
@@ -48802,6 +48802,7 @@ var init_esm2 = __esm({
|
|
|
48802
48802
|
init_encodeFunctionData2();
|
|
48803
48803
|
init_encodePacked2();
|
|
48804
48804
|
init_parseEventLogs2();
|
|
48805
|
+
init_isAddress2();
|
|
48805
48806
|
init_defineChain2();
|
|
48806
48807
|
init_concat2();
|
|
48807
48808
|
init_isHex2();
|
|
@@ -51068,7 +51069,7 @@ var require_bn = __commonJS({
|
|
|
51068
51069
|
}
|
|
51069
51070
|
return this;
|
|
51070
51071
|
};
|
|
51071
|
-
BN3.prototype.add = function
|
|
51072
|
+
BN3.prototype.add = function add4(num2) {
|
|
51072
51073
|
var res;
|
|
51073
51074
|
if (num2.negative !== 0 && this.negative === 0) {
|
|
51074
51075
|
num2.negative = 0;
|
|
@@ -52905,7 +52906,7 @@ var require_bn = __commonJS({
|
|
|
52905
52906
|
}
|
|
52906
52907
|
return this.m.sub(a6)._forceRed(this);
|
|
52907
52908
|
};
|
|
52908
|
-
Red.prototype.add = function
|
|
52909
|
+
Red.prototype.add = function add4(a6, b5) {
|
|
52909
52910
|
this._verify2(a6, b5);
|
|
52910
52911
|
var res = a6.add(b5);
|
|
52911
52912
|
if (res.cmp(this.m) >= 0) {
|
|
@@ -55785,10 +55786,10 @@ var init_fflate = __esm({
|
|
|
55785
55786
|
lm = void 0;
|
|
55786
55787
|
break;
|
|
55787
55788
|
} else {
|
|
55788
|
-
let
|
|
55789
|
+
let add4 = sym - 254;
|
|
55789
55790
|
if (sym > 264) {
|
|
55790
55791
|
const i6 = sym - 257, b5 = fleb[i6];
|
|
55791
|
-
|
|
55792
|
+
add4 = bits(dat, pos, (1 << b5) - 1) + fl[i6];
|
|
55792
55793
|
pos += b5;
|
|
55793
55794
|
}
|
|
55794
55795
|
const d5 = dm[bits16(dat, pos) & dms], dsym = d5 >>> 4;
|
|
@@ -55804,7 +55805,7 @@ var init_fflate = __esm({
|
|
|
55804
55805
|
throw "unexpected EOF";
|
|
55805
55806
|
if (noBuf)
|
|
55806
55807
|
cbuf(bt + 131072);
|
|
55807
|
-
const end = bt +
|
|
55808
|
+
const end = bt + add4;
|
|
55808
55809
|
for (; bt < end; bt += 4) {
|
|
55809
55810
|
buf[bt] = buf[bt - dt];
|
|
55810
55811
|
buf[bt + 1] = buf[bt + 1 - dt];
|
|
@@ -83508,15 +83509,15 @@ var require_fromEvent = __commonJS({
|
|
|
83508
83509
|
return function(handler) {
|
|
83509
83510
|
return target[methodName](eventName, handler, options);
|
|
83510
83511
|
};
|
|
83511
|
-
}) : isNodeStyleEventEmitter(target) ? nodeEventEmitterMethods.map(toCommonHandlerRegistry(target, eventName)) : isJQueryStyleEventEmitter(target) ? jqueryMethods.map(toCommonHandlerRegistry(target, eventName)) : [], 2),
|
|
83512
|
-
if (!
|
|
83512
|
+
}) : isNodeStyleEventEmitter(target) ? nodeEventEmitterMethods.map(toCommonHandlerRegistry(target, eventName)) : isJQueryStyleEventEmitter(target) ? jqueryMethods.map(toCommonHandlerRegistry(target, eventName)) : [], 2), add4 = _a10[0], remove = _a10[1];
|
|
83513
|
+
if (!add4) {
|
|
83513
83514
|
if (isArrayLike_1.isArrayLike(target)) {
|
|
83514
83515
|
return mergeMap_1.mergeMap(function(subTarget) {
|
|
83515
83516
|
return fromEvent(subTarget, eventName, options);
|
|
83516
83517
|
})(innerFrom_1.innerFrom(target));
|
|
83517
83518
|
}
|
|
83518
83519
|
}
|
|
83519
|
-
if (!
|
|
83520
|
+
if (!add4) {
|
|
83520
83521
|
throw new TypeError("Invalid event target");
|
|
83521
83522
|
}
|
|
83522
83523
|
return new Observable_1.Observable(function(subscriber) {
|
|
@@ -83527,7 +83528,7 @@ var require_fromEvent = __commonJS({
|
|
|
83527
83528
|
}
|
|
83528
83529
|
return subscriber.next(1 < args.length ? args : args[0]);
|
|
83529
83530
|
};
|
|
83530
|
-
|
|
83531
|
+
add4(handler);
|
|
83531
83532
|
return function() {
|
|
83532
83533
|
return remove(handler);
|
|
83533
83534
|
};
|
|
@@ -233929,8 +233930,8 @@ function addToExternrefTable0(obj) {
|
|
|
233929
233930
|
function passArrayJsValueToWasm0(array, malloc) {
|
|
233930
233931
|
const ptr = malloc(array.length * 4, 4) >>> 0;
|
|
233931
233932
|
for (let i6 = 0; i6 < array.length; i6++) {
|
|
233932
|
-
const
|
|
233933
|
-
getDataViewMemory0().setUint32(ptr + 4 * i6,
|
|
233933
|
+
const add4 = addToExternrefTable0(array[i6]);
|
|
233934
|
+
getDataViewMemory0().setUint32(ptr + 4 * i6, add4, true);
|
|
233934
233935
|
}
|
|
233935
233936
|
WASM_VECTOR_LEN = array.length;
|
|
233936
233937
|
return ptr;
|
|
@@ -235360,7 +235361,7 @@ function resolveOrderFeeGasPriceBump(sourceStateMachineId, isSameChain) {
|
|
|
235360
235361
|
if (isSameChain) {
|
|
235361
235362
|
return 0n;
|
|
235362
235363
|
}
|
|
235363
|
-
return
|
|
235364
|
+
return sourceStateMachineId === "EVM-1" ? ETHEREUM_ORDER_FEE_GAS_PRICE_BUMP_PERCENT : DEFAULT_ORDER_FEE_GAS_PRICE_BUMP_PERCENT;
|
|
235364
235365
|
}
|
|
235365
235366
|
function utf8Encode(text2) {
|
|
235366
235367
|
const bytes5 = [];
|
|
@@ -235421,7 +235422,7 @@ function encodePhantomBidDeclaration(declaration) {
|
|
|
235421
235422
|
}
|
|
235422
235423
|
return u8aToHex(new Uint8Array(bytes5));
|
|
235423
235424
|
}
|
|
235424
|
-
var import_merge_race, __defProp3, __getOwnPropNames2, __esm2, __export2, node_exports, wasm, full_path, __dirname$1, cachedTextDecoder, cachedUint8ArrayMemory0, WASM_VECTOR_LEN, cachedTextEncoder, encodeString5, cachedDataViewMemory0, KeccakMergeFinalization, KeccakMerge, wasmPath, wasmBytes2, bindings, wasmModule, wasmInstance, __wasm, init_node11, RequestStatus, TimeoutStatus, IntentOrderStatus, ABI, evmHost_default, ABI2, handlerV2_default, polkadotAssetHubPaseo, polkadotHubMainnet, pharosMainnet, pharosAtlantic, tronNile, chainConfigs, configsByStateMachineId, getConfigByStateMachineId, getChainId3, getViemChain, hyperbridgeAddress, ABI3, IntentGatewayV2_default, ChainConfigService, ABI4, uniswapRouterV2_default, chains, DEFAULT_ADDRESS, EvmChain, REQUEST_COMMITMENTS_SLOT, RESPONSE_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, STATE_COMMITMENTS_SLOT, MISSING_CONSENSUS_UPDATE_TIME_MESSAGE, MissingConsensusUpdateTimeError, TokenBucket, BATCHES_NOT_SUPPORTED_CODE, TOO_BIG_BATCH_REQUEST_CODE, DEFAULT_MAX_BATCH_SIZE, _endpoint2, _headers3, _limiter, _maxBatchSize, _batchingSupported, _pending2, _flushTimer, _flushing, _nextId, __BatchingHttpProvider_instances, scheduleFlush_fn, flushNow_fn, flush_fn, post_fn, settleBatch_fn, settle_fn, handleBatchRefusal_fn, requeue_fn, _a5, BatchingHttpProvider, OFFCHAIN_BID_PREFIX, HYPERBRIDGE_TYPES_BUNDLE, BASE_TIP, HTTP_CONNECT_TIMEOUT_MS, INCLUSION_TIMEOUT_MS, DEFAULT_RPC_MAX_RPS, rpcLimiters, BidCodec, PackedUserOperationCodec, IntentsCoprocessor, ReviveContractInfo, ReviveAccountType, ReviveAccountInfo, H256, EvmStateProof, SubstrateHashing, SubstrateStateMachineProof, BasicProof, LeafIndexAndPos, MmrProof, ConsensusStateId, ConsensusMessage, FraudProofMessage, StateMachine, StateMachineId, StateMachineHeight, Proof, PostRequest, PostResponse, GetRequest, StorageValue, GetResponse, Request3, Response2, RequestMessage, RequestResponse, ResponseMessage, TimeoutMessage, GetRequestsWithProof, Message, DEFAULT_CHILD_STORAGE_PREFIX, PharosProofNodeCodec, SiblingLeftmostLeafProofCodec, NonExistenceProofCodec, AccountProofDataCodec, PharosStateProof, DEFAULT_POLL_INTERVAL, ADDRESS_ZERO2, DEFAULT_GRAFFITI, DEFAULT_LOGGER, REQUEST_STATUS_WEIGHTS, TIMEOUT_STATUS_WEIGHTS, COMBINED_STATUS_WEIGHTS, CHAIN_ID_TO_COINGECKO_NATIVE, TESTNET_CHAINS, ORDER_STATUS, loadDriver, detectEnvironment, STORAGE_KEYS, LEGACY_STORAGE_KEYS, ABI5, uniswapV3Quoter_default, UNISWAP_V4_QUOTER_ABI, ABI6, universalRouter_default, PERMIT2_ABI, UniswapQuoteEngine, COMMON_FEE_TIERS, Swap, ABI7, erc7281_default, DEFAULT_GRAFFITI2, ERC7821_BATCH_MODE, BundlerMethod, SELECT_SOLVER_TYPEHASH, PACKED_USEROP_TYPEHASH, DOMAIN_TYPEHASH, CryptoUtils, FEE_TOKEN_CACHE_TTL_MS, OrderPlacer, TOKEN_KEYED_GATEWAY_ABI, keyingByClient, PARTIAL_FILLS_SLOT, USED_USEROPS_STORAGE_KEY, OrderExecutor, _a6, OrderCanceller, FILL_ORDER_SELECTOR, SUPPORTED_INTENTS_VERSION, CONTRACT_VERSION_ABI, CANONICAL_EVM_TOKEN, ENTRY_POINT_EVENT_ABI, BidImpl, BidManager, RELAYER_MESSAGE_GAS, NO_BUNDLER_FILL_GAS_BASE, NO_BUNDLER_FILL_GAS_PER_OUTPUT, NO_BUNDLER_PAYMASTER_VERIFICATION_GAS, NO_BUNDLER_PAYMASTER_POST_OP_GAS, BID_PVG_ESTIMATION_ACCOUNT_CODE, SELECTED_BID_SIGNATURE_BYTES, BID_PVG_HEADROOM_PERCENT, ESCROW_MAPPING_SLOT, GasEstimator, OrderStatusChecker, ORDERBOOK_URLS, ORDERBOOK_DECIMALS, ORDERBOOK_SCALE, OrderbookRequestError, RATE_FIELDS, TOP_OF_BOOK_QUERY, ROUTE_LIQUIDITY_QUERY, QUOTE_QUERY, QUOTE_PESSIMISTIC_QUERY, HyperFxOrderbook, UnsupportedLiquidityAssetError, UnsupportedLiquidityChainError, OrderbookQuoteNotConvergedError, MAX_EXACT_OUTPUT_ROUNDS, OrderbookMarket,
|
|
235425
|
+
var import_merge_race, __defProp3, __getOwnPropNames2, __esm2, __export2, node_exports, wasm, full_path, __dirname$1, cachedTextDecoder, cachedUint8ArrayMemory0, WASM_VECTOR_LEN, cachedTextEncoder, encodeString5, cachedDataViewMemory0, KeccakMergeFinalization, KeccakMerge, wasmPath, wasmBytes2, bindings, wasmModule, wasmInstance, __wasm, init_node11, RequestStatus, TimeoutStatus, IntentOrderStatus, ABI, evmHost_default, ABI2, handlerV2_default, polkadotAssetHubPaseo, polkadotHubMainnet, pharosMainnet, pharosAtlantic, tronNile, chainConfigs, configsByStateMachineId, getConfigByStateMachineId, getChainId3, getViemChain, hyperbridgeAddress, ABI3, IntentGatewayV2_default, ChainConfigService, ABI4, uniswapRouterV2_default, chains, DEFAULT_ADDRESS, EvmChain, REQUEST_COMMITMENTS_SLOT, RESPONSE_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, STATE_COMMITMENTS_SLOT, MISSING_CONSENSUS_UPDATE_TIME_MESSAGE, MissingConsensusUpdateTimeError, TokenBucket, BATCHES_NOT_SUPPORTED_CODE, TOO_BIG_BATCH_REQUEST_CODE, DEFAULT_MAX_BATCH_SIZE, _endpoint2, _headers3, _limiter, _maxBatchSize, _batchingSupported, _pending2, _flushTimer, _flushing, _nextId, __BatchingHttpProvider_instances, scheduleFlush_fn, flushNow_fn, flush_fn, post_fn, settleBatch_fn, settle_fn, handleBatchRefusal_fn, requeue_fn, _a5, BatchingHttpProvider, OFFCHAIN_BID_PREFIX, HYPERBRIDGE_TYPES_BUNDLE, BASE_TIP, HTTP_CONNECT_TIMEOUT_MS, INCLUSION_TIMEOUT_MS, DEFAULT_RPC_MAX_RPS, rpcLimiters, BidCodec, PackedUserOperationCodec, IntentsCoprocessor, ReviveContractInfo, ReviveAccountType, ReviveAccountInfo, H256, EvmStateProof, SubstrateHashing, SubstrateStateMachineProof, BasicProof, LeafIndexAndPos, MmrProof, ConsensusStateId, ConsensusMessage, FraudProofMessage, StateMachine, StateMachineId, StateMachineHeight, Proof, PostRequest, PostResponse, GetRequest, StorageValue, GetResponse, Request3, Response2, RequestMessage, RequestResponse, ResponseMessage, TimeoutMessage, GetRequestsWithProof, Message, DEFAULT_CHILD_STORAGE_PREFIX, PharosProofNodeCodec, SiblingLeftmostLeafProofCodec, NonExistenceProofCodec, AccountProofDataCodec, PharosStateProof, DEFAULT_POLL_INTERVAL, ADDRESS_ZERO2, DEFAULT_GRAFFITI, DEFAULT_LOGGER, REQUEST_STATUS_WEIGHTS, TIMEOUT_STATUS_WEIGHTS, COMBINED_STATUS_WEIGHTS, CHAIN_ID_TO_COINGECKO_NATIVE, TESTNET_CHAINS, ORDER_STATUS, loadDriver, detectEnvironment, STORAGE_KEYS, LEGACY_STORAGE_KEYS, ABI5, uniswapV3Quoter_default, UNISWAP_V4_QUOTER_ABI, ABI6, universalRouter_default, PERMIT2_ABI, UniswapQuoteEngine, COMMON_FEE_TIERS, Swap, ABI7, erc7281_default, DEFAULT_GRAFFITI2, ERC7821_BATCH_MODE, BundlerMethod, SELECT_SOLVER_TYPEHASH, PACKED_USEROP_TYPEHASH, DOMAIN_TYPEHASH, CryptoUtils, FEE_TOKEN_CACHE_TTL_MS, OrderPlacer, TOKEN_KEYED_GATEWAY_ABI, keyingByClient, PARTIAL_FILLS_SLOT, USED_USEROPS_STORAGE_KEY, OrderExecutor, _a6, OrderCanceller, FILL_ORDER_SELECTOR, SUPPORTED_INTENTS_VERSION, CONTRACT_VERSION_ABI, CANONICAL_EVM_TOKEN, ENTRY_POINT_EVENT_ABI, BidImpl, BidManager, RELAYER_MESSAGE_GAS, NO_BUNDLER_FILL_GAS_BASE, NO_BUNDLER_FILL_GAS_PER_OUTPUT, NO_BUNDLER_PAYMASTER_VERIFICATION_GAS, NO_BUNDLER_PAYMASTER_POST_OP_GAS, BID_PVG_ESTIMATION_ACCOUNT_CODE, SELECTED_BID_SIGNATURE_BYTES, BID_PVG_HEADROOM_PERCENT, ESCROW_MAPPING_SLOT, GasEstimator, OrderStatusChecker, ORDERBOOK_URLS, ORDERBOOK_DECIMALS, ORDERBOOK_SCALE, OrderbookRequestError, RATE_FIELDS, TOP_OF_BOOK_QUERY, ROUTE_LIQUIDITY_QUERY, QUOTE_QUERY, QUOTE_PESSIMISTIC_QUERY, HyperFxOrderbook, UnsupportedLiquidityAssetError, UnsupportedLiquidityChainError, OrderbookQuoteNotConvergedError, MAX_EXACT_OUTPUT_ROUNDS, OrderbookMarket, ETHEREUM_ORDER_FEE_GAS_PRICE_BUMP_PERCENT, DEFAULT_ORDER_FEE_GAS_PRICE_BUMP_PERCENT, IntentGateway, DECLARATION_V1, DECLARATION_V2, PAYMASTER_ADDRESS_BYTES, PAYMASTER_GAS_LIMIT_BYTES, PAYMASTER_DATA_OFFSET, PERMIT2_DATA_BYTES, PERMIT2_SPONSORSHIP_BYTES, MAX_DECLARED_ENTRIES, MAX_TOKEN_ID_BYTES, TeleportParams, MultiAccount;
|
|
235425
235426
|
var init_node10 = __esm({
|
|
235426
235427
|
"../sdk/dist/node/index.js"() {
|
|
235427
235428
|
"use strict";
|
|
@@ -247567,9 +247568,17 @@ query OrderStatus($commitment: String!) {
|
|
|
247567
247568
|
* order. Frontends can use `relayerFee` to approve the ERC-20 spend before
|
|
247568
247569
|
* submitting the cancel transaction.
|
|
247569
247570
|
*
|
|
247571
|
+
* A cross-chain cancel is paid on the chain that receives the cancel
|
|
247572
|
+
* transaction: the source chain for the source route, the destination chain
|
|
247573
|
+
* for the destination route. When that chain is a testnet, the quote has no
|
|
247574
|
+
* native value, since testnet hosts have no router to swap it into the fee
|
|
247575
|
+
* token. The caller must first approve `relayerFee` of that host's fee token
|
|
247576
|
+
* to that chain's IntentGateway.
|
|
247577
|
+
*
|
|
247570
247578
|
* @param order - The order to quote.
|
|
247571
247579
|
* @param options - Choose the initiation side. Defaults to source-side cancellation.
|
|
247572
|
-
* @returns `{ nativeValue }` — native token amount (wei) to send as `value
|
|
247580
|
+
* @returns `{ nativeValue }` — native token amount (wei) to send as `value`,
|
|
247581
|
+
* or `0n` when the relayer fee must be paid in the fee token;
|
|
247573
247582
|
* `{ relayerFee }` — relayer incentive denominated in the chain's fee token.
|
|
247574
247583
|
*/
|
|
247575
247584
|
async quoteCancelOrder(order, options = {}) {
|
|
@@ -247583,11 +247592,12 @@ query OrderStatus($commitment: String!) {
|
|
|
247583
247592
|
*
|
|
247584
247593
|
* Constructs the ISMP GET request the source gateway will dispatch, one
|
|
247585
247594
|
* `_partialFills` key per leg, and calls `quoteNative` on the source host to
|
|
247586
|
-
* obtain the dispatch fee.
|
|
247595
|
+
* obtain the dispatch fee. Returns a zero `nativeValue` when the source is a
|
|
247596
|
+
* testnet chain, leaving the relayer fee to be paid in its fee token.
|
|
247587
247597
|
* Returns 0 for same-chain orders (no ISMP call needed).
|
|
247588
247598
|
*
|
|
247589
247599
|
* @param order - The order to quote.
|
|
247590
|
-
* @returns The native token dispatch fee in wei.
|
|
247600
|
+
* @returns The native token dispatch fee in wei and the relayer fee.
|
|
247591
247601
|
*/
|
|
247592
247602
|
async quoteCancelFromSource(order) {
|
|
247593
247603
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
@@ -247595,6 +247605,14 @@ query OrderStatus($commitment: String!) {
|
|
|
247595
247605
|
if (sourceStateMachine === destStateMachine) {
|
|
247596
247606
|
return { nativeValue: 0n, relayerFee: 0n };
|
|
247597
247607
|
}
|
|
247608
|
+
const feeInSourceFeeToken = await convertGasToFeeToken(
|
|
247609
|
+
this.ctx,
|
|
247610
|
+
_a6.SOURCE_GET_RESPONSE_GAS,
|
|
247611
|
+
"source",
|
|
247612
|
+
sourceStateMachine
|
|
247613
|
+
);
|
|
247614
|
+
const relayerFee = feeInSourceFeeToken * 1005n / 1000n;
|
|
247615
|
+
if (TESTNET_CHAINS.has(sourceStateMachine)) return { nativeValue: 0n, relayerFee };
|
|
247598
247616
|
const height = order.deadline + 1n;
|
|
247599
247617
|
const destIntentGateway = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachine);
|
|
247600
247618
|
const commitment = this.orderId(order);
|
|
@@ -247603,20 +247621,13 @@ query OrderStatus($commitment: String!) {
|
|
|
247603
247621
|
const getRequest = {
|
|
247604
247622
|
source: sourceStateMachine,
|
|
247605
247623
|
dest: destStateMachine,
|
|
247606
|
-
from: this.ctx.source.configService.getIntentGatewayAddress(
|
|
247624
|
+
from: this.ctx.source.configService.getIntentGatewayAddress(sourceStateMachine),
|
|
247607
247625
|
nonce: await this.ctx.source.getHostNonce(),
|
|
247608
247626
|
height,
|
|
247609
247627
|
keys: keys3,
|
|
247610
247628
|
timeoutTimestamp: 0n,
|
|
247611
247629
|
context
|
|
247612
247630
|
};
|
|
247613
|
-
const feeInSourceFeeToken = await convertGasToFeeToken(
|
|
247614
|
-
this.ctx,
|
|
247615
|
-
_a6.SOURCE_GET_RESPONSE_GAS,
|
|
247616
|
-
"source",
|
|
247617
|
-
sourceStateMachine
|
|
247618
|
-
);
|
|
247619
|
-
const relayerFee = feeInSourceFeeToken * 1005n / 1000n;
|
|
247620
247631
|
const nativeValue = await this.ctx.source.quoteNative(getRequest, relayerFee) * 101n / 100n;
|
|
247621
247632
|
return { nativeValue, relayerFee };
|
|
247622
247633
|
}
|
|
@@ -247637,7 +247648,10 @@ query OrderStatus($commitment: String!) {
|
|
|
247637
247648
|
* cancellation. Same-chain orders always use the direct local route.
|
|
247638
247649
|
* @yields {@link CancelEvent} objects describing each stage of the
|
|
247639
247650
|
* cancellation lifecycle. The caller signs or broadcasts the yielded
|
|
247640
|
-
* transaction,
|
|
247651
|
+
* transaction, and the gateway decides who may sign it. A same-chain cancel
|
|
247652
|
+
* or a cross-chain cancel from the destination accepts only `order.user`
|
|
247653
|
+
* through the deadline and any signer strictly after it. A cross-chain
|
|
247654
|
+
* cancel from the source accepts only `order.user`, before or after expiry.
|
|
247641
247655
|
*/
|
|
247642
247656
|
async *cancelOrder(order, indexerClient, options = {}) {
|
|
247643
247657
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
@@ -247857,11 +247871,13 @@ query OrderStatus($commitment: String!) {
|
|
|
247857
247871
|
*
|
|
247858
247872
|
* Estimates the relayer fee for delivering the refund POST request from the
|
|
247859
247873
|
* destination chain back to the source chain, converts it to the destination
|
|
247860
|
-
* fee token, and calls `quoteNative` on the destination host.
|
|
247874
|
+
* fee token, and calls `quoteNative` on the destination host. Returns a zero
|
|
247875
|
+
* `nativeValue` when the destination is a testnet chain, leaving the relayer
|
|
247876
|
+
* fee to be paid in its fee token.
|
|
247861
247877
|
* Returns 0 for same-chain orders.
|
|
247862
247878
|
*
|
|
247863
247879
|
* @param order - The order to quote.
|
|
247864
|
-
* @returns The native token dispatch fee in wei.
|
|
247880
|
+
* @returns The native token dispatch fee in wei and the relayer fee.
|
|
247865
247881
|
*/
|
|
247866
247882
|
async quoteCancelFromDest(order) {
|
|
247867
247883
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
@@ -247872,6 +247888,7 @@ query OrderStatus($commitment: String!) {
|
|
|
247872
247888
|
const destIntentGateway = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachine);
|
|
247873
247889
|
const sourceIntentGateway = this.ctx.source.configService.getIntentGatewayAddress(sourceStateMachine);
|
|
247874
247890
|
const relayerFee = await this.estimateRelayerFee(sourceStateMachine, destStateMachine);
|
|
247891
|
+
if (TESTNET_CHAINS.has(destStateMachine)) return { nativeValue: 0n, relayerFee };
|
|
247875
247892
|
const body = constructRefundEscrowRequestBody(order, order.user);
|
|
247876
247893
|
const postRequest = {
|
|
247877
247894
|
source: destStateMachine,
|
|
@@ -248855,6 +248872,8 @@ query OrderStatus($commitment: String!) {
|
|
|
248855
248872
|
constructor(ctx, crypto10) {
|
|
248856
248873
|
__publicField(this, "ctx");
|
|
248857
248874
|
__publicField(this, "crypto");
|
|
248875
|
+
/** Call dispatchers read from a gateway, for chains whose config carries none. */
|
|
248876
|
+
__publicField(this, "dispatchers", /* @__PURE__ */ new Map());
|
|
248858
248877
|
this.ctx = ctx;
|
|
248859
248878
|
this.crypto = crypto10;
|
|
248860
248879
|
}
|
|
@@ -248876,7 +248895,9 @@ query OrderStatus($commitment: String!) {
|
|
|
248876
248895
|
* ephemeral keypair, applies state overrides, and calls
|
|
248877
248896
|
* `eth_estimateUserOperationGas`. Gas limits are bumped by 5-10% for
|
|
248878
248897
|
* headroom. If the bundler is Pimlico, gas prices are refined with
|
|
248879
|
-
* `pimlico_getUserOperationGasPrice`.
|
|
248898
|
+
* `pimlico_getUserOperationGasPrice`. If the bundler rejects the estimate,
|
|
248899
|
+
* fixed gas limits are returned in its place, or the call throws when
|
|
248900
|
+
* `params.requireBundlerEstimate` is set.
|
|
248880
248901
|
*
|
|
248881
248902
|
* **Fallback path (no bundler):** uses a fixed budget
|
|
248882
248903
|
* ({@link NO_BUNDLER_FILL_GAS_BASE} plus {@link NO_BUNDLER_FILL_GAS_PER_OUTPUT}
|
|
@@ -248890,6 +248911,8 @@ query OrderStatus($commitment: String!) {
|
|
|
248890
248911
|
* @returns A {@link FillOrderEstimate} containing all gas components,
|
|
248891
248912
|
* EIP-1559 fee values, total cost in wei, and total cost in the source
|
|
248892
248913
|
* chain's fee token.
|
|
248914
|
+
* @throws If `params.requireBundlerEstimate` is set and the bundler fails to
|
|
248915
|
+
* estimate the fill.
|
|
248893
248916
|
*/
|
|
248894
248917
|
async estimateFillOrder(params, pricingOptions = {}) {
|
|
248895
248918
|
const { order } = params;
|
|
@@ -249087,6 +249110,11 @@ query OrderStatus($commitment: String!) {
|
|
|
249087
249110
|
maxFeePerGas = bufferedBaseFee + maxPriorityFeePerGas;
|
|
249088
249111
|
}
|
|
249089
249112
|
} catch (e4) {
|
|
249113
|
+
if (params.requireBundlerEstimate) {
|
|
249114
|
+
throw new Error(`Bundler gas estimation failed: ${e4 instanceof Error ? e4.message : String(e4)}`, {
|
|
249115
|
+
cause: e4
|
|
249116
|
+
});
|
|
249117
|
+
}
|
|
249090
249118
|
console.warn("Bundler gas estimation failed, using fallback values:", e4);
|
|
249091
249119
|
}
|
|
249092
249120
|
} else {
|
|
@@ -249121,6 +249149,27 @@ query OrderStatus($commitment: String!) {
|
|
|
249121
249149
|
inputs
|
|
249122
249150
|
};
|
|
249123
249151
|
}
|
|
249152
|
+
/**
|
|
249153
|
+
* The call dispatcher the gateway on `chain` uses: the configured address, or the one
|
|
249154
|
+
* the gateway reports when the chain's config carries none.
|
|
249155
|
+
*
|
|
249156
|
+
* {@link buildStateOverride} writes it back into the gateway's params slot. Without an
|
|
249157
|
+
* address that value is 12 bytes instead of 32, and the bundler rejects the whole
|
|
249158
|
+
* estimate as `Invalid params`.
|
|
249159
|
+
*/
|
|
249160
|
+
async callDispatcher(chain2, gateway) {
|
|
249161
|
+
const configured = this.ctx.dest.configService.getCalldispatcherAddress(chain2);
|
|
249162
|
+
if (isAddress2(configured)) return configured;
|
|
249163
|
+
const known3 = this.dispatchers.get(chain2);
|
|
249164
|
+
if (known3) return known3;
|
|
249165
|
+
const params = await this.ctx.dest.client.readContract({
|
|
249166
|
+
abi: ABI3,
|
|
249167
|
+
address: gateway,
|
|
249168
|
+
functionName: "params"
|
|
249169
|
+
});
|
|
249170
|
+
this.dispatchers.set(chain2, params.dispatcher);
|
|
249171
|
+
return params.dispatcher;
|
|
249172
|
+
}
|
|
249124
249173
|
/**
|
|
249125
249174
|
* Asks the bundler for the `preVerificationGas` of the bid UserOperation that will
|
|
249126
249175
|
* actually be signed, with every funding call, approval and signature byte in it.
|
|
@@ -249234,7 +249283,7 @@ query OrderStatus($commitment: String!) {
|
|
|
249234
249283
|
const bundlerOverrides = {};
|
|
249235
249284
|
if (intentGatewayV2Address) {
|
|
249236
249285
|
const paramsSlot5 = pad4(toHex3(5n), { size: 32 });
|
|
249237
|
-
const dispatcherAddress = this.
|
|
249286
|
+
const dispatcherAddress = await this.callDispatcher(chain2, intentGatewayV2Address);
|
|
249238
249287
|
const newSlot5Value = "0x" + "0".repeat(22) + "00" + dispatcherAddress.slice(2).toLowerCase();
|
|
249239
249288
|
const gatewayDiffs = [{ slot: paramsSlot5, value: newSlot5Value }];
|
|
249240
249289
|
for (const [leg, input] of (escrow?.inputs ?? []).entries()) {
|
|
@@ -249775,15 +249824,8 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
249775
249824
|
return withDecimals(resolvedChain, symbol3, this.configService.getAssetMetadataBySymbol(resolvedChain, symbol3));
|
|
249776
249825
|
}
|
|
249777
249826
|
};
|
|
249778
|
-
|
|
249779
|
-
|
|
249780
|
-
bySourceStateMachineId: {
|
|
249781
|
-
[
|
|
249782
|
-
"EVM-1"
|
|
249783
|
-
/* MAINNET */
|
|
249784
|
-
]: 50n
|
|
249785
|
-
}
|
|
249786
|
-
};
|
|
249827
|
+
ETHEREUM_ORDER_FEE_GAS_PRICE_BUMP_PERCENT = 50n;
|
|
249828
|
+
DEFAULT_ORDER_FEE_GAS_PRICE_BUMP_PERCENT = 100n;
|
|
249787
249829
|
IntentGateway = class _IntentGateway {
|
|
249788
249830
|
/**
|
|
249789
249831
|
* Private constructor — use {@link IntentGateway.create} instead.
|
|
@@ -249964,9 +250006,9 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
249964
250006
|
* 1. If `order.fees` is unset or zero, prices the fee on an internal copy
|
|
249965
250007
|
* via {@link quoteOrderFees}: same-chain fees are twice the fill-gas
|
|
249966
250008
|
* estimate without a gas-price bump; cross-chain order fees originating on
|
|
249967
|
-
* Ethereum price gas 50% above the live price, while other source
|
|
249968
|
-
*
|
|
249969
|
-
* with a further 5% buffer over the whole sum — strictly above the solver's
|
|
250009
|
+
* Ethereum mainnet price gas 50% above the live price, while other source
|
|
250010
|
+
* chains use 100%, before attaching (fill gas + the settlement relayer
|
|
250011
|
+
* fee) with a further 5% buffer over the whole sum — strictly above the solver's
|
|
249970
250012
|
* unpadded requirement. Direct solver estimates remain unbumped. The wei
|
|
249971
250013
|
* cost used for the `value` field receives a 2% buffer.
|
|
249972
250014
|
* 2. Yields `AWAITING_PLACE_ORDER` with `{ to, data, value, nativeFee,
|
|
@@ -250206,6 +250248,8 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
250206
250248
|
* order. Use `relayerFee` to approve the ERC-20 spend before submitting.
|
|
250207
250249
|
* Same-chain orders use the direct local route for either `from` option and
|
|
250208
250250
|
* return `{ nativeValue: 0n, relayerFee: 0n }`.
|
|
250251
|
+
* When the chain receiving the cancel transaction is a testnet, `nativeValue` is `0n` and the caller
|
|
250252
|
+
* approves `relayerFee` of that host's fee token to that chain's gateway.
|
|
250209
250253
|
*
|
|
250210
250254
|
* Delegates to {@link OrderCanceller.quoteCancelOrder}.
|
|
250211
250255
|
*
|
|
@@ -250356,7 +250400,7 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
250356
250400
|
*
|
|
250357
250401
|
* @param order - The order to quote. `order.fees` is ignored and not mutated.
|
|
250358
250402
|
* Gas prices used to derive cross-chain `fees` receive 50% SDK-only headroom
|
|
250359
|
-
* when the source chain is Ethereum mainnet and
|
|
250403
|
+
* when the source chain is Ethereum mainnet and 100% for other source chains.
|
|
250360
250404
|
* Same-chain quotes and direct calls to {@link estimateFillOrder}, including
|
|
250361
250405
|
* Simplex solver estimates, remain unbumped.
|
|
250362
250406
|
*
|
|
@@ -250645,7 +250689,7 @@ async function resolveChainConfigs(chains2, options = {}) {
|
|
|
250645
250689
|
})
|
|
250646
250690
|
);
|
|
250647
250691
|
}
|
|
250648
|
-
var DEFAULT_BLOCK_SCAN_INTERVAL_SECONDS, MIN_BLOCK_SCAN_INTERVAL_SECONDS, FillerConfigService;
|
|
250692
|
+
var DEFAULT_BLOCK_SCAN_INTERVAL_SECONDS, MIN_BLOCK_SCAN_INTERVAL_SECONDS, DEFAULT_MIN_ORDER_SIZE_USD, FillerConfigService;
|
|
250649
250693
|
var init_FillerConfigService = __esm({
|
|
250650
250694
|
"src/services/FillerConfigService.ts"() {
|
|
250651
250695
|
"use strict";
|
|
@@ -250654,6 +250698,7 @@ var init_FillerConfigService = __esm({
|
|
|
250654
250698
|
init_node10();
|
|
250655
250699
|
DEFAULT_BLOCK_SCAN_INTERVAL_SECONDS = 3;
|
|
250656
250700
|
MIN_BLOCK_SCAN_INTERVAL_SECONDS = 0.1;
|
|
250701
|
+
DEFAULT_MIN_ORDER_SIZE_USD = 20;
|
|
250657
250702
|
FillerConfigService = class {
|
|
250658
250703
|
constructor(chainConfigs2, fillerConfig, loggers) {
|
|
250659
250704
|
this.rpcOverrides = /* @__PURE__ */ new Map();
|
|
@@ -250994,6 +251039,13 @@ var init_FillerConfigService = __esm({
|
|
|
250994
251039
|
getBidValiditySeconds() {
|
|
250995
251040
|
return this.fillerConfig?.bidValiditySeconds ?? 300;
|
|
250996
251041
|
}
|
|
251042
|
+
/**
|
|
251043
|
+
* The order size, in USD, below which `order.fees` must cover the execution cost.
|
|
251044
|
+
* Defaults to 20. An order at or above it is filled whatever fees it carries.
|
|
251045
|
+
*/
|
|
251046
|
+
getMinOrderSizeUsd() {
|
|
251047
|
+
return this.fillerConfig?.minOrderSizeUsd ?? DEFAULT_MIN_ORDER_SIZE_USD;
|
|
251048
|
+
}
|
|
250997
251049
|
/** Ceiling bps above user-requested output. Default 500 (5%). */
|
|
250998
251050
|
getMaxOverfillBps() {
|
|
250999
251051
|
return BigInt(this.fillerConfig?.overfillProtection?.maxOverfillBps ?? 500);
|
|
@@ -251106,6 +251158,12 @@ function validateConfig(config5, cliWatchOnly = false) {
|
|
|
251106
251158
|
);
|
|
251107
251159
|
}
|
|
251108
251160
|
}
|
|
251161
|
+
const minOrderSize = config5.simplex.minOrderSizeUsd;
|
|
251162
|
+
if (minOrderSize !== void 0) {
|
|
251163
|
+
if (!Number.isFinite(minOrderSize) || minOrderSize < 0) {
|
|
251164
|
+
throw new Error(`simplex.minOrderSizeUsd must be a number >= 0 (USD); got ${minOrderSize}`);
|
|
251165
|
+
}
|
|
251166
|
+
}
|
|
251109
251167
|
if (config5.allowlist) {
|
|
251110
251168
|
for (const user of config5.allowlist.users ?? []) {
|
|
251111
251169
|
if (!isAddress(user)) {
|
|
@@ -251591,6 +251649,10 @@ function emitFillerToml(config5, options = {}) {
|
|
|
251591
251649
|
push("# Gas units to keep deposited at the ERC-4337 EntryPoint on chains without a paymaster.");
|
|
251592
251650
|
push(kv("targetGasUnits", config5.simplex.targetGasUnits));
|
|
251593
251651
|
}
|
|
251652
|
+
if (config5.simplex.minOrderSizeUsd !== void 0) {
|
|
251653
|
+
push("# Order size in USD below which an order's fees must cover gas. Default 20.");
|
|
251654
|
+
push(kv("minOrderSizeUsd", config5.simplex.minOrderSizeUsd));
|
|
251655
|
+
}
|
|
251594
251656
|
push();
|
|
251595
251657
|
if (config5.simplex.signer) {
|
|
251596
251658
|
push("# Wallet that signs fills and holds the stablecoin float on every chain.");
|
|
@@ -254188,7 +254250,7 @@ var require_bn2 = __commonJS({
|
|
|
254188
254250
|
}
|
|
254189
254251
|
return this;
|
|
254190
254252
|
};
|
|
254191
|
-
BN3.prototype.add = function
|
|
254253
|
+
BN3.prototype.add = function add4(num2) {
|
|
254192
254254
|
var res;
|
|
254193
254255
|
if (num2.negative !== 0 && this.negative === 0) {
|
|
254194
254256
|
num2.negative = 0;
|
|
@@ -256015,7 +256077,7 @@ var require_bn2 = __commonJS({
|
|
|
256015
256077
|
}
|
|
256016
256078
|
return this.m.sub(a6)._forceRed(this);
|
|
256017
256079
|
};
|
|
256018
|
-
Red.prototype.add = function
|
|
256080
|
+
Red.prototype.add = function add4(a6, b5) {
|
|
256019
256081
|
this._verify2(a6, b5);
|
|
256020
256082
|
var res = a6.add(b5);
|
|
256021
256083
|
if (res.cmp(this.m) >= 0) {
|
|
@@ -267026,7 +267088,7 @@ var require_namespace = __commonJS({
|
|
|
267026
267088
|
return this.nested[name3].values;
|
|
267027
267089
|
throw Error("no such enum: " + name3);
|
|
267028
267090
|
};
|
|
267029
|
-
Namespace.prototype.add = function
|
|
267091
|
+
Namespace.prototype.add = function add4(object) {
|
|
267030
267092
|
if (!(object instanceof Field6 && object.extend !== void 0 || object instanceof Type2 || object instanceof OneOf || object instanceof Enum3 || object instanceof Service || object instanceof Namespace))
|
|
267031
267093
|
throw TypeError("object must be a valid nested object");
|
|
267032
267094
|
if (!this.nested)
|
|
@@ -267406,7 +267468,7 @@ var require_service2 = __commonJS({
|
|
|
267406
267468
|
});
|
|
267407
267469
|
return this;
|
|
267408
267470
|
};
|
|
267409
|
-
Service.prototype.add = function
|
|
267471
|
+
Service.prototype.add = function add4(object) {
|
|
267410
267472
|
if (this.get(object.name))
|
|
267411
267473
|
throw Error("duplicate name '" + object.name + "' in " + this);
|
|
267412
267474
|
if (object instanceof Method2) {
|
|
@@ -268111,7 +268173,7 @@ var require_type2 = __commonJS({
|
|
|
268111
268173
|
Type2.prototype.get = function get4(name3) {
|
|
268112
268174
|
return this.fields[name3] || this.oneofs && this.oneofs[name3] || this.nested && this.nested[name3] || null;
|
|
268113
268175
|
};
|
|
268114
|
-
Type2.prototype.add = function
|
|
268176
|
+
Type2.prototype.add = function add4(object) {
|
|
268115
268177
|
if (this.get(object.name))
|
|
268116
268178
|
throw Error("duplicate name '" + object.name + "' in " + this);
|
|
268117
268179
|
if (object instanceof Field6 && object.extend === void 0) {
|
|
@@ -269022,7 +269084,7 @@ var require_oneof = __commonJS({
|
|
|
269022
269084
|
oneof.parent.add(oneof.fieldsArray[i6]);
|
|
269023
269085
|
}
|
|
269024
269086
|
}
|
|
269025
|
-
OneOf.prototype.add = function
|
|
269087
|
+
OneOf.prototype.add = function add4(field) {
|
|
269026
269088
|
if (!(field instanceof Field6))
|
|
269027
269089
|
throw TypeError("field must be a Field");
|
|
269028
269090
|
if (field.parent && field.parent !== this.parent)
|
|
@@ -269351,7 +269413,7 @@ var require_enum = __commonJS({
|
|
|
269351
269413
|
keepComments ? this.comments : void 0
|
|
269352
269414
|
]);
|
|
269353
269415
|
};
|
|
269354
|
-
Enum3.prototype.add = function
|
|
269416
|
+
Enum3.prototype.add = function add4(name3, id2, comment, options) {
|
|
269355
269417
|
if (!util7.isString(name3))
|
|
269356
269418
|
throw TypeError("name must be a string");
|
|
269357
269419
|
if (!util7.isInteger(id2))
|
|
@@ -273828,7 +273890,7 @@ var require_umd = __commonJS({
|
|
|
273828
273890
|
return this.not().add(ONE2);
|
|
273829
273891
|
};
|
|
273830
273892
|
LongPrototype.neg = LongPrototype.negate;
|
|
273831
|
-
LongPrototype.add = function
|
|
273893
|
+
LongPrototype.add = function add4(addend) {
|
|
273832
273894
|
if (!isLong(addend)) addend = fromValue(addend);
|
|
273833
273895
|
var a48 = this.high >>> 16;
|
|
273834
273896
|
var a32 = this.high & 65535;
|
|
@@ -340188,6 +340250,35 @@ var LIMITS_QUERY = `
|
|
|
340188
340250
|
chains { id name tokens { symbol decimals } }
|
|
340189
340251
|
}
|
|
340190
340252
|
`;
|
|
340253
|
+
var LEVEL_FIELDS = "fillChain priceBucket price worstPrice baseSize quoteSize orderCount solverCount";
|
|
340254
|
+
var SNAPSHOT_QUERY = `
|
|
340255
|
+
query OrderbookSnapshot($id: ID!, $sourceChain: String, $fillChain: String) {
|
|
340256
|
+
book(id: $id) {
|
|
340257
|
+
id base quote
|
|
340258
|
+
bids: levels(side: BID, sourceChain: $sourceChain, fillChain: $fillChain) { ${LEVEL_FIELDS} }
|
|
340259
|
+
asks: levels(side: ASK, sourceChain: $sourceChain, fillChain: $fillChain) { ${LEVEL_FIELDS} }
|
|
340260
|
+
bidLiquidity: availableLiquidity(side: BID, sourceChain: $sourceChain, fillChain: $fillChain)
|
|
340261
|
+
askLiquidity: availableLiquidity(side: ASK, sourceChain: $sourceChain, fillChain: $fillChain)
|
|
340262
|
+
}
|
|
340263
|
+
serverInfo { priceGranularities { book granularity } }
|
|
340264
|
+
}
|
|
340265
|
+
`;
|
|
340266
|
+
var LEVEL_ORDERS_QUERY = `
|
|
340267
|
+
query OrderbookLevelOrders($id: ID!, $side: Side!, $fillChain: String, $sourceChain: String, $after: String) {
|
|
340268
|
+
book(id: $id) {
|
|
340269
|
+
orders(side: $side, fillChain: $fillChain, sourceChain: $sourceChain, first: 50, after: $after) {
|
|
340270
|
+
edges {
|
|
340271
|
+
node {
|
|
340272
|
+
solver { address }
|
|
340273
|
+
commitment fillChain price priceBucket advertisedSize quotedAmount resized expiresAt acceptedSources
|
|
340274
|
+
}
|
|
340275
|
+
}
|
|
340276
|
+
pageInfo { hasNextPage endCursor }
|
|
340277
|
+
}
|
|
340278
|
+
}
|
|
340279
|
+
}
|
|
340280
|
+
`;
|
|
340281
|
+
var LEVEL_ORDER_PAGES = 20;
|
|
340191
340282
|
var POSTED_ORDER_FIELDS = "commitment side status price quotedAmount advertisedSize expiresAt acceptedSources";
|
|
340192
340283
|
var SUBMIT_ORDER_MUTATION = `
|
|
340193
340284
|
mutation SubmitOrder($userOp: Bytes!) {
|
|
@@ -340252,6 +340343,44 @@ var OrderbookClient = class {
|
|
|
340252
340343
|
async limits() {
|
|
340253
340344
|
return this.request(LIMITS_QUERY, {});
|
|
340254
340345
|
}
|
|
340346
|
+
/** The public book across all solvers, restricted to the selected route. */
|
|
340347
|
+
async snapshot(id2, filters = {}) {
|
|
340348
|
+
const { book, serverInfo } = await this.request(SNAPSHOT_QUERY, {
|
|
340349
|
+
id: id2,
|
|
340350
|
+
sourceChain: filters.sourceChain || null,
|
|
340351
|
+
fillChain: filters.fillChain || null
|
|
340352
|
+
});
|
|
340353
|
+
if (!book) return null;
|
|
340354
|
+
const granularity = serverInfo.priceGranularities.find((entry) => entry.book === book.id)?.granularity ?? null;
|
|
340355
|
+
return { ...book, granularity };
|
|
340356
|
+
}
|
|
340357
|
+
/**
|
|
340358
|
+
* The orders behind one price level. The orderbook filters orders by side and route but not by
|
|
340359
|
+
* price bucket, so this walks the side's orders on the level's fill chain and keeps the bucket.
|
|
340360
|
+
* Null when the book does not exist.
|
|
340361
|
+
*/
|
|
340362
|
+
async levelOrders(id2, level) {
|
|
340363
|
+
const found = [];
|
|
340364
|
+
let after = null;
|
|
340365
|
+
for (let page = 0; page < LEVEL_ORDER_PAGES; page++) {
|
|
340366
|
+
const { book } = await this.request(LEVEL_ORDERS_QUERY, {
|
|
340367
|
+
id: id2,
|
|
340368
|
+
side: level.side,
|
|
340369
|
+
fillChain: level.fillChain,
|
|
340370
|
+
sourceChain: level.sourceChain || null,
|
|
340371
|
+
after
|
|
340372
|
+
});
|
|
340373
|
+
if (!book) return null;
|
|
340374
|
+
for (const { node } of book.orders.edges) {
|
|
340375
|
+
if (node.priceBucket !== level.priceBucket) continue;
|
|
340376
|
+
const { solver, priceBucket: _bucket, ...order } = node;
|
|
340377
|
+
found.push({ ...order, solver: solver.address });
|
|
340378
|
+
}
|
|
340379
|
+
if (!book.orders.pageInfo.hasNextPage || !book.orders.pageInfo.endCursor) break;
|
|
340380
|
+
after = book.orders.pageInfo.endCursor;
|
|
340381
|
+
}
|
|
340382
|
+
return found;
|
|
340383
|
+
}
|
|
340255
340384
|
async submitOrder(userOp) {
|
|
340256
340385
|
const { submitOrder } = await this.request(SUBMIT_ORDER_MUTATION, { userOp });
|
|
340257
340386
|
switch (submitOrder.__typename) {
|
|
@@ -340440,16 +340569,16 @@ function signedAmounts(params) {
|
|
|
340440
340569
|
function offerFor(params) {
|
|
340441
340570
|
const { side, inputAmount, price, outputDecimals } = params;
|
|
340442
340571
|
if (price <= 0n) throw new Error("A limit order's price must be greater than zero");
|
|
340443
|
-
const
|
|
340572
|
+
const scaled2 = side === "BID" ? inputAmount * price / ORDERBOOK_SCALE2 : inputAmount * ORDERBOOK_SCALE2 / price;
|
|
340444
340573
|
const unit = outputDecimals >= 18 ? 1n : 10n ** BigInt(18 - outputDecimals);
|
|
340445
|
-
return
|
|
340574
|
+
return scaled2 / unit * unit;
|
|
340446
340575
|
}
|
|
340447
340576
|
function inputFor(params) {
|
|
340448
340577
|
const { side, outputAmount, price, inputDecimals } = params;
|
|
340449
340578
|
if (price <= 0n) throw new Error("A limit order's price must be greater than zero");
|
|
340450
|
-
const
|
|
340579
|
+
const scaled2 = side === "BID" ? divCeil2(outputAmount * ORDERBOOK_SCALE2, price) : divCeil2(outputAmount * price, ORDERBOOK_SCALE2);
|
|
340451
340580
|
const unit = inputDecimals >= 18 ? 1n : 10n ** BigInt(18 - inputDecimals);
|
|
340452
|
-
return divCeil2(
|
|
340581
|
+
return divCeil2(scaled2, unit) * unit;
|
|
340453
340582
|
}
|
|
340454
340583
|
|
|
340455
340584
|
// src/orderbook/matching.ts
|
|
@@ -340707,6 +340836,14 @@ var LimitOrderService = class {
|
|
|
340707
340836
|
throw err;
|
|
340708
340837
|
}
|
|
340709
340838
|
}
|
|
340839
|
+
/** Public market levels read through the configured orderbook client. */
|
|
340840
|
+
orderbookSnapshot(book, filters = {}) {
|
|
340841
|
+
return this.client.snapshot(book, filters);
|
|
340842
|
+
}
|
|
340843
|
+
/** Every solver's order behind one public price level. */
|
|
340844
|
+
orderbookLevelOrders(book, level) {
|
|
340845
|
+
return this.client.levelOrders(book, level);
|
|
340846
|
+
}
|
|
340710
340847
|
/**
|
|
340711
340848
|
* The pairs an order can be written against, the smallest payout each token may carry, and
|
|
340712
340849
|
* the tokens the orderbook registers on each chain.
|
|
@@ -340761,16 +340898,16 @@ var LimitOrderService = class {
|
|
|
340761
340898
|
if (!this.configService.getConfiguredChainIds().includes(getChainId3(request3.fillChain) ?? -1)) {
|
|
340762
340899
|
throw new LimitOrderValidationError(`'${request3.fillChain}' is not a chain this filler is configured for`);
|
|
340763
340900
|
}
|
|
340764
|
-
const
|
|
340901
|
+
const scaled2 = { amountIn: 0n, amountOut: 0n };
|
|
340765
340902
|
for (const name3 of ["amountIn", "amountOut"]) {
|
|
340766
340903
|
try {
|
|
340767
|
-
|
|
340904
|
+
scaled2[name3] = fromHuman(request3[name3] ?? "");
|
|
340768
340905
|
} catch (err) {
|
|
340769
340906
|
throw new LimitOrderValidationError(
|
|
340770
340907
|
`${name3} must be an amount in whole tokens, like "1000" or "1500.25"; ${err.message}`
|
|
340771
340908
|
);
|
|
340772
340909
|
}
|
|
340773
|
-
if (
|
|
340910
|
+
if (scaled2[name3] <= 0n) throw new LimitOrderValidationError(`${name3} must be greater than zero`);
|
|
340774
340911
|
}
|
|
340775
340912
|
const sources = request3.acceptedSources ?? [];
|
|
340776
340913
|
if (sources.length === 0) {
|
|
@@ -340817,7 +340954,7 @@ var LimitOrderService = class {
|
|
|
340817
340954
|
);
|
|
340818
340955
|
}
|
|
340819
340956
|
const floor2 = limits.serverInfo.minOrderSizes.find((entry) => entry.symbol === request3.tokenOut);
|
|
340820
|
-
if (floor2 &&
|
|
340957
|
+
if (floor2 && scaled2.amountOut < BigInt(floor2.size)) {
|
|
340821
340958
|
throw new LimitOrderValidationError(
|
|
340822
340959
|
`amountOut is below the orderbook's dust floor for ${request3.tokenOut} (${toHuman(BigInt(floor2.size))})`
|
|
340823
340960
|
);
|
|
@@ -340827,7 +340964,7 @@ var LimitOrderService = class {
|
|
|
340827
340964
|
throw new LimitOrderValidationError(`'${symbol3}' does not resolve to a token address on ${request3.fillChain}`);
|
|
340828
340965
|
}
|
|
340829
340966
|
}
|
|
340830
|
-
return { amountIn:
|
|
340967
|
+
return { amountIn: scaled2.amountIn, amountOut: scaled2.amountOut };
|
|
340831
340968
|
}
|
|
340832
340969
|
/**
|
|
340833
340970
|
* Refuses an order the wallet cannot pay out.
|
|
@@ -341353,6 +341490,459 @@ function underFunded(entry) {
|
|
|
341353
341490
|
return entry.resized ? `UNDER_FUNDED: the orderbook is advertising ${entry.advertisedSize} of the ${entry.quotedAmount} quoted` : "UNDER_FUNDED: the solver's balance does not cover this posting";
|
|
341354
341491
|
}
|
|
341355
341492
|
|
|
341493
|
+
// src/orderbook/profitability.ts
|
|
341494
|
+
init_esm_shims();
|
|
341495
|
+
init_decimal();
|
|
341496
|
+
init_asset_registry();
|
|
341497
|
+
|
|
341498
|
+
// src/data/inventory.ts
|
|
341499
|
+
init_esm_shims();
|
|
341500
|
+
var INVENTORY_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
341501
|
+
function inventoryOf(snapshot) {
|
|
341502
|
+
if (snapshot.status !== "fresh") return null;
|
|
341503
|
+
const held = {};
|
|
341504
|
+
for (const chain2 of snapshot.chains) {
|
|
341505
|
+
for (const asset of chain2.assets) {
|
|
341506
|
+
if (asset.total === null) return null;
|
|
341507
|
+
held[asset.symbol] = (held[asset.symbol] ?? 0) + asset.total;
|
|
341508
|
+
}
|
|
341509
|
+
}
|
|
341510
|
+
return Object.keys(held).length > 0 ? held : null;
|
|
341511
|
+
}
|
|
341512
|
+
function parseUtc(value) {
|
|
341513
|
+
return Date.parse(`${value.replace(" ", "T")}Z`);
|
|
341514
|
+
}
|
|
341515
|
+
var InventoryRecorder = class {
|
|
341516
|
+
constructor(store, balances, logger8, now = Date.now) {
|
|
341517
|
+
this.store = store;
|
|
341518
|
+
this.balances = balances;
|
|
341519
|
+
this.logger = logger8;
|
|
341520
|
+
this.now = now;
|
|
341521
|
+
this.recording = false;
|
|
341522
|
+
this.onSnapshot = (snapshot) => void this.consider(snapshot);
|
|
341523
|
+
}
|
|
341524
|
+
start() {
|
|
341525
|
+
this.balances.on("snapshot", this.onSnapshot);
|
|
341526
|
+
void this.consider(this.balances.getSnapshot());
|
|
341527
|
+
}
|
|
341528
|
+
stop() {
|
|
341529
|
+
this.balances.off("snapshot", this.onSnapshot);
|
|
341530
|
+
}
|
|
341531
|
+
/** Takes a snapshot from `snapshot` if one is due and the read is complete. Never rejects. */
|
|
341532
|
+
async consider(snapshot) {
|
|
341533
|
+
if (this.recording) return;
|
|
341534
|
+
const held = inventoryOf(snapshot);
|
|
341535
|
+
if (!held) return;
|
|
341536
|
+
this.recording = true;
|
|
341537
|
+
try {
|
|
341538
|
+
if (this.lastTakenAt === void 0) {
|
|
341539
|
+
const latest2 = await this.store.latest();
|
|
341540
|
+
this.lastTakenAt = latest2 ? parseUtc(latest2.takenAt) : 0;
|
|
341541
|
+
}
|
|
341542
|
+
if (this.now() - this.lastTakenAt < INVENTORY_INTERVAL_MS) return;
|
|
341543
|
+
await this.store.record(held);
|
|
341544
|
+
this.lastTakenAt = this.now();
|
|
341545
|
+
this.logger.info({ tokens: Object.keys(held).length }, "Recorded an inventory snapshot");
|
|
341546
|
+
} catch (err) {
|
|
341547
|
+
this.logger.warn({ err }, "Could not record an inventory snapshot");
|
|
341548
|
+
} finally {
|
|
341549
|
+
this.recording = false;
|
|
341550
|
+
}
|
|
341551
|
+
}
|
|
341552
|
+
};
|
|
341553
|
+
|
|
341554
|
+
// src/orderbook/usd.ts
|
|
341555
|
+
init_esm_shims();
|
|
341556
|
+
init_decimal();
|
|
341557
|
+
init_asset_registry();
|
|
341558
|
+
function limitOrderUsdEdges(orders) {
|
|
341559
|
+
return orders.filter((order) => normalizeSymbol(order.base) !== normalizeSymbol(order.quote)).map((order) => ({
|
|
341560
|
+
base: normalizeSymbol(order.base),
|
|
341561
|
+
quote: normalizeSymbol(order.quote),
|
|
341562
|
+
rate: new Decimal(order.price).div(ORDERBOOK_SCALE2.toString())
|
|
341563
|
+
})).filter((edge) => edge.rate.isFinite() && edge.rate.gt(0));
|
|
341564
|
+
}
|
|
341565
|
+
function usdFactorsFrom(edges) {
|
|
341566
|
+
const factors = /* @__PURE__ */ new Map();
|
|
341567
|
+
for (const symbol3 of USD_STABLE_SYMBOLS) factors.set(symbol3, new Decimal(1));
|
|
341568
|
+
const ordered = [...edges].sort((a6, b5) => a6.base.localeCompare(b5.base) || a6.quote.localeCompare(b5.quote));
|
|
341569
|
+
let grew = true;
|
|
341570
|
+
while (grew) {
|
|
341571
|
+
grew = false;
|
|
341572
|
+
for (const edge of ordered) {
|
|
341573
|
+
const usdBase = factors.get(edge.base);
|
|
341574
|
+
const usdQuote = factors.get(edge.quote);
|
|
341575
|
+
if (usdBase && !usdQuote) {
|
|
341576
|
+
factors.set(edge.quote, usdBase.div(edge.rate));
|
|
341577
|
+
grew = true;
|
|
341578
|
+
} else if (usdQuote && !usdBase) {
|
|
341579
|
+
factors.set(edge.base, usdQuote.mul(edge.rate));
|
|
341580
|
+
grew = true;
|
|
341581
|
+
}
|
|
341582
|
+
}
|
|
341583
|
+
}
|
|
341584
|
+
return factors;
|
|
341585
|
+
}
|
|
341586
|
+
function usdValueOf(factors, symbol3, amount) {
|
|
341587
|
+
const factor = factors.get(normalizeSymbol(symbol3));
|
|
341588
|
+
return factor ? amount.mul(factor) : null;
|
|
341589
|
+
}
|
|
341590
|
+
|
|
341591
|
+
// src/orderbook/profitability.ts
|
|
341592
|
+
var Decimal2 = Decimal.clone({ precision: 40 });
|
|
341593
|
+
var PROFIT_PERIODS = {
|
|
341594
|
+
"7d": { bucket: "day", count: 7 },
|
|
341595
|
+
"30d": { bucket: "day", count: 30 },
|
|
341596
|
+
"12w": { bucket: "week", count: 12 },
|
|
341597
|
+
"12m": { bucket: "month", count: 12 },
|
|
341598
|
+
all: { bucket: "year", count: null }
|
|
341599
|
+
};
|
|
341600
|
+
function isProfitPeriod(value) {
|
|
341601
|
+
return value in PROFIT_PERIODS;
|
|
341602
|
+
}
|
|
341603
|
+
var MINUTE = 6e4;
|
|
341604
|
+
var DAY = 864e5;
|
|
341605
|
+
var BALANCES_REACH_MS = 7 * DAY;
|
|
341606
|
+
function bucketStart(local, bucket) {
|
|
341607
|
+
const date = new Date(local);
|
|
341608
|
+
const year = date.getUTCFullYear();
|
|
341609
|
+
const month = date.getUTCMonth();
|
|
341610
|
+
if (bucket === "year") return Date.UTC(year, 0, 1);
|
|
341611
|
+
if (bucket === "month") return Date.UTC(year, month, 1);
|
|
341612
|
+
const day = Date.UTC(year, month, date.getUTCDate());
|
|
341613
|
+
return bucket === "day" ? day : day - (date.getUTCDay() + 6) % 7 * DAY;
|
|
341614
|
+
}
|
|
341615
|
+
function shiftBucket(start, bucket, steps) {
|
|
341616
|
+
if (bucket === "day") return start + steps * DAY;
|
|
341617
|
+
if (bucket === "week") return start + steps * 7 * DAY;
|
|
341618
|
+
const date = new Date(start);
|
|
341619
|
+
return bucket === "month" ? Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + steps, 1) : Date.UTC(date.getUTCFullYear() + steps, 0, 1);
|
|
341620
|
+
}
|
|
341621
|
+
function scaled(value) {
|
|
341622
|
+
return new Decimal2(value).div(ORDERBOOK_SCALE2.toString());
|
|
341623
|
+
}
|
|
341624
|
+
function tradeOf(fill, at) {
|
|
341625
|
+
try {
|
|
341626
|
+
const paid = scaled(fill.amount);
|
|
341627
|
+
const taken = fill.amountIn === null ? null : scaled(fill.amountIn);
|
|
341628
|
+
const price = scaled(fill.price);
|
|
341629
|
+
if (!paid.gt(0) || !price.gt(0) || taken !== null && !taken.gt(0)) return null;
|
|
341630
|
+
const buying = fill.side === "BID";
|
|
341631
|
+
const [baseAmount, quoteAmount] = buying ? [taken ?? paid.div(price), paid] : [paid, taken ?? paid.mul(price)];
|
|
341632
|
+
return {
|
|
341633
|
+
at,
|
|
341634
|
+
book: fill.book,
|
|
341635
|
+
base: normalizeSymbol(fill.base),
|
|
341636
|
+
quote: normalizeSymbol(fill.quote),
|
|
341637
|
+
buying,
|
|
341638
|
+
baseAmount,
|
|
341639
|
+
quoteAmount,
|
|
341640
|
+
estimated: taken === null
|
|
341641
|
+
};
|
|
341642
|
+
} catch {
|
|
341643
|
+
return null;
|
|
341644
|
+
}
|
|
341645
|
+
}
|
|
341646
|
+
function add3(holdings, symbol3, amount) {
|
|
341647
|
+
holdings.set(symbol3, (holdings.get(symbol3) ?? new Decimal2(0)).add(amount));
|
|
341648
|
+
}
|
|
341649
|
+
function apply3(holdings, trade, sign6) {
|
|
341650
|
+
const base4 = trade.buying ? trade.baseAmount : trade.baseAmount.neg();
|
|
341651
|
+
const quote = trade.buying ? trade.quoteAmount.neg() : trade.quoteAmount;
|
|
341652
|
+
add3(holdings, trade.base, base4.mul(sign6));
|
|
341653
|
+
add3(holdings, trade.quote, quote.mul(sign6));
|
|
341654
|
+
}
|
|
341655
|
+
var Sums = class {
|
|
341656
|
+
constructor() {
|
|
341657
|
+
this.change = /* @__PURE__ */ new Map();
|
|
341658
|
+
this.boughtUsd = new Decimal2(0);
|
|
341659
|
+
this.soldUsd = new Decimal2(0);
|
|
341660
|
+
this.buys = 0;
|
|
341661
|
+
this.sells = 0;
|
|
341662
|
+
}
|
|
341663
|
+
};
|
|
341664
|
+
var BookLedger = class {
|
|
341665
|
+
constructor(id2, base4, quote) {
|
|
341666
|
+
this.id = id2;
|
|
341667
|
+
this.base = base4;
|
|
341668
|
+
this.quote = quote;
|
|
341669
|
+
this.bought = new Decimal2(0);
|
|
341670
|
+
this.boughtQuote = new Decimal2(0);
|
|
341671
|
+
this.sold = new Decimal2(0);
|
|
341672
|
+
this.soldQuote = new Decimal2(0);
|
|
341673
|
+
/** The rates of the book's latest buy and latest sell, over all of its history. */
|
|
341674
|
+
this.latestBuy = null;
|
|
341675
|
+
this.latestSell = null;
|
|
341676
|
+
this.inPeriod = false;
|
|
341677
|
+
}
|
|
341678
|
+
/**
|
|
341679
|
+
* The rate the book is valued at. Midway between the latest buy and the latest sell, because
|
|
341680
|
+
* either alone sits half a spread to one side and would price open volume against whichever
|
|
341681
|
+
* way the book happened to trade last.
|
|
341682
|
+
*/
|
|
341683
|
+
rate() {
|
|
341684
|
+
if (this.latestBuy && this.latestSell) return this.latestBuy.add(this.latestSell).div(2);
|
|
341685
|
+
return this.latestBuy ?? this.latestSell;
|
|
341686
|
+
}
|
|
341687
|
+
};
|
|
341688
|
+
function readingOf(reading) {
|
|
341689
|
+
const held = /* @__PURE__ */ new Map();
|
|
341690
|
+
const cover = /* @__PURE__ */ new Map();
|
|
341691
|
+
for (const [symbol3, amount] of Object.entries(reading.balances)) {
|
|
341692
|
+
const chains2 = reading.chains[symbol3];
|
|
341693
|
+
if (!Number.isFinite(amount) || !chains2?.length) continue;
|
|
341694
|
+
add3(held, normalizeSymbol(symbol3), new Decimal2(amount));
|
|
341695
|
+
cover.set(normalizeSymbol(symbol3), [...chains2].sort().join(","));
|
|
341696
|
+
}
|
|
341697
|
+
return { held, cover };
|
|
341698
|
+
}
|
|
341699
|
+
function movedBetween(earlier, later) {
|
|
341700
|
+
if (!earlier || !later) return null;
|
|
341701
|
+
const moved = /* @__PURE__ */ new Map();
|
|
341702
|
+
for (const [symbol3, cover] of later.cover) {
|
|
341703
|
+
if (earlier.cover.get(symbol3) !== cover) continue;
|
|
341704
|
+
const before = earlier.held.get(symbol3) ?? new Decimal2(0);
|
|
341705
|
+
moved.set(symbol3, (later.held.get(symbol3) ?? new Decimal2(0)).sub(before));
|
|
341706
|
+
}
|
|
341707
|
+
return moved;
|
|
341708
|
+
}
|
|
341709
|
+
function nearestRecord(instant, records) {
|
|
341710
|
+
let record;
|
|
341711
|
+
let gap = Number.POSITIVE_INFINITY;
|
|
341712
|
+
for (const candidate of records) {
|
|
341713
|
+
const distance = Math.abs(candidate.at - instant);
|
|
341714
|
+
if (candidate.live && distance > BALANCES_REACH_MS) continue;
|
|
341715
|
+
if (distance < gap || distance === gap && record?.live && !candidate.live) {
|
|
341716
|
+
record = candidate;
|
|
341717
|
+
gap = distance;
|
|
341718
|
+
}
|
|
341719
|
+
}
|
|
341720
|
+
return record;
|
|
341721
|
+
}
|
|
341722
|
+
function inventoryAt(instant, records, trades, outflows, readings) {
|
|
341723
|
+
const record = nearestRecord(instant, records);
|
|
341724
|
+
if (!record) return null;
|
|
341725
|
+
const recorded = /* @__PURE__ */ new Map();
|
|
341726
|
+
for (const [symbol3, amount] of Object.entries(record.balances)) {
|
|
341727
|
+
if (Number.isFinite(amount)) add3(recorded, normalizeSymbol(symbol3), new Decimal2(amount));
|
|
341728
|
+
}
|
|
341729
|
+
const held = new Map(recorded);
|
|
341730
|
+
const after = record.at >= instant;
|
|
341731
|
+
const [from32, to] = after ? [instant, record.at] : [record.at, instant];
|
|
341732
|
+
const sign6 = after ? -1 : 1;
|
|
341733
|
+
for (const trade of trades) {
|
|
341734
|
+
if (trade.at >= from32 && trade.at < to) apply3(held, trade, sign6);
|
|
341735
|
+
}
|
|
341736
|
+
for (const outflow of outflows) {
|
|
341737
|
+
if (outflow.at >= from32 && outflow.at < to) {
|
|
341738
|
+
add3(held, normalizeSymbol(outflow.symbol), new Decimal2(outflow.amount).mul(-sign6));
|
|
341739
|
+
}
|
|
341740
|
+
}
|
|
341741
|
+
const moved = movedBetween(readings.get(from32), readings.get(to));
|
|
341742
|
+
if (moved) {
|
|
341743
|
+
for (const [symbol3, amount] of moved) {
|
|
341744
|
+
held.set(symbol3, (recorded.get(symbol3) ?? new Decimal2(0)).add(amount.mul(sign6)));
|
|
341745
|
+
}
|
|
341746
|
+
}
|
|
341747
|
+
for (const [symbol3, amount] of held) if (amount.isNegative()) held.set(symbol3, new Decimal2(0));
|
|
341748
|
+
return { held, record };
|
|
341749
|
+
}
|
|
341750
|
+
function tradesOf(fills, now) {
|
|
341751
|
+
const trades = [];
|
|
341752
|
+
for (const fill of fills) {
|
|
341753
|
+
const at = parseUtc(fill.filledAt);
|
|
341754
|
+
if (!Number.isFinite(at) || at > now) continue;
|
|
341755
|
+
const trade = tradeOf(fill, at);
|
|
341756
|
+
if (trade) trades.push(trade);
|
|
341757
|
+
}
|
|
341758
|
+
return trades.sort((a6, b5) => a6.at - b5.at);
|
|
341759
|
+
}
|
|
341760
|
+
function bucketStarts(period, now, offset, firstAt) {
|
|
341761
|
+
const { bucket, count } = PROFIT_PERIODS[period];
|
|
341762
|
+
const last = bucketStart(now - offset, bucket);
|
|
341763
|
+
const first3 = count === null ? bucketStart((firstAt ?? now) - offset, bucket) : shiftBucket(last, bucket, 1 - count);
|
|
341764
|
+
const starts = [];
|
|
341765
|
+
for (let start = first3; start <= last; start = shiftBucket(start, bucket, 1)) starts.push(start);
|
|
341766
|
+
return starts;
|
|
341767
|
+
}
|
|
341768
|
+
function inventoryInstants(fills, options) {
|
|
341769
|
+
const { period, now } = options;
|
|
341770
|
+
const offset = (options.tzOffsetMinutes ?? 0) * MINUTE;
|
|
341771
|
+
const records = (options.inventory ?? []).filter((record) => record.at <= now);
|
|
341772
|
+
const instants = /* @__PURE__ */ new Set([now]);
|
|
341773
|
+
for (const start of bucketStarts(period, now, offset, tradesOf(fills, now)[0]?.at)) {
|
|
341774
|
+
instants.add(start + offset);
|
|
341775
|
+
const record = nearestRecord(start + offset, records);
|
|
341776
|
+
if (record) instants.add(record.at);
|
|
341777
|
+
}
|
|
341778
|
+
return [...instants].sort((a6, b5) => a6 - b5);
|
|
341779
|
+
}
|
|
341780
|
+
function summarizeProfit(fills, options) {
|
|
341781
|
+
const { period, now } = options;
|
|
341782
|
+
const offset = (options.tzOffsetMinutes ?? 0) * MINUTE;
|
|
341783
|
+
const { bucket } = PROFIT_PERIODS[period];
|
|
341784
|
+
const records = (options.inventory ?? []).filter((record) => record.at <= now);
|
|
341785
|
+
const outflows = options.outflows ?? [];
|
|
341786
|
+
const readings = new Map((options.readings ?? []).map((reading) => [reading.at, readingOf(reading)]));
|
|
341787
|
+
const trades = tradesOf(fills, now);
|
|
341788
|
+
const starts = bucketStarts(period, now, offset, trades[0]?.at);
|
|
341789
|
+
const first3 = starts[0];
|
|
341790
|
+
const books = /* @__PURE__ */ new Map();
|
|
341791
|
+
const spelling2 = /* @__PURE__ */ new Map();
|
|
341792
|
+
for (const record of records) {
|
|
341793
|
+
for (const symbol3 of Object.keys(record.balances)) {
|
|
341794
|
+
if (!spelling2.has(normalizeSymbol(symbol3))) spelling2.set(normalizeSymbol(symbol3), symbol3);
|
|
341795
|
+
}
|
|
341796
|
+
}
|
|
341797
|
+
for (const fill of fills) {
|
|
341798
|
+
for (const symbol3 of [fill.base, fill.quote]) {
|
|
341799
|
+
if (!spelling2.has(normalizeSymbol(symbol3))) spelling2.set(normalizeSymbol(symbol3), symbol3);
|
|
341800
|
+
}
|
|
341801
|
+
}
|
|
341802
|
+
for (const trade of trades) {
|
|
341803
|
+
let book = books.get(trade.book);
|
|
341804
|
+
if (!book) {
|
|
341805
|
+
book = new BookLedger(trade.book, trade.base, trade.quote);
|
|
341806
|
+
books.set(trade.book, book);
|
|
341807
|
+
}
|
|
341808
|
+
const rate = trade.quoteAmount.div(trade.baseAmount);
|
|
341809
|
+
if (trade.buying) book.latestBuy = rate;
|
|
341810
|
+
else book.latestSell = rate;
|
|
341811
|
+
}
|
|
341812
|
+
const edges = [];
|
|
341813
|
+
for (const book of books.values()) {
|
|
341814
|
+
const rate = book.rate();
|
|
341815
|
+
if (rate && book.base !== book.quote) {
|
|
341816
|
+
edges.push({ base: book.base, quote: book.quote, rate: new Decimal(rate.toString()) });
|
|
341817
|
+
}
|
|
341818
|
+
}
|
|
341819
|
+
const factors = usdFactorsFrom(edges);
|
|
341820
|
+
const priceOf = (symbol3) => {
|
|
341821
|
+
const factor = factors.get(symbol3);
|
|
341822
|
+
return factor ? new Decimal2(factor.toString()) : null;
|
|
341823
|
+
};
|
|
341824
|
+
const unpriced = /* @__PURE__ */ new Set();
|
|
341825
|
+
const valueOf = (holdings) => {
|
|
341826
|
+
let total = new Decimal2(0);
|
|
341827
|
+
for (const [symbol3, amount] of holdings) {
|
|
341828
|
+
if (amount.isZero()) continue;
|
|
341829
|
+
const price = priceOf(symbol3);
|
|
341830
|
+
if (price) total = total.add(amount.mul(price));
|
|
341831
|
+
else unpriced.add(symbol3);
|
|
341832
|
+
}
|
|
341833
|
+
return total;
|
|
341834
|
+
};
|
|
341835
|
+
const totals = new Sums();
|
|
341836
|
+
const buckets = new Map(starts.map((start) => [start, new Sums()]));
|
|
341837
|
+
let estimatedFills = 0;
|
|
341838
|
+
for (const trade of trades) {
|
|
341839
|
+
const sums = buckets.get(bucketStart(trade.at - offset, bucket));
|
|
341840
|
+
if (!sums) continue;
|
|
341841
|
+
const book = books.get(trade.book);
|
|
341842
|
+
if (!book) continue;
|
|
341843
|
+
book.inPeriod = true;
|
|
341844
|
+
if (trade.estimated) estimatedFills += 1;
|
|
341845
|
+
if (trade.buying) {
|
|
341846
|
+
book.bought = book.bought.add(trade.baseAmount);
|
|
341847
|
+
book.boughtQuote = book.boughtQuote.add(trade.quoteAmount);
|
|
341848
|
+
} else {
|
|
341849
|
+
book.sold = book.sold.add(trade.baseAmount);
|
|
341850
|
+
book.soldQuote = book.soldQuote.add(trade.quoteAmount);
|
|
341851
|
+
}
|
|
341852
|
+
const basePrice = priceOf(trade.base);
|
|
341853
|
+
const quotePrice = priceOf(trade.quote);
|
|
341854
|
+
const volume = basePrice ? trade.baseAmount.mul(basePrice) : quotePrice ? trade.quoteAmount.mul(quotePrice) : new Decimal2(0);
|
|
341855
|
+
for (const sum2 of [totals, sums]) {
|
|
341856
|
+
apply3(sum2.change, trade, 1);
|
|
341857
|
+
if (trade.buying) {
|
|
341858
|
+
sum2.buys += 1;
|
|
341859
|
+
sum2.boughtUsd = sum2.boughtUsd.add(volume);
|
|
341860
|
+
} else {
|
|
341861
|
+
sum2.sells += 1;
|
|
341862
|
+
sum2.soldUsd = sum2.soldUsd.add(volume);
|
|
341863
|
+
}
|
|
341864
|
+
}
|
|
341865
|
+
}
|
|
341866
|
+
const figures = (sums, startsAt, endsAt) => {
|
|
341867
|
+
const profit = valueOf(sums.change);
|
|
341868
|
+
const began2 = inventoryAt(startsAt, records, trades, outflows, readings);
|
|
341869
|
+
const inventory = began2 ? valueOf(began2.held) : null;
|
|
341870
|
+
const moved = movedBetween(readings.get(startsAt), readings.get(endsAt));
|
|
341871
|
+
if (moved) {
|
|
341872
|
+
for (const [symbol3, amount] of sums.change) {
|
|
341873
|
+
if (moved.has(symbol3)) moved.set(symbol3, (moved.get(symbol3) ?? new Decimal2(0)).sub(amount));
|
|
341874
|
+
}
|
|
341875
|
+
}
|
|
341876
|
+
return {
|
|
341877
|
+
profitUsd: profit.toNumber(),
|
|
341878
|
+
startInventoryUsd: inventory ? inventory.toNumber() : null,
|
|
341879
|
+
returnPct: inventory?.gt(0) ? profit.div(inventory).mul(100).toNumber() : null,
|
|
341880
|
+
transfersUsd: moved && moved.size > 0 ? valueOf(moved).toNumber() : null,
|
|
341881
|
+
boughtUsd: sums.boughtUsd.toNumber(),
|
|
341882
|
+
soldUsd: sums.soldUsd.toNumber(),
|
|
341883
|
+
buys: sums.buys,
|
|
341884
|
+
sells: sums.sells
|
|
341885
|
+
};
|
|
341886
|
+
};
|
|
341887
|
+
const from32 = first3 + offset;
|
|
341888
|
+
const began = inventoryAt(from32, records, trades, outflows, readings);
|
|
341889
|
+
const startInventory = began && {
|
|
341890
|
+
at: from32,
|
|
341891
|
+
source: began.record.live ? "balances" : "snapshot",
|
|
341892
|
+
recordedAt: began.record.at,
|
|
341893
|
+
usd: valueOf(began.held).toNumber(),
|
|
341894
|
+
tokens: [...began.held].filter(([, amount]) => amount.gt(0)).map(([symbol3, amount]) => {
|
|
341895
|
+
const price = priceOf(symbol3);
|
|
341896
|
+
return {
|
|
341897
|
+
symbol: spelling2.get(symbol3) ?? symbol3,
|
|
341898
|
+
amount: amount.toNumber(),
|
|
341899
|
+
usd: price ? amount.mul(price).toNumber() : null
|
|
341900
|
+
};
|
|
341901
|
+
}).sort((a6, b5) => (b5.usd ?? 0) - (a6.usd ?? 0) || a6.symbol.localeCompare(b5.symbol))
|
|
341902
|
+
};
|
|
341903
|
+
const rows = [];
|
|
341904
|
+
for (const book of books.values()) {
|
|
341905
|
+
if (!book.inPeriod) continue;
|
|
341906
|
+
const averageBuy = book.bought.gt(0) ? book.boughtQuote.div(book.bought) : null;
|
|
341907
|
+
const averageSell = book.sold.gt(0) ? book.soldQuote.div(book.sold) : null;
|
|
341908
|
+
const baseChange = book.bought.sub(book.sold);
|
|
341909
|
+
const quoteChange = book.soldQuote.sub(book.boughtQuote);
|
|
341910
|
+
const basePrice = priceOf(book.base);
|
|
341911
|
+
const quotePrice = priceOf(book.quote);
|
|
341912
|
+
rows.push({
|
|
341913
|
+
book: book.id,
|
|
341914
|
+
base: spelling2.get(book.base) ?? book.base,
|
|
341915
|
+
quote: spelling2.get(book.quote) ?? book.quote,
|
|
341916
|
+
bought: book.bought.toNumber(),
|
|
341917
|
+
sold: book.sold.toNumber(),
|
|
341918
|
+
averageBuy: averageBuy ? averageBuy.toNumber() : null,
|
|
341919
|
+
averageSell: averageSell ? averageSell.toNumber() : null,
|
|
341920
|
+
spreadPct: averageBuy && averageSell ? averageSell.div(averageBuy).sub(1).mul(100).toNumber() : null,
|
|
341921
|
+
baseChange: baseChange.toNumber(),
|
|
341922
|
+
quoteChange: quoteChange.toNumber(),
|
|
341923
|
+
rate: book.rate()?.toNumber() ?? null,
|
|
341924
|
+
profitUsd: basePrice && quotePrice ? baseChange.mul(basePrice).add(quoteChange.mul(quotePrice)).toNumber() : null
|
|
341925
|
+
});
|
|
341926
|
+
}
|
|
341927
|
+
rows.sort((a6, b5) => (b5.profitUsd ?? 0) - (a6.profitUsd ?? 0) || a6.book.localeCompare(b5.book));
|
|
341928
|
+
return {
|
|
341929
|
+
period,
|
|
341930
|
+
bucket,
|
|
341931
|
+
from: from32,
|
|
341932
|
+
to: now,
|
|
341933
|
+
totals: figures(totals, from32, now),
|
|
341934
|
+
series: starts.map((start, index3) => {
|
|
341935
|
+
const sums = buckets.get(start) ?? new Sums();
|
|
341936
|
+
const endsAt = index3 + 1 < starts.length ? starts[index3 + 1] + offset : now;
|
|
341937
|
+
return { start: start + offset, ...figures(sums, start + offset, endsAt) };
|
|
341938
|
+
}),
|
|
341939
|
+
books: rows,
|
|
341940
|
+
startInventory,
|
|
341941
|
+
estimatedFills,
|
|
341942
|
+
unpricedTokens: [...unpriced].map((symbol3) => spelling2.get(symbol3) ?? symbol3).sort()
|
|
341943
|
+
};
|
|
341944
|
+
}
|
|
341945
|
+
|
|
341356
341946
|
// src/services/server/UiServer.ts
|
|
341357
341947
|
init_Logger();
|
|
341358
341948
|
|
|
@@ -343595,6 +344185,55 @@ var UiServer = class {
|
|
|
343595
344185
|
if (method !== "GET") return sendJson(res, 405, { error: "Method not allowed" });
|
|
343596
344186
|
return this.handleLimitOrders(res, () => this.operator.limitOrders.books());
|
|
343597
344187
|
}
|
|
344188
|
+
if (path2 === "/api/analytics/profitability") {
|
|
344189
|
+
if (this.mode !== "operator") return sendJson(res, 409, { error: "Filler is not running" });
|
|
344190
|
+
if (method !== "GET") return sendJson(res, 405, { error: "Method not allowed" });
|
|
344191
|
+
const params = new URL(req.url ?? "/", "http://localhost").searchParams;
|
|
344192
|
+
const period = params.get("period") ?? "7d";
|
|
344193
|
+
if (!isProfitPeriod(period)) return sendJson(res, 400, { error: "period must be 7d, 30d, 12w, 12m or all" });
|
|
344194
|
+
const tz = Number(params.get("tz") ?? 0);
|
|
344195
|
+
if (!Number.isInteger(tz) || Math.abs(tz) > 14 * 60) {
|
|
344196
|
+
return sendJson(res, 400, { error: "tz must be a whole number of minutes" });
|
|
344197
|
+
}
|
|
344198
|
+
return this.handleLimitOrders(res, () => this.operator.limitOrders.profitability(period, tz));
|
|
344199
|
+
}
|
|
344200
|
+
if (path2 === "/api/orderbook/snapshot") {
|
|
344201
|
+
if (this.mode !== "operator") return sendJson(res, 409, { error: "Filler is not running" });
|
|
344202
|
+
if (method !== "GET") return sendJson(res, 405, { error: "Method not allowed" });
|
|
344203
|
+
const params = new URL(req.url ?? "/", "http://localhost").searchParams;
|
|
344204
|
+
const book = params.get("book")?.trim();
|
|
344205
|
+
if (!book) return sendJson(res, 400, { error: "A book is required" });
|
|
344206
|
+
return this.handleLimitOrders(
|
|
344207
|
+
res,
|
|
344208
|
+
() => this.operator.limitOrders.orderbookSnapshot(book, {
|
|
344209
|
+
sourceChain: params.get("sourceChain") || void 0,
|
|
344210
|
+
fillChain: params.get("fillChain") || void 0
|
|
344211
|
+
})
|
|
344212
|
+
);
|
|
344213
|
+
}
|
|
344214
|
+
if (path2 === "/api/orderbook/level-orders") {
|
|
344215
|
+
if (this.mode !== "operator") return sendJson(res, 409, { error: "Filler is not running" });
|
|
344216
|
+
if (method !== "GET") return sendJson(res, 405, { error: "Method not allowed" });
|
|
344217
|
+
const params = new URL(req.url ?? "/", "http://localhost").searchParams;
|
|
344218
|
+
const book = params.get("book")?.trim();
|
|
344219
|
+
const side = params.get("side");
|
|
344220
|
+
const fillChain = params.get("fillChain")?.trim();
|
|
344221
|
+
const priceBucket = params.get("priceBucket")?.trim();
|
|
344222
|
+
if (!book) return sendJson(res, 400, { error: "A book is required" });
|
|
344223
|
+
if (side !== "BID" && side !== "ASK") return sendJson(res, 400, { error: "side must be BID or ASK" });
|
|
344224
|
+
if (!fillChain) return sendJson(res, 400, { error: "A fill chain is required" });
|
|
344225
|
+
if (!priceBucket || !/^\d+$/.test(priceBucket))
|
|
344226
|
+
return sendJson(res, 400, { error: "priceBucket must be an integer" });
|
|
344227
|
+
return this.handleLimitOrders(
|
|
344228
|
+
res,
|
|
344229
|
+
() => this.operator.limitOrders.orderbookLevelOrders(book, {
|
|
344230
|
+
side,
|
|
344231
|
+
fillChain,
|
|
344232
|
+
priceBucket,
|
|
344233
|
+
sourceChain: params.get("sourceChain") || void 0
|
|
344234
|
+
})
|
|
344235
|
+
);
|
|
344236
|
+
}
|
|
343598
344237
|
const limitOrderMatch = path2.match(/^\/api\/limit-orders\/([\w-]+)$/);
|
|
343599
344238
|
if (limitOrderMatch) {
|
|
343600
344239
|
if (this.mode !== "operator") return sendJson(res, 409, { error: "Filler is not running" });
|
|
@@ -344731,6 +345370,7 @@ var CacheService = class {
|
|
|
344731
345370
|
matchedLimitOrders: {},
|
|
344732
345371
|
bidPlans: {},
|
|
344733
345372
|
partialFills: {},
|
|
345373
|
+
feeChecksWaived: {},
|
|
344734
345374
|
feeTokens: {},
|
|
344735
345375
|
tokenDecimals: {},
|
|
344736
345376
|
solverSelection: {}
|
|
@@ -344770,6 +345410,10 @@ var CacheService = class {
|
|
|
344770
345410
|
stalePartialIds.forEach((orderId) => {
|
|
344771
345411
|
delete this.cacheData.partialFills[orderId];
|
|
344772
345412
|
});
|
|
345413
|
+
const staleWaivedIds = Object.entries(this.cacheData.feeChecksWaived).filter(([_5, data4]) => !this.isCacheValid(data4.timestamp)).map(([orderId]) => orderId);
|
|
345414
|
+
staleWaivedIds.forEach((orderId) => {
|
|
345415
|
+
delete this.cacheData.feeChecksWaived[orderId];
|
|
345416
|
+
});
|
|
344773
345417
|
}
|
|
344774
345418
|
getGasEstimate(orderId) {
|
|
344775
345419
|
try {
|
|
@@ -344951,6 +345595,7 @@ var CacheService = class {
|
|
|
344951
345595
|
})),
|
|
344952
345596
|
partialFill: plan.partialFill,
|
|
344953
345597
|
profit: plan.profit,
|
|
345598
|
+
...plan.inputDecimals !== void 0 ? { inputDecimals: plan.inputDecimals } : {},
|
|
344954
345599
|
...plan.budget ? { budget: budgetFromCache(plan.budget) } : {}
|
|
344955
345600
|
}));
|
|
344956
345601
|
} catch (error) {
|
|
@@ -344981,6 +345626,7 @@ var CacheService = class {
|
|
|
344981
345626
|
})),
|
|
344982
345627
|
partialFill: plan.partialFill,
|
|
344983
345628
|
profit: plan.profit,
|
|
345629
|
+
...plan.inputDecimals !== void 0 ? { inputDecimals: plan.inputDecimals } : {},
|
|
344984
345630
|
...plan.budget ? { budget: budgetToCache(plan.budget) } : {}
|
|
344985
345631
|
})),
|
|
344986
345632
|
timestamp: Date.now()
|
|
@@ -345082,6 +345728,24 @@ var CacheService = class {
|
|
|
345082
345728
|
clearPartialFill(orderId) {
|
|
345083
345729
|
delete this.cacheData.partialFills[orderId];
|
|
345084
345730
|
}
|
|
345731
|
+
/**
|
|
345732
|
+
* Whether the strategy's completed evaluation let a bid through without holding
|
|
345733
|
+
* `order.fees` to the execution cost, because the order is at or above the
|
|
345734
|
+
* operator's minimum size.
|
|
345735
|
+
*
|
|
345736
|
+
* Written and cleared the way {@link isPartialFill} is, for the same reason: the
|
|
345737
|
+
* caller exempts such an order from its profit floor.
|
|
345738
|
+
*/
|
|
345739
|
+
isFeeCheckWaived(orderId) {
|
|
345740
|
+
const cache = this.cacheData.feeChecksWaived[orderId];
|
|
345741
|
+
return cache !== void 0 && this.isCacheValid(cache.timestamp) && cache.waived;
|
|
345742
|
+
}
|
|
345743
|
+
setFeeCheckWaived(orderId, waived) {
|
|
345744
|
+
this.cacheData.feeChecksWaived[orderId] = { waived, timestamp: Date.now() };
|
|
345745
|
+
}
|
|
345746
|
+
clearFeeCheckWaived(orderId) {
|
|
345747
|
+
delete this.cacheData.feeChecksWaived[orderId];
|
|
345748
|
+
}
|
|
345085
345749
|
getFeeTokenWithDecimals(chain2) {
|
|
345086
345750
|
try {
|
|
345087
345751
|
const cache = this.cacheData.feeTokens[chain2];
|
|
@@ -350396,7 +351060,10 @@ var ContractInteractionService = class {
|
|
|
350396
351060
|
order,
|
|
350397
351061
|
prependCalls: void 0,
|
|
350398
351062
|
maxPriorityFeePerGasBumpPercent: gasFeeBumpConfig?.maxPriorityFeePerGasBumpPercent,
|
|
350399
|
-
maxFeePerGasBumpPercent: gasFeeBumpConfig?.maxFeePerGasBumpPercent
|
|
351063
|
+
maxFeePerGasBumpPercent: gasFeeBumpConfig?.maxFeePerGasBumpPercent,
|
|
351064
|
+
// No bid without the bundler's own figures: an op signed with the SDK's
|
|
351065
|
+
// fixed fallback limits does not execute, so a failed estimate skips the order.
|
|
351066
|
+
requireBundlerEstimate: true
|
|
350400
351067
|
});
|
|
350401
351068
|
this.logger.info({ orderId: order.id }, "Caching gas estimate");
|
|
350402
351069
|
this.logger.info({ estimate }, "Estimate");
|
|
@@ -350419,7 +351086,7 @@ var ContractInteractionService = class {
|
|
|
350419
351086
|
callGasLimit: estimate.callGasLimit
|
|
350420
351087
|
};
|
|
350421
351088
|
} catch (error) {
|
|
350422
|
-
this.logger.error({ err: error }, "Error estimating gas,
|
|
351089
|
+
this.logger.error({ err: error, orderId: order.id }, "Error estimating gas, not bidding on this order");
|
|
350423
351090
|
throw new Error(`Failed to estimate gas: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
350424
351091
|
}
|
|
350425
351092
|
}
|
|
@@ -384242,6 +384909,23 @@ var IntentFiller = class {
|
|
|
384242
384909
|
this.monitor.emit("orderSkipped", { orderId: order.id, reason: "watch-only" });
|
|
384243
384910
|
return null;
|
|
384244
384911
|
}
|
|
384912
|
+
const destinationHead = await this.destinationHead(order);
|
|
384913
|
+
if (destinationHead !== null && order.deadline <= destinationHead) {
|
|
384914
|
+
this.logger.info(
|
|
384915
|
+
{
|
|
384916
|
+
orderId: order.id,
|
|
384917
|
+
destChain: order.destination,
|
|
384918
|
+
deadline: order.deadline.toString(),
|
|
384919
|
+
head: destinationHead.toString()
|
|
384920
|
+
},
|
|
384921
|
+
"Skipping order: its deadline has passed on the destination chain"
|
|
384922
|
+
);
|
|
384923
|
+
this.monitor.emit("orderSkipped", {
|
|
384924
|
+
orderId: order.id,
|
|
384925
|
+
reason: "Order deadline has passed on the destination chain"
|
|
384926
|
+
});
|
|
384927
|
+
return null;
|
|
384928
|
+
}
|
|
384245
384929
|
const evalStartMs = Date.now();
|
|
384246
384930
|
const eligibleStrategies = await Promise.all(
|
|
384247
384931
|
this.strategies.map(async (strategy) => {
|
|
@@ -384251,7 +384935,10 @@ var IntentFiller = class {
|
|
|
384251
384935
|
})
|
|
384252
384936
|
);
|
|
384253
384937
|
const fillsPartially = this.fillsPartially(order);
|
|
384254
|
-
const
|
|
384938
|
+
const feeCheckWaived = this.feeCheckWaived(order);
|
|
384939
|
+
const validStrategies = eligibleStrategies.filter(
|
|
384940
|
+
(s4) => s4 !== null && (s4.profitability > 0 || fillsPartially || feeCheckWaived)
|
|
384941
|
+
).sort((a6, b5) => b5.profitability - a6.profitability);
|
|
384255
384942
|
const evalDurationSec = (Date.now() - evalStartMs) / 1e3;
|
|
384256
384943
|
this.monitor.emit("orderTiming", { orderId: order.id, phase: "evaluation", durationSec: evalDurationSec });
|
|
384257
384944
|
if (validStrategies.length === 0) {
|
|
@@ -384276,6 +384963,23 @@ var IntentFiller = class {
|
|
|
384276
384963
|
);
|
|
384277
384964
|
return validStrategies[0];
|
|
384278
384965
|
}
|
|
384966
|
+
/**
|
|
384967
|
+
* The destination chain's latest block number, the clock `order.deadline` is read on.
|
|
384968
|
+
*
|
|
384969
|
+
* Null when the read fails. That is not an answer about the order, so evaluation goes
|
|
384970
|
+
* on: the gas estimate simulates the same deadline check and refuses an expired order.
|
|
384971
|
+
*/
|
|
384972
|
+
async destinationHead(order) {
|
|
384973
|
+
try {
|
|
384974
|
+
return await this.chainClientManager.getPublicClient(order.destination).getBlockNumber();
|
|
384975
|
+
} catch (err) {
|
|
384976
|
+
this.logger.warn(
|
|
384977
|
+
{ orderId: order.id, destChain: order.destination, err },
|
|
384978
|
+
"Could not read the destination head to check the order's deadline"
|
|
384979
|
+
);
|
|
384980
|
+
return null;
|
|
384981
|
+
}
|
|
384982
|
+
}
|
|
384279
384983
|
/**
|
|
384280
384984
|
* Whether the strategy's evaluation concluded in a deliberate partial fill.
|
|
384281
384985
|
*
|
|
@@ -384289,6 +384993,15 @@ var IntentFiller = class {
|
|
|
384289
384993
|
if (!order.id) return false;
|
|
384290
384994
|
return this.contractService.cacheService.isPartialFill(order.id);
|
|
384291
384995
|
}
|
|
384996
|
+
/**
|
|
384997
|
+
* Whether the strategy's evaluation let a bid through without the fee check, because
|
|
384998
|
+
* the order is at or above the operator's minimum size. Read from a flag the strategy
|
|
384999
|
+
* sets only once it has an answer, as {@link fillsPartially} is.
|
|
385000
|
+
*/
|
|
385001
|
+
feeCheckWaived(order) {
|
|
385002
|
+
if (!order.id) return false;
|
|
385003
|
+
return this.contractService.cacheService.isFeeCheckWaived(order.id);
|
|
385004
|
+
}
|
|
384292
385005
|
executeOrder(order, bestStrategy, solverSelectionActive, inputUsdValue, profitUsd) {
|
|
384293
385006
|
const chainQueue = this.chainQueues.get(getChainId3(order.destination));
|
|
384294
385007
|
if (!chainQueue) {
|
|
@@ -384316,7 +385029,12 @@ var IntentFiller = class {
|
|
|
384316
385029
|
else cache.clearFundingPrepends(order.id);
|
|
384317
385030
|
}
|
|
384318
385031
|
reservation = await this.holdAll([
|
|
384319
|
-
{
|
|
385032
|
+
{
|
|
385033
|
+
limitOrderId: plan.limitOrderId,
|
|
385034
|
+
payout: plan.payout,
|
|
385035
|
+
take: plan.fillerInputs[plan.leg]?.amount,
|
|
385036
|
+
takeDecimals: plan.inputDecimals
|
|
385037
|
+
}
|
|
384320
385038
|
]);
|
|
384321
385039
|
if (reservation.length === 0) {
|
|
384322
385040
|
this.logger.info(
|
|
@@ -384486,7 +385204,8 @@ var IntentFiller = class {
|
|
|
384486
385204
|
taken.push({
|
|
384487
385205
|
limitOrderId: hold.limitOrderId,
|
|
384488
385206
|
amount,
|
|
384489
|
-
...hold.take !== void 0 ? { take: hold.take.toString() } : {}
|
|
385207
|
+
...hold.take !== void 0 ? { take: hold.take.toString() } : {},
|
|
385208
|
+
...hold.takeDecimals !== void 0 ? { takeDecimals: hold.takeDecimals } : {}
|
|
384490
385209
|
});
|
|
384491
385210
|
}
|
|
384492
385211
|
return taken;
|
|
@@ -384513,6 +385232,7 @@ var IntentFiller = class {
|
|
|
384513
385232
|
}
|
|
384514
385233
|
const settled = executedHold(claimed, delivered.scaled, released);
|
|
384515
385234
|
const charged = chargedFor(settled, delivered, released);
|
|
385235
|
+
const takenIn = released > 0n && settled.takeDecimals !== void 0 ? toScaled(released, settled.takeDecimals) : null;
|
|
384516
385236
|
const settledBid = rows.find(
|
|
384517
385237
|
(row) => row.reservations.some(
|
|
384518
385238
|
(hold) => hold.limitOrderId === settled.limitOrderId && hold.amount === settled.amount && hold.take === settled.take
|
|
@@ -384531,6 +385251,7 @@ var IntentFiller = class {
|
|
|
384531
385251
|
commitment,
|
|
384532
385252
|
bid: settledBid,
|
|
384533
385253
|
amount: share.toString(),
|
|
385254
|
+
amountIn: takenIn?.toString() ?? null,
|
|
384534
385255
|
transactionHash: transactionHash ?? null
|
|
384535
385256
|
});
|
|
384536
385257
|
}
|
|
@@ -384683,45 +385404,6 @@ init_esm();
|
|
|
384683
385404
|
init_Logger();
|
|
384684
385405
|
init_asset_registry();
|
|
384685
385406
|
init_decimal();
|
|
384686
|
-
|
|
384687
|
-
// src/orderbook/usd.ts
|
|
384688
|
-
init_esm_shims();
|
|
384689
|
-
init_decimal();
|
|
384690
|
-
init_asset_registry();
|
|
384691
|
-
function limitOrderUsdEdges(orders) {
|
|
384692
|
-
return orders.filter((order) => normalizeSymbol(order.base) !== normalizeSymbol(order.quote)).map((order) => ({
|
|
384693
|
-
base: normalizeSymbol(order.base),
|
|
384694
|
-
quote: normalizeSymbol(order.quote),
|
|
384695
|
-
rate: new Decimal(order.price).div(ORDERBOOK_SCALE2.toString())
|
|
384696
|
-
})).filter((edge) => edge.rate.isFinite() && edge.rate.gt(0));
|
|
384697
|
-
}
|
|
384698
|
-
function usdFactorsFrom(edges) {
|
|
384699
|
-
const factors = /* @__PURE__ */ new Map();
|
|
384700
|
-
for (const symbol3 of USD_STABLE_SYMBOLS) factors.set(symbol3, new Decimal(1));
|
|
384701
|
-
const ordered = [...edges].sort((a6, b5) => a6.base.localeCompare(b5.base) || a6.quote.localeCompare(b5.quote));
|
|
384702
|
-
let grew = true;
|
|
384703
|
-
while (grew) {
|
|
384704
|
-
grew = false;
|
|
384705
|
-
for (const edge of ordered) {
|
|
384706
|
-
const usdBase = factors.get(edge.base);
|
|
384707
|
-
const usdQuote = factors.get(edge.quote);
|
|
384708
|
-
if (usdBase && !usdQuote) {
|
|
384709
|
-
factors.set(edge.quote, usdBase.div(edge.rate));
|
|
384710
|
-
grew = true;
|
|
384711
|
-
} else if (usdQuote && !usdBase) {
|
|
384712
|
-
factors.set(edge.base, usdQuote.mul(edge.rate));
|
|
384713
|
-
grew = true;
|
|
384714
|
-
}
|
|
384715
|
-
}
|
|
384716
|
-
}
|
|
384717
|
-
return factors;
|
|
384718
|
-
}
|
|
384719
|
-
function usdValueOf(factors, symbol3, amount) {
|
|
384720
|
-
const factor = factors.get(normalizeSymbol(symbol3));
|
|
384721
|
-
return factor ? amount.mul(factor) : null;
|
|
384722
|
-
}
|
|
384723
|
-
|
|
384724
|
-
// src/strategies/fx.ts
|
|
384725
385407
|
function adjustDecimalsFloor(amount, fromDecimals, toDecimals) {
|
|
384726
385408
|
if (fromDecimals === toDecimals) return amount;
|
|
384727
385409
|
if (fromDecimals < toDecimals) return amount * BigInt(10 ** (toDecimals - fromDecimals));
|
|
@@ -384865,11 +385547,13 @@ var FXFiller = class _FXFiller {
|
|
|
384865
385547
|
* - Treat a payout below the ask as a partial fill, which only orders
|
|
384866
385548
|
* without output calldata and without an earlier partial fill allow.
|
|
384867
385549
|
* - Cap each payout by the filler's balance plus funding-venue withdrawals,
|
|
384868
|
-
* then gate it on fees (full fills) and the
|
|
385550
|
+
* then gate it on fees (full fills of orders below `minOrderSizeUsd`) and the
|
|
385551
|
+
* same-asset spread.
|
|
384869
385552
|
* - Cache the resulting bids for later use in `executeOrder`.
|
|
384870
385553
|
*/
|
|
384871
385554
|
async calculateProfitability(order) {
|
|
384872
385555
|
if (order.id) this.contractService.cacheService.clearPartialFill(order.id);
|
|
385556
|
+
if (order.id) this.contractService.cacheService.clearFeeCheckWaived(order.id);
|
|
384873
385557
|
if (this.halted) {
|
|
384874
385558
|
this.logger.warn({ orderId: order.id }, "FXFiller halted \u2014 rejecting order");
|
|
384875
385559
|
return 0;
|
|
@@ -384885,6 +385569,15 @@ var FXFiller = class _FXFiller {
|
|
|
384885
385569
|
const plans = [];
|
|
384886
385570
|
const plannedOn = /* @__PURE__ */ new Map();
|
|
384887
385571
|
const spentOn = /* @__PURE__ */ new Map();
|
|
385572
|
+
let atOrAboveMinSize;
|
|
385573
|
+
const feeCheckWaived = async () => {
|
|
385574
|
+
if (atOrAboveMinSize === void 0) {
|
|
385575
|
+
const usd = await this.getOrderUsdValue(order);
|
|
385576
|
+
atOrAboveMinSize = usd !== null && usd.inputUsd.gte(this.configService.getMinOrderSizeUsd());
|
|
385577
|
+
}
|
|
385578
|
+
return atOrAboveMinSize;
|
|
385579
|
+
};
|
|
385580
|
+
let feesWaived = false;
|
|
384888
385581
|
for (let leg = 0; leg < order.inputs.length; leg++) {
|
|
384889
385582
|
const input = order.inputs[leg];
|
|
384890
385583
|
const output3 = order.output.assets[leg];
|
|
@@ -385128,17 +385821,21 @@ var FXFiller = class _FXFiller {
|
|
|
385128
385821
|
const executionCost = totalCostInSourceFeeToken + relayerFeeInSourceFeeToken;
|
|
385129
385822
|
const partialEdgeUsd = sameAssetEdgeUsd.plus(payoutSurplusUsd);
|
|
385130
385823
|
if (!partialFill && order.fees < executionCost) {
|
|
385131
|
-
|
|
385132
|
-
|
|
385133
|
-
|
|
385134
|
-
|
|
385135
|
-
|
|
385136
|
-
|
|
385137
|
-
|
|
385138
|
-
|
|
385139
|
-
|
|
385140
|
-
|
|
385141
|
-
|
|
385824
|
+
if (!await feeCheckWaived()) {
|
|
385825
|
+
this.logger.info(
|
|
385826
|
+
{
|
|
385827
|
+
orderId: order.id,
|
|
385828
|
+
orderFees: formatUnits(order.fees, feeTokenDecimals),
|
|
385829
|
+
fillGas: formatUnits(totalCostInSourceFeeToken, feeTokenDecimals),
|
|
385830
|
+
relayerFee: formatUnits(relayerFeeInSourceFeeToken, feeTokenDecimals),
|
|
385831
|
+
executionCost: formatUnits(executionCost, feeTokenDecimals),
|
|
385832
|
+
minOrderSizeUsd: this.configService.getMinOrderSizeUsd()
|
|
385833
|
+
},
|
|
385834
|
+
"Skipping order: attached fees do not cover execution cost (fill gas + relayer fee)"
|
|
385835
|
+
);
|
|
385836
|
+
continue;
|
|
385837
|
+
}
|
|
385838
|
+
feesWaived = true;
|
|
385142
385839
|
}
|
|
385143
385840
|
if (sameAsset && !sameAssetProfitable) {
|
|
385144
385841
|
this.logger.info(
|
|
@@ -385172,7 +385869,8 @@ var FXFiller = class _FXFiller {
|
|
|
385172
385869
|
realizedSpreadProfit: formatUnits(realizedSpreadProfit, feeTokenDecimals),
|
|
385173
385870
|
payoutSurplusUsd: payoutSurplusUsd.toString(),
|
|
385174
385871
|
totalProfit,
|
|
385175
|
-
profitable: totalProfit > 0
|
|
385872
|
+
profitable: totalProfit > 0,
|
|
385873
|
+
feeCheckWaived: !partialFill && order.fees < executionCost
|
|
385176
385874
|
},
|
|
385177
385875
|
"FX swap profitability evaluation"
|
|
385178
385876
|
);
|
|
@@ -385186,6 +385884,7 @@ var FXFiller = class _FXFiller {
|
|
|
385186
385884
|
payout: toScaled(finalOutputAmount, outputDecimals),
|
|
385187
385885
|
fillerOutputs,
|
|
385188
385886
|
fillerInputs,
|
|
385887
|
+
inputDecimals,
|
|
385189
385888
|
fundingCalls: [...fundingCalls],
|
|
385190
385889
|
partialFill,
|
|
385191
385890
|
profit: totalProfit,
|
|
@@ -385204,6 +385903,7 @@ var FXFiller = class _FXFiller {
|
|
|
385204
385903
|
plans[0].budget
|
|
385205
385904
|
);
|
|
385206
385905
|
this.contractService.cacheService.setPartialFill(order.id, plans[0].partialFill);
|
|
385906
|
+
this.contractService.cacheService.setFeeCheckWaived(order.id, feesWaived);
|
|
385207
385907
|
this.contractService.cacheService.setMatchedLimitOrder(order.id, [
|
|
385208
385908
|
{ limitOrderId: plans[0].limitOrderId, payout: plans[0].payout }
|
|
385209
385909
|
]);
|
|
@@ -386470,6 +387170,7 @@ async function bootFiller(config5, options) {
|
|
|
386470
387170
|
rebalancing: config5.rebalancing,
|
|
386471
387171
|
targetGasUnits: config5.simplex.targetGasUnits,
|
|
386472
387172
|
bidValiditySeconds: config5.simplex.bidValiditySeconds,
|
|
387173
|
+
minOrderSizeUsd: config5.simplex.minOrderSizeUsd,
|
|
386473
387174
|
blockScanIntervalSeconds: config5.simplex.blockScanIntervalSeconds,
|
|
386474
387175
|
gasFeeBump: config5.simplex.gasFeeBump,
|
|
386475
387176
|
overfillProtection: config5.simplex.overfillProtection,
|
|
@@ -386678,9 +387379,10 @@ async function bootFiller(config5, options) {
|
|
|
386678
387379
|
const activity = new ActivityRecorder(options.data.activity, options.loggers, { describeToken });
|
|
386679
387380
|
activity.attach(intentFiller.monitor);
|
|
386680
387381
|
const network = resolvedChains.some((chain2) => chainByChainId(chain2.chainId)?.network === "testnet") ? "testnet" : "mainnet";
|
|
387382
|
+
const indexerUrl = config5.simplex.indexerUrl ?? DEFAULT_INDEXER_URLS[network];
|
|
386681
387383
|
void backfillOrderSummaries({
|
|
386682
387384
|
store: options.data.activity,
|
|
386683
|
-
indexerUrl
|
|
387385
|
+
indexerUrl,
|
|
386684
387386
|
fillerAddress: runtimeSigner.address,
|
|
386685
387387
|
describeToken,
|
|
386686
387388
|
onUpdated: (rows) => {
|
|
@@ -386746,6 +387448,15 @@ async function bootFiller(config5, options) {
|
|
|
386746
387448
|
vaultVenue?.startSweeping();
|
|
386747
387449
|
started.push(() => balanceProvider.stop());
|
|
386748
387450
|
await balanceProvider.start();
|
|
387451
|
+
if (options.signer) {
|
|
387452
|
+
const inventoryRecorder = new InventoryRecorder(
|
|
387453
|
+
options.data.inventory,
|
|
387454
|
+
balanceProvider,
|
|
387455
|
+
moduleLogger(options.loggers, "inventory")
|
|
387456
|
+
);
|
|
387457
|
+
started.push(() => inventoryRecorder.stop());
|
|
387458
|
+
inventoryRecorder.start();
|
|
387459
|
+
}
|
|
386749
387460
|
const watchOnlyChains = watchOnlyConfig ? Object.entries(watchOnlyConfig).filter(([, value]) => value === true).map(([chainId]) => Number.parseInt(chainId, 10)) : [];
|
|
386750
387461
|
logger8.info(
|
|
386751
387462
|
{
|
|
@@ -386791,6 +387502,8 @@ async function bootFiller(config5, options) {
|
|
|
386791
387502
|
rebalancingService,
|
|
386792
387503
|
resolvedChains,
|
|
386793
387504
|
fillerAddress: runtimeSigner.address,
|
|
387505
|
+
indexerUrl,
|
|
387506
|
+
describeToken,
|
|
386794
387507
|
watchOnly: watchOnlyConfig,
|
|
386795
387508
|
config: config5,
|
|
386796
387509
|
configPath: options.configPath,
|
|
@@ -387074,10 +387787,20 @@ var MemoryLimitOrderStore = class {
|
|
|
387074
387787
|
commitment: fill.commitment,
|
|
387075
387788
|
bid: fill.bid ?? null,
|
|
387076
387789
|
amount: fill.amount,
|
|
387790
|
+
amountIn: fill.amountIn ?? null,
|
|
387077
387791
|
transactionHash: fill.transactionHash ?? null,
|
|
387078
387792
|
filledAt: sqliteDatetime(/* @__PURE__ */ new Date())
|
|
387079
387793
|
});
|
|
387080
387794
|
}
|
|
387795
|
+
async fillHistory() {
|
|
387796
|
+
return this.fillRows.flatMap((fill) => {
|
|
387797
|
+
const order = this.orders.get(fill.limitOrderId);
|
|
387798
|
+
if (!order) return [];
|
|
387799
|
+
const { id: id2, limitOrderId, amount, amountIn, filledAt } = fill;
|
|
387800
|
+
const { book, base: base4, quote, side, price } = order;
|
|
387801
|
+
return [{ id: id2, limitOrderId, book, base: base4, quote, side, price, amount, amountIn, filledAt }];
|
|
387802
|
+
});
|
|
387803
|
+
}
|
|
387081
387804
|
async fills(limitOrderId, limit = 100) {
|
|
387082
387805
|
return this.fillRows.filter((fill) => fill.limitOrderId === limitOrderId).slice(-capLimit(limit)).reverse().map((fill) => ({ ...fill }));
|
|
387083
387806
|
}
|
|
@@ -387184,12 +387907,29 @@ var MemoryStateStore = class {
|
|
|
387184
387907
|
this.state = { ...state };
|
|
387185
387908
|
}
|
|
387186
387909
|
};
|
|
387910
|
+
var MemoryInventoryStore = class {
|
|
387911
|
+
constructor() {
|
|
387912
|
+
this.rows = [];
|
|
387913
|
+
}
|
|
387914
|
+
async record(balances) {
|
|
387915
|
+
this.rows.push({ id: this.rows.length + 1, takenAt: sqliteDatetime(/* @__PURE__ */ new Date()), balances: { ...balances } });
|
|
387916
|
+
}
|
|
387917
|
+
async latest() {
|
|
387918
|
+
const last = this.rows[this.rows.length - 1];
|
|
387919
|
+
return last ? { ...last, balances: { ...last.balances } } : null;
|
|
387920
|
+
}
|
|
387921
|
+
async since(from32) {
|
|
387922
|
+
const cutoff = sqliteDatetime(from32);
|
|
387923
|
+
return this.rows.filter((row) => row.takenAt >= cutoff).map((row) => ({ ...row, balances: { ...row.balances } }));
|
|
387924
|
+
}
|
|
387925
|
+
};
|
|
387187
387926
|
var MemoryDataStore = class {
|
|
387188
387927
|
constructor() {
|
|
387189
387928
|
this.bids = new MemoryBidStore();
|
|
387190
387929
|
this.activity = new MemoryActivityStore();
|
|
387191
387930
|
this.state = new MemoryStateStore();
|
|
387192
387931
|
this.limitOrders = new MemoryLimitOrderStore();
|
|
387932
|
+
this.inventory = new MemoryInventoryStore();
|
|
387193
387933
|
}
|
|
387194
387934
|
};
|
|
387195
387935
|
|
|
@@ -387801,6 +388541,107 @@ var OrderScanner = class _OrderScanner {
|
|
|
387801
388541
|
}
|
|
387802
388542
|
};
|
|
387803
388543
|
|
|
388544
|
+
// src/data/indexer-inventory.ts
|
|
388545
|
+
init_esm_shims();
|
|
388546
|
+
init_esm();
|
|
388547
|
+
var READ_TIMEOUT_MS = 1e4;
|
|
388548
|
+
var SETTLED_AFTER_MS = 10 * 6e4;
|
|
388549
|
+
var BATCH = 40;
|
|
388550
|
+
var MAX_KEPT = 2e3;
|
|
388551
|
+
var IndexerInventory = class {
|
|
388552
|
+
constructor(options) {
|
|
388553
|
+
this.options = options;
|
|
388554
|
+
this.kept = /* @__PURE__ */ new Map();
|
|
388555
|
+
this.described = /* @__PURE__ */ new Map();
|
|
388556
|
+
this.fetch = options.fetch ?? fetch;
|
|
388557
|
+
}
|
|
388558
|
+
/**
|
|
388559
|
+
* A reading for each of `instants` the indexer could answer for. Never rejects: an instant it
|
|
388560
|
+
* could not be asked about is simply missing from the answer.
|
|
388561
|
+
*/
|
|
388562
|
+
async at(instants, now) {
|
|
388563
|
+
const readings = [];
|
|
388564
|
+
const wanted = [];
|
|
388565
|
+
for (const instant of new Set(instants)) {
|
|
388566
|
+
const kept = this.kept.get(instant);
|
|
388567
|
+
if (kept) readings.push(kept);
|
|
388568
|
+
else wanted.push(instant);
|
|
388569
|
+
}
|
|
388570
|
+
try {
|
|
388571
|
+
for (let index3 = 0; index3 < wanted.length; index3 += BATCH) {
|
|
388572
|
+
for (const reading of await this.read(wanted.slice(index3, index3 + BATCH))) {
|
|
388573
|
+
readings.push(reading);
|
|
388574
|
+
if (reading.at <= now - SETTLED_AFTER_MS) this.keep(reading);
|
|
388575
|
+
}
|
|
388576
|
+
}
|
|
388577
|
+
} catch (err) {
|
|
388578
|
+
this.options.logger.warn(
|
|
388579
|
+
{ err: err instanceof Error ? err.message : String(err) },
|
|
388580
|
+
"Could not read inventory from the indexer; carrying records by fills and sends alone"
|
|
388581
|
+
);
|
|
388582
|
+
}
|
|
388583
|
+
return readings;
|
|
388584
|
+
}
|
|
388585
|
+
keep(reading) {
|
|
388586
|
+
if (this.kept.size >= MAX_KEPT) this.kept.clear();
|
|
388587
|
+
this.kept.set(reading.at, reading);
|
|
388588
|
+
}
|
|
388589
|
+
/** One request for several instants, each its own aliased query at that moment in history. */
|
|
388590
|
+
async read(instants) {
|
|
388591
|
+
const queries = instants.map(
|
|
388592
|
+
(instant, index3) => `r${index3}: solverInventories(filter: { solver: { equalTo: $solver } }, blockHeight: "${Math.floor(instant)}", first: 1000) { nodes { chain tokenAddress balance } }`
|
|
388593
|
+
);
|
|
388594
|
+
const response = await this.fetch(this.options.indexerUrl, {
|
|
388595
|
+
method: "POST",
|
|
388596
|
+
headers: { "content-type": "application/json" },
|
|
388597
|
+
body: JSON.stringify({
|
|
388598
|
+
query: `query SolverInventory($solver: String!) {
|
|
388599
|
+
${queries.join("\n")}
|
|
388600
|
+
}`,
|
|
388601
|
+
variables: { solver: this.options.solver.toLowerCase() }
|
|
388602
|
+
}),
|
|
388603
|
+
signal: AbortSignal.timeout(READ_TIMEOUT_MS)
|
|
388604
|
+
});
|
|
388605
|
+
if (!response.ok) throw new Error(`Indexer responded ${response.status}`);
|
|
388606
|
+
const body = await response.json();
|
|
388607
|
+
if (body.errors?.length) throw new Error(body.errors.map((error) => error.message).join("; "));
|
|
388608
|
+
const readings = [];
|
|
388609
|
+
for (const [index3, instant] of instants.entries()) {
|
|
388610
|
+
const rows = body.data?.[`r${index3}`]?.nodes;
|
|
388611
|
+
if (rows) readings.push(await this.readingOf(instant, rows));
|
|
388612
|
+
}
|
|
388613
|
+
return readings;
|
|
388614
|
+
}
|
|
388615
|
+
async readingOf(at, rows) {
|
|
388616
|
+
const balances = {};
|
|
388617
|
+
const chains2 = {};
|
|
388618
|
+
for (const row of rows) {
|
|
388619
|
+
const token = await this.describe(row.chain, row.tokenAddress);
|
|
388620
|
+
if (!token) continue;
|
|
388621
|
+
let amount;
|
|
388622
|
+
try {
|
|
388623
|
+
amount = Number(formatUnits(BigInt(row.balance), token.decimals));
|
|
388624
|
+
} catch {
|
|
388625
|
+
continue;
|
|
388626
|
+
}
|
|
388627
|
+
balances[token.symbol] = (balances[token.symbol] ?? 0) + amount;
|
|
388628
|
+
chains2[token.symbol] = [...chains2[token.symbol] ?? [], row.chain];
|
|
388629
|
+
}
|
|
388630
|
+
return { at, balances, chains: chains2 };
|
|
388631
|
+
}
|
|
388632
|
+
/** A token's symbol and decimals, remembered once both are known. */
|
|
388633
|
+
async describe(chain2, token) {
|
|
388634
|
+
const key = `${chain2}:${token.toLowerCase()}`;
|
|
388635
|
+
const known3 = this.described.get(key);
|
|
388636
|
+
if (known3) return known3;
|
|
388637
|
+
const { symbol: symbol3, decimals } = await this.options.describeToken(chain2, token);
|
|
388638
|
+
if (!symbol3 || decimals === null) return null;
|
|
388639
|
+
const description = { symbol: symbol3, decimals };
|
|
388640
|
+
this.described.set(key, description);
|
|
388641
|
+
return description;
|
|
388642
|
+
}
|
|
388643
|
+
};
|
|
388644
|
+
|
|
387804
388645
|
// src/simplex.ts
|
|
387805
388646
|
var EVENT_MAP = {
|
|
387806
388647
|
newOrder: "order:detected",
|
|
@@ -387846,10 +388687,66 @@ var LimitOrderController = class {
|
|
|
387846
388687
|
]);
|
|
387847
388688
|
return { order, fills, bids };
|
|
387848
388689
|
}
|
|
388690
|
+
/**
|
|
388691
|
+
* What the operator's buys and sells earned over `period`, bucketed on a clock
|
|
388692
|
+
* `tzOffsetMinutes` behind UTC.
|
|
388693
|
+
*
|
|
388694
|
+
* Profit is the change the period's fills made to what the solver holds, and
|
|
388695
|
+
* it is compared with the inventory the period began with. That inventory
|
|
388696
|
+
* comes from the stored snapshots and, when the balances have been read in
|
|
388697
|
+
* full, from what is held now, each carried to the period's start by what
|
|
388698
|
+
* moved between. The indexer says what moved, deposits and withdrawals
|
|
388699
|
+
* included, wherever it has followed the solver; elsewhere the fills and
|
|
388700
|
+
* sends on record stand in. It answers whether or not an orderbook is
|
|
388701
|
+
* configured, and whether or not the indexer does.
|
|
388702
|
+
*/
|
|
388703
|
+
async profitability(period, tzOffsetMinutes = 0) {
|
|
388704
|
+
const now = Date.now();
|
|
388705
|
+
const { data: data4, balanceProvider } = this.runtime;
|
|
388706
|
+
const [fills, snapshots, ledger] = await Promise.all([
|
|
388707
|
+
data4.limitOrders.fillHistory(),
|
|
388708
|
+
data4.inventory.since(/* @__PURE__ */ new Date(0)),
|
|
388709
|
+
data4.activity.walletTxs(500)
|
|
388710
|
+
]);
|
|
388711
|
+
const inventory = snapshots.map((snapshot) => ({
|
|
388712
|
+
at: parseUtc(snapshot.takenAt),
|
|
388713
|
+
balances: snapshot.balances
|
|
388714
|
+
}));
|
|
388715
|
+
const held = inventoryOf(balanceProvider.getSnapshot());
|
|
388716
|
+
if (held) inventory.push({ at: now, balances: held, live: true });
|
|
388717
|
+
const outflows = [];
|
|
388718
|
+
for (const tx of ledger) {
|
|
388719
|
+
const amount = Number(tx.amount);
|
|
388720
|
+
if (tx.kind === "send" && tx.token && Number.isFinite(amount) && amount > 0) {
|
|
388721
|
+
outflows.push({ at: tx.ts, symbol: tx.token, amount });
|
|
388722
|
+
}
|
|
388723
|
+
}
|
|
388724
|
+
const instants = inventoryInstants(fills, { period, now, tzOffsetMinutes, inventory });
|
|
388725
|
+
const readings = await this.indexerInventory().at(instants, now);
|
|
388726
|
+
return summarizeProfit(fills, { period, now, tzOffsetMinutes, inventory, outflows, readings });
|
|
388727
|
+
}
|
|
388728
|
+
/** One reader for the life of the filler, so the readings it has already fetched are kept. */
|
|
388729
|
+
indexerInventory() {
|
|
388730
|
+
this.indexed ?? (this.indexed = new IndexerInventory({
|
|
388731
|
+
indexerUrl: this.runtime.indexerUrl,
|
|
388732
|
+
solver: this.runtime.fillerAddress,
|
|
388733
|
+
describeToken: this.runtime.describeToken,
|
|
388734
|
+
logger: this.runtime.loggers.get("inventory")
|
|
388735
|
+
}));
|
|
388736
|
+
return this.indexed;
|
|
388737
|
+
}
|
|
387849
388738
|
/** The pairs the orderbook lists, the smallest payout each token may carry, and its tokens per chain. */
|
|
387850
388739
|
books() {
|
|
387851
388740
|
return this.service.books();
|
|
387852
388741
|
}
|
|
388742
|
+
/** Public bids and asks across solvers, optionally restricted to a route. */
|
|
388743
|
+
orderbookSnapshot(book, filters = {}) {
|
|
388744
|
+
return this.service.orderbookSnapshot(book, filters);
|
|
388745
|
+
}
|
|
388746
|
+
/** Every solver's order behind one public price level. */
|
|
388747
|
+
orderbookLevelOrders(book, level) {
|
|
388748
|
+
return this.service.orderbookLevelOrders(book, level);
|
|
388749
|
+
}
|
|
387853
388750
|
/** Creates the order, posts it, and reports what the orderbook made of it. */
|
|
387854
388751
|
async create(request3) {
|
|
387855
388752
|
const posted = await this.service.create(request3);
|
|
@@ -388940,6 +389837,40 @@ var SqliteBidStore = class {
|
|
|
388940
389837
|
}
|
|
388941
389838
|
};
|
|
388942
389839
|
|
|
389840
|
+
// src/data/sqlite/inventory.ts
|
|
389841
|
+
init_esm_shims();
|
|
389842
|
+
var SqliteInventoryStore = class {
|
|
389843
|
+
constructor(db) {
|
|
389844
|
+
this.db = db;
|
|
389845
|
+
this.db.exec(`
|
|
389846
|
+
CREATE TABLE IF NOT EXISTS inventory_snapshots (
|
|
389847
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
389848
|
+
taken_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
389849
|
+
balances TEXT NOT NULL
|
|
389850
|
+
);
|
|
389851
|
+
|
|
389852
|
+
CREATE INDEX IF NOT EXISTS idx_inventory_snapshots_taken_at ON inventory_snapshots(taken_at);
|
|
389853
|
+
`);
|
|
389854
|
+
}
|
|
389855
|
+
toSnapshot(row) {
|
|
389856
|
+
return { id: row.id, takenAt: row.takenAt, balances: JSON.parse(row.balances) };
|
|
389857
|
+
}
|
|
389858
|
+
async record(balances) {
|
|
389859
|
+
this.db.prepare("INSERT INTO inventory_snapshots (balances) VALUES (?)").run(JSON.stringify(balances));
|
|
389860
|
+
}
|
|
389861
|
+
async latest() {
|
|
389862
|
+
const row = this.db.prepare("SELECT id, taken_at as takenAt, balances FROM inventory_snapshots ORDER BY id DESC LIMIT 1").get();
|
|
389863
|
+
return row ? this.toSnapshot(row) : null;
|
|
389864
|
+
}
|
|
389865
|
+
async since(from32) {
|
|
389866
|
+
const cutoff = from32.toISOString().replace("T", " ").replace(/\.\d{3}Z$/, "");
|
|
389867
|
+
const rows = this.db.prepare(
|
|
389868
|
+
"SELECT id, taken_at as takenAt, balances FROM inventory_snapshots WHERE taken_at >= ? ORDER BY taken_at, id"
|
|
389869
|
+
).all(cutoff);
|
|
389870
|
+
return rows.map((row) => this.toSnapshot(row));
|
|
389871
|
+
}
|
|
389872
|
+
};
|
|
389873
|
+
|
|
388943
389874
|
// src/data/sqlite/limit-orders.ts
|
|
388944
389875
|
init_esm_shims();
|
|
388945
389876
|
init_Logger();
|
|
@@ -389013,12 +389944,17 @@ var SqliteLimitOrderStore = class {
|
|
|
389013
389944
|
commitment TEXT NOT NULL,
|
|
389014
389945
|
bid TEXT,
|
|
389015
389946
|
amount TEXT NOT NULL,
|
|
389947
|
+
amount_in TEXT,
|
|
389016
389948
|
transaction_hash TEXT,
|
|
389017
389949
|
filled_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
389018
389950
|
);
|
|
389019
389951
|
|
|
389020
389952
|
CREATE INDEX IF NOT EXISTS idx_limit_order_fills_order ON limit_order_fills(limit_order_id);
|
|
389021
389953
|
`);
|
|
389954
|
+
if (!columnNames(this.db, "limit_order_fills").has("amount_in")) {
|
|
389955
|
+
this.db.exec("ALTER TABLE limit_order_fills ADD COLUMN amount_in TEXT");
|
|
389956
|
+
this.logger.info({ column: "amount_in" }, "Migrated limit order fill schema");
|
|
389957
|
+
}
|
|
389022
389958
|
}
|
|
389023
389959
|
// biome-ignore lint/suspicious/noExplicitAny: raw sqlite row
|
|
389024
389960
|
toLimitOrder(row) {
|
|
@@ -389128,12 +390064,27 @@ var SqliteLimitOrderStore = class {
|
|
|
389128
390064
|
}
|
|
389129
390065
|
async recordFill(fill) {
|
|
389130
390066
|
this.db.prepare(
|
|
389131
|
-
"INSERT INTO limit_order_fills (limit_order_id, commitment, bid, amount, transaction_hash) VALUES (?, ?, ?, ?, ?)"
|
|
389132
|
-
).run(
|
|
390067
|
+
"INSERT INTO limit_order_fills (limit_order_id, commitment, bid, amount, amount_in, transaction_hash) VALUES (?, ?, ?, ?, ?, ?)"
|
|
390068
|
+
).run(
|
|
390069
|
+
fill.limitOrderId,
|
|
390070
|
+
fill.commitment,
|
|
390071
|
+
fill.bid ?? null,
|
|
390072
|
+
fill.amount,
|
|
390073
|
+
fill.amountIn ?? null,
|
|
390074
|
+
fill.transactionHash ?? null
|
|
390075
|
+
);
|
|
390076
|
+
}
|
|
390077
|
+
async fillHistory() {
|
|
390078
|
+
return this.db.prepare(
|
|
390079
|
+
`SELECT f.id, f.limit_order_id as limitOrderId, o.book, o.base, o.quote, o.side, o.price,
|
|
390080
|
+
f.amount, f.amount_in as amountIn, f.filled_at as filledAt
|
|
390081
|
+
FROM limit_order_fills f JOIN limit_orders o ON o.id = f.limit_order_id
|
|
390082
|
+
ORDER BY f.filled_at, f.id`
|
|
390083
|
+
).all();
|
|
389133
390084
|
}
|
|
389134
390085
|
async fills(limitOrderId, limit = 100) {
|
|
389135
390086
|
return this.db.prepare(
|
|
389136
|
-
`SELECT id, limit_order_id as limitOrderId, commitment, bid, amount, transaction_hash as transactionHash,
|
|
390087
|
+
`SELECT id, limit_order_id as limitOrderId, commitment, bid, amount, amount_in as amountIn, transaction_hash as transactionHash,
|
|
389137
390088
|
filled_at as filledAt
|
|
389138
390089
|
FROM limit_order_fills WHERE limit_order_id = ? ORDER BY id DESC LIMIT ?`
|
|
389139
390090
|
).all(limitOrderId, Math.min(Math.max(limit, 1), 500));
|
|
@@ -389322,6 +390273,7 @@ var SqliteDataStore = class {
|
|
|
389322
390273
|
this.activity = new SqliteActivityStore(activityDb, loggers);
|
|
389323
390274
|
this.state = new SqliteStateStore(bidsDb, dataDir, loggers);
|
|
389324
390275
|
this.limitOrders = new SqliteLimitOrderStore(bidsDb, loggers);
|
|
390276
|
+
this.inventory = new SqliteInventoryStore(activityDb);
|
|
389325
390277
|
this.logger.info({ dataDir }, "SQLite data store opened");
|
|
389326
390278
|
}
|
|
389327
390279
|
/**
|