@atomiqlabs/chain-starknet 8.3.0 → 8.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.
@@ -69,7 +69,7 @@ function initializeStarknet(options, bitcoinRpc, network) {
69
69
  const Fees = options.fees ?? new StarknetFees_1.StarknetFees(provider);
70
70
  const chainId = options.chainId ??
71
71
  (network === base_1.BitcoinNetwork.MAINNET ? starknet_1.constants.StarknetChainId.SN_MAIN : starknet_1.constants.StarknetChainId.SN_SEPOLIA);
72
- const chainInterface = new StarknetChainInterface_1.StarknetChainInterface(chainId, provider, wsChannel, Fees, options.starknetConfig);
72
+ const chainInterface = new StarknetChainInterface_1.StarknetChainInterface(chainId, provider, wsChannel, Fees, options.starknetConfig, network);
73
73
  const btcRelay = new StarknetBtcRelay_1.StarknetBtcRelay(chainInterface, bitcoinRpc, network, options.btcRelayContract, options.btcRelayContractDeploymentHeight);
74
74
  const swapContract = new StarknetSwapContract_1.StarknetSwapContract(chainInterface, btcRelay, options.swapContract, options.handlerContracts, options.swapContractDeploymentHeight);
75
75
  const spvVaultContract = new StarknetSpvVaultContract_1.StarknetSpvVaultContract(chainInterface, btcRelay, bitcoinRpc, options.spvVaultContract, options.spvVaultContractDeploymentHeight);
@@ -6,7 +6,7 @@ import { StarknetEvents } from "./modules/StarknetEvents";
6
6
  import { StarknetSignatures } from "./modules/StarknetSignatures";
7
7
  import { StarknetAccounts } from "./modules/StarknetAccounts";
8
8
  import { StarknetBlocks } from "./modules/StarknetBlocks";
9
- import { ChainInterface, TransactionConfirmationOptions } from "@atomiqlabs/base";
9
+ import { BitcoinNetwork, ChainInterface, TransactionConfirmationOptions } from "@atomiqlabs/base";
10
10
  import { StarknetSigner } from "../wallet/StarknetSigner";
11
11
  /**
12
12
  * Configuration options for Starknet chain interface
@@ -64,7 +64,8 @@ export declare class StarknetChainInterface implements ChainInterface<StarknetTx
64
64
  readonly Accounts: StarknetAccounts;
65
65
  readonly Blocks: StarknetBlocks;
66
66
  readonly config: StarknetConfig;
67
- constructor(chainId: constants.StarknetChainId, provider: Provider, wsChannel?: WebSocketChannel, feeEstimator?: StarknetFees, options?: StarknetConfig);
67
+ private readonly bitcoinNetwork?;
68
+ constructor(chainId: constants.StarknetChainId, provider: Provider, wsChannel?: WebSocketChannel, feeEstimator?: StarknetFees, options?: StarknetConfig, bitcoinNetwork?: BitcoinNetwork);
68
69
  /**
69
70
  * @inheritDoc
70
71
  */
@@ -137,6 +138,10 @@ export declare class StarknetChainInterface implements ChainInterface<StarknetTx
137
138
  * @inheritDoc
138
139
  */
139
140
  deserializeSignedTx(txData: string): Promise<SignedStarknetTx>;
141
+ /**
142
+ * @inheritDoc
143
+ */
144
+ getTxId(signedTX: SignedStarknetTx): Promise<string>;
140
145
  /**
141
146
  * @inheritDoc
142
147
  */
@@ -164,4 +169,5 @@ export declare class StarknetChainInterface implements ChainInterface<StarknetTx
164
169
  * @inheritDoc
165
170
  */
166
171
  wrapSigner(signer: Account): Promise<StarknetSigner>;
172
+ verifyNetwork(bitcoinNetwork: BitcoinNetwork): Promise<void>;
167
173
  }
@@ -11,6 +11,7 @@ const StarknetEvents_1 = require("./modules/StarknetEvents");
11
11
  const StarknetSignatures_1 = require("./modules/StarknetSignatures");
12
12
  const StarknetAccounts_1 = require("./modules/StarknetAccounts");
13
13
  const StarknetBlocks_1 = require("./modules/StarknetBlocks");
14
+ const base_1 = require("@atomiqlabs/base");
14
15
  const StarknetSigner_1 = require("../wallet/StarknetSigner");
15
16
  const buffer_1 = require("buffer");
16
17
  const StarknetKeypairWallet_1 = require("../wallet/accounts/StarknetKeypairWallet");
@@ -21,7 +22,7 @@ const StarknetBrowserSigner_1 = require("../wallet/StarknetBrowserSigner");
21
22
  * @category Chain Interface
22
23
  */
23
24
  class StarknetChainInterface {
24
- constructor(chainId, provider, wsChannel, feeEstimator = new StarknetFees_1.StarknetFees(provider), options) {
25
+ constructor(chainId, provider, wsChannel, feeEstimator = new StarknetFees_1.StarknetFees(provider), options, bitcoinNetwork) {
25
26
  var _a, _b, _c, _d;
26
27
  this.chainId = "STARKNET";
27
28
  this.starknetChainId = chainId;
@@ -39,6 +40,7 @@ class StarknetChainInterface {
39
40
  this.Events = new StarknetEvents_1.StarknetEvents(this);
40
41
  this.Accounts = new StarknetAccounts_1.StarknetAccounts(this);
41
42
  this.Blocks = new StarknetBlocks_1.StarknetBlocks(this);
43
+ this.bitcoinNetwork = bitcoinNetwork;
42
44
  }
43
45
  /**
44
46
  * @inheritDoc
@@ -154,6 +156,12 @@ class StarknetChainInterface {
154
156
  deserializeSignedTx(txData) {
155
157
  return Promise.resolve(StarknetTransactions_1.StarknetTransactions.deserializeTx(txData));
156
158
  }
159
+ /**
160
+ * @inheritDoc
161
+ */
162
+ getTxId(signedTX) {
163
+ return Promise.resolve(signedTX.txId ?? (0, Utils_1.calculateHash)(signedTX));
164
+ }
157
165
  /**
158
166
  * @inheritDoc
159
167
  */
@@ -201,5 +209,16 @@ class StarknetChainInterface {
201
209
  return Promise.resolve(new StarknetSigner_1.StarknetSigner(signer));
202
210
  }
203
211
  }
212
+ async verifyNetwork(bitcoinNetwork) {
213
+ if (this.bitcoinNetwork != null && bitcoinNetwork !== this.bitcoinNetwork)
214
+ throw new Error(`Network mismatch, the chain interface was not setup for ${base_1.BitcoinNetwork[bitcoinNetwork]}, chain interface network: ${base_1.BitcoinNetwork[this.bitcoinNetwork]}`);
215
+ const chainId = await this.provider.getChainId();
216
+ if (chainId !== starknet_1.constants.StarknetChainId.SN_MAIN && chainId !== starknet_1.constants.StarknetChainId.SN_SEPOLIA) {
217
+ starknet_1.logger.warn(`verifyNetwork(): Using non-standard chainId ${chainId}, skipping network verfication!`);
218
+ return;
219
+ }
220
+ if (this.starknetChainId !== chainId)
221
+ throw new Error(`Network mismatch, the underlying RPC provider isn't using the correct chainId, expected: ${this.starknetChainId}, provider returned: ${chainId}`);
222
+ }
204
223
  }
205
224
  exports.StarknetChainInterface = StarknetChainInterface;
@@ -52,7 +52,7 @@ export type StarknetTx = StarknetTxInvoke | StarknetTxDeployAccount;
52
52
  * Represents a signed Starknet transactions, which can either be an "INVOKE" or "DEPLOY_ACCOUNT" type, use the
53
53
  * {@link isStarknetTxInvoke} & {@link isStarknetTxDeployAccount} to narrow down the type.
54
54
  *
55
- * @remark For Starknet this is just an alias for {@link StarknetTx}
55
+ * @remarks For Starknet this is just an alias for {@link StarknetTx}
56
56
  *
57
57
  * @category Chain Interface
58
58
  */
@@ -299,15 +299,30 @@ class StarknetSwapContract extends StarknetContractBase_1.StarknetContractBase {
299
299
  const escrowHash = data.getEscrowHash();
300
300
  const stateData = await this.contract.get_hash_state("0x" + escrowHash);
301
301
  const state = Number(stateData.state);
302
+ const initBlockHeight = Number(stateData.init_blockheight);
302
303
  const blockHeight = Number(stateData.finish_blockheight);
304
+ const getInitTxId = async () => {
305
+ const events = await this._Events.getContractBlockEvents(["escrow_manager::events::Initialize"], [null, null, null, "0x" + escrowHash], initBlockHeight, initBlockHeight);
306
+ if (events.length === 0)
307
+ throw new Error("Initialize event not found!");
308
+ return events[0].txHash;
309
+ };
303
310
  switch (state) {
304
311
  case ESCROW_STATE_COMMITTED:
305
- if (data.isOfferer(signer) && await this.isExpired(signer, data))
306
- return { type: base_1.SwapCommitStateType.REFUNDABLE };
307
- return { type: base_1.SwapCommitStateType.COMMITED };
312
+ if (data.isOfferer(signer) && await this.isExpired(signer, data)) {
313
+ return {
314
+ type: base_1.SwapCommitStateType.REFUNDABLE,
315
+ getInitTxId
316
+ };
317
+ }
318
+ return {
319
+ type: base_1.SwapCommitStateType.COMMITED,
320
+ getInitTxId
321
+ };
308
322
  case ESCROW_STATE_CLAIMED:
309
323
  return {
310
324
  type: base_1.SwapCommitStateType.PAID,
325
+ getInitTxId,
311
326
  getTxBlock: async () => {
312
327
  return {
313
328
  blockTime: await this.Chain.Blocks.getBlockTime(blockHeight),
@@ -336,6 +351,7 @@ class StarknetSwapContract extends StarknetContractBase_1.StarknetContractBase {
336
351
  case ESCROW_STATE_REFUNDED:
337
352
  return {
338
353
  type: await this.isExpired(signer, data) ? base_1.SwapCommitStateType.EXPIRED : base_1.SwapCommitStateType.NOT_COMMITED,
354
+ getInitTxId,
339
355
  getTxBlock: async () => {
340
356
  return {
341
357
  blockTime: await this.Chain.Blocks.getBlockTime(blockHeight),
@@ -435,6 +451,7 @@ class StarknetSwapContract extends StarknetContractBase_1.StarknetContractBase {
435
451
  },
436
452
  state: {
437
453
  type: base_1.SwapCommitStateType.PAID,
454
+ getInitTxId: foundSwapData?.getInitTxId,
438
455
  getClaimTxId: () => Promise.resolve(event.txHash),
439
456
  getClaimResult: () => Promise.resolve(claimHandler.parseWitnessResult(event.params.witness_result)),
440
457
  getTxBlock: async () => {
@@ -462,6 +479,7 @@ class StarknetSwapContract extends StarknetContractBase_1.StarknetContractBase {
462
479
  },
463
480
  state: {
464
481
  type: isExpired ? base_1.SwapCommitStateType.EXPIRED : base_1.SwapCommitStateType.NOT_COMMITED,
482
+ getInitTxId: foundSwapData?.getInitTxId,
465
483
  getRefundTxId: () => Promise.resolve(event.txHash),
466
484
  getTxBlock: async () => {
467
485
  return {
@@ -489,8 +507,8 @@ class StarknetSwapContract extends StarknetContractBase_1.StarknetContractBase {
489
507
  getTxBlock: foundSwapData.getTxBlock
490
508
  },
491
509
  state: data.isOfferer(signer) && await this.isExpired(signer, data)
492
- ? { type: base_1.SwapCommitStateType.REFUNDABLE }
493
- : { type: base_1.SwapCommitStateType.COMMITED }
510
+ ? { type: base_1.SwapCommitStateType.REFUNDABLE, getInitTxId: foundSwapData.getInitTxId }
511
+ : { type: base_1.SwapCommitStateType.COMMITED, getInitTxId: foundSwapData.getInitTxId }
494
512
  };
495
513
  }
496
514
  await Promise.all(promises);
@@ -311,7 +311,7 @@ function replaceBigInts(obj) {
311
311
  if (Array.isArray(value)) {
312
312
  return value.map(replace);
313
313
  }
314
- const mapped = Object.create(Object.getPrototypeOf(value));
314
+ const mapped = {};
315
315
  for (const key of Object.keys(value)) {
316
316
  mapped[key] = replace(value[key]);
317
317
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomiqlabs/chain-starknet",
3
- "version": "8.3.0",
3
+ "version": "8.4.1",
4
4
  "description": "Starknet specific base implementation",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -31,7 +31,7 @@
31
31
  "url": "git+https://github.com/atomiqlabs/atomiq-chain-starknet.git"
32
32
  },
33
33
  "dependencies": {
34
- "@atomiqlabs/base": "^13.3.0",
34
+ "@atomiqlabs/base": "^13.4.2",
35
35
  "@noble/hashes": "^1.7.1",
36
36
  "@scure/btc-signer": "^1.6.0",
37
37
  "abi-wan-kanabi": "2.2.4",
@@ -152,7 +152,7 @@ export function initializeStarknet(
152
152
  const chainId = options.chainId ??
153
153
  (network===BitcoinNetwork.MAINNET ? constants.StarknetChainId.SN_MAIN : constants.StarknetChainId.SN_SEPOLIA);
154
154
 
155
- const chainInterface = new StarknetChainInterface(chainId, provider, wsChannel, Fees, options.starknetConfig);
155
+ const chainInterface = new StarknetChainInterface(chainId, provider, wsChannel, Fees, options.starknetConfig, network);
156
156
 
157
157
  const btcRelay = new StarknetBtcRelay(
158
158
  chainInterface, bitcoinRpc, network, options.btcRelayContract, options.btcRelayContractDeploymentHeight
@@ -1,5 +1,5 @@
1
- import {Provider, constants, stark, ec, Account, provider, wallet, WebSocketChannel} from "starknet";
2
- import {getLogger, toHex} from "../../utils/Utils";
1
+ import {Provider, constants, stark, ec, Account, provider, wallet, WebSocketChannel, logger} from "starknet";
2
+ import {calculateHash, getLogger, toHex} from "../../utils/Utils";
3
3
  import {SignedStarknetTx, StarknetTransactions, StarknetTx} from "./modules/StarknetTransactions";
4
4
  import {StarknetFees} from "./modules/StarknetFees";
5
5
  import {StarknetAddresses} from "./modules/StarknetAddresses";
@@ -8,7 +8,7 @@ import {StarknetEvents} from "./modules/StarknetEvents";
8
8
  import {StarknetSignatures} from "./modules/StarknetSignatures";
9
9
  import {StarknetAccounts} from "./modules/StarknetAccounts";
10
10
  import {StarknetBlocks} from "./modules/StarknetBlocks";
11
- import {ChainInterface, TransactionConfirmationOptions} from "@atomiqlabs/base";
11
+ import {BitcoinNetwork, ChainInterface, TransactionConfirmationOptions} from "@atomiqlabs/base";
12
12
  import {StarknetSigner} from "../wallet/StarknetSigner";
13
13
  import {Buffer} from "buffer";
14
14
  import {StarknetKeypairWallet} from "../wallet/accounts/StarknetKeypairWallet";
@@ -76,12 +76,15 @@ export class StarknetChainInterface implements ChainInterface<StarknetTx, Signed
76
76
 
77
77
  public readonly config: StarknetConfig;
78
78
 
79
+ private readonly bitcoinNetwork?: BitcoinNetwork;
80
+
79
81
  constructor(
80
82
  chainId: constants.StarknetChainId,
81
83
  provider: Provider,
82
84
  wsChannel?: WebSocketChannel,
83
85
  feeEstimator: StarknetFees = new StarknetFees(provider),
84
- options?: StarknetConfig
86
+ options?: StarknetConfig,
87
+ bitcoinNetwork?: BitcoinNetwork
85
88
  ) {
86
89
  this.starknetChainId = chainId;
87
90
  this.provider = provider;
@@ -100,6 +103,8 @@ export class StarknetChainInterface implements ChainInterface<StarknetTx, Signed
100
103
  this.Events = new StarknetEvents(this);
101
104
  this.Accounts = new StarknetAccounts(this);
102
105
  this.Blocks = new StarknetBlocks(this);
106
+
107
+ this.bitcoinNetwork = bitcoinNetwork;
103
108
  }
104
109
 
105
110
  /**
@@ -247,6 +252,13 @@ export class StarknetChainInterface implements ChainInterface<StarknetTx, Signed
247
252
  return Promise.resolve(StarknetTransactions.deserializeTx(txData));
248
253
  }
249
254
 
255
+ /**
256
+ * @inheritDoc
257
+ */
258
+ getTxId(signedTX: SignedStarknetTx): Promise<string> {
259
+ return Promise.resolve(signedTX.txId ?? calculateHash(signedTX));
260
+ }
261
+
250
262
  /**
251
263
  * @inheritDoc
252
264
  */
@@ -305,4 +317,18 @@ export class StarknetChainInterface implements ChainInterface<StarknetTx, Signed
305
317
  }
306
318
  }
307
319
 
320
+ async verifyNetwork(bitcoinNetwork: BitcoinNetwork): Promise<void> {
321
+ if(this.bitcoinNetwork!=null && bitcoinNetwork!==this.bitcoinNetwork)
322
+ throw new Error(`Network mismatch, the chain interface was not setup for ${BitcoinNetwork[bitcoinNetwork]}, chain interface network: ${BitcoinNetwork[this.bitcoinNetwork]}`);
323
+
324
+ const chainId = await this.provider.getChainId();
325
+ if(chainId!==constants.StarknetChainId.SN_MAIN && chainId!==constants.StarknetChainId.SN_SEPOLIA) {
326
+ logger.warn(`verifyNetwork(): Using non-standard chainId ${chainId}, skipping network verfication!`);
327
+ return;
328
+ }
329
+
330
+ if(this.starknetChainId!==chainId)
331
+ throw new Error(`Network mismatch, the underlying RPC provider isn't using the correct chainId, expected: ${this.starknetChainId}, provider returned: ${chainId}`);
332
+ }
333
+
308
334
  }
@@ -97,7 +97,7 @@ export type StarknetTx = StarknetTxInvoke | StarknetTxDeployAccount;
97
97
  * Represents a signed Starknet transactions, which can either be an "INVOKE" or "DEPLOY_ACCOUNT" type, use the
98
98
  * {@link isStarknetTxInvoke} & {@link isStarknetTxDeployAccount} to narrow down the type.
99
99
  *
100
- * @remark For Starknet this is just an alias for {@link StarknetTx}
100
+ * @remarks For Starknet this is just an alias for {@link StarknetTx}
101
101
  *
102
102
  * @category Chain Interface
103
103
  */
@@ -375,14 +375,35 @@ export class StarknetSwapContract
375
375
  const escrowHash = data.getEscrowHash();
376
376
  const stateData = await this.contract.get_hash_state("0x"+escrowHash);
377
377
  const state = Number(stateData.state);
378
+ const initBlockHeight = Number(stateData.init_blockheight);
378
379
  const blockHeight = Number(stateData.finish_blockheight);
380
+
381
+ const getInitTxId = async () => {
382
+ const events = await this._Events.getContractBlockEvents(
383
+ ["escrow_manager::events::Initialize"],
384
+ [null, null, null, "0x"+escrowHash],
385
+ initBlockHeight, initBlockHeight
386
+ );
387
+ if(events.length===0) throw new Error("Initialize event not found!");
388
+ return events[0].txHash;
389
+ }
390
+
379
391
  switch(state) {
380
392
  case ESCROW_STATE_COMMITTED:
381
- if(data.isOfferer(signer) && await this.isExpired(signer,data)) return {type: SwapCommitStateType.REFUNDABLE};
382
- return {type: SwapCommitStateType.COMMITED};
393
+ if(data.isOfferer(signer) && await this.isExpired(signer,data)) {
394
+ return {
395
+ type: SwapCommitStateType.REFUNDABLE,
396
+ getInitTxId
397
+ };
398
+ }
399
+ return {
400
+ type: SwapCommitStateType.COMMITED,
401
+ getInitTxId
402
+ };
383
403
  case ESCROW_STATE_CLAIMED:
384
404
  return {
385
405
  type: SwapCommitStateType.PAID,
406
+ getInitTxId,
386
407
  getTxBlock: async () => {
387
408
  return {
388
409
  blockTime: await this.Chain.Blocks.getBlockTime(blockHeight),
@@ -417,6 +438,7 @@ export class StarknetSwapContract
417
438
  case ESCROW_STATE_REFUNDED:
418
439
  return {
419
440
  type: await this.isExpired(signer, data) ? SwapCommitStateType.EXPIRED : SwapCommitStateType.NOT_COMMITED,
441
+ getInitTxId,
420
442
  getTxBlock: async () => {
421
443
  return {
422
444
  blockTime: await this.Chain.Blocks.getBlockTime(blockHeight),
@@ -563,6 +585,7 @@ export class StarknetSwapContract
563
585
  },
564
586
  state: {
565
587
  type: SwapCommitStateType.PAID,
588
+ getInitTxId: foundSwapData?.getInitTxId,
566
589
  getClaimTxId: () => Promise.resolve(event.txHash),
567
590
  getClaimResult: () => Promise.resolve(claimHandler.parseWitnessResult(event.params.witness_result)),
568
591
  getTxBlock: async () => {
@@ -590,6 +613,7 @@ export class StarknetSwapContract
590
613
  },
591
614
  state: {
592
615
  type: isExpired ? SwapCommitStateType.EXPIRED : SwapCommitStateType.NOT_COMMITED,
616
+ getInitTxId: foundSwapData?.getInitTxId,
593
617
  getRefundTxId: () => Promise.resolve(event.txHash),
594
618
  getTxBlock: async () => {
595
619
  return {
@@ -628,8 +652,8 @@ export class StarknetSwapContract
628
652
  getTxBlock: foundSwapData.getTxBlock
629
653
  },
630
654
  state: data.isOfferer(signer) && await this.isExpired(signer, data)
631
- ? {type: SwapCommitStateType.REFUNDABLE}
632
- : {type: SwapCommitStateType.COMMITED}
655
+ ? {type: SwapCommitStateType.REFUNDABLE, getInitTxId: foundSwapData.getInitTxId}
656
+ : {type: SwapCommitStateType.COMMITED, getInitTxId: foundSwapData.getInitTxId}
633
657
  }
634
658
  }
635
659