[Tech] AccountKey — Lagacy,Public

Tech At CHANNEL-iN
@CHANNEL-iN
Published in
5 min readJan 10, 2024

이번 시간에는

Web3 Klaytn의 “4가지 ext” 에서

ethers-ext 을 이용해

여러 AccountKey 형식 중

Lagacy 방식과 Public 방식을 알아보겠습니다.

Web3 Klaytn을 잘 모르겠다면? 🤷

위 포스팅을 확인해주세요.

목차

  1. AccountKey란?
  2. Lagacy 키 형식이란?
  3. 서명이란?
  4. Public 키 형식이란?

1 . AccountKey란?

지갑 주소에는 다양한 키의 형식이 있습니다

대표적인 키의 형식은 Lagacy 형식과 Public 형식이 있습니다

여기서 키의 형식이란?

주소를 생성했을 때 공개키와 개인키의 형식이

Legacy 형식인지 Public 형식인지를 의미합니다.

예를 들어 내 지갑의 주소가 0xc4E0E85A0550288419f….라고 해봅시다.

그럼 모든 사람의 지갑 주소에는 ( 공개키 / 개인키 ) 형식이 들어가 있습니다.

그 (공개키 / 개인키)의 형식 중에는

Lagacy 형식이 있고 Public 형식이 있습니다.

그리고 이 모든 형식을 통틀어서 AccountKey라고 칭합니다.

2. Lagacy 키 형식이란?

Lagacy 키 형식 같은 경우는

이더리움과 호환이 되는 키입니다.

여기서 이더리움과 호환이 된다는 것은?

이더리움 서명 방식을 의미합니다.

이더리움은 시스템상 트랜잭션을 보내려면 주소에 대한 서명이 필요한데

그 서명하는 형식을 이더리움 시스템을 이용합니다

이 형식을 Lagacy 형식이라 칭합니다.

그럼 코드상으론 어떻게 Web3 Klaytn을 이용해서 Lagacy 형식을 이용할 수 있는지

저와 예제를 통해서 쉽고 빠르게 익혀봅시다.

  • 전체 코드
// index.js

// 필요한 라이브러리 및 모듈 가져오기
const { ethers } = require("ethers");
const { Wallet,JsonRpcProvider} = require("@klaytn/ethers-ext");

// // 보내는 자, 보내는 자의 개인키 , 받는자 주소
const senderAddr = "Your Address";
const senderPriv = "Your Private Address";
const recieverAddr = "Receiver Address";



// // Klaytn 노드 프로바이더
const provider = new ethers.providers.JsonRpcProvider("https://public-en-baobab.klaytn.net");

// 지갑 생성
const wallet = new Wallet(senderPriv, provider);



// 트랜잭션 전송
async function sendTx() {


// 누가 누구한테 얼마를 보내는 설정
const tx = {
from: senderAddr,
to: recieverAddr,
value: 0,
};

// 트랜잭션을 지갑에 요청하고 그 결과를 담음

const sentTx = await wallet.sendTransaction(tx);
console.log("sentTx", sentTx);

// 트랜잭션 결과를 기다림
const receipt = await sentTx.wait();
console.log("receipt", receipt);

}

// 메인 함수 실행
async function main() {
await sendTx();
}
main().catch(console.error);

Run

node index.js

Legacy 방식을 이용해 트랜잭션을 보내봤으니

서명을 생성해 보고 그 서명을 통해서 지갑 주소를 확인하는 방법을

예제와 함께 알아봅시다.

그전에 “서명”에 대해 아리송할 수도 있을 것 같습니다.

서명이란 무엇일까요?

3. 서명이란?

메시지 서명 (Message Signing)

서명은 트랜잭션의 송신자가 트랜잭션을 생성하고

그 트랜잭션을 누가 소유하고 있음을 입증하기 위해서 꼭 필요합니다

“ 서명이 없다면 ”

블록체인에서의 트랜잭션은 송신자의 신원을 확인할 방법이 없게 됩니다.

트랜잭션의 송신자를 확인할 수 없다면 어떻게 될까요? 🤔

보안이 매우 취약해져 데이터를 조작해 잘못된 정보(블록)들을 전파합니다.

“송신자의 신원을 확인할 수 없다면 “

블록체인 네트워크의 참여자들은

더 이상 트랜잭션에 대한 신뢰를 잃어버리게 됩니다

그렇게 돼버리면

블록체인이 추구하는 철학에 대해서 굉장히 뒤틀려버립니다.

아래 예제 코드는 메세지와 서명을 통해 송신자를 검증하는 코드입니다.

  • 전체 코드
// index.js


// 필요한 라이브러리 및 모듈 가져오기
const { ethers } = require("ethers");
const { Wallet,JsonRpcProvider} = require("@klaytn/ethers-ext");

// // 보내는 자, 보내는 자의 개인키 , 받는자 주소
const senderAddr = "Your Address";
const senderPriv = "Your Private Address";
const recieverAddr = "Receiver Address";

// // Klaytn 노드 프로바이더
const provider = new ethers.providers.JsonRpcProvider("https://public-en-baobab.klaytn.net");

// 지갑 생성
const wallet = new Wallet(senderPriv, provider);



async function recoverMsg() {

// 서명할 데이터
const msg = "hello";


// msg -> UTF-8 인코딩 -> 16진수 문자열
// 16진수 문자열은 서명에 필요합니다.
const msghex = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(msg));


// 지갑을 사용하여 메세지를 서명합니다
const sig = await wallet.signMessage(msg);

// 메세지와 서명을 통해 해당 주소(송신자)를 확인할 수 있습니다
const addr1 = ethers.utils.verifyMessage(msg, sig);


// Klaytn 노드 RPC를 통해서 주소(송신자)를 검증한다.
const addr2 = await provider.send("klay_recoverFromMessage",
[senderAddr, msghex, sig, "latest"]);
}


// 메인 함수 실행
async function main() {
await recoverMsg()
}
main().catch(console.error);

Run

node index.js

4. Public 키 형식이란?

AccountKeyPublic 형식 같은 경우는

기존 이더리움 시스템을 사용하지 않고

독자적으로 클레이튼 시스템을 이용한 키 방식입니다.

이 형식을 통해서 기존 주소가

Legacy 키 형식을 AccountKeyPublic 형식으로

Legacy — > AccountKeyPublic

업그레이드를 해 해당 지갑 주소가 클레이튼 시스템을 사용할 수 있게
했습니다.

먼저 우리의 지갑 주소가 어떤 AccountKey 형식인지 확인을 해봅시다.

https://baobab.klaytnscope.com/ 사이트에 들어가서 지갑 주소를 입력.

지갑 주소가 AccountKeyLegacy 형식으로 되어있습니다.

그렇다는 건 이 지갑 주소는 이더리움 시스템을 이용해 트랜잭션을 보낼 수 있겠네요

저희는 이 AccountKeyLegacy 형식을 AccountKeyPublic 형식으로 바꾸려고 합니다.

AccountKeyPublic 형식으로 바뀌면 Klaytn 시스템을 사용할 수 있겠네요.

바로 예제 코드와 함께 알아봅시다

  • 전체 코드
// AccountKeyPublic
// https://docs.klaytn.foundation/content/klaytn/design/accounts#accountkeypublic
// index2.js

// 필요한 라이브러리 및 모듈 가져오기
const { Wallet, TxType, AccountKeyType, parseKlay } = require("@klaytn/ethers-ext");
const { ethers } = require("ethers");


// 보내는 사람 지갑 주소 , 개인키 , 받는사람 지갑주소
const senderAddr = "senderAddr";
const senderPriv = "senderPriv";
const senderNewPriv = "senderNewPriv";
const recieverAddr = "recieverAddr";

// 프로바이더 설정 어떤 네트워크에서 서비스를 제공해줄것인지
const provider = new ethers.providers.JsonRpcProvider("https://public-en-baobab.klaytn.net");


// 지갑을 생성
const wallet = new Wallet(senderAddr, senderPriv, provider);


// Lagacy 방식에서 -> Public 방식으로 업그레이드 됐을때 생성되는 지갑
const newWallet = new Wallet(senderAddr, senderNewPriv, provider);



// 지갑 주소를 Lagacy 방식에서 -> Public 방식으로 업그레이드 하는 함수
async function updateAccount() {

// 새로운 개인키를 사용하여 공개키를 생성한다.
let senderNewPub = ethers.utils.computePublicKey(senderNewPriv, true);


// 새로운 공개키를 이용하여 키 타입을 퍼블릭으로 바꿔줌
const tx = {
type: TxType.AccountUpdate,
from: senderAddr,
key: {
type: AccountKeyType.Public,
key: senderNewPub,
}
};


// 기존 Legacy 였던 지갑에 Public으로 바꾸는 트랜잭션
const sentTx = await wallet.sendTransaction(tx);
console.log("sentTx", sentTx);

// 트랜잭션의 결과값을 받아볼 수 있음
const receipt = await sentTx.wait();
console.log("receipt", receipt);

}



async function main() {
await updateAccount();
// await sendTx();

main().catch(console.error);

여기서 senderNewPriv 의 값을 설정해줍시다.

index3.js

const { randomBytes } = require("crypto");
const newPrivateKey = `0x${randomBytes(32).toString("hex")}`;
console.log("newPrivateKey",newPrivateKey)

모든 재료가 준비되어있으니 update함수를 호출해

AccountKey를 변경해볼까요?

Run

node index2.js

다시 한번 https://baobab.klaytnscope.com/에 들어가서 지갑 주소를 입력

AccountKey를 보시면 AccountKeyPublic로 변경되어 있는 걸 확인해 볼 수 있습니다.

자 그럼 Legacy를 -> Public으로 변경한 지갑을 이용해서 트랜잭션을 보내볼까요?

// AccountKeyPublic
// https://docs.klaytn.foundation/content/klaytn/design/accounts#accountkeypublic
// index2.js

// 필요한 라이브러리 및 모듈 가져오기
const { Wallet, TxType, AccountKeyType, parseKlay } = require("@klaytn/ethers-ext");
const { ethers } = require("ethers");

// 보내는 사람 지갑 주소 , 개인키 , 받는사람 지갑주소
const senderAddr = "senderAddr";
const senderPriv = "senderPriv";
const senderNewPriv = "senderNewPriv";
const recieverAddr = "recieverAddr";

// 프로바이더 설정 어떤 네트워크에서 서비스를 제공해줄것인지
const provider = new ethers.providers.JsonRpcProvider("https://public-en-baobab.klaytn.net");

// 지갑을 생성
const wallet = new Wallet(senderAddr, senderPriv, provider);

// Lagacy 방식에서 -> Public 방식으로 업그레이드 됐을때 생성되는 지갑
const newWallet = new Wallet(senderAddr, senderNewPriv, provider);

// 지갑 주소를 Lagacy 방식에서 -> Public 방식으로 업그레이드 하는 함수
async function updateAccount() {

// 새로운 개인키를 사용하여 공개키를 생성한다.
let senderNewPub = ethers.utils.computePublicKey(senderNewPriv, true);

// 새로운 공개키를 이용하여 키 타입을 퍼블릭으로 바꿔줌
const tx = {
type: TxType.AccountUpdate,
from: senderAddr,
key: {
type: AccountKeyType.Public,
key: senderNewPub,
}
};

// 기존 Legacy 였던 지갑에 Public으로 바꾸는 트랜잭션
const sentTx = await wallet.sendTransaction(tx);
console.log("sentTx", sentTx);

// 트랜잭션의 결과값을 받아볼 수 있음
const receipt = await sentTx.wait();
console.log("receipt", receipt);

}



// Public 키 형식으로 바꾼 다음 트랜잭션을 보내는 함수

async function sendTx() {

// 트랜잭션의 타입 , 누가 누구한테 얼마를 보낼지
let tx = {
type: TxType.ValueTransfer,
from: senderAddr,
to: recieverAddr,
value: parseKlay("0.01"),
};


// Public형식으로 등록된 지갑에 트랜잭션을 보냄
const sentTx = await newWallet.sendTransaction(tx);
console.log("sentTx", sentTx);

// 트랜잭션 영수증 확인
const receipt = await sentTx.wait();
console.log("receipt", receipt);
}




async function main() {
await updateAccount();
await sendTx();

main().catch(console.error);

Run

node index2.js  

이렇게 PublicKey로 바꾼 지갑에 트랜잭션까지 보내봤습니다.

자 이렇게 해서 이번 시간에는

AccountKey
Lagacy 키 형식
서명
Public 키 형식
을 저와 함께 아주 쉽게 배워봤습니다.

유익한 글이 되셨으면 좋겠습니다 감사합니다. 😄

--

--