新手指南
This documentation is for developers using caver-js v1.5.0 or higher.
先決條件
依賴關係
使用 caver-js 庫需要以下軟件包。
注意* caver-js 可在 Node.js 12 和 14 版本上運行。 推薦的版本如下
如果使用不同版本的 Node(例如 Node v15),請使用 Node Version Manager(nvm) 安裝並使用 caver-js 支持的版本。
安裝
要試用它,請使用以下命令通過 npm 安裝 caver-js:
$ npm install caver-js
注意:package.json文件應存在於同一安裝路徑中。 如果不存在,可通過
npm init生成
package.json`。
要安裝特定版本的 caver-js,請嘗試執行以下命令:
$ npm install caver-js@X.X.X
從 caver-js 開始
完成 caver-js 安裝後,就可以使用 caver-js 連接 kaia 節點了。
要練習下面的示例,首先在工作目錄中創建一個測試文件。
$ touch test.js
您可以看到在工作目錄中創建的 test.js
文件。
在 test.js 中編寫以下代碼。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const version = await caver.rpc.klay.getClientVersion() console.log(version)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.jskaia/v1.4.0/linux-amd64/go1.14.1
如果看到如上所示的 console.log 輸出,請繼續以下步驟。 版本號可能因所連接的 kaia 節點版本不同而不同。
連接 kaia 節點
您可以導入 caver-js 模塊,並將其連接到 Kairos 測試網絡中的 kaia 節點,如下圖所示:
const Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')
如果運行的是 EN,可以通過更改主機和端口將其連接到自己的節點,如下所示:
const Caver = require('caver-js')const caver = new Caver('https://your.en.url:8651/')
管理 Keyrings
Keyring是一個包含 kaia 賬戶地址和私鑰的結構。
根據所存儲密鑰的類型,Keyring 可分為三種類型:SingleKeyring 用於存儲一個地址和一個私人鑰匙,MultipleKeyring 用於存儲一個地址和多個私人鑰匙,RoleBasedKeyring 用於存儲一個地址和每個角色的一個或多個私人鑰匙。
SingleKeyring在內部定義了 "key "屬性,該 "key "存儲一個私人密鑰。
MultipleKeyring在內部定義了 "keys "屬性,該 "keys "以數組形式實現,用於存儲多個私鑰。
RoleBasedKeyring](api/caver-wallet/keyring.md#rolebasedkeyring)中定義的keys
屬性是以二維數組的形式實現的(空keys
看起來像[ [], [], [] ]
),每個role可以包含多個鍵。 數組的第一個元素填入用於 roleTransactionKey
的私鑰,第二個元素填入用於 roleAccountUpdateKey
的私鑰,第三個元素填入用於 roleFeePayerKey
的私鑰。
創建Keyring
生成 SingleKeyring
如下圖所示,您可以隨機生成一個keyring。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const keyring = caver.wallet.keyring.generate() console.log(keyring)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.jsSingleKeyring { _address: '0x3d263c3c0df60c5516f932d244531742f45eed5c', _key: PrivateKey { _privateKey: '0x{private key}' }}
執行結果如上圖所示。 可以通過 keyring.address
和 keyring.key
訪問實例內部定義的成員變量。
從私人密鑰創建SingleKeyring
此外,如果你擁有特定的私人密鑰,還可以用它創建一個鑰匙圈,如下圖所示。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { // Create a keyring from a private key const keyringFromPrivateKey = caver.wallet.keyring.createFromPrivateKey('0x{private key}') console.log(keyringFromPrivateKey)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.jsSingleKeyring { _address: '0xf5a9079f311f9ec55170af351627aff0c5d2e287', _key: PrivateKey { _privateKey: '0x{private key}' } }
caver.wallet.keyring.createFromPrivateKey "的結果,就像上面 "caver.wallet.keyring.generate "的結果一樣,是一個SingleKeyring實例,其中定義了一個地址和 "keyring.key "中的一個[PrivateKey]實例。
使用私鑰和地址創建 SingleKeyring
如果 kaia 賬戶的私鑰與地址不相關聯,則可以使用給定的地址和私鑰創建一個密鑰環,如下所示。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { // Create a keyring with an address and a private key const keyring = caver.wallet.keyring.createWithSingleKey('0x{address in hex}', '0x{private key}') console.log(keyring) // Create a keyring from a KlaytnWalletKey const keyringFromKlaytnWalletKey = caver.wallet.keyring.createFromKlaytnWalletKey('0x{private key}0x{type}0x{address in hex}') console.log(keyringFromKlaytnWalletKey)}testFunction()
在控制檯中運行代碼,如下所示。
$ node ./test.jsSingleKeyring { _address: '0x17e7531b40ad5d7b5fa7b4ec78df64ce1cb36d24', _key: PrivateKey { _privateKey: '0x{private key}' }}SingleKeyring { _address: '0x17e7531b40ad5d7b5fa7b4ec78df64ce1cb36d24', _key: PrivateKey { _privateKey: '0x{private key}' }}
創建具有多個私人密鑰的 MultipleKeyring
如果要使用多個私鑰,可以使用一個地址和多個私鑰創建一個[MultipleKeyring](api/caver-wallet/keyring.md#multiplekeyring)。 下面的示例展示瞭如何創建具有多個私鑰的 MultipleKeyring 。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { // Create a keyring with an address and private keys const keyring = caver.wallet.keyring.createWithMultipleKey('0x{address in hex}', [ '0x{private key1}', '0x{private key2}' ]) console.log(keyring)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.jsMultipleKeyring { _address: '0x17e7531b40ad5d7b5fa7b4ec78df64ce1cb36d24', _keys: [ PrivateKey { _privateKey: '0x{private key1}' }, PrivateKey { _privateKey: '0x{private key2}' } ]}
可以看到,_keys
數組中有多個 PrivateKey 實例。 可以通過 keyring.address
和 keyring.keys
訪問實例內部定義的成員 變量。
創建帶有私鑰的基於角色的密鑰環
要為每個 role 使用不同的私鑰,可使用 caver.wallet.keyring.createWithRoleBasedKey
代替。 每個數組元素代表 RoleBasedKeyring 中描述的一個角色。 下面的示例展示瞭如何根據每個角色的不同密鑰創建 RoleBasedKeyring 實例。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { // Create a keyring with an address and private keys defined by each roles const keyring = caver.wallet.keyring.createWithRoleBasedKey('0x{address in hex}', [ [ '0x{private key1}', '0x{private key2}', '0x{private key3}' ], [ '0x{private key4}'], [ '0x{private key5}', '0x{private key6}' ], ]) console.log(keyring)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.jsRoleBasedKeyring { _address: '0x17e7531b40ad5d7b5fa7b4ec78df64ce1cb36d24', _keys: [ [ PrivateKey { _privateKey: '0x{private key1}' }, PrivateKey { _privateKey: '0x{private key2}' }, PrivateKey { _privateKey: '0x{private key3}' } ], [ PrivateKey { _privateKey: '0x{private key4}' } ], [ PrivateKey { _privateKey: '0x{private key5}' }, PrivateKey { _privateKey: '0x{private key6}' } ] ]}
從上面的輸出來看,鍵數組的第一個元素 roleTransactionKey
有三個私鑰實例,第二個元素 roleAccountUpdateKey
有一個私鑰實例。 而數組的最後一個元素 roleFeePayerKey
有兩個 PrivateKey 實例。
注意:調用與鑰匙圈(caver.wallet.keyring)或錢包(caver.wallet)相關的函數不會影響實際的 kaia 區塊鏈平臺 (kaia)。
為 caver-js 添加關鍵字
您可以使用 caver-js 提供的內存錢包,輕鬆使用鑰匙圈。 下面的示例說明了如何使用密鑰實例和從 [Kaia 錢包] 導出的密鑰存儲文件 (.../.../.../build/tools/wallets/kaia-wallet.md)向錢包添加密鑰。
開發時,最好使用一個與任何真實資金都不相關的賬戶。 好的方法是創建一個新的瀏覽器配置文件(在 Chrome、Brave、Firefox 等瀏覽器上),並在該瀏覽器上安裝 Kaia 錢包,而且永遠不要向該錢包匯款。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')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()
在控制檯中運行
$ node ./test.jsSingleKeyring { _address: '0x66391720b488a3fb2c7c69d99cd4cd6e23ca18e3', _key: PrivateKey { _privateKey: '0x{private key}' }}SingleKeyring { _address: '0xc02cec4d0346bf4124deeb55c5216a4138a40a8c', _key: PrivateKey { _privateKey: '0x{private key}' }}
從上面的輸出結果來看,將密鑰添加到 caver.wallet
後,就可以從 caver.wallet
中查詢密鑰。
如果您有需要使用的地址和私鑰,可以通過 caver.wallet.newKeyring 輕鬆創建一個密鑰環,並將其直接添加到 caver.wallet 中。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { // Add to wallet with an address and a private key const addedSingle = caver.wallet.newKeyring('0x{address in hex}', '0x{private key1}') console.log(caver.wallet.getKeyring(addedSingle.address)) // Add to wallet with an address and private keys const addedMultiple = caver.wallet.newKeyring('0x{address in hex}', ['0x{private key2}', '0x{private key3}', '0x{private key4}']) console.log(caver.wallet.getKeyring(addedMultiple.address)) // Add to wallet with an address and private keys defined by each roles const addedRoleBased = caver.wallet.newKeyring('0x{address in hex}', [ ['0x{private key5}', '0x{private key6}', '0x{private key7}'], ['0x{private key8}', '0x{private key9}'], ['0x{private key10}', '0x{private key11}'] ]) console.log(caver.wallet.getKeyring(addedRoleBased.address))}testFunction()
運行上述代碼會得到以下結果。 上述代碼的執行結果如下所示。 當使用私鑰執行 caver.wallet.newKeyring
時,一個帶有私鑰的 Keyring 實例就會創建並添加到 caver.wallet
中。 對於多個私鑰,會創建一個包含多個私鑰的 Keyring 實例。 如果為每個角色傳遞一個或多個私鑰作為參數,就會為每個角色創建一個帶有不同私鑰的 Keyring 實例,並將其添加到 caver.wallet
中。
$ node ./test.jsSingleKeyring { _address: '0x651f6ae6b45750082b22805583acc989399c6552', _key: PrivateKey { _privateKey: '0x{private key1}' }}MultipleKeyring { _address: '0xce3ee92aeb4d600a41c98bdf92e8b337e186bf58', _keys: [ PrivateKey { _privateKey: '0x{private key2}' }, PrivateKey { _privateKey: '0x{private key3}' }, PrivateKey { _privateKey: '0x{private key4}' } ]}RoleBasedKeyring { _address: '0x626d5b94ec76a105c5afa370bb7e59050a22b8b5', _keys: [ [ PrivateKey { _privateKey: '0x{private key5}' }, PrivateKey { _privateKey: '0x{private key6}' }, PrivateKey { _privateKey: '0x{private key7}' } ], [ PrivateKey { _privateKey: '0x{private key8}' }, PrivateKey { _privateKey: '0x{private key9}' } ], [ PrivateKey { _privateKey: '0x{private key10}' }, PrivateKey { _privateKey: '0x{private key11}' } ] ]}
caver.wallet.add
或 caver.wallet.newKeyring
返回一個添加到 caver.wallet
的 Keyring 實例。
發送交易
本節將向您介紹如何在 Kairos Testnet 上使用 caver-js 發送 KAIA。
通過 Kairos 龍頭獲取 KAIA
If you need KAIA for testing, you can get Kairos testnet KAIA from the Kaia Faucet.
發送價值轉移交易
您可以使用 caver-js 錢包生成交易簽名。 您必須經過以下兩個步驟才能將交易發送到網絡。
- 簽署交易
- 如果要使用的密鑰已添加到 caver.wallet,則可以使用
caver.wallet.sign
函數簽 名。 - 如果單獨管理鑰匙圈而不將其添加到
caver.wallet
中,則可以通過transaction.sign
函數簽署交易。
- 如果要使用的密鑰已添加到 caver.wallet,則可以使用
- 通過
caver.rpc.klay.sendRawTransaction
,向 kaia 發送已簽名事務的 RLP 編碼字符串。
注意: 發件人應有足夠數量的 KAIA。
簽署交易
在向 kaia 發送交易之前,您應該先簽署交易。
下面是一個例子,說明在 caver.wallet 中添加密鑰後如何簽署交易。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')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 = caver.transaction.valueTransfer.create({ 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()
上述代碼向 caver.wallet
添加了一個密鑰,創建了一個交易,並通過 caver.wallet.sign
簽署了該交易。
運行上述代碼會得到以下結果。 執行上述代碼後,事務的 RLP 編碼字符串如下所示。 (您得到的 RLP 編碼字符串輸出可能與下圖所 示的字符串輸出不同)。
RLP-encoded string: 0x08f87e808505d21dba0082753094176ff0344de49c04be577a3512b6991507647f720194ade4883d092e2a972d70637ca7de9ab5166894a2f847f845824e44a0e1ec99789157e5cb6bc691935c204a23aaa3dc049efafca106992a5d5db2d179a0511c421d5e508fdb335b6048ca7aa84560a53a5881d531644ff178b6aa4c0a41
向 kaia 發送已簽名交易的 RLP 編碼字符串
現在你可以像下面這樣向網絡發送已簽名的交易。 如果要運行下面的示例,請將 0x{RLP-encoded string}
替換為上述 rlpEncoded
的值。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')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
的情況下籤署交易並將其發送到網絡,請參閱下面的示例。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { // Create a value transfer transaction const keyring = caver.wallet.keyring.createFromPrivateKey('0x{private key}') const valueTransfer = caver.transaction.valueTransfer.create({ from: keyring.address, to: '0x176ff0344de49c04be577a3512b6991507647f72', value: 1, gas: 30000, }) // Sign the transaction via transaction.sign await valueTransfer.sign(keyring) // Send the transaction to the kaia using `caver.rpc.klay.sendRawTransaction`. const receipt = await caver.rpc.klay.sendRawTransaction(valueTransfer) console.log(receipt)}testFunction()
執行上述代碼後,就會像上一個示例一樣打印交易收據。
檢查收據
當您通過 caver.rpc.klay.sendRawTransaction 向 kaia 傳輸事務時,您可以使用承諾或事件發射器來獲取事務收據。
下面的示例展示瞭如何使用承諾和事件發射器獲取收據。
// Using a promise - async/awaitconst receipt = await caver.rpc.klay.sendRawTransaction(rawTransaction)console.log(receipt)// Using a promisecaver.rpc.klay.sendRawTransaction(rawTransaction).then(console.log)// Using an event emittercaver.rpc.klay.sendRawTransaction(rawTransaction).on('receipt', console.log)
如上例所述,您可以通過承諾和事件發射器獲取發送事務的結果。 transactionHash "字段在收據對象中定義。 您可以使用caver.rpc.klay.getTransactionReceipt RPC 調用和receipt.transactionHash
,在交易被納入區塊後的任何時間從網絡查詢交易的收據。 下面的示例展示瞭如何使用 caver.rpc.klay.getTransactionReceipt RPC 調用獲取收據。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const receipt = await caver.rpc.klay.getTransactionReceipt('0x40552efbba23347d36f6f5aaba6b9aeb6602e004df62c1988d9b7b1f036e676a') console.log(receipt)}testFunction()
運行上述代碼會得到以下結果。 執行上述代碼後,交易收據如下所示。
$ node ./test.js{ blockHash: '0x65d041011440e04643c546eb8bbb1dcabb659c3b3216e01473cb0712e47b5f69', blockNumber: '0x20db', contractAddress: null, from: '0x09a08f2289d3eb3499868908f1c84fd9523fe11b', gas: '0x7530', ... signatures: [ { V: '0x4e43', R: '0xfabe48071a8b72f0c340b2ee9d948a496cce467aebe027159d66a175e6b4b5b4', S: '0x1d4e503f1b084cda15edeba6b7b8eba15057b9d2484f7f3d095c980c2d98f13' } ], status: '0x1', to: '0x176ff0344de49c04be577a3512b6991507647f72', transactionHash: '0x40552efbba23347d36f6f5aaba6b9aeb6602e004df62c1988d9b7b1f036e676a', transactionIndex: 0, type: 'TxTypeValueTransfer', typeInt: 8, value: '0x1'}
交易結果可通過收據的 "狀態 "查詢。 有關返回值的詳細信息,請參閱 caver.rpc.klay.getTransactionReceipt。 如果交易失敗,可以在收據的 txError
中查看更多有關錯誤的信息。 For more information about txError
, see txError: Detailed Information of Transaction Failures.
執行其他事務類型
Kaia 提供各種事務類型,以提高可擴展性和性能。 For more information, see Transactions. 本節將介紹一些可與 caver-js 配合使用的示例。
收費代表團
Kaia provides Fee Delegation feature. 下面是一個製作 RLP 編碼交易的示例,當您是此類交易的發送方時:
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const sender = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(sender) const feeDelegatedTx = caver.transaction.feeDelegatedValueTransfer.create({ from: sender.address, to: '0x176ff0344de49c04be577a3512b6991507647f72', value: 5, gas: 50000, }) await caver.wallet.sign(sender.address, feeDelegatedTx) const rlpEncoded = feeDelegatedTx.getRLPEncoding() console.log(rlpEncoded)}testFunction()
執行上述代碼後,將打印 RLP 編碼字符串。 (您得到的 RLP 編碼字符串輸出可能與下圖所示的字符串輸出不同)。
$ node ./test.js0x09f884028505d21dba0082c35094176ff0344de49c04be577a3512b6991507647f720594f5a9079f311f9ec55170af351627aff0c5d2e287f847f845824e43a0f4b53dbd4c915cb73b9c7fa17e22106ee9640155a06ab4a7ed8661f846d2a5cca035b5bba6a26d4ccd20c65e8f31cce265c193f1c874806f9fae6b0ee9df0addf080c4c3018080
在將 "feePayerSignatures"(付費者簽名)附加到由交易發送者簽名的 RLP 編碼字符串("rawTransaction"(原始交易))之後,付費者就可以向 kaia 發送交易。 如果 caver.wallet
也有繳費人的密鑰,則可通過調用 caver.wallet.signAsFeePayer(feePayer.address, feeDelegatedTx)
,將繳費人的簽名注入到 feeDelegatedTx
中。 否則,費用支付方必須從發送方簽名的 RLP 編碼字符串中創建一個 "feeDelegatedTx",並在其上添加費用支付方的簽名,如下圖所示。 如果要運行下面的示例,請將 0x{RLP-encoded string}
替換為上述 rlpEncoded
的值。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const feePayer = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(feePayer) const rlpEncoded = '0x{RLP-encoded string}' const feeDelegateTxFromRLPEncoding = caver.transaction.feeDelegatedValueTransfer.create(rlpEncoded) // Set the fee payer address. feeDelegateTxFromRLPEncoding.feePayer = feePayer.address await caver.wallet.signAsFeePayer(feePayer.address, feeDelegateTxFromRLPEncoding) console.log(feeDelegateTxFromRLPEncoding.getRLPEncoding())}testFunction()
執行上述代碼後,包括寄件人簽名和繳費人簽名在內的 RLP 編碼字符串將打印如下。 (您得到的輸出結果可能與下面顯示的字符串輸出結果不同)。
$ node ./test.js0x09f8dc028505d21dba0082c35094176ff0344de49c04be577a3512b6991507647f720594f5a9079f311f9ec55170af351627aff0c5d2e287f847f845824e43a0f4b53dbd4c915cb73b9c7fa17e22106ee9640155a06ab4a7ed8661f846d2a5cca035b5bba6a26d4ccd20c65e8f31cce265c193f1c874806f9fae6b0ee9df0addf09417e7531b40ad5d7b5fa7b4ec78df64ce1cb36d24f847f845824e44a0921b7c3be69db96ce14134b306c2ada423613cb66ecc6697ee8067983c268b6ea07b86b255d1c781781315d85d7904226fb2101eb9498c4a03f3fbd30ba3ec5b79
現在,發送方和繳費方都對交易進行了簽名,並可通過網絡發送。 將 0x{RLP-encoded string}
替換為上述示例代碼輸出的 RLP 編碼字符串。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const rlpEncoded = '0x{RLP-encoded string}' const receipt = await caver.rpc.klay.sendRawTransaction(rlpEncoded) console.log(receipt)}testFunction()
運行上述代碼會得到以下結果。 通過上述代碼的執行結果,您可以查看 FeeDelegatedValueTransfer 交易的結果。
$ node ./test.js{ blockHash: '0xb6a76163c4c558f50bdae77968a0f35dcfececf78b5cb780c3514a30a1c0a864', blockNumber: '0xede', contractAddress: null, feePayer: '0x17e7531b40ad5d7b5fa7b4ec78df64ce1cb36d24', feePayerSignatures: [ { V: '0x4e44', R: '0x921b7c3be69db96ce14134b306c2ada423613cb66ecc6697ee8067983c268b6e', S: '0x7b86b255d1c781781315d85d7904226fb2101eb9498c4a03f3fbd30ba3ec5b79' } ], from: '0xf5a9079f311f9ec55170af351627aff0c5d2e287', gas: '0xc350', ... signatures: [ { V: '0x4e43', R: '0xf4b53dbd4c915cb73b9c7fa17e22106ee9640155a06ab4a7ed8661f846d2a5cc', S: '0x35b5bba6a26d4ccd20c65e8f31cce265c193f1c874806f9fae6b0ee9df0addf0' } ], status: '0x1', to: '0x176ff0344de49c04be577a3512b6991507647f72', transactionHash: '0x1878cc27b7f259a98d3248b41bffb6158640b4a07c503095deac1913fb3856c2', transactionIndex: 0, type: 'TxTypeFeeDelegatedValueTransfer', typeInt: 9, value: '0x5'}
賬戶更新
如果要更改 kaia 帳戶的私鑰,需要記住 3 件重要的事情:
- kaia 會驗證您發送給它的每一筆交易。
- 驗證需要與您的私人密鑰完全對應的公鑰。
- 因此,在將私鑰更改為新密鑰之前,必須先將舊公鑰更改為新密鑰。 新的公開密鑰必須來自新的私人密鑰。
牢記以上三點,你就可以按照以下步驟更改你的私人密鑰了:
- 準備新私鑰,創建新鑰匙圈。
- 根據需要的類型(單個鑰匙圈、多個鑰匙圈或基於角色的鑰匙圈)創建鑰匙圈。
- 從新鑰匙圈生成一個賬戶實例。 該賬戶實例持有 kaia 賬戶的新公鑰。
- 向 kaia 發送包含賬戶實例的 AccountUpdate 事務。
- 最後,將舊鑰匙圈替換為步驟 2 中創建的新鑰匙圈。
詳情請查看 [Account Update](api/caver-transaction/basic.md#accountupdate)。
要更改 AccountKey,必須在 caver.transaction.accountUpdate
的輸入參數對象中為 account
字段提供一個 Account實例。 賬戶](api/caver.account.md)實例包含 kaia 賬戶的地址和要更新的賬戶密鑰。
下面的代碼是一個示例代碼,用於更改 kaia 帳戶使用的私鑰,同時將 kaia 帳戶的 AccountKey 更改為 [AccountKeyPublic](../../../learn/accounts.md#accountkeypublic)。 別忘了準備新的私人密鑰。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { let sender = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(sender) const newPrivateKey = caver.wallet.keyring.generateSingleKey() console.log(`new private key string: ${newPrivateKey}`) const newKeyring = caver.wallet.keyring.createWithSingleKey(sender.address, newPrivateKey) // create an Account instance const account = newKeyring.toAccount() const updateTx = caver.transaction.accountUpdate.create({ from: sender.address, account: account, gas: 50000, }) await caver.wallet.sign(sender.address, updateTx) const receipt = await caver.rpc.klay.sendRawTransaction(updateTx) console.log(receipt) // Update the keyring in caver.wallet for signing afterward. sender = caver.wallet.updateKeyring(newKeyring)}testFunction()
如果上述代碼執行成功,你就不能再使用舊私鑰來簽署任何與舊鑰匙圈有關的交易。 因此,您必須通過 caver.wallet.updateKeyring(newKeyring)
使用newKeyring
更新舊鑰匙圈。 一旦更新,簽名將由新更新的私鑰完成。
運行上述代碼會得到以下結果。 在上述代碼的執行結果中,私鑰和新使用的賬戶更新結果打印如下。
$ node ./test.jsnew private key string: 0x{private key}{ blockHash: '0x4c0221245e7c810cc19b05257e8d7cd34f24cc829f8787a832c08682640173f5', blockNumber: '0x26d6', contractAddress: null, from: '0xeec694a4143e05945823b216d0c62ab91c192a63', gas: '0xc350', gasPrice: '0x5d21dba00', gasUsed: 41000, key: '0x02a1024cc461670797071be16c34b22df1a3588653da5c1e9279b1d9e4b24fbcba07d8', ... signatures: [ { V: '0x4e43', R: '0xd0fa2d25711de4bfc3a7a6a660d307264fa3b2cacbb7eb71ab68f47661ebcfaf', S: '0x4652102241e61968988a22f9fa2d5d38d4e654d1f4b193fba5627c0856c9da7b' } ], status: '0x1', transactionHash: '0x4efdeeb1bb1e52ace11d64a19f564a973b36c29a0d85899a215621659b793665', transactionIndex: 0, type: 'TxTypeAccountUpdate', typeInt: 32}
如何用多個([AccountKeys])更新 kaia 帳戶的 AccountKey? 下面的示例解釋瞭如何創建一個帶有多個私鑰的 賬戶 實例(您可以通過 caver.account.create創建一個帶有多個公鑰的 賬戶 實例)。 同樣,在將創建的賬戶實例輸入事務對象內的 "賬戶 "字段後,其餘的更新過程與上例相同。
首先,讓我們創建一個使用 [AccountKeyWeightedMultiSig] 更新的賬戶實例(.../.../.../learn/accounts.md#accountkeyweightedmultisig)。 對於 AccountKeyWeightedMultiSig ,必須為每個密鑰定義閾值和權重。 為此,請使用 caver.account.weightedMultiSigOptions. 第一個參數是閾值,第二個參數是包含每個鍵權重的數組。
// Create an account instance with three private keys using AccountKeyWeightedMultiSigconst newPrivateKeys = caver.wallet.keyring.generateMultipleKeys(3)const newKeyring = caver.wallet.keyring.createWithMultipleKey(sender.address, newPrivateKeys)// threshold = 3, the weights of the three keys = [1, 2, 1]const options = new caver.account.weightedMultiSigOptions(3, [1, 2, 1])const account = newKeyring.toAccount(options)
現在,讓我們使用 AccountKeyRoleBased 更新 AccountKey。 AccountKeyRoleBased是一種 "AccountKey "類型,定義了每個role要使用的密鑰。
// Create an account instance with roles using AccountKeyRoleBased. In the account instance created, each role has a public key that corresponds to one private key.const newPrivateKeys = caver.wallet.keyring.generateRoleBasedKeys([1, 1, 1])const newKeyring = caver.wallet.keyring.createWithRoleBasedKey(sender.address, newPrivateKeys)const account = newKeyring.toAccount()
上面的 AccountKeyRoleBased 就是為每個角色使用一個公鑰的例子。 從上面的代碼中可以看到,每個密鑰對應一個私人密鑰。 如果要為每個角色使用多個私鑰,則必須為每個角色定義 caver.account.weightedMultiSigOptions 如下所示。
// Create an account instance with [3, 2, 3] keys for each role using AccountKeyRoleBasedconst newPrivateKeys = caver.wallet.keyring.generateRoleBasedKeys([3, 2, 3])const newKeyring = caver.wallet.keyring.createWithRoleBasedKey(sender.address, newPrivateKeys)const options = [ // thresold = 4, weights of keys = [2, 2, 4] for roleTransactionKey new caver.account.weightedMultiSigOptions(4, [2, 2, 4]), // threshold = 2, weights of keys = [1, 1] new caver.account.weightedMultiSigOptions(2, [1, 1]), // threshold = 3, weights of keys = [1, 1, 1] new caver.account.weightedMultiSigOptions(3, [1, 1, 1]),]const account = newKeyring.toAccount(options)
如果要將 AccountKey 更新為 AccountKeyLegacy 或 accountKeyFail,請如下所示創建一個 Account 實例,並將其分配給事務的account
字段。
// Create an account with AccountKeyLegacyconst accountWithLegacyKey = caver.account.createWithAccountKeyLegacy(keyringToUpdate.address)// Create an account with AccountKeyFailconst accountWithFailKey = caver.account.createWithAccountKeyFail(keyringToUpdate.address)
智能合約
通過 caver.contract 軟件包,可以輕鬆與 kaia 上的智能合約進行交互。 當給出智能合約的底層 ABI(應用程序二進制接口)時,它會自動將智能合約的所有方法轉換為 javascript 調用。 這樣,您就可以像使用 JavaScript 對象一樣與智能合約進行交互。
首先,我們製作一個簡單的實體示例,如下所示。 創建一個 "test.sol "文件,並寫下以下示例。
pragma solidity ^0.5.6;contract KVstore { mapping(string=>string) store; function get(string memory key) public view returns (string memory) { return store[key]; } function set(string memory key, string memory value) public { store[key] = value; }}
現在,我們可以編譯智能合約,獲取其字節碼和 ABI。
> solc --abi --bin ./test.sol======= ./test.sol:KVstore =======Binary: 608060405234801561001057600080fd5b5061051f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063693ec85e1461003b578063e942b5161461016f575b600080fd5b6100f46004803603602081101561005157600080fd5b810190808035906020019064010000000081111561006e57600080fd5b82018360208201111561008057600080fd5b803590602001918460018302840111640100000000831117156100a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506102c1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610134578082015181840152602081019050610119565b50505050905090810190601f1680156101615780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102bf6004803603604081101561018557600080fd5b81019080803590602001906401000000008111156101a257600080fd5b8201836020820111156101b457600080fd5b803590602001918460018302840111640100000000831117156101d657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561023957600080fd5b82018360208201111561024b57600080fd5b8035906020019184600183028401116401000000008311171561026d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506103cc565b005b60606000826040518082805190602001908083835b602083106102f957805182526020820191506020810190506020830392506102d6565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103c05780601f10610395576101008083540402835291602001916103c0565b820191906000526020600020905b8154815290600101906020018083116103a357829003601f168201915b50505050509050919050565b806000836040518082805190602001908083835b6020831061040357805182526020820191506020810190506020830392506103e0565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061044992919061044e565b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061048f57805160ff19168380011785556104bd565b828001600101855582156104bd579182015b828111156104bc5782518255916020019190600101906104a1565b5b5090506104ca91906104ce565b5090565b6104f091905b808211156104ec5760008160009055506001016104d4565b5090565b9056fea165627a7a723058203ffebc792829e0434ecc495da1b53d24399cd7fff506a4fd03589861843e14990029Contract JSON ABI [{"constant":true,"inputs":[{"name":"key","type":"string"}],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"key","type":"string"},{"name":"value","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
注意:要編譯智能合約,必須安裝 solidity 編譯器。
對於智能合約的部署,您可以使用 caver.contract 進行部署,也可以使用 caver.transaction.smartContractDeploy, caver.transaction.feeDelegatedSmartContractDeploy 或 caver.transaction.smartContractDeploy 進行部署。feeDelegatedSmartContractDeploy](api/caver-transaction/fee-delegation.md#feedelegatedsmartcontractdeploy)或caver.transaction.feeDelegatedSmartContractDeployWithRatio交易。 下面是使用 [caver.contract] 的示例(api/caver.contract.md)。
您可以使用編譯智能合約的結果創建一個合約實例,如下所示。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const abi = [ { constant: true, inputs: [{ name: 'key', type: 'string' }], name: 'get', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: false, inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', }, ] const contractInstance = caver.contract.create(abi) console.log(contractInstance) console.log(contractInstance.options.address)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.jsContract { ... methods: { get: [Function: bound _createTxObject], '0x693ec85e': [Function: bound _createTxObject], 'get(string)': [Function: bound _createTxObject], set: [Function: bound _createTxObject], '0xe942b516': [Function: bound _createTxObject], 'set(string,string)': [Function: bound _createTxObject] }, events: { allEvents: [Function: bound ] }, _address: null, _jsonInterface: [ ... ], _keyrings: KeyringContainer { ... }}null
從上面的輸出可以看出,這些方法是通過合同實例內部的 abi 管理的。 由於尚未部署,因此可以看到 contractInstance.options.address
的輸出結果為空。
如果智能合約已經部署,並且您知道部署智能合約的合約地址,請將合約地址傳給第二個參數,如下所示。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const abi = [ { constant: true, inputs: [{ name: 'key', type: 'string' }], name: 'get', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: false, inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', }, ] const contractInstance = caver.contract.create(abi, '0x3466D49256b0982E1f240b64e097FF04f99Ed4b9') console.log(contractInstance) console.log(contractInstance.options.address)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.jsContract { ... methods: { get: [Function: bound _createTxObject], '0x693ec85e': [Function: bound _createTxObject], 'get(string)': [Function: bound _createTxObject], set: [Function: bound _createTxObject], '0xe942b516': [Function: bound _createTxObject], 'set(string,string)': [Function: bound _createTxObject] }, events: { allEvents: [Function: bound ] }, _address: '0x3466D49256b0982E1f240b64e097FF04f99Ed4b9', _jsonInterface: [ ... ], _keyrings: KeyringContainer { ... }}0x3466D49256b0982E1f240b64e097FF04f99Ed4b9
由於該合約實例接收到了智能合約的地址,因此會將合約地址存儲在 contractInstance.options.address
中。
如果創建了合約實例,您可以通過將字節碼傳遞到 data
字段來部署它,如下圖所示。
請注意,caver.contract 會發送事務以供部署和執行。 它使用 caver.wallet
中的密鑰來簽署交易。 使用的鑰匙圈必須事先添加到 caver.wallet
中。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const deployer = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(deployer) const abi = [ { constant: true, inputs: [{ name: 'key', type: 'string' }], name: 'get', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: false, inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', }, ] const byteCode = '608060405234801561001057600080fd5b5061051f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063693ec85e1461003b578063e942b5161461016f575b600080fd5b6100f46004803603602081101561005157600080fd5b810190808035906020019064010000000081111561006e57600080fd5b82018360208201111561008057600080fd5b803590602001918460018302840111640100000000831117156100a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506102c1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610134578082015181840152602081019050610119565b50505050905090810190601f1680156101615780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102bf6004803603604081101561018557600080fd5b81019080803590602001906401000000008111156101a257600080fd5b8201836020820111156101b457600080fd5b803590602001918460018302840111640100000000831117156101d657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561023957600080fd5b82018360208201111561024b57600080fd5b8035906020019184600183028401116401000000008311171561026d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506103cc565b005b60606000826040518082805190602001908083835b602083106102f957805182526020820191506020810190506020830392506102d6565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103c05780601f10610395576101008083540402835291602001916103c0565b820191906000526020600020905b8154815290600101906020018083116103a357829003601f168201915b50505050509050919050565b806000836040518082805190602001908083835b6020831061040357805182526020820191506020810190506020830392506103e0565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061044992919061044e565b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061048f57805160ff19168380011785556104bd565b828001600101855582156104bd579182015b828111156104bc5782518255916020019190600101906104a1565b5b5090506104ca91906104ce565b5090565b6104f091905b808211156104ec5760008160009055506001016104d4565b5090565b9056fea165627a7a723058203ffebc792829e0434ecc495da1b53d24399cd7fff506a4fd03589861843e14990029' const contractInstance = caver.contract.create(abi) const deployedInstance = await contractInstance.deploy({ from: deployer.address, gas: 1500000, }, byteCode) console.log(deployedInstance) console.log(deployedInstance.options.address)}testFunction()
在上面的代碼中,"deployer "會將合約部署到 kaia,並返回已部署的合約實例。
$ node ./test.jsContract { ... methods: { get: [Function: bound _createTxObject], '0x693ec85e': [Function: bound _createTxObject], 'get(string)': [Function: bound _createTxObject], set: [Function: bound _createTxObject], '0xe942b516': [Function: bound _createTxObject], 'set(string,string)': [Function: bound _createTxObject] }, events: { allEvents: [Function: bound ] }, _address: '0x3466D49256b0982E1f240b64e097FF04f99Ed4b9', _jsonInterface: [ ... ], _keyrings: KeyringContainer { ... }}0x3466D49256b0982E1f240b64e097FF04f99Ed4b9
要通過費用委託交易部署智能合約,請像下面的示例一樣定義 "feeDelegation "和 "feePayer":
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function deployWithFeeDelegation() { const deployer = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(deployer) const feePayer = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(feePayer) const abi = [ { constant: true, inputs: [{ name: 'key', type: 'string' }], name: 'get', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: false, inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', }, ] const byteCode = '608060405234801561001057600080fd5b5061051f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063693ec85e1461003b578063e942b5161461016f575b600080fd5b6100f46004803603602081101561005157600080fd5b810190808035906020019064010000000081111561006e57600080fd5b82018360208201111561008057600080fd5b803590602001918460018302840111640100000000831117156100a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506102c1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610134578082015181840152602081019050610119565b50505050905090810190601f1680156101615780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102bf6004803603604081101561018557600080fd5b81019080803590602001906401000000008111156101a257600080fd5b8201836020820111156101b457600080fd5b803590602001918460018302840111640100000000831117156101d657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561023957600080fd5b82018360208201111561024b57600080fd5b8035906020019184600183028401116401000000008311171561026d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506103cc565b005b60606000826040518082805190602001908083835b602083106102f957805182526020820191506020810190506020830392506102d6565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103c05780601f10610395576101008083540402835291602001916103c0565b820191906000526020600020905b8154815290600101906020018083116103a357829003601f168201915b50505050509050919050565b806000836040518082805190602001908083835b6020831061040357805182526020820191506020810190506020830392506103e0565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061044992919061044e565b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061048f57805160ff19168380011785556104bd565b828001600101855582156104bd579182015b828111156104bc5782518255916020019190600101906104a1565b5b5090506104ca91906104ce565b5090565b6104f091905b808211156104ec5760008160009055506001016104d4565b5090565b9056fea165627a7a723058203ffebc792829e0434ecc495da1b53d24399cd7fff506a4fd03589861843e14990029' const contractInstance = caver.contract.create(abi) const deployedInstance = await contractInstance.deploy({ from: deployer.address, feeDelegation: true, feePayer: feePayer.address, gas: 1500000, }, byteCode) console.log(deployedInstance) console.log(deployedInstance.options.address)}
如果您想在通過 caver.contract
部署智能合約時發送發送方和付費方分別簽名的交易,請參考下面的代碼:
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function deployWithFeeDelegation() { const deployer = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(deployer) const feePayer = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(feePayer) const abi = [ { constant: true, inputs: [{ name: 'key', type: 'string' }], name: 'get', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: false, inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', }, ] const byteCode = '608060405234801561001057600080fd5b5061051f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063693ec85e1461003b578063e942b5161461016f575b600080fd5b6100f46004803603602081101561005157600080fd5b810190808035906020019064010000000081111561006e57600080fd5b82018360208201111561008057600080fd5b803590602001918460018302840111640100000000831117156100a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506102c1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610134578082015181840152602081019050610119565b50505050905090810190601f1680156101615780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102bf6004803603604081101561018557600080fd5b81019080803590602001906401000000008111156101a257600080fd5b8201836020820111156101b457600080fd5b803590602001918460018302840111640100000000831117156101d657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561023957600080fd5b82018360208201111561024b57600080fd5b8035906020019184600183028401116401000000008311171561026d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506103cc565b005b60606000826040518082805190602001908083835b602083106102f957805182526020820191506020810190506020830392506102d6565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103c05780601f10610395576101008083540402835291602001916103c0565b820191906000526020600020905b8154815290600101906020018083116103a357829003601f168201915b50505050509050919050565b806000836040518082805190602001908083835b6020831061040357805182526020820191506020810190506020830392506103e0565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061044992919061044e565b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061048f57805160ff19168380011785556104bd565b828001600101855582156104bd579182015b828111156104bc5782518255916020019190600101906104a1565b5b5090506104ca91906104ce565b5090565b6104f091905b808211156104ec5760008160009055506001016104d4565b5090565b9056fea165627a7a723058203ffebc792829e0434ecc495da1b53d24399cd7fff506a4fd03589861843e14990029' const contractInstance = caver.contract.create(abi) const signed = await contractInstance.sign({ from: deployer.address, feeDelegation: true, gas: 1500000, }, 'constructor', byteCode) await caver.wallet.signAsFeePayer(feePayer.address, signed) const receipt = await caver.rpc.klay.sendRawTransaction(signed) const deployed = caver.contract.create(abi, receipt.contractAddress)}
A smart contract can be executed using one of the followings, depending on the type of contract executing transaction: Contract
class in caver.contract
or caver.transaction.smartContractExecution, caver.transaction.feeDelegatedSmartContractExecution, or caver.transaction.feeDelegatedSmartContractExecutionWithRatio. 發送執行智能合約的交易:
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const keyring = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(keyring) const abi = [ { constant: true, inputs: [{ name: 'key', type: 'string' }], name: 'get', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: false, inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', }, ] const contractInstance = caver.contract.create(abi, '0x{address in hex}') const receipt = await contractInstance.send({ from: keyring.address, gas: '0x4bfd200' }, 'set', 'testKey', 'testValue') console.log(receipt)}testFunction()
執行上述代碼後,執行 set
的事務結果如下。
$ node ./test.js{ blockHash: '0x610336d43644abc5ab71156f7334ff67deabdd8de27778faa9dec99d225927e6', blockNumber: 4724, contractAddress: null, from: '0xbbfa9e3f76ddafedc28197e0f893366dd3c5c74a', gas: '0x4bfd200', gasPrice: '0x5d21dba00', gasUsed: 62351, input: '0xe942b...', ... status: true, to: '0x3466d49256b0982e1f240b64e097ff04f99ed4b9', transactionHash: '0x3a354703ab4a7b32492edab454b446dd3e92eec81ecbdaf2c3d84ffdd5cf9948', transactionIndex: 0, type: 'TxTypeSmartContractExecution', typeInt: 48, value: '0x0', events: {}}
要通過費用委託交易執行智能合約,請像下面的示例一樣定義 "feeDelegation "和 "feePayer":
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function executionWithFeeDelegation() { const executor = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(executor) const feePayer = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(feePayer) const abi = [ { constant: true, inputs: [{ name: 'key', type: 'string' }], name: 'get', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: false, inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', }, ] // Pass contract address as a second parameter const contractInstance = caver.contract.create(abi, '0x{address in hex}') const receipt = await contractInstance.send({ from: executor.address, gas: 1000000, feeDelegation: true, feePayer: feePayer.address, }, 'set', 'testKey', 'testValue') console.log(receipt)}
如果您想在通過 caver.contract
執行智能合約時發送一個發送方和支付方分別簽名的交易,請參考下面的代碼:
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function deployWithFeeDelegation() { const deployer = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(deployer) const feePayer = caver.wallet.keyring.createFromPrivateKey('0x{private key}') caver.wallet.add(feePayer) const abi = [ { constant: true, inputs: [{ name: 'key', type: 'string' }], name: 'get', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: false, inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', }, ] const contractInstance = caver.contract.create(abi) const signed = await contractInstance.sign({ from: deployer.address, feeDelegation: true, gas: 1500000, }, 'set', 'testKey', 'testValue') await caver.wallet.signAsFeePayer(feePayer.address, signed) const receipt = await caver.rpc.klay.sendRawTransaction(signed) console.log(receipt)}
加載合約實例並調用其中一個函數:
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const abi = [ { constant: true, inputs: [{ name: 'key', type: 'string' }], name: 'get', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: false, inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', }, ] const contractInstance = caver.contract.create(abi, '0x{smart contract address}') const value = await contractInstance.call('get', 'testKey') console.log(value)}testFunction()
執行上述代碼後,輸出值如下所示。
$ node ./test.jstestValue
如需瞭解更多信息,請參閱 [caver.contract](api/caver.contract.md)。
發送有多個簽名人的交易
如果 kaia 賬戶的 AccountKey 是 AccountKeyMultiSig 或 AccountKeyRoleBased,則管理每個密鑰的人可以不同。
本節介紹在有多個簽名者的情況下如何收集簽名和發送交易。
要運行此示例,需要使用 [AccountKeyWeightedMultiSig] 更新用於測試的 kaia 帳戶的 AccountKey(../../../learn/accounts.md#accountkeyweightedmultisig) 。 請參閱 賬戶更新 瞭解如何更新您的 kaia 賬戶。
按順序簽署
使用 caver.wallet
或交易的 sign
函數簽署交易時,簽名(或付費人簽名)會在交易中定義(或附加)。 您可以調用已簽名事務實例的 transaction.getRLPEncoding()
函數,獲取包含簽名(和付費者簽名)的 RLP 編碼字符串(rawTransaction
)。
下面的示例展示瞭如何使用多個私鑰按順序簽署交易。 假設發送此交易的賬戶的 AccountKey 是由兩個公鑰組成的 AccountKeyWeightedMultiSig,這意味著 kaia 賬戶可以使用兩個私鑰串,每個用戶一個私鑰。 這是兩個用戶共享同一個 kaia 帳戶的情況。
在下面的示例中,用戶 1 和用戶 2 創建了一個要使用的 Keyring
實例。 之後,各自使用自己的密鑰來簽署交易。 下面的示例使用 transaction.sign
進行簽名。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const user1 = caver.wallet.keyring.createWithSingleKey('0x{address in hex}', '0x{private key1}') const user2 = caver.wallet.keyring.createWithSingleKey('0x{address in hex}', '0x{private key2}') const transaction = caver.transaction.valueTransfer.create({ from: user1.address, to: '0x45c2a1e3a1c3957a06dae73ad516461c2d2c7ccc', value: 1, gas: 70000, }) await transaction.sign(user1) console.log(transaction.signatures) await transaction.sign(user2) console.log(transaction.signatures)}testFunction()
運行上述代碼會得到以下結果。 從上面代碼的執行結果來看,如果用戶 1 簽名,就會創建一個簽名。 如果用戶 2 簽名,則附加用戶 2 的簽名。 簽名數據 是一個存儲簽名的對象。
$ node ./test.js[ SignatureData { _v: '0x4e43', _r: '0x3f3d3...', _s: '0x24f94...' }][ SignatureData { _v: '0x4e43', _r: '0x3f3d3...', _s: '0x24f94...' }, SignatureData { _v: '0x4e44', _r: '0xd6a94...', _s: '0x72dc8...' }]
然後,讓我們看看如何在不共享同一事務對象的情況下按順序簽名。 在下面的示例中,用戶 1 將已簽名事務的 getRLPEncoding 函數產生的 RLP 編碼字符串傳遞給用戶 2。
下面的代碼解釋瞭如何使用 RLP 編碼字符串簽署和附加簽名。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { // Create user1's keyring const user1 = caver.wallet.keyring.createWithSingleKey('0x{address in hex}', '0x{private key1}') // Create a value transfer transaction const transaction = caver.transaction.valueTransfer.create({ from: user1.address, to: '0x45c2a1e3a1c3957a06dae73ad516461c2d2c7ccc', value: 1, gas: 70000, }) // Sign the transaction await transaction.sign(user1) // Create user2's keyring const user2 = caver.wallet.keyring.createWithSingleKey('0x{address in hex}', '0x{private key2}') // Create a value transfer transaction from the RLP-encoded string const rlpEncoding = transaction.getRLPEncoding() const transactionFromRLP = caver.transaction.valueTransfer.create(rlpEncoding) await transactionFromRLP.sign(user2) console.log(transactionFromRLP.signatures)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.js[ SignatureData { _v: '0x4e43', _r: '0x3f3d3...', _s: '0x24f94...' }, SignatureData { _v: '0x4e44', _r: '0xd6a94...', _s: '0x72dc8...' }]
如果運行上述代碼,可以看到用戶 2 的簽名已添加到 transactionFromRLP.signatures
中,其中總共包含兩個簽名。
所有用戶簽名後,通過 await caver.rpc.klay.sendRawTransaction(transactionFromRLP)
向網絡發送事務。
如果您發送的是費用委託交易,而費用支付者使用多個密鑰,您可以使用 caver.wallet.signAsFeePayer
繼續上述邏輯。
合併已簽名的原始交易
如果從幾個人那裡收到多個已簽名的 RLP 編碼原始事務字符串,可以將它們合併為一個包含所有簽名的 RLP 編碼原始事務字符串。
下面的示例顯示瞭如何合併和發送 RLP 編碼的事務。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const vt = caver.transaction.valueTransfer.create({ from: '0x0fa355263f37f5a54d9179452baa8b63b8b2cdde', to: '0x45c2a1e3a1c3957a06dae73ad516461c2d2c7ccc', value: 1, gas: 70000, }) const rlpEncodedStrings = [ '0x08f87f018505d21dba00830111709445c2a1e3a1c3957a06dae73ad516461c2d2c7ccc01940fa355263f37f5a54d9179452baa8b63b8b2cddef847f845824e44a01aa72b883ca540c8a63de244cd061ec4f9efb139541e8db304c07ec27bc9d272a06a4ca54f6269f2ddfe3648eb9ed57b0c5739f0077e1a38449f3ae3cc0b20dc3e', '0x08f8c6018505d21dba00830111709445c2a1e3a1c3957a06dae73ad516461c2d2c7ccc01940fa355263f37f5a54d9179452baa8b63b8b2cddef88ef845824e44a01aa72b883ca540c8a63de244cd061ec4f9efb139541e8db304c07ec27bc9d272a06a4ca54f6269f2ddfe3648eb9ed57b0c5739f0077e1a38449f3ae3cc0b20dc3ef845824e43a0fd76dfc53c812ec6aa860076f731e3913936088a1518cc34f2d176bcbe0ac772a071491c938458fffe106dde485fc8b26cbebe8a517c46bd185b126930f480d773', '0x08f8c6018505d21dba00830111709445c2a1e3a1c3957a06dae73ad516461c2d2c7ccc01940fa355263f37f5a54d9179452baa8b63b8b2cddef88ef845824e44a01aa72b883ca540c8a63de244cd061ec4f9efb139541e8db304c07ec27bc9d272a06a4ca54f6269f2ddfe3648eb9ed57b0c5739f0077e1a38449f3ae3cc0b20dc3ef845824e43a021e84a4740b374cdcf0cc38f93225f6d2f77388a9d90302d47b4f3ed84e4db5fa072ff5e77d2506d5222081c4d2a341c6ee5d258500030564f985951472f247b7d', ] const combined = vt.combineSignedRawTransactions(rlpEncodedStrings) console.log(combined)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.js0x08f9010d808505d21dba00830111709445c2a1e3a1c3957a06dae73ad516461c2d2c7ccc01940fa355263f37f5a54d9179452baa8b63b8b2cddef8d5f8458207f5a094ce13c39d25d44ad1d07ba2fd89f476c4dc6eef6071a2ef1f496f9b04d049e5a00f7abddd548998b0a55e53600a48286c38262fffc6c153a64e8f65a77c11c722f8458207f6a0ceeea7287b2670719d8ac15cf3b21b36fcaf74d58cce99935ce17e100064037aa0499067788d5db5e7c09ed7bfe19764d66684abc06b81e8f54ea254377bc81066f8458207f5a05c3ba89336c7d84d4ce08104cfd6f7ef33cd9f29766a1955baae8bcf964fd50fa015accbbce6bb11847a3b0660491775d64ef6d692ea709b768f64f12968c09240
運行上述代碼後,就會輸出一個 RLP 編碼的原始事務字符串,其中包含所有簽名信息。
執行 "combineSignedRawTransactions "時,除了簽名和事務實例中的可選變量外,要合併的簽名 RLP 編碼原始事務字符串必須完全相同。 在基礎事務實例("combineSignedRawTransactions "的調用者)中沒有任何給定值的可選變量,將與接下來要合併的原始事務字符串中的相應變量進行置換。 如果要合併的所有原始事務字符串(包括其中的可選變量值)不一致,就會發生錯誤。
CombineSignedRawTransactions 的結果是返回一個 RLP 編碼字符串,其中包含所有簽名(如果交易是收費委託交易,還包括收費人簽名)。 您可以通過 await caver.rpc.klay.sendRawTransaction(combined)
向網絡發送事務。
檢測 KCT 接口的實施情況
caver.kct "提供的函數可返回有關給定的 KCT 令牌合約實現了哪些接口的信息。 使用它,你可以看到在 kaia 上部署的 KCT 令牌合約實現了哪個接口。
檢測 KIP-7 接口
為了檢測 KIP-7 令牌合約實現的接口,可以使用 caver.kct.kip7.detectInterface(contractAddress)
或 kip7.detectInterface()
。
下面的代碼說明了如何使用 caver.kct.kip7
中提供的靜態方法檢測在 kaia 上部署的 KIP-7 令牌合約的已實現接口。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const result = await caver.kct.kip7.detectInterface('0x{address in hex}') console.log(result)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.js{ IKIP7: true, IKIP7Metadata: true, IKIP7Mintable: true, IKIP7Burnable: true, IKIP7Pausable: true,}
下面是如何使用 KIP7 成員方法檢測在 kaia 上部署的 KIP-7 令牌合約的已實施接口的代碼。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const kip7 = new caver.kct.kip7('0x{address in hex}') const result = await kip7.detectInterface() console.log(result)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.js{ IKIP7: true, IKIP7Metadata: true, IKIP7Mintable: true, IKIP7Burnable: true, IKIP7Pausable: true,}
檢測 KIP-17 接口
為了檢測 KIP-17 令牌合約實現的接口,可以使用 caver.kct.kip17.detectInterface(contractAddress)
或 kip17.detectInterface()
。
下面是一段代碼,說明如何使用 caver.kct.kip17
中提供的靜態方法檢測在 kaia 上部署的 KIP-17 令牌合約的已實現接口。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const result = await caver.kct.kip17.detectInterface('0x{address in hex}') console.log(result)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.js{ IKIP17: true, IKIP17Metadata: true, IKIP17Enumerable: true, IKIP17Mintable: true, IKIP17MetadataMintable: true, IKIP17Burnable: true, IKIP17Pausable: true,}
下面是如何使用 KIP17 的成員方法檢測在 kaia 上部署的 KIP-17 令牌合約的已實現接口的代碼。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const kip17 = new caver.kct.kip17('0x{address in hex}') const result = await kip17.detectInterface() console.log(result)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.js{ IKIP17: true, IKIP17Metadata: true, IKIP17Enumerable: true, IKIP17Mintable: true, IKIP17MetadataMintable: true, IKIP17Burnable: true, IKIP17Pausable: true,}
檢測 KIP-37 接口
為了檢測 KIP-37 令牌合約實現的接口,可以使用 caver.kct.kip37.detectInterface(contractAddress)
或 kip37.detectInterface()
。
下面的代碼說明了如何使用 caver.kct.kip37
中提供的靜態方法檢測在 kaia 上部署的 KIP-37 令牌合約的已實現接口。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const result = await caver.kct.kip37.detectInterface('0x{address in hex}') console.log(result)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.js{ IKIP37: true, IKIP37Metadata: true, IKIP37Mintable: true, IKIP37Burnable: true, IKIP37Pausable: true,}
下面是如何使用 KIP37 的成員方法檢測在 kaia 上部署的 KIP-37 令牌合約的已實施接口的代碼。
// test.jsconst Caver = require('caver-js')const caver = new Caver('https://public-en-kairos.node.kaia.io/')async function testFunction() { const kip37 = new caver.kct.kip37('0x{address in hex}') const result = await kip37.detectInterface() console.log(result)}testFunction()
運行上述代碼會得到以下結果。
$ node ./test.js{ IKIP37: true, IKIP37Metadata: true, IKIP37Mintable: true, IKIP37Burnable: true, IKIP37Pausable: true,}
樣本項目
使用 caver-js 開發的 DApp(區塊鏈應用程序)示例項目如下:
故障排除
-
錯誤:無法解析 'fs' 在網絡瀏覽器中使用 caver-js 構建過程中出現:
- 添加以下 webpack 配置
module.exports = {...node: {fs: 'empty',},...}如果使用 Next.js 網絡框架,可以按如下方式在next.config.json文件中添加 webpack 配置:
module.exports = {webpack: (config, { isServer }) => {if (!isServer) {config.node = {fs: 'empty'}}return config}}