I created a new wallet using Lace wallet. And I got 24 words. Now I would like to know how I can derive the seed from 24 words in nodejs. I was using bip39 and was able to build my wallet. Here is my code:
const entropy = bip39.mnemonicToEntropy(my_mnemonic, wordlist);
seed = Buffer.from(entropy).toString('hex');
But right now the code is not working anymore. It returns a different wallet address. It worked fine in the past.
Thanks
2 Likes
sylwek
October 10, 2025, 10:45am
2
I encounter the same problem. How to get seed from 24 words that were generate by Lace wallet preview. I want to pass this seed to WalletBuilder.build function from @midnight-ntwrk/wallet
1 Like
I was able to share this issue with someone from Midnight. He isn’t a dev, but will try to get some help for this issue (derive seed from mnemonic words)
2 Likes
I was investigating this some weeks ago, I’m not fully sure if this is a valid way of doing it, and I couldn’t get it to properly derive the correct seed, but this is what I was attempting without success:
import * as bip39 from '@scure/bip39';
import { WalletBuilder } from '@midnight-ntwrk/wallet';
import { createHash, createHmac } from 'crypto';
const seed64 = await bip39.mnemonicToSeed(mnemonic, '');
const hmac = createHmac('sha512', seed64);
hmac.update(Buffer.from(''));
const hmacResult = hmac.digest();
const masterPrivateKey = hmacResult.slice(0, 32);
const seed = masterPrivateKey.toString('hex');
const wallet = await WalletBuilder.build(.., seed, ...);
I don’t see an API in that lib to get the seed from a given mnemonic.
1 Like
With the help from Midnight team and Lace, I learned how to derive it:
Use BIP39 library: https://www.npmjs.com/package/bip39
const mnemonic = ''abandon car water …. “; // your mnemonic
const seed = bip39.mnemonicToSeedSync(mnemonic);
const generatedWallet = HDWallet.fromSeed(seed);
let finalSeed;
if (generatedWallet.type == 'seedOk') {
const zswapKey = generatedWallet.hdWallet.selectAccount(0).selectRole(Roles.Zswap).deriveKeyAt(0);
if (zswapKey.type === 'keyDerived') {
finalSeed = Buffer.from(zswapKey.key).toString('hex')
} else {
console.error('Error deriving key');
}
} else {
console.error('Error generating HDWallet');
}
await WalletBuilder.build(
this.indexerUrl,
this.indexerWsUrl,
this.proofServer,
this.node,
finalSeed || '',
getZswapNetworkId(),
'info',
);
2 Likes
I was going to comment on something, but then I realised that this solution is effective! great job guys
1 Like
This doesn’t appear to work for generating mn_dust_*** addresses that the latest lace midnight preview generates. i.e. as opposed to mn_shielded and mn_unshielded. I’m trying to programmatically generate a mn_dust address from the mnemonic generated from Lace wallet and nothing works.
1 Like
nel349
February 4, 2026, 1:08am
11
there was a gap in the documentation. it was fixed in the following issue:
opened 08:28PM - 12 Jan 26 UTC
## Summary
Lace v2 generates **different Midnight addresses** from the same mne… monic compared to the official `@midnight-ntwrk/wallet-sdk-hd` package. This prevents wallet interoperability between Lace and other wallets built using the standard Midnight SDK.
## Background
I'm developing an Android wallet for Midnight blockchain. To ensure users can restore wallets between Lace and my application, I need to understand Lace's exact key derivation implementation.
## Test Case
**Mnemonic (BIP-39 standard test vector):**
```
abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art
```
**BIP-39 Passphrase:** `""` (empty string)
### Result Comparison
| Implementation | Address |
|---|---|
| **Lace v2** | `mn_addr_preview15jlkezafp4mju3v7cdh3ywre2y2s3szgpqrkw8p4tzxjqhuaqhlshsa9pv` |
| **Midnight SDK** | `mn_addr_preview19kxg8sxrsty37elmm6yd68tuy7prryjst2r48eapf2fdtd8z4gpq8xczf2` |
❌ **Addresses do not match**
## My Implementation (Using Official Midnight SDK)
```javascript
import { mnemonicToSeed } from '@scure/bip39';
import { wordlist } from '@scure/bip39/wordlists/english.js';
import { HDWallet, Roles } from '@midnight-ntwrk/wallet-sdk-hd';
import * as ledger from '@midnight-ntwrk/ledger-v6';
import { MidnightBech32m } from '@midnight-ntwrk/wallet-sdk-address-format';
const mnemonic = "abandon abandon abandon ... art"; // 24 words
const masterSeed = await mnemonicToSeed(mnemonic, '', wordlist); // BIP-39
const hdWalletResult = HDWallet.fromSeed(masterSeed); // BIP-32
const account = hdWalletResult.hdWallet.selectAccount(0);
// Derivation path: m/44'/2400'/0'/0/0 (NightExternal role)
const nightExternalKey = account.selectRole(Roles.NightExternal).deriveKeyAt(0);
const privateKey = nightExternalKey.key;
// Public key and address generation
const privateKeyHex = bytesToHex(privateKey);
const publicKey = ledger.signatureVerifyingKey(privateKeyHex);
const userAddress = ledger.addressFromKey(publicKey);
const addressBuffer = Buffer.from(userAddress, 'hex');
const bech32Address = new MidnightBech32m('addr', 'preview', addressBuffer).asString();
console.log(bech32Address);
// Output: mn_addr_preview19kxg8sxrsty37elmm6yd68tuy7prryjst2r48eapf2fdtd8z4gpq8xczf2
// Expected (from Lace): mn_addr_preview15jlkezafp4mju3v7cdh3ywre2y2s3szgpqrkw8p4tzxjqhuaqhlshsa9pv
```
## Exhaustive Search Conducted
Tested **400+ addresses** with no matches:
- âś… Accounts: 0-4
- âś… Roles: NightExternal (0), NightInternal (1), Dust (2), Zswap (3)
- âś… Indices: 0-19 per role
- âś… Passphrase: empty string
## Decoded Address Comparison
**Lace Address:**
```
Type: addr
Network: preview
Data (hex): a4bf6c8ba90d772e459ec36f123879511508c0480807671c35588d205f9d05ff
Length: 32 bytes
```
**Midnight SDK Address:**
```
Type: addr
Network: preview
Data (hex): 2d8c83c0c382c91f67fbde88dd1d7c27823192505a8753e7a14a92d5b4e2aa02
Length: 32 bytes
```
The underlying public key data is completely different.
## Hypothesis
Since Lace is primarily a **Cardano wallet** (with Midnight support added in v2), I suspect Lace may be using:
1. **Cardano's CIP-3 or CIP-1852** key derivation instead of standard BIP-32
2. **Different derivation path** than Midnight's `m/44'/2400'/account'/role/index`
3. **Cardano-specific cryptographic primitives** (Ed25519 instead of secp256k1?)
## Questions for Lace Development Team
1. **Does Lace v2 use the standard `@midnight-ntwrk/wallet-sdk-hd` package for Midnight addresses?**
2. **If not, what key derivation method does Lace use?**
- CIP-3 (Cardano's Icarus derivation)?
- CIP-1852 (Cardano HD wallets)?
- Custom implementation?
3. **What is the exact derivation path Lace uses for Midnight addresses?**
- Is it `m/44'/2400'/0'/0/0` as per Midnight docs?
- Or something else?
4. **What cryptographic curve does Lace use for Midnight?**
- secp256k1 (Midnight standard)?
- Ed25519 (Cardano standard)?
5. **Is there technical documentation for Lace v2's Midnight implementation?**
## Why This Matters
**Wallet interoperability is critical for the Midnight ecosystem.** Users should be able to:
- ✅ Create a wallet in Lace → Restore in any Midnight wallet
- ✅ Create a wallet in any Midnight wallet → Restore in Lace
Currently, this is **not possible** due to different address generation methods.
## Request
Could the Lace development team either:
1. **Provide technical documentation** on Lace v2's Midnight key derivation
2. **Point to the relevant source code** in this repository
3. **Confirm if Lace plans to standardize** on the official Midnight SDK
This information is essential for building interoperable wallets in the Midnight ecosystem.
## Environment
- **Lace Version:** v2.x (with Midnight Preview support)
- **Midnight SDK Versions:**
- `@midnight-ntwrk/wallet-sdk-hd`: 3.0.0-beta.9
- `@midnight-ntwrk/ledger-v6`: 6.1.0-alpha.6
- `@midnight-ntwrk/wallet-sdk-address-format`: 3.0.0-beta.9
- **Test Network:** Midnight Preview (testnet)
## Related Documentation
- [Midnight Wallet Developer Guide](https://docs.midnight.network/develop/guides/wallet-dev-guide)
- [Midnight HD Wallet Package](https://github.com/midnightntwrk/midnight-wallet/tree/main/packages/hd)
- [BIP-32 Standard](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
- [BIP-39 Standard](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)
---
**Thank you for your help!** Understanding Lace's implementation will help build a more interoperable Midnight ecosystem.
1 Like