본문 바로가기
Blockchain/Wallet

Mnemonic Wallet 개발하기

by Rezal 2022. 4. 7.

1. newMnemonic API 만들기

  • mnemonic 변수를 만듭니다.
  • (응답) mnemonic 변수에 lightwallet.keystore.generateRandomSeed()을 담아, mnemonic을 응답으로 전송합니다.
  • (에러) 에러를 응답합니다.
router.post('/newMnemonic', async(req,res) => {
  let mnemonic;
  try {
      mnemonic = lightwallet.keystore.generateRandomSeed();
      res.json({mnemonic});
  } catch(err) {
      console.log(err);
  }
});

 

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

  • 로컬 서버를 실행시키고, 엔드포인트를 정확히 입력합니다.
    • 이 경우에는 http://localhost:3000/wallet/newMnemonic 입니다.
  • Postman에서 정확한 method POST 를 입력했다면, send를 눌러 서버로 요청을 보냅니다.
  • 서버가 응답하는 니모닉 코드를 확인합니다.

 

 

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

  • password 와 mnemonic 을 입력값으로, 서버에 요청을 보냅니다.
    • password 와 mnemonic 변수를 만듭니다.
    • 요청에 포함되어 있는 password 와 mnemonic을 각 변수에 할당합니다.
  • (응답) lightwallet.keystore.createVault를 사용하여 키스토어를 생성합니다.
    • 첫번째 인자(options)에는 password, seedPhrase, hdPathString을 담습니다.
    • 두번째 인자(callback)에는 키스토어를 인자로 사용하는 함수를 만듭니다.
    • eth-lightwallet 모듈의keystore.keyFromPassword(password, callback) 내장 함수를 사용합니다.
    • 첫번째 인자에는 password, 두번째 인자(callback)에는 pwDerivedKey를 인자로 사용하는 함수를 만듭니다.
    • 두번째 콜백함수가 실행되면, eth-lightwallet 모듈의 keystore.generateNewAddress(pwDerivedKey, [num])을 이용해 새로운 주소 생성 함수를 실행합니다.
    • address 변수를 만들고, keystore.getAddresses()을 문자열로 할당합니다.
    • keystore 변수를 만들고, keystore.serialize()을 할당합니다.
    • 위에서 만들어준 변수를 응답으로 전송합니다.
  • (오류) 에러를 응답합니다.
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);
    }
});

 

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

  • 로컬 서버를 실행시키고, 엔드포인트를 정확히 입력합니다.
    • 이 경우에는 http://localhost:3000/wallet/newWallet 입니다.
  • Postman에서 정확한 method POST 를 입력했다면, send를 눌러 서버로 요청을 보냅니다.
  • 이때, 3.에서 얻은 니모닉 코드를 mnemonic이라는 키의 값으로, password에는 원하는 비밀번호를 입력 후 send 버튼을 누릅니다.

 

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

 

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

 

 

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

 

  • 5.에서처럼 동일하게 실행합니다.
  • 로컬 서버의 경로에 파일이 생기는지 확인합니다.

 

- Reference keystore file(wallet.json)

{"encSeed":{"encStr":"low95I8NyboOjPWnjBqLqh2EHWMEWKFr4ugGWtHR9MyFPLMIwepIaCmnvQZbueQDVS8c+xzrXLIihqiK9/6/DoZu5u+Xwhs0is6U1PRUgEVJ9wlHCX54+TCQkrAEgsmNZw5W0tCacvBtAksXpTfzvlGSRNJDrXVZiQGo89Tf08xs1V7SUqvfkw==","nonce":"9d+yJS2zQrLkKdXkMF4z94YszobP6xKb"},"encHdRootPriv":{"encStr":"EzldevsVjLxCbgniR0l2cYgfiFs7jCO+n+y4FEX3V3buBApszXtvPyxuOKaRR+phWSdTWBvJ4UBjJbbF72zMMTPUViPecpxx1JBRZhht4jLggwQ5hb0gh77AFJ7N6PVi/osSF+YRzt/STokMgooaLB4Iaxtwa8K5/KND67aI/w==","nonce":"t6sAKrEgkZqvWPVWgpdnb+1fVnQU8MFg"},"addresses":["b48f0dac43b8a1bda5595d5bb2d46ba6b3b6cede"],"encPrivKeys":{"b48f0dac43b8a1bda5595d5bb2d46ba6b3b6cede":{"key":"t5ua+ZqO7A4it17rfFr66uNY4MT2Rwz4+UzGdkGsHFdXGC5mIVvD3GzAXvNblJlc","nonce":"PIsnwUkT/rvVNBr5tO1RAIxYBamvaOV5"}},"hdPathString":"m/0'/0'/0'","salt":"TABp5NmjYF1GoCfN6BgW7e85iOsVXFfsMlz5HOEPeAc=","hdIndex":1,"version":3}
 

- 회고

: 니모닉 지갑을 개발하는 것도 중요하지만, 왜 니모닉을 사용하는 이유 및 니모닉 지갑의 특징, 니모닉 코드의 표준인 BIP-39에서 정의된  니모닉 코드와 시드 생성 9단계에 대한 이해도 필요해보인다. 이론 부분과 실습부분을 번갈아 학습하면서, 차근차근 내 코드로 만들도록 하자.