@atomiqlabs/chain-solana 7.3.8 → 8.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/solana/SolanaChains.d.ts +14 -0
- package/dist/solana/SolanaChains.js +18 -0
- package/dist/solana/SolanaInitializer.d.ts +18 -0
- package/dist/solana/SolanaInitializer.js +59 -0
- package/dist/solana/base/SolanaAction.js +25 -38
- package/dist/solana/base/modules/SolanaBlocks.js +18 -29
- package/dist/solana/base/modules/SolanaEvents.js +15 -26
- package/dist/solana/base/modules/SolanaFees.d.ts +4 -5
- package/dist/solana/base/modules/SolanaFees.js +168 -182
- package/dist/solana/base/modules/SolanaSlots.js +16 -29
- package/dist/solana/base/modules/SolanaTokens.d.ts +6 -7
- package/dist/solana/base/modules/SolanaTokens.js +63 -84
- package/dist/solana/base/modules/SolanaTransactions.d.ts +2 -2
- package/dist/solana/base/modules/SolanaTransactions.js +143 -165
- package/dist/solana/btcrelay/SolanaBtcRelay.d.ts +2 -3
- package/dist/solana/btcrelay/SolanaBtcRelay.js +185 -221
- package/dist/solana/events/SolanaChainEvents.js +113 -138
- package/dist/solana/events/SolanaChainEventsBrowser.js +56 -65
- package/dist/solana/program/modules/SolanaProgramEvents.js +13 -24
- package/dist/solana/swaps/SolanaSwapData.d.ts +15 -11
- package/dist/solana/swaps/SolanaSwapData.js +29 -13
- package/dist/solana/swaps/SolanaSwapProgram.d.ts +40 -41
- package/dist/solana/swaps/SolanaSwapProgram.js +212 -221
- package/dist/solana/swaps/modules/SolanaDataAccount.d.ts +2 -3
- package/dist/solana/swaps/modules/SolanaDataAccount.js +117 -141
- package/dist/solana/swaps/modules/SolanaLpVault.d.ts +4 -5
- package/dist/solana/swaps/modules/SolanaLpVault.js +87 -110
- package/dist/solana/swaps/modules/SwapClaim.d.ts +4 -4
- package/dist/solana/swaps/modules/SwapClaim.js +122 -134
- package/dist/solana/swaps/modules/SwapInit.d.ts +2 -3
- package/dist/solana/swaps/modules/SwapInit.js +254 -285
- package/dist/solana/swaps/modules/SwapRefund.d.ts +2 -3
- package/dist/solana/swaps/modules/SwapRefund.js +103 -113
- package/dist/utils/Utils.d.ts +10 -0
- package/dist/utils/Utils.js +62 -35
- package/package.json +9 -6
- package/src/index.ts +1 -0
- package/src/solana/SolanaChains.ts +16 -0
- package/src/solana/SolanaInitializer.ts +98 -0
- package/src/solana/base/SolanaBase.ts +1 -2
- package/src/solana/base/modules/SolanaEvents.ts +0 -1
- package/src/solana/base/modules/SolanaFees.ts +35 -31
- package/src/solana/base/modules/SolanaTokens.ts +26 -27
- package/src/solana/base/modules/SolanaTransactions.ts +33 -28
- package/src/solana/btcrelay/SolanaBtcRelay.ts +6 -10
- package/src/solana/events/SolanaChainEventsBrowser.ts +14 -10
- package/src/solana/program/modules/SolanaProgramEvents.ts +1 -1
- package/src/solana/swaps/SolanaSwapData.ts +38 -19
- package/src/solana/swaps/SolanaSwapProgram.ts +133 -105
- package/src/solana/swaps/modules/SolanaDataAccount.ts +4 -6
- package/src/solana/swaps/modules/SolanaLpVault.ts +18 -18
- package/src/solana/swaps/modules/SwapClaim.ts +14 -17
- package/src/solana/swaps/modules/SwapInit.ts +35 -38
- package/src/solana/swaps/modules/SwapRefund.ts +20 -23
- package/src/utils/Utils.ts +35 -0
|
@@ -1,18 +1,8 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.SwapInit = void 0;
|
|
13
4
|
const web3_js_1 = require("@solana/web3.js");
|
|
14
5
|
const base_1 = require("@atomiqlabs/base");
|
|
15
|
-
const BN = require("bn.js");
|
|
16
6
|
const SolanaAction_1 = require("../../base/SolanaAction");
|
|
17
7
|
const spl_token_1 = require("@solana/spl-token");
|
|
18
8
|
const SolanaSwapModule_1 = require("../SolanaSwapModule");
|
|
@@ -32,33 +22,40 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
32
22
|
* @param timeout
|
|
33
23
|
* @private
|
|
34
24
|
*/
|
|
35
|
-
Init(swapData, timeout) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
25
|
+
async Init(swapData, timeout) {
|
|
26
|
+
const claimerAta = (0, spl_token_1.getAssociatedTokenAddressSync)(swapData.token, swapData.claimer);
|
|
27
|
+
const paymentHash = buffer_1.Buffer.from(swapData.paymentHash, "hex");
|
|
28
|
+
const accounts = {
|
|
29
|
+
claimer: swapData.claimer,
|
|
30
|
+
offerer: swapData.offerer,
|
|
31
|
+
escrowState: this.root.SwapEscrowState(paymentHash),
|
|
32
|
+
mint: swapData.token,
|
|
33
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
34
|
+
claimerAta: swapData.payOut ? claimerAta : null,
|
|
35
|
+
claimerUserData: !swapData.payOut ? this.root.SwapUserVault(swapData.claimer, swapData.token) : null
|
|
36
|
+
};
|
|
37
|
+
if (swapData.payIn) {
|
|
38
|
+
const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(swapData.token, swapData.offerer);
|
|
39
|
+
return new SolanaAction_1.SolanaAction(swapData.offerer, this.root, await this.program.methods
|
|
40
|
+
.offererInitializePayIn(swapData.toSwapDataStruct(), [...buffer_1.Buffer.alloc(32, 0)], (0, Utils_1.toBN)(timeout))
|
|
41
|
+
.accounts({
|
|
42
|
+
...accounts,
|
|
43
|
+
offererAta: ata,
|
|
44
|
+
vault: this.root.SwapVault(swapData.token),
|
|
45
|
+
vaultAuthority: this.root.SwapVaultAuthority,
|
|
46
|
+
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
47
|
+
})
|
|
48
|
+
.instruction(), SwapInit.CUCosts.INIT_PAY_IN);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
return new SolanaAction_1.SolanaAction(swapData.claimer, this.root, await this.program.methods
|
|
52
|
+
.offererInitialize(swapData.toSwapDataStruct(), swapData.securityDeposit, swapData.claimerBounty, [...(swapData.txoHash != null ? buffer_1.Buffer.from(swapData.txoHash, "hex") : buffer_1.Buffer.alloc(32, 0))], (0, Utils_1.toBN)(timeout))
|
|
53
|
+
.accounts({
|
|
54
|
+
...accounts,
|
|
55
|
+
offererUserData: this.root.SwapUserVault(swapData.offerer, swapData.token),
|
|
56
|
+
})
|
|
57
|
+
.instruction(), SwapInit.CUCosts.INIT);
|
|
58
|
+
}
|
|
62
59
|
}
|
|
63
60
|
/**
|
|
64
61
|
* InitPayIn action which includes SOL to WSOL wrapping if indicated by the fee rate
|
|
@@ -69,16 +66,14 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
69
66
|
* @constructor
|
|
70
67
|
* @private
|
|
71
68
|
*/
|
|
72
|
-
InitPayIn(swapData, timeout, feeRate) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return action;
|
|
81
|
-
});
|
|
69
|
+
async InitPayIn(swapData, timeout, feeRate) {
|
|
70
|
+
if (!swapData.isPayIn())
|
|
71
|
+
throw new Error("Must be payIn==true");
|
|
72
|
+
const action = new SolanaAction_1.SolanaAction(swapData.offerer, this.root);
|
|
73
|
+
if (this.shouldWrapOnInit(swapData, feeRate))
|
|
74
|
+
action.addAction(this.Wrap(swapData, feeRate));
|
|
75
|
+
action.addAction(await this.Init(swapData, timeout));
|
|
76
|
+
return action;
|
|
82
77
|
}
|
|
83
78
|
/**
|
|
84
79
|
* InitNotPayIn action with additional createAssociatedTokenAccountIdempotentInstruction instruction, such that
|
|
@@ -89,21 +84,19 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
89
84
|
* @constructor
|
|
90
85
|
* @private
|
|
91
86
|
*/
|
|
92
|
-
InitNotPayIn(swapData, timeout) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return action;
|
|
100
|
-
});
|
|
87
|
+
async InitNotPayIn(swapData, timeout) {
|
|
88
|
+
if (swapData.isPayIn())
|
|
89
|
+
throw new Error("Must be payIn==false");
|
|
90
|
+
const action = new SolanaAction_1.SolanaAction(swapData.claimer, this.root);
|
|
91
|
+
action.addIx((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(swapData.claimer, swapData.claimerAta, swapData.claimer, swapData.token));
|
|
92
|
+
action.addAction(await this.Init(swapData, timeout));
|
|
93
|
+
return action;
|
|
101
94
|
}
|
|
102
95
|
Wrap(swapData, feeRate) {
|
|
103
96
|
const data = this.extractAtaDataFromFeeRate(feeRate);
|
|
104
97
|
if (data == null)
|
|
105
98
|
throw new Error("Tried to add wrap instruction, but feeRate malformed: " + feeRate);
|
|
106
|
-
return this.root.Tokens.Wrap(swapData.offerer, swapData.
|
|
99
|
+
return this.root.Tokens.Wrap(swapData.offerer, swapData.getAmount() - data.balance, data.initAta);
|
|
107
100
|
}
|
|
108
101
|
/**
|
|
109
102
|
* Extracts data about SOL to WSOL wrapping from the fee rate, fee rate is used to convey this information from
|
|
@@ -121,7 +114,7 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
121
114
|
if (arr.length <= 1)
|
|
122
115
|
return null;
|
|
123
116
|
return {
|
|
124
|
-
balance:
|
|
117
|
+
balance: BigInt(arr[1]),
|
|
125
118
|
initAta: arr[0] === "1"
|
|
126
119
|
};
|
|
127
120
|
}
|
|
@@ -137,7 +130,7 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
137
130
|
const data = this.extractAtaDataFromFeeRate(feeRate);
|
|
138
131
|
if (data == null)
|
|
139
132
|
return false;
|
|
140
|
-
return data.balance.
|
|
133
|
+
return data.balance < swapData.getAmount();
|
|
141
134
|
}
|
|
142
135
|
/**
|
|
143
136
|
* Returns the transaction to be signed as an initialization signature from the intermediary, also adds
|
|
@@ -148,14 +141,12 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
148
141
|
* @param feeRate
|
|
149
142
|
* @private
|
|
150
143
|
*/
|
|
151
|
-
getTxToSign(swapData, timeout, feeRate) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return tx;
|
|
158
|
-
});
|
|
144
|
+
async getTxToSign(swapData, timeout, feeRate) {
|
|
145
|
+
const action = swapData.isPayIn() ?
|
|
146
|
+
await this.InitPayIn(swapData, BigInt(timeout), feeRate) :
|
|
147
|
+
await this.InitNotPayIn(swapData, BigInt(timeout));
|
|
148
|
+
const tx = (await action.tx(feeRate)).tx;
|
|
149
|
+
return tx;
|
|
159
150
|
}
|
|
160
151
|
/**
|
|
161
152
|
* Returns auth prefix to be used with a specific swap, payIn=true & payIn=false use different prefixes (these
|
|
@@ -206,34 +197,30 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
206
197
|
*
|
|
207
198
|
* @param data
|
|
208
199
|
*/
|
|
209
|
-
preFetchForInitSignatureVerification(data) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
};
|
|
222
|
-
});
|
|
200
|
+
async preFetchForInitSignatureVerification(data) {
|
|
201
|
+
const [latestSlot, txBlock] = await Promise.all([
|
|
202
|
+
this.root.Slots.getSlotAndTimestamp("processed"),
|
|
203
|
+
this.root.Blocks.getParsedBlock(data.slot)
|
|
204
|
+
]);
|
|
205
|
+
return {
|
|
206
|
+
latestSlot,
|
|
207
|
+
transactionSlot: {
|
|
208
|
+
slot: data.slot,
|
|
209
|
+
blockhash: txBlock.blockhash
|
|
210
|
+
}
|
|
211
|
+
};
|
|
223
212
|
}
|
|
224
213
|
/**
|
|
225
214
|
* Pre-fetches block data required for signing the init message by the LP, this can happen in parallel before
|
|
226
215
|
* signing takes place making the quoting quicker
|
|
227
216
|
*/
|
|
228
|
-
preFetchBlockDataForSignatures() {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
};
|
|
236
|
-
});
|
|
217
|
+
async preFetchBlockDataForSignatures() {
|
|
218
|
+
const latestParsedBlock = await this.root.Blocks.findLatestParsedBlock("finalized");
|
|
219
|
+
return {
|
|
220
|
+
block: latestParsedBlock.block,
|
|
221
|
+
slot: latestParsedBlock.slot,
|
|
222
|
+
timestamp: Date.now()
|
|
223
|
+
};
|
|
237
224
|
}
|
|
238
225
|
/**
|
|
239
226
|
* Signs swap initialization authorization, using data from preFetchedBlockData if provided & still valid (subject
|
|
@@ -246,28 +233,26 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
246
233
|
* @param preFetchedBlockData
|
|
247
234
|
* @public
|
|
248
235
|
*/
|
|
249
|
-
signSwapInitialization(signer, swapData, authorizationTimeout, preFetchedBlockData, feeRate) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
};
|
|
270
|
-
});
|
|
236
|
+
async signSwapInitialization(signer, swapData, authorizationTimeout, preFetchedBlockData, feeRate) {
|
|
237
|
+
if (signer.keypair == null)
|
|
238
|
+
throw new Error("Unsupported");
|
|
239
|
+
if (!signer.getPublicKey().equals(swapData.isPayIn() ? swapData.claimer : swapData.offerer))
|
|
240
|
+
throw new Error("Invalid signer, wrong public key!");
|
|
241
|
+
if (preFetchedBlockData != null && Date.now() - preFetchedBlockData.timestamp > this.SIGNATURE_PREFETCH_DATA_VALIDITY)
|
|
242
|
+
preFetchedBlockData = null;
|
|
243
|
+
const { block: latestBlock, slot: latestSlot } = preFetchedBlockData || await this.root.Blocks.findLatestParsedBlock("finalized");
|
|
244
|
+
const authTimeout = Math.floor(Date.now() / 1000) + authorizationTimeout;
|
|
245
|
+
const txToSign = await this.getTxToSign(swapData, authTimeout.toString(10), feeRate);
|
|
246
|
+
txToSign.feePayer = swapData.isPayIn() ? swapData.offerer : swapData.claimer;
|
|
247
|
+
txToSign.recentBlockhash = latestBlock.blockhash;
|
|
248
|
+
txToSign.sign(signer.keypair);
|
|
249
|
+
this.logger.debug("signSwapInitialization(): Signed tx: ", txToSign);
|
|
250
|
+
const sig = txToSign.signatures.find(e => e.publicKey.equals(signer.getPublicKey()));
|
|
251
|
+
return {
|
|
252
|
+
prefix: this.getAuthPrefix(swapData),
|
|
253
|
+
timeout: authTimeout.toString(10),
|
|
254
|
+
signature: latestSlot + ";" + sig.signature.toString("hex")
|
|
255
|
+
};
|
|
271
256
|
}
|
|
272
257
|
/**
|
|
273
258
|
* Checks whether the provided signature data is valid, using preFetchedData if provided and still valid
|
|
@@ -280,39 +265,37 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
280
265
|
* @param preFetchedData
|
|
281
266
|
* @public
|
|
282
267
|
*/
|
|
283
|
-
isSignatureValid(swapData, timeout, prefix, signature, feeRate, preFetchedData) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return buffer_1.Buffer.from(blockhash);
|
|
315
|
-
});
|
|
268
|
+
async isSignatureValid(swapData, timeout, prefix, signature, feeRate, preFetchedData) {
|
|
269
|
+
const sender = swapData.isPayIn() ? swapData.offerer : swapData.claimer;
|
|
270
|
+
const signer = swapData.isPayIn() ? swapData.claimer : swapData.offerer;
|
|
271
|
+
if (!swapData.isPayIn() && await this.root.isExpired(sender.toString(), swapData)) {
|
|
272
|
+
throw new base_1.SignatureVerificationError("Swap will expire too soon!");
|
|
273
|
+
}
|
|
274
|
+
if (prefix !== this.getAuthPrefix(swapData))
|
|
275
|
+
throw new base_1.SignatureVerificationError("Invalid prefix");
|
|
276
|
+
const currentTimestamp = BigInt(Math.floor(Date.now() / 1000));
|
|
277
|
+
const isExpired = (BigInt(timeout) - currentTimestamp) < BigInt(this.root.authGracePeriod);
|
|
278
|
+
if (isExpired)
|
|
279
|
+
throw new base_1.SignatureVerificationError("Authorization expired!");
|
|
280
|
+
const [transactionSlot, signatureString] = signature.split(";");
|
|
281
|
+
const txSlot = parseInt(transactionSlot);
|
|
282
|
+
const [latestSlot, blockhash] = await Promise.all([
|
|
283
|
+
this.getSlotForSignature(preFetchedData),
|
|
284
|
+
this.getBlockhashForSignature(txSlot, preFetchedData)
|
|
285
|
+
]);
|
|
286
|
+
const lastValidTransactionSlot = txSlot + this.root.TX_SLOT_VALIDITY;
|
|
287
|
+
const slotsLeft = lastValidTransactionSlot - latestSlot - this.SIGNATURE_SLOT_BUFFER;
|
|
288
|
+
if (slotsLeft < 0)
|
|
289
|
+
throw new base_1.SignatureVerificationError("Authorization expired!");
|
|
290
|
+
const txToSign = await this.getTxToSign(swapData, timeout, feeRate);
|
|
291
|
+
txToSign.feePayer = sender;
|
|
292
|
+
txToSign.recentBlockhash = blockhash;
|
|
293
|
+
txToSign.addSignature(signer, buffer_1.Buffer.from(signatureString, "hex"));
|
|
294
|
+
this.logger.debug("isSignatureValid(): Signed tx: ", txToSign);
|
|
295
|
+
const valid = txToSign.verifySignatures(false);
|
|
296
|
+
if (!valid)
|
|
297
|
+
throw new base_1.SignatureVerificationError("Invalid signature!");
|
|
298
|
+
return buffer_1.Buffer.from(blockhash);
|
|
316
299
|
}
|
|
317
300
|
/**
|
|
318
301
|
* Gets expiry of the provided signature data, this is a minimum of slot expiry & swap signature expiry
|
|
@@ -322,21 +305,19 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
322
305
|
* @param preFetchedData
|
|
323
306
|
* @public
|
|
324
307
|
*/
|
|
325
|
-
getSignatureExpiry(timeout, signature, preFetchedData) {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
return expiry;
|
|
339
|
-
});
|
|
308
|
+
async getSignatureExpiry(timeout, signature, preFetchedData) {
|
|
309
|
+
const [transactionSlotStr, signatureString] = signature.split(";");
|
|
310
|
+
const txSlot = parseInt(transactionSlotStr);
|
|
311
|
+
const latestSlot = await this.getSlotForSignature(preFetchedData);
|
|
312
|
+
const lastValidTransactionSlot = txSlot + this.root.TX_SLOT_VALIDITY;
|
|
313
|
+
const slotsLeft = lastValidTransactionSlot - latestSlot - this.SIGNATURE_SLOT_BUFFER;
|
|
314
|
+
const now = Date.now();
|
|
315
|
+
const slotExpiryTime = now + (slotsLeft * this.root.SLOT_TIME);
|
|
316
|
+
const timeoutExpiryTime = (parseInt(timeout) - this.root.authGracePeriod) * 1000;
|
|
317
|
+
const expiry = Math.min(slotExpiryTime, timeoutExpiryTime);
|
|
318
|
+
if (expiry < now)
|
|
319
|
+
return 0;
|
|
320
|
+
return expiry;
|
|
340
321
|
}
|
|
341
322
|
/**
|
|
342
323
|
* Checks whether signature is expired for good (uses "finalized" slot)
|
|
@@ -345,19 +326,17 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
345
326
|
* @param timeout
|
|
346
327
|
* @public
|
|
347
328
|
*/
|
|
348
|
-
isSignatureExpired(signature, timeout) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
return false;
|
|
360
|
-
});
|
|
329
|
+
async isSignatureExpired(signature, timeout) {
|
|
330
|
+
const [transactionSlotStr, signatureString] = signature.split(";");
|
|
331
|
+
const txSlot = parseInt(transactionSlotStr);
|
|
332
|
+
const lastValidTransactionSlot = txSlot + this.root.TX_SLOT_VALIDITY;
|
|
333
|
+
const latestSlot = await this.root.Slots.getSlot("finalized");
|
|
334
|
+
const slotsLeft = lastValidTransactionSlot - latestSlot + this.SIGNATURE_SLOT_BUFFER;
|
|
335
|
+
if (slotsLeft < 0)
|
|
336
|
+
return true;
|
|
337
|
+
if ((parseInt(timeout) + this.root.authGracePeriod) * 1000 < Date.now())
|
|
338
|
+
return true;
|
|
339
|
+
return false;
|
|
361
340
|
}
|
|
362
341
|
/**
|
|
363
342
|
* Creates init transaction (InitPayIn) with a valid signature from an LP, also adds a SOL to WSOL wrapping ix to
|
|
@@ -371,38 +350,36 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
371
350
|
* @param skipChecks whether to skip signature validity checks
|
|
372
351
|
* @param feeRate fee rate to use for the transaction
|
|
373
352
|
*/
|
|
374
|
-
txsInitPayIn(swapData, timeout, prefix, signature, skipChecks, feeRate) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
isWrapping = true;
|
|
397
|
-
}
|
|
353
|
+
async txsInitPayIn(swapData, timeout, prefix, signature, skipChecks, feeRate) {
|
|
354
|
+
if (!skipChecks) {
|
|
355
|
+
const [_, payStatus] = await Promise.all([
|
|
356
|
+
(0, Utils_1.tryWithRetries)(() => this.isSignatureValid(swapData, timeout, prefix, signature, feeRate), this.retryPolicy, (e) => e instanceof base_1.SignatureVerificationError),
|
|
357
|
+
(0, Utils_1.tryWithRetries)(() => this.root.getClaimHashStatus(swapData.getClaimHash()), this.retryPolicy)
|
|
358
|
+
]);
|
|
359
|
+
if (payStatus !== base_1.SwapCommitStatus.NOT_COMMITED)
|
|
360
|
+
throw new base_1.SwapDataVerificationError("Invoice already being paid for or paid");
|
|
361
|
+
}
|
|
362
|
+
const [slotNumber, signatureStr] = signature.split(";");
|
|
363
|
+
const block = await (0, Utils_1.tryWithRetries)(() => this.root.Blocks.getParsedBlock(parseInt(slotNumber)), this.retryPolicy);
|
|
364
|
+
const txs = [];
|
|
365
|
+
let isWrapping = false;
|
|
366
|
+
const isWrappedInSignedTx = feeRate != null && feeRate.split("#").length > 1;
|
|
367
|
+
if (!isWrappedInSignedTx && swapData.token.equals(SolanaTokens_1.SolanaTokens.WSOL_ADDRESS)) {
|
|
368
|
+
const ataAcc = await (0, Utils_1.tryWithRetries)(() => this.root.Tokens.getATAOrNull(swapData.offererAta), this.retryPolicy);
|
|
369
|
+
const balance = ataAcc == null ? 0n : ataAcc.amount;
|
|
370
|
+
if (balance < swapData.getAmount()) {
|
|
371
|
+
//Need to wrap more SOL to WSOL
|
|
372
|
+
await this.root.Tokens.Wrap(swapData.offerer, swapData.getAmount() - balance, ataAcc == null)
|
|
373
|
+
.addToTxs(txs, feeRate, block);
|
|
374
|
+
isWrapping = true;
|
|
398
375
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
376
|
+
}
|
|
377
|
+
const initTx = await (await this.InitPayIn(swapData, BigInt(timeout), feeRate)).tx(feeRate, block);
|
|
378
|
+
initTx.tx.addSignature(swapData.claimer, buffer_1.Buffer.from(signatureStr, "hex"));
|
|
379
|
+
txs.push(initTx);
|
|
380
|
+
this.logger.debug("txsInitPayIn(): create swap init TX, swap: " + swapData.getClaimHash() +
|
|
381
|
+
" wrapping client-side: " + isWrapping + " feerate: " + feeRate);
|
|
382
|
+
return txs;
|
|
406
383
|
}
|
|
407
384
|
/**
|
|
408
385
|
* Creates init transactions (InitNotPayIn) with a valid signature from an intermediary
|
|
@@ -414,18 +391,16 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
414
391
|
* @param skipChecks whether to skip signature validity checks
|
|
415
392
|
* @param feeRate fee rate to use for the transaction
|
|
416
393
|
*/
|
|
417
|
-
txsInit(swapData, timeout, prefix, signature, skipChecks, feeRate) {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
return [initTx];
|
|
428
|
-
});
|
|
394
|
+
async txsInit(swapData, timeout, prefix, signature, skipChecks, feeRate) {
|
|
395
|
+
if (!skipChecks) {
|
|
396
|
+
await (0, Utils_1.tryWithRetries)(() => this.isSignatureValid(swapData, timeout, prefix, signature, feeRate), this.retryPolicy, (e) => e instanceof base_1.SignatureVerificationError);
|
|
397
|
+
}
|
|
398
|
+
const [slotNumber, signatureStr] = signature.split(";");
|
|
399
|
+
const block = await (0, Utils_1.tryWithRetries)(() => this.root.Blocks.getParsedBlock(parseInt(slotNumber)), this.retryPolicy);
|
|
400
|
+
const initTx = await (await this.InitNotPayIn(swapData, BigInt(timeout))).tx(feeRate, block);
|
|
401
|
+
initTx.tx.addSignature(swapData.offerer, buffer_1.Buffer.from(signatureStr, "hex"));
|
|
402
|
+
this.logger.debug("txsInit(): create swap init TX, swap: " + swapData.getClaimHash() + " feerate: " + feeRate);
|
|
403
|
+
return [initTx];
|
|
429
404
|
}
|
|
430
405
|
/**
|
|
431
406
|
* Returns the fee rate to be used for a specific init transaction, also adding indication whether the WSOL ATA
|
|
@@ -436,36 +411,34 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
436
411
|
* @param token
|
|
437
412
|
* @param paymentHash
|
|
438
413
|
*/
|
|
439
|
-
getInitPayInFeeRate(offerer, claimer, token, paymentHash) {
|
|
440
|
-
|
|
441
|
-
|
|
414
|
+
async getInitPayInFeeRate(offerer, claimer, token, paymentHash) {
|
|
415
|
+
const accounts = [];
|
|
416
|
+
if (offerer != null)
|
|
417
|
+
accounts.push(offerer);
|
|
418
|
+
if (token != null) {
|
|
419
|
+
accounts.push(this.root.SwapVault(token));
|
|
442
420
|
if (offerer != null)
|
|
443
|
-
accounts.push(offerer);
|
|
444
|
-
if (
|
|
445
|
-
accounts.push(this.root.
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
feeRate += "#" + (account != null ? "0" : "1") + ";" + balance.toString(10);
|
|
465
|
-
}
|
|
466
|
-
this.logger.debug("getInitPayInFeeRate(): feerate computed: " + feeRate);
|
|
467
|
-
return feeRate;
|
|
468
|
-
});
|
|
421
|
+
accounts.push((0, spl_token_1.getAssociatedTokenAddressSync)(token, offerer));
|
|
422
|
+
if (claimer != null)
|
|
423
|
+
accounts.push(this.root.SwapUserVault(claimer, token));
|
|
424
|
+
}
|
|
425
|
+
if (paymentHash != null)
|
|
426
|
+
accounts.push(this.root.SwapEscrowState(buffer_1.Buffer.from(paymentHash, "hex")));
|
|
427
|
+
const shouldCheckWSOLAta = token != null && offerer != null && token.equals(SolanaTokens_1.SolanaTokens.WSOL_ADDRESS);
|
|
428
|
+
let [feeRate, _account] = await Promise.all([
|
|
429
|
+
this.root.Fees.getFeeRate(accounts),
|
|
430
|
+
shouldCheckWSOLAta ?
|
|
431
|
+
this.root.Tokens.getATAOrNull((0, spl_token_1.getAssociatedTokenAddressSync)(token, offerer)) :
|
|
432
|
+
Promise.resolve(null)
|
|
433
|
+
]);
|
|
434
|
+
if (shouldCheckWSOLAta) {
|
|
435
|
+
const account = _account;
|
|
436
|
+
const balance = account == null ? 0n : account.amount;
|
|
437
|
+
//Add an indication about whether the ATA is initialized & balance it contains
|
|
438
|
+
feeRate += "#" + (account != null ? "0" : "1") + ";" + balance.toString(10);
|
|
439
|
+
}
|
|
440
|
+
this.logger.debug("getInitPayInFeeRate(): feerate computed: " + feeRate);
|
|
441
|
+
return feeRate;
|
|
469
442
|
}
|
|
470
443
|
/**
|
|
471
444
|
* Returns the fee rate to be used for a specific init transaction
|
|
@@ -489,50 +462,46 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
489
462
|
* Get the estimated solana fee of the init transaction, this includes the required deposit for creating swap PDA
|
|
490
463
|
* and also deposit for ATAs
|
|
491
464
|
*/
|
|
492
|
-
getInitFee(swapData, feeRate) {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
(swapData.
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
swapData
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
return resultingFee;
|
|
513
|
-
});
|
|
465
|
+
async getInitFee(swapData, feeRate) {
|
|
466
|
+
if (swapData == null)
|
|
467
|
+
return BigInt(this.root.ESCROW_STATE_RENT_EXEMPT) + await this.getRawInitFee(swapData, feeRate);
|
|
468
|
+
feeRate = feeRate ||
|
|
469
|
+
(swapData.payIn
|
|
470
|
+
? await this.getInitPayInFeeRate(swapData.offerer, swapData.claimer, swapData.token, swapData.paymentHash)
|
|
471
|
+
: await this.getInitFeeRate(swapData.offerer, swapData.claimer, swapData.token, swapData.paymentHash));
|
|
472
|
+
const [rawFee, initAta] = await Promise.all([
|
|
473
|
+
this.getRawInitFee(swapData, feeRate),
|
|
474
|
+
swapData != null && swapData.payOut ?
|
|
475
|
+
this.root.Tokens.getATAOrNull((0, spl_token_1.getAssociatedTokenAddressSync)(swapData.token, swapData.claimer)).then(acc => acc == null) :
|
|
476
|
+
Promise.resolve(null)
|
|
477
|
+
]);
|
|
478
|
+
let resultingFee = BigInt(this.root.ESCROW_STATE_RENT_EXEMPT) + rawFee;
|
|
479
|
+
if (initAta)
|
|
480
|
+
resultingFee += BigInt(SolanaTokens_1.SolanaTokens.SPL_ATA_RENT_EXEMPT);
|
|
481
|
+
if (swapData.payIn && this.shouldWrapOnInit(swapData, feeRate) && this.extractAtaDataFromFeeRate(feeRate).initAta) {
|
|
482
|
+
resultingFee += BigInt(SolanaTokens_1.SolanaTokens.SPL_ATA_RENT_EXEMPT);
|
|
483
|
+
}
|
|
484
|
+
return resultingFee;
|
|
514
485
|
}
|
|
515
486
|
/**
|
|
516
487
|
* Get the estimated solana fee of the init transaction, without the required deposit for creating swap PDA
|
|
517
488
|
*/
|
|
518
|
-
getRawInitFee(swapData, feeRate) {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
(swapData.
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
return new BN(baseFee).add(this.root.Fees.getPriorityFee(computeBudget, feeRate));
|
|
535
|
-
});
|
|
489
|
+
async getRawInitFee(swapData, feeRate) {
|
|
490
|
+
if (swapData == null)
|
|
491
|
+
return 10000n;
|
|
492
|
+
feeRate = feeRate ||
|
|
493
|
+
(swapData.payIn
|
|
494
|
+
? await this.getInitPayInFeeRate(swapData.offerer, swapData.claimer, swapData.token, swapData.paymentHash)
|
|
495
|
+
: await this.getInitFeeRate(swapData.offerer, swapData.claimer, swapData.token, swapData.paymentHash));
|
|
496
|
+
let computeBudget = swapData.payIn ? SwapInit.CUCosts.INIT_PAY_IN : SwapInit.CUCosts.INIT;
|
|
497
|
+
if (swapData.payIn && this.shouldWrapOnInit(swapData, feeRate)) {
|
|
498
|
+
computeBudget += SolanaTokens_1.SolanaTokens.CUCosts.WRAP_SOL;
|
|
499
|
+
const data = this.extractAtaDataFromFeeRate(feeRate);
|
|
500
|
+
if (data.initAta)
|
|
501
|
+
computeBudget += SolanaTokens_1.SolanaTokens.CUCosts.ATA_INIT;
|
|
502
|
+
}
|
|
503
|
+
const baseFee = swapData.payIn ? 10000n : 10000n + 5000n;
|
|
504
|
+
return baseFee + this.root.Fees.getPriorityFee(computeBudget, feeRate);
|
|
536
505
|
}
|
|
537
506
|
}
|
|
538
507
|
exports.SwapInit = SwapInit;
|