使用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 亲测有效

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容