[Caver] How to Update Klaytn Account Keys with Caver #1 — AccountKeyPublic

One of the cool features of the Klaytn blockchain is that it has decoupled keys from addresses, so that you can update your account key. In this post, we will be explaining how to update your account key to AccountKeyPublic using caver-js and caver-java. For more details on the different types of AccountKey, please refer to Klaytn Docs.

This tutorial assumes that you have the necessary environment setup. If you haven’t yet set up the environment, please refer to caver-js — Prerequisites or caver-java — Prerequisites.

In each section, we will go through little snippets of the whole code; you can check the code in its entirety in the links below.

1. Creating a keyring

First, create an Klaytn account to use for this tutorial. Your account must have sufficient KLAY, because it will be used for sending a transaction to make the necessary update to the key stored on the network.

Caver uses a structure called Keyring to store private key(s) used for Klaytn account addresses and accounts.

Below is how you can create a Keyring instance in caver-js.

// caver-js
const senderKeyring = caver.wallet.keyring.create(senderAddress, senderPrivateKey)

If you have a keystore file instead of a private key string, use caver.wallet.keyring.decrypt to create a Keyring.

And you can create a Keyring instance in caver-java:

// caver-java
SingleKeyring senderKeyring = caver.wallet.keyring.create(senderAddress, senderPrivateKey);

You can also use caver.wallet.keyring.decrypt for java, if you have a keystore file.

2. Adding a keyring to caver in-memory wallet

In this exercise, we will be using an in-memory wallet. If you add a Keyring to caver’s in-memory wallet, the key stored in that Keyring will automatically be used to sign transactions even if you don’t designate a specific key.

This is how you add a Keyring to in-memory wallet using caver-js:

// caver-js
caver.wallet.add(senderKeyring)

It is the same for caver-java:

// caver-java
caver.wallet.add(senderKeyring);

3. Creating a new private key

In order to update Klaytn account’s AccountKey to AccountKeyPublic, you need a private key for your Klaytn account. Here we will use a private key that is randomly generated using the generateSingleKey function. But if there is a specific private key that you want to use, you can use that one.

Below is how you create a new private key string for your Klaytn account using caver-js:

// caver-js
const newKey = caver.wallet.keyring.generateSingleKey()

And for caver-java:

// caver-java
String newKey = caver.wallet.keyring.generateSingleKey();

4. Creating a new keyring

Now that we have created a new private key, we will go on to create a Keyring instance to store this key. You can start using the Keyring instance once the AccountKey in the Klaytn account has been successfully changed.

You can create a Keyring instance that stores the new private key using caver-js as shown below:

// caver-js
const newKeyring = caver.wallet.keyring.create(senderKeyring.address, newKey)

The newKeyring that stores the new private key will sign the transaction using newKey.

Using caver-java, creating a Keyring instance for storing the new private key looks like this:

// caver-java
SingleKeyring newKeyring = caver.wallet.keyring.create(senderKeyring.getAddress(), newKey);

5. Creating an Account instance

The Account class provided by caver contains the information required to update accounts. When making the update to AccountKeyPublic, you need the Klaytn account address that you want to update, as well as the new public key.

You can create an Account instance by calling the toAccount function of the keyring that stores the newly created private key. Here is what it looks like when you are using caver-js:

// caver-js
const account = newKeyring.toAccount()

You can also create an Account instance using caver-java by calling the toAccountfunction:

// caver-java
Account account = newKeyring.toAccount();

The Account instance will now store the Klaytn account address to be updated and the public key derived from the new private key.

6. Creating a transaction

Once you have created an Account instance, you can use it to create an Account Update transaction.

Here is how you create a transaction using caver-js:

// caver-js
const accountUpdate = caver.transaction.accountUpdate.create({
from: senderKeyring.address,
account: account,
gas: 50000,
})

And here is how you do it using caver-java:

// caver-java
AccountUpdate accountUpdate = caver.transaction.accountUpdate.create(
TxPropertyBuilder.accountUpdate()
.setFrom(senderKeyring.getAddress())
.setAccount(account)
.setGas(BigInteger.valueOf(50000))
);

7. Signing the transaction

Once you have created an account update transaction, you need to sign it using the keyring that was added to the in-memory wallet. Caver’s in-memory wallet, caver.wallet, has a sign function.

Here is how you sign a transaction using caver-js:

// caver-js
await caver.wallet.sign(senderKeyring.address, accountUpdate)

And for caver-java:

// caver-java
caver.wallet.sign(senderKeyring.getAddress(), accountUpdate);

If caver.wallet.sign has been successfully executed, you should see that the signature has been assigned to the signatures field of accountUpdate.

Now all that is left for us to do is to send the transaction to the network.

8. Sending the transaction

Now that we have created and signed the transaction, let’s try sending it to the network. Once this transaction goes through on the network, the old key for your Klaytn account will no longer be usable. Since your old keyring will also no longer be usable, you have to use the new one that stores the new private key.

You can send the signed transaction to the network using caver.rpc.klay.sendRawTransaction.

Below is a sample that shows how to send a transaction with caver-js, using an EventEmitter:

// caver-js
caver.rpc.klay.sendRawTransaction(accountUpdate)
.on(‘transactionHash’, hash => {
console.log(hash)
})
.on(‘receipt’, receipt => {
console.log(receipt)
})

When you are sending a transaction using caver-js, you can get a receipt of the transaction result using Promise with the code below:

// caver-js
const receipt = await caver.rpc.klay.sendRawTransaction(accountUpdate)

You can also send a transaction using caver-java like this:

// caver-java
Bytes32 sendResult = caver.rpc.klay.sendRawTransaction(accountUpdate).send();
String txHash = sendResult.getResult();

When the above code is executed, you will get a transaction hash. The result of the transaction can be obtained with the code as shown below:

// caver-java
public String objectToString(Object value) throws JsonProcessingException {
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
return ow.writeValueAsString(value);
}
TransactionReceiptProcessor receiptProcessor = new PollingTransactionReceiptProcessor(caver, 1000, 15);TransactionReceipt.TransactionReceiptData receiptData = receiptProcessor.waitForTransactionReceipt(hash);System.out.println(objectToString(receiptData));

If you see that the status has returned true in the receipt, it means that the transaction has been successfully processed. Transaction type is TxTypeAccountUpdate and the updated AccountKeyPublic is returned in the key field in encoded form.

{
blockHash: ‘0x073ae74db35f15c8f763c89ee4cede3f0a9bfb1256d2b28e2e12f2b4c4ccca18’,
blockNumber: ‘0x33c80b0’,
contractAddress: null,
from: ‘0x405e1c9109684626b5b94177335b2db88e974f86’,
gas: ‘0xc350’,
gasPrice: ‘0x5d21dba00’,
gasUsed: ‘0xa028’,
key: ‘0x02a102259cbde6ac40681c0bdb36a7bd714d7f12214f060a3708a964d80a46a8985d94’,
logs: [],
logsBloom: ‘0x00000…’,
nonce: ‘0x0’,
senderTxHash: ‘0x6d0ccf6afb1b715909244fa8d6affdb9a2fcac74f070cffcb10f6cc1b8b0eb8c’,
signatures: [{ V: ‘0x7f5’, R: ‘0xcc180…’, S: ‘0x161b2…’ }],
status: ‘0x1’,
transactionHash: ‘0x6d0ccf6afb1b715909244fa8d6affdb9a2fcac74f070cffcb10f6cc1b8b0eb8c’,
transactionIndex: ‘0x0’,
type: ‘TxTypeAccountUpdate’,
typeInt: 32
}

9. Confirming AccountKey

If the transaction was successful, the account key stored on the network will have been updated. You can check the result using caver.rpc.klay.getAccountKey.

Confirm your new accountKey in caver-js:

// caver-js
const accountKey = await caver.rpc.klay.getAccountKey(keyring.address)console.log(accountKey)

Or in caver-java:

// caver-java
AccountKey accountKey = caver.rpc.klay.getAccountKey(keyring.getAddress()).send();
System.out.println(objectToString(accountKey));

The above code will return the the account key stored on the Klaytn account. Since the key has been updated to AccountKeyPublic, the keyType, representing a key type ID, is 2. For more details on Account Key Type IDs, please refer to Klaytn Docs.

{
keyType: 2,
key: {
x: ‘0x259cb…’,
y: ‘0x707b7…’
}
}

10. Updating in-memory wallet’s keyring

If your account key has been updated with the successfully processed transaction, you have to start using the updated key for signing transactions.

For now, the key that is used in the keyring, and stored in the in-memory wallet, is the old one before the update. Sending a transaction in this state will cause an error, as shown below:

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

That is why you also have to update the keyring’s key stored in the in-memory wallet after updating your Klaytn account key.

The private key used in keyring, and stored in the in-memory wallet can be updated using caver.wallet.updateKeyring. The newKeyring that contains the updated Klaytn account address and new private key will be passed as parameter.

Below is how you can update in-memory wallet’s keyring using caver-js:

// caver-js
caver.wallet.updateKeyring(newKeyring)

And here is how you can do this using caver-java:

// caver-java
caver.wallet.updateKeyring(newKeyring);

11. Sending a transaction with the updated account

Your Klaytn account key has been updated, now let’s try sending a transaction using the updated account.

Since the account key stored on the network has been updated, you will now have to sign the transaction using the new key. In section [10. Updating in-memory wallet’s keyring], we also updated the key in the keyring in the in-memory wallet, so when a transaction is sent, it will be signed with this updated key.

Here we will just send a simple value transfer transaction to confirm the update.

The sample code below shows how to create, sign and send a valueTransfer transaction using caver-js:

// caver-js
const vt = caver.transaction.valueTransfer.create({
from: senderKeyring.address,
to: recipientAddress,
value: 1,
gas: 25000,
})

await caver.wallet.sign(senderKeyring.address, vt)

const vtReceipt = await caver.rpc.klay.sendRawTransaction(vt)

Create a transaction using caver.transaction.valueTransfer, and sign it using the caver.wallet.sign function as already demonstrated. Since the keyring in caver.wallet has been updated in [10. Updating in-memory wallet’s keyring], the new private key will be used to sign the transaction. After that, the transaction will be sent to the network using caver.rpc.klay.sendRawTransaction. In this tutorial, the transaction result is returned using Promise.

Below is the same process in caver-java:

// caver-java
ValueTransfer vt = caver.transaction.valueTransfer.create(
TxPropertyBuilder.valueTransfer()
.setFrom(senderKeyring.getAddress())
.setTo(recipientAddress)
.setValue(BigInteger.valueOf(1))
.setGas(BigInteger.valueOf(25000))
);

caver.wallet.sign(senderKeyring.getAddress(), vt);

Bytes32 vtResult = caver.rpc.klay.sendRawTransaction(vt).send();

TransactionReceipt.TransactionReceiptData vtReceiptData = receiptProcessor.waitForTransactionReceipt(vtResult.getResult());

Create a ValueTransfer transaction and sign it using the caver.wallet.sign function. The transaction will be sent to the network with caver.rpc.klay.sendRawTransaction. You can confirm the transaction status using the returned transaction hash.

In this post, we have demonstrated how to update an account key to AccountKeyPublic. We hope that the explanation was straightforward.

In our next post, we will be looking at how to update your key to AccountKeyWeightedMultiSig. The process is pretty much similar to this one, only with a different key type. If you had no problems following this tutorial, the next one should also be a breeze!

Source code links used in this post:

If you have any questions, please visit our Developer Forum. 😉

Thank you for reading and stay tuned for more posts!

MORE FROM Tutorials

Ecosystem

Bringing access to the Klaytn metaverse through CEXes

07/06/2022

Announcements

Monthly round-up: May 2022

31/05/2022

Ecosystem

Gaming: Our key to metaverse global adoption

27/05/2022

CATEGORIES

© Klaytn Foundation 2022. All rights reserved.
© Klaytn Foundation 2022. All rights reserved.