@atomiqlabs/chain-evm 2.1.12 → 2.2.0

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 (151) hide show
  1. package/README.md +75 -0
  2. package/dist/chains/EVMOptions.d.ts +66 -0
  3. package/dist/chains/EVMOptions.js +2 -0
  4. package/dist/chains/alpen/AlpenInitializer.d.ts +3 -30
  5. package/dist/chains/alpen/AlpenInitializer.js +3 -3
  6. package/dist/chains/botanix/BotanixInitializer.d.ts +3 -30
  7. package/dist/chains/botanix/BotanixInitializer.js +3 -3
  8. package/dist/chains/citrea/CitreaBtcRelay.d.ts +5 -0
  9. package/dist/chains/citrea/CitreaBtcRelay.js +7 -2
  10. package/dist/chains/citrea/CitreaFees.d.ts +3 -5
  11. package/dist/chains/citrea/CitreaFees.js +3 -5
  12. package/dist/chains/citrea/CitreaInitializer.d.ts +3 -29
  13. package/dist/chains/citrea/CitreaInitializer.js +3 -3
  14. package/dist/chains/citrea/CitreaSpvVaultContract.d.ts +5 -0
  15. package/dist/chains/citrea/CitreaSpvVaultContract.js +7 -2
  16. package/dist/chains/citrea/CitreaSwapContract.d.ts +7 -2
  17. package/dist/chains/citrea/CitreaSwapContract.js +10 -5
  18. package/dist/chains/citrea/CitreaTokens.d.ts +5 -0
  19. package/dist/chains/citrea/CitreaTokens.js +5 -0
  20. package/dist/chains/goat/GoatInitializer.d.ts +3 -30
  21. package/dist/chains/goat/GoatInitializer.js +3 -3
  22. package/dist/evm/btcrelay/EVMBtcRelay.d.ts +41 -10
  23. package/dist/evm/btcrelay/EVMBtcRelay.js +50 -18
  24. package/dist/evm/btcrelay/headers/EVMBtcHeader.d.ts +53 -7
  25. package/dist/evm/btcrelay/headers/EVMBtcHeader.js +43 -5
  26. package/dist/evm/btcrelay/headers/EVMBtcStoredHeader.d.ts +53 -8
  27. package/dist/evm/btcrelay/headers/EVMBtcStoredHeader.js +41 -1
  28. package/dist/evm/chain/EVMChainInterface.d.ts +61 -2
  29. package/dist/evm/chain/EVMChainInterface.js +14 -7
  30. package/dist/evm/chain/EVMModule.d.ts +5 -0
  31. package/dist/evm/chain/EVMModule.js +6 -1
  32. package/dist/evm/chain/modules/EVMBlocks.d.ts +7 -0
  33. package/dist/evm/chain/modules/EVMBlocks.js +2 -0
  34. package/dist/evm/chain/modules/EVMEvents.js +19 -19
  35. package/dist/evm/chain/modules/EVMFees.d.ts +41 -5
  36. package/dist/evm/chain/modules/EVMFees.js +24 -5
  37. package/dist/evm/chain/modules/EVMTokens.d.ts +1 -1
  38. package/dist/evm/chain/modules/EVMTokens.js +1 -1
  39. package/dist/evm/chain/modules/EVMTransactions.d.ts +22 -5
  40. package/dist/evm/chain/modules/EVMTransactions.js +31 -22
  41. package/dist/evm/contract/EVMContractBase.d.ts +28 -10
  42. package/dist/evm/contract/EVMContractBase.js +9 -18
  43. package/dist/evm/contract/EVMContractModule.d.ts +5 -0
  44. package/dist/evm/contract/EVMContractModule.js +5 -0
  45. package/dist/evm/contract/modules/EVMContractEvents.d.ts +7 -1
  46. package/dist/evm/contract/modules/EVMContractEvents.js +23 -3
  47. package/dist/evm/events/EVMChainEvents.d.ts +8 -0
  48. package/dist/evm/events/EVMChainEvents.js +8 -0
  49. package/dist/evm/events/EVMChainEventsBrowser.d.ts +87 -19
  50. package/dist/evm/events/EVMChainEventsBrowser.js +53 -18
  51. package/dist/evm/providers/JsonRpcProviderWithRetries.d.ts +9 -0
  52. package/dist/evm/providers/JsonRpcProviderWithRetries.js +9 -0
  53. package/dist/evm/providers/ReconnectingWebSocketProvider.d.ts +5 -0
  54. package/dist/evm/providers/ReconnectingWebSocketProvider.js +5 -0
  55. package/dist/evm/providers/WebSocketProviderWithRetries.d.ts +9 -0
  56. package/dist/evm/providers/WebSocketProviderWithRetries.js +9 -0
  57. package/dist/evm/spv_swap/EVMSpvVaultContract.d.ts +46 -21
  58. package/dist/evm/spv_swap/EVMSpvVaultContract.js +61 -23
  59. package/dist/evm/spv_swap/EVMSpvVaultData.d.ts +57 -2
  60. package/dist/evm/spv_swap/EVMSpvVaultData.js +57 -2
  61. package/dist/evm/spv_swap/EVMSpvWithdrawalData.d.ts +12 -0
  62. package/dist/evm/spv_swap/EVMSpvWithdrawalData.js +12 -0
  63. package/dist/evm/swaps/EVMSwapContract.d.ts +58 -13
  64. package/dist/evm/swaps/EVMSwapContract.js +81 -54
  65. package/dist/evm/swaps/EVMSwapData.d.ts +27 -6
  66. package/dist/evm/swaps/EVMSwapData.js +26 -0
  67. package/dist/evm/swaps/EVMSwapModule.d.ts +5 -0
  68. package/dist/evm/swaps/EVMSwapModule.js +5 -0
  69. package/dist/evm/swaps/handlers/IHandler.d.ts +5 -0
  70. package/dist/evm/swaps/handlers/claim/ClaimHandlers.d.ts +15 -0
  71. package/dist/evm/swaps/handlers/claim/ClaimHandlers.js +5 -0
  72. package/dist/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.d.ts +5 -0
  73. package/dist/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.d.ts +10 -0
  74. package/dist/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.d.ts +5 -0
  75. package/dist/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.d.ts +15 -0
  76. package/dist/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.js +7 -2
  77. package/dist/evm/swaps/modules/EVMLpVault.d.ts +5 -0
  78. package/dist/evm/swaps/modules/EVMLpVault.js +9 -4
  79. package/dist/evm/swaps/modules/EVMSwapClaim.d.ts +7 -2
  80. package/dist/evm/swaps/modules/EVMSwapClaim.js +11 -6
  81. package/dist/evm/swaps/modules/EVMSwapInit.d.ts +10 -0
  82. package/dist/evm/swaps/modules/EVMSwapInit.js +11 -6
  83. package/dist/evm/swaps/modules/EVMSwapRefund.d.ts +5 -0
  84. package/dist/evm/swaps/modules/EVMSwapRefund.js +9 -4
  85. package/dist/evm/wallet/EVMBrowserSigner.d.ts +22 -2
  86. package/dist/evm/wallet/EVMBrowserSigner.js +40 -2
  87. package/dist/evm/wallet/EVMPersistentSigner.d.ts +13 -2
  88. package/dist/evm/wallet/EVMPersistentSigner.js +13 -1
  89. package/dist/evm/wallet/EVMSigner.d.ts +30 -1
  90. package/dist/evm/wallet/EVMSigner.js +34 -1
  91. package/dist/index.d.ts +71 -0
  92. package/dist/index.js +70 -0
  93. package/dist/node/index.d.ts +10 -0
  94. package/dist/node/index.js +15 -0
  95. package/dist/utils/Utils.d.ts +50 -0
  96. package/dist/utils/Utils.js +45 -0
  97. package/node/index.d.ts +1 -0
  98. package/node/index.js +3 -0
  99. package/package.json +5 -3
  100. package/src/chains/EVMOptions.ts +70 -0
  101. package/src/chains/alpen/AlpenInitializer.ts +5 -27
  102. package/src/chains/botanix/BotanixChainType.ts +5 -5
  103. package/src/chains/botanix/BotanixInitializer.ts +5 -27
  104. package/src/chains/citrea/CitreaBtcRelay.ts +8 -3
  105. package/src/chains/citrea/CitreaFees.ts +3 -6
  106. package/src/chains/citrea/CitreaInitializer.ts +5 -27
  107. package/src/chains/citrea/CitreaSpvVaultContract.ts +7 -2
  108. package/src/chains/citrea/CitreaSwapContract.ts +11 -6
  109. package/src/chains/citrea/CitreaTokens.ts +6 -1
  110. package/src/chains/goat/GoatChainType.ts +5 -5
  111. package/src/chains/goat/GoatInitializer.ts +3 -25
  112. package/src/evm/btcrelay/EVMBtcRelay.ts +54 -22
  113. package/src/evm/btcrelay/headers/EVMBtcHeader.ts +60 -13
  114. package/src/evm/btcrelay/headers/EVMBtcStoredHeader.ts +55 -10
  115. package/src/evm/chain/EVMChainInterface.ts +74 -14
  116. package/src/evm/chain/EVMModule.ts +6 -1
  117. package/src/evm/chain/modules/EVMBlocks.ts +7 -0
  118. package/src/evm/chain/modules/EVMEvents.ts +19 -19
  119. package/src/evm/chain/modules/EVMFees.ts +41 -5
  120. package/src/evm/chain/modules/EVMTokens.ts +1 -1
  121. package/src/evm/chain/modules/EVMTransactions.ts +40 -17
  122. package/src/evm/contract/EVMContractBase.ts +29 -24
  123. package/src/evm/contract/EVMContractModule.ts +5 -0
  124. package/src/evm/contract/modules/EVMContractEvents.ts +27 -8
  125. package/src/evm/events/EVMChainEvents.ts +8 -0
  126. package/src/evm/events/EVMChainEventsBrowser.ts +103 -29
  127. package/src/evm/providers/JsonRpcProviderWithRetries.ts +10 -1
  128. package/src/evm/providers/ReconnectingWebSocketProvider.ts +6 -1
  129. package/src/evm/providers/WebSocketProviderWithRetries.ts +10 -1
  130. package/src/evm/spv_swap/EVMSpvVaultContract.ts +72 -32
  131. package/src/evm/spv_swap/EVMSpvVaultData.ts +57 -2
  132. package/src/evm/spv_swap/EVMSpvWithdrawalData.ts +12 -0
  133. package/src/evm/swaps/EVMSwapContract.ts +108 -63
  134. package/src/evm/swaps/EVMSwapData.ts +27 -1
  135. package/src/evm/swaps/EVMSwapModule.ts +5 -0
  136. package/src/evm/swaps/handlers/IHandler.ts +5 -0
  137. package/src/evm/swaps/handlers/claim/ClaimHandlers.ts +15 -0
  138. package/src/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.ts +5 -0
  139. package/src/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.ts +10 -0
  140. package/src/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.ts +5 -0
  141. package/src/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.ts +17 -2
  142. package/src/evm/swaps/modules/EVMLpVault.ts +10 -5
  143. package/src/evm/swaps/modules/EVMSwapClaim.ts +12 -7
  144. package/src/evm/swaps/modules/EVMSwapInit.ts +17 -7
  145. package/src/evm/swaps/modules/EVMSwapRefund.ts +9 -4
  146. package/src/evm/wallet/EVMBrowserSigner.ts +44 -5
  147. package/src/evm/wallet/EVMPersistentSigner.ts +14 -2
  148. package/src/evm/wallet/EVMSigner.ts +37 -1
  149. package/src/index.ts +72 -0
  150. package/src/node/index.ts +10 -0
  151. package/src/utils/Utils.ts +50 -1
@@ -10,9 +10,25 @@ import {timeoutPromise} from "../../../utils/Utils";
10
10
  import {EVMSigner} from "../../wallet/EVMSigner";
11
11
  import {TransactionRevertedError} from "@atomiqlabs/base";
12
12
 
13
+ /**
14
+ * Unsigned EVM transaction type used by chain modules.
15
+ *
16
+ * @category Chain Interface
17
+ */
13
18
  export type EVMTx = TransactionRequest;
19
+
20
+ /**
21
+ * Signed EVM transaction type as produced by ethers.
22
+ *
23
+ * @category Chain Interface
24
+ */
14
25
  export type SignedEVMTx = Transaction;
15
26
 
27
+ /**
28
+ * Simplified call-trace structure returned by `debug_traceTransaction` with `callTracer`.
29
+ *
30
+ * @category Internal/Chain
31
+ */
16
32
  export type EVMTxTrace = {
17
33
  from: string,
18
34
  gas: string,
@@ -29,6 +45,8 @@ export type EVMTxTrace = {
29
45
  const MAX_UNCONFIRMED_TXNS = 10;
30
46
 
31
47
  /**
48
+ * Transaction service for preparing, signing, broadcasting and confirming EVM transactions.
49
+ *
32
50
  * @category Internal/Chain
33
51
  */
34
52
  export class EVMTransactions extends EVMModule<any> {
@@ -84,7 +102,7 @@ export class EVMTransactions extends EVMModule<any> {
84
102
  }
85
103
  this.logger.warn("confirmTransaction(): All transactions not found, fetching the latest account nonce...");
86
104
  const _latestConfirmedNonce = this.latestConfirmedNonces[tx.from!];
87
- const currentLatestNonce = await this.provider.getTransactionCount(tx.from!, this.root.config.safeBlockTag);
105
+ const currentLatestNonce = await this.provider.getTransactionCount(tx.from!, this.root._config.safeBlockTag);
88
106
  if(_latestConfirmedNonce==null || _latestConfirmedNonce < currentLatestNonce) {
89
107
  this.latestConfirmedNonces[tx.from!] = currentLatestNonce;
90
108
  }
@@ -126,9 +144,9 @@ export class EVMTransactions extends EVMModule<any> {
126
144
  value: toBeHex(tx.value ?? 0n),
127
145
  input: tx.data,
128
146
  data: tx.data,
129
- accessList: this.root.config.defaultAccessListAddresses==null
147
+ accessList: this.root._config.defaultAccessListAddresses==null
130
148
  ? undefined
131
- : this.root.config.defaultAccessListAddresses.map(val => ({address: val, storageKeys: []}))
149
+ : this.root._config.defaultAccessListAddresses.map(val => ({address: val, storageKeys: []}))
132
150
  }, "pending"]);
133
151
  } catch (e: any) {
134
152
  //Unable to create access list, fuck it
@@ -140,22 +158,27 @@ export class EVMTransactions extends EVMModule<any> {
140
158
  }
141
159
 
142
160
  /**
143
- * Prepares starknet transactions, checks if the account is deployed, assigns nonces if needed & calls beforeTxSigned callback
161
+ * Prepares EVM transactions, assigns nonces when needed, and optionally applies access lists
162
+ * before signing.
144
163
  *
145
- * @param signer
146
164
  * @param txs
165
+ * @param signer
147
166
  * @param useAccessList Whether to use access lists for sending txns
148
- * @private
149
167
  */
150
- private async prepareTransactions(signer: EVMSigner, txs: TransactionRequest[], useAccessList?: boolean): Promise<void> {
168
+ public async prepareTransactions(txs: TransactionRequest[], signer?: EVMSigner, useAccessList?: boolean): Promise<void> {
169
+ if(txs.length===0) return;
170
+ const signerAddress = signer?.getAddress()
171
+ ?? (txs[0].from==null ? null : await resolveAddress(txs[0].from, this.provider));
172
+ if(signerAddress==null) throw new Error("Cannot get tx sender address!");
173
+
151
174
  for(let tx of txs) {
152
175
  tx.chainId = this.root.evmChainId;
153
- tx.from = signer.getAddress();
176
+ tx.from = signerAddress;
154
177
  }
155
178
 
156
- if(!signer.isManagingNoncesInternally) {
157
- let nonce: number = await this.root.provider.getTransactionCount(signer.getAddress(), "pending");
158
- const latestKnownNonce = this.latestPendingNonces[signer.getAddress()];
179
+ if(signer==null || !signer.isManagingNoncesInternally) {
180
+ let nonce: number = await this.root.provider.getTransactionCount(signerAddress, "pending");
181
+ const latestKnownNonce = this.latestPendingNonces[signerAddress];
159
182
  if(latestKnownNonce!=null && latestKnownNonce > nonce) {
160
183
  this.logger.debug("prepareTransactions(): Using nonce from local cache!");
161
184
  nonce = latestKnownNonce;
@@ -164,7 +187,7 @@ export class EVMTransactions extends EVMModule<any> {
164
187
  for(let i=0;i<txs.length;i++) {
165
188
  const tx = txs[i];
166
189
  if(tx.nonce!=null) nonce = tx.nonce; //Take the nonce from last tx
167
- if(nonce==null) nonce = await this.root.provider.getTransactionCount(signer.getAddress(), "pending"); //Fetch the nonce
190
+ if(nonce==null) nonce = await this.root.provider.getTransactionCount(signerAddress, "pending"); //Fetch the nonce
168
191
  if(tx.nonce==null) tx.nonce = nonce;
169
192
 
170
193
  this.logger.debug("sendAndConfirm(): transaction prepared ("+(i+1)+"/"+txs.length+"), nonce: "+tx.nonce);
@@ -173,7 +196,7 @@ export class EVMTransactions extends EVMModule<any> {
173
196
  }
174
197
  }
175
198
 
176
- for(let tx of txs) {
199
+ if(signer!=null) for(let tx of txs) {
177
200
  if(useAccessList) await this.applyAccessList(tx);
178
201
  for(let callback of this.cbksBeforeTxSigned) {
179
202
  await callback(tx);
@@ -227,7 +250,7 @@ export class EVMTransactions extends EVMModule<any> {
227
250
  abortSignal?: AbortSignal, parallel?: boolean, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>,
228
251
  useAccessLists?: boolean
229
252
  ): Promise<string[]> {
230
- await this.prepareTransactions(signer, txs, useAccessLists ?? this.root.config.useAccessLists);
253
+ await this.prepareTransactions(txs, signer, useAccessLists ?? this.root._config.useAccessLists);
231
254
  const signedTxs: Transaction[] = [];
232
255
 
233
256
  //Don't separate the signing process from the sending when using browser-based wallet
@@ -415,7 +438,7 @@ export class EVMTransactions extends EVMModule<any> {
415
438
  }
416
439
 
417
440
  /**
418
- * Gets the status of the raw starknet transaction
441
+ * Gets the status of a raw signed EVM transaction.
419
442
  *
420
443
  * @param tx
421
444
  */
@@ -435,9 +458,9 @@ export class EVMTransactions extends EVMModule<any> {
435
458
  if(txResponse.blockHash==null) return "pending";
436
459
 
437
460
  const [safeBlockNumber, txReceipt] = await Promise.all([
438
- this.root.config.safeBlockTag==="latest"
461
+ this.root._config.safeBlockTag==="latest"
439
462
  ? Promise.resolve(null)
440
- : this.provider.getBlock(this.root.config.safeBlockTag).then(res => res?.number ?? 0),
463
+ : this.provider.getBlock(this.root._config.safeBlockTag).then(res => res?.number ?? 0),
441
464
  this.provider.getTransactionReceipt(txId)
442
465
  ]);
443
466
 
@@ -13,23 +13,39 @@ type KeysOfType<T, ValueType> = keyof {
13
13
  [K in keyof T]: T[K] extends ValueType ? K : never;
14
14
  };
15
15
 
16
+ /**
17
+ * Typed transaction call decoded from calldata for a specific contract method.
18
+ *
19
+ * @category Internal/Contracts
20
+ */
16
21
  export interface TypedFunctionCall<TCMethod extends TypedContractMethod>
17
22
  extends Omit<TransactionDescription, "args"> {
18
23
  args: __TypechainOutputObject<TCMethod>;
19
24
  }
20
25
 
21
26
  /**
22
- * Base class providing program specific utilities
27
+ * Base contract wrapper providing typed event and calldata parsing helpers.
28
+ *
29
+ * @category Internal/Contracts
23
30
  */
24
31
  export class EVMContractBase<T extends BaseContract> {
25
32
 
26
- contract: T;
33
+ readonly contract: T;
27
34
 
28
- public readonly Events: EVMContractEvents<T>;
29
- public readonly Chain: EVMChainInterface<any>;
35
+ /**
36
+ * @internal
37
+ */
38
+ readonly _Events: EVMContractEvents<T>;
39
+ protected readonly Chain: EVMChainInterface<any>;
30
40
 
31
- public readonly contractAddress: string;
32
- public readonly contractDeploymentHeight?: number;
41
+ /**
42
+ * @internal
43
+ */
44
+ readonly _contractAddress: string;
45
+ /**
46
+ * @internal
47
+ */
48
+ readonly _contractDeploymentHeight?: number;
33
49
 
34
50
  constructor(
35
51
  chainInterface: EVMChainInterface<any>,
@@ -39,26 +55,15 @@ export class EVMContractBase<T extends BaseContract> {
39
55
  ) {
40
56
  this.Chain = chainInterface;
41
57
  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]> | null {
48
- let foundFragment: EventFragment | null = null;
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
- return null;
58
+ this._Events = new EVMContractEvents<T>(chainInterface, this);
59
+ this._contractAddress = contractAddress;
60
+ this._contractDeploymentHeight = contractDeploymentHeight;
59
61
  }
60
62
 
61
- parseCalldata<TMethod extends TypedContractMethod>(calldata: string): TypedFunctionCall<TMethod> {
63
+ /**
64
+ * @internal
65
+ */
66
+ protected parseCalldata<TMethod extends TypedContractMethod>(calldata: string): TypedFunctionCall<TMethod> {
62
67
  return this.contract.interface.parseTransaction({data: calldata}) as unknown as TypedFunctionCall<TMethod>;
63
68
  }
64
69
 
@@ -4,6 +4,11 @@ import {EVMChainInterface} from "../chain/EVMChainInterface";
4
4
  import {EVMContractBase} from "./EVMContractBase";
5
5
 
6
6
 
7
+ /**
8
+ * Base module class for EVM components tied to a specific contract wrapper.
9
+ *
10
+ * @category Internal/Contracts
11
+ */
7
12
  export class EVMContractModule<T extends BaseContract, C extends EVMContractBase<T> = EVMContractBase<T>> extends EVMModule<any> {
8
13
 
9
14
  readonly contract: C;
@@ -1,8 +1,8 @@
1
- import {BaseContract, Log} from "ethers";
1
+ import {BaseContract, EventFragment, EventLog, Log} from "ethers";
2
2
  import {EVMEvents} from "../../chain/modules/EVMEvents";
3
- import {EVMContractBase} from "../EVMContractBase";
3
+ import {EVMContractBase, TypedFunctionCall} from "../EVMContractBase";
4
4
  import {EVMChainInterface} from "../../chain/EVMChainInterface";
5
- import {TypedEventLog} from "../../typechain/common";
5
+ import {TypedContractMethod, TypedEventLog} from "../../typechain/common";
6
6
 
7
7
  function normalizeTopic(topic: string) {
8
8
  if(topic.length!==66) {
@@ -12,9 +12,14 @@ function normalizeTopic(topic: string) {
12
12
  }
13
13
 
14
14
 
15
+ /**
16
+ * Typed contract event utilities built on top of generic EVM log querying helpers.
17
+ *
18
+ * @category Internal/Contracts
19
+ */
15
20
  export class EVMContractEvents<T extends BaseContract> extends EVMEvents {
16
21
 
17
- readonly contract: EVMContractBase<T>;
22
+ private readonly contract: EVMContractBase<T>;
18
23
  readonly baseContract: T;
19
24
 
20
25
  constructor(chainInterface: EVMChainInterface<any>, contract: EVMContractBase<T>) {
@@ -23,8 +28,22 @@ export class EVMContractEvents<T extends BaseContract> extends EVMEvents {
23
28
  this.baseContract = contract.contract;
24
29
  }
25
30
 
26
- public toTypedEvents<TEventName extends keyof T["filters"]>(blockEvents: Log[]): (TypedEventLog<T["filters"][TEventName]> | null)[] {
27
- return blockEvents.map(log => this.contract.toTypedEvent<TEventName>(log));
31
+ private toTypedEvent<TEventName extends keyof T["filters"] = keyof T["filters"]>(log: Log): TypedEventLog<T["filters"][TEventName]> | null {
32
+ let foundFragment: EventFragment | null = null;
33
+ try {
34
+ foundFragment = this.baseContract.interface.getEvent(log.topics[0]);
35
+ } catch (error) { }
36
+ if(!foundFragment) return null;
37
+
38
+ try {
39
+ return new EventLog(log, this.baseContract.interface, foundFragment) as unknown as TypedEventLog<T["filters"][TEventName]>;
40
+ } catch (error: any) { }
41
+
42
+ return null;
43
+ }
44
+
45
+ toTypedEvents<TEventName extends keyof T["filters"]>(blockEvents: Log[]): (TypedEventLog<T["filters"][TEventName]> | null)[] {
46
+ return blockEvents.map(log => this.toTypedEvent<TEventName>(log));
28
47
  }
29
48
 
30
49
  private toFilter<TEventName extends keyof T["filters"]>(
@@ -83,7 +102,7 @@ export class EVMContractEvents<T extends BaseContract> extends EVMEvents {
83
102
  if(result!=null) return result;
84
103
  }
85
104
  return null;
86
- }, abortSignal, this.contract.contractDeploymentHeight);
105
+ }, abortSignal, this.contract._contractDeploymentHeight);
87
106
  }
88
107
 
89
108
  /**
@@ -111,7 +130,7 @@ export class EVMContractEvents<T extends BaseContract> extends EVMEvents {
111
130
  if(result!=null) return result;
112
131
  }
113
132
  return null;
114
- }, abortSignal, Math.max(this.contract.contractDeploymentHeight ?? 0, startHeight ?? 0));
133
+ }, abortSignal, Math.max(this.contract._contractDeploymentHeight ?? 0, startHeight ?? 0));
115
134
  }
116
135
 
117
136
  }
@@ -6,6 +6,11 @@ import {EVMSwapContract} from "../swaps/EVMSwapContract";
6
6
  import {EVMSpvVaultContract} from "../spv_swap/EVMSpvVaultContract";
7
7
 
8
8
 
9
+ /**
10
+ * Backend event listener with persisted polling cursor stored on filesystem.
11
+ *
12
+ * @category Events
13
+ */
9
14
  export class EVMChainEvents extends EVMChainEventsBrowser {
10
15
 
11
16
  private readonly directory: string;
@@ -77,6 +82,9 @@ export class EVMChainEvents extends EVMChainEventsBrowser {
77
82
  }).join(";"));
78
83
  }
79
84
 
85
+ /**
86
+ * @inheritDoc
87
+ */
80
88
  async init(noAutomaticPoll?: boolean): Promise<void> {
81
89
  if(noAutomaticPoll) return Promise.resolve();
82
90
  this.stopped = false;
@@ -24,6 +24,12 @@ const LOGS_SLIDING_WINDOW_LENGTH = 60;
24
24
 
25
25
  const PROCESSED_EVENTS_BACKLOG = 1000;
26
26
 
27
+ /**
28
+ * Current state of the EVM event listener, containing the last processed block number
29
+ * and event position.
30
+ *
31
+ * @category Events
32
+ */
27
33
  export type EVMEventListenerState = {lastBlockNumber: number, lastEvent?: {blockHash: string, logIndex: number}} | null;
28
34
 
29
35
  type AtomiqTypedEvent = (
@@ -35,6 +41,8 @@ type AtomiqTypedEvent = (
35
41
  * EVM on-chain event handler for front-end systems without access to fs, uses WS or long-polling to subscribe, might lose
36
42
  * out on some events if the network is unreliable, front-end systems should take this into consideration and not
37
43
  * rely purely on events
44
+ *
45
+ * @category Events
38
46
  */
39
47
  export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventListenerState[]> {
40
48
 
@@ -44,23 +52,59 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
44
52
  private processedEvents: string[] = [];
45
53
  private processedEventsIndex: number = 0;
46
54
 
55
+ /**
56
+ * @internal
57
+ */
47
58
  protected readonly listeners: EventListener<EVMSwapData>[] = [];
59
+ /**
60
+ * @internal
61
+ */
48
62
  protected readonly provider: JsonRpcApiProvider;
63
+ /**
64
+ * @internal
65
+ */
49
66
  protected readonly chainInterface: EVMChainInterface;
67
+ /**
68
+ * @internal
69
+ */
50
70
  protected readonly evmSwapContract: EVMSwapContract;
71
+ /**
72
+ * @internal
73
+ */
51
74
  protected readonly evmSpvVaultContract: EVMSpvVaultContract<any>;
75
+ /**
76
+ * @internal
77
+ */
52
78
  protected readonly logger = getLogger("EVMChainEventsBrowser: ");
53
79
 
80
+ /**
81
+ * @internal
82
+ */
54
83
  protected stopped: boolean = true;
84
+ /**
85
+ * @internal
86
+ */
55
87
  protected pollIntervalSeconds: number;
56
88
 
57
89
  private timeout?: any;
58
90
 
59
91
  //Websocket
92
+ /**
93
+ * @internal
94
+ */
60
95
  protected readonly spvVaultContractLogFilter: EventFilter;
96
+ /**
97
+ * @internal
98
+ */
61
99
  protected readonly swapContractLogFilter: EventFilter;
62
100
 
101
+ /**
102
+ * @internal
103
+ */
63
104
  protected unconfirmedEventQueue: AtomiqTypedEvent[] = [];
105
+ /**
106
+ * @internal
107
+ */
64
108
  protected confirmedEventQueue: {event: AtomiqTypedEvent, block: Block}[] = [];
65
109
 
66
110
  constructor(
@@ -76,10 +120,10 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
76
120
  this.pollIntervalSeconds = pollIntervalSeconds;
77
121
 
78
122
  this.spvVaultContractLogFilter = {
79
- address: this.evmSpvVaultContract.contractAddress
123
+ address: this.evmSpvVaultContract._contractAddress
80
124
  };
81
125
  this.swapContractLogFilter = {
82
- address: this.evmSwapContract.contractAddress
126
+ address: this.evmSwapContract._contractAddress
83
127
  };
84
128
  }
85
129
 
@@ -112,12 +156,12 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
112
156
  }
113
157
  }
114
158
 
115
- protected parseInitializeEvent(
159
+ private parseInitializeEvent(
116
160
  event: TypedEventLog<EscrowManager["filters"]["Initialize"]>
117
161
  ): InitializeEvent<EVMSwapData> | null {
118
162
  const escrowHash = event.args.escrowHash.substring(2);
119
163
  const claimHandlerHex = event.args.claimHandler;
120
- const claimHandler = this.evmSwapContract.claimHandlersByAddress[claimHandlerHex.toLowerCase()];
164
+ const claimHandler = this.evmSwapContract._claimHandlersByAddress[claimHandlerHex.toLowerCase()];
121
165
  if(claimHandler==null) {
122
166
  this.logger.warn("parseInitializeEvent("+escrowHash+"): Unknown claim handler with claim: "+claimHandlerHex);
123
167
  return null;
@@ -132,7 +176,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
132
176
  );
133
177
  }
134
178
 
135
- protected parseRefundEvent(
179
+ private parseRefundEvent(
136
180
  event: TypedEventLog<EscrowManager["filters"]["Refund"]>
137
181
  ): RefundEvent<EVMSwapData> {
138
182
  const escrowHash = event.args.escrowHash.substring(2);
@@ -140,12 +184,12 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
140
184
  return new RefundEvent<EVMSwapData>(escrowHash);
141
185
  }
142
186
 
143
- protected parseClaimEvent(
187
+ private parseClaimEvent(
144
188
  event: TypedEventLog<EscrowManager["filters"]["Claim"]>
145
189
  ): ClaimEvent<EVMSwapData> | null {
146
190
  const escrowHash = event.args.escrowHash.substring(2);
147
191
  const claimHandlerHex = event.args.claimHandler;
148
- const claimHandler = this.evmSwapContract.claimHandlersByAddress[claimHandlerHex.toLowerCase()];
192
+ const claimHandler = this.evmSwapContract._claimHandlersByAddress[claimHandlerHex.toLowerCase()];
149
193
  if(claimHandler==null) {
150
194
  this.logger.warn("parseClaimEvent("+escrowHash+"): Unknown claim handler with claim: "+claimHandlerHex);
151
195
  return null;
@@ -155,7 +199,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
155
199
  return new ClaimEvent<EVMSwapData>(escrowHash, witnessResult);
156
200
  }
157
201
 
158
- protected parseSpvOpenEvent(
202
+ private parseSpvOpenEvent(
159
203
  event: TypedEventLog<SpvVaultManager["filters"]["Opened"]>
160
204
  ): SpvVaultOpenEvent {
161
205
  const owner = event.args.owner;
@@ -167,7 +211,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
167
211
  return new SpvVaultOpenEvent(owner, vaultId, btcTxId, vout);
168
212
  }
169
213
 
170
- protected parseSpvDepositEvent(
214
+ private parseSpvDepositEvent(
171
215
  event: TypedEventLog<SpvVaultManager["filters"]["Deposited"]>
172
216
  ): SpvVaultDepositEvent {
173
217
  const [owner, vaultId] = unpackOwnerAndVaultId(event.args.ownerAndVaultId);
@@ -178,7 +222,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
178
222
  return new SpvVaultDepositEvent(owner, vaultId, amounts, depositCount);
179
223
  }
180
224
 
181
- protected parseSpvFrontEvent(
225
+ private parseSpvFrontEvent(
182
226
  event: TypedEventLog<SpvVaultManager["filters"]["Fronted"]>
183
227
  ): SpvVaultFrontEvent {
184
228
  const [owner, vaultId] = unpackOwnerAndVaultId(event.args.ownerAndVaultId);
@@ -193,7 +237,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
193
237
  return new SpvVaultFrontEvent(owner, vaultId, btcTxId, recipient, executionHash, amounts, frontingAddress);
194
238
  }
195
239
 
196
- protected parseSpvClaimEvent(
240
+ private parseSpvClaimEvent(
197
241
  event: TypedEventLog<SpvVaultManager["filters"]["Claimed"]>
198
242
  ): SpvVaultClaimEvent {
199
243
  const [owner, vaultId] = unpackOwnerAndVaultId(event.args.ownerAndVaultId);
@@ -211,7 +255,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
211
255
  return new SpvVaultClaimEvent(owner, vaultId, btcTxId, recipient, executionHash, amounts, caller, frontingAddress, withdrawCount);
212
256
  }
213
257
 
214
- protected parseSpvCloseEvent(
258
+ private parseSpvCloseEvent(
215
259
  event: TypedEventLog<SpvVaultManager["filters"]["Closed"]>
216
260
  ): SpvVaultCloseEvent {
217
261
  const btcTxId = Buffer.from(event.args.btcTxHash.substring(2), "hex").reverse().toString("hex");
@@ -226,7 +270,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
226
270
  * @param currentBlock
227
271
  * @protected
228
272
  */
229
- protected async processEvents(
273
+ private async processEvents(
230
274
  events : (
231
275
  TypedEventLog<EscrowManager["filters"]["Initialize" | "Refund" | "Claim"]> |
232
276
  TypedEventLog<SpvVaultManager["filters"]["Opened" | "Deposited" | "Fronted" | "Claimed" | "Closed"]>
@@ -300,7 +344,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
300
344
  }
301
345
  }
302
346
 
303
- protected async checkEventsEcrowManager(
347
+ private async checkEventsEcrowManager(
304
348
  currentBlock: Block,
305
349
  lastEvent?: {blockHash: string, logIndex: number},
306
350
  lastBlockNumber?: number
@@ -311,7 +355,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
311
355
  return {lastEvent, lastBlockNumber};
312
356
  }
313
357
  // this.logger.debug(`checkEvents(EscrowManager): Requesting logs: ${lastBlockNumber}...${currentBlock.number}`);
314
- let events = await this.evmSwapContract.Events.getContractBlockEvents(
358
+ let events = await this.evmSwapContract._Events.getContractBlockEvents(
315
359
  ["Initialize", "Claim", "Refund"],
316
360
  [],
317
361
  lastBlockNumber,
@@ -341,7 +385,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
341
385
  return {lastEvent, lastBlockNumber};
342
386
  }
343
387
 
344
- protected async checkEventsSpvVaults(
388
+ private async checkEventsSpvVaults(
345
389
  currentBlock: Block,
346
390
  lastEvent?: {blockHash: string, logIndex: number},
347
391
  lastBlockNumber?: number
@@ -352,7 +396,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
352
396
  return {lastEvent, lastBlockNumber};
353
397
  }
354
398
  // this.logger.debug(`checkEvents(SpvVaults): Requesting logs: ${lastBlockNumber}...${currentBlock.number}`);
355
- let events = await this.evmSpvVaultContract.Events.getContractBlockEvents(
399
+ let events = await this.evmSpvVaultContract._Events.getContractBlockEvents(
356
400
  ["Opened", "Deposited", "Closed", "Fronted", "Claimed"],
357
401
  [],
358
402
  lastBlockNumber,
@@ -388,8 +432,8 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
388
432
  async poll(lastState?: EVMEventListenerState[]): Promise<EVMEventListenerState[]> {
389
433
  lastState ??= [];
390
434
 
391
- const currentBlock = await this.provider.getBlock(this.chainInterface.config.safeBlockTag, false);
392
- if(currentBlock==null) throw new Error(`Cannot fetch '${this.chainInterface.config.safeBlockTag}' block!`);
435
+ const currentBlock = await this.provider.getBlock(this.chainInterface._config.safeBlockTag, false);
436
+ if(currentBlock==null) throw new Error(`Cannot fetch '${this.chainInterface._config.safeBlockTag}' block!`);
393
437
 
394
438
  const resultEscrow = await this.checkEventsEcrowManager(currentBlock, lastState?.[0]?.lastEvent, lastState?.[0]?.lastBlockNumber);
395
439
  const resultSpvVault = await this.checkEventsSpvVaults(currentBlock, lastState?.[1]?.lastEvent, lastState?.[1]?.lastBlockNumber);
@@ -405,7 +449,7 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
405
449
  /**
406
450
  * Sets up event handlers listening for swap events over websocket
407
451
  *
408
- * @protected
452
+ * @internal
409
453
  */
410
454
  protected async setupPoll(
411
455
  lastState?: EVMEventListenerState[],
@@ -428,26 +472,47 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
428
472
 
429
473
  //Websocket
430
474
 
475
+ /**
476
+ * @internal
477
+ */
431
478
  protected handleWsEvent(
432
479
  event: AtomiqTypedEvent
433
480
  ): Promise<void> {
434
- if(this.chainInterface.config.safeBlockTag==="latest" || this.chainInterface.config.safeBlockTag==="pending") {
481
+ if(this.chainInterface._config.safeBlockTag==="latest" || this.chainInterface._config.safeBlockTag==="pending") {
435
482
  return this.processEvents([event]);
436
483
  }
437
484
  this.unconfirmedEventQueue.push(event);
438
485
  return this.addOrRemoveBlockListener();
439
486
  }
440
487
 
488
+ /**
489
+ * @internal
490
+ */
441
491
  protected spvVaultContractListener?: (log: Log) => void;
492
+ /**
493
+ * @internal
494
+ */
442
495
  protected swapContractListener?: (log: Log) => void;
496
+ /**
497
+ * @internal
498
+ */
443
499
  protected blockListener?: (blockNumber: number) => Promise<void>;
500
+ /**
501
+ * @internal
502
+ */
444
503
  protected finalityCheckTimer: any;
504
+ /**
505
+ * @internal
506
+ */
445
507
  protected wsStarted: boolean = false;
446
508
 
509
+ /**
510
+ * @internal
511
+ */
447
512
  protected async checkUnconfirmedEventsFinality() {
448
513
  if(this.unconfirmedEventQueue.length>0) {
449
- const latestSafeBlock = await this.provider.getBlock(this.chainInterface.config.safeBlockTag);
450
- if(latestSafeBlock==null) throw new Error(`Failed to fetch '${this.chainInterface.config.safeBlockTag}' block!`);
514
+ const latestSafeBlock = await this.provider.getBlock(this.chainInterface._config.safeBlockTag);
515
+ if(latestSafeBlock==null) throw new Error(`Failed to fetch '${this.chainInterface._config.safeBlockTag}' block!`);
451
516
 
452
517
  const events = this.unconfirmedEventQueue.filter(event => {
453
518
  return event.blockNumber <= latestSafeBlock.number;
@@ -473,8 +538,11 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
473
538
  }
474
539
  }
475
540
 
541
+ /**
542
+ * @internal
543
+ */
476
544
  protected async addOrRemoveBlockListener() {
477
- if(this.chainInterface.config.finalityCheckStrategy?.type!=="blocks") return;
545
+ if(this.chainInterface._config.finalityCheckStrategy?.type!=="blocks") return;
478
546
  if(this.unconfirmedEventQueue.length>0 || this.confirmedEventQueue.length>0) {
479
547
  this.logger.debug(`addOrRemoveBlockListener(): Adding block listener, unconfirmed/confirmed event count: ${this.unconfirmedEventQueue.length + this.confirmedEventQueue.length}`);
480
548
  await this.provider.on("block", this.blockListener!);
@@ -484,6 +552,9 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
484
552
  }
485
553
  }
486
554
 
555
+ /**
556
+ * @internal
557
+ */
487
558
  protected async startFinalityCheckTimer() {
488
559
  let check: () => Promise<void>;
489
560
  check = async () => {
@@ -496,11 +567,14 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
496
567
  }
497
568
  }
498
569
  if(!this.wsStarted) return;
499
- this.finalityCheckTimer = setTimeout(check, this.chainInterface.config.finalityCheckStrategy?.delayMs ?? 5*1000);
570
+ this.finalityCheckTimer = setTimeout(check, this.chainInterface._config.finalityCheckStrategy?.delayMs ?? 5*1000);
500
571
  };
501
572
  await check();
502
573
  }
503
574
 
575
+ /**
576
+ * @internal
577
+ */
504
578
  protected async setupWebsocket() {
505
579
  this.wsStarted = true;
506
580
 
@@ -518,18 +592,18 @@ export class EVMChainEventsBrowser implements ChainEvents<EVMSwapData, EVMEventL
518
592
  await this.addOrRemoveBlockListener();
519
593
  }
520
594
 
521
- if(this.chainInterface.config.safeBlockTag==="safe" || this.chainInterface.config.safeBlockTag==="finalized") {
522
- if(this.chainInterface.config.finalityCheckStrategy?.type==="timer") this.startFinalityCheckTimer();
595
+ if(this.chainInterface._config.safeBlockTag==="safe" || this.chainInterface._config.safeBlockTag==="finalized") {
596
+ if(this.chainInterface._config.finalityCheckStrategy?.type==="timer") this.startFinalityCheckTimer();
523
597
  }
524
598
 
525
599
  await this.provider.on(this.spvVaultContractLogFilter, this.spvVaultContractListener = (log) => {
526
- let [event] = this.evmSpvVaultContract.Events.toTypedEvents([log]);
600
+ let [event] = this.evmSpvVaultContract._Events.toTypedEvents([log]);
527
601
  if(event==null || event.removed) return;
528
602
  this.handleWsEvent(event);
529
603
  });
530
604
 
531
605
  await this.provider.on(this.swapContractLogFilter, this.swapContractListener = (log) => {
532
- let [event] = this.evmSwapContract.Events.toTypedEvents([log]);
606
+ let [event] = this.evmSwapContract._Events.toTypedEvents([log]);
533
607
  if(event==null || event.removed) return;
534
608
  if(event.eventName!=="Initialize" && event.eventName!=="Refund" && event.eventName!=="Claim") return;
535
609
  this.handleWsEvent(event);