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