@atomiqlabs/chain-starknet 1.0.8 → 2.0.0-beta.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 (121) hide show
  1. package/dist/index.d.ts +13 -9
  2. package/dist/index.js +13 -9
  3. package/dist/starknet/StarknetChainType.d.ts +6 -2
  4. package/dist/starknet/StarknetInitializer.d.ts +3 -2
  5. package/dist/starknet/StarknetInitializer.js +17 -6
  6. package/dist/starknet/btcrelay/StarknetBtcRelay.d.ts +28 -7
  7. package/dist/starknet/btcrelay/StarknetBtcRelay.js +75 -20
  8. package/dist/starknet/{base → chain}/StarknetAction.d.ts +2 -2
  9. package/dist/starknet/chain/StarknetChainInterface.d.ts +52 -0
  10. package/dist/starknet/chain/StarknetChainInterface.js +91 -0
  11. package/dist/starknet/{base → chain}/StarknetModule.d.ts +3 -3
  12. package/dist/starknet/{base → chain}/modules/StarknetAddresses.d.ts +1 -1
  13. package/dist/starknet/{base → chain}/modules/StarknetAddresses.js +1 -1
  14. package/dist/starknet/{base → chain}/modules/StarknetSignatures.d.ts +2 -2
  15. package/dist/starknet/{base → chain}/modules/StarknetTokens.js +2 -1
  16. package/dist/starknet/{base → chain}/modules/StarknetTransactions.d.ts +7 -1
  17. package/dist/starknet/{base → chain}/modules/StarknetTransactions.js +45 -16
  18. package/dist/starknet/contract/StarknetContractBase.d.ts +5 -5
  19. package/dist/starknet/contract/StarknetContractBase.js +5 -7
  20. package/dist/starknet/contract/StarknetContractModule.d.ts +8 -0
  21. package/dist/starknet/contract/StarknetContractModule.js +11 -0
  22. package/dist/starknet/contract/modules/StarknetContractEvents.d.ts +15 -4
  23. package/dist/starknet/contract/modules/StarknetContractEvents.js +26 -6
  24. package/dist/starknet/events/StarknetChainEvents.d.ts +3 -1
  25. package/dist/starknet/events/StarknetChainEvents.js +9 -9
  26. package/dist/starknet/events/StarknetChainEventsBrowser.d.ts +24 -6
  27. package/dist/starknet/events/StarknetChainEventsBrowser.js +116 -28
  28. package/dist/starknet/provider/RpcProviderWithRetries.d.ts +21 -0
  29. package/dist/starknet/provider/RpcProviderWithRetries.js +32 -0
  30. package/dist/starknet/spv_swap/SpvVaultContractAbi.d.ts +488 -0
  31. package/dist/starknet/spv_swap/SpvVaultContractAbi.js +656 -0
  32. package/dist/starknet/spv_swap/StarknetSpvVaultContract.d.ts +65 -0
  33. package/dist/starknet/spv_swap/StarknetSpvVaultContract.js +372 -0
  34. package/dist/starknet/spv_swap/StarknetSpvVaultData.d.ts +49 -0
  35. package/dist/starknet/spv_swap/StarknetSpvVaultData.js +144 -0
  36. package/dist/starknet/spv_swap/StarknetSpvWithdrawalData.d.ts +24 -0
  37. package/dist/starknet/spv_swap/StarknetSpvWithdrawalData.js +61 -0
  38. package/dist/starknet/swaps/StarknetSwapContract.d.ts +4 -22
  39. package/dist/starknet/swaps/StarknetSwapContract.js +23 -80
  40. package/dist/starknet/swaps/StarknetSwapModule.d.ts +6 -5
  41. package/dist/starknet/swaps/StarknetSwapModule.js +5 -6
  42. package/dist/starknet/swaps/handlers/IHandler.d.ts +2 -2
  43. package/dist/starknet/swaps/handlers/claim/ClaimHandlers.d.ts +1 -1
  44. package/dist/starknet/swaps/handlers/claim/HashlockClaimHandler.d.ts +2 -2
  45. package/dist/starknet/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.d.ts +2 -2
  46. package/dist/starknet/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.d.ts +2 -2
  47. package/dist/starknet/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.d.ts +2 -2
  48. package/dist/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.d.ts +2 -21
  49. package/dist/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.js +7 -41
  50. package/dist/starknet/swaps/handlers/refund/TimelockRefundHandler.d.ts +2 -2
  51. package/dist/starknet/swaps/modules/StarknetLpVault.d.ts +1 -1
  52. package/dist/starknet/swaps/modules/StarknetLpVault.js +9 -9
  53. package/dist/starknet/swaps/modules/StarknetSwapClaim.d.ts +1 -1
  54. package/dist/starknet/swaps/modules/StarknetSwapClaim.js +8 -8
  55. package/dist/starknet/swaps/modules/StarknetSwapInit.d.ts +1 -1
  56. package/dist/starknet/swaps/modules/StarknetSwapInit.js +9 -9
  57. package/dist/starknet/swaps/modules/StarknetSwapRefund.d.ts +1 -3
  58. package/dist/starknet/swaps/modules/StarknetSwapRefund.js +8 -11
  59. package/dist/starknet/wallet/StarknetSigner.js +1 -1
  60. package/dist/utils/Utils.d.ts +2 -2
  61. package/dist/utils/Utils.js +3 -1
  62. package/package.json +2 -2
  63. package/src/index.ts +15 -9
  64. package/src/starknet/StarknetChainType.ts +10 -2
  65. package/src/starknet/StarknetInitializer.ts +23 -7
  66. package/src/starknet/btcrelay/StarknetBtcRelay.ts +104 -30
  67. package/src/starknet/{base → chain}/StarknetAction.ts +3 -3
  68. package/src/starknet/chain/StarknetChainInterface.ts +149 -0
  69. package/src/starknet/{base → chain}/StarknetModule.ts +3 -3
  70. package/src/starknet/{base → chain}/modules/StarknetAddresses.ts +1 -1
  71. package/src/starknet/{base → chain}/modules/StarknetSignatures.ts +2 -2
  72. package/src/starknet/{base → chain}/modules/StarknetTokens.ts +2 -1
  73. package/src/starknet/{base → chain}/modules/StarknetTransactions.ts +43 -18
  74. package/src/starknet/contract/StarknetContractBase.ts +9 -12
  75. package/src/starknet/contract/StarknetContractModule.ts +16 -0
  76. package/src/starknet/contract/modules/StarknetContractEvents.ts +33 -7
  77. package/src/starknet/events/StarknetChainEvents.ts +15 -11
  78. package/src/starknet/events/StarknetChainEventsBrowser.ts +168 -41
  79. package/src/starknet/provider/RpcProviderWithRetries.ts +43 -0
  80. package/src/starknet/spv_swap/SpvVaultContractAbi.ts +656 -0
  81. package/src/starknet/spv_swap/StarknetSpvVaultContract.ts +475 -0
  82. package/src/starknet/spv_swap/StarknetSpvVaultData.ts +194 -0
  83. package/src/starknet/spv_swap/StarknetSpvWithdrawalData.ts +68 -0
  84. package/src/starknet/swaps/StarknetSwapContract.ts +28 -116
  85. package/src/starknet/swaps/StarknetSwapModule.ts +8 -8
  86. package/src/starknet/swaps/handlers/IHandler.ts +2 -2
  87. package/src/starknet/swaps/handlers/claim/ClaimHandlers.ts +1 -1
  88. package/src/starknet/swaps/handlers/claim/HashlockClaimHandler.ts +2 -2
  89. package/src/starknet/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.ts +2 -2
  90. package/src/starknet/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.ts +2 -2
  91. package/src/starknet/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.ts +2 -2
  92. package/src/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.ts +12 -61
  93. package/src/starknet/swaps/handlers/refund/TimelockRefundHandler.ts +2 -2
  94. package/src/starknet/swaps/modules/StarknetLpVault.ts +10 -10
  95. package/src/starknet/swaps/modules/StarknetSwapClaim.ts +9 -9
  96. package/src/starknet/swaps/modules/StarknetSwapInit.ts +10 -10
  97. package/src/starknet/swaps/modules/StarknetSwapRefund.ts +9 -13
  98. package/src/starknet/wallet/StarknetSigner.ts +1 -1
  99. package/src/utils/Utils.ts +4 -3
  100. package/dist/starknet/base/StarknetBase.d.ts +0 -34
  101. package/dist/starknet/base/StarknetBase.js +0 -29
  102. package/src/starknet/base/StarknetBase.ts +0 -56
  103. /package/dist/starknet/{base → chain}/StarknetAction.js +0 -0
  104. /package/dist/starknet/{base → chain}/StarknetModule.js +0 -0
  105. /package/dist/starknet/{base → chain}/modules/ERC20Abi.d.ts +0 -0
  106. /package/dist/starknet/{base → chain}/modules/ERC20Abi.js +0 -0
  107. /package/dist/starknet/{base → chain}/modules/StarknetAccounts.d.ts +0 -0
  108. /package/dist/starknet/{base → chain}/modules/StarknetAccounts.js +0 -0
  109. /package/dist/starknet/{base → chain}/modules/StarknetBlocks.d.ts +0 -0
  110. /package/dist/starknet/{base → chain}/modules/StarknetBlocks.js +0 -0
  111. /package/dist/starknet/{base → chain}/modules/StarknetEvents.d.ts +0 -0
  112. /package/dist/starknet/{base → chain}/modules/StarknetEvents.js +0 -0
  113. /package/dist/starknet/{base → chain}/modules/StarknetFees.d.ts +0 -0
  114. /package/dist/starknet/{base → chain}/modules/StarknetFees.js +0 -0
  115. /package/dist/starknet/{base → chain}/modules/StarknetSignatures.js +0 -0
  116. /package/dist/starknet/{base → chain}/modules/StarknetTokens.d.ts +0 -0
  117. /package/src/starknet/{base → chain}/modules/ERC20Abi.ts +0 -0
  118. /package/src/starknet/{base → chain}/modules/StarknetAccounts.ts +0 -0
  119. /package/src/starknet/{base → chain}/modules/StarknetBlocks.ts +0 -0
  120. /package/src/starknet/{base → chain}/modules/StarknetEvents.ts +0 -0
  121. /package/src/starknet/{base → chain}/modules/StarknetFees.ts +0 -0
@@ -1,29 +1,26 @@
1
- import {StarknetBase, StarknetRetryPolicy} from "../base/StarknetBase";
2
- import {constants, Contract, Provider, TypedContractV2} from "starknet";
3
- import {StarknetFees} from "../base/modules/StarknetFees";
1
+ import {StarknetChainInterface} from "../chain/StarknetChainInterface";
2
+ import {Contract, TypedContractV2} from "starknet";
4
3
  import {Abi} from "abi-wan-kanabi";
5
4
  import {StarknetContractEvents} from "./modules/StarknetContractEvents";
6
5
 
7
6
  /**
8
7
  * Base class providing program specific utilities
9
8
  */
10
- export class StarknetContractBase<T extends Abi> extends StarknetBase {
9
+ export class StarknetContractBase<T extends Abi> {
11
10
 
12
11
  contract: TypedContractV2<T>;
13
12
 
14
13
  public readonly Events: StarknetContractEvents<T>;
14
+ public readonly Chain: StarknetChainInterface;
15
15
 
16
16
  constructor(
17
- chainId: constants.StarknetChainId,
18
- provider: Provider,
17
+ chainInterface: StarknetChainInterface,
19
18
  contractAddress: string,
20
- contractAbi: T,
21
- retryPolicy?: StarknetRetryPolicy,
22
- solanaFeeEstimator: StarknetFees = new StarknetFees(provider)
19
+ contractAbi: T
23
20
  ) {
24
- super(chainId, provider, retryPolicy, solanaFeeEstimator);
25
- this.contract = new Contract(contractAbi, contractAddress, provider).typedv2(contractAbi);
26
- this.Events = new StarknetContractEvents(this, contractAbi);
21
+ this.Chain = chainInterface;
22
+ this.contract = new Contract(contractAbi, contractAddress, chainInterface.provider).typedv2(contractAbi);
23
+ this.Events = new StarknetContractEvents(chainInterface, this, contractAbi);
27
24
  }
28
25
 
29
26
  }
@@ -0,0 +1,16 @@
1
+ import {Abi} from "abi-wan-kanabi";
2
+ import {StarknetContractBase} from "./StarknetContractBase";
3
+ import {StarknetChainInterface} from "../chain/StarknetChainInterface";
4
+ import {StarknetModule} from "../chain/StarknetModule";
5
+
6
+
7
+ export class StarknetContractModule<TAbi extends Abi> extends StarknetModule {
8
+
9
+ readonly contract: StarknetContractBase<TAbi>;
10
+
11
+ constructor(chainInterface: StarknetChainInterface, contract: StarknetContractBase<TAbi>) {
12
+ super(chainInterface)
13
+ this.contract = contract;
14
+ }
15
+
16
+ }
@@ -1,9 +1,10 @@
1
1
  import {Abi} from "abi-wan-kanabi";
2
2
  import {EventToPrimitiveType, ExtractAbiEventNames} from "abi-wan-kanabi/dist/kanabi";
3
- import {StarknetEvent, StarknetEvents} from "../../base/modules/StarknetEvents";
3
+ import {StarknetEvent, StarknetEvents} from "../../chain/modules/StarknetEvents";
4
4
  import {CallData, events, hash} from "starknet";
5
5
  import {StarknetContractBase} from "../StarknetContractBase";
6
6
  import {toHex} from "../../../utils/Utils";
7
+ import {StarknetChainInterface} from "../../chain/StarknetChainInterface";
7
8
 
8
9
  export type StarknetAbiEvent<TAbi extends Abi, TEventName extends ExtractAbiEventNames<TAbi>> = {
9
10
  name: TEventName,
@@ -17,11 +18,12 @@ export type StarknetAbiEvent<TAbi extends Abi, TEventName extends ExtractAbiEven
17
18
 
18
19
  export class StarknetContractEvents<TAbi extends Abi> extends StarknetEvents {
19
20
 
20
- readonly root: StarknetContractBase<TAbi>;
21
+ readonly contract: StarknetContractBase<TAbi>;
21
22
  readonly abi: TAbi;
22
23
 
23
- constructor(root: StarknetContractBase<TAbi>, abi: TAbi) {
24
- super(root);
24
+ constructor(chainInterface: StarknetChainInterface, contract: StarknetContractBase<TAbi>, abi: TAbi) {
25
+ super(chainInterface);
26
+ this.contract = contract;
25
27
  this.abi = abi;
26
28
  }
27
29
 
@@ -76,12 +78,12 @@ export class StarknetContractEvents<TAbi extends Abi> extends StarknetEvents {
76
78
  startBlockHeight?: number,
77
79
  endBlockHeight: number = startBlockHeight
78
80
  ): Promise<StarknetAbiEvent<TAbi, T>[]> {
79
- const blockEvents = await super.getBlockEvents(this.root.contract.address, this.toFilter(events, keys), startBlockHeight, endBlockHeight);
81
+ const blockEvents = await super.getBlockEvents(this.contract.contract.address, this.toFilter(events, keys), startBlockHeight, endBlockHeight);
80
82
  return this.toStarknetAbiEvents(blockEvents);
81
83
  }
82
84
 
83
85
  /**
84
- * Runs a search forawrds in time, processing the events for a specific topic public key
86
+ * Runs a search backwards in time, processing the events for a specific topic public key
85
87
  *
86
88
  * @param events
87
89
  * @param keys
@@ -95,7 +97,31 @@ export class StarknetContractEvents<TAbi extends Abi> extends StarknetEvents {
95
97
  processor: (event: StarknetAbiEvent<TAbi, TEvent>) => Promise<T>,
96
98
  abortSignal?: AbortSignal
97
99
  ) {
98
- return this.findInEvents<T>(this.root.contract.address, this.toFilter(events, keys), async (events: StarknetEvent[]) => {
100
+ return this.findInEvents<T>(this.contract.contract.address, this.toFilter(events, keys), async (events: StarknetEvent[]) => {
101
+ const parsedEvents = this.toStarknetAbiEvents<TEvent>(events);
102
+ for(let event of parsedEvents) {
103
+ const result: T = await processor(event);
104
+ if(result!=null) return result;
105
+ }
106
+ }, abortSignal);
107
+ }
108
+
109
+ /**
110
+ * Runs a search forwards in time, processing the events for a specific topic public key
111
+ *
112
+ * @param events
113
+ * @param keys
114
+ * @param processor called for every event, should return a value if the correct event was found, or null
115
+ * if the search should continue
116
+ * @param abortSignal
117
+ */
118
+ public async findInContractEventsForward<T, TEvent extends ExtractAbiEventNames<TAbi>>(
119
+ events: TEvent[],
120
+ keys: string[],
121
+ processor: (event: StarknetAbiEvent<TAbi, TEvent>) => Promise<T>,
122
+ abortSignal?: AbortSignal
123
+ ) {
124
+ return this.findInEventsForward<T>(this.contract.contract.address, this.toFilter(events, keys), async (events: StarknetEvent[]) => {
99
125
  const parsedEvents = this.toStarknetAbiEvents<TEvent>(events);
100
126
  for(let event of parsedEvents) {
101
127
  const result: T = await processor(event);
@@ -2,6 +2,8 @@ import {StarknetChainEventsBrowser} from "./StarknetChainEventsBrowser";
2
2
  //@ts-ignore
3
3
  import * as fs from "fs/promises";
4
4
  import {StarknetSwapContract} from "../swaps/StarknetSwapContract";
5
+ import {StarknetChainInterface} from "../chain/StarknetChainInterface";
6
+ import {StarknetSpvVaultContract} from "../spv_swap/StarknetSpvVaultContract";
5
7
 
6
8
  const BLOCKHEIGHT_FILENAME = "/strk-blockheight.txt";
7
9
 
@@ -11,10 +13,12 @@ export class StarknetChainEvents extends StarknetChainEventsBrowser {
11
13
 
12
14
  constructor(
13
15
  directory: string,
16
+ chainInterface: StarknetChainInterface,
14
17
  starknetSwapContract: StarknetSwapContract,
18
+ starknetSpvVaultContract: StarknetSpvVaultContract,
15
19
  pollIntervalSeconds?: number
16
20
  ) {
17
- super(starknetSwapContract, pollIntervalSeconds);
21
+ super(chainInterface, starknetSwapContract, starknetSpvVaultContract, pollIntervalSeconds);
18
22
  this.directory = directory;
19
23
  }
20
24
 
@@ -23,22 +27,22 @@ export class StarknetChainEvents extends StarknetChainEventsBrowser {
23
27
  *
24
28
  * @private
25
29
  */
26
- private async getLastEventData(): Promise<{blockNumber: number, txHash: string}> {
30
+ private async getLastEventData(): Promise<{blockNumber: number, txHashes: string[]}> {
27
31
  try {
28
- const txt = (await fs.readFile(this.directory+BLOCKHEIGHT_FILENAME)).toString();
32
+ const txt: string = (await fs.readFile(this.directory+BLOCKHEIGHT_FILENAME)).toString();
29
33
  const arr = txt.split(";");
30
34
  if(arr.length<2) return {
31
35
  blockNumber: parseInt(arr[0]),
32
- txHash: null
36
+ txHashes: null
33
37
  };
34
38
  return {
35
39
  blockNumber: parseInt(arr[0]),
36
- txHash: arr[1]
40
+ txHashes: arr.slice(1)
37
41
  };
38
42
  } catch (e) {
39
43
  return {
40
44
  blockNumber: null,
41
- txHash: null
45
+ txHashes: null
42
46
  };
43
47
  }
44
48
  }
@@ -48,16 +52,16 @@ export class StarknetChainEvents extends StarknetChainEventsBrowser {
48
52
  *
49
53
  * @private
50
54
  */
51
- private saveLastEventData(blockNumber: number, txHash: string): Promise<void> {
52
- return fs.writeFile(this.directory+BLOCKHEIGHT_FILENAME, blockNumber.toString()+";"+txHash);
55
+ private saveLastEventData(blockNumber: number, txHashes: string[]): Promise<void> {
56
+ return fs.writeFile(this.directory+BLOCKHEIGHT_FILENAME, blockNumber.toString()+";"+txHashes.join(";"));
53
57
  }
54
58
 
55
59
  async init(): Promise<void> {
56
- const {blockNumber, txHash} = await this.getLastEventData();
60
+ const {blockNumber, txHashes} = await this.getLastEventData();
57
61
  await this.setupPoll(
58
62
  blockNumber,
59
- txHash,
60
- (blockNumber: number, txHash: string) => this.saveLastEventData(blockNumber, txHash)
63
+ txHashes,
64
+ (blockNumber: number, txHashes: string[]) => this.saveLastEventData(blockNumber, txHashes)
61
65
  );
62
66
  }
63
67
 
@@ -1,11 +1,11 @@
1
1
  import {
2
+ ChainEvent,
2
3
  ChainEvents,
3
4
  ChainSwapType,
4
5
  ClaimEvent,
5
6
  EventListener,
6
7
  InitializeEvent,
7
- RefundEvent,
8
- SwapEvent
8
+ RefundEvent, SpvVaultClaimEvent, SpvVaultCloseEvent, SpvVaultDepositEvent, SpvVaultFrontEvent, SpvVaultOpenEvent
9
9
  } from "@atomiqlabs/base";
10
10
  import {StarknetSwapData} from "../swaps/StarknetSwapData";
11
11
  import {
@@ -13,8 +13,7 @@ import {
13
13
  bytes31SpanToBuffer, findLastIndex,
14
14
  getLogger,
15
15
  onceAsync,
16
- parseInitFunctionCalldata,
17
- timeoutPromise,
16
+ parseInitFunctionCalldata, toBigInt,
18
17
  toHex
19
18
  } from "../../utils/Utils";
20
19
  import {StarknetSwapContract} from "../swaps/StarknetSwapContract";
@@ -23,6 +22,9 @@ import {StarknetAbiEvent} from "../contract/modules/StarknetContractEvents";
23
22
  import {EscrowManagerAbiType} from "../swaps/EscrowManagerAbi";
24
23
  import {ExtractAbiFunctionNames} from "abi-wan-kanabi/dist/kanabi";
25
24
  import {IClaimHandler} from "../swaps/handlers/claim/ClaimHandlers";
25
+ import {StarknetSpvVaultContract} from "../spv_swap/StarknetSpvVaultContract";
26
+ import {StarknetChainInterface} from "../chain/StarknetChainInterface";
27
+ import {SpvVaultContractAbiType} from "../spv_swap/SpvVaultContractAbi";
26
28
 
27
29
  export type StarknetTraceCall = {
28
30
  calldata: string[],
@@ -41,6 +43,7 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
41
43
  protected readonly listeners: EventListener<StarknetSwapData>[] = [];
42
44
  protected readonly provider: Provider;
43
45
  protected readonly starknetSwapContract: StarknetSwapContract;
46
+ protected readonly starknetSpvVaultContract: StarknetSpvVaultContract;
44
47
  protected eventListeners: number[] = [];
45
48
  protected readonly logger = getLogger("StarknetChainEventsBrowser: ");
46
49
 
@@ -52,9 +55,15 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
52
55
 
53
56
  private timeout: number;
54
57
 
55
- constructor(starknetSwapContract: StarknetSwapContract, pollIntervalSeconds: number = 5) {
56
- this.provider = starknetSwapContract.provider;
58
+ constructor(
59
+ chainInterface: StarknetChainInterface,
60
+ starknetSwapContract: StarknetSwapContract,
61
+ starknetSpvVaultContract: StarknetSpvVaultContract,
62
+ pollIntervalSeconds: number = 5
63
+ ) {
64
+ this.provider = chainInterface.provider;
57
65
  this.starknetSwapContract = starknetSwapContract;
66
+ this.starknetSpvVaultContract = starknetSpvVaultContract;
58
67
  this.pollIntervalSeconds = pollIntervalSeconds;
59
68
  }
60
69
 
@@ -146,33 +155,108 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
146
155
  return new ClaimEvent<StarknetSwapData>(escrowHash, witnessResult);
147
156
  }
148
157
 
158
+ protected parseSpvOpenEvent(
159
+ event: StarknetAbiEvent<SpvVaultContractAbiType, "spv_swap_vault::events::Opened">
160
+ ): SpvVaultOpenEvent {
161
+ const owner = toHex(event.params.owner);
162
+ const vaultId = toBigInt(event.params.vault_id);
163
+ const btcTxId = bigNumberishToBuffer(event.params.btc_tx_hash, 32).reverse().toString("hex");
164
+ const vout = Number(toBigInt(event.params.vout));
165
+
166
+ this.logger.debug("SpvOpenEvent owner: "+owner+" vaultId: "+vaultId+" utxo: "+btcTxId+":"+vout);
167
+ return new SpvVaultOpenEvent(owner, vaultId, btcTxId, vout);
168
+ }
169
+
170
+ protected parseSpvDepositEvent(
171
+ event: StarknetAbiEvent<SpvVaultContractAbiType, "spv_swap_vault::events::Deposited">
172
+ ): SpvVaultDepositEvent {
173
+ const owner = toHex(event.params.owner);
174
+ const vaultId = toBigInt(event.params.vault_id);
175
+ const amounts = [toBigInt(event.params.amounts["0"] as BigNumberish), toBigInt(event.params.amounts["1"] as BigNumberish)];
176
+ const depositCount = Number(toBigInt(event.params.deposit_count));
177
+
178
+ this.logger.debug("SpvDepositEvent owner: "+owner+" vaultId: "+vaultId+" depositCount: "+depositCount+" amounts: ", amounts);
179
+ return new SpvVaultDepositEvent(owner, vaultId, amounts, depositCount);
180
+ }
181
+
182
+ protected parseSpvFrontEvent(
183
+ event: StarknetAbiEvent<SpvVaultContractAbiType, "spv_swap_vault::events::Fronted">
184
+ ): SpvVaultFrontEvent {
185
+ const owner = toHex(event.params.owner);
186
+ const vaultId = toBigInt(event.params.vault_id);
187
+ const btcTxId = bigNumberishToBuffer(event.params.btc_tx_hash, 32).reverse().toString("hex");
188
+ const recipient = toHex(event.params.recipient);
189
+ const executionHash = toHex(event.params.execution_hash);
190
+ const amounts = [toBigInt(event.params.amounts["0"] as BigNumberish), toBigInt(event.params.amounts["1"] as BigNumberish)];
191
+ const frontingAddress = toHex(event.params.caller);
192
+
193
+ this.logger.debug("SpvFrontEvent owner: "+owner+" vaultId: "+vaultId+" btcTxId: "+btcTxId+
194
+ " recipient: "+recipient+" frontedBy: "+frontingAddress+" amounts: ", amounts);
195
+ return new SpvVaultFrontEvent(owner, vaultId, btcTxId, recipient, executionHash, amounts, frontingAddress);
196
+ }
197
+
198
+ protected parseSpvClaimEvent(
199
+ event: StarknetAbiEvent<SpvVaultContractAbiType, "spv_swap_vault::events::Claimed">
200
+ ): SpvVaultClaimEvent {
201
+ const owner = toHex(event.params.owner);
202
+ const vaultId = toBigInt(event.params.vault_id);
203
+ const btcTxId = bigNumberishToBuffer(event.params.btc_tx_hash, 32).reverse().toString("hex");
204
+ const recipient = toHex(event.params.recipient);
205
+ const executionHash = toHex(event.params.execution_hash);
206
+ const amounts = [toBigInt(event.params.amounts["0"] as BigNumberish), toBigInt(event.params.amounts["1"] as BigNumberish)];
207
+ const caller = toHex(event.params.caller);
208
+ const frontingAddress = toHex(event.params.fronting_address);
209
+ const withdrawCount = Number(toBigInt(event.params.withdraw_count));
210
+
211
+ this.logger.debug("SpvClaimEvent owner: "+owner+" vaultId: "+vaultId+" btcTxId: "+btcTxId+" withdrawCount: "+withdrawCount+
212
+ " recipient: "+recipient+" frontedBy: "+frontingAddress+" claimedBy: "+caller+" amounts: ", amounts);
213
+ return new SpvVaultClaimEvent(owner, vaultId, btcTxId, recipient, executionHash, amounts, caller, frontingAddress, withdrawCount);
214
+ }
215
+
216
+ protected parseSpvCloseEvent(
217
+ event: StarknetAbiEvent<SpvVaultContractAbiType, "spv_swap_vault::events::Closed">
218
+ ): SpvVaultCloseEvent {
219
+ const owner = toHex(event.params.owner);
220
+ const vaultId = toBigInt(event.params.vault_id);
221
+ const btcTxId = bigNumberishToBuffer(event.params.btc_tx_hash, 32).reverse().toString("hex");
222
+ const error = bigNumberishToBuffer(event.params.error).toString();
223
+
224
+ return new SpvVaultCloseEvent(owner, vaultId, btcTxId, error);
225
+ }
226
+
149
227
  /**
150
228
  * Processes event as received from the chain, parses it & calls event listeners
151
229
  *
152
230
  * @param events
153
231
  * @param currentBlockNumber
154
232
  * @param currentBlockTimestamp
233
+ * @param pendingEventTime
155
234
  * @protected
156
235
  */
157
236
  protected async processEvents(
158
- events : StarknetAbiEvent<
237
+ events : (StarknetAbiEvent<
159
238
  EscrowManagerAbiType,
160
239
  "escrow_manager::events::Initialize" | "escrow_manager::events::Refund" | "escrow_manager::events::Claim"
161
- >[],
240
+ > | StarknetAbiEvent<
241
+ SpvVaultContractAbiType,
242
+ "spv_swap_vault::events::Opened" | "spv_swap_vault::events::Deposited" | "spv_swap_vault::events::Fronted" | "spv_swap_vault::events::Claimed" | "spv_swap_vault::events::Closed"
243
+ >)[],
162
244
  currentBlockNumber: number,
163
- currentBlockTimestamp: number
245
+ currentBlockTimestamp: number,
246
+ pendingEventTime: number
164
247
  ) {
165
248
  const blockTimestampsCache: {[blockNumber: string]: number} = {};
166
249
  const getBlockTimestamp: (blockNumber: number) => Promise<number> = async (blockNumber: number)=> {
250
+ if(blockNumber===currentBlockNumber) return currentBlockTimestamp;
167
251
  const blockNumberString = blockNumber.toString();
168
252
  blockTimestampsCache[blockNumberString] ??= (await this.provider.getBlockWithTxHashes(blockNumber)).timestamp;
169
253
  return blockTimestampsCache[blockNumberString];
170
254
  }
171
255
 
172
- const parsedEvents: SwapEvent<StarknetSwapData>[] = [];
256
+ const parsedEvents: ChainEvent<StarknetSwapData>[] = [];
173
257
 
174
258
  for(let event of events) {
175
- let parsedEvent: SwapEvent<StarknetSwapData>;
259
+ let parsedEvent: ChainEvent<StarknetSwapData>;
176
260
  switch(event.name) {
177
261
  case "escrow_manager::events::Claim":
178
262
  parsedEvent = this.parseClaimEvent(event as any);
@@ -183,8 +267,23 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
183
267
  case "escrow_manager::events::Initialize":
184
268
  parsedEvent = this.parseInitializeEvent(event as any);
185
269
  break;
270
+ case "spv_swap_vault::events::Opened":
271
+ parsedEvent = this.parseSpvOpenEvent(event as any);
272
+ break;
273
+ case "spv_swap_vault::events::Deposited":
274
+ parsedEvent = this.parseSpvDepositEvent(event as any);
275
+ break;
276
+ case "spv_swap_vault::events::Fronted":
277
+ parsedEvent = this.parseSpvFrontEvent(event as any);
278
+ break;
279
+ case "spv_swap_vault::events::Claimed":
280
+ parsedEvent = this.parseSpvClaimEvent(event as any);
281
+ break;
282
+ case "spv_swap_vault::events::Closed":
283
+ parsedEvent = this.parseSpvCloseEvent(event as any);
284
+ break;
186
285
  }
187
- const timestamp = (event.blockNumber==null || event.blockNumber===currentBlockNumber) ? currentBlockTimestamp : await getBlockTimestamp(event.blockNumber);
286
+ const timestamp = event.blockNumber==null ? pendingEventTime : await getBlockTimestamp(event.blockNumber);
188
287
  parsedEvent.meta = {
189
288
  blockTime: timestamp,
190
289
  txId: event.txHash,
@@ -198,41 +297,69 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
198
297
  }
199
298
  }
200
299
 
201
- protected async checkEvents(lastBlockNumber: number, lastTxHash: string): Promise<{txHash: string, blockNumber: number}> {
202
- //Get pending events
203
- let pendingEvents = await this.starknetSwapContract.Events.getContractBlockEvents(
300
+ protected async checkEventsEcrowManager(lastTxHash: string, lastBlockNumber?: number, currentBlock?: {timestamp: number, block_number: number}): Promise<string> {
301
+ const currentBlockNumber: number = (currentBlock as any).block_number;
302
+ lastBlockNumber ??= currentBlockNumber;
303
+ const logStartHeight = currentBlockNumber>lastBlockNumber ? lastBlockNumber+1 : lastBlockNumber;
304
+ this.logger.debug("checkEvents(EscrowManager): Requesting logs: "+logStartHeight+"...pending");
305
+ let events = await this.starknetSwapContract.Events.getContractBlockEvents(
204
306
  ["escrow_manager::events::Initialize", "escrow_manager::events::Claim", "escrow_manager::events::Refund"],
205
- []
307
+ [],
308
+ logStartHeight,
309
+ null
310
+ );
311
+ if(lastTxHash!=null) {
312
+ const latestProcessedEventIndex = findLastIndex(events, val => val.txHash===lastTxHash);
313
+ if(latestProcessedEventIndex!==-1) {
314
+ events.splice(0, latestProcessedEventIndex+1);
315
+ this.logger.debug("checkEvents(EscrowManager): Splicing processed events, resulting size: "+events.length);
316
+ }
317
+ }
318
+ if(events.length>0) {
319
+ await this.processEvents(events, currentBlock?.block_number, currentBlock?.timestamp, Math.floor(Date.now()/1000));
320
+ lastTxHash = events[events.length-1].txHash;
321
+ }
322
+ return lastTxHash;
323
+ }
324
+
325
+ protected async checkEventsSpvVaults(lastTxHash: string, lastBlockNumber?: number, currentBlock?: {timestamp: number, block_number: number}): Promise<string> {
326
+ const currentBlockNumber: number = (currentBlock as any).block_number;
327
+ lastBlockNumber ??= currentBlockNumber;
328
+ const logStartHeight = currentBlockNumber>lastBlockNumber ? lastBlockNumber+1 : lastBlockNumber;
329
+ this.logger.debug("checkEvents(SpvVaults): Requesting logs: "+logStartHeight+"...pending");
330
+ let events = await this.starknetSpvVaultContract.Events.getContractBlockEvents(
331
+ ["spv_swap_vault::events::Opened", "spv_swap_vault::events::Deposited", "spv_swap_vault::events::Closed", "spv_swap_vault::events::Fronted", "spv_swap_vault::events::Claimed"],
332
+ [],
333
+ logStartHeight,
334
+ null
206
335
  );
207
336
  if(lastTxHash!=null) {
208
- const latestProcessedEventIndex = findLastIndex(pendingEvents, val => val.txHash===lastTxHash);
209
- if(latestProcessedEventIndex!==-1) pendingEvents.splice(0, latestProcessedEventIndex+1);
337
+ const latestProcessedEventIndex = findLastIndex(events, val => val.txHash===lastTxHash);
338
+ if(latestProcessedEventIndex!==-1) {
339
+ events.splice(0, latestProcessedEventIndex+1);
340
+ this.logger.debug("checkEvents(SpvVaults): Splicing processed events, resulting size: "+events.length);
341
+ }
210
342
  }
211
- if(pendingEvents.length>0) {
212
- await this.processEvents(pendingEvents, null, Math.floor(Date.now()/1000));
213
- lastTxHash = pendingEvents[pendingEvents.length-1].txHash;
343
+ if(events.length>0) {
344
+ await this.processEvents(events, currentBlock?.block_number, currentBlock?.timestamp, Math.floor(Date.now()/1000));
345
+ lastTxHash = events[events.length-1].txHash;
214
346
  }
347
+ return lastTxHash;
348
+ }
349
+
350
+ protected async checkEvents(lastBlockNumber: number, lastTxHashes: string[]): Promise<{txHashes: string[], blockNumber: number}> {
351
+ lastTxHashes ??= [];
215
352
 
216
353
  const currentBlock = await this.provider.getBlockWithTxHashes("latest");
217
354
  const currentBlockNumber: number = (currentBlock as any).block_number;
355
+
218
356
  if(lastBlockNumber!=null && currentBlockNumber>lastBlockNumber) {
219
- const events = await this.starknetSwapContract.Events.getContractBlockEvents(
220
- ["escrow_manager::events::Initialize", "escrow_manager::events::Claim", "escrow_manager::events::Refund"],
221
- [],
222
- lastBlockNumber+1,
223
- currentBlockNumber
224
- );
225
- if(lastTxHash!=null) {
226
- const latestProcessedEventIndex = findLastIndex(events, val => val.txHash === lastTxHash);
227
- if (latestProcessedEventIndex !== -1) events.splice(0, latestProcessedEventIndex + 1);
228
- }
229
- if(events.length>0) {
230
- await this.processEvents(events, currentBlockNumber, currentBlock.timestamp);
231
- lastTxHash = events[events.length - 1].txHash;
232
- }
357
+ lastTxHashes[0] = await this.checkEventsEcrowManager(lastTxHashes[0], lastBlockNumber, currentBlock as any);
358
+ lastTxHashes[1] = await this.checkEventsSpvVaults(lastTxHashes[1], lastBlockNumber, currentBlock as any);
233
359
  }
360
+
234
361
  return {
235
- txHash: lastTxHash,
362
+ txHashes: lastTxHashes,
236
363
  blockNumber: currentBlockNumber
237
364
  };
238
365
  }
@@ -244,16 +371,16 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
244
371
  */
245
372
  protected async setupPoll(
246
373
  lastBlockNumber?: number,
247
- lastTxHash?: string,
248
- saveLatestProcessedBlockNumber?: (blockNumber: number, lastTxHash: string) => Promise<void>
374
+ lastTxHashes?: string[],
375
+ saveLatestProcessedBlockNumber?: (blockNumber: number, lastTxHashes: string[]) => Promise<void>
249
376
  ) {
250
377
  this.stopped = false;
251
378
  let func;
252
379
  func = async () => {
253
- await this.checkEvents(lastBlockNumber, lastTxHash).then(({blockNumber, txHash}) => {
380
+ await this.checkEvents(lastBlockNumber, lastTxHashes).then(({blockNumber, txHashes}) => {
254
381
  lastBlockNumber = blockNumber;
255
- lastTxHash = txHash;
256
- if(saveLatestProcessedBlockNumber!=null) return saveLatestProcessedBlockNumber(blockNumber, lastTxHash);
382
+ lastTxHashes = txHashes;
383
+ if(saveLatestProcessedBlockNumber!=null) return saveLatestProcessedBlockNumber(blockNumber, lastTxHashes);
257
384
  }).catch(e => {
258
385
  this.logger.error("setupPoll(): Failed to fetch starknet log: ", e);
259
386
  });
@@ -0,0 +1,43 @@
1
+ import {
2
+ RpcChannel,
3
+ RpcProvider,
4
+ RpcProviderOptions
5
+ } from "starknet";
6
+ import {tryWithRetries} from "../../utils/Utils";
7
+
8
+ export class RpcChannelWithRetries extends RpcChannel {
9
+
10
+ readonly retryPolicy?: {
11
+ maxRetries?: number, delay?: number, exponential?: boolean
12
+ };
13
+
14
+ constructor(options?: RpcProviderOptions, retryPolicy?: {
15
+ maxRetries?: number, delay?: number, exponential?: boolean
16
+ }) {
17
+ super(options);
18
+ this.retryPolicy = retryPolicy;
19
+ }
20
+
21
+ protected fetchEndpoint(method: any, params?: any): Promise<any> {
22
+ return tryWithRetries(() => super.fetchEndpoint(method, params), this.retryPolicy, e => {
23
+ if(!e.message.startsWith("RPC: ")) return false;
24
+ const arr = e.message.split("\n");
25
+ const errorCode = parseInt(arr[arr.length-1]);
26
+ if(isNaN(errorCode)) return false;
27
+ if(errorCode < 0) return false; //Not defined error, e.g. Rate limit (-32097)
28
+ return true;
29
+ });
30
+ }
31
+
32
+ }
33
+
34
+ export class RpcProviderWithRetries extends RpcProvider {
35
+
36
+ constructor(options?: RpcProviderOptions, retryPolicy?: {
37
+ maxRetries?: number, delay?: number, exponential?: boolean
38
+ }) {
39
+ super(options);
40
+ this.channel = new RpcChannelWithRetries({ ...options, waitMode: false }, retryPolicy);
41
+ }
42
+
43
+ }