forked from Stellar-split/split-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfinalityChecker.ts
More file actions
77 lines (64 loc) · 2.28 KB
/
Copy pathfinalityChecker.ts
File metadata and controls
77 lines (64 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import { FinalityTimeoutError } from "./errors.js";
import { emitSdkEvent } from "./events.js";
import type { FinalityCheckConfig, FinalityStatus } from "./types.js";
interface CallBuilder<T> {
call(): Promise<T>;
}
interface TransactionRecordLike {
ledger: number | string;
successful?: boolean;
result_successful?: boolean;
}
interface LedgerRecordLike {
sequence?: number | string;
}
export interface FinalityServerLike {
transactions(): {
transaction(hash: string): CallBuilder<TransactionRecordLike>;
};
ledgers(): {
order(direction: "desc"): {
limit(limit: number): CallBuilder<{ records: LedgerRecordLike[] }>;
};
};
}
const sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));
export class FinalityChecker {
private readonly server: FinalityServerLike;
private readonly config: Required<FinalityCheckConfig>;
constructor(server: FinalityServerLike, config: FinalityCheckConfig = {}) {
this.server = server;
this.config = {
minConfirmations: config.minConfirmations ?? 2,
pollIntervalMs: config.pollIntervalMs ?? 1_000,
maxWaitMs: config.maxWaitMs ?? 30_000,
};
}
async check(txHash: string): Promise<FinalityStatus> {
const startedAt = Date.now();
while (true) {
const status = await this.readStatus(txHash);
if (status.finalized) {
emitSdkEvent("invoiceFinalized", { txHash, finality: status });
return status;
}
if (Date.now() - startedAt >= this.config.maxWaitMs) {
throw new FinalityTimeoutError(txHash, this.config.maxWaitMs);
}
await sleep(this.config.pollIntervalMs);
}
}
private async readStatus(txHash: string): Promise<FinalityStatus> {
const tx = await this.server.transactions().transaction(txHash).call();
const ledgerSequence = Number(tx.ledger);
const latest = await this.server.ledgers().order("desc").limit(1).call();
const currentLedger = Number(latest.records[0]?.sequence ?? ledgerSequence);
const confirmations = Math.max(0, currentLedger - ledgerSequence);
const successful = tx.successful === true || tx.result_successful === true;
return {
finalized: successful && confirmations >= this.config.minConfirmations,
confirmations,
ledgerSequence,
};
}
}