The following packages are required to use the caver-js library.
Note caver-js can run on Node.js versions 8 and 10, and the recommended versions are:
lts/carbon ()
lts/dubnium ()
If you are already using a different version of the Node (for example, Node v12), use the Node Version Manager() to install and use the version supported by caver-js.
Installation
To try it out, install caver-js with npm using the following command:
$ npm install caver-js
Note: package.json file should exist on the same install path. If it does not exist, package.json should be generated via npm init.
To install a specific version of caver-js, try the following command:
$ npm install caver-js@X.X.X
Starting with caver-js
Once you have finished installing caver-js, you can now connect caver-js with a Klaytn Node.
You can import the caver-js module and connect it to a Klaytn Node in the Baobab testnet as shown in the example below:
You can use your account easily by using the in-memory wallet provided by caver-js. The following examples illustrate how to add an account to a wallet using an account object and a keystore file generated by Klaytn Wallet.
The account added to the caver-js wallet can be used for sendTransaction.
Sending a Transaction
This section will show you how to send a KLAY using caver-js on the Baobab network.
Getting KLAY via Baobab Faucet
Sending a Value Transfer Transaction
You can use a caver-js wallet to generate a signature of a transaction. If you have an account in the caver-js wallet, the signature generation will be done with the private key inside the caver-js wallet when you execute caver.klay.sendTransaction. Note that caver.klay.sendTransaction performs both signature generation and submission of the transaction at once.
// If you have not added an account to caver-js's wallet, add it to your wallet by running 'caver.klay.accounts.wallet.add'.
// If the same account is already in the wallet, 'Error: Account exists with {hex in address}' is returned. In this case, you can use the address string in the `from` field to reference the account in the wallet.
> const account = caver.klay.accounts.wallet.add('0x{private key}')
> caver.klay.sendTransaction({
type: 'VALUE_TRANSFER',
from: account.address',
to: '0xeF5cd886C7f8d85fbe8023291761341aCBb4DA01',
gas: '300000',
value: 1,
}).then(console.log)
{
blockHash: '0x5e9f427c9550a6f7575bcf60aba9257634884519a6273a23e8eefee2a696cce4',
blockNumber: 3841096,
contractAddress: null,
from: '0x3bd32d55e64d6cbe54bec4f5200e678ee8d1a990',
...
status: true,
to: '0xef5cd886c7f8d85fbe8023291761341acbb4da01',
transactionHash: '0xb09f6d26734074a259f6cbe4d509d2bf40f6f0a4559081354527ae211dd9d00f',
transactionIndex: 1,
type: 'TxTypeValueTransfer',
typeInt: 8,
value: '0x1'
}
If you want to generate a signature directly from the private key without a caver-js wallet, the following steps are required:
caver.klay.accounts.signTransaction - The process of signing a transaction with a private key and getting a RLP-encoded transaction.
caver.klay.sendSignedTransaction - sends the RLP-encoded transaction to the node connected to caver-js.
First, to sign the transaction, specify the sender, recipient, and the private key appropriately like shown below:
Note: The sender should have enough amount of KLAY.
As shown in the example above, you can send a request and use the event emitter to get the hash of the submitted transaction by calling .on('transactionHash', console.log).
Checking Receipts
The following example shows how to get a receipt using promise and event emitter.
With the signed RLP-encoded transaction object (rawTransaction), the fee payer can send the transaction after attaching the one's signature. The fee payer sets the rawTransaction to senderRawTransaction and signs with the address of the fee payer, as in the example below.
// If you have not added a fee payer account to caver-js's wallet, add it to your wallet by running 'caver.klay.accounts.wallet.add'.
// If an account is already added to the wallet, 'Error: Account is existed with {hex in address}' is returned. In this case, please use the account's address instead of `feePayer.address`.
> const feePayer = caver.klay.accounts.wallet.add('0x{private key}')
> caver.klay.sendTransaction({
senderRawTransaction: rawTransaction,
feePayer: feePayer.address,
}).then(console.log)
{
blockHash: '0xf0c4ef717a674ffaea8bf68597c936ce8a3773dab1e1f6f42508963f124bc301',
blockNumber: 3840725,
...
transactionHash: '0x8d1fea7710bc351540257a4ae7f2274d66ddd7f62bcdb6f1f77893cecb659405',
transactionIndex: 2,
type: 'TxTypeFeeDelegatedValueTransfer',
typeInt: 9,
value: '0xde0b6b3a7640000'
}
NOTE: The fee payer's account must be in the caver-js wallet.
Account Update
// If you have not added an account to caver-js's wallet, add it to your wallet by running 'caver.klay.accounts.wallet.add'.
// If the same account is already in the wallet, 'Error: Account exists with {hex in address}' is returned. In this case, you can use the address string in the `from` field to reference the account in the wallet.
> const account = caver.klay.accounts.wallet.add('0x{private key}')
> caver.klay.sendTransaction({
type: 'ACCOUNT_UPDATE',
from: account.address,
publicKey: '0x9016de15ebb219b1e8bc732070df93a28903e5799d0cd24a807a5afabf4601f7e5ab312b5a682dd8c0e72e71e67552174d5082cde25db3626a5b025f97f8a005',
gas: '300000',
}).then(console.log);
Smart Contract
First, we start by compiling a smart contract to get its bytecode and ABI.
NOTE: To compile a smart contract, you must have a solidity compiler installed.
If the contract instance is created, you can deploy it by passing the bytecode to the data field as shown below:
// If you have not added an account to caver-js's wallet, add it to your wallet by running 'caver.klay.accounts.wallet.add'.
// If the same account is already in the wallet, 'Error: Account exists with {hex in address}' is returned. In this case, you can use the address string in the `from` field to reference the account in the wallet.
> const account = caver.klay.accounts.wallet.add('0x{private key}')
> contractInstance.deploy({
data: '60806040526000805534801561001457600080fd5b50610123806100246000396000f3fe6080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60df565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260e5565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060dd6004803603602081101560c857600080fd5b810190808035906020019092919050505060ed565b005b60005481565b600043905090565b806000819055505056fea165627a7a72305820e381897039d8e48bf74b4a096bb1c4ed02f331bd1a7a4add6217b72fa888f2f10029',
}).send({
from: account.address,
gas: '0x4bfd200',
value: '0x0',
}).then(console.log)
{
blockHash: '0x71426773ed65f307bdfac5070ac54f11f406086bbe8dfa170215ed4190f176ed',
blockNumber: 226,
codeFormat: '0x0',
contractAddress: '0xC9f0b868e5103b6823171a2Df85E7B696660E466',
from: '0x71959675eeb7c7ec1e0c74f206a9c488d7f178d4',
gas: '0x4bfd200',
gasPrice: '0x5d21dba00',
gasUsed: 149017,
humanReadable: false,
input: '0x60806040526000805534801561001457600080fd5b50610123806100246000396000f3fe6080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60df565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260e5565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060dd6004803603602081101560c857600080fd5b810190808035906020019092919050505060ed565b005b60005481565b600043905090565b806000819055505056fea165627a7a72305820e381897039d8e48bf74b4a096bb1c4ed02f331bd1a7a4add6217b72fa888f2f10029',
...
type: 'TxTypeSmartContractDeploy',
typeInt: 40,
value: '0x0',
events: {}
}
The deployed contract address can be found in contractAddress of the transaction receipt. Before sending a smart contract execution transaction, set the address to the address of the contract instance as follows:
// If you have not added an account to caver-js's wallet, add it to your wallet by running 'caver.klay.accounts.wallet.add'.
// If the same account is already in the wallet, 'Error: Account exists with {hex in address}' is returned. In this case, you can use the address string in the `from` field to reference the account in the wallet.
> const account = caver.klay.accounts.wallet.add('0x{private key}')
> contractInstance.methods.setCount(1).send({from:account.address, gas:'0x4bfd200'}).then(console.log)
{
blockHash: '0x159f8515102951bca9c403b2b1b37850ca01a08dffb9a763837f55a6d518bbb6',
blockNumber: 644,
contractAddress: null,
from: '0x71959675eeb7c7ec1e0c74f206a9c488d7f178d4',
gas: '0x4bfd200',
gasPrice: '0x5d21dba00',
gasUsed: 44875,
input: '0xd14e62b80000000000000000000000000000000000000000000000000000000000000001',
...
type: 'TxTypeSmartContractExecution',
typeInt: 48,
value: '0x0',
events: {}
}
The examples below describe the example in a Node.js file. To practice the examples, first create a test file in the working directory as shown below.
$ touch test.js
You can see the test.js file created in the working directory.
Write the following code in test.js.
// test.js file
const Caver = require('caver-js')
const caver = new Caver('https://public-en-baobab.klaytn.net/')
async function testFunction() {
const version = await caver.klay.getNodeInfo()
console.log(version)
}
testFunction()
Save the file and run it in your console.
$ node ./test.js
If you see the output of console.log, proceed with the steps below.
Account
The following example creates an account with AccountKeyPublic as accountKey.
// test.js file
async function testFunction() {
// Create random account with accountKeyPublic by default
const account = caver.klay.accounts.create()
printAccount(account)
// Create account with specific private key string
const privateKey = caver.klay.accounts.create().privateKey
const accountFromKey = caver.klay.accounts.privateKeyToAccount(privateKey)
printAccount(accountFromKey)
}
function printAccount(account) {
console.log(`address: ${account.address}`)
console.log(`privateKey: ${account.privateKey}`)
console.log(`accountKeyType: ${account.accountKeyType}`)
console.log(`accountKey`)
console.log(account.accountKey)
console.log(`account.keys: ${account.keys}`)
console.log(`account.transactionKey: ${account.transactionKey}`)
console.log(`account.updateKey: ${account.updateKey}`)
console.log(`account.feePayerKey: ${account.feePayerKey}\n`)
}
The printAccount above shows how to use the properties of the Account instance. The properties inside Account are as follows.
Property Name
Description
address
The address of the account.
privateKey
Default key string of accountKey that the account has. This property is left for backward compatibility. privateKey only represents the default key of accountKey, so using privateKey to sign or send a transaction is not recommended. It is recommended to use transactionKey, updateKey, or feePayerKey in context.
accountKeyType
Type of accountKey the account has. This can be AccountKeyPublic, AccountKeyMultiSig, or AccountKeyRoleBased
accountKey
The key of the account. This is AccountKeyPublic, AccountKeyMultiSig or AccountKeyRoleBased.
keys
All keys inside accountKey that the account has.
transactionKey
updateKey
feePayerKey
NOTEtransactionKey, updateKey, and feePayerKey return a private key string or an array of private key strings that should be used for the role. So rather than using privateKey property, it is recommended that you use transactionKey, updateKey and feePayerKey as appropriate, without worrying about the accountKey type.
AccountKey
To support this structure, caver-js introduces new classes called AccountKeyPublic, AccountKeyMultiSig, and AccountKeyRoleBased.
To create an AccountKey, use caver.klay.accounts.createAccountKey. This function determines which AccountKey to generate based on the type of the parameter. It creates AccountKeyPublic if a private key string comes as a parameter, or AccountKeyMultiSig if an array of private key strings comes. And if there is an object with a different key for each role, it creates AccountKeyRoleBased.
NOTE The classes for AccountKey defined in caver-js are data structures for storing private keys for use in caver-js. It can be different from the key in your account on Klaytn network.
AccountKeyPublic
AccountKeyPublic is a class for storing and managing a single private key string.
The following describes how to update an account with AccountKeyPublic. Write the following code into testFunction() and run it.
AccountKeyPublic stores and manages a private key string, so if you run the example above, you will see that keys, transactionKey, updateKey and feePayerKey all represent the same private key string.
See below for an example of creating an Account with AccountKeyPublic as its accountKey.
const privateKey = caver.klay.accounts.create().privateKey
const accountKey = caver.klay.accounts.createAccountKey(privateKey)
const address = caver.klay.accounts.create().address
// Create an Account instance with a private key string
const accountFromStringKey = caver.klay.accounts.createWithAccountKey(address, privateKey)
// Create an Account instance with an AccountKeyPublic instance
const accountFromAccountKey = caver.klay.accounts.createWithAccountKey(address, accountKey)
AccountKeyMultiSig
AccountKeyMultiSig is a class for storing and managing multiple private key strings.
The following describes how to update an account with AccountKeyMultiSig. Write the following code into testFunction() and run it.
AccountKeyMultiSig stores and manages multiple private key strings, so if you run the example above, you will see that keys, transactionKey, updateKey and feePayerKey all represent the same multiple private key strings.
If you do not specify a private key (or an array of private key strings) to use when signing a transaction, caver-js will find an account from the in-memory wallet that matches the from or fee payer and sign with it. In this case, if your account has multiple private keys, caver-js will sign the transaction with all of those keys.
See below for an example of creating an Account with AccountKeyMultiSig as its accountKey.
See below for an example of creating an Account with AccountKeyRoleBased as its accountKey.
const keyobject = {
transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
updateKey: caver.klay.accounts.create().privateKey,
feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
}
const accountKey = caver.klay.accounts.createAccountKey(keyobject)
const address = caver.klay.accounts.create().address
// Create Account instance with an object that defines key by role
const accountFromStringKey = caver.klay.accounts.createWithAccountKey(address, keyobject)
// Create Account instance with AccountKeyRoleBased instance
const accountFromAccountKey = caver.klay.accounts.createWithAccountKey(address, accountKey)
Through the above examples you will see how to use Account and various AccountKey types in caver-js.
Note that these examples do not affect the Klaytn network. If you want to use your account with a specific account key type, such as AccountKeyPublic, AccountKeyMultiSig, or AccountKeyRoleBased, you must send an account update transaction to the Klaytn network.
AccountForUpdate
AccountForUpdate is a class designed to make it easier to use transactions for account updates.
The AccountForUpdate contains only the public key to be used for account update and the address of the account to update.
Create an AccountForUpdate
Let's start by creating an AccountForUpdate.
You can create it by calling createAccountForUpdate() with the target account address and the new key you want to use.
NOTE If you want to update with multiple private key strings, you must define thresholds and weights in the options object.
Account update with AccountForUpdate
You can easily create an account update transaction using AccountForUpdate created above.
There are three types of transactions used to update an account: ACCOUNT_UPDATE, FEE_DELEGATED_ACCOUNT_UPDATE and FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO.
In the example below, account is an account that has enough KLAY balance, and accountForUpdate is an AccountForUpdate instance that contains the new key and the target account address. accountForUpdate is created using caver.klay.accounts.createAccountForUpdate`.
The example below demonstrates how to create a transaction using AccountForUpdate and send it to the Klaytn network.
const updateTx = {
type: 'ACCOUNT_UPDATE',
from: account.address,
key: accountForUpdate,
gas: 300000,
}
// Sign transaction with updateKey of account
const signed = await caver.klay.accounts.signTransaction(updateTx, account.updateKey)
// Send account update transaction
const receipt = await caver.klay.sendSignedTransaction(signed)
console.log(receipt)
// Get accountKey from Klaytn network
const updatedKey = await caver.klay.getAccountKey(account.address)
console.log(updatedKey)
If you want to use FEE_DELEGATED_ACCOUNT_UPDATE transaction, see the example below.
If your account has been updated successfully, the old key can no longer be used. Update the accountKey of the account stored in caver-js as follows.
When updating the accountKey property of an account directly, the assigning value must be an instance of AccountKeyPublic, AccountKeyMultiSig, or AccountKeyRoleBased.
If your account is in the caver-js in-memory wallet, please update it as below.
// Add account to in-memory wallet
caver.klay.accounts.wallet.add(account)
caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
You are now ready to use the updated account in caver-js.
Sending a Transaction with multiple signer
If the account's accountKey is AccountKeyMultiSig or AccountKeyRoleBased, the person who manages each key can be different.
This section describes how to collect signatures and send the transaction if there are multiple signers.
Sequential sign
The rawTransaction has an RLP encoded transaction that contains both signatures and feePayerSignatures. feePayerSignature is included only when the transaction is a fee delegated transaction.
The following example shows how to sign a transaction sequentially with multiple private keys. Assume the account's transactionKey has two private key strings.
See the example below for signing with a fee payer's key whose type is an AccountKeyRoleBased. The fee payer is assumed to have three private key strings in feePayerKey.
If the account you use exists in the caver-js in-memory wallet, you do not need to pass the key(s) to signTransaction or feePayerSignTransaction. See the example below.
const tx = {
type: 'FEE_DELEGATED_VALUE_TRANSFER_WITH_RATIO',
from: account.address,
to: caver.klay.accounts.create().address,
value: 1,
gas: 900000,
feeRatio: 10,
}
// Sign with transactionKey[0] and transactionKey[1]
const userSigned = await caver.klay.accounts.signTransaction(tx)
// Fee payer signs transaction with feePayerKey[0], feePayerKey[1] and feePayerKey[2]
const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(userSigned.rawTransaction, feePayer.address)
const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
console.log(receipt)
Combine signatures from RawTransaction
If you receive the result object of the caver.klay.accounts.signTransaction or caver.klay.accounts.feePayerSignTransaction from several people, you can create a single RLP encoded transaction that contains all the signature information.
The example below shows how to combine and send the RLP encoded transactions.
Send transaction object with Signatures and FeePayerSignatures
If you only receive signatures or feePayerSignatures from multiple signers, you can send a transaction as follows:
const tx = {
type: 'FEE_DELEGATED_VALUE_TRANSFER_WITH_RATIO',
from: account.address,
to: caver.klay.accounts.create().address,
value: 1,
gas: 900000,
feeRatio: 10,
}
// Sign with transactionKey[0] and transactionKey[1]
const { signatures } = await caver.klay.accounts.signTransaction(tx)
// Fee payer signs transaction with feePayerKey[0], feePayerKey[1] and feePayerKey[2]
const { feePayerSignatures } = await caver.klay.accounts.feePayerSignTransaction(tx, feePayer.address)
// Fill in the missing information in the tx object.
tx.signatures = signatures
tx.feePayer = feePayer.address
tx.feePayerSignatures = feePayerSignatures
const receipt = await caver.klay.sendSignedTransaction(tx)
console.log(receipt)
You can also call caver.klay.accounts.getRawTransactionWithSignatures to get an RLP encoded transaction containing the signatures and feePayerSignatures of the transaction object.
const tx = {
type: 'FEE_DELEGATED_VALUE_TRANSFER_WITH_RATIO',
from: account.address,
to: caver.klay.accounts.create().address,
value: 1,
gas: 900000,
feeRatio: 10,
}
// Sign with transactionKey[0] and transactionKey[1]
const { signatures } = await caver.klay.accounts.signTransaction(tx)
// Fee payer signs transaction with feePayerKey[0], feePayerKey[1] and feePayerKey[2]
const { feePayerSignatures } = await caver.klay.accounts.feePayerSignTransaction(tx, feePayer.address)
// Fill in the missing information in the tx object.
tx.signatures = signatures
tx.feePayer = feePayer.address
tx.feePayerSignatures = feePayerSignatures
const { rawTransaction } = await caver.klay.accounts.getRawTransactionWithSignatures(tx)
console.log(rawTransaction)
Sample Projects
Sample projects for development of dApps (Decentralized Applications) using caver-js can be found below:
Links
You can use caver-js to create an account as shown below. You can also create an account via .
Note: Functions associated with have no effect on the actual Klaytn network.
If you need KLAY for testing, you can get Baobab testnet KLAY from the . Log in to the Klaytn Wallet using the private key or the keystore file and receive Baobab testnet KLAY via the faucet for testing.
You can get a RLP-encoded transaction (rawTransaction) using as above and use this to transfer the transaction to the Klaytn network as below.
You can use the promise or event emitter to get the receipt of the transaction when you transfer the transaction to or .
As described in the example above, you can get the result of sending a transaction through the promise and event emitter. And also, if you know the transaction hash, you can query the transaction receipt using the RPC call. The example below shows how to get a receipt using the RPC call.
The result of the transaction can be found through the status of the receipt. For a detailed description of the return values, see . If a transaction is failed, you can check the detailed error in txError of the receipt. For more information about txError, see .
Klaytn provides various transaction types for extensibility and performance. For more information, see . This section describes various examples that can be used with caver-js.
Klaytn provides feature. Here's an example code.
If you want to change the key of the account, send a transaction as shown below. Please check for the transaction field according to the key type.
The package makes it easy to interact with smart contracts on Klaytn. It automatically converts all methods of a smart contract into javascript calls when its low-level ABI (Application Binary Interface) is given. This allows you to interact with smart contracts as if they were JavaScript objects.
For smart contract deployment, you can use to deploy it, or you can deploy it using transaction. Here is an example of using .
One way to invoke a specific method of a smart contract is to use it with caver.klay.Contract or use .
See for details.
caver-js introduces new classes to support the various types of supported by the platform.
NOTE Those classes are supported since caver-js .
Account is a class containing the address and key of an account. The Account has an , which can be of type , , or .
The caver.klay.accounts package uses , which stores and manages a private key string by default.
Key used for the . AccountKeyPublic or AccountKeyMultiSig are not bound to any roles, so transactionKey holds the same value as keys.
Key used for the . AccountKeyPublic or AccountKeyMultiSig are not bound to any roles, so updateKey holds the same value as keys.
Key used for . AccountKeyPublic or AccountKeyMultiSig are not bound to any roles, so feePayerKey holds the same value as keys.
An explanation of the various AccountKey classes is provided in the part.
AccountKey is a data structure that stores the keys of an account. An account can have one private key string or multiple private key strings to be used for signing. Account can also manage the private keys by .
AccountKeyRoleBased stores and manages keys by role, so if you run the example above, you will see three roles (transactionKey, updateKey, feePayerKey) defined in keys property. Therefore, unlike other AccountKey ( or ), transactionKey, updateKey and feePayerKey each represents a different key.
The following explains how to update an account by sending a transaction to the Klaytn network.
The examples below start with updating your account with accountKey. There must be enough KLAY in the account to be used for testing. Test KLAY for the Baobab network is available through .
NOTEcaver.klay.accounts.feePayerSignTransaction is supported since caver-js .
The result object of has a rawTransaction field.
NOTEcaver.klay.accounts.feePayerSignTransaction is supported since caver-js .
NOTEcaver.klay.accounts.combineSignatures is supported since caver-js .
NOTEcaver.klay.accounts.getRawTransactionWithSignatures is supported since caver-js .