1 | const { sleep, loop } = require('../utils');
|
2 | const LazyPromise = require('./LazyPromise');
|
3 |
|
4 | class PendingTransaction extends LazyPromise {
|
5 | constructor(cfx, func, params) {
|
6 | super(func, params);
|
7 | this.cfx = cfx;
|
8 | }
|
9 |
|
10 | /**
|
11 | * Get transaction by hash.
|
12 | *
|
13 | * @param [options] {object}
|
14 | * @param [options.delay=0] {number} - Defer execute after `delay` ms.
|
15 | * @return {Promise<Object|null>} See `Conflux.getTransactionByHash`
|
16 | */
|
17 | async get({ delay = 0 } = {}) {
|
18 | await sleep(delay);
|
19 | const txHash = await this;
|
20 | return this.cfx.getTransactionByHash(txHash);
|
21 | }
|
22 |
|
23 | /**
|
24 | * Async wait till transaction been mined.
|
25 | *
|
26 | * - blockHash !== null
|
27 | *
|
28 | * @param [options] {object}
|
29 | * @param [options.delta=1000] {number} - Loop transaction interval in ms.
|
30 | * @param [options.timeout=30*1000] {number} - Loop timeout in ms.
|
31 | * @return {Promise<object>} See `Conflux.getTransactionByHash`
|
32 | */
|
33 | async mined({ delta = 1000, timeout = 60 * 1000 } = {}) {
|
34 | return loop({ delta, timeout }, async () => {
|
35 | const tx = await this.get();
|
36 | if (tx.blockHash) {
|
37 | return tx;
|
38 | }
|
39 |
|
40 | return undefined;
|
41 | });
|
42 | }
|
43 |
|
44 | /**
|
45 | * Async wait till transaction been executed.
|
46 | *
|
47 | * - mined
|
48 | * - receipt !== null
|
49 | * - receipt.outcomeStatus === 0
|
50 | *
|
51 | * @param [options] {object}
|
52 | * @param [options.delta=1000] {number} - Loop transaction interval in ms.
|
53 | * @param [options.timeout=60*1000] {number} - Loop timeout in ms.
|
54 | * @return {Promise<object>} See `Conflux.getTransactionReceipt`
|
55 | */
|
56 | async executed({ delta = 1000, timeout = 5 * 60 * 1000 } = {}) {
|
57 | const txHash = await this;
|
58 | return loop({ delta, timeout }, async () => {
|
59 | const receipt = await this.cfx.getTransactionReceipt(txHash);
|
60 | if (receipt) {
|
61 | if (receipt.outcomeStatus === 0) {
|
62 | return receipt;
|
63 | }
|
64 | throw new Error(`transaction "${txHash}" executed failed, outcomeStatus ${receipt.outcomeStatus}`);
|
65 | }
|
66 |
|
67 | return undefined;
|
68 | });
|
69 | }
|
70 |
|
71 | /**
|
72 | * Async wait till transaction been confirmed.
|
73 | *
|
74 | * - executed
|
75 | * - transaction block risk coefficient < threshold
|
76 | *
|
77 | * @param [options] {object}
|
78 | * @param [options.delta=1000] {number} - Loop transaction interval in ms.
|
79 | * @param [options.timeout=5*60*1000] {number} - Loop timeout in ms.
|
80 | * @param [options.threshold=0.01] {number} - Number in range (0,1)
|
81 | * @return {Promise<object>} See `Conflux.getTransactionReceipt`
|
82 | */
|
83 | async confirmed({ threshold = 0.01, delta = 1000, timeout = 30 * 60 * 1000 } = {}) {
|
84 | return loop({ delta, timeout }, async () => {
|
85 | const receipt = await this.executed({ delta, timeout });
|
86 | const risk = await this.cfx.getRiskCoefficient(receipt.epochNumber);
|
87 | if (risk < threshold) {
|
88 | return receipt;
|
89 | }
|
90 |
|
91 | return undefined;
|
92 | });
|
93 | }
|
94 |
|
95 | /**
|
96 | * Async wait till contract create transaction deployed.
|
97 | * - transaction confirmed
|
98 | *
|
99 | * @param [options] {object} - See `PendingTransaction.confirmed`
|
100 | * @return {Promise<string>} The contract address.
|
101 | */
|
102 | async deployed(options) {
|
103 | const { transactionHash, outcomeStatus, contractCreated } = await this.confirmed(options);
|
104 | if (outcomeStatus === 0) {
|
105 | return contractCreated;
|
106 | }
|
107 | throw new Error(`transaction "${transactionHash}" deploy failed with ${outcomeStatus}`);
|
108 | }
|
109 | }
|
110 |
|
111 | module.exports = PendingTransaction;
|