@atomiqlabs/chain-solana 13.5.13 → 13.5.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -201
- package/README.md +73 -73
- package/dist/index.d.ts +81 -81
- package/dist/index.js +102 -102
- package/dist/node/index.d.ts +9 -9
- package/dist/node/index.js +13 -13
- package/dist/solana/SolanaChainType.d.ts +15 -15
- package/dist/solana/SolanaChainType.js +2 -2
- package/dist/solana/SolanaChains.d.ts +12 -12
- package/dist/solana/SolanaChains.js +45 -45
- package/dist/solana/SolanaInitializer.d.ts +94 -94
- package/dist/solana/SolanaInitializer.js +174 -174
- package/dist/solana/btcrelay/SolanaBtcRelay.d.ts +222 -222
- package/dist/solana/btcrelay/SolanaBtcRelay.js +455 -455
- package/dist/solana/btcrelay/headers/SolanaBtcHeader.d.ts +84 -84
- package/dist/solana/btcrelay/headers/SolanaBtcHeader.js +70 -70
- package/dist/solana/btcrelay/headers/SolanaBtcStoredHeader.d.ts +92 -92
- package/dist/solana/btcrelay/headers/SolanaBtcStoredHeader.js +109 -109
- package/dist/solana/btcrelay/program/programIdl.json +671 -671
- package/dist/solana/chain/SolanaAction.d.ts +26 -26
- package/dist/solana/chain/SolanaAction.js +87 -87
- package/dist/solana/chain/SolanaChainInterface.d.ts +224 -224
- package/dist/solana/chain/SolanaChainInterface.js +275 -275
- package/dist/solana/chain/SolanaModule.d.ts +14 -14
- package/dist/solana/chain/SolanaModule.js +13 -13
- package/dist/solana/chain/modules/SolanaAddresses.d.ts +8 -8
- package/dist/solana/chain/modules/SolanaAddresses.js +22 -22
- package/dist/solana/chain/modules/SolanaBlocks.d.ts +32 -32
- package/dist/solana/chain/modules/SolanaBlocks.js +78 -78
- package/dist/solana/chain/modules/SolanaEvents.d.ts +68 -68
- package/dist/solana/chain/modules/SolanaEvents.js +238 -238
- package/dist/solana/chain/modules/SolanaFees.d.ts +189 -189
- package/dist/solana/chain/modules/SolanaFees.js +434 -434
- package/dist/solana/chain/modules/SolanaSignatures.d.ts +24 -24
- package/dist/solana/chain/modules/SolanaSignatures.js +39 -39
- package/dist/solana/chain/modules/SolanaSlots.d.ts +33 -33
- package/dist/solana/chain/modules/SolanaSlots.js +72 -72
- package/dist/solana/chain/modules/SolanaTokens.d.ts +123 -123
- package/dist/solana/chain/modules/SolanaTokens.js +242 -242
- package/dist/solana/chain/modules/SolanaTransactions.d.ts +149 -149
- package/dist/solana/chain/modules/SolanaTransactions.js +445 -445
- package/dist/solana/connection/ConnectionWithRetries.d.ts +35 -35
- package/dist/solana/connection/ConnectionWithRetries.js +86 -71
- package/dist/solana/events/SolanaChainEvents.d.ts +45 -45
- package/dist/solana/events/SolanaChainEvents.js +108 -108
- package/dist/solana/events/SolanaChainEventsBrowser.d.ts +205 -205
- package/dist/solana/events/SolanaChainEventsBrowser.js +404 -404
- package/dist/solana/program/SolanaProgramBase.d.ts +73 -73
- package/dist/solana/program/SolanaProgramBase.js +54 -54
- package/dist/solana/program/SolanaProgramModule.d.ts +8 -8
- package/dist/solana/program/SolanaProgramModule.js +11 -11
- package/dist/solana/program/modules/SolanaProgramEvents.d.ts +53 -53
- package/dist/solana/program/modules/SolanaProgramEvents.js +117 -117
- package/dist/solana/swaps/SolanaSwapData.d.ts +333 -333
- package/dist/solana/swaps/SolanaSwapData.js +535 -535
- package/dist/solana/swaps/SolanaSwapModule.d.ts +11 -11
- package/dist/solana/swaps/SolanaSwapModule.js +12 -12
- package/dist/solana/swaps/SolanaSwapProgram.d.ts +376 -376
- package/dist/solana/swaps/SolanaSwapProgram.js +769 -769
- package/dist/solana/swaps/SwapTypeEnum.d.ts +11 -11
- package/dist/solana/swaps/SwapTypeEnum.js +43 -43
- package/dist/solana/swaps/modules/SolanaDataAccount.d.ts +95 -95
- package/dist/solana/swaps/modules/SolanaDataAccount.js +232 -232
- package/dist/solana/swaps/modules/SolanaLpVault.d.ts +69 -69
- package/dist/solana/swaps/modules/SolanaLpVault.js +171 -171
- package/dist/solana/swaps/modules/SwapClaim.d.ts +126 -126
- package/dist/solana/swaps/modules/SwapClaim.js +294 -294
- package/dist/solana/swaps/modules/SwapInit.d.ts +213 -213
- package/dist/solana/swaps/modules/SwapInit.js +658 -658
- package/dist/solana/swaps/modules/SwapRefund.d.ts +87 -87
- package/dist/solana/swaps/modules/SwapRefund.js +293 -293
- package/dist/solana/swaps/programIdl.json +945 -945
- package/dist/solana/swaps/programTypes.d.ts +943 -943
- package/dist/solana/swaps/programTypes.js +945 -945
- package/dist/solana/swaps/v1/programIdl.json +945 -945
- package/dist/solana/swaps/v1/programTypes.d.ts +943 -943
- package/dist/solana/swaps/v1/programTypes.js +945 -945
- package/dist/solana/swaps/v2/programIdl.json +952 -952
- package/dist/solana/swaps/v2/programTypes.d.ts +950 -950
- package/dist/solana/swaps/v2/programTypes.js +952 -952
- package/dist/solana/wallet/SolanaKeypairWallet.d.ts +29 -29
- package/dist/solana/wallet/SolanaKeypairWallet.js +50 -50
- package/dist/solana/wallet/SolanaSigner.d.ts +30 -30
- package/dist/solana/wallet/SolanaSigner.js +30 -30
- package/dist/utils/Utils.d.ts +58 -58
- package/dist/utils/Utils.js +170 -170
- package/node/index.d.ts +1 -1
- package/node/index.js +3 -3
- package/package.json +46 -46
- package/src/index.ts +87 -87
- package/src/node/index.ts +9 -9
- package/src/solana/SolanaChainType.ts +32 -32
- package/src/solana/SolanaChains.ts +46 -46
- package/src/solana/SolanaInitializer.ts +278 -278
- package/src/solana/btcrelay/SolanaBtcRelay.ts +615 -615
- package/src/solana/btcrelay/headers/SolanaBtcHeader.ts +116 -116
- package/src/solana/btcrelay/headers/SolanaBtcStoredHeader.ts +148 -148
- package/src/solana/btcrelay/program/programIdl.json +670 -670
- package/src/solana/chain/SolanaAction.ts +109 -109
- package/src/solana/chain/SolanaChainInterface.ts +404 -404
- package/src/solana/chain/SolanaModule.ts +20 -20
- package/src/solana/chain/modules/SolanaAddresses.ts +20 -20
- package/src/solana/chain/modules/SolanaBlocks.ts +89 -89
- package/src/solana/chain/modules/SolanaEvents.ts +271 -271
- package/src/solana/chain/modules/SolanaFees.ts +522 -522
- package/src/solana/chain/modules/SolanaSignatures.ts +39 -39
- package/src/solana/chain/modules/SolanaSlots.ts +85 -85
- package/src/solana/chain/modules/SolanaTokens.ts +300 -300
- package/src/solana/chain/modules/SolanaTransactions.ts +503 -503
- package/src/solana/connection/ConnectionWithRetries.ts +113 -96
- package/src/solana/events/SolanaChainEvents.ts +127 -127
- package/src/solana/events/SolanaChainEventsBrowser.ts +495 -495
- package/src/solana/program/SolanaProgramBase.ts +119 -119
- package/src/solana/program/SolanaProgramModule.ts +15 -15
- package/src/solana/program/modules/SolanaProgramEvents.ts +157 -157
- package/src/solana/swaps/SolanaSwapData.ts +735 -735
- package/src/solana/swaps/SolanaSwapModule.ts +19 -19
- package/src/solana/swaps/SolanaSwapProgram.ts +1074 -1074
- package/src/solana/swaps/SwapTypeEnum.ts +30 -30
- package/src/solana/swaps/modules/SolanaDataAccount.ts +302 -302
- package/src/solana/swaps/modules/SolanaLpVault.ts +208 -208
- package/src/solana/swaps/modules/SwapClaim.ts +387 -387
- package/src/solana/swaps/modules/SwapInit.ts +785 -785
- package/src/solana/swaps/modules/SwapRefund.ts +353 -353
- package/src/solana/swaps/v1/programIdl.json +944 -944
- package/src/solana/swaps/v1/programTypes.ts +1885 -1885
- package/src/solana/swaps/v2/programIdl.json +951 -951
- package/src/solana/swaps/v2/programTypes.ts +1899 -1899
- package/src/solana/wallet/SolanaKeypairWallet.ts +56 -56
- package/src/solana/wallet/SolanaSigner.ts +43 -43
- package/src/utils/Utils.ts +194 -194
|
@@ -1,735 +1,735 @@
|
|
|
1
|
-
import {PublicKey, SystemProgram, SYSVAR_INSTRUCTIONS_PUBKEY} from "@solana/web3.js";
|
|
2
|
-
import * as BN from "bn.js";
|
|
3
|
-
import {ChainSwapType, SwapData} from "@atomiqlabs/base";
|
|
4
|
-
import {SwapProgram} from "./v1/programTypes";
|
|
5
|
-
import {IdlAccounts, IdlTypes} from "@coral-xyz/anchor";
|
|
6
|
-
import {SwapTypeEnum} from "./SwapTypeEnum";
|
|
7
|
-
import {Buffer} from "buffer";
|
|
8
|
-
import {getAssociatedTokenAddressSync, TOKEN_PROGRAM_ID} from "@solana/spl-token";
|
|
9
|
-
import {Serialized, toBigInt, toClaimHash, toEscrowHash} from "../../utils/Utils";
|
|
10
|
-
import {SolanaTokens} from "../chain/modules/SolanaTokens";
|
|
11
|
-
import {SingleInstructionWithAccounts} from "../program/modules/SolanaProgramEvents";
|
|
12
|
-
import {SolanaSwapProgram} from "./SolanaSwapProgram";
|
|
13
|
-
import {SwapProgramV2} from "./v2/programTypes";
|
|
14
|
-
|
|
15
|
-
export type InitInstruction = SingleInstructionWithAccounts<SwapProgram["instructions"][2 | 3] | SwapProgramV2["instructions"][2 | 3], SwapProgram>;
|
|
16
|
-
|
|
17
|
-
const EXPIRY_BLOCKHEIGHT_THRESHOLD = new BN("1000000000");
|
|
18
|
-
|
|
19
|
-
export type SolanaSwapDataCtorArgs = {
|
|
20
|
-
programId: PublicKey,
|
|
21
|
-
version: "v1" | "v2",
|
|
22
|
-
|
|
23
|
-
offerer: PublicKey,
|
|
24
|
-
claimer: PublicKey,
|
|
25
|
-
token: PublicKey,
|
|
26
|
-
amount: BN,
|
|
27
|
-
paymentHash: string,
|
|
28
|
-
sequence: BN,
|
|
29
|
-
expiry: BN,
|
|
30
|
-
|
|
31
|
-
nonce: BN,
|
|
32
|
-
confirmations: number,
|
|
33
|
-
payOut: boolean,
|
|
34
|
-
kind: number,
|
|
35
|
-
payIn: boolean,
|
|
36
|
-
offererAta?: PublicKey,
|
|
37
|
-
claimerAta?: PublicKey,
|
|
38
|
-
|
|
39
|
-
securityDeposit: BN,
|
|
40
|
-
claimerBounty: BN,
|
|
41
|
-
|
|
42
|
-
txoHash?: string,
|
|
43
|
-
offererInitializer?: boolean
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export function isSerializedData(obj: any): obj is ({type: "sol"} & Serialized<SolanaSwapData>) {
|
|
47
|
-
return obj.type==="sol";
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Represents Solana swap data for executing PrTLC (on-chain) or HTLC (lightning) based swaps.
|
|
52
|
-
*
|
|
53
|
-
* @category Swaps
|
|
54
|
-
*/
|
|
55
|
-
export class SolanaSwapData extends SwapData {
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Program ID for which this swap data was created
|
|
59
|
-
*/
|
|
60
|
-
programId: PublicKey;
|
|
61
|
-
/**
|
|
62
|
-
* Program version for which this swap was created
|
|
63
|
-
*/
|
|
64
|
-
version: "v1" | "v2";
|
|
65
|
-
/**
|
|
66
|
-
* Offerer address funding the swap.
|
|
67
|
-
*/
|
|
68
|
-
offerer: PublicKey;
|
|
69
|
-
/**
|
|
70
|
-
* Claimer address receiving the swap funds.
|
|
71
|
-
*/
|
|
72
|
-
claimer: PublicKey;
|
|
73
|
-
/**
|
|
74
|
-
* Token mint used for the swap.
|
|
75
|
-
*/
|
|
76
|
-
token: PublicKey;
|
|
77
|
-
/**
|
|
78
|
-
* Swap amount.
|
|
79
|
-
*/
|
|
80
|
-
amount: BN;
|
|
81
|
-
/**
|
|
82
|
-
* Payment hash identifying the swap.
|
|
83
|
-
*/
|
|
84
|
-
paymentHash: string;
|
|
85
|
-
/**
|
|
86
|
-
* Swap sequence used for uniqueness.
|
|
87
|
-
*/
|
|
88
|
-
sequence: BN;
|
|
89
|
-
/**
|
|
90
|
-
* Swap expiry timestamp.
|
|
91
|
-
*/
|
|
92
|
-
expiry: BN;
|
|
93
|
-
/**
|
|
94
|
-
* Nonce used in claim hash derivation.
|
|
95
|
-
*/
|
|
96
|
-
nonce: BN;
|
|
97
|
-
/**
|
|
98
|
-
* Required bitcoin confirmations for claim.
|
|
99
|
-
*/
|
|
100
|
-
confirmations: number;
|
|
101
|
-
/**
|
|
102
|
-
* Whether funds are paid out to claimer wallet directly.
|
|
103
|
-
*/
|
|
104
|
-
payOut: boolean;
|
|
105
|
-
/**
|
|
106
|
-
* Solana on-chain swap kind discriminator.
|
|
107
|
-
*/
|
|
108
|
-
kind: number;
|
|
109
|
-
/**
|
|
110
|
-
* Whether funds are paid in from offerer wallet.
|
|
111
|
-
*/
|
|
112
|
-
payIn: boolean;
|
|
113
|
-
/**
|
|
114
|
-
* Optional claimer associated token account.
|
|
115
|
-
*/
|
|
116
|
-
claimerAta?: PublicKey;
|
|
117
|
-
/**
|
|
118
|
-
* Optional offerer associated token account.
|
|
119
|
-
*/
|
|
120
|
-
offererAta?: PublicKey;
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Security deposit amount.
|
|
124
|
-
*/
|
|
125
|
-
securityDeposit: BN;
|
|
126
|
-
/**
|
|
127
|
-
* Claimer bounty amount.
|
|
128
|
-
*/
|
|
129
|
-
claimerBounty: BN;
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Optional txo hash hint.
|
|
133
|
-
*/
|
|
134
|
-
txoHash?: string;
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Optional flag whether the offerer is the initializer for V2 swap data
|
|
138
|
-
*/
|
|
139
|
-
offererInitializer?: boolean;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Creates swap data from structured constructor arguments.
|
|
143
|
-
*
|
|
144
|
-
* @param args Swap data fields
|
|
145
|
-
*/
|
|
146
|
-
constructor(args: SolanaSwapDataCtorArgs);
|
|
147
|
-
/**
|
|
148
|
-
* Deserializes swap data from serialized storage representation.
|
|
149
|
-
*
|
|
150
|
-
* @param data Serialized swap data from {@link SolanaSwapData.serialize}
|
|
151
|
-
*/
|
|
152
|
-
constructor(data: {type: "sol"} & Serialized<SolanaSwapData>);
|
|
153
|
-
|
|
154
|
-
constructor(data: ({type: "sol"} & Serialized<SolanaSwapData>) | SolanaSwapDataCtorArgs) {
|
|
155
|
-
super();
|
|
156
|
-
if(!isSerializedData(data)) {
|
|
157
|
-
this.programId = data.programId;
|
|
158
|
-
this.version = data.version;
|
|
159
|
-
this.offerer = data.offerer;
|
|
160
|
-
this.claimer = data.claimer;
|
|
161
|
-
this.token = data.token;
|
|
162
|
-
this.amount = data.amount;
|
|
163
|
-
this.paymentHash = data.paymentHash;
|
|
164
|
-
this.sequence = data.sequence;
|
|
165
|
-
this.expiry = data.expiry;
|
|
166
|
-
this.nonce = data.nonce;
|
|
167
|
-
this.confirmations = data.confirmations;
|
|
168
|
-
this.payOut = data.payOut;
|
|
169
|
-
this.kind = data.kind;
|
|
170
|
-
this.payIn = data.payIn;
|
|
171
|
-
this.claimerAta = data.claimerAta;
|
|
172
|
-
this.offererAta = data.offererAta;
|
|
173
|
-
this.securityDeposit = data.securityDeposit;
|
|
174
|
-
this.claimerBounty = data.claimerBounty;
|
|
175
|
-
this.txoHash = data.txoHash;
|
|
176
|
-
this.offererInitializer = data.offererInitializer;
|
|
177
|
-
} else {
|
|
178
|
-
this.programId = new PublicKey(data.programId ?? "4hfUykhqmD7ZRvNh1HuzVKEY7ToENixtdUKZspNDCrEM");
|
|
179
|
-
this.version = data.version ?? "v1";
|
|
180
|
-
this.offerer = new PublicKey(data.offerer);
|
|
181
|
-
this.claimer = new PublicKey(data.claimer);
|
|
182
|
-
this.token = new PublicKey(data.token);
|
|
183
|
-
this.amount = new BN(data.amount);
|
|
184
|
-
this.paymentHash = data.paymentHash;
|
|
185
|
-
this.sequence = new BN(data.sequence);
|
|
186
|
-
this.expiry = new BN(data.expiry);
|
|
187
|
-
this.nonce = new BN(data.nonce);
|
|
188
|
-
this.confirmations = data.confirmations;
|
|
189
|
-
this.payOut = data.payOut;
|
|
190
|
-
this.kind = data.kind;
|
|
191
|
-
this.payIn = data.payIn;
|
|
192
|
-
this.claimerAta = data.claimerAta==null ? undefined : new PublicKey(data.claimerAta);
|
|
193
|
-
this.offererAta = data.offererAta==null ? undefined : new PublicKey(data.offererAta);
|
|
194
|
-
this.securityDeposit = new BN(data.securityDeposit);
|
|
195
|
-
this.claimerBounty = new BN(data.claimerBounty);
|
|
196
|
-
this.txoHash = data.txoHash;
|
|
197
|
-
this.offererInitializer = data.offererInitializer;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* @inheritDoc
|
|
203
|
-
*/
|
|
204
|
-
getOfferer(): string {
|
|
205
|
-
return this.offerer.toBase58();
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* @inheritDoc
|
|
210
|
-
*/
|
|
211
|
-
setOfferer(newOfferer: string) {
|
|
212
|
-
this.offerer = new PublicKey(newOfferer);
|
|
213
|
-
this.offererAta = getAssociatedTokenAddressSync(this.token, this.offerer);
|
|
214
|
-
this.payIn = true;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* @inheritDoc
|
|
219
|
-
*/
|
|
220
|
-
getClaimer(): string {
|
|
221
|
-
return this.claimer.toBase58();
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* @inheritDoc
|
|
226
|
-
*/
|
|
227
|
-
setClaimer(newClaimer: string) {
|
|
228
|
-
this.claimer = new PublicKey(newClaimer);
|
|
229
|
-
this.payIn = false;
|
|
230
|
-
this.payOut = true;
|
|
231
|
-
this.claimerAta = getAssociatedTokenAddressSync(this.token, this.claimer);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* @inheritDoc
|
|
236
|
-
*/
|
|
237
|
-
serialize(): {type: "sol"} & Serialized<SolanaSwapData> {
|
|
238
|
-
return {
|
|
239
|
-
type: "sol",
|
|
240
|
-
programId: this.programId?.toBase58(),
|
|
241
|
-
version: this.version,
|
|
242
|
-
offerer: this.offerer?.toBase58(),
|
|
243
|
-
claimer: this.claimer?.toBase58(),
|
|
244
|
-
token: this.token?.toBase58(),
|
|
245
|
-
amount: this.amount?.toString(10),
|
|
246
|
-
paymentHash: this.paymentHash,
|
|
247
|
-
sequence: this.sequence?.toString(10),
|
|
248
|
-
expiry: this.expiry?.toString(10),
|
|
249
|
-
nonce: this.nonce?.toString(10),
|
|
250
|
-
confirmations: this.confirmations,
|
|
251
|
-
payOut: this.payOut,
|
|
252
|
-
kind: this.kind,
|
|
253
|
-
payIn: this.payIn,
|
|
254
|
-
offererAta: this.offererAta?.toBase58(),
|
|
255
|
-
claimerAta: this.claimerAta?.toBase58(),
|
|
256
|
-
securityDeposit: this.securityDeposit?.toString(10),
|
|
257
|
-
claimerBounty: this.claimerBounty?.toString(10),
|
|
258
|
-
txoHash: this.txoHash,
|
|
259
|
-
offererInitializer: this.offererInitializer
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* @inheritDoc
|
|
265
|
-
*/
|
|
266
|
-
getAmount(): bigint {
|
|
267
|
-
return toBigInt(this.amount);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* @inheritDoc
|
|
272
|
-
*/
|
|
273
|
-
getToken(): string {
|
|
274
|
-
return this.token.toString();
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* @inheritDoc
|
|
279
|
-
*/
|
|
280
|
-
isToken(token: string): boolean {
|
|
281
|
-
return this.token.equals(new PublicKey(token));
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* @inheritDoc
|
|
286
|
-
*/
|
|
287
|
-
getType(): ChainSwapType {
|
|
288
|
-
return SolanaSwapData.kindToType(this.kind);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* @inheritDoc
|
|
293
|
-
*/
|
|
294
|
-
getExpiry(): bigint {
|
|
295
|
-
if(this.expiry.lt(EXPIRY_BLOCKHEIGHT_THRESHOLD)) throw new Error("Expiry expressed as bitcoin blockheight!");
|
|
296
|
-
return toBigInt(this.expiry);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* @inheritDoc
|
|
301
|
-
*/
|
|
302
|
-
getConfirmationsHint(): number {
|
|
303
|
-
return this.confirmations;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* @inheritDoc
|
|
308
|
-
*/
|
|
309
|
-
getNonceHint(): bigint {
|
|
310
|
-
return toBigInt(this.nonce);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* @inheritDoc
|
|
315
|
-
*/
|
|
316
|
-
isPayIn(): boolean {
|
|
317
|
-
return this.payIn;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* @inheritDoc
|
|
322
|
-
*/
|
|
323
|
-
isPayOut(): boolean {
|
|
324
|
-
return this.payOut;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* @inheritDoc
|
|
329
|
-
*/
|
|
330
|
-
isTrackingReputation(): boolean {
|
|
331
|
-
return !this.payOut;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* @inheritDoc
|
|
336
|
-
*/
|
|
337
|
-
getClaimHash(): string {
|
|
338
|
-
return toClaimHash(this.paymentHash, toBigInt(this.nonce), this.confirmations);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* @inheritDoc
|
|
343
|
-
*/
|
|
344
|
-
getEscrowHash(): string {
|
|
345
|
-
return toEscrowHash(this.paymentHash, this.sequence);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* @inheritDoc
|
|
350
|
-
*/
|
|
351
|
-
getSequence(): bigint {
|
|
352
|
-
return toBigInt(this.sequence);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* @inheritDoc
|
|
357
|
-
*/
|
|
358
|
-
getTxoHashHint(): string | null {
|
|
359
|
-
if(this.txoHash==="0000000000000000000000000000000000000000000000000000000000000000") return null; //Txo hash opt-out flag
|
|
360
|
-
return this.txoHash ?? null
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* @inheritDoc
|
|
365
|
-
*/
|
|
366
|
-
getHTLCHashHint(): string | null {
|
|
367
|
-
if(this.getType()===ChainSwapType.HTLC) return this.paymentHash;
|
|
368
|
-
return null;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* @inheritDoc
|
|
373
|
-
*/
|
|
374
|
-
getExtraData(): string | null {
|
|
375
|
-
return this.txoHash ?? null;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* @inheritDoc
|
|
380
|
-
*/
|
|
381
|
-
setExtraData(txoHash: string): void {
|
|
382
|
-
this.txoHash = txoHash;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* @inheritDoc
|
|
387
|
-
*/
|
|
388
|
-
getSecurityDeposit(): bigint {
|
|
389
|
-
return toBigInt(this.securityDeposit);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* @inheritDoc
|
|
394
|
-
*/
|
|
395
|
-
getClaimerBounty(): bigint {
|
|
396
|
-
return toBigInt(this.claimerBounty);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* @inheritDoc
|
|
401
|
-
*/
|
|
402
|
-
getTotalDeposit(): bigint {
|
|
403
|
-
return toBigInt(this.claimerBounty.lt(this.securityDeposit) ? this.securityDeposit : this.claimerBounty);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Serializes the swap data into the Solana program `SwapData` struct representation.
|
|
408
|
-
*/
|
|
409
|
-
toSwapDataStruct(): IdlTypes<SwapProgram>["SwapData"] {
|
|
410
|
-
return {
|
|
411
|
-
kind: SwapTypeEnum.fromNumber(this.kind as 0 | 1 | 2 | 3),
|
|
412
|
-
confirmations: this.confirmations,
|
|
413
|
-
nonce: this.nonce,
|
|
414
|
-
hash: [...Buffer.from(this.paymentHash, "hex")],
|
|
415
|
-
payIn: this.payIn,
|
|
416
|
-
payOut: this.payOut,
|
|
417
|
-
amount: this.amount,
|
|
418
|
-
expiry: this.expiry,
|
|
419
|
-
sequence: this.sequence
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Checks whether the provided escrow account matches this swap data.
|
|
425
|
-
*
|
|
426
|
-
* @param account Escrow account data fetched from chain
|
|
427
|
-
*/
|
|
428
|
-
correctPDA(account: IdlAccounts<SwapProgram | SwapProgramV2>["escrowState"]): boolean {
|
|
429
|
-
return SwapTypeEnum.toNumber(account.data.kind)===this.kind &&
|
|
430
|
-
account.data.confirmations===this.confirmations &&
|
|
431
|
-
this.nonce.eq(account.data.nonce) &&
|
|
432
|
-
Buffer.from(account.data.hash).toString("hex")===this.paymentHash &&
|
|
433
|
-
account.data.payIn===this.payIn &&
|
|
434
|
-
account.data.payOut===this.payOut &&
|
|
435
|
-
this.amount.eq(account.data.amount) &&
|
|
436
|
-
this.expiry.eq(account.data.expiry) &&
|
|
437
|
-
this.sequence.eq(account.data.sequence) &&
|
|
438
|
-
|
|
439
|
-
account.offerer.equals(this.offerer) &&
|
|
440
|
-
(this.offererAta==null || account.offererAta.equals(this.offererAta)) &&
|
|
441
|
-
account.claimer.equals(this.claimer) &&
|
|
442
|
-
(this.claimerAta==null || account.claimerAta.equals(this.claimerAta)) &&
|
|
443
|
-
account.mint.equals(this.token) &&
|
|
444
|
-
this.claimerBounty.eq(account.claimerBounty) &&
|
|
445
|
-
this.securityDeposit.eq(account.securityDeposit) &&
|
|
446
|
-
(this.offererInitializer==null || account.offererInitializer===this.offererInitializer);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* @inheritDoc
|
|
451
|
-
*/
|
|
452
|
-
equals(other: SolanaSwapData): boolean {
|
|
453
|
-
if(this.claimerAta==null && other.claimerAta!=null) return false;
|
|
454
|
-
if(this.claimerAta!=null && other.claimerAta==null) return false;
|
|
455
|
-
if(this.claimerAta!=null && other.claimerAta!=null) {
|
|
456
|
-
if(!this.claimerAta.equals(other.claimerAta)) return false;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if(this.offererAta==null && other.offererAta!=null) return false;
|
|
460
|
-
if(this.offererAta!=null && other.offererAta==null) return false;
|
|
461
|
-
if(this.offererAta!=null && other.offererAta!=null) {
|
|
462
|
-
if(!this.offererAta.equals(other.offererAta)) return false;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
if(this.offererInitializer==null && other.offererInitializer!=null) return false;
|
|
466
|
-
if(this.offererInitializer!=null && other.offererInitializer==null) return false;
|
|
467
|
-
if(this.offererInitializer!=null && other.offererInitializer!=null) {
|
|
468
|
-
if(this.offererInitializer!==other.offererInitializer) return false;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
return other.kind===this.kind &&
|
|
472
|
-
other.confirmations===this.confirmations &&
|
|
473
|
-
this.nonce.eq(other.nonce) &&
|
|
474
|
-
other.paymentHash===this.paymentHash &&
|
|
475
|
-
this.sequence.eq(other.sequence) &&
|
|
476
|
-
other.payIn===this.payIn &&
|
|
477
|
-
other.payOut===this.payOut &&
|
|
478
|
-
other.offerer.equals(this.offerer) &&
|
|
479
|
-
other.claimer.equals(this.claimer) &&
|
|
480
|
-
other.expiry.eq(this.expiry) &&
|
|
481
|
-
other.amount.eq(this.amount) &&
|
|
482
|
-
other.securityDeposit.eq(this.securityDeposit) &&
|
|
483
|
-
other.claimerBounty.eq(this.claimerBounty) &&
|
|
484
|
-
other.token.equals(this.token)
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
/**
|
|
488
|
-
* Converts initialize instruction data into {@link SolanaSwapData}.
|
|
489
|
-
*
|
|
490
|
-
* @param programId
|
|
491
|
-
* @param version
|
|
492
|
-
* @param initIx Decoded initialize instruction
|
|
493
|
-
* @param txoHash Parsed txo hash hint from initialize event
|
|
494
|
-
* @returns Converted and parsed swap data
|
|
495
|
-
*/
|
|
496
|
-
static fromInstruction(
|
|
497
|
-
programId: PublicKey,
|
|
498
|
-
version: "v1" | "v2",
|
|
499
|
-
initIx: InitInstruction,
|
|
500
|
-
txoHash: string
|
|
501
|
-
): SolanaSwapData {
|
|
502
|
-
const paymentHash: Buffer = Buffer.from(initIx.data.swapData.hash);
|
|
503
|
-
let securityDeposit: BN = new BN(0);
|
|
504
|
-
let claimerBounty: BN = new BN(0);
|
|
505
|
-
let payIn: boolean = true;
|
|
506
|
-
if(initIx.name === "offererInitialize") {
|
|
507
|
-
payIn = false;
|
|
508
|
-
securityDeposit = initIx.data.securityDeposit;
|
|
509
|
-
claimerBounty = initIx.data.claimerBounty;
|
|
510
|
-
}
|
|
511
|
-
if(version!=="v1" && initIx.name === "offererInitializePayIn") {
|
|
512
|
-
payIn = true;
|
|
513
|
-
securityDeposit = initIx.data.securityDeposit;
|
|
514
|
-
claimerBounty = initIx.data.claimerBounty;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
return new SolanaSwapData({
|
|
518
|
-
programId,
|
|
519
|
-
version,
|
|
520
|
-
offerer: initIx.accounts.offerer,
|
|
521
|
-
claimer: initIx.accounts.claimer,
|
|
522
|
-
token: initIx.accounts.mint,
|
|
523
|
-
amount: initIx.data.swapData.amount,
|
|
524
|
-
paymentHash: paymentHash.toString("hex"),
|
|
525
|
-
sequence: initIx.data.swapData.sequence,
|
|
526
|
-
expiry: initIx.data.swapData.expiry,
|
|
527
|
-
nonce: initIx.data.swapData.nonce,
|
|
528
|
-
confirmations: initIx.data.swapData.confirmations,
|
|
529
|
-
payOut: initIx.data.swapData.payOut,
|
|
530
|
-
kind: SwapTypeEnum.toNumber(initIx.data.swapData.kind),
|
|
531
|
-
payIn,
|
|
532
|
-
offererAta: initIx.name === "offererInitializePayIn" ? initIx.accounts.offererAta : PublicKey.default,
|
|
533
|
-
claimerAta: initIx.data.swapData.payOut ? initIx.accounts.claimerAta : PublicKey.default,
|
|
534
|
-
securityDeposit,
|
|
535
|
-
claimerBounty,
|
|
536
|
-
txoHash,
|
|
537
|
-
offererInitializer: initIx.accounts.initializer!=null ? initIx.accounts.initializer.equals(initIx.accounts.offerer) : undefined
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
/**
|
|
542
|
-
* Deserializes swap data from an on-chain escrow account state.
|
|
543
|
-
*
|
|
544
|
-
* @param programId
|
|
545
|
-
* @param version
|
|
546
|
-
* @param account Escrow account state as returned by Anchor
|
|
547
|
-
*/
|
|
548
|
-
static fromEscrowState(
|
|
549
|
-
programId: PublicKey,
|
|
550
|
-
version: "v1" | "v2",
|
|
551
|
-
account: IdlAccounts<SwapProgram | SwapProgramV2>["escrowState"]
|
|
552
|
-
) {
|
|
553
|
-
const data: IdlTypes<SwapProgram | SwapProgramV2>["SwapData"] = account.data;
|
|
554
|
-
|
|
555
|
-
return new SolanaSwapData({
|
|
556
|
-
programId,
|
|
557
|
-
version,
|
|
558
|
-
offerer: account.offerer,
|
|
559
|
-
claimer: account.claimer,
|
|
560
|
-
token: account.mint,
|
|
561
|
-
amount: data.amount,
|
|
562
|
-
paymentHash: Buffer.from(data.hash).toString("hex"),
|
|
563
|
-
sequence: data.sequence,
|
|
564
|
-
expiry: data.expiry,
|
|
565
|
-
nonce: data.nonce,
|
|
566
|
-
confirmations: data.confirmations,
|
|
567
|
-
payOut: data.payOut,
|
|
568
|
-
kind: SwapTypeEnum.toNumber(data.kind),
|
|
569
|
-
payIn: data.payIn,
|
|
570
|
-
offererAta: account.offererAta,
|
|
571
|
-
claimerAta: account.claimerAta,
|
|
572
|
-
securityDeposit: account.securityDeposit,
|
|
573
|
-
claimerBounty: account.claimerBounty,
|
|
574
|
-
offererInitializer: account.offererInitializer ?? undefined
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
/**
|
|
579
|
-
* Converts abstract swap type to Solana program kind discriminator.
|
|
580
|
-
*
|
|
581
|
-
* @param type Chain-agnostic swap type
|
|
582
|
-
*/
|
|
583
|
-
static typeToKind(type: ChainSwapType): number {
|
|
584
|
-
switch (type) {
|
|
585
|
-
case ChainSwapType.HTLC:
|
|
586
|
-
return 0;
|
|
587
|
-
case ChainSwapType.CHAIN:
|
|
588
|
-
return 1;
|
|
589
|
-
case ChainSwapType.CHAIN_NONCED:
|
|
590
|
-
return 2;
|
|
591
|
-
case ChainSwapType.CHAIN_TXID:
|
|
592
|
-
return 3;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
/**
|
|
597
|
-
* Converts Solana program kind discriminator to abstract swap type.
|
|
598
|
-
*
|
|
599
|
-
* @param value Solana program swap kind value
|
|
600
|
-
*/
|
|
601
|
-
static kindToType(value: number): ChainSwapType {
|
|
602
|
-
switch(value) {
|
|
603
|
-
case 0:
|
|
604
|
-
return ChainSwapType.HTLC;
|
|
605
|
-
case 1:
|
|
606
|
-
return ChainSwapType.CHAIN;
|
|
607
|
-
case 2:
|
|
608
|
-
return ChainSwapType.CHAIN_NONCED;
|
|
609
|
-
case 3:
|
|
610
|
-
return ChainSwapType.CHAIN_TXID;
|
|
611
|
-
}
|
|
612
|
-
throw new Error("Unknown swap kind type!");
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
/**
|
|
616
|
-
* @inheritDoc
|
|
617
|
-
*/
|
|
618
|
-
isClaimer(address: string) {
|
|
619
|
-
const _address = new PublicKey(address);
|
|
620
|
-
if(this.isPayOut()) {
|
|
621
|
-
//Also check that swapData's ATA is correct
|
|
622
|
-
const ourAta = getAssociatedTokenAddressSync(this.token, _address);
|
|
623
|
-
if(this.claimerAta==null || !this.claimerAta.equals(ourAta)) return false;
|
|
624
|
-
}
|
|
625
|
-
return this.claimer.equals(new PublicKey(address));
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
* @inheritDoc
|
|
630
|
-
*/
|
|
631
|
-
isOfferer(address: string) {
|
|
632
|
-
return this.offerer.equals(new PublicKey(address));
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* @inheritDoc
|
|
637
|
-
*/
|
|
638
|
-
getDepositToken(): string {
|
|
639
|
-
return SolanaTokens.WSOL_ADDRESS.toString();
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
/**
|
|
643
|
-
* @inheritDoc
|
|
644
|
-
*/
|
|
645
|
-
isDepositToken(token: string): boolean {
|
|
646
|
-
return SolanaTokens.WSOL_ADDRESS.equals(new PublicKey(token));
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
/**
|
|
650
|
-
* @inheritDoc
|
|
651
|
-
*/
|
|
652
|
-
getEscrowStruct(): any {
|
|
653
|
-
return {
|
|
654
|
-
accounts: {
|
|
655
|
-
offerer: this.offerer.toString(),
|
|
656
|
-
claimer: this.claimer.toString(),
|
|
657
|
-
claimerAta: this.claimerAta==null || this.claimerAta.equals(PublicKey.default) ? null : this.claimerAta.toString(),
|
|
658
|
-
offererAta: this.offererAta==null || this.offererAta.equals(PublicKey.default) ? null : this.offererAta.toString(),
|
|
659
|
-
claimerUserData: SolanaSwapProgram._SwapUserVault(this.programId, this.claimer, this.token).toString(),
|
|
660
|
-
offererUserData: SolanaSwapProgram._SwapUserVault(this.programId, this.offerer, this.token).toString(),
|
|
661
|
-
|
|
662
|
-
initializer: this.offererInitializer!=null
|
|
663
|
-
? (
|
|
664
|
-
this.offererInitializer ? this.offerer.toString() : this.claimer.toString()
|
|
665
|
-
)
|
|
666
|
-
: (
|
|
667
|
-
this.isPayIn() ? this.offerer.toString() : this.claimer.toString()
|
|
668
|
-
),
|
|
669
|
-
|
|
670
|
-
escrowState: SolanaSwapProgram._SwapEscrowState(this.programId, Buffer.from(this.paymentHash, "hex")).toString(),
|
|
671
|
-
mint: this.token.toString(),
|
|
672
|
-
vault: SolanaSwapProgram._SwapVault(this.programId, this.token).toString(),
|
|
673
|
-
vaultAuthority: SolanaSwapProgram._SwapVaultAuthority(this.programId).toString(),
|
|
674
|
-
|
|
675
|
-
systemProgram: SystemProgram.programId.toString(),
|
|
676
|
-
tokenProgram: TOKEN_PROGRAM_ID.toString(),
|
|
677
|
-
ixSysvar: SYSVAR_INSTRUCTIONS_PUBKEY.toString(),
|
|
678
|
-
},
|
|
679
|
-
data: {
|
|
680
|
-
kind: SwapTypeEnum.fromNumber(this.kind as 0 | 1 | 2 | 3),
|
|
681
|
-
confirmations: this.confirmations,
|
|
682
|
-
nonce: this.nonce.toString(10),
|
|
683
|
-
hash: [...Buffer.from(this.paymentHash, "hex")],
|
|
684
|
-
payIn: this.payIn,
|
|
685
|
-
payOut: this.payOut,
|
|
686
|
-
amount: this.amount.toString(10),
|
|
687
|
-
expiry: this.expiry.toString(10),
|
|
688
|
-
sequence: this.sequence.toString(10)
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
export class SolanaSwapDataV1 extends SolanaSwapData {
|
|
696
|
-
/**
|
|
697
|
-
* Creates swap data from structured constructor arguments.
|
|
698
|
-
*
|
|
699
|
-
* @param args Swap data fields
|
|
700
|
-
*/
|
|
701
|
-
constructor(args: SolanaSwapDataCtorArgs);
|
|
702
|
-
/**
|
|
703
|
-
* Deserializes swap data from serialized storage representation.
|
|
704
|
-
*
|
|
705
|
-
* @param data Serialized swap data from {@link SolanaSwapData.serialize}
|
|
706
|
-
*/
|
|
707
|
-
constructor(data: {type: "sol"} & Serialized<SolanaSwapData>);
|
|
708
|
-
|
|
709
|
-
constructor(data: ({type: "sol"} & Serialized<SolanaSwapData>) | SolanaSwapDataCtorArgs) {
|
|
710
|
-
super(data as any);
|
|
711
|
-
if(this.version!=="v1") throw new Error(`Invalid swap data version, expected v1, got ${this.version}`);
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
export class SolanaSwapDataV2 extends SolanaSwapData {
|
|
716
|
-
/**
|
|
717
|
-
* Creates swap data from structured constructor arguments.
|
|
718
|
-
*
|
|
719
|
-
* @param args Swap data fields
|
|
720
|
-
*/
|
|
721
|
-
constructor(args: SolanaSwapDataCtorArgs);
|
|
722
|
-
/**
|
|
723
|
-
* Deserializes swap data from serialized storage representation.
|
|
724
|
-
*
|
|
725
|
-
* @param data Serialized swap data from {@link SolanaSwapData.serialize}
|
|
726
|
-
*/
|
|
727
|
-
constructor(data: {type: "sol"} & Serialized<SolanaSwapData>);
|
|
728
|
-
|
|
729
|
-
constructor(data: ({type: "sol"} & Serialized<SolanaSwapData>) | SolanaSwapDataCtorArgs) {
|
|
730
|
-
super(data as any);
|
|
731
|
-
if(this.version!=="v2") throw new Error(`Invalid swap data version, expected v2, got ${this.version}`);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
SwapData.deserializers["sol"] = SolanaSwapData;
|
|
1
|
+
import {PublicKey, SystemProgram, SYSVAR_INSTRUCTIONS_PUBKEY} from "@solana/web3.js";
|
|
2
|
+
import * as BN from "bn.js";
|
|
3
|
+
import {ChainSwapType, SwapData} from "@atomiqlabs/base";
|
|
4
|
+
import {SwapProgram} from "./v1/programTypes";
|
|
5
|
+
import {IdlAccounts, IdlTypes} from "@coral-xyz/anchor";
|
|
6
|
+
import {SwapTypeEnum} from "./SwapTypeEnum";
|
|
7
|
+
import {Buffer} from "buffer";
|
|
8
|
+
import {getAssociatedTokenAddressSync, TOKEN_PROGRAM_ID} from "@solana/spl-token";
|
|
9
|
+
import {Serialized, toBigInt, toClaimHash, toEscrowHash} from "../../utils/Utils";
|
|
10
|
+
import {SolanaTokens} from "../chain/modules/SolanaTokens";
|
|
11
|
+
import {SingleInstructionWithAccounts} from "../program/modules/SolanaProgramEvents";
|
|
12
|
+
import {SolanaSwapProgram} from "./SolanaSwapProgram";
|
|
13
|
+
import {SwapProgramV2} from "./v2/programTypes";
|
|
14
|
+
|
|
15
|
+
export type InitInstruction = SingleInstructionWithAccounts<SwapProgram["instructions"][2 | 3] | SwapProgramV2["instructions"][2 | 3], SwapProgram>;
|
|
16
|
+
|
|
17
|
+
const EXPIRY_BLOCKHEIGHT_THRESHOLD = new BN("1000000000");
|
|
18
|
+
|
|
19
|
+
export type SolanaSwapDataCtorArgs = {
|
|
20
|
+
programId: PublicKey,
|
|
21
|
+
version: "v1" | "v2",
|
|
22
|
+
|
|
23
|
+
offerer: PublicKey,
|
|
24
|
+
claimer: PublicKey,
|
|
25
|
+
token: PublicKey,
|
|
26
|
+
amount: BN,
|
|
27
|
+
paymentHash: string,
|
|
28
|
+
sequence: BN,
|
|
29
|
+
expiry: BN,
|
|
30
|
+
|
|
31
|
+
nonce: BN,
|
|
32
|
+
confirmations: number,
|
|
33
|
+
payOut: boolean,
|
|
34
|
+
kind: number,
|
|
35
|
+
payIn: boolean,
|
|
36
|
+
offererAta?: PublicKey,
|
|
37
|
+
claimerAta?: PublicKey,
|
|
38
|
+
|
|
39
|
+
securityDeposit: BN,
|
|
40
|
+
claimerBounty: BN,
|
|
41
|
+
|
|
42
|
+
txoHash?: string,
|
|
43
|
+
offererInitializer?: boolean
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export function isSerializedData(obj: any): obj is ({type: "sol"} & Serialized<SolanaSwapData>) {
|
|
47
|
+
return obj.type==="sol";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Represents Solana swap data for executing PrTLC (on-chain) or HTLC (lightning) based swaps.
|
|
52
|
+
*
|
|
53
|
+
* @category Swaps
|
|
54
|
+
*/
|
|
55
|
+
export class SolanaSwapData extends SwapData {
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Program ID for which this swap data was created
|
|
59
|
+
*/
|
|
60
|
+
programId: PublicKey;
|
|
61
|
+
/**
|
|
62
|
+
* Program version for which this swap was created
|
|
63
|
+
*/
|
|
64
|
+
version: "v1" | "v2";
|
|
65
|
+
/**
|
|
66
|
+
* Offerer address funding the swap.
|
|
67
|
+
*/
|
|
68
|
+
offerer: PublicKey;
|
|
69
|
+
/**
|
|
70
|
+
* Claimer address receiving the swap funds.
|
|
71
|
+
*/
|
|
72
|
+
claimer: PublicKey;
|
|
73
|
+
/**
|
|
74
|
+
* Token mint used for the swap.
|
|
75
|
+
*/
|
|
76
|
+
token: PublicKey;
|
|
77
|
+
/**
|
|
78
|
+
* Swap amount.
|
|
79
|
+
*/
|
|
80
|
+
amount: BN;
|
|
81
|
+
/**
|
|
82
|
+
* Payment hash identifying the swap.
|
|
83
|
+
*/
|
|
84
|
+
paymentHash: string;
|
|
85
|
+
/**
|
|
86
|
+
* Swap sequence used for uniqueness.
|
|
87
|
+
*/
|
|
88
|
+
sequence: BN;
|
|
89
|
+
/**
|
|
90
|
+
* Swap expiry timestamp.
|
|
91
|
+
*/
|
|
92
|
+
expiry: BN;
|
|
93
|
+
/**
|
|
94
|
+
* Nonce used in claim hash derivation.
|
|
95
|
+
*/
|
|
96
|
+
nonce: BN;
|
|
97
|
+
/**
|
|
98
|
+
* Required bitcoin confirmations for claim.
|
|
99
|
+
*/
|
|
100
|
+
confirmations: number;
|
|
101
|
+
/**
|
|
102
|
+
* Whether funds are paid out to claimer wallet directly.
|
|
103
|
+
*/
|
|
104
|
+
payOut: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Solana on-chain swap kind discriminator.
|
|
107
|
+
*/
|
|
108
|
+
kind: number;
|
|
109
|
+
/**
|
|
110
|
+
* Whether funds are paid in from offerer wallet.
|
|
111
|
+
*/
|
|
112
|
+
payIn: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Optional claimer associated token account.
|
|
115
|
+
*/
|
|
116
|
+
claimerAta?: PublicKey;
|
|
117
|
+
/**
|
|
118
|
+
* Optional offerer associated token account.
|
|
119
|
+
*/
|
|
120
|
+
offererAta?: PublicKey;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Security deposit amount.
|
|
124
|
+
*/
|
|
125
|
+
securityDeposit: BN;
|
|
126
|
+
/**
|
|
127
|
+
* Claimer bounty amount.
|
|
128
|
+
*/
|
|
129
|
+
claimerBounty: BN;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Optional txo hash hint.
|
|
133
|
+
*/
|
|
134
|
+
txoHash?: string;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Optional flag whether the offerer is the initializer for V2 swap data
|
|
138
|
+
*/
|
|
139
|
+
offererInitializer?: boolean;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Creates swap data from structured constructor arguments.
|
|
143
|
+
*
|
|
144
|
+
* @param args Swap data fields
|
|
145
|
+
*/
|
|
146
|
+
constructor(args: SolanaSwapDataCtorArgs);
|
|
147
|
+
/**
|
|
148
|
+
* Deserializes swap data from serialized storage representation.
|
|
149
|
+
*
|
|
150
|
+
* @param data Serialized swap data from {@link SolanaSwapData.serialize}
|
|
151
|
+
*/
|
|
152
|
+
constructor(data: {type: "sol"} & Serialized<SolanaSwapData>);
|
|
153
|
+
|
|
154
|
+
constructor(data: ({type: "sol"} & Serialized<SolanaSwapData>) | SolanaSwapDataCtorArgs) {
|
|
155
|
+
super();
|
|
156
|
+
if(!isSerializedData(data)) {
|
|
157
|
+
this.programId = data.programId;
|
|
158
|
+
this.version = data.version;
|
|
159
|
+
this.offerer = data.offerer;
|
|
160
|
+
this.claimer = data.claimer;
|
|
161
|
+
this.token = data.token;
|
|
162
|
+
this.amount = data.amount;
|
|
163
|
+
this.paymentHash = data.paymentHash;
|
|
164
|
+
this.sequence = data.sequence;
|
|
165
|
+
this.expiry = data.expiry;
|
|
166
|
+
this.nonce = data.nonce;
|
|
167
|
+
this.confirmations = data.confirmations;
|
|
168
|
+
this.payOut = data.payOut;
|
|
169
|
+
this.kind = data.kind;
|
|
170
|
+
this.payIn = data.payIn;
|
|
171
|
+
this.claimerAta = data.claimerAta;
|
|
172
|
+
this.offererAta = data.offererAta;
|
|
173
|
+
this.securityDeposit = data.securityDeposit;
|
|
174
|
+
this.claimerBounty = data.claimerBounty;
|
|
175
|
+
this.txoHash = data.txoHash;
|
|
176
|
+
this.offererInitializer = data.offererInitializer;
|
|
177
|
+
} else {
|
|
178
|
+
this.programId = new PublicKey(data.programId ?? "4hfUykhqmD7ZRvNh1HuzVKEY7ToENixtdUKZspNDCrEM");
|
|
179
|
+
this.version = data.version ?? "v1";
|
|
180
|
+
this.offerer = new PublicKey(data.offerer);
|
|
181
|
+
this.claimer = new PublicKey(data.claimer);
|
|
182
|
+
this.token = new PublicKey(data.token);
|
|
183
|
+
this.amount = new BN(data.amount);
|
|
184
|
+
this.paymentHash = data.paymentHash;
|
|
185
|
+
this.sequence = new BN(data.sequence);
|
|
186
|
+
this.expiry = new BN(data.expiry);
|
|
187
|
+
this.nonce = new BN(data.nonce);
|
|
188
|
+
this.confirmations = data.confirmations;
|
|
189
|
+
this.payOut = data.payOut;
|
|
190
|
+
this.kind = data.kind;
|
|
191
|
+
this.payIn = data.payIn;
|
|
192
|
+
this.claimerAta = data.claimerAta==null ? undefined : new PublicKey(data.claimerAta);
|
|
193
|
+
this.offererAta = data.offererAta==null ? undefined : new PublicKey(data.offererAta);
|
|
194
|
+
this.securityDeposit = new BN(data.securityDeposit);
|
|
195
|
+
this.claimerBounty = new BN(data.claimerBounty);
|
|
196
|
+
this.txoHash = data.txoHash;
|
|
197
|
+
this.offererInitializer = data.offererInitializer;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* @inheritDoc
|
|
203
|
+
*/
|
|
204
|
+
getOfferer(): string {
|
|
205
|
+
return this.offerer.toBase58();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @inheritDoc
|
|
210
|
+
*/
|
|
211
|
+
setOfferer(newOfferer: string) {
|
|
212
|
+
this.offerer = new PublicKey(newOfferer);
|
|
213
|
+
this.offererAta = getAssociatedTokenAddressSync(this.token, this.offerer);
|
|
214
|
+
this.payIn = true;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @inheritDoc
|
|
219
|
+
*/
|
|
220
|
+
getClaimer(): string {
|
|
221
|
+
return this.claimer.toBase58();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @inheritDoc
|
|
226
|
+
*/
|
|
227
|
+
setClaimer(newClaimer: string) {
|
|
228
|
+
this.claimer = new PublicKey(newClaimer);
|
|
229
|
+
this.payIn = false;
|
|
230
|
+
this.payOut = true;
|
|
231
|
+
this.claimerAta = getAssociatedTokenAddressSync(this.token, this.claimer);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @inheritDoc
|
|
236
|
+
*/
|
|
237
|
+
serialize(): {type: "sol"} & Serialized<SolanaSwapData> {
|
|
238
|
+
return {
|
|
239
|
+
type: "sol",
|
|
240
|
+
programId: this.programId?.toBase58(),
|
|
241
|
+
version: this.version,
|
|
242
|
+
offerer: this.offerer?.toBase58(),
|
|
243
|
+
claimer: this.claimer?.toBase58(),
|
|
244
|
+
token: this.token?.toBase58(),
|
|
245
|
+
amount: this.amount?.toString(10),
|
|
246
|
+
paymentHash: this.paymentHash,
|
|
247
|
+
sequence: this.sequence?.toString(10),
|
|
248
|
+
expiry: this.expiry?.toString(10),
|
|
249
|
+
nonce: this.nonce?.toString(10),
|
|
250
|
+
confirmations: this.confirmations,
|
|
251
|
+
payOut: this.payOut,
|
|
252
|
+
kind: this.kind,
|
|
253
|
+
payIn: this.payIn,
|
|
254
|
+
offererAta: this.offererAta?.toBase58(),
|
|
255
|
+
claimerAta: this.claimerAta?.toBase58(),
|
|
256
|
+
securityDeposit: this.securityDeposit?.toString(10),
|
|
257
|
+
claimerBounty: this.claimerBounty?.toString(10),
|
|
258
|
+
txoHash: this.txoHash,
|
|
259
|
+
offererInitializer: this.offererInitializer
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* @inheritDoc
|
|
265
|
+
*/
|
|
266
|
+
getAmount(): bigint {
|
|
267
|
+
return toBigInt(this.amount);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* @inheritDoc
|
|
272
|
+
*/
|
|
273
|
+
getToken(): string {
|
|
274
|
+
return this.token.toString();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* @inheritDoc
|
|
279
|
+
*/
|
|
280
|
+
isToken(token: string): boolean {
|
|
281
|
+
return this.token.equals(new PublicKey(token));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* @inheritDoc
|
|
286
|
+
*/
|
|
287
|
+
getType(): ChainSwapType {
|
|
288
|
+
return SolanaSwapData.kindToType(this.kind);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* @inheritDoc
|
|
293
|
+
*/
|
|
294
|
+
getExpiry(): bigint {
|
|
295
|
+
if(this.expiry.lt(EXPIRY_BLOCKHEIGHT_THRESHOLD)) throw new Error("Expiry expressed as bitcoin blockheight!");
|
|
296
|
+
return toBigInt(this.expiry);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* @inheritDoc
|
|
301
|
+
*/
|
|
302
|
+
getConfirmationsHint(): number {
|
|
303
|
+
return this.confirmations;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @inheritDoc
|
|
308
|
+
*/
|
|
309
|
+
getNonceHint(): bigint {
|
|
310
|
+
return toBigInt(this.nonce);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* @inheritDoc
|
|
315
|
+
*/
|
|
316
|
+
isPayIn(): boolean {
|
|
317
|
+
return this.payIn;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* @inheritDoc
|
|
322
|
+
*/
|
|
323
|
+
isPayOut(): boolean {
|
|
324
|
+
return this.payOut;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* @inheritDoc
|
|
329
|
+
*/
|
|
330
|
+
isTrackingReputation(): boolean {
|
|
331
|
+
return !this.payOut;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* @inheritDoc
|
|
336
|
+
*/
|
|
337
|
+
getClaimHash(): string {
|
|
338
|
+
return toClaimHash(this.paymentHash, toBigInt(this.nonce), this.confirmations);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* @inheritDoc
|
|
343
|
+
*/
|
|
344
|
+
getEscrowHash(): string {
|
|
345
|
+
return toEscrowHash(this.paymentHash, this.sequence);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* @inheritDoc
|
|
350
|
+
*/
|
|
351
|
+
getSequence(): bigint {
|
|
352
|
+
return toBigInt(this.sequence);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* @inheritDoc
|
|
357
|
+
*/
|
|
358
|
+
getTxoHashHint(): string | null {
|
|
359
|
+
if(this.txoHash==="0000000000000000000000000000000000000000000000000000000000000000") return null; //Txo hash opt-out flag
|
|
360
|
+
return this.txoHash ?? null
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* @inheritDoc
|
|
365
|
+
*/
|
|
366
|
+
getHTLCHashHint(): string | null {
|
|
367
|
+
if(this.getType()===ChainSwapType.HTLC) return this.paymentHash;
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* @inheritDoc
|
|
373
|
+
*/
|
|
374
|
+
getExtraData(): string | null {
|
|
375
|
+
return this.txoHash ?? null;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* @inheritDoc
|
|
380
|
+
*/
|
|
381
|
+
setExtraData(txoHash: string): void {
|
|
382
|
+
this.txoHash = txoHash;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* @inheritDoc
|
|
387
|
+
*/
|
|
388
|
+
getSecurityDeposit(): bigint {
|
|
389
|
+
return toBigInt(this.securityDeposit);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @inheritDoc
|
|
394
|
+
*/
|
|
395
|
+
getClaimerBounty(): bigint {
|
|
396
|
+
return toBigInt(this.claimerBounty);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* @inheritDoc
|
|
401
|
+
*/
|
|
402
|
+
getTotalDeposit(): bigint {
|
|
403
|
+
return toBigInt(this.claimerBounty.lt(this.securityDeposit) ? this.securityDeposit : this.claimerBounty);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Serializes the swap data into the Solana program `SwapData` struct representation.
|
|
408
|
+
*/
|
|
409
|
+
toSwapDataStruct(): IdlTypes<SwapProgram>["SwapData"] {
|
|
410
|
+
return {
|
|
411
|
+
kind: SwapTypeEnum.fromNumber(this.kind as 0 | 1 | 2 | 3),
|
|
412
|
+
confirmations: this.confirmations,
|
|
413
|
+
nonce: this.nonce,
|
|
414
|
+
hash: [...Buffer.from(this.paymentHash, "hex")],
|
|
415
|
+
payIn: this.payIn,
|
|
416
|
+
payOut: this.payOut,
|
|
417
|
+
amount: this.amount,
|
|
418
|
+
expiry: this.expiry,
|
|
419
|
+
sequence: this.sequence
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Checks whether the provided escrow account matches this swap data.
|
|
425
|
+
*
|
|
426
|
+
* @param account Escrow account data fetched from chain
|
|
427
|
+
*/
|
|
428
|
+
correctPDA(account: IdlAccounts<SwapProgram | SwapProgramV2>["escrowState"]): boolean {
|
|
429
|
+
return SwapTypeEnum.toNumber(account.data.kind)===this.kind &&
|
|
430
|
+
account.data.confirmations===this.confirmations &&
|
|
431
|
+
this.nonce.eq(account.data.nonce) &&
|
|
432
|
+
Buffer.from(account.data.hash).toString("hex")===this.paymentHash &&
|
|
433
|
+
account.data.payIn===this.payIn &&
|
|
434
|
+
account.data.payOut===this.payOut &&
|
|
435
|
+
this.amount.eq(account.data.amount) &&
|
|
436
|
+
this.expiry.eq(account.data.expiry) &&
|
|
437
|
+
this.sequence.eq(account.data.sequence) &&
|
|
438
|
+
|
|
439
|
+
account.offerer.equals(this.offerer) &&
|
|
440
|
+
(this.offererAta==null || account.offererAta.equals(this.offererAta)) &&
|
|
441
|
+
account.claimer.equals(this.claimer) &&
|
|
442
|
+
(this.claimerAta==null || account.claimerAta.equals(this.claimerAta)) &&
|
|
443
|
+
account.mint.equals(this.token) &&
|
|
444
|
+
this.claimerBounty.eq(account.claimerBounty) &&
|
|
445
|
+
this.securityDeposit.eq(account.securityDeposit) &&
|
|
446
|
+
(this.offererInitializer==null || account.offererInitializer===this.offererInitializer);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* @inheritDoc
|
|
451
|
+
*/
|
|
452
|
+
equals(other: SolanaSwapData): boolean {
|
|
453
|
+
if(this.claimerAta==null && other.claimerAta!=null) return false;
|
|
454
|
+
if(this.claimerAta!=null && other.claimerAta==null) return false;
|
|
455
|
+
if(this.claimerAta!=null && other.claimerAta!=null) {
|
|
456
|
+
if(!this.claimerAta.equals(other.claimerAta)) return false;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if(this.offererAta==null && other.offererAta!=null) return false;
|
|
460
|
+
if(this.offererAta!=null && other.offererAta==null) return false;
|
|
461
|
+
if(this.offererAta!=null && other.offererAta!=null) {
|
|
462
|
+
if(!this.offererAta.equals(other.offererAta)) return false;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if(this.offererInitializer==null && other.offererInitializer!=null) return false;
|
|
466
|
+
if(this.offererInitializer!=null && other.offererInitializer==null) return false;
|
|
467
|
+
if(this.offererInitializer!=null && other.offererInitializer!=null) {
|
|
468
|
+
if(this.offererInitializer!==other.offererInitializer) return false;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return other.kind===this.kind &&
|
|
472
|
+
other.confirmations===this.confirmations &&
|
|
473
|
+
this.nonce.eq(other.nonce) &&
|
|
474
|
+
other.paymentHash===this.paymentHash &&
|
|
475
|
+
this.sequence.eq(other.sequence) &&
|
|
476
|
+
other.payIn===this.payIn &&
|
|
477
|
+
other.payOut===this.payOut &&
|
|
478
|
+
other.offerer.equals(this.offerer) &&
|
|
479
|
+
other.claimer.equals(this.claimer) &&
|
|
480
|
+
other.expiry.eq(this.expiry) &&
|
|
481
|
+
other.amount.eq(this.amount) &&
|
|
482
|
+
other.securityDeposit.eq(this.securityDeposit) &&
|
|
483
|
+
other.claimerBounty.eq(this.claimerBounty) &&
|
|
484
|
+
other.token.equals(this.token)
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Converts initialize instruction data into {@link SolanaSwapData}.
|
|
489
|
+
*
|
|
490
|
+
* @param programId
|
|
491
|
+
* @param version
|
|
492
|
+
* @param initIx Decoded initialize instruction
|
|
493
|
+
* @param txoHash Parsed txo hash hint from initialize event
|
|
494
|
+
* @returns Converted and parsed swap data
|
|
495
|
+
*/
|
|
496
|
+
static fromInstruction(
|
|
497
|
+
programId: PublicKey,
|
|
498
|
+
version: "v1" | "v2",
|
|
499
|
+
initIx: InitInstruction,
|
|
500
|
+
txoHash: string
|
|
501
|
+
): SolanaSwapData {
|
|
502
|
+
const paymentHash: Buffer = Buffer.from(initIx.data.swapData.hash);
|
|
503
|
+
let securityDeposit: BN = new BN(0);
|
|
504
|
+
let claimerBounty: BN = new BN(0);
|
|
505
|
+
let payIn: boolean = true;
|
|
506
|
+
if(initIx.name === "offererInitialize") {
|
|
507
|
+
payIn = false;
|
|
508
|
+
securityDeposit = initIx.data.securityDeposit;
|
|
509
|
+
claimerBounty = initIx.data.claimerBounty;
|
|
510
|
+
}
|
|
511
|
+
if(version!=="v1" && initIx.name === "offererInitializePayIn") {
|
|
512
|
+
payIn = true;
|
|
513
|
+
securityDeposit = initIx.data.securityDeposit;
|
|
514
|
+
claimerBounty = initIx.data.claimerBounty;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return new SolanaSwapData({
|
|
518
|
+
programId,
|
|
519
|
+
version,
|
|
520
|
+
offerer: initIx.accounts.offerer,
|
|
521
|
+
claimer: initIx.accounts.claimer,
|
|
522
|
+
token: initIx.accounts.mint,
|
|
523
|
+
amount: initIx.data.swapData.amount,
|
|
524
|
+
paymentHash: paymentHash.toString("hex"),
|
|
525
|
+
sequence: initIx.data.swapData.sequence,
|
|
526
|
+
expiry: initIx.data.swapData.expiry,
|
|
527
|
+
nonce: initIx.data.swapData.nonce,
|
|
528
|
+
confirmations: initIx.data.swapData.confirmations,
|
|
529
|
+
payOut: initIx.data.swapData.payOut,
|
|
530
|
+
kind: SwapTypeEnum.toNumber(initIx.data.swapData.kind),
|
|
531
|
+
payIn,
|
|
532
|
+
offererAta: initIx.name === "offererInitializePayIn" ? initIx.accounts.offererAta : PublicKey.default,
|
|
533
|
+
claimerAta: initIx.data.swapData.payOut ? initIx.accounts.claimerAta : PublicKey.default,
|
|
534
|
+
securityDeposit,
|
|
535
|
+
claimerBounty,
|
|
536
|
+
txoHash,
|
|
537
|
+
offererInitializer: initIx.accounts.initializer!=null ? initIx.accounts.initializer.equals(initIx.accounts.offerer) : undefined
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Deserializes swap data from an on-chain escrow account state.
|
|
543
|
+
*
|
|
544
|
+
* @param programId
|
|
545
|
+
* @param version
|
|
546
|
+
* @param account Escrow account state as returned by Anchor
|
|
547
|
+
*/
|
|
548
|
+
static fromEscrowState(
|
|
549
|
+
programId: PublicKey,
|
|
550
|
+
version: "v1" | "v2",
|
|
551
|
+
account: IdlAccounts<SwapProgram | SwapProgramV2>["escrowState"]
|
|
552
|
+
) {
|
|
553
|
+
const data: IdlTypes<SwapProgram | SwapProgramV2>["SwapData"] = account.data;
|
|
554
|
+
|
|
555
|
+
return new SolanaSwapData({
|
|
556
|
+
programId,
|
|
557
|
+
version,
|
|
558
|
+
offerer: account.offerer,
|
|
559
|
+
claimer: account.claimer,
|
|
560
|
+
token: account.mint,
|
|
561
|
+
amount: data.amount,
|
|
562
|
+
paymentHash: Buffer.from(data.hash).toString("hex"),
|
|
563
|
+
sequence: data.sequence,
|
|
564
|
+
expiry: data.expiry,
|
|
565
|
+
nonce: data.nonce,
|
|
566
|
+
confirmations: data.confirmations,
|
|
567
|
+
payOut: data.payOut,
|
|
568
|
+
kind: SwapTypeEnum.toNumber(data.kind),
|
|
569
|
+
payIn: data.payIn,
|
|
570
|
+
offererAta: account.offererAta,
|
|
571
|
+
claimerAta: account.claimerAta,
|
|
572
|
+
securityDeposit: account.securityDeposit,
|
|
573
|
+
claimerBounty: account.claimerBounty,
|
|
574
|
+
offererInitializer: account.offererInitializer ?? undefined
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Converts abstract swap type to Solana program kind discriminator.
|
|
580
|
+
*
|
|
581
|
+
* @param type Chain-agnostic swap type
|
|
582
|
+
*/
|
|
583
|
+
static typeToKind(type: ChainSwapType): number {
|
|
584
|
+
switch (type) {
|
|
585
|
+
case ChainSwapType.HTLC:
|
|
586
|
+
return 0;
|
|
587
|
+
case ChainSwapType.CHAIN:
|
|
588
|
+
return 1;
|
|
589
|
+
case ChainSwapType.CHAIN_NONCED:
|
|
590
|
+
return 2;
|
|
591
|
+
case ChainSwapType.CHAIN_TXID:
|
|
592
|
+
return 3;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Converts Solana program kind discriminator to abstract swap type.
|
|
598
|
+
*
|
|
599
|
+
* @param value Solana program swap kind value
|
|
600
|
+
*/
|
|
601
|
+
static kindToType(value: number): ChainSwapType {
|
|
602
|
+
switch(value) {
|
|
603
|
+
case 0:
|
|
604
|
+
return ChainSwapType.HTLC;
|
|
605
|
+
case 1:
|
|
606
|
+
return ChainSwapType.CHAIN;
|
|
607
|
+
case 2:
|
|
608
|
+
return ChainSwapType.CHAIN_NONCED;
|
|
609
|
+
case 3:
|
|
610
|
+
return ChainSwapType.CHAIN_TXID;
|
|
611
|
+
}
|
|
612
|
+
throw new Error("Unknown swap kind type!");
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* @inheritDoc
|
|
617
|
+
*/
|
|
618
|
+
isClaimer(address: string) {
|
|
619
|
+
const _address = new PublicKey(address);
|
|
620
|
+
if(this.isPayOut()) {
|
|
621
|
+
//Also check that swapData's ATA is correct
|
|
622
|
+
const ourAta = getAssociatedTokenAddressSync(this.token, _address);
|
|
623
|
+
if(this.claimerAta==null || !this.claimerAta.equals(ourAta)) return false;
|
|
624
|
+
}
|
|
625
|
+
return this.claimer.equals(new PublicKey(address));
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* @inheritDoc
|
|
630
|
+
*/
|
|
631
|
+
isOfferer(address: string) {
|
|
632
|
+
return this.offerer.equals(new PublicKey(address));
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* @inheritDoc
|
|
637
|
+
*/
|
|
638
|
+
getDepositToken(): string {
|
|
639
|
+
return SolanaTokens.WSOL_ADDRESS.toString();
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* @inheritDoc
|
|
644
|
+
*/
|
|
645
|
+
isDepositToken(token: string): boolean {
|
|
646
|
+
return SolanaTokens.WSOL_ADDRESS.equals(new PublicKey(token));
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* @inheritDoc
|
|
651
|
+
*/
|
|
652
|
+
getEscrowStruct(): any {
|
|
653
|
+
return {
|
|
654
|
+
accounts: {
|
|
655
|
+
offerer: this.offerer.toString(),
|
|
656
|
+
claimer: this.claimer.toString(),
|
|
657
|
+
claimerAta: this.claimerAta==null || this.claimerAta.equals(PublicKey.default) ? null : this.claimerAta.toString(),
|
|
658
|
+
offererAta: this.offererAta==null || this.offererAta.equals(PublicKey.default) ? null : this.offererAta.toString(),
|
|
659
|
+
claimerUserData: SolanaSwapProgram._SwapUserVault(this.programId, this.claimer, this.token).toString(),
|
|
660
|
+
offererUserData: SolanaSwapProgram._SwapUserVault(this.programId, this.offerer, this.token).toString(),
|
|
661
|
+
|
|
662
|
+
initializer: this.offererInitializer!=null
|
|
663
|
+
? (
|
|
664
|
+
this.offererInitializer ? this.offerer.toString() : this.claimer.toString()
|
|
665
|
+
)
|
|
666
|
+
: (
|
|
667
|
+
this.isPayIn() ? this.offerer.toString() : this.claimer.toString()
|
|
668
|
+
),
|
|
669
|
+
|
|
670
|
+
escrowState: SolanaSwapProgram._SwapEscrowState(this.programId, Buffer.from(this.paymentHash, "hex")).toString(),
|
|
671
|
+
mint: this.token.toString(),
|
|
672
|
+
vault: SolanaSwapProgram._SwapVault(this.programId, this.token).toString(),
|
|
673
|
+
vaultAuthority: SolanaSwapProgram._SwapVaultAuthority(this.programId).toString(),
|
|
674
|
+
|
|
675
|
+
systemProgram: SystemProgram.programId.toString(),
|
|
676
|
+
tokenProgram: TOKEN_PROGRAM_ID.toString(),
|
|
677
|
+
ixSysvar: SYSVAR_INSTRUCTIONS_PUBKEY.toString(),
|
|
678
|
+
},
|
|
679
|
+
data: {
|
|
680
|
+
kind: SwapTypeEnum.fromNumber(this.kind as 0 | 1 | 2 | 3),
|
|
681
|
+
confirmations: this.confirmations,
|
|
682
|
+
nonce: this.nonce.toString(10),
|
|
683
|
+
hash: [...Buffer.from(this.paymentHash, "hex")],
|
|
684
|
+
payIn: this.payIn,
|
|
685
|
+
payOut: this.payOut,
|
|
686
|
+
amount: this.amount.toString(10),
|
|
687
|
+
expiry: this.expiry.toString(10),
|
|
688
|
+
sequence: this.sequence.toString(10)
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
export class SolanaSwapDataV1 extends SolanaSwapData {
|
|
696
|
+
/**
|
|
697
|
+
* Creates swap data from structured constructor arguments.
|
|
698
|
+
*
|
|
699
|
+
* @param args Swap data fields
|
|
700
|
+
*/
|
|
701
|
+
constructor(args: SolanaSwapDataCtorArgs);
|
|
702
|
+
/**
|
|
703
|
+
* Deserializes swap data from serialized storage representation.
|
|
704
|
+
*
|
|
705
|
+
* @param data Serialized swap data from {@link SolanaSwapData.serialize}
|
|
706
|
+
*/
|
|
707
|
+
constructor(data: {type: "sol"} & Serialized<SolanaSwapData>);
|
|
708
|
+
|
|
709
|
+
constructor(data: ({type: "sol"} & Serialized<SolanaSwapData>) | SolanaSwapDataCtorArgs) {
|
|
710
|
+
super(data as any);
|
|
711
|
+
if(this.version!=="v1") throw new Error(`Invalid swap data version, expected v1, got ${this.version}`);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
export class SolanaSwapDataV2 extends SolanaSwapData {
|
|
716
|
+
/**
|
|
717
|
+
* Creates swap data from structured constructor arguments.
|
|
718
|
+
*
|
|
719
|
+
* @param args Swap data fields
|
|
720
|
+
*/
|
|
721
|
+
constructor(args: SolanaSwapDataCtorArgs);
|
|
722
|
+
/**
|
|
723
|
+
* Deserializes swap data from serialized storage representation.
|
|
724
|
+
*
|
|
725
|
+
* @param data Serialized swap data from {@link SolanaSwapData.serialize}
|
|
726
|
+
*/
|
|
727
|
+
constructor(data: {type: "sol"} & Serialized<SolanaSwapData>);
|
|
728
|
+
|
|
729
|
+
constructor(data: ({type: "sol"} & Serialized<SolanaSwapData>) | SolanaSwapDataCtorArgs) {
|
|
730
|
+
super(data as any);
|
|
731
|
+
if(this.version!=="v2") throw new Error(`Invalid swap data version, expected v2, got ${this.version}`);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
SwapData.deserializers["sol"] = SolanaSwapData;
|