@atomiqlabs/chain-solana 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/LICENSE +201 -0
  2. package/dist/index.d.ts +28 -0
  3. package/dist/index.js +44 -0
  4. package/dist/solana/SolanaChainType.d.ts +9 -0
  5. package/dist/solana/SolanaChainType.js +2 -0
  6. package/dist/solana/base/SolanaAction.d.ts +26 -0
  7. package/dist/solana/base/SolanaAction.js +99 -0
  8. package/dist/solana/base/SolanaBase.d.ts +36 -0
  9. package/dist/solana/base/SolanaBase.js +30 -0
  10. package/dist/solana/base/SolanaModule.d.ts +14 -0
  11. package/dist/solana/base/SolanaModule.js +13 -0
  12. package/dist/solana/base/modules/SolanaAddresses.d.ts +9 -0
  13. package/dist/solana/base/modules/SolanaAddresses.js +23 -0
  14. package/dist/solana/base/modules/SolanaBlocks.d.ts +28 -0
  15. package/dist/solana/base/modules/SolanaBlocks.js +83 -0
  16. package/dist/solana/base/modules/SolanaEvents.d.ts +25 -0
  17. package/dist/solana/base/modules/SolanaEvents.js +69 -0
  18. package/dist/solana/base/modules/SolanaFees.d.ts +121 -0
  19. package/dist/solana/base/modules/SolanaFees.js +393 -0
  20. package/dist/solana/base/modules/SolanaSignatures.d.ts +23 -0
  21. package/dist/solana/base/modules/SolanaSignatures.js +39 -0
  22. package/dist/solana/base/modules/SolanaSlots.d.ts +31 -0
  23. package/dist/solana/base/modules/SolanaSlots.js +81 -0
  24. package/dist/solana/base/modules/SolanaTokens.d.ts +134 -0
  25. package/dist/solana/base/modules/SolanaTokens.js +269 -0
  26. package/dist/solana/base/modules/SolanaTransactions.d.ts +124 -0
  27. package/dist/solana/base/modules/SolanaTransactions.js +354 -0
  28. package/dist/solana/btcrelay/SolanaBtcRelay.d.ts +229 -0
  29. package/dist/solana/btcrelay/SolanaBtcRelay.js +477 -0
  30. package/dist/solana/btcrelay/headers/SolanaBtcHeader.d.ts +29 -0
  31. package/dist/solana/btcrelay/headers/SolanaBtcHeader.js +34 -0
  32. package/dist/solana/btcrelay/headers/SolanaBtcStoredHeader.d.ts +46 -0
  33. package/dist/solana/btcrelay/headers/SolanaBtcStoredHeader.js +78 -0
  34. package/dist/solana/btcrelay/program/programIdl.json +671 -0
  35. package/dist/solana/events/SolanaChainEvents.d.ts +84 -0
  36. package/dist/solana/events/SolanaChainEvents.js +268 -0
  37. package/dist/solana/events/SolanaChainEventsBrowser.d.ts +85 -0
  38. package/dist/solana/events/SolanaChainEventsBrowser.js +202 -0
  39. package/dist/solana/program/SolanaProgramBase.d.ts +34 -0
  40. package/dist/solana/program/SolanaProgramBase.js +43 -0
  41. package/dist/solana/program/modules/SolanaProgramEvents.d.ts +58 -0
  42. package/dist/solana/program/modules/SolanaProgramEvents.js +114 -0
  43. package/dist/solana/swaps/SolanaSwapData.d.ts +55 -0
  44. package/dist/solana/swaps/SolanaSwapData.js +251 -0
  45. package/dist/solana/swaps/SolanaSwapModule.d.ts +9 -0
  46. package/dist/solana/swaps/SolanaSwapModule.js +12 -0
  47. package/dist/solana/swaps/SolanaSwapProgram.d.ts +218 -0
  48. package/dist/solana/swaps/SolanaSwapProgram.js +523 -0
  49. package/dist/solana/swaps/SwapTypeEnum.d.ts +11 -0
  50. package/dist/solana/swaps/SwapTypeEnum.js +42 -0
  51. package/dist/solana/swaps/modules/SolanaDataAccount.d.ts +94 -0
  52. package/dist/solana/swaps/modules/SolanaDataAccount.js +255 -0
  53. package/dist/solana/swaps/modules/SolanaLpVault.d.ts +72 -0
  54. package/dist/solana/swaps/modules/SolanaLpVault.js +196 -0
  55. package/dist/solana/swaps/modules/SwapClaim.d.ts +129 -0
  56. package/dist/solana/swaps/modules/SwapClaim.js +307 -0
  57. package/dist/solana/swaps/modules/SwapInit.d.ts +212 -0
  58. package/dist/solana/swaps/modules/SwapInit.js +508 -0
  59. package/dist/solana/swaps/modules/SwapRefund.d.ts +83 -0
  60. package/dist/solana/swaps/modules/SwapRefund.js +264 -0
  61. package/dist/solana/swaps/programIdl.json +945 -0
  62. package/dist/solana/swaps/programTypes.d.ts +943 -0
  63. package/dist/solana/swaps/programTypes.js +945 -0
  64. package/dist/solana/wallet/SolanaKeypairWallet.d.ts +9 -0
  65. package/dist/solana/wallet/SolanaKeypairWallet.js +33 -0
  66. package/dist/solana/wallet/SolanaSigner.d.ts +10 -0
  67. package/dist/solana/wallet/SolanaSigner.js +16 -0
  68. package/dist/utils/Utils.d.ts +43 -0
  69. package/dist/utils/Utils.js +143 -0
  70. package/package.json +40 -0
  71. package/src/index.ts +35 -0
  72. package/src/solana/SolanaChainType.ts +20 -0
  73. package/src/solana/base/SolanaAction.ts +109 -0
  74. package/src/solana/base/SolanaBase.ts +57 -0
  75. package/src/solana/base/SolanaModule.ts +21 -0
  76. package/src/solana/base/modules/SolanaAddresses.ts +22 -0
  77. package/src/solana/base/modules/SolanaBlocks.ts +79 -0
  78. package/src/solana/base/modules/SolanaEvents.ts +58 -0
  79. package/src/solana/base/modules/SolanaFees.ts +445 -0
  80. package/src/solana/base/modules/SolanaSignatures.ts +40 -0
  81. package/src/solana/base/modules/SolanaSlots.ts +83 -0
  82. package/src/solana/base/modules/SolanaTokens.ts +310 -0
  83. package/src/solana/base/modules/SolanaTransactions.ts +366 -0
  84. package/src/solana/btcrelay/SolanaBtcRelay.ts +591 -0
  85. package/src/solana/btcrelay/headers/SolanaBtcHeader.ts +58 -0
  86. package/src/solana/btcrelay/headers/SolanaBtcStoredHeader.ts +103 -0
  87. package/src/solana/btcrelay/program/programIdl.json +671 -0
  88. package/src/solana/events/SolanaChainEvents.ts +286 -0
  89. package/src/solana/events/SolanaChainEventsBrowser.ts +251 -0
  90. package/src/solana/program/SolanaProgramBase.ts +77 -0
  91. package/src/solana/program/modules/SolanaProgramEvents.ts +140 -0
  92. package/src/solana/swaps/SolanaSwapData.ts +360 -0
  93. package/src/solana/swaps/SolanaSwapModule.ts +17 -0
  94. package/src/solana/swaps/SolanaSwapProgram.ts +739 -0
  95. package/src/solana/swaps/SwapTypeEnum.ts +30 -0
  96. package/src/solana/swaps/modules/SolanaDataAccount.ts +309 -0
  97. package/src/solana/swaps/modules/SolanaLpVault.ts +216 -0
  98. package/src/solana/swaps/modules/SwapClaim.ts +397 -0
  99. package/src/solana/swaps/modules/SwapInit.ts +621 -0
  100. package/src/solana/swaps/modules/SwapRefund.ts +316 -0
  101. package/src/solana/swaps/programIdl.json +945 -0
  102. package/src/solana/swaps/programTypes.ts +1885 -0
  103. package/src/solana/wallet/SolanaKeypairWallet.ts +36 -0
  104. package/src/solana/wallet/SolanaSigner.ts +23 -0
  105. package/src/utils/Utils.ts +145 -0
@@ -0,0 +1,508 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SwapInit = void 0;
13
+ const web3_js_1 = require("@solana/web3.js");
14
+ const base_1 = require("@atomiqlabs/base");
15
+ const BN = require("bn.js");
16
+ const SolanaAction_1 = require("../../base/SolanaAction");
17
+ const spl_token_1 = require("@solana/spl-token");
18
+ const SolanaSwapModule_1 = require("../SolanaSwapModule");
19
+ const Utils_1 = require("../../../utils/Utils");
20
+ const buffer_1 = require("buffer");
21
+ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
22
+ constructor() {
23
+ super(...arguments);
24
+ this.SIGNATURE_SLOT_BUFFER = 20;
25
+ this.SIGNATURE_PREFETCH_DATA_VALIDITY = 5000;
26
+ }
27
+ /**
28
+ * bare Init action based on the data passed in swapData
29
+ *
30
+ * @param swapData
31
+ * @param timeout
32
+ * @private
33
+ */
34
+ Init(swapData, timeout) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const claimerAta = (0, spl_token_1.getAssociatedTokenAddressSync)(swapData.token, swapData.claimer);
37
+ const paymentHash = buffer_1.Buffer.from(swapData.paymentHash, "hex");
38
+ const accounts = {
39
+ claimer: swapData.claimer,
40
+ offerer: swapData.offerer,
41
+ escrowState: this.root.SwapEscrowState(paymentHash),
42
+ mint: swapData.token,
43
+ systemProgram: web3_js_1.SystemProgram.programId,
44
+ claimerAta: swapData.payOut ? claimerAta : null,
45
+ claimerUserData: !swapData.payOut ? this.root.SwapUserVault(swapData.claimer, swapData.token) : null
46
+ };
47
+ if (swapData.payIn) {
48
+ const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(swapData.token, swapData.offerer);
49
+ return new SolanaAction_1.SolanaAction(swapData.offerer, this.root, yield this.program.methods
50
+ .offererInitializePayIn(swapData.toSwapDataStruct(), [...buffer_1.Buffer.alloc(32, 0)], timeout)
51
+ .accounts(Object.assign(Object.assign({}, accounts), { offererAta: ata, vault: this.root.SwapVault(swapData.token), vaultAuthority: this.root.SwapVaultAuthority, tokenProgram: spl_token_1.TOKEN_PROGRAM_ID }))
52
+ .instruction(), SwapInit.CUCosts.INIT_PAY_IN);
53
+ }
54
+ else {
55
+ return new SolanaAction_1.SolanaAction(swapData.claimer, this.root, yield this.program.methods
56
+ .offererInitialize(swapData.toSwapDataStruct(), swapData.securityDeposit, swapData.claimerBounty, [...(swapData.txoHash != null ? buffer_1.Buffer.from(swapData.txoHash, "hex") : buffer_1.Buffer.alloc(32, 0))], new BN(timeout))
57
+ .accounts(Object.assign(Object.assign({}, accounts), { offererUserData: this.root.SwapUserVault(swapData.offerer, swapData.token) }))
58
+ .instruction(), SwapInit.CUCosts.INIT);
59
+ }
60
+ });
61
+ }
62
+ /**
63
+ * InitPayIn action which includes SOL to WSOL wrapping if indicated by the fee rate
64
+ *
65
+ * @param swapData
66
+ * @param timeout
67
+ * @param feeRate
68
+ * @constructor
69
+ * @private
70
+ */
71
+ InitPayIn(swapData, timeout, feeRate) {
72
+ return __awaiter(this, void 0, void 0, function* () {
73
+ if (!swapData.isPayIn())
74
+ throw new Error("Must be payIn==true");
75
+ const action = new SolanaAction_1.SolanaAction(swapData.offerer, this.root);
76
+ if (this.shouldWrapOnInit(swapData, feeRate))
77
+ action.addAction(this.Wrap(swapData, feeRate));
78
+ action.addAction(yield this.Init(swapData, timeout));
79
+ return action;
80
+ });
81
+ }
82
+ /**
83
+ * InitNotPayIn action with additional createAssociatedTokenAccountIdempotentInstruction instruction, such that
84
+ * a recipient ATA is created if it doesn't exist
85
+ *
86
+ * @param swapData
87
+ * @param timeout
88
+ * @constructor
89
+ * @private
90
+ */
91
+ InitNotPayIn(swapData, timeout) {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ if (swapData.isPayIn())
94
+ throw new Error("Must be payIn==false");
95
+ const action = new SolanaAction_1.SolanaAction(swapData.claimer, this.root);
96
+ action.addIx((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(swapData.claimer, swapData.claimerAta, swapData.claimer, swapData.token));
97
+ action.addAction(yield this.Init(swapData, timeout));
98
+ return action;
99
+ });
100
+ }
101
+ Wrap(swapData, feeRate) {
102
+ const data = this.extractAtaDataFromFeeRate(feeRate);
103
+ if (data == null)
104
+ throw new Error("Tried to add wrap instruction, but feeRate malformed: " + feeRate);
105
+ return this.root.Tokens.Wrap(swapData.offerer, swapData.amount.sub(data.balance), data.initAta);
106
+ }
107
+ /**
108
+ * Extracts data about SOL to WSOL wrapping from the fee rate, fee rate is used to convey this information from
109
+ * the user to the intermediary, such that the intermediary creates valid signature for transaction including
110
+ * the SOL to WSOL wrapping instructions
111
+ *
112
+ * @param feeRate
113
+ * @private
114
+ */
115
+ extractAtaDataFromFeeRate(feeRate) {
116
+ const hashArr = feeRate == null ? [] : feeRate.split("#");
117
+ if (hashArr.length <= 1)
118
+ return null;
119
+ const arr = hashArr[1].split(";");
120
+ if (arr.length <= 1)
121
+ return null;
122
+ return {
123
+ balance: new BN(arr[1]),
124
+ initAta: arr[0] === "1"
125
+ };
126
+ }
127
+ /**
128
+ * Checks whether a wrap instruction (SOL -> WSOL) should be a part of the signed init message
129
+ *
130
+ * @param swapData
131
+ * @param feeRate
132
+ * @private
133
+ * @returns {boolean} returns true if wrap instruction should be added
134
+ */
135
+ shouldWrapOnInit(swapData, feeRate) {
136
+ const data = this.extractAtaDataFromFeeRate(feeRate);
137
+ if (data == null)
138
+ return false;
139
+ return data.balance.lt(swapData.amount);
140
+ }
141
+ /**
142
+ * Returns the transaction to be signed as an initialization signature from the intermediary, also adds
143
+ * SOL to WSOL wrapping if indicated by the fee rate
144
+ *
145
+ * @param swapData
146
+ * @param timeout
147
+ * @param feeRate
148
+ * @private
149
+ */
150
+ getTxToSign(swapData, timeout, feeRate) {
151
+ return __awaiter(this, void 0, void 0, function* () {
152
+ const action = swapData.isPayIn() ?
153
+ yield this.InitPayIn(swapData, new BN(timeout), feeRate) :
154
+ yield this.InitNotPayIn(swapData, new BN(timeout));
155
+ const tx = (yield action.tx(feeRate)).tx;
156
+ return tx;
157
+ });
158
+ }
159
+ /**
160
+ * Returns auth prefix to be used with a specific swap, payIn=true & payIn=false use different prefixes (these
161
+ * actually have no meaning for the smart contract/solana program in the Solana case)
162
+ *
163
+ * @param swapData
164
+ * @private
165
+ */
166
+ getAuthPrefix(swapData) {
167
+ return swapData.isPayIn() ? "claim_initialize" : "initialize";
168
+ }
169
+ /**
170
+ * Returns "processed" slot required for signature validation, uses preFetchedData if provided & valid
171
+ *
172
+ * @param preFetchedData
173
+ * @private
174
+ */
175
+ getSlotForSignature(preFetchedData) {
176
+ if (preFetchedData != null &&
177
+ preFetchedData.latestSlot != null &&
178
+ preFetchedData.latestSlot.timestamp > Date.now() - this.root.Slots.SLOT_CACHE_TIME) {
179
+ const estimatedSlotsPassed = Math.floor((Date.now() - preFetchedData.latestSlot.timestamp) / this.root.SLOT_TIME);
180
+ const estimatedCurrentSlot = preFetchedData.latestSlot.slot + estimatedSlotsPassed;
181
+ this.logger.debug("getSlotForSignature(): slot: " + preFetchedData.latestSlot.slot +
182
+ " estimated passed slots: " + estimatedSlotsPassed + " estimated current slot: " + estimatedCurrentSlot);
183
+ return Promise.resolve(estimatedCurrentSlot);
184
+ }
185
+ return this.root.Slots.getSlot("processed");
186
+ }
187
+ /**
188
+ * Returns blockhash required for signature validation, uses preFetchedData if provided & valid
189
+ *
190
+ * @param txSlot
191
+ * @param preFetchedData
192
+ * @private
193
+ */
194
+ getBlockhashForSignature(txSlot, preFetchedData) {
195
+ if (preFetchedData != null &&
196
+ preFetchedData.transactionSlot != null &&
197
+ preFetchedData.transactionSlot.slot === txSlot) {
198
+ return Promise.resolve(preFetchedData.transactionSlot.blockhash);
199
+ }
200
+ return this.root.Blocks.getParsedBlock(txSlot).then(val => val.blockhash);
201
+ }
202
+ /**
203
+ * Pre-fetches slot & block based on priorly received SolanaPreFetchData, such that it can later be used
204
+ * by signature verification
205
+ *
206
+ * @param data
207
+ */
208
+ preFetchForInitSignatureVerification(data) {
209
+ return __awaiter(this, void 0, void 0, function* () {
210
+ const [latestSlot, txBlock] = yield Promise.all([
211
+ this.root.Slots.getSlotAndTimestamp("processed"),
212
+ this.root.Blocks.getParsedBlock(data.slot)
213
+ ]);
214
+ return {
215
+ latestSlot,
216
+ transactionSlot: {
217
+ slot: data.slot,
218
+ blockhash: txBlock.blockhash
219
+ }
220
+ };
221
+ });
222
+ }
223
+ /**
224
+ * Pre-fetches block data required for signing the init message by the LP, this can happen in parallel before
225
+ * signing takes place making the quoting quicker
226
+ */
227
+ preFetchBlockDataForSignatures() {
228
+ return __awaiter(this, void 0, void 0, function* () {
229
+ const latestParsedBlock = yield this.root.Blocks.findLatestParsedBlock("finalized");
230
+ return {
231
+ block: latestParsedBlock.block,
232
+ slot: latestParsedBlock.slot,
233
+ timestamp: Date.now()
234
+ };
235
+ });
236
+ }
237
+ /**
238
+ * Signs swap initialization authorization, using data from preFetchedBlockData if provided & still valid (subject
239
+ * to SIGNATURE_PREFETCH_DATA_VALIDITY)
240
+ *
241
+ * @param signer
242
+ * @param swapData
243
+ * @param authorizationTimeout
244
+ * @param feeRate
245
+ * @param preFetchedBlockData
246
+ * @public
247
+ */
248
+ signSwapInitialization(signer, swapData, authorizationTimeout, preFetchedBlockData, feeRate) {
249
+ return __awaiter(this, void 0, void 0, function* () {
250
+ if (signer.keypair == null)
251
+ throw new Error("Unsupported");
252
+ if (!signer.getPublicKey().equals(swapData.isPayIn() ? swapData.claimer : swapData.offerer))
253
+ throw new Error("Invalid signer, wrong public key!");
254
+ if (preFetchedBlockData != null && Date.now() - preFetchedBlockData.timestamp > this.SIGNATURE_PREFETCH_DATA_VALIDITY)
255
+ preFetchedBlockData = null;
256
+ const { block: latestBlock, slot: latestSlot } = preFetchedBlockData || (yield this.root.Blocks.findLatestParsedBlock("finalized"));
257
+ const authTimeout = Math.floor(Date.now() / 1000) + authorizationTimeout;
258
+ const txToSign = yield this.getTxToSign(swapData, authTimeout.toString(10), feeRate);
259
+ txToSign.feePayer = swapData.isPayIn() ? swapData.offerer : swapData.claimer;
260
+ txToSign.recentBlockhash = latestBlock.blockhash;
261
+ txToSign.sign(signer.keypair);
262
+ this.logger.debug("signSwapInitialization(): Signed tx: ", txToSign);
263
+ const sig = txToSign.signatures.find(e => e.publicKey.equals(signer.getPublicKey()));
264
+ return {
265
+ prefix: this.getAuthPrefix(swapData),
266
+ timeout: authTimeout.toString(10),
267
+ signature: latestSlot + ";" + sig.signature.toString("hex")
268
+ };
269
+ });
270
+ }
271
+ /**
272
+ * Checks whether the provided signature data is valid, using preFetchedData if provided and still valid
273
+ *
274
+ * @param swapData
275
+ * @param timeout
276
+ * @param prefix
277
+ * @param signature
278
+ * @param feeRate
279
+ * @param preFetchedData
280
+ * @public
281
+ */
282
+ isSignatureValid(swapData, timeout, prefix, signature, feeRate, preFetchedData) {
283
+ return __awaiter(this, void 0, void 0, function* () {
284
+ const sender = swapData.isPayIn() ? swapData.offerer : swapData.claimer;
285
+ const signer = swapData.isPayIn() ? swapData.claimer : swapData.offerer;
286
+ if (!swapData.isPayIn() && this.root.isExpired(sender.toString(), swapData)) {
287
+ throw new base_1.SignatureVerificationError("Swap will expire too soon!");
288
+ }
289
+ if (prefix !== this.getAuthPrefix(swapData))
290
+ throw new base_1.SignatureVerificationError("Invalid prefix");
291
+ const currentTimestamp = new BN(Math.floor(Date.now() / 1000));
292
+ const isExpired = new BN(timeout).sub(currentTimestamp).lt(new BN(this.root.authGracePeriod));
293
+ if (isExpired)
294
+ throw new base_1.SignatureVerificationError("Authorization expired!");
295
+ const [transactionSlot, signatureString] = signature.split(";");
296
+ const txSlot = parseInt(transactionSlot);
297
+ const [latestSlot, blockhash] = yield Promise.all([
298
+ this.getSlotForSignature(preFetchedData),
299
+ this.getBlockhashForSignature(txSlot, preFetchedData)
300
+ ]);
301
+ const lastValidTransactionSlot = txSlot + this.root.TX_SLOT_VALIDITY;
302
+ const slotsLeft = lastValidTransactionSlot - latestSlot - this.SIGNATURE_SLOT_BUFFER;
303
+ if (slotsLeft < 0)
304
+ throw new base_1.SignatureVerificationError("Authorization expired!");
305
+ const txToSign = yield this.getTxToSign(swapData, timeout, feeRate);
306
+ txToSign.feePayer = sender;
307
+ txToSign.recentBlockhash = blockhash;
308
+ txToSign.addSignature(signer, buffer_1.Buffer.from(signatureString, "hex"));
309
+ this.logger.debug("isSignatureValid(): Signed tx: ", txToSign);
310
+ const valid = txToSign.verifySignatures(false);
311
+ if (!valid)
312
+ throw new base_1.SignatureVerificationError("Invalid signature!");
313
+ return buffer_1.Buffer.from(blockhash);
314
+ });
315
+ }
316
+ /**
317
+ * Gets expiry of the provided signature data, this is a minimum of slot expiry & swap signature expiry
318
+ *
319
+ * @param timeout
320
+ * @param signature
321
+ * @param preFetchedData
322
+ * @public
323
+ */
324
+ getSignatureExpiry(timeout, signature, preFetchedData) {
325
+ return __awaiter(this, void 0, void 0, function* () {
326
+ const [transactionSlotStr, signatureString] = signature.split(";");
327
+ const txSlot = parseInt(transactionSlotStr);
328
+ const latestSlot = yield this.getSlotForSignature(preFetchedData);
329
+ const lastValidTransactionSlot = txSlot + this.root.TX_SLOT_VALIDITY;
330
+ const slotsLeft = lastValidTransactionSlot - latestSlot - this.SIGNATURE_SLOT_BUFFER;
331
+ const now = Date.now();
332
+ const slotExpiryTime = now + (slotsLeft * this.root.SLOT_TIME);
333
+ const timeoutExpiryTime = (parseInt(timeout) - this.root.authGracePeriod) * 1000;
334
+ const expiry = Math.min(slotExpiryTime, timeoutExpiryTime);
335
+ if (expiry < now)
336
+ return 0;
337
+ return expiry;
338
+ });
339
+ }
340
+ /**
341
+ * Checks whether signature is expired for good (uses "finalized" slot)
342
+ *
343
+ * @param signature
344
+ * @param timeout
345
+ * @public
346
+ */
347
+ isSignatureExpired(signature, timeout) {
348
+ return __awaiter(this, void 0, void 0, function* () {
349
+ const [transactionSlotStr, signatureString] = signature.split(";");
350
+ const txSlot = parseInt(transactionSlotStr);
351
+ const lastValidTransactionSlot = txSlot + this.root.TX_SLOT_VALIDITY;
352
+ const latestSlot = yield this.root.Slots.getSlot("finalized");
353
+ const slotsLeft = lastValidTransactionSlot - latestSlot + this.SIGNATURE_SLOT_BUFFER;
354
+ if (slotsLeft < 0)
355
+ return true;
356
+ if ((parseInt(timeout) + this.root.authGracePeriod) * 1000 < Date.now())
357
+ return true;
358
+ return false;
359
+ });
360
+ }
361
+ /**
362
+ * Creates init transaction (InitPayIn) with a valid signature from an LP, also adds a SOL to WSOL wrapping ix to
363
+ * the init transaction (if indicated by the fee rate) or adds the wrapping in a separate transaction (if no
364
+ * indication in the fee rate)
365
+ *
366
+ * @param swapData swap to initialize
367
+ * @param timeout init signature timeout
368
+ * @param prefix init signature prefix
369
+ * @param signature init signature
370
+ * @param skipChecks whether to skip signature validity checks
371
+ * @param feeRate fee rate to use for the transaction
372
+ */
373
+ txsInitPayIn(swapData, timeout, prefix, signature, skipChecks, feeRate) {
374
+ return __awaiter(this, void 0, void 0, function* () {
375
+ if (!skipChecks) {
376
+ const [_, payStatus] = yield Promise.all([
377
+ (0, Utils_1.tryWithRetries)(() => this.isSignatureValid(swapData, timeout, prefix, signature, feeRate), this.retryPolicy, (e) => e instanceof base_1.SignatureVerificationError),
378
+ (0, Utils_1.tryWithRetries)(() => this.root.getPaymentHashStatus(swapData.paymentHash), this.retryPolicy)
379
+ ]);
380
+ if (payStatus !== base_1.SwapCommitStatus.NOT_COMMITED)
381
+ throw new base_1.SwapDataVerificationError("Invoice already being paid for or paid");
382
+ }
383
+ const [slotNumber, signatureStr] = signature.split(";");
384
+ const block = yield (0, Utils_1.tryWithRetries)(() => this.root.Blocks.getParsedBlock(parseInt(slotNumber)), this.retryPolicy);
385
+ const txs = [];
386
+ let isWrapping = false;
387
+ const isWrappedInSignedTx = feeRate != null && feeRate.split("#").length > 1;
388
+ if (!isWrappedInSignedTx && swapData.token.equals(this.root.Tokens.WSOL_ADDRESS)) {
389
+ const ataAcc = yield (0, Utils_1.tryWithRetries)(() => this.root.Tokens.getATAOrNull(swapData.offererAta), this.retryPolicy);
390
+ const balance = ataAcc == null ? new BN(0) : new BN(ataAcc.amount.toString());
391
+ if (balance.lt(swapData.amount)) {
392
+ //Need to wrap more SOL to WSOL
393
+ yield this.root.Tokens.Wrap(swapData.offerer, swapData.amount.sub(balance), ataAcc == null)
394
+ .addToTxs(txs, feeRate, block);
395
+ isWrapping = true;
396
+ }
397
+ }
398
+ const initTx = yield (yield this.InitPayIn(swapData, new BN(timeout), feeRate)).tx(feeRate, block);
399
+ initTx.tx.addSignature(swapData.claimer, buffer_1.Buffer.from(signatureStr, "hex"));
400
+ txs.push(initTx);
401
+ this.logger.debug("txsInitPayIn(): create swap init TX, swap: " + swapData.getHash() +
402
+ " wrapping client-side: " + isWrapping + " feerate: " + feeRate);
403
+ return txs;
404
+ });
405
+ }
406
+ /**
407
+ * Creates init transactions (InitNotPayIn) with a valid signature from an intermediary
408
+ *
409
+ * @param swapData swap to initialize
410
+ * @param timeout init signature timeout
411
+ * @param prefix init signature prefix
412
+ * @param signature init signature
413
+ * @param skipChecks whether to skip signature validity checks
414
+ * @param feeRate fee rate to use for the transaction
415
+ */
416
+ txsInit(swapData, timeout, prefix, signature, skipChecks, feeRate) {
417
+ return __awaiter(this, void 0, void 0, function* () {
418
+ if (!skipChecks) {
419
+ yield (0, Utils_1.tryWithRetries)(() => this.isSignatureValid(swapData, timeout, prefix, signature, feeRate), this.retryPolicy, (e) => e instanceof base_1.SignatureVerificationError);
420
+ }
421
+ const [slotNumber, signatureStr] = signature.split(";");
422
+ const block = yield (0, Utils_1.tryWithRetries)(() => this.root.Blocks.getParsedBlock(parseInt(slotNumber)), this.retryPolicy);
423
+ const initTx = yield (yield this.InitNotPayIn(swapData, new BN(timeout))).tx(feeRate, block);
424
+ initTx.tx.addSignature(swapData.offerer, buffer_1.Buffer.from(signatureStr, "hex"));
425
+ this.logger.debug("txsInit(): create swap init TX, swap: " + swapData.getHash() + " feerate: " + feeRate);
426
+ return [initTx];
427
+ });
428
+ }
429
+ /**
430
+ * Returns the fee rate to be used for a specific init transaction, also adding indication whether the WSOL ATA
431
+ * should be initialized in the init transaction and/or current balance in the WSOL ATA
432
+ *
433
+ * @param offerer
434
+ * @param claimer
435
+ * @param token
436
+ * @param paymentHash
437
+ */
438
+ getInitPayInFeeRate(offerer, claimer, token, paymentHash) {
439
+ return __awaiter(this, void 0, void 0, function* () {
440
+ const accounts = [];
441
+ if (offerer != null)
442
+ accounts.push(offerer);
443
+ if (token != null) {
444
+ accounts.push(this.root.SwapVault(token));
445
+ if (offerer != null)
446
+ accounts.push((0, spl_token_1.getAssociatedTokenAddressSync)(token, offerer));
447
+ if (claimer != null)
448
+ accounts.push(this.root.SwapUserVault(claimer, token));
449
+ }
450
+ if (paymentHash != null)
451
+ accounts.push(this.root.SwapEscrowState(buffer_1.Buffer.from(paymentHash, "hex")));
452
+ const shouldCheckWSOLAta = token != null && offerer != null && token.equals(this.root.Tokens.WSOL_ADDRESS);
453
+ let [feeRate, _account] = yield Promise.all([
454
+ this.root.Fees.getFeeRate(accounts),
455
+ shouldCheckWSOLAta ?
456
+ this.root.Tokens.getATAOrNull((0, spl_token_1.getAssociatedTokenAddressSync)(token, offerer)) :
457
+ Promise.resolve(null)
458
+ ]);
459
+ if (shouldCheckWSOLAta) {
460
+ const account = _account;
461
+ const balance = account == null ? new BN(0) : new BN(account.amount.toString());
462
+ //Add an indication about whether the ATA is initialized & balance it contains
463
+ feeRate += "#" + (account != null ? "0" : "1") + ";" + balance.toString(10);
464
+ }
465
+ this.logger.debug("getInitPayInFeeRate(): feerate computed: " + feeRate);
466
+ return feeRate;
467
+ });
468
+ }
469
+ /**
470
+ * Returns the fee rate to be used for a specific init transaction
471
+ *
472
+ * @param offerer
473
+ * @param claimer
474
+ * @param token
475
+ * @param paymentHash
476
+ */
477
+ getInitFeeRate(offerer, claimer, token, paymentHash) {
478
+ const accounts = [];
479
+ if (offerer != null && token != null)
480
+ accounts.push(this.root.SwapUserVault(offerer, token));
481
+ if (claimer != null)
482
+ accounts.push(claimer);
483
+ if (paymentHash != null)
484
+ accounts.push(this.root.SwapEscrowState(buffer_1.Buffer.from(paymentHash, "hex")));
485
+ return this.root.Fees.getFeeRate(accounts);
486
+ }
487
+ /**
488
+ * Get the estimated solana fee of the init transaction, this includes the required deposit for creating swap PDA
489
+ */
490
+ getInitFee(swapData, feeRate) {
491
+ return __awaiter(this, void 0, void 0, function* () {
492
+ if (swapData == null)
493
+ return new BN(this.root.ESCROW_STATE_RENT_EXEMPT + 10000);
494
+ feeRate = feeRate ||
495
+ (swapData.payIn
496
+ ? yield this.getInitPayInFeeRate(swapData.offerer, swapData.claimer, swapData.token, swapData.paymentHash)
497
+ : yield this.getInitFeeRate(swapData.offerer, swapData.claimer, swapData.token, swapData.paymentHash));
498
+ const computeBudget = swapData.payIn ? SwapInit.CUCosts.INIT_PAY_IN : SwapInit.CUCosts.INIT;
499
+ const baseFee = swapData.payIn ? 10000 : 10000 + 5000;
500
+ return new BN(this.root.ESCROW_STATE_RENT_EXEMPT + baseFee).add(this.root.Fees.getPriorityFee(computeBudget, feeRate));
501
+ });
502
+ }
503
+ }
504
+ exports.SwapInit = SwapInit;
505
+ SwapInit.CUCosts = {
506
+ INIT: 90000,
507
+ INIT_PAY_IN: 50000,
508
+ };
@@ -0,0 +1,83 @@
1
+ /// <reference types="node" />
2
+ import { SolanaSwapModule } from "../SolanaSwapModule";
3
+ import { SolanaSwapData } from "../SolanaSwapData";
4
+ import * as BN from "bn.js";
5
+ import { SolanaTx } from "../../base/modules/SolanaTransactions";
6
+ import { Buffer } from "buffer";
7
+ import { SolanaSigner } from "../../wallet/SolanaSigner";
8
+ export declare class SwapRefund extends SolanaSwapModule {
9
+ private static readonly CUCosts;
10
+ /**
11
+ * Action for generic Refund instruction
12
+ *
13
+ * @param swapData
14
+ * @param refundAuthTimeout optional refund authorization timeout (should be 0 for refunding expired swaps)
15
+ * @constructor
16
+ * @private
17
+ */
18
+ private Refund;
19
+ /**
20
+ * Action for refunding with signature, adds the Ed25519 verify instruction
21
+ *
22
+ * @param swapData
23
+ * @param timeout
24
+ * @param prefix
25
+ * @param signature
26
+ * @constructor
27
+ * @private
28
+ */
29
+ private RefundWithSignature;
30
+ /**
31
+ * Gets the message to be signed as a refund authorization
32
+ *
33
+ * @param swapData
34
+ * @param prefix
35
+ * @param timeout
36
+ * @private
37
+ */
38
+ private getRefundMessage;
39
+ /**
40
+ * Checks whether we should unwrap the WSOL to SOL when refunding the swap
41
+ *
42
+ * @param swapData
43
+ * @private
44
+ */
45
+ private shouldUnwrap;
46
+ signSwapRefund(signer: SolanaSigner, swapData: SolanaSwapData, authorizationTimeout: number): Promise<{
47
+ prefix: string;
48
+ timeout: string;
49
+ signature: string;
50
+ }>;
51
+ isSignatureValid(swapData: SolanaSwapData, timeout: string, prefix: string, signature: string): Promise<Buffer>;
52
+ /**
53
+ * Creates transactions required for refunding timed out swap, also unwraps WSOL to SOL
54
+ *
55
+ * @param swapData swap data to refund
56
+ * @param check whether to check if swap is already expired and refundable
57
+ * @param initAta should initialize ATA if it doesn't exist
58
+ * @param feeRate fee rate to be used for the transactions
59
+ */
60
+ txsRefund(swapData: SolanaSwapData, check?: boolean, initAta?: boolean, feeRate?: string): Promise<SolanaTx[]>;
61
+ /**
62
+ * Creates transactions required for refunding the swap with authorization signature, also unwraps WSOL to SOL
63
+ *
64
+ * @param swapData swap data to refund
65
+ * @param timeout signature timeout
66
+ * @param prefix signature prefix of the counterparty
67
+ * @param signature signature of the counterparty
68
+ * @param check whether to check if swap is committed before attempting refund
69
+ * @param initAta should initialize ATA if it doesn't exist
70
+ * @param feeRate fee rate to be used for the transactions
71
+ */
72
+ txsRefundWithAuthorization(swapData: SolanaSwapData, timeout: string, prefix: string, signature: string, check?: boolean, initAta?: boolean, feeRate?: string): Promise<SolanaTx[]>;
73
+ getRefundFeeRate(swapData: SolanaSwapData): Promise<string>;
74
+ /**
75
+ * Get the estimated solana transaction fee of the refund transaction, this fee might be negative since it
76
+ * includes the rebate for closing the swap PDA
77
+ */
78
+ getRefundFee(swapData: SolanaSwapData, feeRate?: string): Promise<BN>;
79
+ /**
80
+ * Get the estimated solana transaction fee of the refund transaction
81
+ */
82
+ getRawRefundFee(swapData: SolanaSwapData, feeRate?: string): Promise<BN>;
83
+ }