使用react-native导入助记词创建 solana账户

由于ed25519-hd-key 在 React Native (RN) 上没法直接用,由于它内部依赖了 Node.js 的 crypto 模块,RN 环境里没有,导致使用

import { derivePath } from  ed25519-hd-key ;

中的 derivePath这个方法一直会报错,
解决方案一:
写一个 React Native 兼容版的助记词 → Solana Keypair 导入工具,不依赖 ed25519-hd-key,只用轻量的 noble 库
依赖安装

yarn add @noble/hashes @noble/ed25519 @scure/bip39

@scure/bip39:助记词 → seed
@noble/hashes:实现 HMAC-SHA512
@noble/ed25519:Ed25519 密钥生成
@solana/web3.js:Solana Keypair

具体代码:


import * as bip39 from "bip39";
import { mnemonicToSeedSync } from "@scure/bip39";
import { hmac } from  @noble/hashes/hmac ;
import { sha512 } from  @noble/hashes/sha512 ;
import { Keypair } from "@solana/web3.js";
import bs58 from "bs58";


  function deriveEd25519Path(seed: Uint8Array, path: string): Uint8Array {
    // 解析 path,例如 m/44 /501 /0 /0 
    const segments = path
      .split( / )
      .slice(1)
      .map((part) => {
        if (!part.endsWith(" ")) throw new Error( Only hardened paths allowed );
        return (parseInt(part.slice(0, -1)) | 0x80000000) >>> 0;
      });
  
    let key = hmac.create(sha512, Buffer.from( ed25519 seed )).update(seed).digest();
    let priv = key.slice(0, 32);
    let chainCode = key.slice(32);
  
    for (const index of segments) {
      const data = new Uint8Array(1 + 32 + 4);
      data[0] = 0x00;
      data.set(priv, 1);
      data[33] = (index >> 24) & 0xff;
      data[34] = (index >> 16) & 0xff;
      data[35] = (index >> 8) & 0xff;
      data[36] = index & 0xff;
      const I = hmac.create(sha512, chainCode).update(data).digest();
      priv = I.slice(0, 32);
      chainCode = I.slice(32);
    }
    return priv;
  }
  
  export const testNewImportSol = async (
    mnemonic: string
  ): Promise<{ publicKey: string; secretKey: string; keyStore: string }> => {
    try {
      // 验证助记词
      if (!bip39.validateMnemonic(mnemonic)) {
        throw new Error("Invalid mnemonic");
      }
      const seed = mnemonicToSeedSync(mnemonic);
      const path = `m/44 /501 /0 /0 `;
      const privateKey  = deriveEd25519Path(seed,path);
      const keypair = Keypair.fromSeed(privateKey);
  
      console.log("Generated keypair======:", {
        publicKey: keypair.publicKey.toBase58(),
        secretKeyLength: bs58.encode(keypair.secretKey),
      });
      return {
        publicKey: keypair.publicKey.toBase58(), // Base58 编码的公钥
        secretKey: bs58.encode(keypair.secretKey), // Base58 编码的私钥
        keyStore: "",
      };
    } catch (error: any) {
      console.error("Error generating Solana account:", error.message);
      throw new Error(`Failed to generate Solana account: ${error.message}`);
    }
  };

使用:

export const testNewImportSol = async (
  mnemonic: string
): Promise<{ publicKey: string; secretKey: string; keyStore: string }> => {
  try {
    // 验证助记词
    if (!bip39.validateMnemonic(mnemonic)) {
      throw new Error("Invalid mnemonic");
    }
    const seed = mnemonicToSeedSync(mnemonic);
    const path = `m/44 /501 /0 /0 `;
    const privateKey  = deriveEd25519Path(seed,path);
    const keypair = Keypair.fromSeed(privateKey);

    console.log("Generated keypair======:", {
      publicKey: keypair.publicKey.toBase58(),
      secretKeyLength: bs58.encode(keypair.secretKey),
    });
    return {
      publicKey: keypair.publicKey.toBase58(), // Base58 编码的公钥
      secretKey: bs58.encode(keypair.secretKey), // Base58 编码的私钥
      keyStore: "",
    };
  } catch (error: any) {
    console.error("Error generating Solana account:", error.message);
    throw new Error(`Failed to generate Solana account: ${error.message}`);
  }
};

方案二 :不使用ed25519
使用 @scure/bip39 @scure/bip32 @noble/curves
具体代码

import * as bip39 from "bip39";
import { mnemonicToSeedSync } from "@scure/bip39";
import { Keypair } from "@solana/web3.js";
import { HDKey } from "@scure/bip32";
import bs58 from "bs58";

// 可以直接生成solana账户,但是不是ed25519
export const testImportSol = async (
    mnemonic: string,
  ): Promise<{ publicKey: string; secretKey: string; keyStore: string }> => {
    try {
      if (!bip39.validateMnemonic(mnemonic)) {
        throw new Error("Invalid mnemonic");
      }
      const seed = mnemonicToSeedSync(mnemonic);
      const hd = HDKey.fromMasterSeed(seed);
      console.log("Seed:", seed, "Length:", seed.length);
      const path = `m/44 /501 /0 /0 `;
      const child = hd.derive(path);
      if (!child.privateKey) {
        throw new Error("Failed to derive private key");
      }
      const privateKey = child.privateKey;
      console.log("privateKey====", privateKey);
      const keypair = Keypair.fromSeed(privateKey);
      console.log("Generated keypair======:", {
        publicKey: keypair.publicKey.toBase58(),
        secretKey: bs58.encode(keypair.secretKey),
      });
      return {
        publicKey: keypair.publicKey.toBase58(), // Base58 编码的公钥
        secretKey: bs58.encode(keypair.secretKey), // Base58 编码的私钥
        keyStore: "",
      };
    } catch (error: any) {
      console.error("Error generating Solana account:", error.message);
      throw new Error(`Failed to generate Solana account: ${error.message}`);
    }
  };

提议使用方案一,这样可以兼容网页端react,使用 phantom 亲测有效

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...