@hyperbridge/simplex 0.18.1 → 0.18.3
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 +4311 -1541
- package/dist/bin/simplex.js.map +1 -1
- package/dist/index.cjs +7273 -4705
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1199 -812
- package/dist/index.d.ts +1199 -812
- package/dist/index.js +7311 -4737
- 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-BqOM_gBm.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
|
@@ -113,12 +113,6 @@ interface RebalancingConfig$1 {
|
|
|
113
113
|
USDT?: Record<string, string>;
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
|
-
interface OverfillProtectionConfig {
|
|
117
|
-
/** Ceiling bps above user-requested output; filler clamps its computed output to this. Default 500 (5%). */
|
|
118
|
-
maxOverfillBps?: number;
|
|
119
|
-
/** Consecutive clamped evaluations before the strategy halts itself. Default 3. */
|
|
120
|
-
maxConsecutiveClamps?: number;
|
|
121
|
-
}
|
|
122
116
|
interface AllowlistConfig {
|
|
123
117
|
/** Hex addresses eligible across all chains. */
|
|
124
118
|
users?: string[];
|
|
@@ -153,10 +147,10 @@ interface FillerConfig {
|
|
|
153
147
|
*/
|
|
154
148
|
minOrderSizeUsd?: number;
|
|
155
149
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
150
|
+
* Smallest payout, in USD, a partial fill may bid. Defaults to 20. Set to 0 to
|
|
151
|
+
* bid whatever can be filled. See `minPartialFillUsd` in filler-toml.
|
|
158
152
|
*/
|
|
159
|
-
|
|
153
|
+
minPartialFillUsd?: number;
|
|
160
154
|
/**
|
|
161
155
|
* Restricts which order `user` addresses the filler processes. When omitted, all
|
|
162
156
|
* users are accepted. When present, only listed users (global ∪ per-source) are
|
|
@@ -341,10 +335,11 @@ declare class FillerConfigService {
|
|
|
341
335
|
* Defaults to 20. An order at or above it is filled whatever fees it carries.
|
|
342
336
|
*/
|
|
343
337
|
getMinOrderSizeUsd(): number;
|
|
344
|
-
/**
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
338
|
+
/**
|
|
339
|
+
* The smallest payout, in USD, a partial fill may bid. Defaults to 20. `0` bids
|
|
340
|
+
* whatever can be filled. Full fills are not checked.
|
|
341
|
+
*/
|
|
342
|
+
getMinPartialFillUsd(): number;
|
|
348
343
|
}
|
|
349
344
|
|
|
350
345
|
/**
|
|
@@ -369,9 +364,10 @@ interface QuorumBudget {
|
|
|
369
364
|
}
|
|
370
365
|
/**
|
|
371
366
|
* Wraps multiple viem `PublicClient`s — one per configured RPC URL — and runs
|
|
372
|
-
* selected read paths (`getLogs`, `getBlockNumber`, `
|
|
373
|
-
* as a **BFT quorum**: a result is
|
|
374
|
-
* `m` endpoints that answered agree
|
|
367
|
+
* selected read paths (`getLogs`, `getBlockNumber`, `getTransactionInclusion` /
|
|
368
|
+
* `getTransactionConfirmations`, `readWithQuorum`) as a **BFT quorum**: a result is
|
|
369
|
+
* accepted only when `quorumThreshold(m)` of the `m` endpoints that answered agree
|
|
370
|
+
* on it.
|
|
375
371
|
*
|
|
376
372
|
* A provider that *answers with divergent data* is never special-cased away — it
|
|
377
373
|
* simply fails to join the agreeing group, which is what makes a lying or reorged
|
|
@@ -477,22 +473,46 @@ declare class QuorumPublicClient {
|
|
|
477
473
|
*/
|
|
478
474
|
getBlockNumber(): Promise<bigint>;
|
|
479
475
|
/**
|
|
480
|
-
*
|
|
476
|
+
* The inclusion a quorum of endpoints agreed on for a transaction, and its depth.
|
|
481
477
|
*
|
|
482
478
|
* Every endpoint is asked for the receipt and its head. A "receipt not found"
|
|
483
479
|
* answer is a valid **no** vote — the endpoint is responsive but does not see
|
|
484
480
|
* the transaction (not yet propagated, or reorged out) — so it counts toward
|
|
485
|
-
* responsiveness but joins no inclusion group. The
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
* reorged/fabricated receipt can never reach the quorum.
|
|
481
|
+
* responsiveness but joins no inclusion group. The block is reported only when a
|
|
482
|
+
* quorum agrees on the same `(blockHash, blockNumber)`; the depth is then the
|
|
483
|
+
* quorum head of that agreeing group. A minority still serving a
|
|
484
|
+
* reorged/fabricated receipt can never reach the quorum. Returning the block as
|
|
485
|
+
* well as the depth lets a caller bind the count to the block it read the event
|
|
486
|
+
* from: a placement re-mined elsewhere keeps its transaction hash but not its
|
|
487
|
+
* block, and not the commitment built from it.
|
|
489
488
|
*
|
|
490
489
|
* Throws {@link QuorumError} when no inclusion reaches the quorum — including
|
|
491
490
|
* the ordinary window where the tx is not yet mined on enough endpoints.
|
|
492
491
|
*/
|
|
492
|
+
getTransactionInclusion({ hash }: {
|
|
493
|
+
hash: Hash;
|
|
494
|
+
}): Promise<TransactionInclusion>;
|
|
495
|
+
/**
|
|
496
|
+
* Confirmation count for a transaction under the quorum. See
|
|
497
|
+
* {@link getTransactionInclusion}, whose depth this is.
|
|
498
|
+
*/
|
|
493
499
|
getTransactionConfirmations({ hash }: {
|
|
494
500
|
hash: Hash;
|
|
495
501
|
}): Promise<bigint>;
|
|
502
|
+
/**
|
|
503
|
+
* Runs an arbitrary read on every endpoint and returns the value a quorum
|
|
504
|
+
* agrees on. The `read` callback is the whole vote: one endpoint's answer is
|
|
505
|
+
* whatever its callback resolves to, so a caller that reads a vector of slots
|
|
506
|
+
* (e.g. every leg's escrow) votes on the vector, not on each slot separately.
|
|
507
|
+
* Values are compared under `JSON.stringify(..., bigIntReplacer)`, so bigints
|
|
508
|
+
* and arrays compare by value rather than by identity.
|
|
509
|
+
*
|
|
510
|
+
* An endpoint whose `read` throws does not vote — the class's rule for every
|
|
511
|
+
* quorum path. A quorum-meeting group is unique, so the first satisfiable
|
|
512
|
+
* agreement is final. Fails with {@link QuorumError} when no value reaches the
|
|
513
|
+
* bar, naming `label`.
|
|
514
|
+
*/
|
|
515
|
+
readWithQuorum<T>(label: string, read: (client: PublicClient) => Promise<T>): Promise<T>;
|
|
496
516
|
/**
|
|
497
517
|
* Fetches logs from every endpoint in parallel and returns the result once a
|
|
498
518
|
* quorum agrees. Fails with {@link QuorumError} otherwise.
|
|
@@ -510,6 +530,12 @@ declare class QuorumPublicClient {
|
|
|
510
530
|
private describeResponders;
|
|
511
531
|
private formatFailures;
|
|
512
532
|
}
|
|
533
|
+
/** The inclusion a quorum of endpoints agreed on for a transaction, and its depth. */
|
|
534
|
+
interface TransactionInclusion {
|
|
535
|
+
blockHash: string;
|
|
536
|
+
blockNumber: bigint;
|
|
537
|
+
confirmations: bigint;
|
|
538
|
+
}
|
|
513
539
|
|
|
514
540
|
/**
|
|
515
541
|
* The signing contract a solver runs on, and the config shapes the bundled
|
|
@@ -755,93 +781,6 @@ declare class ChainClientManager {
|
|
|
755
781
|
};
|
|
756
782
|
}
|
|
757
783
|
|
|
758
|
-
/**
|
|
759
|
-
* Raw EIP-7702 authorization, as produced by the delegation flow. Attached to the
|
|
760
|
-
* bundler UserOp so a not-yet-delegated EOA can be delegated in the same op.
|
|
761
|
-
*/
|
|
762
|
-
interface Eip7702Authorization {
|
|
763
|
-
chainId: number;
|
|
764
|
-
address: HexString;
|
|
765
|
-
nonce: number;
|
|
766
|
-
r: HexString;
|
|
767
|
-
s: HexString;
|
|
768
|
-
yParity: number;
|
|
769
|
-
}
|
|
770
|
-
interface UserOpGasLimits {
|
|
771
|
-
verificationGasLimit: bigint;
|
|
772
|
-
callGasLimit: bigint;
|
|
773
|
-
preVerificationGas: bigint;
|
|
774
|
-
}
|
|
775
|
-
interface SponsoredUserOpRequest {
|
|
776
|
-
chain: string;
|
|
777
|
-
/** ERC-7821 batch (or "0x" for a no-op, e.g. delegation). */
|
|
778
|
-
callData: HexString;
|
|
779
|
-
/**
|
|
780
|
-
* Attach when the EOA still needs delegating in this op. Pass a factory rather
|
|
781
|
-
* than a pre-signed tuple: building paymaster data can send an approve tx from
|
|
782
|
-
* the authority EOA (the Simplex bootstrap approve to Permit2), and an authorization signed before
|
|
783
|
-
* that tx embeds a stale nonce the bundler will reject. The factory runs only
|
|
784
|
-
* after paymaster data is built.
|
|
785
|
-
*/
|
|
786
|
-
eip7702Auth?: Eip7702Authorization | (() => Promise<Eip7702Authorization>);
|
|
787
|
-
/** EntryPoint nonce key. Defaults to 0. */
|
|
788
|
-
nonceKey?: bigint;
|
|
789
|
-
/**
|
|
790
|
-
* Explicit gas limits. Provide them to skip bundler estimation — required for
|
|
791
|
-
* the not-yet-delegated EIP-7702 case, where the account has no code to
|
|
792
|
-
* simulate so estimation is unreliable. When omitted, limits are estimated.
|
|
793
|
-
*/
|
|
794
|
-
gas?: UserOpGasLimits;
|
|
795
|
-
/**
|
|
796
|
-
* Lets the paymaster fall back to an EIP-2612 permit when the fee token has no
|
|
797
|
-
* Permit2 allowance yet. Only a first-time delegation sets this — it carries the
|
|
798
|
-
* `approve(Permit2, max)` in its own callData, so the permit buys the one op that
|
|
799
|
-
* makes every later Permit2 op possible without native.
|
|
800
|
-
*/
|
|
801
|
-
permitBootstrap?: boolean;
|
|
802
|
-
}
|
|
803
|
-
/**
|
|
804
|
-
* Submits self-initiated, paymaster-sponsored UserOperations through the bundler,
|
|
805
|
-
* so the solver pays gas in stablecoins rather than native token. Shared by the
|
|
806
|
-
* delegation setup and the vault sweep/redeem paths.
|
|
807
|
-
*
|
|
808
|
-
* Submission contract (so callers can safely fall back to a native tx without
|
|
809
|
-
* risking a double-execution):
|
|
810
|
-
* - Returns `null` when the op was **never submitted** — paymaster/bundler not
|
|
811
|
-
* configured, insufficient USDC, preparation failed (approve tx or signing), or
|
|
812
|
-
* the bundler rejected `eth_sendUserOperation` outright (it never entered the
|
|
813
|
-
* mempool). The caller may fall back to native.
|
|
814
|
-
* - Returns `{ txHash }` once a receipt is observed.
|
|
815
|
-
* - **Throws** only when the op **was submitted** but no receipt arrived. The
|
|
816
|
-
* caller must NOT fall back (the op may still land) — retry on the next cycle.
|
|
817
|
-
*/
|
|
818
|
-
declare class UserOpSender {
|
|
819
|
-
private readonly clientManager;
|
|
820
|
-
private readonly configService;
|
|
821
|
-
private readonly signer;
|
|
822
|
-
private logger;
|
|
823
|
-
constructor(clientManager: ChainClientManager, configService: FillerConfigService, signer: Signer);
|
|
824
|
-
/** True when a sponsored UserOp is even possible on this chain (paymaster + bundler configured). */
|
|
825
|
-
canSponsor(chain: string): boolean;
|
|
826
|
-
trySendSponsored(req: SponsoredUserOpRequest): Promise<{
|
|
827
|
-
txHash: HexString;
|
|
828
|
-
} | null>;
|
|
829
|
-
/**
|
|
830
|
-
* Estimates account gas limits via the bundler. The op is signed first so the
|
|
831
|
-
* estimation simulation passes the account's ECDSA validation. Falls back to
|
|
832
|
-
* generous constants when the bundler estimate is unavailable.
|
|
833
|
-
*/
|
|
834
|
-
private estimateGas;
|
|
835
|
-
private buildSignedUserOp;
|
|
836
|
-
/**
|
|
837
|
-
* Prices the op for the rundler bundler, as the fill path does: its suggested fees, or the
|
|
838
|
-
* chain's gas price raised to the priority fee it requires where it suggests none.
|
|
839
|
-
*/
|
|
840
|
-
private getGasPrice;
|
|
841
|
-
private sendBundlerRpc;
|
|
842
|
-
private waitForUserOpReceipt;
|
|
843
|
-
}
|
|
844
|
-
|
|
845
784
|
/**
|
|
846
785
|
* Service for managing EIP-7702 delegation of the filler's EOA to the SolverAccount contract.
|
|
847
786
|
* This enables the filler to participate in solver selection mode.
|
|
@@ -866,8 +805,18 @@ declare class DelegationService {
|
|
|
866
805
|
private readonly userOpSender;
|
|
867
806
|
constructor(clientManager: ChainClientManager, configService: FillerConfigService, signer: Signer);
|
|
868
807
|
/**
|
|
869
|
-
*
|
|
870
|
-
*
|
|
808
|
+
* Signs the authorization tuple and reports the nonce a direct set-code tx must carry.
|
|
809
|
+
*
|
|
810
|
+
* The tx nonce and the tuple nonce are two different counters, and the tuple's is the
|
|
811
|
+
* one *after* the tx's: EIP-7702 compares the tuple's nonce against the authority's
|
|
812
|
+
* nonce once the tx has bumped it. A direct tx therefore reads `pending` — what viem
|
|
813
|
+
* would fill anyway — and signs the tuple at `nonce + 1`. Reading `latest` instead
|
|
814
|
+
* signs one too low whenever an EOA tx is in flight, and a mismatched tuple is skipped
|
|
815
|
+
* without reverting: the receipt reads success while the account stays undelegated.
|
|
816
|
+
*
|
|
817
|
+
* @param viaBundler When true, the bundler submits the tx, so the tuple uses the
|
|
818
|
+
* authority's current nonce. When false, the EOA sends the type-0x04
|
|
819
|
+
* tx itself and the tuple is signed at that tx's nonce + 1.
|
|
871
820
|
*/
|
|
872
821
|
private buildAuthorization;
|
|
873
822
|
private sendDelegationTransaction;
|
|
@@ -879,8 +828,27 @@ declare class DelegationService {
|
|
|
879
828
|
private resolvePendingPermit2Approval;
|
|
880
829
|
/**
|
|
881
830
|
* Checks if the filler's EOA is already delegated to the SolverAccount contract on a specific chain.
|
|
831
|
+
*
|
|
832
|
+
* Best-effort: callers retry, so a read failure answers "not delegated".
|
|
882
833
|
*/
|
|
883
834
|
isDelegated(chain: string): Promise<boolean>;
|
|
835
|
+
/**
|
|
836
|
+
* Whether the EOA's code is the EIP-7702 delegation to the configured SolverAccount.
|
|
837
|
+
*
|
|
838
|
+
* A `blockNumber` makes this a claim about one mined block, so a read failure throws
|
|
839
|
+
* rather than answering "not delegated"; `confirmDelegationAt` turns that into "not
|
|
840
|
+
* confirmed". Without one it is a best-effort check, and `isDelegated` swallows a
|
|
841
|
+
* read failure to false.
|
|
842
|
+
*/
|
|
843
|
+
private readDelegation;
|
|
844
|
+
/**
|
|
845
|
+
* Confirms the delegation at the block a tx mined in. A failed read of that one block is
|
|
846
|
+
* not a verdict, so the wallet's delegation at `latest` decides instead: a delegation that
|
|
847
|
+
* landed is not reported as failed because a node could not serve a historical `getCode`.
|
|
848
|
+
* `isDelegated` answers false when `latest` cannot be read either, which is "not confirmed",
|
|
849
|
+
* never a pass.
|
|
850
|
+
*/
|
|
851
|
+
private confirmDelegationAt;
|
|
884
852
|
/**
|
|
885
853
|
* Sets up EIP-7702 delegation via the bundler. Uses the Simplex paymaster when
|
|
886
854
|
* configured and the filler holds a sufficient stablecoin balance.
|
|
@@ -891,8 +859,46 @@ declare class DelegationService {
|
|
|
891
859
|
* paymaster for PERMIT mode: the permit covers this op's gas, and the op installs
|
|
892
860
|
* the allowance every later op authorizes against. That is the whole zero-native
|
|
893
861
|
* bootstrap — one sponsored op, after which the account never needs a permit again.
|
|
862
|
+
*
|
|
863
|
+
* Returns an outcome rather than a boolean because only "unavailable" may fall back to
|
|
864
|
+
* a native tx: once the op reached the bundler it may still land, and a native retry
|
|
865
|
+
* alongside it would delegate twice.
|
|
894
866
|
*/
|
|
895
867
|
private setupDelegationViaBundler;
|
|
868
|
+
/**
|
|
869
|
+
* Resolves the sponsored delegation op an earlier attempt left unconfirmed, before anything
|
|
870
|
+
* new is built on its nonce.
|
|
871
|
+
*
|
|
872
|
+
* - Its receipt is found: the delegation is confirmed on chain.
|
|
873
|
+
* - The EntryPoint nonce at `latest` has moved past the op's and the wallet is not delegated:
|
|
874
|
+
* the nonce was consumed without delegating, so the op is gone.
|
|
875
|
+
* - The nonce has not moved, but the bundler definitely no longer holds the op and it is past
|
|
876
|
+
* the grace period (see {@link DelegationService.bundlerDroppedOp}): it was dropped, so "gone".
|
|
877
|
+
* - Anything else, including a lookup or read that failed: still unresolved, so "pending".
|
|
878
|
+
* The op may land, and a replacement or a native delegation alongside it would double up.
|
|
879
|
+
*/
|
|
880
|
+
private resolveUnconfirmedOp;
|
|
881
|
+
/**
|
|
882
|
+
* Whether the bundler has definitely dropped an unconfirmed delegation op. Rundler's
|
|
883
|
+
* `eth_getUserOperationByHash` checks its mempool and then the chain, so a definite `null`
|
|
884
|
+
* means the op is neither pooled nor landed. That only counts once the op is older than
|
|
885
|
+
* {@link UNCONFIRMED_OP_GRACE_MS}, so a lookup racing the bundler's own indexing is not read
|
|
886
|
+
* as a drop, and a failed or ambiguous lookup is not an answer at all.
|
|
887
|
+
*
|
|
888
|
+
* A wrong "gone" costs at most one set-code transaction's gas: once a native set-code tx
|
|
889
|
+
* lands it consumes the EOA nonce the old op's 7702 authorization was signed for, so the
|
|
890
|
+
* old op can no longer delegate. And "gone" only falls through to the normal setup, which
|
|
891
|
+
* tries a sponsored op first.
|
|
892
|
+
*/
|
|
893
|
+
private bundlerDroppedOp;
|
|
894
|
+
/**
|
|
895
|
+
* Confirms the delegation at the block a sponsored op's transaction mined in. The public
|
|
896
|
+
* RPC can lag the bundler's, so the receipt is waited for, bounded by
|
|
897
|
+
* {@link BUNDLER_RECEIPT_WAIT_TIMEOUT_MS}. A receipt that cannot be read is not evidence
|
|
898
|
+
* either way, so the wallet's delegation at `latest` decides instead: a delegation that
|
|
899
|
+
* landed is not reported as failed because the receipt wait timed out.
|
|
900
|
+
*/
|
|
901
|
+
private confirmBundlerDelegation;
|
|
896
902
|
/**
|
|
897
903
|
* Installs `approve(Permit2, max)` on an account that is ALREADY delegated, using the same
|
|
898
904
|
* permit-funded op the first-time delegation carries — minus the authorization, which it
|
|
@@ -923,8 +929,25 @@ declare class DelegationService {
|
|
|
923
929
|
*
|
|
924
930
|
* With nothing pending — the allowance is already in place — the bundler path goes
|
|
925
931
|
* first as usual. A plain direct tx is the last fallback in every case.
|
|
932
|
+
*
|
|
933
|
+
* One operation runs per wallet and chain at a time. Two services delegate the same
|
|
934
|
+
* wallet (the filler's and the limit-order service's, see
|
|
935
|
+
* `inFlightDelegationByWallet`), so a second call joins the attempt already in flight
|
|
936
|
+
* instead of sending a competing op.
|
|
926
937
|
*/
|
|
927
938
|
setupDelegation(chain: string): Promise<boolean>;
|
|
939
|
+
/** The key every per-wallet, per-chain delegation map shares. */
|
|
940
|
+
private walletKey;
|
|
941
|
+
/**
|
|
942
|
+
* Runs one delegation operation under the per-wallet/chain lock.
|
|
943
|
+
*
|
|
944
|
+
* A second call of the same operation joins the one in flight (they would do the same
|
|
945
|
+
* thing). A different operation — a revoke during a setup — queues behind it so the
|
|
946
|
+
* two never overlap, but still runs: returning the other operation's result would
|
|
947
|
+
* report a revoke that never happened.
|
|
948
|
+
*/
|
|
949
|
+
private withDelegationLock;
|
|
950
|
+
private setupDelegationOnce;
|
|
928
951
|
/** Whether the EOA can pay for one direct set-code tx at the current gas price. */
|
|
929
952
|
private nativeCoversDirectTx;
|
|
930
953
|
/**
|
|
@@ -942,9 +965,180 @@ declare class DelegationService {
|
|
|
942
965
|
results: Record<string, boolean>;
|
|
943
966
|
}>;
|
|
944
967
|
/**
|
|
945
|
-
* Revokes delegation by delegating to the zero address
|
|
968
|
+
* Revokes delegation by delegating to the zero address, under the same per-wallet/chain
|
|
969
|
+
* lock setupDelegation uses so a revoke and a setup cannot overlap.
|
|
946
970
|
*/
|
|
947
971
|
revokeDelegation(chain: string): Promise<boolean>;
|
|
972
|
+
private revokeDelegationOnce;
|
|
973
|
+
/** Confirms the EOA's code is empty at the block a revoke tx mined in. */
|
|
974
|
+
private confirmRevokedAt;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/** A sponsored UserOp the bundler accepted but had no receipt for. */
|
|
978
|
+
interface SubmittedUserOp {
|
|
979
|
+
kind: "userOp";
|
|
980
|
+
userOpHash: HexString;
|
|
981
|
+
/** The EntryPoint nonce and nonce key the op was signed with, for a later `getNonce` check. */
|
|
982
|
+
nonce: bigint;
|
|
983
|
+
nonceKey: bigint;
|
|
984
|
+
/**
|
|
985
|
+
* Whether the paymaster attached a validity deadline. A Permit2-mode op does, so once its
|
|
986
|
+
* permit deadline has passed it can no longer land; a PERMIT bootstrap op does not, so it can
|
|
987
|
+
* land any time until its EntryPoint nonce is consumed.
|
|
988
|
+
*/
|
|
989
|
+
expires: boolean;
|
|
990
|
+
/** When the bundler accepted the op, in ms. */
|
|
991
|
+
submittedAt: number;
|
|
992
|
+
}
|
|
993
|
+
/** A native transaction the node accepted but that got no receipt within the wait. */
|
|
994
|
+
interface SubmittedTx {
|
|
995
|
+
kind: "tx";
|
|
996
|
+
txHash: HexString;
|
|
997
|
+
/**
|
|
998
|
+
* The wallet nonce the tx was sent with. A node or mempool that no longer lists the tx proves
|
|
999
|
+
* nothing; the wallet's nonce moving past this one does.
|
|
1000
|
+
*/
|
|
1001
|
+
nonce: number;
|
|
1002
|
+
/** When the transaction was sent, in ms. */
|
|
1003
|
+
submittedAt: number;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Raw EIP-7702 authorization, as produced by the delegation flow. Attached to the
|
|
1008
|
+
* bundler UserOp so a not-yet-delegated EOA can be delegated in the same op.
|
|
1009
|
+
*/
|
|
1010
|
+
interface Eip7702Authorization {
|
|
1011
|
+
chainId: number;
|
|
1012
|
+
address: HexString;
|
|
1013
|
+
nonce: number;
|
|
1014
|
+
r: HexString;
|
|
1015
|
+
s: HexString;
|
|
1016
|
+
yParity: number;
|
|
1017
|
+
}
|
|
1018
|
+
interface UserOpGasLimits {
|
|
1019
|
+
verificationGasLimit: bigint;
|
|
1020
|
+
callGasLimit: bigint;
|
|
1021
|
+
preVerificationGas: bigint;
|
|
1022
|
+
}
|
|
1023
|
+
interface SponsoredUserOpRequest {
|
|
1024
|
+
chain: string;
|
|
1025
|
+
/** ERC-7821 batch (or "0x" for a no-op, e.g. delegation). */
|
|
1026
|
+
callData: HexString;
|
|
1027
|
+
/**
|
|
1028
|
+
* Attach when the EOA still needs delegating in this op. Pass a factory rather
|
|
1029
|
+
* than a pre-signed tuple: building paymaster data can send an approve tx from
|
|
1030
|
+
* the authority EOA (the Simplex bootstrap approve to Permit2), and an authorization signed before
|
|
1031
|
+
* that tx embeds a stale nonce the bundler will reject. The factory runs only
|
|
1032
|
+
* after paymaster data is built.
|
|
1033
|
+
*/
|
|
1034
|
+
eip7702Auth?: Eip7702Authorization | (() => Promise<Eip7702Authorization>);
|
|
1035
|
+
/** EntryPoint nonce key. Defaults to 0. */
|
|
1036
|
+
nonceKey?: bigint;
|
|
1037
|
+
/**
|
|
1038
|
+
* Explicit gas limits. Provide them to skip bundler estimation — required for
|
|
1039
|
+
* the not-yet-delegated EIP-7702 case, where the account has no code to
|
|
1040
|
+
* simulate so estimation is unreliable. When omitted, limits are estimated.
|
|
1041
|
+
*/
|
|
1042
|
+
gas?: UserOpGasLimits;
|
|
1043
|
+
/**
|
|
1044
|
+
* Lets the paymaster fall back to an EIP-2612 permit when the fee token has no
|
|
1045
|
+
* Permit2 allowance yet. Only a first-time delegation sets this — it carries the
|
|
1046
|
+
* `approve(Permit2, max)` in its own callData, so the permit buys the one op that
|
|
1047
|
+
* makes every later Permit2 op possible without native.
|
|
1048
|
+
*/
|
|
1049
|
+
permitBootstrap?: boolean;
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Submits self-initiated, paymaster-sponsored UserOperations through the bundler,
|
|
1053
|
+
* so the solver pays gas in stablecoins rather than native token. Shared by the
|
|
1054
|
+
* delegation setup and the vault sweep/redeem paths.
|
|
1055
|
+
*
|
|
1056
|
+
* Submission contract (so callers can safely fall back to a native tx without
|
|
1057
|
+
* risking a double-execution):
|
|
1058
|
+
* - Returns `null` when the op was **never submitted** — paymaster/bundler not
|
|
1059
|
+
* configured, insufficient USDC, preparation failed (approve tx or signing), the
|
|
1060
|
+
* bundler rejected `eth_sendUserOperation` outright, the connection could not be
|
|
1061
|
+
* established, or a post-failure lookup proved the op never entered the pool. The
|
|
1062
|
+
* caller may fall back to native.
|
|
1063
|
+
* - Returns `{ txHash, userOp }` once a receipt is observed.
|
|
1064
|
+
* - **Throws** {@link SubmittedUnconfirmedError} when the op **was submitted** but no
|
|
1065
|
+
* receipt arrived, or when its submission could not be determined at all (the send
|
|
1066
|
+
* response was lost and the lookup could not ask). The caller must NOT fall back (the
|
|
1067
|
+
* op may still land) — retry on the next cycle, and resolve the op's fate later with
|
|
1068
|
+
* {@link lookupUserOpReceipt}.
|
|
1069
|
+
* - **Throws** {@link PendingOpOnNonceError} when the bundler refuses the op because an
|
|
1070
|
+
* earlier op from this sender already holds its EntryPoint nonce ("replacement
|
|
1071
|
+
* underpriced", "already known"). Not a rejection: that earlier op may still land, so
|
|
1072
|
+
* the caller must NOT fall back — retry later.
|
|
1073
|
+
*/
|
|
1074
|
+
declare class UserOpSender {
|
|
1075
|
+
private readonly clientManager;
|
|
1076
|
+
private readonly configService;
|
|
1077
|
+
private readonly signer;
|
|
1078
|
+
private logger;
|
|
1079
|
+
constructor(clientManager: ChainClientManager, configService: FillerConfigService, signer: Signer);
|
|
1080
|
+
/** True when a sponsored UserOp is even possible on this chain (paymaster + bundler configured). */
|
|
1081
|
+
canSponsor(chain: string): boolean;
|
|
1082
|
+
trySendSponsored(req: SponsoredUserOpRequest): Promise<{
|
|
1083
|
+
txHash: HexString;
|
|
1084
|
+
userOp: SubmittedUserOp;
|
|
1085
|
+
} | null>;
|
|
1086
|
+
/**
|
|
1087
|
+
* One `eth_getUserOperationReceipt` for an op this filler submitted. Null when the bundler
|
|
1088
|
+
* does not know it — the op has not been indexed, which is not proof it never landed. Throws
|
|
1089
|
+
* when the bundler could not be asked, so a caller can tell "not found" apart from "couldn't ask".
|
|
1090
|
+
*/
|
|
1091
|
+
lookupUserOpReceipt(chain: string, userOpHash: HexString): Promise<{
|
|
1092
|
+
txHash: HexString;
|
|
1093
|
+
success: boolean;
|
|
1094
|
+
} | null>;
|
|
1095
|
+
/**
|
|
1096
|
+
* Whether the bundler still knows an op this filler submitted. Rundler's
|
|
1097
|
+
* `eth_getUserOperationByHash` checks its mempool and then the chain, so `false` is a definite
|
|
1098
|
+
* `null` answer: the op is neither pooled nor landed. Throws when the bundler could not be
|
|
1099
|
+
* asked or answered ambiguously, so a caller can tell "dropped" apart from "couldn't ask".
|
|
1100
|
+
*/
|
|
1101
|
+
isUserOpKnown(chain: string, userOpHash: HexString): Promise<boolean>;
|
|
1102
|
+
/**
|
|
1103
|
+
* Estimates account gas limits via the bundler. The op is signed first so the
|
|
1104
|
+
* estimation simulation passes the account's ECDSA validation. Falls back to
|
|
1105
|
+
* generous constants when the bundler estimate is unavailable.
|
|
1106
|
+
*/
|
|
1107
|
+
private estimateGas;
|
|
1108
|
+
private buildSignedUserOp;
|
|
1109
|
+
/**
|
|
1110
|
+
* Prices the op for the rundler bundler, as the fill path does: its suggested fees, or the
|
|
1111
|
+
* chain's gas price raised to the priority fee it requires where it suggests none.
|
|
1112
|
+
*/
|
|
1113
|
+
private getGasPrice;
|
|
1114
|
+
/**
|
|
1115
|
+
* One bundler JSON-RPC call, used by every request in this class. `timeoutMs` bounds the
|
|
1116
|
+
* request; a failure is thrown as a {@link BundlerCallError} whose `outcome` says whether it
|
|
1117
|
+
* is safe to treat the call as never having reached the bundler — the distinction the send
|
|
1118
|
+
* path relies on to avoid a native resend of an op that may already be submitted.
|
|
1119
|
+
*/
|
|
1120
|
+
private sendBundlerRpc;
|
|
1121
|
+
/**
|
|
1122
|
+
* After an ambiguous `eth_sendUserOperation`, asks the bundler whether it actually holds the
|
|
1123
|
+
* op. Rundler's `eth_getUserOperationByHash` checks its mempool and then the chain, so a
|
|
1124
|
+
* non-null result means the op was accepted; a definite `null` on every attempt means it
|
|
1125
|
+
* never entered the pool.
|
|
1126
|
+
*
|
|
1127
|
+
* `lookupDelaysMs` are inter-attempt waits, so the default `[2_000, 5_000, 10_000]` looks up
|
|
1128
|
+
* at about 2 s, 7 s and 17 s after the failed send.
|
|
1129
|
+
*
|
|
1130
|
+
* Returns `"unknown"` when any attempt failed, because that is not proof of absence: a
|
|
1131
|
+
* bundler still validating the op after our request timed out could add it after the last
|
|
1132
|
+
* attempt, and the widening delays exist to shrink that window. Only `"absent"` — a `null`
|
|
1133
|
+
* from every attempt — lets the caller fall back.
|
|
1134
|
+
*/
|
|
1135
|
+
private findSubmittedOp;
|
|
1136
|
+
/**
|
|
1137
|
+
* Polls for the op's receipt until `deadlineMs` has elapsed, 2 s apart. Time-based so the
|
|
1138
|
+
* wait cannot stretch with the per-poll timeout; `deadlineMs` and `intervalMs` stay
|
|
1139
|
+
* overridable for tests.
|
|
1140
|
+
*/
|
|
1141
|
+
private waitForUserOpReceipt;
|
|
948
1142
|
}
|
|
949
1143
|
|
|
950
1144
|
/** `[simplex.tunnel]` in the config file. */
|
|
@@ -1186,8 +1380,13 @@ interface FillerTomlConfig {
|
|
|
1186
1380
|
queue?: QueueConfig;
|
|
1187
1381
|
logging?: string;
|
|
1188
1382
|
watchOnly?: boolean | Record<string, boolean>;
|
|
1189
|
-
|
|
1190
|
-
|
|
1383
|
+
/**
|
|
1384
|
+
* The Hyperbridge account that signs bid extrinsics and holds BRIDGE for their deposits.
|
|
1385
|
+
* Optional: without it the solver bids on the HyperFX orderbook alone.
|
|
1386
|
+
*/
|
|
1387
|
+
substratePrivateKey?: string;
|
|
1388
|
+
/** The Hyperbridge WebSocket endpoint bids go to. Required when a key is set. */
|
|
1389
|
+
hyperbridgeWsUrl?: string;
|
|
1191
1390
|
/**
|
|
1192
1391
|
* Hyperbridge indexer GraphQL endpoint, used to backfill order details on
|
|
1193
1392
|
* activity rows recorded before they were captured. Defaults per network
|
|
@@ -1214,16 +1413,14 @@ interface FillerTomlConfig {
|
|
|
1214
1413
|
maxFeePerGasBumpPercent?: number;
|
|
1215
1414
|
};
|
|
1216
1415
|
/**
|
|
1217
|
-
*
|
|
1218
|
-
*
|
|
1219
|
-
*
|
|
1220
|
-
*
|
|
1221
|
-
*
|
|
1416
|
+
* Removed. `[simplex.overfillProtection]` was dropped when the overfill clamp
|
|
1417
|
+
* and the self-halt were taken out. It is no longer read: boot warns when a
|
|
1418
|
+
* config still carries it, and `simplex init` drops it. Not rejected, because
|
|
1419
|
+
* `simplex init` wrote the section uncommented for existing operators, and
|
|
1420
|
+
* refusing it would crash-loop their Docker deployments. Typed `unknown` so
|
|
1421
|
+
* whatever an old file holds still parses.
|
|
1222
1422
|
*/
|
|
1223
|
-
overfillProtection?:
|
|
1224
|
-
maxOverfillBps?: number;
|
|
1225
|
-
maxConsecutiveClamps?: number;
|
|
1226
|
-
};
|
|
1423
|
+
overfillProtection?: unknown;
|
|
1227
1424
|
/**
|
|
1228
1425
|
* How long a signed bid stays executable, in seconds. Defaults to 300 (5 minutes).
|
|
1229
1426
|
*
|
|
@@ -1246,6 +1443,18 @@ interface FillerTomlConfig {
|
|
|
1246
1443
|
* order nothing can put a dollar figure on is treated as below it.
|
|
1247
1444
|
*/
|
|
1248
1445
|
minOrderSizeUsd?: number;
|
|
1446
|
+
/**
|
|
1447
|
+
* The smallest payout, in USD, a partial fill may bid. Defaults to 20.
|
|
1448
|
+
*
|
|
1449
|
+
* A partial fill collects none of the order's fees, and is deliberately exempt from
|
|
1450
|
+
* the fee check and the profit floor: its gas is paid by the margin in the limit
|
|
1451
|
+
* order that prices it. That leaves it with no size floor of its own, so a
|
|
1452
|
+
* near-exhausted limit order, or a wallet just above its gas reserve, used to bid
|
|
1453
|
+
* dust on every matching order — each bid paying fill gas and the relayer fee.
|
|
1454
|
+
* Bids worth less than this are skipped. Set to 0 to bid whatever can be filled.
|
|
1455
|
+
* Full fills are unaffected.
|
|
1456
|
+
*/
|
|
1457
|
+
minPartialFillUsd?: number;
|
|
1249
1458
|
/**
|
|
1250
1459
|
* Remote access: an outbound SSH tunnel to a rendezvous relay so a phone's
|
|
1251
1460
|
* SSH client can reach the local web UI. Off unless `enabled = true`; the
|
|
@@ -1356,13 +1565,34 @@ declare class TokenSender {
|
|
|
1356
1565
|
private readonly userOpSender?;
|
|
1357
1566
|
/** Only needed to size the paymaster's gas reserve; without it a send reserves nothing. */
|
|
1358
1567
|
private readonly configService?;
|
|
1568
|
+
/**
|
|
1569
|
+
* Whether the filler's account is EIP-7702-delegated on a chain. A native multi-call
|
|
1570
|
+
* batch is addressed to the account itself, so an undelegated EOA would accept the
|
|
1571
|
+
* transaction and do nothing; without this check the send is reported as done.
|
|
1572
|
+
*/
|
|
1573
|
+
private readonly isDelegated?;
|
|
1359
1574
|
private readonly logger;
|
|
1360
1575
|
constructor(clientManager: ChainClientManager, solver: HexString,
|
|
1361
1576
|
/** Live view of the configured vaults so runtime vault edits are honored. */
|
|
1362
1577
|
getVaults: () => VaultToml[], userOpSender?: UserOpSender | undefined,
|
|
1363
1578
|
/** Only needed to size the paymaster's gas reserve; without it a send reserves nothing. */
|
|
1364
|
-
configService?: FillerConfigService | undefined
|
|
1579
|
+
configService?: FillerConfigService | undefined,
|
|
1580
|
+
/**
|
|
1581
|
+
* Whether the filler's account is EIP-7702-delegated on a chain. A native multi-call
|
|
1582
|
+
* batch is addressed to the account itself, so an undelegated EOA would accept the
|
|
1583
|
+
* transaction and do nothing; without this check the send is reported as done.
|
|
1584
|
+
*/
|
|
1585
|
+
isDelegated?: ((chain: string) => Promise<boolean>) | undefined);
|
|
1365
1586
|
send(params: SendTokenParams): Promise<SendTokenResult>;
|
|
1587
|
+
/**
|
|
1588
|
+
* Refuses recipients a transfer can never usefully reach. Each is a well-formed address, so
|
|
1589
|
+
* a mistyped or pasted value would otherwise go out: the zero address and a token's own
|
|
1590
|
+
* contract burn or strand the funds, a vault would take the tokens as a donation to its
|
|
1591
|
+
* share holders, and a native or ERC-20 send to the solver itself only spends gas to move
|
|
1592
|
+
* nothing. Vault shares are the exception to the last: they leave as `redeem(shares, to,
|
|
1593
|
+
* solver)`, so sending them to the solver is how an exact amount is withdrawn into the wallet.
|
|
1594
|
+
*/
|
|
1595
|
+
private assertRecipient;
|
|
1366
1596
|
/**
|
|
1367
1597
|
* A `withdraw(shortfall, solver, solver)` call against a configured vault on
|
|
1368
1598
|
* this chain whose underlying is the token being sent and that can cover the
|
|
@@ -1381,13 +1611,33 @@ declare class TokenSender {
|
|
|
1381
1611
|
* reason to refuse a transfer the operator asked for.
|
|
1382
1612
|
*/
|
|
1383
1613
|
private vaultWithdrawalCall;
|
|
1614
|
+
/**
|
|
1615
|
+
* One bundler lookup for an op this sender submitted, for a caller that has to settle whether
|
|
1616
|
+
* a placement landed. Null when the bundler does not know the op; throws when it could not be
|
|
1617
|
+
* asked. See {@link UserOpSender.lookupUserOpReceipt}.
|
|
1618
|
+
*/
|
|
1619
|
+
userOpReceipt(chain: string, userOpHash: HexString): Promise<{
|
|
1620
|
+
txHash: HexString;
|
|
1621
|
+
success: boolean;
|
|
1622
|
+
} | null>;
|
|
1384
1623
|
/**
|
|
1385
1624
|
* Executes a batch from the filler wallet: sponsored UserOp first, native tx
|
|
1386
1625
|
* when no sponsor is available. Shared by every operator-initiated outbound flow.
|
|
1626
|
+
*
|
|
1627
|
+
* `nonceKey` puts the sponsored op on its own EntryPoint nonce lane (default 0). Two ops on one
|
|
1628
|
+
* key read the same `getNonce`, so a caller that can run alongside another key-0 sender passes
|
|
1629
|
+
* its own. It has no effect on the native fallback.
|
|
1630
|
+
*
|
|
1631
|
+
* A `PendingOpOnNonceError` from the sponsored path is not caught: an earlier op from
|
|
1632
|
+
* this wallet is still pending on the nonce and may land, so a native send of the same calls
|
|
1633
|
+
* could pay twice. It reaches the caller, which waits and retries.
|
|
1387
1634
|
*/
|
|
1388
|
-
submitCalls(chain: string, calls: ERC7821Call[]
|
|
1635
|
+
submitCalls(chain: string, calls: ERC7821Call[], opts?: {
|
|
1636
|
+
nonceKey?: bigint;
|
|
1637
|
+
}): Promise<{
|
|
1389
1638
|
txHash: HexString;
|
|
1390
1639
|
sponsored: boolean;
|
|
1640
|
+
submission: SubmittedUserOp | SubmittedTx;
|
|
1391
1641
|
}>;
|
|
1392
1642
|
/**
|
|
1393
1643
|
* The `approve(Permit2, max)` to run first when the wallet has never approved Permit2 for its fee
|
|
@@ -1470,6 +1720,8 @@ interface BridgeTopUpDeps {
|
|
|
1470
1720
|
substratePublicKey: HexString;
|
|
1471
1721
|
/** Coprocessor the order's bids are read from. */
|
|
1472
1722
|
hyperbridge?: Promise<IntentsCoprocessor>;
|
|
1723
|
+
/** Re-reads the filler's BRIDGE balance the moment a delivery lands, for the dashboard. */
|
|
1724
|
+
refreshBridgeBalance?: () => Promise<void>;
|
|
1473
1725
|
loggers?: Parameters<typeof moduleLogger>[0];
|
|
1474
1726
|
}
|
|
1475
1727
|
/**
|
|
@@ -1498,6 +1750,8 @@ declare class BridgeTopUp {
|
|
|
1498
1750
|
* reading its last statuses when the operator starts the next one, which must not wait.
|
|
1499
1751
|
*/
|
|
1500
1752
|
private driving;
|
|
1753
|
+
/** Consecutive failed recovery attempts; reset by recorded progress, an operator restart, a long attempt, and a fresh process. */
|
|
1754
|
+
private reclaimFailures;
|
|
1501
1755
|
constructor(deps: BridgeTopUpDeps);
|
|
1502
1756
|
get bridgeToken(): HexString;
|
|
1503
1757
|
/** Loads the stored top-up and resumes driving it when it was left open. Never rejects. */
|
|
@@ -1510,6 +1764,14 @@ declare class BridgeTopUp {
|
|
|
1510
1764
|
quote(params: BridgeTopUpQuoteParams): Promise<BridgeTopUpQuote>;
|
|
1511
1765
|
/** Re-quotes, then places and drives the order in the background. Returns its state. */
|
|
1512
1766
|
start(params: BridgeTopUpQuoteParams): Promise<BridgeTopUpState>;
|
|
1767
|
+
/**
|
|
1768
|
+
* Throws unless the wallet covers the input and the solver fee, net of the paymaster reserve.
|
|
1769
|
+
* The order goes out with `fees: 0n` and the SDK prices the fee only as it places, in the
|
|
1770
|
+
* host's fee token, which the placement batch then approves alongside the input. A wallet that
|
|
1771
|
+
* covers the input alone would revert inside a sponsored op the paymaster still charges for.
|
|
1772
|
+
* The quote here is for this check only; the SDK still prices the fee it places.
|
|
1773
|
+
*/
|
|
1774
|
+
private assertCanPay;
|
|
1513
1775
|
/** Cancels an unfilled order and refunds its escrowed input to the filler wallet. */
|
|
1514
1776
|
reclaim(): Promise<BridgeTopUpState>;
|
|
1515
1777
|
/**
|
|
@@ -1520,12 +1782,94 @@ declare class BridgeTopUp {
|
|
|
1520
1782
|
*/
|
|
1521
1783
|
private place;
|
|
1522
1784
|
/**
|
|
1523
|
-
* Reads the placement receipt and stores the order as the gateway committed it
|
|
1524
|
-
*
|
|
1785
|
+
* Reads the placement receipt and stores the order as the gateway committed it, from the
|
|
1786
|
+
* `OrderPlaced` log that names this top-up's session key. A UserOp placement's receipt is a
|
|
1787
|
+
* bundle that can carry other users' placements, so the first log is not necessarily ours.
|
|
1788
|
+
*
|
|
1789
|
+
* A mined receipt with no such log, or one that reverted, is settled: the placement is final
|
|
1790
|
+
* and nothing was escrowed, so it is written `failed` and false is returned. A receipt that
|
|
1791
|
+
* cannot be read throws, so the caller retries or falls back to the chain scan.
|
|
1525
1792
|
*/
|
|
1526
1793
|
private recordPlacement;
|
|
1527
|
-
/**
|
|
1794
|
+
/**
|
|
1795
|
+
* Continues a placement whose outcome was never recorded, using every piece of evidence the
|
|
1796
|
+
* chain offers: the tx receipt if there is one, the bundler's receipt for a UserOp, and the
|
|
1797
|
+
* paying chain's own `OrderPlaced` log for this session. It settles the record as failed only
|
|
1798
|
+
* once the batch can no longer land; otherwise it throws so the caller retries.
|
|
1799
|
+
*/
|
|
1528
1800
|
private recoverPlacement;
|
|
1801
|
+
/**
|
|
1802
|
+
* The transaction that placed this order, found on the paying chain rather than from a
|
|
1803
|
+
* receipt: the `OrderPlaced` log whose `session` is this top-up's session key, from the scan
|
|
1804
|
+
* cursor (or the block stored before submission), each an evidence margin lower, up to the latest.
|
|
1805
|
+
* Returns `undefined` when the record predates the scan; a read failure, or a node behind the
|
|
1806
|
+
* range that must be read, throws, so an unread range is never counted as "not found".
|
|
1807
|
+
* `scannedTo` is the height the scan reached, the reference for every later read of the chain.
|
|
1808
|
+
* See {@link scanGatewayEvent} for the margin and the cursor.
|
|
1809
|
+
*/
|
|
1810
|
+
private findPlacementLog;
|
|
1811
|
+
/**
|
|
1812
|
+
* The transaction whose `OrderCancelled` log on the paying chain's gateway names this order,
|
|
1813
|
+
* from the cancel's saved cursor (or a margin below `fromBlock`, the height read before the
|
|
1814
|
+
* cancel was sent) up to the latest block. `cancelOrder` emits it on every cancel that succeeds
|
|
1815
|
+
* and the gateway itself is the emitter, however the cancel was submitted; a cancel that
|
|
1816
|
+
* reverted leaves none. Throws on a read failure, so an unread range is never "not found".
|
|
1817
|
+
*/
|
|
1818
|
+
private findCancelLog;
|
|
1819
|
+
/**
|
|
1820
|
+
* Scans the paying chain's IntentGateway for an event this top-up emitted, in chunks, and
|
|
1821
|
+
* returns the transaction of the first log `isOurs` accepts. A scan starts an evidence margin
|
|
1822
|
+
* below its saved cursor, not at it, so a page a lagging backend served empty is read again;
|
|
1823
|
+
* the first scan starts that margin below the height read before the send, since that height
|
|
1824
|
+
* came from one backend of a load-balanced endpoint that can be ahead of the one that took
|
|
1825
|
+
* the broadcast. The cursor is saved per chunk, so a scan that fails late resumes where it
|
|
1826
|
+
* got to. It trails the tip by the margin and never decides anything on its own: the evidence
|
|
1827
|
+
* was read up to `scannedTo`, the latest block, the reference for every later read of the chain.
|
|
1828
|
+
* A read failure, or a node behind the range that must be read, throws.
|
|
1829
|
+
*/
|
|
1830
|
+
private scanGatewayEvent;
|
|
1831
|
+
/**
|
|
1832
|
+
* Scans a block range in the small chunks public endpoints accept, handing each page to `read`
|
|
1833
|
+
* and stopping at the first page that resolves a value. A failure propagates, so a caller
|
|
1834
|
+
* retries rather than treating an unread range as empty.
|
|
1835
|
+
*/
|
|
1836
|
+
private scanLogs;
|
|
1837
|
+
/**
|
|
1838
|
+
* The paying-chain scan (placement and cancel), in chunks wider than BSC's fill search. A chunk a public endpoint
|
|
1839
|
+
* refuses is halved and retried, down to a floor, before the attempt gives up and the caller
|
|
1840
|
+
* retries. `onChunk` runs after each chunk read without a match. Kept separate from
|
|
1841
|
+
* {@link scanLogs} so the BSC fill search is unchanged.
|
|
1842
|
+
*/
|
|
1843
|
+
private scanPlacementLogs;
|
|
1844
|
+
/**
|
|
1845
|
+
* Settles a placement with no order on chain. "Nothing was escrowed" is written only on
|
|
1846
|
+
* positive evidence that the batch can no longer land, read an evidence margin (see
|
|
1847
|
+
* {@link evidenceMarginBlocks}) below the height the scan covered, so it is asserted against state every backend agrees on:
|
|
1848
|
+
*
|
|
1849
|
+
* - a native tx whose nonce the wallet has moved past: some other tx took that nonce, and had
|
|
1850
|
+
* it been ours the scan would have found its `OrderPlaced`. A node that no longer lists the
|
|
1851
|
+
* tx proves nothing, since one backend or mempool can lack a tx another still holds, so a
|
|
1852
|
+
* tx this record has a nonce for keeps waiting. A legacy record has none: it takes the
|
|
1853
|
+
* nonce of a tx the node still lists, and is settled `failed`, unverified, when the node
|
|
1854
|
+
* does not know the tx, because waiting would block every new top-up for good;
|
|
1855
|
+
* - a UserOp whose EntryPoint nonce was consumed, or whose Permit2 permit expired by the
|
|
1856
|
+
* timestamp of the block that nonce is read at, not by this host's clock.
|
|
1857
|
+
*
|
|
1858
|
+
* A tx hash that came from the bundler's receipt is never settled as a native tx: a bundle
|
|
1859
|
+
* reorged out can be re-bundled under a different hash, so it falls to the UserOp rules (the
|
|
1860
|
+
* scan would find a re-bundled placement). A tx the node reports with a block number has been
|
|
1861
|
+
* mined, so its receipt will be readable. A bootstrap UserOp has no expiry and stays pending
|
|
1862
|
+
* until its nonce moves or its log appears: it could still land. Inconclusive cases throw, so
|
|
1863
|
+
* the caller retries.
|
|
1864
|
+
*/
|
|
1865
|
+
private settleUnplaceable;
|
|
1866
|
+
/**
|
|
1867
|
+
* Whether the order's deadline has passed. The deadline is a block height on the order's
|
|
1868
|
+
* destination (BSC), so it is read there; the gateway rejects a fill only once the height is
|
|
1869
|
+
* strictly past it. An unreadable height is treated as not passed: an order must not be
|
|
1870
|
+
* settled from a read that failed.
|
|
1871
|
+
*/
|
|
1872
|
+
private deadlinePassed;
|
|
1529
1873
|
private resumeDelivery;
|
|
1530
1874
|
private resumeOrder;
|
|
1531
1875
|
/** Follows a placed order through bids to a fill, or to its deadline. */
|
|
@@ -1547,9 +1891,14 @@ declare class BridgeTopUp {
|
|
|
1547
1891
|
private syncDelivery;
|
|
1548
1892
|
private readDelivery;
|
|
1549
1893
|
/**
|
|
1550
|
-
* The HyperFungibleToken request the fill dispatched to
|
|
1551
|
-
*
|
|
1552
|
-
*
|
|
1894
|
+
* The HyperFungibleToken request the fill dispatched to this filler's Hyperbridge account.
|
|
1895
|
+
*
|
|
1896
|
+
* The fill's own receipt is read first and the `Sent` log it carries is taken, because it is
|
|
1897
|
+
* the transaction this order's output call ran in. A bundled fill can carry several HFT sends,
|
|
1898
|
+
* so only logs from the BRIDGE token addressed to this filler's substrate key count; when more
|
|
1899
|
+
* than one matches, the amount the order's output call sends picks the right one. The indexer
|
|
1900
|
+
* finds the request by the fill's transaction too, as the explorer's search does, and is the
|
|
1901
|
+
* fallback only while the receipt cannot be read — and only when it is unambiguous.
|
|
1553
1902
|
*/
|
|
1554
1903
|
private deliveryRequest;
|
|
1555
1904
|
/**
|
|
@@ -1560,7 +1909,14 @@ declare class BridgeTopUp {
|
|
|
1560
1909
|
/**
|
|
1561
1910
|
* The transaction that filled the order. The executor reports it only for a fill this
|
|
1562
1911
|
* process selected, so it comes from the indexer, or, while the indexer has yet to reach
|
|
1563
|
-
* BSC's latest blocks, from the gateway's `OrderFilled` log
|
|
1912
|
+
* BSC's latest blocks, from the gateway's `OrderFilled` log.
|
|
1913
|
+
*
|
|
1914
|
+
* The log is searched over the whole range a fill can be in, not around when it was seen: a
|
|
1915
|
+
* fill found late (another filler's, after a restart) landed any time before the deadline. The
|
|
1916
|
+
* range starts where the order became fillable, which placement fixed as the deadline less
|
|
1917
|
+
* {@link ORDER_WINDOW_SECONDS} of BSC blocks (less an evidence margin, since the block time
|
|
1918
|
+
* is measured now and the order was built at an earlier one), and ends at the deadline or the
|
|
1919
|
+
* head. A failed read throws, so the caller retries; it never reads as "no fill".
|
|
1564
1920
|
*/
|
|
1565
1921
|
private findFill;
|
|
1566
1922
|
/** The order's statuses as the indexer has them: placed, filled, redeemed or refunded. */
|
|
@@ -1572,6 +1928,7 @@ declare class BridgeTopUp {
|
|
|
1572
1928
|
*/
|
|
1573
1929
|
sync(): Promise<void>;
|
|
1574
1930
|
private reconcile;
|
|
1931
|
+
private reconcileRecord;
|
|
1575
1932
|
/**
|
|
1576
1933
|
* Submits the request to Hyperbridge with a proof from BSC state. Public BSC endpoints
|
|
1577
1934
|
* differ in whether they serve `eth_getProof` for recent blocks, so each is tried in turn.
|
|
@@ -1586,27 +1943,108 @@ declare class BridgeTopUp {
|
|
|
1586
1943
|
* cancel flow from the paying chain (BSC's expiry height finalized, the cancel sent, the
|
|
1587
1944
|
* cancellation finalized on the source, verified and finalized on Hyperbridge), then the
|
|
1588
1945
|
* refund. A relayer normally delivers that refund; if none has within a few minutes of
|
|
1589
|
-
* Hyperbridge finalizing, the filler submits Hyperbridge's response itself.
|
|
1590
|
-
*
|
|
1946
|
+
* Hyperbridge finalizing, the filler submits Hyperbridge's response itself. The cancel pays
|
|
1947
|
+
* the relayer fee in the source host's fee token, and repeated failures, retried on a
|
|
1948
|
+
* backoff, stop the recovery and return the top-up to `unfilled`, where the operator restarts
|
|
1949
|
+
* it from the SDK's saved progress. The refund claim is rebuilt when its calldata is missing or
|
|
1950
|
+
* a claim reverted, since the SDK reports it only once.
|
|
1591
1951
|
*/
|
|
1592
1952
|
private driveReclaim;
|
|
1953
|
+
/**
|
|
1954
|
+
* The calls that cancel an unfilled order's escrow from its source chain. The cancel carries
|
|
1955
|
+
* no value: the source host pulls the relayer fee from the filler in its fee token, and the
|
|
1956
|
+
* filler wallet holds stablecoins, not the native token the SDK's quote would spend. The fee
|
|
1957
|
+
* is decoded from the SDK's own calldata so the approval matches what the gateway pulls.
|
|
1958
|
+
*/
|
|
1959
|
+
private cancelCalls;
|
|
1960
|
+
/**
|
|
1961
|
+
* Whether a submitted cancel landed. Returns its transaction hash when it did, and undefined
|
|
1962
|
+
* when it can no longer land (it reverted, or its nonce was taken by another transaction), so a
|
|
1963
|
+
* new cancel is safe to send. Throws while it could still land, or while the evidence cannot be
|
|
1964
|
+
* read, which keeps the recovery waiting and retrying.
|
|
1965
|
+
*
|
|
1966
|
+
* A duplicate cross-chain cancel does not revert: `_cancelFromSource` checks only the creator
|
|
1967
|
+
* and the height, so a second one dispatches another GET request and pulls the relayer fee
|
|
1968
|
+
* again. A cancel is therefore resent only on positive evidence that it cannot land. The
|
|
1969
|
+
* evidence, strongest first:
|
|
1970
|
+
*
|
|
1971
|
+
* 1. The receipt: a tx's by hash, a UserOp's from the bundler if it answers. A bundler that
|
|
1972
|
+
* cannot be asked (it lost the op, is down, or its URL was removed) is not fatal.
|
|
1973
|
+
* 2. The paying chain's own `OrderCancelled` log for this order, scanned from the height read
|
|
1974
|
+
* before the send, which backs the cancel whatever the bundler says. Its transaction is the
|
|
1975
|
+
* cancel.
|
|
1976
|
+
* 3. With no log up to `scannedTo`, the nonce rules, read an evidence margin below it: the
|
|
1977
|
+
* wallet's nonce is past a tx's, or the EntryPoint's is past the op's, so some other
|
|
1978
|
+
* transaction took it; or a Permit2 op's deadline has passed by the chain's own clock.
|
|
1979
|
+
* 4. Anything else waits.
|
|
1980
|
+
*/
|
|
1981
|
+
private settleCancel;
|
|
1982
|
+
/** How the fee token reads in an error: USDC/USDT when configured, else its raw address in raw units. */
|
|
1983
|
+
private feeTokenLabel;
|
|
1593
1984
|
/**
|
|
1594
1985
|
* Submits Hyperbridge's finalized response to the source chain's ISMP handler, which
|
|
1595
1986
|
* refunds the escrow, as the Hyperbridge app's "Claim funds" does.
|
|
1596
1987
|
*/
|
|
1597
1988
|
private claimRefund;
|
|
1598
1989
|
/**
|
|
1599
|
-
*
|
|
1600
|
-
*
|
|
1990
|
+
* Builds Hyperbridge's finalized response for the cancel's GET request again, from the SDK's
|
|
1991
|
+
* own snapshot of it. The SDK reports the calldata once, proven at the height known then;
|
|
1992
|
+
* this is what replaces calldata that reverted or was never saved.
|
|
1993
|
+
*/
|
|
1994
|
+
private rebuildClaim;
|
|
1995
|
+
/** The cancel's GET request: as recorded, else read back from the cancel's receipt. */
|
|
1996
|
+
private cancelCommitment;
|
|
1997
|
+
/** The GET request the IntentGateway on `chain` dispatched through its host, among a cancel receipt's logs. */
|
|
1998
|
+
private cancelRequestCommitment;
|
|
1999
|
+
/**
|
|
2000
|
+
* Whether there is nothing left to reclaim: the escrow is back with the filler, as the source
|
|
2001
|
+
* gateway reports it, which is recorded as the recovery's last step. The indexer's REFUNDED
|
|
2002
|
+
* status only supplies that step's tx hash and time: it is not evidence on its own.
|
|
2003
|
+
* `isOrderRefunded` reads the escrow and is true for an empty one, including an order that was
|
|
2004
|
+
* never placed, so it only counts for a record whose placement was seen (`commitment`).
|
|
2005
|
+
*
|
|
2006
|
+
* An empty escrow is also what a fill leaves: `IntentsBase._withdraw` releases it for a redeem
|
|
2007
|
+
* too. So before calling it a refund the order's fill is checked on BSC ({@link filledByOther}),
|
|
2008
|
+
* and an order that filled moves to `delivering` instead (also true, since the reclaim has
|
|
2009
|
+
* nothing to do).
|
|
2010
|
+
*
|
|
2011
|
+
* An escrow read that fails reads as "not refunded" so the reclaim goes on to the cancel; a
|
|
2012
|
+
* caller that records an outcome from the answer passes `strict` to have it throw instead.
|
|
1601
2013
|
*/
|
|
1602
2014
|
private refunded;
|
|
2015
|
+
/**
|
|
2016
|
+
* Whether someone other than the order's creator took the order on BSC. The gateway's
|
|
2017
|
+
* `_filled[commitment]` cannot tell a fill from a refund by itself: a fill sets it to the
|
|
2018
|
+
* filler, but `IntentsBase._withdraw` sets it to the beneficiary on every finalising
|
|
2019
|
+
* withdrawal, and a destination-side cancel sets it to `order.user`. A same-chain top-up's own
|
|
2020
|
+
* cancel, or a third party's, therefore leaves it non-zero, so only an address that is not the
|
|
2021
|
+
* creator counts as a fill (`isOrderFilled` in the SDK would count both). A read that fails
|
|
2022
|
+
* throws: neither `reclaimed` nor `delivering` is recorded from a value that was not read.
|
|
2023
|
+
*/
|
|
2024
|
+
private filledByOther;
|
|
1603
2025
|
private hasRecoveryStep;
|
|
1604
|
-
/**
|
|
2026
|
+
/**
|
|
2027
|
+
* Records a recovery step once, at the time it landed (or now). `also` is written in the same
|
|
2028
|
+
* update, for what a restart must never see without the step.
|
|
2029
|
+
*/
|
|
1605
2030
|
private recordRecoveryStep;
|
|
1606
|
-
/**
|
|
2031
|
+
/**
|
|
2032
|
+
* Schedules a retry in `delayMs` ({@link DELIVERY_RETRY_MS} unless given), but only while the
|
|
2033
|
+
* record it was scheduled for is still the current one. A timer from a finished top-up must
|
|
2034
|
+
* never drive the next one: a top-up the operator started after this record was replaced has
|
|
2035
|
+
* its own state to protect.
|
|
2036
|
+
*/
|
|
2037
|
+
private scheduleRetry;
|
|
2038
|
+
/**
|
|
2039
|
+
* Runs one background flow for the record; a failure is recorded rather than thrown. Every
|
|
2040
|
+
* write the flow makes, its failure handling included, is bound to this record.
|
|
2041
|
+
*/
|
|
1607
2042
|
private drive;
|
|
2043
|
+
private driveRecord;
|
|
1608
2044
|
/** Keeps what the executor reported, for the timeline's offers and its links. */
|
|
1609
2045
|
private recordEvent;
|
|
2046
|
+
/** Whether the calling flow was started for a record that has since been replaced. */
|
|
2047
|
+
private superseded;
|
|
1610
2048
|
private update;
|
|
1611
2049
|
private persist;
|
|
1612
2050
|
private buildOrder;
|
|
@@ -1684,30 +2122,36 @@ interface StoredBid {
|
|
|
1684
2122
|
/** The order was seen filled on-chain, so this bid can never win — reclaim its deposit now. */
|
|
1685
2123
|
dead: boolean;
|
|
1686
2124
|
/**
|
|
1687
|
-
*
|
|
1688
|
-
*
|
|
1689
|
-
*
|
|
1690
|
-
*
|
|
2125
|
+
* The HyperFX orderbook took this bid, so a swapper can execute it whatever Hyperbridge said.
|
|
2126
|
+
* The orderbook serves a bid for its TTL and nothing withdraws it, so this never changes; the
|
|
2127
|
+
* bid is live there until its op's `validUntil`. False for a bid the orderbook refused or was
|
|
2128
|
+
* not offered, and for rows from before bids went to the orderbook.
|
|
2129
|
+
*/
|
|
2130
|
+
onOrderbook: boolean;
|
|
2131
|
+
/**
|
|
2132
|
+
* The limit order that priced this bid and the terms it signed, written when the bid is stored
|
|
2133
|
+
* and never changed. Null for a bid no limit order priced.
|
|
1691
2134
|
*
|
|
1692
|
-
*
|
|
1693
|
-
*
|
|
1694
|
-
* bid may be meeting several of the operator's own orders at once.
|
|
2135
|
+
* Provenance only: nothing is held against the order. The order's on-chain budget refuses a
|
|
2136
|
+
* fill past its cap, and settlement re-reads that budget rather than doing arithmetic on this.
|
|
1695
2137
|
*/
|
|
1696
|
-
|
|
2138
|
+
pricedBy: BidPricing | null;
|
|
1697
2139
|
}
|
|
1698
|
-
/**
|
|
1699
|
-
interface
|
|
2140
|
+
/** The limit order a bid drew on and what the bid signed against it. */
|
|
2141
|
+
interface BidPricing {
|
|
1700
2142
|
limitOrderId: string;
|
|
1701
|
-
|
|
2143
|
+
/** The output the bid offered to pay, at 1e18. */
|
|
2144
|
+
payout: string;
|
|
1702
2145
|
/**
|
|
1703
|
-
* The take the bid signed beside `
|
|
1704
|
-
* works out what the gateway charged: the escrow it released at `
|
|
1705
|
-
* before bids carried their own rate
|
|
2146
|
+
* The take the bid signed beside `payout`, in the input token's raw units. With it, settlement
|
|
2147
|
+
* works out what the gateway charged: the escrow it released at `payout / take`, and which of
|
|
2148
|
+
* several bids on one order a fill executed. Bids recorded before bids carried their own rate
|
|
2149
|
+
* have none.
|
|
1706
2150
|
*/
|
|
1707
2151
|
take?: string;
|
|
1708
2152
|
/**
|
|
1709
2153
|
* The input token's decimals on the order's source chain, which is where `take` and the escrow
|
|
1710
|
-
* a fill releases are counted. With it, settlement records what a fill took in at 1e18.
|
|
2154
|
+
* a fill releases are counted. With it, settlement records what a fill took in at 1e18. Bids
|
|
1711
2155
|
* recorded before fills kept their input have none.
|
|
1712
2156
|
*/
|
|
1713
2157
|
takeDecimals?: number;
|
|
@@ -1722,18 +2166,22 @@ interface BidInsert {
|
|
|
1722
2166
|
* from the same account, lands after it and reclaims its deposit all the same.
|
|
1723
2167
|
*/
|
|
1724
2168
|
bid?: string;
|
|
1725
|
-
/**
|
|
1726
|
-
|
|
2169
|
+
/** The limit order that priced this bid; see {@link StoredBid.pricedBy}. */
|
|
2170
|
+
pricedBy?: BidPricing;
|
|
1727
2171
|
extrinsicHash?: string;
|
|
1728
2172
|
blockHash?: string;
|
|
1729
2173
|
success: boolean;
|
|
1730
2174
|
/** Submission is still in the pool; see {@link StoredBid.pending}. */
|
|
1731
2175
|
pending?: boolean;
|
|
1732
2176
|
error?: string;
|
|
2177
|
+
/** The orderbook holds this bid; see {@link StoredBid.onOrderbook}. */
|
|
2178
|
+
onOrderbook?: boolean;
|
|
1733
2179
|
}
|
|
1734
2180
|
interface BidStats {
|
|
1735
2181
|
total: number;
|
|
2182
|
+
/** Bids a venue took: Hyperbridge, or the orderbook alone. */
|
|
1736
2183
|
successful: number;
|
|
2184
|
+
/** Bids no venue took. */
|
|
1737
2185
|
failed: number;
|
|
1738
2186
|
retracted: number;
|
|
1739
2187
|
/** Deposits still locked: successful or pending, and not yet retracted. */
|
|
@@ -1772,35 +2220,29 @@ interface BidStore {
|
|
|
1772
2220
|
*
|
|
1773
2221
|
* Resolves false when no unretracted bid matched (already retracted, or never
|
|
1774
2222
|
* stored) — the caller treats that as success, not an error.
|
|
1775
|
-
*/
|
|
1776
|
-
markRetracted(commitment: string, retractExtrinsicHash: string | null): Promise<boolean>;
|
|
1777
|
-
/** Flags a bid dead (its order was filled on-chain). False when nothing matched. */
|
|
1778
|
-
markDead(commitment: string): Promise<boolean>;
|
|
1779
|
-
/**
|
|
1780
|
-
* Takes what this bid holds, exactly once, and returns it.
|
|
1781
2223
|
*
|
|
1782
|
-
*
|
|
1783
|
-
*
|
|
1784
|
-
*
|
|
1785
|
-
*
|
|
1786
|
-
* the other gets an empty list and does nothing.
|
|
2224
|
+
* With `rows` (the {@link StoredBid.id}s) only those bids are marked: a retraction
|
|
2225
|
+
* closes the bids it sent retractions for, not one stored on the commitment while it
|
|
2226
|
+
* was in flight. Without, every unretracted bid on the commitment is marked. An empty
|
|
2227
|
+
* `rows` marks nothing.
|
|
1787
2228
|
*/
|
|
2229
|
+
markRetracted(commitment: string, retractExtrinsicHash: string | null, rows?: readonly number[]): Promise<boolean>;
|
|
1788
2230
|
/**
|
|
1789
|
-
*
|
|
1790
|
-
*
|
|
1791
|
-
* With
|
|
1792
|
-
*
|
|
1793
|
-
*
|
|
2231
|
+
* Flags a bid dead, so the sweep retries its retraction next cycle rather than after
|
|
2232
|
+
* the TTL: its order was filled on-chain, or a retraction selected it and could not
|
|
2233
|
+
* close it. With `rows` (the {@link StoredBid.id}s) only those bids are flagged;
|
|
2234
|
+
* without, every unretracted bid on the commitment. An empty `rows` flags nothing.
|
|
2235
|
+
* False when nothing matched.
|
|
1794
2236
|
*/
|
|
1795
|
-
|
|
2237
|
+
markDead(commitment: string, rows?: readonly number[]): Promise<boolean>;
|
|
1796
2238
|
/**
|
|
1797
|
-
* Every bid
|
|
1798
|
-
* explicable to the operator: which bids
|
|
2239
|
+
* Every bid a limit order priced, newest first, from each bid's `pricedBy`. What
|
|
2240
|
+
* makes a `remaining` explicable to the operator: which bids drew on the order.
|
|
1799
2241
|
*/
|
|
1800
2242
|
byLimitOrder(limitOrderId: string, limit?: number): Promise<StoredBid[]>;
|
|
1801
2243
|
/** Newest first. Implementations should cap `limit` at a few hundred. */
|
|
1802
2244
|
recent(limit?: number): Promise<StoredBid[]>;
|
|
1803
|
-
/**
|
|
2245
|
+
/** Bids no venue took (neither Hyperbridge nor the orderbook), newest first — for debugging. */
|
|
1804
2246
|
failed(limit?: number): Promise<StoredBid[]>;
|
|
1805
2247
|
byDateRange(from: Date, to: Date): Promise<StoredBid[]>;
|
|
1806
2248
|
stats(): Promise<BidStats>;
|
|
@@ -1965,8 +2407,6 @@ interface LimitOrder {
|
|
|
1965
2407
|
size: string;
|
|
1966
2408
|
/** Output not yet delivered. */
|
|
1967
2409
|
remaining: string;
|
|
1968
|
-
/** Output promised to bids that have neither filled nor been retracted. */
|
|
1969
|
-
reserved: string;
|
|
1970
2410
|
/** Source chains this order accepts swaps from. Never empty. */
|
|
1971
2411
|
acceptedSources: string[];
|
|
1972
2412
|
/** TTL written into each posting. */
|
|
@@ -2026,15 +2466,8 @@ interface LimitOrderPosting {
|
|
|
2026
2466
|
lastError: string | null;
|
|
2027
2467
|
}
|
|
2028
2468
|
/**
|
|
2029
|
-
*
|
|
2030
|
-
*
|
|
2031
|
-
* This is inventory, not a cache: `remaining` and `reserved` are what stop two
|
|
2032
|
-
* chains from paying out the same liability twice, so a store that loses writes
|
|
2033
|
-
* overcommits real money.
|
|
2034
|
-
*/
|
|
2035
|
-
/**
|
|
2036
|
-
* One fill that drew a limit order down: kept apart from the bid that priced it, whose
|
|
2037
|
-
* holds are cleared on settlement, so an order keeps its history across every resize.
|
|
2469
|
+
* One fill of a limit order, kept apart from the bid row so an order keeps its history
|
|
2470
|
+
* across every resize and repost.
|
|
2038
2471
|
*/
|
|
2039
2472
|
interface LimitOrderFill {
|
|
2040
2473
|
id: number;
|
|
@@ -2052,6 +2485,12 @@ interface LimitOrderFill {
|
|
|
2052
2485
|
amountIn: string | null;
|
|
2053
2486
|
/** The fill's transaction on the order's fill chain, when the event carried it. */
|
|
2054
2487
|
transactionHash: string | null;
|
|
2488
|
+
/**
|
|
2489
|
+
* Which log of that transaction the fill is. One transaction can carry several of our
|
|
2490
|
+
* fills, so the hash alone does not name one. Null for a fill recorded before this was
|
|
2491
|
+
* kept, and for one whose event carried none.
|
|
2492
|
+
*/
|
|
2493
|
+
logIndex: number | null;
|
|
2055
2494
|
/** SQLite-style "YYYY-MM-DD HH:MM:SS" in UTC. */
|
|
2056
2495
|
filledAt: string;
|
|
2057
2496
|
}
|
|
@@ -2062,6 +2501,7 @@ interface LimitOrderFillInsert {
|
|
|
2062
2501
|
amount: string;
|
|
2063
2502
|
amountIn?: string | null;
|
|
2064
2503
|
transactionHash?: string | null;
|
|
2504
|
+
logIndex?: number | null;
|
|
2065
2505
|
}
|
|
2066
2506
|
/**
|
|
2067
2507
|
* A fill with the terms of the order it drew on: what profitability is worked out from. The
|
|
@@ -2079,6 +2519,13 @@ interface LimitOrderFillRecord {
|
|
|
2079
2519
|
amountIn: string | null;
|
|
2080
2520
|
filledAt: string;
|
|
2081
2521
|
}
|
|
2522
|
+
/**
|
|
2523
|
+
* Persistent record of the operator's limit orders.
|
|
2524
|
+
*
|
|
2525
|
+
* `remaining` follows the order's on-chain budget, which is what actually refuses a fill
|
|
2526
|
+
* past the order's size: it is lowered to that budget after each fill and by the periodic
|
|
2527
|
+
* tally reconciliation, and never raised.
|
|
2528
|
+
*/
|
|
2082
2529
|
interface LimitOrderStore {
|
|
2083
2530
|
create(order: LimitOrderInsert): Promise<LimitOrder>;
|
|
2084
2531
|
get(id: string): Promise<LimitOrder | null>;
|
|
@@ -2096,51 +2543,30 @@ interface LimitOrderStore {
|
|
|
2096
2543
|
setPosting(id: string, posting: LimitOrderPosting, only?: readonly LimitOrderStatus[]): Promise<LimitOrder | null>;
|
|
2097
2544
|
setStatus(id: string, status: LimitOrderStatus, lastError?: string | null, only?: readonly LimitOrderStatus[]): Promise<LimitOrder | null>;
|
|
2098
2545
|
/**
|
|
2099
|
-
*
|
|
2100
|
-
*
|
|
2546
|
+
* Lowers an `open` or `resizing` order's `remaining` to `room`, what the solver's
|
|
2547
|
+
* account on chain will still pay for this order, at 1e18. Never raises it.
|
|
2548
|
+
* Returns the order when it was lowered, null otherwise, including for an order in
|
|
2549
|
+
* any other status.
|
|
2101
2550
|
*
|
|
2102
|
-
*
|
|
2103
|
-
*
|
|
2104
|
-
*
|
|
2105
|
-
* a
|
|
2106
|
-
*
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
release(id: string, amount: string): Promise<void>;
|
|
2111
|
-
/**
|
|
2112
|
-
* Works the order down by output that has actually been delivered, floored at
|
|
2113
|
-
* zero. Returns the order as it now stands, or null when there is none.
|
|
2114
|
-
*/
|
|
2115
|
-
drawDown(id: string, amount: string): Promise<LimitOrder | null>;
|
|
2116
|
-
/**
|
|
2117
|
-
* Lowers an `open` order's `remaining` to `room + reserved`, where `room` is
|
|
2118
|
-
* what the solver's account on chain will still pay for this order, at 1e18.
|
|
2119
|
-
* Never raises it. Returns the order when it was lowered, null otherwise.
|
|
2551
|
+
* `only` narrows the statuses it may act on, like `setStatus` and `setPosting` take;
|
|
2552
|
+
* it never widens them, so a status other than `open` or `resizing` is never clamped.
|
|
2553
|
+
* Both callers pass it, because the two statuses mean different things. A repost
|
|
2554
|
+
* holds a row in `resizing` and lowers it to the tally before it posts, so that call
|
|
2555
|
+
* passes `["resizing"]`: a store that refused `resizing` would have the repost
|
|
2556
|
+
* advertise the pre-fill size. A fill's sync starts a repost of its own after it
|
|
2557
|
+
* lowers the row, so it passes `["open"]`: a row a repost already holds is left to
|
|
2558
|
+
* it, and two reposts of one row would orphan a book entry.
|
|
2120
2559
|
*
|
|
2121
|
-
*
|
|
2122
|
-
*
|
|
2123
|
-
* settles. Clamping to `room` alone would take that fill off twice.
|
|
2560
|
+
* A custom store must apply the status check and the write atomically: a row that
|
|
2561
|
+
* moved to another status after the caller read it is left as it is.
|
|
2124
2562
|
*/
|
|
2125
|
-
clampRemaining(id: string, room: string): Promise<LimitOrder | null>;
|
|
2126
|
-
/** Records a fill against its limit order
|
|
2563
|
+
clampRemaining(id: string, room: string, only?: readonly LimitOrderStatus[]): Promise<LimitOrder | null>;
|
|
2564
|
+
/** Records a fill against its limit order, for its history and profit. */
|
|
2127
2565
|
recordFill(fill: LimitOrderFillInsert): Promise<void>;
|
|
2128
2566
|
/** Every fill of every limit order, oldest first, each with its order's terms. */
|
|
2129
2567
|
fillHistory(): Promise<LimitOrderFillRecord[]>;
|
|
2130
2568
|
/** A limit order's fills, newest first. */
|
|
2131
2569
|
fills(limitOrderId: string, limit?: number): Promise<LimitOrderFill[]>;
|
|
2132
|
-
/**
|
|
2133
|
-
* Runs `settle` as one unit where the backend can.
|
|
2134
|
-
*
|
|
2135
|
-
* A fill claims what its bid held, works the orders down by what went out and
|
|
2136
|
-
* gives the rest back, and a crash between those leaves the hold released
|
|
2137
|
-
* against an order that was never drawn down. The bid rows live in the same
|
|
2138
|
-
* database as the limit orders, which is what lets one transaction cover both.
|
|
2139
|
-
*
|
|
2140
|
-
* Only store calls belong inside: they are synchronous underneath, so nothing
|
|
2141
|
-
* else interleaves on the connection, which would not hold for a network call.
|
|
2142
|
-
*/
|
|
2143
|
-
transaction<T>(settle: () => Promise<T>): Promise<T>;
|
|
2144
2570
|
}
|
|
2145
2571
|
/** Operator state that must survive a restart. */
|
|
2146
2572
|
interface RuntimeState {
|
|
@@ -2167,8 +2593,59 @@ interface StoredBridgeTopUp {
|
|
|
2167
2593
|
sessionPrivateKey?: HexString;
|
|
2168
2594
|
commitment?: HexString;
|
|
2169
2595
|
placeTxHash?: HexString;
|
|
2596
|
+
/**
|
|
2597
|
+
* The wallet nonce a native placement tx was sent with. Only the wallet's nonce moving past it
|
|
2598
|
+
* shows the tx can no longer be mined; a node that forgot the tx shows nothing.
|
|
2599
|
+
*/
|
|
2600
|
+
placeTxNonce?: number;
|
|
2601
|
+
/**
|
|
2602
|
+
* The placement UserOp the bundler accepted when its receipt never arrived. The batch may have
|
|
2603
|
+
* been mined, so the record stays pending and the op is looked up again; without it a restart
|
|
2604
|
+
* would declare that nothing was escrowed while the order could still be live.
|
|
2605
|
+
*/
|
|
2606
|
+
placeUserOpHash?: HexString;
|
|
2607
|
+
/** The EntryPoint `nonce` the op was signed with, as a decimal string (the record is JSON-persisted). */
|
|
2608
|
+
placeUserOpNonce?: string;
|
|
2609
|
+
/** The EntryPoint `nonceKey` the op was signed with, as a decimal string. */
|
|
2610
|
+
placeUserOpNonceKey?: string;
|
|
2611
|
+
/**
|
|
2612
|
+
* Whether a UserOp placement's paymaster attached a validity deadline (Permit2 mode). A
|
|
2613
|
+
* bootstrap op has none, so it can still land; without this a restart cannot tell them apart.
|
|
2614
|
+
*/
|
|
2615
|
+
placeUserOpExpires?: boolean;
|
|
2616
|
+
/**
|
|
2617
|
+
* When the placement batch was submitted, in ms. Dates a UserOp's permit window. Records from
|
|
2618
|
+
* before this was recorded are dated by `stageTimes.placing`, then `createdAt`; `updatedAt` is
|
|
2619
|
+
* rewritten by every save, so it never ages.
|
|
2620
|
+
*/
|
|
2621
|
+
placeSubmittedAt?: number;
|
|
2622
|
+
/**
|
|
2623
|
+
* The order's session-key address, matched against `OrderPlaced.session`. A placement receipt
|
|
2624
|
+
* can carry other users' placements (a UserOp is a bundle), so only the log naming this address
|
|
2625
|
+
* is this top-up's.
|
|
2626
|
+
*/
|
|
2627
|
+
placeSession?: HexString;
|
|
2628
|
+
/** Block the paying chain was at before the placement was submitted, as a decimal string; the scan starts here. */
|
|
2629
|
+
placeFromBlock?: string;
|
|
2630
|
+
/**
|
|
2631
|
+
* The next block a recovery scan reads, as a decimal string. Saved after each chunk and trailing
|
|
2632
|
+
* the tip by the evidence margin; the next scan starts a margin below it, so a page a lagging
|
|
2633
|
+
* backend served empty is read again.
|
|
2634
|
+
*/
|
|
2635
|
+
placeScannedTo?: string;
|
|
2170
2636
|
fillTxHash?: HexString;
|
|
2637
|
+
/**
|
|
2638
|
+
* The cancel's transaction. With no `reclaimSubmission` it is a cancel whose send was confirmed
|
|
2639
|
+
* (the only way it was ever written before submissions were kept), and is handed to the SDK as is.
|
|
2640
|
+
*/
|
|
2171
2641
|
reclaimTxHash?: HexString;
|
|
2642
|
+
/**
|
|
2643
|
+
* The cancel as submitted, kept until the `ORDER_CANCELED` step is recorded. It is settled from
|
|
2644
|
+
* on-chain evidence before the SDK is handed a hash or a new cancel is sent: a duplicate
|
|
2645
|
+
* cross-chain cancel does not revert, it dispatches another GET request and pays the relayer fee
|
|
2646
|
+
* again. See {@link StoredSubmission}.
|
|
2647
|
+
*/
|
|
2648
|
+
reclaimSubmission?: StoredSubmission;
|
|
2172
2649
|
/** The HyperFungibleToken request that carries the BRIDGE to Hyperbridge. */
|
|
2173
2650
|
deliveryCommitment?: HexString;
|
|
2174
2651
|
/** The Hyperbridge extrinsic that delivered it, when this filler relayed it. */
|
|
@@ -2185,12 +2662,37 @@ interface StoredBridgeTopUp {
|
|
|
2185
2662
|
deliveryStatuses?: DeliveryStatus[];
|
|
2186
2663
|
/** The unfilled order's recovery, step by step, as the SDK's cancel flow reported it. */
|
|
2187
2664
|
recoverySteps?: RecoveryStepRecord[];
|
|
2665
|
+
/** The GET request a cross-chain cancel dispatched; Hyperbridge answers it with the refund response. */
|
|
2666
|
+
getCommitment?: HexString;
|
|
2188
2667
|
/** Hyperbridge's finalized response, which refunds the escrow when submitted on the source. */
|
|
2189
2668
|
claimCalldata?: HexString;
|
|
2190
2669
|
/** The filler's own refund claim, when no relayer delivered it in time. */
|
|
2191
2670
|
claimTxHash?: HexString;
|
|
2192
2671
|
error?: string;
|
|
2193
2672
|
}
|
|
2673
|
+
/**
|
|
2674
|
+
* A submission as kept in the JSON state: bigints as decimal strings, plus the evidence window of
|
|
2675
|
+
* the chain scan that settles it.
|
|
2676
|
+
*/
|
|
2677
|
+
type StoredSubmission = ({
|
|
2678
|
+
kind: "tx";
|
|
2679
|
+
txHash: HexString;
|
|
2680
|
+
nonce: number;
|
|
2681
|
+
submittedAt: number;
|
|
2682
|
+
} | {
|
|
2683
|
+
kind: "userOp";
|
|
2684
|
+
userOpHash: HexString;
|
|
2685
|
+
nonce: string;
|
|
2686
|
+
nonceKey: string;
|
|
2687
|
+
/** Whether the paymaster attached a validity deadline; see {@link StoredBridgeTopUp.placeUserOpExpires}. */
|
|
2688
|
+
expires: boolean;
|
|
2689
|
+
submittedAt: number;
|
|
2690
|
+
}) & {
|
|
2691
|
+
/** The paying chain's height, read before the send, as a decimal string; the evidence scan starts a margin below it. */
|
|
2692
|
+
fromBlock: string;
|
|
2693
|
+
/** The next block the scan reads, as a decimal string; see {@link StoredBridgeTopUp.placeScannedTo}. */
|
|
2694
|
+
scannedTo?: string;
|
|
2695
|
+
};
|
|
2194
2696
|
interface RecoveryStepRecord {
|
|
2195
2697
|
step: "DESTINATION_FINALIZED" | "ORDER_CANCELED" | "SOURCE_FINALIZED" | "HYPERBRIDGE_DELIVERED" | "HYPERBRIDGE_FINALIZED" | "FUNDS_CLAIMED";
|
|
2196
2698
|
/** When the step completed, in ms. */
|
|
@@ -2294,4 +2796,4 @@ interface InventoryStore {
|
|
|
2294
2796
|
since(from: Date): Promise<InventorySnapshot[]>;
|
|
2295
2797
|
}
|
|
2296
2798
|
|
|
2297
|
-
export { type LimitOrderPosting as $, type ActivityStore as A, type BidStore as B, ChainClientManager as C, type DerivingSigner as D, type AuthorizationRequest as E, FillerConfigService as F, type BidInsert as G, type
|
|
2799
|
+
export { type LimitOrderPosting as $, type ActivityStore as A, type BidStore as B, ChainClientManager as C, type DerivingSigner as D, type AuthorizationRequest as E, FillerConfigService as F, type BidInsert as G, type BidPricing as H, type InventoryStore as I, type BinanceConfig as J, type CurveConfig as K, LoggerContext as L, type MpcVaultSignerConfig as M, type CurvePoint as N, type OrderHistoryPage as O, type Eip7702Authorization$1 as P, type FillerConfigFile as Q, type ResolvedChainConfig as R, type SignerConfig as S, type TurnkeySignerConfig as T, UserOpSender as U, type VaultToml as V, type WalletTx as W, type InventorySnapshot as X, type LimitOrderFillInsert as Y, type LimitOrderFillRecord as Z, type LimitOrderInsert as _, type Signer as a, type LimitOrderSide as a0, type LimitOrderStatus as a1, type Logger as a2, type OperatorNotification as a3, type PrivateKeySignerConfig as a4, type QueueConfig as a5, type RuntimeState as a6, type SignerTransaction as a7, SignerType as a8, type TypedDataPayload as a9, USD_STABLE_SYMBOLS as aa, type UserProvidedChainConfig as ab, type VaultTomlConfig as ac, type WalletTxKind as ad, addLogSink as ae, assertConfirmationCoverage as af, configureLogger as ag, formatChainKey as ah, getLogger as ai, isRegistrySymbol as aj, normalizeSymbol as ak, parseChainKey as al, registrySymbols as am, validateAssetDefinitions as an, validateConfig as ao, validateVaultToml as ap, type OrderSummary as aq, type Signature as b, type SecretPhraseSignerConfig as c, DelegationService as d, type ActivityInsert as e, type ActivityEvent as f, type LimitOrderStore as g, AssetRegistry as h, type LimitOrder as i, type LimitOrderFilter as j, type SimplexDataStore as k, ConfirmationPolicy as l, type FillerTomlConfig as m, TokenSender as n, BridgeTopUp as o, type AssetDefinition as p, type ChainConfirmationPolicy as q, type LimitOrderFill as r, type StoredBid as s, type RebalancingConfig as t, type LogSink as u, type BidStats as v, type AllowlistConfig as w, type LogLevel as x, type StateStore as y, type ActivityType as z };
|