@hyperbridge/simplex 0.16.8 → 0.16.11
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/README.md +31 -14
- package/dist/bin/simplex.js +23713 -2079
- package/dist/bin/simplex.js.map +1 -1
- package/dist/config-storage.cjs +186 -0
- package/dist/config-storage.cjs.map +1 -0
- package/dist/config-storage.d.cts +28 -0
- package/dist/config-storage.d.ts +28 -0
- package/dist/config-storage.js +163 -0
- package/dist/config-storage.js.map +1 -0
- package/dist/index.cjs +589 -284
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +201 -100
- package/dist/index.d.ts +201 -100
- package/dist/index.js +460 -160
- package/dist/index.js.map +1 -1
- package/dist/sqlite.cjs +12 -0
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.d.cts +2 -1
- package/dist/sqlite.d.ts +2 -1
- package/dist/sqlite.js +12 -0
- package/dist/sqlite.js.map +1 -1
- package/dist/{types-C7rnnKWn.d.cts → types-B5zkFhxR.d.cts} +11 -1
- package/dist/{types-C7rnnKWn.d.ts → types-B5zkFhxR.d.ts} +11 -1
- package/dist/ui/assets/{index-C3T-gubp.css → index-B_p2oQkc.css} +1 -1
- package/dist/ui/assets/{index-BQu6BMxc.js → index-CD2NZXpG.js} +35 -35
- package/dist/ui/index.html +2 -2
- package/package.json +13 -2
package/dist/index.cjs
CHANGED
|
@@ -32,6 +32,8 @@ var src_exports = {};
|
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
AssetController: () => AssetController,
|
|
34
34
|
ChainController: () => ChainController,
|
|
35
|
+
LimitOrderController: () => LimitOrderController,
|
|
36
|
+
LimitOrderValidationError: () => LimitOrderValidationError,
|
|
35
37
|
LoggerContext: () => LoggerContext,
|
|
36
38
|
MemoryDataStore: () => MemoryDataStore,
|
|
37
39
|
OrderScanner: () => OrderScanner,
|
|
@@ -44,6 +46,7 @@ __export(src_exports, {
|
|
|
44
46
|
WalletController: () => WalletController,
|
|
45
47
|
addLogSink: () => addLogSink,
|
|
46
48
|
assertConfirmationCoverage: () => assertConfirmationCoverage,
|
|
49
|
+
canDerive: () => canDerive,
|
|
47
50
|
configureLogger: () => configureLogger,
|
|
48
51
|
createSigner: () => createSigner,
|
|
49
52
|
digestSigner: () => digestSigner,
|
|
@@ -56,10 +59,12 @@ __export(src_exports, {
|
|
|
56
59
|
pickAnchorStable: () => pickAnchorStable,
|
|
57
60
|
privateKeySigner: () => privateKeySigner,
|
|
58
61
|
registrySymbols: () => registrySymbols,
|
|
62
|
+
secretPhraseSigner: () => secretPhraseSigner,
|
|
59
63
|
turnkeySigner: () => turnkeySigner,
|
|
60
64
|
validateAssetDefinitions: () => validateAssetDefinitions,
|
|
61
65
|
validateConfig: () => validateConfig,
|
|
62
66
|
validatePairConfigs: () => validatePairConfigs,
|
|
67
|
+
validateSecretPhrase: () => validateSecretPhrase,
|
|
63
68
|
validateSignerConfig: () => validateSignerConfig,
|
|
64
69
|
validateVaultToml: () => validateVaultToml,
|
|
65
70
|
viemSigner: () => viemSigner
|
|
@@ -70,7 +75,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
70
75
|
var import_node_events3 = require("node:events");
|
|
71
76
|
|
|
72
77
|
// src/core/boot.ts
|
|
73
|
-
var
|
|
78
|
+
var import_viem32 = require("viem");
|
|
74
79
|
|
|
75
80
|
// src/core/filler.ts
|
|
76
81
|
var import_util_crypto = require("@polkadot/util-crypto");
|
|
@@ -2838,11 +2843,21 @@ var import_node_crypto = require("node:crypto");
|
|
|
2838
2843
|
var import_sdk4 = require("@hyperbridge/sdk");
|
|
2839
2844
|
|
|
2840
2845
|
// src/orderbook/amounts.ts
|
|
2846
|
+
var import_viem6 = require("viem");
|
|
2841
2847
|
var ORDERBOOK_SCALE = 10n ** 18n;
|
|
2842
2848
|
function toRaw(amount, decimals) {
|
|
2843
2849
|
const shift = 18 - decimals;
|
|
2844
2850
|
return shift >= 0 ? amount / 10n ** BigInt(shift) : amount * 10n ** BigInt(-shift);
|
|
2845
2851
|
}
|
|
2852
|
+
function budgetIdFor(limitOrderId) {
|
|
2853
|
+
return (0, import_viem6.keccak256)((0, import_viem6.stringToBytes)(limitOrderId));
|
|
2854
|
+
}
|
|
2855
|
+
function budgetFor(order, token, decimals) {
|
|
2856
|
+
return { budgetId: budgetIdFor(order.id), cap: toRaw(BigInt(order.size), decimals), token };
|
|
2857
|
+
}
|
|
2858
|
+
function budgetRoom(budget, spent, decimals) {
|
|
2859
|
+
return spent >= budget.cap ? 0n : toScaled(budget.cap - spent, decimals);
|
|
2860
|
+
}
|
|
2846
2861
|
function fromHuman(amount) {
|
|
2847
2862
|
const text = amount.trim();
|
|
2848
2863
|
if (!/^[0-9]+(\.[0-9]+)?$/.test(text)) {
|
|
@@ -2863,6 +2878,10 @@ function toScaled(amount, decimals) {
|
|
|
2863
2878
|
const shift = 18 - decimals;
|
|
2864
2879
|
return shift >= 0 ? amount * 10n ** BigInt(shift) : amount / 10n ** BigInt(-shift);
|
|
2865
2880
|
}
|
|
2881
|
+
function toScaledUp(amount, decimals) {
|
|
2882
|
+
const shift = 18 - decimals;
|
|
2883
|
+
return shift >= 0 ? amount * 10n ** BigInt(shift) : divCeil(amount, 10n ** BigInt(-shift));
|
|
2884
|
+
}
|
|
2866
2885
|
function divCeil(numerator, denominator) {
|
|
2867
2886
|
return (numerator + denominator - 1n) / denominator;
|
|
2868
2887
|
}
|
|
@@ -2904,6 +2923,87 @@ function inputFor(params) {
|
|
|
2904
2923
|
return divCeil(scaled, unit) * unit;
|
|
2905
2924
|
}
|
|
2906
2925
|
|
|
2926
|
+
// src/orderbook/matching.ts
|
|
2927
|
+
function limitOrderLegs(order) {
|
|
2928
|
+
return order.side === "BID" ? { input: order.base, output: order.quote } : { input: order.quote, output: order.base };
|
|
2929
|
+
}
|
|
2930
|
+
function matchLimitOrders(orders, incoming, resolve, now = /* @__PURE__ */ new Date()) {
|
|
2931
|
+
const qualifying = orders.filter((order) => serves(order, incoming, resolve, now)).map((order) => {
|
|
2932
|
+
const offer = offerFor({
|
|
2933
|
+
side: order.side,
|
|
2934
|
+
inputAmount: incoming.inputNet,
|
|
2935
|
+
price: BigInt(order.price),
|
|
2936
|
+
outputDecimals: incoming.outputDecimals
|
|
2937
|
+
});
|
|
2938
|
+
const available = BigInt(order.remaining);
|
|
2939
|
+
return { order, offer, available, payout: offer < available ? offer : available };
|
|
2940
|
+
}).filter((candidate) => candidate.offer >= incoming.requestedOutput && candidate.payout > 0n).sort(byBestOfferFirst);
|
|
2941
|
+
return qualifying;
|
|
2942
|
+
}
|
|
2943
|
+
function byBestOfferFirst(a, b) {
|
|
2944
|
+
if (a.offer !== b.offer) return a.offer > b.offer ? -1 : 1;
|
|
2945
|
+
if (a.available !== b.available) return a.available > b.available ? -1 : 1;
|
|
2946
|
+
return a.order.id < b.order.id ? -1 : 1;
|
|
2947
|
+
}
|
|
2948
|
+
function whyUnmatched(orders, incoming, resolve, now = /* @__PURE__ */ new Date()) {
|
|
2949
|
+
let furthest = -1;
|
|
2950
|
+
for (const order of orders) {
|
|
2951
|
+
const failed = firstFailed(order, incoming, resolve, now);
|
|
2952
|
+
furthest = Math.max(furthest, failed === null ? CHECKS.length : CHECKS.indexOf(failed));
|
|
2953
|
+
}
|
|
2954
|
+
const { source, destination, inputSymbol } = incoming;
|
|
2955
|
+
if (furthest < CHECKS.length) {
|
|
2956
|
+
switch (CHECKS[Math.max(furthest, 0)]) {
|
|
2957
|
+
case "open":
|
|
2958
|
+
return "no limit order is open";
|
|
2959
|
+
case "chain":
|
|
2960
|
+
return `no open limit order fills on ${destination}`;
|
|
2961
|
+
case "input":
|
|
2962
|
+
return `no limit order on ${destination} takes ${inputSymbol} in`;
|
|
2963
|
+
case "output":
|
|
2964
|
+
return `no limit order on ${destination} taking ${inputSymbol} in pays out the token this order asks for`;
|
|
2965
|
+
case "source":
|
|
2966
|
+
return `no limit order for this pair on ${destination} accepts swaps from ${source}`;
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
const priced = orders.filter((order) => firstFailed(order, incoming, resolve, now) === null).map((order) => ({
|
|
2970
|
+
order,
|
|
2971
|
+
offer: offerFor({
|
|
2972
|
+
side: order.side,
|
|
2973
|
+
inputAmount: incoming.inputNet,
|
|
2974
|
+
price: BigInt(order.price),
|
|
2975
|
+
outputDecimals: incoming.outputDecimals
|
|
2976
|
+
})
|
|
2977
|
+
}));
|
|
2978
|
+
if (priced.some(({ offer }) => offer >= incoming.requestedOutput)) {
|
|
2979
|
+
return "the limit orders that meet its rate have nothing left to pay out";
|
|
2980
|
+
}
|
|
2981
|
+
const best = priced.reduce((a, b) => b.offer > a.offer ? b : a);
|
|
2982
|
+
const symbol = limitOrderLegs(best.order).output;
|
|
2983
|
+
return `it asks for ${readable(incoming.requestedOutput)} ${symbol}; the best limit order offers ${readable(best.offer)} ${symbol}`;
|
|
2984
|
+
}
|
|
2985
|
+
var CHECKS = ["open", "chain", "input", "output", "source"];
|
|
2986
|
+
function serves(order, incoming, resolve, now) {
|
|
2987
|
+
return firstFailed(order, incoming, resolve, now) === null;
|
|
2988
|
+
}
|
|
2989
|
+
function firstFailed(order, incoming, resolve, now) {
|
|
2990
|
+
if (order.status !== "open") return "open";
|
|
2991
|
+
if (order.expiresAt !== null && new Date(order.expiresAt) <= now) return "open";
|
|
2992
|
+
if (order.fillChain !== incoming.destination) return "chain";
|
|
2993
|
+
const legs = limitOrderLegs(order);
|
|
2994
|
+
if (normalizeSymbol(legs.input) !== normalizeSymbol(incoming.inputSymbol)) return "input";
|
|
2995
|
+
const outputToken = resolve(legs.output, order.fillChain);
|
|
2996
|
+
if (!outputToken || outputToken.toLowerCase() !== incoming.outputToken.toLowerCase()) return "output";
|
|
2997
|
+
if (incoming.source === incoming.destination) return null;
|
|
2998
|
+
return order.acceptedSources.includes(incoming.source) ? null : "source";
|
|
2999
|
+
}
|
|
3000
|
+
function readable(amount) {
|
|
3001
|
+
const [whole, fraction] = toHuman(amount).split(".");
|
|
3002
|
+
const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
3003
|
+
const cut = fraction?.slice(0, 6).replace(/0+$/, "");
|
|
3004
|
+
return cut ? `${grouped}.${cut}` : grouped;
|
|
3005
|
+
}
|
|
3006
|
+
|
|
2907
3007
|
// src/orderbook/limit-orders.ts
|
|
2908
3008
|
var LIMITS_TTL_MS = 5 * 60 * 1e3;
|
|
2909
3009
|
var POSTABLE = ["open", "resizing"];
|
|
@@ -3418,6 +3518,58 @@ var LimitOrderService = class {
|
|
|
3418
3518
|
}
|
|
3419
3519
|
return report;
|
|
3420
3520
|
}
|
|
3521
|
+
/**
|
|
3522
|
+
* Lowers every open order's `remaining` to what the solver's account will still
|
|
3523
|
+
* pay for it, and puts the order back on the book at that size.
|
|
3524
|
+
*
|
|
3525
|
+
* The account tallies each order's payouts on the fill chain and refuses a fill
|
|
3526
|
+
* that would take the tally past the order's size. A fill that never settled
|
|
3527
|
+
* here, or a store restored from an older copy, leaves `remaining` above that
|
|
3528
|
+
* room and the order posted at a size the account will refuse. A tally behind
|
|
3529
|
+
* the store changes nothing: `remaining` is never raised.
|
|
3530
|
+
*
|
|
3531
|
+
* Answers how many orders were lowered.
|
|
3532
|
+
*/
|
|
3533
|
+
async reconcileTallies() {
|
|
3534
|
+
let lowered = 0;
|
|
3535
|
+
for (const order of await this.store.list({ status: "open" })) {
|
|
3536
|
+
try {
|
|
3537
|
+
const clamped = await this.clampToTally(order);
|
|
3538
|
+
if (!clamped) continue;
|
|
3539
|
+
lowered++;
|
|
3540
|
+
await this.resize(clamped, BigInt(order.remaining) - BigInt(clamped.remaining));
|
|
3541
|
+
} catch (err) {
|
|
3542
|
+
this.logger.error({ id: order.id, err }, "Could not bring the limit order in line with its on-chain tally");
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
return lowered;
|
|
3546
|
+
}
|
|
3547
|
+
/** The order as the store now holds it when its tally lowered it, null when it was left alone. */
|
|
3548
|
+
async clampToTally(order) {
|
|
3549
|
+
const token = this.assetRegistry.getAddress(limitOrderLegs(order).output, order.fillChain);
|
|
3550
|
+
if (!token) return null;
|
|
3551
|
+
const decimals = await this.contractService.getTokenDecimals(token, order.fillChain);
|
|
3552
|
+
const budget = budgetFor(order, token, decimals);
|
|
3553
|
+
const spent = await this.contractService.limitOrderSpent(order.fillChain, budget.budgetId);
|
|
3554
|
+
if (spent === null) return null;
|
|
3555
|
+
const room = budgetRoom(budget, spent, decimals);
|
|
3556
|
+
const over = BigInt(order.remaining) - (room + BigInt(order.reserved));
|
|
3557
|
+
if (over < toScaled(1n, decimals)) return null;
|
|
3558
|
+
const clamped = await this.store.clampRemaining(order.id, room.toString());
|
|
3559
|
+
if (!clamped) return null;
|
|
3560
|
+
this.logger.warn(
|
|
3561
|
+
{
|
|
3562
|
+
id: order.id,
|
|
3563
|
+
before: order.remaining,
|
|
3564
|
+
after: clamped.remaining,
|
|
3565
|
+
spent: spent.toString(),
|
|
3566
|
+
cap: budget.cap.toString(),
|
|
3567
|
+
reserved: clamped.reserved
|
|
3568
|
+
},
|
|
3569
|
+
"Limit order had more left than its on-chain tally allows; lowering it"
|
|
3570
|
+
);
|
|
3571
|
+
return clamped;
|
|
3572
|
+
}
|
|
3421
3573
|
/**
|
|
3422
3574
|
* Withdraws every order that has outlived the operator's own `expiresAt`.
|
|
3423
3575
|
*
|
|
@@ -3679,7 +3831,7 @@ async function patchRuntimeState(store, patch) {
|
|
|
3679
3831
|
}
|
|
3680
3832
|
|
|
3681
3833
|
// src/services/wallet/mpcvault.ts
|
|
3682
|
-
var
|
|
3834
|
+
var import_viem7 = require("viem");
|
|
3683
3835
|
var grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
3684
3836
|
|
|
3685
3837
|
// src/proto/mpcvault/platform/v1/api.ts
|
|
@@ -12243,18 +12395,18 @@ var MpcVaultService = class {
|
|
|
12243
12395
|
// Signature assembly
|
|
12244
12396
|
// -----------------------------------------------------------------------
|
|
12245
12397
|
signatureFromParts(parts, normalizeV = false) {
|
|
12246
|
-
const r = (0,
|
|
12247
|
-
const s = (0,
|
|
12398
|
+
const r = (0, import_viem7.padHex)((0, import_viem7.toHex)(BigInt(parts.R || "0")), { size: 32 });
|
|
12399
|
+
const s = (0, import_viem7.padHex)((0, import_viem7.toHex)(BigInt(parts.S || "0")), { size: 32 });
|
|
12248
12400
|
const vInt = this.parseFlexibleBigInt(parts.V || "0");
|
|
12249
|
-
let v = (0,
|
|
12401
|
+
let v = (0, import_viem7.padHex)((0, import_viem7.toHex)(vInt), { size: 1 });
|
|
12250
12402
|
if (normalizeV) {
|
|
12251
|
-
v = (0,
|
|
12403
|
+
v = (0, import_viem7.padHex)((0, import_viem7.toHex)(vInt < 27n ? vInt + 27n : vInt), { size: 1 });
|
|
12252
12404
|
}
|
|
12253
|
-
return (0,
|
|
12405
|
+
return (0, import_viem7.concatHex)([r, s, v]);
|
|
12254
12406
|
}
|
|
12255
12407
|
ecdsaPartsToSignatureComponents(parts) {
|
|
12256
|
-
const r = (0,
|
|
12257
|
-
const s = (0,
|
|
12408
|
+
const r = (0, import_viem7.padHex)((0, import_viem7.toHex)(BigInt(parts.R || "0")), { size: 32 });
|
|
12409
|
+
const s = (0, import_viem7.padHex)((0, import_viem7.toHex)(BigInt(parts.S || "0")), { size: 32 });
|
|
12258
12410
|
const vInt = this.parseFlexibleBigInt(parts.V || "0");
|
|
12259
12411
|
const yParity = vInt >= 27n ? Number(vInt - 27n) : Number(vInt);
|
|
12260
12412
|
if (yParity !== 0 && yParity !== 1) {
|
|
@@ -12290,7 +12442,7 @@ var MpcVaultService = class {
|
|
|
12290
12442
|
const messageBytes = Buffer.from(messageHash.slice(2), "hex");
|
|
12291
12443
|
const prefix = Buffer.from(`Ethereum Signed Message:
|
|
12292
12444
|
${messageBytes.length}`);
|
|
12293
|
-
const ethSignedMessageHash = (0,
|
|
12445
|
+
const ethSignedMessageHash = (0, import_viem7.keccak256)((0, import_viem7.concatHex)([(0, import_viem7.toHex)(prefix), messageHash]));
|
|
12294
12446
|
const ethSignedBytes = Buffer.from(ethSignedMessageHash.slice(2), "hex");
|
|
12295
12447
|
const uuid = await this.createSigningRequest({
|
|
12296
12448
|
vaultUuid: this.vaultUuid,
|
|
@@ -12378,11 +12530,12 @@ var SignerType = /* @__PURE__ */ ((SignerType2) => {
|
|
|
12378
12530
|
SignerType2["PrivateKey"] = "privateKey";
|
|
12379
12531
|
SignerType2["MpcVault"] = "mpcVault";
|
|
12380
12532
|
SignerType2["Turnkey"] = "turnkey";
|
|
12533
|
+
SignerType2["SecretPhrase"] = "secretPhrase";
|
|
12381
12534
|
return SignerType2;
|
|
12382
12535
|
})(SignerType || {});
|
|
12383
12536
|
|
|
12384
12537
|
// src/services/wallet/accounts/mpc.ts
|
|
12385
|
-
var
|
|
12538
|
+
var import_viem8 = require("viem");
|
|
12386
12539
|
var import_utils = require("viem/utils");
|
|
12387
12540
|
function mpcVaultSigner(config) {
|
|
12388
12541
|
const service = new MpcVaultService({
|
|
@@ -12417,9 +12570,9 @@ function mpcVaultSigner(config) {
|
|
|
12417
12570
|
if (tx.authorizationList?.length) {
|
|
12418
12571
|
const serializable = { ...tx, type: "eip7702" };
|
|
12419
12572
|
const signature = await service.signRawHashComponents(
|
|
12420
|
-
(0,
|
|
12573
|
+
(0, import_viem8.keccak256)((0, import_viem8.serializeTransaction)(serializable))
|
|
12421
12574
|
);
|
|
12422
|
-
return (0,
|
|
12575
|
+
return (0, import_viem8.serializeTransaction)(serializable, signature);
|
|
12423
12576
|
}
|
|
12424
12577
|
return service.signTransaction({
|
|
12425
12578
|
chainId: tx.chainId,
|
|
@@ -12444,10 +12597,10 @@ function requireChainId(value) {
|
|
|
12444
12597
|
var import_accounts = require("viem/accounts");
|
|
12445
12598
|
|
|
12446
12599
|
// src/services/wallet/accounts/viem.ts
|
|
12447
|
-
var
|
|
12600
|
+
var import_viem9 = require("viem");
|
|
12448
12601
|
var import_utils2 = require("viem/utils");
|
|
12449
12602
|
function splitSignature(signature, source) {
|
|
12450
|
-
const sig = (0,
|
|
12603
|
+
const sig = (0, import_viem9.parseSignature)(signature);
|
|
12451
12604
|
const yParity = sig.yParity ?? (sig.v !== void 0 ? Number(sig.v >= 27n ? sig.v - 27n : sig.v) : void 0);
|
|
12452
12605
|
if (yParity !== 0 && yParity !== 1) {
|
|
12453
12606
|
throw new Error(`Failed to derive yParity from ${source} signature`);
|
|
@@ -12499,9 +12652,54 @@ function privateKeySigner(privateKey) {
|
|
|
12499
12652
|
return viemSigner((0, import_accounts.privateKeyToAccount)(privateKey));
|
|
12500
12653
|
}
|
|
12501
12654
|
|
|
12655
|
+
// src/services/wallet/accounts/secretphrase.ts
|
|
12656
|
+
var import_bip39 = require("@scure/bip39");
|
|
12657
|
+
var import_accounts2 = require("viem/accounts");
|
|
12658
|
+
var WORD_COUNTS = [12, 15, 18, 21, 24];
|
|
12659
|
+
var MAX_DERIVATION_INDEX = 2 ** 31 - 1;
|
|
12660
|
+
function normaliseSecretPhrase(phrase) {
|
|
12661
|
+
return phrase.trim().split(/\s+/).join(" ").toLowerCase();
|
|
12662
|
+
}
|
|
12663
|
+
function validateSecretPhrase(phrase) {
|
|
12664
|
+
if (typeof phrase !== "string") throw new Error("Secret phrase must be a string");
|
|
12665
|
+
const normalised = normaliseSecretPhrase(phrase);
|
|
12666
|
+
const words = normalised === "" ? [] : normalised.split(" ");
|
|
12667
|
+
if (!WORD_COUNTS.includes(words.length)) {
|
|
12668
|
+
throw new Error(`Secret phrase must have ${WORD_COUNTS.join(", ")} words; got ${words.length}`);
|
|
12669
|
+
}
|
|
12670
|
+
if (words.some((word) => !import_accounts2.english.includes(word))) {
|
|
12671
|
+
throw new Error("Secret phrase contains a word that is not in the BIP-39 English wordlist");
|
|
12672
|
+
}
|
|
12673
|
+
if (!(0, import_bip39.validateMnemonic)(normalised, import_accounts2.english)) {
|
|
12674
|
+
throw new Error("Secret phrase checksum does not match; check the words and their order");
|
|
12675
|
+
}
|
|
12676
|
+
}
|
|
12677
|
+
function assertDerivationIndex(index, name = "Derivation index") {
|
|
12678
|
+
const expected = `${name} must be an integer between 0 and ${MAX_DERIVATION_INDEX}`;
|
|
12679
|
+
if (typeof index !== "number") throw new Error(expected);
|
|
12680
|
+
if (!Number.isInteger(index) || index < 0 || index > MAX_DERIVATION_INDEX) {
|
|
12681
|
+
throw new Error(`${expected}; got ${index}`);
|
|
12682
|
+
}
|
|
12683
|
+
}
|
|
12684
|
+
function secretPhraseSigner(config) {
|
|
12685
|
+
validateSecretPhrase(config.phrase);
|
|
12686
|
+
const phrase = normaliseSecretPhrase(config.phrase);
|
|
12687
|
+
const accountIndex = config.accountIndex ?? 0;
|
|
12688
|
+
assertDerivationIndex(accountIndex, "accountIndex");
|
|
12689
|
+
const derive = (index) => {
|
|
12690
|
+
assertDerivationIndex(index);
|
|
12691
|
+
return { ...viemSigner((0, import_accounts2.mnemonicToAccount)(phrase, { addressIndex: index })), mode: "secretPhrase" };
|
|
12692
|
+
};
|
|
12693
|
+
return { ...derive(accountIndex), accountIndex, derive };
|
|
12694
|
+
}
|
|
12695
|
+
function canDerive(signer) {
|
|
12696
|
+
const candidate = signer;
|
|
12697
|
+
return typeof candidate.derive === "function" && typeof candidate.accountIndex === "number";
|
|
12698
|
+
}
|
|
12699
|
+
|
|
12502
12700
|
// src/services/wallet/accounts/turnkey.ts
|
|
12503
12701
|
var import_sdk_server = require("@turnkey/sdk-server");
|
|
12504
|
-
var
|
|
12702
|
+
var import_viem12 = require("@turnkey/viem");
|
|
12505
12703
|
async function turnkeySigner(config) {
|
|
12506
12704
|
const turnkey = new import_sdk_server.Turnkey({
|
|
12507
12705
|
defaultOrganizationId: config.organizationId,
|
|
@@ -12509,7 +12707,7 @@ async function turnkeySigner(config) {
|
|
|
12509
12707
|
apiPrivateKey: config.apiPrivateKey,
|
|
12510
12708
|
apiPublicKey: config.apiPublicKey
|
|
12511
12709
|
});
|
|
12512
|
-
const account = await (0,
|
|
12710
|
+
const account = await (0, import_viem12.createAccount)({
|
|
12513
12711
|
client: turnkey.apiClient(),
|
|
12514
12712
|
organizationId: config.organizationId,
|
|
12515
12713
|
signWith: config.signWith
|
|
@@ -12522,6 +12720,7 @@ async function createSigner(config) {
|
|
|
12522
12720
|
if (config.type === "privateKey" /* PrivateKey */) return privateKeySigner(config.key);
|
|
12523
12721
|
if (config.type === "mpcVault" /* MpcVault */) return mpcVaultSigner(config);
|
|
12524
12722
|
if (config.type === "turnkey" /* Turnkey */) return turnkeySigner(config);
|
|
12723
|
+
if (config.type === "secretPhrase" /* SecretPhrase */) return secretPhraseSigner(config);
|
|
12525
12724
|
throw new Error(`Unsupported signer mode: ${config.type ?? "unknown"}`);
|
|
12526
12725
|
}
|
|
12527
12726
|
function validateSignerConfig(config) {
|
|
@@ -12547,15 +12746,23 @@ function validateSignerConfig(config) {
|
|
|
12547
12746
|
if (!config.signWith) throw new Error("simplex.signer.signWith is required");
|
|
12548
12747
|
return;
|
|
12549
12748
|
}
|
|
12749
|
+
if (config.type === "secretPhrase" /* SecretPhrase */) {
|
|
12750
|
+
if (!config.phrase) {
|
|
12751
|
+
throw new Error("simplex.signer.phrase is required when simplex.signer.type=secretPhrase");
|
|
12752
|
+
}
|
|
12753
|
+
validateSecretPhrase(config.phrase);
|
|
12754
|
+
if (config.accountIndex !== void 0) assertDerivationIndex(config.accountIndex, "simplex.signer.accountIndex");
|
|
12755
|
+
return;
|
|
12756
|
+
}
|
|
12550
12757
|
throw new Error(`Unsupported signer mode: ${config.type ?? "unknown"}`);
|
|
12551
12758
|
}
|
|
12552
12759
|
|
|
12553
12760
|
// src/services/wallet/account.ts
|
|
12554
|
-
var
|
|
12761
|
+
var import_viem14 = require("viem");
|
|
12555
12762
|
var import_utils3 = require("viem/utils");
|
|
12556
|
-
var
|
|
12763
|
+
var import_accounts3 = require("viem/accounts");
|
|
12557
12764
|
function accountFor(signer) {
|
|
12558
|
-
return (0,
|
|
12765
|
+
return (0, import_accounts3.toAccount)({
|
|
12559
12766
|
address: signer.address,
|
|
12560
12767
|
signTypedData: (typedData) => signer.signTypedData(typedData),
|
|
12561
12768
|
signTransaction: async (transaction) => await signer.signTransaction(toSignerTransaction(transaction)),
|
|
@@ -12595,7 +12802,7 @@ function digestSigner(opts) {
|
|
|
12595
12802
|
return {
|
|
12596
12803
|
address: opts.address,
|
|
12597
12804
|
mode: opts.mode,
|
|
12598
|
-
signTypedData: async (typedData) => (0,
|
|
12805
|
+
signTypedData: async (typedData) => (0, import_viem14.serializeSignature)(await sign((0, import_viem14.hashTypedData)(typedData))),
|
|
12599
12806
|
signAuthorization: (auth) => sign(
|
|
12600
12807
|
(0, import_utils3.hashAuthorization)({
|
|
12601
12808
|
address: auth.contractAddress,
|
|
@@ -12605,8 +12812,8 @@ function digestSigner(opts) {
|
|
|
12605
12812
|
),
|
|
12606
12813
|
signTransaction: async (tx) => {
|
|
12607
12814
|
const serializable = tx;
|
|
12608
|
-
const signature = await sign((0,
|
|
12609
|
-
return (0,
|
|
12815
|
+
const signature = await sign((0, import_viem14.keccak256)((0, import_viem14.serializeTransaction)(serializable)));
|
|
12816
|
+
return (0, import_viem14.serializeTransaction)(serializable, signature);
|
|
12610
12817
|
}
|
|
12611
12818
|
};
|
|
12612
12819
|
}
|
|
@@ -12635,6 +12842,12 @@ async function deriveSubstrateKeyPair(key) {
|
|
|
12635
12842
|
}
|
|
12636
12843
|
|
|
12637
12844
|
// src/services/CacheService.ts
|
|
12845
|
+
function budgetToCache(budget) {
|
|
12846
|
+
return { budgetId: budget.budgetId, cap: budget.cap.toString(), token: budget.token };
|
|
12847
|
+
}
|
|
12848
|
+
function budgetFromCache(budget) {
|
|
12849
|
+
return { budgetId: budget.budgetId, cap: BigInt(budget.cap), token: budget.token };
|
|
12850
|
+
}
|
|
12638
12851
|
var CacheService = class {
|
|
12639
12852
|
constructor(loggers = defaultLoggerContext()) {
|
|
12640
12853
|
this.CACHE_EXPIRY_MS = 1 * 60 * 1e3;
|
|
@@ -12792,7 +13005,24 @@ var CacheService = class {
|
|
|
12792
13005
|
return null;
|
|
12793
13006
|
}
|
|
12794
13007
|
}
|
|
12795
|
-
|
|
13008
|
+
/**
|
|
13009
|
+
* The budget of the limit order that priced the outputs cached for this order, or
|
|
13010
|
+
* null when no limit order did.
|
|
13011
|
+
*
|
|
13012
|
+
* Kept on the same entry as the outputs, so the two are replaced and expire
|
|
13013
|
+
* together: a bid can never sign one limit order's payout beside another's budget.
|
|
13014
|
+
*/
|
|
13015
|
+
getBidBudget(orderId) {
|
|
13016
|
+
try {
|
|
13017
|
+
const cache = this.cacheData.fillerOutputs[orderId];
|
|
13018
|
+
if (cache?.budget && this.isCacheValid(cache.timestamp)) return budgetFromCache(cache.budget);
|
|
13019
|
+
return null;
|
|
13020
|
+
} catch (error) {
|
|
13021
|
+
this.logger.error({ err: error }, "Error getting bid budget");
|
|
13022
|
+
return null;
|
|
13023
|
+
}
|
|
13024
|
+
}
|
|
13025
|
+
setFillerOutputs(orderId, outputs, inputs = [], budget) {
|
|
12796
13026
|
try {
|
|
12797
13027
|
this.cleanupStaleData();
|
|
12798
13028
|
this.cacheData.fillerOutputs[orderId] = {
|
|
@@ -12804,6 +13034,7 @@ var CacheService = class {
|
|
|
12804
13034
|
token: o.token,
|
|
12805
13035
|
amount: o.amount.toString()
|
|
12806
13036
|
})),
|
|
13037
|
+
...budget ? { budget: budgetToCache(budget) } : {},
|
|
12807
13038
|
timestamp: Date.now()
|
|
12808
13039
|
};
|
|
12809
13040
|
} catch (error) {
|
|
@@ -12849,7 +13080,8 @@ var CacheService = class {
|
|
|
12849
13080
|
data: call.data
|
|
12850
13081
|
})),
|
|
12851
13082
|
partialFill: plan.partialFill,
|
|
12852
|
-
profit: plan.profit
|
|
13083
|
+
profit: plan.profit,
|
|
13084
|
+
...plan.budget ? { budget: budgetFromCache(plan.budget) } : {}
|
|
12853
13085
|
}));
|
|
12854
13086
|
} catch (error) {
|
|
12855
13087
|
this.logger.error({ err: error }, "Error getting bid plans");
|
|
@@ -12878,7 +13110,8 @@ var CacheService = class {
|
|
|
12878
13110
|
data: call.data
|
|
12879
13111
|
})),
|
|
12880
13112
|
partialFill: plan.partialFill,
|
|
12881
|
-
profit: plan.profit
|
|
13113
|
+
profit: plan.profit,
|
|
13114
|
+
...plan.budget ? { budget: budgetToCache(plan.budget) } : {}
|
|
12882
13115
|
})),
|
|
12883
13116
|
timestamp: Date.now()
|
|
12884
13117
|
};
|
|
@@ -13036,12 +13269,12 @@ var CacheService = class {
|
|
|
13036
13269
|
};
|
|
13037
13270
|
|
|
13038
13271
|
// src/services/ChainClientManager.ts
|
|
13039
|
-
var
|
|
13040
|
-
var
|
|
13272
|
+
var import_viem17 = require("viem");
|
|
13273
|
+
var import_accounts4 = require("viem/accounts");
|
|
13041
13274
|
var import_sdk6 = require("@hyperbridge/sdk");
|
|
13042
13275
|
|
|
13043
13276
|
// src/services/QuorumPublicClient.ts
|
|
13044
|
-
var
|
|
13277
|
+
var import_viem16 = require("viem");
|
|
13045
13278
|
var import_sdk5 = require("@hyperbridge/sdk");
|
|
13046
13279
|
function quorumThreshold(numProviders) {
|
|
13047
13280
|
return Math.floor(2 * numProviders / 3) + 1;
|
|
@@ -13141,9 +13374,9 @@ var _QuorumPublicClient = class _QuorumPublicClient {
|
|
|
13141
13374
|
this.deadlineMs = budget.deadlineMs;
|
|
13142
13375
|
const chain = (0, import_sdk5.getViemChain)(chainId);
|
|
13143
13376
|
this.clients = this.rpcUrls.map(
|
|
13144
|
-
(url) => (0,
|
|
13377
|
+
(url) => (0, import_viem16.createPublicClient)({
|
|
13145
13378
|
chain,
|
|
13146
|
-
transport: (0,
|
|
13379
|
+
transport: (0, import_viem16.http)(url, {
|
|
13147
13380
|
timeout: budget.timeoutMs,
|
|
13148
13381
|
// No transport-level retry. viem's retry sleeps for the provider's
|
|
13149
13382
|
// `Retry-After` verbatim and uncapped, which reaches the socket
|
|
@@ -13559,9 +13792,9 @@ var HTTP_TRANSPORT_OPTS = {
|
|
|
13559
13792
|
};
|
|
13560
13793
|
function buildTransport(rpcUrls) {
|
|
13561
13794
|
if (rpcUrls.length === 1) {
|
|
13562
|
-
return (0,
|
|
13795
|
+
return (0, import_viem17.http)(rpcUrls[0], HTTP_TRANSPORT_OPTS);
|
|
13563
13796
|
}
|
|
13564
|
-
return (0,
|
|
13797
|
+
return (0, import_viem17.fallback)(rpcUrls.map((url) => (0, import_viem17.http)(url, HTTP_TRANSPORT_OPTS)));
|
|
13565
13798
|
}
|
|
13566
13799
|
function walletClientCacheKey(chainId, accountAddress) {
|
|
13567
13800
|
return `${chainId}:${accountAddress.toLowerCase()}`;
|
|
@@ -13587,7 +13820,7 @@ var ViemClientFactoryImpl = class {
|
|
|
13587
13820
|
if (!this.publicClients.has(chainConfig.chainId)) {
|
|
13588
13821
|
const chain = (0, import_sdk6.getViemChain)(chainConfig.chainId);
|
|
13589
13822
|
const urls = rpcUrls && rpcUrls.length > 0 ? rpcUrls : [chainConfig.rpcUrl];
|
|
13590
|
-
const publicClient = (0,
|
|
13823
|
+
const publicClient = (0, import_viem17.createPublicClient)({
|
|
13591
13824
|
chain,
|
|
13592
13825
|
transport: buildTransport(urls)
|
|
13593
13826
|
});
|
|
@@ -13600,7 +13833,7 @@ var ViemClientFactoryImpl = class {
|
|
|
13600
13833
|
if (!this.walletClients.has(key)) {
|
|
13601
13834
|
const chain = (0, import_sdk6.getViemChain)(chainConfig.chainId);
|
|
13602
13835
|
const urls = rpcUrls && rpcUrls.length > 0 ? rpcUrls : [chainConfig.rpcUrl];
|
|
13603
|
-
const walletClient = (0,
|
|
13836
|
+
const walletClient = (0, import_viem17.createWalletClient)({
|
|
13604
13837
|
chain,
|
|
13605
13838
|
account,
|
|
13606
13839
|
transport: buildTransport(urls)
|
|
@@ -13615,7 +13848,7 @@ var ChainClientManager = class {
|
|
|
13615
13848
|
this.clientFactory = new ViemClientFactoryImpl();
|
|
13616
13849
|
this.quorumClients = /* @__PURE__ */ new Map();
|
|
13617
13850
|
this.configService = configService;
|
|
13618
|
-
this.signer = signer ?? privateKeySigner((0,
|
|
13851
|
+
this.signer = signer ?? privateKeySigner((0, import_accounts4.generatePrivateKey)());
|
|
13619
13852
|
this.account = accountFor(this.signer);
|
|
13620
13853
|
}
|
|
13621
13854
|
/** This filler's logging destination, relayed from the config service. */
|
|
@@ -13684,9 +13917,47 @@ var ChainClientManager = class {
|
|
|
13684
13917
|
};
|
|
13685
13918
|
|
|
13686
13919
|
// src/services/ContractInteractionService.ts
|
|
13687
|
-
var
|
|
13920
|
+
var import_viem23 = require("viem");
|
|
13688
13921
|
var import_sdk7 = require("@hyperbridge/sdk");
|
|
13689
13922
|
|
|
13923
|
+
// src/config/abis/SolverAccount.ts
|
|
13924
|
+
var SOLVER_ACCOUNT_ABI = [
|
|
13925
|
+
{
|
|
13926
|
+
inputs: [
|
|
13927
|
+
{ name: "orderId", type: "bytes32" },
|
|
13928
|
+
{ name: "cap", type: "uint256" },
|
|
13929
|
+
{ name: "token", type: "address" },
|
|
13930
|
+
{ name: "approved", type: "uint256" },
|
|
13931
|
+
{ name: "fee", type: "uint256" }
|
|
13932
|
+
],
|
|
13933
|
+
name: "debitOrder",
|
|
13934
|
+
outputs: [],
|
|
13935
|
+
stateMutability: "nonpayable",
|
|
13936
|
+
type: "function"
|
|
13937
|
+
},
|
|
13938
|
+
{
|
|
13939
|
+
inputs: [{ name: "orderId", type: "bytes32" }],
|
|
13940
|
+
name: "spent",
|
|
13941
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
13942
|
+
stateMutability: "view",
|
|
13943
|
+
type: "function"
|
|
13944
|
+
},
|
|
13945
|
+
{
|
|
13946
|
+
inputs: [{ name: "sender", type: "address" }],
|
|
13947
|
+
name: "AccountUnauthorized",
|
|
13948
|
+
type: "error"
|
|
13949
|
+
},
|
|
13950
|
+
{
|
|
13951
|
+
inputs: [
|
|
13952
|
+
{ name: "orderId", type: "bytes32" },
|
|
13953
|
+
{ name: "total", type: "uint256" },
|
|
13954
|
+
{ name: "cap", type: "uint256" }
|
|
13955
|
+
],
|
|
13956
|
+
name: "LimitOrderExceeded",
|
|
13957
|
+
type: "error"
|
|
13958
|
+
}
|
|
13959
|
+
];
|
|
13960
|
+
|
|
13690
13961
|
// src/config/abis/EvmHost.ts
|
|
13691
13962
|
var EVM_HOST = [
|
|
13692
13963
|
{
|
|
@@ -17539,10 +17810,10 @@ var ENTRYPOINT_ABI = [
|
|
|
17539
17810
|
];
|
|
17540
17811
|
|
|
17541
17812
|
// src/services/paymaster/provider/simplex.ts
|
|
17542
|
-
var
|
|
17813
|
+
var import_viem22 = require("viem");
|
|
17543
17814
|
|
|
17544
17815
|
// src/services/paymaster/types.ts
|
|
17545
|
-
var
|
|
17816
|
+
var import_viem18 = require("viem");
|
|
17546
17817
|
var RECOMMENDED_AMOUNT_USD = 5n;
|
|
17547
17818
|
var VERIFICATION_GAS_LIMIT_PERMIT2 = 200000n;
|
|
17548
17819
|
var VERIFICATION_GAS_LIMIT_PERMIT = 250000n;
|
|
@@ -17550,19 +17821,19 @@ var PERMIT2_DEADLINE_SECONDS = 3600n;
|
|
|
17550
17821
|
var POST_OP_GAS_LIMIT_SIMPLEX = 40000n;
|
|
17551
17822
|
var DEPOSIT_HEADROOM_PERCENT = 150n;
|
|
17552
17823
|
function packPaymasterAndData(pm) {
|
|
17553
|
-
return (0,
|
|
17824
|
+
return (0, import_viem18.encodePacked)(
|
|
17554
17825
|
["address", "uint128", "uint128", "bytes"],
|
|
17555
17826
|
[pm.paymaster, pm.paymasterVerificationGasLimit, pm.paymasterPostOpGasLimit, pm.paymasterData]
|
|
17556
17827
|
);
|
|
17557
17828
|
}
|
|
17558
17829
|
|
|
17559
17830
|
// src/services/paymaster/permit.ts
|
|
17560
|
-
var
|
|
17831
|
+
var import_viem21 = require("viem");
|
|
17561
17832
|
|
|
17562
17833
|
// src/config/abis/EIP2612.ts
|
|
17563
|
-
var
|
|
17834
|
+
var import_viem19 = require("viem");
|
|
17564
17835
|
var EIP2612_ABI = [
|
|
17565
|
-
...
|
|
17836
|
+
...import_viem19.erc20Abi,
|
|
17566
17837
|
{
|
|
17567
17838
|
inputs: [{ internalType: "address", name: "owner", type: "address" }],
|
|
17568
17839
|
stateMutability: "view",
|
|
@@ -17580,7 +17851,7 @@ var EIP2612_ABI = [
|
|
|
17580
17851
|
];
|
|
17581
17852
|
|
|
17582
17853
|
// src/services/paymaster/permit2.ts
|
|
17583
|
-
var
|
|
17854
|
+
var import_viem20 = require("viem");
|
|
17584
17855
|
function permit2TransferTypedData(p) {
|
|
17585
17856
|
return {
|
|
17586
17857
|
types: {
|
|
@@ -17615,16 +17886,16 @@ function permit2TransferTypedData(p) {
|
|
|
17615
17886
|
};
|
|
17616
17887
|
}
|
|
17617
17888
|
function randomPermit2Nonce() {
|
|
17618
|
-
return (0,
|
|
17889
|
+
return (0, import_viem20.bytesToBigInt)(crypto.getRandomValues(new Uint8Array(32)));
|
|
17619
17890
|
}
|
|
17620
17891
|
async function signPermit2Transfer(signer, p) {
|
|
17621
17892
|
const signature = await signer.signTypedData(permit2TransferTypedData(p));
|
|
17622
17893
|
return normalizeSignature65(signature);
|
|
17623
17894
|
}
|
|
17624
17895
|
function normalizeSignature65(signature) {
|
|
17625
|
-
const length = (0,
|
|
17896
|
+
const length = (0, import_viem20.size)(signature);
|
|
17626
17897
|
if (length === 64) {
|
|
17627
|
-
return (0,
|
|
17898
|
+
return (0, import_viem20.serializeSignature)((0, import_viem20.compactSignatureToSignature)((0, import_viem20.parseCompactSignature)(signature)));
|
|
17628
17899
|
}
|
|
17629
17900
|
if (length !== 65) {
|
|
17630
17901
|
throw new Error(`Permit2 signature must be 64 or 65 bytes, got ${length}`);
|
|
@@ -17638,7 +17909,7 @@ function normalizeSignature65(signature) {
|
|
|
17638
17909
|
|
|
17639
17910
|
// src/services/paymaster/permit.ts
|
|
17640
17911
|
async function signEip2612Permit(client, signer, owner, spender, tokenAddress, value, chainId) {
|
|
17641
|
-
const token = (0,
|
|
17912
|
+
const token = (0, import_viem21.getContract)({
|
|
17642
17913
|
client,
|
|
17643
17914
|
address: tokenAddress,
|
|
17644
17915
|
abi: EIP2612_ABI
|
|
@@ -17676,7 +17947,7 @@ async function signEip2612Permit(client, signer, owner, spender, tokenAddress, v
|
|
|
17676
17947
|
spender,
|
|
17677
17948
|
value,
|
|
17678
17949
|
nonce,
|
|
17679
|
-
deadline:
|
|
17950
|
+
deadline: import_viem21.maxUint256
|
|
17680
17951
|
}
|
|
17681
17952
|
};
|
|
17682
17953
|
return normalizeSignature65(await signer.signTypedData(typedData));
|
|
@@ -17804,7 +18075,7 @@ async function selectToken(client, solverAccount, tokens, permit2) {
|
|
|
17804
18075
|
for (const token of tokens) {
|
|
17805
18076
|
const balance = await client.readContract({
|
|
17806
18077
|
address: token.address,
|
|
17807
|
-
abi:
|
|
18078
|
+
abi: import_viem22.erc20Abi,
|
|
17808
18079
|
functionName: "balanceOf",
|
|
17809
18080
|
args: [solverAccount]
|
|
17810
18081
|
});
|
|
@@ -17834,7 +18105,7 @@ async function paymasterSupportsPermit2(client, chainId, paymasterAddress) {
|
|
|
17834
18105
|
permit2Support.set(key, { supported: true, checkedAt: Date.now() });
|
|
17835
18106
|
return true;
|
|
17836
18107
|
} catch (error) {
|
|
17837
|
-
const isRevert = error instanceof
|
|
18108
|
+
const isRevert = error instanceof import_viem22.BaseError && error.walk((e) => e instanceof import_viem22.ContractFunctionRevertedError || e instanceof import_viem22.ContractFunctionZeroDataError);
|
|
17838
18109
|
if (isRevert) {
|
|
17839
18110
|
permit2Support.set(key, { supported: false, checkedAt: Date.now() });
|
|
17840
18111
|
return false;
|
|
@@ -17845,7 +18116,7 @@ async function paymasterSupportsPermit2(client, chainId, paymasterAddress) {
|
|
|
17845
18116
|
async function readAllowance(client, token, owner, spender) {
|
|
17846
18117
|
return await client.readContract({
|
|
17847
18118
|
address: token,
|
|
17848
|
-
abi:
|
|
18119
|
+
abi: import_viem22.erc20Abi,
|
|
17849
18120
|
functionName: "allowance",
|
|
17850
18121
|
args: [owner, spender]
|
|
17851
18122
|
});
|
|
@@ -17865,7 +18136,7 @@ async function buildPermit2Mode(signer, p) {
|
|
|
17865
18136
|
const r = `0x${signature.slice(2, 66)}`;
|
|
17866
18137
|
const s = `0x${signature.slice(66, 130)}`;
|
|
17867
18138
|
const v = Number.parseInt(signature.slice(130, 132), 16);
|
|
17868
|
-
const paymasterData = (0,
|
|
18139
|
+
const paymasterData = (0, import_viem22.encodePacked)(
|
|
17869
18140
|
["uint8", "address", "uint256", "uint256", "uint256", "uint8", "bytes32", "bytes32"],
|
|
17870
18141
|
[2, p.token, p.amount, nonce, deadline, v, r, s]
|
|
17871
18142
|
);
|
|
@@ -17889,9 +18160,9 @@ async function buildPermitMode(client, signer, solverAccount, paymasterAddress,
|
|
|
17889
18160
|
const r = `0x${permitSignature.slice(2, 66)}`;
|
|
17890
18161
|
const s = `0x${permitSignature.slice(66, 130)}`;
|
|
17891
18162
|
const v = Number.parseInt(permitSignature.slice(130, 132), 16);
|
|
17892
|
-
const paymasterData = (0,
|
|
18163
|
+
const paymasterData = (0, import_viem22.encodePacked)(
|
|
17893
18164
|
["uint8", "address", "uint256", "uint256", "uint8", "bytes32", "bytes32"],
|
|
17894
|
-
[0, tokenAddress, permitAmount,
|
|
18165
|
+
[0, tokenAddress, permitAmount, import_viem22.maxUint256, v, r, s]
|
|
17895
18166
|
);
|
|
17896
18167
|
return {
|
|
17897
18168
|
paymaster: paymasterAddress,
|
|
@@ -17905,7 +18176,7 @@ async function ensureFundedApprove(client, walletClient, chainId, solverAccount,
|
|
|
17905
18176
|
const key = `${chainId}:${tokenAddress.toLowerCase()}:${solverAccount.toLowerCase()}`;
|
|
17906
18177
|
const inFlight = approvalsInFlight.get(key);
|
|
17907
18178
|
if (inFlight) return inFlight;
|
|
17908
|
-
const pending = sendFundedApprove(client, walletClient, solverAccount, tokenAddress, spender,
|
|
18179
|
+
const pending = sendFundedApprove(client, walletClient, solverAccount, tokenAddress, spender, import_viem22.maxUint256).finally(
|
|
17909
18180
|
() => {
|
|
17910
18181
|
approvalsInFlight.delete(key);
|
|
17911
18182
|
}
|
|
@@ -17923,7 +18194,7 @@ async function sendFundedApprove(client, walletClient, solverAccount, tokenAddre
|
|
|
17923
18194
|
const requiredNative = APPROVE_TX_GAS * gasPrice * (needsReset ? 2n : 1n);
|
|
17924
18195
|
if (nativeBalance < requiredNative) {
|
|
17925
18196
|
throw new Error(
|
|
17926
|
-
`SimplexPaymaster needs a one-time Permit2 approval for the fee token on this chain; send native dust (>= ${(0,
|
|
18197
|
+
`SimplexPaymaster needs a one-time Permit2 approval for the fee token on this chain; send native dust (>= ${(0, import_viem22.formatEther)(requiredNative)}) to ${solverAccount}`
|
|
17927
18198
|
);
|
|
17928
18199
|
}
|
|
17929
18200
|
if (needsReset) {
|
|
@@ -17934,7 +18205,7 @@ async function sendFundedApprove(client, walletClient, solverAccount, tokenAddre
|
|
|
17934
18205
|
async function sendApproveTx(client, walletClient, tokenAddress, spender, amount) {
|
|
17935
18206
|
const hash = await walletClient.writeContract({
|
|
17936
18207
|
address: tokenAddress,
|
|
17937
|
-
abi:
|
|
18208
|
+
abi: import_viem22.erc20Abi,
|
|
17938
18209
|
functionName: "approve",
|
|
17939
18210
|
args: [spender, amount],
|
|
17940
18211
|
chain: walletClient.chain,
|
|
@@ -17959,7 +18230,7 @@ async function tokenSupportsPermit(client, tokenAddress) {
|
|
|
17959
18230
|
});
|
|
17960
18231
|
return true;
|
|
17961
18232
|
} catch (error) {
|
|
17962
|
-
const isRevert = error instanceof
|
|
18233
|
+
const isRevert = error instanceof import_viem22.BaseError && error.walk((e) => e instanceof import_viem22.ContractFunctionRevertedError || e instanceof import_viem22.ContractFunctionZeroDataError);
|
|
17963
18234
|
if (isRevert) return false;
|
|
17964
18235
|
throw error;
|
|
17965
18236
|
}
|
|
@@ -18066,6 +18337,10 @@ function describeShortfall(balances) {
|
|
|
18066
18337
|
// src/services/ContractInteractionService.ts
|
|
18067
18338
|
import_decimal2.Decimal.config({ precision: 28, rounding: 4 });
|
|
18068
18339
|
var FUNDING_GAS_PER_CALL = 400000n;
|
|
18340
|
+
var DEBIT_ORDER_GAS = 60000n;
|
|
18341
|
+
function settles(budget) {
|
|
18342
|
+
return !!budget && budget.token.toLowerCase() !== import_sdk7.ADDRESS_ZERO;
|
|
18343
|
+
}
|
|
18069
18344
|
var LIMIT_ORDER_CALL_GAS_LIMIT = 500000n;
|
|
18070
18345
|
var LIMIT_ORDER_VERIFICATION_GAS_LIMIT = 150000n;
|
|
18071
18346
|
var LIMIT_ORDER_PRE_VERIFICATION_GAS = 50000n;
|
|
@@ -18255,17 +18530,19 @@ var ContractInteractionService = class {
|
|
|
18255
18530
|
}
|
|
18256
18531
|
/**
|
|
18257
18532
|
* The call gas a bid needs: the shared estimate plus room for the funding calls
|
|
18258
|
-
* this bid prepends.
|
|
18533
|
+
* this bid prepends and for settling its limit order's budget.
|
|
18259
18534
|
*
|
|
18260
18535
|
* Funding calls are not simulated (the V4 PositionManager's flash accounting does
|
|
18261
18536
|
* not resolve in the bundler's estimation context), so each one adds a fixed
|
|
18262
18537
|
* allowance for its modifyLiquidities + take. They differ between the bids on one
|
|
18263
18538
|
* order, since each draws on its own limit order and so on its own funding, which
|
|
18264
18539
|
* is why this is worked out per bid rather than baked into the cached estimate.
|
|
18540
|
+
* The estimate is of a lone fillOrder, so the budget call is not in it either.
|
|
18265
18541
|
*/
|
|
18266
|
-
callGasLimitFor(order, baseCallGasLimit) {
|
|
18542
|
+
callGasLimitFor(order, baseCallGasLimit, budget) {
|
|
18267
18543
|
const funding = order.id ? this.cacheService.getFundingPrepends(order.id) : null;
|
|
18268
|
-
|
|
18544
|
+
const fundingGas = FUNDING_GAS_PER_CALL * BigInt(funding?.calls?.length ?? 0);
|
|
18545
|
+
return baseCallGasLimit + fundingGas + (settles(budget) ? DEBIT_ORDER_GAS : 0n);
|
|
18269
18546
|
}
|
|
18270
18547
|
/**
|
|
18271
18548
|
* Gets the fee token address and decimals for a given chain.
|
|
@@ -18337,7 +18614,7 @@ var ContractInteractionService = class {
|
|
|
18337
18614
|
this.logger.warn(
|
|
18338
18615
|
{
|
|
18339
18616
|
chain,
|
|
18340
|
-
walletBalance: (0,
|
|
18617
|
+
walletBalance: (0, import_viem23.formatEther)(solverBalance),
|
|
18341
18618
|
walletGasUnits: walletGasUnits.toString(),
|
|
18342
18619
|
gasPrice: gasPrice.toString()
|
|
18343
18620
|
},
|
|
@@ -18352,10 +18629,10 @@ var ContractInteractionService = class {
|
|
|
18352
18629
|
this.logger.info(
|
|
18353
18630
|
{
|
|
18354
18631
|
chain,
|
|
18355
|
-
currentDeposit: (0,
|
|
18632
|
+
currentDeposit: (0, import_viem23.formatEther)(currentDeposit),
|
|
18356
18633
|
depositGasUnits: depositGasUnits.toString(),
|
|
18357
18634
|
targetGasUnits: targetGasUnits.toString(),
|
|
18358
|
-
walletBalance: (0,
|
|
18635
|
+
walletBalance: (0, import_viem23.formatEther)(solverBalance)
|
|
18359
18636
|
},
|
|
18360
18637
|
"EntryPoint deposit covers target gas units, no top-up needed"
|
|
18361
18638
|
);
|
|
@@ -18366,8 +18643,8 @@ var ContractInteractionService = class {
|
|
|
18366
18643
|
this.logger.warn(
|
|
18367
18644
|
{
|
|
18368
18645
|
chain,
|
|
18369
|
-
deficit: (0,
|
|
18370
|
-
solverBalance: (0,
|
|
18646
|
+
deficit: (0, import_viem23.formatEther)(deficit),
|
|
18647
|
+
solverBalance: (0, import_viem23.formatEther)(solverBalance),
|
|
18371
18648
|
depositGasUnits: depositGasUnits.toString(),
|
|
18372
18649
|
targetGasUnits: targetGasUnits.toString()
|
|
18373
18650
|
},
|
|
@@ -18379,10 +18656,10 @@ var ContractInteractionService = class {
|
|
|
18379
18656
|
this.logger.info(
|
|
18380
18657
|
{
|
|
18381
18658
|
chain,
|
|
18382
|
-
currentDeposit: (0,
|
|
18659
|
+
currentDeposit: (0, import_viem23.formatEther)(currentDeposit),
|
|
18383
18660
|
depositGasUnits: depositGasUnits.toString(),
|
|
18384
18661
|
targetGasUnits: targetGasUnits.toString(),
|
|
18385
|
-
topUpAmount: (0,
|
|
18662
|
+
topUpAmount: (0, import_viem23.formatEther)(deficit)
|
|
18386
18663
|
},
|
|
18387
18664
|
"Topping up EntryPoint deposit to cover target gas units"
|
|
18388
18665
|
);
|
|
@@ -18405,7 +18682,7 @@ var ContractInteractionService = class {
|
|
|
18405
18682
|
const addr = tokenAddress.toLowerCase();
|
|
18406
18683
|
if (addr !== sourceUsdc && addr !== sourceUsdt) continue;
|
|
18407
18684
|
const decimals = await this.getTokenDecimals(tokenAddress, order.source);
|
|
18408
|
-
const tokenAmount = new import_decimal2.Decimal((0,
|
|
18685
|
+
const tokenAmount = new import_decimal2.Decimal((0, import_viem23.formatUnits)(input.amount, decimals));
|
|
18409
18686
|
inputUsdValue = inputUsdValue.plus(tokenAmount);
|
|
18410
18687
|
}
|
|
18411
18688
|
return inputUsdValue;
|
|
@@ -18447,6 +18724,27 @@ var ContractInteractionService = class {
|
|
|
18447
18724
|
{ maxRetries: 3, backoffMs: 250, logMessage: "Failed to read token balance" }
|
|
18448
18725
|
);
|
|
18449
18726
|
}
|
|
18727
|
+
/**
|
|
18728
|
+
* What the solver's account has tallied against a limit order's budget on `chain`, in
|
|
18729
|
+
* the paid token's own units, or null when it cannot be read.
|
|
18730
|
+
*
|
|
18731
|
+
* Null rather than a throw: an account whose implementation keeps no tally answers
|
|
18732
|
+
* with a revert or with no data, and the caller carries on without the figure either
|
|
18733
|
+
* way. Not retried, since that answer does not change on a second ask.
|
|
18734
|
+
*/
|
|
18735
|
+
async limitOrderSpent(chain, budgetId) {
|
|
18736
|
+
try {
|
|
18737
|
+
return await this.clientManager.getPublicClient(chain).readContract({
|
|
18738
|
+
address: this.solverAccountAddress,
|
|
18739
|
+
abi: SOLVER_ACCOUNT_ABI,
|
|
18740
|
+
functionName: "spent",
|
|
18741
|
+
args: [budgetId]
|
|
18742
|
+
});
|
|
18743
|
+
} catch (err) {
|
|
18744
|
+
this.logger.warn({ err, chain, budgetId }, "Could not read the limit order's tally from the solver account");
|
|
18745
|
+
return null;
|
|
18746
|
+
}
|
|
18747
|
+
}
|
|
18450
18748
|
async getSolverEntryPointBalance(chain) {
|
|
18451
18749
|
const entryPointAddress = this.configService.getEntryPointAddress(chain);
|
|
18452
18750
|
if (!entryPointAddress) {
|
|
@@ -18475,7 +18773,7 @@ var ContractInteractionService = class {
|
|
|
18475
18773
|
const walletClient = this.clientManager.getWalletClient(chain);
|
|
18476
18774
|
const publicClient = this.clientManager.getPublicClient(chain);
|
|
18477
18775
|
this.logger.info(
|
|
18478
|
-
{ chain, solver: this.solverAccountAddress, amount: (0,
|
|
18776
|
+
{ chain, solver: this.solverAccountAddress, amount: (0, import_viem23.formatEther)(amount) },
|
|
18479
18777
|
"Depositing to EntryPoint"
|
|
18480
18778
|
);
|
|
18481
18779
|
const hash = await walletClient.writeContract({
|
|
@@ -18490,7 +18788,7 @@ var ContractInteractionService = class {
|
|
|
18490
18788
|
if (receipt.status !== "success") {
|
|
18491
18789
|
throw new Error(`EntryPoint deposit transaction reverted: ${hash}`);
|
|
18492
18790
|
}
|
|
18493
|
-
this.logger.info({ chain, txHash: hash, amount: (0,
|
|
18791
|
+
this.logger.info({ chain, txHash: hash, amount: (0, import_viem23.formatEther)(amount) }, "EntryPoint deposit confirmed");
|
|
18494
18792
|
return hash;
|
|
18495
18793
|
}
|
|
18496
18794
|
/**
|
|
@@ -18510,7 +18808,7 @@ var ContractInteractionService = class {
|
|
|
18510
18808
|
const walletClient = this.clientManager.getWalletClient(chain);
|
|
18511
18809
|
const publicClient = this.clientManager.getPublicClient(chain);
|
|
18512
18810
|
this.logger.info(
|
|
18513
|
-
{ chain, solver: this.solverAccountAddress, amount: (0,
|
|
18811
|
+
{ chain, solver: this.solverAccountAddress, amount: (0, import_viem23.formatEther)(balance) },
|
|
18514
18812
|
"Withdrawing from EntryPoint"
|
|
18515
18813
|
);
|
|
18516
18814
|
const hash = await walletClient.writeContract({
|
|
@@ -18524,7 +18822,7 @@ var ContractInteractionService = class {
|
|
|
18524
18822
|
if (receipt.status !== "success") {
|
|
18525
18823
|
throw new Error(`EntryPoint withdrawal transaction reverted: ${hash}`);
|
|
18526
18824
|
}
|
|
18527
|
-
this.logger.info({ chain, txHash: hash, amount: (0,
|
|
18825
|
+
this.logger.info({ chain, txHash: hash, amount: (0, import_viem23.formatEther)(balance) }, "EntryPoint withdrawal confirmed");
|
|
18528
18826
|
return hash;
|
|
18529
18827
|
}
|
|
18530
18828
|
/**
|
|
@@ -18587,7 +18885,8 @@ var ContractInteractionService = class {
|
|
|
18587
18885
|
if (!cachedEstimate) {
|
|
18588
18886
|
throw new Error(`No cached gas estimate found for order ${order.id}. Call estimateGasFillPost first.`);
|
|
18589
18887
|
}
|
|
18590
|
-
const
|
|
18888
|
+
const budget = this.cacheService.getBidBudget(order.id);
|
|
18889
|
+
const callGasLimit = this.callGasLimitFor(order, cachedEstimate.callGasLimit, budget);
|
|
18591
18890
|
const cachedFillerOutputs = this.cacheService.getFillerOutputs(order.id);
|
|
18592
18891
|
const cachedFillerInputs = this.cacheService.getFillerInputs(order.id);
|
|
18593
18892
|
if (!cachedFillerOutputs || !cachedFillerInputs) {
|
|
@@ -18614,7 +18913,8 @@ var ContractInteractionService = class {
|
|
|
18614
18913
|
order,
|
|
18615
18914
|
cachedFillerOutputs,
|
|
18616
18915
|
fillOptions,
|
|
18617
|
-
cachedEstimate.totalCostInSourceFeeToken + dispatchFeeTokenAmount
|
|
18916
|
+
cachedEstimate.totalCostInSourceFeeToken + dispatchFeeTokenAmount,
|
|
18917
|
+
budget ? { budget, solverAccount: solverAccountAddress } : void 0
|
|
18618
18918
|
);
|
|
18619
18919
|
const commitment = (0, import_sdk7.orderCommitment)(order);
|
|
18620
18920
|
const nonce = await this.clientManager.getPublicClient(order.destination).readContract({
|
|
@@ -18760,7 +19060,7 @@ var ContractInteractionService = class {
|
|
|
18760
19060
|
{
|
|
18761
19061
|
target: outputToken,
|
|
18762
19062
|
value: 0n,
|
|
18763
|
-
data: (0,
|
|
19063
|
+
data: (0, import_viem23.encodeFunctionData)({
|
|
18764
19064
|
abi: ERC20_ABI,
|
|
18765
19065
|
functionName: "approve",
|
|
18766
19066
|
args: [gateway, outputAmount]
|
|
@@ -18806,8 +19106,13 @@ var ContractInteractionService = class {
|
|
|
18806
19106
|
* Same-chain fills release escrow locally with no Hyperbridge dispatch, so the
|
|
18807
19107
|
* gateway never pulls the fee token — its approval is skipped. Only cross-chain
|
|
18808
19108
|
* fills, which dispatch a RedeemEscrow message paid in the fee token, need it.
|
|
19109
|
+
*
|
|
19110
|
+
* A bid priced by a limit order ends with `debitOrder`, which takes the budget's id
|
|
19111
|
+
* as its `orderId`, works out what the fill paid from what is left of the allowance
|
|
19112
|
+
* and reverts the whole batch if the order's payouts would pass its size. It has to
|
|
19113
|
+
* come last, after the gateway has drawn on the allowance.
|
|
18809
19114
|
*/
|
|
18810
|
-
async buildApprovalAndFillCalldata(order, fillerOutputs, fillOptions, requiredFeeTokenAmount) {
|
|
19115
|
+
async buildApprovalAndFillCalldata(order, fillerOutputs, fillOptions, requiredFeeTokenAmount, settlement) {
|
|
18811
19116
|
const chain = order.destination;
|
|
18812
19117
|
const intentGatewayV2Address = this.configService.getIntentGatewayAddress(chain);
|
|
18813
19118
|
const perTokenRequired = /* @__PURE__ */ new Map();
|
|
@@ -18817,9 +19122,10 @@ var ContractInteractionService = class {
|
|
|
18817
19122
|
const key = addr.toLowerCase();
|
|
18818
19123
|
perTokenRequired.set(key, (perTokenRequired.get(key) ?? 0n) + output.amount);
|
|
18819
19124
|
}
|
|
19125
|
+
let feeKey;
|
|
18820
19126
|
if (order.source !== order.destination) {
|
|
18821
19127
|
const feeToken = await this.getFeeTokenWithDecimals(chain);
|
|
18822
|
-
|
|
19128
|
+
feeKey = feeToken.address.toLowerCase();
|
|
18823
19129
|
perTokenRequired.set(feeKey, (perTokenRequired.get(feeKey) ?? 0n) + requiredFeeTokenAmount);
|
|
18824
19130
|
}
|
|
18825
19131
|
const fundingPrepends = order.id ? this.cacheService.getFundingPrepends(order.id) : null;
|
|
@@ -18831,7 +19137,7 @@ var ContractInteractionService = class {
|
|
|
18831
19137
|
calls.push({
|
|
18832
19138
|
target: tokenAddress,
|
|
18833
19139
|
value: 0n,
|
|
18834
|
-
data: (0,
|
|
19140
|
+
data: (0, import_viem23.encodeFunctionData)({
|
|
18835
19141
|
abi: ERC20_ABI,
|
|
18836
19142
|
functionName: "approve",
|
|
18837
19143
|
args: [intentGatewayV2Address, amount]
|
|
@@ -18845,17 +19151,37 @@ var ContractInteractionService = class {
|
|
|
18845
19151
|
value: nativeOutputValue,
|
|
18846
19152
|
data: (0, import_sdk7.encodeFillOrder)((0, import_sdk7.transformOrderForContract)(order), fillOptions)
|
|
18847
19153
|
});
|
|
19154
|
+
if (settlement && settles(settlement.budget)) {
|
|
19155
|
+
const { budget, solverAccount } = settlement;
|
|
19156
|
+
const budgetToken = budget.token.toLowerCase();
|
|
19157
|
+
const approved = perTokenRequired.get(budgetToken) ?? 0n;
|
|
19158
|
+
if (approved === 0n) {
|
|
19159
|
+
throw new Error(
|
|
19160
|
+
`Bid on order ${order.id} approves nothing in ${budget.token}, the token budget ${budget.budgetId} is measured in`
|
|
19161
|
+
);
|
|
19162
|
+
}
|
|
19163
|
+
const fee = feeKey === budgetToken ? fillOptions.relayerFee : 0n;
|
|
19164
|
+
calls.push({
|
|
19165
|
+
target: solverAccount,
|
|
19166
|
+
value: 0n,
|
|
19167
|
+
data: (0, import_viem23.encodeFunctionData)({
|
|
19168
|
+
abi: SOLVER_ACCOUNT_ABI,
|
|
19169
|
+
functionName: "debitOrder",
|
|
19170
|
+
args: [budget.budgetId, budget.cap, budgetToken, approved, fee]
|
|
19171
|
+
})
|
|
19172
|
+
});
|
|
19173
|
+
}
|
|
18848
19174
|
return (0, import_sdk7.encodeERC7821ExecuteBatch)(calls);
|
|
18849
19175
|
}
|
|
18850
19176
|
};
|
|
18851
19177
|
|
|
18852
19178
|
// src/services/DelegationService.ts
|
|
18853
|
-
var
|
|
19179
|
+
var import_viem25 = require("viem");
|
|
18854
19180
|
var import_sdk9 = require("@hyperbridge/sdk");
|
|
18855
19181
|
|
|
18856
19182
|
// src/services/UserOpSender.ts
|
|
18857
19183
|
var import_sdk8 = require("@hyperbridge/sdk");
|
|
18858
|
-
var
|
|
19184
|
+
var import_viem24 = require("viem");
|
|
18859
19185
|
var FALLBACK_VERIFICATION_GAS_LIMIT = 250000n;
|
|
18860
19186
|
var FALLBACK_CALL_GAS_LIMIT = 1500000n;
|
|
18861
19187
|
var FALLBACK_PRE_VERIFICATION_GAS = 150000n;
|
|
@@ -18928,11 +19254,11 @@ var UserOpSender = class {
|
|
|
18928
19254
|
});
|
|
18929
19255
|
const formattedAuth = auth ? {
|
|
18930
19256
|
address: auth.address,
|
|
18931
|
-
chainId: (0,
|
|
18932
|
-
nonce: (0,
|
|
19257
|
+
chainId: (0, import_viem24.toHex)(auth.chainId),
|
|
19258
|
+
nonce: (0, import_viem24.toHex)(auth.nonce),
|
|
18933
19259
|
r: auth.r,
|
|
18934
19260
|
s: auth.s,
|
|
18935
|
-
yParity: (0,
|
|
19261
|
+
yParity: (0, import_viem24.toHex)(auth.yParity)
|
|
18936
19262
|
} : void 0;
|
|
18937
19263
|
const { verificationGasLimit, callGasLimit, preVerificationGas } = gas ?? await this.estimateGas({
|
|
18938
19264
|
bundlerUrl,
|
|
@@ -19100,10 +19426,10 @@ function bootstrapCallData(approval) {
|
|
|
19100
19426
|
{
|
|
19101
19427
|
target: approval.token,
|
|
19102
19428
|
value: 0n,
|
|
19103
|
-
data: (0,
|
|
19104
|
-
abi:
|
|
19429
|
+
data: (0, import_viem25.encodeFunctionData)({
|
|
19430
|
+
abi: import_viem25.erc20Abi,
|
|
19105
19431
|
functionName: "approve",
|
|
19106
|
-
args: [approval.spender,
|
|
19432
|
+
args: [approval.spender, import_viem25.maxUint256]
|
|
19107
19433
|
})
|
|
19108
19434
|
}
|
|
19109
19435
|
]);
|
|
@@ -19154,10 +19480,10 @@ var DelegationService = class {
|
|
|
19154
19480
|
return await walletClient.sendTransaction({
|
|
19155
19481
|
to: approval.token,
|
|
19156
19482
|
value: 0n,
|
|
19157
|
-
data: (0,
|
|
19158
|
-
abi:
|
|
19483
|
+
data: (0, import_viem25.encodeFunctionData)({
|
|
19484
|
+
abi: import_viem25.erc20Abi,
|
|
19159
19485
|
functionName: "approve",
|
|
19160
|
-
args: [approval.spender,
|
|
19486
|
+
args: [approval.spender, import_viem25.maxUint256]
|
|
19161
19487
|
}),
|
|
19162
19488
|
authorizationList: [authorization],
|
|
19163
19489
|
chain: walletClient.chain,
|
|
@@ -19391,8 +19717,8 @@ var DelegationService = class {
|
|
|
19391
19717
|
{
|
|
19392
19718
|
chain,
|
|
19393
19719
|
authority,
|
|
19394
|
-
nativeBalance: (0,
|
|
19395
|
-
requiredNative: (0,
|
|
19720
|
+
nativeBalance: (0, import_viem25.formatEther)(native.nativeBalance),
|
|
19721
|
+
requiredNative: (0, import_viem25.formatEther)(native.requiredNative)
|
|
19396
19722
|
},
|
|
19397
19723
|
"Delegation failed: insufficient native balance for direct EIP-7702 tx and paymaster path unavailable"
|
|
19398
19724
|
);
|
|
@@ -19467,7 +19793,7 @@ var DelegationService = class {
|
|
|
19467
19793
|
{ chain, authority: this.signer.address, mode: this.signer.mode ?? "custom" },
|
|
19468
19794
|
"Revoking EIP-7702 delegation"
|
|
19469
19795
|
);
|
|
19470
|
-
const authorization = await this.buildAuthorization(chain,
|
|
19796
|
+
const authorization = await this.buildAuthorization(chain, import_viem25.zeroAddress);
|
|
19471
19797
|
const hash = await this.sendDelegationTransaction(chain, authorization);
|
|
19472
19798
|
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
19473
19799
|
if (receipt.status === "success") {
|
|
@@ -19483,13 +19809,13 @@ var DelegationService = class {
|
|
|
19483
19809
|
};
|
|
19484
19810
|
|
|
19485
19811
|
// src/services/RebalancingService.ts
|
|
19486
|
-
var
|
|
19812
|
+
var import_viem28 = require("viem");
|
|
19487
19813
|
var import_sdk13 = require("@hyperbridge/sdk");
|
|
19488
19814
|
var import_decimal3 = require("decimal.js");
|
|
19489
19815
|
|
|
19490
19816
|
// src/services/rebalancers/binance.ts
|
|
19491
19817
|
var import_wallet2 = require("@binance/wallet");
|
|
19492
|
-
var
|
|
19818
|
+
var import_viem26 = require("viem");
|
|
19493
19819
|
var import_sdk10 = require("@hyperbridge/sdk");
|
|
19494
19820
|
var DEPOSIT_STATUS_SUCCESS = 1;
|
|
19495
19821
|
var WITHDRAW_STATUS_COMPLETED = 6;
|
|
@@ -19801,7 +20127,7 @@ var BinanceRebalancer = class {
|
|
|
19801
20127
|
abi: ERC20_ABI,
|
|
19802
20128
|
functionName: "decimals"
|
|
19803
20129
|
});
|
|
19804
|
-
const amountWei = (0,
|
|
20130
|
+
const amountWei = (0, import_viem26.parseUnits)(amount, Number(tokenDecimals));
|
|
19805
20131
|
const balance = await publicClient.readContract({
|
|
19806
20132
|
address: tokenAddress,
|
|
19807
20133
|
abi: ERC20_ABI,
|
|
@@ -20025,7 +20351,7 @@ var CctpRebalancer = class {
|
|
|
20025
20351
|
};
|
|
20026
20352
|
|
|
20027
20353
|
// src/services/rebalancers/usdt0.ts
|
|
20028
|
-
var
|
|
20354
|
+
var import_viem27 = require("viem");
|
|
20029
20355
|
var import_sdk12 = require("@hyperbridge/sdk");
|
|
20030
20356
|
|
|
20031
20357
|
// src/config/abis/Oft.ts
|
|
@@ -20188,7 +20514,7 @@ var Usdt0Rebalancer = class {
|
|
|
20188
20514
|
const publicClient = this.chainClientManager.getPublicClient(source);
|
|
20189
20515
|
const walletClient = this.chainClientManager.getWalletClient(source);
|
|
20190
20516
|
const recipient = recipientAddress || this.account.address;
|
|
20191
|
-
const amountWei = (0,
|
|
20517
|
+
const amountWei = (0, import_viem27.parseUnits)(amount, 6);
|
|
20192
20518
|
if (sourceChainId === 1) {
|
|
20193
20519
|
const allowance = await publicClient.readContract({
|
|
20194
20520
|
address: tokenAddress,
|
|
@@ -20201,7 +20527,7 @@ var Usdt0Rebalancer = class {
|
|
|
20201
20527
|
address: tokenAddress,
|
|
20202
20528
|
abi: ERC20_ABI,
|
|
20203
20529
|
functionName: "approve",
|
|
20204
|
-
args: [oftAddress,
|
|
20530
|
+
args: [oftAddress, import_viem27.maxUint256],
|
|
20205
20531
|
chain: walletClient.chain
|
|
20206
20532
|
});
|
|
20207
20533
|
await publicClient.waitForTransactionReceipt({ hash: approveTx, confirmations: 1 });
|
|
@@ -20283,8 +20609,8 @@ var Usdt0Rebalancer = class {
|
|
|
20283
20609
|
if (!oftAddress) throw new Error(`Chain ${source} not supported by USDT0`);
|
|
20284
20610
|
const publicClient = this.chainClientManager.getPublicClient(source);
|
|
20285
20611
|
const recipient = recipientAddress || this.account.address;
|
|
20286
|
-
const amountWei = (0,
|
|
20287
|
-
const recipientBytes32 = (0,
|
|
20612
|
+
const amountWei = (0, import_viem27.parseUnits)(amount, 6);
|
|
20613
|
+
const recipientBytes32 = (0, import_viem27.padHex)(recipient, { size: 32 });
|
|
20288
20614
|
const sendParam = {
|
|
20289
20615
|
dstEid: destEid,
|
|
20290
20616
|
to: recipientBytes32,
|
|
@@ -20636,7 +20962,7 @@ var RebalancingService = class {
|
|
|
20636
20962
|
functionName: "balanceOf",
|
|
20637
20963
|
args: [this.walletAddress]
|
|
20638
20964
|
});
|
|
20639
|
-
const balanceDecimal = new import_decimal3.Decimal((0,
|
|
20965
|
+
const balanceDecimal = new import_decimal3.Decimal((0, import_viem28.formatUnits)(balanceWei, Number(decimals)));
|
|
20640
20966
|
return balanceDecimal.toNumber();
|
|
20641
20967
|
} catch (error) {
|
|
20642
20968
|
this.logger.error({ error, chain, asset }, "Failed to get current balance");
|
|
@@ -20684,11 +21010,11 @@ function byBestRate(a, b) {
|
|
|
20684
21010
|
return left === right ? 0 : left > right ? -1 : 1;
|
|
20685
21011
|
}
|
|
20686
21012
|
function chargedFor(hold, delivered, released) {
|
|
20687
|
-
|
|
20688
|
-
|
|
20689
|
-
|
|
20690
|
-
const atRate = (
|
|
20691
|
-
return atRate > delivered ? atRate : delivered;
|
|
21013
|
+
const take = hold.take === void 0 ? 0n : BigInt(hold.take);
|
|
21014
|
+
if (take === 0n || released === 0n) return toScaledUp(delivered.raw, delivered.decimals);
|
|
21015
|
+
const offered = toRaw(BigInt(hold.amount), delivered.decimals);
|
|
21016
|
+
const atRate = (offered * released + take - 1n) / take;
|
|
21017
|
+
return toScaledUp(atRate > delivered.raw ? atRate : delivered.raw, delivered.decimals);
|
|
20692
21018
|
}
|
|
20693
21019
|
var IntentFiller = class {
|
|
20694
21020
|
constructor(chainConfigs, strategies, config, configService, chainClientManager, contractService, signer, scanners, rebalancingService, bidStorage, limitOrders, assetRegistry) {
|
|
@@ -20765,6 +21091,17 @@ var IntentFiller = class {
|
|
|
20765
21091
|
setLimitOrderService(service) {
|
|
20766
21092
|
this.limitOrderService = service;
|
|
20767
21093
|
}
|
|
21094
|
+
/**
|
|
21095
|
+
* Brings the limit orders' `remaining` in line with their on-chain tallies.
|
|
21096
|
+
*
|
|
21097
|
+
* On the settlement queue, so the pass and a fill never resize the same order at
|
|
21098
|
+
* once. Resolves when the pass has run.
|
|
21099
|
+
*/
|
|
21100
|
+
async reconcileLimitOrderTallies() {
|
|
21101
|
+
await this.settlementQueue.add(async () => {
|
|
21102
|
+
await this.limitOrderService?.reconcileTallies();
|
|
21103
|
+
});
|
|
21104
|
+
}
|
|
20768
21105
|
/** Whether the given chain id is configured for watch-only (monitor, never fill). */
|
|
20769
21106
|
isChainWatchOnly(chainId) {
|
|
20770
21107
|
const watchOnly = this.config.watchOnly;
|
|
@@ -21410,7 +21747,7 @@ var IntentFiller = class {
|
|
|
21410
21747
|
let reservation = [];
|
|
21411
21748
|
if (plan) {
|
|
21412
21749
|
if (order.id) {
|
|
21413
|
-
cache.setFillerOutputs(order.id, plan.fillerOutputs, plan.fillerInputs);
|
|
21750
|
+
cache.setFillerOutputs(order.id, plan.fillerOutputs, plan.fillerInputs, plan.budget);
|
|
21414
21751
|
cache.setPartialFill(order.id, plan.partialFill);
|
|
21415
21752
|
if (plan.fundingCalls.length > 0) cache.setFundingPrepends(order.id, plan.fundingCalls);
|
|
21416
21753
|
else cache.clearFundingPrepends(order.id);
|
|
@@ -21611,7 +21948,7 @@ var IntentFiller = class {
|
|
|
21611
21948
|
await this.releaseAll(claimed);
|
|
21612
21949
|
return;
|
|
21613
21950
|
}
|
|
21614
|
-
const settled = executedHold(claimed, delivered, released);
|
|
21951
|
+
const settled = executedHold(claimed, delivered.scaled, released);
|
|
21615
21952
|
const charged = chargedFor(settled, delivered, released);
|
|
21616
21953
|
const settledBid = rows.find(
|
|
21617
21954
|
(row) => row.reservations.some(
|
|
@@ -21664,15 +22001,15 @@ var IntentFiller = class {
|
|
|
21664
22001
|
if (delivered === null) return [];
|
|
21665
22002
|
const settled = executedHold(
|
|
21666
22003
|
holds.map((entry) => entry.hold),
|
|
21667
|
-
delivered,
|
|
22004
|
+
delivered.scaled,
|
|
21668
22005
|
released
|
|
21669
22006
|
);
|
|
21670
22007
|
const row = holds.find((entry) => entry.hold === settled).row;
|
|
21671
22008
|
return this.bidStorage.claimReservation(commitment, row.bid ?? void 0);
|
|
21672
22009
|
}
|
|
21673
22010
|
/**
|
|
21674
|
-
* What this fill delivered of the token the limit order pays,
|
|
21675
|
-
*
|
|
22011
|
+
* What this fill delivered of the token the limit order pays, or null when the
|
|
22012
|
+
* fill names none of it.
|
|
21676
22013
|
*/
|
|
21677
22014
|
async deliveredAgainst(limitOrderId, chainId, outputs) {
|
|
21678
22015
|
const order = await this.limitOrders?.get(limitOrderId);
|
|
@@ -21688,7 +22025,7 @@ var IntentFiller = class {
|
|
|
21688
22025
|
}
|
|
21689
22026
|
if (total === 0n) return null;
|
|
21690
22027
|
const decimals = await this.contractService.getTokenDecimals(address, chain);
|
|
21691
|
-
return toScaled(total, decimals);
|
|
22028
|
+
return { scaled: toScaled(total, decimals), raw: total, decimals };
|
|
21692
22029
|
}
|
|
21693
22030
|
/**
|
|
21694
22031
|
* Gives back whatever this bid still holds against its limit order.
|
|
@@ -21778,90 +22115,9 @@ var IntentFiller = class {
|
|
|
21778
22115
|
|
|
21779
22116
|
// src/strategies/fx.ts
|
|
21780
22117
|
var import_sdk15 = require("@hyperbridge/sdk");
|
|
21781
|
-
var
|
|
22118
|
+
var import_viem29 = require("viem");
|
|
21782
22119
|
var import_decimal6 = require("decimal.js");
|
|
21783
22120
|
|
|
21784
|
-
// src/orderbook/matching.ts
|
|
21785
|
-
function limitOrderLegs(order) {
|
|
21786
|
-
return order.side === "BID" ? { input: order.base, output: order.quote } : { input: order.quote, output: order.base };
|
|
21787
|
-
}
|
|
21788
|
-
function matchLimitOrders(orders, incoming, resolve, now = /* @__PURE__ */ new Date()) {
|
|
21789
|
-
const qualifying = orders.filter((order) => serves(order, incoming, resolve, now)).map((order) => {
|
|
21790
|
-
const offer = offerFor({
|
|
21791
|
-
side: order.side,
|
|
21792
|
-
inputAmount: incoming.inputNet,
|
|
21793
|
-
price: BigInt(order.price),
|
|
21794
|
-
outputDecimals: incoming.outputDecimals
|
|
21795
|
-
});
|
|
21796
|
-
const available = BigInt(order.remaining);
|
|
21797
|
-
return { order, offer, available, payout: offer < available ? offer : available };
|
|
21798
|
-
}).filter((candidate) => candidate.offer >= incoming.requestedOutput && candidate.payout > 0n).sort(byBestOfferFirst);
|
|
21799
|
-
return qualifying;
|
|
21800
|
-
}
|
|
21801
|
-
function byBestOfferFirst(a, b) {
|
|
21802
|
-
if (a.offer !== b.offer) return a.offer > b.offer ? -1 : 1;
|
|
21803
|
-
if (a.available !== b.available) return a.available > b.available ? -1 : 1;
|
|
21804
|
-
return a.order.id < b.order.id ? -1 : 1;
|
|
21805
|
-
}
|
|
21806
|
-
function whyUnmatched(orders, incoming, resolve, now = /* @__PURE__ */ new Date()) {
|
|
21807
|
-
let furthest = -1;
|
|
21808
|
-
for (const order of orders) {
|
|
21809
|
-
const failed = firstFailed(order, incoming, resolve, now);
|
|
21810
|
-
furthest = Math.max(furthest, failed === null ? CHECKS.length : CHECKS.indexOf(failed));
|
|
21811
|
-
}
|
|
21812
|
-
const { source, destination, inputSymbol } = incoming;
|
|
21813
|
-
if (furthest < CHECKS.length) {
|
|
21814
|
-
switch (CHECKS[Math.max(furthest, 0)]) {
|
|
21815
|
-
case "open":
|
|
21816
|
-
return "no limit order is open";
|
|
21817
|
-
case "chain":
|
|
21818
|
-
return `no open limit order fills on ${destination}`;
|
|
21819
|
-
case "input":
|
|
21820
|
-
return `no limit order on ${destination} takes ${inputSymbol} in`;
|
|
21821
|
-
case "output":
|
|
21822
|
-
return `no limit order on ${destination} taking ${inputSymbol} in pays out the token this order asks for`;
|
|
21823
|
-
case "source":
|
|
21824
|
-
return `no limit order for this pair on ${destination} accepts swaps from ${source}`;
|
|
21825
|
-
}
|
|
21826
|
-
}
|
|
21827
|
-
const priced = orders.filter((order) => firstFailed(order, incoming, resolve, now) === null).map((order) => ({
|
|
21828
|
-
order,
|
|
21829
|
-
offer: offerFor({
|
|
21830
|
-
side: order.side,
|
|
21831
|
-
inputAmount: incoming.inputNet,
|
|
21832
|
-
price: BigInt(order.price),
|
|
21833
|
-
outputDecimals: incoming.outputDecimals
|
|
21834
|
-
})
|
|
21835
|
-
}));
|
|
21836
|
-
if (priced.some(({ offer }) => offer >= incoming.requestedOutput)) {
|
|
21837
|
-
return "the limit orders that meet its rate have nothing left to pay out";
|
|
21838
|
-
}
|
|
21839
|
-
const best = priced.reduce((a, b) => b.offer > a.offer ? b : a);
|
|
21840
|
-
const symbol = limitOrderLegs(best.order).output;
|
|
21841
|
-
return `it asks for ${readable(incoming.requestedOutput)} ${symbol}; the best limit order offers ${readable(best.offer)} ${symbol}`;
|
|
21842
|
-
}
|
|
21843
|
-
var CHECKS = ["open", "chain", "input", "output", "source"];
|
|
21844
|
-
function serves(order, incoming, resolve, now) {
|
|
21845
|
-
return firstFailed(order, incoming, resolve, now) === null;
|
|
21846
|
-
}
|
|
21847
|
-
function firstFailed(order, incoming, resolve, now) {
|
|
21848
|
-
if (order.status !== "open") return "open";
|
|
21849
|
-
if (order.expiresAt !== null && new Date(order.expiresAt) <= now) return "open";
|
|
21850
|
-
if (order.fillChain !== incoming.destination) return "chain";
|
|
21851
|
-
const legs = limitOrderLegs(order);
|
|
21852
|
-
if (normalizeSymbol(legs.input) !== normalizeSymbol(incoming.inputSymbol)) return "input";
|
|
21853
|
-
const outputToken = resolve(legs.output, order.fillChain);
|
|
21854
|
-
if (!outputToken || outputToken.toLowerCase() !== incoming.outputToken.toLowerCase()) return "output";
|
|
21855
|
-
if (incoming.source === incoming.destination) return null;
|
|
21856
|
-
return order.acceptedSources.includes(incoming.source) ? null : "source";
|
|
21857
|
-
}
|
|
21858
|
-
function readable(amount) {
|
|
21859
|
-
const [whole, fraction] = toHuman(amount).split(".");
|
|
21860
|
-
const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
21861
|
-
const cut = fraction?.slice(0, 6).replace(/0+$/, "");
|
|
21862
|
-
return cut ? `${grouped}.${cut}` : grouped;
|
|
21863
|
-
}
|
|
21864
|
-
|
|
21865
22121
|
// src/orderbook/usd.ts
|
|
21866
22122
|
var import_decimal5 = require("decimal.js");
|
|
21867
22123
|
function limitOrderUsdEdges(orders) {
|
|
@@ -21916,9 +22172,13 @@ var FXFiller = class _FXFiller {
|
|
|
21916
22172
|
*/
|
|
21917
22173
|
constructor(signer, configService, clientManager, contractService, pairs, registry, options) {
|
|
21918
22174
|
this.name = "FXFiller";
|
|
21919
|
-
/**
|
|
22175
|
+
/**
|
|
22176
|
+
* Consecutive orders where the overfill clamp activated. Dormant: the clamp
|
|
22177
|
+
* existed for venue-priced legs, which went with Uniswap V4 pricing, so every
|
|
22178
|
+
* outcome is now recorded unclamped and this never climbs. See `recordOrderOutcome`.
|
|
22179
|
+
*/
|
|
21920
22180
|
this.consecutiveClamps = 0;
|
|
21921
|
-
/** Once set, the filler refuses all orders until
|
|
22181
|
+
/** Once set, the filler refuses all orders until reset. Unreachable while the clamp is dormant. */
|
|
21922
22182
|
this.halted = false;
|
|
21923
22183
|
this.logger = moduleLogger(configService.loggers, "fx-simplex");
|
|
21924
22184
|
const { confirmationPolicy, fundingVenues = [], limitOrders } = options ?? {};
|
|
@@ -21967,10 +22227,9 @@ var FXFiller = class _FXFiller {
|
|
|
21967
22227
|
this.pairs.push(pair);
|
|
21968
22228
|
}
|
|
21969
22229
|
/**
|
|
21970
|
-
* Removes a market from the running engine.
|
|
21971
|
-
*
|
|
21972
|
-
*
|
|
21973
|
-
* rechecks of orders on the removed pair simply stop matching.
|
|
22230
|
+
* Removes a market from the running engine. At least one market must remain.
|
|
22231
|
+
* Matching reads the limit orders rather than the pairs, so removing a market
|
|
22232
|
+
* changes what the dashboard lists, not what the filler fills.
|
|
21974
22233
|
*/
|
|
21975
22234
|
removePair(pair) {
|
|
21976
22235
|
const index = this.pairs.indexOf(pair);
|
|
@@ -22026,22 +22285,20 @@ var FXFiller = class _FXFiller {
|
|
|
22026
22285
|
}
|
|
22027
22286
|
}
|
|
22028
22287
|
/**
|
|
22029
|
-
* Evaluates whether an order is profitable to fill
|
|
22030
|
-
*
|
|
22288
|
+
* Evaluates whether an order is profitable to fill against the operator's
|
|
22289
|
+
* limit orders and the filler's current token balances.
|
|
22031
22290
|
*
|
|
22032
22291
|
* High-level flow:
|
|
22033
|
-
* -
|
|
22034
|
-
* -
|
|
22035
|
-
*
|
|
22036
|
-
*
|
|
22037
|
-
*
|
|
22038
|
-
*
|
|
22039
|
-
*
|
|
22040
|
-
*
|
|
22041
|
-
*
|
|
22042
|
-
*
|
|
22043
|
-
* Note: we may intentionally overfill relative to the user's requested
|
|
22044
|
-
* outputs if the pair pricing makes that attractive. This is how we stay competitive.
|
|
22292
|
+
* - Match each (input, output) leg against the open limit orders.
|
|
22293
|
+
* - Build one bid per matching order, best offer first, each paying the
|
|
22294
|
+
* order's whole offer for the input at its own rate, capped by what the
|
|
22295
|
+
* order has left. The gateway credits the swapper the ask and splits
|
|
22296
|
+
* anything above it between the swapper and the protocol.
|
|
22297
|
+
* - Treat a payout below the ask as a partial fill, which only orders
|
|
22298
|
+
* without output calldata and without an earlier partial fill allow.
|
|
22299
|
+
* - Cap each payout by the filler's balance plus funding-venue withdrawals,
|
|
22300
|
+
* then gate it on fees (full fills) and the same-asset spread.
|
|
22301
|
+
* - Cache the resulting bids for later use in `executeOrder`.
|
|
22045
22302
|
*/
|
|
22046
22303
|
async calculateProfitability(order) {
|
|
22047
22304
|
if (order.id) this.contractService.cacheService.clearPartialFill(order.id);
|
|
@@ -22059,6 +22316,7 @@ var FXFiller = class _FXFiller {
|
|
|
22059
22316
|
const multiLeg = order.inputs.length > 1;
|
|
22060
22317
|
const plans = [];
|
|
22061
22318
|
const plannedOn = /* @__PURE__ */ new Map();
|
|
22319
|
+
const spentOn = /* @__PURE__ */ new Map();
|
|
22062
22320
|
for (let leg = 0; leg < order.inputs.length; leg++) {
|
|
22063
22321
|
const input = order.inputs[leg];
|
|
22064
22322
|
const output = order.output.assets[leg];
|
|
@@ -22080,7 +22338,30 @@ var FXFiller = class _FXFiller {
|
|
|
22080
22338
|
for (const candidate of matches) {
|
|
22081
22339
|
let partialFill = false;
|
|
22082
22340
|
const fundingCalls = [];
|
|
22083
|
-
const
|
|
22341
|
+
const budget = budgetFor(candidate.order, outputToken, outputDecimals);
|
|
22342
|
+
if (!spentOn.has(candidate.order.id)) {
|
|
22343
|
+
spentOn.set(
|
|
22344
|
+
candidate.order.id,
|
|
22345
|
+
await this.contractService.limitOrderSpent(destChain, budget.budgetId)
|
|
22346
|
+
);
|
|
22347
|
+
}
|
|
22348
|
+
const spent = spentOn.get(candidate.order.id) ?? null;
|
|
22349
|
+
const room = spent === null ? candidate.available : budgetRoom(budget, spent, outputDecimals);
|
|
22350
|
+
if (room === 0n) {
|
|
22351
|
+
this.logger.info(
|
|
22352
|
+
{
|
|
22353
|
+
orderId: order.id,
|
|
22354
|
+
leg,
|
|
22355
|
+
limitOrder: candidate.order.id,
|
|
22356
|
+
spent: spent?.toString(),
|
|
22357
|
+
cap: budget.cap.toString()
|
|
22358
|
+
},
|
|
22359
|
+
"Skipping a bid: the limit order has nothing left on chain"
|
|
22360
|
+
);
|
|
22361
|
+
continue;
|
|
22362
|
+
}
|
|
22363
|
+
const available = room < candidate.available ? room : candidate.available;
|
|
22364
|
+
const left = available - (plannedOn.get(candidate.order.id) ?? 0n);
|
|
22084
22365
|
if (left <= 0n) {
|
|
22085
22366
|
this.logger.info(
|
|
22086
22367
|
{ orderId: order.id, leg, limitOrder: candidate.order.id },
|
|
@@ -22115,10 +22396,7 @@ var FXFiller = class _FXFiller {
|
|
|
22115
22396
|
{
|
|
22116
22397
|
orderId: order.id,
|
|
22117
22398
|
limitOrder: candidate.order.id,
|
|
22118
|
-
available: (0,
|
|
22119
|
-
candidate.available,
|
|
22120
|
-
18
|
|
22121
|
-
),
|
|
22399
|
+
available: (0, import_viem29.formatUnits)(available, 18),
|
|
22122
22400
|
userRequested: output.amount.toString(),
|
|
22123
22401
|
payout: targetOutput.toString(),
|
|
22124
22402
|
crossChain: sourceChain !== destChain
|
|
@@ -22163,7 +22441,10 @@ var FXFiller = class _FXFiller {
|
|
|
22163
22441
|
}
|
|
22164
22442
|
}
|
|
22165
22443
|
const effectiveBalance = walletContribution + credited;
|
|
22166
|
-
const finalOutputAmount =
|
|
22444
|
+
const finalOutputAmount = toRaw(
|
|
22445
|
+
toScaled(effectiveBalance > targetOutput ? targetOutput : effectiveBalance, outputDecimals),
|
|
22446
|
+
outputDecimals
|
|
22447
|
+
);
|
|
22167
22448
|
if (finalOutputAmount === 0n) {
|
|
22168
22449
|
this.logger.info(
|
|
22169
22450
|
{
|
|
@@ -22252,7 +22533,7 @@ var FXFiller = class _FXFiller {
|
|
|
22252
22533
|
const spread = convertedInput - finalOutputAmount;
|
|
22253
22534
|
if (spread <= 0n) sameAssetProfitable = false;
|
|
22254
22535
|
realizedSpreadProfit = adjustDecimalsFloor(spread, outputDecimals, feeTokenDecimals);
|
|
22255
|
-
const spreadUsd = outputSymbol && usdValueOf(usdFactors, outputSymbol, new import_decimal6.Decimal((0,
|
|
22536
|
+
const spreadUsd = outputSymbol && usdValueOf(usdFactors, outputSymbol, new import_decimal6.Decimal((0, import_viem29.formatUnits)(spread, outputDecimals)));
|
|
22256
22537
|
if (spreadUsd) sameAssetEdgeUsd = spreadUsd;
|
|
22257
22538
|
}
|
|
22258
22539
|
const payoutSurplusUsd = new import_decimal6.Decimal(0);
|
|
@@ -22267,9 +22548,9 @@ var FXFiller = class _FXFiller {
|
|
|
22267
22548
|
{
|
|
22268
22549
|
orderId: order.id,
|
|
22269
22550
|
feeToken: feeTokenLower,
|
|
22270
|
-
residual: (0,
|
|
22271
|
-
dispatchFee: (0,
|
|
22272
|
-
required: (0,
|
|
22551
|
+
residual: (0, import_viem29.formatUnits)(residual, feeToken.decimals),
|
|
22552
|
+
dispatchFee: (0, import_viem29.formatUnits)(dispatchFee, feeToken.decimals),
|
|
22553
|
+
required: (0, import_viem29.formatUnits)(required, feeToken.decimals)
|
|
22273
22554
|
},
|
|
22274
22555
|
"Skipping order: fill leaves too little of the fee token to dispatch the escrow release"
|
|
22275
22556
|
);
|
|
@@ -22282,10 +22563,10 @@ var FXFiller = class _FXFiller {
|
|
|
22282
22563
|
this.logger.info(
|
|
22283
22564
|
{
|
|
22284
22565
|
orderId: order.id,
|
|
22285
|
-
orderFees: (0,
|
|
22286
|
-
fillGas: (0,
|
|
22287
|
-
relayerFee: (0,
|
|
22288
|
-
executionCost: (0,
|
|
22566
|
+
orderFees: (0, import_viem29.formatUnits)(order.fees, feeTokenDecimals),
|
|
22567
|
+
fillGas: (0, import_viem29.formatUnits)(totalCostInSourceFeeToken, feeTokenDecimals),
|
|
22568
|
+
relayerFee: (0, import_viem29.formatUnits)(relayerFeeInSourceFeeToken, feeTokenDecimals),
|
|
22569
|
+
executionCost: (0, import_viem29.formatUnits)(executionCost, feeTokenDecimals)
|
|
22289
22570
|
},
|
|
22290
22571
|
"Skipping order: attached fees do not cover execution cost (fill gas + relayer fee)"
|
|
22291
22572
|
);
|
|
@@ -22293,13 +22574,13 @@ var FXFiller = class _FXFiller {
|
|
|
22293
22574
|
}
|
|
22294
22575
|
if (sameAsset && !sameAssetProfitable) {
|
|
22295
22576
|
this.logger.info(
|
|
22296
|
-
{ orderId: order.id, realizedSpreadProfit: (0,
|
|
22577
|
+
{ orderId: order.id, realizedSpreadProfit: (0, import_viem29.formatUnits)(realizedSpreadProfit, feeTokenDecimals) },
|
|
22297
22578
|
"Skipping order: a same-asset fill does not net a positive spread"
|
|
22298
22579
|
);
|
|
22299
22580
|
continue;
|
|
22300
22581
|
}
|
|
22301
22582
|
const feeProfit = order.fees - executionCost;
|
|
22302
|
-
const totalProfit = partialFill ? partialEdgeUsd.toNumber() : Number.parseFloat((0,
|
|
22583
|
+
const totalProfit = partialFill ? partialEdgeUsd.toNumber() : Number.parseFloat((0, import_viem29.formatUnits)(feeProfit + realizedSpreadProfit, feeTokenDecimals));
|
|
22303
22584
|
this.logger.info(
|
|
22304
22585
|
{
|
|
22305
22586
|
orderId: order.id,
|
|
@@ -22315,12 +22596,12 @@ var FXFiller = class _FXFiller {
|
|
|
22315
22596
|
limitOrders: matches.length,
|
|
22316
22597
|
available: candidate.available.toString(),
|
|
22317
22598
|
payout: targetOutput.toString(),
|
|
22318
|
-
orderFees: (0,
|
|
22319
|
-
fillGas: (0,
|
|
22320
|
-
relayerFee: (0,
|
|
22321
|
-
executionCost: (0,
|
|
22322
|
-
feeProfit: (0,
|
|
22323
|
-
realizedSpreadProfit: (0,
|
|
22599
|
+
orderFees: (0, import_viem29.formatUnits)(order.fees, feeTokenDecimals),
|
|
22600
|
+
fillGas: (0, import_viem29.formatUnits)(totalCostInSourceFeeToken, feeTokenDecimals),
|
|
22601
|
+
relayerFee: (0, import_viem29.formatUnits)(relayerFeeInSourceFeeToken, feeTokenDecimals),
|
|
22602
|
+
executionCost: (0, import_viem29.formatUnits)(executionCost, feeTokenDecimals),
|
|
22603
|
+
feeProfit: (0, import_viem29.formatUnits)(feeProfit, feeTokenDecimals),
|
|
22604
|
+
realizedSpreadProfit: (0, import_viem29.formatUnits)(realizedSpreadProfit, feeTokenDecimals),
|
|
22324
22605
|
payoutSurplusUsd: payoutSurplusUsd.toString(),
|
|
22325
22606
|
totalProfit,
|
|
22326
22607
|
profitable: totalProfit > 0
|
|
@@ -22339,7 +22620,8 @@ var FXFiller = class _FXFiller {
|
|
|
22339
22620
|
fillerInputs,
|
|
22340
22621
|
fundingCalls: [...fundingCalls],
|
|
22341
22622
|
partialFill,
|
|
22342
|
-
profit: totalProfit
|
|
22623
|
+
profit: totalProfit,
|
|
22624
|
+
budget
|
|
22343
22625
|
});
|
|
22344
22626
|
if (!partialEligibleCheap) break;
|
|
22345
22627
|
}
|
|
@@ -22347,7 +22629,12 @@ var FXFiller = class _FXFiller {
|
|
|
22347
22629
|
if (plans.length === 0) return 0;
|
|
22348
22630
|
if (order.id) {
|
|
22349
22631
|
this.contractService.cacheService.setBidPlans(order.id, plans);
|
|
22350
|
-
this.contractService.cacheService.setFillerOutputs(
|
|
22632
|
+
this.contractService.cacheService.setFillerOutputs(
|
|
22633
|
+
order.id,
|
|
22634
|
+
plans[0].fillerOutputs,
|
|
22635
|
+
plans[0].fillerInputs,
|
|
22636
|
+
plans[0].budget
|
|
22637
|
+
);
|
|
22351
22638
|
this.contractService.cacheService.setPartialFill(order.id, plans[0].partialFill);
|
|
22352
22639
|
this.contractService.cacheService.setMatchedLimitOrder(order.id, [
|
|
22353
22640
|
{ limitOrderId: plans[0].limitOrderId, payout: plans[0].payout }
|
|
@@ -22442,10 +22729,14 @@ var FXFiller = class _FXFiller {
|
|
|
22442
22729
|
// =========================================================================
|
|
22443
22730
|
/**
|
|
22444
22731
|
* Update consecutive-clamp counter after a successful order evaluation.
|
|
22445
|
-
*
|
|
22446
|
-
*
|
|
22447
|
-
*
|
|
22448
|
-
*
|
|
22732
|
+
*
|
|
22733
|
+
* Dormant. Only venue-priced legs ever fed a clamped outcome here: a streak
|
|
22734
|
+
* of those meant a live market source had gone off (stale pool, manipulated
|
|
22735
|
+
* venue). Venue pricing went with Uniswap V4, and limit orders are prices the
|
|
22736
|
+
* operator set, so the only caller records `false` and the filler never
|
|
22737
|
+
* halts. `isHalted`, `resetHalt` and `[simplex.overfillProtection]
|
|
22738
|
+
* maxConsecutiveClamps` are kept so existing configs and the halt API still
|
|
22739
|
+
* load; they can go once nothing reads them.
|
|
22449
22740
|
*/
|
|
22450
22741
|
recordOrderOutcome(clamped, orderId) {
|
|
22451
22742
|
if (clamped) {
|
|
@@ -22471,18 +22762,6 @@ var FXFiller = class _FXFiller {
|
|
|
22471
22762
|
this.consecutiveClamps = 0;
|
|
22472
22763
|
this.logger.warn("FXFiller halt reset by operator \u2014 resuming order evaluation");
|
|
22473
22764
|
}
|
|
22474
|
-
/**
|
|
22475
|
-
* Given a single (input, output) leg and the remaining token0 budget of its
|
|
22476
|
-
* pair, computes how much token0 notional to allocate to this leg and the
|
|
22477
|
-
* corresponding maximum output amount at the pair's rate.
|
|
22478
|
-
*
|
|
22479
|
-
* `rate` is **token1 per 1 token0**:
|
|
22480
|
-
* - token0 input → token1 output: token0 × rate → token1 amount.
|
|
22481
|
-
* - token1 input → token0 output: token1 ÷ rate → token0 amount.
|
|
22482
|
-
*
|
|
22483
|
-
* Returns `null` when this leg cannot consume any of the pair's remaining
|
|
22484
|
-
* budget (e.g. the cap has already been exhausted).
|
|
22485
|
-
*/
|
|
22486
22765
|
/**
|
|
22487
22766
|
* Whether any solver has already delivered output against this order.
|
|
22488
22767
|
*
|
|
@@ -22622,7 +22901,7 @@ var FXFiller = class _FXFiller {
|
|
|
22622
22901
|
const symbol = this.registry.symbolFor(inputToken, order.source);
|
|
22623
22902
|
if (!symbol) return null;
|
|
22624
22903
|
const decimals = await this.contractService.getTokenDecimals(inputToken, order.source);
|
|
22625
|
-
const legUsd = usdValueOf(factors, symbol, new import_decimal6.Decimal((0,
|
|
22904
|
+
const legUsd = usdValueOf(factors, symbol, new import_decimal6.Decimal((0, import_viem29.formatUnits)(input.amount, decimals)));
|
|
22626
22905
|
if (!legUsd) return null;
|
|
22627
22906
|
inputUsd = inputUsd.plus(legUsd);
|
|
22628
22907
|
}
|
|
@@ -22635,7 +22914,7 @@ function minBigInt(first, ...rest) {
|
|
|
22635
22914
|
|
|
22636
22915
|
// src/services/TokenSender.ts
|
|
22637
22916
|
var import_sdk16 = require("@hyperbridge/sdk");
|
|
22638
|
-
var
|
|
22917
|
+
var import_viem30 = require("viem");
|
|
22639
22918
|
var TokenSender = class {
|
|
22640
22919
|
constructor(clientManager, solver, getVaults, userOpSender, configService) {
|
|
22641
22920
|
this.clientManager = clientManager;
|
|
@@ -22647,18 +22926,18 @@ var TokenSender = class {
|
|
|
22647
22926
|
}
|
|
22648
22927
|
async send(params) {
|
|
22649
22928
|
const { chain, token, amount, to } = params;
|
|
22650
|
-
if (!(0,
|
|
22929
|
+
if (!(0, import_viem30.isAddress)(to)) throw new Error(`Invalid recipient address: ${to}`);
|
|
22651
22930
|
const publicClient = this.clientManager.getPublicClient(chain);
|
|
22652
22931
|
const calls = [];
|
|
22653
22932
|
let redeemed = false;
|
|
22654
22933
|
if (token === "native") {
|
|
22655
|
-
const value = (0,
|
|
22934
|
+
const value = (0, import_viem30.parseUnits)(amount, 18);
|
|
22656
22935
|
if (value <= 0n) throw new Error("Amount must be greater than 0");
|
|
22657
22936
|
const balance = await publicClient.getBalance({ address: this.solver });
|
|
22658
22937
|
if (balance < value) throw new Error(`Insufficient native balance: have ${balance}, need ${value}`);
|
|
22659
22938
|
calls.push({ target: to, value, data: "0x" });
|
|
22660
22939
|
} else {
|
|
22661
|
-
if (!(0,
|
|
22940
|
+
if (!(0, import_viem30.isAddress)(token)) throw new Error(`Invalid token address: ${token}`);
|
|
22662
22941
|
const tokenLower = token.toLowerCase();
|
|
22663
22942
|
const [decimals, balance] = await Promise.all([
|
|
22664
22943
|
publicClient.readContract({ abi: ERC20_ABI, address: token, functionName: "decimals" }),
|
|
@@ -22669,7 +22948,7 @@ var TokenSender = class {
|
|
|
22669
22948
|
args: [this.solver]
|
|
22670
22949
|
})
|
|
22671
22950
|
]);
|
|
22672
|
-
const units = (0,
|
|
22951
|
+
const units = (0, import_viem30.parseUnits)(amount, decimals);
|
|
22673
22952
|
if (units <= 0n) throw new Error("Amount must be greater than 0");
|
|
22674
22953
|
const isVaultShare = this.getVaults().some(
|
|
22675
22954
|
(v) => v.chain === chain && v.vault.toLowerCase() === tokenLower
|
|
@@ -22680,7 +22959,7 @@ var TokenSender = class {
|
|
|
22680
22959
|
calls.push({
|
|
22681
22960
|
target: token,
|
|
22682
22961
|
value: 0n,
|
|
22683
|
-
data: (0,
|
|
22962
|
+
data: (0, import_viem30.encodeFunctionData)({ abi: ERC4626_ABI, functionName: "redeem", args: [units, to, this.solver] })
|
|
22684
22963
|
});
|
|
22685
22964
|
} else {
|
|
22686
22965
|
const reserve = this.userOpSender?.canSponsor(chain) && this.configService ? paymasterReserveForToken(chain, tokenLower, this.configService) : 0n;
|
|
@@ -22703,7 +22982,7 @@ var TokenSender = class {
|
|
|
22703
22982
|
calls.push({
|
|
22704
22983
|
target: token,
|
|
22705
22984
|
value: 0n,
|
|
22706
|
-
data: (0,
|
|
22985
|
+
data: (0, import_viem30.encodeFunctionData)({ abi: ERC20_ABI, functionName: "transfer", args: [to, units] })
|
|
22707
22986
|
});
|
|
22708
22987
|
}
|
|
22709
22988
|
}
|
|
@@ -22746,7 +23025,7 @@ var TokenSender = class {
|
|
|
22746
23025
|
});
|
|
22747
23026
|
const required = shortfall > 0n ? shortfall : 0n;
|
|
22748
23027
|
if (available < required) continue;
|
|
22749
|
-
const floor = vault.minBalance === void 0 ? 0n : (0,
|
|
23028
|
+
const floor = vault.minBalance === void 0 ? 0n : (0, import_viem30.parseUnits)(vault.minBalance, decimals);
|
|
22750
23029
|
const headroom = reserve > floor ? reserve : floor;
|
|
22751
23030
|
const wanted = shortfall + headroom;
|
|
22752
23031
|
const amount = available >= wanted ? wanted : required;
|
|
@@ -22754,7 +23033,7 @@ var TokenSender = class {
|
|
|
22754
23033
|
return {
|
|
22755
23034
|
target: vault.vault,
|
|
22756
23035
|
value: 0n,
|
|
22757
|
-
data: (0,
|
|
23036
|
+
data: (0, import_viem30.encodeFunctionData)({
|
|
22758
23037
|
abi: ERC4626_ABI,
|
|
22759
23038
|
functionName: "withdraw",
|
|
22760
23039
|
args: [amount, this.solver, this.solver]
|
|
@@ -22820,9 +23099,9 @@ var LimitOrderLifecycle = class {
|
|
|
22820
23099
|
const reconcileMs = this.options.reconcileIntervalSecs * 1e3;
|
|
22821
23100
|
this.every(heartbeatMs, "heartbeat", () => this.service.heartbeat());
|
|
22822
23101
|
this.every(EXPIRY_SWEEP_MS, "expiry", () => this.expire());
|
|
22823
|
-
this.every(reconcileMs, "reconciliation", () => this.
|
|
23102
|
+
this.every(reconcileMs, "reconciliation", () => this.upkeep());
|
|
22824
23103
|
this.logger.info({ heartbeatMs, expiryMs: EXPIRY_SWEEP_MS, reconcileMs }, "Orderbook lifecycle started");
|
|
22825
|
-
void this.
|
|
23104
|
+
void this.upkeep();
|
|
22826
23105
|
}
|
|
22827
23106
|
stop() {
|
|
22828
23107
|
this.timers.forEach((timer) => clearInterval(timer));
|
|
@@ -22833,6 +23112,14 @@ var LimitOrderLifecycle = class {
|
|
|
22833
23112
|
const expired = await this.service.expireStale();
|
|
22834
23113
|
if (expired > 0) this.logger.info({ expired }, "Withdrew limit orders that had outlived their expiry");
|
|
22835
23114
|
}
|
|
23115
|
+
/**
|
|
23116
|
+
* The tally pass first, so reconciliation against the orderbook reads the sizes
|
|
23117
|
+
* it left. Each fails on its own.
|
|
23118
|
+
*/
|
|
23119
|
+
async upkeep() {
|
|
23120
|
+
await this.run("tally reconciliation", async () => this.options.reconcileTallies());
|
|
23121
|
+
await this.run("reconciliation", () => this.reconcile());
|
|
23122
|
+
}
|
|
22836
23123
|
async reconcile() {
|
|
22837
23124
|
const report = await this.service.reconcile();
|
|
22838
23125
|
if (report.cancelled || report.reposted || report.underFunded) {
|
|
@@ -22868,7 +23155,7 @@ var LimitOrderLifecycle = class {
|
|
|
22868
23155
|
|
|
22869
23156
|
// src/services/BalanceProvider.ts
|
|
22870
23157
|
var import_node_events = require("node:events");
|
|
22871
|
-
var
|
|
23158
|
+
var import_viem31 = require("viem");
|
|
22872
23159
|
var BalanceProvider = class extends import_node_events.EventEmitter {
|
|
22873
23160
|
constructor(options) {
|
|
22874
23161
|
super();
|
|
@@ -22961,7 +23248,7 @@ var BalanceProvider = class extends import_node_events.EventEmitter {
|
|
|
22961
23248
|
try {
|
|
22962
23249
|
const native = await client.getBalance({ address: fillerAddr });
|
|
22963
23250
|
const symbol = nativeTokenSymbol(chainId);
|
|
22964
|
-
row.native = { symbol, amount: Number.parseFloat((0,
|
|
23251
|
+
row.native = { symbol, amount: Number.parseFloat((0, import_viem31.formatUnits)(native, 18)) };
|
|
22965
23252
|
} catch (err) {
|
|
22966
23253
|
issues.push({ chainId, source: "native", message: errorMessage(err) });
|
|
22967
23254
|
}
|
|
@@ -23032,7 +23319,7 @@ var BalanceProvider = class extends import_node_events.EventEmitter {
|
|
|
23032
23319
|
functionName: "balanceOf",
|
|
23033
23320
|
args: [fillerAddr]
|
|
23034
23321
|
});
|
|
23035
|
-
wallet = Number.parseFloat((0,
|
|
23322
|
+
wallet = Number.parseFloat((0, import_viem31.formatUnits)(balance, definition.decimals));
|
|
23036
23323
|
} catch (err) {
|
|
23037
23324
|
issues.push({
|
|
23038
23325
|
chainId,
|
|
@@ -23060,8 +23347,8 @@ var BalanceProvider = class extends import_node_events.EventEmitter {
|
|
|
23060
23347
|
available: wallet !== null && vaultDataAvailable ? Math.max(wallet - walletReserve, 0) + vaultAvailable : null,
|
|
23061
23348
|
vaults: positions.map((position) => ({
|
|
23062
23349
|
address: position.vault,
|
|
23063
|
-
position: Number.parseFloat((0,
|
|
23064
|
-
available: Number.parseFloat((0,
|
|
23350
|
+
position: Number.parseFloat((0, import_viem31.formatUnits)(position.positionAssets, position.decimals)),
|
|
23351
|
+
available: Number.parseFloat((0, import_viem31.formatUnits)(position.availableAssets, position.decimals)),
|
|
23065
23352
|
acceptsDeposits: position.acceptsDeposits
|
|
23066
23353
|
})),
|
|
23067
23354
|
status: complete ? "fresh" : wallet !== null || positions.length > 0 ? "partial" : "unavailable"
|
|
@@ -23104,8 +23391,8 @@ var BalanceProvider = class extends import_node_events.EventEmitter {
|
|
|
23104
23391
|
const api = await coprocessor.queryApi();
|
|
23105
23392
|
const account = await api.query.system.account(address);
|
|
23106
23393
|
const decimals = api.registry.chainDecimals[0] ?? 12;
|
|
23107
|
-
const free = Number.parseFloat((0,
|
|
23108
|
-
const reserved = Number.parseFloat((0,
|
|
23394
|
+
const free = Number.parseFloat((0, import_viem31.formatUnits)(BigInt(account.data.free.toString()), decimals));
|
|
23395
|
+
const reserved = Number.parseFloat((0, import_viem31.formatUnits)(BigInt(account.data.reserved.toString()), decimals));
|
|
23109
23396
|
this.snapshot = { ...this.snapshot, hyperbridge: { address, free, reserved } };
|
|
23110
23397
|
} catch (err) {
|
|
23111
23398
|
this.logger.warn({ err }, "Failed to fetch Hyperbridge balance");
|
|
@@ -23125,7 +23412,7 @@ function isConfiguredAddress(address) {
|
|
|
23125
23412
|
}
|
|
23126
23413
|
function sumFormatted(positions, field) {
|
|
23127
23414
|
return positions.reduce(
|
|
23128
|
-
(total, position) => total + Number.parseFloat((0,
|
|
23415
|
+
(total, position) => total + Number.parseFloat((0, import_viem31.formatUnits)(position[field], position.decimals)),
|
|
23129
23416
|
0
|
|
23130
23417
|
);
|
|
23131
23418
|
}
|
|
@@ -23633,7 +23920,7 @@ async function bootFiller(config, options) {
|
|
|
23633
23920
|
const sharedCacheService = new CacheService(options.loggers);
|
|
23634
23921
|
if (!options.signer && !globalWatchOnly && !allChainsWatchOnly(watchOnlyConfig, resolvedChains)) {
|
|
23635
23922
|
throw new Error(
|
|
23636
|
-
"A signer is required unless every chain is watch-only: pass `signer` to Simplex.start (privateKeySigner, turnkeySigner, mpcVaultSigner, viemSigner, or your own Signer implementation). Running the binary? Configure it under [simplex.signer]."
|
|
23923
|
+
"A signer is required unless every chain is watch-only: pass `signer` to Simplex.start (privateKeySigner, secretPhraseSigner, turnkeySigner, mpcVaultSigner, viemSigner, or your own Signer implementation). Running the binary? Configure it under [simplex.signer]."
|
|
23637
23924
|
);
|
|
23638
23925
|
}
|
|
23639
23926
|
const chainClientManager = new ChainClientManager(configService, options.signer);
|
|
@@ -23772,7 +24059,8 @@ async function bootFiller(config, options) {
|
|
|
23772
24059
|
const lifecycle = new LimitOrderLifecycle(
|
|
23773
24060
|
limitOrderService,
|
|
23774
24061
|
{
|
|
23775
|
-
reconcileIntervalSecs: config.orderbook?.reconcileIntervalSecs ?? DEFAULT_RECONCILE_INTERVAL_SECS
|
|
24062
|
+
reconcileIntervalSecs: config.orderbook?.reconcileIntervalSecs ?? DEFAULT_RECONCILE_INTERVAL_SECS,
|
|
24063
|
+
reconcileTallies: () => intentFiller.reconcileLimitOrderTallies()
|
|
23776
24064
|
},
|
|
23777
24065
|
options.loggers
|
|
23778
24066
|
);
|
|
@@ -23810,8 +24098,8 @@ async function bootFiller(config, options) {
|
|
|
23810
24098
|
if (vaultVenue) {
|
|
23811
24099
|
vaultVenue.onTx = ({ chain, kind, txHash, sponsored, movements }) => {
|
|
23812
24100
|
const rows = movements.length > 0 ? movements.map((move) => {
|
|
23813
|
-
const underlying = { token: move.symbol, amount: (0,
|
|
23814
|
-
const shares = move.shares === void 0 ? { token: null, amount: null } : { token: move.shareSymbol, amount: (0,
|
|
24101
|
+
const underlying = { token: move.symbol, amount: (0, import_viem32.formatUnits)(move.amount, move.decimals) };
|
|
24102
|
+
const shares = move.shares === void 0 ? { token: null, amount: null } : { token: move.shareSymbol, amount: (0, import_viem32.formatUnits)(move.shares, move.shareDecimals) };
|
|
23815
24103
|
const out = kind === "sweep" ? underlying : shares;
|
|
23816
24104
|
const back = kind === "sweep" ? shares : underlying;
|
|
23817
24105
|
return { token: out.token, amount: out.amount, to: move.vault, tokenIn: back.token, amountIn: back.amount };
|
|
@@ -24243,6 +24531,14 @@ var MemoryLimitOrderStore = class {
|
|
|
24243
24531
|
const remaining = BigInt(order.remaining) - BigInt(amount);
|
|
24244
24532
|
return this.patch(id, { remaining: (remaining > 0n ? remaining : 0n).toString() });
|
|
24245
24533
|
}
|
|
24534
|
+
async clampRemaining(id, room) {
|
|
24535
|
+
const order = this.orders.get(id);
|
|
24536
|
+
if (!order || order.status !== "open") return null;
|
|
24537
|
+
const sum = BigInt(room) + BigInt(order.reserved);
|
|
24538
|
+
const target = sum > 0n ? sum : 0n;
|
|
24539
|
+
if (target >= BigInt(order.remaining)) return null;
|
|
24540
|
+
return this.patch(id, { remaining: target.toString() });
|
|
24541
|
+
}
|
|
24246
24542
|
async release(id, amount) {
|
|
24247
24543
|
const order = this.orders.get(id);
|
|
24248
24544
|
if (!order) return;
|
|
@@ -24751,7 +25047,8 @@ var OrderScanner = class _OrderScanner {
|
|
|
24751
25047
|
* back from its own endpoints, which also proves they answer for one chain
|
|
24752
25048
|
* before a filler ever depends on them.
|
|
24753
25049
|
*
|
|
24754
|
-
* @throws if an endpoint set is invalid
|
|
25050
|
+
* @throws if an endpoint set is invalid, if none of a chain's endpoints answer,
|
|
25051
|
+
* if its endpoints disagree on the chain, if two entries resolve
|
|
24755
25052
|
* to the same chain, or if `scanIntervalSecs` is below the minimum.
|
|
24756
25053
|
*/
|
|
24757
25054
|
static async create(options) {
|
|
@@ -24811,7 +25108,10 @@ var OrderScanner = class _OrderScanner {
|
|
|
24811
25108
|
async addChainNow(chain) {
|
|
24812
25109
|
if (this.closed) throw new Error("This OrderScanner is closed");
|
|
24813
25110
|
const rpcUrls = validateRpcUrls(chain.rpcUrls);
|
|
24814
|
-
const chainId = chain.chainId ?? await
|
|
25111
|
+
const chainId = chain.chainId ?? (await resolveChainConfigs([{ rpcUrls, bundlerUrl: chain.bundlerUrl ?? "" }], {
|
|
25112
|
+
loggers: this.loggers,
|
|
25113
|
+
tolerateUnreachable: true
|
|
25114
|
+
}))[0].chainId;
|
|
24815
25115
|
if (this.closed) throw new Error("This OrderScanner is closed");
|
|
24816
25116
|
if (this.scanners.has(chainId)) {
|
|
24817
25117
|
throw new Error(`Chain ${chainId} is already in this scanner`);
|
|
@@ -24911,7 +25211,7 @@ var LimitOrderController = class {
|
|
|
24911
25211
|
get service() {
|
|
24912
25212
|
const service = this.runtime.limitOrders;
|
|
24913
25213
|
if (!service) {
|
|
24914
|
-
throw new Error("No orderbook is configured \u2014 set [orderbook]
|
|
25214
|
+
throw new Error("No orderbook is configured \u2014 set [orderbook] url to use limit orders");
|
|
24915
25215
|
}
|
|
24916
25216
|
return service;
|
|
24917
25217
|
}
|
|
@@ -25376,7 +25676,7 @@ var Simplex = class _Simplex extends import_node_events3.EventEmitter {
|
|
|
25376
25676
|
const tomlSigner = options.config.simplex?.signer;
|
|
25377
25677
|
if (tomlSigner && !options.signer) {
|
|
25378
25678
|
throw new Error(
|
|
25379
|
-
"config.simplex.signer describes a signer but none was passed. Simplex.start takes a Signer instance: `signer: await createSigner(config.simplex.signer)`, or build one directly with privateKeySigner/turnkeySigner/mpcVaultSigner/viemSigner."
|
|
25679
|
+
"config.simplex.signer describes a signer but none was passed. Simplex.start takes a Signer instance: `signer: await createSigner(config.simplex.signer)`, or build one directly with privateKeySigner/secretPhraseSigner/turnkeySigner/mpcVaultSigner/viemSigner."
|
|
25380
25680
|
);
|
|
25381
25681
|
}
|
|
25382
25682
|
const loggers = new LoggerContext({
|
|
@@ -25580,6 +25880,8 @@ var Simplex = class _Simplex extends import_node_events3.EventEmitter {
|
|
|
25580
25880
|
0 && (module.exports = {
|
|
25581
25881
|
AssetController,
|
|
25582
25882
|
ChainController,
|
|
25883
|
+
LimitOrderController,
|
|
25884
|
+
LimitOrderValidationError,
|
|
25583
25885
|
LoggerContext,
|
|
25584
25886
|
MemoryDataStore,
|
|
25585
25887
|
OrderScanner,
|
|
@@ -25592,6 +25894,7 @@ var Simplex = class _Simplex extends import_node_events3.EventEmitter {
|
|
|
25592
25894
|
WalletController,
|
|
25593
25895
|
addLogSink,
|
|
25594
25896
|
assertConfirmationCoverage,
|
|
25897
|
+
canDerive,
|
|
25595
25898
|
configureLogger,
|
|
25596
25899
|
createSigner,
|
|
25597
25900
|
digestSigner,
|
|
@@ -25604,10 +25907,12 @@ var Simplex = class _Simplex extends import_node_events3.EventEmitter {
|
|
|
25604
25907
|
pickAnchorStable,
|
|
25605
25908
|
privateKeySigner,
|
|
25606
25909
|
registrySymbols,
|
|
25910
|
+
secretPhraseSigner,
|
|
25607
25911
|
turnkeySigner,
|
|
25608
25912
|
validateAssetDefinitions,
|
|
25609
25913
|
validateConfig,
|
|
25610
25914
|
validatePairConfigs,
|
|
25915
|
+
validateSecretPhrase,
|
|
25611
25916
|
validateSignerConfig,
|
|
25612
25917
|
validateVaultToml,
|
|
25613
25918
|
viemSigner
|