@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,7 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { SolanaSwapModule } from "../SolanaSwapModule";
|
|
3
3
|
import { SolanaSwapData } from "../SolanaSwapData";
|
|
4
|
-
import * as BN from "bn.js";
|
|
5
4
|
import { SolanaTx } from "../../base/modules/SolanaTransactions";
|
|
6
5
|
import { Buffer } from "buffer";
|
|
7
6
|
import { SolanaSigner } from "../../wallet/SolanaSigner";
|
|
@@ -75,9 +74,9 @@ export declare class SwapRefund extends SolanaSwapModule {
|
|
|
75
74
|
* Get the estimated solana transaction fee of the refund transaction, in the worst case scenario in case where the
|
|
76
75
|
* ATA needs to be initialized again (i.e. adding the ATA rent exempt lamports to the fee)
|
|
77
76
|
*/
|
|
78
|
-
getRefundFee(swapData: SolanaSwapData, feeRate?: string): Promise<
|
|
77
|
+
getRefundFee(swapData: SolanaSwapData, feeRate?: string): Promise<bigint>;
|
|
79
78
|
/**
|
|
80
79
|
* Get the estimated solana transaction fee of the refund transaction
|
|
81
80
|
*/
|
|
82
|
-
getRawRefundFee(swapData: SolanaSwapData, feeRate?: string): Promise<
|
|
81
|
+
getRawRefundFee(swapData: SolanaSwapData, feeRate?: string): Promise<bigint>;
|
|
83
82
|
}
|
|
@@ -1,25 +1,17 @@
|
|
|
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.SwapRefund = void 0;
|
|
13
4
|
const SolanaSwapModule_1 = require("../SolanaSwapModule");
|
|
14
5
|
const createHash = require("create-hash");
|
|
15
6
|
const tweetnacl_1 = require("tweetnacl");
|
|
16
7
|
const base_1 = require("@atomiqlabs/base");
|
|
17
|
-
const BN = require("bn.js");
|
|
18
8
|
const web3_js_1 = require("@solana/web3.js");
|
|
19
9
|
const spl_token_1 = require("@solana/spl-token");
|
|
20
10
|
const SolanaAction_1 = require("../../base/SolanaAction");
|
|
21
11
|
const Utils_1 = require("../../../utils/Utils");
|
|
22
12
|
const buffer_1 = require("buffer");
|
|
13
|
+
const SolanaTokens_1 = require("../../base/modules/SolanaTokens");
|
|
14
|
+
const BN = require("bn.js");
|
|
23
15
|
class SwapRefund extends SolanaSwapModule_1.SolanaSwapModule {
|
|
24
16
|
/**
|
|
25
17
|
* Action for generic Refund instruction
|
|
@@ -29,30 +21,37 @@ class SwapRefund extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
29
21
|
* @constructor
|
|
30
22
|
* @private
|
|
31
23
|
*/
|
|
32
|
-
Refund(swapData, refundAuthTimeout) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
24
|
+
async Refund(swapData, refundAuthTimeout) {
|
|
25
|
+
const accounts = {
|
|
26
|
+
offerer: swapData.offerer,
|
|
27
|
+
claimer: swapData.claimer,
|
|
28
|
+
escrowState: this.root.SwapEscrowState(buffer_1.Buffer.from(swapData.paymentHash, "hex")),
|
|
29
|
+
claimerUserData: !swapData.payOut ? this.root.SwapUserVault(swapData.claimer, swapData.token) : null,
|
|
30
|
+
ixSysvar: refundAuthTimeout != null ? web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY : null
|
|
31
|
+
};
|
|
32
|
+
const useTimeout = refundAuthTimeout != null ? refundAuthTimeout : 0n;
|
|
33
|
+
if (swapData.isPayIn()) {
|
|
34
|
+
const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(swapData.token, swapData.offerer);
|
|
35
|
+
return new SolanaAction_1.SolanaAction(swapData.offerer, this.root, await this.program.methods
|
|
36
|
+
.offererRefundPayIn((0, Utils_1.toBN)(useTimeout))
|
|
37
|
+
.accounts({
|
|
38
|
+
...accounts,
|
|
39
|
+
offererAta: ata,
|
|
40
|
+
vault: this.root.SwapVault(swapData.token),
|
|
41
|
+
vaultAuthority: this.root.SwapVaultAuthority,
|
|
42
|
+
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID
|
|
43
|
+
})
|
|
44
|
+
.instruction(), SwapRefund.CUCosts.REFUND_PAY_OUT);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
return new SolanaAction_1.SolanaAction(swapData.offerer, this.root, await this.program.methods
|
|
48
|
+
.offererRefund((0, Utils_1.toBN)(useTimeout))
|
|
49
|
+
.accounts({
|
|
50
|
+
...accounts,
|
|
51
|
+
offererUserData: this.root.SwapUserVault(swapData.offerer, swapData.token)
|
|
52
|
+
})
|
|
53
|
+
.instruction(), SwapRefund.CUCosts.REFUND);
|
|
54
|
+
}
|
|
56
55
|
}
|
|
57
56
|
/**
|
|
58
57
|
* Action for refunding with signature, adds the Ed25519 verify instruction
|
|
@@ -64,16 +63,14 @@ class SwapRefund extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
64
63
|
* @constructor
|
|
65
64
|
* @private
|
|
66
65
|
*/
|
|
67
|
-
RefundWithSignature(swapData, timeout, prefix, signature) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return action;
|
|
76
|
-
});
|
|
66
|
+
async RefundWithSignature(swapData, timeout, prefix, signature) {
|
|
67
|
+
const action = new SolanaAction_1.SolanaAction(swapData.offerer, this.root, web3_js_1.Ed25519Program.createInstructionWithPublicKey({
|
|
68
|
+
message: this.getRefundMessage(swapData, prefix, timeout),
|
|
69
|
+
publicKey: swapData.claimer.toBuffer(),
|
|
70
|
+
signature: signature
|
|
71
|
+
}), 0, null, null, true);
|
|
72
|
+
action.addAction(await this.Refund(swapData, BigInt(timeout)));
|
|
73
|
+
return action;
|
|
77
74
|
}
|
|
78
75
|
/**
|
|
79
76
|
* Gets the message to be signed as a refund authorization
|
|
@@ -102,7 +99,7 @@ class SwapRefund extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
102
99
|
*/
|
|
103
100
|
shouldUnwrap(swapData) {
|
|
104
101
|
return swapData.isPayIn() &&
|
|
105
|
-
swapData.token.equals(
|
|
102
|
+
swapData.token.equals(SolanaTokens_1.SolanaTokens.WSOL_ADDRESS) &&
|
|
106
103
|
swapData.offerer.equals(swapData.offerer);
|
|
107
104
|
}
|
|
108
105
|
signSwapRefund(signer, swapData, authorizationTimeout) {
|
|
@@ -123,9 +120,9 @@ class SwapRefund extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
123
120
|
isSignatureValid(swapData, timeout, prefix, signature) {
|
|
124
121
|
if (prefix !== "refund")
|
|
125
122
|
throw new base_1.SignatureVerificationError("Invalid prefix");
|
|
126
|
-
const expiryTimestamp =
|
|
127
|
-
const currentTimestamp =
|
|
128
|
-
const isExpired = expiryTimestamp
|
|
123
|
+
const expiryTimestamp = BigInt(timeout);
|
|
124
|
+
const currentTimestamp = BigInt(Math.floor(Date.now() / 1000));
|
|
125
|
+
const isExpired = (expiryTimestamp - currentTimestamp) < BigInt(this.root.authGracePeriod);
|
|
129
126
|
if (isExpired)
|
|
130
127
|
throw new base_1.SignatureVerificationError("Authorization expired!");
|
|
131
128
|
const signatureBuffer = buffer_1.Buffer.from(signature, "hex");
|
|
@@ -143,31 +140,29 @@ class SwapRefund extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
143
140
|
* @param initAta should initialize ATA if it doesn't exist
|
|
144
141
|
* @param feeRate fee rate to be used for the transactions
|
|
145
142
|
*/
|
|
146
|
-
txsRefund(swapData, check, initAta, feeRate) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return [yield action.tx(feeRate)];
|
|
170
|
-
});
|
|
143
|
+
async txsRefund(swapData, check, initAta, feeRate) {
|
|
144
|
+
if (check && !await (0, Utils_1.tryWithRetries)(() => this.root.isRequestRefundable(swapData.offerer.toString(), swapData), this.retryPolicy)) {
|
|
145
|
+
throw new base_1.SwapDataVerificationError("Not refundable yet!");
|
|
146
|
+
}
|
|
147
|
+
const shouldInitAta = swapData.isPayIn() && !await this.root.Tokens.ataExists(swapData.offererAta);
|
|
148
|
+
if (shouldInitAta && !initAta)
|
|
149
|
+
throw new base_1.SwapDataVerificationError("ATA not initialized");
|
|
150
|
+
if (feeRate == null)
|
|
151
|
+
feeRate = await this.root.getRefundFeeRate(swapData);
|
|
152
|
+
const shouldUnwrap = this.shouldUnwrap(swapData);
|
|
153
|
+
const action = new SolanaAction_1.SolanaAction(swapData.offerer, this.root);
|
|
154
|
+
if (shouldInitAta) {
|
|
155
|
+
const initAction = this.root.Tokens.InitAta(swapData.offerer, swapData.offerer, swapData.token, swapData.offererAta);
|
|
156
|
+
if (initAction == null)
|
|
157
|
+
throw new base_1.SwapDataVerificationError("Invalid claimer token account address");
|
|
158
|
+
action.addAction(initAction);
|
|
159
|
+
}
|
|
160
|
+
action.add(await this.Refund(swapData));
|
|
161
|
+
if (shouldUnwrap)
|
|
162
|
+
action.add(this.root.Tokens.Unwrap(swapData.offerer));
|
|
163
|
+
this.logger.debug("txsRefund(): creating claim transaction, swap: " + swapData.getClaimHash() +
|
|
164
|
+
" initializingAta: " + shouldInitAta + " unwrapping: " + shouldUnwrap);
|
|
165
|
+
return [await action.tx(feeRate)];
|
|
171
166
|
}
|
|
172
167
|
/**
|
|
173
168
|
* Creates transactions required for refunding the swap with authorization signature, also unwraps WSOL to SOL
|
|
@@ -180,34 +175,32 @@ class SwapRefund extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
180
175
|
* @param initAta should initialize ATA if it doesn't exist
|
|
181
176
|
* @param feeRate fee rate to be used for the transactions
|
|
182
177
|
*/
|
|
183
|
-
txsRefundWithAuthorization(swapData, timeout, prefix, signature, check, initAta, feeRate) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
return [yield action.tx(feeRate)];
|
|
210
|
-
});
|
|
178
|
+
async txsRefundWithAuthorization(swapData, timeout, prefix, signature, check, initAta, feeRate) {
|
|
179
|
+
if (check && !await (0, Utils_1.tryWithRetries)(() => this.root.isCommited(swapData), this.retryPolicy)) {
|
|
180
|
+
throw new base_1.SwapDataVerificationError("Not correctly committed");
|
|
181
|
+
}
|
|
182
|
+
await (0, Utils_1.tryWithRetries)(() => this.isSignatureValid(swapData, timeout, prefix, signature), this.retryPolicy, (e) => e instanceof base_1.SignatureVerificationError);
|
|
183
|
+
const shouldInitAta = swapData.isPayIn() && !await this.root.Tokens.ataExists(swapData.offererAta);
|
|
184
|
+
if (shouldInitAta && !initAta)
|
|
185
|
+
throw new base_1.SwapDataVerificationError("ATA not initialized");
|
|
186
|
+
if (feeRate == null)
|
|
187
|
+
feeRate = await this.root.getRefundFeeRate(swapData);
|
|
188
|
+
console.log("[SolanaSwapProgram] txsRefundsWithAuthorization: feeRate: ", feeRate);
|
|
189
|
+
const signatureBuffer = buffer_1.Buffer.from(signature, "hex");
|
|
190
|
+
const shouldUnwrap = this.shouldUnwrap(swapData);
|
|
191
|
+
const action = await this.RefundWithSignature(swapData, timeout, prefix, signatureBuffer);
|
|
192
|
+
if (shouldInitAta) {
|
|
193
|
+
const initAction = this.root.Tokens.InitAta(swapData.offerer, swapData.offerer, swapData.token, swapData.offererAta);
|
|
194
|
+
if (initAction == null)
|
|
195
|
+
throw new base_1.SwapDataVerificationError("Invalid claimer token account address");
|
|
196
|
+
action.addAction(initAction, 1); //Need to add it after the Ed25519 verify IX, but before the actual refund IX
|
|
197
|
+
}
|
|
198
|
+
if (shouldUnwrap)
|
|
199
|
+
action.add(this.root.Tokens.Unwrap(swapData.offerer));
|
|
200
|
+
this.logger.debug("txsRefundWithAuthorization(): creating claim transaction, swap: " + swapData.getClaimHash() +
|
|
201
|
+
" initializingAta: " + shouldInitAta + " unwrapping: " + shouldUnwrap +
|
|
202
|
+
" auth expiry: " + timeout + " signature: " + signature);
|
|
203
|
+
return [await action.tx(feeRate)];
|
|
211
204
|
}
|
|
212
205
|
getRefundFeeRate(swapData) {
|
|
213
206
|
const accounts = [];
|
|
@@ -238,22 +231,19 @@ class SwapRefund extends SolanaSwapModule_1.SolanaSwapModule {
|
|
|
238
231
|
* Get the estimated solana transaction fee of the refund transaction, in the worst case scenario in case where the
|
|
239
232
|
* ATA needs to be initialized again (i.e. adding the ATA rent exempt lamports to the fee)
|
|
240
233
|
*/
|
|
241
|
-
getRefundFee(swapData, feeRate) {
|
|
242
|
-
return
|
|
243
|
-
|
|
244
|
-
});
|
|
234
|
+
async getRefundFee(swapData, feeRate) {
|
|
235
|
+
return BigInt(swapData == null || swapData.payIn ? SolanaTokens_1.SolanaTokens.SPL_ATA_RENT_EXEMPT : 0) +
|
|
236
|
+
await this.getRawRefundFee(swapData, feeRate);
|
|
245
237
|
}
|
|
246
238
|
/**
|
|
247
239
|
* Get the estimated solana transaction fee of the refund transaction
|
|
248
240
|
*/
|
|
249
|
-
getRawRefundFee(swapData, feeRate) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
return new BN(10000).add(this.root.Fees.getPriorityFee(computeBudget, feeRate));
|
|
256
|
-
});
|
|
241
|
+
async getRawRefundFee(swapData, feeRate) {
|
|
242
|
+
if (swapData == null)
|
|
243
|
+
return 10000n;
|
|
244
|
+
feeRate = feeRate || await this.getRefundFeeRate(swapData);
|
|
245
|
+
const computeBudget = swapData.payIn ? SwapRefund.CUCosts.REFUND_PAY_OUT : SwapRefund.CUCosts.REFUND;
|
|
246
|
+
return 10000n + this.root.Fees.getPriorityFee(computeBudget, feeRate);
|
|
257
247
|
}
|
|
258
248
|
}
|
|
259
249
|
exports.SwapRefund = SwapRefund;
|
package/dist/utils/Utils.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PublicKey, Transaction } from "@solana/web3.js";
|
|
2
|
+
import * as BN from "bn.js";
|
|
2
3
|
export declare function timeoutPromise(timeoutMillis: number, abortSignal?: AbortSignal): Promise<void>;
|
|
3
4
|
export declare function onceAsync<T>(executor: () => Promise<T>): () => Promise<T>;
|
|
4
5
|
export declare function getLogger(prefix: string): {
|
|
@@ -41,3 +42,12 @@ export declare class SolanaTxUtils {
|
|
|
41
42
|
*/
|
|
42
43
|
static getTxSize(tx: Transaction, feePayer: PublicKey): number;
|
|
43
44
|
}
|
|
45
|
+
export declare function toClaimHash(paymentHash: string, nonce: bigint, confirmations: number): string;
|
|
46
|
+
export declare function fromClaimHash(claimHash: string): {
|
|
47
|
+
paymentHash: string;
|
|
48
|
+
nonce: BN;
|
|
49
|
+
confirmations: number;
|
|
50
|
+
};
|
|
51
|
+
export declare function toEscrowHash(paymentHash: string, sequence: BN): string;
|
|
52
|
+
export declare function toBN(value: bigint): BN;
|
|
53
|
+
export declare function toBigInt(value: BN): bigint;
|
package/dist/utils/Utils.js
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
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
|
-
exports.SolanaTxUtils = exports.tryWithRetries = exports.getLogger = exports.onceAsync = exports.timeoutPromise = void 0;
|
|
3
|
+
exports.toBigInt = exports.toBN = exports.toEscrowHash = exports.fromClaimHash = exports.toClaimHash = exports.SolanaTxUtils = exports.tryWithRetries = exports.getLogger = exports.onceAsync = exports.timeoutPromise = void 0;
|
|
13
4
|
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
const BN = require("bn.js");
|
|
6
|
+
const buffer_1 = require("buffer");
|
|
7
|
+
const createHash = require("create-hash");
|
|
14
8
|
function timeoutPromise(timeoutMillis, abortSignal) {
|
|
15
9
|
return new Promise((resolve, reject) => {
|
|
16
10
|
const timeout = setTimeout(resolve, timeoutMillis);
|
|
@@ -45,32 +39,30 @@ function getLogger(prefix) {
|
|
|
45
39
|
}
|
|
46
40
|
exports.getLogger = getLogger;
|
|
47
41
|
const logger = getLogger("Utils: ");
|
|
48
|
-
function tryWithRetries(func, retryPolicy, errorAllowed, abortSignal) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return resp;
|
|
59
|
-
}
|
|
60
|
-
catch (e) {
|
|
61
|
-
if (errorAllowed != null && errorAllowed(e))
|
|
62
|
-
throw e;
|
|
63
|
-
err = e;
|
|
64
|
-
logger.error("tryWithRetries(): error on try number: " + i, e);
|
|
65
|
-
}
|
|
66
|
-
if (abortSignal != null && abortSignal.aborted)
|
|
67
|
-
throw new Error("Aborted");
|
|
68
|
-
if (i !== retryPolicy.maxRetries - 1) {
|
|
69
|
-
yield timeoutPromise(retryPolicy.exponential ? retryPolicy.delay * Math.pow(2, i) : retryPolicy.delay, abortSignal);
|
|
70
|
-
}
|
|
42
|
+
async function tryWithRetries(func, retryPolicy, errorAllowed, abortSignal) {
|
|
43
|
+
retryPolicy = retryPolicy || {};
|
|
44
|
+
retryPolicy.maxRetries = retryPolicy.maxRetries || 5;
|
|
45
|
+
retryPolicy.delay = retryPolicy.delay || 500;
|
|
46
|
+
retryPolicy.exponential = retryPolicy.exponential == null ? true : retryPolicy.exponential;
|
|
47
|
+
let err = null;
|
|
48
|
+
for (let i = 0; i < retryPolicy.maxRetries; i++) {
|
|
49
|
+
try {
|
|
50
|
+
const resp = await func();
|
|
51
|
+
return resp;
|
|
71
52
|
}
|
|
72
|
-
|
|
73
|
-
|
|
53
|
+
catch (e) {
|
|
54
|
+
if (errorAllowed != null && errorAllowed(e))
|
|
55
|
+
throw e;
|
|
56
|
+
err = e;
|
|
57
|
+
logger.error("tryWithRetries(): error on try number: " + i, e);
|
|
58
|
+
}
|
|
59
|
+
if (abortSignal != null && abortSignal.aborted)
|
|
60
|
+
throw new Error("Aborted");
|
|
61
|
+
if (i !== retryPolicy.maxRetries - 1) {
|
|
62
|
+
await timeoutPromise(retryPolicy.exponential ? retryPolicy.delay * Math.pow(2, i) : retryPolicy.delay, abortSignal);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
throw err;
|
|
74
66
|
}
|
|
75
67
|
exports.tryWithRetries = tryWithRetries;
|
|
76
68
|
class SolanaTxUtils {
|
|
@@ -141,3 +133,38 @@ exports.SolanaTxUtils = SolanaTxUtils;
|
|
|
141
133
|
// COMPACT ARRAY
|
|
142
134
|
SolanaTxUtils.LOW_VALUE = 127; // 0x7f
|
|
143
135
|
SolanaTxUtils.HIGH_VALUE = 16383; // 0x3fff
|
|
136
|
+
function toClaimHash(paymentHash, nonce, confirmations) {
|
|
137
|
+
return paymentHash +
|
|
138
|
+
nonce.toString(16).padStart(16, "0") +
|
|
139
|
+
confirmations.toString(16).padStart(4, "0");
|
|
140
|
+
}
|
|
141
|
+
exports.toClaimHash = toClaimHash;
|
|
142
|
+
function fromClaimHash(claimHash) {
|
|
143
|
+
if (claimHash.length !== 84)
|
|
144
|
+
throw new Error("Claim hash invalid length: " + claimHash.length);
|
|
145
|
+
return {
|
|
146
|
+
paymentHash: claimHash.slice(0, 64),
|
|
147
|
+
nonce: new BN(claimHash.slice(64, 80), "hex"),
|
|
148
|
+
confirmations: parseInt(claimHash.slice(80, 84), 16)
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
exports.fromClaimHash = fromClaimHash;
|
|
152
|
+
function toEscrowHash(paymentHash, sequence) {
|
|
153
|
+
return createHash("sha256").update(buffer_1.Buffer.concat([
|
|
154
|
+
buffer_1.Buffer.from(paymentHash, "hex"),
|
|
155
|
+
sequence.toArrayLike(buffer_1.Buffer, "be", 8)
|
|
156
|
+
])).digest().toString("hex");
|
|
157
|
+
}
|
|
158
|
+
exports.toEscrowHash = toEscrowHash;
|
|
159
|
+
function toBN(value) {
|
|
160
|
+
if (value == null)
|
|
161
|
+
return null;
|
|
162
|
+
return new BN(value.toString(10));
|
|
163
|
+
}
|
|
164
|
+
exports.toBN = toBN;
|
|
165
|
+
function toBigInt(value) {
|
|
166
|
+
if (value == null)
|
|
167
|
+
return null;
|
|
168
|
+
return BigInt(value.toString(10));
|
|
169
|
+
}
|
|
170
|
+
exports.toBigInt = toBigInt;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atomiqlabs/chain-solana",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0-beta.0",
|
|
4
4
|
"description": "Solana specific base implementation",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types:": "./dist/index.d.ts",
|
|
@@ -22,18 +22,21 @@
|
|
|
22
22
|
"author": "adambor",
|
|
23
23
|
"license": "ISC",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@atomiqlabs/base": "
|
|
26
|
-
"@coral-xyz/anchor": "0.29.0",
|
|
27
|
-
"@solana/spl-token": "0.3.9",
|
|
28
|
-
"@solana/web3.js": "1.95.2",
|
|
25
|
+
"@atomiqlabs/base": "8.0.0-beta.0",
|
|
29
26
|
"bn.js": "5.2.1",
|
|
27
|
+
"bs58": "4.0.1",
|
|
30
28
|
"buffer": "6.0.3",
|
|
31
29
|
"create-hash": "1.2.0",
|
|
32
30
|
"randombytes": "2.1.0",
|
|
33
31
|
"tweetnacl": "1.0.3"
|
|
34
32
|
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@coral-xyz/anchor": "^0.29.0",
|
|
35
|
+
"@solana/spl-token": "^0.3.9",
|
|
36
|
+
"@solana/web3.js": "^1.95.2"
|
|
37
|
+
},
|
|
35
38
|
"devDependencies": {
|
|
36
|
-
"@types/bn.js": "5.1.
|
|
39
|
+
"@types/bn.js": "5.1.6",
|
|
37
40
|
"@types/node": "18.15.11",
|
|
38
41
|
"typescript": "4.9.5"
|
|
39
42
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {BitcoinNetwork} from "@atomiqlabs/base";
|
|
2
|
+
|
|
3
|
+
export const SolanaChains = {
|
|
4
|
+
[BitcoinNetwork.TESTNET]: {
|
|
5
|
+
addresses: {
|
|
6
|
+
swapContract: "4hfUykhqmD7ZRvNh1HuzVKEY7ToENixtdUKZspNDCrEM",
|
|
7
|
+
btcRelayContract: "3KHSHFpEK6bsjg3bqcxQ9qssJYtRCMi2S9TYVe4q6CQc"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
[BitcoinNetwork.MAINNET]: {
|
|
11
|
+
addresses: {
|
|
12
|
+
swapContract: "4hfUykhqmD7ZRvNh1HuzVKEY7ToENixtdUKZspNDCrEM",
|
|
13
|
+
btcRelayContract: "3KHSHFpEK6bsjg3bqcxQ9qssJYtRCMi2S9TYVe4q6CQc"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
} as const;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseTokenType,
|
|
3
|
+
BitcoinNetwork,
|
|
4
|
+
BitcoinRpc,
|
|
5
|
+
ChainData,
|
|
6
|
+
ChainInitializer,
|
|
7
|
+
IStorageManager,
|
|
8
|
+
StorageObject
|
|
9
|
+
} from "@atomiqlabs/base";
|
|
10
|
+
import {Connection} from "@solana/web3.js";
|
|
11
|
+
import {StoredDataAccount} from "./swaps/modules/SolanaDataAccount";
|
|
12
|
+
import {SolanaRetryPolicy} from "./base/SolanaBase";
|
|
13
|
+
import {SolanaFees} from "./base/modules/SolanaFees";
|
|
14
|
+
import {SolanaChainType} from "./SolanaChainType";
|
|
15
|
+
import {SolanaBtcRelay} from "./btcrelay/SolanaBtcRelay";
|
|
16
|
+
import {SolanaChains} from "./SolanaChains";
|
|
17
|
+
import {SolanaSwapProgram} from "./swaps/SolanaSwapProgram";
|
|
18
|
+
import {SolanaChainEventsBrowser} from "./events/SolanaChainEventsBrowser";
|
|
19
|
+
import {SolanaSwapData} from "./swaps/SolanaSwapData";
|
|
20
|
+
|
|
21
|
+
const chainId = "SOLANA" as const;
|
|
22
|
+
|
|
23
|
+
export type SolanaAssetsType = BaseTokenType<"WBTC" | "USDC" | "USDT" | "SOL" | "BONK">;
|
|
24
|
+
const SolanaAssets: SolanaAssetsType = {
|
|
25
|
+
WBTC: {
|
|
26
|
+
address: "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh",
|
|
27
|
+
decimals: 8
|
|
28
|
+
},
|
|
29
|
+
USDC: {
|
|
30
|
+
address: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
31
|
+
decimals: 6
|
|
32
|
+
},
|
|
33
|
+
USDT: {
|
|
34
|
+
address: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
|
|
35
|
+
decimals: 6
|
|
36
|
+
},
|
|
37
|
+
SOL: {
|
|
38
|
+
address: "So11111111111111111111111111111111111111112",
|
|
39
|
+
decimals: 9
|
|
40
|
+
},
|
|
41
|
+
BONK: {
|
|
42
|
+
address: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
|
|
43
|
+
decimals: 5
|
|
44
|
+
}
|
|
45
|
+
} as const;
|
|
46
|
+
|
|
47
|
+
export type SolanaSwapperOptions = {
|
|
48
|
+
rpcUrl: string | Connection,
|
|
49
|
+
dataAccountStorage?: IStorageManager<StoredDataAccount>,
|
|
50
|
+
retryPolicy?: SolanaRetryPolicy,
|
|
51
|
+
|
|
52
|
+
btcRelayContract?: string,
|
|
53
|
+
swapContract?: string,
|
|
54
|
+
|
|
55
|
+
fees?: SolanaFees
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export function initializeSolana(
|
|
59
|
+
options: SolanaSwapperOptions,
|
|
60
|
+
bitcoinRpc: BitcoinRpc<any>,
|
|
61
|
+
network: BitcoinNetwork,
|
|
62
|
+
storageCtor: <T extends StorageObject>(name: string) => IStorageManager<T>
|
|
63
|
+
): ChainData<SolanaChainType> {
|
|
64
|
+
const connection = typeof(options.rpcUrl)==="string" ?
|
|
65
|
+
new Connection(options.rpcUrl) :
|
|
66
|
+
options.rpcUrl;
|
|
67
|
+
|
|
68
|
+
const Fees = options.fees ?? new SolanaFees(connection, 200000, 4, 100);
|
|
69
|
+
const btcRelay = new SolanaBtcRelay(connection, bitcoinRpc, options.btcRelayContract ?? SolanaChains[network].addresses.btcRelayContract, Fees);
|
|
70
|
+
const swapContract = new SolanaSwapProgram(
|
|
71
|
+
connection,
|
|
72
|
+
btcRelay,
|
|
73
|
+
options.dataAccountStorage || storageCtor("solAccounts"),
|
|
74
|
+
options.swapContract ?? SolanaChains[network].addresses.swapContract,
|
|
75
|
+
options.retryPolicy ?? {transactionResendInterval: 1000},
|
|
76
|
+
Fees
|
|
77
|
+
);
|
|
78
|
+
const chainEvents = new SolanaChainEventsBrowser(connection, swapContract);
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
chainId,
|
|
82
|
+
btcRelay,
|
|
83
|
+
swapContract,
|
|
84
|
+
chainEvents,
|
|
85
|
+
swapDataConstructor: SolanaSwapData,
|
|
86
|
+
//These are defined here to keep the data from old SolLightning-sdk, not needed for other chains
|
|
87
|
+
storagePrefix: "SOLv4-"+network+"-"
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export type SolanaInitializerType = ChainInitializer<SolanaSwapperOptions, SolanaChainType, SolanaAssetsType>;
|
|
92
|
+
export const SolanaInitializer: SolanaInitializerType = {
|
|
93
|
+
chainId,
|
|
94
|
+
chainType: null as SolanaChainType,
|
|
95
|
+
initializer: initializeSolana,
|
|
96
|
+
tokens: SolanaAssets,
|
|
97
|
+
options: null as SolanaSwapperOptions
|
|
98
|
+
} as const;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {Connection
|
|
2
|
-
import {AnchorProvider} from "@coral-xyz/anchor";
|
|
1
|
+
import {Connection} from "@solana/web3.js";
|
|
3
2
|
import {SolanaFees} from "./modules/SolanaFees";
|
|
4
3
|
import {SolanaBlocks} from "./modules/SolanaBlocks";
|
|
5
4
|
import {SolanaSlots} from "./modules/SolanaSlots";
|