@atomiqlabs/chain-evm 1.0.0-dev.62 → 1.0.0-dev.64

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.
Files changed (187) hide show
  1. package/LICENSE +201 -201
  2. package/dist/chains/botanix/BotanixChainType.d.ts +13 -13
  3. package/dist/chains/botanix/BotanixChainType.js +2 -2
  4. package/dist/chains/botanix/BotanixInitializer.d.ts +30 -30
  5. package/dist/chains/botanix/BotanixInitializer.js +122 -122
  6. package/dist/chains/citrea/CitreaBtcRelay.d.ts +21 -21
  7. package/dist/chains/citrea/CitreaBtcRelay.js +43 -43
  8. package/dist/chains/citrea/CitreaChainType.d.ts +13 -13
  9. package/dist/chains/citrea/CitreaChainType.js +2 -2
  10. package/dist/chains/citrea/CitreaFees.d.ts +29 -29
  11. package/dist/chains/citrea/CitreaFees.js +67 -67
  12. package/dist/chains/citrea/CitreaInitializer.d.ts +30 -30
  13. package/dist/chains/citrea/CitreaInitializer.js +129 -129
  14. package/dist/chains/citrea/CitreaSpvVaultContract.d.ts +15 -15
  15. package/dist/chains/citrea/CitreaSpvVaultContract.js +74 -74
  16. package/dist/chains/citrea/CitreaSwapContract.d.ts +22 -22
  17. package/dist/chains/citrea/CitreaSwapContract.js +96 -96
  18. package/dist/chains/citrea/CitreaTokens.d.ts +9 -9
  19. package/dist/chains/citrea/CitreaTokens.js +20 -20
  20. package/dist/evm/btcrelay/BtcRelayAbi.d.ts +198 -198
  21. package/dist/evm/btcrelay/BtcRelayAbi.js +261 -261
  22. package/dist/evm/btcrelay/BtcRelayTypechain.d.ts +172 -172
  23. package/dist/evm/btcrelay/BtcRelayTypechain.js +2 -2
  24. package/dist/evm/btcrelay/EVMBtcRelay.d.ts +195 -195
  25. package/dist/evm/btcrelay/EVMBtcRelay.js +423 -423
  26. package/dist/evm/btcrelay/headers/EVMBtcHeader.d.ts +33 -33
  27. package/dist/evm/btcrelay/headers/EVMBtcHeader.js +84 -84
  28. package/dist/evm/btcrelay/headers/EVMBtcStoredHeader.d.ts +56 -56
  29. package/dist/evm/btcrelay/headers/EVMBtcStoredHeader.js +123 -123
  30. package/dist/evm/chain/EVMChainInterface.d.ts +51 -51
  31. package/dist/evm/chain/EVMChainInterface.js +89 -89
  32. package/dist/evm/chain/EVMModule.d.ts +9 -9
  33. package/dist/evm/chain/EVMModule.js +13 -13
  34. package/dist/evm/chain/modules/ERC20Abi.d.ts +168 -168
  35. package/dist/evm/chain/modules/ERC20Abi.js +225 -225
  36. package/dist/evm/chain/modules/EVMAddresses.d.ts +10 -10
  37. package/dist/evm/chain/modules/EVMAddresses.js +30 -30
  38. package/dist/evm/chain/modules/EVMBlocks.d.ts +20 -20
  39. package/dist/evm/chain/modules/EVMBlocks.js +64 -64
  40. package/dist/evm/chain/modules/EVMEvents.d.ts +36 -36
  41. package/dist/evm/chain/modules/EVMEvents.js +122 -122
  42. package/dist/evm/chain/modules/EVMFees.d.ts +36 -36
  43. package/dist/evm/chain/modules/EVMFees.js +73 -73
  44. package/dist/evm/chain/modules/EVMSignatures.d.ts +29 -29
  45. package/dist/evm/chain/modules/EVMSignatures.js +68 -68
  46. package/dist/evm/chain/modules/EVMTokens.d.ts +70 -70
  47. package/dist/evm/chain/modules/EVMTokens.js +142 -142
  48. package/dist/evm/chain/modules/EVMTransactions.d.ts +89 -89
  49. package/dist/evm/chain/modules/EVMTransactions.js +235 -235
  50. package/dist/evm/contract/EVMContractBase.d.ts +22 -22
  51. package/dist/evm/contract/EVMContractBase.js +34 -34
  52. package/dist/evm/contract/EVMContractModule.d.ts +8 -8
  53. package/dist/evm/contract/EVMContractModule.js +11 -11
  54. package/dist/evm/contract/modules/EVMContractEvents.d.ts +42 -42
  55. package/dist/evm/contract/modules/EVMContractEvents.js +75 -75
  56. package/dist/evm/events/EVMChainEvents.d.ts +22 -22
  57. package/dist/evm/events/EVMChainEvents.js +69 -69
  58. package/dist/evm/events/EVMChainEventsBrowser.d.ts +102 -102
  59. package/dist/evm/events/EVMChainEventsBrowser.js +402 -400
  60. package/dist/evm/providers/JsonRpcProviderWithRetries.d.ts +15 -15
  61. package/dist/evm/providers/JsonRpcProviderWithRetries.js +19 -19
  62. package/dist/evm/providers/ReconnectingWebSocketProvider.d.ts +22 -20
  63. package/dist/evm/providers/ReconnectingWebSocketProvider.js +87 -77
  64. package/dist/evm/providers/SocketProvider.d.ts +111 -111
  65. package/dist/evm/providers/SocketProvider.js +334 -334
  66. package/dist/evm/providers/WebSocketProviderWithRetries.d.ts +17 -17
  67. package/dist/evm/providers/WebSocketProviderWithRetries.js +19 -19
  68. package/dist/evm/spv_swap/EVMSpvVaultContract.d.ts +78 -78
  69. package/dist/evm/spv_swap/EVMSpvVaultContract.js +478 -478
  70. package/dist/evm/spv_swap/EVMSpvVaultData.d.ts +39 -39
  71. package/dist/evm/spv_swap/EVMSpvVaultData.js +180 -180
  72. package/dist/evm/spv_swap/EVMSpvWithdrawalData.d.ts +19 -19
  73. package/dist/evm/spv_swap/EVMSpvWithdrawalData.js +55 -55
  74. package/dist/evm/spv_swap/SpvVaultContractAbi.d.ts +91 -91
  75. package/dist/evm/spv_swap/SpvVaultContractAbi.js +849 -849
  76. package/dist/evm/spv_swap/SpvVaultContractTypechain.d.ts +450 -450
  77. package/dist/evm/spv_swap/SpvVaultContractTypechain.js +2 -2
  78. package/dist/evm/swaps/EVMSwapContract.d.ts +193 -193
  79. package/dist/evm/swaps/EVMSwapContract.js +378 -378
  80. package/dist/evm/swaps/EVMSwapData.d.ts +66 -66
  81. package/dist/evm/swaps/EVMSwapData.js +260 -260
  82. package/dist/evm/swaps/EVMSwapModule.d.ts +9 -9
  83. package/dist/evm/swaps/EVMSwapModule.js +11 -11
  84. package/dist/evm/swaps/EscrowManagerAbi.d.ts +120 -120
  85. package/dist/evm/swaps/EscrowManagerAbi.js +985 -985
  86. package/dist/evm/swaps/EscrowManagerTypechain.d.ts +475 -475
  87. package/dist/evm/swaps/EscrowManagerTypechain.js +2 -2
  88. package/dist/evm/swaps/handlers/IHandler.d.ts +13 -13
  89. package/dist/evm/swaps/handlers/IHandler.js +2 -2
  90. package/dist/evm/swaps/handlers/claim/ClaimHandlers.d.ts +10 -10
  91. package/dist/evm/swaps/handlers/claim/ClaimHandlers.js +13 -13
  92. package/dist/evm/swaps/handlers/claim/HashlockClaimHandler.d.ts +20 -20
  93. package/dist/evm/swaps/handlers/claim/HashlockClaimHandler.js +39 -39
  94. package/dist/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.d.ts +24 -24
  95. package/dist/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.js +59 -59
  96. package/dist/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.d.ts +25 -25
  97. package/dist/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.js +51 -51
  98. package/dist/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.d.ts +21 -21
  99. package/dist/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.js +28 -28
  100. package/dist/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.d.ts +48 -48
  101. package/dist/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.js +63 -63
  102. package/dist/evm/swaps/handlers/refund/TimelockRefundHandler.d.ts +17 -17
  103. package/dist/evm/swaps/handlers/refund/TimelockRefundHandler.js +28 -28
  104. package/dist/evm/swaps/modules/EVMLpVault.d.ts +69 -69
  105. package/dist/evm/swaps/modules/EVMLpVault.js +134 -134
  106. package/dist/evm/swaps/modules/EVMSwapClaim.d.ts +54 -54
  107. package/dist/evm/swaps/modules/EVMSwapClaim.js +137 -137
  108. package/dist/evm/swaps/modules/EVMSwapInit.d.ts +88 -88
  109. package/dist/evm/swaps/modules/EVMSwapInit.js +274 -274
  110. package/dist/evm/swaps/modules/EVMSwapRefund.d.ts +62 -62
  111. package/dist/evm/swaps/modules/EVMSwapRefund.js +167 -167
  112. package/dist/evm/typechain/common.d.ts +50 -50
  113. package/dist/evm/typechain/common.js +2 -2
  114. package/dist/evm/wallet/EVMSigner.d.ts +10 -10
  115. package/dist/evm/wallet/EVMSigner.js +17 -17
  116. package/dist/index.d.ts +43 -43
  117. package/dist/index.js +59 -59
  118. package/dist/utils/Utils.d.ts +15 -15
  119. package/dist/utils/Utils.js +71 -71
  120. package/package.json +37 -37
  121. package/src/chains/botanix/BotanixChainType.ts +28 -28
  122. package/src/chains/botanix/BotanixInitializer.ts +171 -171
  123. package/src/chains/citrea/CitreaBtcRelay.ts +57 -57
  124. package/src/chains/citrea/CitreaChainType.ts +28 -28
  125. package/src/chains/citrea/CitreaFees.ts +77 -77
  126. package/src/chains/citrea/CitreaInitializer.ts +178 -178
  127. package/src/chains/citrea/CitreaSpvVaultContract.ts +75 -75
  128. package/src/chains/citrea/CitreaSwapContract.ts +102 -102
  129. package/src/chains/citrea/CitreaTokens.ts +21 -21
  130. package/src/evm/btcrelay/BtcRelayAbi.ts +258 -258
  131. package/src/evm/btcrelay/BtcRelayTypechain.ts +371 -371
  132. package/src/evm/btcrelay/EVMBtcRelay.ts +522 -522
  133. package/src/evm/btcrelay/headers/EVMBtcHeader.ts +109 -109
  134. package/src/evm/btcrelay/headers/EVMBtcStoredHeader.ts +152 -152
  135. package/src/evm/chain/EVMChainInterface.ts +155 -155
  136. package/src/evm/chain/EVMModule.ts +21 -21
  137. package/src/evm/chain/modules/ERC20Abi.ts +222 -222
  138. package/src/evm/chain/modules/EVMAddresses.ts +28 -28
  139. package/src/evm/chain/modules/EVMBlocks.ts +75 -75
  140. package/src/evm/chain/modules/EVMEvents.ts +139 -139
  141. package/src/evm/chain/modules/EVMFees.ts +104 -104
  142. package/src/evm/chain/modules/EVMSignatures.ts +76 -76
  143. package/src/evm/chain/modules/EVMTokens.ts +155 -155
  144. package/src/evm/chain/modules/EVMTransactions.ts +263 -263
  145. package/src/evm/contract/EVMContractBase.ts +63 -63
  146. package/src/evm/contract/EVMContractModule.ts +16 -16
  147. package/src/evm/contract/modules/EVMContractEvents.ts +102 -102
  148. package/src/evm/events/EVMChainEvents.ts +82 -82
  149. package/src/evm/events/EVMChainEventsBrowser.ts +524 -523
  150. package/src/evm/providers/JsonRpcProviderWithRetries.ts +26 -26
  151. package/src/evm/providers/ReconnectingWebSocketProvider.ts +101 -93
  152. package/src/evm/providers/SocketProvider.ts +368 -368
  153. package/src/evm/providers/WebSocketProviderWithRetries.ts +28 -28
  154. package/src/evm/spv_swap/EVMSpvVaultContract.ts +608 -608
  155. package/src/evm/spv_swap/EVMSpvVaultData.ts +224 -224
  156. package/src/evm/spv_swap/EVMSpvWithdrawalData.ts +70 -70
  157. package/src/evm/spv_swap/SpvVaultContractAbi.ts +846 -846
  158. package/src/evm/spv_swap/SpvVaultContractTypechain.ts +685 -685
  159. package/src/evm/swaps/EVMSwapContract.ts +600 -600
  160. package/src/evm/swaps/EVMSwapData.ts +378 -378
  161. package/src/evm/swaps/EVMSwapModule.ts +16 -16
  162. package/src/evm/swaps/EscrowManagerAbi.ts +982 -982
  163. package/src/evm/swaps/EscrowManagerTypechain.ts +723 -723
  164. package/src/evm/swaps/handlers/IHandler.ts +17 -17
  165. package/src/evm/swaps/handlers/claim/ClaimHandlers.ts +20 -20
  166. package/src/evm/swaps/handlers/claim/HashlockClaimHandler.ts +46 -46
  167. package/src/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.ts +82 -82
  168. package/src/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.ts +76 -76
  169. package/src/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.ts +46 -46
  170. package/src/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.ts +115 -115
  171. package/src/evm/swaps/handlers/refund/TimelockRefundHandler.ts +37 -37
  172. package/src/evm/swaps/modules/EVMLpVault.ts +154 -154
  173. package/src/evm/swaps/modules/EVMSwapClaim.ts +172 -172
  174. package/src/evm/swaps/modules/EVMSwapInit.ts +328 -328
  175. package/src/evm/swaps/modules/EVMSwapRefund.ts +229 -229
  176. package/src/evm/typechain/common.ts +131 -131
  177. package/src/evm/wallet/EVMSigner.ts +25 -25
  178. package/src/index.ts +52 -52
  179. package/src/utils/Utils.ts +81 -81
  180. package/dist/evm/JsonRpcProviderWithRetries.d.ts +0 -15
  181. package/dist/evm/JsonRpcProviderWithRetries.js +0 -19
  182. package/dist/evm/ReconnectingWebSocketProvider.d.ts +0 -20
  183. package/dist/evm/ReconnectingWebSocketProvider.js +0 -77
  184. package/dist/evm/SocketProvider.d.ts +0 -111
  185. package/dist/evm/SocketProvider.js +0 -334
  186. package/dist/evm/WebSocketProviderWithRetries.d.ts +0 -17
  187. package/dist/evm/WebSocketProviderWithRetries.js +0 -19
@@ -1,263 +1,263 @@
1
- import {EVMModule} from "../EVMModule";
2
- import {Transaction, TransactionRequest} from "ethers";
3
- import {timeoutPromise} from "../../../utils/Utils";
4
- import {EVMSigner} from "../../wallet/EVMSigner";
5
-
6
- export type EVMTx = TransactionRequest;
7
-
8
- export type EVMTxTrace = {
9
- from: string,
10
- gas: string,
11
- gasused: string,
12
- to: string,
13
- input: string,
14
- output: string,
15
- error: string,
16
- revertReason: string,
17
- calls: EVMTxTrace[],
18
- type: "CREATE" | "CALL" | "STATICCALL"
19
- };
20
-
21
- const MAX_UNCONFIRMED_TXNS = 10;
22
-
23
- export class EVMTransactions extends EVMModule<any> {
24
-
25
- private readonly latestConfirmedNonces: {[address: string]: number} = {};
26
-
27
- private cbkBeforeTxSigned: (tx: TransactionRequest) => Promise<void>;
28
- private cbkSendTransaction: (tx: string) => Promise<string>;
29
-
30
- /**
31
- * Waits for transaction confirmation using WS subscription and occasional HTTP polling, also re-sends
32
- * the transaction at regular interval
33
- *
34
- * @param tx EVM transaction to wait for confirmation for
35
- * @param abortSignal signal to abort waiting for tx confirmation
36
- * @private
37
- */
38
- private async confirmTransaction(tx: {nonce: number, from: string, hash: string}, abortSignal?: AbortSignal) {
39
- let state = "pending";
40
- while(state==="pending" || state==="not_found") {
41
- await timeoutPromise(3000, abortSignal);
42
- state = await this.getTxIdStatus(tx.hash);
43
- //Don't re-send transactions
44
- // if(state==="not_found") await this.sendSignedTransaction(tx).catch(e => {
45
- // if(e.baseError?.code === 59) return; //Transaction already in the mempool
46
- // this.logger.error("confirmTransaction(): Error on transaction re-send: ", e);
47
- // });
48
- }
49
- const nextAccountNonce = tx.nonce + 1;
50
- const currentNonce = this.latestConfirmedNonces[tx.from];
51
- if(currentNonce==null || nextAccountNonce > currentNonce) {
52
- this.latestConfirmedNonces[tx.from] = nextAccountNonce;
53
- }
54
- if(state==="reverted") throw new Error("Transaction reverted!");
55
- }
56
-
57
- /**
58
- * Prepares starknet transactions, checks if the account is deployed, assigns nonces if needed & calls beforeTxSigned callback
59
- *
60
- * @param signer
61
- * @param txs
62
- * @private
63
- */
64
- private async prepareTransactions(signer: EVMSigner, txs: TransactionRequest[]): Promise<void> {
65
- let nonce: number = (await signer.getNonce()) ?? await this.root.provider.getTransactionCount(signer.getAddress(), "pending");
66
- const latestConfirmedNonce = this.latestConfirmedNonces[signer.getAddress()];
67
- if(latestConfirmedNonce!=null && latestConfirmedNonce > nonce) {
68
- this.logger.debug("prepareTransactions(): Using nonce from local cache!");
69
- nonce = latestConfirmedNonce;
70
- }
71
-
72
- for(let i=0;i<txs.length;i++) {
73
- const tx = txs[i];
74
- tx.chainId = this.root.evmChainId;
75
- tx.from = signer.getAddress();
76
- if(tx.nonce!=null) nonce = tx.nonce; //Take the nonce from last tx
77
- if(nonce==null) nonce = await this.root.provider.getTransactionCount(signer.getAddress(), "pending"); //Fetch the nonce
78
- if(tx.nonce==null) tx.nonce = nonce;
79
-
80
- this.logger.debug("sendAndConfirm(): transaction prepared ("+(i+1)+"/"+txs.length+"), nonce: "+tx.nonce);
81
-
82
- nonce++;
83
-
84
- if(this.cbkBeforeTxSigned!=null) await this.cbkBeforeTxSigned(tx);
85
- }
86
- }
87
-
88
- /**
89
- * Sends out a signed transaction to the RPC
90
- *
91
- * @param tx EVM tx to send
92
- * @param onBeforePublish a callback called before every transaction is published
93
- * @private
94
- */
95
- private async sendSignedTransaction(
96
- tx: Transaction,
97
- onBeforePublish?: (txId: string, rawTx: string) => Promise<void>,
98
- ): Promise<string> {
99
- if(onBeforePublish!=null) await onBeforePublish(tx.hash, await this.serializeTx(tx));
100
- this.logger.debug("sendSignedTransaction(): sending transaction: ", tx.hash);
101
-
102
- const serializedTx = tx.serialized;
103
-
104
- let result: string;
105
- if(this.cbkSendTransaction!=null) result = await this.cbkSendTransaction(serializedTx);
106
- if(result==null) {
107
- const broadcastResult = await this.provider.broadcastTransaction(tx.serialized);
108
- result = broadcastResult.hash;
109
- }
110
-
111
- this.logger.info("sendSignedTransaction(): tx sent, txHash: "+result);
112
- return result;
113
- }
114
-
115
- /**
116
- * Prepares, signs, sends (in parallel or sequentially) & optionally waits for confirmation
117
- * of a batch of EVM transactions
118
- *
119
- * @param signer
120
- * @param txs transactions to send
121
- * @param waitForConfirmation whether to wait for transaction confirmations (this also makes sure the transactions
122
- * are re-sent at regular intervals)
123
- * @param abortSignal abort signal to abort waiting for transaction confirmations
124
- * @param parallel whether the send all the transaction at once in parallel or sequentially (such that transactions
125
- * are executed in order)
126
- * @param onBeforePublish a callback called before every transaction is published, NOTE: callback is not called when using browser-based wallet!
127
- */
128
- public async sendAndConfirm(signer: EVMSigner, txs: TransactionRequest[], waitForConfirmation?: boolean, abortSignal?: AbortSignal, parallel?: boolean, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>): Promise<string[]> {
129
- await this.prepareTransactions(signer, txs);
130
- const signedTxs: Transaction[] = [];
131
-
132
- //Don't separate the signing process from the sending when using browser-based wallet
133
- if(!signer.isBrowserWallet) for(let i=0;i<txs.length;i++) {
134
- const tx = txs[i];
135
- const signedTx = Transaction.from(await signer.account.signTransaction(tx));
136
- signedTxs.push(signedTx);
137
- this.logger.debug("sendAndConfirm(): transaction signed ("+(i+1)+"/"+txs.length+"): "+signedTx);
138
- }
139
-
140
- this.logger.debug("sendAndConfirm(): sending transactions, count: "+txs.length+
141
- " waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
142
-
143
- const txIds: string[] = [];
144
- if(parallel) {
145
- let promises: Promise<void>[] = [];
146
- for(let i=0;i<txs.length;i++) {
147
- let tx: {nonce: number, from: string, hash: string};
148
- if(signer.isBrowserWallet) {
149
- tx = await signer.account.sendTransaction(txs[i]);
150
- } else {
151
- const signedTx = signedTxs[i];
152
- await this.sendSignedTransaction(signedTx, onBeforePublish);
153
- tx = signedTx;
154
- }
155
- if(waitForConfirmation) promises.push(this.confirmTransaction(tx, abortSignal));
156
- txIds.push(tx.hash);
157
- this.logger.debug("sendAndConfirm(): transaction sent ("+(i+1)+"/"+signedTxs.length+"): "+tx.hash);
158
- if(promises.length >= MAX_UNCONFIRMED_TXNS) {
159
- await Promise.all(promises);
160
- promises = [];
161
- }
162
- }
163
- if(promises.length>0) await Promise.all(promises);
164
- } else {
165
- for(let i=0;i<txs.length;i++) {
166
- let tx: {nonce: number, from: string, hash: string};
167
- if(signer.isBrowserWallet) {
168
- tx = await signer.account.sendTransaction(txs[i]);
169
- } else {
170
- const signedTx = signedTxs[i];
171
- await this.sendSignedTransaction(signedTx, onBeforePublish);
172
- tx = signedTx;
173
- }
174
- const confirmPromise = this.confirmTransaction(tx, abortSignal);
175
- this.logger.debug("sendAndConfirm(): transaction sent ("+(i+1)+"/"+txs.length+"): "+tx.hash);
176
- //Don't await the last promise when !waitForConfirmation
177
- if(i<txs.length-1 || waitForConfirmation) await confirmPromise;
178
- txIds.push(tx.hash);
179
- }
180
- }
181
-
182
- this.logger.info("sendAndConfirm(): sent transactions, count: "+txs.length+
183
- " waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
184
-
185
- return txIds;
186
- }
187
-
188
- /**
189
- * Serializes the signed EVM transaction
190
- *
191
- * @param tx
192
- */
193
- public serializeTx(tx: Transaction): Promise<string> {
194
- return Promise.resolve(tx.serialized);
195
- }
196
-
197
- /**
198
- * Deserializes signed EVM transaction
199
- *
200
- * @param txData
201
- */
202
- public deserializeTx(txData: string): Promise<Transaction> {
203
- return Promise.resolve(Transaction.from(txData));
204
- }
205
-
206
- /**
207
- * Gets the status of the raw starknet transaction
208
- *
209
- * @param tx
210
- */
211
- public async getTxStatus(tx: string): Promise<"pending" | "success" | "not_found" | "reverted"> {
212
- const parsedTx: Transaction = await this.deserializeTx(tx);
213
- return await this.getTxIdStatus(parsedTx.hash);
214
- }
215
-
216
- /**
217
- * Gets the status of the starknet transaction with a specific txId
218
- *
219
- * @param txId
220
- */
221
- public async getTxIdStatus(txId: string): Promise<"pending" | "success" | "not_found" | "reverted"> {
222
- const txResponse = await this.provider.getTransaction(txId);
223
- if(txResponse==null) return "not_found";
224
- if(txResponse.blockHash==null) return "pending";
225
-
226
- const [safeBlockNumber, txReceipt] = await Promise.all([
227
- this.root.config.safeBlockTag==="latest" ? Promise.resolve(null) : this.provider.getBlock(this.root.config.safeBlockTag).then(res => res.number),
228
- this.provider.getTransactionReceipt(txId)
229
- ]);
230
-
231
- if(txReceipt==null || (safeBlockNumber!=null && txReceipt.blockNumber > safeBlockNumber)) return "pending";
232
- if(txReceipt.status===0) return "reverted";
233
- return "success";
234
- }
235
-
236
- public onBeforeTxSigned(callback: (tx: TransactionRequest) => Promise<void>): void {
237
- this.cbkBeforeTxSigned = callback;
238
- }
239
-
240
- public offBeforeTxSigned(callback: (tx: TransactionRequest) => Promise<void>): boolean {
241
- this.cbkBeforeTxSigned = null;
242
- return true;
243
- }
244
-
245
- public onSendTransaction(callback: (tx: string) => Promise<string>): void {
246
- this.cbkSendTransaction = callback;
247
- }
248
-
249
- public offSendTransaction(callback: (tx: string) => Promise<string>): boolean {
250
- this.cbkSendTransaction = null;
251
- return true;
252
- }
253
-
254
- public traceTransaction(txId: string): Promise<EVMTxTrace> {
255
- return this.provider.send("debug_traceTransaction", [
256
- txId,
257
- {
258
- tracer: "callTracer"
259
- }
260
- ]);
261
- }
262
-
263
- }
1
+ import {EVMModule} from "../EVMModule";
2
+ import {Transaction, TransactionRequest} from "ethers";
3
+ import {timeoutPromise} from "../../../utils/Utils";
4
+ import {EVMSigner} from "../../wallet/EVMSigner";
5
+
6
+ export type EVMTx = TransactionRequest;
7
+
8
+ export type EVMTxTrace = {
9
+ from: string,
10
+ gas: string,
11
+ gasused: string,
12
+ to: string,
13
+ input: string,
14
+ output: string,
15
+ error: string,
16
+ revertReason: string,
17
+ calls: EVMTxTrace[],
18
+ type: "CREATE" | "CALL" | "STATICCALL"
19
+ };
20
+
21
+ const MAX_UNCONFIRMED_TXNS = 10;
22
+
23
+ export class EVMTransactions extends EVMModule<any> {
24
+
25
+ private readonly latestConfirmedNonces: {[address: string]: number} = {};
26
+
27
+ private cbkBeforeTxSigned: (tx: TransactionRequest) => Promise<void>;
28
+ private cbkSendTransaction: (tx: string) => Promise<string>;
29
+
30
+ /**
31
+ * Waits for transaction confirmation using WS subscription and occasional HTTP polling, also re-sends
32
+ * the transaction at regular interval
33
+ *
34
+ * @param tx EVM transaction to wait for confirmation for
35
+ * @param abortSignal signal to abort waiting for tx confirmation
36
+ * @private
37
+ */
38
+ private async confirmTransaction(tx: {nonce: number, from: string, hash: string}, abortSignal?: AbortSignal) {
39
+ let state = "pending";
40
+ while(state==="pending" || state==="not_found") {
41
+ await timeoutPromise(3000, abortSignal);
42
+ state = await this.getTxIdStatus(tx.hash);
43
+ //Don't re-send transactions
44
+ // if(state==="not_found") await this.sendSignedTransaction(tx).catch(e => {
45
+ // if(e.baseError?.code === 59) return; //Transaction already in the mempool
46
+ // this.logger.error("confirmTransaction(): Error on transaction re-send: ", e);
47
+ // });
48
+ }
49
+ const nextAccountNonce = tx.nonce + 1;
50
+ const currentNonce = this.latestConfirmedNonces[tx.from];
51
+ if(currentNonce==null || nextAccountNonce > currentNonce) {
52
+ this.latestConfirmedNonces[tx.from] = nextAccountNonce;
53
+ }
54
+ if(state==="reverted") throw new Error("Transaction reverted!");
55
+ }
56
+
57
+ /**
58
+ * Prepares starknet transactions, checks if the account is deployed, assigns nonces if needed & calls beforeTxSigned callback
59
+ *
60
+ * @param signer
61
+ * @param txs
62
+ * @private
63
+ */
64
+ private async prepareTransactions(signer: EVMSigner, txs: TransactionRequest[]): Promise<void> {
65
+ let nonce: number = (await signer.getNonce()) ?? await this.root.provider.getTransactionCount(signer.getAddress(), "pending");
66
+ const latestConfirmedNonce = this.latestConfirmedNonces[signer.getAddress()];
67
+ if(latestConfirmedNonce!=null && latestConfirmedNonce > nonce) {
68
+ this.logger.debug("prepareTransactions(): Using nonce from local cache!");
69
+ nonce = latestConfirmedNonce;
70
+ }
71
+
72
+ for(let i=0;i<txs.length;i++) {
73
+ const tx = txs[i];
74
+ tx.chainId = this.root.evmChainId;
75
+ tx.from = signer.getAddress();
76
+ if(tx.nonce!=null) nonce = tx.nonce; //Take the nonce from last tx
77
+ if(nonce==null) nonce = await this.root.provider.getTransactionCount(signer.getAddress(), "pending"); //Fetch the nonce
78
+ if(tx.nonce==null) tx.nonce = nonce;
79
+
80
+ this.logger.debug("sendAndConfirm(): transaction prepared ("+(i+1)+"/"+txs.length+"), nonce: "+tx.nonce);
81
+
82
+ nonce++;
83
+
84
+ if(this.cbkBeforeTxSigned!=null) await this.cbkBeforeTxSigned(tx);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Sends out a signed transaction to the RPC
90
+ *
91
+ * @param tx EVM tx to send
92
+ * @param onBeforePublish a callback called before every transaction is published
93
+ * @private
94
+ */
95
+ private async sendSignedTransaction(
96
+ tx: Transaction,
97
+ onBeforePublish?: (txId: string, rawTx: string) => Promise<void>,
98
+ ): Promise<string> {
99
+ if(onBeforePublish!=null) await onBeforePublish(tx.hash, await this.serializeTx(tx));
100
+ this.logger.debug("sendSignedTransaction(): sending transaction: ", tx.hash);
101
+
102
+ const serializedTx = tx.serialized;
103
+
104
+ let result: string;
105
+ if(this.cbkSendTransaction!=null) result = await this.cbkSendTransaction(serializedTx);
106
+ if(result==null) {
107
+ const broadcastResult = await this.provider.broadcastTransaction(tx.serialized);
108
+ result = broadcastResult.hash;
109
+ }
110
+
111
+ this.logger.info("sendSignedTransaction(): tx sent, txHash: "+result);
112
+ return result;
113
+ }
114
+
115
+ /**
116
+ * Prepares, signs, sends (in parallel or sequentially) & optionally waits for confirmation
117
+ * of a batch of EVM transactions
118
+ *
119
+ * @param signer
120
+ * @param txs transactions to send
121
+ * @param waitForConfirmation whether to wait for transaction confirmations (this also makes sure the transactions
122
+ * are re-sent at regular intervals)
123
+ * @param abortSignal abort signal to abort waiting for transaction confirmations
124
+ * @param parallel whether the send all the transaction at once in parallel or sequentially (such that transactions
125
+ * are executed in order)
126
+ * @param onBeforePublish a callback called before every transaction is published, NOTE: callback is not called when using browser-based wallet!
127
+ */
128
+ public async sendAndConfirm(signer: EVMSigner, txs: TransactionRequest[], waitForConfirmation?: boolean, abortSignal?: AbortSignal, parallel?: boolean, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>): Promise<string[]> {
129
+ await this.prepareTransactions(signer, txs);
130
+ const signedTxs: Transaction[] = [];
131
+
132
+ //Don't separate the signing process from the sending when using browser-based wallet
133
+ if(!signer.isBrowserWallet) for(let i=0;i<txs.length;i++) {
134
+ const tx = txs[i];
135
+ const signedTx = Transaction.from(await signer.account.signTransaction(tx));
136
+ signedTxs.push(signedTx);
137
+ this.logger.debug("sendAndConfirm(): transaction signed ("+(i+1)+"/"+txs.length+"): "+signedTx);
138
+ }
139
+
140
+ this.logger.debug("sendAndConfirm(): sending transactions, count: "+txs.length+
141
+ " waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
142
+
143
+ const txIds: string[] = [];
144
+ if(parallel) {
145
+ let promises: Promise<void>[] = [];
146
+ for(let i=0;i<txs.length;i++) {
147
+ let tx: {nonce: number, from: string, hash: string};
148
+ if(signer.isBrowserWallet) {
149
+ tx = await signer.account.sendTransaction(txs[i]);
150
+ } else {
151
+ const signedTx = signedTxs[i];
152
+ await this.sendSignedTransaction(signedTx, onBeforePublish);
153
+ tx = signedTx;
154
+ }
155
+ if(waitForConfirmation) promises.push(this.confirmTransaction(tx, abortSignal));
156
+ txIds.push(tx.hash);
157
+ this.logger.debug("sendAndConfirm(): transaction sent ("+(i+1)+"/"+signedTxs.length+"): "+tx.hash);
158
+ if(promises.length >= MAX_UNCONFIRMED_TXNS) {
159
+ await Promise.all(promises);
160
+ promises = [];
161
+ }
162
+ }
163
+ if(promises.length>0) await Promise.all(promises);
164
+ } else {
165
+ for(let i=0;i<txs.length;i++) {
166
+ let tx: {nonce: number, from: string, hash: string};
167
+ if(signer.isBrowserWallet) {
168
+ tx = await signer.account.sendTransaction(txs[i]);
169
+ } else {
170
+ const signedTx = signedTxs[i];
171
+ await this.sendSignedTransaction(signedTx, onBeforePublish);
172
+ tx = signedTx;
173
+ }
174
+ const confirmPromise = this.confirmTransaction(tx, abortSignal);
175
+ this.logger.debug("sendAndConfirm(): transaction sent ("+(i+1)+"/"+txs.length+"): "+tx.hash);
176
+ //Don't await the last promise when !waitForConfirmation
177
+ if(i<txs.length-1 || waitForConfirmation) await confirmPromise;
178
+ txIds.push(tx.hash);
179
+ }
180
+ }
181
+
182
+ this.logger.info("sendAndConfirm(): sent transactions, count: "+txs.length+
183
+ " waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
184
+
185
+ return txIds;
186
+ }
187
+
188
+ /**
189
+ * Serializes the signed EVM transaction
190
+ *
191
+ * @param tx
192
+ */
193
+ public serializeTx(tx: Transaction): Promise<string> {
194
+ return Promise.resolve(tx.serialized);
195
+ }
196
+
197
+ /**
198
+ * Deserializes signed EVM transaction
199
+ *
200
+ * @param txData
201
+ */
202
+ public deserializeTx(txData: string): Promise<Transaction> {
203
+ return Promise.resolve(Transaction.from(txData));
204
+ }
205
+
206
+ /**
207
+ * Gets the status of the raw starknet transaction
208
+ *
209
+ * @param tx
210
+ */
211
+ public async getTxStatus(tx: string): Promise<"pending" | "success" | "not_found" | "reverted"> {
212
+ const parsedTx: Transaction = await this.deserializeTx(tx);
213
+ return await this.getTxIdStatus(parsedTx.hash);
214
+ }
215
+
216
+ /**
217
+ * Gets the status of the starknet transaction with a specific txId
218
+ *
219
+ * @param txId
220
+ */
221
+ public async getTxIdStatus(txId: string): Promise<"pending" | "success" | "not_found" | "reverted"> {
222
+ const txResponse = await this.provider.getTransaction(txId);
223
+ if(txResponse==null) return "not_found";
224
+ if(txResponse.blockHash==null) return "pending";
225
+
226
+ const [safeBlockNumber, txReceipt] = await Promise.all([
227
+ this.root.config.safeBlockTag==="latest" ? Promise.resolve(null) : this.provider.getBlock(this.root.config.safeBlockTag).then(res => res.number),
228
+ this.provider.getTransactionReceipt(txId)
229
+ ]);
230
+
231
+ if(txReceipt==null || (safeBlockNumber!=null && txReceipt.blockNumber > safeBlockNumber)) return "pending";
232
+ if(txReceipt.status===0) return "reverted";
233
+ return "success";
234
+ }
235
+
236
+ public onBeforeTxSigned(callback: (tx: TransactionRequest) => Promise<void>): void {
237
+ this.cbkBeforeTxSigned = callback;
238
+ }
239
+
240
+ public offBeforeTxSigned(callback: (tx: TransactionRequest) => Promise<void>): boolean {
241
+ this.cbkBeforeTxSigned = null;
242
+ return true;
243
+ }
244
+
245
+ public onSendTransaction(callback: (tx: string) => Promise<string>): void {
246
+ this.cbkSendTransaction = callback;
247
+ }
248
+
249
+ public offSendTransaction(callback: (tx: string) => Promise<string>): boolean {
250
+ this.cbkSendTransaction = null;
251
+ return true;
252
+ }
253
+
254
+ public traceTransaction(txId: string): Promise<EVMTxTrace> {
255
+ return this.provider.send("debug_traceTransaction", [
256
+ txId,
257
+ {
258
+ tracer: "callTracer"
259
+ }
260
+ ]);
261
+ }
262
+
263
+ }
@@ -1,63 +1,63 @@
1
- import {BaseContract, Contract, EventFragment, Log, TransactionDescription, EventLog} from "ethers";
2
- import {EVMChainInterface} from "../chain/EVMChainInterface";
3
- import {EVMContractEvents} from "./modules/EVMContractEvents";
4
- import {TypedContractMethod, TypedEventLog} from "../typechain/common";
5
-
6
- type __TypechainOutputObject<T> = T extends TypedContractMethod<
7
- infer V
8
- >
9
- ? V
10
- : never;
11
-
12
- type KeysOfType<T, ValueType> = keyof {
13
- [K in keyof T]: T[K] extends ValueType ? K : never;
14
- };
15
-
16
- export interface TypedFunctionCall<TCMethod extends TypedContractMethod>
17
- extends Omit<TransactionDescription, "args"> {
18
- args: __TypechainOutputObject<TCMethod>;
19
- }
20
-
21
- /**
22
- * Base class providing program specific utilities
23
- */
24
- export class EVMContractBase<T extends BaseContract> {
25
-
26
- contract: T;
27
-
28
- public readonly Events: EVMContractEvents<T>;
29
- public readonly Chain: EVMChainInterface<any>;
30
-
31
- public readonly contractAddress: string;
32
- public readonly contractDeploymentHeight: number;
33
-
34
- constructor(
35
- chainInterface: EVMChainInterface<any>,
36
- contractAddress: string,
37
- contractAbi: any,
38
- contractDeploymentHeight?: number,
39
- ) {
40
- this.Chain = chainInterface;
41
- this.contract = new Contract(contractAddress, contractAbi, chainInterface.provider) as unknown as T;
42
- this.Events = new EVMContractEvents<T>(chainInterface, this);
43
- this.contractAddress = contractAddress;
44
- this.contractDeploymentHeight = contractDeploymentHeight;
45
- }
46
-
47
- toTypedEvent<TEventName extends keyof T["filters"] = keyof T["filters"]>(log: Log): TypedEventLog<T["filters"][TEventName]> {
48
- let foundFragment: EventFragment;
49
- try {
50
- foundFragment = this.contract.interface.getEvent(log.topics[0]);
51
- } catch (error) { }
52
- if(!foundFragment) return null;
53
-
54
- try {
55
- return new EventLog(log, this.contract.interface, foundFragment) as unknown as TypedEventLog<T["filters"][TEventName]>;
56
- } catch (error: any) { }
57
- }
58
-
59
- parseCalldata<TMethod extends TypedContractMethod>(calldata: string): TypedFunctionCall<TMethod> {
60
- return this.contract.interface.parseTransaction({data: calldata}) as unknown as TypedFunctionCall<TMethod>;
61
- }
62
-
63
- }
1
+ import {BaseContract, Contract, EventFragment, Log, TransactionDescription, EventLog} from "ethers";
2
+ import {EVMChainInterface} from "../chain/EVMChainInterface";
3
+ import {EVMContractEvents} from "./modules/EVMContractEvents";
4
+ import {TypedContractMethod, TypedEventLog} from "../typechain/common";
5
+
6
+ type __TypechainOutputObject<T> = T extends TypedContractMethod<
7
+ infer V
8
+ >
9
+ ? V
10
+ : never;
11
+
12
+ type KeysOfType<T, ValueType> = keyof {
13
+ [K in keyof T]: T[K] extends ValueType ? K : never;
14
+ };
15
+
16
+ export interface TypedFunctionCall<TCMethod extends TypedContractMethod>
17
+ extends Omit<TransactionDescription, "args"> {
18
+ args: __TypechainOutputObject<TCMethod>;
19
+ }
20
+
21
+ /**
22
+ * Base class providing program specific utilities
23
+ */
24
+ export class EVMContractBase<T extends BaseContract> {
25
+
26
+ contract: T;
27
+
28
+ public readonly Events: EVMContractEvents<T>;
29
+ public readonly Chain: EVMChainInterface<any>;
30
+
31
+ public readonly contractAddress: string;
32
+ public readonly contractDeploymentHeight: number;
33
+
34
+ constructor(
35
+ chainInterface: EVMChainInterface<any>,
36
+ contractAddress: string,
37
+ contractAbi: any,
38
+ contractDeploymentHeight?: number,
39
+ ) {
40
+ this.Chain = chainInterface;
41
+ this.contract = new Contract(contractAddress, contractAbi, chainInterface.provider) as unknown as T;
42
+ this.Events = new EVMContractEvents<T>(chainInterface, this);
43
+ this.contractAddress = contractAddress;
44
+ this.contractDeploymentHeight = contractDeploymentHeight;
45
+ }
46
+
47
+ toTypedEvent<TEventName extends keyof T["filters"] = keyof T["filters"]>(log: Log): TypedEventLog<T["filters"][TEventName]> {
48
+ let foundFragment: EventFragment;
49
+ try {
50
+ foundFragment = this.contract.interface.getEvent(log.topics[0]);
51
+ } catch (error) { }
52
+ if(!foundFragment) return null;
53
+
54
+ try {
55
+ return new EventLog(log, this.contract.interface, foundFragment) as unknown as TypedEventLog<T["filters"][TEventName]>;
56
+ } catch (error: any) { }
57
+ }
58
+
59
+ parseCalldata<TMethod extends TypedContractMethod>(calldata: string): TypedFunctionCall<TMethod> {
60
+ return this.contract.interface.parseTransaction({data: calldata}) as unknown as TypedFunctionCall<TMethod>;
61
+ }
62
+
63
+ }