@hyperbridge/simplex 0.16.12 → 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 +966 -148
- package/dist/bin/simplex.js.map +1 -1
- package/dist/index.cjs +753 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +168 -12
- package/dist/index.d.ts +168 -12
- package/dist/index.js +753 -64
- 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 +4 -4
- package/dist/ui/assets/index-QU1Ik7IX.js +0 -106
- package/dist/ui/assets/index-XKHMOpY2.css +0 -1
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);
|
|
@@ -51069,7 +51069,7 @@ var require_bn = __commonJS({
|
|
|
51069
51069
|
}
|
|
51070
51070
|
return this;
|
|
51071
51071
|
};
|
|
51072
|
-
BN3.prototype.add = function
|
|
51072
|
+
BN3.prototype.add = function add4(num2) {
|
|
51073
51073
|
var res;
|
|
51074
51074
|
if (num2.negative !== 0 && this.negative === 0) {
|
|
51075
51075
|
num2.negative = 0;
|
|
@@ -52906,7 +52906,7 @@ var require_bn = __commonJS({
|
|
|
52906
52906
|
}
|
|
52907
52907
|
return this.m.sub(a6)._forceRed(this);
|
|
52908
52908
|
};
|
|
52909
|
-
Red.prototype.add = function
|
|
52909
|
+
Red.prototype.add = function add4(a6, b5) {
|
|
52910
52910
|
this._verify2(a6, b5);
|
|
52911
52911
|
var res = a6.add(b5);
|
|
52912
52912
|
if (res.cmp(this.m) >= 0) {
|
|
@@ -55786,10 +55786,10 @@ var init_fflate = __esm({
|
|
|
55786
55786
|
lm = void 0;
|
|
55787
55787
|
break;
|
|
55788
55788
|
} else {
|
|
55789
|
-
let
|
|
55789
|
+
let add4 = sym - 254;
|
|
55790
55790
|
if (sym > 264) {
|
|
55791
55791
|
const i6 = sym - 257, b5 = fleb[i6];
|
|
55792
|
-
|
|
55792
|
+
add4 = bits(dat, pos, (1 << b5) - 1) + fl[i6];
|
|
55793
55793
|
pos += b5;
|
|
55794
55794
|
}
|
|
55795
55795
|
const d5 = dm[bits16(dat, pos) & dms], dsym = d5 >>> 4;
|
|
@@ -55805,7 +55805,7 @@ var init_fflate = __esm({
|
|
|
55805
55805
|
throw "unexpected EOF";
|
|
55806
55806
|
if (noBuf)
|
|
55807
55807
|
cbuf(bt + 131072);
|
|
55808
|
-
const end = bt +
|
|
55808
|
+
const end = bt + add4;
|
|
55809
55809
|
for (; bt < end; bt += 4) {
|
|
55810
55810
|
buf[bt] = buf[bt - dt];
|
|
55811
55811
|
buf[bt + 1] = buf[bt + 1 - dt];
|
|
@@ -83509,15 +83509,15 @@ var require_fromEvent = __commonJS({
|
|
|
83509
83509
|
return function(handler) {
|
|
83510
83510
|
return target[methodName](eventName, handler, options);
|
|
83511
83511
|
};
|
|
83512
|
-
}) : isNodeStyleEventEmitter(target) ? nodeEventEmitterMethods.map(toCommonHandlerRegistry(target, eventName)) : isJQueryStyleEventEmitter(target) ? jqueryMethods.map(toCommonHandlerRegistry(target, eventName)) : [], 2),
|
|
83513
|
-
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) {
|
|
83514
83514
|
if (isArrayLike_1.isArrayLike(target)) {
|
|
83515
83515
|
return mergeMap_1.mergeMap(function(subTarget) {
|
|
83516
83516
|
return fromEvent(subTarget, eventName, options);
|
|
83517
83517
|
})(innerFrom_1.innerFrom(target));
|
|
83518
83518
|
}
|
|
83519
83519
|
}
|
|
83520
|
-
if (!
|
|
83520
|
+
if (!add4) {
|
|
83521
83521
|
throw new TypeError("Invalid event target");
|
|
83522
83522
|
}
|
|
83523
83523
|
return new Observable_1.Observable(function(subscriber) {
|
|
@@ -83528,7 +83528,7 @@ var require_fromEvent = __commonJS({
|
|
|
83528
83528
|
}
|
|
83529
83529
|
return subscriber.next(1 < args.length ? args : args[0]);
|
|
83530
83530
|
};
|
|
83531
|
-
|
|
83531
|
+
add4(handler);
|
|
83532
83532
|
return function() {
|
|
83533
83533
|
return remove(handler);
|
|
83534
83534
|
};
|
|
@@ -233930,8 +233930,8 @@ function addToExternrefTable0(obj) {
|
|
|
233930
233930
|
function passArrayJsValueToWasm0(array, malloc) {
|
|
233931
233931
|
const ptr = malloc(array.length * 4, 4) >>> 0;
|
|
233932
233932
|
for (let i6 = 0; i6 < array.length; i6++) {
|
|
233933
|
-
const
|
|
233934
|
-
getDataViewMemory0().setUint32(ptr + 4 * i6,
|
|
233933
|
+
const add4 = addToExternrefTable0(array[i6]);
|
|
233934
|
+
getDataViewMemory0().setUint32(ptr + 4 * i6, add4, true);
|
|
233935
233935
|
}
|
|
233936
233936
|
WASM_VECTOR_LEN = array.length;
|
|
233937
233937
|
return ptr;
|
|
@@ -247568,9 +247568,17 @@ query OrderStatus($commitment: String!) {
|
|
|
247568
247568
|
* order. Frontends can use `relayerFee` to approve the ERC-20 spend before
|
|
247569
247569
|
* submitting the cancel transaction.
|
|
247570
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
|
+
*
|
|
247571
247578
|
* @param order - The order to quote.
|
|
247572
247579
|
* @param options - Choose the initiation side. Defaults to source-side cancellation.
|
|
247573
|
-
* @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;
|
|
247574
247582
|
* `{ relayerFee }` — relayer incentive denominated in the chain's fee token.
|
|
247575
247583
|
*/
|
|
247576
247584
|
async quoteCancelOrder(order, options = {}) {
|
|
@@ -247584,11 +247592,12 @@ query OrderStatus($commitment: String!) {
|
|
|
247584
247592
|
*
|
|
247585
247593
|
* Constructs the ISMP GET request the source gateway will dispatch, one
|
|
247586
247594
|
* `_partialFills` key per leg, and calls `quoteNative` on the source host to
|
|
247587
|
-
* 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.
|
|
247588
247597
|
* Returns 0 for same-chain orders (no ISMP call needed).
|
|
247589
247598
|
*
|
|
247590
247599
|
* @param order - The order to quote.
|
|
247591
|
-
* @returns The native token dispatch fee in wei.
|
|
247600
|
+
* @returns The native token dispatch fee in wei and the relayer fee.
|
|
247592
247601
|
*/
|
|
247593
247602
|
async quoteCancelFromSource(order) {
|
|
247594
247603
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
@@ -247596,6 +247605,14 @@ query OrderStatus($commitment: String!) {
|
|
|
247596
247605
|
if (sourceStateMachine === destStateMachine) {
|
|
247597
247606
|
return { nativeValue: 0n, relayerFee: 0n };
|
|
247598
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 };
|
|
247599
247616
|
const height = order.deadline + 1n;
|
|
247600
247617
|
const destIntentGateway = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachine);
|
|
247601
247618
|
const commitment = this.orderId(order);
|
|
@@ -247604,20 +247621,13 @@ query OrderStatus($commitment: String!) {
|
|
|
247604
247621
|
const getRequest = {
|
|
247605
247622
|
source: sourceStateMachine,
|
|
247606
247623
|
dest: destStateMachine,
|
|
247607
|
-
from: this.ctx.source.configService.getIntentGatewayAddress(
|
|
247624
|
+
from: this.ctx.source.configService.getIntentGatewayAddress(sourceStateMachine),
|
|
247608
247625
|
nonce: await this.ctx.source.getHostNonce(),
|
|
247609
247626
|
height,
|
|
247610
247627
|
keys: keys3,
|
|
247611
247628
|
timeoutTimestamp: 0n,
|
|
247612
247629
|
context
|
|
247613
247630
|
};
|
|
247614
|
-
const feeInSourceFeeToken = await convertGasToFeeToken(
|
|
247615
|
-
this.ctx,
|
|
247616
|
-
_a6.SOURCE_GET_RESPONSE_GAS,
|
|
247617
|
-
"source",
|
|
247618
|
-
sourceStateMachine
|
|
247619
|
-
);
|
|
247620
|
-
const relayerFee = feeInSourceFeeToken * 1005n / 1000n;
|
|
247621
247631
|
const nativeValue = await this.ctx.source.quoteNative(getRequest, relayerFee) * 101n / 100n;
|
|
247622
247632
|
return { nativeValue, relayerFee };
|
|
247623
247633
|
}
|
|
@@ -247638,7 +247648,10 @@ query OrderStatus($commitment: String!) {
|
|
|
247638
247648
|
* cancellation. Same-chain orders always use the direct local route.
|
|
247639
247649
|
* @yields {@link CancelEvent} objects describing each stage of the
|
|
247640
247650
|
* cancellation lifecycle. The caller signs or broadcasts the yielded
|
|
247641
|
-
* 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.
|
|
247642
247655
|
*/
|
|
247643
247656
|
async *cancelOrder(order, indexerClient, options = {}) {
|
|
247644
247657
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
@@ -247858,11 +247871,13 @@ query OrderStatus($commitment: String!) {
|
|
|
247858
247871
|
*
|
|
247859
247872
|
* Estimates the relayer fee for delivering the refund POST request from the
|
|
247860
247873
|
* destination chain back to the source chain, converts it to the destination
|
|
247861
|
-
* 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.
|
|
247862
247877
|
* Returns 0 for same-chain orders.
|
|
247863
247878
|
*
|
|
247864
247879
|
* @param order - The order to quote.
|
|
247865
|
-
* @returns The native token dispatch fee in wei.
|
|
247880
|
+
* @returns The native token dispatch fee in wei and the relayer fee.
|
|
247866
247881
|
*/
|
|
247867
247882
|
async quoteCancelFromDest(order) {
|
|
247868
247883
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
@@ -247873,6 +247888,7 @@ query OrderStatus($commitment: String!) {
|
|
|
247873
247888
|
const destIntentGateway = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachine);
|
|
247874
247889
|
const sourceIntentGateway = this.ctx.source.configService.getIntentGatewayAddress(sourceStateMachine);
|
|
247875
247890
|
const relayerFee = await this.estimateRelayerFee(sourceStateMachine, destStateMachine);
|
|
247891
|
+
if (TESTNET_CHAINS.has(destStateMachine)) return { nativeValue: 0n, relayerFee };
|
|
247876
247892
|
const body = constructRefundEscrowRequestBody(order, order.user);
|
|
247877
247893
|
const postRequest = {
|
|
247878
247894
|
source: destStateMachine,
|
|
@@ -250232,6 +250248,8 @@ query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
|
|
|
250232
250248
|
* order. Use `relayerFee` to approve the ERC-20 spend before submitting.
|
|
250233
250249
|
* Same-chain orders use the direct local route for either `from` option and
|
|
250234
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.
|
|
250235
250253
|
*
|
|
250236
250254
|
* Delegates to {@link OrderCanceller.quoteCancelOrder}.
|
|
250237
250255
|
*
|
|
@@ -254232,7 +254250,7 @@ var require_bn2 = __commonJS({
|
|
|
254232
254250
|
}
|
|
254233
254251
|
return this;
|
|
254234
254252
|
};
|
|
254235
|
-
BN3.prototype.add = function
|
|
254253
|
+
BN3.prototype.add = function add4(num2) {
|
|
254236
254254
|
var res;
|
|
254237
254255
|
if (num2.negative !== 0 && this.negative === 0) {
|
|
254238
254256
|
num2.negative = 0;
|
|
@@ -256059,7 +256077,7 @@ var require_bn2 = __commonJS({
|
|
|
256059
256077
|
}
|
|
256060
256078
|
return this.m.sub(a6)._forceRed(this);
|
|
256061
256079
|
};
|
|
256062
|
-
Red.prototype.add = function
|
|
256080
|
+
Red.prototype.add = function add4(a6, b5) {
|
|
256063
256081
|
this._verify2(a6, b5);
|
|
256064
256082
|
var res = a6.add(b5);
|
|
256065
256083
|
if (res.cmp(this.m) >= 0) {
|
|
@@ -267070,7 +267088,7 @@ var require_namespace = __commonJS({
|
|
|
267070
267088
|
return this.nested[name3].values;
|
|
267071
267089
|
throw Error("no such enum: " + name3);
|
|
267072
267090
|
};
|
|
267073
|
-
Namespace.prototype.add = function
|
|
267091
|
+
Namespace.prototype.add = function add4(object) {
|
|
267074
267092
|
if (!(object instanceof Field6 && object.extend !== void 0 || object instanceof Type2 || object instanceof OneOf || object instanceof Enum3 || object instanceof Service || object instanceof Namespace))
|
|
267075
267093
|
throw TypeError("object must be a valid nested object");
|
|
267076
267094
|
if (!this.nested)
|
|
@@ -267450,7 +267468,7 @@ var require_service2 = __commonJS({
|
|
|
267450
267468
|
});
|
|
267451
267469
|
return this;
|
|
267452
267470
|
};
|
|
267453
|
-
Service.prototype.add = function
|
|
267471
|
+
Service.prototype.add = function add4(object) {
|
|
267454
267472
|
if (this.get(object.name))
|
|
267455
267473
|
throw Error("duplicate name '" + object.name + "' in " + this);
|
|
267456
267474
|
if (object instanceof Method2) {
|
|
@@ -268155,7 +268173,7 @@ var require_type2 = __commonJS({
|
|
|
268155
268173
|
Type2.prototype.get = function get4(name3) {
|
|
268156
268174
|
return this.fields[name3] || this.oneofs && this.oneofs[name3] || this.nested && this.nested[name3] || null;
|
|
268157
268175
|
};
|
|
268158
|
-
Type2.prototype.add = function
|
|
268176
|
+
Type2.prototype.add = function add4(object) {
|
|
268159
268177
|
if (this.get(object.name))
|
|
268160
268178
|
throw Error("duplicate name '" + object.name + "' in " + this);
|
|
268161
268179
|
if (object instanceof Field6 && object.extend === void 0) {
|
|
@@ -269066,7 +269084,7 @@ var require_oneof = __commonJS({
|
|
|
269066
269084
|
oneof.parent.add(oneof.fieldsArray[i6]);
|
|
269067
269085
|
}
|
|
269068
269086
|
}
|
|
269069
|
-
OneOf.prototype.add = function
|
|
269087
|
+
OneOf.prototype.add = function add4(field) {
|
|
269070
269088
|
if (!(field instanceof Field6))
|
|
269071
269089
|
throw TypeError("field must be a Field");
|
|
269072
269090
|
if (field.parent && field.parent !== this.parent)
|
|
@@ -269395,7 +269413,7 @@ var require_enum = __commonJS({
|
|
|
269395
269413
|
keepComments ? this.comments : void 0
|
|
269396
269414
|
]);
|
|
269397
269415
|
};
|
|
269398
|
-
Enum3.prototype.add = function
|
|
269416
|
+
Enum3.prototype.add = function add4(name3, id2, comment, options) {
|
|
269399
269417
|
if (!util7.isString(name3))
|
|
269400
269418
|
throw TypeError("name must be a string");
|
|
269401
269419
|
if (!util7.isInteger(id2))
|
|
@@ -273872,7 +273890,7 @@ var require_umd = __commonJS({
|
|
|
273872
273890
|
return this.not().add(ONE2);
|
|
273873
273891
|
};
|
|
273874
273892
|
LongPrototype.neg = LongPrototype.negate;
|
|
273875
|
-
LongPrototype.add = function
|
|
273893
|
+
LongPrototype.add = function add4(addend) {
|
|
273876
273894
|
if (!isLong(addend)) addend = fromValue(addend);
|
|
273877
273895
|
var a48 = this.high >>> 16;
|
|
273878
273896
|
var a32 = this.high & 65535;
|
|
@@ -340232,6 +340250,35 @@ var LIMITS_QUERY = `
|
|
|
340232
340250
|
chains { id name tokens { symbol decimals } }
|
|
340233
340251
|
}
|
|
340234
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;
|
|
340235
340282
|
var POSTED_ORDER_FIELDS = "commitment side status price quotedAmount advertisedSize expiresAt acceptedSources";
|
|
340236
340283
|
var SUBMIT_ORDER_MUTATION = `
|
|
340237
340284
|
mutation SubmitOrder($userOp: Bytes!) {
|
|
@@ -340296,6 +340343,44 @@ var OrderbookClient = class {
|
|
|
340296
340343
|
async limits() {
|
|
340297
340344
|
return this.request(LIMITS_QUERY, {});
|
|
340298
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
|
+
}
|
|
340299
340384
|
async submitOrder(userOp) {
|
|
340300
340385
|
const { submitOrder } = await this.request(SUBMIT_ORDER_MUTATION, { userOp });
|
|
340301
340386
|
switch (submitOrder.__typename) {
|
|
@@ -340484,16 +340569,16 @@ function signedAmounts(params) {
|
|
|
340484
340569
|
function offerFor(params) {
|
|
340485
340570
|
const { side, inputAmount, price, outputDecimals } = params;
|
|
340486
340571
|
if (price <= 0n) throw new Error("A limit order's price must be greater than zero");
|
|
340487
|
-
const
|
|
340572
|
+
const scaled2 = side === "BID" ? inputAmount * price / ORDERBOOK_SCALE2 : inputAmount * ORDERBOOK_SCALE2 / price;
|
|
340488
340573
|
const unit = outputDecimals >= 18 ? 1n : 10n ** BigInt(18 - outputDecimals);
|
|
340489
|
-
return
|
|
340574
|
+
return scaled2 / unit * unit;
|
|
340490
340575
|
}
|
|
340491
340576
|
function inputFor(params) {
|
|
340492
340577
|
const { side, outputAmount, price, inputDecimals } = params;
|
|
340493
340578
|
if (price <= 0n) throw new Error("A limit order's price must be greater than zero");
|
|
340494
|
-
const
|
|
340579
|
+
const scaled2 = side === "BID" ? divCeil2(outputAmount * ORDERBOOK_SCALE2, price) : divCeil2(outputAmount * price, ORDERBOOK_SCALE2);
|
|
340495
340580
|
const unit = inputDecimals >= 18 ? 1n : 10n ** BigInt(18 - inputDecimals);
|
|
340496
|
-
return divCeil2(
|
|
340581
|
+
return divCeil2(scaled2, unit) * unit;
|
|
340497
340582
|
}
|
|
340498
340583
|
|
|
340499
340584
|
// src/orderbook/matching.ts
|
|
@@ -340751,6 +340836,14 @@ var LimitOrderService = class {
|
|
|
340751
340836
|
throw err;
|
|
340752
340837
|
}
|
|
340753
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
|
+
}
|
|
340754
340847
|
/**
|
|
340755
340848
|
* The pairs an order can be written against, the smallest payout each token may carry, and
|
|
340756
340849
|
* the tokens the orderbook registers on each chain.
|
|
@@ -340805,16 +340898,16 @@ var LimitOrderService = class {
|
|
|
340805
340898
|
if (!this.configService.getConfiguredChainIds().includes(getChainId3(request3.fillChain) ?? -1)) {
|
|
340806
340899
|
throw new LimitOrderValidationError(`'${request3.fillChain}' is not a chain this filler is configured for`);
|
|
340807
340900
|
}
|
|
340808
|
-
const
|
|
340901
|
+
const scaled2 = { amountIn: 0n, amountOut: 0n };
|
|
340809
340902
|
for (const name3 of ["amountIn", "amountOut"]) {
|
|
340810
340903
|
try {
|
|
340811
|
-
|
|
340904
|
+
scaled2[name3] = fromHuman(request3[name3] ?? "");
|
|
340812
340905
|
} catch (err) {
|
|
340813
340906
|
throw new LimitOrderValidationError(
|
|
340814
340907
|
`${name3} must be an amount in whole tokens, like "1000" or "1500.25"; ${err.message}`
|
|
340815
340908
|
);
|
|
340816
340909
|
}
|
|
340817
|
-
if (
|
|
340910
|
+
if (scaled2[name3] <= 0n) throw new LimitOrderValidationError(`${name3} must be greater than zero`);
|
|
340818
340911
|
}
|
|
340819
340912
|
const sources = request3.acceptedSources ?? [];
|
|
340820
340913
|
if (sources.length === 0) {
|
|
@@ -340861,7 +340954,7 @@ var LimitOrderService = class {
|
|
|
340861
340954
|
);
|
|
340862
340955
|
}
|
|
340863
340956
|
const floor2 = limits.serverInfo.minOrderSizes.find((entry) => entry.symbol === request3.tokenOut);
|
|
340864
|
-
if (floor2 &&
|
|
340957
|
+
if (floor2 && scaled2.amountOut < BigInt(floor2.size)) {
|
|
340865
340958
|
throw new LimitOrderValidationError(
|
|
340866
340959
|
`amountOut is below the orderbook's dust floor for ${request3.tokenOut} (${toHuman(BigInt(floor2.size))})`
|
|
340867
340960
|
);
|
|
@@ -340871,7 +340964,7 @@ var LimitOrderService = class {
|
|
|
340871
340964
|
throw new LimitOrderValidationError(`'${symbol3}' does not resolve to a token address on ${request3.fillChain}`);
|
|
340872
340965
|
}
|
|
340873
340966
|
}
|
|
340874
|
-
return { amountIn:
|
|
340967
|
+
return { amountIn: scaled2.amountIn, amountOut: scaled2.amountOut };
|
|
340875
340968
|
}
|
|
340876
340969
|
/**
|
|
340877
340970
|
* Refuses an order the wallet cannot pay out.
|
|
@@ -341397,6 +341490,459 @@ function underFunded(entry) {
|
|
|
341397
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";
|
|
341398
341491
|
}
|
|
341399
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
|
+
|
|
341400
341946
|
// src/services/server/UiServer.ts
|
|
341401
341947
|
init_Logger();
|
|
341402
341948
|
|
|
@@ -343639,6 +344185,55 @@ var UiServer = class {
|
|
|
343639
344185
|
if (method !== "GET") return sendJson(res, 405, { error: "Method not allowed" });
|
|
343640
344186
|
return this.handleLimitOrders(res, () => this.operator.limitOrders.books());
|
|
343641
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
|
+
}
|
|
343642
344237
|
const limitOrderMatch = path2.match(/^\/api\/limit-orders\/([\w-]+)$/);
|
|
343643
344238
|
if (limitOrderMatch) {
|
|
343644
344239
|
if (this.mode !== "operator") return sendJson(res, 409, { error: "Filler is not running" });
|
|
@@ -345000,6 +345595,7 @@ var CacheService = class {
|
|
|
345000
345595
|
})),
|
|
345001
345596
|
partialFill: plan.partialFill,
|
|
345002
345597
|
profit: plan.profit,
|
|
345598
|
+
...plan.inputDecimals !== void 0 ? { inputDecimals: plan.inputDecimals } : {},
|
|
345003
345599
|
...plan.budget ? { budget: budgetFromCache(plan.budget) } : {}
|
|
345004
345600
|
}));
|
|
345005
345601
|
} catch (error) {
|
|
@@ -345030,6 +345626,7 @@ var CacheService = class {
|
|
|
345030
345626
|
})),
|
|
345031
345627
|
partialFill: plan.partialFill,
|
|
345032
345628
|
profit: plan.profit,
|
|
345629
|
+
...plan.inputDecimals !== void 0 ? { inputDecimals: plan.inputDecimals } : {},
|
|
345033
345630
|
...plan.budget ? { budget: budgetToCache(plan.budget) } : {}
|
|
345034
345631
|
})),
|
|
345035
345632
|
timestamp: Date.now()
|
|
@@ -384432,7 +385029,12 @@ var IntentFiller = class {
|
|
|
384432
385029
|
else cache.clearFundingPrepends(order.id);
|
|
384433
385030
|
}
|
|
384434
385031
|
reservation = await this.holdAll([
|
|
384435
|
-
{
|
|
385032
|
+
{
|
|
385033
|
+
limitOrderId: plan.limitOrderId,
|
|
385034
|
+
payout: plan.payout,
|
|
385035
|
+
take: plan.fillerInputs[plan.leg]?.amount,
|
|
385036
|
+
takeDecimals: plan.inputDecimals
|
|
385037
|
+
}
|
|
384436
385038
|
]);
|
|
384437
385039
|
if (reservation.length === 0) {
|
|
384438
385040
|
this.logger.info(
|
|
@@ -384602,7 +385204,8 @@ var IntentFiller = class {
|
|
|
384602
385204
|
taken.push({
|
|
384603
385205
|
limitOrderId: hold.limitOrderId,
|
|
384604
385206
|
amount,
|
|
384605
|
-
...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 } : {}
|
|
384606
385209
|
});
|
|
384607
385210
|
}
|
|
384608
385211
|
return taken;
|
|
@@ -384629,6 +385232,7 @@ var IntentFiller = class {
|
|
|
384629
385232
|
}
|
|
384630
385233
|
const settled = executedHold(claimed, delivered.scaled, released);
|
|
384631
385234
|
const charged = chargedFor(settled, delivered, released);
|
|
385235
|
+
const takenIn = released > 0n && settled.takeDecimals !== void 0 ? toScaled(released, settled.takeDecimals) : null;
|
|
384632
385236
|
const settledBid = rows.find(
|
|
384633
385237
|
(row) => row.reservations.some(
|
|
384634
385238
|
(hold) => hold.limitOrderId === settled.limitOrderId && hold.amount === settled.amount && hold.take === settled.take
|
|
@@ -384647,6 +385251,7 @@ var IntentFiller = class {
|
|
|
384647
385251
|
commitment,
|
|
384648
385252
|
bid: settledBid,
|
|
384649
385253
|
amount: share.toString(),
|
|
385254
|
+
amountIn: takenIn?.toString() ?? null,
|
|
384650
385255
|
transactionHash: transactionHash ?? null
|
|
384651
385256
|
});
|
|
384652
385257
|
}
|
|
@@ -384799,45 +385404,6 @@ init_esm();
|
|
|
384799
385404
|
init_Logger();
|
|
384800
385405
|
init_asset_registry();
|
|
384801
385406
|
init_decimal();
|
|
384802
|
-
|
|
384803
|
-
// src/orderbook/usd.ts
|
|
384804
|
-
init_esm_shims();
|
|
384805
|
-
init_decimal();
|
|
384806
|
-
init_asset_registry();
|
|
384807
|
-
function limitOrderUsdEdges(orders) {
|
|
384808
|
-
return orders.filter((order) => normalizeSymbol(order.base) !== normalizeSymbol(order.quote)).map((order) => ({
|
|
384809
|
-
base: normalizeSymbol(order.base),
|
|
384810
|
-
quote: normalizeSymbol(order.quote),
|
|
384811
|
-
rate: new Decimal(order.price).div(ORDERBOOK_SCALE2.toString())
|
|
384812
|
-
})).filter((edge) => edge.rate.isFinite() && edge.rate.gt(0));
|
|
384813
|
-
}
|
|
384814
|
-
function usdFactorsFrom(edges) {
|
|
384815
|
-
const factors = /* @__PURE__ */ new Map();
|
|
384816
|
-
for (const symbol3 of USD_STABLE_SYMBOLS) factors.set(symbol3, new Decimal(1));
|
|
384817
|
-
const ordered = [...edges].sort((a6, b5) => a6.base.localeCompare(b5.base) || a6.quote.localeCompare(b5.quote));
|
|
384818
|
-
let grew = true;
|
|
384819
|
-
while (grew) {
|
|
384820
|
-
grew = false;
|
|
384821
|
-
for (const edge of ordered) {
|
|
384822
|
-
const usdBase = factors.get(edge.base);
|
|
384823
|
-
const usdQuote = factors.get(edge.quote);
|
|
384824
|
-
if (usdBase && !usdQuote) {
|
|
384825
|
-
factors.set(edge.quote, usdBase.div(edge.rate));
|
|
384826
|
-
grew = true;
|
|
384827
|
-
} else if (usdQuote && !usdBase) {
|
|
384828
|
-
factors.set(edge.base, usdQuote.mul(edge.rate));
|
|
384829
|
-
grew = true;
|
|
384830
|
-
}
|
|
384831
|
-
}
|
|
384832
|
-
}
|
|
384833
|
-
return factors;
|
|
384834
|
-
}
|
|
384835
|
-
function usdValueOf(factors, symbol3, amount) {
|
|
384836
|
-
const factor = factors.get(normalizeSymbol(symbol3));
|
|
384837
|
-
return factor ? amount.mul(factor) : null;
|
|
384838
|
-
}
|
|
384839
|
-
|
|
384840
|
-
// src/strategies/fx.ts
|
|
384841
385407
|
function adjustDecimalsFloor(amount, fromDecimals, toDecimals) {
|
|
384842
385408
|
if (fromDecimals === toDecimals) return amount;
|
|
384843
385409
|
if (fromDecimals < toDecimals) return amount * BigInt(10 ** (toDecimals - fromDecimals));
|
|
@@ -385318,6 +385884,7 @@ var FXFiller = class _FXFiller {
|
|
|
385318
385884
|
payout: toScaled(finalOutputAmount, outputDecimals),
|
|
385319
385885
|
fillerOutputs,
|
|
385320
385886
|
fillerInputs,
|
|
385887
|
+
inputDecimals,
|
|
385321
385888
|
fundingCalls: [...fundingCalls],
|
|
385322
385889
|
partialFill,
|
|
385323
385890
|
profit: totalProfit,
|
|
@@ -386812,9 +387379,10 @@ async function bootFiller(config5, options) {
|
|
|
386812
387379
|
const activity = new ActivityRecorder(options.data.activity, options.loggers, { describeToken });
|
|
386813
387380
|
activity.attach(intentFiller.monitor);
|
|
386814
387381
|
const network = resolvedChains.some((chain2) => chainByChainId(chain2.chainId)?.network === "testnet") ? "testnet" : "mainnet";
|
|
387382
|
+
const indexerUrl = config5.simplex.indexerUrl ?? DEFAULT_INDEXER_URLS[network];
|
|
386815
387383
|
void backfillOrderSummaries({
|
|
386816
387384
|
store: options.data.activity,
|
|
386817
|
-
indexerUrl
|
|
387385
|
+
indexerUrl,
|
|
386818
387386
|
fillerAddress: runtimeSigner.address,
|
|
386819
387387
|
describeToken,
|
|
386820
387388
|
onUpdated: (rows) => {
|
|
@@ -386880,6 +387448,15 @@ async function bootFiller(config5, options) {
|
|
|
386880
387448
|
vaultVenue?.startSweeping();
|
|
386881
387449
|
started.push(() => balanceProvider.stop());
|
|
386882
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
|
+
}
|
|
386883
387460
|
const watchOnlyChains = watchOnlyConfig ? Object.entries(watchOnlyConfig).filter(([, value]) => value === true).map(([chainId]) => Number.parseInt(chainId, 10)) : [];
|
|
386884
387461
|
logger8.info(
|
|
386885
387462
|
{
|
|
@@ -386925,6 +387502,8 @@ async function bootFiller(config5, options) {
|
|
|
386925
387502
|
rebalancingService,
|
|
386926
387503
|
resolvedChains,
|
|
386927
387504
|
fillerAddress: runtimeSigner.address,
|
|
387505
|
+
indexerUrl,
|
|
387506
|
+
describeToken,
|
|
386928
387507
|
watchOnly: watchOnlyConfig,
|
|
386929
387508
|
config: config5,
|
|
386930
387509
|
configPath: options.configPath,
|
|
@@ -387208,10 +387787,20 @@ var MemoryLimitOrderStore = class {
|
|
|
387208
387787
|
commitment: fill.commitment,
|
|
387209
387788
|
bid: fill.bid ?? null,
|
|
387210
387789
|
amount: fill.amount,
|
|
387790
|
+
amountIn: fill.amountIn ?? null,
|
|
387211
387791
|
transactionHash: fill.transactionHash ?? null,
|
|
387212
387792
|
filledAt: sqliteDatetime(/* @__PURE__ */ new Date())
|
|
387213
387793
|
});
|
|
387214
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
|
+
}
|
|
387215
387804
|
async fills(limitOrderId, limit = 100) {
|
|
387216
387805
|
return this.fillRows.filter((fill) => fill.limitOrderId === limitOrderId).slice(-capLimit(limit)).reverse().map((fill) => ({ ...fill }));
|
|
387217
387806
|
}
|
|
@@ -387318,12 +387907,29 @@ var MemoryStateStore = class {
|
|
|
387318
387907
|
this.state = { ...state };
|
|
387319
387908
|
}
|
|
387320
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
|
+
};
|
|
387321
387926
|
var MemoryDataStore = class {
|
|
387322
387927
|
constructor() {
|
|
387323
387928
|
this.bids = new MemoryBidStore();
|
|
387324
387929
|
this.activity = new MemoryActivityStore();
|
|
387325
387930
|
this.state = new MemoryStateStore();
|
|
387326
387931
|
this.limitOrders = new MemoryLimitOrderStore();
|
|
387932
|
+
this.inventory = new MemoryInventoryStore();
|
|
387327
387933
|
}
|
|
387328
387934
|
};
|
|
387329
387935
|
|
|
@@ -387935,6 +388541,107 @@ var OrderScanner = class _OrderScanner {
|
|
|
387935
388541
|
}
|
|
387936
388542
|
};
|
|
387937
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
|
+
|
|
387938
388645
|
// src/simplex.ts
|
|
387939
388646
|
var EVENT_MAP = {
|
|
387940
388647
|
newOrder: "order:detected",
|
|
@@ -387980,10 +388687,66 @@ var LimitOrderController = class {
|
|
|
387980
388687
|
]);
|
|
387981
388688
|
return { order, fills, bids };
|
|
387982
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
|
+
}
|
|
387983
388738
|
/** The pairs the orderbook lists, the smallest payout each token may carry, and its tokens per chain. */
|
|
387984
388739
|
books() {
|
|
387985
388740
|
return this.service.books();
|
|
387986
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
|
+
}
|
|
387987
388750
|
/** Creates the order, posts it, and reports what the orderbook made of it. */
|
|
387988
388751
|
async create(request3) {
|
|
387989
388752
|
const posted = await this.service.create(request3);
|
|
@@ -389074,6 +389837,40 @@ var SqliteBidStore = class {
|
|
|
389074
389837
|
}
|
|
389075
389838
|
};
|
|
389076
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
|
+
|
|
389077
389874
|
// src/data/sqlite/limit-orders.ts
|
|
389078
389875
|
init_esm_shims();
|
|
389079
389876
|
init_Logger();
|
|
@@ -389147,12 +389944,17 @@ var SqliteLimitOrderStore = class {
|
|
|
389147
389944
|
commitment TEXT NOT NULL,
|
|
389148
389945
|
bid TEXT,
|
|
389149
389946
|
amount TEXT NOT NULL,
|
|
389947
|
+
amount_in TEXT,
|
|
389150
389948
|
transaction_hash TEXT,
|
|
389151
389949
|
filled_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
389152
389950
|
);
|
|
389153
389951
|
|
|
389154
389952
|
CREATE INDEX IF NOT EXISTS idx_limit_order_fills_order ON limit_order_fills(limit_order_id);
|
|
389155
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
|
+
}
|
|
389156
389958
|
}
|
|
389157
389959
|
// biome-ignore lint/suspicious/noExplicitAny: raw sqlite row
|
|
389158
389960
|
toLimitOrder(row) {
|
|
@@ -389262,12 +390064,27 @@ var SqliteLimitOrderStore = class {
|
|
|
389262
390064
|
}
|
|
389263
390065
|
async recordFill(fill) {
|
|
389264
390066
|
this.db.prepare(
|
|
389265
|
-
"INSERT INTO limit_order_fills (limit_order_id, commitment, bid, amount, transaction_hash) VALUES (?, ?, ?, ?, ?)"
|
|
389266
|
-
).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();
|
|
389267
390084
|
}
|
|
389268
390085
|
async fills(limitOrderId, limit = 100) {
|
|
389269
390086
|
return this.db.prepare(
|
|
389270
|
-
`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,
|
|
389271
390088
|
filled_at as filledAt
|
|
389272
390089
|
FROM limit_order_fills WHERE limit_order_id = ? ORDER BY id DESC LIMIT ?`
|
|
389273
390090
|
).all(limitOrderId, Math.min(Math.max(limit, 1), 500));
|
|
@@ -389456,6 +390273,7 @@ var SqliteDataStore = class {
|
|
|
389456
390273
|
this.activity = new SqliteActivityStore(activityDb, loggers);
|
|
389457
390274
|
this.state = new SqliteStateStore(bidsDb, dataDir, loggers);
|
|
389458
390275
|
this.limitOrders = new SqliteLimitOrderStore(bidsDb, loggers);
|
|
390276
|
+
this.inventory = new SqliteInventoryStore(activityDb);
|
|
389459
390277
|
this.logger.info({ dataDir }, "SQLite data store opened");
|
|
389460
390278
|
}
|
|
389461
390279
|
/**
|