How to create your own Mnemonic Wallet API for Ethereum
What is Mnemonic?
Well for starters, mnemonic in the blockchain world refers to a set of words that are used recover a crypto wallet.
Crypto wallets use asymmetric key algorithm so you'll have a 'public key' and a 'private key'. With just the private key one can figure out the public key but the opposite is not possible. And obviously that means your private key is very important.
But when your private key is expressed like below it is obviously not easy to remember. Zeros(0) and Os(O) can be confusing as well when you handwrite your private key to a paper (which a lot of crypto users do to prevent keys from being hacked).
Private Key: 5KRQ7XK5oU48pqABR2bkiwqP6oZj2W1Fb6stJgjdoNhBZsVYK7m
In order to remember or write down your private key in a more intuitive way, we can turn it into mnemonic words. The process behind this is as below.
Let's make our own Mnemonic Wallet API Server ๐
1) Preparation
We'll be using:
- eth-lightwallet to create random mnemonic codes and turn them into a keystore
- Express to create a local API
- Postman to check results
- fs module to store the key in local
For starter code: HERE
After downloading the starter code start off with npm i
to install the required dependencies.
We'll be working with the routes/wallet.js
file. A simple express app.js
that'll import the wallet file is already coded up like below.
const express = require('express');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const cors = require('cors');
const walletRouter = require('./routes/wallet');
const app = express();
const port = 3000;
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(
cors({
origin: ['http://localhost:3000'],
methods: ['GET', 'POST'],
credentials: true
})
);
app.get('/', function(req, res, next) {
res.status(200).send({"message": "Mnemonic server is running..."});
});
app.use('/wallet', walletRouter);
// catch 404 and forward to error handler
app.use((req, res, next) => {
const err = new Error('Not Found');
err['status'] = 404;
next(err);
});
// error handler
app.use((err, req, res, next) => {
res.status(err.status || 500);
res.json({
errors: {
message: err.message,
},
});
});
app.listen(port, () => {
console.log(`
################################################
๐ก๏ธ Server listening on port: ${port} ๐ก๏ธ
http://localhost:${port}
################################################
`);
});
module.exports = app;
2) Creating newMnemonic API
In the routes/wallet.js
we can simply use eth-lightwallet
to generate random seed for the mnemonic code.
const express = require('express');
const router = express.Router();
const lightwallet = require("eth-lightwallet");
const fs = require('fs');
// TODO : use lightwallet module to create random mnemonic code
router.post('/newMnemonic', async(req,res) => {
let mnemonic;
try {
mnemonic = lightwallet.keystore.generateRandomSeed();
res.json({mnemonic});
} catch(err) {
console.log(err);
}
});
And I've checked that it functions with Postman. A mnemonic code was returned.
3) Creating newWallet API
We only have the mnemonic code at the moment. So now we're going to request the keystore and address from our API server by sending in the mnemonic and password of our choice.
lightwallet.keystore.createVault
is used for this.
We pass in the password, seedPhrase, hdPathString
for options and in the callback we use the functions: keystore.keyFromPassword(password, callback)
and keystore.generateNewAddress(pwDerivedKey, [num])
.
Save address and keystore to return as response. (using keystore.getAddresses()
and keystore.serialize()
)
// TODO : use mnemonic code and password to create keystore & address
router.post('/newWallet', async(req, res) => {
let password = req.body.password
let mnemonic = req.body.mnemonic;
try {
lightwallet.keystore.createVault(
{
password: password,
seedPhrase: mnemonic,
hdPathString: "m/0'/0'/0'"
},
function (err, ks) {
ks.keyFromPassword(password, function (err, pwDerivedKey) {
ks.generateNewAddress(pwDerivedKey, 1);
let address = (ks.getAddresses()).toString();
let keystore = ks.serialize();
res.json({ keystore: keystore, address: address });
});
}
);
} catch (exception) {
console.log("NewWallet ==>>>> " + exception);
}
});
And with Postman we can check that our local API server returns a keystore and address properly.
4) Saving keystore on local server
If you want you can replace the newWallet API response like below.
It'll no longer return the keystore and wallet as a server response but save it as a json file on the server.
fs.writeFile('wallet.json',keystore,function(err,data){
if(err) {
res.json({code:999,message:"Failed"});
} else {
res.json({code:1,message:"Success"});
}
});
With this change, when we call the server we'll only get a 'success' response. And the keystore will be saved as a json file.
Inside that json file it'll look like this:
{"encSeed":{"encStr":"wA3c+1Ub3nKGNSFRdXYebeePZXRFgsaKqrhvn0sFe6WTyp/uSwrqWs77dsGZLA/8JQq8OxUhlE+nqCOjXH3/lhTa/7JJQ/LAgWhajwgAruFGre6gq08AGhshE8qK9XTkUqqks6x7gAQIZyoBclRWLbpf8iUL+gJpJp/+inbuhRlBewRvMSQXDQ==","nonce":"t7VykU0PENO37RNUJiIdmFJozWl8jLqM"},"encHdRootPriv":{"encStr":"+nGvncTU5pJiXKHBf7SdBbmyeWom0GHx1Qh9ibuNBavc1Utctq9Ew/4kkSg2axpJxFROf/fKlIai/t3ItoElwg7ZdAMkh3NhCZXXgqx2aDr56zXGtNDdnddzBdUZd7lguXr1NxHjDcuNbFaEmKW5UEWA8cvvUGFCuR4l9LRMfQ==","nonce":"TvIE0pV34lawGQTlCGptrrAyfud9gCWm"},"addresses":["821f5000f463c95ef5662590a98724e16b8dc884"],"encPrivKeys":{"821f5000f463c95ef5662590a98724e16b8dc884":{"key":"rEAP+LADhqGMEbgXyia9q+8zmQLFWfFGGWktSgtv71IREL8WjiScF0ttWqdXqRGX","nonce":"yKrB5C51mxCL537zuZC9aDCCCruo8APs"}},"hdPathString":"m/0'/0'/0'","salt":"HPE+2W31twXQ8KTBVR9SCzJpvTBDjEKYM5aGYLRg0a0=","hdIndex":1,"version":3}
And that's it!
If you have followed along well you'll have your own local API server that can be used to request a mnemonic code and turn that into a keystore & address for your use in blockchain.
Check out the full code here.
Hope that helped and sparked some new ideas :)
Subscribe to my newsletter
Read articles from Jinwoo Cheon directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Jinwoo Cheon
Jinwoo Cheon
Former PO @ Naver Financial. Now working my way to become a pro Web3 Dev w/ Solidity and React. Passionate about NFTs.