SHA256
Обновление архитектуры ключей и кошельков
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { extractClientKey32FromStoredValue } from './client-key-utils.js';
|
||||
import { extractEd25519Seed32FromStoredValue } from './client-key-utils.js';
|
||||
import { base64ToBytes } from './crypto-utils.js';
|
||||
import { loadEncryptedUserSecrets } from './key-vault.js';
|
||||
import { SOLANA_ENDPOINT_DEFAULT } from '../solana-programs.js';
|
||||
@@ -104,7 +104,7 @@ function decodeBase58(input) {
|
||||
|
||||
async function keypairFromPkcs8(pkcs8B64) {
|
||||
const solana = await loadSolanaLib();
|
||||
const seed32 = extractClientKey32FromStoredValue(pkcs8B64);
|
||||
const seed32 = extractEd25519Seed32FromStoredValue(pkcs8B64);
|
||||
try {
|
||||
return solana.Keypair.fromSeed(seed32);
|
||||
} finally {
|
||||
@@ -114,7 +114,7 @@ async function keypairFromPkcs8(pkcs8B64) {
|
||||
|
||||
async function keypairFromStoredSecret(storedSecret) {
|
||||
const solana = await loadSolanaLib();
|
||||
const seed32 = extractClientKey32FromStoredValue(storedSecret);
|
||||
const seed32 = extractEd25519Seed32FromStoredValue(storedSecret);
|
||||
try {
|
||||
return solana.Keypair.fromSeed(seed32);
|
||||
} finally {
|
||||
@@ -161,7 +161,7 @@ export async function createSolanaWalletFromPrivateBase58(privateKey32Base58) {
|
||||
};
|
||||
}
|
||||
|
||||
export async function getWalletFromStoredClientKey({ login, storagePwd }) {
|
||||
) {
|
||||
const cleanLogin = String(login || '').trim();
|
||||
const cleanPwd = String(storagePwd || '').trim();
|
||||
if (!cleanLogin || !cleanPwd) {
|
||||
@@ -200,7 +200,7 @@ export async function getWalletFromStoredBlockchainKey({ login, storagePwd }) {
|
||||
};
|
||||
}
|
||||
|
||||
export async function getWalletFromStoredRootKey({ login, storagePwd }) {
|
||||
) {
|
||||
const cleanLogin = String(login || '').trim();
|
||||
const cleanPwd = String(storagePwd || '').trim();
|
||||
if (!cleanLogin || !cleanPwd) {
|
||||
@@ -227,7 +227,7 @@ export async function getStoredSolanaWalletChoices({ login, storagePwd } = {}) {
|
||||
return [{
|
||||
id: 'blockchain-key',
|
||||
keySource: 'blockchain',
|
||||
label: 'blockchain key',
|
||||
label: 'Ключ блокчейна',
|
||||
address: wallet.address,
|
||||
keypair: wallet.keypair,
|
||||
}];
|
||||
@@ -289,6 +289,70 @@ export async function transferSol({ endpoint, fromKeypair, toAddress, amountSol
|
||||
return { endpoint: rpc, signature, lamports };
|
||||
}
|
||||
|
||||
export async function transferAllSol({ endpoint, fromKeypair, toAddress }) {
|
||||
const solana = await loadSolanaLib();
|
||||
const rpc = normalizeEndpoint(endpoint);
|
||||
const cleanTo = String(toAddress || '').trim();
|
||||
if (!fromKeypair?.publicKey) throw new Error('Не передан старый Solana-кошелёк');
|
||||
if (!cleanTo) throw new Error('Не указан новый адрес кошелька');
|
||||
if (fromKeypair.publicKey.toBase58() === cleanTo) {
|
||||
throw new Error('Старый и новый кошельки совпадают');
|
||||
}
|
||||
|
||||
const conn = new solana.Connection(rpc, 'confirmed');
|
||||
const balanceLamports = await conn.getBalance(fromKeypair.publicKey, 'confirmed');
|
||||
if (balanceLamports <= 0) {
|
||||
return { endpoint: rpc, signature: '', lamports: 0, feeLamports: 0, balanceLamports, skipped: true };
|
||||
}
|
||||
|
||||
const latest = await conn.getLatestBlockhash('confirmed');
|
||||
const probeTx = new solana.Transaction({
|
||||
feePayer: fromKeypair.publicKey,
|
||||
recentBlockhash: latest.blockhash,
|
||||
}).add(solana.SystemProgram.transfer({
|
||||
fromPubkey: fromKeypair.publicKey,
|
||||
toPubkey: new solana.PublicKey(cleanTo),
|
||||
lamports: 1,
|
||||
}));
|
||||
const feeResult = await conn.getFeeForMessage(probeTx.compileMessage(), 'confirmed');
|
||||
const feeLamports = Number(feeResult?.value ?? 5000);
|
||||
const transferLamports = balanceLamports - feeLamports;
|
||||
if (transferLamports <= 0) {
|
||||
return {
|
||||
endpoint: rpc,
|
||||
signature: '',
|
||||
lamports: 0,
|
||||
feeLamports,
|
||||
balanceLamports,
|
||||
skipped: true,
|
||||
};
|
||||
}
|
||||
|
||||
const tx = new solana.Transaction({
|
||||
feePayer: fromKeypair.publicKey,
|
||||
recentBlockhash: latest.blockhash,
|
||||
}).add(solana.SystemProgram.transfer({
|
||||
fromPubkey: fromKeypair.publicKey,
|
||||
toPubkey: new solana.PublicKey(cleanTo),
|
||||
lamports: transferLamports,
|
||||
}));
|
||||
tx.sign(fromKeypair);
|
||||
const signature = await conn.sendRawTransaction(tx.serialize(), { skipPreflight: false });
|
||||
await conn.confirmTransaction({
|
||||
signature,
|
||||
blockhash: latest.blockhash,
|
||||
lastValidBlockHeight: latest.lastValidBlockHeight,
|
||||
}, 'confirmed');
|
||||
return {
|
||||
endpoint: rpc,
|
||||
signature,
|
||||
lamports: transferLamports,
|
||||
feeLamports,
|
||||
balanceLamports,
|
||||
skipped: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function formatSol(value, digits = 6) {
|
||||
const n = Number(value);
|
||||
if (!Number.isFinite(n)) return '0';
|
||||
|
||||
Reference in New Issue
Block a user