@atomiqlabs/chain-starknet 1.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 (136) hide show
  1. package/LICENSE +201 -0
  2. package/dist/get_serialized_block.d.ts +1 -0
  3. package/dist/get_serialized_block.js +28 -0
  4. package/dist/index.d.ts +34 -0
  5. package/dist/index.js +50 -0
  6. package/dist/starknet/StarknetChainType.d.ts +9 -0
  7. package/dist/starknet/StarknetChainType.js +2 -0
  8. package/dist/starknet/StarknetInitializer.d.ts +18 -0
  9. package/dist/starknet/StarknetInitializer.js +49 -0
  10. package/dist/starknet/base/StarknetAction.d.ts +27 -0
  11. package/dist/starknet/base/StarknetAction.js +73 -0
  12. package/dist/starknet/base/StarknetBase.d.ts +34 -0
  13. package/dist/starknet/base/StarknetBase.js +29 -0
  14. package/dist/starknet/base/StarknetModule.d.ts +14 -0
  15. package/dist/starknet/base/StarknetModule.js +13 -0
  16. package/dist/starknet/base/modules/ERC20Abi.d.ts +755 -0
  17. package/dist/starknet/base/modules/ERC20Abi.js +1032 -0
  18. package/dist/starknet/base/modules/StarknetAccounts.d.ts +6 -0
  19. package/dist/starknet/base/modules/StarknetAccounts.js +24 -0
  20. package/dist/starknet/base/modules/StarknetAddresses.d.ts +9 -0
  21. package/dist/starknet/base/modules/StarknetAddresses.js +26 -0
  22. package/dist/starknet/base/modules/StarknetBlocks.d.ts +19 -0
  23. package/dist/starknet/base/modules/StarknetBlocks.js +49 -0
  24. package/dist/starknet/base/modules/StarknetEvents.d.ts +44 -0
  25. package/dist/starknet/base/modules/StarknetEvents.js +88 -0
  26. package/dist/starknet/base/modules/StarknetFees.d.ts +55 -0
  27. package/dist/starknet/base/modules/StarknetFees.js +102 -0
  28. package/dist/starknet/base/modules/StarknetSignatures.d.ts +30 -0
  29. package/dist/starknet/base/modules/StarknetSignatures.js +71 -0
  30. package/dist/starknet/base/modules/StarknetTokens.d.ts +67 -0
  31. package/dist/starknet/base/modules/StarknetTokens.js +97 -0
  32. package/dist/starknet/base/modules/StarknetTransactions.d.ts +87 -0
  33. package/dist/starknet/base/modules/StarknetTransactions.js +226 -0
  34. package/dist/starknet/btcrelay/BtcRelayAbi.d.ts +250 -0
  35. package/dist/starknet/btcrelay/BtcRelayAbi.js +341 -0
  36. package/dist/starknet/btcrelay/StarknetBtcRelay.d.ts +166 -0
  37. package/dist/starknet/btcrelay/StarknetBtcRelay.js +323 -0
  38. package/dist/starknet/btcrelay/headers/StarknetBtcHeader.d.ts +32 -0
  39. package/dist/starknet/btcrelay/headers/StarknetBtcHeader.js +74 -0
  40. package/dist/starknet/btcrelay/headers/StarknetBtcStoredHeader.d.ts +52 -0
  41. package/dist/starknet/btcrelay/headers/StarknetBtcStoredHeader.js +113 -0
  42. package/dist/starknet/contract/StarknetContractBase.d.ts +13 -0
  43. package/dist/starknet/contract/StarknetContractBase.js +18 -0
  44. package/dist/starknet/contract/modules/StarknetContractEvents.d.ts +40 -0
  45. package/dist/starknet/contract/modules/StarknetContractEvents.js +77 -0
  46. package/dist/starknet/events/StarknetChainEvents.d.ts +19 -0
  47. package/dist/starknet/events/StarknetChainEvents.js +51 -0
  48. package/dist/starknet/events/StarknetChainEventsBrowser.d.ts +73 -0
  49. package/dist/starknet/events/StarknetChainEventsBrowser.js +210 -0
  50. package/dist/starknet/swaps/EscrowManagerAbi.d.ts +445 -0
  51. package/dist/starknet/swaps/EscrowManagerAbi.js +601 -0
  52. package/dist/starknet/swaps/StarknetSwapContract.d.ts +215 -0
  53. package/dist/starknet/swaps/StarknetSwapContract.js +452 -0
  54. package/dist/starknet/swaps/StarknetSwapData.d.ts +74 -0
  55. package/dist/starknet/swaps/StarknetSwapData.js +316 -0
  56. package/dist/starknet/swaps/StarknetSwapModule.d.ts +9 -0
  57. package/dist/starknet/swaps/StarknetSwapModule.js +12 -0
  58. package/dist/starknet/swaps/handlers/IHandler.d.ts +13 -0
  59. package/dist/starknet/swaps/handlers/IHandler.js +2 -0
  60. package/dist/starknet/swaps/handlers/claim/ClaimHandlers.d.ts +13 -0
  61. package/dist/starknet/swaps/handlers/claim/ClaimHandlers.js +13 -0
  62. package/dist/starknet/swaps/handlers/claim/HashlockClaimHandler.d.ts +22 -0
  63. package/dist/starknet/swaps/handlers/claim/HashlockClaimHandler.js +44 -0
  64. package/dist/starknet/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.d.ts +25 -0
  65. package/dist/starknet/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.js +48 -0
  66. package/dist/starknet/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.d.ts +26 -0
  67. package/dist/starknet/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.js +40 -0
  68. package/dist/starknet/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.d.ts +20 -0
  69. package/dist/starknet/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.js +29 -0
  70. package/dist/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.d.ts +64 -0
  71. package/dist/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.js +86 -0
  72. package/dist/starknet/swaps/handlers/refund/TimelockRefundHandler.d.ts +17 -0
  73. package/dist/starknet/swaps/handlers/refund/TimelockRefundHandler.js +27 -0
  74. package/dist/starknet/swaps/modules/StarknetLpVault.d.ts +69 -0
  75. package/dist/starknet/swaps/modules/StarknetLpVault.js +122 -0
  76. package/dist/starknet/swaps/modules/StarknetSwapClaim.d.ts +53 -0
  77. package/dist/starknet/swaps/modules/StarknetSwapClaim.js +100 -0
  78. package/dist/starknet/swaps/modules/StarknetSwapInit.d.ts +84 -0
  79. package/dist/starknet/swaps/modules/StarknetSwapInit.js +164 -0
  80. package/dist/starknet/swaps/modules/StarknetSwapRefund.d.ts +64 -0
  81. package/dist/starknet/swaps/modules/StarknetSwapRefund.js +131 -0
  82. package/dist/starknet/swaps/modules/SwapClaim.d.ts +54 -0
  83. package/dist/starknet/swaps/modules/SwapClaim.js +115 -0
  84. package/dist/starknet/swaps/modules/SwapInit.d.ts +79 -0
  85. package/dist/starknet/swaps/modules/SwapInit.js +174 -0
  86. package/dist/starknet/swaps/modules/SwapRefund.d.ts +63 -0
  87. package/dist/starknet/swaps/modules/SwapRefund.js +149 -0
  88. package/dist/starknet/wallet/StarknetKeypairWallet.d.ts +6 -0
  89. package/dist/starknet/wallet/StarknetKeypairWallet.js +26 -0
  90. package/dist/starknet/wallet/StarknetSigner.d.ts +12 -0
  91. package/dist/starknet/wallet/StarknetSigner.js +46 -0
  92. package/dist/utils/Utils.d.ts +38 -0
  93. package/dist/utils/Utils.js +255 -0
  94. package/package.json +39 -0
  95. package/src/index.ts +41 -0
  96. package/src/starknet/StarknetChainType.ts +20 -0
  97. package/src/starknet/StarknetInitializer.ts +75 -0
  98. package/src/starknet/base/StarknetAction.ts +90 -0
  99. package/src/starknet/base/StarknetBase.ts +56 -0
  100. package/src/starknet/base/StarknetModule.ts +20 -0
  101. package/src/starknet/base/modules/ERC20Abi.ts +1029 -0
  102. package/src/starknet/base/modules/StarknetAccounts.ts +26 -0
  103. package/src/starknet/base/modules/StarknetAddresses.ts +23 -0
  104. package/src/starknet/base/modules/StarknetBlocks.ts +59 -0
  105. package/src/starknet/base/modules/StarknetEvents.ts +105 -0
  106. package/src/starknet/base/modules/StarknetFees.ts +136 -0
  107. package/src/starknet/base/modules/StarknetSignatures.ts +91 -0
  108. package/src/starknet/base/modules/StarknetTokens.ts +116 -0
  109. package/src/starknet/base/modules/StarknetTransactions.ts +254 -0
  110. package/src/starknet/btcrelay/BtcRelayAbi.ts +338 -0
  111. package/src/starknet/btcrelay/StarknetBtcRelay.ts +415 -0
  112. package/src/starknet/btcrelay/headers/StarknetBtcHeader.ts +101 -0
  113. package/src/starknet/btcrelay/headers/StarknetBtcStoredHeader.ts +142 -0
  114. package/src/starknet/contract/StarknetContractBase.ts +29 -0
  115. package/src/starknet/contract/modules/StarknetContractEvents.ts +108 -0
  116. package/src/starknet/events/StarknetChainEvents.ts +63 -0
  117. package/src/starknet/events/StarknetChainEventsBrowser.ts +289 -0
  118. package/src/starknet/swaps/EscrowManagerAbi.ts +600 -0
  119. package/src/starknet/swaps/StarknetSwapContract.ts +694 -0
  120. package/src/starknet/swaps/StarknetSwapData.ts +441 -0
  121. package/src/starknet/swaps/StarknetSwapModule.ts +17 -0
  122. package/src/starknet/swaps/handlers/IHandler.ts +20 -0
  123. package/src/starknet/swaps/handlers/claim/ClaimHandlers.ts +23 -0
  124. package/src/starknet/swaps/handlers/claim/HashlockClaimHandler.ts +54 -0
  125. package/src/starknet/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.ts +73 -0
  126. package/src/starknet/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.ts +67 -0
  127. package/src/starknet/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.ts +49 -0
  128. package/src/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.ts +151 -0
  129. package/src/starknet/swaps/handlers/refund/TimelockRefundHandler.ts +39 -0
  130. package/src/starknet/swaps/modules/StarknetLpVault.ts +148 -0
  131. package/src/starknet/swaps/modules/StarknetSwapClaim.ts +142 -0
  132. package/src/starknet/swaps/modules/StarknetSwapInit.ts +226 -0
  133. package/src/starknet/swaps/modules/StarknetSwapRefund.ts +202 -0
  134. package/src/starknet/wallet/StarknetKeypairWallet.ts +34 -0
  135. package/src/starknet/wallet/StarknetSigner.ts +55 -0
  136. package/src/utils/Utils.ts +247 -0
@@ -0,0 +1,323 @@
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("../base/modules/StarknetFees");
13
+ const StarknetAction_1 = require("../base/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 = 750;
26
+ const GAS_PER_BLOCKHEADER_FORK = 750;
27
+ const btcRelayAddreses = {
28
+ [starknet_1.constants.StarknetChainId.SN_SEPOLIA]: "0x032afcea912ba13f6a1878fe38af23eaec3e6b4c7db31a3571550d3cf80d3e31",
29
+ [starknet_1.constants.StarknetChainId.SN_MAIN]: "0x05cc69b09e8c53520f9e328f6eca72cf02fe46ce290b757d42414e2238001603"
30
+ };
31
+ function serializeCalldata(headers, storedHeader, span) {
32
+ span.push((0, Utils_1.toHex)(headers.length));
33
+ headers.forEach(header => {
34
+ span.push(...header.serialize());
35
+ });
36
+ span.push(...storedHeader.serialize());
37
+ return span;
38
+ }
39
+ class StarknetBtcRelay extends StarknetContractBase_1.StarknetContractBase {
40
+ SaveMainHeaders(signer, mainHeaders, storedHeader) {
41
+ return new StarknetAction_1.StarknetAction(signer, this, {
42
+ contractAddress: this.contract.address,
43
+ entrypoint: "submit_main_blockheaders",
44
+ calldata: serializeCalldata(mainHeaders, storedHeader, [])
45
+ }, { l1: GAS_PER_BLOCKHEADER * mainHeaders.length, l2: 0 });
46
+ }
47
+ SaveShortForkHeaders(signer, forkHeaders, storedHeader) {
48
+ return new StarknetAction_1.StarknetAction(signer, this, {
49
+ contractAddress: this.contract.address,
50
+ entrypoint: "submit_short_fork_blockheaders",
51
+ calldata: serializeCalldata(forkHeaders, storedHeader, [])
52
+ }, { l1: GAS_PER_BLOCKHEADER * forkHeaders.length, l2: 0 });
53
+ }
54
+ SaveLongForkHeaders(signer, forkId, forkHeaders, storedHeader, totalForkHeaders = 100) {
55
+ return new StarknetAction_1.StarknetAction(signer, this, {
56
+ contractAddress: this.contract.address,
57
+ entrypoint: "submit_fork_blockheaders",
58
+ calldata: serializeCalldata(forkHeaders, storedHeader, [(0, Utils_1.toHex)(forkId)])
59
+ }, { l1: (GAS_PER_BLOCKHEADER * forkHeaders.length) + (GAS_PER_BLOCKHEADER_FORK * totalForkHeaders), l2: 0 });
60
+ }
61
+ constructor(chainId, provider, bitcoinRpc, contractAddress = btcRelayAddreses[chainId], retryPolicy, solanaFeeEstimator = new StarknetFees_1.StarknetFees(provider)) {
62
+ super(chainId, provider, contractAddress, BtcRelayAbi_1.BtcRelayAbi, retryPolicy, solanaFeeEstimator);
63
+ this.maxHeadersPerTx = 100;
64
+ this.maxForkHeadersPerTx = 100;
65
+ this.maxShortForkHeadersPerTx = 100;
66
+ this.bitcoinRpc = bitcoinRpc;
67
+ }
68
+ /**
69
+ * Computes subsequent commited headers as they will appear on the blockchain when transactions
70
+ * are submitted & confirmed
71
+ *
72
+ * @param initialStoredHeader
73
+ * @param syncedHeaders
74
+ * @private
75
+ */
76
+ computeCommitedHeaders(initialStoredHeader, syncedHeaders) {
77
+ const computedCommitedHeaders = [initialStoredHeader];
78
+ for (let blockHeader of syncedHeaders) {
79
+ computedCommitedHeaders.push(computedCommitedHeaders[computedCommitedHeaders.length - 1].computeNext(blockHeader));
80
+ }
81
+ return computedCommitedHeaders;
82
+ }
83
+ /**
84
+ * A common logic for submitting blockheaders in a transaction
85
+ *
86
+ * @param signer
87
+ * @param headers headers to sync to the btc relay
88
+ * @param storedHeader current latest stored block header for a given fork
89
+ * @param tipWork work of the current tip in a given fork
90
+ * @param forkId forkId to submit to, forkId=0 means main chain, forkId=-1 means short fork
91
+ * @param feeRate feeRate for the transaction
92
+ * @private
93
+ */
94
+ async _saveHeaders(signer, headers, storedHeader, tipWork, forkId, feeRate) {
95
+ const blockHeaderObj = headers.map(serializeBlockHeader);
96
+ let starknetAction;
97
+ switch (forkId) {
98
+ case -1:
99
+ starknetAction = this.SaveShortForkHeaders(signer, blockHeaderObj, storedHeader);
100
+ break;
101
+ case 0:
102
+ starknetAction = this.SaveMainHeaders(signer, blockHeaderObj, storedHeader);
103
+ break;
104
+ default:
105
+ starknetAction = this.SaveLongForkHeaders(signer, forkId, blockHeaderObj, storedHeader);
106
+ break;
107
+ }
108
+ const tx = await starknetAction.tx(feeRate);
109
+ const computedCommitedHeaders = this.computeCommitedHeaders(storedHeader, blockHeaderObj);
110
+ const lastStoredHeader = computedCommitedHeaders[computedCommitedHeaders.length - 1];
111
+ if (forkId !== 0 && base_1.StatePredictorUtils.gtBuffer(lastStoredHeader.getBlockHash(), tipWork)) {
112
+ //Fork's work is higher than main chain's work, this fork will become a main chain
113
+ forkId = 0;
114
+ }
115
+ return {
116
+ forkId: forkId,
117
+ lastStoredHeader,
118
+ tx,
119
+ computedCommitedHeaders
120
+ };
121
+ }
122
+ getBlock(commitHash, blockHash) {
123
+ const keys = [commitHash == null ? null : (0, Utils_1.toHex)(commitHash)];
124
+ if (blockHash != null) {
125
+ const starknetBlockHash = starknet_1.hash.computePoseidonHashOnElements((0, Utils_1.bufferToU32Array)(buffer_1.Buffer.from([...blockHash]).reverse()));
126
+ keys.push(starknetBlockHash);
127
+ }
128
+ return this.Events.findInContractEvents(["btc_relay::events::StoreHeader", "btc_relay::events::StoreForkHeader"], keys, (event) => {
129
+ return Promise.resolve([StarknetBtcStoredHeader_1.StarknetBtcStoredHeader.fromSerializedFeltArray(event.data), BigInt(event.params.commit_hash)]);
130
+ });
131
+ }
132
+ async getBlockHeight() {
133
+ return Number(await this.contract.get_blockheight());
134
+ }
135
+ /**
136
+ * Returns data about current main chain tip stored in the btc relay
137
+ */
138
+ async getTipData() {
139
+ const commitHash = await this.contract.get_tip_commit_hash();
140
+ if (commitHash == null || BigInt(commitHash) === BigInt(0))
141
+ return null;
142
+ const result = await this.getBlock(commitHash);
143
+ if (result == null)
144
+ return null;
145
+ const [storedBlockHeader] = result;
146
+ return {
147
+ blockheight: storedBlockHeader.getBlockheight(),
148
+ commitHash: (0, Utils_1.bigNumberishToBuffer)(commitHash, 32).toString("hex"),
149
+ blockhash: storedBlockHeader.getBlockHash().toString("hex"),
150
+ chainWork: storedBlockHeader.getChainWork()
151
+ };
152
+ }
153
+ /**
154
+ * Retrieves blockheader with a specific blockhash, returns null if requiredBlockheight is provided and
155
+ * btc relay contract is not synced up to the desired blockheight
156
+ *
157
+ * @param blockData
158
+ * @param requiredBlockheight
159
+ */
160
+ async retrieveLogAndBlockheight(blockData, requiredBlockheight) {
161
+ //TODO: we can fetch the blockheight and events in parallel
162
+ const blockHeight = await this.getBlockHeight();
163
+ if (requiredBlockheight != null && blockHeight < requiredBlockheight) {
164
+ return null;
165
+ }
166
+ const result = await this.getBlock(null, buffer_1.Buffer.from(blockData.blockhash, "hex"));
167
+ if (result == null)
168
+ return null;
169
+ const [storedBlockHeader, commitHash] = result;
170
+ //Check if block is part of the main chain
171
+ const chainCommitment = await this.contract.get_commit_hash(storedBlockHeader.block_height);
172
+ if (BigInt(chainCommitment) !== BigInt(commitHash))
173
+ return null;
174
+ this.logger.debug("retrieveLogAndBlockheight(): block found," +
175
+ " commit hash: " + (0, Utils_1.toHex)(commitHash) + " blockhash: " + blockData.blockhash + " current btc relay height: " + blockHeight);
176
+ return { header: storedBlockHeader, height: blockHeight };
177
+ }
178
+ /**
179
+ * Retrieves blockheader data by blockheader's commit hash,
180
+ *
181
+ * @param commitmentHashStr
182
+ * @param blockData
183
+ */
184
+ async retrieveLogByCommitHash(commitmentHashStr, blockData) {
185
+ const result = await this.getBlock(commitmentHashStr, buffer_1.Buffer.from(blockData.blockhash, "hex"));
186
+ if (result == null)
187
+ return null;
188
+ const [storedBlockHeader, commitHash] = result;
189
+ //Check if block is part of the main chain
190
+ const chainCommitment = await this.contract.get_commit_hash(storedBlockHeader.block_height);
191
+ if (BigInt(chainCommitment) !== BigInt(commitHash))
192
+ return null;
193
+ this.logger.debug("retrieveLogByCommitHash(): block found," +
194
+ " commit hash: " + commitmentHashStr + " blockhash: " + blockData.blockhash + " height: " + storedBlockHeader.block_height);
195
+ return storedBlockHeader;
196
+ }
197
+ /**
198
+ * Retrieves latest known stored blockheader & blockheader from bitcoin RPC that is in the main chain
199
+ */
200
+ async retrieveLatestKnownBlockLog() {
201
+ const data = await this.Events.findInContractEvents(["btc_relay::events::StoreHeader", "btc_relay::events::StoreForkHeader"], null, async (event) => {
202
+ const storedHeader = StarknetBtcStoredHeader_1.StarknetBtcStoredHeader.fromSerializedFeltArray(event.data);
203
+ const blockHashHex = storedHeader.getBlockHash().toString("hex");
204
+ const commitHash = event.params.commit_hash;
205
+ const [isInBtcMainChain, btcRelayCommitHash] = await Promise.all([
206
+ this.bitcoinRpc.isInMainChain(blockHashHex).catch(() => false),
207
+ this.contract.get_commit_hash(storedHeader.block_height)
208
+ ]);
209
+ if (!isInBtcMainChain)
210
+ return null;
211
+ if (BigInt(commitHash) !== BigInt(btcRelayCommitHash))
212
+ return null;
213
+ return {
214
+ resultStoredHeader: storedHeader,
215
+ resultBitcoinHeader: await this.bitcoinRpc.getBlockHeader(blockHashHex),
216
+ commitHash: commitHash
217
+ };
218
+ });
219
+ if (data != null)
220
+ this.logger.debug("retrieveLatestKnownBlockLog(): block found," +
221
+ " commit hash: " + (0, Utils_1.toHex)(data.commitHash) + " blockhash: " + data.resultBitcoinHeader.getHash() +
222
+ " height: " + data.resultStoredHeader.getBlockheight());
223
+ return data;
224
+ }
225
+ /**
226
+ * Saves blockheaders as a bitcoin main chain to the btc relay
227
+ *
228
+ * @param signer
229
+ * @param mainHeaders
230
+ * @param storedHeader
231
+ * @param feeRate
232
+ */
233
+ saveMainHeaders(signer, mainHeaders, storedHeader, feeRate) {
234
+ this.logger.debug("saveMainHeaders(): submitting main blockheaders, count: " + mainHeaders.length);
235
+ return this._saveHeaders(signer, mainHeaders, storedHeader, null, 0, feeRate);
236
+ }
237
+ /**
238
+ * Creates a new long fork and submits the headers to it
239
+ *
240
+ * @param signer
241
+ * @param forkHeaders
242
+ * @param storedHeader
243
+ * @param tipWork
244
+ * @param feeRate
245
+ */
246
+ async saveNewForkHeaders(signer, forkHeaders, storedHeader, tipWork, feeRate) {
247
+ let forkId = Math.floor(Math.random() * 0xFFFFFFFFFFFF);
248
+ this.logger.debug("saveNewForkHeaders(): submitting new fork & blockheaders," +
249
+ " count: " + forkHeaders.length + " forkId: 0x" + forkId.toString(16));
250
+ return await this._saveHeaders(signer, forkHeaders, storedHeader, tipWork, forkId, feeRate);
251
+ }
252
+ /**
253
+ * Continues submitting blockheaders to a given fork
254
+ *
255
+ * @param signer
256
+ * @param forkHeaders
257
+ * @param storedHeader
258
+ * @param forkId
259
+ * @param tipWork
260
+ * @param feeRate
261
+ */
262
+ saveForkHeaders(signer, forkHeaders, storedHeader, forkId, tipWork, feeRate) {
263
+ this.logger.debug("saveForkHeaders(): submitting blockheaders to existing fork," +
264
+ " count: " + forkHeaders.length + " forkId: 0x" + forkId.toString(16));
265
+ return this._saveHeaders(signer, forkHeaders, storedHeader, tipWork, forkId, feeRate);
266
+ }
267
+ /**
268
+ * Submits short fork with given blockheaders
269
+ *
270
+ * @param signer
271
+ * @param forkHeaders
272
+ * @param storedHeader
273
+ * @param tipWork
274
+ * @param feeRate
275
+ */
276
+ saveShortForkHeaders(signer, forkHeaders, storedHeader, tipWork, feeRate) {
277
+ this.logger.debug("saveShortForkHeaders(): submitting short fork blockheaders," +
278
+ " count: " + forkHeaders.length);
279
+ return this._saveHeaders(signer, forkHeaders, storedHeader, tipWork, -1, feeRate);
280
+ }
281
+ /**
282
+ * Estimate required synchronization fee (worst case) to synchronize btc relay to the required blockheight
283
+ *
284
+ * @param requiredBlockheight
285
+ * @param feeRate
286
+ */
287
+ async estimateSynchronizeFee(requiredBlockheight, feeRate) {
288
+ const tipData = await this.getTipData();
289
+ const currBlockheight = tipData.blockheight;
290
+ const blockheightDelta = requiredBlockheight - currBlockheight;
291
+ if (blockheightDelta <= 0)
292
+ return 0n;
293
+ const synchronizationFee = BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate);
294
+ this.logger.debug("estimateSynchronizeFee(): required blockheight: " + requiredBlockheight +
295
+ " blockheight delta: " + blockheightDelta + " fee: " + synchronizationFee.toString(10));
296
+ return synchronizationFee;
297
+ }
298
+ /**
299
+ * Returns fee required (in SOL) to synchronize a single block to btc relay
300
+ *
301
+ * @param feeRate
302
+ */
303
+ async getFeePerBlock(feeRate) {
304
+ feeRate ?? (feeRate = await this.Fees.getFeeRate());
305
+ return StarknetFees_1.StarknetFees.getGasFee(GAS_PER_BLOCKHEADER, feeRate);
306
+ }
307
+ /**
308
+ * Gets fee rate required for submitting blockheaders to the main chain
309
+ */
310
+ getMainFeeRate(signer) {
311
+ return this.Fees.getFeeRate();
312
+ }
313
+ /**
314
+ * Gets fee rate required for submitting blockheaders to the specific fork
315
+ */
316
+ getForkFeeRate(signer, forkId) {
317
+ return this.Fees.getFeeRate();
318
+ }
319
+ saveInitialHeader(signer, header, epochStart, pastBlocksTimestamps, feeRate) {
320
+ throw new Error("Not supported, starknet contract is initialized with constructor!");
321
+ }
322
+ }
323
+ exports.StarknetBtcRelay = StarknetBtcRelay;
@@ -0,0 +1,32 @@
1
+ /// <reference types="node" />
2
+ import { BtcHeader } from "@atomiqlabs/base";
3
+ import { Buffer } from "buffer";
4
+ import { BigNumberish } from "starknet";
5
+ export type StarknetBtcHeaderType = {
6
+ reversed_version: BigNumberish;
7
+ previous_blockhash: BigNumberish[];
8
+ merkle_root: BigNumberish[];
9
+ reversed_timestamp: BigNumberish;
10
+ nbits: BigNumberish;
11
+ nonce: BigNumberish;
12
+ hash?: Buffer;
13
+ };
14
+ export declare class StarknetBtcHeader implements BtcHeader {
15
+ reversed_version: number;
16
+ previous_blockhash: number[];
17
+ merkle_root: number[];
18
+ reversed_timestamp: number;
19
+ nbits: number;
20
+ nonce: number;
21
+ hash?: Buffer;
22
+ constructor(obj: StarknetBtcHeaderType);
23
+ getMerkleRoot(): Buffer;
24
+ getNbits(): number;
25
+ getNonce(): number;
26
+ getReversedPrevBlockhash(): Buffer;
27
+ getTimestamp(): number;
28
+ getVersion(): number;
29
+ getHash(): Buffer;
30
+ serialize(): BigNumberish[];
31
+ static fromSerializedFeltArray(span: BigNumberish[]): StarknetBtcHeader;
32
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StarknetBtcHeader = void 0;
4
+ const buffer_1 = require("buffer");
5
+ const Utils_1 = require("../../../utils/Utils");
6
+ const createHash = require("create-hash");
7
+ class StarknetBtcHeader {
8
+ constructor(obj) {
9
+ this.reversed_version = Number(obj.reversed_version);
10
+ this.previous_blockhash = obj.previous_blockhash.map(val => Number(val));
11
+ this.merkle_root = obj.merkle_root.map(val => Number(val));
12
+ this.reversed_timestamp = Number(obj.reversed_timestamp);
13
+ this.nbits = Number(obj.nbits);
14
+ this.nonce = Number(obj.nonce);
15
+ this.hash = obj.hash;
16
+ }
17
+ getMerkleRoot() {
18
+ return (0, Utils_1.u32ArrayToBuffer)(this.merkle_root);
19
+ }
20
+ getNbits() {
21
+ return (0, Utils_1.u32ReverseEndianness)(this.nbits);
22
+ }
23
+ getNonce() {
24
+ return (0, Utils_1.u32ReverseEndianness)(this.nonce);
25
+ }
26
+ getReversedPrevBlockhash() {
27
+ return (0, Utils_1.u32ArrayToBuffer)(this.previous_blockhash);
28
+ }
29
+ getTimestamp() {
30
+ return (0, Utils_1.u32ReverseEndianness)(this.reversed_timestamp);
31
+ }
32
+ getVersion() {
33
+ return (0, Utils_1.u32ReverseEndianness)(this.reversed_version);
34
+ }
35
+ getHash() {
36
+ if (this.hash != null)
37
+ return this.hash;
38
+ const buffer = buffer_1.Buffer.alloc(80);
39
+ buffer.writeUInt32BE(this.reversed_version);
40
+ (0, Utils_1.u32ArrayToBuffer)(this.previous_blockhash).copy(buffer, 4);
41
+ (0, Utils_1.u32ArrayToBuffer)(this.merkle_root).copy(buffer, 36);
42
+ buffer.writeUInt32BE(this.reversed_timestamp, 68);
43
+ buffer.writeUInt32BE(this.nbits, 72);
44
+ buffer.writeUInt32BE(this.nonce, 76);
45
+ return createHash("sha256").update(createHash("sha256").update(buffer).digest()).digest();
46
+ }
47
+ serialize() {
48
+ return [
49
+ this.reversed_version,
50
+ ...this.previous_blockhash,
51
+ ...this.merkle_root,
52
+ this.reversed_timestamp,
53
+ this.nbits,
54
+ this.nonce
55
+ ];
56
+ }
57
+ static fromSerializedFeltArray(span) {
58
+ const reversed_version = (0, Utils_1.toHex)(span.shift());
59
+ const previous_blockhash = span.splice(0, 8).map(Utils_1.toHex);
60
+ const merkle_root = span.splice(0, 8).map(Utils_1.toHex);
61
+ const reversed_timestamp = (0, Utils_1.toHex)(span.shift());
62
+ const nbits = (0, Utils_1.toHex)(span.shift());
63
+ const nonce = (0, Utils_1.toHex)(span.shift());
64
+ return new StarknetBtcHeader({
65
+ reversed_version,
66
+ previous_blockhash,
67
+ merkle_root,
68
+ reversed_timestamp,
69
+ nbits,
70
+ nonce
71
+ });
72
+ }
73
+ }
74
+ exports.StarknetBtcHeader = StarknetBtcHeader;
@@ -0,0 +1,52 @@
1
+ /// <reference types="node" />
2
+ import { BtcStoredHeader } from "@atomiqlabs/base";
3
+ import { StarknetBtcHeader, StarknetBtcHeaderType } from "./StarknetBtcHeader";
4
+ import { Buffer } from "buffer";
5
+ import { BigNumberish, Uint256 } from "starknet";
6
+ export type StarknetBtcStoredHeaderType = {
7
+ blockheader: StarknetBtcHeader | StarknetBtcHeaderType;
8
+ block_hash: BigNumberish[];
9
+ chain_work: BigNumberish | Uint256;
10
+ block_height: BigNumberish;
11
+ last_diff_adjustment: BigNumberish;
12
+ prev_block_timestamps: BigNumberish[];
13
+ };
14
+ export declare class StarknetBtcStoredHeader implements BtcStoredHeader<StarknetBtcHeader> {
15
+ blockheader: StarknetBtcHeader;
16
+ block_hash: number[];
17
+ chain_work: Uint256;
18
+ block_height: number;
19
+ last_diff_adjustment: number;
20
+ prev_block_timestamps: number[];
21
+ constructor(obj: StarknetBtcStoredHeaderType);
22
+ getBlockheight(): number;
23
+ getChainWork(): Buffer;
24
+ getHeader(): StarknetBtcHeader;
25
+ getLastDiffAdjustment(): number;
26
+ getPrevBlockTimestamps(): number[];
27
+ getBlockHash(): Buffer;
28
+ /**
29
+ * Computes prevBlockTimestamps for a next block, shifting the old block timestamps to the left & appending
30
+ * this block's timestamp to the end
31
+ *
32
+ * @private
33
+ */
34
+ private computeNextBlockTimestamps;
35
+ /**
36
+ * Computes total chain work after a new header with "nbits" is added to the chain
37
+ *
38
+ * @param nbits
39
+ * @private
40
+ */
41
+ private computeNextChainWork;
42
+ /**
43
+ * Computes lastDiffAdjustment, this changes only once every DIFF_ADJUSTMENT_PERIOD blocks
44
+ *
45
+ * @param headerTimestamp
46
+ * @private
47
+ */
48
+ private computeNextLastDiffAdjustment;
49
+ computeNext(header: StarknetBtcHeader): StarknetBtcStoredHeader;
50
+ serialize(): BigNumberish[];
51
+ static fromSerializedFeltArray(span: BigNumberish[]): StarknetBtcStoredHeader;
52
+ }
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StarknetBtcStoredHeader = void 0;
4
+ const base_1 = require("@atomiqlabs/base");
5
+ const StarknetBtcHeader_1 = require("./StarknetBtcHeader");
6
+ const buffer_1 = require("buffer");
7
+ const starknet_1 = require("starknet");
8
+ const Utils_1 = require("../../../utils/Utils");
9
+ class StarknetBtcStoredHeader {
10
+ constructor(obj) {
11
+ this.blockheader = obj.blockheader instanceof StarknetBtcHeader_1.StarknetBtcHeader ? obj.blockheader : new StarknetBtcHeader_1.StarknetBtcHeader(obj.blockheader);
12
+ this.block_hash = obj.block_hash.map(val => Number(val));
13
+ this.chain_work = (0, Utils_1.isUint256)(obj.chain_work) ? obj.chain_work : starknet_1.cairo.uint256(obj.chain_work);
14
+ this.block_height = Number(obj.block_height);
15
+ this.last_diff_adjustment = Number(obj.last_diff_adjustment);
16
+ this.prev_block_timestamps = obj.prev_block_timestamps.map(val => Number(val));
17
+ }
18
+ getBlockheight() {
19
+ return this.block_height;
20
+ }
21
+ getChainWork() {
22
+ return (0, Utils_1.bigNumberishToBuffer)(this.chain_work, 32);
23
+ }
24
+ getHeader() {
25
+ return this.blockheader;
26
+ }
27
+ getLastDiffAdjustment() {
28
+ return this.last_diff_adjustment;
29
+ }
30
+ getPrevBlockTimestamps() {
31
+ return this.prev_block_timestamps;
32
+ }
33
+ getBlockHash() {
34
+ return (0, Utils_1.u32ArrayToBuffer)(this.block_hash).reverse();
35
+ }
36
+ /**
37
+ * Computes prevBlockTimestamps for a next block, shifting the old block timestamps to the left & appending
38
+ * this block's timestamp to the end
39
+ *
40
+ * @private
41
+ */
42
+ computeNextBlockTimestamps() {
43
+ const prevBlockTimestamps = [...this.prev_block_timestamps];
44
+ for (let i = 1; i < 10; i++) {
45
+ prevBlockTimestamps[i - 1] = prevBlockTimestamps[i];
46
+ }
47
+ prevBlockTimestamps[9] = this.blockheader.getTimestamp();
48
+ return prevBlockTimestamps;
49
+ }
50
+ /**
51
+ * Computes total chain work after a new header with "nbits" is added to the chain
52
+ *
53
+ * @param nbits
54
+ * @private
55
+ */
56
+ computeNextChainWork(nbits) {
57
+ const chainWork = [...this.getChainWork()];
58
+ base_1.StatePredictorUtils.addInPlace(chainWork, [...base_1.StatePredictorUtils.getChainwork(nbits)]);
59
+ return buffer_1.Buffer.from(chainWork);
60
+ }
61
+ /**
62
+ * Computes lastDiffAdjustment, this changes only once every DIFF_ADJUSTMENT_PERIOD blocks
63
+ *
64
+ * @param headerTimestamp
65
+ * @private
66
+ */
67
+ computeNextLastDiffAdjustment(headerTimestamp) {
68
+ const blockheight = this.block_height + 1;
69
+ let lastDiffAdjustment = this.last_diff_adjustment;
70
+ if (blockheight % base_1.StatePredictorUtils.DIFF_ADJUSTMENT_PERIOD === 0) {
71
+ lastDiffAdjustment = headerTimestamp;
72
+ }
73
+ return lastDiffAdjustment;
74
+ }
75
+ computeNext(header) {
76
+ return new StarknetBtcStoredHeader({
77
+ chain_work: "0x" + this.computeNextChainWork(header.getNbits()).toString("hex"),
78
+ prev_block_timestamps: this.computeNextBlockTimestamps(),
79
+ block_height: this.block_height + 1,
80
+ last_diff_adjustment: this.computeNextLastDiffAdjustment(header.getTimestamp()),
81
+ block_hash: (0, Utils_1.bufferToU32Array)(header.getHash()),
82
+ blockheader: header
83
+ });
84
+ }
85
+ serialize() {
86
+ return [
87
+ ...this.blockheader.serialize(),
88
+ ...this.block_hash,
89
+ this.chain_work.low,
90
+ this.chain_work.high,
91
+ this.block_height,
92
+ this.last_diff_adjustment,
93
+ ...this.prev_block_timestamps
94
+ ];
95
+ }
96
+ static fromSerializedFeltArray(span) {
97
+ const blockheader = StarknetBtcHeader_1.StarknetBtcHeader.fromSerializedFeltArray(span);
98
+ const block_hash = span.splice(0, 8).map(Utils_1.toHex);
99
+ const chain_work = { low: span.shift(), high: span.shift() };
100
+ const block_height = (0, Utils_1.toHex)(span.shift());
101
+ const last_diff_adjustment = (0, Utils_1.toHex)(span.shift());
102
+ const prev_block_timestamps = span.splice(0, 10).map(Utils_1.toHex);
103
+ return new StarknetBtcStoredHeader({
104
+ blockheader,
105
+ block_hash,
106
+ chain_work,
107
+ block_height,
108
+ last_diff_adjustment,
109
+ prev_block_timestamps
110
+ });
111
+ }
112
+ }
113
+ exports.StarknetBtcStoredHeader = StarknetBtcStoredHeader;
@@ -0,0 +1,13 @@
1
+ import { StarknetBase, StarknetRetryPolicy } from "../base/StarknetBase";
2
+ import { constants, Provider, TypedContractV2 } from "starknet";
3
+ import { StarknetFees } from "../base/modules/StarknetFees";
4
+ import { Abi } from "abi-wan-kanabi";
5
+ import { StarknetContractEvents } from "./modules/StarknetContractEvents";
6
+ /**
7
+ * Base class providing program specific utilities
8
+ */
9
+ export declare class StarknetContractBase<T extends Abi> extends StarknetBase {
10
+ contract: TypedContractV2<T>;
11
+ readonly Events: StarknetContractEvents<T>;
12
+ constructor(chainId: constants.StarknetChainId, provider: Provider, contractAddress: string, contractAbi: T, retryPolicy?: StarknetRetryPolicy, solanaFeeEstimator?: StarknetFees);
13
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StarknetContractBase = void 0;
4
+ const StarknetBase_1 = require("../base/StarknetBase");
5
+ const starknet_1 = require("starknet");
6
+ const StarknetFees_1 = require("../base/modules/StarknetFees");
7
+ const StarknetContractEvents_1 = require("./modules/StarknetContractEvents");
8
+ /**
9
+ * Base class providing program specific utilities
10
+ */
11
+ class StarknetContractBase extends StarknetBase_1.StarknetBase {
12
+ constructor(chainId, provider, contractAddress, contractAbi, retryPolicy, solanaFeeEstimator = new StarknetFees_1.StarknetFees(provider)) {
13
+ super(chainId, provider, retryPolicy, solanaFeeEstimator);
14
+ this.contract = new starknet_1.Contract(contractAbi, contractAddress, provider).typedv2(contractAbi);
15
+ this.Events = new StarknetContractEvents_1.StarknetContractEvents(this, contractAbi);
16
+ }
17
+ }
18
+ exports.StarknetContractBase = StarknetContractBase;
@@ -0,0 +1,40 @@
1
+ import { Abi } from "abi-wan-kanabi";
2
+ import { EventToPrimitiveType, ExtractAbiEventNames } from "abi-wan-kanabi/dist/kanabi";
3
+ import { StarknetEvents } from "../../base/modules/StarknetEvents";
4
+ import { StarknetContractBase } from "../StarknetContractBase";
5
+ export type StarknetAbiEvent<TAbi extends Abi, TEventName extends ExtractAbiEventNames<TAbi>> = {
6
+ name: TEventName;
7
+ params: EventToPrimitiveType<TAbi, TEventName>;
8
+ txHash: string;
9
+ blockHash: string;
10
+ blockNumber: number;
11
+ keys: string[];
12
+ data: string[];
13
+ };
14
+ export declare class StarknetContractEvents<TAbi extends Abi> extends StarknetEvents {
15
+ readonly root: StarknetContractBase<TAbi>;
16
+ readonly abi: TAbi;
17
+ constructor(root: StarknetContractBase<TAbi>, abi: TAbi);
18
+ private toStarknetAbiEvents;
19
+ private toFilter;
20
+ /**
21
+ * Returns the events occuring in a range of starknet block as identified by the contract and keys,
22
+ * returns pending events if no startHeight & endHeight is passed
23
+ *
24
+ * @param events
25
+ * @param keys
26
+ * @param startBlockHeight
27
+ * @param endBlockHeight
28
+ */
29
+ getContractBlockEvents<T extends ExtractAbiEventNames<TAbi>>(events: T[], keys: string[], startBlockHeight?: number, endBlockHeight?: number): Promise<StarknetAbiEvent<TAbi, T>[]>;
30
+ /**
31
+ * Runs a search forawrds in time, processing the events for a specific topic public key
32
+ *
33
+ * @param events
34
+ * @param keys
35
+ * @param processor called for every event, should return a value if the correct event was found, or null
36
+ * if the search should continue
37
+ * @param abortSignal
38
+ */
39
+ findInContractEvents<T, TEvent extends ExtractAbiEventNames<TAbi>>(events: TEvent[], keys: string[], processor: (event: StarknetAbiEvent<TAbi, TEvent>) => Promise<T>, abortSignal?: AbortSignal): Promise<T>;
40
+ }