Development of Mnemonic Wallet

JourniYoon·2022년 4월 7일
0
post-thumbnail

GitHub

github repository


Mnemonic이란?

다양한 암호화폐 지갑들은 비대칭키 암호 방식을 사용한다. 비대칭키 암호화 방식에는 공개키와 개인키가 있다. 개인키를 사용자가 보관해야 하는데 의미없는 숫자와 문자의 나열은 개인이 기억하기 힘들다. 따라서 사용자가 자신의 개인키를 쉽게 기억하고 사용할 수 있도록 만든 것이 Mnemonic이다.
Mnemonic은 보통 12개의 영단어로 조합되어 있다.


개발환경

API 테스트로 postman 사용했습니다.


postman 테스트, mnemonic 코드 얻기

// Get Mnemonic code using lightwallet module
router.post("/newMnemonic", async (req, res) => {
	let mnemonic;
	try {
		mnemonic = lightwallet.keystore.generateRandomSeed();
		res.json({ mnemonic });
	} catch (err) {
		console.log(err);
		res.status(404).send({ message: "Bad Request" });
	}
});

lightwallet 모듈의 generateRandomSeed 함수를 사용하여 api를 이용해 생성된 seed를 받아오는 함수이다.
서버를 실행시킨 후, 포스트맨에서 method를 POST로 변경한 후 http://localhost:3000/wallet/newMnemonic를 입력한다. 그럼 아래와 같이 mnemonic 코드가 생성된다.

mnemonic코드, password로 newWallet API 만들기

newWallet이라는 엔드포인트로 POST 요청을 보내면 keywstore와 address를 받을 수 있다. keystore란 암호화폐 지갑을 사용하기 위해 개인키를 비밀번호로 암호화한 텍스트파일이다.
코드를 보면 password, mnenonic 두 가지 인자를 통해 newWallet을 생성한다.

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);
    }
});

keysotre, address 응답 API 테스트

body에 아래와 같이 입력하면 newWallet API가 생성된다. newWallet에는 keysotre파일과 address가 들어있다.

{
    "mnemonic": "saddle bind borrow tackle want thank acquire select jazz brass maximum female",
    "password": "abcde12345"
}

keystore 파일로 저장하기

원래의 코드를 변형해 keystore를 로컬에 저장할 수 있다.

// before
res.json({ keystore: keystore, address: address });

// after
fs.writeFile("wallet.json", keystore, function (err, data) {
  if (err) {
    res.json({ code: 404, message: "Fail" });
  	} else {
      	res.json({ code: 204, message: "Success" });


로컬 서버에 wallet.json파일이 생성된 것을 확인할 수 있다.

파일 내용은 아래와 같다.

{"encSeed":{"encStr":"oQn0nUrhXhwJPLz891FlorSHMghkh8nSb2kHhRsh3S4nQBNgHgS7WjygiBG6qWGeZy0PMMgoiCETOxCJYFPt4Nc5ymws/kw5/BHti1pFLHCGJmbXkAFRDtcZU9aqJSwIyiaZ2kXSruF8XP2+fkmUWuNL6V4IyejI6Jmh+nDsfSgehxSPBmyy3w==","nonce":"b8Hj1IarDYHlZD4nFZ5WbrV1qmOY8US4"},"encHdRootPriv":{"encStr":"PpeXCQ8huIUPHGuhSudSuqr0cPKME3Uf8IymqIK112NMyNjFy53DjryQuPly+7Wys1pFfPDht6kX04+M6w6p7gHhrEbUNgi+l2dwNybMYchrLYG+C5mSY3Q0ojVb2BL/MpWw9M27+/Z6z/IDQfxLwzsK5xWFtiPbA0xBTmK5IA==","nonce":"pd8asOjx+RiEp6mF8ccCc0VxapDgkyg7"},"addresses":["fd0e7665a7d2c6a7f6b5cc3aa61be20fccc4340f"],"encPrivKeys":{"fd0e7665a7d2c6a7f6b5cc3aa61be20fccc4340f":{"key":"KPRn1VTKqo5A0cQCfD/cYkJK1jq+Qpnax8IYXKHNMaZHU/LyiqOYOSuJkpbCSgvO","nonce":"cDYcs2cmNf9qYG6qhmb1AKSH1TzNhOV1"}},"hdPathString":"m/0'/0'/0'","salt":"7a3thZwzUpJEgfWQDluHA/f4yBUxrpmIUJtQRvA7Xc0=","hdIndex":1,"version":3}

전체 코드

const express = require("express");
const router = express.Router();
const lightwallet = require("eth-lightwallet");
const fs = require("fs");

// Get Mnemonic code using lightwallet module
router.post("/newMnemonic", async (req, res) => {
	let mnemonic;
	try {
		mnemonic = lightwallet.keystore.generateRandomSeed();
		res.json({ mnemonic });
	} catch (err) {
		console.log(err);
		res.status(404).send({ message: "Bad Request" });
	}
});

// Create keysotre file using Mnemonic code and password
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();

					fs.writeFile("wallet.json", keystore, function (err, data) {
						if (err) {
							res.json({ code: 404, message: "Fail" });
						} else {
							res.json({ code: 204, message: "Success" });
						}
					});
				});
			}
		);
	} catch (exception) {
		console.log("NewWallet ==>>>> " + exception);
	}
});

module.exports = router;

개발 회고 (KPT)

KEEP(작업 및 코드적으로 좋았던 경험)

실습을 통해 Mnemonic code와 HD Wallet의 이론 및 작동원리에 대해 좀 더 배울 수 있는 시간을 가질 수 있어 유익했다.

PROBLEM(작업 및 코드에서 좋지 않았던 경험)

블록체인에 대해 배우기 시작하며 많은 이론들을 접했지만 아직은 설명하는 것이 쉽지 않았고 블로깅하면서 그런 부족한 부분이 여실히 드러났다.

TRY(앞으로 시도해볼 액션 아이템 설정)

배웠던 이론들에 대해 하나씩 정리하는 글을 작성해야겠다.

0개의 댓글