@hyperbridge/simplex 0.18.1 → 0.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/simplex.js +4252 -1528
- package/dist/bin/simplex.js.map +1 -1
- package/dist/index.cjs +7230 -4708
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1179 -815
- package/dist/index.d.ts +1179 -815
- package/dist/index.js +7254 -4726
- package/dist/index.js.map +1 -1
- package/dist/sqlite.cjs +77 -90
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.d.cts +4 -9
- package/dist/sqlite.d.ts +4 -9
- package/dist/sqlite.js +77 -90
- package/dist/sqlite.js.map +1 -1
- package/dist/{types-6MEltdkX.d.cts → types-CW6STIE7.d.cts} +725 -223
- package/dist/{types-6MEltdkX.d.ts → types-CW6STIE7.d.ts} +725 -223
- package/dist/ui/assets/{index-BEaKgtAo.js → index-DoVF9R8x.js} +44 -44
- package/dist/ui/assets/{index-aSBiKM_B.css → index-DypSLK4f.css} +1 -1
- package/dist/ui/index.html +2 -2
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
|
-
import { HexString, ERC7821Call, IntentsCoprocessor, Order, TokenInfo, ChainConfig, ExecutionResult, IntentGateway, FillOptions, FillerConfig } from '@hyperbridge/sdk';
|
|
3
|
-
import { S as SignerConfig, a as Signer, b as Signature, D as DerivingSigner, c as SecretPhraseSignerConfig, M as MpcVaultSignerConfig, T as TurnkeySignerConfig, C as ChainClientManager, F as FillerConfigService, U as UserOpSender, L as LoggerContext, A as ActivityStore,
|
|
4
|
-
export { z as ActivityType, E as AuthorizationRequest, G as BidInsert, H as
|
|
2
|
+
import { HexString, ERC7821Call, IntentsCoprocessor, Order, TokenInfo, ChainConfig, BidSubmissionResult, ExecutionResult, IntentGateway, FillOptions, FillerConfig } from '@hyperbridge/sdk';
|
|
3
|
+
import { S as SignerConfig, a as Signer, b as Signature, D as DerivingSigner, c as SecretPhraseSignerConfig, M as MpcVaultSignerConfig, T as TurnkeySignerConfig, C as ChainClientManager, F as FillerConfigService, U as UserOpSender, d as DelegationService, L as LoggerContext, A as ActivityStore, e as ActivityInsert, f as ActivityEvent, O as OrderHistoryPage, W as WalletTx, g as LimitOrderStore, h as AssetRegistry, i as LimitOrder, j as LimitOrderFilter, B as BidStore, k as SimplexDataStore, l as ConfirmationPolicy, R as ResolvedChainConfig, m as FillerTomlConfig, V as VaultToml, n as TokenSender, o as BridgeTopUp, p as AssetDefinition, q as ChainConfirmationPolicy, r as LimitOrderFill, s as StoredBid, t as RebalancingConfig, u as LogSink, v as BidStats, w as AllowlistConfig, x as LogLevel, y as StateStore, I as InventoryStore } from './types-CW6STIE7.cjs';
|
|
4
|
+
export { z as ActivityType, E as AuthorizationRequest, G as BidInsert, H as BidPricing, J as BinanceConfig, K as CurveConfig, N as CurvePoint, P as Eip7702Authorization, Q as FillerConfigFile, X as InventorySnapshot, Y as LimitOrderFillInsert, Z as LimitOrderFillRecord, _ as LimitOrderInsert, $ as LimitOrderPosting, a0 as LimitOrderSide, a1 as LimitOrderStatus, a2 as Logger, a3 as OperatorNotification, a4 as PrivateKeySignerConfig, a5 as QueueConfig, a6 as RuntimeState, a7 as SignerTransaction, a8 as SignerType, a9 as TypedDataPayload, aa as USD_STABLE_SYMBOLS, ab as UserProvidedChainConfig, ac as VaultTomlConfig, ad as WalletTxKind, ae as addLogSink, af as assertConfirmationCoverage, ag as configureLogger, ah as formatChainKey, ai as getLogger, aj as isRegistrySymbol, ak as normalizeSymbol, al as parseChainKey, am as registrySymbols, an as validateAssetDefinitions, ao as validateConfig, ap as validateVaultToml } from './types-CW6STIE7.cjs';
|
|
5
5
|
import { EventEmitter as EventEmitter$1 } from 'events';
|
|
6
6
|
import { Decimal } from 'decimal.js';
|
|
7
7
|
import * as _circle_fin_bridge_kit from '@circle-fin/bridge-kit';
|
|
@@ -28,10 +28,15 @@ interface FundingVenue {
|
|
|
28
28
|
* from LP positions on `destChain`. Returns the calls and the credited
|
|
29
29
|
* amount that will become available after execution.
|
|
30
30
|
*
|
|
31
|
+
* `alreadyPlanned` is what the caller's current evaluation has already
|
|
32
|
+
* planned from this venue for this token on this chain, and is taken off
|
|
33
|
+
* what the venue can release. It is the caller's to keep; the venue holds
|
|
34
|
+
* nothing between calls.
|
|
35
|
+
*
|
|
31
36
|
* Access is serialised per chain via a mutex so concurrent evaluations
|
|
32
37
|
* do not race on shared liquidity state.
|
|
33
38
|
*/
|
|
34
|
-
planWithdrawalForToken(destChain: string, solver: HexString, tokenOutLower: string, amountNeeded: bigint, deadlineTimestamp?: bigint): Promise<FundingPlanResult>;
|
|
39
|
+
planWithdrawalForToken(destChain: string, solver: HexString, tokenOutLower: string, amountNeeded: bigint, deadlineTimestamp?: bigint, alreadyPlanned?: bigint): Promise<FundingPlanResult>;
|
|
35
40
|
/**
|
|
36
41
|
* Wallet balance of `tokenLower` the fill must keep liquid and never source
|
|
37
42
|
* from — the vault's `minBalance` floor, reserved for gas/paymaster paid in
|
|
@@ -85,7 +90,7 @@ interface VaultBalancePosition {
|
|
|
85
90
|
decimals: number;
|
|
86
91
|
/** Solver-owned vault position in underlying-asset terms. */
|
|
87
92
|
positionAssets: bigint;
|
|
88
|
-
/** Immediately withdrawable amount
|
|
93
|
+
/** Immediately withdrawable amount: the vault's `maxWithdraw(solver)`. */
|
|
89
94
|
availableAssets: bigint;
|
|
90
95
|
/** Underlying amount deliberately kept liquid in the solver wallet. */
|
|
91
96
|
walletReserve: bigint;
|
|
@@ -252,7 +257,7 @@ interface AssetBalanceRow {
|
|
|
252
257
|
walletReserve: number;
|
|
253
258
|
/** Total solver-owned underlying represented by vault shares. */
|
|
254
259
|
vaultPosition: number;
|
|
255
|
-
/** Vault assets that can be withdrawn now
|
|
260
|
+
/** Vault assets that can be withdrawn now: the vault's `maxWithdraw(solver)`. */
|
|
256
261
|
vaultAvailable: number;
|
|
257
262
|
/** Wallet plus vault position. Null when any required source was unavailable. */
|
|
258
263
|
total: number | null;
|
|
@@ -327,6 +332,14 @@ declare class BalanceProvider extends EventEmitter {
|
|
|
327
332
|
refresh(): Promise<BalanceSnapshot>;
|
|
328
333
|
private collectChain;
|
|
329
334
|
private addConfiguredStable;
|
|
335
|
+
private hyperbridgeAccount?;
|
|
336
|
+
/**
|
|
337
|
+
* Re-reads the filler's BRIDGE balance on Hyperbridge, outside the once-a-minute interval:
|
|
338
|
+
* a BRIDGE top-up calls it the moment its delivery lands, so the dashboard's reload shows
|
|
339
|
+
* the new balance. A failed read leaves the last snapshot in place. No-op while tracking
|
|
340
|
+
* is not initialized (no Hyperbridge key).
|
|
341
|
+
*/
|
|
342
|
+
refreshHyperbridgeBalance(): Promise<void>;
|
|
330
343
|
private trackHyperbridgeBalance;
|
|
331
344
|
}
|
|
332
345
|
|
|
@@ -503,6 +516,13 @@ declare class VaultFundingPlanner implements FundingVenue {
|
|
|
503
516
|
private readonly clientManager;
|
|
504
517
|
private config;
|
|
505
518
|
private readonly userOpSender?;
|
|
519
|
+
/**
|
|
520
|
+
* Read-only EIP-7702 check for the native-tx fallback. A vault batch is an
|
|
521
|
+
* `executeBatch` on the solver account, so it only does anything once the EOA is
|
|
522
|
+
* delegated to that account; sent to a codeless EOA it succeeds and moves nothing.
|
|
523
|
+
* Left out, the fallback is sent unchecked (library callers without a signer).
|
|
524
|
+
*/
|
|
525
|
+
private readonly delegation?;
|
|
506
526
|
private readonly logger;
|
|
507
527
|
name: string;
|
|
508
528
|
private stateByChain;
|
|
@@ -525,7 +545,14 @@ declare class VaultFundingPlanner implements FundingVenue {
|
|
|
525
545
|
* sponsored UserOps (gas paid in USDC) where the chain supports it, falling back
|
|
526
546
|
* to a native EOA tx. Omit to always use native txs.
|
|
527
547
|
*/
|
|
528
|
-
constructor(clientManager: ChainClientManager, config: VaultOutputFundingConfig, userOpSender?: UserOpSender | undefined
|
|
548
|
+
constructor(clientManager: ChainClientManager, config: VaultOutputFundingConfig, userOpSender?: UserOpSender | undefined,
|
|
549
|
+
/**
|
|
550
|
+
* Read-only EIP-7702 check for the native-tx fallback. A vault batch is an
|
|
551
|
+
* `executeBatch` on the solver account, so it only does anything once the EOA is
|
|
552
|
+
* delegated to that account; sent to a codeless EOA it succeeds and moves nothing.
|
|
553
|
+
* Left out, the fallback is sent unchecked (library callers without a signer).
|
|
554
|
+
*/
|
|
555
|
+
delegation?: Pick<DelegationService, "isDelegated"> | undefined);
|
|
529
556
|
/** Invoked after each submitted sweep/redeem batch so wallet history can record it. */
|
|
530
557
|
onTx?: (tx: {
|
|
531
558
|
chain: string;
|
|
@@ -555,9 +582,9 @@ declare class VaultFundingPlanner implements FundingVenue {
|
|
|
555
582
|
initialise(solver: HexString): Promise<void>;
|
|
556
583
|
refresh(chain?: string): Promise<void>;
|
|
557
584
|
/**
|
|
558
|
-
* Returns a coherent read-only view of every configured vault
|
|
559
|
-
* under the same per-chain mutex
|
|
560
|
-
*
|
|
585
|
+
* Returns a coherent read-only view of every configured vault, refreshed
|
|
586
|
+
* under the same per-chain mutex withdrawal planning uses. Availability is
|
|
587
|
+
* the vault's own `maxWithdraw(solver)`.
|
|
561
588
|
*/
|
|
562
589
|
getBalanceSnapshot(requestedChain?: string): Promise<VaultBalancePosition[]>;
|
|
563
590
|
/**
|
|
@@ -570,8 +597,13 @@ declare class VaultFundingPlanner implements FundingVenue {
|
|
|
570
597
|
* Produces a single `vault.withdraw` ERC-7821 call that sends up to
|
|
571
598
|
* `amountNeeded` of `tokenOutLower` to the solver, capped by the vault's
|
|
572
599
|
* `maxWithdraw`. Returns a no-op when no configured vault holds the token.
|
|
600
|
+
*
|
|
601
|
+
* `maxWithdraw` is read afresh for every plan, less `alreadyPlanned`: what
|
|
602
|
+
* the caller's own evaluation has planned from this vault so far. Nothing is
|
|
603
|
+
* held back across evaluations: a plan whose withdrawal another evaluation's
|
|
604
|
+
* fill has already spent reverts its batch on chain, which is the accepted cost.
|
|
573
605
|
*/
|
|
574
|
-
planWithdrawalForToken(destChain: string, solver: HexString, tokenOutLower: string, amountNeeded: bigint, _deadlineTimestamp?: bigint): Promise<FundingPlanResult>;
|
|
606
|
+
planWithdrawalForToken(destChain: string, solver: HexString, tokenOutLower: string, amountNeeded: bigint, _deadlineTimestamp?: bigint, alreadyPlanned?: bigint): Promise<FundingPlanResult>;
|
|
575
607
|
/**
|
|
576
608
|
* Starts the periodic sweep timer. Runs one sweep shortly after start, then
|
|
577
609
|
* every `sweepIntervalMs`. Idempotent — a second call is a no-op.
|
|
@@ -601,7 +633,9 @@ declare class VaultFundingPlanner implements FundingVenue {
|
|
|
601
633
|
*
|
|
602
634
|
* The sponsored path only falls back to native when the op was **never
|
|
603
635
|
* submitted**; a submitted-but-unconfirmed op throws so a native resend can't
|
|
604
|
-
* double-execute the batch (the caller's timer logs and retries next cycle).
|
|
636
|
+
* double-execute the batch (the caller's timer logs and retries next cycle). So does a
|
|
637
|
+
* `PendingOpOnNonceError`: an earlier op from this wallet still holds the nonce, which is
|
|
638
|
+
* "not now", never a reason to send natively.
|
|
605
639
|
*/
|
|
606
640
|
private submitBatch;
|
|
607
641
|
/**
|
|
@@ -816,412 +850,756 @@ declare class EventMonitor extends EventEmitter$1 {
|
|
|
816
850
|
stopListening(): Promise<void>;
|
|
817
851
|
}
|
|
818
852
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
* is neither success nor failure: the extrinsic may yet land and reserve a
|
|
824
|
-
* deposit, so the bid record has to be reclaimable even though `success` is
|
|
825
|
-
* false. Widened here rather than on the SDK's `ExecutionResult` so simplex does
|
|
826
|
-
* not need an unreleased SDK.
|
|
827
|
-
*/
|
|
828
|
-
interface FillResult extends ExecutionResult {
|
|
829
|
-
pending?: boolean;
|
|
830
|
-
/**
|
|
831
|
-
* The identifier Hyperbridge files the bid under, once its op was built:
|
|
832
|
-
* `keccak256` of its calldata. It tells the bids on one order apart, and retracting the bid names it.
|
|
833
|
-
*/
|
|
834
|
-
bid?: HexString;
|
|
853
|
+
interface Book {
|
|
854
|
+
id: string;
|
|
855
|
+
base: string;
|
|
856
|
+
quote: string;
|
|
835
857
|
}
|
|
836
|
-
|
|
837
|
-
interface
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
getOrderUsdValue?(order: Order): Promise<{
|
|
847
|
-
inputUsd: Decimal;
|
|
848
|
-
} | null>;
|
|
849
|
-
/**
|
|
850
|
-
* Optional confirmation policy for this strategy.
|
|
851
|
-
* If absent, no confirmation waiting is required (e.g. same-chain strategies).
|
|
852
|
-
*/
|
|
853
|
-
confirmationPolicy?: {
|
|
854
|
-
getConfirmationBlocks: (chainId: number, amountUsd: number) => number;
|
|
855
|
-
};
|
|
858
|
+
/** Live price levels. All prices and sizes are decimal integer strings at 1e18. */
|
|
859
|
+
interface OrderbookLevel {
|
|
860
|
+
fillChain: string;
|
|
861
|
+
priceBucket: string;
|
|
862
|
+
price: string;
|
|
863
|
+
worstPrice: string;
|
|
864
|
+
baseSize: string;
|
|
865
|
+
quoteSize: string;
|
|
866
|
+
orderCount: number;
|
|
867
|
+
solverCount: number;
|
|
856
868
|
}
|
|
857
|
-
|
|
858
|
-
/**
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
869
|
+
interface OrderbookSnapshot extends Book {
|
|
870
|
+
/** Best first: bids descending, asks ascending. */
|
|
871
|
+
bids: OrderbookLevel[];
|
|
872
|
+
asks: OrderbookLevel[];
|
|
873
|
+
/** True backing liquidity, in quote for bids and base for asks. */
|
|
874
|
+
bidLiquidity: string;
|
|
875
|
+
askLiquidity: string;
|
|
876
|
+
/** Price bucket width, quote per 1 base at 1e18; null when the orderbook does not report one. */
|
|
877
|
+
granularity: string | null;
|
|
862
878
|
}
|
|
863
|
-
/**
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
879
|
+
/** One solver's order inside a price level. Prices and sizes are decimal integer strings at 1e18. */
|
|
880
|
+
interface OrderbookLevelOrder {
|
|
881
|
+
solver: string;
|
|
882
|
+
commitment: string;
|
|
883
|
+
fillChain: string;
|
|
884
|
+
price: string;
|
|
885
|
+
/** What the order publishes as depth, in the token its side pays out: quote for bids, base for asks. */
|
|
886
|
+
advertisedSize: string;
|
|
887
|
+
/** The signed output before any balance cap, in the same token as `advertisedSize`. */
|
|
888
|
+
quotedAmount: string;
|
|
889
|
+
/** True when the solver's balance, not the quote, binds `advertisedSize`. */
|
|
890
|
+
resized: boolean;
|
|
891
|
+
expiresAt: string;
|
|
892
|
+
acceptedSources: string[];
|
|
871
893
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
private summaries;
|
|
893
|
-
constructor(store: ActivityStore, loggers?: LoggerContext, options?: ActivityRecorderOptions);
|
|
894
|
-
/** Subscribes to the filler's order lifecycle events. Idempotent per monitor. */
|
|
895
|
-
attach(monitor: EventMonitor): void;
|
|
896
|
-
private subscribe;
|
|
897
|
-
/** Unsubscribes from the attached monitor. Safe to call when never attached. */
|
|
898
|
-
detach(): void;
|
|
899
|
-
private remember;
|
|
900
|
-
private summaryFor;
|
|
901
|
-
/**
|
|
902
|
-
* Settles an order from its on-chain fill: `filled` when this filler won it,
|
|
903
|
-
* `lost` (reason = the winner) when a rival did. A rival's fill is recorded
|
|
904
|
-
* only for orders this filler has rows for — every fill on the chain passes
|
|
905
|
-
* through here, and the feed is about this filler's orders.
|
|
906
|
-
*/
|
|
907
|
-
private settle;
|
|
908
|
-
/**
|
|
909
|
-
* Captures the order for the feed. Token metadata lookups may hit the chain;
|
|
910
|
-
* a failure degrades that leg to address + raw amount rather than dropping the row.
|
|
911
|
-
*/
|
|
912
|
-
private summarize;
|
|
894
|
+
interface OrderbookLevelQuery {
|
|
895
|
+
side: "BID" | "ASK";
|
|
896
|
+
fillChain: string;
|
|
897
|
+
priceBucket: string;
|
|
898
|
+
sourceChain?: string;
|
|
899
|
+
}
|
|
900
|
+
interface OrderbookFilters {
|
|
901
|
+
sourceChain?: string;
|
|
902
|
+
fillChain?: string;
|
|
903
|
+
}
|
|
904
|
+
interface TokenMinSize {
|
|
905
|
+
symbol: string;
|
|
906
|
+
size: string;
|
|
907
|
+
}
|
|
908
|
+
interface ServerInfo {
|
|
909
|
+
minOrderTtlSecs: number;
|
|
910
|
+
heartbeatIntervalSecs: number;
|
|
911
|
+
signatureSkewSecs: number;
|
|
912
|
+
maxBatchSize: number;
|
|
913
|
+
minOrderSizes: TokenMinSize[];
|
|
913
914
|
/**
|
|
914
|
-
*
|
|
915
|
-
*
|
|
915
|
+
* Every chain the orderbook serves, by state machine id: the chains orders
|
|
916
|
+
* fill on, and the source chains they may declare.
|
|
916
917
|
*/
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
orderHistory(page: number, pageSize: number): Promise<OrderHistoryPage>;
|
|
921
|
-
recordWalletTx(tx: Omit<WalletTx, "id" | "ts">): Promise<void>;
|
|
922
|
-
walletTxs(limit?: number): Promise<WalletTx[]>;
|
|
918
|
+
chains: string[];
|
|
919
|
+
eip712DomainName: string;
|
|
920
|
+
eip712DomainVersion: string;
|
|
923
921
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
resetHalt(): void;
|
|
922
|
+
/** One token on one chain, as the orderbook's own registry has it. */
|
|
923
|
+
interface ChainToken {
|
|
924
|
+
symbol: string;
|
|
925
|
+
/** Its decimals there: USDC and USDT carry 18 on BNB Chain and 6 on the rest. */
|
|
926
|
+
decimals: number;
|
|
930
927
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
/** The token the order pays on its fill chain. */
|
|
938
|
-
token: HexString;
|
|
928
|
+
/** One chain the orderbook serves, with the tokens it registers on it. */
|
|
929
|
+
interface ChainInfo {
|
|
930
|
+
/** State machine id, such as `EVM-8453`. */
|
|
931
|
+
id: string;
|
|
932
|
+
name: string;
|
|
933
|
+
tokens: ChainToken[];
|
|
939
934
|
}
|
|
940
|
-
|
|
941
|
-
interface
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
935
|
+
/** `serverInfo`, `books` and `chains` together, which is how simplex reads them. */
|
|
936
|
+
interface OrderbookLimits {
|
|
937
|
+
serverInfo: ServerInfo;
|
|
938
|
+
books: Book[];
|
|
939
|
+
chains: ChainInfo[];
|
|
945
940
|
}
|
|
946
|
-
interface
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
941
|
+
interface PostedOrder {
|
|
942
|
+
commitment: HexString;
|
|
943
|
+
side: "BID" | "ASK";
|
|
944
|
+
status: "ACTIVE" | "SUSPENDED";
|
|
945
|
+
price: string;
|
|
946
|
+
quotedAmount: string;
|
|
947
|
+
advertisedSize: string;
|
|
948
|
+
expiresAt: string;
|
|
949
|
+
acceptedSources: string[];
|
|
950
|
+
/** The balance, not the quote, is what binds `advertisedSize`. */
|
|
951
|
+
resized?: boolean;
|
|
952
|
+
/**
|
|
953
|
+
* Whether the solver's balance covers the whole quote. Also false before any
|
|
954
|
+
* balance has been read, which is why {@link PostedOrder.validatedAt} decides
|
|
955
|
+
* whether a false here means anything.
|
|
956
|
+
*/
|
|
957
|
+
backed?: boolean;
|
|
958
|
+
/**
|
|
959
|
+
* The last cycle that read this order's balance, absent until one has. An
|
|
960
|
+
* order surfaces at its quoted size meanwhile.
|
|
961
|
+
*/
|
|
962
|
+
validatedAt?: string | null;
|
|
950
963
|
}
|
|
951
964
|
/**
|
|
952
|
-
*
|
|
965
|
+
* Every code the orderbook's `RejectionCode` enum can send, listed rather than
|
|
966
|
+
* written as a union so a test can hold it against the published schema.
|
|
953
967
|
*
|
|
954
|
-
*
|
|
955
|
-
*
|
|
956
|
-
*
|
|
957
|
-
*
|
|
968
|
+
* Why the orderbook refuses an order. `MIN_ORDER_SIZE`, `TTL_TOO_SHORT` and
|
|
969
|
+
* `UNSUPPORTED_SOURCE_CHAIN` are prevented by validation before posting, the last
|
|
970
|
+
* against the chains the server serves and the tokens its registry lists on each;
|
|
971
|
+
* `REPLAYED` and `ORDER_EXISTS` are answered by bumping the nonce; the rest are
|
|
972
|
+
* encoding bugs on our side.
|
|
958
973
|
*/
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
974
|
+
declare const REJECTION_CODES: readonly ["MALFORMED_USER_OP", "NO_FILL_ORDER", "UNSUPPORTED_CHAIN", "UNSUPPORTED_SHAPE", "NOT_PHANTOM", "TTL_TOO_SHORT", "UNSUPPORTED_PAIR", "BAD_SIGNATURE", "BAD_NONCE_BINDING", "REPLAYED", "ORDER_EXISTS", "TOO_MANY_ORDERS", "MIN_ORDER_SIZE", "MISSING_DECLARATION", "EMPTY_DECLARATION", "UNSUPPORTED_SOURCE_CHAIN", "NO_LIMIT_ORDER", "TOO_MANY_BIDS"];
|
|
975
|
+
type RejectionCode = (typeof REJECTION_CODES)[number];
|
|
976
|
+
/**
|
|
977
|
+
* Why the orderbook could not decide an op at all. Ingest reads no chain, so it
|
|
978
|
+
* is the database or the submission running out of time, and both are worth
|
|
979
|
+
* another attempt.
|
|
980
|
+
*/
|
|
981
|
+
declare const FAILURE_CODES: readonly ["DATABASE_UNAVAILABLE", "TIMEOUT"];
|
|
982
|
+
type FailureCode = (typeof FAILURE_CODES)[number];
|
|
983
|
+
type SubmitOrderResult = {
|
|
984
|
+
kind: "accepted";
|
|
985
|
+
order: PostedOrder;
|
|
986
|
+
surfaced: boolean;
|
|
987
|
+
} | {
|
|
988
|
+
kind: "unchanged";
|
|
989
|
+
order: PostedOrder;
|
|
990
|
+
} | {
|
|
991
|
+
kind: "rejected";
|
|
992
|
+
code: RejectionCode;
|
|
993
|
+
message: string;
|
|
994
|
+
} | {
|
|
995
|
+
kind: "failed";
|
|
996
|
+
code: FailureCode | "REQUEST_FAILED";
|
|
997
|
+
message: string;
|
|
998
|
+
retryable: boolean;
|
|
999
|
+
};
|
|
1000
|
+
/**
|
|
1001
|
+
* A bid on a swapper's order as the orderbook holds it, under the order's commitment. Amounts
|
|
1002
|
+
* and the price are decimal strings at 1e18.
|
|
1003
|
+
*/
|
|
1004
|
+
interface PostedBid {
|
|
1005
|
+
commitment: HexString;
|
|
1006
|
+
/** Which of the order's legs the bid quotes, from 0. */
|
|
1007
|
+
leg: number;
|
|
1008
|
+
side: "BID" | "ASK";
|
|
1009
|
+
fillChain: string;
|
|
1010
|
+
sourceChain: string;
|
|
1011
|
+
/** The rate the bid signed, quote per 1 base, before the protocol fee. */
|
|
1012
|
+
price: string;
|
|
1013
|
+
amountIn: string;
|
|
1014
|
+
amountOut: string;
|
|
1015
|
+
/** ISO-8601: when the orderbook stops serving the bid (`receivedAt` plus `serverInfo.bidTtlSecs`). */
|
|
1016
|
+
expiresAt: string;
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* The orderbook's answer to a bid. `unchanged` is the same op posted again while its bid is
|
|
1020
|
+
* still live, which changed nothing; a bid is served until its TTL and cannot be withdrawn.
|
|
1021
|
+
*/
|
|
1022
|
+
type SubmitBidResult = {
|
|
1023
|
+
kind: "accepted";
|
|
1024
|
+
bid: PostedBid;
|
|
1025
|
+
} | {
|
|
1026
|
+
kind: "unchanged";
|
|
1027
|
+
bid: PostedBid;
|
|
1028
|
+
} | {
|
|
1029
|
+
kind: "rejected";
|
|
1030
|
+
code: RejectionCode;
|
|
1031
|
+
message: string;
|
|
1032
|
+
} | {
|
|
1033
|
+
kind: "failed";
|
|
1034
|
+
code: FailureCode | "REQUEST_FAILED";
|
|
1035
|
+
message: string;
|
|
1036
|
+
retryable: boolean;
|
|
1037
|
+
};
|
|
1038
|
+
/** Why a signed message was refused, shared by `cancelOrder` and `heartbeat`. */
|
|
1039
|
+
declare const MESSAGE_REJECTION_CODES: readonly ["BAD_SIGNATURE", "SOLVER_MISMATCH", "SIGNATURE_EXPIRED", "SIGNATURE_REUSED", "UNKNOWN_ORDER", "UNKNOWN_SOLVER"];
|
|
1040
|
+
type MessageRejectionCode = (typeof MESSAGE_REJECTION_CODES)[number];
|
|
1041
|
+
type SolverStatus = "ACTIVE" | "SUSPENDED";
|
|
1042
|
+
type HeartbeatResult = {
|
|
1043
|
+
kind: "accepted";
|
|
1044
|
+
status: SolverStatus;
|
|
1045
|
+
reactivatedOrders: number;
|
|
1046
|
+
heartbeatDueBy: string;
|
|
1047
|
+
} | {
|
|
1048
|
+
kind: "rejected";
|
|
1049
|
+
code: MessageRejectionCode;
|
|
1050
|
+
message: string;
|
|
1051
|
+
};
|
|
1052
|
+
/** One page of the solver's own orders, as reconciliation walks them. */
|
|
1053
|
+
interface PostedOrderPage {
|
|
1054
|
+
orders: PostedOrder[];
|
|
1055
|
+
/** Cursor for the next page, absent on the last one. */
|
|
1056
|
+
cursor?: string;
|
|
1057
|
+
status: SolverStatus;
|
|
1058
|
+
}
|
|
1059
|
+
type CancelOrderResult = {
|
|
1060
|
+
kind: "cancelled";
|
|
1061
|
+
commitment: HexString;
|
|
1062
|
+
} | {
|
|
1063
|
+
kind: "rejected";
|
|
1064
|
+
code: MessageRejectionCode;
|
|
1065
|
+
message: string;
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* The request never got an answer. Distinct from `UNKNOWN_ORDER`, which is the
|
|
1069
|
+
* orderbook saying the entry is already gone: here the entry may well still be
|
|
1070
|
+
* live, and a caller that treats the two alike orphans it.
|
|
1071
|
+
*/
|
|
1072
|
+
| {
|
|
1073
|
+
kind: "failed";
|
|
1074
|
+
message: string;
|
|
1075
|
+
};
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* Talks to one HyperFX orderbook over GraphQL.
|
|
1079
|
+
*
|
|
1080
|
+
* Stateless apart from the endpoint and timeout. Every method either returns the
|
|
1081
|
+
* orderbook's own answer, including its refusals, or throws
|
|
1082
|
+
* {@link OrderbookRequestError} because it could not get one.
|
|
1083
|
+
*/
|
|
1084
|
+
declare class OrderbookClient {
|
|
1085
|
+
private readonly requestTimeoutMs;
|
|
1086
|
+
private logger;
|
|
1087
|
+
/** The configured endpoint, with `/graphql` if it was left off. */
|
|
1088
|
+
private readonly url;
|
|
1089
|
+
constructor(url: string, requestTimeoutMs: number, loggers?: LoggerContext);
|
|
1090
|
+
/** The limits to validate against before posting, plus the books on offer. */
|
|
1091
|
+
limits(): Promise<OrderbookLimits>;
|
|
1092
|
+
/** The public book across all solvers, restricted to the selected route. */
|
|
1093
|
+
snapshot(id: string, filters?: OrderbookFilters): Promise<OrderbookSnapshot | null>;
|
|
1010
1094
|
/**
|
|
1011
|
-
* The
|
|
1012
|
-
*
|
|
1013
|
-
*
|
|
1014
|
-
* Kept on the same entry as the outputs, so the two are replaced and expire
|
|
1015
|
-
* together: a bid can never sign one limit order's payout beside another's budget.
|
|
1095
|
+
* The orders behind one price level. The orderbook filters orders by side and route but not by
|
|
1096
|
+
* price bucket, so this walks the side's orders on the level's fill chain and keeps the bucket.
|
|
1097
|
+
* Null when the book does not exist.
|
|
1016
1098
|
*/
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
token: HexString;
|
|
1020
|
-
amount: bigint;
|
|
1021
|
-
}[], inputs?: {
|
|
1022
|
-
token: HexString;
|
|
1023
|
-
amount: bigint;
|
|
1024
|
-
}[], budget?: LimitOrderBudget): void;
|
|
1099
|
+
levelOrders(id: string, level: OrderbookLevelQuery): Promise<OrderbookLevelOrder[] | null>;
|
|
1100
|
+
submitOrder(userOp: HexString): Promise<SubmitOrderResult>;
|
|
1025
1101
|
/**
|
|
1026
|
-
*
|
|
1027
|
-
*
|
|
1028
|
-
*
|
|
1029
|
-
*
|
|
1030
|
-
* bid
|
|
1102
|
+
* Posts a bid on a swapper's order: the signed fill UserOp, SCALE-encoded, exactly as it goes
|
|
1103
|
+
* to Hyperbridge. The orderbook verifies it as it does a limit order, except that it need not
|
|
1104
|
+
* be phantom and carries no TTL, and accepts it only from a solver holding an active limit
|
|
1105
|
+
* order on the leg's book filling on the order's destination (`NO_LIMIT_ORDER`). It serves
|
|
1106
|
+
* the bid under the order's commitment for `serverInfo.bidTtlSecs`; there is no withdrawing
|
|
1107
|
+
* it before then.
|
|
1031
1108
|
*/
|
|
1032
|
-
|
|
1033
|
-
limitOrderId: string;
|
|
1034
|
-
payout: bigint;
|
|
1035
|
-
}[];
|
|
1036
|
-
getBidPlans(orderId: string): BidPlan[];
|
|
1037
|
-
setBidPlans(orderId: string, plans: BidPlan[]): void;
|
|
1038
|
-
clearBidPlans(orderId: string): void;
|
|
1039
|
-
setMatchedLimitOrder(orderId: string, holds: {
|
|
1040
|
-
limitOrderId: string;
|
|
1041
|
-
payout: bigint;
|
|
1042
|
-
}[]): void;
|
|
1043
|
-
getPairClassifications(orderId: string): CachedPairClassification[] | null;
|
|
1044
|
-
setPairClassifications(orderId: string, pairs: CachedPairClassification[]): void;
|
|
1045
|
-
getFundingPrepends(orderId: string): {
|
|
1046
|
-
calls: ERC7821Call[];
|
|
1047
|
-
} | null;
|
|
1048
|
-
setFundingPrepends(orderId: string, calls: ERC7821Call[]): void;
|
|
1049
|
-
clearFundingPrepends(orderId: string): void;
|
|
1109
|
+
submitBid(userOp: HexString): Promise<SubmitBidResult>;
|
|
1050
1110
|
/**
|
|
1051
|
-
*
|
|
1111
|
+
* The entry this solver holds at `commitment`, or null when it holds none.
|
|
1052
1112
|
*
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
1055
|
-
*
|
|
1113
|
+
* What tells `ORDER_EXISTS` from `REPLAYED`: the first means a live entry is
|
|
1114
|
+
* already sitting there, and posting again on a new nonce would put a second
|
|
1115
|
+
* one behind the same liability.
|
|
1056
1116
|
*/
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1117
|
+
orderAt(solver: HexString, commitment: HexString): Promise<PostedOrder | null>;
|
|
1118
|
+
cancelOrder(params: {
|
|
1119
|
+
solver: HexString;
|
|
1120
|
+
commitment: HexString;
|
|
1121
|
+
timestamp: number;
|
|
1122
|
+
signature: HexString;
|
|
1123
|
+
}): Promise<CancelOrderResult>;
|
|
1124
|
+
heartbeat(params: {
|
|
1125
|
+
solver: HexString;
|
|
1126
|
+
timestamp: number;
|
|
1127
|
+
signature: HexString;
|
|
1128
|
+
}): Promise<HeartbeatResult>;
|
|
1060
1129
|
/**
|
|
1061
|
-
*
|
|
1062
|
-
* `order.fees` to the execution cost, because the order is at or above the
|
|
1063
|
-
* operator's minimum size.
|
|
1130
|
+
* One page of the solver's own orders as the orderbook holds them.
|
|
1064
1131
|
*
|
|
1065
|
-
*
|
|
1066
|
-
*
|
|
1132
|
+
* A solver the orderbook has never accepted an order from is not an error:
|
|
1133
|
+
* it answers with no solver at all, which reads here as an empty page.
|
|
1067
1134
|
*/
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
clearFeeCheckWaived(orderId: string): void;
|
|
1071
|
-
getFeeTokenWithDecimals(chain: string): {
|
|
1072
|
-
address: HexString;
|
|
1073
|
-
decimals: number;
|
|
1074
|
-
} | null;
|
|
1075
|
-
setFeeTokenWithDecimals(chain: string, address: HexString, decimals: number): void;
|
|
1076
|
-
getTokenDecimals(chain: string, tokenAddress: HexString): number | null;
|
|
1077
|
-
setTokenDecimals(chain: string, tokenAddress: HexString, decimals: number): void;
|
|
1078
|
-
getSolverSelection(chain: string): boolean | null;
|
|
1079
|
-
setSolverSelection(chain: string, active: boolean): void;
|
|
1135
|
+
myOrders(solver: HexString, after?: string): Promise<PostedOrderPage>;
|
|
1136
|
+
private request;
|
|
1080
1137
|
}
|
|
1081
1138
|
|
|
1082
|
-
/**
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
}
|
|
1088
|
-
declare class ContractInteractionService {
|
|
1089
|
-
private clientManager;
|
|
1090
|
-
private configService;
|
|
1091
|
-
cacheService: CacheService;
|
|
1092
|
-
private logger;
|
|
1093
|
-
private sdkHelperCache;
|
|
1094
|
-
private blockTimes;
|
|
1095
|
-
private solverAccountAddress;
|
|
1096
|
-
private signer;
|
|
1097
|
-
constructor(clientManager: ChainClientManager, configService: FillerConfigService, signer: Signer, sharedCacheService?: CacheService);
|
|
1139
|
+
/**
|
|
1140
|
+
* Where a bid goes. A strategy builds the signed fill op and hands it here; the venues decide
|
|
1141
|
+
* who receives it. The filler passes one of these to `FillerStrategy.executeOrder`.
|
|
1142
|
+
*/
|
|
1143
|
+
interface BidPlacer {
|
|
1098
1144
|
/**
|
|
1099
|
-
*
|
|
1100
|
-
*
|
|
1145
|
+
* @param commitment - The swap order the bid is on.
|
|
1146
|
+
* @param userOp - The signed fill UserOp, SCALE-encoded: the same bytes every venue takes.
|
|
1147
|
+
* @param bid - The identifier Hyperbridge files the bid under, `keccak256` of its calldata.
|
|
1101
1148
|
*/
|
|
1102
|
-
|
|
1149
|
+
place(commitment: HexString, userOp: HexString, bid: HexString): Promise<BidPlacement>;
|
|
1150
|
+
}
|
|
1151
|
+
/** What each venue said. A venue the bid was not sent to is absent. */
|
|
1152
|
+
interface BidPlacement {
|
|
1153
|
+
/** Hyperbridge's answer: the extrinsic landed, is pooled, or failed. */
|
|
1154
|
+
hyperbridge?: BidSubmissionResult;
|
|
1155
|
+
/** The HyperFX orderbook's answer. */
|
|
1156
|
+
orderbook?: SubmitBidResult;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
/**
|
|
1160
|
+
* An execution outcome that can also report a still-pooled bid, and what the orderbook said.
|
|
1161
|
+
*
|
|
1162
|
+
* `success`, `txHash`, `pending` and `error` are Hyperbridge's answer. `submitBid` can time out
|
|
1163
|
+
* with the extrinsic still in Hyperbridge's pool. That is neither success nor failure: the
|
|
1164
|
+
* extrinsic may yet land and reserve a deposit, so the bid record has to be reclaimable even
|
|
1165
|
+
* though `success` is false. Widened here rather than on the SDK's `ExecutionResult` so simplex
|
|
1166
|
+
* does not need an unreleased SDK.
|
|
1167
|
+
*
|
|
1168
|
+
* A bid goes to the HyperFX orderbook as well, and to it alone when the filler holds no BRIDGE
|
|
1169
|
+
* for the Hyperbridge deposit; `orderbook` is that venue's answer. A bid the orderbook holds is
|
|
1170
|
+
* live whatever Hyperbridge said.
|
|
1171
|
+
*/
|
|
1172
|
+
interface FillResult extends ExecutionResult {
|
|
1173
|
+
pending?: boolean;
|
|
1103
1174
|
/**
|
|
1104
|
-
*
|
|
1105
|
-
*
|
|
1175
|
+
* The identifier Hyperbridge files the bid under, once its op was built:
|
|
1176
|
+
* `keccak256` of its calldata. It tells the bids on one order apart, and retracting the bid names it.
|
|
1106
1177
|
*/
|
|
1107
|
-
|
|
1108
|
-
/**
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
initCache(): Promise<void>;
|
|
1116
|
-
getCache(): CacheService;
|
|
1178
|
+
bid?: HexString;
|
|
1179
|
+
/** The orderbook's answer; absent when the bid was not offered to it. */
|
|
1180
|
+
orderbook?: SubmitBidResult;
|
|
1181
|
+
}
|
|
1182
|
+
interface FillerStrategy {
|
|
1183
|
+
name: string;
|
|
1184
|
+
canFill(order: Order): Promise<boolean>;
|
|
1185
|
+
calculateProfitability(order: Order): Promise<number>;
|
|
1117
1186
|
/**
|
|
1118
|
-
*
|
|
1187
|
+
* Places the strategy's bid on `order` through `bids`, the venues the filler bids on
|
|
1188
|
+
* (Hyperbridge and the HyperFX orderbook). Without `bids` the destination selects no
|
|
1189
|
+
* solver, so there is nothing to bid on.
|
|
1119
1190
|
*/
|
|
1120
|
-
|
|
1191
|
+
executeOrder(order: Order, bids?: BidPlacer): Promise<FillResult>;
|
|
1121
1192
|
/**
|
|
1122
|
-
*
|
|
1193
|
+
* Optional hook for strategies to provide a USD value for the full input basket.
|
|
1194
|
+
* Returns null when the strategy cannot or does not want to price the order.
|
|
1123
1195
|
*/
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
dispatchFee: bigint;
|
|
1128
|
-
callGasLimit: bigint;
|
|
1129
|
-
}>;
|
|
1196
|
+
getOrderUsdValue?(order: Order): Promise<{
|
|
1197
|
+
inputUsd: Decimal;
|
|
1198
|
+
} | null>;
|
|
1130
1199
|
/**
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1133
|
-
*
|
|
1134
|
-
* Funding calls are not simulated (the V4 PositionManager's flash accounting does
|
|
1135
|
-
* not resolve in the bundler's estimation context), so each one adds a fixed
|
|
1136
|
-
* allowance for its modifyLiquidities + take. They differ between the bids on one
|
|
1137
|
-
* order, since each draws on its own limit order and so on its own funding, which
|
|
1138
|
-
* is why this is worked out per bid rather than baked into the cached estimate.
|
|
1139
|
-
* The estimate is of a lone fillOrder, so the budget call is not in it either.
|
|
1200
|
+
* Optional confirmation policy for this strategy.
|
|
1201
|
+
* If absent, no confirmation waiting is required (e.g. same-chain strategies).
|
|
1140
1202
|
*/
|
|
1141
|
-
|
|
1203
|
+
confirmationPolicy?: {
|
|
1204
|
+
getConfirmationBlocks: (chainId: number, amountUsd: number) => number;
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
/** Symbol and decimals for a token on a chain, as far as the filler knows them. */
|
|
1209
|
+
interface TokenDescription {
|
|
1210
|
+
symbol: string | null;
|
|
1211
|
+
decimals: number | null;
|
|
1212
|
+
}
|
|
1213
|
+
/** Resolves display metadata for `token` (20-byte address) on `chain` (state machine id). */
|
|
1214
|
+
type TokenDescriber = (chain: string, token: string) => Promise<TokenDescription>;
|
|
1215
|
+
interface ActivityRecorderOptions {
|
|
1142
1216
|
/**
|
|
1143
|
-
*
|
|
1144
|
-
*
|
|
1145
|
-
* @param chain - The chain identifier to get fee token info for
|
|
1146
|
-
* @returns An object containing the fee token address and its decimal places
|
|
1217
|
+
* Enriches order legs with symbol/decimals so the feed can show "19,585 USDC"
|
|
1218
|
+
* rather than a raw integer. Omit to record addresses and raw amounts only.
|
|
1147
1219
|
*/
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1220
|
+
describeToken?: TokenDescriber;
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Bridges the filler's order lifecycle onto an {@link ActivityStore}.
|
|
1224
|
+
*
|
|
1225
|
+
* The store used to subscribe to the `EventMonitor` itself, which meant a
|
|
1226
|
+
* consumer implementing the data interface also had to know about the filler's
|
|
1227
|
+
* internal event names. Ownership is inverted here: the recorder listens, the
|
|
1228
|
+
* store just receives rows.
|
|
1229
|
+
*
|
|
1230
|
+
* Writes are fire-and-forget — the activity feed is observability, and a failed
|
|
1231
|
+
* insert must never propagate back into the fill path that emitted it. Each
|
|
1232
|
+
* stored row is re-emitted as `event` for live consumers (the UI's SSE stream,
|
|
1233
|
+
* and `Simplex`'s `activity` event).
|
|
1234
|
+
*/
|
|
1235
|
+
declare class ActivityRecorder extends EventEmitter {
|
|
1236
|
+
private store;
|
|
1237
|
+
private logger;
|
|
1238
|
+
private monitor?;
|
|
1239
|
+
private handlers;
|
|
1240
|
+
private describeToken?;
|
|
1241
|
+
/** Order summaries by order id, so filled/skipped rows carry the order too. Insertion-ordered for eviction. */
|
|
1242
|
+
private summaries;
|
|
1243
|
+
constructor(store: ActivityStore, loggers?: LoggerContext, options?: ActivityRecorderOptions);
|
|
1244
|
+
/** Subscribes to the filler's order lifecycle events. Idempotent per monitor. */
|
|
1245
|
+
attach(monitor: EventMonitor): void;
|
|
1246
|
+
private subscribe;
|
|
1247
|
+
/** Unsubscribes from the attached monitor. Safe to call when never attached. */
|
|
1248
|
+
detach(): void;
|
|
1249
|
+
private remember;
|
|
1250
|
+
private summaryFor;
|
|
1152
1251
|
/**
|
|
1153
|
-
*
|
|
1154
|
-
* `
|
|
1155
|
-
*
|
|
1156
|
-
*
|
|
1157
|
-
* @param chain - The chain identifier
|
|
1158
|
-
* @param targetGasUnits - Gas units the deposit should cover (default 3M)
|
|
1159
|
-
* @param thresholdGasUnits - Only top up if deposit is below this many gas units (defaults to targetGasUnits)
|
|
1252
|
+
* Settles an order from its on-chain fill: `filled` when this filler won it,
|
|
1253
|
+
* `lost` (reason = the winner) when a rival did. A rival's fill is recorded
|
|
1254
|
+
* only for orders this filler has rows for — every fill on the chain passes
|
|
1255
|
+
* through here, and the feed is about this filler's orders.
|
|
1160
1256
|
*/
|
|
1161
|
-
|
|
1257
|
+
private settle;
|
|
1162
1258
|
/**
|
|
1163
|
-
*
|
|
1164
|
-
*
|
|
1165
|
-
*
|
|
1166
|
-
* @param order - The order to calculate input value for
|
|
1167
|
-
* @returns The total USD value of inputs (sum of normalized stable amounts, or 0 if none)
|
|
1259
|
+
* Captures the order for the feed. Token metadata lookups may hit the chain;
|
|
1260
|
+
* a failure degrades that leg to address + raw amount rather than dropping the row.
|
|
1168
1261
|
*/
|
|
1169
|
-
|
|
1262
|
+
private summarize;
|
|
1170
1263
|
/**
|
|
1171
|
-
*
|
|
1172
|
-
*
|
|
1173
|
-
*
|
|
1174
|
-
* @param chain - The chain identifier to check
|
|
1175
|
-
* @returns True if solver selection is active
|
|
1264
|
+
* Writes an event and emits the stored row. Never rejects — a failed write is
|
|
1265
|
+
* logged and dropped, because the caller is usually a fill in progress.
|
|
1176
1266
|
*/
|
|
1177
|
-
|
|
1267
|
+
record(event: ActivityInsert): void;
|
|
1268
|
+
recent(limit?: number, beforeId?: number): Promise<ActivityEvent[]>;
|
|
1269
|
+
fills(limit?: number): Promise<ActivityEvent[]>;
|
|
1270
|
+
orderHistory(page: number, pageSize: number): Promise<OrderHistoryPage>;
|
|
1271
|
+
recordWalletTx(tx: Omit<WalletTx, "id" | "ts">): Promise<void>;
|
|
1272
|
+
walletTxs(limit?: number): Promise<WalletTx[]>;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/** What a limit order may pay out over its whole life, as the fill chain enforces it. */
|
|
1276
|
+
interface LimitOrderBudget {
|
|
1277
|
+
budgetId: HexString;
|
|
1278
|
+
/** The order's whole size in the output token's own units. */
|
|
1279
|
+
cap: bigint;
|
|
1280
|
+
/** The token the order pays on its fill chain. */
|
|
1281
|
+
token: HexString;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
interface SwapCall {
|
|
1285
|
+
to: string;
|
|
1286
|
+
data: string;
|
|
1287
|
+
value: string;
|
|
1288
|
+
}
|
|
1289
|
+
interface CachedPairClassification {
|
|
1290
|
+
inputIsStable: boolean;
|
|
1291
|
+
stableToken: string;
|
|
1292
|
+
exoticToken: string;
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1295
|
+
* One bid: what a single limit order pays for an incoming order, and what funds it.
|
|
1296
|
+
*
|
|
1297
|
+
* An order that several limit orders can serve produces several of these, one per
|
|
1298
|
+
* order, each priced against the whole input at its own rate. They are never
|
|
1299
|
+
* summed: each bid is its own fill, and the gateway clamps whichever one lands
|
|
1300
|
+
* against what is still outstanding.
|
|
1301
|
+
*/
|
|
1302
|
+
interface BidPlan {
|
|
1303
|
+
limitOrderId: string;
|
|
1304
|
+
/** The order leg this bid fills; every other leg is quoted at zero. */
|
|
1305
|
+
leg: number;
|
|
1306
|
+
/** What this bid draws from that limit order, at 1e18. */
|
|
1307
|
+
payout: bigint;
|
|
1308
|
+
/** The outputs the bid signs, in the output token's own units. */
|
|
1309
|
+
fillerOutputs: TokenInfo[];
|
|
1310
|
+
/** The take signed beside each output: the escrow this bid's fill earns. */
|
|
1311
|
+
fillerInputs: TokenInfo[];
|
|
1312
|
+
/** The decimals `fillerInputs[leg]` is counted in: the input token's, on the order's source chain. */
|
|
1313
|
+
inputDecimals?: number;
|
|
1314
|
+
fundingCalls: ERC7821Call[];
|
|
1315
|
+
partialFill: boolean;
|
|
1316
|
+
profit: number;
|
|
1317
|
+
/** That limit order's budget, which the bid settles against on the fill chain. */
|
|
1318
|
+
budget?: LimitOrderBudget;
|
|
1319
|
+
}
|
|
1320
|
+
declare class CacheService {
|
|
1321
|
+
private cacheData;
|
|
1322
|
+
private readonly CACHE_EXPIRY_MS;
|
|
1323
|
+
/** When each order's bid loop began, for the orders whose loop is still running. */
|
|
1324
|
+
private readonly pins;
|
|
1325
|
+
private logger;
|
|
1326
|
+
constructor(loggers?: LoggerContext);
|
|
1178
1327
|
/**
|
|
1179
|
-
*
|
|
1328
|
+
* Whether an entry is still fresh. A pinned order's entries are aged as of the pin,
|
|
1329
|
+
* so what was fresh when its bid loop began stays fresh until the loop ends, and
|
|
1330
|
+
* what had already expired stays expired.
|
|
1180
1331
|
*/
|
|
1181
|
-
|
|
1182
|
-
getTokenBalance(chain: string, token: HexString, holder: HexString): Promise<bigint>;
|
|
1332
|
+
private isCacheValid;
|
|
1183
1333
|
/**
|
|
1184
|
-
*
|
|
1185
|
-
* the paid token's own units, or null when it cannot be read.
|
|
1334
|
+
* Keeps the order's evaluation alive while its bids go out, and returns the release.
|
|
1186
1335
|
*
|
|
1187
|
-
*
|
|
1188
|
-
*
|
|
1189
|
-
*
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
/**
|
|
1194
|
-
* Deposits native tokens to the ERC-4337 EntryPoint on behalf of the solver account.
|
|
1195
|
-
* @returns The transaction hash of the deposit.
|
|
1196
|
-
*/
|
|
1197
|
-
depositToEntryPoint(chain: string, amount: bigint): Promise<HexString>;
|
|
1198
|
-
/**
|
|
1199
|
-
* Withdraws the solver's full EntryPoint deposit back to the solver EOA on a single chain.
|
|
1200
|
-
* @returns The transaction hash, or null if there was nothing to withdraw.
|
|
1201
|
-
*/
|
|
1202
|
-
withdrawFromEntryPoint(chain: string): Promise<HexString | null>;
|
|
1203
|
-
/**
|
|
1204
|
-
* Withdraws EntryPoint deposits on all configured chains that have a positive balance.
|
|
1336
|
+
* The bids on one order are sent in turn, each priced by the evaluation that planned
|
|
1337
|
+
* them, and every one reads the shared gas estimate back out of here. Submitting a
|
|
1338
|
+
* bid can take longer than `CACHE_EXPIRY_MS` on its own, and the order is not
|
|
1339
|
+
* evaluated again, so the estimate has to outlive the loop for the later bids to be
|
|
1340
|
+
* sent at all. Estimating afresh instead would sign them at a gas cost their payouts
|
|
1341
|
+
* were not priced against.
|
|
1205
1342
|
*/
|
|
1206
|
-
|
|
1343
|
+
pinOrder(orderId: string): () => void;
|
|
1344
|
+
private cleanupStaleData;
|
|
1345
|
+
getGasEstimate(orderId: string): {
|
|
1346
|
+
totalCostInSourceFeeToken: bigint;
|
|
1347
|
+
relayerFeeInSourceFeeToken: bigint;
|
|
1348
|
+
dispatchFee: bigint;
|
|
1349
|
+
callGasLimit: bigint;
|
|
1350
|
+
verificationGasLimit: bigint;
|
|
1351
|
+
preVerificationGas: bigint;
|
|
1352
|
+
maxFeePerGas: bigint;
|
|
1353
|
+
maxPriorityFeePerGas: bigint;
|
|
1354
|
+
totalGasCostWei: bigint;
|
|
1355
|
+
} | null;
|
|
1356
|
+
setGasEstimate(orderId: string, totalCostInSourceFeeToken: bigint, relayerFeeInSourceFeeToken: bigint, dispatchFee: bigint, callGasLimit: bigint, verificationGasLimit: bigint, preVerificationGas: bigint, maxFeePerGas: bigint, maxPriorityFeePerGas: bigint, totalGasCostWei: bigint): void;
|
|
1357
|
+
getSwapOperations(orderId: string): {
|
|
1358
|
+
calls: SwapCall[];
|
|
1359
|
+
totalGasEstimate: bigint;
|
|
1360
|
+
} | null;
|
|
1361
|
+
setSwapOperations(orderId: string, calls: SwapCall[], totalGasEstimate: bigint): void;
|
|
1362
|
+
getFillerOutputs(orderId: string): {
|
|
1363
|
+
token: HexString;
|
|
1364
|
+
amount: bigint;
|
|
1365
|
+
}[] | null;
|
|
1366
|
+
/** The takes cached with the order's filler outputs, or null when absent or stale. */
|
|
1367
|
+
getFillerInputs(orderId: string): {
|
|
1368
|
+
token: HexString;
|
|
1369
|
+
amount: bigint;
|
|
1370
|
+
}[] | null;
|
|
1207
1371
|
/**
|
|
1208
|
-
*
|
|
1209
|
-
*
|
|
1210
|
-
* upgraded to per-leg escrow is read by token).
|
|
1211
|
-
*
|
|
1212
|
-
* A partially filled order has had its escrow drawn down, so the pro-rata
|
|
1213
|
-
* release a later filler receives is computed against the *residual*, not
|
|
1214
|
-
* against `order.inputs[i].amount`. A strategy that prices off the original
|
|
1215
|
-
* inputs would overstate its take, which is why the partial-fill path refuses
|
|
1216
|
-
* any order this reports as already touched.
|
|
1372
|
+
* The budget of the limit order that priced the outputs cached for this order, or
|
|
1373
|
+
* null when no limit order did.
|
|
1217
1374
|
*
|
|
1218
|
-
*
|
|
1375
|
+
* Kept on the same entry as the outputs, so the two are replaced and expire
|
|
1376
|
+
* together: a bid can never sign one limit order's payout beside another's budget.
|
|
1219
1377
|
*/
|
|
1220
|
-
|
|
1378
|
+
getBidBudget(orderId: string): LimitOrderBudget | null;
|
|
1379
|
+
setFillerOutputs(orderId: string, outputs: {
|
|
1380
|
+
token: HexString;
|
|
1381
|
+
amount: bigint;
|
|
1382
|
+
}[], inputs?: {
|
|
1383
|
+
token: HexString;
|
|
1384
|
+
amount: bigint;
|
|
1385
|
+
}[], budget?: LimitOrderBudget): void;
|
|
1221
1386
|
/**
|
|
1222
|
-
*
|
|
1387
|
+
* The limit order this order was priced against, and the payout it allowed.
|
|
1223
1388
|
*
|
|
1224
|
-
*
|
|
1389
|
+
* Carried from `calculateProfitability` to the bid so the reservation lands on
|
|
1390
|
+
* the same limit order the price came from. A fill later finds it through the
|
|
1391
|
+
* bid row, not through here.
|
|
1392
|
+
*/
|
|
1393
|
+
getMatchedLimitOrder(orderId: string): {
|
|
1394
|
+
limitOrderId: string;
|
|
1395
|
+
payout: bigint;
|
|
1396
|
+
}[];
|
|
1397
|
+
getBidPlans(orderId: string): BidPlan[];
|
|
1398
|
+
setBidPlans(orderId: string, plans: BidPlan[]): void;
|
|
1399
|
+
clearBidPlans(orderId: string): void;
|
|
1400
|
+
setMatchedLimitOrder(orderId: string, holds: {
|
|
1401
|
+
limitOrderId: string;
|
|
1402
|
+
payout: bigint;
|
|
1403
|
+
}[]): void;
|
|
1404
|
+
getPairClassifications(orderId: string): CachedPairClassification[] | null;
|
|
1405
|
+
setPairClassifications(orderId: string, pairs: CachedPairClassification[]): void;
|
|
1406
|
+
getFundingPrepends(orderId: string): {
|
|
1407
|
+
calls: ERC7821Call[];
|
|
1408
|
+
} | null;
|
|
1409
|
+
setFundingPrepends(orderId: string, calls: ERC7821Call[]): void;
|
|
1410
|
+
clearFundingPrepends(orderId: string): void;
|
|
1411
|
+
/**
|
|
1412
|
+
* Whether the strategy's completed evaluation of this order chose a partial fill.
|
|
1413
|
+
*
|
|
1414
|
+
* Only ever written by an evaluation that went on to return a fillable answer,
|
|
1415
|
+
* and cleared at the start of every evaluation — so a refusal can never leave a
|
|
1416
|
+
* `true` behind for the caller to act on.
|
|
1417
|
+
*/
|
|
1418
|
+
isPartialFill(orderId: string): boolean;
|
|
1419
|
+
setPartialFill(orderId: string, partial: boolean): void;
|
|
1420
|
+
clearPartialFill(orderId: string): void;
|
|
1421
|
+
/**
|
|
1422
|
+
* Whether the strategy's completed evaluation let a bid through without holding
|
|
1423
|
+
* `order.fees` to the execution cost, because the order is at or above the
|
|
1424
|
+
* operator's minimum size.
|
|
1425
|
+
*
|
|
1426
|
+
* Written and cleared the way {@link isPartialFill} is, for the same reason: the
|
|
1427
|
+
* caller exempts such an order from its profit floor.
|
|
1428
|
+
*/
|
|
1429
|
+
isFeeCheckWaived(orderId: string): boolean;
|
|
1430
|
+
setFeeCheckWaived(orderId: string, waived: boolean): void;
|
|
1431
|
+
clearFeeCheckWaived(orderId: string): void;
|
|
1432
|
+
getFeeTokenWithDecimals(chain: string): {
|
|
1433
|
+
address: HexString;
|
|
1434
|
+
decimals: number;
|
|
1435
|
+
} | null;
|
|
1436
|
+
setFeeTokenWithDecimals(chain: string, address: HexString, decimals: number): void;
|
|
1437
|
+
getTokenDecimals(chain: string, tokenAddress: HexString): number | null;
|
|
1438
|
+
setTokenDecimals(chain: string, tokenAddress: HexString, decimals: number): void;
|
|
1439
|
+
getSolverSelection(chain: string): boolean | null;
|
|
1440
|
+
setSolverSelection(chain: string, active: boolean): void;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
/** What a bid's batch needs to settle its limit order's budget. */
|
|
1444
|
+
interface BudgetSettlement {
|
|
1445
|
+
budget: LimitOrderBudget;
|
|
1446
|
+
/** The solver's account, which is the only caller `debitOrder` accepts. */
|
|
1447
|
+
solverAccount: HexString;
|
|
1448
|
+
}
|
|
1449
|
+
declare class ContractInteractionService {
|
|
1450
|
+
private clientManager;
|
|
1451
|
+
private configService;
|
|
1452
|
+
cacheService: CacheService;
|
|
1453
|
+
private logger;
|
|
1454
|
+
private sdkHelperCache;
|
|
1455
|
+
private blockTimes;
|
|
1456
|
+
private solverAccountAddress;
|
|
1457
|
+
private signer;
|
|
1458
|
+
constructor(clientManager: ChainClientManager, configService: FillerConfigService, signer: Signer, sharedCacheService?: CacheService);
|
|
1459
|
+
/**
|
|
1460
|
+
* The endpoint SDK helpers should use for `chain`: the first configured RPC,
|
|
1461
|
+
* matching the one viem's `fallback` transport tries first.
|
|
1462
|
+
*/
|
|
1463
|
+
private primaryRpcUrl;
|
|
1464
|
+
/**
|
|
1465
|
+
* Gets the SDK helper for a given source and destination chain.
|
|
1466
|
+
* Instances are cached and reused to avoid redundant RPC calls.
|
|
1467
|
+
*/
|
|
1468
|
+
getIntentGateway(source: string, destination: string): Promise<IntentGateway>;
|
|
1469
|
+
/**
|
|
1470
|
+
* Best-effort cache warm-up. Deliberately never rejects: this runs unawaited from the
|
|
1471
|
+
* constructor, so a rejection would surface as an unhandled rejection and take the
|
|
1472
|
+
* process down. A failed prewarm only means the value is fetched on first use, where
|
|
1473
|
+
* `getTokenDecimals` is strict — which is the right place for strictness, because
|
|
1474
|
+
* there it can skip a single order instead of killing the filler at boot.
|
|
1475
|
+
*/
|
|
1476
|
+
initCache(): Promise<void>;
|
|
1477
|
+
getCache(): CacheService;
|
|
1478
|
+
/**
|
|
1479
|
+
* Gets the decimals for a token
|
|
1480
|
+
*/
|
|
1481
|
+
getTokenDecimals(tokenAddress: string, chain: string): Promise<number>;
|
|
1482
|
+
/**
|
|
1483
|
+
* Estimates gas for filling an order and caches the full estimate for bid preparation
|
|
1484
|
+
*/
|
|
1485
|
+
estimateGasFillPost(order: Order): Promise<{
|
|
1486
|
+
totalCostInSourceFeeToken: bigint;
|
|
1487
|
+
relayerFeeInSourceFeeToken: bigint;
|
|
1488
|
+
dispatchFee: bigint;
|
|
1489
|
+
callGasLimit: bigint;
|
|
1490
|
+
}>;
|
|
1491
|
+
/**
|
|
1492
|
+
* Logs a bundler gas estimate for `order` that failed transiently and is sent again
|
|
1493
|
+
* (the SDK retries a network failure, a JSON-RPC internal error, or an HTTP 408, 429 or 5xx).
|
|
1494
|
+
*/
|
|
1495
|
+
private logBundlerRetry;
|
|
1496
|
+
/**
|
|
1497
|
+
* The call gas a bid needs: the shared estimate plus room for the funding calls
|
|
1498
|
+
* this bid prepends and for settling its limit order's budget.
|
|
1499
|
+
*
|
|
1500
|
+
* Funding calls are not simulated (the V4 PositionManager's flash accounting does
|
|
1501
|
+
* not resolve in the bundler's estimation context), so each one adds a fixed
|
|
1502
|
+
* allowance for its modifyLiquidities + take. They differ between the bids on one
|
|
1503
|
+
* order, since each draws on its own limit order and so on its own funding, which
|
|
1504
|
+
* is why this is worked out per bid rather than baked into the cached estimate.
|
|
1505
|
+
* The estimate is of a lone fillOrder, so the budget call is not in it either, nor are
|
|
1506
|
+
* the approvals: each token the batch approves adds `APPROVAL_GAS_PER_TOKEN`.
|
|
1507
|
+
*/
|
|
1508
|
+
private callGasLimitFor;
|
|
1509
|
+
/**
|
|
1510
|
+
* What the batch approves to the gateway for `order`, per token, and the fee token's key
|
|
1511
|
+
* when the fill dispatches. The fee token is read from the destination host.
|
|
1512
|
+
*/
|
|
1513
|
+
private approvalsFor;
|
|
1514
|
+
/**
|
|
1515
|
+
* Gets the fee token address and decimals for a given chain.
|
|
1516
|
+
*
|
|
1517
|
+
* @param chain - The chain identifier to get fee token info for
|
|
1518
|
+
* @returns An object containing the fee token address and its decimal places
|
|
1519
|
+
*/
|
|
1520
|
+
getFeeTokenWithDecimals(chain: string): Promise<{
|
|
1521
|
+
address: HexString;
|
|
1522
|
+
decimals: number;
|
|
1523
|
+
}>;
|
|
1524
|
+
/**
|
|
1525
|
+
* Tops up the solver's EntryPoint deposit so it covers at least
|
|
1526
|
+
* `targetGasUnits` at the current gas price. Skips if the wallet
|
|
1527
|
+
* balance cannot afford at least 1M gas units (not enough to send txs).
|
|
1528
|
+
*
|
|
1529
|
+
* @param chain - The chain identifier
|
|
1530
|
+
* @param targetGasUnits - Gas units the deposit should cover (default 3M)
|
|
1531
|
+
* @param thresholdGasUnits - Only top up if deposit is below this many gas units (defaults to targetGasUnits)
|
|
1532
|
+
*/
|
|
1533
|
+
topUpEntryPointDeposit(chain: string, targetGasUnits?: bigint, thresholdGasUnits?: bigint): Promise<void>;
|
|
1534
|
+
/**
|
|
1535
|
+
* Calculates the total USD value of an order's inputs.
|
|
1536
|
+
* Only stable (USDC/USDT) inputs contribute; non-stables contribute 0.
|
|
1537
|
+
*
|
|
1538
|
+
* @param order - The order to calculate input value for
|
|
1539
|
+
* @returns The total USD value of inputs (sum of normalized stable amounts, or 0 if none)
|
|
1540
|
+
*/
|
|
1541
|
+
getInputUsdValue(order: Order): Promise<Decimal>;
|
|
1542
|
+
/**
|
|
1543
|
+
* Checks if solver selection mode is active on the destination chain
|
|
1544
|
+
* When active, fillers must submit bids to Hyperbridge instead of filling directly
|
|
1545
|
+
*
|
|
1546
|
+
* @param chain - The chain identifier to check
|
|
1547
|
+
* @returns True if solver selection is active
|
|
1548
|
+
*/
|
|
1549
|
+
isSolverSelectionActive(chain: string): Promise<boolean>;
|
|
1550
|
+
/**
|
|
1551
|
+
* Reads the solver account's deposit balance on the ERC-4337 EntryPoint.
|
|
1552
|
+
*/
|
|
1553
|
+
/** What `holder` holds of an ERC-20 on `chain`, in the token's own units. */
|
|
1554
|
+
getTokenBalance(chain: string, token: HexString, holder: HexString): Promise<bigint>;
|
|
1555
|
+
/**
|
|
1556
|
+
* What the solver's account has tallied against a limit order's budget on `chain`, in
|
|
1557
|
+
* the paid token's own units, or null when it cannot be read.
|
|
1558
|
+
*
|
|
1559
|
+
* Null rather than a throw: an account whose implementation keeps no tally answers
|
|
1560
|
+
* with a revert or with no data, and the caller carries on without the figure either
|
|
1561
|
+
* way. Not retried, since that answer does not change on a second ask.
|
|
1562
|
+
*
|
|
1563
|
+
* Read at `blockNumber` when given, otherwise at the latest block. A load-balanced
|
|
1564
|
+
* endpoint can lag the one that saw a fill, so a read at `latest` right after the
|
|
1565
|
+
* fill can return the tally from before it. The tally only grows, so a read at the
|
|
1566
|
+
* fill's own block already includes that fill. An endpoint that has not reached the
|
|
1567
|
+
* block answers with an error, which is null here: no figure, rather than a stale one.
|
|
1568
|
+
*/
|
|
1569
|
+
limitOrderSpent(chain: string, budgetId: HexString, blockNumber?: bigint): Promise<bigint | null>;
|
|
1570
|
+
getSolverEntryPointBalance(chain: string): Promise<bigint>;
|
|
1571
|
+
/**
|
|
1572
|
+
* Deposits native tokens to the ERC-4337 EntryPoint on behalf of the solver account.
|
|
1573
|
+
* @returns The transaction hash of the deposit.
|
|
1574
|
+
*/
|
|
1575
|
+
depositToEntryPoint(chain: string, amount: bigint): Promise<HexString>;
|
|
1576
|
+
/**
|
|
1577
|
+
* Withdraws the solver's full EntryPoint deposit back to the solver EOA on a single chain.
|
|
1578
|
+
* @returns The transaction hash, or null if there was nothing to withdraw.
|
|
1579
|
+
*/
|
|
1580
|
+
withdrawFromEntryPoint(chain: string): Promise<HexString | null>;
|
|
1581
|
+
/**
|
|
1582
|
+
* Withdraws EntryPoint deposits on all configured chains that have a positive balance.
|
|
1583
|
+
*/
|
|
1584
|
+
withdrawAllEntryPointDeposits(): Promise<void>;
|
|
1585
|
+
/**
|
|
1586
|
+
* Output already delivered against this order by any solver, per leg (the gateway keys fill
|
|
1587
|
+
* progress by output index, so legs repeating a token are reported separately; a gateway not yet
|
|
1588
|
+
* upgraded to per-leg escrow is read by token).
|
|
1589
|
+
*
|
|
1590
|
+
* A partially filled order has had its escrow drawn down, so the pro-rata
|
|
1591
|
+
* release a later filler receives is computed against the *residual*, not
|
|
1592
|
+
* against `order.inputs[i].amount`. A strategy that prices off the original
|
|
1593
|
+
* inputs would overstate its take, which is why the partial-fill path refuses
|
|
1594
|
+
* any order this reports as already touched.
|
|
1595
|
+
*
|
|
1596
|
+
* Same-chain concept only — the cross-chain path has no partial-fill state.
|
|
1597
|
+
*/
|
|
1598
|
+
partialFillsFor(order: Order, chain: string): Promise<bigint[]>;
|
|
1599
|
+
/**
|
|
1600
|
+
* Prepares a signed PackedUserOperation for bid submission to Hyperbridge
|
|
1601
|
+
*
|
|
1602
|
+
* Uses cached gas estimates from prior profitability check (estimateGasFillPost)
|
|
1225
1603
|
* to avoid redundant RPC calls.
|
|
1226
1604
|
*
|
|
1227
1605
|
* @param order - The order to prepare a bid for
|
|
@@ -1239,6 +1617,16 @@ declare class ContractInteractionService {
|
|
|
1239
1617
|
userOp: HexString;
|
|
1240
1618
|
bid: HexString;
|
|
1241
1619
|
}>;
|
|
1620
|
+
/**
|
|
1621
|
+
* Throws unless an op with no paymaster can pay its own prefund. The EntryPoint takes it from
|
|
1622
|
+
* the account's deposit and asks the account for the rest out of its native balance, so
|
|
1623
|
+
* between them they must cover `required`. Nothing funds a deposit on a chain with a
|
|
1624
|
+
* paymaster configured, so when selection comes back empty there a solver holding little
|
|
1625
|
+
* native would place a bid, pay Hyperbridge's bid fee for it, and fail validation (AA21)
|
|
1626
|
+
* when it is selected. Reads that fail let the bid through, as the paymaster deposit gate
|
|
1627
|
+
* does: a transient RPC error must not cost a bid, and the worst case is that failure.
|
|
1628
|
+
*/
|
|
1629
|
+
private assertUnsponsoredBidFunded;
|
|
1242
1630
|
/**
|
|
1243
1631
|
* Last block on the destination chain at which a bid signed now may still execute.
|
|
1244
1632
|
*
|
|
@@ -1264,7 +1652,11 @@ declare class ContractInteractionService {
|
|
|
1264
1652
|
* speeds up (BSC makes a block every 0.45s against a declared 0.75s) and some chains
|
|
1265
1653
|
* declare none. Converting at a slower block time than the chain's ends a bid early, so
|
|
1266
1654
|
* the faster of the measured and the declared figure is used, and a stalled or idle
|
|
1267
|
-
* stretch in the sample never shortens a bid.
|
|
1655
|
+
* stretch in the sample never shortens a bid. A measurement below half the declared figure is
|
|
1656
|
+
* discarded, which limits how far one RPC can stretch a bid to twice its window. A chain that
|
|
1657
|
+
* declares none has no reference to judge a sample against, so it only gets the flat floor
|
|
1658
|
+
* {@link MIN_PLAUSIBLE_BLOCK_TIME_SECONDS}; below that the measurement is discarded for
|
|
1659
|
+
* {@link FALLBACK_BLOCK_TIME_SECONDS}.
|
|
1268
1660
|
*
|
|
1269
1661
|
* Blocks that cannot be read fall back to the declared figure, then to
|
|
1270
1662
|
* {@link FALLBACK_BLOCK_TIME_SECONDS}. That answer is not kept.
|
|
@@ -1307,6 +1699,13 @@ declare class ContractInteractionService {
|
|
|
1307
1699
|
* Builds ERC-7821 batch calldata that approves exactly what this bid can pay
|
|
1308
1700
|
* before the fillOrder call, all within a single UserOp payload.
|
|
1309
1701
|
*
|
|
1702
|
+
* The gateway is approved for exactly what this fill pays: the outputs in each
|
|
1703
|
+
* ERC20, plus the dispatch fee (`dispatchFee`) in the fee token on a cross-chain
|
|
1704
|
+
* fill. Nothing else goes in an approval: the fill's gas is paid through the
|
|
1705
|
+
* paymaster's Permit2 pull. The batch ends by setting every allowance it set back
|
|
1706
|
+
* to zero, so none stands once it completes. The gateway is an upgradeable proxy
|
|
1707
|
+
* and a standing allowance is exposure to a future implementation.
|
|
1708
|
+
*
|
|
1310
1709
|
* The approvals are unconditional. One solver can hold several bids on one
|
|
1311
1710
|
* order, at different levels of its book, and they execute one after another:
|
|
1312
1711
|
* an approval skipped because the allowance covered this bid when it was signed
|
|
@@ -1322,9 +1721,11 @@ declare class ContractInteractionService {
|
|
|
1322
1721
|
* A bid priced by a limit order ends with `debitOrder`, which takes the budget's id
|
|
1323
1722
|
* as its `orderId`, works out what the fill paid from what is left of the allowance
|
|
1324
1723
|
* and reverts the whole batch if the order's payouts would pass its size. It has to
|
|
1325
|
-
* come
|
|
1724
|
+
* come after the gateway has drawn on the allowance, and the zero-resets after it,
|
|
1725
|
+
* since it reads the allowance that is left. It clears the budget token's allowance
|
|
1726
|
+
* itself, so the resets skip that token.
|
|
1326
1727
|
*/
|
|
1327
|
-
buildApprovalAndFillCalldata(order: Order, fillerOutputs: TokenInfo[], fillOptions: FillOptions,
|
|
1728
|
+
buildApprovalAndFillCalldata(order: Order, fillerOutputs: TokenInfo[], fillOptions: FillOptions, settlement?: BudgetSettlement): Promise<HexString>;
|
|
1328
1729
|
}
|
|
1329
1730
|
|
|
1330
1731
|
interface BinanceCexConfig {
|
|
@@ -1390,386 +1791,147 @@ declare class CctpRebalancer {
|
|
|
1390
1791
|
*/
|
|
1391
1792
|
sendCctp(options: RebalanceOptions): Promise<BridgeResult>;
|
|
1392
1793
|
/**
|
|
1393
|
-
* Estimates the cost of a CCTP transfer
|
|
1394
|
-
*/
|
|
1395
|
-
estimateCctp(options: RebalanceOptions): Promise<EstimateResult>;
|
|
1396
|
-
/**
|
|
1397
|
-
* Retries a failed CCTP transfer
|
|
1398
|
-
*/
|
|
1399
|
-
retrySendCctp(failedResult: BridgeResult): Promise<BridgeResult>;
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
|
-
interface Usdt0TransferResult {
|
|
1403
|
-
success: boolean;
|
|
1404
|
-
txHash: HexString;
|
|
1405
|
-
amountSent: bigint;
|
|
1406
|
-
amountReceived: bigint;
|
|
1407
|
-
nativeFee: bigint;
|
|
1408
|
-
}
|
|
1409
|
-
interface Usdt0EstimateResult {
|
|
1410
|
-
amountSent: bigint;
|
|
1411
|
-
amountReceived: bigint;
|
|
1412
|
-
nativeFee: bigint;
|
|
1413
|
-
minAmount: bigint;
|
|
1414
|
-
maxAmount: bigint;
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
/**
|
|
1418
|
-
* Options for rebalancing transfers (CCTP, USDT0, or CEX).
|
|
1419
|
-
* - For CCTP/USDT0: coin is implicit (CCTP=USDC, USDT0=USDT), recipientAddress is optional
|
|
1420
|
-
* - For unified router/CEX: coin is required for routing, recipientAddress is ignored
|
|
1421
|
-
*/
|
|
1422
|
-
interface RebalanceOptions {
|
|
1423
|
-
/** Amount in human-readable format (e.g., "100.00") */
|
|
1424
|
-
amount: string;
|
|
1425
|
-
/** Source chain in state machine format (e.g., "EVM-137") */
|
|
1426
|
-
source: string;
|
|
1427
|
-
/** Destination chain in state machine format (e.g., "EVM-42161") */
|
|
1428
|
-
destination: string;
|
|
1429
|
-
/** Optional recipient address (defaults to sender's address) - only used for CCTP/USDT0, ignored for CEX */
|
|
1430
|
-
recipientAddress?: HexString;
|
|
1431
|
-
}
|
|
1432
|
-
/**
|
|
1433
|
-
* UnifiedRebalanceOptions is kept for broader compatibility.
|
|
1434
|
-
*/
|
|
1435
|
-
type UnifiedRebalanceOptions = RebalanceOptions & {
|
|
1436
|
-
coin: "USDC" | "USDT";
|
|
1437
|
-
};
|
|
1438
|
-
|
|
1439
|
-
/**
|
|
1440
|
-
* Represents a planned transfer from one chain to another for portfolio-level rebalancing.
|
|
1441
|
-
*/
|
|
1442
|
-
interface PlannedTransfer {
|
|
1443
|
-
sourceChain: string;
|
|
1444
|
-
destChain: string;
|
|
1445
|
-
coin: "USDC" | "USDT";
|
|
1446
|
-
amount: string;
|
|
1447
|
-
}
|
|
1448
|
-
/**
|
|
1449
|
-
* Result of checking portfolio rebalancing triggers.
|
|
1450
|
-
*/
|
|
1451
|
-
interface TriggerCheckResult {
|
|
1452
|
-
triggered: boolean;
|
|
1453
|
-
triggeredChains: Array<{
|
|
1454
|
-
chain: string;
|
|
1455
|
-
asset: "USDC" | "USDT";
|
|
1456
|
-
deficit: number;
|
|
1457
|
-
}>;
|
|
1458
|
-
}
|
|
1459
|
-
/**
|
|
1460
|
-
* Result of a portfolio rebalancing operation.
|
|
1461
|
-
*/
|
|
1462
|
-
interface RebalancingResult {
|
|
1463
|
-
success: boolean;
|
|
1464
|
-
transfers: PlannedTransfer[];
|
|
1465
|
-
executedTransfers: Array<{
|
|
1466
|
-
transfer: PlannedTransfer;
|
|
1467
|
-
result: unknown;
|
|
1468
|
-
}>;
|
|
1469
|
-
errors?: string[];
|
|
1470
|
-
}
|
|
1471
|
-
/**
|
|
1472
|
-
* RebalancingService - Facade over CCTP, USDT0, and Binance CEX rebalancers.
|
|
1473
|
-
* Provides both low-level methods (sendCctp, sendUsdt0, sendViaCex) and a high-level router (rebalance).
|
|
1474
|
-
*/
|
|
1475
|
-
declare class RebalancingService {
|
|
1476
|
-
private readonly chainClientManager;
|
|
1477
|
-
private readonly configService;
|
|
1478
|
-
private readonly walletAddress;
|
|
1479
|
-
private readonly cctpRebalancer;
|
|
1480
|
-
private readonly usdt0Rebalancer;
|
|
1481
|
-
private readonly binanceRebalancer?;
|
|
1482
|
-
private readonly logger;
|
|
1483
|
-
constructor(chainClientManager: ChainClientManager, configService: FillerConfigService, binanceConfig?: BinanceCexConfig);
|
|
1484
|
-
sendCctp(options: RebalanceOptions): Promise<_circle_fin_bridge_kit.BridgeResult>;
|
|
1485
|
-
estimateCctp(options: RebalanceOptions): Promise<_circle_fin_bridge_kit.EstimateResult>;
|
|
1486
|
-
retrySendCctp(failedResult: Awaited<ReturnType<CctpRebalancer["sendCctp"]>>): Promise<_circle_fin_bridge_kit.BridgeResult>;
|
|
1487
|
-
sendUsdt0(options: RebalanceOptions): Promise<Usdt0TransferResult>;
|
|
1488
|
-
estimateUsdt0(options: RebalanceOptions): Promise<Usdt0EstimateResult>;
|
|
1489
|
-
sendViaCex(options: UnifiedRebalanceOptions): Promise<CexRebalanceResult>;
|
|
1490
|
-
estimateCexRebalance(options: UnifiedRebalanceOptions): Promise<CexRebalanceEstimate>;
|
|
1491
|
-
/**
|
|
1492
|
-
* Execute a single cross-chain transfer, selecting the best route (CCTP / USDT0 / CEX).
|
|
1493
|
-
* Requires coin to be specified for routing decisions.
|
|
1494
|
-
*/
|
|
1495
|
-
rebalance(options: UnifiedRebalanceOptions): Promise<Awaited<ReturnType<CctpRebalancer["sendCctp"]>> | Usdt0TransferResult | CexRebalanceResult>;
|
|
1496
|
-
/**
|
|
1497
|
-
* Check if any chains/assets have triggered portfolio rebalancing thresholds.
|
|
1498
|
-
*/
|
|
1499
|
-
checkRebalanceTriggers(): Promise<TriggerCheckResult>;
|
|
1500
|
-
/**
|
|
1501
|
-
* Plan portfolio-level rebalancing transfers for triggered chains using greedy matching.
|
|
1502
|
-
*/
|
|
1503
|
-
planPortfolioRebalancing(triggeredChains: TriggerCheckResult["triggeredChains"]): Promise<PlannedTransfer[]>;
|
|
1504
|
-
/**
|
|
1505
|
-
* Plan transfers for a specific asset using greedy surplus–deficit matching.
|
|
1506
|
-
*/
|
|
1507
|
-
private planTransfersForAsset;
|
|
1508
|
-
/**
|
|
1509
|
-
* Execute planned portfolio-level transfers via this service.
|
|
1510
|
-
*/
|
|
1511
|
-
executePortfolioRebalancing(transfers: PlannedTransfer[]): Promise<RebalancingResult>;
|
|
1512
|
-
/**
|
|
1513
|
-
* High-level portfolio rebalance:
|
|
1514
|
-
* 1) Check triggers
|
|
1515
|
-
* 2) Plan transfers
|
|
1516
|
-
* 3) Execute transfers
|
|
1517
|
-
*/
|
|
1518
|
-
rebalancePortfolio(): Promise<RebalancingResult>;
|
|
1519
|
-
/**
|
|
1520
|
-
* Get current balance for a token on a chain.
|
|
1521
|
-
* Returns balance in normalized USD value (treating token as $1).
|
|
1522
|
-
*/
|
|
1523
|
-
private getCurrentBalance;
|
|
1524
|
-
estimate(options: UnifiedRebalanceOptions): Promise<{
|
|
1525
|
-
method: "cctp";
|
|
1526
|
-
estimate: Awaited<ReturnType<CctpRebalancer["estimateCctp"]>>;
|
|
1527
|
-
} | {
|
|
1528
|
-
method: "usdt0";
|
|
1529
|
-
estimate: Usdt0EstimateResult;
|
|
1530
|
-
} | {
|
|
1531
|
-
method: "cex";
|
|
1532
|
-
estimate: CexRebalanceEstimate;
|
|
1533
|
-
}>;
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
interface Book {
|
|
1537
|
-
id: string;
|
|
1538
|
-
base: string;
|
|
1539
|
-
quote: string;
|
|
1540
|
-
}
|
|
1541
|
-
/** Live price levels. All prices and sizes are decimal integer strings at 1e18. */
|
|
1542
|
-
interface OrderbookLevel {
|
|
1543
|
-
fillChain: string;
|
|
1544
|
-
priceBucket: string;
|
|
1545
|
-
price: string;
|
|
1546
|
-
worstPrice: string;
|
|
1547
|
-
baseSize: string;
|
|
1548
|
-
quoteSize: string;
|
|
1549
|
-
orderCount: number;
|
|
1550
|
-
solverCount: number;
|
|
1551
|
-
}
|
|
1552
|
-
interface OrderbookSnapshot extends Book {
|
|
1553
|
-
/** Best first: bids descending, asks ascending. */
|
|
1554
|
-
bids: OrderbookLevel[];
|
|
1555
|
-
asks: OrderbookLevel[];
|
|
1556
|
-
/** True backing liquidity, in quote for bids and base for asks. */
|
|
1557
|
-
bidLiquidity: string;
|
|
1558
|
-
askLiquidity: string;
|
|
1559
|
-
/** Price bucket width, quote per 1 base at 1e18; null when the orderbook does not report one. */
|
|
1560
|
-
granularity: string | null;
|
|
1561
|
-
}
|
|
1562
|
-
/** One solver's order inside a price level. Prices and sizes are decimal integer strings at 1e18. */
|
|
1563
|
-
interface OrderbookLevelOrder {
|
|
1564
|
-
solver: string;
|
|
1565
|
-
commitment: string;
|
|
1566
|
-
fillChain: string;
|
|
1567
|
-
price: string;
|
|
1568
|
-
/** What the order publishes as depth, in the token its side pays out: quote for bids, base for asks. */
|
|
1569
|
-
advertisedSize: string;
|
|
1570
|
-
/** The signed output before any balance cap, in the same token as `advertisedSize`. */
|
|
1571
|
-
quotedAmount: string;
|
|
1572
|
-
/** True when the solver's balance, not the quote, binds `advertisedSize`. */
|
|
1573
|
-
resized: boolean;
|
|
1574
|
-
expiresAt: string;
|
|
1575
|
-
acceptedSources: string[];
|
|
1576
|
-
}
|
|
1577
|
-
interface OrderbookLevelQuery {
|
|
1578
|
-
side: "BID" | "ASK";
|
|
1579
|
-
fillChain: string;
|
|
1580
|
-
priceBucket: string;
|
|
1581
|
-
sourceChain?: string;
|
|
1582
|
-
}
|
|
1583
|
-
interface OrderbookFilters {
|
|
1584
|
-
sourceChain?: string;
|
|
1585
|
-
fillChain?: string;
|
|
1586
|
-
}
|
|
1587
|
-
interface TokenMinSize {
|
|
1588
|
-
symbol: string;
|
|
1589
|
-
size: string;
|
|
1590
|
-
}
|
|
1591
|
-
interface ServerInfo {
|
|
1592
|
-
minOrderTtlSecs: number;
|
|
1593
|
-
heartbeatIntervalSecs: number;
|
|
1594
|
-
signatureSkewSecs: number;
|
|
1595
|
-
maxBatchSize: number;
|
|
1596
|
-
minOrderSizes: TokenMinSize[];
|
|
1597
|
-
/**
|
|
1598
|
-
* Every chain the orderbook serves, by state machine id: the chains orders
|
|
1599
|
-
* fill on, and the source chains they may declare.
|
|
1600
|
-
*/
|
|
1601
|
-
chains: string[];
|
|
1602
|
-
eip712DomainName: string;
|
|
1603
|
-
eip712DomainVersion: string;
|
|
1604
|
-
}
|
|
1605
|
-
/** One token on one chain, as the orderbook's own registry has it. */
|
|
1606
|
-
interface ChainToken {
|
|
1607
|
-
symbol: string;
|
|
1608
|
-
/** Its decimals there: USDC and USDT carry 18 on BNB Chain and 6 on the rest. */
|
|
1609
|
-
decimals: number;
|
|
1610
|
-
}
|
|
1611
|
-
/** One chain the orderbook serves, with the tokens it registers on it. */
|
|
1612
|
-
interface ChainInfo {
|
|
1613
|
-
/** State machine id, such as `EVM-8453`. */
|
|
1614
|
-
id: string;
|
|
1615
|
-
name: string;
|
|
1616
|
-
tokens: ChainToken[];
|
|
1617
|
-
}
|
|
1618
|
-
/** `serverInfo`, `books` and `chains` together, which is how simplex reads them. */
|
|
1619
|
-
interface OrderbookLimits {
|
|
1620
|
-
serverInfo: ServerInfo;
|
|
1621
|
-
books: Book[];
|
|
1622
|
-
chains: ChainInfo[];
|
|
1623
|
-
}
|
|
1624
|
-
interface PostedOrder {
|
|
1625
|
-
commitment: HexString;
|
|
1626
|
-
side: "BID" | "ASK";
|
|
1627
|
-
status: "ACTIVE" | "SUSPENDED";
|
|
1628
|
-
price: string;
|
|
1629
|
-
quotedAmount: string;
|
|
1630
|
-
advertisedSize: string;
|
|
1631
|
-
expiresAt: string;
|
|
1632
|
-
acceptedSources: string[];
|
|
1633
|
-
/** The balance, not the quote, is what binds `advertisedSize`. */
|
|
1634
|
-
resized?: boolean;
|
|
1635
|
-
/**
|
|
1636
|
-
* Whether the solver's balance covers the whole quote. Also false before any
|
|
1637
|
-
* balance has been read, which is why {@link PostedOrder.validatedAt} decides
|
|
1638
|
-
* whether a false here means anything.
|
|
1639
|
-
*/
|
|
1640
|
-
backed?: boolean;
|
|
1641
|
-
/**
|
|
1642
|
-
* The last cycle that read this order's balance, absent until one has. An
|
|
1643
|
-
* order surfaces at its quoted size meanwhile.
|
|
1644
|
-
*/
|
|
1645
|
-
validatedAt?: string | null;
|
|
1646
|
-
}
|
|
1647
|
-
/**
|
|
1648
|
-
* Every code the orderbook's `RejectionCode` enum can send, listed rather than
|
|
1649
|
-
* written as a union so a test can hold it against the published schema.
|
|
1650
|
-
*
|
|
1651
|
-
* Why the orderbook refuses an order. `MIN_ORDER_SIZE`, `TTL_TOO_SHORT` and
|
|
1652
|
-
* `UNSUPPORTED_SOURCE_CHAIN` are prevented by validation before posting, the last
|
|
1653
|
-
* against the chains the server serves and the tokens its registry lists on each;
|
|
1654
|
-
* `REPLAYED` and `ORDER_EXISTS` are answered by bumping the nonce; the rest are
|
|
1655
|
-
* encoding bugs on our side.
|
|
1656
|
-
*/
|
|
1657
|
-
declare const REJECTION_CODES: readonly ["MALFORMED_USER_OP", "NO_FILL_ORDER", "UNSUPPORTED_CHAIN", "UNSUPPORTED_SHAPE", "NOT_PHANTOM", "TTL_TOO_SHORT", "UNSUPPORTED_PAIR", "BAD_SIGNATURE", "BAD_NONCE_BINDING", "REPLAYED", "ORDER_EXISTS", "TOO_MANY_ORDERS", "MIN_ORDER_SIZE", "MISSING_DECLARATION", "EMPTY_DECLARATION", "UNSUPPORTED_SOURCE_CHAIN"];
|
|
1658
|
-
type RejectionCode = (typeof REJECTION_CODES)[number];
|
|
1659
|
-
/**
|
|
1660
|
-
* Why the orderbook could not decide an op at all. Ingest reads no chain, so it
|
|
1661
|
-
* is the database or the submission running out of time, and both are worth
|
|
1662
|
-
* another attempt.
|
|
1663
|
-
*/
|
|
1664
|
-
declare const FAILURE_CODES: readonly ["DATABASE_UNAVAILABLE", "TIMEOUT"];
|
|
1665
|
-
type FailureCode = (typeof FAILURE_CODES)[number];
|
|
1666
|
-
type SubmitOrderResult = {
|
|
1667
|
-
kind: "accepted";
|
|
1668
|
-
order: PostedOrder;
|
|
1669
|
-
surfaced: boolean;
|
|
1670
|
-
} | {
|
|
1671
|
-
kind: "unchanged";
|
|
1672
|
-
order: PostedOrder;
|
|
1673
|
-
} | {
|
|
1674
|
-
kind: "rejected";
|
|
1675
|
-
code: RejectionCode;
|
|
1676
|
-
message: string;
|
|
1677
|
-
} | {
|
|
1678
|
-
kind: "failed";
|
|
1679
|
-
code: FailureCode | "REQUEST_FAILED";
|
|
1680
|
-
message: string;
|
|
1681
|
-
retryable: boolean;
|
|
1682
|
-
};
|
|
1683
|
-
/** Why a signed message was refused, shared by `cancelOrder` and `heartbeat`. */
|
|
1684
|
-
declare const MESSAGE_REJECTION_CODES: readonly ["BAD_SIGNATURE", "SOLVER_MISMATCH", "SIGNATURE_EXPIRED", "SIGNATURE_REUSED", "UNKNOWN_ORDER", "UNKNOWN_SOLVER"];
|
|
1685
|
-
type MessageRejectionCode = (typeof MESSAGE_REJECTION_CODES)[number];
|
|
1686
|
-
type SolverStatus = "ACTIVE" | "SUSPENDED";
|
|
1687
|
-
type HeartbeatResult = {
|
|
1688
|
-
kind: "accepted";
|
|
1689
|
-
status: SolverStatus;
|
|
1690
|
-
reactivatedOrders: number;
|
|
1691
|
-
heartbeatDueBy: string;
|
|
1692
|
-
} | {
|
|
1693
|
-
kind: "rejected";
|
|
1694
|
-
code: MessageRejectionCode;
|
|
1695
|
-
message: string;
|
|
1696
|
-
};
|
|
1697
|
-
/** One page of the solver's own orders, as reconciliation walks them. */
|
|
1698
|
-
interface PostedOrderPage {
|
|
1699
|
-
orders: PostedOrder[];
|
|
1700
|
-
/** Cursor for the next page, absent on the last one. */
|
|
1701
|
-
cursor?: string;
|
|
1702
|
-
status: SolverStatus;
|
|
1794
|
+
* Estimates the cost of a CCTP transfer
|
|
1795
|
+
*/
|
|
1796
|
+
estimateCctp(options: RebalanceOptions): Promise<EstimateResult>;
|
|
1797
|
+
/**
|
|
1798
|
+
* Retries a failed CCTP transfer
|
|
1799
|
+
*/
|
|
1800
|
+
retrySendCctp(failedResult: BridgeResult): Promise<BridgeResult>;
|
|
1703
1801
|
}
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1802
|
+
|
|
1803
|
+
interface Usdt0TransferResult {
|
|
1804
|
+
success: boolean;
|
|
1805
|
+
txHash: HexString;
|
|
1806
|
+
amountSent: bigint;
|
|
1807
|
+
amountReceived: bigint;
|
|
1808
|
+
nativeFee: bigint;
|
|
1809
|
+
}
|
|
1810
|
+
interface Usdt0EstimateResult {
|
|
1811
|
+
amountSent: bigint;
|
|
1812
|
+
amountReceived: bigint;
|
|
1813
|
+
nativeFee: bigint;
|
|
1814
|
+
minAmount: bigint;
|
|
1815
|
+
maxAmount: bigint;
|
|
1711
1816
|
}
|
|
1817
|
+
|
|
1712
1818
|
/**
|
|
1713
|
-
*
|
|
1714
|
-
*
|
|
1715
|
-
*
|
|
1819
|
+
* Options for rebalancing transfers (CCTP, USDT0, or CEX).
|
|
1820
|
+
* - For CCTP/USDT0: coin is implicit (CCTP=USDC, USDT0=USDT), recipientAddress is optional
|
|
1821
|
+
* - For unified router/CEX: coin is required for routing, recipientAddress is ignored
|
|
1716
1822
|
*/
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1823
|
+
interface RebalanceOptions {
|
|
1824
|
+
/** Amount in human-readable format (e.g., "100.00") */
|
|
1825
|
+
amount: string;
|
|
1826
|
+
/** Source chain in state machine format (e.g., "EVM-137") */
|
|
1827
|
+
source: string;
|
|
1828
|
+
/** Destination chain in state machine format (e.g., "EVM-42161") */
|
|
1829
|
+
destination: string;
|
|
1830
|
+
/** Optional recipient address (defaults to sender's address) - only used for CCTP/USDT0, ignored for CEX */
|
|
1831
|
+
recipientAddress?: HexString;
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* UnifiedRebalanceOptions is kept for broader compatibility.
|
|
1835
|
+
*/
|
|
1836
|
+
type UnifiedRebalanceOptions = RebalanceOptions & {
|
|
1837
|
+
coin: "USDC" | "USDT";
|
|
1720
1838
|
};
|
|
1721
1839
|
|
|
1722
1840
|
/**
|
|
1723
|
-
*
|
|
1724
|
-
*
|
|
1725
|
-
* Stateless apart from the endpoint and timeout. Every method either returns the
|
|
1726
|
-
* orderbook's own answer, including its refusals, or throws
|
|
1727
|
-
* {@link OrderbookRequestError} because it could not get one.
|
|
1841
|
+
* Represents a planned transfer from one chain to another for portfolio-level rebalancing.
|
|
1728
1842
|
*/
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1843
|
+
interface PlannedTransfer {
|
|
1844
|
+
sourceChain: string;
|
|
1845
|
+
destChain: string;
|
|
1846
|
+
coin: "USDC" | "USDT";
|
|
1847
|
+
amount: string;
|
|
1848
|
+
}
|
|
1849
|
+
/**
|
|
1850
|
+
* Result of checking portfolio rebalancing triggers.
|
|
1851
|
+
*/
|
|
1852
|
+
interface TriggerCheckResult {
|
|
1853
|
+
triggered: boolean;
|
|
1854
|
+
triggeredChains: Array<{
|
|
1855
|
+
chain: string;
|
|
1856
|
+
asset: "USDC" | "USDT";
|
|
1857
|
+
deficit: number;
|
|
1858
|
+
}>;
|
|
1859
|
+
}
|
|
1860
|
+
/**
|
|
1861
|
+
* Result of a portfolio rebalancing operation.
|
|
1862
|
+
*/
|
|
1863
|
+
interface RebalancingResult {
|
|
1864
|
+
success: boolean;
|
|
1865
|
+
transfers: PlannedTransfer[];
|
|
1866
|
+
executedTransfers: Array<{
|
|
1867
|
+
transfer: PlannedTransfer;
|
|
1868
|
+
result: unknown;
|
|
1869
|
+
}>;
|
|
1870
|
+
errors?: string[];
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* RebalancingService - Facade over CCTP, USDT0, and Binance CEX rebalancers.
|
|
1874
|
+
* Provides both low-level methods (sendCctp, sendUsdt0, sendViaCex) and a high-level router (rebalance).
|
|
1875
|
+
*/
|
|
1876
|
+
declare class RebalancingService {
|
|
1877
|
+
private readonly chainClientManager;
|
|
1878
|
+
private readonly configService;
|
|
1879
|
+
private readonly walletAddress;
|
|
1880
|
+
private readonly cctpRebalancer;
|
|
1881
|
+
private readonly usdt0Rebalancer;
|
|
1882
|
+
private readonly binanceRebalancer?;
|
|
1883
|
+
private readonly logger;
|
|
1884
|
+
constructor(chainClientManager: ChainClientManager, configService: FillerConfigService, binanceConfig?: BinanceCexConfig);
|
|
1885
|
+
sendCctp(options: RebalanceOptions): Promise<_circle_fin_bridge_kit.BridgeResult>;
|
|
1886
|
+
estimateCctp(options: RebalanceOptions): Promise<_circle_fin_bridge_kit.EstimateResult>;
|
|
1887
|
+
retrySendCctp(failedResult: Awaited<ReturnType<CctpRebalancer["sendCctp"]>>): Promise<_circle_fin_bridge_kit.BridgeResult>;
|
|
1888
|
+
sendUsdt0(options: RebalanceOptions): Promise<Usdt0TransferResult>;
|
|
1889
|
+
estimateUsdt0(options: RebalanceOptions): Promise<Usdt0EstimateResult>;
|
|
1890
|
+
sendViaCex(options: UnifiedRebalanceOptions): Promise<CexRebalanceResult>;
|
|
1891
|
+
estimateCexRebalance(options: UnifiedRebalanceOptions): Promise<CexRebalanceEstimate>;
|
|
1739
1892
|
/**
|
|
1740
|
-
*
|
|
1741
|
-
*
|
|
1742
|
-
* Null when the book does not exist.
|
|
1893
|
+
* Execute a single cross-chain transfer, selecting the best route (CCTP / USDT0 / CEX).
|
|
1894
|
+
* Requires coin to be specified for routing decisions.
|
|
1743
1895
|
*/
|
|
1744
|
-
|
|
1745
|
-
submitOrder(userOp: HexString): Promise<SubmitOrderResult>;
|
|
1896
|
+
rebalance(options: UnifiedRebalanceOptions): Promise<Awaited<ReturnType<CctpRebalancer["sendCctp"]>> | Usdt0TransferResult | CexRebalanceResult>;
|
|
1746
1897
|
/**
|
|
1747
|
-
*
|
|
1748
|
-
*
|
|
1749
|
-
* What tells `ORDER_EXISTS` from `REPLAYED`: the first means a live entry is
|
|
1750
|
-
* already sitting there, and posting again on a new nonce would put a second
|
|
1751
|
-
* one behind the same liability.
|
|
1898
|
+
* Check if any chains/assets have triggered portfolio rebalancing thresholds.
|
|
1752
1899
|
*/
|
|
1753
|
-
|
|
1754
|
-
cancelOrder(params: {
|
|
1755
|
-
solver: HexString;
|
|
1756
|
-
commitment: HexString;
|
|
1757
|
-
timestamp: number;
|
|
1758
|
-
signature: HexString;
|
|
1759
|
-
}): Promise<CancelOrderResult>;
|
|
1760
|
-
heartbeat(params: {
|
|
1761
|
-
solver: HexString;
|
|
1762
|
-
timestamp: number;
|
|
1763
|
-
signature: HexString;
|
|
1764
|
-
}): Promise<HeartbeatResult>;
|
|
1900
|
+
checkRebalanceTriggers(): Promise<TriggerCheckResult>;
|
|
1765
1901
|
/**
|
|
1766
|
-
*
|
|
1767
|
-
*
|
|
1768
|
-
* A solver the orderbook has never accepted an order from is not an error:
|
|
1769
|
-
* it answers with no solver at all, which reads here as an empty page.
|
|
1902
|
+
* Plan portfolio-level rebalancing transfers for triggered chains using greedy matching.
|
|
1770
1903
|
*/
|
|
1771
|
-
|
|
1772
|
-
|
|
1904
|
+
planPortfolioRebalancing(triggeredChains: TriggerCheckResult["triggeredChains"]): Promise<PlannedTransfer[]>;
|
|
1905
|
+
/**
|
|
1906
|
+
* Plan transfers for a specific asset using greedy surplus–deficit matching.
|
|
1907
|
+
*/
|
|
1908
|
+
private planTransfersForAsset;
|
|
1909
|
+
/**
|
|
1910
|
+
* Execute planned portfolio-level transfers via this service.
|
|
1911
|
+
*/
|
|
1912
|
+
executePortfolioRebalancing(transfers: PlannedTransfer[]): Promise<RebalancingResult>;
|
|
1913
|
+
/**
|
|
1914
|
+
* High-level portfolio rebalance:
|
|
1915
|
+
* 1) Check triggers
|
|
1916
|
+
* 2) Plan transfers
|
|
1917
|
+
* 3) Execute transfers
|
|
1918
|
+
*/
|
|
1919
|
+
rebalancePortfolio(): Promise<RebalancingResult>;
|
|
1920
|
+
/**
|
|
1921
|
+
* Get current balance for a token on a chain.
|
|
1922
|
+
* Returns balance in normalized USD value (treating token as $1).
|
|
1923
|
+
*/
|
|
1924
|
+
private getCurrentBalance;
|
|
1925
|
+
estimate(options: UnifiedRebalanceOptions): Promise<{
|
|
1926
|
+
method: "cctp";
|
|
1927
|
+
estimate: Awaited<ReturnType<CctpRebalancer["estimateCctp"]>>;
|
|
1928
|
+
} | {
|
|
1929
|
+
method: "usdt0";
|
|
1930
|
+
estimate: Usdt0EstimateResult;
|
|
1931
|
+
} | {
|
|
1932
|
+
method: "cex";
|
|
1933
|
+
estimate: CexRebalanceEstimate;
|
|
1934
|
+
}>;
|
|
1773
1935
|
}
|
|
1774
1936
|
|
|
1775
1937
|
/**
|
|
@@ -1809,8 +1971,9 @@ interface CreateLimitOrderRequest {
|
|
|
1809
1971
|
}
|
|
1810
1972
|
/**
|
|
1811
1973
|
* What the service reports about an order nobody asked it about: a fill worked it
|
|
1812
|
-
* down,
|
|
1813
|
-
*
|
|
1974
|
+
* down, took it under the dust floor, it outlived its `expiresAt` and was
|
|
1975
|
+
* retired, or the orderbook refused its posting. Operator-initiated changes are
|
|
1976
|
+
* reported by the controller that took the request.
|
|
1814
1977
|
*/
|
|
1815
1978
|
type LimitOrderEvent = {
|
|
1816
1979
|
kind: "resized";
|
|
@@ -1819,6 +1982,12 @@ type LimitOrderEvent = {
|
|
|
1819
1982
|
} | {
|
|
1820
1983
|
kind: "filled";
|
|
1821
1984
|
order: LimitOrder;
|
|
1985
|
+
} | {
|
|
1986
|
+
kind: "expired";
|
|
1987
|
+
order: LimitOrder;
|
|
1988
|
+
} | {
|
|
1989
|
+
kind: "rejected";
|
|
1990
|
+
order: LimitOrder;
|
|
1822
1991
|
};
|
|
1823
1992
|
/**
|
|
1824
1993
|
* What came of an order being created: the orderbook's answer, or `unposted` for
|
|
@@ -1876,6 +2045,11 @@ declare class LimitOrderService {
|
|
|
1876
2045
|
private readonly startingNonce;
|
|
1877
2046
|
/** The configured ERC-4626 vaults, when the operator runs any. */
|
|
1878
2047
|
private readonly vaultBalances?;
|
|
2048
|
+
/**
|
|
2049
|
+
* Whether the filler only watches a chain (`--watch-only`, or `watchOnly` in the config,
|
|
2050
|
+
* globally or for that chain). Live: the operator can flip it while running.
|
|
2051
|
+
*/
|
|
2052
|
+
private readonly isWatchOnly?;
|
|
1879
2053
|
private logger;
|
|
1880
2054
|
private cachedLimits?;
|
|
1881
2055
|
private onEvent?;
|
|
@@ -1885,7 +2059,12 @@ declare class LimitOrderService {
|
|
|
1885
2059
|
/** Where a new order's nonce starts; tests pin it, production draws it at random. */
|
|
1886
2060
|
startingNonce?: () => bigint,
|
|
1887
2061
|
/** The configured ERC-4626 vaults, when the operator runs any. */
|
|
1888
|
-
vaultBalances?: VaultHoldings | undefined
|
|
2062
|
+
vaultBalances?: VaultHoldings | undefined,
|
|
2063
|
+
/**
|
|
2064
|
+
* Whether the filler only watches a chain (`--watch-only`, or `watchOnly` in the config,
|
|
2065
|
+
* globally or for that chain). Live: the operator can flip it while running.
|
|
2066
|
+
*/
|
|
2067
|
+
isWatchOnly?: ((chain: string) => boolean) | undefined);
|
|
1889
2068
|
/**
|
|
1890
2069
|
* Attaches the listener fill-driven changes are reported to. `Simplex` does
|
|
1891
2070
|
* this after boot, the same way the filler is handed the service itself.
|
|
@@ -1970,7 +2149,7 @@ declare class LimitOrderService {
|
|
|
1970
2149
|
* balance between them. Whichever order fills first draws the inventory down,
|
|
1971
2150
|
* and the rest are cut to what is left. Netting them here would refuse the
|
|
1972
2151
|
* second side of every book. Vault positions are counted the same way: the
|
|
1973
|
-
* whole position
|
|
2152
|
+
* whole position.
|
|
1974
2153
|
*/
|
|
1975
2154
|
private assertWalletCanPay;
|
|
1976
2155
|
/**
|
|
@@ -1981,28 +2160,19 @@ declare class LimitOrderService {
|
|
|
1981
2160
|
* filler might have managed rather than accepting one it could not.
|
|
1982
2161
|
*/
|
|
1983
2162
|
private vaultHoldings;
|
|
1984
|
-
/**
|
|
1985
|
-
* Works a limit order down by what a fill delivered, and puts the rest back on
|
|
1986
|
-
* the orderbook.
|
|
1987
|
-
*
|
|
1988
|
-
* The order is moved to `resizing` and its new size written before the
|
|
1989
|
-
* orderbook is touched, so a crash mid-way leaves a row that says what it was
|
|
1990
|
-
* doing rather than one that silently advertises output it has already paid.
|
|
1991
|
-
*
|
|
1992
|
-
* The old entry is cancelled before the new one is posted. Two live entries
|
|
1993
|
-
* for one liability would advertise the same output twice, and the gap between
|
|
1994
|
-
* the two calls is at most one request.
|
|
1995
|
-
*/
|
|
1996
|
-
settleFill(id: string, delivered: bigint): Promise<LimitOrder | null>;
|
|
1997
2163
|
/**
|
|
1998
2164
|
* Puts an order that has already been worked down back on the book, or closes
|
|
1999
2165
|
* it when what is left is under the orderbook's dust floor for what it pays.
|
|
2000
2166
|
*
|
|
2001
|
-
*
|
|
2002
|
-
*
|
|
2003
|
-
*
|
|
2167
|
+
* The order is moved to `resizing` before the orderbook is touched, so a crash
|
|
2168
|
+
* mid-way leaves a row that says what it was doing rather than one that silently
|
|
2169
|
+
* advertises output it has already paid. The old entry is cancelled before the
|
|
2170
|
+
* new one is posted: two live entries for one liability would advertise the same
|
|
2171
|
+
* output twice, and the gap between the two calls is at most one request.
|
|
2004
2172
|
*/
|
|
2005
2173
|
resize(remaining: LimitOrder, delivered: bigint): Promise<LimitOrder | null>;
|
|
2174
|
+
/** Takes an order that has been worked down past the dust floor off the book and closes the row. */
|
|
2175
|
+
private closeFilled;
|
|
2006
2176
|
/**
|
|
2007
2177
|
* Cancels the current posting and puts the order back at its present size.
|
|
2008
2178
|
*
|
|
@@ -2011,6 +2181,13 @@ declare class LimitOrderService {
|
|
|
2011
2181
|
* thing: whatever the order has left, live on the book again.
|
|
2012
2182
|
*/
|
|
2013
2183
|
repost(order: LimitOrder | null): Promise<LimitOrder | null>;
|
|
2184
|
+
/**
|
|
2185
|
+
* The order at the size the chain's tally allows, ready to post: lowered in the store
|
|
2186
|
+
* when the tally leaves it less than it holds, and closed when what is left is under
|
|
2187
|
+
* the dust floor (answering null). A tally that cannot be read leaves the size alone,
|
|
2188
|
+
* and the periodic tally pass follows up.
|
|
2189
|
+
*/
|
|
2190
|
+
private lowerBeforePosting;
|
|
2014
2191
|
/** A listener that throws is the listener's problem, not the fill's. */
|
|
2015
2192
|
private report;
|
|
2016
2193
|
/**
|
|
@@ -2042,9 +2219,10 @@ declare class LimitOrderService {
|
|
|
2042
2219
|
*
|
|
2043
2220
|
* The row is read again and claimed out of `open` first: a fill can have worked
|
|
2044
2221
|
* it down or started its own repost since reconciliation listed it, and that
|
|
2045
|
-
* write is the one to follow. A fill that lands once the claim is taken
|
|
2046
|
-
*
|
|
2047
|
-
*
|
|
2222
|
+
* write is the one to follow. A fill that lands once the claim is taken cannot
|
|
2223
|
+
* sync the row, which is `resizing`; the repost lowers the order to the chain's
|
|
2224
|
+
* tally before it posts, and `resize` waits for this to finish. The EntryPoint
|
|
2225
|
+
* is only written with a posting that landed, so a pass cut short anywhere leaves a row the next pass still
|
|
2048
2226
|
* reads as stale, or as having no entry, and finishes the job.
|
|
2049
2227
|
*/
|
|
2050
2228
|
private resign;
|
|
@@ -2054,15 +2232,40 @@ declare class LimitOrderService {
|
|
|
2054
2232
|
* pay for it, and puts the order back on the book at that size.
|
|
2055
2233
|
*
|
|
2056
2234
|
* The account tallies each order's payouts on the fill chain and refuses a fill
|
|
2057
|
-
* that would take the tally past the order's size.
|
|
2058
|
-
*
|
|
2059
|
-
*
|
|
2060
|
-
* the store changes nothing: `remaining` is
|
|
2235
|
+
* that would take the tally past the order's size. Settlement brings an order
|
|
2236
|
+
* down to its tally after each fill; this pass catches what that missed: a sync
|
|
2237
|
+
* that failed, a chain read that did not yet show the fill, a store restored
|
|
2238
|
+
* from an older copy. A tally behind the store changes nothing: `remaining` is
|
|
2239
|
+
* never raised.
|
|
2061
2240
|
*
|
|
2062
2241
|
* Answers how many orders were lowered.
|
|
2063
2242
|
*/
|
|
2064
2243
|
reconcileTallies(): Promise<number>;
|
|
2065
|
-
/**
|
|
2244
|
+
/**
|
|
2245
|
+
* Brings one order's `remaining` down to its on-chain tally and puts it back on
|
|
2246
|
+
* the book at that size, or closes it under the dust floor: what
|
|
2247
|
+
* {@link reconcileTallies} does for every open order.
|
|
2248
|
+
*
|
|
2249
|
+
* The tally is read at `blockNumber` when given: a fill passes the block it landed
|
|
2250
|
+
* in, so an endpoint lagging behind it cannot answer with the tally from before the
|
|
2251
|
+
* fill. The periodic pass reads the latest block.
|
|
2252
|
+
*
|
|
2253
|
+
* The read falls back to the latest block when the pinned one fails.
|
|
2254
|
+
*
|
|
2255
|
+
* Answers whether the order was lowered. False when it is not `open` (also when a
|
|
2256
|
+
* repost takes it between the check and the write), or when the tally leaves it where it is, including a chain that has not yet counted a
|
|
2257
|
+
* fill and a tally that cannot be read (logged by the read). Throws when the chain
|
|
2258
|
+
* cannot be read for the token's decimals, or the store or orderbook fail;
|
|
2259
|
+
* settlement catches that and the periodic pass follows up.
|
|
2260
|
+
*/
|
|
2261
|
+
syncToChain(id: string, blockNumber?: bigint): Promise<boolean>;
|
|
2262
|
+
private lowerToTally;
|
|
2263
|
+
/**
|
|
2264
|
+
* The order as the store now holds it when its tally lowered it, null when it was left alone.
|
|
2265
|
+
*
|
|
2266
|
+
* `only` is the statuses the row may hold for the clamp to apply, so a row that moved to
|
|
2267
|
+
* another between the caller's read and this write is not touched.
|
|
2268
|
+
*/
|
|
2066
2269
|
private clampToTally;
|
|
2067
2270
|
/**
|
|
2068
2271
|
* Withdraws every order that has outlived the operator's own `expiresAt`.
|
|
@@ -2074,7 +2277,13 @@ declare class LimitOrderService {
|
|
|
2074
2277
|
* reaches its TTL.
|
|
2075
2278
|
*/
|
|
2076
2279
|
expireStale(now?: Date): Promise<number>;
|
|
2077
|
-
/**
|
|
2280
|
+
/**
|
|
2281
|
+
* Takes an expired order off the book and closes the row, and reports it so the bids
|
|
2282
|
+
* it priced, which would otherwise still pay out at its price, are retracted.
|
|
2283
|
+
*
|
|
2284
|
+
* Guarded like every other posting write: an order the operator cancelled, or a fill
|
|
2285
|
+
* closed, while the entry was coming down keeps that status and is not reported here.
|
|
2286
|
+
*/
|
|
2078
2287
|
private retire;
|
|
2079
2288
|
/** Every order that has a posting on the book, or should have one. */
|
|
2080
2289
|
private live;
|
|
@@ -2137,20 +2346,55 @@ declare class IntentFiller {
|
|
|
2137
2346
|
* built from this same store, so it cannot exist before the filler does.
|
|
2138
2347
|
*/
|
|
2139
2348
|
private limitOrderService?;
|
|
2349
|
+
/**
|
|
2350
|
+
* Set after construction, like the service: the orderbook every bid is posted to, beside
|
|
2351
|
+
* Hyperbridge. Absent only in tests that bid on Hyperbridge alone.
|
|
2352
|
+
*/
|
|
2353
|
+
private orderbookClient?;
|
|
2354
|
+
/**
|
|
2355
|
+
* Whether the Hyperbridge account can pay for a bid, read once the connection is up. A bid
|
|
2356
|
+
* the account cannot pay for goes to the orderbook alone.
|
|
2357
|
+
*/
|
|
2358
|
+
private bridgeBalance?;
|
|
2140
2359
|
private retractionQueue;
|
|
2141
2360
|
/**
|
|
2142
2361
|
* Fills are settled one at a time, in the order they were scanned. Several fills of
|
|
2143
|
-
* one order can land in one scan, and each settlement names its bid from the
|
|
2144
|
-
* the previous ones
|
|
2145
|
-
* claim the same one.
|
|
2362
|
+
* one order can land in one scan, and each settlement names its bid from the fills
|
|
2363
|
+
* the previous ones recorded: run side by side, two of them would name the same bid.
|
|
2146
2364
|
*/
|
|
2147
2365
|
private settlementQueue;
|
|
2148
2366
|
private paused;
|
|
2149
2367
|
private stopping;
|
|
2150
2368
|
private pendingRetractions;
|
|
2369
|
+
/**
|
|
2370
|
+
* Orders seen completed on chain, by us or a rival, lower-cased. The bid loop reads it
|
|
2371
|
+
* before each placement, because a bid placed on a completed order can only revert with
|
|
2372
|
+
* `Filled()` and still pays the placement fee and locks a deposit. Capped at
|
|
2373
|
+
* {@link MAX_COMPLETED_ORDERS}, oldest first.
|
|
2374
|
+
*/
|
|
2375
|
+
private completedOrders;
|
|
2151
2376
|
private rebalancingInterval?;
|
|
2152
2377
|
private initialRebalanceTimer?;
|
|
2153
2378
|
private activeRebalances;
|
|
2379
|
+
/**
|
|
2380
|
+
* Chains whose EIP-7702 delegation to the SolverAccount failed at boot.
|
|
2381
|
+
*
|
|
2382
|
+
* The bundler's estimate injects the SolverAccount code by state override, so an
|
|
2383
|
+
* undelegated EOA's bid passes estimation and pays the Hyperbridge bid fees and
|
|
2384
|
+
* deposit for a fill that can never execute. Orders for these chains are skipped
|
|
2385
|
+
* at intake, and a later successful delegation (`enableFills`) clears the entry.
|
|
2386
|
+
*
|
|
2387
|
+
* A mark is a belief about the chain, not proof: a delegation transaction that
|
|
2388
|
+
* mines after its receipt timeout, or a `getCode` that failed, leaves the wallet
|
|
2389
|
+
* delegated on chain while the chain stays marked. The dashboard cannot clear it
|
|
2390
|
+
* (its switch reads the chain and shows "Fills enabled"), so intake re-reads the
|
|
2391
|
+
* chain at most once per `DELEGATION_RECHECK_MS` and drops a stale mark.
|
|
2392
|
+
*/
|
|
2393
|
+
private undelegatedChains;
|
|
2394
|
+
/** When each marked chain was last compared with the chain, by `Date.now()`. */
|
|
2395
|
+
private delegationCheckedAt;
|
|
2396
|
+
/** The re-check running now for a chain, so concurrent orders await its answer. */
|
|
2397
|
+
private delegationRechecks;
|
|
2154
2398
|
private retractionSweepInterval?;
|
|
2155
2399
|
private hyperbridge;
|
|
2156
2400
|
private hyperbridgeEndpoint?;
|
|
@@ -2176,6 +2420,11 @@ declare class IntentFiller {
|
|
|
2176
2420
|
*/
|
|
2177
2421
|
/** Hands the filler the service that keeps the orderbook in step with a fill. */
|
|
2178
2422
|
setLimitOrderService(service: LimitOrderService): void;
|
|
2423
|
+
/**
|
|
2424
|
+
* Hands the filler the orderbook its bids are posted to. Every bid goes there; it goes to
|
|
2425
|
+
* Hyperbridge as well when the account holds BRIDGE for the deposit.
|
|
2426
|
+
*/
|
|
2427
|
+
setOrderbook(client: OrderbookClient): void;
|
|
2179
2428
|
/**
|
|
2180
2429
|
* Brings the limit orders' `remaining` in line with their on-chain tallies.
|
|
2181
2430
|
*
|
|
@@ -2198,6 +2447,24 @@ declare class IntentFiller {
|
|
|
2198
2447
|
initialize(): Promise<void>;
|
|
2199
2448
|
/** Chains that both fill and have solver selection active, as state machine ids. */
|
|
2200
2449
|
private solverSelectionChains;
|
|
2450
|
+
private delegation;
|
|
2451
|
+
/**
|
|
2452
|
+
* Whether a marked chain is in fact delegated, and clears the mark when it is.
|
|
2453
|
+
*
|
|
2454
|
+
* Read at most once per `DELEGATION_RECHECK_MS` per chain. Orders arriving while a
|
|
2455
|
+
* read is in flight await its answer rather than being skipped on the old mark: the
|
|
2456
|
+
* read can be the one that clears it. A read that fails counts as not delegated,
|
|
2457
|
+
* the same as at boot.
|
|
2458
|
+
*/
|
|
2459
|
+
private recheckDelegation;
|
|
2460
|
+
/**
|
|
2461
|
+
* Marks a chain undelegated when the wallet is not delegated there. For a chain
|
|
2462
|
+
* that was watch-only at boot: boot skips those, so delegation was never tried or
|
|
2463
|
+
* recorded, and turning watch-only off must not open a chain nothing can fill on.
|
|
2464
|
+
* A chain without solver selection needs no delegation and is left alone. The mark
|
|
2465
|
+
* clears through intake's re-check or `enableFills`.
|
|
2466
|
+
*/
|
|
2467
|
+
guardDelegation(chainId: number): Promise<void>;
|
|
2201
2468
|
/**
|
|
2202
2469
|
* Delegates the filler EOA via EIP-7702 and tops up EntryPoint deposits.
|
|
2203
2470
|
*
|
|
@@ -2268,9 +2535,25 @@ declare class IntentFiller {
|
|
|
2268
2535
|
*/
|
|
2269
2536
|
private checkAndRebalance;
|
|
2270
2537
|
private startRetractionSweep;
|
|
2271
|
-
/** Enqueues retraction for every due bid; returns how many were
|
|
2538
|
+
/** Enqueues retraction for every due bid, one pass per commitment; returns how many bids were due. */
|
|
2272
2539
|
private sweepExpiredBids;
|
|
2273
2540
|
stop(): Promise<void>;
|
|
2541
|
+
/**
|
|
2542
|
+
* Whether the source gateway still holds escrow for every leg of the order:
|
|
2543
|
+
* `"held"`, `"missing"` for a read that came back empty, or `"unverifiable"` when
|
|
2544
|
+
* the read itself failed. The two failures are kept apart because they mean
|
|
2545
|
+
* different things to an operator: a confirmed zero is a phantom or reorged
|
|
2546
|
+
* commitment, while an unreadable escrow is an RPC fault that says nothing about
|
|
2547
|
+
* the order.
|
|
2548
|
+
*
|
|
2549
|
+
* With `quorum`, every leg is read in one `readWithQuorum` call so each
|
|
2550
|
+
* endpoint's vote is the whole escrow vector — an endpoint that disagrees on any
|
|
2551
|
+
* leg fails to join the agreeing group. That is the read used right before
|
|
2552
|
+
* bidding, where one endpoint alone should not vouch for a commitment a source
|
|
2553
|
+
* reorg may have rewritten; a quorum of the endpoints that answer must. Without
|
|
2554
|
+
* it, the legs are read on the single source client, as the pre-bid check has
|
|
2555
|
+
* always done.
|
|
2556
|
+
*/
|
|
2274
2557
|
private verifyOrderOnSource;
|
|
2275
2558
|
private handleNewOrder;
|
|
2276
2559
|
private evaluateOrder;
|
|
@@ -2298,12 +2581,17 @@ declare class IntentFiller {
|
|
|
2298
2581
|
*/
|
|
2299
2582
|
private feeCheckWaived;
|
|
2300
2583
|
private executeOrder;
|
|
2584
|
+
/**
|
|
2585
|
+
* The venues a bid goes to. The orderbook always; Hyperbridge when there is a connection and
|
|
2586
|
+
* the account holds BRIDGE for the deposit, which the gate decides per bid.
|
|
2587
|
+
*/
|
|
2588
|
+
private bidVenues;
|
|
2301
2589
|
private handleOrderFilledOnChain;
|
|
2302
2590
|
/**
|
|
2303
2591
|
* A rival completed an order we bid on. `_filled[commitment]` is now set, so
|
|
2304
2592
|
* every bid of ours on it can only revert with `Filled()`: retract them, which
|
|
2305
|
-
* returns their Hyperbridge deposits
|
|
2306
|
-
*
|
|
2593
|
+
* returns their Hyperbridge deposits now rather than when the stale-bid sweep
|
|
2594
|
+
* reaches them.
|
|
2307
2595
|
*
|
|
2308
2596
|
* Only a complete fill closes the order. After a rival's partial fill our bid
|
|
2309
2597
|
* may still fill the rest, so it is left standing.
|
|
@@ -2313,68 +2601,138 @@ declare class IntentFiller {
|
|
|
2313
2601
|
*/
|
|
2314
2602
|
private handleRivalCompletion;
|
|
2315
2603
|
/**
|
|
2316
|
-
*
|
|
2604
|
+
* Settles a fill of ours against the limit orders that priced our bids on its order.
|
|
2317
2605
|
*
|
|
2318
|
-
* The
|
|
2319
|
-
*
|
|
2320
|
-
* the
|
|
2321
|
-
*
|
|
2606
|
+
* The fill is attributed to one of those bids and recorded against that bid's
|
|
2607
|
+
* limit order, for its history and profit. Then every limit order that priced one
|
|
2608
|
+
* of our bids on the order is brought down to its on-chain tally, which is what
|
|
2609
|
+
* counted the fill: `remaining` follows the chain, not arithmetic here. A partial
|
|
2610
|
+
* fill and a completing one take the same path.
|
|
2322
2611
|
*
|
|
2323
|
-
*
|
|
2324
|
-
*
|
|
2325
|
-
* still available, and both are worse than an order that looks unchanged
|
|
2326
|
-
* until reconciliation notices.
|
|
2612
|
+
* Nothing here throws for a sync that failed or a chain that does not show the fill
|
|
2613
|
+
* yet; the periodic tally reconciliation lowers the order instead.
|
|
2327
2614
|
*/
|
|
2615
|
+
private settleFilledLimitOrder;
|
|
2328
2616
|
/**
|
|
2329
|
-
*
|
|
2617
|
+
* Records the fill against the limit order of the bid it executed.
|
|
2618
|
+
*
|
|
2619
|
+
* A bid that failed outright cannot have executed, and a bid executes at most once,
|
|
2620
|
+
* so one already recorded against this order is passed over. A retracted bid is not:
|
|
2621
|
+
* retraction takes it out of discovery but does not stop a placer that already fetched
|
|
2622
|
+
* it, which can execute it until its `validUntil`. A retracted bid placed longer before
|
|
2623
|
+
* the fill than its validity window cannot have executed and is passed over; the window is
|
|
2624
|
+
* counted back from when the fill happened, not from when it is settled, which can be long
|
|
2625
|
+
* after behind the settlement queue (see `fillTimeMs`). The
|
|
2626
|
+
* same fill delivered twice, which a scanner replaying from a cursor can do, is recorded
|
|
2627
|
+
* once: a fill is named by its transaction hash and log index, since one transaction can
|
|
2628
|
+
* carry several of our fills.
|
|
2330
2629
|
*
|
|
2331
|
-
*
|
|
2332
|
-
*
|
|
2333
|
-
*
|
|
2334
|
-
*
|
|
2630
|
+
* Deduplication is weaker where those are missing. A fill with no transaction hash
|
|
2631
|
+
* cannot be named, and a bid row with no `bid` identifier cannot be told from the
|
|
2632
|
+
* others on its swap, so a replay of either may be recorded again. Only rows from
|
|
2633
|
+
* before bids carried an identifier and logs that carried no hash are affected.
|
|
2634
|
+
*
|
|
2635
|
+
* A multi-leg swap can be priced by limit orders that pay different tokens, so
|
|
2636
|
+
* the delivery is read per limit order and only bids whose order pays a token the
|
|
2637
|
+
* fill delivered are candidates. The fill is attributed by the escrow it released
|
|
2638
|
+
* (see `executedPricing`): a retracted bid at a better rate must not take the fill from a
|
|
2639
|
+
* live bid whose take covers that escrow, so retracted bids are attributed only when no
|
|
2640
|
+
* live bid could have been it. A live bid the escrow rules out does not hide a retracted
|
|
2641
|
+
* one that covers it.
|
|
2335
2642
|
*/
|
|
2336
|
-
private
|
|
2337
|
-
|
|
2338
|
-
|
|
2643
|
+
private recordExecutedFill;
|
|
2644
|
+
/**
|
|
2645
|
+
* Retracts the bids of a limit order the fill left closed (filled, cancelled or expired),
|
|
2646
|
+
* which can no longer pay out at its price. While the order is live its other bids are
|
|
2647
|
+
* left to the chain: `debitOrder` refuses a fill past its budget, and the gas of such a
|
|
2648
|
+
* revert is the accepted cost of not holding anything locally. Never throws.
|
|
2649
|
+
*/
|
|
2650
|
+
private retractBidsOfClosedLimitOrder;
|
|
2651
|
+
/**
|
|
2652
|
+
* How long after it is stored a retracted bid may still execute, in milliseconds:
|
|
2653
|
+
* `bidValiditySeconds` plus `BID_DISCOVERY_PAD_SECONDS`, the window the bid is signed for,
|
|
2654
|
+
* counted from the row (written after the head that window was counted from was read),
|
|
2655
|
+
* plus `BID_PERMIT_SKEW_SECONDS`.
|
|
2656
|
+
*
|
|
2657
|
+
* The skew is the same execution tail the bid's Permit2 deadline allows: a bid can execute
|
|
2658
|
+
* until its permit deadline, which is this window plus that skew. `validUntil` is block-based
|
|
2659
|
+
* and the window is converted to blocks at the fastest block time seen, so a slower chain
|
|
2660
|
+
* keeps a bid executable longer in wall-clock time, and the fill is seen only after its block
|
|
2661
|
+
* is scanned.
|
|
2662
|
+
*/
|
|
2663
|
+
private retractedBidWindowMs;
|
|
2664
|
+
/**
|
|
2665
|
+
* When a fill happened, in milliseconds: the timestamp of the block it landed in.
|
|
2666
|
+
*
|
|
2667
|
+
* The event's arrival time is only a stand-in. After downtime or a scanner catch-up a
|
|
2668
|
+
* fill arrives long after it landed, and measuring a retracted bid's window from the
|
|
2669
|
+
* arrival would put every such bid outside it. The arrival time is used when the block
|
|
2670
|
+
* is unknown (`undefined`, or the `0n` a scanner substitutes) or cannot be read.
|
|
2671
|
+
*/
|
|
2672
|
+
private fillTimeMs;
|
|
2339
2673
|
/**
|
|
2340
|
-
*
|
|
2341
|
-
*
|
|
2342
|
-
* fill names it, then claimed by its bid identifier, so the other bids keep their
|
|
2343
|
-
* holds and can still fill the rest. A fill that names none of what our limit
|
|
2344
|
-
* orders pay claims nothing.
|
|
2674
|
+
* Brings one limit order down to its on-chain tally after a fill, logging rather than throwing.
|
|
2675
|
+
* The tally is read at the fill's block, so a lagging endpoint cannot return the tally from before it.
|
|
2345
2676
|
*/
|
|
2346
|
-
private
|
|
2677
|
+
private syncLimitOrder;
|
|
2347
2678
|
/**
|
|
2348
2679
|
* What this fill delivered of the token the limit order pays, or null when the
|
|
2349
2680
|
* fill names none of it.
|
|
2350
2681
|
*/
|
|
2351
2682
|
private deliveredAgainst;
|
|
2352
2683
|
/**
|
|
2353
|
-
*
|
|
2684
|
+
* Whether a limit order can still stand behind a bid at its price: `open`, or `resizing`
|
|
2685
|
+
* while a repost holds it. False once it is filled, cancelled, expired or rejected, or is
|
|
2686
|
+
* gone. Undefined when the store cannot be read, which a caller placing a bid treats as
|
|
2687
|
+
* unconfirmed and one retracting treats as nothing to do.
|
|
2688
|
+
*/
|
|
2689
|
+
private limitOrderStands;
|
|
2690
|
+
private markCompleted;
|
|
2691
|
+
private hasCompleted;
|
|
2692
|
+
/**
|
|
2693
|
+
* Retracts the live bids a limit order priced, on every commitment they sit on.
|
|
2694
|
+
*
|
|
2695
|
+
* Called once the order can no longer stand behind them: the operator cancelled it, it
|
|
2696
|
+
* expired, or a fill left it filled or closed. Each such bid would still pay out at a
|
|
2697
|
+
* price the order no longer offers. Only the rows this order priced are retracted, so
|
|
2698
|
+
* another limit order's bid on the same swap order keeps standing, and a bid a pass
|
|
2699
|
+
* cannot close is flagged `dead` by row only.
|
|
2700
|
+
*
|
|
2701
|
+
* Retraction does not make the bids unexecutable: a placer that already fetched one can
|
|
2702
|
+
* execute it until its `validUntil`. A bid that does is settled by provenance like any
|
|
2703
|
+
* other fill, and the order's budget stays on chain. This only returns the deposit and
|
|
2704
|
+
* takes the bid out of discovery.
|
|
2354
2705
|
*
|
|
2355
|
-
*
|
|
2356
|
-
*
|
|
2357
|
-
* a fill releases nothing here.
|
|
2706
|
+
* Never throws: it runs after a settlement, a cancel or an expiry that has already
|
|
2707
|
+
* happened, and a bid it misses is still retracted by the stale-bid sweep.
|
|
2358
2708
|
*/
|
|
2709
|
+
retractBidsForLimitOrder(limitOrderId: string): Promise<void>;
|
|
2359
2710
|
/**
|
|
2360
|
-
*
|
|
2361
|
-
*
|
|
2711
|
+
* Queues a retraction of this filler's live bids on a commitment: all of them, or only
|
|
2712
|
+
* those named by bid identifier (`bids`) or by row (`rows`).
|
|
2713
|
+
*
|
|
2714
|
+
* A retraction takes the bid out of Hyperbridge's discovery and returns its deposit. It
|
|
2715
|
+
* does not stop a placer that already fetched the bid, which can still execute it until
|
|
2716
|
+
* its `validUntil` (`bidValiditySeconds` plus the pad), so it narrows the exposure and
|
|
2717
|
+
* `bidValiditySeconds` remains the hard bound on it.
|
|
2362
2718
|
*/
|
|
2363
|
-
private releaseReservation;
|
|
2364
2719
|
private enqueueRetraction;
|
|
2365
2720
|
/**
|
|
2366
|
-
* Retracts
|
|
2367
|
-
*
|
|
2721
|
+
* Retracts the given bid rows on a commitment, by the identifiers recorded when each was
|
|
2722
|
+
* placed, and answers which rows each outcome closed.
|
|
2368
2723
|
*
|
|
2369
2724
|
* The identifiers come from the bid rows rather than from Hyperbridge's storage: a bid whose
|
|
2370
2725
|
* `place_bid` is still in the pool is not in storage yet, and reading storage would find
|
|
2371
2726
|
* nothing and abandon its deposit once it lands. Its retraction goes out after it from the same
|
|
2372
2727
|
* account, so it lands after it and reclaims it.
|
|
2373
2728
|
*
|
|
2374
|
-
*
|
|
2375
|
-
*
|
|
2376
|
-
*
|
|
2377
|
-
*
|
|
2729
|
+
* A retraction that succeeded closes its rows with its hash. `BidNotFound` is terminal, not
|
|
2730
|
+
* retryable: bids only leave the pallet by retraction, so "no bid" means there is nothing
|
|
2731
|
+
* left to reclaim, and its rows close without one. A legacy row with no identifier closes the
|
|
2732
|
+
* same way. A failure leaves its rows open for a retry, and so does a retraction still in
|
|
2733
|
+
* Hyperbridge's pool: resubmitting can only bounce off it (1014), and if it lands the next
|
|
2734
|
+
* attempt's `BidNotFound` closes the row. A pooled one also stops the pass, since the
|
|
2735
|
+
* account's next extrinsic queues behind it; the bids after it stay open too.
|
|
2378
2736
|
*/
|
|
2379
2737
|
private retractStoredBids;
|
|
2380
2738
|
}
|
|
@@ -2384,8 +2742,6 @@ interface FillerRuntime {
|
|
|
2384
2742
|
intentFiller: IntentFiller;
|
|
2385
2743
|
balanceProvider: BalanceProvider;
|
|
2386
2744
|
vaultVenue?: VaultFundingPlanner;
|
|
2387
|
-
/** Self-halt visibility/reset for the trading engine (overfill protection). */
|
|
2388
|
-
haltControls: HaltControl[];
|
|
2389
2745
|
/** Live order-activity bridge; emits `event` per stored row. */
|
|
2390
2746
|
activity: ActivityRecorder;
|
|
2391
2747
|
/** The persistence backend this filler was started with. */
|
|
@@ -2509,9 +2865,14 @@ interface SimplexOptions {
|
|
|
2509
2865
|
}
|
|
2510
2866
|
/** Events a running filler emits. */
|
|
2511
2867
|
interface SimplexEvents {
|
|
2868
|
+
/**
|
|
2869
|
+
* `blockHash` is the block the scanner read the placement from; a cross-chain
|
|
2870
|
+
* order is only filled while a quorum still places its transaction there.
|
|
2871
|
+
*/
|
|
2512
2872
|
"order:detected": {
|
|
2513
2873
|
order: Order;
|
|
2514
2874
|
transactionHash: string;
|
|
2875
|
+
blockHash: string;
|
|
2515
2876
|
};
|
|
2516
2877
|
"order:skipped": {
|
|
2517
2878
|
orderId: string;
|
|
@@ -2606,7 +2967,6 @@ interface ChainInput {
|
|
|
2606
2967
|
}
|
|
2607
2968
|
interface SimplexStatus {
|
|
2608
2969
|
paused: boolean;
|
|
2609
|
-
halted: boolean;
|
|
2610
2970
|
/** The solver's EVM account — the same value as `simplex.address`. */
|
|
2611
2971
|
address: HexString;
|
|
2612
2972
|
startedAt: number;
|
|
@@ -2630,7 +2990,7 @@ declare class LimitOrderController {
|
|
|
2630
2990
|
list(filter?: LimitOrderFilter): Promise<LimitOrder[]>;
|
|
2631
2991
|
get(id: string): Promise<LimitOrder | null>;
|
|
2632
2992
|
/**
|
|
2633
|
-
* One limit order with its fills and the bids
|
|
2993
|
+
* One limit order with its fills and the bids it priced, newest first.
|
|
2634
2994
|
*
|
|
2635
2995
|
* What makes `remaining` explicable: a size that shrank is the sum of the fills
|
|
2636
2996
|
* behind it, and the operator can see which ones. Fills are recorded when they
|
|
@@ -2729,7 +3089,17 @@ declare class ChainController {
|
|
|
2729
3089
|
* lacks the gateway fee token or the native the paymaster's one-time setup needs.
|
|
2730
3090
|
*/
|
|
2731
3091
|
enableFills(chainId: number): Promise<void>;
|
|
2732
|
-
/**
|
|
3092
|
+
/**
|
|
3093
|
+
* Writes watch-only edits back into the config. A global boolean is left alone —
|
|
3094
|
+
* expanding it per chain changes how the config validates.
|
|
3095
|
+
*
|
|
3096
|
+
* `changed` is the chain just added, removed or toggled, and its new value. It only
|
|
3097
|
+
* matters under the `--watch-only` override: there the in-memory snapshot marks every
|
|
3098
|
+
* chain, and writing it back would make one run permanent for every later run.
|
|
3099
|
+
* Instead only the edited chain is applied — its key deleted when it stops being
|
|
3100
|
+
* watch-only, kept as an explicit flag otherwise — so the override itself never lands
|
|
3101
|
+
* in the file and a later override-free run sees what it would have anyway.
|
|
3102
|
+
*/
|
|
2733
3103
|
private syncWatchOnlyToConfig;
|
|
2734
3104
|
}
|
|
2735
3105
|
/** ERC-4626 treasury vaults the filler sources fills from and sweeps into. */
|
|
@@ -2866,12 +3236,6 @@ declare class Simplex extends EventEmitter {
|
|
|
2866
3236
|
* deposits still locked in the solver-selection pallet.
|
|
2867
3237
|
*/
|
|
2868
3238
|
bidStats(): Promise<BidStats>;
|
|
2869
|
-
/**
|
|
2870
|
-
* Whether overfill protection has self-halted the engine. A halted filler
|
|
2871
|
-
* refuses every order until {@link resetHalt}.
|
|
2872
|
-
*/
|
|
2873
|
-
isHalted(): boolean;
|
|
2874
|
-
resetHalt(): void;
|
|
2875
3239
|
/** Restricts which order `user` addresses are processed. Omit to accept all. */
|
|
2876
3240
|
setAllowlist(allowlist: AllowlistConfig | undefined): Promise<void>;
|
|
2877
3241
|
setLogLevel(level: LogLevel): void;
|