@atomiqlabs/chain-evm 2.3.0 → 2.4.1

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.
@@ -120,7 +120,7 @@ function initializeAlpen(options, bitcoinRpc, network) {
120
120
  maxParallelCalls: options?.evmConfig?.maxParallelCalls ?? 5,
121
121
  useAccessLists: options?.evmConfig?.useAccessLists,
122
122
  defaultAccessListAddresses: options?.evmConfig?.defaultAccessListAddresses
123
- }, options.retryPolicy, Fees);
123
+ }, options.retryPolicy, Fees, network);
124
124
  const btcRelay = new EVMBtcRelay_1.EVMBtcRelay(chainInterface, bitcoinRpc, network, options.btcRelayContract ?? defaultContractAddresses.btcRelayContract, options.btcRelayDeploymentHeight ?? defaultContractAddresses.btcRelayDeploymentHeight);
125
125
  const swapContract = new EVMSwapContract_1.EVMSwapContract(chainInterface, btcRelay, options.swapContract ?? defaultContractAddresses.swapContract, {
126
126
  refund: {
@@ -102,7 +102,7 @@ function initializeBotanix(options, bitcoinRpc, network) {
102
102
  type: "timer",
103
103
  delayMs: 1000
104
104
  }
105
- }, options.retryPolicy, Fees);
105
+ }, options.retryPolicy, Fees, network);
106
106
  const btcRelay = new EVMBtcRelay_1.EVMBtcRelay(chainInterface, bitcoinRpc, network, options.btcRelayContract ?? defaultContractAddresses.btcRelayContract, options.btcRelayDeploymentHeight ?? defaultContractAddresses.btcRelayDeploymentHeight);
107
107
  const swapContract = new EVMSwapContract_1.EVMSwapContract(chainInterface, btcRelay, options.swapContract ?? defaultContractAddresses.swapContract, {
108
108
  refund: {
@@ -111,7 +111,7 @@ function initializeCitrea(options, bitcoinRpc, network) {
111
111
  maxParallelCalls: options?.evmConfig?.maxParallelCalls ?? 5,
112
112
  useAccessLists: options?.evmConfig?.useAccessLists,
113
113
  defaultAccessListAddresses: options?.evmConfig?.defaultAccessListAddresses
114
- }, options.retryPolicy, Fees);
114
+ }, options.retryPolicy, Fees, network);
115
115
  chainInterface.Tokens = new CitreaTokens_1.CitreaTokens(chainInterface); //Override with custom token module allowing l1 state diff based fee calculation
116
116
  const btcRelay = new CitreaBtcRelay_1.CitreaBtcRelay(chainInterface, bitcoinRpc, network, options.btcRelayContract ?? defaultContractAddresses.btcRelayContract, options.btcRelayDeploymentHeight ?? defaultContractAddresses.btcRelayDeploymentHeight);
117
117
  const swapContract = new CitreaSwapContract_1.CitreaSwapContract(chainInterface, btcRelay, options.swapContract ?? defaultContractAddresses.swapContract, {
@@ -130,7 +130,7 @@ function initializeGoat(options, bitcoinRpc, network) {
130
130
  maxParallelCalls: options?.evmConfig?.maxParallelCalls ?? 5,
131
131
  useAccessLists: options?.evmConfig?.useAccessLists,
132
132
  defaultAccessListAddresses: options?.evmConfig?.defaultAccessListAddresses
133
- }, options.retryPolicy, Fees);
133
+ }, options.retryPolicy, Fees, network);
134
134
  const btcRelay = new EVMBtcRelay_1.EVMBtcRelay(chainInterface, bitcoinRpc, network, options.btcRelayContract ?? defaultContractAddresses.btcRelayContract, options.btcRelayDeploymentHeight ?? defaultContractAddresses.btcRelayDeploymentHeight);
135
135
  const swapContract = new EVMSwapContract_1.EVMSwapContract(chainInterface, btcRelay, options.swapContract ?? defaultContractAddresses.swapContract, {
136
136
  refund: {
@@ -1,4 +1,4 @@
1
- import { ChainInterface, TransactionConfirmationOptions } from "@atomiqlabs/base";
1
+ import { BitcoinNetwork, ChainInterface, TransactionConfirmationOptions } from "@atomiqlabs/base";
2
2
  import { LoggerType } from "../../utils/Utils";
3
3
  import { JsonRpcApiProvider, Signer, Transaction, TransactionRequest } from "ethers";
4
4
  import { EVMBlocks, EVMBlockTag } from "./modules/EVMBlocks";
@@ -107,7 +107,8 @@ export declare class EVMChainInterface<ChainId extends string = string> implemen
107
107
  * @internal
108
108
  */
109
109
  protected logger: LoggerType;
110
- constructor(chainId: ChainId, evmChainId: number, provider: JsonRpcApiProvider, config: EVMConfiguration, retryPolicy?: EVMRetryPolicy, evmFeeEstimator?: EVMFees);
110
+ private readonly bitcoinNetwork?;
111
+ constructor(chainId: ChainId, evmChainId: number, provider: JsonRpcApiProvider, config: EVMConfiguration, retryPolicy?: EVMRetryPolicy, evmFeeEstimator?: EVMFees, bitcoinNetwork?: BitcoinNetwork);
111
112
  /**
112
113
  * @inheritDoc
113
114
  */
@@ -184,6 +185,10 @@ export declare class EVMChainInterface<ChainId extends string = string> implemen
184
185
  * @inheritDoc
185
186
  */
186
187
  getTxIdStatus(txId: string): Promise<"not_found" | "pending" | "success" | "reverted">;
188
+ /**
189
+ * @inheritDoc
190
+ */
191
+ getTxId(signedTX: Transaction): Promise<string>;
187
192
  /**
188
193
  * @inheritDoc
189
194
  */
@@ -207,4 +212,5 @@ export declare class EVMChainInterface<ChainId extends string = string> implemen
207
212
  * @inheritDoc
208
213
  */
209
214
  wrapSigner(signer: Signer): Promise<EVMSigner>;
215
+ verifyNetwork(bitcoinNetwork: BitcoinNetwork): Promise<void>;
210
216
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EVMChainInterface = void 0;
4
+ const base_1 = require("@atomiqlabs/base");
4
5
  const Utils_1 = require("../../utils/Utils");
5
6
  const ethers_1 = require("ethers");
6
7
  const EVMBlocks_1 = require("./modules/EVMBlocks");
@@ -17,7 +18,7 @@ const EVMBrowserSigner_1 = require("../wallet/EVMBrowserSigner");
17
18
  * @category Chain Interface
18
19
  */
19
20
  class EVMChainInterface {
20
- constructor(chainId, evmChainId, provider, config, retryPolicy, evmFeeEstimator = new EVMFees_1.EVMFees(provider)) {
21
+ constructor(chainId, evmChainId, provider, config, retryPolicy, evmFeeEstimator = new EVMFees_1.EVMFees(provider), bitcoinNetwork) {
21
22
  var _a, _b, _c, _d;
22
23
  this.chainId = chainId;
23
24
  this.evmChainId = evmChainId;
@@ -28,6 +29,7 @@ class EVMChainInterface {
28
29
  (_b = this._config).finalizedBlockTag ?? (_b.finalizedBlockTag = "finalized");
29
30
  (_c = this._config).finalityCheckStrategy ?? (_c.finalityCheckStrategy = { type: "timer" });
30
31
  (_d = this._config.finalityCheckStrategy).delayMs ?? (_d.delayMs = 1000);
32
+ this.bitcoinNetwork = bitcoinNetwork;
31
33
  this.logger = (0, Utils_1.getLogger)("EVMChainInterface(" + this.evmChainId + "): ");
32
34
  this.Fees = evmFeeEstimator;
33
35
  this.Tokens = new EVMTokens_1.EVMTokens(this);
@@ -155,6 +157,15 @@ class EVMChainInterface {
155
157
  getTxIdStatus(txId) {
156
158
  return this.Transactions.getTxIdStatus(txId);
157
159
  }
160
+ /**
161
+ * @inheritDoc
162
+ */
163
+ getTxId(signedTX) {
164
+ const txId = signedTX.hash;
165
+ if (txId == null)
166
+ throw new Error("Passed transaction is not signed!");
167
+ return Promise.resolve(txId);
168
+ }
158
169
  /**
159
170
  * @inheritDoc
160
171
  */
@@ -195,5 +206,12 @@ class EVMChainInterface {
195
206
  }
196
207
  return new EVMSigner_1.EVMSigner(signer, address);
197
208
  }
209
+ async verifyNetwork(bitcoinNetwork) {
210
+ if (this.bitcoinNetwork != null && bitcoinNetwork !== this.bitcoinNetwork)
211
+ throw new Error(`Network mismatch, the chain interface was not setup for ${base_1.BitcoinNetwork[bitcoinNetwork]}, chain interface network: ${base_1.BitcoinNetwork[this.bitcoinNetwork]}`);
212
+ const network = await this.provider.getNetwork();
213
+ if (network.chainId !== BigInt(this.evmChainId))
214
+ throw new Error(`Network mismatch, the underlying RPC provider isn't using the correct chainId, expected: ${this.evmChainId}, provider returned: ${network.chainId.toString(10)}`);
215
+ }
198
216
  }
199
217
  exports.EVMChainInterface = EVMChainInterface;
@@ -247,15 +247,30 @@ class EVMSwapContract extends EVMContractBase_1.EVMContractBase {
247
247
  const escrowHash = data.getEscrowHash();
248
248
  const stateData = await this.contract.getHashState("0x" + escrowHash);
249
249
  const state = Number(stateData.state);
250
+ const initBlockHeight = Number(stateData.initBlockheight);
250
251
  const blockHeight = Number(stateData.finishBlockheight);
252
+ const getInitTxId = async () => {
253
+ const events = await this._Events.getContractBlockEvents(["Initialize"], [null, null, "0x" + escrowHash], initBlockHeight, initBlockHeight);
254
+ if (events.length === 0)
255
+ throw new Error("Initialize event not found!");
256
+ return events[0].transactionHash;
257
+ };
251
258
  switch (state) {
252
259
  case ESCROW_STATE_COMMITTED:
253
- if (data.isOfferer(signer) && await this.isExpired(signer, data))
254
- return { type: base_1.SwapCommitStateType.REFUNDABLE };
255
- return { type: base_1.SwapCommitStateType.COMMITED };
260
+ if (data.isOfferer(signer) && await this.isExpired(signer, data)) {
261
+ return {
262
+ type: base_1.SwapCommitStateType.REFUNDABLE,
263
+ getInitTxId
264
+ };
265
+ }
266
+ return {
267
+ type: base_1.SwapCommitStateType.COMMITED,
268
+ getInitTxId
269
+ };
256
270
  case ESCROW_STATE_CLAIMED:
257
271
  return {
258
272
  type: base_1.SwapCommitStateType.PAID,
273
+ getInitTxId,
259
274
  getTxBlock: async () => {
260
275
  return {
261
276
  blockTime: await this.Chain.Blocks.getBlockTime(blockHeight),
@@ -278,6 +293,7 @@ class EVMSwapContract extends EVMContractBase_1.EVMContractBase {
278
293
  case ESCROW_STATE_REFUNDED:
279
294
  return {
280
295
  type: await this.isExpired(signer, data) ? base_1.SwapCommitStateType.EXPIRED : base_1.SwapCommitStateType.NOT_COMMITED,
296
+ getInitTxId,
281
297
  getTxBlock: async () => {
282
298
  return {
283
299
  blockTime: await this.Chain.Blocks.getBlockTime(blockHeight),
@@ -358,6 +374,7 @@ class EVMSwapContract extends EVMContractBase_1.EVMContractBase {
358
374
  init: foundSwapData,
359
375
  state: {
360
376
  type: base_1.SwapCommitStateType.PAID,
377
+ getInitTxId: foundSwapData?.getInitTxId,
361
378
  getClaimTxId: () => Promise.resolve(event.transactionHash),
362
379
  getClaimResult: () => Promise.resolve(event.args.witnessResult.substring(2)),
363
380
  getTxBlock: async () => {
@@ -378,6 +395,7 @@ class EVMSwapContract extends EVMContractBase_1.EVMContractBase {
378
395
  init: foundSwapData,
379
396
  state: {
380
397
  type: isExpired ? base_1.SwapCommitStateType.EXPIRED : base_1.SwapCommitStateType.NOT_COMMITED,
398
+ getInitTxId: foundSwapData?.getInitTxId,
381
399
  getRefundTxId: () => Promise.resolve(event.transactionHash),
382
400
  getTxBlock: async () => {
383
401
  return {
@@ -399,8 +417,8 @@ class EVMSwapContract extends EVMContractBase_1.EVMContractBase {
399
417
  resultingSwaps[escrowHash] = {
400
418
  init: foundSwapData,
401
419
  state: foundSwapData.data.isOfferer(signer) && await this.isExpired(signer, foundSwapData.data)
402
- ? { type: base_1.SwapCommitStateType.REFUNDABLE }
403
- : { type: base_1.SwapCommitStateType.COMMITED }
420
+ ? { type: base_1.SwapCommitStateType.REFUNDABLE, getInitTxId: foundSwapData.getInitTxId }
421
+ : { type: base_1.SwapCommitStateType.COMMITED, getInitTxId: foundSwapData.getInitTxId }
404
422
  };
405
423
  }
406
424
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomiqlabs/chain-evm",
3
- "version": "2.3.0",
3
+ "version": "2.4.1",
4
4
  "description": "EVM specific base implementation",
5
5
  "main": "./dist/index.js",
6
6
  "types:": "./dist/index.d.ts",
@@ -27,7 +27,7 @@
27
27
  "author": "adambor",
28
28
  "license": "Apache-2.0",
29
29
  "dependencies": {
30
- "@atomiqlabs/base": "^13.3.0",
30
+ "@atomiqlabs/base": "^13.4.2",
31
31
  "@noble/hashes": "^1.8.0",
32
32
  "@scure/btc-signer": "^1.6.0",
33
33
  "buffer": "6.0.3",
@@ -145,7 +145,7 @@ export function initializeAlpen(
145
145
  maxParallelCalls: options?.evmConfig?.maxParallelCalls ?? 5,
146
146
  useAccessLists: options?.evmConfig?.useAccessLists,
147
147
  defaultAccessListAddresses: options?.evmConfig?.defaultAccessListAddresses
148
- }, options.retryPolicy, Fees);
148
+ }, options.retryPolicy, Fees, network);
149
149
 
150
150
  const btcRelay = new EVMBtcRelay(
151
151
  chainInterface, bitcoinRpc, network, options.btcRelayContract ?? defaultContractAddresses.btcRelayContract,
@@ -127,7 +127,7 @@ export function initializeBotanix(
127
127
  type: "timer",
128
128
  delayMs: 1000
129
129
  }
130
- }, options.retryPolicy, Fees);
130
+ }, options.retryPolicy, Fees, network);
131
131
 
132
132
  const btcRelay = new EVMBtcRelay(
133
133
  chainInterface, bitcoinRpc, network, options.btcRelayContract ?? defaultContractAddresses.btcRelayContract,
@@ -135,7 +135,7 @@ export function initializeCitrea(
135
135
  maxParallelCalls: options?.evmConfig?.maxParallelCalls ?? 5,
136
136
  useAccessLists: options?.evmConfig?.useAccessLists,
137
137
  defaultAccessListAddresses: options?.evmConfig?.defaultAccessListAddresses
138
- }, options.retryPolicy, Fees);
138
+ }, options.retryPolicy, Fees, network);
139
139
  chainInterface.Tokens = new CitreaTokens(chainInterface); //Override with custom token module allowing l1 state diff based fee calculation
140
140
 
141
141
  const btcRelay = new CitreaBtcRelay(
@@ -155,7 +155,7 @@ export function initializeGoat(
155
155
  maxParallelCalls: options?.evmConfig?.maxParallelCalls ?? 5,
156
156
  useAccessLists: options?.evmConfig?.useAccessLists,
157
157
  defaultAccessListAddresses: options?.evmConfig?.defaultAccessListAddresses
158
- }, options.retryPolicy, Fees);
158
+ }, options.retryPolicy, Fees, network);
159
159
 
160
160
  const btcRelay = new EVMBtcRelay(
161
161
  chainInterface, bitcoinRpc, network, options.btcRelayContract ?? defaultContractAddresses.btcRelayContract,
@@ -1,4 +1,4 @@
1
- import {ChainInterface, TransactionConfirmationOptions} from "@atomiqlabs/base";
1
+ import {BitcoinNetwork, ChainInterface, TransactionConfirmationOptions} from "@atomiqlabs/base";
2
2
  import {getLogger, LoggerType} from "../../utils/Utils";
3
3
  import {
4
4
  BrowserProvider,
@@ -128,13 +128,16 @@ export class EVMChainInterface<ChainId extends string = string> implements Chain
128
128
  */
129
129
  protected logger: LoggerType;
130
130
 
131
+ private readonly bitcoinNetwork?: BitcoinNetwork;
132
+
131
133
  constructor(
132
134
  chainId: ChainId,
133
135
  evmChainId: number,
134
136
  provider: JsonRpcApiProvider,
135
137
  config: EVMConfiguration,
136
138
  retryPolicy?: EVMRetryPolicy,
137
- evmFeeEstimator: EVMFees = new EVMFees(provider)
139
+ evmFeeEstimator: EVMFees = new EVMFees(provider),
140
+ bitcoinNetwork?: BitcoinNetwork
138
141
  ) {
139
142
  this.chainId = chainId;
140
143
  this.evmChainId = evmChainId;
@@ -146,6 +149,8 @@ export class EVMChainInterface<ChainId extends string = string> implements Chain
146
149
  this._config.finalityCheckStrategy ??= {type: "timer"};
147
150
  this._config.finalityCheckStrategy.delayMs ??= 1000;
148
151
 
152
+ this.bitcoinNetwork = bitcoinNetwork;
153
+
149
154
  this.logger = getLogger("EVMChainInterface("+this.evmChainId+"): ");
150
155
 
151
156
  this.Fees = evmFeeEstimator;
@@ -307,6 +312,15 @@ export class EVMChainInterface<ChainId extends string = string> implements Chain
307
312
  return this.Transactions.getTxIdStatus(txId);
308
313
  }
309
314
 
315
+ /**
316
+ * @inheritDoc
317
+ */
318
+ getTxId(signedTX: Transaction): Promise<string> {
319
+ const txId = signedTX.hash;
320
+ if(txId==null) throw new Error("Passed transaction is not signed!");
321
+ return Promise.resolve(txId);
322
+ }
323
+
310
324
  /**
311
325
  * @inheritDoc
312
326
  */
@@ -358,4 +372,13 @@ export class EVMChainInterface<ChainId extends string = string> implements Chain
358
372
  return new EVMSigner(signer, address);
359
373
  }
360
374
 
375
+ async verifyNetwork(bitcoinNetwork: BitcoinNetwork): Promise<void> {
376
+ if(this.bitcoinNetwork!=null && bitcoinNetwork!==this.bitcoinNetwork)
377
+ throw new Error(`Network mismatch, the chain interface was not setup for ${BitcoinNetwork[bitcoinNetwork]}, chain interface network: ${BitcoinNetwork[this.bitcoinNetwork]}`);
378
+
379
+ const network = await this.provider.getNetwork();
380
+ if(network.chainId!==BigInt(this.evmChainId))
381
+ throw new Error(`Network mismatch, the underlying RPC provider isn't using the correct chainId, expected: ${this.evmChainId}, provider returned: ${network.chainId.toString(10)}`);
382
+ }
383
+
361
384
  }
@@ -333,14 +333,35 @@ export class EVMSwapContract<ChainId extends string = string>
333
333
  const escrowHash = data.getEscrowHash();
334
334
  const stateData = await this.contract.getHashState("0x"+escrowHash);
335
335
  const state = Number(stateData.state);
336
+ const initBlockHeight = Number(stateData.initBlockheight);
336
337
  const blockHeight = Number(stateData.finishBlockheight);
338
+
339
+ const getInitTxId = async () => {
340
+ const events = await this._Events.getContractBlockEvents(
341
+ ["Initialize"],
342
+ [null, null, "0x"+escrowHash],
343
+ initBlockHeight, initBlockHeight
344
+ );
345
+ if(events.length===0) throw new Error("Initialize event not found!");
346
+ return events[0].transactionHash;
347
+ }
348
+
337
349
  switch(state) {
338
350
  case ESCROW_STATE_COMMITTED:
339
- if(data.isOfferer(signer) && await this.isExpired(signer,data)) return {type: SwapCommitStateType.REFUNDABLE};
340
- return {type: SwapCommitStateType.COMMITED};
351
+ if(data.isOfferer(signer) && await this.isExpired(signer,data)) {
352
+ return {
353
+ type: SwapCommitStateType.REFUNDABLE,
354
+ getInitTxId
355
+ };
356
+ }
357
+ return {
358
+ type: SwapCommitStateType.COMMITED,
359
+ getInitTxId
360
+ };
341
361
  case ESCROW_STATE_CLAIMED:
342
362
  return {
343
363
  type: SwapCommitStateType.PAID,
364
+ getInitTxId,
344
365
  getTxBlock: async () => {
345
366
  return {
346
367
  blockTime: await this.Chain.Blocks.getBlockTime(blockHeight),
@@ -369,6 +390,7 @@ export class EVMSwapContract<ChainId extends string = string>
369
390
  case ESCROW_STATE_REFUNDED:
370
391
  return {
371
392
  type: await this.isExpired(signer, data) ? SwapCommitStateType.EXPIRED : SwapCommitStateType.NOT_COMMITED,
393
+ getInitTxId,
372
394
  getTxBlock: async () => {
373
395
  return {
374
396
  blockTime: await this.Chain.Blocks.getBlockTime(blockHeight),
@@ -493,6 +515,7 @@ export class EVMSwapContract<ChainId extends string = string>
493
515
  init: foundSwapData,
494
516
  state: {
495
517
  type: SwapCommitStateType.PAID,
518
+ getInitTxId: foundSwapData?.getInitTxId,
496
519
  getClaimTxId: () => Promise.resolve(event.transactionHash),
497
520
  getClaimResult: () => Promise.resolve(event.args.witnessResult.substring(2)),
498
521
  getTxBlock: async () => {
@@ -513,6 +536,7 @@ export class EVMSwapContract<ChainId extends string = string>
513
536
  init: foundSwapData,
514
537
  state: {
515
538
  type: isExpired ? SwapCommitStateType.EXPIRED : SwapCommitStateType.NOT_COMMITED,
539
+ getInitTxId: foundSwapData?.getInitTxId,
516
540
  getRefundTxId: () => Promise.resolve(event.transactionHash),
517
541
  getTxBlock: async () => {
518
542
  return {
@@ -547,8 +571,8 @@ export class EVMSwapContract<ChainId extends string = string>
547
571
  resultingSwaps[escrowHash] = {
548
572
  init: foundSwapData,
549
573
  state: foundSwapData.data.isOfferer(signer) && await this.isExpired(signer, foundSwapData.data)
550
- ? {type: SwapCommitStateType.REFUNDABLE}
551
- : {type: SwapCommitStateType.COMMITED}
574
+ ? {type: SwapCommitStateType.REFUNDABLE, getInitTxId: foundSwapData.getInitTxId}
575
+ : {type: SwapCommitStateType.COMMITED, getInitTxId: foundSwapData.getInitTxId}
552
576
  }
553
577
  }
554
578