개발자가 HTTP 또는 웹소켓 연결을 사용하여 Klaytn 노드와 상호작용할 수 있도록 하는 자바스크립트 API 라이브러리
https://ko.docs.klaytn.com/bapp/sdk/caver-js/getting-started#smart-contract
caver-js는 Klaytn에서 오류 메시지를 포착할 수 있음
트랜잭션 영수증의 txError에서 찾을 수 있음
고정된 가스 가격만큼을 제출해야 함
$ npm install caver-js
이 때, package.json파일이 설치 경로와 동일한 곳에 존재해야 함
👉 KLAY 전송 알아보기
keystore file을 이용해 KLAY전송
const fs = require('fs')
const Caver = require('./index')
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
async function testFunction() {
// Read keystore json file
const keystore = fs.readFileSync('./keystore.json', 'utf8')
// Decrypt keystore
const keyring = caver.wallet.keyring.decrypt(keystore, 'password')
console.log(keyring)
// Add to caver.wallet
caver.wallet.add(keyring)
// Create value transfer transaction
const vt = new caver.transaction.valueTransfer({
from: keyring.address,
to: '0x8084fed6b1847448c24692470fc3b2ed87f9eb47',
value: caver.utils.toPeb(1, 'KLAY'),
gas: 25000,
})
// Sign to the transaction
const signed = await caver.wallet.sign(keyring.address, vt)
// Send transaction to the Klaytn blockchain platform (Klaytn)
const receipt = await caver.rpc.klay.sendRawTransaction(signed)
console.log(receipt)
}
testFunction()
<코드 입력>
$ touch test.js
작업 디렉토리에 생성된 test.js 파일을 확인해보기
<test.js에 코드를 작성>
// test.js
const Caver = require('caver-js')
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
async function testFunction() {
const version = await caver.rpc.klay.getClientVersion()
console.log(version)
}
testFunction()
<코드 실행 결과>
$ node ./test.js
Klaytn/v1.4.0/linux-amd64/go1.14.1
<caver-js 모듈을 가져와 Baobab 테스트넷의 Klaytn 노드에 연결>
const Caver = require('caver-js')
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
만약 EN을 실행중이라면?
const Caver = require('caver-js')
const caver = new Caver('http://localhost:8551/')
Klaytn 계정 주소와 개인 키가 포함된 structure
<Keyring 종류>
1. SingleKeyring : 하나의 주소와 하나의 개인 키를 저장
2. MultipleKeyring : 하나의 주소와 여러 개인 키를 저장
3. RoleBasedKeyring : 각 역할에 대해 하나의 주소와 하나 이상의 개인 키를 저장
지갑(caver.walle)에 Keyring 추가하기
// test.js
const Caver = require('caver-js')
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
async function testFunction() {
// Using a keyring instance
const keyring = caver.wallet.keyring.generate()
caver.wallet.add(keyring)
console.log(caver.wallet.getKeyring(keyring.address))
// Using a keystore file
const decrypted = caver.wallet.keyring.decrypt({
version: 4,
id: '9c12de05-0153-41c7-a8b7-849472eb5de7',
address: '0xc02cec4d0346bf4124deeb55c5216a4138a40a8c',
keyring: [
{
ciphertext: 'eacf496cea5e80eca291251b3743bf93cdbcf7072efc3a74efeaf518e2796b15',
cipherparams: { iv: 'd688a4319342e872cefcf51aef3ec2da' },
cipher: 'aes-128-ctr',
kdf: 'scrypt',
kdfparams: {
dklen: 32,
salt: 'c3cee502c7157e0faa42386c6d666116ffcdf093c345166c502e23bc34e6ba40',
n: 4096,
r: 8,
p: 1
},
mac: '4b49574f3d3356fa0d04f73e07d5a2a6bbfdd185bedfa31f37f347bc98f2ef26'
}
]
}, 'password')
caver.wallet.add(decrypted)
console.log(caver.wallet.getKeyring(decrypted.address))
}
testFunction()
<Baobab 네트워크에서 caver-js를 사용하여 KLAY 보내기>
개인키 또는 키스토어 파일을 사용하여 Klaytn Wallet에 로그인,
faucet을 통해 Baobab 테스트넷 KLAY를 받아옴
caver-js 지갑을 통해 트랜잭션 서명 가능
트랜잭션 서명하기
caver.wallet 또는 caver.wallet.sign 사용
caver.wallet에 Keyring을 추가하지 않고 따로 관리할 경우, transaction.sign 사용
<서명 방법>
Keyring을 caver.wallet에 추가하고, 트랜잭션을 생성하고,
caver.wallet.sign를 통해 이 트랜잭션에 서명
// test.js
const Caver = require('caver-js')
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
async function testFunction() {
// Add a keyring to caver.wallet
const keyring = caver.wallet.keyring.createFromPrivateKey('0x{private key}')
caver.wallet.add(keyring)
// Create a value transfer transaction
const valueTransfer = new caver.transaction.valueTransfer({
from: keyring.address,
to: '0x176ff0344de49c04be577a3512b6991507647f72',
value: 1,
gas: 30000,
})
// Sign the transaction via caver.wallet.sign
await caver.wallet.sign(keyring.address, valueTransfer)
const rlpEncoded = valueTransfer.getRLPEncoding()
console.log(`RLP-encoded string: ${rlpEncoded}`)
}
testFunction()
<코드 실행 결과>
RLP-encoded string: 0x08f87e808505d21dba0082753094176ff0344de49c04be577a3512b6991507647f720194ade4883d092e2a972d70637ca7de9ab5166894a2f847f845824e44a0e1ec99789157e5cb6bc691935c204a23aaa3dc049efafca106992a5d5db2d179a0511c421d5e508fdb335b6048ca7aa84560a53a5881d531644ff178b6aa4c0a41
caver.rpc.klay.sendRawTransaction을 통해 Klaytn에 전송0x{RLP-encoded string}를 위 rlpEncoded 값으로 대체하여 아래 코드 실행
// test.js
const Caver = require('caver-js')
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
async function testFunction() {
const rlpEncoding = `0x{RLP-encoded string}`
// Send the transaction using `caver.rpc.klay.sendRawTransaction`.
const receipt = await caver.rpc.klay.sendRawTransaction(rlpEncoding)
console.log(receipt)
}
testFunction()
<코드 실행 결과>
$ node ./test.js
{
blockHash: '0xd20066b448da77a41a46fbf0856792b85b60c42213126f661f6434b5b1263072',
blockNumber: '0x1efb',
contractAddress: null,
from: '0x09a08f2289d3eb3499868908f1c84fd9523fe11b',
gas: '0x7530',
...
signatures: [
{
V: '0x4e43',
R: '0x5737aa8c88f019a3ee184faed6d34d103f77773bd5434cb0328c11738c8d9755',
S: '0x578b118f4400999e5232bd0860cfbdbf89622f6e11cc6bd9722a86767d2723b7'
}
],
status: '0x1',
to: '0x176ff0344de49c04be577a3512b6991507647f72',
transactionHash: '0x43e8ab1a2365ad598448b4402c1cfce6a71b3a103fce3a69905613e50b978113',
transactionIndex: 0,
type: 'TxTypeValueTransfer',
typeInt: 8,
value: '0x1'
}
caver.wallet없이 전송도 가능
프로미스(promise)와 이벤트 이미터(event emitter)를 통해 트랜잭션을 전송한 결과를 가져올 수 있음
트랜잭션의 실행 결과는 영수증의 status를 통하여 확인 가능
수수료 위임에는 발신자 서명, 수수료 납부자 서명이 필요함.
// test.js
const Caver = require('caver-js')
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
async function testFunction() {
const sender = caver.wallet.keyring.createFromPrivateKey('0x{private key}')
caver.wallet.add(sender)
const feeDelegatedTx = new caver.transaction.feeDelegatedValueTransfer({
from: sender.address,
to: '0x176ff0344de49c04be577a3512b6991507647f72',
value: 5,
gas: 50000,
})
await caver.wallet.sign(sender.address, feeDelegatedTx)
const rlpEncoded = feeDelegatedTx.getRLPEncoding()
console.log(rlpEncoded)
}
testFunction()
if caver.wallet에 수수료 납부자 키도 같이 있음 - caver.wallet.signAsFeePayer(feePayer.address, feeDelegatedTx)를 호출하여 수수료 납부자 서명을 feeDelegatedTx에 넣음
else - 수수료 납부자는 트랜잭션 발신자가 서명한 RLP 인코딩된 문자열에서 feeDelegatedTx를 새로 만들고, 자신의 서명을 여기에 추가
// test.js
const Caver = require('caver-js')
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
async function testFunction() {
const feePayer = caver.wallet.keyring.createFromPrivateKey('0x{private key}')
caver.wallet.add(feePayer)
const rlpEncoded = '0x{RLP-encoded string}'
const feeDelegateTxFromRLPEncoding = new caver.transaction.feeDelegatedValueTransfer(rlpEncoded)
// Set the fee payer address.
feeDelegateTxFromRLPEncoding.feePayer = feePayer.address
await caver.wallet.signAsFeePayer(feePayer.address, feeDelegateTxFromRLPEncoding)
console.log(feeDelegateTxFromRLPEncoding.getRLPEncoding())
}
testFunction()
저수준 ABI(Application Binary Interface)가 주어지면 스마트 컨트랙트의 모든 메소드를 자동으로 자바스크립트 호출로 변환하기 때문에, 스마트 컨트랙트가 자바스크립트 개체인 것처럼 사용됨
contractInstance.options.address)에 스마트 컨트랙트 주소를 입력.data필드에 전달해 배포같은 트랜잭션을 공유할 때
여러 개인 키를 사용하여 트랜잭션에 순차적으로 서명
같은 트랜잭션을 공유하지 않을 때
서명을 RLP 인코딩된 문자열에 첨부
서명된 raw transaction들을 결합( RLP 인코딩된 트랜잭션들을 하나로 통합하 고 전송)
// test.js
const Caver = require('caver-js')
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
async function testFunction() {
const vt = new caver.transaction.valueTransfer({
from: '0x0fa355263f37f5a54d9179452baa8b63b8b2cdde',
to: '0x45c2a1e3a1c3957a06dae73ad516461c2d2c7ccc',
value: 1,
gas: 70000,
})
const rlpEncodedStrings = [
'0x08f87f018505d21dba00830111709445c2a1e3a1c3957a06dae73ad516461c2d2c7ccc01940fa355263f37f5a54d9179452baa8b63b8b2cddef847f845824e44a01aa72b883ca540c8a63de244cd061ec4f9efb139541e8db304c07ec27bc9d272a06a4ca54f6269f2ddfe3648eb9ed57b0c5739f0077e1a38449f3ae3cc0b20dc3e',
'0x08f8c6018505d21dba00830111709445c2a1e3a1c3957a06dae73ad516461c2d2c7ccc01940fa355263f37f5a54d9179452baa8b63b8b2cddef88ef845824e44a01aa72b883ca540c8a63de244cd061ec4f9efb139541e8db304c07ec27bc9d272a06a4ca54f6269f2ddfe3648eb9ed57b0c5739f0077e1a38449f3ae3cc0b20dc3ef845824e43a0fd76dfc53c812ec6aa860076f731e3913936088a1518cc34f2d176bcbe0ac772a071491c938458fffe106dde485fc8b26cbebe8a517c46bd185b126930f480d773',
'0x08f8c6018505d21dba00830111709445c2a1e3a1c3957a06dae73ad516461c2d2c7ccc01940fa355263f37f5a54d9179452baa8b63b8b2cddef88ef845824e44a01aa72b883ca540c8a63de244cd061ec4f9efb139541e8db304c07ec27bc9d272a06a4ca54f6269f2ddfe3648eb9ed57b0c5739f0077e1a38449f3ae3cc0b20dc3ef845824e43a021e84a4740b374cdcf0cc38f93225f6d2f77388a9d90302d47b4f3ed84e4db5fa072ff5e77d2506d5222081c4d2a341c6ee5d258500030564f985951472f247b7d',
]
const combined = vt.combineSignedRawTransactions(rlpEncodedStrings)
console.log(combined)
}
testFunction()