caver-js로 내 계정의 키를 바꾸는 방법 #1 — AccountKeyPublic

Tech at Klaytn
Klaytn
Published in
13 min readJan 2, 2020

Klaytn은 키와 주소를 분리하여 계정에서 사용하는 키를 변경할 수 있습니다. 아래의 포스팅을 통해 caver-js로 계정의 키를 바꾸는 다양한 방법들에 대해 알아보고자 합니다.

이 포스팅에서는 caver-js를 사용하여 계정의 키를 AccountKeyPublic으로 변경하는 방법에 대해서 설명합니다. 다양한 AccountKey에 대한 설명은 Klaytn Docs를 참고하세요.

이 문서는 실습을 위주로 설명되며, 실습을 위한 환경이 모두 갖춰진 상태에서 설명이 진행됩니다. 실습 환경이 아직 구축되지 않았다면 caver-js Getting Started — Prerequisites 을 참고하세요.

각 파트에서는 코드의 일부분을 설명하며, 전체 예제 코드는 10.예제코드에서 확인할 수 있습니다.

1. 계정 만들기

먼저 실습에서 사용될 계정을 생성합니다. 이 계정은 트랜잭션을 실제로 전송하여 네트워크에 저장된 계정의 키를 업데이트하기 때문에 충분한 KLAY를 가지고 있어야 합니다. 이 실습은 Baobab Testnet에서 진행되므로, Klaytn Wallet의 Baobab Faucet을 통하여 testnet KLAY를 받을 수 있습니다.

2. caver-js in-memory wallet에 계정 추가하기

이 실습에서는 caver-js의 in-memory wallet을 사용합니다. caver-js의 in-memory wallet에 계정이 추가되어 있으면, 트랜잭션에 서명할 때 따로 사용할 키를 지정해 주지 않아도 in-memory wallet 내부의 계정의 키로 서명하여 결과를 리턴합니다.

그럼 in-memory wallet에 계정을 추가하기 위해 위에서 생성한 계정의 address와 private key를 사용하여 아래와 같이 Account 인스턴스를 생성합니다.

let account = caver.klay.accounts.createWithAccountKey('0x{address}', '0x{private key}')

Account 인스턴스를 생성했다면 caver.klay.accounts.wallet.add를 사용하여 간단하게 in-memory wallet에 계정을 추가할 수 있습니다.

caver.klay.accounts.wallet.add(account)

3. 새로운 개인 키 생성하기

AccountKeyPublic으로 업데이트하기 위해서는 새롭게 사용할 private key가 필요합니다. 여기서는 caver.klay.accounts.create()를 통해 랜덤한 private key를 사용합니다. 만약 따로 사용하고자 하는 private key가 있는 경우, 이를 사용해도 됩니다.

caver.klay.accounts.create()는 기본적으로 주소와 키가 decoupling되지 않은 계정을 생성하므로, keys 프로퍼티는 하나의 private key string을 리턴합니다.

const newKey = caver.klay.accounts.create().keys

4. AccountForUpdate 인스턴스 만들기

AccountForUpdate 클래스는 계정을 업데이트할 때에 필요한 정보들을 포함하는 클래스입니다. AccountKeyPublic으로 업데이트하는 경우, 계정의 주소와 새롭게 사용하고자 하는 public key가 필요합니다.

계정의 주소와 위에서 정의한 새로운 private key를 사용하여 AccountForUpdate 인스턴스를 아래와 같이 생성할수 있습니다.

const key = caver.klay.accounts.createAccountForUpdate(account.address, newKey)

생성된 AccountForUpdate 인스턴스를 console.log로 출력하면 아래와 같이 keyForUpdate에 newKey가 publicKey의 형태로 변환되어 저장되어 있는 것을 확인할 수 있습니다.

AccountForUpdate {
address: '0x1754cf7a609767399d140e715345cbf78d573323',
keyForUpdate: { publicKey: '0x96112…' }
}

5. 트랜잭션 만들기

AccountForUpdate 인스턴스를 생성했다면, 이를 사용하여 아래와 같이 ‘ACCOUNT_UPDATE’ 타입의 트랜잭션을 간단하게 생성할 수 있습니다.

const accountUpdateTx = {
type: 'ACCOUNT_UPDATE',
from: account.address,
key,
gas: 50000,
}

이제 생성된 트랜잭션을 실제로 네트워크로 전송하는 작업만 남아있습니다!

6. 트랜잭션 전송하기

트랜잭션을 생성했다면, 이를 실제로 네트워크에 전송해 봅시다. 이 트랜잭션이 네트워크에서 처리되면 계정의 키가 변경되므로, 기존의 키는 더이상 사용할 수 없습니다. 새롭게 사용하고자 하는 private key를 분실한다면, 더이상 해당 계정을 사용할 수 없으니 주의해야 합니다.

아래와 같이 caver.klay.sendTransaction을 사용하여 트랜잭션을 네트워크에 전송할 수 있습니다.

const receipt = await caver.klay.sendTransaction(accountUpdateTx)

위의 코드가 실행되면 트랜잭션 처리 결과가 transaction receipt 형태로 아래와 같이 리턴됩니다.

{
blockHash: '0x278e8c...22e706',
blockNumber: 15516504,
contractAddress: null,
from: ‘0x1754cf7a609767399d140e715345cbf78d573323’,
gas: '0xc350',
gasPrice: '0x5d21dba00',
gasUsed: 41000,
key: '0x02a102...60cae91',

status: true,
transactionHash: '0xf1622...',
transactionIndex: 1,
type: 'TxTypeAccountUpdate',
typeInt: 32,
}

위의 receipt을 보면 status가 true로 트랜잭션이 성공적으로 처리되었으며, 트랜잭션의 타입은 TxTypeAccountUpdate이고 key필드에는 새롭게 업데이트한 AccountKeyPublic이 인코딩 된 형태로 리턴되는 것을 확인할 수 있습니다.

7. AccountKey 확인하기

트랜잭션이 성공적으로 처리되었다면 네트워크에 저장된 계정의 키가 변경됩니다. caver.klay.getAccountKey를 사용하여 이를 확인할 수 있습니다.

const accountKeyFromNetwork = await caver.klay.getAccountKey(account.address)

위의 결과를 출력하면 아래와 같이 Klaytn 네트워크에 저장된 계정의 키를 알 수 있습니다. 계정의 키를 AccountKeyPublic으로 업데이트 하였으므로, caver.klay.getAccountKey 결과의 keyType은 2로 출력되는 것을 확인할 수 있습니다. Account Key Type ID에 대한 자세한 내용은 Klaytn Docs를 참고해 주세요.

{
keyType: 2,
key: { x: '0x9c200…', y: '0xa9e89…' },
}

8. in-memory key 업데이트

트랜잭션이 성공적으로 처리되어 계정의 키가 업데이트 되었다면, 이제 트랜잭션에 서명할 때에 업데이트된 키를 사용해야 합니다.

지금 in-memory wallet의 계정에서 사용하는 키는 업데이트되기 전의 키이므로, 트랜잭션을 전송하면 실패하게 됩니다. in-memory wallet의 계정에서 사용하는 키가 업데이트되지 않은 상태에서 트랜잭션을 전송하게 되면 아래와 같은 에러가 발생하게 됩니다.

Error: Returned error: invalid transaction v, r, s values of the sender

그렇기 때문에 계정의 키를 업데이트 했다면 따로 in-memory wallet에 저장된 계정의 키도 업데이트해야 합니다.

아래와 같이 caver.klay.accounts.wallet.updateAccountKey를 사용하여 in-memory 내 계정에서 사용하는 key를 업데이트 합니다.

caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)

9. 업데이트된 계정으로 트랜잭션 전송하기

계정의 키가 정상적으로 업데이트된 것을 확인했다면, 이제 업데이트된 계정으로 트랜잭션을 전송해 볼까요?

네트워크에 저장되는 계정의 키가 업데이트 되었기 때문에, 트랜잭션을 전송할 때 업데이트된 키를 사용하여 서명해야 합니다. [8.in-memory key 업데이트]에서 in-memory wallet에 있는 계정의 키도 업데이트 했으므로, 트랜잭션을 전송하면 새롭게 업데이트된 키로 서명하여 전송됩니다.

그럼 아래와 같이 트랜잭션을 정의해 볼까요? 여기서는 ‘VALUE_TRANSFER’타입의 트랜잭션을 전송합니다. 다양한 타입의 트랜잭션에 대한 전송 방법은 Klaytn Docs를 참고하세요.

const valueTransferTx = {
type: 'VALUE_TRANSFER',
from: account.address,
to: account.address,
value: 1,
gas: 25000,
}

그럼 위에서 생성한 트랜잭션을 caver.klay.sendTransaction을 사용하여 전송할 수 있습니다.

const valueTxReceipt = await caver.klay.sendTransaction(valueTransferTx)

10. 예제 코드

아래는 이 문서에서 설명한 전체 코드입니다. testAddress와 testPrivateKey를 위에서 생성한 계정의 정보로 변경한 후 실행해 볼 수 있습니다.

const Caver = require('caver-js')
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
const testAddress = '0x{address}'
const testPrivateKey = '0x{private key}'
test()async function test () {
console.log('=====> Example for account key update to AccountKeyPublic')
// Add account to in-memory wallet
let account = caver.klay.accounts.createWithAccountKey(testAddress, testPrivateKey)
caver.klay.accounts.wallet.add(account)
// Create new private key
const newKey = caver.klay.accounts.create().keys
console.log('new private key: ${newKey}')
// Create AccountForUpdate instance
const key = caver.klay.accounts.createAccountForUpdate(account.address, newKey)
console.log('AccountForUpdate instance => ')
console.log(key)
// Create transaction object
const accountUpdateTx = {
type: ‘ACCOUNT_UPDATE’,
from: account.address,
key,
gas: 50000,
}
// Send transaction
const receipt = await caver.klay.sendTransaction(accountUpdateTx)
console.log('Account Update Transaction receipt => ')
console.log(receipt)

// Get accountKey from network
const accountKeyFromNetwork = await caver.klay.getAccountKey(account.address)
console.log('Result of account key update to AccountKeyPublic')
console.log('Account address: ${account.address}')
console.log('accountKeyFromNetwork =>')
console.log(accountKeyFromNetwork)
// Update account’s key in in-memory wallet
caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
const valueTransferTx = {
type: 'VALUE_TRANSFER',
from: account.address,
to: account.address,
value: 1,
gas: 25000,
}
const valueTxReceipt = await caver.klay.sendTransaction(valueTransferTx)
console.log('After account update value transfer transaction receipt => ')
console.log(valueTxReceipt)
}

위의 실습을 통하여 계정의 키를 AccountKeyPublic으로 변경하는 방법에 대해서 이해가 되셨나요?

다음 포스팅에서는 계정의 키를 AccountKeyWeightedMultiSig로 변경하는 방법에 대해서 설명할 예정입니다. 과정은 거의 동일하나, 새롭게 사용할 키의 종류만 변경되므로 이 문서의 실습을 따라하고 이해하는 데에 문제가 없으셨다면 다음 포스팅도 쉽게 따라 하실 수 있습니다.

--

--