I'm implementing BIP32-Ed25519 derivation and I need to support the Exodus wallet.
According to their docs, Exodus uses the following derivation path for Solana:
m/44'/501'/0'/0/0
However, Solana uses the ed25519 curve, and the path above contains non-hardened (soft) derivation steps (/0/0), which are not valid for ed25519 (SLIP-0010).
As a workaround, I tried the following approach:
Derive the path using a secp256k1 BIP32 implementation (bitcoinjs-lib / bip32)
Take the left 32 bytes (IL) of the derived private key
Use that as the ed25519 private key seed
Compute the ed25519 public key
Here is the code:
import base58 from "bs58";
import { getPublicKey } from "ed25519-hd-key";
import { mnemonicToSeedSync } from "bip39";
import { BIP32Factory } from "bip32";
import { ECPairFactory } from "ecpair";
import * as ecc from "tiny-secp256k1";
import { initEccLib } from "bitcoinjs-lib";
initEccLib(ecc);
const mnemonic = "deposit potato belt enroll space involve sing angry marine shop ostrich midnight";
const seed = mnemonicToSeedSync(mnemonic);
const bip32Factory = BIP32Factory(ecc)
const bip32RootKey = bip32Factory.fromSeed(Uint8Array.from(seed));
const node = bip32RootKey.derivePath("m/44'/501'/0'/0/0");
const IL = node.privateKey.slice(0, 32);
const publicKeyBuffer = getPublicKey(Buffer.from(IL), false);
const privateKey = base58.encode(Buffer.concat([IL, publicKeyBuffer));
const publicKey = base58.encode(rawPublicKey);
This produces the Solana address that matching Exodus.
Question:
Is this approach safe and valid, or is it risky to mix secp256k1 BIP32 derivation and ed25519 key generation like this?
Could this break in edge cases, or is this an acceptable way to replicate what Exodus is doing?
Any insight into how Exodus handles this internally or whether there is a standard for this kind of “curve mixing” would be very helpful.
yea fs twin it definetely works on fonem grave