@atomiqlabs/chain-starknet 8.0.13 → 8.1.10

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 (119) hide show
  1. package/dist/index.d.ts +18 -18
  2. package/dist/index.js +42 -42
  3. package/dist/starknet/StarknetChainType.d.ts +19 -19
  4. package/dist/starknet/StarknetChainType.js +2 -2
  5. package/dist/starknet/StarknetInitializer.d.ts +66 -63
  6. package/dist/starknet/StarknetInitializer.js +101 -101
  7. package/dist/starknet/btcrelay/BtcRelayAbi.d.ts +250 -250
  8. package/dist/starknet/btcrelay/BtcRelayAbi.js +341 -341
  9. package/dist/starknet/btcrelay/StarknetBtcRelay.d.ts +196 -196
  10. package/dist/starknet/btcrelay/StarknetBtcRelay.js +419 -411
  11. package/dist/starknet/btcrelay/headers/StarknetBtcHeader.d.ts +70 -70
  12. package/dist/starknet/btcrelay/headers/StarknetBtcHeader.js +115 -115
  13. package/dist/starknet/btcrelay/headers/StarknetBtcStoredHeader.d.ts +91 -91
  14. package/dist/starknet/btcrelay/headers/StarknetBtcStoredHeader.js +155 -155
  15. package/dist/starknet/chain/StarknetAction.d.ts +19 -19
  16. package/dist/starknet/chain/StarknetAction.js +74 -74
  17. package/dist/starknet/chain/StarknetChainInterface.d.ts +142 -143
  18. package/dist/starknet/chain/StarknetChainInterface.js +198 -199
  19. package/dist/starknet/chain/StarknetModule.d.ts +8 -8
  20. package/dist/starknet/chain/StarknetModule.js +12 -12
  21. package/dist/starknet/chain/modules/ERC20Abi.d.ts +755 -755
  22. package/dist/starknet/chain/modules/ERC20Abi.js +1032 -1032
  23. package/dist/starknet/chain/modules/StarknetAccounts.d.ts +6 -6
  24. package/dist/starknet/chain/modules/StarknetAccounts.js +26 -26
  25. package/dist/starknet/chain/modules/StarknetAddresses.d.ts +10 -10
  26. package/dist/starknet/chain/modules/StarknetAddresses.js +27 -27
  27. package/dist/starknet/chain/modules/StarknetBlocks.d.ts +27 -27
  28. package/dist/starknet/chain/modules/StarknetBlocks.js +82 -82
  29. package/dist/starknet/chain/modules/StarknetEvents.d.ts +47 -47
  30. package/dist/starknet/chain/modules/StarknetEvents.js +90 -90
  31. package/dist/starknet/chain/modules/StarknetFees.d.ts +118 -104
  32. package/dist/starknet/chain/modules/StarknetFees.js +150 -146
  33. package/dist/starknet/chain/modules/StarknetSignatures.d.ts +29 -29
  34. package/dist/starknet/chain/modules/StarknetSignatures.js +72 -72
  35. package/dist/starknet/chain/modules/StarknetTokens.d.ts +66 -66
  36. package/dist/starknet/chain/modules/StarknetTokens.js +99 -99
  37. package/dist/starknet/chain/modules/StarknetTransactions.d.ts +122 -115
  38. package/dist/starknet/chain/modules/StarknetTransactions.js +633 -612
  39. package/dist/starknet/contract/StarknetContractBase.d.ts +14 -13
  40. package/dist/starknet/contract/StarknetContractBase.js +21 -20
  41. package/dist/starknet/contract/StarknetContractModule.d.ts +8 -8
  42. package/dist/starknet/contract/StarknetContractModule.js +11 -11
  43. package/dist/starknet/contract/modules/StarknetContractEvents.d.ts +56 -57
  44. package/dist/starknet/contract/modules/StarknetContractEvents.js +111 -111
  45. package/dist/starknet/events/StarknetChainEvents.d.ts +21 -21
  46. package/dist/starknet/events/StarknetChainEvents.js +61 -61
  47. package/dist/starknet/events/StarknetChainEventsBrowser.d.ts +178 -190
  48. package/dist/starknet/events/StarknetChainEventsBrowser.js +523 -582
  49. package/dist/starknet/provider/RpcProviderWithRetries.d.ts +49 -53
  50. package/dist/starknet/provider/RpcProviderWithRetries.js +94 -94
  51. package/dist/starknet/provider/WebSocketChannelWithRetries.d.ts +21 -21
  52. package/dist/starknet/provider/WebSocketChannelWithRetries.js +46 -46
  53. package/dist/starknet/spv_swap/SpvVaultContractAbi.d.ts +488 -488
  54. package/dist/starknet/spv_swap/SpvVaultContractAbi.js +656 -656
  55. package/dist/starknet/spv_swap/StarknetSpvVaultContract.d.ts +225 -219
  56. package/dist/starknet/spv_swap/StarknetSpvVaultContract.js +663 -621
  57. package/dist/starknet/spv_swap/StarknetSpvVaultData.d.ts +108 -108
  58. package/dist/starknet/spv_swap/StarknetSpvVaultData.js +190 -190
  59. package/dist/starknet/spv_swap/StarknetSpvWithdrawalData.d.ts +56 -56
  60. package/dist/starknet/spv_swap/StarknetSpvWithdrawalData.js +103 -103
  61. package/dist/starknet/swaps/EscrowManagerAbi.d.ts +431 -431
  62. package/dist/starknet/swaps/EscrowManagerAbi.js +583 -583
  63. package/dist/starknet/swaps/StarknetSwapContract.d.ts +309 -278
  64. package/dist/starknet/swaps/StarknetSwapContract.js +755 -579
  65. package/dist/starknet/swaps/StarknetSwapData.d.ts +234 -234
  66. package/dist/starknet/swaps/StarknetSwapData.js +474 -474
  67. package/dist/starknet/swaps/StarknetSwapModule.d.ts +10 -10
  68. package/dist/starknet/swaps/StarknetSwapModule.js +12 -12
  69. package/dist/starknet/swaps/handlers/IHandler.d.ts +13 -13
  70. package/dist/starknet/swaps/handlers/IHandler.js +2 -2
  71. package/dist/starknet/swaps/handlers/claim/ClaimHandlers.d.ts +13 -13
  72. package/dist/starknet/swaps/handlers/claim/ClaimHandlers.js +13 -13
  73. package/dist/starknet/swaps/handlers/claim/HashlockClaimHandler.d.ts +21 -21
  74. package/dist/starknet/swaps/handlers/claim/HashlockClaimHandler.js +44 -44
  75. package/dist/starknet/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.d.ts +24 -24
  76. package/dist/starknet/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.js +48 -48
  77. package/dist/starknet/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.d.ts +25 -25
  78. package/dist/starknet/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.js +40 -40
  79. package/dist/starknet/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.d.ts +20 -20
  80. package/dist/starknet/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.js +30 -30
  81. package/dist/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.d.ts +42 -45
  82. package/dist/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.js +50 -54
  83. package/dist/starknet/swaps/handlers/refund/TimelockRefundHandler.d.ts +17 -17
  84. package/dist/starknet/swaps/handlers/refund/TimelockRefundHandler.js +27 -27
  85. package/dist/starknet/swaps/modules/StarknetLpVault.d.ts +67 -67
  86. package/dist/starknet/swaps/modules/StarknetLpVault.js +122 -122
  87. package/dist/starknet/swaps/modules/StarknetSwapClaim.d.ts +52 -52
  88. package/dist/starknet/swaps/modules/StarknetSwapClaim.js +99 -99
  89. package/dist/starknet/swaps/modules/StarknetSwapInit.d.ts +94 -94
  90. package/dist/starknet/swaps/modules/StarknetSwapInit.js +239 -239
  91. package/dist/starknet/swaps/modules/StarknetSwapRefund.d.ts +60 -60
  92. package/dist/starknet/swaps/modules/StarknetSwapRefund.js +126 -126
  93. package/dist/starknet/wallet/StarknetBrowserSigner.d.ts +11 -11
  94. package/dist/starknet/wallet/StarknetBrowserSigner.js +17 -17
  95. package/dist/starknet/wallet/StarknetPersistentSigner.d.ts +76 -76
  96. package/dist/starknet/wallet/StarknetPersistentSigner.js +291 -291
  97. package/dist/starknet/wallet/StarknetSigner.d.ts +72 -72
  98. package/dist/starknet/wallet/StarknetSigner.js +114 -114
  99. package/dist/starknet/wallet/accounts/StarknetKeypairWallet.d.ts +18 -18
  100. package/dist/starknet/wallet/accounts/StarknetKeypairWallet.js +45 -45
  101. package/dist/utils/Utils.d.ts +77 -77
  102. package/dist/utils/Utils.js +304 -303
  103. package/package.json +2 -2
  104. package/src/starknet/StarknetInitializer.ts +6 -3
  105. package/src/starknet/btcrelay/StarknetBtcRelay.ts +19 -6
  106. package/src/starknet/btcrelay/headers/StarknetBtcHeader.ts +7 -7
  107. package/src/starknet/btcrelay/headers/StarknetBtcStoredHeader.ts +6 -6
  108. package/src/starknet/chain/StarknetAction.ts +1 -0
  109. package/src/starknet/chain/StarknetChainInterface.ts +0 -2
  110. package/src/starknet/chain/modules/StarknetFees.ts +15 -2
  111. package/src/starknet/chain/modules/StarknetTransactions.ts +24 -0
  112. package/src/starknet/contract/StarknetContractBase.ts +7 -4
  113. package/src/starknet/contract/StarknetContractModule.ts +1 -1
  114. package/src/starknet/contract/modules/StarknetContractEvents.ts +7 -7
  115. package/src/starknet/events/StarknetChainEventsBrowser.ts +2 -64
  116. package/src/starknet/provider/RpcProviderWithRetries.ts +1 -1
  117. package/src/starknet/spv_swap/StarknetSpvVaultContract.ts +84 -18
  118. package/src/starknet/swaps/StarknetSwapContract.ts +242 -6
  119. package/src/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.ts +0 -4
@@ -1,411 +1,419 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StarknetBtcRelay = void 0;
4
- const buffer_1 = require("buffer");
5
- const StarknetBtcHeader_1 = require("./headers/StarknetBtcHeader");
6
- const base_1 = require("@atomiqlabs/base");
7
- const Utils_1 = require("../../utils/Utils");
8
- const StarknetContractBase_1 = require("../contract/StarknetContractBase");
9
- const StarknetBtcStoredHeader_1 = require("./headers/StarknetBtcStoredHeader");
10
- const BtcRelayAbi_1 = require("./BtcRelayAbi");
11
- const starknet_1 = require("starknet");
12
- const StarknetFees_1 = require("../chain/modules/StarknetFees");
13
- const StarknetAction_1 = require("../chain/StarknetAction");
14
- function serializeBlockHeader(e) {
15
- return new StarknetBtcHeader_1.StarknetBtcHeader({
16
- reversed_version: (0, Utils_1.u32ReverseEndianness)(e.getVersion()),
17
- previous_blockhash: (0, Utils_1.bufferToU32Array)(buffer_1.Buffer.from(e.getPrevBlockhash(), "hex").reverse()),
18
- merkle_root: (0, Utils_1.bufferToU32Array)(buffer_1.Buffer.from(e.getMerkleRoot(), "hex").reverse()),
19
- reversed_timestamp: (0, Utils_1.u32ReverseEndianness)(e.getTimestamp()),
20
- nbits: (0, Utils_1.u32ReverseEndianness)(e.getNbits()),
21
- nonce: (0, Utils_1.u32ReverseEndianness)(e.getNonce()),
22
- hash: buffer_1.Buffer.from(e.getHash(), "hex").reverse()
23
- });
24
- }
25
- const GAS_PER_BLOCKHEADER = { l1DataGas: 600, l2Gas: 24000000, l1Gas: 0 };
26
- const GAS_PER_BLOCKHEADER_FORK = { l1DataGas: 1000, l2Gas: 40000000, l1Gas: 0 };
27
- const btcRelayAddreses = {
28
- [base_1.BitcoinNetwork.TESTNET4]: "0x0099b63f39f0cabb767361de3d8d3e97212351a51540e2687c2571f4da490dbe",
29
- [base_1.BitcoinNetwork.TESTNET]: "0x068601c79da2231d21e015ccfd59c243861156fa523a12c9f987ec28eb8dbc8c",
30
- [base_1.BitcoinNetwork.MAINNET]: "0x057b14a4231b82f1e525ff35a722d893ca3dd2bde0baa6cee97937c5be861dbc"
31
- };
32
- function serializeCalldata(headers, storedHeader, span) {
33
- span.push((0, Utils_1.toHex)(headers.length));
34
- headers.forEach(header => {
35
- span.push(...header.serialize());
36
- });
37
- span.push(...storedHeader.serialize());
38
- return span;
39
- }
40
- const logger = (0, Utils_1.getLogger)("StarknetBtcRelay: ");
41
- /**
42
- * Starknet BTC Relay bitcoin light client contract representation
43
- *
44
- * @category BTC Relay
45
- */
46
- class StarknetBtcRelay extends StarknetContractBase_1.StarknetContractBase {
47
- /**
48
- * Returns a {@link StarknetAction} that submits new main chain bitcoin blockheaders to the light client
49
- *
50
- * @param signer Starknet signer's address
51
- * @param mainHeaders New bitcoin blockheaders to submit
52
- * @param storedHeader Current latest committed and stored bitcoin blockheader in the light client
53
- */
54
- SaveMainHeaders(signer, mainHeaders, storedHeader) {
55
- return new StarknetAction_1.StarknetAction(signer, this.Chain, {
56
- contractAddress: this.contract.address,
57
- entrypoint: "submit_main_blockheaders",
58
- calldata: serializeCalldata(mainHeaders, storedHeader, [])
59
- }, (0, StarknetFees_1.starknetGasMul)(GAS_PER_BLOCKHEADER, mainHeaders.length));
60
- }
61
- /**
62
- * Returns a {@link StarknetAction} for submitting a short fork bitcoin blockheaders to the light client,
63
- * forking the chain from the provided `storedHeader` param's blockheight. For a successful fork the
64
- * submitted chain needs to have higher total chainwork than the current cannonical chain
65
- *
66
- * @param signer Starknet signer's address
67
- * @param forkHeaders Fork bitcoin blockheaders to submit
68
- * @param storedHeader Committed and stored bitcoin blockheader from which to fork the light client
69
- */
70
- SaveShortForkHeaders(signer, forkHeaders, storedHeader) {
71
- return new StarknetAction_1.StarknetAction(signer, this.Chain, {
72
- contractAddress: this.contract.address,
73
- entrypoint: "submit_short_fork_blockheaders",
74
- calldata: serializeCalldata(forkHeaders, storedHeader, [])
75
- }, (0, StarknetFees_1.starknetGasMul)(GAS_PER_BLOCKHEADER, forkHeaders.length));
76
- }
77
- /**
78
- * Returns a {@link StarknetAction} for submitting a long fork of bitcoin blockheaders to the light client.
79
- *
80
- * @param signer Starknet signer's address
81
- * @param forkId Fork ID to submit the fork blockheaders to
82
- * @param forkHeaders Fork bitcoin blockheaders to submit
83
- * @param storedHeader Either a committed and stored bitcoin blockheader from which to fork the light client (when
84
- * creating the fork), or the tip of the fork (when adding more blockheaders to the fork)
85
- * @param totalForkHeaders Total blockheaders in the fork - used to estimate the gas usage when re-org happens
86
- */
87
- SaveLongForkHeaders(signer, forkId, forkHeaders, storedHeader, totalForkHeaders = 100) {
88
- return new StarknetAction_1.StarknetAction(signer, this.Chain, {
89
- contractAddress: this.contract.address,
90
- entrypoint: "submit_fork_blockheaders",
91
- calldata: serializeCalldata(forkHeaders, storedHeader, [(0, Utils_1.toHex)(forkId)])
92
- }, (0, StarknetFees_1.starknetGasAdd)((0, StarknetFees_1.starknetGasMul)(GAS_PER_BLOCKHEADER, forkHeaders.length), (0, StarknetFees_1.starknetGasMul)(GAS_PER_BLOCKHEADER_FORK, totalForkHeaders)));
93
- }
94
- constructor(chainInterface, bitcoinRpc, bitcoinNetwork, contractAddress = btcRelayAddreses[bitcoinNetwork]) {
95
- if (contractAddress == null)
96
- throw new Error("No BtcRelay address specified!");
97
- super(chainInterface, contractAddress, BtcRelayAbi_1.BtcRelayAbi);
98
- this.maxHeadersPerTx = 40;
99
- this.maxForkHeadersPerTx = 30;
100
- this.maxShortForkHeadersPerTx = 40;
101
- this.bitcoinRpc = bitcoinRpc;
102
- }
103
- /**
104
- * Computes subsequent commited headers as they will appear on the blockchain when transactions
105
- * are submitted & confirmed
106
- *
107
- * @param initialStoredHeader
108
- * @param syncedHeaders
109
- * @private
110
- */
111
- computeCommitedHeaders(initialStoredHeader, syncedHeaders) {
112
- const computedCommitedHeaders = [initialStoredHeader];
113
- for (let blockHeader of syncedHeaders) {
114
- computedCommitedHeaders.push(computedCommitedHeaders[computedCommitedHeaders.length - 1].computeNext(blockHeader));
115
- }
116
- return computedCommitedHeaders;
117
- }
118
- /**
119
- * A common logic for submitting blockheaders in a transaction
120
- *
121
- * @param signer Starknet signer's address
122
- * @param headers Bitcoin blockheaders to submit to the btc relay
123
- * @param storedHeader Current latest stored block header for a given fork or main chain
124
- * @param forkId Fork ID to submit to, `forkId`=0 means main chain, `forkId`=-1 means short fork
125
- * @param feeRate Fee rate for the transaction
126
- * @private
127
- */
128
- async _saveHeaders(signer, headers, storedHeader, forkId, feeRate) {
129
- const blockHeaderObj = headers.map(serializeBlockHeader);
130
- let starknetAction;
131
- switch (forkId) {
132
- case -1:
133
- starknetAction = this.SaveShortForkHeaders(signer, blockHeaderObj, storedHeader);
134
- break;
135
- case 0:
136
- starknetAction = this.SaveMainHeaders(signer, blockHeaderObj, storedHeader);
137
- break;
138
- default:
139
- starknetAction = this.SaveLongForkHeaders(signer, forkId, blockHeaderObj, storedHeader);
140
- break;
141
- }
142
- const tx = await starknetAction.tx(feeRate);
143
- const computedCommitedHeaders = this.computeCommitedHeaders(storedHeader, blockHeaderObj);
144
- const lastStoredHeader = computedCommitedHeaders[computedCommitedHeaders.length - 1];
145
- return {
146
- forkId: forkId,
147
- lastStoredHeader,
148
- tx,
149
- computedCommitedHeaders
150
- };
151
- }
152
- /**
153
- * Returns a committed bitcoin blockheader based on the provided `commitHash` or `blockHash`
154
- *
155
- * @param commitHash Commitment hash of the stored blockheader
156
- * @param blockHash Block's hash
157
- * @private
158
- */
159
- getBlock(commitHash, blockHash) {
160
- const keys = [commitHash == null ? null : (0, Utils_1.toHex)(commitHash)];
161
- if (blockHash != null) {
162
- const starknetBlockHash = starknet_1.hash.computePoseidonHashOnElements((0, Utils_1.bufferToU32Array)(buffer_1.Buffer.from([...blockHash]).reverse()));
163
- keys.push(starknetBlockHash);
164
- }
165
- return this.Events.findInContractEvents(["btc_relay::events::StoreHeader", "btc_relay::events::StoreForkHeader"], keys, (event) => {
166
- return Promise.resolve([StarknetBtcStoredHeader_1.StarknetBtcStoredHeader.fromSerializedFeltArray(event.data), BigInt(event.params.commit_hash)]);
167
- });
168
- }
169
- /**
170
- * Returns the current main chain blockheight of the BTC Relay
171
- *
172
- * @private
173
- */
174
- async getBlockHeight() {
175
- return Number(await this.contract.get_blockheight());
176
- }
177
- /**
178
- * @inheritDoc
179
- */
180
- async getTipData() {
181
- const commitHash = await this.contract.get_tip_commit_hash();
182
- if (commitHash == null || BigInt(commitHash) === BigInt(0))
183
- return null;
184
- const result = await this.getBlock(commitHash);
185
- if (result == null)
186
- return null;
187
- const [storedBlockHeader] = result;
188
- return {
189
- blockheight: storedBlockHeader.getBlockheight(),
190
- commitHash: (0, Utils_1.bigNumberishToBuffer)(commitHash, 32).toString("hex"),
191
- blockhash: storedBlockHeader.getBlockHash().toString("hex"),
192
- chainWork: storedBlockHeader.getChainWork()
193
- };
194
- }
195
- /**
196
- * @inheritDoc
197
- */
198
- async retrieveLogAndBlockheight(blockData, requiredBlockheight) {
199
- //TODO: we can fetch the blockheight and events in parallel
200
- const blockHeight = await this.getBlockHeight();
201
- if (requiredBlockheight != null && blockHeight < requiredBlockheight) {
202
- return null;
203
- }
204
- const result = await this.getBlock(undefined, buffer_1.Buffer.from(blockData.blockhash, "hex"));
205
- if (result == null)
206
- return null;
207
- const [storedBlockHeader, commitHash] = result;
208
- //Check if block is part of the main chain
209
- const chainCommitment = await this.contract.get_commit_hash(storedBlockHeader.block_height);
210
- if (BigInt(chainCommitment) !== BigInt(commitHash))
211
- return null;
212
- logger.debug("retrieveLogAndBlockheight(): block found," +
213
- " commit hash: " + (0, Utils_1.toHex)(commitHash) + " blockhash: " + blockData.blockhash + " current btc relay height: " + blockHeight);
214
- return { header: storedBlockHeader, height: blockHeight };
215
- }
216
- /**
217
- * @inheritDoc
218
- */
219
- async retrieveLogByCommitHash(commitmentHash, blockData) {
220
- const result = await this.getBlock(commitmentHash, buffer_1.Buffer.from(blockData.blockhash, "hex"));
221
- if (result == null)
222
- return null;
223
- const [storedBlockHeader, commitHash] = result;
224
- //Check if block is part of the main chain
225
- const chainCommitment = await this.contract.get_commit_hash(storedBlockHeader.block_height);
226
- if (BigInt(chainCommitment) !== BigInt(commitHash))
227
- return null;
228
- logger.debug("retrieveLogByCommitHash(): block found," +
229
- " commit hash: " + commitmentHash + " blockhash: " + blockData.blockhash + " height: " + storedBlockHeader.block_height);
230
- return storedBlockHeader;
231
- }
232
- /**
233
- * @inheritDoc
234
- */
235
- async retrieveLatestKnownBlockLog() {
236
- const data = await this.Events.findInContractEvents(["btc_relay::events::StoreHeader", "btc_relay::events::StoreForkHeader"], null, async (event) => {
237
- const storedHeader = StarknetBtcStoredHeader_1.StarknetBtcStoredHeader.fromSerializedFeltArray(event.data);
238
- const blockHashHex = storedHeader.getBlockHash().toString("hex");
239
- const commitHash = event.params.commit_hash;
240
- const [isInBtcMainChain, btcRelayCommitHash] = await Promise.all([
241
- this.bitcoinRpc.isInMainChain(blockHashHex).catch(() => false),
242
- this.contract.get_commit_hash(storedHeader.block_height)
243
- ]);
244
- if (!isInBtcMainChain)
245
- return null;
246
- if (BigInt(commitHash) !== BigInt(btcRelayCommitHash))
247
- return null;
248
- const bitcoinBlockHeader = await this.bitcoinRpc.getBlockHeader(blockHashHex);
249
- if (bitcoinBlockHeader == null)
250
- return null;
251
- return {
252
- resultStoredHeader: storedHeader,
253
- resultBitcoinHeader: bitcoinBlockHeader,
254
- commitHash: commitHash
255
- };
256
- });
257
- if (data != null)
258
- logger.debug("retrieveLatestKnownBlockLog(): block found," +
259
- " commit hash: " + (0, Utils_1.toHex)(data.commitHash) + " blockhash: " + data.resultBitcoinHeader.getHash() +
260
- " height: " + data.resultStoredHeader.getBlockheight());
261
- return data;
262
- }
263
- /**
264
- * @inheritDoc
265
- */
266
- async saveMainHeaders(signer, mainHeaders, storedHeader, feeRate) {
267
- feeRate ?? (feeRate = await this.getMainFeeRate(signer));
268
- logger.debug("saveMainHeaders(): submitting main blockheaders, count: " + mainHeaders.length);
269
- return this._saveHeaders(signer, mainHeaders, storedHeader, 0, feeRate);
270
- }
271
- /**
272
- * @inheritDoc
273
- */
274
- async saveNewForkHeaders(signer, forkHeaders, storedHeader, tipWork, feeRate) {
275
- let forkId = Math.floor(Math.random() * 0xFFFFFFFFFFFF);
276
- feeRate ?? (feeRate = await this.getForkFeeRate(signer, forkId));
277
- logger.debug("saveNewForkHeaders(): submitting new fork & blockheaders," +
278
- " count: " + forkHeaders.length + " forkId: 0x" + forkId.toString(16));
279
- const result = await this._saveHeaders(signer, forkHeaders, storedHeader, forkId, feeRate);
280
- if (result.forkId !== 0 && base_1.StatePredictorUtils.gtBuffer(result.lastStoredHeader.getChainWork(), tipWork)) {
281
- //Fork's work is higher than main chain's work, this fork will become a main chain
282
- result.forkId = 0;
283
- }
284
- return result;
285
- }
286
- /**
287
- * @inheritDoc
288
- */
289
- async saveForkHeaders(signer, forkHeaders, storedHeader, forkId, tipWork, feeRate) {
290
- feeRate ?? (feeRate = await this.getForkFeeRate(signer, forkId));
291
- logger.debug("saveForkHeaders(): submitting blockheaders to existing fork," +
292
- " count: " + forkHeaders.length + " forkId: 0x" + forkId.toString(16));
293
- const result = await this._saveHeaders(signer, forkHeaders, storedHeader, forkId, feeRate);
294
- if (result.forkId !== 0 && base_1.StatePredictorUtils.gtBuffer(result.lastStoredHeader.getChainWork(), tipWork)) {
295
- //Fork's work is higher than main chain's work, this fork will become a main chain
296
- result.forkId = 0;
297
- }
298
- return result;
299
- }
300
- /**
301
- * @inheritDoc
302
- */
303
- async saveShortForkHeaders(signer, forkHeaders, storedHeader, tipWork, feeRate) {
304
- feeRate ?? (feeRate = await this.getMainFeeRate(signer));
305
- logger.debug("saveShortForkHeaders(): submitting short fork blockheaders," +
306
- " count: " + forkHeaders.length);
307
- const result = await this._saveHeaders(signer, forkHeaders, storedHeader, -1, feeRate);
308
- if (result.forkId !== 0 && base_1.StatePredictorUtils.gtBuffer(result.lastStoredHeader.getChainWork(), tipWork)) {
309
- //Fork's work is higher than main chain's work, this fork will become a main chain
310
- result.forkId = 0;
311
- }
312
- return result;
313
- }
314
- /**
315
- * @inheritDoc
316
- */
317
- async estimateSynchronizeFee(requiredBlockheight, feeRate) {
318
- const tipData = await this.getTipData();
319
- if (tipData == null)
320
- throw new Error("Cannot get relay tip data, relay not initialized?");
321
- const currBlockheight = tipData.blockheight;
322
- const blockheightDelta = requiredBlockheight - currBlockheight;
323
- if (blockheightDelta <= 0)
324
- return 0n;
325
- const synchronizationFee = BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate);
326
- logger.debug("estimateSynchronizeFee(): required blockheight: " + requiredBlockheight +
327
- " blockheight delta: " + blockheightDelta + " fee: " + synchronizationFee.toString(10));
328
- return synchronizationFee;
329
- }
330
- /**
331
- * @inheritDoc
332
- */
333
- async getFeePerBlock(feeRate) {
334
- feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
335
- return StarknetFees_1.StarknetFees.getGasFee(GAS_PER_BLOCKHEADER, feeRate);
336
- }
337
- /**
338
- * @inheritDoc
339
- */
340
- getMainFeeRate(signer) {
341
- return this.Chain.Fees.getFeeRate();
342
- }
343
- /**
344
- * @inheritDoc
345
- */
346
- getForkFeeRate(signer, forkId) {
347
- return this.Chain.Fees.getFeeRate();
348
- }
349
- /**
350
- * @inheritDoc
351
- */
352
- saveInitialHeader(signer, header, epochStart, pastBlocksTimestamps, feeRate) {
353
- throw new Error("Not supported, starknet contract is initialized with constructor!");
354
- }
355
- /**
356
- * Gets committed headers, identified by blockhash & blockheight, determines required BTC relay blockheight based on
357
- * requiredConfirmations.
358
- * If synchronizer is passed & some blockhash is not found (or blockhash doesn't have enough confirmations),
359
- * it produces transactions to sync up the btc relay to the current chain tip & adds them to the passed txs array.
360
- *
361
- * @param signer A signer's address to use for the transactions
362
- * @param btcRelay BtcRelay contract to use for retrieving committed headers
363
- * @param btcTxs Bitcoin transactions to fetch the stored blockheaders for
364
- * @param txs Transactions array, in case we need to synchronize the btc relay ourselves the synchronization
365
- * txns are added here
366
- * @param synchronizer optional synchronizer to use to synchronize the btc relay in case it is not yet synchronized
367
- * to the required blockheight
368
- * @param feeRate Fee rate to use for synchronization transactions
369
- *
370
- * @private
371
- */
372
- static async getCommitedHeadersAndSynchronize(signer, btcRelay, btcTxs, txs, synchronizer, feeRate) {
373
- const leavesTxs = [];
374
- const blockheaders = {};
375
- for (let btcTx of btcTxs) {
376
- const requiredBlockheight = btcTx.blockheight + btcTx.requiredConfirmations - 1;
377
- const result = await btcRelay.retrieveLogAndBlockheight({
378
- blockhash: btcTx.blockhash
379
- }, requiredBlockheight);
380
- if (result != null) {
381
- blockheaders[result.header.getBlockHash().toString("hex")] = result.header;
382
- }
383
- else {
384
- leavesTxs.push(btcTx);
385
- }
386
- }
387
- if (leavesTxs.length === 0)
388
- return blockheaders;
389
- //Need to synchronize
390
- if (synchronizer == null)
391
- return null;
392
- //TODO: We don't have to synchronize to tip, only to our required blockheight
393
- const resp = await synchronizer.syncToLatestTxs(signer.toString(), feeRate);
394
- logger.debug("getCommitedHeaderAndSynchronize(): BTC Relay not synchronized to required blockheight, " +
395
- "synchronizing ourselves in " + resp.txs.length + " txs");
396
- logger.debug("getCommitedHeaderAndSynchronize(): BTC Relay computed header map: ", resp.computedHeaderMap);
397
- txs.push(...resp.txs);
398
- for (let key in resp.computedHeaderMap) {
399
- const header = resp.computedHeaderMap[key];
400
- blockheaders[header.getBlockHash().toString("hex")] = header;
401
- }
402
- //Check that blockhashes of all the rest txs are included
403
- for (let btcTx of leavesTxs) {
404
- if (blockheaders[btcTx.blockhash] == null)
405
- return null;
406
- }
407
- //Retrieve computed headers
408
- return blockheaders;
409
- }
410
- }
411
- exports.StarknetBtcRelay = StarknetBtcRelay;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StarknetBtcRelay = void 0;
4
+ const buffer_1 = require("buffer");
5
+ const StarknetBtcHeader_1 = require("./headers/StarknetBtcHeader");
6
+ const base_1 = require("@atomiqlabs/base");
7
+ const Utils_1 = require("../../utils/Utils");
8
+ const StarknetContractBase_1 = require("../contract/StarknetContractBase");
9
+ const StarknetBtcStoredHeader_1 = require("./headers/StarknetBtcStoredHeader");
10
+ const BtcRelayAbi_1 = require("./BtcRelayAbi");
11
+ const starknet_1 = require("starknet");
12
+ const StarknetFees_1 = require("../chain/modules/StarknetFees");
13
+ const StarknetAction_1 = require("../chain/StarknetAction");
14
+ function serializeBlockHeader(e) {
15
+ return new StarknetBtcHeader_1.StarknetBtcHeader({
16
+ reversed_version: (0, Utils_1.u32ReverseEndianness)(e.getVersion()),
17
+ previous_blockhash: (0, Utils_1.bufferToU32Array)(buffer_1.Buffer.from(e.getPrevBlockhash(), "hex").reverse()),
18
+ merkle_root: (0, Utils_1.bufferToU32Array)(buffer_1.Buffer.from(e.getMerkleRoot(), "hex").reverse()),
19
+ reversed_timestamp: (0, Utils_1.u32ReverseEndianness)(e.getTimestamp()),
20
+ nbits: (0, Utils_1.u32ReverseEndianness)(e.getNbits()),
21
+ nonce: (0, Utils_1.u32ReverseEndianness)(e.getNonce()),
22
+ hash: buffer_1.Buffer.from(e.getHash(), "hex").reverse()
23
+ });
24
+ }
25
+ const GAS_PER_BLOCKHEADER = { l1DataGas: 600, l2Gas: 24000000, l1Gas: 0 };
26
+ const GAS_PER_BLOCKHEADER_FORK = { l1DataGas: 1000, l2Gas: 40000000, l1Gas: 0 };
27
+ const btcRelayAddreses = {
28
+ [base_1.BitcoinNetwork.TESTNET4]: "0x0099b63f39f0cabb767361de3d8d3e97212351a51540e2687c2571f4da490dbe",
29
+ [base_1.BitcoinNetwork.TESTNET]: "0x068601c79da2231d21e015ccfd59c243861156fa523a12c9f987ec28eb8dbc8c",
30
+ [base_1.BitcoinNetwork.MAINNET]: "0x057b14a4231b82f1e525ff35a722d893ca3dd2bde0baa6cee97937c5be861dbc"
31
+ };
32
+ const btcRelayDeploymentHeights = {
33
+ [base_1.BitcoinNetwork.TESTNET4]: 760719,
34
+ [base_1.BitcoinNetwork.TESTNET]: 633915,
35
+ [base_1.BitcoinNetwork.MAINNET]: 1278562
36
+ };
37
+ function serializeCalldata(headers, storedHeader, span) {
38
+ span.push((0, Utils_1.toHex)(headers.length));
39
+ headers.forEach(header => {
40
+ span.push(...header.serialize());
41
+ });
42
+ span.push(...storedHeader.serialize());
43
+ return span;
44
+ }
45
+ const logger = (0, Utils_1.getLogger)("StarknetBtcRelay: ");
46
+ /**
47
+ * Starknet BTC Relay bitcoin light client contract representation
48
+ *
49
+ * @category BTC Relay
50
+ */
51
+ class StarknetBtcRelay extends StarknetContractBase_1.StarknetContractBase {
52
+ /**
53
+ * Returns a {@link StarknetAction} that submits new main chain bitcoin blockheaders to the light client
54
+ *
55
+ * @param signer Starknet signer's address
56
+ * @param mainHeaders New bitcoin blockheaders to submit
57
+ * @param storedHeader Current latest committed and stored bitcoin blockheader in the light client
58
+ */
59
+ SaveMainHeaders(signer, mainHeaders, storedHeader) {
60
+ return new StarknetAction_1.StarknetAction(signer, this.Chain, {
61
+ contractAddress: this.contract.address,
62
+ entrypoint: "submit_main_blockheaders",
63
+ calldata: serializeCalldata(mainHeaders, storedHeader, [])
64
+ }, (0, StarknetFees_1.starknetGasMul)(GAS_PER_BLOCKHEADER, mainHeaders.length));
65
+ }
66
+ /**
67
+ * Returns a {@link StarknetAction} for submitting a short fork bitcoin blockheaders to the light client,
68
+ * forking the chain from the provided `storedHeader` param's blockheight. For a successful fork the
69
+ * submitted chain needs to have higher total chainwork than the current cannonical chain
70
+ *
71
+ * @param signer Starknet signer's address
72
+ * @param forkHeaders Fork bitcoin blockheaders to submit
73
+ * @param storedHeader Committed and stored bitcoin blockheader from which to fork the light client
74
+ */
75
+ SaveShortForkHeaders(signer, forkHeaders, storedHeader) {
76
+ return new StarknetAction_1.StarknetAction(signer, this.Chain, {
77
+ contractAddress: this.contract.address,
78
+ entrypoint: "submit_short_fork_blockheaders",
79
+ calldata: serializeCalldata(forkHeaders, storedHeader, [])
80
+ }, (0, StarknetFees_1.starknetGasMul)(GAS_PER_BLOCKHEADER, forkHeaders.length));
81
+ }
82
+ /**
83
+ * Returns a {@link StarknetAction} for submitting a long fork of bitcoin blockheaders to the light client.
84
+ *
85
+ * @param signer Starknet signer's address
86
+ * @param forkId Fork ID to submit the fork blockheaders to
87
+ * @param forkHeaders Fork bitcoin blockheaders to submit
88
+ * @param storedHeader Either a committed and stored bitcoin blockheader from which to fork the light client (when
89
+ * creating the fork), or the tip of the fork (when adding more blockheaders to the fork)
90
+ * @param totalForkHeaders Total blockheaders in the fork - used to estimate the gas usage when re-org happens
91
+ */
92
+ SaveLongForkHeaders(signer, forkId, forkHeaders, storedHeader, totalForkHeaders = 100) {
93
+ return new StarknetAction_1.StarknetAction(signer, this.Chain, {
94
+ contractAddress: this.contract.address,
95
+ entrypoint: "submit_fork_blockheaders",
96
+ calldata: serializeCalldata(forkHeaders, storedHeader, [(0, Utils_1.toHex)(forkId)])
97
+ }, (0, StarknetFees_1.starknetGasAdd)((0, StarknetFees_1.starknetGasMul)(GAS_PER_BLOCKHEADER, forkHeaders.length), (0, StarknetFees_1.starknetGasMul)(GAS_PER_BLOCKHEADER_FORK, totalForkHeaders)));
98
+ }
99
+ constructor(chainInterface, bitcoinRpc, bitcoinNetwork, contractAddress = btcRelayAddreses[bitcoinNetwork], contractDeploymentHeight) {
100
+ if (contractAddress == null)
101
+ throw new Error("No BtcRelay address specified!");
102
+ super(chainInterface, contractAddress, BtcRelayAbi_1.BtcRelayAbi, contractDeploymentHeight ??
103
+ (btcRelayAddreses[bitcoinNetwork] === contractAddress
104
+ ? btcRelayDeploymentHeights[bitcoinNetwork]
105
+ : undefined));
106
+ this.maxHeadersPerTx = 40;
107
+ this.maxForkHeadersPerTx = 30;
108
+ this.maxShortForkHeadersPerTx = 40;
109
+ this.bitcoinRpc = bitcoinRpc;
110
+ }
111
+ /**
112
+ * Computes subsequent commited headers as they will appear on the blockchain when transactions
113
+ * are submitted & confirmed
114
+ *
115
+ * @param initialStoredHeader
116
+ * @param syncedHeaders
117
+ * @private
118
+ */
119
+ computeCommitedHeaders(initialStoredHeader, syncedHeaders) {
120
+ const computedCommitedHeaders = [initialStoredHeader];
121
+ for (let blockHeader of syncedHeaders) {
122
+ computedCommitedHeaders.push(computedCommitedHeaders[computedCommitedHeaders.length - 1].computeNext(blockHeader));
123
+ }
124
+ return computedCommitedHeaders;
125
+ }
126
+ /**
127
+ * A common logic for submitting blockheaders in a transaction
128
+ *
129
+ * @param signer Starknet signer's address
130
+ * @param headers Bitcoin blockheaders to submit to the btc relay
131
+ * @param storedHeader Current latest stored block header for a given fork or main chain
132
+ * @param forkId Fork ID to submit to, `forkId`=0 means main chain, `forkId`=-1 means short fork
133
+ * @param feeRate Fee rate for the transaction
134
+ * @private
135
+ */
136
+ async _saveHeaders(signer, headers, storedHeader, forkId, feeRate) {
137
+ const blockHeaderObj = headers.map(serializeBlockHeader);
138
+ let starknetAction;
139
+ switch (forkId) {
140
+ case -1:
141
+ starknetAction = this.SaveShortForkHeaders(signer, blockHeaderObj, storedHeader);
142
+ break;
143
+ case 0:
144
+ starknetAction = this.SaveMainHeaders(signer, blockHeaderObj, storedHeader);
145
+ break;
146
+ default:
147
+ starknetAction = this.SaveLongForkHeaders(signer, forkId, blockHeaderObj, storedHeader);
148
+ break;
149
+ }
150
+ const tx = await starknetAction.tx(feeRate);
151
+ const computedCommitedHeaders = this.computeCommitedHeaders(storedHeader, blockHeaderObj);
152
+ const lastStoredHeader = computedCommitedHeaders[computedCommitedHeaders.length - 1];
153
+ return {
154
+ forkId: forkId,
155
+ lastStoredHeader,
156
+ tx,
157
+ computedCommitedHeaders
158
+ };
159
+ }
160
+ /**
161
+ * Returns a committed bitcoin blockheader based on the provided `commitHash` or `blockHash`
162
+ *
163
+ * @param commitHash Commitment hash of the stored blockheader
164
+ * @param blockHash Block's hash
165
+ * @private
166
+ */
167
+ getBlock(commitHash, blockHash) {
168
+ const keys = [commitHash == null ? null : (0, Utils_1.toHex)(commitHash)];
169
+ if (blockHash != null) {
170
+ const starknetBlockHash = starknet_1.hash.computePoseidonHashOnElements((0, Utils_1.bufferToU32Array)(buffer_1.Buffer.from([...blockHash]).reverse()));
171
+ keys.push(starknetBlockHash);
172
+ }
173
+ return this.Events.findInContractEvents(["btc_relay::events::StoreHeader", "btc_relay::events::StoreForkHeader"], keys, (event) => {
174
+ return Promise.resolve([StarknetBtcStoredHeader_1.StarknetBtcStoredHeader.fromSerializedFeltArray(event.data), BigInt(event.params.commit_hash)]);
175
+ });
176
+ }
177
+ /**
178
+ * Returns the current main chain blockheight of the BTC Relay
179
+ *
180
+ * @private
181
+ */
182
+ async getBlockHeight() {
183
+ return Number(await this.contract.get_blockheight());
184
+ }
185
+ /**
186
+ * @inheritDoc
187
+ */
188
+ async getTipData() {
189
+ const commitHash = await this.contract.get_tip_commit_hash();
190
+ if (commitHash == null || BigInt(commitHash) === BigInt(0))
191
+ return null;
192
+ const result = await this.getBlock(commitHash);
193
+ if (result == null)
194
+ return null;
195
+ const [storedBlockHeader] = result;
196
+ return {
197
+ blockheight: storedBlockHeader.getBlockheight(),
198
+ commitHash: (0, Utils_1.bigNumberishToBuffer)(commitHash, 32).toString("hex"),
199
+ blockhash: storedBlockHeader.getBlockHash().toString("hex"),
200
+ chainWork: storedBlockHeader.getChainWork()
201
+ };
202
+ }
203
+ /**
204
+ * @inheritDoc
205
+ */
206
+ async retrieveLogAndBlockheight(blockData, requiredBlockheight) {
207
+ //TODO: we can fetch the blockheight and events in parallel
208
+ const blockHeight = await this.getBlockHeight();
209
+ if (requiredBlockheight != null && blockHeight < requiredBlockheight) {
210
+ return null;
211
+ }
212
+ const result = await this.getBlock(undefined, buffer_1.Buffer.from(blockData.blockhash, "hex"));
213
+ if (result == null)
214
+ return null;
215
+ const [storedBlockHeader, commitHash] = result;
216
+ //Check if block is part of the main chain
217
+ const chainCommitment = await this.contract.get_commit_hash(storedBlockHeader.getBlockheight());
218
+ if (BigInt(chainCommitment) !== BigInt(commitHash))
219
+ return null;
220
+ logger.debug("retrieveLogAndBlockheight(): block found," +
221
+ " commit hash: " + (0, Utils_1.toHex)(commitHash) + " blockhash: " + blockData.blockhash + " current btc relay height: " + blockHeight);
222
+ return { header: storedBlockHeader, height: blockHeight };
223
+ }
224
+ /**
225
+ * @inheritDoc
226
+ */
227
+ async retrieveLogByCommitHash(commitmentHash, blockData) {
228
+ const result = await this.getBlock(commitmentHash, buffer_1.Buffer.from(blockData.blockhash, "hex"));
229
+ if (result == null)
230
+ return null;
231
+ const [storedBlockHeader, commitHash] = result;
232
+ //Check if block is part of the main chain
233
+ const chainCommitment = await this.contract.get_commit_hash(storedBlockHeader.getBlockheight());
234
+ if (BigInt(chainCommitment) !== BigInt(commitHash))
235
+ return null;
236
+ logger.debug("retrieveLogByCommitHash(): block found," +
237
+ " commit hash: " + commitmentHash + " blockhash: " + blockData.blockhash + " height: " + storedBlockHeader.getBlockheight());
238
+ return storedBlockHeader;
239
+ }
240
+ /**
241
+ * @inheritDoc
242
+ */
243
+ async retrieveLatestKnownBlockLog() {
244
+ const data = await this.Events.findInContractEvents(["btc_relay::events::StoreHeader", "btc_relay::events::StoreForkHeader"], null, async (event) => {
245
+ const storedHeader = StarknetBtcStoredHeader_1.StarknetBtcStoredHeader.fromSerializedFeltArray(event.data);
246
+ const blockHashHex = storedHeader.getBlockHash().toString("hex");
247
+ const commitHash = event.params.commit_hash;
248
+ const [isInBtcMainChain, btcRelayCommitHash] = await Promise.all([
249
+ this.bitcoinRpc.isInMainChain(blockHashHex).catch(() => false),
250
+ this.contract.get_commit_hash(storedHeader.getBlockheight())
251
+ ]);
252
+ if (!isInBtcMainChain)
253
+ return null;
254
+ if (BigInt(commitHash) !== BigInt(btcRelayCommitHash))
255
+ return null;
256
+ const bitcoinBlockHeader = await this.bitcoinRpc.getBlockHeader(blockHashHex);
257
+ if (bitcoinBlockHeader == null)
258
+ return null;
259
+ return {
260
+ resultStoredHeader: storedHeader,
261
+ resultBitcoinHeader: bitcoinBlockHeader,
262
+ commitHash: commitHash
263
+ };
264
+ });
265
+ if (data != null)
266
+ logger.debug("retrieveLatestKnownBlockLog(): block found," +
267
+ " commit hash: " + (0, Utils_1.toHex)(data.commitHash) + " blockhash: " + data.resultBitcoinHeader.getHash() +
268
+ " height: " + data.resultStoredHeader.getBlockheight());
269
+ return data;
270
+ }
271
+ /**
272
+ * @inheritDoc
273
+ */
274
+ async saveMainHeaders(signer, mainHeaders, storedHeader, feeRate) {
275
+ feeRate ?? (feeRate = await this.getMainFeeRate(signer));
276
+ logger.debug("saveMainHeaders(): submitting main blockheaders, count: " + mainHeaders.length);
277
+ return this._saveHeaders(signer, mainHeaders, storedHeader, 0, feeRate);
278
+ }
279
+ /**
280
+ * @inheritDoc
281
+ */
282
+ async saveNewForkHeaders(signer, forkHeaders, storedHeader, tipWork, feeRate) {
283
+ let forkId = Math.floor(Math.random() * 0xFFFFFFFFFFFF);
284
+ feeRate ?? (feeRate = await this.getForkFeeRate(signer, forkId));
285
+ logger.debug("saveNewForkHeaders(): submitting new fork & blockheaders," +
286
+ " count: " + forkHeaders.length + " forkId: 0x" + forkId.toString(16));
287
+ const result = await this._saveHeaders(signer, forkHeaders, storedHeader, forkId, feeRate);
288
+ if (result.forkId !== 0 && base_1.StatePredictorUtils.gtBuffer(result.lastStoredHeader.getChainWork(), tipWork)) {
289
+ //Fork's work is higher than main chain's work, this fork will become a main chain
290
+ result.forkId = 0;
291
+ }
292
+ return result;
293
+ }
294
+ /**
295
+ * @inheritDoc
296
+ */
297
+ async saveForkHeaders(signer, forkHeaders, storedHeader, forkId, tipWork, feeRate) {
298
+ feeRate ?? (feeRate = await this.getForkFeeRate(signer, forkId));
299
+ logger.debug("saveForkHeaders(): submitting blockheaders to existing fork," +
300
+ " count: " + forkHeaders.length + " forkId: 0x" + forkId.toString(16));
301
+ const result = await this._saveHeaders(signer, forkHeaders, storedHeader, forkId, feeRate);
302
+ if (result.forkId !== 0 && base_1.StatePredictorUtils.gtBuffer(result.lastStoredHeader.getChainWork(), tipWork)) {
303
+ //Fork's work is higher than main chain's work, this fork will become a main chain
304
+ result.forkId = 0;
305
+ }
306
+ return result;
307
+ }
308
+ /**
309
+ * @inheritDoc
310
+ */
311
+ async saveShortForkHeaders(signer, forkHeaders, storedHeader, tipWork, feeRate) {
312
+ feeRate ?? (feeRate = await this.getMainFeeRate(signer));
313
+ logger.debug("saveShortForkHeaders(): submitting short fork blockheaders," +
314
+ " count: " + forkHeaders.length);
315
+ const result = await this._saveHeaders(signer, forkHeaders, storedHeader, -1, feeRate);
316
+ if (result.forkId !== 0 && base_1.StatePredictorUtils.gtBuffer(result.lastStoredHeader.getChainWork(), tipWork)) {
317
+ //Fork's work is higher than main chain's work, this fork will become a main chain
318
+ result.forkId = 0;
319
+ }
320
+ return result;
321
+ }
322
+ /**
323
+ * @inheritDoc
324
+ */
325
+ async estimateSynchronizeFee(requiredBlockheight, feeRate) {
326
+ const tipData = await this.getTipData();
327
+ if (tipData == null)
328
+ throw new Error("Cannot get relay tip data, relay not initialized?");
329
+ const currBlockheight = tipData.blockheight;
330
+ const blockheightDelta = requiredBlockheight - currBlockheight;
331
+ if (blockheightDelta <= 0)
332
+ return 0n;
333
+ const synchronizationFee = BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate);
334
+ logger.debug("estimateSynchronizeFee(): required blockheight: " + requiredBlockheight +
335
+ " blockheight delta: " + blockheightDelta + " fee: " + synchronizationFee.toString(10));
336
+ return synchronizationFee;
337
+ }
338
+ /**
339
+ * @inheritDoc
340
+ */
341
+ async getFeePerBlock(feeRate) {
342
+ feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
343
+ return StarknetFees_1.StarknetFees.getGasFee(GAS_PER_BLOCKHEADER, feeRate);
344
+ }
345
+ /**
346
+ * @inheritDoc
347
+ */
348
+ getMainFeeRate(signer) {
349
+ return this.Chain.Fees.getFeeRate();
350
+ }
351
+ /**
352
+ * @inheritDoc
353
+ */
354
+ getForkFeeRate(signer, forkId) {
355
+ return this.Chain.Fees.getFeeRate();
356
+ }
357
+ /**
358
+ * @inheritDoc
359
+ */
360
+ saveInitialHeader(signer, header, epochStart, pastBlocksTimestamps, feeRate) {
361
+ throw new Error("Not supported, starknet contract is initialized with constructor!");
362
+ }
363
+ /**
364
+ * Gets committed headers, identified by blockhash & blockheight, determines required BTC relay blockheight based on
365
+ * requiredConfirmations.
366
+ * If synchronizer is passed & some blockhash is not found (or blockhash doesn't have enough confirmations),
367
+ * it produces transactions to sync up the btc relay to the current chain tip & adds them to the passed txs array.
368
+ *
369
+ * @param signer A signer's address to use for the transactions
370
+ * @param btcRelay BtcRelay contract to use for retrieving committed headers
371
+ * @param btcTxs Bitcoin transactions to fetch the stored blockheaders for
372
+ * @param txs Transactions array, in case we need to synchronize the btc relay ourselves the synchronization
373
+ * txns are added here
374
+ * @param synchronizer optional synchronizer to use to synchronize the btc relay in case it is not yet synchronized
375
+ * to the required blockheight
376
+ * @param feeRate Fee rate to use for synchronization transactions
377
+ *
378
+ * @private
379
+ */
380
+ static async getCommitedHeadersAndSynchronize(signer, btcRelay, btcTxs, txs, synchronizer, feeRate) {
381
+ const leavesTxs = [];
382
+ const blockheaders = {};
383
+ for (let btcTx of btcTxs) {
384
+ const requiredBlockheight = btcTx.blockheight + btcTx.requiredConfirmations - 1;
385
+ const result = await btcRelay.retrieveLogAndBlockheight({
386
+ blockhash: btcTx.blockhash
387
+ }, requiredBlockheight);
388
+ if (result != null) {
389
+ blockheaders[result.header.getBlockHash().toString("hex")] = result.header;
390
+ }
391
+ else {
392
+ leavesTxs.push(btcTx);
393
+ }
394
+ }
395
+ if (leavesTxs.length === 0)
396
+ return blockheaders;
397
+ //Need to synchronize
398
+ if (synchronizer == null)
399
+ return null;
400
+ //TODO: We don't have to synchronize to tip, only to our required blockheight
401
+ const resp = await synchronizer.syncToLatestTxs(signer.toString(), feeRate);
402
+ logger.debug("getCommitedHeaderAndSynchronize(): BTC Relay not synchronized to required blockheight, " +
403
+ "synchronizing ourselves in " + resp.txs.length + " txs");
404
+ logger.debug("getCommitedHeaderAndSynchronize(): BTC Relay computed header map: ", resp.computedHeaderMap);
405
+ txs.push(...resp.txs);
406
+ for (let key in resp.computedHeaderMap) {
407
+ const header = resp.computedHeaderMap[key];
408
+ blockheaders[header.getBlockHash().toString("hex")] = header;
409
+ }
410
+ //Check that blockhashes of all the rest txs are included
411
+ for (let btcTx of leavesTxs) {
412
+ if (blockheaders[btcTx.blockhash] == null)
413
+ return null;
414
+ }
415
+ //Retrieve computed headers
416
+ return blockheaders;
417
+ }
418
+ }
419
+ exports.StarknetBtcRelay = StarknetBtcRelay;