@atomiqlabs/chain-solana 12.0.12 → 12.0.14

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 (114) hide show
  1. package/LICENSE +201 -201
  2. package/dist/index.d.ts +29 -29
  3. package/dist/index.js +45 -45
  4. package/dist/solana/SolanaChainType.d.ts +11 -11
  5. package/dist/solana/SolanaChainType.js +2 -2
  6. package/dist/solana/SolanaChains.d.ts +20 -20
  7. package/dist/solana/SolanaChains.js +25 -25
  8. package/dist/solana/SolanaInitializer.d.ts +18 -18
  9. package/dist/solana/SolanaInitializer.js +63 -63
  10. package/dist/solana/btcrelay/SolanaBtcRelay.d.ts +228 -228
  11. package/dist/solana/btcrelay/SolanaBtcRelay.js +441 -441
  12. package/dist/solana/btcrelay/headers/SolanaBtcHeader.d.ts +29 -29
  13. package/dist/solana/btcrelay/headers/SolanaBtcHeader.js +34 -34
  14. package/dist/solana/btcrelay/headers/SolanaBtcStoredHeader.d.ts +46 -46
  15. package/dist/solana/btcrelay/headers/SolanaBtcStoredHeader.js +78 -78
  16. package/dist/solana/btcrelay/program/programIdl.json +671 -671
  17. package/dist/solana/chain/SolanaAction.d.ts +26 -26
  18. package/dist/solana/chain/SolanaAction.js +86 -86
  19. package/dist/solana/chain/SolanaChainInterface.d.ts +65 -65
  20. package/dist/solana/chain/SolanaChainInterface.js +125 -125
  21. package/dist/solana/chain/SolanaModule.d.ts +14 -14
  22. package/dist/solana/chain/SolanaModule.js +13 -13
  23. package/dist/solana/chain/modules/SolanaAddresses.d.ts +8 -8
  24. package/dist/solana/chain/modules/SolanaAddresses.js +22 -22
  25. package/dist/solana/chain/modules/SolanaBlocks.d.ts +28 -28
  26. package/dist/solana/chain/modules/SolanaBlocks.js +72 -72
  27. package/dist/solana/chain/modules/SolanaEvents.d.ts +68 -68
  28. package/dist/solana/chain/modules/SolanaEvents.js +238 -225
  29. package/dist/solana/chain/modules/SolanaFees.d.ts +121 -121
  30. package/dist/solana/chain/modules/SolanaFees.js +379 -379
  31. package/dist/solana/chain/modules/SolanaSignatures.d.ts +23 -23
  32. package/dist/solana/chain/modules/SolanaSignatures.js +39 -39
  33. package/dist/solana/chain/modules/SolanaSlots.d.ts +31 -31
  34. package/dist/solana/chain/modules/SolanaSlots.js +68 -68
  35. package/dist/solana/chain/modules/SolanaTokens.d.ts +136 -136
  36. package/dist/solana/chain/modules/SolanaTokens.js +248 -248
  37. package/dist/solana/chain/modules/SolanaTransactions.d.ts +124 -124
  38. package/dist/solana/chain/modules/SolanaTransactions.js +323 -323
  39. package/dist/solana/events/SolanaChainEvents.d.ts +88 -88
  40. package/dist/solana/events/SolanaChainEvents.js +256 -256
  41. package/dist/solana/events/SolanaChainEventsBrowser.d.ts +75 -75
  42. package/dist/solana/events/SolanaChainEventsBrowser.js +172 -172
  43. package/dist/solana/program/SolanaProgramBase.d.ts +40 -40
  44. package/dist/solana/program/SolanaProgramBase.js +43 -43
  45. package/dist/solana/program/SolanaProgramModule.d.ts +8 -8
  46. package/dist/solana/program/SolanaProgramModule.js +11 -11
  47. package/dist/solana/program/modules/SolanaProgramEvents.d.ts +53 -53
  48. package/dist/solana/program/modules/SolanaProgramEvents.js +114 -114
  49. package/dist/solana/swaps/SolanaSwapData.d.ts +71 -71
  50. package/dist/solana/swaps/SolanaSwapData.js +292 -292
  51. package/dist/solana/swaps/SolanaSwapModule.d.ts +10 -10
  52. package/dist/solana/swaps/SolanaSwapModule.js +11 -11
  53. package/dist/solana/swaps/SolanaSwapProgram.d.ts +224 -224
  54. package/dist/solana/swaps/SolanaSwapProgram.js +570 -570
  55. package/dist/solana/swaps/SwapTypeEnum.d.ts +11 -11
  56. package/dist/solana/swaps/SwapTypeEnum.js +42 -42
  57. package/dist/solana/swaps/modules/SolanaDataAccount.d.ts +94 -94
  58. package/dist/solana/swaps/modules/SolanaDataAccount.js +231 -231
  59. package/dist/solana/swaps/modules/SolanaLpVault.d.ts +71 -71
  60. package/dist/solana/swaps/modules/SolanaLpVault.js +173 -173
  61. package/dist/solana/swaps/modules/SwapClaim.d.ts +129 -129
  62. package/dist/solana/swaps/modules/SwapClaim.js +291 -291
  63. package/dist/solana/swaps/modules/SwapInit.d.ts +217 -217
  64. package/dist/solana/swaps/modules/SwapInit.js +519 -519
  65. package/dist/solana/swaps/modules/SwapRefund.d.ts +82 -82
  66. package/dist/solana/swaps/modules/SwapRefund.js +262 -262
  67. package/dist/solana/swaps/programIdl.json +945 -945
  68. package/dist/solana/swaps/programTypes.d.ts +943 -943
  69. package/dist/solana/swaps/programTypes.js +945 -945
  70. package/dist/solana/wallet/SolanaKeypairWallet.d.ts +9 -9
  71. package/dist/solana/wallet/SolanaKeypairWallet.js +33 -33
  72. package/dist/solana/wallet/SolanaSigner.d.ts +11 -11
  73. package/dist/solana/wallet/SolanaSigner.js +17 -17
  74. package/dist/utils/Utils.d.ts +53 -53
  75. package/dist/utils/Utils.js +170 -170
  76. package/package.json +41 -41
  77. package/src/index.ts +36 -36
  78. package/src/solana/SolanaChainType.ts +27 -27
  79. package/src/solana/SolanaChains.ts +23 -23
  80. package/src/solana/SolanaInitializer.ts +102 -102
  81. package/src/solana/btcrelay/SolanaBtcRelay.ts +589 -589
  82. package/src/solana/btcrelay/headers/SolanaBtcHeader.ts +57 -57
  83. package/src/solana/btcrelay/headers/SolanaBtcStoredHeader.ts +102 -102
  84. package/src/solana/btcrelay/program/programIdl.json +670 -670
  85. package/src/solana/chain/SolanaAction.ts +108 -108
  86. package/src/solana/chain/SolanaChainInterface.ts +192 -192
  87. package/src/solana/chain/SolanaModule.ts +20 -20
  88. package/src/solana/chain/modules/SolanaAddresses.ts +20 -20
  89. package/src/solana/chain/modules/SolanaBlocks.ts +78 -78
  90. package/src/solana/chain/modules/SolanaEvents.ts +270 -256
  91. package/src/solana/chain/modules/SolanaFees.ts +450 -450
  92. package/src/solana/chain/modules/SolanaSignatures.ts +39 -39
  93. package/src/solana/chain/modules/SolanaSlots.ts +82 -82
  94. package/src/solana/chain/modules/SolanaTokens.ts +307 -307
  95. package/src/solana/chain/modules/SolanaTransactions.ts +365 -365
  96. package/src/solana/events/SolanaChainEvents.ts +299 -299
  97. package/src/solana/events/SolanaChainEventsBrowser.ts +209 -209
  98. package/src/solana/program/SolanaProgramBase.ts +79 -79
  99. package/src/solana/program/SolanaProgramModule.ts +15 -15
  100. package/src/solana/program/modules/SolanaProgramEvents.ts +155 -155
  101. package/src/solana/swaps/SolanaSwapData.ts +430 -430
  102. package/src/solana/swaps/SolanaSwapModule.ts +16 -16
  103. package/src/solana/swaps/SolanaSwapProgram.ts +854 -854
  104. package/src/solana/swaps/SwapTypeEnum.ts +29 -29
  105. package/src/solana/swaps/modules/SolanaDataAccount.ts +307 -307
  106. package/src/solana/swaps/modules/SolanaLpVault.ts +215 -215
  107. package/src/solana/swaps/modules/SwapClaim.ts +389 -389
  108. package/src/solana/swaps/modules/SwapInit.ts +663 -663
  109. package/src/solana/swaps/modules/SwapRefund.ts +323 -323
  110. package/src/solana/swaps/programIdl.json +944 -944
  111. package/src/solana/swaps/programTypes.ts +1885 -1885
  112. package/src/solana/wallet/SolanaKeypairWallet.ts +36 -36
  113. package/src/solana/wallet/SolanaSigner.ts +24 -24
  114. package/src/utils/Utils.ts +180 -180
@@ -1,441 +1,441 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SolanaBtcRelay = void 0;
4
- const web3_js_1 = require("@solana/web3.js");
5
- const SolanaBtcStoredHeader_1 = require("./headers/SolanaBtcStoredHeader");
6
- const SolanaBtcHeader_1 = require("./headers/SolanaBtcHeader");
7
- const programIdl = require("./program/programIdl.json");
8
- const base_1 = require("@atomiqlabs/base");
9
- const SolanaProgramBase_1 = require("../program/SolanaProgramBase");
10
- const SolanaAction_1 = require("../chain/SolanaAction");
11
- const buffer_1 = require("buffer");
12
- const BN = require("bn.js");
13
- const MAX_CLOSE_IX_PER_TX = 10;
14
- function serializeBlockHeader(e) {
15
- return new SolanaBtcHeader_1.SolanaBtcHeader({
16
- version: e.getVersion(),
17
- reversedPrevBlockhash: [...buffer_1.Buffer.from(e.getPrevBlockhash(), "hex").reverse()],
18
- merkleRoot: [...buffer_1.Buffer.from(e.getMerkleRoot(), "hex").reverse()],
19
- timestamp: e.getTimestamp(),
20
- nbits: e.getNbits(),
21
- nonce: e.getNonce(),
22
- hash: buffer_1.Buffer.from(e.getHash(), "hex").reverse()
23
- });
24
- }
25
- ;
26
- class SolanaBtcRelay extends SolanaProgramBase_1.SolanaProgramBase {
27
- /**
28
- * Creates initialization action for initializing the btc relay
29
- *
30
- * @param signer
31
- * @param header
32
- * @param epochStart
33
- * @param pastBlocksTimestamps
34
- * @constructor
35
- * @private
36
- */
37
- async Initialize(signer, header, epochStart, pastBlocksTimestamps) {
38
- const serializedBlock = serializeBlockHeader(header);
39
- return new SolanaAction_1.SolanaAction(signer, this.Chain, await this.program.methods
40
- .initialize(serializedBlock, header.getHeight(), header.getChainWork(), epochStart, pastBlocksTimestamps)
41
- .accounts({
42
- signer,
43
- mainState: this.BtcRelayMainState,
44
- headerTopic: this.BtcRelayHeader(serializedBlock.hash),
45
- systemProgram: web3_js_1.SystemProgram.programId
46
- })
47
- .instruction(), 100000);
48
- }
49
- /**
50
- * Creates verify action to be used with the swap program, specifies the action to be firstIxBeforeComputeBudget,
51
- * such that the verify instruction will always be the 0th in the transaction, this is required because
52
- * swap program expects the verify instruction to be at the 0th position
53
- *
54
- * @param signer
55
- * @param reversedTxId
56
- * @param confirmations
57
- * @param position
58
- * @param reversedMerkleProof
59
- * @param committedHeader
60
- */
61
- async Verify(signer, reversedTxId, confirmations, position, reversedMerkleProof, committedHeader) {
62
- return new SolanaAction_1.SolanaAction(signer, this.Chain, await this.program.methods
63
- .verifyTransaction(reversedTxId, confirmations, position, reversedMerkleProof, committedHeader)
64
- .accounts({
65
- signer,
66
- mainState: this.BtcRelayMainState
67
- })
68
- .instruction(), null, null, null, true);
69
- }
70
- async CloseForkAccount(signer, forkId) {
71
- return new SolanaAction_1.SolanaAction(signer, this.Chain, await this.program.methods
72
- .closeForkAccount(new BN(forkId))
73
- .accounts({
74
- signer,
75
- forkState: this.BtcRelayFork(forkId, signer),
76
- systemProgram: web3_js_1.SystemProgram.programId,
77
- })
78
- .instruction(), 20000);
79
- }
80
- constructor(chainInterface, bitcoinRpc, programAddress) {
81
- super(chainInterface, programIdl, programAddress);
82
- this.BtcRelayMainState = this.pda("state");
83
- this.BtcRelayHeader = this.pda("header", (hash) => [hash]);
84
- this.BtcRelayFork = this.pda("fork", (forkId, pubkey) => [new BN(forkId).toArrayLike(buffer_1.Buffer, "le", 8), pubkey.toBuffer()]);
85
- this.maxHeadersPerTx = 5;
86
- this.maxForkHeadersPerTx = 4;
87
- this.maxShortForkHeadersPerTx = 4;
88
- this.bitcoinRpc = bitcoinRpc;
89
- }
90
- /**
91
- * Gets set of block commitments representing current main chain from the mainState
92
- *
93
- * @param mainState
94
- * @private
95
- */
96
- getBlockCommitmentsSet(mainState) {
97
- const storedCommitments = new Set();
98
- mainState.blockCommitments.forEach(e => {
99
- storedCommitments.add(buffer_1.Buffer.from(e).toString("hex"));
100
- });
101
- return storedCommitments;
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
122
- * @param headers headers to sync to the btc relay
123
- * @param storedHeader current latest stored block header for a given fork
124
- * @param tipWork work of the current tip in a given fork
125
- * @param forkId forkId to submit to, forkId=0 means main chain
126
- * @param feeRate feeRate for the transaction
127
- * @param createTx transaction generator function
128
- * @private
129
- */
130
- async _saveHeaders(signer, headers, storedHeader, tipWork, forkId, feeRate, createTx) {
131
- const blockHeaderObj = headers.map(serializeBlockHeader);
132
- const tx = await createTx(blockHeaderObj)
133
- .remainingAccounts(blockHeaderObj.map(e => {
134
- return {
135
- pubkey: this.BtcRelayHeader(e.hash),
136
- isSigner: false,
137
- isWritable: false
138
- };
139
- }))
140
- .transaction();
141
- tx.feePayer = signer;
142
- this.Chain.Fees.applyFeeRateBegin(tx, null, feeRate);
143
- this.Chain.Fees.applyFeeRateEnd(tx, null, feeRate);
144
- const computedCommitedHeaders = this.computeCommitedHeaders(storedHeader, blockHeaderObj);
145
- const lastStoredHeader = computedCommitedHeaders[computedCommitedHeaders.length - 1];
146
- if (forkId !== 0 && base_1.StatePredictorUtils.gtBuffer(buffer_1.Buffer.from(lastStoredHeader.chainWork), tipWork)) {
147
- //Fork's work is higher than main chain's work, this fork will become a main chain
148
- forkId = 0;
149
- }
150
- return {
151
- forkId: forkId,
152
- lastStoredHeader,
153
- tx: {
154
- tx,
155
- signers: []
156
- },
157
- computedCommitedHeaders
158
- };
159
- }
160
- /**
161
- * Returns data about current main chain tip stored in the btc relay
162
- */
163
- async getTipData() {
164
- const data = await this.program.account.mainState.fetchNullable(this.BtcRelayMainState);
165
- if (data == null)
166
- return null;
167
- return {
168
- blockheight: data.blockHeight,
169
- commitHash: buffer_1.Buffer.from(data.tipCommitHash).toString("hex"),
170
- blockhash: buffer_1.Buffer.from(data.tipBlockHash).reverse().toString("hex"),
171
- chainWork: buffer_1.Buffer.from(data.chainWork)
172
- };
173
- }
174
- /**
175
- * Retrieves blockheader with a specific blockhash, returns null if requiredBlockheight is provided and
176
- * btc relay contract is not synced up to the desired blockheight
177
- *
178
- * @param blockData
179
- * @param requiredBlockheight
180
- */
181
- async retrieveLogAndBlockheight(blockData, requiredBlockheight) {
182
- const mainState = await this.program.account.mainState.fetch(this.BtcRelayMainState);
183
- if (requiredBlockheight != null && mainState.blockHeight < requiredBlockheight) {
184
- return null;
185
- }
186
- const storedCommitments = this.getBlockCommitmentsSet(mainState);
187
- const blockHashBuffer = buffer_1.Buffer.from(blockData.blockhash, 'hex').reverse();
188
- const topicKey = this.BtcRelayHeader(blockHashBuffer);
189
- const data = await this.Events.findInEvents(topicKey, async (event) => {
190
- if (event.name === "StoreFork" || event.name === "StoreHeader") {
191
- const eventData = event.data;
192
- const commitHash = buffer_1.Buffer.from(eventData.commitHash).toString("hex");
193
- if (blockHashBuffer.equals(buffer_1.Buffer.from(eventData.blockHash)) && storedCommitments.has(commitHash))
194
- return {
195
- header: new SolanaBtcStoredHeader_1.SolanaBtcStoredHeader(eventData.header),
196
- height: mainState.blockHeight,
197
- commitHash
198
- };
199
- }
200
- });
201
- if (data != null)
202
- this.logger.debug("retrieveLogAndBlockheight(): block found," +
203
- " commit hash: " + data.commitHash + " blockhash: " + blockData.blockhash + " height: " + data.height);
204
- return data;
205
- }
206
- /**
207
- * Retrieves blockheader data by blockheader's commit hash,
208
- *
209
- * @param commitmentHashStr
210
- * @param blockData
211
- */
212
- async retrieveLogByCommitHash(commitmentHashStr, blockData) {
213
- const blockHashBuffer = buffer_1.Buffer.from(blockData.blockhash, "hex").reverse();
214
- const topicKey = this.BtcRelayHeader(blockHashBuffer);
215
- const data = await this.Events.findInEvents(topicKey, async (event) => {
216
- if (event.name === "StoreFork" || event.name === "StoreHeader") {
217
- const eventData = event.data;
218
- const commitHash = buffer_1.Buffer.from(eventData.commitHash).toString("hex");
219
- if (commitmentHashStr === commitHash)
220
- return new SolanaBtcStoredHeader_1.SolanaBtcStoredHeader(eventData.header);
221
- }
222
- });
223
- if (data != null)
224
- this.logger.debug("retrieveLogByCommitHash(): block found," +
225
- " commit hash: " + commitmentHashStr + " blockhash: " + blockData.blockhash + " height: " + data.blockheight);
226
- return data;
227
- }
228
- /**
229
- * Retrieves latest known stored blockheader & blockheader from bitcoin RPC that is in the main chain
230
- */
231
- async retrieveLatestKnownBlockLog() {
232
- const mainState = await this.program.account.mainState.fetch(this.BtcRelayMainState);
233
- const storedCommitments = this.getBlockCommitmentsSet(mainState);
234
- const data = await this.Events.findInEvents(this.program.programId, async (event) => {
235
- if (event.name === "StoreFork" || event.name === "StoreHeader") {
236
- const eventData = event.data;
237
- const blockHashHex = buffer_1.Buffer.from(eventData.blockHash).reverse().toString("hex");
238
- const isInMainChain = await this.bitcoinRpc.isInMainChain(blockHashHex).catch(() => false);
239
- const commitHash = buffer_1.Buffer.from(eventData.commitHash).toString("hex");
240
- //Check if this fork is part of main chain
241
- if (isInMainChain && storedCommitments.has(commitHash))
242
- return {
243
- resultStoredHeader: new SolanaBtcStoredHeader_1.SolanaBtcStoredHeader(eventData.header),
244
- resultBitcoinHeader: await this.bitcoinRpc.getBlockHeader(blockHashHex),
245
- commitHash: commitHash
246
- };
247
- }
248
- }, null, 10);
249
- if (data != null)
250
- this.logger.debug("retrieveLatestKnownBlockLog(): block found," +
251
- " commit hash: " + data.commitHash + " blockhash: " + data.resultBitcoinHeader.getHash() +
252
- " height: " + data.resultStoredHeader.blockheight);
253
- return data;
254
- }
255
- /**
256
- * Saves initial block header when the btc relay is in uninitialized state
257
- *
258
- * @param signer
259
- * @param header a bitcoin blockheader to submit
260
- * @param epochStart timestamp of the start of the epoch (block timestamp at blockheight-(blockheight%2016))
261
- * @param pastBlocksTimestamps timestamp of the past 10 blocks
262
- * @param feeRate fee rate to use for the transaction
263
- */
264
- async saveInitialHeader(signer, header, epochStart, pastBlocksTimestamps, feeRate) {
265
- if (pastBlocksTimestamps.length !== 10)
266
- throw new Error("Invalid prevBlocksTimestamps");
267
- const action = await this.Initialize(new web3_js_1.PublicKey(signer), header, epochStart, pastBlocksTimestamps);
268
- this.logger.debug("saveInitialHeader(): saving initial header, blockhash: " + header.getHash() +
269
- " blockheight: " + header.getHeight() + " epochStart: " + epochStart + " past block timestamps: " + pastBlocksTimestamps.join());
270
- return await action.tx(feeRate);
271
- }
272
- /**
273
- * Saves blockheaders as a bitcoin main chain to the btc relay
274
- *
275
- * @param signer
276
- * @param mainHeaders
277
- * @param storedHeader
278
- * @param feeRate
279
- */
280
- saveMainHeaders(signer, mainHeaders, storedHeader, feeRate) {
281
- this.logger.debug("saveMainHeaders(): submitting main blockheaders, count: " + mainHeaders.length);
282
- const _signer = new web3_js_1.PublicKey(signer);
283
- return this._saveHeaders(_signer, mainHeaders, storedHeader, null, 0, feeRate, (blockHeaders) => this.program.methods
284
- .submitBlockHeaders(blockHeaders, storedHeader)
285
- .accounts({
286
- signer: _signer,
287
- mainState: this.BtcRelayMainState,
288
- }));
289
- }
290
- /**
291
- * Creates a new long fork and submits the headers to it
292
- *
293
- * @param signer
294
- * @param forkHeaders
295
- * @param storedHeader
296
- * @param tipWork
297
- * @param feeRate
298
- */
299
- async saveNewForkHeaders(signer, forkHeaders, storedHeader, tipWork, feeRate) {
300
- const mainState = await this.program.account.mainState.fetch(this.BtcRelayMainState);
301
- let forkId = mainState.forkCounter;
302
- const _signer = new web3_js_1.PublicKey(signer);
303
- this.logger.debug("saveNewForkHeaders(): submitting new fork & blockheaders," +
304
- " count: " + forkHeaders.length + " forkId: " + forkId.toString(10));
305
- return await this._saveHeaders(_signer, forkHeaders, storedHeader, tipWork, forkId.toNumber(), feeRate, (blockHeaders) => this.program.methods
306
- .submitForkHeaders(blockHeaders, storedHeader, forkId, true)
307
- .accounts({
308
- signer: _signer,
309
- mainState: this.BtcRelayMainState,
310
- forkState: this.BtcRelayFork(forkId.toNumber(), _signer),
311
- systemProgram: web3_js_1.SystemProgram.programId,
312
- }));
313
- }
314
- /**
315
- * Continues submitting blockheaders to a given fork
316
- *
317
- * @param signer
318
- * @param forkHeaders
319
- * @param storedHeader
320
- * @param forkId
321
- * @param tipWork
322
- * @param feeRate
323
- */
324
- saveForkHeaders(signer, forkHeaders, storedHeader, forkId, tipWork, feeRate) {
325
- this.logger.debug("saveForkHeaders(): submitting blockheaders to existing fork," +
326
- " count: " + forkHeaders.length + " forkId: " + forkId.toString(10));
327
- const _signer = new web3_js_1.PublicKey(signer);
328
- return this._saveHeaders(_signer, forkHeaders, storedHeader, tipWork, forkId, feeRate, (blockHeaders) => this.program.methods
329
- .submitForkHeaders(blockHeaders, storedHeader, new BN(forkId), false)
330
- .accounts({
331
- signer: _signer,
332
- mainState: this.BtcRelayMainState,
333
- forkState: this.BtcRelayFork(forkId, _signer),
334
- systemProgram: web3_js_1.SystemProgram.programId,
335
- }));
336
- }
337
- /**
338
- * Submits short fork with given blockheaders
339
- *
340
- * @param signer
341
- * @param forkHeaders
342
- * @param storedHeader
343
- * @param tipWork
344
- * @param feeRate
345
- */
346
- saveShortForkHeaders(signer, forkHeaders, storedHeader, tipWork, feeRate) {
347
- this.logger.debug("saveShortForkHeaders(): submitting short fork blockheaders," +
348
- " count: " + forkHeaders.length);
349
- const _signer = new web3_js_1.PublicKey(signer);
350
- return this._saveHeaders(_signer, forkHeaders, storedHeader, tipWork, -1, feeRate, (blockHeaders) => this.program.methods
351
- .submitShortForkHeaders(blockHeaders, storedHeader)
352
- .accounts({
353
- signer: _signer,
354
- mainState: this.BtcRelayMainState
355
- }));
356
- }
357
- /**
358
- * Sweeps fork data PDAs back to self
359
- *
360
- * @param signer
361
- * @param lastSweepId lastCheckedId returned from the previous sweepForkData() call
362
- * @returns {number} lastCheckedId that should be passed to the next call of sweepForkData()
363
- */
364
- async sweepForkData(signer, lastSweepId) {
365
- const mainState = await this.program.account.mainState.fetch(this.BtcRelayMainState);
366
- let forkId = mainState.forkCounter.toNumber();
367
- const txs = [];
368
- let action = new SolanaAction_1.SolanaAction(signer.getPublicKey(), this.Chain);
369
- let lastCheckedId = lastSweepId;
370
- for (let i = lastSweepId == null ? 0 : lastSweepId + 1; i <= forkId; i++) {
371
- lastCheckedId = i;
372
- const accountAddr = this.BtcRelayFork(i, signer.getPublicKey());
373
- let forkState = await this.program.account.forkState.fetchNullable(accountAddr);
374
- if (forkState == null)
375
- continue;
376
- this.logger.info("sweepForkData(): sweeping forkId: " + i);
377
- action.add(await this.CloseForkAccount(signer.getPublicKey(), i));
378
- if (action.ixsLength() >= MAX_CLOSE_IX_PER_TX) {
379
- await action.addToTxs(txs);
380
- action = new SolanaAction_1.SolanaAction(signer.getPublicKey(), this.Chain);
381
- }
382
- }
383
- if (action.ixsLength() >= MAX_CLOSE_IX_PER_TX) {
384
- await action.addToTxs(txs);
385
- }
386
- if (txs.length > 0) {
387
- const signatures = await this.Chain.sendAndConfirm(signer, txs, true);
388
- this.logger.info("sweepForkData(): forks swept, signatures: " + signatures.join());
389
- }
390
- return lastCheckedId;
391
- }
392
- /**
393
- * Estimate required synchronization fee (worst case) to synchronize btc relay to the required blockheight
394
- *
395
- * @param requiredBlockheight
396
- * @param feeRate
397
- */
398
- async estimateSynchronizeFee(requiredBlockheight, feeRate) {
399
- const tipData = await this.getTipData();
400
- const currBlockheight = tipData.blockheight;
401
- const blockheightDelta = requiredBlockheight - currBlockheight;
402
- if (blockheightDelta <= 0)
403
- return 0n;
404
- const synchronizationFee = BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate);
405
- this.logger.debug("estimateSynchronizeFee(): required blockheight: " + requiredBlockheight +
406
- " blockheight delta: " + blockheightDelta + " fee: " + synchronizationFee.toString(10));
407
- return synchronizationFee;
408
- }
409
- /**
410
- * Returns fee required (in SOL) to synchronize a single block to btc relay
411
- *
412
- * @param feeRate
413
- */
414
- async getFeePerBlock(feeRate) {
415
- // feeRate = feeRate || await this.getMainFeeRate(null);
416
- // return BASE_FEE_SOL_PER_BLOCKHEADER.add(this.Fees.getPriorityFee(200000, feeRate, false));
417
- return 50000n;
418
- }
419
- /**
420
- * Gets fee rate required for submitting blockheaders to the main chain
421
- */
422
- getMainFeeRate(signer) {
423
- const _signer = signer == null ? null : new web3_js_1.PublicKey(signer);
424
- return this.Chain.Fees.getFeeRate(_signer == null ? [this.BtcRelayMainState] : [
425
- _signer,
426
- this.BtcRelayMainState
427
- ]);
428
- }
429
- /**
430
- * Gets fee rate required for submitting blockheaders to the specific fork
431
- */
432
- getForkFeeRate(signer, forkId) {
433
- const _signer = new web3_js_1.PublicKey(signer);
434
- return this.Chain.Fees.getFeeRate([
435
- _signer,
436
- this.BtcRelayMainState,
437
- this.BtcRelayFork(forkId, _signer)
438
- ]);
439
- }
440
- }
441
- exports.SolanaBtcRelay = SolanaBtcRelay;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SolanaBtcRelay = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const SolanaBtcStoredHeader_1 = require("./headers/SolanaBtcStoredHeader");
6
+ const SolanaBtcHeader_1 = require("./headers/SolanaBtcHeader");
7
+ const programIdl = require("./program/programIdl.json");
8
+ const base_1 = require("@atomiqlabs/base");
9
+ const SolanaProgramBase_1 = require("../program/SolanaProgramBase");
10
+ const SolanaAction_1 = require("../chain/SolanaAction");
11
+ const buffer_1 = require("buffer");
12
+ const BN = require("bn.js");
13
+ const MAX_CLOSE_IX_PER_TX = 10;
14
+ function serializeBlockHeader(e) {
15
+ return new SolanaBtcHeader_1.SolanaBtcHeader({
16
+ version: e.getVersion(),
17
+ reversedPrevBlockhash: [...buffer_1.Buffer.from(e.getPrevBlockhash(), "hex").reverse()],
18
+ merkleRoot: [...buffer_1.Buffer.from(e.getMerkleRoot(), "hex").reverse()],
19
+ timestamp: e.getTimestamp(),
20
+ nbits: e.getNbits(),
21
+ nonce: e.getNonce(),
22
+ hash: buffer_1.Buffer.from(e.getHash(), "hex").reverse()
23
+ });
24
+ }
25
+ ;
26
+ class SolanaBtcRelay extends SolanaProgramBase_1.SolanaProgramBase {
27
+ /**
28
+ * Creates initialization action for initializing the btc relay
29
+ *
30
+ * @param signer
31
+ * @param header
32
+ * @param epochStart
33
+ * @param pastBlocksTimestamps
34
+ * @constructor
35
+ * @private
36
+ */
37
+ async Initialize(signer, header, epochStart, pastBlocksTimestamps) {
38
+ const serializedBlock = serializeBlockHeader(header);
39
+ return new SolanaAction_1.SolanaAction(signer, this.Chain, await this.program.methods
40
+ .initialize(serializedBlock, header.getHeight(), header.getChainWork(), epochStart, pastBlocksTimestamps)
41
+ .accounts({
42
+ signer,
43
+ mainState: this.BtcRelayMainState,
44
+ headerTopic: this.BtcRelayHeader(serializedBlock.hash),
45
+ systemProgram: web3_js_1.SystemProgram.programId
46
+ })
47
+ .instruction(), 100000);
48
+ }
49
+ /**
50
+ * Creates verify action to be used with the swap program, specifies the action to be firstIxBeforeComputeBudget,
51
+ * such that the verify instruction will always be the 0th in the transaction, this is required because
52
+ * swap program expects the verify instruction to be at the 0th position
53
+ *
54
+ * @param signer
55
+ * @param reversedTxId
56
+ * @param confirmations
57
+ * @param position
58
+ * @param reversedMerkleProof
59
+ * @param committedHeader
60
+ */
61
+ async Verify(signer, reversedTxId, confirmations, position, reversedMerkleProof, committedHeader) {
62
+ return new SolanaAction_1.SolanaAction(signer, this.Chain, await this.program.methods
63
+ .verifyTransaction(reversedTxId, confirmations, position, reversedMerkleProof, committedHeader)
64
+ .accounts({
65
+ signer,
66
+ mainState: this.BtcRelayMainState
67
+ })
68
+ .instruction(), null, null, null, true);
69
+ }
70
+ async CloseForkAccount(signer, forkId) {
71
+ return new SolanaAction_1.SolanaAction(signer, this.Chain, await this.program.methods
72
+ .closeForkAccount(new BN(forkId))
73
+ .accounts({
74
+ signer,
75
+ forkState: this.BtcRelayFork(forkId, signer),
76
+ systemProgram: web3_js_1.SystemProgram.programId,
77
+ })
78
+ .instruction(), 20000);
79
+ }
80
+ constructor(chainInterface, bitcoinRpc, programAddress) {
81
+ super(chainInterface, programIdl, programAddress);
82
+ this.BtcRelayMainState = this.pda("state");
83
+ this.BtcRelayHeader = this.pda("header", (hash) => [hash]);
84
+ this.BtcRelayFork = this.pda("fork", (forkId, pubkey) => [new BN(forkId).toArrayLike(buffer_1.Buffer, "le", 8), pubkey.toBuffer()]);
85
+ this.maxHeadersPerTx = 5;
86
+ this.maxForkHeadersPerTx = 4;
87
+ this.maxShortForkHeadersPerTx = 4;
88
+ this.bitcoinRpc = bitcoinRpc;
89
+ }
90
+ /**
91
+ * Gets set of block commitments representing current main chain from the mainState
92
+ *
93
+ * @param mainState
94
+ * @private
95
+ */
96
+ getBlockCommitmentsSet(mainState) {
97
+ const storedCommitments = new Set();
98
+ mainState.blockCommitments.forEach(e => {
99
+ storedCommitments.add(buffer_1.Buffer.from(e).toString("hex"));
100
+ });
101
+ return storedCommitments;
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
122
+ * @param headers headers to sync to the btc relay
123
+ * @param storedHeader current latest stored block header for a given fork
124
+ * @param tipWork work of the current tip in a given fork
125
+ * @param forkId forkId to submit to, forkId=0 means main chain
126
+ * @param feeRate feeRate for the transaction
127
+ * @param createTx transaction generator function
128
+ * @private
129
+ */
130
+ async _saveHeaders(signer, headers, storedHeader, tipWork, forkId, feeRate, createTx) {
131
+ const blockHeaderObj = headers.map(serializeBlockHeader);
132
+ const tx = await createTx(blockHeaderObj)
133
+ .remainingAccounts(blockHeaderObj.map(e => {
134
+ return {
135
+ pubkey: this.BtcRelayHeader(e.hash),
136
+ isSigner: false,
137
+ isWritable: false
138
+ };
139
+ }))
140
+ .transaction();
141
+ tx.feePayer = signer;
142
+ this.Chain.Fees.applyFeeRateBegin(tx, null, feeRate);
143
+ this.Chain.Fees.applyFeeRateEnd(tx, null, feeRate);
144
+ const computedCommitedHeaders = this.computeCommitedHeaders(storedHeader, blockHeaderObj);
145
+ const lastStoredHeader = computedCommitedHeaders[computedCommitedHeaders.length - 1];
146
+ if (forkId !== 0 && base_1.StatePredictorUtils.gtBuffer(buffer_1.Buffer.from(lastStoredHeader.chainWork), tipWork)) {
147
+ //Fork's work is higher than main chain's work, this fork will become a main chain
148
+ forkId = 0;
149
+ }
150
+ return {
151
+ forkId: forkId,
152
+ lastStoredHeader,
153
+ tx: {
154
+ tx,
155
+ signers: []
156
+ },
157
+ computedCommitedHeaders
158
+ };
159
+ }
160
+ /**
161
+ * Returns data about current main chain tip stored in the btc relay
162
+ */
163
+ async getTipData() {
164
+ const data = await this.program.account.mainState.fetchNullable(this.BtcRelayMainState);
165
+ if (data == null)
166
+ return null;
167
+ return {
168
+ blockheight: data.blockHeight,
169
+ commitHash: buffer_1.Buffer.from(data.tipCommitHash).toString("hex"),
170
+ blockhash: buffer_1.Buffer.from(data.tipBlockHash).reverse().toString("hex"),
171
+ chainWork: buffer_1.Buffer.from(data.chainWork)
172
+ };
173
+ }
174
+ /**
175
+ * Retrieves blockheader with a specific blockhash, returns null if requiredBlockheight is provided and
176
+ * btc relay contract is not synced up to the desired blockheight
177
+ *
178
+ * @param blockData
179
+ * @param requiredBlockheight
180
+ */
181
+ async retrieveLogAndBlockheight(blockData, requiredBlockheight) {
182
+ const mainState = await this.program.account.mainState.fetch(this.BtcRelayMainState);
183
+ if (requiredBlockheight != null && mainState.blockHeight < requiredBlockheight) {
184
+ return null;
185
+ }
186
+ const storedCommitments = this.getBlockCommitmentsSet(mainState);
187
+ const blockHashBuffer = buffer_1.Buffer.from(blockData.blockhash, 'hex').reverse();
188
+ const topicKey = this.BtcRelayHeader(blockHashBuffer);
189
+ const data = await this.Events.findInEvents(topicKey, async (event) => {
190
+ if (event.name === "StoreFork" || event.name === "StoreHeader") {
191
+ const eventData = event.data;
192
+ const commitHash = buffer_1.Buffer.from(eventData.commitHash).toString("hex");
193
+ if (blockHashBuffer.equals(buffer_1.Buffer.from(eventData.blockHash)) && storedCommitments.has(commitHash))
194
+ return {
195
+ header: new SolanaBtcStoredHeader_1.SolanaBtcStoredHeader(eventData.header),
196
+ height: mainState.blockHeight,
197
+ commitHash
198
+ };
199
+ }
200
+ });
201
+ if (data != null)
202
+ this.logger.debug("retrieveLogAndBlockheight(): block found," +
203
+ " commit hash: " + data.commitHash + " blockhash: " + blockData.blockhash + " height: " + data.height);
204
+ return data;
205
+ }
206
+ /**
207
+ * Retrieves blockheader data by blockheader's commit hash,
208
+ *
209
+ * @param commitmentHashStr
210
+ * @param blockData
211
+ */
212
+ async retrieveLogByCommitHash(commitmentHashStr, blockData) {
213
+ const blockHashBuffer = buffer_1.Buffer.from(blockData.blockhash, "hex").reverse();
214
+ const topicKey = this.BtcRelayHeader(blockHashBuffer);
215
+ const data = await this.Events.findInEvents(topicKey, async (event) => {
216
+ if (event.name === "StoreFork" || event.name === "StoreHeader") {
217
+ const eventData = event.data;
218
+ const commitHash = buffer_1.Buffer.from(eventData.commitHash).toString("hex");
219
+ if (commitmentHashStr === commitHash)
220
+ return new SolanaBtcStoredHeader_1.SolanaBtcStoredHeader(eventData.header);
221
+ }
222
+ });
223
+ if (data != null)
224
+ this.logger.debug("retrieveLogByCommitHash(): block found," +
225
+ " commit hash: " + commitmentHashStr + " blockhash: " + blockData.blockhash + " height: " + data.blockheight);
226
+ return data;
227
+ }
228
+ /**
229
+ * Retrieves latest known stored blockheader & blockheader from bitcoin RPC that is in the main chain
230
+ */
231
+ async retrieveLatestKnownBlockLog() {
232
+ const mainState = await this.program.account.mainState.fetch(this.BtcRelayMainState);
233
+ const storedCommitments = this.getBlockCommitmentsSet(mainState);
234
+ const data = await this.Events.findInEvents(this.program.programId, async (event) => {
235
+ if (event.name === "StoreFork" || event.name === "StoreHeader") {
236
+ const eventData = event.data;
237
+ const blockHashHex = buffer_1.Buffer.from(eventData.blockHash).reverse().toString("hex");
238
+ const isInMainChain = await this.bitcoinRpc.isInMainChain(blockHashHex).catch(() => false);
239
+ const commitHash = buffer_1.Buffer.from(eventData.commitHash).toString("hex");
240
+ //Check if this fork is part of main chain
241
+ if (isInMainChain && storedCommitments.has(commitHash))
242
+ return {
243
+ resultStoredHeader: new SolanaBtcStoredHeader_1.SolanaBtcStoredHeader(eventData.header),
244
+ resultBitcoinHeader: await this.bitcoinRpc.getBlockHeader(blockHashHex),
245
+ commitHash: commitHash
246
+ };
247
+ }
248
+ }, null, 10);
249
+ if (data != null)
250
+ this.logger.debug("retrieveLatestKnownBlockLog(): block found," +
251
+ " commit hash: " + data.commitHash + " blockhash: " + data.resultBitcoinHeader.getHash() +
252
+ " height: " + data.resultStoredHeader.blockheight);
253
+ return data;
254
+ }
255
+ /**
256
+ * Saves initial block header when the btc relay is in uninitialized state
257
+ *
258
+ * @param signer
259
+ * @param header a bitcoin blockheader to submit
260
+ * @param epochStart timestamp of the start of the epoch (block timestamp at blockheight-(blockheight%2016))
261
+ * @param pastBlocksTimestamps timestamp of the past 10 blocks
262
+ * @param feeRate fee rate to use for the transaction
263
+ */
264
+ async saveInitialHeader(signer, header, epochStart, pastBlocksTimestamps, feeRate) {
265
+ if (pastBlocksTimestamps.length !== 10)
266
+ throw new Error("Invalid prevBlocksTimestamps");
267
+ const action = await this.Initialize(new web3_js_1.PublicKey(signer), header, epochStart, pastBlocksTimestamps);
268
+ this.logger.debug("saveInitialHeader(): saving initial header, blockhash: " + header.getHash() +
269
+ " blockheight: " + header.getHeight() + " epochStart: " + epochStart + " past block timestamps: " + pastBlocksTimestamps.join());
270
+ return await action.tx(feeRate);
271
+ }
272
+ /**
273
+ * Saves blockheaders as a bitcoin main chain to the btc relay
274
+ *
275
+ * @param signer
276
+ * @param mainHeaders
277
+ * @param storedHeader
278
+ * @param feeRate
279
+ */
280
+ saveMainHeaders(signer, mainHeaders, storedHeader, feeRate) {
281
+ this.logger.debug("saveMainHeaders(): submitting main blockheaders, count: " + mainHeaders.length);
282
+ const _signer = new web3_js_1.PublicKey(signer);
283
+ return this._saveHeaders(_signer, mainHeaders, storedHeader, null, 0, feeRate, (blockHeaders) => this.program.methods
284
+ .submitBlockHeaders(blockHeaders, storedHeader)
285
+ .accounts({
286
+ signer: _signer,
287
+ mainState: this.BtcRelayMainState,
288
+ }));
289
+ }
290
+ /**
291
+ * Creates a new long fork and submits the headers to it
292
+ *
293
+ * @param signer
294
+ * @param forkHeaders
295
+ * @param storedHeader
296
+ * @param tipWork
297
+ * @param feeRate
298
+ */
299
+ async saveNewForkHeaders(signer, forkHeaders, storedHeader, tipWork, feeRate) {
300
+ const mainState = await this.program.account.mainState.fetch(this.BtcRelayMainState);
301
+ let forkId = mainState.forkCounter;
302
+ const _signer = new web3_js_1.PublicKey(signer);
303
+ this.logger.debug("saveNewForkHeaders(): submitting new fork & blockheaders," +
304
+ " count: " + forkHeaders.length + " forkId: " + forkId.toString(10));
305
+ return await this._saveHeaders(_signer, forkHeaders, storedHeader, tipWork, forkId.toNumber(), feeRate, (blockHeaders) => this.program.methods
306
+ .submitForkHeaders(blockHeaders, storedHeader, forkId, true)
307
+ .accounts({
308
+ signer: _signer,
309
+ mainState: this.BtcRelayMainState,
310
+ forkState: this.BtcRelayFork(forkId.toNumber(), _signer),
311
+ systemProgram: web3_js_1.SystemProgram.programId,
312
+ }));
313
+ }
314
+ /**
315
+ * Continues submitting blockheaders to a given fork
316
+ *
317
+ * @param signer
318
+ * @param forkHeaders
319
+ * @param storedHeader
320
+ * @param forkId
321
+ * @param tipWork
322
+ * @param feeRate
323
+ */
324
+ saveForkHeaders(signer, forkHeaders, storedHeader, forkId, tipWork, feeRate) {
325
+ this.logger.debug("saveForkHeaders(): submitting blockheaders to existing fork," +
326
+ " count: " + forkHeaders.length + " forkId: " + forkId.toString(10));
327
+ const _signer = new web3_js_1.PublicKey(signer);
328
+ return this._saveHeaders(_signer, forkHeaders, storedHeader, tipWork, forkId, feeRate, (blockHeaders) => this.program.methods
329
+ .submitForkHeaders(blockHeaders, storedHeader, new BN(forkId), false)
330
+ .accounts({
331
+ signer: _signer,
332
+ mainState: this.BtcRelayMainState,
333
+ forkState: this.BtcRelayFork(forkId, _signer),
334
+ systemProgram: web3_js_1.SystemProgram.programId,
335
+ }));
336
+ }
337
+ /**
338
+ * Submits short fork with given blockheaders
339
+ *
340
+ * @param signer
341
+ * @param forkHeaders
342
+ * @param storedHeader
343
+ * @param tipWork
344
+ * @param feeRate
345
+ */
346
+ saveShortForkHeaders(signer, forkHeaders, storedHeader, tipWork, feeRate) {
347
+ this.logger.debug("saveShortForkHeaders(): submitting short fork blockheaders," +
348
+ " count: " + forkHeaders.length);
349
+ const _signer = new web3_js_1.PublicKey(signer);
350
+ return this._saveHeaders(_signer, forkHeaders, storedHeader, tipWork, -1, feeRate, (blockHeaders) => this.program.methods
351
+ .submitShortForkHeaders(blockHeaders, storedHeader)
352
+ .accounts({
353
+ signer: _signer,
354
+ mainState: this.BtcRelayMainState
355
+ }));
356
+ }
357
+ /**
358
+ * Sweeps fork data PDAs back to self
359
+ *
360
+ * @param signer
361
+ * @param lastSweepId lastCheckedId returned from the previous sweepForkData() call
362
+ * @returns {number} lastCheckedId that should be passed to the next call of sweepForkData()
363
+ */
364
+ async sweepForkData(signer, lastSweepId) {
365
+ const mainState = await this.program.account.mainState.fetch(this.BtcRelayMainState);
366
+ let forkId = mainState.forkCounter.toNumber();
367
+ const txs = [];
368
+ let action = new SolanaAction_1.SolanaAction(signer.getPublicKey(), this.Chain);
369
+ let lastCheckedId = lastSweepId;
370
+ for (let i = lastSweepId == null ? 0 : lastSweepId + 1; i <= forkId; i++) {
371
+ lastCheckedId = i;
372
+ const accountAddr = this.BtcRelayFork(i, signer.getPublicKey());
373
+ let forkState = await this.program.account.forkState.fetchNullable(accountAddr);
374
+ if (forkState == null)
375
+ continue;
376
+ this.logger.info("sweepForkData(): sweeping forkId: " + i);
377
+ action.add(await this.CloseForkAccount(signer.getPublicKey(), i));
378
+ if (action.ixsLength() >= MAX_CLOSE_IX_PER_TX) {
379
+ await action.addToTxs(txs);
380
+ action = new SolanaAction_1.SolanaAction(signer.getPublicKey(), this.Chain);
381
+ }
382
+ }
383
+ if (action.ixsLength() >= MAX_CLOSE_IX_PER_TX) {
384
+ await action.addToTxs(txs);
385
+ }
386
+ if (txs.length > 0) {
387
+ const signatures = await this.Chain.sendAndConfirm(signer, txs, true);
388
+ this.logger.info("sweepForkData(): forks swept, signatures: " + signatures.join());
389
+ }
390
+ return lastCheckedId;
391
+ }
392
+ /**
393
+ * Estimate required synchronization fee (worst case) to synchronize btc relay to the required blockheight
394
+ *
395
+ * @param requiredBlockheight
396
+ * @param feeRate
397
+ */
398
+ async estimateSynchronizeFee(requiredBlockheight, feeRate) {
399
+ const tipData = await this.getTipData();
400
+ const currBlockheight = tipData.blockheight;
401
+ const blockheightDelta = requiredBlockheight - currBlockheight;
402
+ if (blockheightDelta <= 0)
403
+ return 0n;
404
+ const synchronizationFee = BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate);
405
+ this.logger.debug("estimateSynchronizeFee(): required blockheight: " + requiredBlockheight +
406
+ " blockheight delta: " + blockheightDelta + " fee: " + synchronizationFee.toString(10));
407
+ return synchronizationFee;
408
+ }
409
+ /**
410
+ * Returns fee required (in SOL) to synchronize a single block to btc relay
411
+ *
412
+ * @param feeRate
413
+ */
414
+ async getFeePerBlock(feeRate) {
415
+ // feeRate = feeRate || await this.getMainFeeRate(null);
416
+ // return BASE_FEE_SOL_PER_BLOCKHEADER.add(this.Fees.getPriorityFee(200000, feeRate, false));
417
+ return 50000n;
418
+ }
419
+ /**
420
+ * Gets fee rate required for submitting blockheaders to the main chain
421
+ */
422
+ getMainFeeRate(signer) {
423
+ const _signer = signer == null ? null : new web3_js_1.PublicKey(signer);
424
+ return this.Chain.Fees.getFeeRate(_signer == null ? [this.BtcRelayMainState] : [
425
+ _signer,
426
+ this.BtcRelayMainState
427
+ ]);
428
+ }
429
+ /**
430
+ * Gets fee rate required for submitting blockheaders to the specific fork
431
+ */
432
+ getForkFeeRate(signer, forkId) {
433
+ const _signer = new web3_js_1.PublicKey(signer);
434
+ return this.Chain.Fees.getFeeRate([
435
+ _signer,
436
+ this.BtcRelayMainState,
437
+ this.BtcRelayFork(forkId, _signer)
438
+ ]);
439
+ }
440
+ }
441
+ exports.SolanaBtcRelay = SolanaBtcRelay;