@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,4 +1,3 @@
|
|
|
1
|
-
import * as BN from "bn.js";
|
|
2
1
|
import {
|
|
3
2
|
ComputeBudgetProgram,
|
|
4
3
|
Connection,
|
|
@@ -16,26 +15,26 @@ const MAX_FEE_AGE = 5000;
|
|
|
16
15
|
export type FeeBribeData = {
|
|
17
16
|
address: string,
|
|
18
17
|
endpoint: string,
|
|
19
|
-
getBribeFee?: (original:
|
|
18
|
+
getBribeFee?: (original: bigint) => bigint
|
|
20
19
|
};
|
|
21
20
|
|
|
22
21
|
export class SolanaFees {
|
|
23
22
|
|
|
24
23
|
private readonly connection: Connection;
|
|
25
|
-
private readonly maxFeeMicroLamports:
|
|
24
|
+
private readonly maxFeeMicroLamports: bigint;
|
|
26
25
|
private readonly numSamples: number;
|
|
27
26
|
private readonly period: number;
|
|
28
27
|
private useHeliusApi: "yes" | "no" | "auto";
|
|
29
28
|
private heliusApiSupported: boolean = true;
|
|
30
29
|
private readonly heliusFeeLevel: "min" | "low" | "medium" | "high" | "veryHigh" | "unsafeMax";
|
|
31
30
|
private readonly bribeData?: FeeBribeData;
|
|
32
|
-
private readonly getStaticFee?: (original:
|
|
31
|
+
private readonly getStaticFee?: (original: bigint) => bigint;
|
|
33
32
|
|
|
34
33
|
private readonly logger = getLogger("SolanaFees: ");
|
|
35
34
|
|
|
36
35
|
private blockFeeCache: {
|
|
37
36
|
timestamp: number,
|
|
38
|
-
feeRate: Promise<
|
|
37
|
+
feeRate: Promise<bigint>
|
|
39
38
|
} = null;
|
|
40
39
|
|
|
41
40
|
constructor(
|
|
@@ -45,11 +44,11 @@ export class SolanaFees {
|
|
|
45
44
|
period: number = 150,
|
|
46
45
|
useHeliusApi: "yes" | "no" | "auto" = "auto",
|
|
47
46
|
heliusFeeLevel: "min" | "low" | "medium" | "high" | "veryHigh" | "unsafeMax" = "veryHigh",
|
|
48
|
-
getStaticFee?: (feeRate:
|
|
47
|
+
getStaticFee?: (feeRate: bigint) => bigint,
|
|
49
48
|
bribeData?: FeeBribeData,
|
|
50
49
|
) {
|
|
51
50
|
this.connection = connection;
|
|
52
|
-
this.maxFeeMicroLamports =
|
|
51
|
+
this.maxFeeMicroLamports = BigInt(maxFeeMicroLamports);
|
|
53
52
|
this.numSamples = numSamples;
|
|
54
53
|
this.period = period;
|
|
55
54
|
this.useHeliusApi = useHeliusApi;
|
|
@@ -172,7 +171,7 @@ export class SolanaFees {
|
|
|
172
171
|
* @param parsedTx
|
|
173
172
|
* @private
|
|
174
173
|
*/
|
|
175
|
-
private getJitoTxFee(parsedTx: Transaction):
|
|
174
|
+
private getJitoTxFee(parsedTx: Transaction): bigint | null {
|
|
176
175
|
const lastIx = parsedTx.instructions[parsedTx.instructions.length-1];
|
|
177
176
|
|
|
178
177
|
if(!lastIx.programId.equals(SystemProgram.programId)) return null;
|
|
@@ -180,7 +179,7 @@ export class SolanaFees {
|
|
|
180
179
|
|
|
181
180
|
const decodedIxData = SystemInstruction.decodeTransfer(lastIx);
|
|
182
181
|
if(decodedIxData.toPubkey.toBase58()!==this.bribeData?.address) return null;
|
|
183
|
-
return
|
|
182
|
+
return decodedIxData.lamports;
|
|
184
183
|
}
|
|
185
184
|
|
|
186
185
|
/**
|
|
@@ -189,21 +188,21 @@ export class SolanaFees {
|
|
|
189
188
|
* @param slot
|
|
190
189
|
* @private
|
|
191
190
|
*/
|
|
192
|
-
private async getBlockMeanFeeRate(slot: number): Promise<
|
|
191
|
+
private async getBlockMeanFeeRate(slot: number): Promise<bigint | null> {
|
|
193
192
|
const block = await this.getBlockWithSignature(slot);
|
|
194
193
|
if(block==null) return null;
|
|
195
194
|
|
|
196
195
|
const blockComission = block.rewards.find(e => e.rewardType==="Fee");
|
|
197
|
-
const totalBlockFees =
|
|
196
|
+
const totalBlockFees: bigint = BigInt(blockComission.lamports) * 2n;
|
|
198
197
|
|
|
199
198
|
//Subtract per-signature fees to get pure compute fees
|
|
200
|
-
const totalTransactionBaseFees =
|
|
201
|
-
const computeFees = totalBlockFees
|
|
199
|
+
const totalTransactionBaseFees = BigInt(block.signatures.length) * 5000n;
|
|
200
|
+
const computeFees = totalBlockFees - totalTransactionBaseFees;
|
|
202
201
|
|
|
203
202
|
//Total compute fees in micro lamports
|
|
204
|
-
const computeFeesMicroLamports = computeFees
|
|
203
|
+
const computeFeesMicroLamports = computeFees * 1000000n;
|
|
205
204
|
//micro lamports per CU considering block was full (48M compute units)
|
|
206
|
-
const perCUMicroLamports = computeFeesMicroLamports
|
|
205
|
+
const perCUMicroLamports = computeFeesMicroLamports / 48000000n;
|
|
207
206
|
|
|
208
207
|
this.logger.debug("getBlockMeanFeeRate(): slot: "+slot+" total reward: "+totalBlockFees.toString(10)+
|
|
209
208
|
" total transactions: "+block.signatures.length+" computed fee: "+perCUMicroLamports);
|
|
@@ -217,7 +216,7 @@ export class SolanaFees {
|
|
|
217
216
|
* @private
|
|
218
217
|
* @returns {Promise<BN>} sampled mean microLamports/CU fee over the last period
|
|
219
218
|
*/
|
|
220
|
-
private async _getGlobalFeeRate(): Promise<
|
|
219
|
+
private async _getGlobalFeeRate(): Promise<bigint> {
|
|
221
220
|
let slot = await this.connection.getSlot();
|
|
222
221
|
|
|
223
222
|
const slots: number[] = [];
|
|
@@ -226,10 +225,10 @@ export class SolanaFees {
|
|
|
226
225
|
slots.push(slot-i);
|
|
227
226
|
}
|
|
228
227
|
|
|
229
|
-
const promises: Promise<
|
|
228
|
+
const promises: Promise<bigint>[] = [];
|
|
230
229
|
for(let i=0;i<this.numSamples;i++) {
|
|
231
230
|
promises.push((async () => {
|
|
232
|
-
let feeRate:
|
|
231
|
+
let feeRate: bigint = null;
|
|
233
232
|
while(feeRate==null) {
|
|
234
233
|
if(slots.length===0) throw new Error("Ran out of slots to check!");
|
|
235
234
|
const index = Math.floor(Math.random()*slots.length);
|
|
@@ -244,7 +243,7 @@ export class SolanaFees {
|
|
|
244
243
|
const meanFees = await Promise.all(promises);
|
|
245
244
|
|
|
246
245
|
let min = null;
|
|
247
|
-
meanFees.forEach(e => min==null
|
|
246
|
+
meanFees.forEach(e => min==null || min > e ? min = e : 0);
|
|
248
247
|
|
|
249
248
|
if(min!=null) this.logger.debug("_getGlobalFeeRate(): slot: "+slot+" global fee minimum: "+min.toString(10));
|
|
250
249
|
|
|
@@ -257,13 +256,15 @@ export class SolanaFees {
|
|
|
257
256
|
* @param mutableAccounts
|
|
258
257
|
* @private
|
|
259
258
|
*/
|
|
260
|
-
private async _getFeeRate(mutableAccounts: PublicKey[]): Promise<
|
|
259
|
+
private async _getFeeRate(mutableAccounts: PublicKey[]): Promise<bigint> {
|
|
261
260
|
if(this.useHeliusApi==="yes" || (this.useHeliusApi==="auto" && this.heliusApiSupported)) {
|
|
262
261
|
//Try to use getPriorityFeeEstimate api of Helius
|
|
263
262
|
const fees = await this.getPriorityFeeEstimate(mutableAccounts);
|
|
264
263
|
if(fees!=null) {
|
|
265
|
-
|
|
266
|
-
|
|
264
|
+
let calculatedFee = BigInt(fees[this.heliusFeeLevel]);
|
|
265
|
+
if(calculatedFee < 8000n) calculatedFee = 8000n;
|
|
266
|
+
if(calculatedFee > this.maxFeeMicroLamports) calculatedFee = this.maxFeeMicroLamports;
|
|
267
|
+
return calculatedFee;
|
|
267
268
|
}
|
|
268
269
|
this.logger.warn("_getFeeRate(): tried fetching fees from Helius API, not supported," +
|
|
269
270
|
" falling back to client-side fee estimation");
|
|
@@ -280,13 +281,16 @@ export class SolanaFees {
|
|
|
280
281
|
const data = resp[resp.length-i-1];
|
|
281
282
|
if(data!=null) lamports = Math.min(lamports, data.prioritizationFee);
|
|
282
283
|
}
|
|
283
|
-
return
|
|
284
|
+
return BigInt(lamports);
|
|
284
285
|
})
|
|
285
286
|
]);
|
|
286
287
|
|
|
287
|
-
|
|
288
|
+
let fee = globalFeeRate;
|
|
289
|
+
if(fee < localFeeRate) fee = localFeeRate;
|
|
290
|
+
if(fee < 8000n) fee = 8000n;
|
|
291
|
+
if(fee > this.maxFeeMicroLamports) fee = this.maxFeeMicroLamports;
|
|
288
292
|
|
|
289
|
-
return
|
|
293
|
+
return fee;
|
|
290
294
|
}
|
|
291
295
|
|
|
292
296
|
/**
|
|
@@ -294,7 +298,7 @@ export class SolanaFees {
|
|
|
294
298
|
*
|
|
295
299
|
* @returns {Promise<BN>} global fee rate microLamports/CU
|
|
296
300
|
*/
|
|
297
|
-
public getGlobalFeeRate(): Promise<
|
|
301
|
+
public getGlobalFeeRate(): Promise<bigint> {
|
|
298
302
|
if(this.blockFeeCache==null || Date.now() - this.blockFeeCache.timestamp > MAX_FEE_AGE) {
|
|
299
303
|
let obj = {
|
|
300
304
|
timestamp: Date.now(),
|
|
@@ -344,8 +348,8 @@ export class SolanaFees {
|
|
|
344
348
|
* @param feeRate
|
|
345
349
|
* @param includeStaticFee whether the include the static/base part of the fee rate
|
|
346
350
|
*/
|
|
347
|
-
public getPriorityFee(computeUnits: number, feeRate: string, includeStaticFee: boolean = true):
|
|
348
|
-
if(feeRate==null) return
|
|
351
|
+
public getPriorityFee(computeUnits: number, feeRate: string, includeStaticFee: boolean = true): bigint {
|
|
352
|
+
if(feeRate==null) return 0n;
|
|
349
353
|
|
|
350
354
|
const hashArr = feeRate.split("#");
|
|
351
355
|
if(hashArr.length>1) {
|
|
@@ -353,10 +357,10 @@ export class SolanaFees {
|
|
|
353
357
|
}
|
|
354
358
|
|
|
355
359
|
const arr = feeRate.split(";");
|
|
356
|
-
const cuPrice =
|
|
357
|
-
const staticFee = includeStaticFee ?
|
|
360
|
+
const cuPrice = BigInt(arr[0]);
|
|
361
|
+
const staticFee = includeStaticFee ? BigInt(arr[1]) : 0n;
|
|
358
362
|
|
|
359
|
-
return staticFee
|
|
363
|
+
return staticFee + (cuPrice * BigInt(computeUnits) / 1000000n);
|
|
360
364
|
}
|
|
361
365
|
|
|
362
366
|
/**
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
getAccount, getAssociatedTokenAddressSync,
|
|
7
7
|
TokenAccountNotFoundError
|
|
8
8
|
} from "@solana/spl-token";
|
|
9
|
-
import * as BN from "bn.js";
|
|
10
9
|
import {SolanaTx} from "./SolanaTransactions";
|
|
11
10
|
import {SolanaAction} from "../SolanaAction";
|
|
12
11
|
import {tryWithRetries} from "../../../utils/Utils";
|
|
@@ -55,18 +54,18 @@ export class SolanaTokens extends SolanaModule {
|
|
|
55
54
|
* @param initAta whether we should also initialize the ATA before depositing SOL
|
|
56
55
|
* @constructor
|
|
57
56
|
*/
|
|
58
|
-
public Wrap(publicKey: PublicKey, amount:
|
|
59
|
-
const ata = getAssociatedTokenAddressSync(
|
|
57
|
+
public Wrap(publicKey: PublicKey, amount: bigint, initAta: boolean): SolanaAction {
|
|
58
|
+
const ata = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, publicKey, true);
|
|
60
59
|
const action = new SolanaAction(publicKey, this.root);
|
|
61
60
|
if(initAta) action.addIx(
|
|
62
|
-
createAssociatedTokenAccountInstruction(publicKey, ata, publicKey,
|
|
61
|
+
createAssociatedTokenAccountInstruction(publicKey, ata, publicKey, SolanaTokens.WSOL_ADDRESS),
|
|
63
62
|
SolanaTokens.CUCosts.ATA_INIT
|
|
64
63
|
);
|
|
65
64
|
action.addIx(
|
|
66
65
|
SystemProgram.transfer({
|
|
67
66
|
fromPubkey: publicKey,
|
|
68
67
|
toPubkey: ata,
|
|
69
|
-
lamports:
|
|
68
|
+
lamports: amount
|
|
70
69
|
}),
|
|
71
70
|
SolanaTokens.CUCosts.WRAP_SOL
|
|
72
71
|
);
|
|
@@ -81,7 +80,7 @@ export class SolanaTokens extends SolanaModule {
|
|
|
81
80
|
* @constructor
|
|
82
81
|
*/
|
|
83
82
|
public Unwrap(publicKey: PublicKey): SolanaAction {
|
|
84
|
-
const ata = getAssociatedTokenAddressSync(
|
|
83
|
+
const ata = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, publicKey, true);
|
|
85
84
|
return new SolanaAction(
|
|
86
85
|
publicKey,
|
|
87
86
|
this.root,
|
|
@@ -90,8 +89,8 @@ export class SolanaTokens extends SolanaModule {
|
|
|
90
89
|
);
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
public readonly WSOL_ADDRESS = new PublicKey("So11111111111111111111111111111111111111112");
|
|
94
|
-
public readonly SPL_ATA_RENT_EXEMPT = 2039280;
|
|
92
|
+
public static readonly WSOL_ADDRESS = new PublicKey("So11111111111111111111111111111111111111112");
|
|
93
|
+
public static readonly SPL_ATA_RENT_EXEMPT = 2039280;
|
|
95
94
|
|
|
96
95
|
/**
|
|
97
96
|
* Action for transferring the native SOL token, uses provider's public key as a sender
|
|
@@ -102,12 +101,12 @@ export class SolanaTokens extends SolanaModule {
|
|
|
102
101
|
* @constructor
|
|
103
102
|
* @private
|
|
104
103
|
*/
|
|
105
|
-
private SolTransfer(signer: PublicKey, recipient: PublicKey, amount:
|
|
104
|
+
private SolTransfer(signer: PublicKey, recipient: PublicKey, amount: bigint): SolanaAction {
|
|
106
105
|
return new SolanaAction(signer, this.root,
|
|
107
106
|
SystemProgram.transfer({
|
|
108
107
|
fromPubkey: signer,
|
|
109
108
|
toPubkey: recipient,
|
|
110
|
-
lamports:
|
|
109
|
+
lamports: amount
|
|
111
110
|
}),
|
|
112
111
|
SolanaTokens.CUCosts.TRANSFER_SOL
|
|
113
112
|
);
|
|
@@ -123,7 +122,7 @@ export class SolanaTokens extends SolanaModule {
|
|
|
123
122
|
* @constructor
|
|
124
123
|
* @private
|
|
125
124
|
*/
|
|
126
|
-
private Transfer(signer: PublicKey, recipient: PublicKey, token: PublicKey, amount:
|
|
125
|
+
private Transfer(signer: PublicKey, recipient: PublicKey, token: PublicKey, amount: bigint): SolanaAction {
|
|
127
126
|
const srcAta = getAssociatedTokenAddressSync(token, signer, true)
|
|
128
127
|
const dstAta = getAssociatedTokenAddressSync(token, recipient, true);
|
|
129
128
|
return new SolanaAction(signer, this.root,
|
|
@@ -131,7 +130,7 @@ export class SolanaTokens extends SolanaModule {
|
|
|
131
130
|
srcAta,
|
|
132
131
|
dstAta,
|
|
133
132
|
signer,
|
|
134
|
-
|
|
133
|
+
amount
|
|
135
134
|
),
|
|
136
135
|
SolanaTokens.CUCosts.TRANSFER
|
|
137
136
|
);
|
|
@@ -146,8 +145,8 @@ export class SolanaTokens extends SolanaModule {
|
|
|
146
145
|
* @param feeRate fee rate to use for the transactions
|
|
147
146
|
* @private
|
|
148
147
|
*/
|
|
149
|
-
private async txsTransferSol(signer: PublicKey, amount:
|
|
150
|
-
const wsolAta = getAssociatedTokenAddressSync(
|
|
148
|
+
private async txsTransferSol(signer: PublicKey, amount: bigint, recipient: PublicKey, feeRate?: string): Promise<SolanaTx[]> {
|
|
149
|
+
const wsolAta = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, signer, true);
|
|
151
150
|
|
|
152
151
|
const shouldUnwrap = await this.ataExists(wsolAta);
|
|
153
152
|
const action = new SolanaAction(signer, this.root);
|
|
@@ -175,7 +174,7 @@ export class SolanaTokens extends SolanaModule {
|
|
|
175
174
|
* @param feeRate fee rate to use for the transactions
|
|
176
175
|
* @private
|
|
177
176
|
*/
|
|
178
|
-
private async txsTransferTokens(signer: PublicKey, token: PublicKey, amount:
|
|
177
|
+
private async txsTransferTokens(signer: PublicKey, token: PublicKey, amount: bigint, recipient: PublicKey, feeRate?: string) {
|
|
179
178
|
const srcAta = getAssociatedTokenAddressSync(token, signer, true);
|
|
180
179
|
const dstAta = getAssociatedTokenAddressSync(token, recipient, true);
|
|
181
180
|
|
|
@@ -238,8 +237,8 @@ export class SolanaTokens extends SolanaModule {
|
|
|
238
237
|
/**
|
|
239
238
|
* Returns the rent exempt deposit required to initiate the ATA
|
|
240
239
|
*/
|
|
241
|
-
public getATARentExemptLamports(): Promise<
|
|
242
|
-
return Promise.resolve(
|
|
240
|
+
public getATARentExemptLamports(): Promise<bigint> {
|
|
241
|
+
return Promise.resolve(BigInt(SolanaTokens.SPL_ATA_RENT_EXEMPT));
|
|
243
242
|
}
|
|
244
243
|
|
|
245
244
|
/**
|
|
@@ -248,23 +247,23 @@ export class SolanaTokens extends SolanaModule {
|
|
|
248
247
|
* @param publicKey
|
|
249
248
|
* @param token
|
|
250
249
|
*/
|
|
251
|
-
public async getTokenBalance(publicKey: PublicKey, token: PublicKey): Promise<{balance:
|
|
250
|
+
public async getTokenBalance(publicKey: PublicKey, token: PublicKey): Promise<{balance: bigint, ataExists: boolean}> {
|
|
252
251
|
const ata: PublicKey = getAssociatedTokenAddressSync(token, publicKey, true);
|
|
253
252
|
const [ataAccount, balance] = await Promise.all<[Promise<Account>, Promise<number>]>([
|
|
254
253
|
this.getATAOrNull(ata),
|
|
255
|
-
(token!=null && token.equals(
|
|
254
|
+
(token!=null && token.equals(SolanaTokens.WSOL_ADDRESS)) ? this.connection.getBalance(publicKey) : Promise.resolve(null)
|
|
256
255
|
]);
|
|
257
256
|
|
|
258
257
|
let ataExists: boolean = ataAccount!=null;
|
|
259
|
-
let sum:
|
|
258
|
+
let sum: bigint = 0n;
|
|
260
259
|
if(ataExists) {
|
|
261
|
-
sum
|
|
260
|
+
sum += ataAccount.amount;
|
|
262
261
|
}
|
|
263
262
|
|
|
264
263
|
if(balance!=null) {
|
|
265
|
-
let balanceLamports:
|
|
266
|
-
if(!ataExists) balanceLamports = balanceLamports
|
|
267
|
-
if(
|
|
264
|
+
let balanceLamports: bigint = BigInt(balance);
|
|
265
|
+
if(!ataExists) balanceLamports = balanceLamports - await this.getATARentExemptLamports();
|
|
266
|
+
if(balanceLamports >= 0n) sum += balanceLamports;
|
|
268
267
|
}
|
|
269
268
|
|
|
270
269
|
this.logger.debug("getTokenBalance(): token balance fetched, token: "+token.toString()+
|
|
@@ -277,7 +276,7 @@ export class SolanaTokens extends SolanaModule {
|
|
|
277
276
|
* Returns the native currency address, we use WSOL address as placeholder for SOL
|
|
278
277
|
*/
|
|
279
278
|
public getNativeCurrencyAddress(): PublicKey {
|
|
280
|
-
return
|
|
279
|
+
return SolanaTokens.WSOL_ADDRESS;
|
|
281
280
|
}
|
|
282
281
|
|
|
283
282
|
/**
|
|
@@ -299,8 +298,8 @@ export class SolanaTokens extends SolanaModule {
|
|
|
299
298
|
* @param dstAddress destination address of the recipient
|
|
300
299
|
* @param feeRate fee rate to use for the transaction
|
|
301
300
|
*/
|
|
302
|
-
public txsTransfer(signer:PublicKey, token: PublicKey, amount:
|
|
303
|
-
if(
|
|
301
|
+
public txsTransfer(signer:PublicKey, token: PublicKey, amount: bigint, dstAddress: PublicKey, feeRate?: string): Promise<SolanaTx[]> {
|
|
302
|
+
if(SolanaTokens.WSOL_ADDRESS.equals(token)) {
|
|
304
303
|
return this.txsTransferSol(signer, amount, dstAddress, feeRate);
|
|
305
304
|
}
|
|
306
305
|
return this.txsTransferTokens(signer, token, amount, dstAddress, feeRate);
|
|
@@ -223,7 +223,7 @@ export class SolanaTransactions extends SolanaModule {
|
|
|
223
223
|
* optionally waits for confirmation of a batch of solana transactions
|
|
224
224
|
*
|
|
225
225
|
* @param signer
|
|
226
|
-
* @param
|
|
226
|
+
* @param _txs
|
|
227
227
|
* @param waitForConfirmation whether to wait for transaction confirmations (this also makes sure the transactions
|
|
228
228
|
* are re-sent at regular intervals)
|
|
229
229
|
* @param abortSignal abort signal to abort waiting for transaction confirmations
|
|
@@ -231,43 +231,48 @@ export class SolanaTransactions extends SolanaModule {
|
|
|
231
231
|
* are executed in order)
|
|
232
232
|
* @param onBeforePublish a callback called before every transaction is published
|
|
233
233
|
*/
|
|
234
|
-
public async sendAndConfirm(signer: SolanaSigner,
|
|
235
|
-
await this.prepareTransactions(signer, txs)
|
|
236
|
-
const signedTxs = await signer.wallet.signAllTransactions(txs.map(e => e.tx));
|
|
237
|
-
signedTxs.forEach((tx, index) => {
|
|
238
|
-
const solTx = txs[index];
|
|
239
|
-
tx.lastValidBlockHeight = solTx.tx.lastValidBlockHeight;
|
|
240
|
-
solTx.tx = tx
|
|
241
|
-
});
|
|
242
|
-
|
|
234
|
+
public async sendAndConfirm(signer: SolanaSigner, _txs: SolanaTx[], waitForConfirmation?: boolean, abortSignal?: AbortSignal, parallel?: boolean, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>): Promise<string[]> {
|
|
243
235
|
const options = {
|
|
244
236
|
skipPreflight: true
|
|
245
237
|
};
|
|
246
238
|
|
|
247
|
-
this.logger.debug("sendAndConfirm(): sending transactions, count: "+
|
|
239
|
+
this.logger.debug("sendAndConfirm(): sending transactions, count: "+_txs.length+
|
|
248
240
|
" waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
|
|
249
241
|
|
|
250
242
|
const signatures: string[] = [];
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
243
|
+
for(let e=0;e<_txs.length;e+=50) {
|
|
244
|
+
const txs = _txs.slice(e, e+50);
|
|
245
|
+
|
|
246
|
+
await this.prepareTransactions(signer, txs)
|
|
247
|
+
const signedTxs = await signer.wallet.signAllTransactions(txs.map(e => e.tx));
|
|
248
|
+
signedTxs.forEach((tx, index) => {
|
|
249
|
+
const solTx = txs[index];
|
|
250
|
+
tx.lastValidBlockHeight = solTx.tx.lastValidBlockHeight;
|
|
251
|
+
solTx.tx = tx
|
|
252
|
+
});
|
|
253
|
+
this.logger.debug("sendAndConfirm(): sending transaction batch ("+e+".."+(e+50)+"), count: "+txs.length);
|
|
254
|
+
|
|
255
|
+
if(parallel) {
|
|
256
|
+
const promises: Promise<void>[] = [];
|
|
257
|
+
for(let solTx of txs) {
|
|
258
|
+
const signature = await this.sendSignedTransaction(solTx, options, onBeforePublish);
|
|
259
|
+
if(waitForConfirmation) promises.push(this.confirmTransaction(solTx, abortSignal, "confirmed"));
|
|
260
|
+
signatures.push(signature);
|
|
261
|
+
}
|
|
262
|
+
if(promises.length>0) await Promise.all(promises);
|
|
263
|
+
} else {
|
|
264
|
+
for(let i=0;i<txs.length;i++) {
|
|
265
|
+
const solTx = txs[i];
|
|
266
|
+
const signature = await this.sendSignedTransaction(solTx, options, onBeforePublish);
|
|
267
|
+
const confirmPromise = this.confirmTransaction(solTx, abortSignal, "confirmed");
|
|
268
|
+
//Don't await the last promise when !waitForConfirmation
|
|
269
|
+
if(i<txs.length-1 || e+50<_txs.length || waitForConfirmation) await confirmPromise;
|
|
270
|
+
signatures.push(signature);
|
|
271
|
+
}
|
|
267
272
|
}
|
|
268
273
|
}
|
|
269
274
|
|
|
270
|
-
this.logger.info("sendAndConfirm(): sent transactions, count: "+
|
|
275
|
+
this.logger.info("sendAndConfirm(): sent transactions, count: "+_txs.length+
|
|
271
276
|
" waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
|
|
272
277
|
|
|
273
278
|
return signatures;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {AnchorProvider} from "@coral-xyz/anchor";
|
|
2
1
|
import {
|
|
3
2
|
Connection,
|
|
4
3
|
PublicKey,
|
|
@@ -12,15 +11,12 @@ import * as programIdl from "./program/programIdl.json";
|
|
|
12
11
|
import {BitcoinRpc, BtcBlock, BtcRelay, StatePredictorUtils} from "@atomiqlabs/base";
|
|
13
12
|
import {MethodsBuilder} from "@coral-xyz/anchor/dist/cjs/program/namespace/methods";
|
|
14
13
|
import {SolanaProgramBase} from "../program/SolanaProgramBase";
|
|
15
|
-
import * as BN from "bn.js";
|
|
16
14
|
import {SolanaAction} from "../base/SolanaAction";
|
|
17
15
|
import {Buffer} from "buffer";
|
|
18
16
|
import {SolanaFees} from "../base/modules/SolanaFees";
|
|
19
17
|
import {SolanaTx} from "../base/modules/SolanaTransactions";
|
|
20
18
|
import {SolanaSigner} from "../wallet/SolanaSigner";
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
-
const BASE_FEE_SOL_PER_BLOCKHEADER = new BN(5000);
|
|
19
|
+
import * as BN from "bn.js";
|
|
24
20
|
|
|
25
21
|
const MAX_CLOSE_IX_PER_TX = 10;
|
|
26
22
|
|
|
@@ -540,15 +536,15 @@ export class SolanaBtcRelay<B extends BtcBlock> extends SolanaProgramBase<any> i
|
|
|
540
536
|
* @param requiredBlockheight
|
|
541
537
|
* @param feeRate
|
|
542
538
|
*/
|
|
543
|
-
public async estimateSynchronizeFee(requiredBlockheight: number, feeRate?: string): Promise<
|
|
539
|
+
public async estimateSynchronizeFee(requiredBlockheight: number, feeRate?: string): Promise<bigint> {
|
|
544
540
|
const tipData = await this.getTipData();
|
|
545
541
|
const currBlockheight = tipData.blockheight;
|
|
546
542
|
|
|
547
543
|
const blockheightDelta = requiredBlockheight-currBlockheight;
|
|
548
544
|
|
|
549
|
-
if(blockheightDelta<=0) return
|
|
545
|
+
if(blockheightDelta<=0) return 0n;
|
|
550
546
|
|
|
551
|
-
const synchronizationFee =
|
|
547
|
+
const synchronizationFee = BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate);
|
|
552
548
|
this.logger.debug("estimateSynchronizeFee(): required blockheight: "+requiredBlockheight+
|
|
553
549
|
" blockheight delta: "+blockheightDelta+" fee: "+synchronizationFee.toString(10));
|
|
554
550
|
|
|
@@ -560,10 +556,10 @@ export class SolanaBtcRelay<B extends BtcBlock> extends SolanaProgramBase<any> i
|
|
|
560
556
|
*
|
|
561
557
|
* @param feeRate
|
|
562
558
|
*/
|
|
563
|
-
public async getFeePerBlock(feeRate?: string): Promise<
|
|
559
|
+
public async getFeePerBlock(feeRate?: string): Promise<bigint> {
|
|
564
560
|
// feeRate = feeRate || await this.getMainFeeRate(null);
|
|
565
561
|
// return BASE_FEE_SOL_PER_BLOCKHEADER.add(this.Fees.getPriorityFee(200000, feeRate, false));
|
|
566
|
-
return
|
|
562
|
+
return 50000n;
|
|
567
563
|
}
|
|
568
564
|
|
|
569
565
|
/**
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {ChainEvents, ClaimEvent, EventListener, InitializeEvent, RefundEvent, SwapEvent} from "@atomiqlabs/base";
|
|
2
2
|
import {SolanaSwapData} from "../swaps/SolanaSwapData";
|
|
3
|
-
import {
|
|
3
|
+
import {IdlEvents} from "@coral-xyz/anchor";
|
|
4
4
|
import {SolanaSwapProgram} from "../swaps/SolanaSwapProgram";
|
|
5
5
|
import {
|
|
6
6
|
getLogger,
|
|
7
|
-
onceAsync, tryWithRetries
|
|
7
|
+
onceAsync, toEscrowHash, tryWithRetries
|
|
8
8
|
} from "../../utils/Utils";
|
|
9
9
|
import {Connection, ParsedTransactionWithMeta, PublicKey} from "@solana/web3.js";
|
|
10
10
|
import * as BN from "bn.js";
|
|
@@ -132,11 +132,11 @@ export class SolanaChainEventsBrowser implements ChainEvents<SolanaSwapData> {
|
|
|
132
132
|
protected parseInitializeEvent(data: IdlEvents<SwapProgram>["InitializeEvent"], eventObject: EventObject): InitializeEvent<SolanaSwapData> {
|
|
133
133
|
const paymentHash: string = Buffer.from(data.hash).toString("hex");
|
|
134
134
|
const txoHash: string = Buffer.from(data.txoHash).toString("hex");
|
|
135
|
-
|
|
135
|
+
const escrowHash = toEscrowHash(paymentHash, data.sequence);
|
|
136
|
+
this.logger.debug("InitializeEvent paymentHash: "+paymentHash+" sequence: "+data.sequence.toString(10)+
|
|
137
|
+
" txoHash: "+txoHash+" escrowHash: "+escrowHash);
|
|
136
138
|
return new InitializeEvent<SolanaSwapData>(
|
|
137
|
-
|
|
138
|
-
data.sequence,
|
|
139
|
-
txoHash,
|
|
139
|
+
escrowHash,
|
|
140
140
|
SwapTypeEnum.toChainSwapType(data.kind),
|
|
141
141
|
onceAsync<SolanaSwapData>(this.getSwapDataGetter(eventObject, txoHash))
|
|
142
142
|
);
|
|
@@ -144,15 +144,19 @@ export class SolanaChainEventsBrowser implements ChainEvents<SolanaSwapData> {
|
|
|
144
144
|
|
|
145
145
|
protected parseRefundEvent(data: IdlEvents<SwapProgram>["RefundEvent"]): RefundEvent<SolanaSwapData> {
|
|
146
146
|
const paymentHash: string = Buffer.from(data.hash).toString("hex");
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
const escrowHash = toEscrowHash(paymentHash, data.sequence);
|
|
148
|
+
this.logger.debug("RefundEvent paymentHash: "+paymentHash+" sequence: "+data.sequence.toString(10)+
|
|
149
|
+
" escrowHash: "+escrowHash);
|
|
150
|
+
return new RefundEvent<SolanaSwapData>(escrowHash);
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
protected parseClaimEvent(data: IdlEvents<SwapProgram>["ClaimEvent"]): ClaimEvent<SolanaSwapData> {
|
|
152
154
|
const secret: string = Buffer.from(data.secret).toString("hex");
|
|
153
155
|
const paymentHash: string = Buffer.from(data.hash).toString("hex");
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
const escrowHash = toEscrowHash(paymentHash, data.sequence);
|
|
157
|
+
this.logger.debug("ClaimEvent paymentHash: "+paymentHash+" sequence: "+data.sequence.toString(10)+
|
|
158
|
+
" secret: "+secret+" escrowHash: "+escrowHash);
|
|
159
|
+
return new ClaimEvent<SolanaSwapData>(escrowHash, secret);
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {SolanaEvents} from "../../base/modules/SolanaEvents";
|
|
2
|
-
import {BorshCoder, DecodeType, Event, EventParser, Idl,
|
|
2
|
+
import {BorshCoder, DecodeType, Event, EventParser, Idl, IdlTypes, Instruction} from "@coral-xyz/anchor";
|
|
3
3
|
import {IdlField, IdlInstruction} from "@coral-xyz/anchor/dist/cjs/idl";
|
|
4
4
|
import {ConfirmedSignatureInfo, ParsedMessage, PartiallyDecodedInstruction, PublicKey} from "@solana/web3.js";
|
|
5
5
|
import {SolanaProgramBase} from "../SolanaProgramBase";
|