[Project] Mnemonic Wallet 개발하기

George·2022년 6월 9일
0

project

목록 보기
1/6
post-thumbnail

Mnemonic Wallet 개발하기


eth-lightwallet 모듈을 이용하여 간단한 Mnemonic Wallet을 개발하고, Postman을 사용하여 API 테스트를 진행하려고 합니다.

목표


  • eth-lightwallet 모듈에 내장되어 있는 함수를 사용하여 개발
    • 랜덤한 니모닉 코드를 생성
    • 니모닉을 시드로 키스토어를 생성
  • Postman을 사용하여 결과 확인
  • fs 모듈을 이용한 키스토어 로컬 저장

모듈설치


  "dependencies": {
    "cookie-parser": "^1.4.6", // 요청된 쿠키를 쉽게 추출할 수 있도록 도와주는 미들웨어
    "cors": "^2.8.5", // API를 차단하는 문제해결 미들웨어
    "debug": "^4.3.4",
    "eth-lightwallet": "^4.0.0", // 지갑을 만들 때 필요한 모듈
    "express": "^4.18.1",
    "morgan": "^1.10.0"
  }

전체구성

app.js 구성

app.js

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;

newMnemonic API 만들기


Pseudo code

1. mnemonic 변수를 만듭니다.
2. 응답 > mnemonic 변수에 lightwallet.keystore.generateRandomSeed()을 담아, mnemonic을 응답으로 전송합니다. 하단에 generateRandomSeed() 기능 작성.
3. 에러 > 에러를 응답합니다.

keystore.generateRandomSeed([extraEntropy])
Generates a string consisting of a random 12-word seed and returns it. If the optional argument string extraEntropy is present the random data from the Javascript RNG will be concatenated with extraEntropy and then hashed to produce the final seed. The string extraEntropy can be something like entropy from mouse movements or keyboard presses, or a string representing dice throws.

Code

wallet.js

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

router.post("/newMnemonic", async (req, res) => {
  let mnemonic;
  try {
    mnemonic = lightwallet.keystore.generateRandomSeed();
    res.send({ mnemonic });
  } catch (err) {
    console.log(err);
  }
});

Postman으로 테스트하여 니모닉코드 얻기

sever를 실행시킨 다음 Postman에 http://localhost:3000/wallet/newMnemonic 엔드포인트를 입력, POST method를 선택 후 send

결과화면

mnemonic code와 password를 이용해 newWallet API 만들기


Pseudo code

1. password 와 mnemonic 을 입력값으로, 서버에 요청을 보냅니다.
2. (응답) lightwallet.keystore.createVault를 사용하여 키스토어를 생성합니다.
3. (오류) 에러를 응답합니다.

Code

wallet.js

router.post('/newWallet', async(req, res) => {
  // password 와 mnemonic 변수를 만듭니다.
    let password = req.body.password
    let mnemonic = req.body.mnemonic;
 // 요청에 포함되어 있는 password 와 mnemonic을 각 변수에 할당합니다.

    try {
      lightwallet.keystore.createVault(
        {
          // 첫번째 인자(options)에는 password, seedPhrase, hdPathString을 담습니다.
          password: password, 
          seedPhrase: mnemonic,
          hdPathString: "m/0'/0'/0'"
        },
        function (err, ks) {
          // 두번째 인자(callback)에는 키스토어를 인자로 사용하는 함수를 만듭니다.
          ks.keyFromPassword(password, function (err, pwDerivedKey) {
            // 첫번째 인자에는 password, 두번째 인자(callback)에는 pwDerivedKey를 인자로 사용하는 함수를 만듭니다.
            ks.generateNewAddress(pwDerivedKey, 1);
            // 새로운 주소 생성 함수
            let address = (ks.getAddresses()).toString();
            let keystore = ks.serialize();
            // keystore.getAddresses()을 문자열로 할당합니다.
            // keystore.serialize()을 할당합니다.
            res.json({ keystore: keystore, address: address });
            // 위에서 만들어준 변수를 응답으로 전송합니다.
          });
        }
      );
    } catch (exception) { 
      console.log("NewWallet ==>>>> " + exception);
    }
});

사용된 lightwallet 내장함수

keystore.keyFromPassword(password, callback)
This instance method uses any internally-configured salt to return the appropriate pwDerivedKey.
Takes the user's password as input and generates a symmetric key of type Uint8Array that is used to encrypt/decrypt the keystore.

keystore.generateNewAddress(pwDerivedKey, [num])
Allows the vault to generate additional internal address/private key pairs.
The simplest usage is ks.generateNewAddress(pwDerivedKey).
Generates num new address/private key pairs (defaults to 1) in the keystore from the seed phrase, which will be returned with calls to ks.getAddresses().

keystore.serialize()
Serializes the current keystore object into a JSON-encoded string and returns that string.

keystore.getAddresses()
Returns a list of hex-string addresses currently stored in the keystore.


Postman을 이용해 keystore와 address의 응답 API 테스트

http://localhost:3000/wallet/newWallet 앤드포인트를 작성 후 body input에 아까 얻은 니모닉 코드를 mnemonic이라는 키의 값으로, password에는 원하는 비밀번호를 입력 후 send 버튼을 누릅니다.

결과화면


생성된 keystore를 json 파일로 만들어 로컬 서버에 저장하기


Pseudo code

1. wallet.js 파일에 fs 모듈을 import 합니다. (fs 모듈은 Node.js 내장 모듈입니다.)
2. 함수 keyFromPassword의 콜백 함수에서, 응답대신 fs.writeFile 또는 fs.writeFileSync 를 사용합니다.

Code

wallet.js

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){
            // 첫번째 인자에는 .json 형식의 파일이름을, 두번째 인자에는 keystore 을 입력합니다. 세번째 인자에는 응답에 대한 콜백 함수를 입력합니다.
            if(err) {
              // 로컬 서버에 파일을 저장하기 때문에, 응답으로는 성공 또는 실패 메세지만 전송합니다.
                res.json({code:999,message:"실패"});
            } else {
                res.json({code:1,message:"성공"});
            }
          });
        });
      }
    );
  } catch (exception) { 
    console.log("NewWallet ==>>>> " + exception);
  }
});

Postman을 실행하여, 로컬에 키스토어 파일이 생기는지 확인하기

로컬 서버의 경로에 파일이 생기는지 확인합니다.

결과화면

keystore file(wallet.json)이 생성된 것을 확인할 수 있다.
keystore file(wallet.json)


개발 회고


  • 레퍼런스 코드를 보면 이해는 가지만, 직접 작성하려고 하면 어려움을 느낀다.
  • 추후 eth-lightwallet의 다른 내장 함수도 사용해보자.

참고


github


0개의 댓글