@ledgerhq/coin-tester-solana 1.1.0 → 1.1.1-nightly.1
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +22 -0
- package/lib/src/connection.d.ts +5 -1
- package/lib/src/connection.d.ts.map +1 -1
- package/lib/src/connection.js +23 -1
- package/lib/src/connection.js.map +1 -1
- package/lib/src/fixtures.d.ts +1 -0
- package/lib/src/fixtures.d.ts.map +1 -1
- package/lib/src/fixtures.js +1 -0
- package/lib/src/fixtures.js.map +1 -1
- package/lib/src/scenarii/solana.d.ts.map +1 -1
- package/lib/src/scenarii/solana.js +120 -2
- package/lib/src/scenarii/solana.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib-es/src/connection.d.ts +5 -1
- package/lib-es/src/connection.d.ts.map +1 -1
- package/lib-es/src/connection.js +23 -1
- package/lib-es/src/connection.js.map +1 -1
- package/lib-es/src/fixtures.d.ts +1 -0
- package/lib-es/src/fixtures.d.ts.map +1 -1
- package/lib-es/src/fixtures.js +1 -0
- package/lib-es/src/fixtures.js.map +1 -1
- package/lib-es/src/scenarii/solana.d.ts.map +1 -1
- package/lib-es/src/scenarii/solana.js +120 -2
- package/lib-es/src/scenarii/solana.js.map +1 -1
- package/lib-es/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/connection.ts +32 -1
- package/src/fixtures.ts +1 -0
- package/src/scenarii/solana.ts +157 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ledgerhq/coin-tester-solana",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1-nightly.1",
|
|
4
4
|
"description": "Ledger Solana Coin Tester",
|
|
5
5
|
"main": "src/scenarii.test.ts",
|
|
6
6
|
"keywords": [
|
|
@@ -49,14 +49,14 @@
|
|
|
49
49
|
"bignumber.js": "^9",
|
|
50
50
|
"docker-compose": "^1",
|
|
51
51
|
"msw": "^2",
|
|
52
|
-
"@ledgerhq/coin-framework": "^5.
|
|
52
|
+
"@ledgerhq/coin-framework": "^5.3.0-nightly.1",
|
|
53
53
|
"@ledgerhq/coin-tester": "^0.6.0",
|
|
54
|
-
"@ledgerhq/coin-solana": "^0.25.
|
|
55
|
-
"@ledgerhq/cryptoassets": "^13.18.0",
|
|
56
|
-
"@ledgerhq/live-
|
|
57
|
-
"@ledgerhq/live-signer-solana": "^0.2.0",
|
|
54
|
+
"@ledgerhq/coin-solana": "^0.25.1-nightly.1",
|
|
55
|
+
"@ledgerhq/cryptoassets": "^13.18.1-nightly.0",
|
|
56
|
+
"@ledgerhq/live-signer-solana": "^0.2.1-nightly.1",
|
|
58
57
|
"@ledgerhq/types-cryptoassets": "^7.23.0",
|
|
59
|
-
"@ledgerhq/types-live": "^6.
|
|
58
|
+
"@ledgerhq/types-live": "^6.73.0-nightly.1",
|
|
59
|
+
"@ledgerhq/live-env": "^2.9.1-nightly.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@types/jest": "^29",
|
package/src/connection.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Authorized,
|
|
3
|
+
Connection,
|
|
4
|
+
Keypair,
|
|
5
|
+
PublicKey,
|
|
6
|
+
StakeProgram,
|
|
7
|
+
VoteAccountInfo,
|
|
8
|
+
} from "@solana/web3.js";
|
|
2
9
|
import { createAssociatedTokenAccountIdempotent, mintTo } from "@solana/spl-token";
|
|
3
10
|
import { TokenCurrency } from "@ledgerhq/types-cryptoassets";
|
|
4
11
|
import { SolanaTokenProgram } from "@ledgerhq/coin-solana/types";
|
|
@@ -16,6 +23,8 @@ export const PAYER = Keypair.fromSecretKey(
|
|
|
16
23
|
207,
|
|
17
24
|
]),
|
|
18
25
|
);
|
|
26
|
+
export const STAKE_ACCOUNT = Keypair.generate();
|
|
27
|
+
export let VOTE_ACCOUNT: VoteAccountInfo | null = null;
|
|
19
28
|
|
|
20
29
|
export async function createSplAccount(
|
|
21
30
|
address: string,
|
|
@@ -46,3 +55,25 @@ export async function createSplAccount(
|
|
|
46
55
|
);
|
|
47
56
|
await connection.confirmTransaction({ signature, ...latest });
|
|
48
57
|
}
|
|
58
|
+
|
|
59
|
+
export async function initVoteAccount() {
|
|
60
|
+
const voteAccounts = await connection.getVoteAccounts();
|
|
61
|
+
VOTE_ACCOUNT = voteAccounts.current[0];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function initStakeAccount(address: string, amount: number) {
|
|
65
|
+
const authority = new PublicKey(address);
|
|
66
|
+
const transaction = StakeProgram.createAccount({
|
|
67
|
+
fromPubkey: PAYER.publicKey,
|
|
68
|
+
stakePubkey: STAKE_ACCOUNT.publicKey,
|
|
69
|
+
authorized: new Authorized(authority, authority),
|
|
70
|
+
lamports: amount,
|
|
71
|
+
});
|
|
72
|
+
const latest = await connection.getLatestBlockhash();
|
|
73
|
+
transaction.feePayer = PAYER.publicKey;
|
|
74
|
+
transaction.recentBlockhash = latest.blockhash;
|
|
75
|
+
transaction.lastValidBlockHeight = latest.lastValidBlockHeight;
|
|
76
|
+
transaction.sign(PAYER, STAKE_ACCOUNT);
|
|
77
|
+
const signature = await connection.sendRawTransaction(transaction.serialize());
|
|
78
|
+
await connection.confirmTransaction({ signature, ...latest });
|
|
79
|
+
}
|
package/src/fixtures.ts
CHANGED
|
@@ -13,6 +13,7 @@ export const RECIPIENT = "Hj69wRzkrFuf1Nby4yzPEFHdsmQdMoVYjvDKZSLjZFEp";
|
|
|
13
13
|
export const SOLANA = getCryptoCurrencyById("solana");
|
|
14
14
|
export const SOLANA_USDC = getTokenById("solana/spl/epjfwdd5aufqssqem2qn1xzybapc8g4weggkzwytdt1v");
|
|
15
15
|
export const SOLANA_CWIF = getTokenById("solana/spl/7atgf8kqo4wjrd5atgx7t1v2zvvykpjbffnevf1icfv1");
|
|
16
|
+
export const WITHDRAWABLE_AMOUNT = 2e9;
|
|
16
17
|
|
|
17
18
|
export const makeAccount = (
|
|
18
19
|
address: string,
|
package/src/scenarii/solana.ts
CHANGED
|
@@ -3,7 +3,15 @@ import { SolanaAccount, Transaction as SolanaTransaction } from "@ledgerhq/coin-
|
|
|
3
3
|
import { killSpeculos, spawnSpeculos } from "@ledgerhq/coin-tester/signers/speculos";
|
|
4
4
|
import resolver from "@ledgerhq/coin-solana/hw-getAddress";
|
|
5
5
|
import { LegacySignerSolana } from "@ledgerhq/live-signer-solana";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
RECIPIENT,
|
|
8
|
+
SOLANA,
|
|
9
|
+
SOLANA_CWIF,
|
|
10
|
+
SOLANA_USDC,
|
|
11
|
+
WITHDRAWABLE_AMOUNT,
|
|
12
|
+
initMSW,
|
|
13
|
+
makeAccount,
|
|
14
|
+
} from "../fixtures";
|
|
7
15
|
import { CoinConfig } from "@ledgerhq/coin-framework/config";
|
|
8
16
|
import solanaCoinConfig, { SolanaCoinConfig } from "@ledgerhq/coin-solana/config";
|
|
9
17
|
import BigNumber from "bignumber.js";
|
|
@@ -12,7 +20,14 @@ import { airdrop, killAgave, spawnAgave } from "../agave";
|
|
|
12
20
|
import { encodeAccountIdWithTokenAccountAddress } from "@ledgerhq/coin-solana/logic";
|
|
13
21
|
import { TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync } from "@solana/spl-token";
|
|
14
22
|
import { PublicKey } from "@solana/web3.js";
|
|
15
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
PAYER,
|
|
25
|
+
STAKE_ACCOUNT,
|
|
26
|
+
VOTE_ACCOUNT,
|
|
27
|
+
createSplAccount,
|
|
28
|
+
initStakeAccount,
|
|
29
|
+
initVoteAccount,
|
|
30
|
+
} from "../connection";
|
|
16
31
|
import { Config, getChainAPI } from "@ledgerhq/coin-solana/network/index";
|
|
17
32
|
import { makeBridges } from "@ledgerhq/coin-solana/bridge/bridge";
|
|
18
33
|
|
|
@@ -26,6 +41,14 @@ type SolanaScenarioTransaction = ScenarioTransaction<SolanaTransaction, SolanaAc
|
|
|
26
41
|
export const defaultNanoApp = { firmware: "2.4.2", version: "1.9.1" } as const;
|
|
27
42
|
|
|
28
43
|
function makeScenarioTransactions(address: string): SolanaScenarioTransaction[] {
|
|
44
|
+
if (!VOTE_ACCOUNT) {
|
|
45
|
+
throw new Error("Vote account not initialized");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!STAKE_ACCOUNT) {
|
|
49
|
+
throw new Error("Stake account not initialized");
|
|
50
|
+
}
|
|
51
|
+
|
|
29
52
|
const scenarioSendSolTransaction: SolanaScenarioTransaction = {
|
|
30
53
|
name: "Send 1 Sol",
|
|
31
54
|
amount: new BigNumber(1e9),
|
|
@@ -166,6 +189,76 @@ function makeScenarioTransactions(address: string): SolanaScenarioTransaction[]
|
|
|
166
189
|
},
|
|
167
190
|
};
|
|
168
191
|
|
|
192
|
+
const scenarioCreateSolStakeAccountTransaction: SolanaScenarioTransaction = {
|
|
193
|
+
name: "Create Stake Account 1 Sol",
|
|
194
|
+
amount: new BigNumber(1e9),
|
|
195
|
+
model: {
|
|
196
|
+
kind: "stake.createAccount",
|
|
197
|
+
uiState: { delegate: { voteAccAddress: VOTE_ACCOUNT.votePubkey } },
|
|
198
|
+
},
|
|
199
|
+
expect: (previousAccount, currentAccount) => {
|
|
200
|
+
const [latestOperation] = currentAccount.operations;
|
|
201
|
+
expect(currentAccount.operations.length - previousAccount.operations.length).toEqual(1);
|
|
202
|
+
expect(latestOperation.type).toEqual("DELEGATE");
|
|
203
|
+
expect(latestOperation.value).toStrictEqual(latestOperation.fee);
|
|
204
|
+
expect(latestOperation.senders).toStrictEqual([]);
|
|
205
|
+
expect(latestOperation.recipients).toStrictEqual([]);
|
|
206
|
+
expect(latestOperation.extra).toStrictEqual({
|
|
207
|
+
stake: { address: VOTE_ACCOUNT?.votePubkey, amount: new BigNumber(1e9 + 2287880) }, // amount + rent exempt reserve + fee
|
|
208
|
+
});
|
|
209
|
+
expect(currentAccount.balance).toStrictEqual(
|
|
210
|
+
previousAccount.balance.minus(latestOperation.value),
|
|
211
|
+
);
|
|
212
|
+
expect(currentAccount.spendableBalance).toStrictEqual(
|
|
213
|
+
previousAccount.spendableBalance.minus(1e9 + 2297880),
|
|
214
|
+
);
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const scenarioActivateStakeAccount: SolanaScenarioTransaction = {
|
|
219
|
+
name: "Activate Stake Account",
|
|
220
|
+
model: {
|
|
221
|
+
kind: "stake.delegate",
|
|
222
|
+
uiState: {
|
|
223
|
+
stakeAccAddr: STAKE_ACCOUNT.publicKey.toBase58(),
|
|
224
|
+
voteAccAddr: VOTE_ACCOUNT.votePubkey,
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
expect: (previousAccount, currentAccount) => {
|
|
228
|
+
const [latestOperation] = currentAccount.operations;
|
|
229
|
+
expect(currentAccount.operations.length - previousAccount.operations.length).toEqual(1);
|
|
230
|
+
expect(latestOperation.type).toEqual("DELEGATE");
|
|
231
|
+
expect(latestOperation.value).toStrictEqual(latestOperation.fee);
|
|
232
|
+
expect(latestOperation.senders).toStrictEqual([]);
|
|
233
|
+
expect(latestOperation.recipients).toStrictEqual([]);
|
|
234
|
+
expect(latestOperation.extra).toStrictEqual({
|
|
235
|
+
stake: { address: VOTE_ACCOUNT?.votePubkey, amount: latestOperation.value },
|
|
236
|
+
});
|
|
237
|
+
expect(currentAccount.balance).toStrictEqual(
|
|
238
|
+
previousAccount.balance.minus(latestOperation.value),
|
|
239
|
+
);
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const scenarioDeactivateStakeAccount: SolanaScenarioTransaction = {
|
|
244
|
+
name: "Deactivate Stake Account",
|
|
245
|
+
model: {
|
|
246
|
+
kind: "stake.undelegate",
|
|
247
|
+
uiState: { stakeAccAddr: STAKE_ACCOUNT.publicKey.toBase58() },
|
|
248
|
+
},
|
|
249
|
+
expect: (previousAccount, currentAccount) => {
|
|
250
|
+
const [latestOperation] = currentAccount.operations;
|
|
251
|
+
expect(currentAccount.operations.length - previousAccount.operations.length).toEqual(1);
|
|
252
|
+
expect(latestOperation.type).toEqual("UNDELEGATE");
|
|
253
|
+
expect(latestOperation.value).toStrictEqual(latestOperation.fee);
|
|
254
|
+
expect(latestOperation.senders).toStrictEqual([]);
|
|
255
|
+
expect(latestOperation.recipients).toStrictEqual([]);
|
|
256
|
+
expect(currentAccount.balance).toStrictEqual(
|
|
257
|
+
previousAccount.balance.minus(latestOperation.value),
|
|
258
|
+
);
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
|
|
169
262
|
const scenarioSendAllSolTransaction: SolanaScenarioTransaction = {
|
|
170
263
|
name: "Send All Sol",
|
|
171
264
|
useAllAmount: true,
|
|
@@ -182,13 +275,73 @@ function makeScenarioTransactions(address: string): SolanaScenarioTransaction[]
|
|
|
182
275
|
expect(currentAccount.spendableBalance).toStrictEqual(new BigNumber(0));
|
|
183
276
|
},
|
|
184
277
|
};
|
|
278
|
+
|
|
279
|
+
const scenarioStakeWithdrawTransaction: SolanaScenarioTransaction = {
|
|
280
|
+
name: "Withdraw From Stake Account",
|
|
281
|
+
model: {
|
|
282
|
+
kind: "stake.withdraw",
|
|
283
|
+
uiState: {
|
|
284
|
+
stakeAccAddr: STAKE_ACCOUNT.publicKey.toBase58(),
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
expect: (previousAccount, currentAccount) => {
|
|
288
|
+
const [latestOperation] = currentAccount.operations;
|
|
289
|
+
expect(currentAccount.operations.length - previousAccount.operations.length).toEqual(1);
|
|
290
|
+
expect(latestOperation.type).toEqual("WITHDRAW_UNBONDED");
|
|
291
|
+
expect(latestOperation.value).toStrictEqual(latestOperation.fee);
|
|
292
|
+
expect(latestOperation.senders).toStrictEqual([]);
|
|
293
|
+
expect(latestOperation.recipients).toStrictEqual([]);
|
|
294
|
+
expect(latestOperation.extra).toStrictEqual({
|
|
295
|
+
stake: {
|
|
296
|
+
address: STAKE_ACCOUNT?.publicKey.toBase58(),
|
|
297
|
+
amount: new BigNumber(WITHDRAWABLE_AMOUNT),
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
expect(currentAccount.balance).toStrictEqual(
|
|
301
|
+
previousAccount.balance.minus(latestOperation.value),
|
|
302
|
+
);
|
|
303
|
+
expect(currentAccount.spendableBalance).toStrictEqual(
|
|
304
|
+
previousAccount.spendableBalance.plus(WITHDRAWABLE_AMOUNT),
|
|
305
|
+
);
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
const scenarioCreateAllSolStakeAccountTransaction: SolanaScenarioTransaction = {
|
|
310
|
+
name: "Create Stake Account All Sol",
|
|
311
|
+
useAllAmount: true,
|
|
312
|
+
model: {
|
|
313
|
+
kind: "stake.createAccount",
|
|
314
|
+
uiState: { delegate: { voteAccAddress: VOTE_ACCOUNT.votePubkey } },
|
|
315
|
+
},
|
|
316
|
+
expect: (previousAccount, currentAccount) => {
|
|
317
|
+
const [latestOperation] = currentAccount.operations;
|
|
318
|
+
expect(currentAccount.operations.length - previousAccount.operations.length).toEqual(1);
|
|
319
|
+
expect(latestOperation.type).toEqual("DELEGATE");
|
|
320
|
+
expect(latestOperation.value).toStrictEqual(latestOperation.fee);
|
|
321
|
+
expect(latestOperation.senders).toStrictEqual([]);
|
|
322
|
+
expect(latestOperation.recipients).toStrictEqual([]);
|
|
323
|
+
expect(latestOperation.extra).toMatchObject({
|
|
324
|
+
stake: { address: VOTE_ACCOUNT?.votePubkey },
|
|
325
|
+
});
|
|
326
|
+
expect(currentAccount.balance).toStrictEqual(
|
|
327
|
+
previousAccount.balance.minus(latestOperation.value),
|
|
328
|
+
);
|
|
329
|
+
expect(currentAccount.spendableBalance).toStrictEqual(new BigNumber(0));
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
|
|
185
333
|
return [
|
|
186
334
|
scenarioSendSolTransaction,
|
|
187
335
|
scenarioSendUsdcTransaction,
|
|
188
336
|
scenarioSendAllUsdcTransaction,
|
|
189
337
|
scenarioSendCwifTransaction,
|
|
190
338
|
scenarioSendAllCwifTransaction,
|
|
339
|
+
scenarioCreateSolStakeAccountTransaction,
|
|
340
|
+
scenarioActivateStakeAccount,
|
|
341
|
+
scenarioDeactivateStakeAccount,
|
|
191
342
|
scenarioSendAllSolTransaction,
|
|
343
|
+
scenarioStakeWithdrawTransaction,
|
|
344
|
+
scenarioCreateAllSolStakeAccountTransaction,
|
|
192
345
|
];
|
|
193
346
|
}
|
|
194
347
|
|
|
@@ -235,6 +388,8 @@ export const scenarioSolana: Scenario<SolanaTransaction, SolanaAccount> = {
|
|
|
235
388
|
await airdrop(PAYER.publicKey.toBase58(), 5);
|
|
236
389
|
await createSplAccount(account.freshAddress, SOLANA_USDC, 5, "spl-token");
|
|
237
390
|
await createSplAccount(account.freshAddress, SOLANA_CWIF, 5, "spl-token-2022");
|
|
391
|
+
await initVoteAccount();
|
|
392
|
+
await initStakeAccount(account.freshAddress, WITHDRAWABLE_AMOUNT);
|
|
238
393
|
|
|
239
394
|
initMSW();
|
|
240
395
|
|