diff --git a/README.md b/README.md
index 7a78a08b..6da56a3c 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,7 @@ $ npm install caver-js@X.X.X
Getting Started
=================
-If you want to run your own EN (Endpoint Node), see [EN Operation Guide](https://docs.klaytn.com/node/en) to set up. You can also use Klaytn Public EN like below:
+If you want to run your own EN (Endpoint Node), see [EN Operation Guide](https://docs.klaytn.com/node/endpoint-node) to set up. You can also use Klaytn Public EN like below:
```
$ node
> const Caver = require('caver-js')
@@ -73,8 +73,8 @@ Klaytn/vX.X.X/linux-amd64/goX.X.X
## Using caver-js account/wallet
You can easily manage your account by using the account / wallet packages provided by caver-js.
-[caver.klay.accounts](https://docs.klaytn.com/sdk/caverjs/caver.klay.accounts) package provides functions related to accounts, such as create, signTransaction, and privateKeyToAccount.
-[caver.klay.accounts.wallet](https://docs.klaytn.com/sdk/caverjs/caver.klay.accounts#wallet) provides the **in-memory wallet** for easy account management in caver-js.
+[caver.klay.accounts](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.klay.accounts) package provides functions related to accounts, such as create, signTransaction, and privateKeyToAccount.
+[caver.klay.accounts.wallet](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.klay.accounts#wallet) provides the **in-memory wallet** for easy account management in caver-js.
**Note** Functions associated with wallet and account provided by caver-js have no effect on the actual Klaytn network.
@@ -101,7 +101,7 @@ You can add to the wallet instance of caver-js using the account object created
```
caver-js supports two types of private key formats.
-One is a raw private key format of a 32-byte string type and the other is the [KlaytnWalletKey](https://docs.klaytn.com/klaytn/design/account#klaytn-wallet-key-format).
+One is a raw private key format of a 32-byte string type and the other is the [KlaytnWalletKey](https://docs.klaytn.com/klaytn/design/accounts#klaytn-wallet-key-format).
You can also add your account using the KlaytnWalletKey format as shown below:
```
@@ -121,7 +121,7 @@ The private key that matches a specific account stored in the wallet instance ca
```
## Submitting a Transaction
-You can use caver-js to submit various types of transactions to a node. Please refer to the [caver.klay.sendTransaction](https://docs.klaytn.com/sdk/caverjs/caver.klay/transaction#sendtransaction) to see how to send a transaction of each type.
+You can use caver-js to submit various types of transactions to a node. Please refer to the [caver.klay.sendTransaction](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.klay/transaction#sendtransaction) to see how to send a transaction of each type.
You can submit the transaction as shown below, and the result can be confirmed by the returned receipt:
```
@@ -207,19 +207,19 @@ caver-js provides the caver.utils.toPeb function for unit conversion. Please ref
Documentation
=================
-Documentation can be found at [Klaytn Docs-caver-js](https://docs.klaytn.com/sdk/caverjs).
+Documentation can be found at [Klaytn Docs-caver-js](https://docs.klaytn.com/bapp/sdk/caver-js).
API Specification
=================
The API lists of caver-js are described in folloinwg links:
-* [caver.klay](https://docs.klaytn.com/sdk/caverjs/caver.klay)
-* [caver.klay.accounts](https://docs.klaytn.com/sdk/caverjs/caver.klay.accounts)
-* [caver.klay.contract](https://docs.klaytn.com/sdk/caverjs/caver.klay.contract)
-* [caver.klay.net](https://docs.klaytn.com/sdk/caverjs/caver.klay.net)
-* [caver.klay.abi](https://docs.klaytn.com/sdk/caverjs/caver.klay.abi)
-* [caver.utils](https://docs.klaytn.com/sdk/caverjs/caver.utils)
+* [caver.klay](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.klay)
+* [caver.klay.accounts](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.klay.accounts)
+* [caver.klay.contract](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.klay.contract)
+* [caver.klay.net](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.klay.net)
+* [caver.klay.abi](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.klay.abi)
+* [caver.utils](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.utils)
Web3.js Similarity
@@ -297,8 +297,8 @@ Sample Projects
The BApp (Blockchain Application) Development sample projects using caver-js are the following:
-* [Count BApp](https://docs.klaytn.com/tutorials/countbapp)
-* [Klaystagram](https://docs.klaytn.com/tutorials/klaystagram)
+* [Count BApp](https://docs.klaytn.com/bapp/tutorials/count-bapp)
+* [Klaystagram](https://docs.klaytn.com/bapp/tutorials/klaystagram)
Github Repository
=================
diff --git a/package.json b/package.json
index d9593a06..692cde29 100644
--- a/package.json
+++ b/package.json
@@ -1,16 +1,17 @@
{
"name": "caver-js",
- "version": "1.1.2",
+ "version": "1.2.0",
"description": "caver-js is a JavaScript API library that allows developers to interact with a Klaytn node",
"main": "index.js",
"scripts": {
- "test": "npm run build && mocha test/packages/caver.klay.utils.js && mocha test/packages/caver.klay.net.js && npm run serTest && npm run walletTest",
+ "test": "npm run build && mocha test/packages/caver.utils.js && mocha test/packages/caver.klay.net.js && npm run serTest && npm run walletTest",
"build-all": "gulp all",
"build": "gulp default",
- "serTest": "mocha test/transactionType/serializationTest.js && mocha test/compressPublicKey.js && mocha test/encodeContractDeploy.js && mocha test/isCompressedPublicKey.js && mocha test/parseAccountKey.js",
+ "serTest": "mocha test/transactionType/serializationTest.js && mocha test/compressPublicKey.js && mocha test/encodeContractDeploy.js && mocha test/isCompressedPublicKey.js && mocha test/parseAccountKey.js && mocha test/decodeTransaction.js",
"walletTest": "mocha test/accountLib.js && mocha test/accounts.privateKeyToPublicKey.js && mocha test/accounts.recover.js && mocha test/packages/caver.klay.accounts.js && mocha test/getKlaytnWalletKey.js && mocha test/isValidPrivateKey.js && mocha test/privateKeyToAccount.js",
- "txTest": "mocha test/estimateComputationCost.js && mocha test/getTransactionReceipt.js && mocha test/getTransaction.js && mocha test/setContractOptions.js && mocha test/encodeContractDeploy.js && mocha test/accounts.signTransaction.js && mocha test/transactionType/legacyTransaction.js && mocha test/transactionType/valueTransfer* && mocha test/transactionType/accountUpdate.js && mocha test/transactionType/contract* && mocha test/transactionType/cancelTransaction.js && mocha test/transactionType/feeDelegated*",
- "etcTest": "mocha test/confirmationListener.js && mocha test/hashMessage.js && mocha test/iban.* && mocha test/randomHex.js && mocha test/sha3.js && mocha test/toChecksumAddress.js && mocha test/unitMap.js && mocha test/default* && mocha test/getNodeInfo.js && mocha test/eventEmitter.js && mocha test/packages/caver.klay.net.js && mocha test/getNetworkType.js && mocha test/invalidResponse.js && mocha test/isContractDeployment.js && mocha test/personal.js && mocha test/multiProviderTest.js && mocha test/subscription.js && mocha test/supportsSubscriptions.js && mocha test/contract.once.js",
+ "txTest": "mocha test/sendSignedTransaction.js && mocha test/estimateComputationCost.js && mocha test/getTransactionReceipt.js && mocha test/getTransaction.js && mocha test/setContractOptions.js && mocha test/encodeContractDeploy.js && mocha test/accounts.signTransaction.js && mocha test/sendTransactionCallback.js && mocha test/signWithMultiSig.js && mocha test/transactionType/legacyTransaction.js && mocha test/transactionType/valueTransfer* && mocha test/transactionType/accountUpdate.js && mocha test/transactionType/contract* && mocha test/transactionType/cancelTransaction.js && mocha test/transactionType/feeDelegated*",
+ "etcTest": "mocha test/packages/caver.utils.js && mocha test/confirmationListener.js && mocha test/hashMessage.js && mocha test/iban.* && mocha test/randomHex.js && mocha test/sha3.js && mocha test/toChecksumAddress.js && mocha test/unitMap.js && mocha test/default* && mocha test/getNodeInfo.js && mocha test/eventEmitter.js && mocha test/packages/caver.klay.net.js && mocha test/getNetworkType.js && mocha test/invalidResponse.js && mocha test/isContractDeployment.js && mocha test/personal.js && mocha test/multiProviderTest.js && mocha test/subscription.js && mocha test/supportsSubscriptions.js && mocha test/contract.once.js && mocha test/setProvider.js",
+ "accountKeyTest": "mocha test/scenarioTest/accountKeyPublic.js && mocha test/scenarioTest/accountKeyMultiSig.js && mocha test/scenarioTest/accountKeyRoleBased.js",
"intTxTest": "npm run intLEGACYTest && npm run intVTTest && npm run intVTMTest && npm run intACCUPTest && npm run intDEPLTest && npm run intEXETest && npm run intCANCELTest && npm run intFDTest && npm run intFDRTest",
"intLEGACYTest": "mocha --grep INT-LEGACY/ test/intTest.js",
"intVTTest": "mocha --grep INT-VT/ test/intTest.js",
@@ -33,6 +34,14 @@
"klaytn sdk",
"klaytn api"
],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/klaytn/caver-js.git"
+ },
+ "bugs": {
+ "url": "https://github.com/klaytn/caver-js/issues"
+ },
+ "homepage": "https://github.com/klaytn/caver-js",
"author": "Klaytn Team",
"license": "LGPL",
"dependencies": {
@@ -55,7 +64,7 @@
"oboe": "2.1.3",
"request": "2.87.0",
"requestretry": "^2.0.2",
- "scrypt.js": "0.2.0",
+ "scryptsy": "2.1.0",
"underscore": "^1.9.1",
"utf8": "2.1.1",
"uuid": "2.0.1",
diff --git a/packages/caver-core-helpers/src/formatters.js b/packages/caver-core-helpers/src/formatters.js
index d2c5e3a1..8ae81146 100644
--- a/packages/caver-core-helpers/src/formatters.js
+++ b/packages/caver-core-helpers/src/formatters.js
@@ -76,7 +76,9 @@ var _txInputFormatter = function (options){
if (options.to) {
options.humanReadable = options.humanReadable !== undefined? options.humanReadable : false
if (options.humanReadable) throw new Error('HumanReadableAddress is not supported yet.')
- options.to = inputAddressFormatter(options.to)
+ if (!utils.isContractDeployment(options) || options.to !== '0x') {
+ options.to = inputAddressFormatter(options.to)
+ }
}
if (options.data && options.input) {
@@ -140,12 +142,9 @@ var inputTransactionFormatter = function (options) {
options = _txInputFormatter(options);
- // If 'feePayer' or 'senderRawTransaction' exist in transaction, it means it doesn't need 'from' field.
- if (options.feePayer || options.senderRawTransaction) {
- if (options.senderRawTransaction === undefined) {
- throw new Error('The "senderRawTransaction" field must be defined for signing with feePayer!');
- }
-
+ // If senderRawTransaction' exist in transaction, it means object is fee payer transaction format like below
+ // { senderRawTransaction: '', feePayer: '' }
+ if (options.senderRawTransaction) {
if (options.feePayer === undefined) {
throw new Error('The "feePayer" field must be defined for signing with feePayer!');
}
@@ -164,8 +163,8 @@ var inputTransactionFormatter = function (options) {
options.from = inputAddressFormatter(options.from);
}
- if (options.data && options.data.slice(0, 2) !== '0x') {
- options.data = '0x' + options.data
+ if (options.data) {
+ options.data = utils.addHexPrefix(options.data)
}
const err = validateParams(options)
@@ -198,8 +197,8 @@ var inputPersonalTransactionFormatter = function (options) {
options.from = inputAddressFormatter(options.from);
}
- if (options.data && options.data.slice(0, 2) !== '0x') {
- options.data = '0x' + options.data
+ if (options.data) {
+ options.data = utils.addHexPrefix(options.data)
}
return options;
@@ -474,7 +473,6 @@ var outputPostFormatter = function(post){
};
var inputAddressFormatter = function (address) {
-
var iban = new utils.Iban(address);
if (iban.isValid() && iban.isDirect()) {
return iban.toAddress().toLowerCase();
diff --git a/packages/caver-core-helpers/src/validateFunction.js b/packages/caver-core-helpers/src/validateFunction.js
index 614b4b90..7bfe5588 100644
--- a/packages/caver-core-helpers/src/validateFunction.js
+++ b/packages/caver-core-helpers/src/validateFunction.js
@@ -24,29 +24,50 @@
* @return {Error}
*/
-const VALID_GAS_PRICE = require('./constants').VALID_GAS_PRICE
var utils = require('../../caver-utils')
function validateParams (tx) {
+ let error
+
+ // validate for fee payer transaction format
+ if (tx.senderRawTransaction) {
+ if (!tx.feePayer || tx.feePayer === '0x') {
+ error = new Error(`Invalid fee payer: ${tx.feePayer}`)
+ } else if (!utils.isAddress(tx.feePayer)) {
+ error = new Error(`Invalid address of fee payer: ${tx.feePayer}`)
+ }
+ return error
+ }
+
const isValidateType = validateTxType(tx.type)
if (!isValidateType) {
return new Error('The transaction type [' + tx.type + '] is not supported')
}
- var error = validateTxObjectWithType(tx)
+ error = validateTxObjectWithType(tx)
if (error !== undefined) {
return error
}
if (!tx.from) {
error = new Error('"from" is missing')
+ } else if (!utils.isAddress(tx.from)) {
+ error = new Error(`Invalid address of from: ${tx.from}`)
} else if (tx.gas === undefined && tx.gasLimit === undefined) {
error = new Error('"gas" is missing')
} else if (tx.nonce < 0 || tx.gas < 0 || tx.gasPrice < 0 || tx.chainId < 0) {
error = new Error('gas, gasPrice, nonce or chainId is lower than 0')
- // } else if (tx.gasPrice !== undefined && tx.gasPrice != VALID_GAS_PRICE) {
- // error = new Error(`GasPrice should be a 25Gpeb(${VALID_GAS_PRICE})`);
}
+
+ // If feePayerSignatures is set in transaction object, feePayer also should be defined together.
+ if (tx.feePayerSignatures && !utils.isEmptySig(tx.feePayerSignatures)) {
+ if (!tx.feePayer || tx.feePayer === '0x') {
+ error = new Error(`"feePayer" is missing: feePayer must be defined with feePayerSignatures.`)
+ } else if (!utils.isAddress(tx.feePayer)) {
+ error = new Error(`Invalid address of fee payer: ${tx.feePayer}`)
+ }
+ }
+
return error
}
@@ -103,6 +124,8 @@ function validateParams (tx) {
switch (cf) {
case 0:
case 'EVM':
+ case '0x':
+ case '0x0':
return true
}
return false
@@ -159,6 +182,11 @@ function validateParams (tx) {
if (transaction.to === undefined && transaction.data === undefined) {
return new Error('contract creation without any data provided')
}
+
+ if (transaction.to && transaction.to !== '0x' && !utils.isAddress(transaction.to)) {
+ return new Error(`Invalid address of to: ${transaction.to}`)
+ }
+
if (transaction.codeFormat !== undefined) {
return new Error('"codeFormat" cannot be used with LEGACY transaction')
}
@@ -177,6 +205,9 @@ function validateParams (tx) {
if (transaction.feeRatio !== undefined) {
return new Error('"feeRatio" cannot be used with '+type+' transaction')
}
+ if (transaction.feePayerSignatures !== undefined) {
+ return new Error('"feePayerSignatures" cannot be used with '+type+' transaction')
+ }
}
function validateFeeDelegated(transaction) {
@@ -193,6 +224,9 @@ function validateParams (tx) {
function validateNotAccountTransaction(transaction) {
const type = transaction.type? transaction.type : 'LEGACY'
+ if (transaction.key !== undefined) {
+ return new Error('"key" cannot be used with '+type+' transaction')
+ }
if (transaction.legacyKey !== undefined) {
return new Error('"legacyKey" cannot be used with '+type+' transaction')
}
@@ -219,6 +253,8 @@ function validateParams (tx) {
function checkValueTransferEssential(transaction) {
if (transaction.to === undefined) {
return new Error('"to" is missing')
+ } else if (!utils.isAddress(transaction.to)) {
+ return new Error(`Invalid address of to: ${transaction.to}`)
}
if (transaction.value === undefined) {
return new Error('"value" is missing')
@@ -258,6 +294,8 @@ function validateParams (tx) {
function checkValueTransferMemoEssential(transaction) {
if (transaction.to === undefined) {
return new Error('"to" is missing')
+ } else if (!utils.isAddress(transaction.to)) {
+ return new Error(`Invalid address of to: ${transaction.to}`)
}
if (transaction.value === undefined) {
return new Error('"value" is missing')
@@ -302,12 +340,16 @@ function validateParams (tx) {
return new Error('"codeFormat" cannot be used with '+transaction.type+' transaction')
}
- if (transaction.legacyKey === undefined && !transaction.publicKey && !transaction.multisig && !transaction.roleTransactionKey && !transaction.roleAccountUpdateKey && !transaction.roleFeePayerKey && transaction.failKey === undefined) {
+ if (!transaction.key && transaction.legacyKey === undefined && !transaction.publicKey && !transaction.multisig && !transaction.roleTransactionKey && !transaction.roleAccountUpdateKey && !transaction.roleFeePayerKey && transaction.failKey === undefined) {
return new Error('Missing key information with '+transaction.type+' transaction')
}
const duplicatedKeyInfo = 'The key parameter to be used for '+transaction.type+' is duplicated.'
- if (transaction.legacyKey !== undefined) {
+ if (transaction.key) {
+ if (transaction.legacyKey !== undefined || transaction.publicKey || transaction.multisig || transaction.roleTransactionKey || transaction.roleAccountUpdateKey || transaction.roleFeePayerKey || transaction.failKey !== undefined) {
+ return new Error(duplicatedKeyInfo)
+ }
+ } else if (transaction.legacyKey !== undefined) {
if (transaction.publicKey || transaction.multisig || transaction.roleTransactionKey || transaction.roleAccountUpdateKey || transaction.roleFeePayerKey || transaction.failKey !== undefined) {
return new Error(duplicatedKeyInfo)
}
@@ -366,7 +408,7 @@ function validateParams (tx) {
if (transaction.data === undefined) {
return new Error('"data" is missing')
}
- if (transaction.to !== undefined) {
+ if (transaction.to !== undefined && transaction.to !== '0x') {
return new Error('"to" cannot be used with '+transaction.type+' transaction')
}
if (transaction.codeFormat !== undefined && !validateCodeFormat(transaction.codeFormat)) {
@@ -401,6 +443,8 @@ function validateParams (tx) {
function checkExecutionEssential(transaction) {
if (transaction.to === undefined) {
return new Error('"to" is missing')
+ } else if (!utils.isAddress(transaction.to)) {
+ return new Error(`Invalid address of to: ${transaction.to}`)
}
if (transaction.data === undefined) {
return new Error('"data" is missing')
diff --git a/packages/caver-core-method/src/index.js b/packages/caver-core-method/src/index.js
index adcde298..d4497e9b 100644
--- a/packages/caver-core-method/src/index.js
+++ b/packages/caver-core-method/src/index.js
@@ -246,25 +246,6 @@ function toPayload (args) {
return (this.transformPayload && this.transformPayload(payload)) || payload
}
-var getWallet = function(from, accounts) {
- let wallet = null
-
- // is index given
- if (_.isNumber(from)) {
- wallet = accounts.wallet[from]
-
- // is account given
- } else if (_.isObject(from) && from.address && from.privateKey) {
- wallet = from
-
- // search in wallet for address
- } else {
- wallet = accounts.wallet[from.toLowerCase()]
- }
-
- return wallet
-}
-
const buildSendTxCallbackFunc = (defer, method, payload, isSendTx) => (err, result) => {
try { result = method.formatOutput(result) }
catch (e) {
@@ -289,7 +270,7 @@ const buildSendTxCallbackFunc = (defer, method, payload, isSendTx) => (err, resu
// return PROMISE
if (!isSendTx) {
defer.resolve(result)
- } else if (!_.isObject(result)) {
+ } else {
defer.eventEmitter.emit('transactionHash', result)
method._confirmTransaction(defer, result, payload)
}
@@ -305,49 +286,82 @@ const buildSendSignedTxFunc = (method, payload, sendTxCallback) => (sign) => {
}
const buildSendRequestFunc = (defer, sendSignedTx, sendTxCallback) => (payload, method) => {
+ // Logic for handling multiple cases of parameters in sendSignedTransaction.
+ // 1. Object containing rawTransaction
+ // : call 'klay_sendRawTransaction' with RLP encoded transaction(rawTransaction) in object
+ // 2. A transaction object containing signatures or feePayerSignatures
+ // : call 'getRawTransactionWithSignatures', then call 'klay_sendRawTransaction' with result of getRawTransactionWithSignatures
+ if (method && method.accounts && payload.method === 'klay_sendRawTransaction') {
+ var tx = payload.params[0]
+ if (typeof tx !== 'string' && _.isObject(tx)) {
+ if (tx.rawTransaction) {
+ return sendSignedTx(tx)
+ } else {
+ return method.accounts.getRawTransactionWithSignatures(tx).then(sendSignedTx).catch((e) => {sendTxCallback(e)})
+ }
+ }
+ }
+
if (method && method.accounts && method.accounts.wallet && method.accounts.wallet.length) {
+ let error
switch (payload.method) {
case 'klay_sendTransaction': {
var tx = payload.params[0]
-
- // TODO : Check signTransactionWithSignature function with this logic
- // and if need, implement sendTransactionWithSignature function.
- // if (tx.signature) {
- // return method.accounts.sendTransactionWithSignature(tx).then(sendSignedTx)
- // }
-
- if (tx.senderRawTransaction && tx.from && tx.feePayer){
- console.log('"from" is ignored for a fee-delegated transaction.')
- delete tx.from
+
+ let error
+ if (!_.isObject(tx)) {
+ error = new Error('The transaction must be defined as an object.')
+ sendTxCallback(error)
+ return Promise.reject(error)
+ }
+
+ let addressToUse = tx.from
+
+ if (tx.senderRawTransaction && tx.feePayer){
+ addressToUse = tx.feePayer
+ if (tx.from) {
+ console.log('"from" is ignored for a fee-delegated transaction.')
+ delete tx.from
+ }
}
- const wallet = getWallet(_.isObject(tx) && tx.from || tx.feePayer || null, method.accounts)
+ let wallet
+
+ try {
+ wallet = method.accounts.wallet.getAccount(addressToUse)
+ } catch (e) {
+ sendTxCallback(e)
+ return Promise.reject(e)
+ }
if (wallet && wallet.privateKey) {
+ privateKey = method.accounts._getRoleKey(tx, wallet)
// If wallet was found, sign tx, and send using sendRawTransaction
- return method.accounts.signTransaction(tx, wallet.privateKey, sendTxCallback).then(sendSignedTx)
+ return method.accounts.signTransaction(tx, privateKey).then(sendSignedTx).catch((e) => { sendTxCallback(e) })
+ } else if (tx.signatures) {
+ // If signatures is defined inside of the transaction object,
+ // get rawTransaction string from signed transaction object and send to network
+ return method.accounts.getRawTransactionWithSignatures(tx).then(sendSignedTx).catch((e) => { sendTxCallback(e) })
}
// If wallet was not found in caver-js wallet, then it has to use wallet in Node.
// Signing to transaction using wallet in Node supports only LEGACY transaction, so if transaction is not LEGACY, return error.
if (tx.feePayer !== undefined || (tx.type !== undefined && tx.type !== 'LEGACY')) {
- var error = new Error('Only Legacy transactions can be signed on a Klaytn node!')
+ error = new Error('Only Legacy transactions can be signed on a Klaytn node!')
sendTxCallback(error)
return Promise.reject(error)
}
- if (!tx.senderRawTransaction){
- var error = validateParams(tx)
- if (error) {
- sendTxCallback(error)
- return Promise.reject(error)
- }
+ error = validateParams(tx)
+ if (error) {
+ sendTxCallback(error)
+ return Promise.reject(error)
}
break
}
case 'klay_sign': {
const data = payload.params[1]
- const wallet = getWallet(payload.params[0], method.accounts)
+ const wallet = method.accounts.wallet.getAccount(payload.params[0])
if (wallet && wallet.privateKey) {
// If wallet was found, sign tx, and send using sendRawTransaction
diff --git a/packages/caver-core-requestmanager/caver-providers-ws/src/index.js b/packages/caver-core-requestmanager/caver-providers-ws/src/index.js
index cb837850..b64063b5 100644
--- a/packages/caver-core-requestmanager/caver-providers-ws/src/index.js
+++ b/packages/caver-core-requestmanager/caver-providers-ws/src/index.js
@@ -76,8 +76,12 @@ var WebsocketProvider = function WebsocketProvider(url, options) {
headers.authorization = 'Basic ' + _btoa(parsedURL.username + ':' + parsedURL.password);
}
- this.connection = new Ws(url, protocol, undefined, headers);
- this.reconnect = () => new Ws(url, protocol, undefined, headers);
+ // Allow a custom client configuration
+ var clientConfig = options.clientConfig || undefined;
+
+ this.connection = new Ws(url, protocol, undefined, headers, undefined, clientConfig);
+ this.reconnect = () => new Ws(url, protocol, undefined, headers, undefined, clientConfig);
+
this.addDefaultEvents();
diff --git a/packages/caver-core/src/index.js b/packages/caver-core/src/index.js
index 56efd4c1..fea86560 100644
--- a/packages/caver-core/src/index.js
+++ b/packages/caver-core/src/index.js
@@ -63,6 +63,19 @@ module.exports = {
packageInit: function (pkg, [provider, net]) {
if (!pkg) throw new Error('You need to instantiate using the "new" keyword.')
+ // make property of pkg._provider, which can properly set providers
+ Object.defineProperty(pkg, 'currentProvider', {
+ get: function () {
+ return pkg._provider;
+ },
+ set: function (value) {
+ return pkg.setProvider(value);
+ },
+ enumerable: true,
+ configurable: true
+ });
+
+
if (provider && provider._requestManager) {
pkg._requestManager = new Manager(provider.currentProvider)
// set requestmanager on package
@@ -73,8 +86,7 @@ module.exports = {
pkg.providers = Manager.providers
pkg._provider = pkg._requestManager.provider
- pkg.currentProvider = pkg._provider
-
+
// add SETPROVIDER function (don't overwrite if already existing)
if (!pkg.setProvider) {
pkg.setProvider = (provider, net) => pkg._provider = pkg._requestManager.setProvider(provider, net).provider
diff --git a/packages/caver-klay/caver-klay-accounts/src/account/account.js b/packages/caver-klay/caver-klay-accounts/src/account/account.js
new file mode 100644
index 00000000..60b7f7e4
--- /dev/null
+++ b/packages/caver-klay/caver-klay-accounts/src/account/account.js
@@ -0,0 +1,73 @@
+const AccountKeyPublic = require('../accountKey/accountKeyPublic')
+const AccountKeyMultiSig = require('../accountKey/accountKeyMultiSig')
+const AccountKeyRoleBased = require('../accountKey/accountKeyRoleBased')
+const isAddress = require('../../../../caver-utils/src/utils').isAddress
+const addHexPrefix = require('../../../../caver-utils').addHexPrefix
+
+class Account {
+ static fromObject(obj) { return new Account(obj.address, new AccountKeyPublic(obj.privateKey)) }
+
+ static isAccountKey(accountKey) {
+ let isAccountKey = false
+ if (accountKey instanceof AccountKeyPublic) isAccountKey = true
+ if (accountKey instanceof AccountKeyMultiSig) isAccountKey = true
+ if (accountKey instanceof AccountKeyRoleBased) isAccountKey = true
+
+ return isAccountKey
+ }
+
+ constructor(address, accountKey) {
+ if (!address || !accountKey) throw new Error('Failed to create Account. address and accountKey are needed to create Account.')
+
+ if (!isAddress(address)) throw new Error(`Invalid address : ${address}`)
+ if (!Account.isAccountKey(accountKey)) throw new Error(`Invalid accountKey.`)
+
+ address = addHexPrefix(address)
+
+ Object.defineProperty(this, 'address', {
+ get: function () { return address },
+ set: function (addressInput) {
+ if (!isAddress(addressInput)) throw new Error(`Invalid address : ${addressInput}`)
+ address = addHexPrefix(addressInput)
+ },
+ enumerable: true
+ })
+
+ Object.defineProperty(this, 'accountKey', {
+ get: function () { return accountKey },
+ set: function (accountKeyInput) {
+ if (!Account.isAccountKey(accountKeyInput) && accountKeyInput !== null) throw new Error(`Invalid accountKey.`)
+
+ if (accountKey === null || accountKeyInput === null) {
+ accountKey = accountKeyInput
+ } else if (accountKey.type !== accountKeyInput.type) {
+ accountKey = accountKeyInput
+ } else {
+ accountKey.update(accountKeyInput)
+ }
+ },
+ enumerable: true,
+ configurable: true
+ })
+
+ Object.defineProperty(this, 'privateKey', {
+ get: function () { return this.accountKey.defaultKey },
+ set: function (privateKeyInput) {
+ throw new Error('The privateKey cannot be modified. The privateKey is set to default key of accountKey, so update accountKey to modify the privateKey.')
+ },
+ enumerable: true
+ })
+ }
+
+ get keys() { return this.accountKey.keys }
+ get accountKeyType() { return this.accountKey.type }
+ get transactionKey() { return this.accountKey.transactionKey }
+ get updateKey() { return this.accountKey.updateKey }
+ get feePayerKey() { return this.accountKey.feePayerKey }
+
+ toPublicKey(toPublicKeyFunc) {
+ return this.accountKey.toPublicKey(toPublicKeyFunc)
+ }
+}
+
+module.exports = Account
\ No newline at end of file
diff --git a/packages/caver-klay/caver-klay-accounts/src/account/accountForUpdate.js b/packages/caver-klay/caver-klay-accounts/src/account/accountForUpdate.js
new file mode 100644
index 00000000..f2069107
--- /dev/null
+++ b/packages/caver-klay/caver-klay-accounts/src/account/accountForUpdate.js
@@ -0,0 +1,72 @@
+const isValidRole = require('../../../../caver-utils').isValidRole
+const isValidPublicKey = require('../../../../caver-utils').isValidPublicKey
+
+class AccountForUpdate {
+ constructor(address, keyForUpdate, options) {
+ this.address = address
+ this.keyForUpdate = keyFormatter(keyForUpdate, options)
+ }
+
+ fillUpdateObject(updateObject) {
+ delete updateObject.key
+ Object.assign(updateObject, this.keyForUpdate)
+ }
+}
+
+function keyFormatter(keyForUpdate, options) {
+ const keyObject = {}
+
+ if (typeof keyForUpdate === 'string') {
+ if (options) throw new Error(`Failed to keyFormatter for AccountForUpdate: AccountKeyPublic/legacyKey/failKey cannot have options`)
+ switch(keyForUpdate) {
+ case 'legacyKey':
+ keyObject.legacyKey = true
+ break
+ case 'failKey':
+ keyObject.failKey = true
+ break
+ default:
+ if (!isValidPublicKey(keyForUpdate)) throw new Error(`Invalid public key`)
+ keyObject.publicKey = keyForUpdate
+ break
+ }
+ } else if (Array.isArray(keyForUpdate)) {
+ if (!options || !options.threshold || !options.weight) throw new Error('For AccountKeyMultiSig, threshold and weight should be defined in options object.')
+ if (!Array.isArray(options.weight)) throw new Error('The weight should be defined as a array.')
+ if (options.weight.length !== keyForUpdate.length) throw new Error('The length of keys in AccountKeyMultiSig and the length of weight array do not match.')
+
+ keyObject.multisig = {
+ threshold: options.threshold,
+ keys: []
+ }
+
+ let weightSum = 0
+
+ for (let i = 0; i < keyForUpdate.length; i ++) {
+ const key = keyForUpdate[i]
+ if (!isValidPublicKey(key)) throw new Error(`Invalid public key`)
+ keyObject.multisig.keys.push({weight: options.weight[i], publicKey: key})
+ weightSum += options.weight[i]
+ }
+
+ if (weightSum < options.threshold) throw new Error(`Invalid options for AccountKeyMultiSig: The sum of weights is less than the threshold.`)
+ } else {
+ for (let key in keyForUpdate) {
+ if (!isValidRole(key)) throw new Error(`Invalid role is defined: ${key}`)
+ options = options || {}
+ if (key === 'transactionKey') {
+ keyObject.roleTransactionKey = keyFormatter(keyForUpdate[key], options.transactionKey)
+ }
+ if (key === 'updateKey') {
+ keyObject.roleAccountUpdateKey = keyFormatter(keyForUpdate[key], options.updateKey)
+ }
+ if (key === 'feePayerKey') {
+ keyObject.roleFeePayerKey = keyFormatter(keyForUpdate[key], options.feePayerKey)
+ }
+ }
+ }
+
+ return keyObject
+}
+
+module.exports = AccountForUpdate
\ No newline at end of file
diff --git a/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyEnum.js b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyEnum.js
new file mode 100644
index 00000000..0640f207
--- /dev/null
+++ b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyEnum.js
@@ -0,0 +1,7 @@
+module.exports = {
+ AccountKeyEnum: {
+ ACCOUNT_KEY_PUBLIC: 'AccountKeyPublic',
+ ACCOUNT_KEY_MULTISIG: 'AccountKeyMultiSig',
+ ACCOUNT_KEY_ROLEBASED: 'AccountKeyRoleBased'
+ },
+}
\ No newline at end of file
diff --git a/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js
new file mode 100644
index 00000000..d3e5a340
--- /dev/null
+++ b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js
@@ -0,0 +1,50 @@
+const AccountKeyEnum = require('./accountKeyEnum').AccountKeyEnum
+
+const MAX_MULTISIG_KEY_LENGTH = 10
+
+class AccountKeyMultiSig {
+ constructor(keys) {
+ if (keys instanceof AccountKeyMultiSig) keys = keys.keys
+
+ if (!Array.isArray(keys)) throw new Error('To create AccountKeyMultiSig, an array of private key strings is required.')
+ if (keys.length === 0) throw new Error(`Empty array.`)
+ if (keys.length > MAX_MULTISIG_KEY_LENGTH) throw new Error(`The maximum number of keys is ${MAX_MULTISIG_KEY_LENGTH}.`)
+ if (isDuple(keys)) throw new Error('There is a duplicate key.')
+
+ this._keys = keys
+ }
+
+ get type() { return AccountKeyEnum.ACCOUNT_KEY_MULTISIG }
+
+ get defaultKey() { return this._keys[0] }
+ get keys() { return this._keys }
+ get transactionKey() { return this._keys }
+ get updateKey() { return this._keys }
+ get feePayerKey() { return this._keys }
+
+ toPublicKey(toPublicKeyFunc) {
+ const keys = []
+
+ for (let i = 0; i < this._keys.length; i ++) {
+ let key = this._keys[i]
+ keys.push(toPublicKeyFunc(key))
+ }
+
+ return keys
+ }
+
+ update(keys) {
+ this._keys = keys.keys
+ }
+}
+
+function isDuple(keys) {
+ const map = new Map()
+ for (const key of keys) {
+ if (map.get(key) !== undefined) return true
+ map.set(key, true)
+ }
+ return false
+}
+
+module.exports = AccountKeyMultiSig
diff --git a/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyPublic.js b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyPublic.js
new file mode 100644
index 00000000..6ee74cc7
--- /dev/null
+++ b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyPublic.js
@@ -0,0 +1,28 @@
+const AccountKeyEnum = require('./accountKeyEnum').AccountKeyEnum
+
+class AccountKeyPublic {
+ constructor(key) {
+ if (key instanceof AccountKeyPublic) key = key.keys
+
+ if (typeof key !== 'string') throw new Error('To create AccountKeyPublic, a private key strings is required.')
+ this._key = key
+ }
+
+ get type() { return AccountKeyEnum.ACCOUNT_KEY_PUBLIC }
+
+ get defaultKey() { return this._key }
+ get keys() { return this._key }
+ get transactionKey() { return this._key }
+ get updateKey() { return this._key }
+ get feePayerKey() { return this._key }
+
+ toPublicKey(toPublicKeyFunc) {
+ return toPublicKeyFunc(this._key)
+ }
+
+ update(key) {
+ this._key = key.keys
+ }
+}
+
+module.exports = AccountKeyPublic
\ No newline at end of file
diff --git a/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyRoleBased.js b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyRoleBased.js
new file mode 100644
index 00000000..ab80eac9
--- /dev/null
+++ b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyRoleBased.js
@@ -0,0 +1,98 @@
+const AccountKeyEnum = require('./accountKeyEnum').AccountKeyEnum
+const AccountKeyPublic = require('./accountKeyPublic')
+const AccountKeyMultiSig = require('./accountKeyMultiSig')
+const utils = require('../../../../caver-utils')
+
+class AccountKeyRoleBased {
+ constructor(keyObj = {}) {
+ if (keyObj instanceof AccountKeyRoleBased) keyObj = keyObj.keys
+
+ if (typeof keyObj !== 'object') throw new Error('RoleBasedKey should be created with Object')
+
+ validateKeyObject(keyObj)
+
+ this._transactionKey = makeAccountKey(keyObj.transactionKey)
+ this._updateKey = makeAccountKey(keyObj.updateKey)
+ this._feePayerKey = makeAccountKey(keyObj.feePayerKey)
+ }
+
+ get type() { return AccountKeyEnum.ACCOUNT_KEY_ROLEBASED }
+
+ get defaultKey() {
+ let definedKey = this._transactionKey? this._transactionKey : this._updateKey? this._updateKey : this._feePayerKey? this._feePayerKey : undefined
+
+ if (!definedKey) throw new Error(`There is no key defined in AccountKeyRoleBased.`)
+
+ return definedKey.defaultKey
+ }
+
+ get keys() {
+ const keys = {}
+
+ if (this._transactionKey !== undefined) keys.transactionKey = this._transactionKey.keys
+ if (this._updateKey !== undefined) keys.updateKey = this._updateKey.keys
+ if (this._feePayerKey !== undefined) keys.feePayerKey = this._feePayerKey.keys
+
+ return keys
+ }
+
+ get transactionKey() {
+ if (!this._transactionKey) return undefined
+ return this._transactionKey.keys
+ }
+ get updateKey() {
+ if (!this._updateKey) return undefined
+ return this._updateKey.keys
+ }
+ get feePayerKey() {
+ if (!this._feePayerKey) return undefined
+ return this._feePayerKey.keys
+ }
+
+ toPublicKey(toPublicKeyFunc) {
+ const returnObject = {}
+
+ if (this._transactionKey !== undefined) returnObject.transactionKey = this._transactionKey.toPublicKey(toPublicKeyFunc)
+ if (this._updateKey !== undefined) returnObject.updateKey = this._updateKey.toPublicKey(toPublicKeyFunc)
+ if (this._feePayerKey !== undefined) returnObject.feePayerKey = this._feePayerKey.toPublicKey(toPublicKeyFunc)
+
+ return returnObject
+ }
+
+ update(keys) {
+ // In the case of AccountKeyRoleBased, the key that does not update is not defined.
+ // To handle this case, when updating, only update the key for the defined role.
+ if (keys._transactionKey) this._transactionKey = keys._transactionKey
+ if (keys._updateKey) this._updateKey = keys._updateKey
+ if (keys._feePayerKey) this._feePayerKey = keys._feePayerKey
+ }
+}
+
+function makeAccountKey(key) {
+ if (key === undefined) return undefined
+ if (Array.isArray(key) || key instanceof AccountKeyMultiSig) return new AccountKeyMultiSig(key)
+ if (typeof key !== 'string') throw new Error('Invalid account key type')
+
+ return new AccountKeyPublic(key)
+}
+
+function validateKeyObject(keyObject) {
+ const key = Object.keys(keyObject)
+ if (key.length === 0) throw new Error(`Failed to create AccountKeyRoleBased: empty object`)
+
+ key.map((role) => {
+ if (!utils.isValidRole(role)) throw new Error(`Failed to create AccountKeyRoleBased. Invalid role is defined : ${role}`)
+
+ if (Array.isArray(keyObject[role])) {
+ for (let p of keyObject[role]) {
+ const parsed = utils.parsePrivateKey(p)
+ p = parsed.privateKey
+ if (!utils.isValidPrivateKey(p)) throw new Error(`Failed to create AccountKeyRoleBased. Invalid private key : ${p}`)
+ }
+ } else {
+ if (!utils.isValidPrivateKey(keyObject[role])) throw new Error(`Failed to create AccountKeyRoleBased. Invalid private key : ${keyObject[role]}`)
+ }
+ })
+}
+
+module.exports = AccountKeyRoleBased
\ No newline at end of file
diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js
index 060792a6..0eb14647 100644
--- a/packages/caver-klay/caver-klay-accounts/src/index.js
+++ b/packages/caver-klay/caver-klay-accounts/src/index.js
@@ -29,21 +29,29 @@ var core = require('../../../caver-core');
var Method = require('../../../caver-core-method');
var Promise = require('any-promise');
// account, hash, rlp, nat, bytes library will be used from 'eth-lib' temporarily.
-var Account = require("eth-lib/lib/account");
+var AccountLib = require("eth-lib/lib/account");
var Hash = require("eth-lib/lib/hash");
var RLP = require("eth-lib/lib/rlp");
var Nat = require("eth-lib/lib/nat");
var Bytes = require("eth-lib/lib/bytes");
var cryp = (typeof global === 'undefined') ? require('crypto-browserify') : require('crypto');
-var scryptsy = require('scrypt.js');
+var scrypt = require('./scrypt');
var uuid = require('uuid');
var utils = require('../../../caver-utils');
var helpers = require('../../../caver-core-helpers');
-const { encodeRLPByTxType, makeRawTransaction, getSenderTxHash } = require('./makeRawTransaction')
+const { encodeRLPByTxType, makeRawTransaction, getSenderTxHash, decodeFromRawTransaction, splitFeePayer, extractSignatures } = require('./makeRawTransaction')
var elliptic = require('elliptic')
var secp256k1 = new (elliptic.ec)('secp256k1')
+const AccountKeyPublic = require('./accountKey/accountKeyPublic')
+const AccountKeyMultiSig = require('./accountKey/accountKeyMultiSig')
+const AccountKeyRoleBased = require('./accountKey/accountKeyRoleBased')
+const AccountKeyEnum = require('./accountKey/accountKeyEnum').AccountKeyEnum
+
+const Account = require('./account/account')
+const AccountForUpdate = require('./account/accountForUpdate')
+
const rpc = require('../../../caver-rtm').rpc
var isNot = function(value) {
@@ -52,12 +60,92 @@ var isNot = function(value) {
function coverInitialTxValue(tx) {
if (typeof tx !== 'object') throw ('Invalid transaction')
- tx.to = tx.to || '0x'
- tx.data = tx.data || '0x'
+ if (!tx.senderRawTransaction && (!tx.type || tx.type === 'LEGACY' || tx.type.includes('SMART_CONTRACT_DEPLOY'))) {
+ tx.to = tx.to || '0x'
+ tx.data = utils.addHexPrefix(tx.data || '0x')
+ }
tx.chainId = utils.numberToHex(tx.chainId)
return tx
}
+/**
+ * resolveArgsForSignTransaction parse arguments for signTransaction.
+ *
+ * @method resolveArgsForSignTransaction
+ * @param {Object} args Parameters of signTransaction.
+ * @return {Object}
+ */
+function resolveArgsForSignTransaction(args) {
+ if (args.length === 0 || args.length > 3) throw new Error('Invalid parameter: The number of parameters is invalid.')
+
+ // privateKey and callback are optional parameter
+ // "args.length === 2" means that user sent parameter privateKey or callback
+ let tx = args[0], privateKey, callback
+
+ if (!tx || (!_.isObject(tx) && !_.isString(tx))) {
+ throw new Error('Invalid parameter: The transaction must be defined as an object or RLP encoded string')
+ }
+
+ if (args.length === 2) {
+ if (_.isFunction(args[1])) {
+ callback = args[1]
+ } else {
+ privateKey = args[1]
+ }
+ } else if (args.length === 3) {
+ if (args[1] && typeof args[1] !== 'string' && !_.isArray(args[1])){
+ return handleError('Invalid parameter: The parameter for the private key is invalid')
+ }
+ privateKey = args[1]
+ callback = args[2]
+ }
+
+ // For handling when callback is undefined.
+ callback = callback || function () {}
+
+ return { tx, privateKey, callback }
+}
+
+/**
+ * resolveArgsForFeePayerSignTransaction parse arguments for feePayerSignTransaction.
+ *
+ * @method resolveArgsForFeePayerSignTransaction
+ * @param {Object} args Parameters of feePayerSignTransaction.
+ * @return {Object}
+ */
+function resolveArgsForFeePayerSignTransaction(args) {
+ if (args.length === 0 || args.length > 4) throw new Error('Invalid parameter: The number of parameters is invalid.')
+
+ // privateKey and callback are optional parameter
+ // "args.length === 3" means that user sent parameter privateKey or callback
+ let tx = args[0], feePayer = args[1], privateKey, callback
+
+ if (!tx || (!_.isObject(tx) && !_.isString(tx))) {
+ throw new Error('Invalid parameter: The transaction must be defined as an object or RLP encoded string')
+ }
+
+ if (!utils.isAddress(feePayer)) throw new Error(`Invalid fee payer address : ${feePayer}`)
+
+ if (args.length === 3) {
+ if (_.isFunction(args[2])) {
+ callback = args[2]
+ } else {
+ privateKey = args[2]
+ }
+ } else if (args.length === 4) {
+ if (args[2] && typeof args[2] !== 'string' && !_.isArray(args[2])){
+ return handleError('Invalid parameter: The parameter for the private key is invalid')
+ }
+ privateKey = args[2]
+ callback = args[3]
+ }
+
+ // For handling when callback is undefined.
+ callback = callback || function () {}
+
+ return { tx, privateKey, feePayer, callback }
+}
+
var Accounts = function Accounts(...args) {
var _this = this;
@@ -94,7 +182,7 @@ Accounts.prototype._addAccountFunctions = function (account) {
account.encrypt = function encrypt(password, options = {}) {
options.address = account.address
- return _this.encrypt(account.privateKey, password, options);
+ return _this.encrypt(account.keys, password, options);
};
account.getKlaytnWalletKey = function getKlaytnWalletKey() {
@@ -105,75 +193,455 @@ Accounts.prototype._addAccountFunctions = function (account) {
return account;
};
-Accounts.prototype.create = function create(entropy) {
- return this._addAccountFunctions(Account.create(entropy || utils.randomHex(32)));
-};
-
-Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(privateKey, targetAddressRaw) {
- var { privateKey: prvKey, address, isHumanReadable } = utils.parsePrivateKey(privateKey)
-
- if (!utils.isValidPrivateKey(prvKey)) throw new Error('Invalid private key')
- if (prvKey.slice(0, 2) !== '0x') {
- prvKey = `0x${prvKey}`
- }
-
- let account = Account.fromPrivate(prvKey)
-
- if (targetAddressRaw) {
- if(address && address !== targetAddressRaw) {
+/**
+ * _determineAddress determines the priority of the parameters entered and returns the address that should be used for the account.
+ *
+ * @method _determineAddress
+ * @param {Object} legacyAccount Account with a legacy account key extracted from private key to be used for address determination.
+ * @param {String} addressFromKey Address extracted from key.
+ * @param {String} userInputAddress Address passed as parameter by user.
+ * @return {String}
+ */
+Accounts.prototype._determineAddress = function _determineAddress(legacyAccount, addressFromKey, userInputAddress) {
+ if (userInputAddress) {
+ if(addressFromKey && addressFromKey !== userInputAddress) {
throw new Error('The address extracted from the private key does not match the address received as the input value.')
}
- if(!utils.isAddress(targetAddressRaw)) {
+ if(!utils.isAddress(userInputAddress)) {
throw new Error('The address received as the input value is invalid.')
}
- account.address = targetAddressRaw
+ return userInputAddress
- } else if (address){
- if(!utils.isAddress(address)) {
+ } else if (addressFromKey){
+ if(!utils.isAddress(addressFromKey)) {
throw new Error('The address extracted from the private key is invalid.')
}
- // If targetAddressRaw is undefined and address which is came from private is existed, set address in account.
- account.address = address
+ // If userInputAddress is undefined and address which is came from private is existed, set address in account.
+ return addressFromKey
}
+ return legacyAccount.address
+}
- account.address = account.address.toLowerCase()
- account.address = '0x' + account.address.replace('0x', '')
+/**
+ * _getRoleKey returns a key that matches the role that should be used according to the transaction.
+ *
+ * @method _getRoleKey
+ * @param {Object} tx transaction object to be sign.
+ * @param {Object} account Account to be used for signing.
+ * @return {String|Array}
+ */
+Accounts.prototype._getRoleKey = function _getRoleKey(tx, account) {
+ let key
+
+ if (!account) throw new Error(`The account to be used for signing is not defined.`)
+ if (tx.senderRawTransaction && tx.feePayer) {
+ key = account.feePayerKey
+ } else if (tx.type && tx.type.includes('ACCOUNT_UPDATE')) {
+ key = account.updateKey
+ } else {
+ key = account.transactionKey
+ }
+
+ if (!key) throw new Error(`The key corresponding to the role used for signing is not defined.`)
+
+ return key
+}
+
+/**
+ * create function creates random account with entropy.
+ *
+ * @method create
+ * @param {Object} entropy A random string to increase entropy.
+ * @return {Object}
+ */
+Accounts.prototype.create = function create(entropy) {
+ return this._addAccountFunctions(Account.fromObject(AccountLib.create(entropy || utils.randomHex(32))));
+};
+
+/**
+ * createAccountKey creates AccountKeyPublic, AccountKeyMultiSig or AccountKeyRoleBased instance with parameter.
+ *
+ * @method createAccountKey
+ * @param {String|Array|Object} accountKey Parameters to be used when creating the AccountKey.
+ * @return {Object}
+ */
+Accounts.prototype.createAccountKey = function createAccountKey(accountKey) {
+ if (Account.isAccountKey(accountKey)) accountKey = accountKey.keys
+
+ if (_.isString(accountKey)) {
+ accountKey = this.createAccountKeyPublic(accountKey)
+ } else if (_.isArray(accountKey)) {
+ accountKey = this.createAccountKeyMultiSig(accountKey)
+ } else if (_.isObject(accountKey)) {
+ accountKey = this.createAccountKeyRoleBased(accountKey)
+ } else {
+ throw new Error(`Invalid accountKey type: ${typeof accountKey}`)
+ }
+ return accountKey
+}
+
+/**
+ * createAccountKeyPublic creates AccountKeyPublic with a string of private key.
+ *
+ * @method createAccountKeyPublic
+ * @param {String} privateKey Private key string that will be used to create AccountKeyPublic.
+ * @return {Object}
+ */
+Accounts.prototype.createAccountKeyPublic = function createAccountKeyPublic(privateKey) {
+ if (privateKey instanceof AccountKeyPublic) return privateKey
+
+ if (!_.isString(privateKey)) throw new Error('Creating a AccountKeyPublic requires a private key string.')
+
+ const parsed = utils.parsePrivateKey(privateKey)
+ privateKey = parsed.privateKey
+
+ if (!utils.isValidPrivateKey(privateKey)) throw new Error(`Failed to create AccountKeyPublic. Invalid private key : ${privateKey}`)
+
+ return new AccountKeyPublic(privateKey)
+}
+
+/**
+ * createAccountKeyMultiSig creates AccountKeyMultiSig with an array of private keys.
+ *
+ * @method createAccountKeyMultiSig
+ * @param {Array} privateKeys An Array of private key strings that will be used to create AccountKeyMultiSig.
+ * @return {Object}
+ */
+Accounts.prototype.createAccountKeyMultiSig = function createAccountKeyMultiSig(privateKeys) {
+ if (privateKeys instanceof AccountKeyMultiSig) return privateKeys
+
+ if (!_.isArray(privateKeys)) throw new Error('Creating a AccountKeyMultiSig requires an array of private key string.')
+
+ for (let p of privateKeys) {
+ const parsed = utils.parsePrivateKey(p)
+ p = parsed.privateKey
+ if (!utils.isValidPrivateKey(p)) throw new Error(`Failed to create AccountKeyMultiSig. Invalid private key : ${p}`)
+ }
+
+ return new AccountKeyMultiSig(privateKeys)
+}
+
+/**
+ * createAccountKeyRoleBased creates AccountKeyRoleBased with an obejct of key.
+ *
+ * @method createAccountKeyRoleBased
+ * @param {Object} keyObject Object that defines key for each role to use when creating AccountKeyRoleBased.
+ * @return {Object}
+ */
+Accounts.prototype.createAccountKeyRoleBased = function createAccountKeyRoleBased(keyObject) {
+ if (keyObject instanceof AccountKeyRoleBased) return keyObject
+
+ if (!_.isObject(keyObject) || _.isArray(keyObject)) throw new Error('Creating a AccountKeyRoleBased requires an object.')
+
+ return new AccountKeyRoleBased(keyObject)
+}
+
+/**
+ * accountKeyToPublicKey creates public key format with AccountKey.
+ *
+ * @method accountKeyToPublicKey
+ * @param {Object} accountKey AccountKey instance for which you want to generate a public key format.
+ * @return {String|Array|Object}
+ */
+Accounts.prototype.accountKeyToPublicKey = function accountKeyToPublicKey(accountKey) {
+ accountKey = this.createAccountKey(accountKey)
+ return accountKey.toPublicKey(this.privateKeyToPublicKey)
+}
+
+/**
+ * createWithAccountKey creates Account instance with AccountKey.
+ *
+ * @method createWithAccountKey
+ * @param {String} address The address of account.
+ * @param {String|Array|Object} accountKey The accountKey of account.
+ * @return {Object}
+ */
+Accounts.prototype.createWithAccountKey = function createWithAccountKey(address, accountKey) {
+ const account = new Account(address, this.createAccountKey(accountKey))
return this._addAccountFunctions(account)
}
-Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, callback) {
- var _this = this,
- error = false,
- result
+/**
+ * createWithAccountKeyPublic create an account with AccountKeyPublic.
+ *
+ * @method createWithAccountKeyPublic
+ * @param {String} address An address of account.
+ * @param {String|Object} key Key of account.
+ * @return {Object}
+ */
+Accounts.prototype.createWithAccountKeyPublic = function createWithAccountKeyPublic(address, key) {
+ if (!Account.isAccountKey(key)) key = this.createAccountKeyPublic(key)
- callback = callback || function () {}
+ if (key.type !== AccountKeyEnum.ACCOUNT_KEY_PUBLIC) throw new Error(`Failed to create account with AccountKeyPublic. Invalid account key : ${key.type}`)
+
+ const account = new Account(address, key)
+ return this._addAccountFunctions(account)
+}
+
+/**
+ * createWithAccountKeyMultiSig create an account with AccountKeyMultiSig.
+ *
+ * @method createWithAccountKeyMultiSig
+ * @param {String} address An address of account.
+ * @param {String|Object} keys Key of account.
+ * @return {Object}
+ */
+Accounts.prototype.createWithAccountKeyMultiSig = function createWithAccountKeyMultiSig(address, keys) {
+ if (!Account.isAccountKey(keys)) keys = this.createAccountKeyMultiSig(keys)
+
+ if (keys.type !== AccountKeyEnum.ACCOUNT_KEY_MULTISIG) throw new Error(`Failed to create account with AccountKeyMultiSig. Invalid account key : ${keys.type}`)
+
+ const account = new Account(address, keys)
+ return this._addAccountFunctions(account)
+}
+
+/**
+ * createWithAccountKeyRoleBased create an account with AccountKeyRoleBased.
+ *
+ * @method createWithAccountKeyRoleBased
+ * @param {String} address An address of account.
+ * @param {String|Object} keyObject Key of account.
+ * @return {Object}
+ */
+Accounts.prototype.createWithAccountKeyRoleBased = function createWithAccountKeyRoleBased(address, keyObject) {
+ if (!Account.isAccountKey(keyObject)) keyObject = this.createAccountKeyRoleBased(keyObject)
+
+ if (keyObject.type !== AccountKeyEnum.ACCOUNT_KEY_ROLEBASED) throw new Error(`Failed to create account with AccountKeyRoleBased. Invalid account key : ${keyObject.type}`)
- const parsed = utils.parsePrivateKey(privateKey)
- privateKey = parsed.privateKey
+ const account = new Account(address, keyObject)
+ return this._addAccountFunctions(account)
+}
- if (!utils.isValidPrivateKey(privateKey)) throw new Error('Invalid private key')
- privateKey = privateKey.startsWith('0x') ? privateKey : '0x' + privateKey
+/**
+ * privateKeyToAccount creates and returns an Account through the input passed as parameters.
+ *
+ * @method privateKeyToAccount
+ * @param {String} key The key parameter can be either normal private key or KlaytnWalletKey format.
+ * @param {String} userInputAddress The address entered by the user for use in creating an account.
+ * @return {Object}
+ */
+Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(key, userInputAddress) {
+ let {legacyAccount: account, klaytnWalletKeyAddress} = this.getLegacyAccount(key)
- if (!tx) {
- error = new Error('No transaction object given!')
+ account.address = this._determineAddress(account, klaytnWalletKeyAddress, userInputAddress)
+ account.address = account.address.toLowerCase()
+ account.address = utils.addHexPrefix(account.address)
+
+ return account
+}
+
+
+/**
+ * createAccountForUpdate creates an AccountForUpdate instance.
+ * The AccountForUpdate returned as a result of this function contains only the address and public key used to update the account.
+ *
+ * @method createAccountForUpdate
+ * @param {String} address The address value of AccountForUpdate, a structure that contains data for updating an account.
+ * @param {String|Array|Object} accountKey Private key or AccountKey to update account.
+ * @param {Object} options Options to use for setting threshold and weight for multiSig.
+ * @return {Object}
+ */
+Accounts.prototype.createAccountForUpdate = function createAccountForUpdate(address, accountKey, options) {
+ let legacyOrFail
+
+ // Logic for handling cases where legacyKey or failKey is set inside AccountKeyRoleBased object.
+ if (!_.isArray(accountKey) && _.isObject(accountKey)) {
+ legacyOrFail = {}
+ Object.keys(accountKey).map((role) => {
+ if (accountKey[role] === 'legacyKey' || accountKey[role] === 'failKey') {
+ legacyOrFail[role] = accountKey[role]
+ delete accountKey[role]
+ }
+ })
+ if (Object.keys(accountKey).length === 0) return new AccountForUpdate(address, legacyOrFail, options)
+ }
- callback(error)
- return Promise.reject(error)
+ const publicKey = this.accountKeyToPublicKey(accountKey)
+
+ if (legacyOrFail !== undefined) {
+ Object.assign(publicKey, legacyOrFail)
+ }
+
+ return new AccountForUpdate(address, publicKey, options)
+}
+
+/**
+ * createAccountForUpdateWithPublicKey creates AccountForUpdate instance with public key format.
+ *
+ * @method createAccountForUpdateWithPublicKey
+ * @param {String} address The address value of AccountForUpdate, a structure that contains data for updating an account.
+ * @param {String|Array|Object} keyForUpdate Public key to update.
+ * @param {Object} options Options to use for setting threshold and weight for multiSig.
+ * @return {Object}
+ */
+Accounts.prototype.createAccountForUpdateWithPublicKey = function createAccountForUpdateWithPublicKey(address, keyForUpdate, options) {
+ return new AccountForUpdate(address, keyForUpdate, options)
+}
+
+/**
+ * createAccountForUpdateWithLegacyKey creates AccountForUpdate instance with legacyKey.
+ *
+ * @method createAccountForUpdateWithLegacyKey
+ * @param {String} address The address of account to update with the legacy key.
+ * @return {Object}
+ */
+Accounts.prototype.createAccountForUpdateWithLegacyKey = function createAccountForUpdateWithLegacyKey(address) {
+ return new AccountForUpdate(address, 'legacyKey')
+}
+
+/**
+ * createAccountForUpdateWithFailKey creates AccountForUpdate instance with failKey.
+ *
+ * @method createAccountForUpdateWithFailKey
+ * @param {String} address The address of account to update with the fail key.
+ * @return {Object}
+ */
+Accounts.prototype.createAccountForUpdateWithFailKey = function createAccountForUpdateWithFailKey(address) {
+ return new AccountForUpdate(address, 'failKey')
+}
+
+/**
+ * isDecoupled determines whether or not it is decoupled based on the input value.
+ *
+ * @method isDecoupled
+ * @param {String} key The key parameter can be either normal private key or KlaytnWalletKey format.
+ * @param {String} userInputAddress The address to use when determining whether it is decoupled.
+ * @return {Boolean}
+ */
+Accounts.prototype.isDecoupled = function isDecoupled(key, userInputAddress) {
+ let { legacyAccount, klaytnWalletKeyAddress } = this.getLegacyAccount(key)
+ let actualAddress = this._determineAddress(legacyAccount, klaytnWalletKeyAddress, userInputAddress)
+
+ return legacyAccount.address.toLowerCase() !== actualAddress.toLowerCase()
+}
+
+/**
+ * getLegacyAccount extracts the private key from the input key and returns an account with the corresponding legacy account key.
+ * If the input key is KlaytnWalletKey format, it returns klaytnWalletKeyAddress, which is the address extracted from KlaytnWalletKey.
+ *
+ * @method getLegacyAccount
+ * @param {String} key The key parameter can be either normal private key or KlaytnWalletKey format.
+ * @return {Object}
+ */
+Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) {
+ var { privateKey, address: klaytnWalletKeyAddress, isHumanReadable } = utils.parsePrivateKey(key)
+
+ if (!utils.isValidPrivateKey(privateKey)) throw new Error('Invalid private key')
+
+ privateKey = utils.addHexPrefix(privateKey)
+
+ const account = this._addAccountFunctions(Account.fromObject(AccountLib.fromPrivate(privateKey)))
+
+ return { legacyAccount: account, klaytnWalletKeyAddress }
+}
+
+/**
+ * signTransaction signs to transaction with private key.
+ * If there are signatures(feePayerSignatures if the fee payer signs) in tx entered as a parameter,
+ * the signatures(feePayerSignatures if the fee payer signs) are appended.
+ *
+ * @method signTransaction
+ * @param {String|Object} tx The transaction to sign.
+ * @param {String|Array} privateKey The private key to use for signing.
+ * @param {String} callback The callback function to call.
+ * @return {Object}
+ */
+Accounts.prototype.signTransaction = function signTransaction() {
+ let _this = this
+ let isLegacy = false, isFeePayer = false
+ let existedSenderSignatures = [], existedFeePayerSignatures = []
+ let result, tx, privateKey, callback
+
+ let handleError = (e) => {
+ e = e instanceof Error? e : new Error(e)
+ if (callback) callback(e)
+ return Promise.reject(e)
}
- function signed(tx) {
+ try {
+ let resolved = resolveArgsForSignTransaction(arguments)
+ tx = resolved.tx
+ privateKey = resolved.privateKey
+ callback = resolved.callback
+ } catch(e) { return handleError(e) }
+
+ // If the user signs an RLP encoded transaction, tx is of type string.
+ if (_.isString(tx)) {
+ tx = decodeFromRawTransaction(tx)
+ }
+
+ // Validate tx object
+ const error = helpers.validateFunction.validateParams(tx)
+ if (error) return handleError(error)
+
+ if (tx.senderRawTransaction) {
+ if (tx.feePayerSignatures) {
+ existedFeePayerSignatures = existedFeePayerSignatures.concat(tx.feePayerSignatures)
+ }
- if (!tx.senderRawTransaction) {
- error = helpers.validateFunction.validateParams(tx)
+ try {
+ // Decode senderRawTransaction to get signatures of fee payer
+ const { senderRawTransaction, feePayer, feePayerSignatures } = splitFeePayer(tx.senderRawTransaction)
+
+ // feePayer !== '0x' means that in senderRawTransaction there are feePayerSignatures
+ if (feePayer !== '0x') {
+ // The feePayer inside the tx object does not match the feePayer information contained in the senderRawTransaction.
+ if (feePayer.toLowerCase() !== tx.feePayer.toLowerCase()) return handleError(`Invalid feePayer: The fee payer(${feePayer}) included in the transaction does not match the fee payer(${tx.feePayer}) you want to sign.`)
+ existedFeePayerSignatures = existedFeePayerSignatures.concat(feePayerSignatures)
+ }
+
+ tx.senderRawTransaction = senderRawTransaction
+ isFeePayer = true
+ } catch(e) {
+ return handleError(e)
}
- if (error) {
- callback(error);
- return Promise.reject(error);
+
+ } else {
+ isLegacy = tx.type === undefined || tx.type === 'LEGACY' ? true : false
+
+ if (tx.signatures) {
+ // if there is existed signatures or feePayerSignatures, those should be preserved.
+ if (isLegacy) return handleError('Legacy transaction cannot be signed with multiple keys.')
+ existedSenderSignatures = existedSenderSignatures.concat(tx.signatures)
}
+
+ }
+ // When privateKey is undefined, find Account from Wallet.
+ if (privateKey === undefined) {
+ try {
+ const account = this.wallet.getAccount(isFeePayer? tx.feePayer : tx.from)
+ if (!account) return handleError('Failed to find get private key to sign. The account you want to use for signing must exist in caver.klay.accounts.wallet or you must pass the private key as a parameter.')
+ privateKey = this._getRoleKey(tx, account)
+ } catch(e) {
+ return handleError(e)
+ }
+ }
+
+ let privateKeys = _.isArray(privateKey) ? privateKey : [privateKey]
+
+ try {
+ for (let i = 0; i < privateKeys.length; i ++) {
+ const parsed = utils.parsePrivateKey(privateKeys[i])
+ privateKeys[i] = parsed.privateKey
+ privateKeys[i] = utils.addHexPrefix(privateKeys[i])
+
+ if (!utils.isValidPrivateKey(privateKeys[i])) return handleError('Invalid private key')
+ }
+ } catch(e) {
+ return handleError(e)
+ }
+
+ // Attempting to sign with a decoupled account into a legacy type transaction should be rejected.
+ if (isLegacy) {
+ if (privateKeys.length > 1) return handleError('Legacy transaction cannot signed with multiple keys')
+ if (_this.isDecoupled(privateKeys[0], tx.from)) return handleError('A legacy transaction must be with a legacy account key')
+ }
+
+ function signed(tx) {
try {
// Guarantee all property in transaction is hex.
tx = helpers.formatters.inputCallFormatter(tx)
@@ -184,21 +652,32 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca
const messageHash = Hash.keccak256(rlpEncoded)
- const signature = Account.makeSigner(Nat.toNumber(transaction.chainId || "0x1") * 2 + 35)(messageHash, privateKey)
- const [v, r, s] = Account.decodeSignature(signature).map(sig => utils.makeEven(utils.trimLeadingZero(sig)))
+ let sigs = isFeePayer? existedFeePayerSignatures : existedSenderSignatures
- const rawTransaction = makeRawTransaction(rlpEncoded, [v, r, s], transaction)
+ for(const privateKey of privateKeys) {
+ const signature = AccountLib.makeSigner(Nat.toNumber(transaction.chainId || "0x1") * 2 + 35)(messageHash, privateKey)
+ const [v, r, s] = AccountLib.decodeSignature(signature).map(sig => utils.makeEven(utils.trimLeadingZero(sig)))
+ sigs.push([v, r, s])
+ }
+ // makeRawTransaction will return signatures and feePayerSignatures with duplicates removed.
+ let { rawTransaction, signatures, feePayerSignatures } = makeRawTransaction(rlpEncoded, sigs, transaction)
result = {
messageHash: messageHash,
- v: v,
- r: r,
- s: s,
+ v: sigs[0][0],
+ r: sigs[0][1],
+ s: sigs[0][2],
rawTransaction: rawTransaction,
txHash: Hash.keccak256(rawTransaction),
senderTxHash: getSenderTxHash(rawTransaction),
}
+ if (isFeePayer) {
+ result.feePayerSignatures = feePayerSignatures
+ } else {
+ result.signatures = signatures
+ }
+
} catch(e) {
callback(e)
return Promise.reject(e)
@@ -213,7 +692,7 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca
}
// When the feePayer signs a transaction, required information is only chainId.
- if (tx.senderRawTransaction !== undefined) {
+ if (isFeePayer) {
return Promise.all([
isNot(tx.chainId) ? _this._klaytnCall.getChainId() : tx.chainId,
]).then(function (args) {
@@ -221,51 +700,143 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca
throw new Error('"chainId" couldn\'t be fetched: '+ JSON.stringify(args));
}
return signed(_.extend(tx, {chainId: args[0]}));
- });
+ })
}
// Otherwise, get the missing info from the Klaytn Node
return Promise.all([
isNot(tx.chainId) ? _this._klaytnCall.getChainId() : tx.chainId,
isNot(tx.gasPrice) ? _this._klaytnCall.getGasPrice() : tx.gasPrice,
- isNot(tx.nonce) ? _this._klaytnCall.getTransactionCount(tx.from || _this.privateKeyToAccount(privateKey).address) : tx.nonce
+ isNot(tx.nonce) ? _this._klaytnCall.getTransactionCount(tx.from) : tx.nonce
]).then(function (args) {
if (isNot(args[0]) || isNot(args[1]) || isNot(args[2])) {
throw new Error('One of the values "chainId", "gasPrice", or "nonce" couldn\'t be fetched: '+ JSON.stringify(args));
}
return signed(_.extend(tx, {chainId: args[0], gasPrice: args[1], nonce: args[2]}));
- });
-};
+ })
+}
+
+/**
+* feePayerSignTransaction calls signTransaction, creating a format for feePayer to sign the transaction.
+* If there are feePayerSignatures in tx entered as a parameter, the signatures for fee payer are appended.
+*
+* @method feePayerSignTransaction
+* @param {Object|String} tx The transaction to sign.
+* @param {String} feePayer The address of fee payer.
+* @param {String|Array} privateKey The private key to use for signing.
+* @param {Function} callback The callback function to call.
+* @return {Object}
+*/
+Accounts.prototype.feePayerSignTransaction = function feePayerSignTransaction() {
+ let _this = this
+ let tx, feePayer, privateKey, callback
+
+ let handleError = (e) => {
+ e = e instanceof Error? e : new Error(e)
+ if (callback) callback(e)
+ return Promise.reject(e)
+ }
+
+ try {
+ let resolved = resolveArgsForFeePayerSignTransaction(arguments)
+ tx = resolved.tx
+ feePayer = resolved.feePayer
+ privateKey = resolved.privateKey
+ callback = resolved.callback
+ } catch(e) {
+ return handleError(e)
+ }
+
+ if (_.isString(tx)) {
+ return this.signTransaction({ senderRawTransaction: tx, feePayer }, privateKey, callback)
+ }
+
+ if (!tx.feePayer || tx.feePayer === '0x') { tx.feePayer = feePayer }
+
+ if (!tx.senderRawTransaction) {
+ if (!tx.type || !tx.type.includes('FEE_DELEGATED')) {
+ return handleError(`Failed to sign transaction with fee payer: invalid transaction type(${tx.type? tx.type: 'LEGACY'})`)
+ }
+ }
+
+ let e = helpers.validateFunction.validateParams(tx)
+ if (e) {
+ return handleError(e)
+ }
+
+ if (tx.feePayer.toLowerCase() !== feePayer.toLowerCase()) {
+ return handleError(`Invalid parameter: The address of fee payer does not match.`)
+ }
-Accounts.prototype.signTransactionWithSignature = function signTransactionWithSignature(tx, callback) {
+ if (tx.senderRawTransaction) {
+ return this.signTransaction(tx, privateKey, callback)
+ }
+
+ return Promise.all([
+ isNot(tx.chainId) ? _this._klaytnCall.getChainId() : tx.chainId,
+ isNot(tx.gasPrice) ? _this._klaytnCall.getGasPrice() : tx.gasPrice,
+ isNot(tx.nonce) ? _this._klaytnCall.getTransactionCount(tx.from) : tx.nonce
+ ]).then(function (args) {
+ if (isNot(args[0]) || isNot(args[1]) || isNot(args[2])) {
+ throw new Error('One of the values "chainId", "gasPrice", or "nonce" couldn\'t be fetched: '+ JSON.stringify(args));
+ }
+ let transaction = _.extend(tx, {chainId: args[0], gasPrice: args[1], nonce: args[2]})
+
+ transaction = helpers.formatters.inputCallFormatter(transaction)
+ transaction = coverInitialTxValue(transaction)
+
+ const rlpEncoded = encodeRLPByTxType(transaction)
+ let sig = transaction.signatures? transaction.signatures : [['0x01', '0x', '0x']]
+ let { rawTransaction } = makeRawTransaction(rlpEncoded, sig, transaction)
+
+ return _this.signTransaction({ senderRawTransaction: rawTransaction, feePayer }, privateKey, callback)
+ })
+}
+
+/**
+ * getRawTransactionWithSignatures returns object which contains rawTransaction.
+ *
+ * @method getRawTransactionWithSignatures
+ * @param {Object} tx The transaction object which contains signatures or feePayerSignatures.
+ * @param {Function} callback The callback function to call.
+ * @return {Object}
+ */
+Accounts.prototype.getRawTransactionWithSignatures = function getRawTransactionWithSignatures(tx, callback) {
var _this = this,
- error = false,
result
callback = callback || function () {}
- if (!tx) {
- error = new Error('No transaction object given!')
-
- callback(error)
- return Promise.reject(error)
+ let handleError = (e) => {
+ e = e instanceof Error? e : new Error(e)
+ if (callback) callback(e)
+ return Promise.reject(e)
}
- if (!tx.signature) {
- error = new Error('No tx signature given!')
+ if (!tx || !_.isObject(tx)) return handleError('Invalid parameter: The transaction must be defined as an object')
+ if (!tx.signatures && !tx.feePayerSignatures) return handleError('There are no signatures or feePayerSignatures defined in the transaction object.')
+
+ let error = helpers.validateFunction.validateParams(tx)
+ if (error) return handleError(error)
+
+ if (tx.senderRawTransaction) {
+ tx.feePayerSignatures = tx.feePayerSignatures || [['0x01', '0x', '0x']]
+
+ const decoded = decodeFromRawTransaction(tx.senderRawTransaction)
+ // feePayer !== '0x' means that in senderRawTransaction there are feePayerSignatures
+ if (decoded.feePayer !== '0x' && !utils.isEmptySig(decoded.feePayerSignatures)) {
+ if (decoded.feePayer.toLowerCase() !== tx.feePayer.toLowerCase()) return handleError('Invalid feePayer')
+ tx.feePayerSignatures = tx.feePayerSignatures.concat(decoded.feePayerSignatures)
+ }
+
+ decoded.feePayer = tx.feePayer
+ decoded.feePayerSignatures = tx.feePayerSignatures
- callback(error)
- return Promise.reject(error)
+ if (tx.signatures) decoded.signatures = decoded.signatures.concat(tx.signatures)
+ tx = decoded
}
function signed(tx) {
- if (!tx.senderRawTransaction) {
- error = helpers.validateFunction.validateParams(tx)
- }
- if (error) {
- callback(error)
- return Promise.reject(error)
- }
try {
// Guarantee all property in transaction is hex.
@@ -275,23 +846,24 @@ Accounts.prototype.signTransactionWithSignature = function signTransactionWithSi
const rlpEncoded = encodeRLPByTxType(transaction)
- const messageHash = Hash.keccak256(rlpEncoded)
+ let sigs = transaction.signatures? transaction.signatures : ['0x01', '0x', '0x']
- let sig
- if (_.isArray(transaction.signature)) {
- sig = transaction.signature.map((_sig) => utils.resolveSignature(_sig))
- } else {
- sig = utils.resolveSignature(transaction.signature)
- }
+ if (!_.isArray(sigs[0])) sigs = [sigs]
- const rawTransaction = makeRawTransaction(rlpEncoded, sig, transaction)
+ const { rawTransaction, signatures, feePayerSignatures } = makeRawTransaction(rlpEncoded, sigs, transaction)
result = {
- messageHash: messageHash,
- signature: sig,
- rawTransaction: rawTransaction,
- txHash: Hash.keccak256(rawTransaction),
- senderTxHash: getSenderTxHash(rawTransaction),
+ rawTransaction: rawTransaction,
+ txHash: Hash.keccak256(rawTransaction),
+ senderTxHash: getSenderTxHash(rawTransaction),
+ }
+
+ if (signatures && !utils.isEmptySig(signatures)) {
+ result.signatures = signatures
+ }
+
+ if (feePayerSignatures && !utils.isEmptySig(feePayerSignatures)) {
+ result.feePayerSignatures = feePayerSignatures
}
} catch(e) {
@@ -307,12 +879,11 @@ Accounts.prototype.signTransactionWithSignature = function signTransactionWithSi
return Promise.resolve(signed(tx));
}
-
// Otherwise, get the missing info from the Klaytn Node
return Promise.all([
isNot(tx.chainId) ? _this._klaytnCall.getChainId() : tx.chainId,
isNot(tx.gasPrice) ? _this._klaytnCall.getGasPrice() : tx.gasPrice,
- isNot(tx.nonce) ? _this._klaytnCall.getTransactionCount(tx.feePayer || tx.from) : tx.nonce
+ isNot(tx.nonce) ? _this._klaytnCall.getTransactionCount(tx.from) : tx.nonce
]).then(function (args) {
if (isNot(args[0]) || isNot(args[1]) || isNot(args[2])) {
throw new Error('One of the values "chainId", "gasPrice", or "nonce" couldn\'t be fetched: '+ JSON.stringify(args));
@@ -321,6 +892,86 @@ Accounts.prototype.signTransactionWithSignature = function signTransactionWithSi
});
};
+/**
+ * combineSignatures combines RLP encoded raw transaction strings.
+ * combineSignatures compares transaction before combining, and if values in field are not same, this throws error.
+ * The comparison allows that the address of the fee payer is '0x'(default value) for some transactions while the other transactions have a specific fee payer. This is for the use case that some transactions do not have the fee payer's information.
+ * In this case, feePayer field doesn't have to be compared with other transaction.
+ *
+ * @method combineSignatures
+ * @param {Array} rawTransactions The array of raw transaction string to combine.
+ * @param {Function} callback The callback function to call.
+ * @return {Object}
+ */
+Accounts.prototype.combineSignatures = function combineSignatures(rawTransactions, callback) {
+ let decodedTx
+ let senders = []
+ let feePayers = []
+ let feePayer
+
+ callback = callback || function () {}
+
+ let handleError = (e) => {
+ e = e instanceof Error? e : new Error(e)
+ if (callback) callback(e)
+ return Promise.reject(e)
+ }
+
+ if (!_.isArray(rawTransactions)) return handleError(`The parameter of the combineSignatures function must be an array of RLP encoded transaction strings.`)
+
+ for (const raw of rawTransactions) {
+ const { senderSignatures, feePayerSignatures, decodedTransaction } = extractSignatures(raw)
+
+ senders = senders.concat(senderSignatures)
+ feePayers = feePayers.concat(feePayerSignatures)
+
+ if (decodedTx) {
+ let isSame = true
+ const keys = Object.keys(decodedTx)
+ for (const key of keys) {
+ if (key === 'v' || key === 'r' || key === 's' || key === 'signatures' || key === 'payerV' || key === 'payerR' || key === 'payerS' || key === 'feePayerSignatures') {
+ continue
+ }
+
+ // feePayer field can be '0x' when after sender signs to trasnaction.
+ // For handling this, if feePayer is '0x', don't compare with other transaction
+ if (key === 'feePayer') {
+ if (decodedTransaction[key] === '0x') {
+ continue
+ } else {
+ // set feePayer variable with valid feePayer address(not '0x')
+ feePayer = decodedTransaction[key]
+ if (decodedTx[key] === '0x') {
+ // set feePayer field to decodedTx for comparing feePayer address with other transactions
+ decodedTx[key] = decodedTransaction[key]
+ }
+ }
+ }
+
+ if (decodedTransaction[key] === undefined || decodedTx[key] !== decodedTransaction[key]) {
+ isSame = false
+ break
+ }
+ }
+ if (!isSame) return handleError(`Failed to combineSignatures: Signatures that sign to different transaction cannot be combined.`)
+ } else {
+ decodedTx = decodedTransaction
+ }
+ }
+
+
+ const parsedTxObject = decodeFromRawTransaction(rawTransactions[0])
+ parsedTxObject.signatures = senders
+
+ if (feePayer) {
+ parsedTxObject.feePayer = feePayer
+ if (feePayers.length > 0) {
+ parsedTxObject.feePayerSignatures = feePayers
+ }
+ }
+ return this.getRawTransactionWithSignatures(parsedTxObject, callback)
+}
+
/**
* cav.klay.accounts.recoverTransaction('0xf86180808401ef364594f0109fc8df283027b6285cc889f5aa624eac1f5580801ca031573280d608f75137e33fc14655f097867d691d5c4c44ebe5ae186070ac3d5ea0524410802cdc025034daefcdfa08e7d2ee3f0b9d9ae184b2001fe0aff07603d9');
* > "0xF0109fC8DF283027b6285cc889F5aA624EaC1F55"
@@ -340,13 +991,13 @@ Accounts.prototype.recoverTransaction = function recoverTransaction(rawTx) {
})
arr.unshift(values[6])
- var signature = Account.encodeSignature(arr);
+ var signature = AccountLib.encodeSignature(arr);
var recovery = Bytes.toNumber(values[6]);
var extraData = recovery < 35 ? [] : [Bytes.fromNumber((recovery - 35) >> 1), "0x", "0x"];
var signingData = values.slice(0,6).concat(extraData);
var signingDataHex = RLP.encode(signingData);
- return Account.recover(Hash.keccak256(signingDataHex), signature);
+ return AccountLib.recover(Hash.keccak256(signingDataHex), signature);
};
/**
@@ -392,8 +1043,8 @@ Accounts.prototype.sign = function sign(data, privateKey) {
if (!utils.isValidPrivateKey(privateKey)) throw new Error('Invalid private key')
const messageHash = this.hashMessage(data)
- const signature = Account.sign(messageHash, privateKey)
- const [v, r, s] = Account.decodeSignature(signature)
+ const signature = AccountLib.sign(messageHash, privateKey)
+ const [v, r, s] = AccountLib.decodeSignature(signature)
return {
message: data,
messageHash,
@@ -416,7 +1067,7 @@ Accounts.prototype.recover = function recover(message, signature, preFixed) {
if (_.isObject(message)) {
return this.recover(
message.messageHash,
- Account.encodeSignature([message.v, message.r, message.s]),
+ AccountLib.encodeSignature([message.v, message.r, message.s]),
true,
)
}
@@ -429,21 +1080,21 @@ Accounts.prototype.recover = function recover(message, signature, preFixed) {
preFixed = args.slice(-1)[0];
preFixed = _.isBoolean(preFixed) ? !!preFixed : false;
- return this.recover(message, Account.encodeSignature(args.slice(1, 4)), preFixed); // v, r, s
+ return this.recover(message, AccountLib.encodeSignature(args.slice(1, 4)), preFixed); // v, r, s
}
/**
* recover in Account module
* const recover = (hash, signature) => {
* const vals = decodeSignature(signature);
* const vrs = { v: Bytes.toNumber(vals[0]), r: vals[1].slice(2), s: vals[2].slice(2) };
- * const ecPublicKey = secp256k1.recoverPubKey(new Buffer(hash.slice(2), "hex"), vrs, vrs.v < 2 ? vrs.v : 1 - vrs.v % 2); // because odd vals mean v=0... sadly that means v=0 means v=1... I hate that
- * const publicKey = "0x" + ecPublicKey.encode("hex", false).slice(2);
+ * const ecPublicKey = secp256k1.recoverPubKey(Buffer.from(hash.slice(2), 'hex'), vrs, vrs.v < 2 ? vrs.v : 1 - vrs.v % 2); // because odd vals mean v=0... sadly that means v=0 means v=1... I hate that
+ * const publicKey = "0x" + ecPublicKey.encode('hex', false).slice(2);
* const publicHash = keccak256(publicKey);
* const address = toChecksum("0x" + publicHash.slice(-40));
* return address;
* };
*/
- return Account.recover(message, signature);
+ return AccountLib.recover(message, signature);
};
// Taken from https://github.com/ethereumjs/ethereumjs-wallet
@@ -454,47 +1105,86 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) {
var json = (_.isObject(v3Keystore)) ? v3Keystore : JSON.parse(nonStrict ? v3Keystore.toLowerCase() : v3Keystore);
- if (json.version !== 3) {
- console.warn('This is not a V3 wallet.')
+ if (json.version !== 3 && json.version !== 4) {
+ console.warn('This is not a V3 or V4 wallet.')
// throw new Error('Not a valid V3 wallet');
}
- var derivedKey;
- var kdfparams;
- /**
- * Supported kdf modules are the following:
- * 1) pbkdf2
- * 2) scrypt
- */
- if (json.crypto.kdf === 'scrypt') {
- kdfparams = json.crypto.kdfparams;
+ if (json.version === 3 && !json.crypto) {
+ // crypto field should be existed in keystore version 3
+ throw new Error(`Invalid keystore V3 format: 'crypto' is not defined.`)
+ }
- // FIXME: support progress reporting callback
- derivedKey = scryptsy(new Buffer(password), new Buffer(kdfparams.salt, 'hex'), kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen);
- } else if (json.crypto.kdf === 'pbkdf2') {
- kdfparams = json.crypto.kdfparams;
+ if (json.crypto) {
+ if (json.keyring) throw new Error(`Invalid key store format: 'crypto' can not be with 'keyring'`)
+ json.keyring = [json.crypto]
+ delete json.crypto
+ }
- if (kdfparams.prf !== 'hmac-sha256') {
- throw new Error('Unsupported parameters to PBKDF2');
- }
+ if (_.isArray(json.keyring[0]) && json.keyring.length > 3) {
+ throw new Error(`Invalid key store format`)
+ }
+
+ let accountKey = {}
+
+ // AccountKeyRoleBased format
+ if (_.isArray(json.keyring[0])) {
+ let transactionKey = decryptKey(json.keyring[0])
+ if (transactionKey) accountKey.transactionKey = transactionKey
+
+ let updateKey = decryptKey(json.keyring[1])
+ if (updateKey) accountKey.updateKey = updateKey
- derivedKey = cryp.pbkdf2Sync(new Buffer(password), new Buffer(kdfparams.salt, 'hex'), kdfparams.c, kdfparams.dklen, 'sha256');
+ let feePayerKey = decryptKey(json.keyring[2])
+ if (feePayerKey) accountKey.feePayerKey = feePayerKey
} else {
- throw new Error('Unsupported key derivation scheme');
+ accountKey = decryptKey(json.keyring)
}
- var ciphertext = new Buffer(json.crypto.ciphertext, 'hex');
+ function decryptKey(encryptedArray) {
+ if (!encryptedArray || encryptedArray.length === 0) return undefined
+
+ let decryptedArray = []
+ for (const encrypted of encryptedArray) {
+ var derivedKey
+ var kdfparams
+ /**
+ * Supported kdf modules are the following:
+ * 1) pbkdf2
+ * 2) scrypt
+ */
+ if (encrypted.kdf === 'scrypt') {
+ kdfparams = encrypted.kdfparams;
+
+ // FIXME: support progress reporting callback
+ derivedKey = scrypt(Buffer.from(password), Buffer.from(kdfparams.salt, 'hex'), kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen);
+ } else if (encrypted.kdf === 'pbkdf2') {
+ kdfparams = encrypted.kdfparams;
+
+ if (kdfparams.prf !== 'hmac-sha256') {
+ throw new Error('Unsupported parameters to PBKDF2');
+ }
+
+ derivedKey = cryp.pbkdf2Sync(Buffer.from(password), Buffer.from(kdfparams.salt, 'hex'), kdfparams.c, kdfparams.dklen, 'sha256');
+ } else {
+ throw new Error('Unsupported key derivation scheme');
+ }
- var mac = utils.sha3(Buffer.concat([ derivedKey.slice(16, 32), ciphertext ])).replace('0x','');
- if (mac !== json.crypto.mac) {
- throw new Error('Key derivation failed - possibly wrong password');
- }
+ var ciphertext = Buffer.from(encrypted.ciphertext, 'hex');
- var decipher = cryp.createDecipheriv(json.crypto.cipher, derivedKey.slice(0, 16), new Buffer(json.crypto.cipherparams.iv, 'hex'));
- var seed = '0x'+ Buffer.concat([ decipher.update(ciphertext), decipher.final() ]).toString('hex');
+ var mac = utils.sha3(Buffer.concat([ derivedKey.slice(16, 32), ciphertext ])).replace('0x','');
+ if (mac !== encrypted.mac) {
+ throw new Error('Key derivation failed - possibly wrong password');
+ }
- return this.privateKeyToAccount(seed, json.address);
-};
+ var decipher = cryp.createDecipheriv(encrypted.cipher, derivedKey.slice(0, 16), Buffer.from(encrypted.cipherparams.iv, 'hex'));
+ decryptedArray.push('0x'+ Buffer.concat([ decipher.update(ciphertext), decipher.final() ]).toString('hex'))
+ }
+ return decryptedArray.length === 1? decryptedArray[0] : decryptedArray
+ }
+
+ return this.createWithAccountKey(json.address, accountKey);
+ };
/**
* cav.klay.accounts.encrypt(privateKey, password);
@@ -544,7 +1234,16 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) {
"id":"dfde6a32-4b0e-404f-8b9f-2b18f279fe21",
}
*/
-Accounts.prototype.encrypt = function (privateKey, password, options) {
+/**
+ * encrypt encrypts an account and returns a key store object.
+ *
+ * @method privateKeyToAccount
+ * @param {String} key The key parameter can be either normal private key or KlaytnWalletKey format.
+ * @param {String} password The password to be used for account encryption. The encrypted key store can be decrypted with this password.
+ * @param {Object} options The options to use when encrypt an account.
+ * @return {Object}
+ */
+Accounts.prototype.encrypt = function (key, password, options) {
/**
* options can include below
* {
@@ -563,60 +1262,110 @@ Accounts.prototype.encrypt = function (privateKey, password, options) {
*/
options = options || {};
- var account = this.privateKeyToAccount(privateKey, options.address);
-
- var salt = options.salt || cryp.randomBytes(32);
- var iv = options.iv || cryp.randomBytes(16);
+ let address, account
- var derivedKey;
- var kdf = options.kdf || 'scrypt';
- var kdfparams = {
- dklen: options.dklen || 32,
- salt: salt.toString('hex')
- };
-
- /**
- * Supported kdf modules are the following:
- * 1) pbkdf2
- * 2) scrypt - default
- */
- if (kdf === 'pbkdf2') {
- kdfparams.c = options.c || 262144;
- kdfparams.prf = 'hmac-sha256';
- derivedKey = cryp.pbkdf2Sync(new Buffer(password), salt, kdfparams.c, kdfparams.dklen, 'sha256');
- } else if (kdf === 'scrypt') {
- // FIXME: support progress reporting callback
- kdfparams.n = options.n || 4096; // 2048 4096 8192 16384
- kdfparams.r = options.r || 8;
- kdfparams.p = options.p || 1;
- derivedKey = scryptsy(new Buffer(password), salt, kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen);
+ if (key instanceof Account) {
+ if (options.address && options.address !== key.address) throw new Error(`Address in account is not matched with address in options object`)
+ address = key.address
+ account = key
+ } else if (_.isString(key)) {
+ account = this.privateKeyToAccount(key, options.address)
+ address = account.address
} else {
- throw new Error('Unsupported kdf');
+ if (!options.address) throw new Error(`The address must be defined inside the options object.`)
+ address = options.address
}
- var cipher = cryp.createCipheriv(options.cipher || 'aes-128-ctr', derivedKey.slice(0, 16), iv);
- if (!cipher) {
- throw new Error('Unsupported cipher');
+ if (!account) account = this.createWithAccountKey(address, key)
+
+ let keyring
+
+ switch(account.accountKeyType) {
+ case AccountKeyEnum.ACCOUNT_KEY_PUBLIC:
+ case AccountKeyEnum.ACCOUNT_KEY_MULTISIG:
+ keyring = encryptKey(account.keys)
+ break
+ case AccountKeyEnum.ACCOUNT_KEY_ROLEBASED:
+ keyring = []
+ let transactionKey = encryptKey(account.transactionKey)
+ let updateKey = encryptKey(account.updateKey)
+ let feePayerKey = encryptKey(account.feePayerKey)
+ keyring.push(transactionKey)
+ keyring.push(updateKey)
+ keyring.push(feePayerKey)
+ for (i = keyring.length-1; i >=0; i --) {
+ if (keyring[i].length !== 0) break
+ keyring = keyring.slice(0, i)
+ }
+ break
}
- var ciphertext = Buffer.concat([ cipher.update(new Buffer(account.privateKey.replace('0x',''), 'hex')), cipher.final() ]);
+ function encryptKey(privateKey) {
+ let encryptedArray = []
+
+ if (!privateKey) return encryptedArray
+
+ let privateKeyArray = _.isArray(privateKey)? privateKey : [privateKey]
+
+ for (const privateKey of privateKeyArray) {
+ var salt = options.salt || cryp.randomBytes(32);
+ var iv = options.iv || cryp.randomBytes(16);
+
+ var derivedKey;
+ var kdf = options.kdf || 'scrypt';
+ var kdfparams = {
+ dklen: options.dklen || 32,
+ salt: salt.toString('hex')
+ };
+
+ /**
+ * Supported kdf modules are the following:
+ * 1) pbkdf2
+ * 2) scrypt - default
+ */
+ if (kdf === 'pbkdf2') {
+ kdfparams.c = options.c || 262144;
+ kdfparams.prf = 'hmac-sha256';
+ derivedKey = cryp.pbkdf2Sync(Buffer.from(password), salt, kdfparams.c, kdfparams.dklen, 'sha256');
+ } else if (kdf === 'scrypt') {
+ // FIXME: support progress reporting callback
+ kdfparams.n = options.n || 4096; // 2048 4096 8192 16384
+ kdfparams.r = options.r || 8;
+ kdfparams.p = options.p || 1;
+ derivedKey = scrypt(Buffer.from(password), salt, kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen);
+ } else {
+ throw new Error('Unsupported kdf');
+ }
+
+ var cipher = cryp.createCipheriv(options.cipher || 'aes-128-ctr', derivedKey.slice(0, 16), iv);
+ if (!cipher) {
+ throw new Error('Unsupported cipher');
+ }
+
+ var ciphertext = Buffer.concat([cipher.update(Buffer.from(privateKey.replace('0x',''), 'hex')), cipher.final()]);
+
+ var mac = utils.sha3(Buffer.concat([derivedKey.slice(16, 32), Buffer.from(ciphertext, 'hex')])).replace('0x','');
+
+ encryptedArray.push({
+ ciphertext: ciphertext.toString('hex'),
+ cipherparams: {
+ iv: iv.toString('hex')
+ },
+ cipher: options.cipher || 'aes-128-ctr',
+ kdf: kdf,
+ kdfparams: kdfparams,
+ mac: mac.toString('hex')
+ })
+ }
- var mac = utils.sha3(Buffer.concat([ derivedKey.slice(16, 32), new Buffer(ciphertext, 'hex') ])).replace('0x','');
+ return encryptedArray
+ }
return {
- version: 3,
+ version: 4,
id: uuid.v4({ random: options.uuid || cryp.randomBytes(16) }),
address: account.address.toLowerCase(),
- crypto: {
- ciphertext: ciphertext.toString('hex'),
- cipherparams: {
- iv: iv.toString('hex')
- },
- cipher: options.cipher || 'aes-128-ctr',
- kdf: kdf,
- kdfparams: kdfparams,
- mac: mac.toString('hex')
- }
+ keyring
};
};
@@ -628,7 +1377,7 @@ Accounts.prototype.privateKeyToPublicKey = function (privateKey, compressed = fa
if (privateKey.length !== 64) {
throw new Error('Received a invalid privateKey. The length of privateKey should be 64.')
}
- const buffer = new Buffer(privateKey, "hex");
+ const buffer = Buffer.from(privateKey, 'hex');
const ecKey = secp256k1.keyFromPrivate(buffer)
let publicKey
@@ -727,43 +1476,47 @@ Wallet.prototype.create = function (numberOfAccounts, entropy) {
encrypt: function(password){...}
}
*/
-Wallet.prototype.add = function (account, targetAddressRaw) {
- var klaytnWalletKey
- /**
- * cav.klay.accounts.wallet.add('0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318');
- *
- * cav.klay.accounts.wallet.add({
- * privateKey: '0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709',
- * address: '0xb8CE9ab6943e0eCED004cDe8e3bBed6568B2Fa01'
- * });
- */
- if (_.isString(account)) {
- account = this._accounts.privateKeyToAccount(account, targetAddressRaw);
- } else if(!_.isObject(account)) {
- throw new Error('Invalid private key')
- }
-
- const accountAlreadyExists = !!this[account.address]
-
- if (accountAlreadyExists) {
- throw new Error('Account exists with ' + account.address)
- }
+Wallet.prototype.add = function (account, userInputAddress) {
+ let accountForWallet
+ /**
+ * cav.klay.accounts.wallet.add('0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318');
+ *
+ * cav.klay.accounts.wallet.add({
+ * privateKey: '0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709',
+ * address: '0xb8CE9ab6943e0eCED004cDe8e3bBed6568B2Fa01'
+ * });
+ */
+ if (Account.isAccountKey(account)) {
+ if (!userInputAddress) throw new Error(`Address is not defined. Address cannot be determined from AccountKey`)
+ accountForWallet = this._accounts.createWithAccountKey(userInputAddress, account)
+ } else if(account instanceof Account) {
+ accountForWallet = this._accounts.createWithAccountKey(account.address, account.accountKey)
+ accountForWallet.address = userInputAddress || account.address
+ } else if (_.isObject(account) && account.address && account.privateKey) {
+ accountForWallet = this._accounts.privateKeyToAccount(account.privateKey, userInputAddress || account.address)
+ } else if (_.isString(account)) {
+ accountForWallet = this._accounts.privateKeyToAccount(account, userInputAddress);
+ } else {
+ const accountKey = this._accounts.createAccountKey(account)
+ if (!userInputAddress) throw new Error(`Address is not defined. Address cannot be determined from AccountKey format`)
+ accountForWallet = this._accounts.createWithAccountKey(userInputAddress, accountKey)
+ }
- account = this._accounts.privateKeyToAccount(account.privateKey, targetAddressRaw || account.address)
+ if (!!this[accountForWallet.address]) throw new Error('Account exists with ' + accountForWallet.address)
- account.index = this._findSafeIndex()
- this[account.index] = account
+ accountForWallet.index = this._findSafeIndex()
+ this[accountForWallet.index] = accountForWallet
- this[account.address] = account
- this[account.address.toLowerCase()] = account
- this[account.address.toUpperCase()] = account
- try {
- this[utils.toChecksumAddress(account.address)] = account
- } catch (e) {}
+ this[accountForWallet.address] = accountForWallet
+ this[accountForWallet.address.toLowerCase()] = accountForWallet
+ this[accountForWallet.address.toUpperCase()] = accountForWallet
+ try {
+ this[utils.toChecksumAddress(accountForWallet.address)] = accountForWallet
+ } catch (e) {}
- this.length++
+ this.length++
- return account
+ return accountForWallet
}
Wallet.prototype.updatePrivateKey = function (privateKey, address) {
@@ -776,64 +1529,103 @@ Wallet.prototype.updatePrivateKey = function (privateKey, address) {
throw new Error('The private key used for the update is not a valid string.')
}
+ if (!utils.isAddress(address)) throw new Error(`Invalid address : ${address}`)
+
// If failed to find account through address, return error
const accountExists = !!this[address]
if (!accountExists) throw new Error('Failed to find account with ' + address)
const account = this[address]
+ if (account.accountKeyType !== AccountKeyEnum.ACCOUNT_KEY_PUBLIC) {
+ throw new Error('Account using AccountKeyMultiSig or AccountKeyRoleBased must be updated using the caver.klay.accounts.updateAccountKey function.')
+ }
+
const parsed = utils.parsePrivateKey(privateKey)
if (!utils.isValidPrivateKey(parsed.privateKey)) throw new Error('Invalid private key')
- if (parsed.address && parsed.address !== account.address) throw new Error('The address extracted from the private key does not match the address received as the input value.')
- this[account.index].privateKey = parsed.privateKey
+ if (parsed.address && parsed.address !== account.address) {
+ throw new Error('The address extracted from the private key does not match the address received as the input value.')
+ }
+
+ const newAccountKeyPublic = new AccountKeyPublic(parsed.privateKey)
+ this[account.index].accountKey = newAccountKeyPublic
+ this[account.address].accountKey = newAccountKeyPublic
+ this[account.address.toLowerCase()].accountKey = newAccountKeyPublic
+ this[account.address.toUpperCase()].accountKey = newAccountKeyPublic
- this[account.address].privateKey = parsed.privateKey
- this[account.address.toLowerCase()].privateKey = parsed.privateKey
- this[account.address.toUpperCase()].privateKey = parsed.privateKey
try {
- this[utils.toChecksumAddress(account.address)].privateKey = parsed.privateKey
+ this[utils.toChecksumAddress(account.address)].accountKey = newAccountKeyPublic
} catch (e) {}
return account
}
- Wallet.prototype.remove = function (addressOrIndex) {
- var account = this[addressOrIndex]
+Wallet.prototype.updateAccountKey = function updateAccountKey(address, accountKey) {
+ if (address === undefined || accountKey === undefined) {
+ throw new Error('To update the accountKey in wallet, need to set both address and accountKey.')
+ }
- if (account && account.address) {
- // address
- this[account.address].privateKey = null
- delete this[account.address]
+ if (!Account.isAccountKey(accountKey)) {
+ accountKey = this._accounts.createAccountKey(accountKey)
+ }
- if (this[account.address.toLowerCase()]) {
- // address lowercase
- this[account.address.toLowerCase()].privateKey = null
- delete this[account.address.toLowerCase()]
- }
+ if (!utils.isAddress(address)) throw new Error(`Invalid address : ${address}`)
- if (this[account.address.toUpperCase()]) {
- // address uppercase
- this[account.address.toUpperCase()].privateKey = null
- delete this[account.address.toUpperCase()]
- }
+ // If failed to find account through address, return error
+ const accountExists = !!this[address]
+ if (!accountExists) throw new Error('Failed to find account with ' + address)
+
+ const account = this[address]
- try {
- this[utils.toChecksumAddress(account.address)].privateKey = null
- delete this[utils.toChecksumAddress(account.address)]
- } catch (e) {}
+ this[account.index].accountKey = accountKey
+ this[account.address].accountKey = accountKey
+ this[account.address.toLowerCase()].accountKey = accountKey
+ this[account.address.toUpperCase()].accountKey = accountKey
- // index
- this[account.index].privateKey = null
- delete this[account.index]
+ try {
+ this[utils.toChecksumAddress(account.address)].accountKey = accountKey
+ } catch (e) {}
- this.length--
+ return account
+}
+
+Wallet.prototype.remove = function (addressOrIndex) {
+ var account = this[addressOrIndex]
+
+ if (account && account.address) {
+ // address
+ this[account.address].accountKey = null
+ delete this[account.address]
+
+ if (this[account.address.toLowerCase()]) {
+ // address lowercase
+ this[account.address.toLowerCase()].accountKey = null
+ delete this[account.address.toLowerCase()]
+ }
- return true
- } else {
- return false
+ if (this[account.address.toUpperCase()]) {
+ // address uppercase
+ this[account.address.toUpperCase()].accountKey = null
+ delete this[account.address.toUpperCase()]
}
+
+ try {
+ this[utils.toChecksumAddress(account.address)].accountKey = null
+ delete this[utils.toChecksumAddress(account.address)]
+ } catch (e) {}
+
+ // index
+ this[account.index].accountKey = null
+ delete this[account.index]
+
+ this.length--
+
+ return true
+ } else {
+ return false
}
+}
Wallet.prototype.clear = function () {
var _this = this;
@@ -983,6 +1775,19 @@ Wallet.prototype.getKlaytnWalletKey = function (addressOrIndex) {
return genKlaytnWalletKeyStringFromAccount(account)
}
+Wallet.prototype.getAccount = function (input) {
+ if (_.isNumber(input)) {
+ if (this.length <= input) throw new Error(`The index(${input}) is out of range(Wallet length : ${this.length}).`)
+ return this[input]
+ }
+
+ if (!_.isString(input)) throw new Error(`Accounts in the Wallet can be searched by only index or address. :${input}`)
+
+ if (!utils.isAddress(input)) throw new Error(`Failed to getAccount from Wallet: invalid address(${input})`)
+
+ return this[input.toLowerCase()]
+}
+
function genKlaytnWalletKeyStringFromAccount(account) {
var addressString = account.address
var privateKey = account.privateKey
diff --git a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js
index 1e019c9c..7407c0e8 100644
--- a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js
+++ b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js
@@ -138,14 +138,17 @@ function makeRawTransaction(rlpEncoded, sig, transaction) {
case 'FEE_DELEGATED_VALUE_TRANSFER_MEMO_WITH_RATIO': {
if (transaction.senderRawTransaction) {
const decoded = decodeFromRawTransaction(transaction.senderRawTransaction)
- return _combineFeePayerRawTransaction(rlpEncoded, sig, transaction, [decoded.v, decoded.r, decoded.s])
+ return _combineFeePayerRawTransaction(rlpEncoded, sig, transaction, decoded.signatures)
+ }
+ if (transaction.feePayer && transaction.feePayer !== '0x' && transaction.feePayerSignatures) {
+ return _combineFeePayerRawTransaction(rlpEncoded, transaction.feePayerSignatures, transaction, sig)
}
return _combineSenderRawTransaction(rlpEncoded, sig)
}
case 'LEGACY':
default:
- rawTx = decodedValues.slice(0, 6).concat(sig)
- return RLP.encode(rawTx)
+ rawTx = decodedValues.slice(0, 6).concat(sig[0])
+ return { rawTransaction: RLP.encode(rawTx), signatures: sig[0], feePayerSignatures: undefined }
}
}
@@ -155,27 +158,93 @@ function _combineSenderRawTransaction(rlpEncoded, sig) {
let [data] = decodedValues
let [txType, ...rawTx] = RLP.decode(data)
- rawTx = [...rawTx, [sig]]
+ if (!Array.isArray(sig[0])) sig = [sig]
+ sig = refineSignatures(sig)
+
+ rawTx = [...rawTx, sig]
// set default feepayer's information in rawTx
const typeString = utils.getTxTypeStringFromRawTransaction(txType)
if (typeString !== undefined && typeString.includes('FEE_DELEGATED')) rawTx = [...rawTx, '0x', [['0x01', '0x', '0x']]]
- return txType + RLP.encode(rawTx).slice(2)
+ return { rawTransaction: txType + RLP.encode(rawTx).slice(2), signatures: sig, feePayerSignatures: undefined }
}
-function _combineFeePayerRawTransaction(rlpEncoded, sig, transaction, [senderV, senderR, senderS]) {
+function _combineFeePayerRawTransaction(rlpEncoded, feePayerSignatures, transaction, senderSignature) {
const decodedValues = RLP.decode(rlpEncoded)
let [data] = decodedValues
let [txType, ...rawTx] = RLP.decode(data)
- rawTx = [...rawTx, [[senderV, senderR, senderS]], transaction.feePayer.toLowerCase(), [sig]]
+ if (!Array.isArray(feePayerSignatures[0])) feePayerSignatures = [feePayerSignatures]
+ senderSignature = refineSignatures(senderSignature)
+ feePayerSignatures = refineSignatures(feePayerSignatures)
- return txType + RLP.encode(rawTx).slice(2)
+ rawTx = [...rawTx, senderSignature, transaction.feePayer.toLowerCase(), feePayerSignatures]
+
+ return { rawTransaction: txType + RLP.encode(rawTx).slice(2), signatures: senderSignature, feePayerSignatures }
+}
+
+// refineSignatures removes duplication and empty signatures
+function refineSignatures(sigArray) {
+ const set = new Set()
+ let result = []
+ for (const sig of sigArray) {
+ if (sig.length === 0 || utils.isEmptySig(sig)) continue
+
+ const sigString = sig.join('')
+ if (!set.has(sigString)) {
+ set.add(sigString, true)
+ result.push(sig)
+ }
+ }
+
+ if (result.length === 0) result = [['0x01', '0x', '0x']]
+
+ return result
+}
+
+function extractSignatures(rawTransaction) {
+ let senderSignatures = []
+ let feePayerSignatures = []
+
+ const decoded = _decodeFromRawTransaction(rawTransaction)
+ senderSignatures = senderSignatures.concat(decoded.signatures)
+ if (decoded.feePayerSignatures) {
+ feePayerSignatures = feePayerSignatures.concat(decoded.feePayerSignatures)
+ }
+ return { senderSignatures, feePayerSignatures, decodedTransaction: decoded }
+}
+
+function splitFeePayer(rawTransaction) {
+ const typeString = utils.getTxTypeStringFromRawTransaction(rawTransaction)
+
+ if (!typeString || !typeString.includes('FEE_DELEGATED')) throw new Error(`Failed to split fee payer: not a fee delegated transaction type('${typeString? typeString : 'LEGACY'}')`)
+
+ const txType = rawTransaction.slice(0, 4)
+ const decodedValues = RLP.decode(utils.addHexPrefix(rawTransaction.slice(4)))
+
+ const detachFeePayer = decodedValues.splice(0, decodedValues.length-2)
+ detachFeePayer.push('0x')
+ detachFeePayer.push([['0x01', '0x', '0x']])
+
+ return { senderRawTransaction: txType + RLP.encode(detachFeePayer).slice(2), feePayer: decodedValues[0], feePayerSignatures: decodedValues[1] }
}
function decodeFromRawTransaction (rawTransaction, type) {
+ let decodeResult = _decodeFromRawTransaction(rawTransaction, type)
+
+ switch(decodeResult.type) {
+ case 'ACCOUNT_UPDATE':
+ case 'FEE_DELEGATED_ACCOUNT_UPDATE':
+ case 'FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO': {
+ decodeResult = parseAccountKey(decodeResult)
+ }
+ }
+ return decodeResult
+}
+
+function _decodeFromRawTransaction(rawTransaction, type) {
var typeString = type
if (typeString === undefined || typeString !== 'LEGACY') {
typeString = utils.getTxTypeStringFromRawTransaction(rawTransaction)
@@ -189,86 +258,86 @@ function decodeFromRawTransaction (rawTransaction, type) {
switch(typeString) {
case 'LEGACY': {
const [ nonce, gasPrice, gas, to, value, data, v, r, s ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, data, v, r, s }
+ return { type: typeString, nonce, gasPrice, gas, to, value, data, v, r, s, signatures: [v, r, s] }
}
case 'VALUE_TRANSFER': {
- const [ nonce, gasPrice, gas, to, value, from, [ [ v, r, s ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, v, r, s }
+ const [ nonce, gasPrice, gas, to, value, from, signatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures }
}
case 'FEE_DELEGATED_VALUE_TRANSFER': {
- const [ nonce, gasPrice, gas, to, value, from, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, v, r, s, feePayer, payerV, payerR, payerS }
+ const [ nonce, gasPrice, gas, to, value, from, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'FEE_DELEGATED_VALUE_TRANSFER_WITH_RATIO': {
- const [ nonce, gasPrice, gas, to, value, from, feeRatio, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, feeRatio, v, r, s, feePayer, payerV, payerR, payerS }
+ const [ nonce, gasPrice, gas, to, value, from, feeRatio, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, feeRatio, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'VALUE_TRANSFER_MEMO': {
- const [ nonce, gasPrice, gas, to, value, from, data, [ [ v, r, s ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v, r, s }
+ const [ nonce, gasPrice, gas, to, value, from, data, signatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures }
}
case 'FEE_DELEGATED_VALUE_TRANSFER_MEMO': {
- const [ nonce, gasPrice, gas, to, value, from, data, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v, r, s, feePayer, payerV, payerR, payerS }
+ const [ nonce, gasPrice, gas, to, value, from, data, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'FEE_DELEGATED_VALUE_TRANSFER_MEMO_WITH_RATIO': {
- const [ nonce, gasPrice, gas, to, value, from, data, feeRatio, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, data, feeRatio, v, r, s, feePayer, payerV, payerR, payerS }
+ const [ nonce, gasPrice, gas, to, value, from, data, feeRatio, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, data, feeRatio, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'ACCOUNT_CREATION': {
throw new Error(creationNotSupportError)
}
case 'ACCOUNT_UPDATE': {
- const [ nonce, gasPrice, gas, from, accountKey, [ [ v, r, s ] ] ] = RLP.decode(rawTransaction)
- return parseAccountKey({ type: typeString, nonce, gasPrice, gas, from, accountKey, v, r, s })
+ const [ nonce, gasPrice, gas, from, accountKey, signatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, from, accountKey, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures }
}
case 'FEE_DELEGATED_ACCOUNT_UPDATE': {
- const [ nonce, gasPrice, gas, from, accountKey, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return parseAccountKey({ type: typeString, nonce, gasPrice, gas, from, accountKey, v, r, s, feePayer, payerV, payerR, payerS })
+ const [ nonce, gasPrice, gas, from, accountKey, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, from, accountKey, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO': {
- const [ nonce, gasPrice, gas, from, accountKey, feeRatio, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return parseAccountKey({ type: typeString, nonce, gasPrice, gas, from, accountKey, feeRatio, v, r, s, feePayer, payerV, payerR, payerS })
+ const [ nonce, gasPrice, gas, from, accountKey, feeRatio, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, from, accountKey, feeRatio, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'SMART_CONTRACT_DEPLOY': {
- const [ nonce, gasPrice, gas, to, value, from, data, humanReadable, codeFormat, [ [ v, r, s ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, codeFormat, v, r, s }
+ const [ nonce, gasPrice, gas, to, value, from, data, humanReadable, codeFormat, signatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, codeFormat, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures }
}
case 'FEE_DELEGATED_SMART_CONTRACT_DEPLOY': {
- const [ nonce, gasPrice, gas, to, value, from, data, humanReadable, codeFormat, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, codeFormat, v, r, s, feePayer, payerV, payerR, payerS }
+ const [ nonce, gasPrice, gas, to, value, from, data, humanReadable, codeFormat, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, codeFormat, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'FEE_DELEGATED_SMART_CONTRACT_DEPLOY_WITH_RATIO': {
- const [ nonce, gasPrice, gas, to, value, from, data, humanReadable, feeRatio, codeFormat, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, feeRatio, codeFormat, v, r, s, feePayer, payerV, payerR, payerS }
+ const [ nonce, gasPrice, gas, to, value, from, data, humanReadable, feeRatio, codeFormat, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, feeRatio, codeFormat, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'SMART_CONTRACT_EXECUTION': {
- const [ nonce, gasPrice, gas, to, value, from, data, [ [ v, r, s ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v, r, s }
+ const [ nonce, gasPrice, gas, to, value, from, data, signatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures }
}
case 'FEE_DELEGATED_SMART_CONTRACT_EXECUTION': {
- const [ nonce, gasPrice, gas, to, value, from, data, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v, r, s, feePayer, payerV, payerR, payerS }
+ const [ nonce, gasPrice, gas, to, value, from, data, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'FEE_DELEGATED_SMART_CONTRACT_EXECUTION_WITH_RATIO': {
- const [ nonce, gasPrice, gas, to, value, from, data, feeRatio, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, data, feeRatio, v, r, s, feePayer, payerV, payerR, payerS }
+ const [ nonce, gasPrice, gas, to, value, from, data, feeRatio, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, data, feeRatio, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'CANCEL': {
- const [ nonce, gasPrice, gas, from, [ [ v, r, s ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, from, v, r, s }
+ const [ nonce, gasPrice, gas, from, signatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, from, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures }
}
case 'FEE_DELEGATED_CANCEL': {
- const [ nonce, gasPrice, gas, from, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, from, v, r, s, feePayer, payerV, payerR, payerS }
+ const [ nonce, gasPrice, gas, from, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, from, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'FEE_DELEGATED_CANCEL_WITH_RATIO': {
- const [ nonce, gasPrice, gas, from, feeRatio, [ [ v, r, s ] ], feePayer, [ [ payerV, payerR, payerS ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, from, feeRatio, v, r, s, feePayer, payerV, payerR, payerS }
+ const [ nonce, gasPrice, gas, from, feeRatio, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, from, feeRatio, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures, feePayer, payerV: feePayerSignatures[0][0], payerR: feePayerSignatures[0][1], payerS: feePayerSignatures[0][2], feePayerSignatures }
}
case 'CHAIN_DATA_ANCHORING': {
- const [ nonce, gasPrice, gas, to, value, from, data, [ [ v, r, s ] ] ] = RLP.decode(rawTransaction)
- return { type: typeString, nonce, gasPrice, gas, to, value, from, anchoredData:data, v, r, s }
+ const [ nonce, gasPrice, gas, to, value, from, data, signatures ] = RLP.decode(rawTransaction)
+ return { type: typeString, nonce, gasPrice, gas, to, value, from, anchoredData:data, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures }
}
}
}
@@ -319,4 +388,6 @@ module.exports = {
decodeFromRawTransaction,
overwriteSignature,
getSenderTxHash,
-}
\ No newline at end of file
+ splitFeePayer,
+ extractSignatures,
+}
diff --git a/packages/caver-klay/caver-klay-accounts/src/scrypt.js b/packages/caver-klay/caver-klay-accounts/src/scrypt.js
new file mode 100644
index 00000000..291685b0
--- /dev/null
+++ b/packages/caver-klay/caver-klay-accounts/src/scrypt.js
@@ -0,0 +1,92 @@
+/*
+ Modifications copyright 2019 The caver-js Authors
+ This file is part of web3.js.
+
+ web3.js is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ web3.js is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with web3.js. If not, see .
+
+ This file is derived from web3.js/packages/web3-eth-accounts/src/scrpyt.js (2019/09/03).
+ Modified and improved for the caver-js development.
+*/
+
+var scryptsy = require('scryptsy');
+
+var scrypt;
+
+var isNode = Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]';
+if (isNode) {
+ var NODE_MIN_VER_WITH_BUILTIN_SCRYPT = '10.5.0';
+ var NODE_MIN_VER_INCOMPAT_SCRYPT_PKG = '12.0.0';
+ var semver = require('semver');
+ var useNodeBuiltin = isNode && semver.Range('>=' + NODE_MIN_VER_WITH_BUILTIN_SCRYPT).test(process.version);
+
+ var tryScryptPkg = (function() {
+ var scryptPkg;
+ return function() {
+ if (scryptPkg !== undefined) { return scryptPkg; }
+ try {
+ scryptPkg = (function(m) { return require(m); })('scrypt');
+ } catch (e) {
+ if (/was compiled against a different/.test(e.message)) {
+ throw e;
+ }
+ scryptPkg = null;
+ }
+ return scryptPkg;
+ };
+ })();
+
+ var canImprove = function(nodeVer) {
+ return 'can improve web3\'s peformance when running Node.js versions older than ' + nodeVer + ' by installing the (deprecated) scrypt package in your project';
+ };
+
+ if (useNodeBuiltin) {
+ var crypto = require('crypto');
+ var fallbackCount = 0;
+ scrypt = function(key, salt, N, r, p, dkLen) {
+ try {
+ return crypto.scryptSync(key, salt, dkLen, {N: N, r: r, p: p});
+ } catch (e) {
+ if (/scrypt:memory limit exceeded/.test(e.message)) {
+ var scryptPkg = tryScryptPkg();
+ if (scryptPkg) {
+ return scryptPkg.hashSync(key, {N: N, r: r, p: p}, dkLen, salt);
+ }
+ fallbackCount += 1;
+ console.warn(
+ '\x1b[33m%s\x1b[0m',
+ 'Memory limit exceeded for Node\'s built-in crypto.scrypt, falling back to scryptsy (times: ' + fallbackCount + '), if this happens frequently you ' + canImprove(NODE_MIN_VER_INCOMPAT_SCRYPT_PKG)
+ );
+ return scryptsy(key, salt, N, r, p, dkLen);
+ }
+ throw e;
+ }
+ };
+ } else {
+ var scryptPkg = tryScryptPkg();
+ if (scryptPkg) {
+ scrypt = function(key, salt, N, r, p, dkLen) {
+ return scryptPkg.hashSync(key, {N: N, r: r, p: p}, dkLen, salt);
+ };
+ } else {
+ console.warn(
+ '\x1b[33m%s\x1b[0m',
+ 'You ' + canImprove(NODE_MIN_VER_WITH_BUILTIN_SCRYPT)
+ );
+ }
+ }
+}
+
+scrypt = scrypt || scryptsy;
+
+module.exports = scrypt;
diff --git a/packages/caver-klay/caver-klay-accounts/src/transactionType/account.js b/packages/caver-klay/caver-klay-accounts/src/transactionType/account.js
index 364c6205..19b120dc 100644
--- a/packages/caver-klay/caver-klay-accounts/src/transactionType/account.js
+++ b/packages/caver-klay/caver-klay-accounts/src/transactionType/account.js
@@ -55,7 +55,7 @@ function rlpEncodeForAccountUpdate(transaction) {
function rlpEncodeForFeeDelegatedAccountUpdate(transaction) {
- if (transaction.feePayer) {
+ if (transaction.senderRawTransaction) {
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, from, accountKey, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
@@ -96,7 +96,7 @@ function rlpEncodeForFeeDelegatedAccountUpdate(transaction) {
function rlpEncodeForFeeDelegatedAccountUpdateWithRatio(transaction) {
- if (transaction.feePayer) {
+ if (transaction.senderRawTransaction) {
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, from, accountKey, feeRatio, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
@@ -138,6 +138,14 @@ function rlpEncodeForFeeDelegatedAccountUpdateWithRatio(transaction) {
}
function resolveRawKeyToAccountKey(transaction) {
+ // Handles the case where AccountForUpdate is set in key field in transaction object to update account.
+ if (transaction.key) {
+ if (transaction.from && transaction.from.toLowerCase() !== transaction.key.address.toLowerCase()) {
+ throw new Error(`The value of the from field of the transaction does not match the address of AccountForUpdate.`)
+ }
+ transaction.key.fillUpdateObject(transaction)
+ }
+
if (!!transaction.legacyKey) return ACCOUNT_KEY_LEGACY_TAG
if (!!transaction.failKey) return ACCOUNT_KEY_FAIL_TAG
@@ -167,17 +175,20 @@ function resolveRawKeyToAccountKey(transaction) {
}
if (transaction.roleTransactionKey || transaction.roleAccountUpdateKey || transaction.roleFeePayerKey) {
- transaction.roleTransactionKey = transaction.roleTransactionKey
+ // Create a new object so as not to damage the input transaction object.
+ const roleBasedObject = {}
+
+ roleBasedObject.roleTransactionKey = transaction.roleTransactionKey
? resolveRawKeyToAccountKey(transaction.roleTransactionKey)
: ACCOUNT_KEY_NIL_TAG
- transaction.roleAccountUpdateKey = transaction.roleAccountUpdateKey
+ roleBasedObject.roleAccountUpdateKey = transaction.roleAccountUpdateKey
? resolveRawKeyToAccountKey(transaction.roleAccountUpdateKey)
: ACCOUNT_KEY_NIL_TAG
- transaction.roleFeePayerKey = transaction.roleFeePayerKey
+ roleBasedObject.roleFeePayerKey = transaction.roleFeePayerKey
? resolveRawKeyToAccountKey(transaction.roleFeePayerKey)
: ACCOUNT_KEY_NIL_TAG
- var keys = [transaction.roleTransactionKey, transaction.roleAccountUpdateKey, transaction.roleFeePayerKey]
+ var keys = [roleBasedObject.roleTransactionKey, roleBasedObject.roleAccountUpdateKey, roleBasedObject.roleFeePayerKey]
return ACCOUNT_KEY_ROLE_BASED_TAG + RLP.encode(keys).slice(2)
}
diff --git a/packages/caver-klay/caver-klay-accounts/src/transactionType/cancel.js b/packages/caver-klay/caver-klay-accounts/src/transactionType/cancel.js
index 2aa8e887..138dc056 100644
--- a/packages/caver-klay/caver-klay-accounts/src/transactionType/cancel.js
+++ b/packages/caver-klay/caver-klay-accounts/src/transactionType/cancel.js
@@ -44,7 +44,7 @@ function rlpEncodeForCancel(transaction) {
}
function rlpEncodeForFeeDelegatedCancel(transaction) {
- if (transaction.feePayer) {
+ if (transaction.senderRawTransaction) {
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, from, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
@@ -81,7 +81,7 @@ function rlpEncodeForFeeDelegatedCancel(transaction) {
}
function rlpEncodeForFeeDelegatedCancelWithRatio(transaction) {
- if (transaction.feePayer) {
+ if (transaction.senderRawTransaction) {
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, from, feeRatio, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
diff --git a/packages/caver-klay/caver-klay-accounts/src/transactionType/contract.js b/packages/caver-klay/caver-klay-accounts/src/transactionType/contract.js
index d170c305..5636a698 100644
--- a/packages/caver-klay/caver-klay-accounts/src/transactionType/contract.js
+++ b/packages/caver-klay/caver-klay-accounts/src/transactionType/contract.js
@@ -82,7 +82,7 @@ function rlpEncodeForContractExecution(transaction) {
function rlpEncodeForFeeDelegatedSmartContractDeploy(transaction) {
- if (transaction.feePayer) {
+ if (transaction.senderRawTransaction) {
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, to, value, from, data, humanReadable, codeFormat, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
@@ -129,7 +129,7 @@ function rlpEncodeForFeeDelegatedSmartContractDeploy(transaction) {
function rlpEncodeForFeeDelegatedSmartContractDeployWithRatio(transaction) {
- if (transaction.feePayer) {
+ if (transaction.senderRawTransaction) {
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, to, value, from, data, humanReadable, feeRatio, codeFormat, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
@@ -178,7 +178,7 @@ function rlpEncodeForFeeDelegatedSmartContractDeployWithRatio(transaction) {
function rlpEncodeForFeeDelegatedSmartContractExecution(transaction) {
- if (transaction.feePayer) {
+ if (transaction.senderRawTransaction) {
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, to, value, from, data, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
@@ -221,7 +221,7 @@ function rlpEncodeForFeeDelegatedSmartContractExecution(transaction) {
function rlpEncodeForFeeDelegatedSmartContractExecutionWithRatio(transaction) {
- if (transaction.feePayer) {
+ if (transaction.senderRawTransaction) {
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, to, value, from, data, feeRatio, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
diff --git a/packages/caver-klay/caver-klay-accounts/src/transactionType/valueTransfer.js b/packages/caver-klay/caver-klay-accounts/src/transactionType/valueTransfer.js
index a39162af..9470b293 100644
--- a/packages/caver-klay/caver-klay-accounts/src/transactionType/valueTransfer.js
+++ b/packages/caver-klay/caver-klay-accounts/src/transactionType/valueTransfer.js
@@ -67,7 +67,7 @@ function rlpEncodeForValueTransferMemo(transaction) {
}
function rlpEncodeForFeeDelegatedValueTransfer(transaction) {
- if (transaction.feePayer) { // fee payer rlp encoding.
+ if (transaction.senderRawTransaction) { // fee payer rlp encoding.
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, to, value, from, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
@@ -106,7 +106,7 @@ function rlpEncodeForFeeDelegatedValueTransfer(transaction) {
}
function rlpEncodeForFeeDelegatedValueTransferWithRatio(transaction) {
- if (transaction.feePayer) { // fee payer rlp encoding.
+ if (transaction.senderRawTransaction) { // fee payer rlp encoding.
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, to, value, from, feeRatio, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
@@ -147,7 +147,7 @@ function rlpEncodeForFeeDelegatedValueTransferWithRatio(transaction) {
}
function rlpEncodeForFeeDelegatedValueTransferMemo(transaction) {
- if (transaction.feePayer) { // fee payer rlp encoding.
+ if (transaction.senderRawTransaction) { // fee payer rlp encoding.
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, to, value, from, data, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
@@ -188,7 +188,7 @@ function rlpEncodeForFeeDelegatedValueTransferMemo(transaction) {
}
function rlpEncodeForFeeDelegatedValueTransferMemoWithRatio(transaction) {
- if (transaction.feePayer) { // fee payer rlp encoding.
+ if (transaction.senderRawTransaction) { // fee payer rlp encoding.
const typeDetacehdRawTransaction = '0x' + transaction.senderRawTransaction.slice(4)
const [ nonce, gasPrice, gas, to, value, from, data, feeRatio, [ [ v, r, s ] ] ] = utils.rlpDecode(typeDetacehdRawTransaction)
diff --git a/packages/caver-klay/src/index.js b/packages/caver-klay/src/index.js
index 08c831bf..3e7ecf54 100644
--- a/packages/caver-klay/src/index.js
+++ b/packages/caver-klay/src/index.js
@@ -50,7 +50,7 @@ var Klay = function Klay(...args) {
// overwrite setProvider
var setProvider = this.setProvider;
- this.setProvider = function () {
+ this.setProvider = function (...args) {
setProvider.apply(_this, args);
_this.net.setProvider.apply(_this, args);
_this.personal.setProvider.apply(_this, args);
diff --git a/packages/caver-utils/src/index.js b/packages/caver-utils/src/index.js
index 107d86af..26da72ff 100644
--- a/packages/caver-utils/src/index.js
+++ b/packages/caver-utils/src/index.js
@@ -378,7 +378,8 @@ function _flattenTypes (includeTuple, puts) {
* @return {bool}
*/
var isHexPrefixed = function (str) {
- return isHexParameter(str)
+ if (typeof str !== 'string') return false
+ return str.slice(0, 2) === '0x'
}
/**
@@ -390,7 +391,7 @@ var isHexPrefixed = function (str) {
var addHexPrefix = function (str) {
if (typeof str !== 'string') return str
- return isHexParameter(str) ? str : '0x' + str
+ return isHexPrefixed(str) ? str : '0x' + str
}
/**
@@ -402,7 +403,7 @@ var addHexPrefix = function (str) {
var stripHexPrefix = function (str) {
if (typeof str !== 'string') return str
- return isHexParameter(str) ? str.slice(2) : str
+ return isHexPrefixed(str) ? str.slice(2) : str
}
/**
@@ -505,6 +506,8 @@ module.exports = {
padRight: utils.rightPad,
rightPad: utils.rightPad,
toTwosComplement: utils.toTwosComplement,
+ isTxHash: utils.isTxHash,
+ isTxHashStrict: utils.isTxHashStrict,
// Moved promiEvent to utils,
promiEvent: promiEvent,
Iban: Iban,
@@ -532,6 +535,12 @@ module.exports = {
txTypeToString: utils.txTypeToString,
trimLeadingZero: utils.trimLeadingZero,
makeEven: utils.makeEven,
+ isValidPublicKey: utils.isValidPublicKey,
isCompressedPublicKey: utils.isCompressedPublicKey,
compressPublicKey: utils.compressPublicKey,
+
+ // For account key
+ isValidRole: utils.isValidRole,
+
+ isEmptySig: utils.isEmptySig,
};
diff --git a/packages/caver-utils/src/utils.js b/packages/caver-utils/src/utils.js
index c4fc3d55..b743ddff 100644
--- a/packages/caver-utils/src/utils.js
+++ b/packages/caver-utils/src/utils.js
@@ -57,6 +57,8 @@ const txTypeToString = {
'0x48': 'CHAIN_DATA_ANCHORING',
}
+const TRANSACTION_HASH_LENGTH = 66
+
/**
* Returns true if object is BN, otherwise false
*
@@ -398,6 +400,21 @@ var isHex = function (hex) {
return ((_.isString(hex) || _.isNumber(hex)) && /^(-0x|0x)?[0-9a-f]*$/i.test(hex));
};
+/**
+ * Checks if the given string is a hexadecimal transaction hash with or without prefix 0x
+ * @method isTxHash
+ * @param {String} tx given hexadecimal transaction hash
+ * @return {Boolean}
+ */
+const isTxHash = (tx) => new RegExp(`^(0x|0X)?[0-9a-fA-F]{${TRANSACTION_HASH_LENGTH - 2}}$`).test(tx)
+
+/**
+ * Checks if the given string is a hexadecimal transaction hash that starts with 0x
+ * @method isTxHashStrict
+ * @param {String} tx given hexadecimal transaction hash
+ * @return {Boolean}
+ */
+const isTxHashStrict = (tx) => new RegExp(`^(0x|0X)[0-9a-fA-F]{${TRANSACTION_HASH_LENGTH - 2}}$`).test(tx)
/**
* Returns true if given string is a valid Klaytn block header bloom.
@@ -501,6 +518,8 @@ var sha3 = function (value) {
sha3._Hash = Hash;
function parsePrivateKey(privateKey) {
+ if (typeof privateKey !== 'string') throw new Error(`The private key must be of type string`)
+
const has0xPrefix = privateKey.slice(0, 2) === '0x'
privateKey = has0xPrefix ? privateKey.slice(2) : privateKey
@@ -632,9 +651,25 @@ const getTxTypeStringFromRawTransaction = (rawTransaction) => {
return typeString
}
+const isValidPublicKey = (publicKey) => {
+ publicKey = publicKey.replace('0x', '')
+
+ if (publicKey.length !== 66 && publicKey.length !== 128) return false
+
+ if (publicKey.length === 66 && !isCompressedPublicKey(publicKey)) return false
+
+ if (publicKey.length === 128) {
+ const xyPoints = xyPointFromPublicKey(publicKey)
+ if (xyPoints === undefined || !xyPoints.length) return false
+ }
+
+ return true
+}
+
const isCompressedPublicKey = (publicKey) => {
const compressedIndicators = ['02', '03']
- return publicKey.replace('0x', '').length === 66 && compressedIndicators.includes(publicKey.slice(2, 4))
+ const withoutPrefix = publicKey.replace('0x', '')
+ return withoutPrefix.length === 66 && compressedIndicators.includes(withoutPrefix.slice(0, 2))
}
const compressPublicKey = (uncompressedPublicKey) => {
@@ -675,6 +710,35 @@ const isContractDeployment = (txObject) => {
}
+const isValidRole = (role) => {
+ switch(role) {
+ case 'transactionKey':
+ case 'updateKey':
+ case 'feePayerKey':
+ return true
+ }
+ return false
+}
+
+const isEmptySig = (sig) => {
+ if (!Array.isArray(sig)) return false
+
+ function isEmpty (s) {
+ if (s.length !== 3) throw new Error(`Invalid signatures length: ${s.length}`)
+
+ if (s[0] === '0x01' && s[1] === '0x' && s[2] === '0x') return true
+ return false
+ }
+
+ if (Array.isArray(sig[0])) {
+ // [[v,r,s]]
+ if (sig.length !== 1) return false
+ return isEmpty(sig[0])
+ }
+
+ return isEmpty(sig)
+}
+
module.exports = {
BN: BN,
isBN: isBN,
@@ -715,6 +779,13 @@ module.exports = {
trimLeadingZero,
makeEven,
txTypeToString,
+ isValidPublicKey,
isCompressedPublicKey,
compressPublicKey,
+ isTxHash,
+ isTxHashStrict,
+
+ isValidRole: isValidRole,
+
+ isEmptySig: isEmptySig,
};
diff --git a/test/decodeTransaction.js b/test/decodeTransaction.js
index 74da64be..fb172653 100644
--- a/test/decodeTransaction.js
+++ b/test/decodeTransaction.js
@@ -46,7 +46,7 @@ describe('Decode Transaction', () => {
}
let ret = await caver.klay.accounts.signTransaction(txObj, sender.privateKey)
- let decodedTx = await caver.klay.decodeTransaction(ret.rawTransaction)
+ let decodedTx = caver.klay.decodeTransaction(ret.rawTransaction)
expect(decodedTx.type).to.equals(txObj.type)
expect(decodedTx.nonce).to.equals(txObj.nonce)
@@ -58,6 +58,10 @@ describe('Decode Transaction', () => {
expect(decodedTx.v).not.to.undefined
expect(decodedTx.r).not.to.undefined
expect(decodedTx.s).not.to.undefined
+ expect(decodedTx.signatures).not.to.be.undefined
+ expect(decodedTx.signatures[0][0]).to.equals(decodedTx.v)
+ expect(decodedTx.signatures[0][1]).to.equals(decodedTx.r)
+ expect(decodedTx.signatures[0][2]).to.equals(decodedTx.s)
expect(decodedTx.feePayer).to.equals('0x')
expect(decodedTx.payerV).to.equals('0x01')
expect(decodedTx.payerR).to.equals('0x')
@@ -68,7 +72,7 @@ describe('Decode Transaction', () => {
feePayer: payer.address,
}, payer.privateKey)
- decodedTx = await caver.klay.decodeTransaction(ret.rawTransaction)
+ decodedTx = caver.klay.decodeTransaction(ret.rawTransaction)
expect(decodedTx.type).to.equals(txObj.type)
expect(decodedTx.nonce).to.equals(txObj.nonce)
@@ -80,9 +84,71 @@ describe('Decode Transaction', () => {
expect(decodedTx.v).not.to.undefined
expect(decodedTx.r).not.to.undefined
expect(decodedTx.s).not.to.undefined
- expect(decodedTx.feePayer).to.equals(payer.address)
+ expect(decodedTx.signatures).not.to.be.undefined
+ expect(decodedTx.signatures[0][0]).to.equals(decodedTx.v)
+ expect(decodedTx.signatures[0][1]).to.equals(decodedTx.r)
+ expect(decodedTx.signatures[0][2]).to.equals(decodedTx.s)
+ expect(decodedTx.feePayer.toLowerCase()).to.equals(payer.address.toLowerCase())
expect(decodedTx.payerV).not.to.undefined
expect(decodedTx.payerR).not.to.undefined
expect(decodedTx.payerS).not.to.undefined
+ expect(decodedTx.feePayerSignatures).not.to.be.undefined
+ expect(decodedTx.feePayerSignatures[0][0]).to.equals(decodedTx.payerV)
+ expect(decodedTx.feePayerSignatures[0][1]).to.equals(decodedTx.payerR)
+ expect(decodedTx.feePayerSignatures[0][2]).to.equals(decodedTx.payerS)
+ }).timeout(10000)
+
+ it('CAVERJS-UNIT-SER-064: Decode sender multi signature transaction', () => {
+ const rawTransaction = '0x08f8c6028505d21dba00830dbba094342a2853b442c66e47cc0aff29836983050bd1850294cde32e19cfa95b0f03de3d09c549d636e43bed22f88ef845824e43a0edb3620ea3a317e36000ab8177342770d245c27c0a641593ffef57a16532578ba028ecaf81729774b97d7c859c064c84095b9d575278dc1b7cc45cd88a29c0cf91f845824e43a0b2874877cb71c847ad33af3d4cb0861ce2b32c6d7649a3c99a213724871cb37ca00c3e960b277623d6298b9ebd5711083321f7caa162aec10cf2eb49e042081cdd'
+ let decodedTx = caver.klay.decodeTransaction(rawTransaction)
+
+ expect(decodedTx.type).to.equals('VALUE_TRANSFER')
+ expect(caver.utils.hexToNumber(decodedTx.nonce)).to.equals(2)
+ expect(caver.utils.hexToNumber(decodedTx.gasPrice)).to.equals(25000000000)
+ expect(caver.utils.hexToNumber(decodedTx.gas)).to.equals(900000)
+ expect(decodedTx.to).to.equals('0x342a2853b442c66e47cc0aff29836983050bd185')
+ expect(caver.utils.hexToNumber(decodedTx.value)).to.equals(2)
+ expect(decodedTx.from).to.equals('0xcde32e19cfa95b0f03de3d09c549d636e43bed22')
+ expect(decodedTx.v).not.to.undefined
+ expect(decodedTx.r).not.to.undefined
+ expect(decodedTx.s).not.to.undefined
+ expect(decodedTx.signatures).not.to.be.undefined
+ expect(Array.isArray(decodedTx.signatures)).to.be.true
+ expect(decodedTx.signatures.length).to.equals(2)
+ expect(decodedTx.signatures[0][0]).to.equals(decodedTx.v)
+ expect(decodedTx.signatures[0][1]).to.equals(decodedTx.r)
+ expect(decodedTx.signatures[0][2]).to.equals(decodedTx.s)
+ }).timeout(10000)
+
+ it('CAVERJS-UNIT-SER-065: Decode sender and feePayer multi signature transaction', () => {
+ const rawTransaction = '0x09f9016b018505d21dba00830dbba094ca4f2df6e617e340eb2004453e3cc449a8e51d9803946b0f4bb65b4bb4c92d55b1e8574cf8059f3b2da8f88ef845824e43a0cc14fd91517649de4f3e1e2729fa63dfb2ae401e5da54fa52f305fff445d803fa07e134086a557f28847aa689207bc4375bb69cae64ba6356dedc60d8c93929131f845824e44a07d90c9385ae713199f9c4016e06da63af4956294cd66329edc6bf925f03dbfc3a04802101f506df137b218a0880e5b78585c8b7074ecc246950b8e59473d8816de946b0f4bb65b4bb4c92d55b1e8574cf8059f3b2da8f88ef845824e43a09696eec79df68c33ef2dd43302ebb3e18193266d49d805897d0591c6a7e07de0a051b2467e9f84f75c7f1473c3d709df3c13c6824fdf2061c13fe1c41c6ea24155f845824e43a0f7615987a2eeed696d90405b950e26dde93d35ff2fd9d6d94838dc71a209a017a05811cf04dce40d76873ca9ce02a72bcd5b2e748274dc11cd6cfcd34c14cf49e1'
+ let decodedTx = caver.klay.decodeTransaction(rawTransaction)
+
+ expect(decodedTx.type).to.equals('FEE_DELEGATED_VALUE_TRANSFER')
+ expect(caver.utils.hexToNumber(decodedTx.nonce)).to.equals(1)
+ expect(caver.utils.hexToNumber(decodedTx.gasPrice)).to.equals(25000000000)
+ expect(caver.utils.hexToNumber(decodedTx.gas)).to.equals(900000)
+ expect(decodedTx.to).to.equals('0xca4f2df6e617e340eb2004453e3cc449a8e51d98')
+ expect(caver.utils.hexToNumber(decodedTx.value)).to.equals(3)
+ expect(decodedTx.from).to.equals('0x6b0f4bb65b4bb4c92d55b1e8574cf8059f3b2da8')
+ expect(decodedTx.v).not.to.undefined
+ expect(decodedTx.r).not.to.undefined
+ expect(decodedTx.s).not.to.undefined
+ expect(decodedTx.signatures).not.to.be.undefined
+ expect(Array.isArray(decodedTx.signatures)).to.be.true
+ expect(decodedTx.signatures.length).to.equals(2)
+ expect(decodedTx.signatures[0][0]).to.equals(decodedTx.v)
+ expect(decodedTx.signatures[0][1]).to.equals(decodedTx.r)
+ expect(decodedTx.signatures[0][2]).to.equals(decodedTx.s)
+ expect(decodedTx.feePayer).to.equals('0x6b0f4bb65b4bb4c92d55b1e8574cf8059f3b2da8')
+ expect(decodedTx.payerV).not.to.undefined
+ expect(decodedTx.payerR).not.to.undefined
+ expect(decodedTx.payerS).not.to.undefined
+ expect(decodedTx.feePayerSignatures).not.to.be.undefined
+ expect(Array.isArray(decodedTx.feePayerSignatures)).to.be.true
+ expect(decodedTx.feePayerSignatures.length).to.equals(2)
+ expect(decodedTx.feePayerSignatures[0][0]).to.equals(decodedTx.payerV)
+ expect(decodedTx.feePayerSignatures[0][1]).to.equals(decodedTx.payerR)
+ expect(decodedTx.feePayerSignatures[0][2]).to.equals(decodedTx.payerS)
}).timeout(10000)
})
\ No newline at end of file
diff --git a/test/intTest.js b/test/intTest.js
index 029a95a8..058f4612 100644
--- a/test/intTest.js
+++ b/test/intTest.js
@@ -320,7 +320,7 @@ const getSignedRawTransaction = async (t) => {
rawTransaction = signedRawTx.rawTransaction
if (t.tx.v !== undefined || t.tx.r !== undefined || t.tx.s !== undefined) {
- const txObj = await caver.klay.decodeTransaction(rawTransaction, t.tx.type)
+ const txObj = caver.klay.decodeTransaction(rawTransaction, t.tx.type)
if (t.tx.v !== undefined) { txObj.v = t.tx.v }
if (t.tx.r !== undefined) { txObj.r = t.tx.r }
if (t.tx.s !== undefined) { txObj.s = t.tx.s }
@@ -350,11 +350,11 @@ const getSignedRawTransaction = async (t) => {
// If v or r or s value is set in test case, overwrite with that.
if (t.tx.payerV !== undefined || t.tx.payerR !== undefined || t.tx.payerS !== undefined) {
- const txObj = await caver.klay.decodeTransaction(rawTransaction, t.tx.type)
+ const txObj = caver.klay.decodeTransaction(rawTransaction, t.tx.type)
if (t.tx.payerV !== undefined) { txObj.payerV = t.tx.payerV }
if (t.tx.payerR !== undefined) { txObj.payerR = t.tx.payerR }
if (t.tx.payerS !== undefined) { txObj.payerS = t.tx.payerS }
- rawTransaction = overwriteSignature(rawTransaction, txObj, undefined, [t.tx.payerV, t.tx.payerR, t.tx.payerS])
+ rawTransaction = overwriteSignature(rawTransaction, txObj, undefined, [txObj.payerV, txObj.payerR, txObj.payerS])
}
}
diff --git a/test/isCompressedPublicKey.js b/test/isCompressedPublicKey.js
index 85f585dd..8d4923de 100644
--- a/test/isCompressedPublicKey.js
+++ b/test/isCompressedPublicKey.js
@@ -32,6 +32,9 @@ describe('caver.utils.isCompressedPublicKey', (done) => {
expect(caver.utils.isCompressedPublicKey(uncompressedPublicKey1)).to.false
expect(caver.utils.isCompressedPublicKey(uncompressedPublicKey2)).to.false
expect(caver.utils.isCompressedPublicKey(uncompressedPublicKey3)).to.false
+ expect(caver.utils.isCompressedPublicKey(uncompressedPublicKey1.slice(2))).to.false
+ expect(caver.utils.isCompressedPublicKey(uncompressedPublicKey2.slice(2))).to.false
+ expect(caver.utils.isCompressedPublicKey(uncompressedPublicKey3.slice(2))).to.false
})
it('CAVERJS-UNIT-SER-026 : Should return true if the argument is compressed public key', () => {
@@ -45,5 +48,8 @@ describe('caver.utils.isCompressedPublicKey', (done) => {
expect(caver.utils.isCompressedPublicKey(compressedPublicKey1)).to.true
expect(caver.utils.isCompressedPublicKey(compressedPublicKey2)).to.true
expect(caver.utils.isCompressedPublicKey(compressedPublicKey3)).to.true
+ expect(caver.utils.isCompressedPublicKey(compressedPublicKey1.slice(2))).to.true
+ expect(caver.utils.isCompressedPublicKey(compressedPublicKey2.slice(2))).to.true
+ expect(caver.utils.isCompressedPublicKey(compressedPublicKey3.slice(2))).to.true
})
})
diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js
index af49e013..d33f5797 100644
--- a/test/packages/caver.klay.accounts.js
+++ b/test/packages/caver.klay.accounts.js
@@ -32,10 +32,11 @@ beforeEach(() => {
caver = new Caver(testRPCURL)
})
-function isAccount(data, { privateKey, address } = {}) {
+function isAccount(data, { keys, address } = {}) {
// account object keys
- const keys = [
+ const objectKeys = [
'address',
+ 'accountKey',
'privateKey',
'signTransaction',
'sign',
@@ -43,16 +44,16 @@ function isAccount(data, { privateKey, address } = {}) {
'getKlaytnWalletKey'
]
- expect(Object.getOwnPropertyNames(data)).to.deep.equal(keys)
+ expect(Object.getOwnPropertyNames(data)).to.deep.equal(objectKeys)
expect(caver.utils.isAddress(data.address)).to.equal(true)
- if (privateKey !== undefined) {
- expect(data.privateKey).to.equal(privateKey)
+ if (keys !== undefined) {
+ compareAccountKey(data.accountKey, keys)
}
if (address !== undefined) {
- expect(data.address).to.equal(address.toLowerCase())
+ expect(data.address.toLowerCase()).to.equal(address.toLowerCase())
}
}
@@ -62,9 +63,11 @@ function checkHashMessage(hashed, originMessage) {
expect(hashed).to.equal(originHashed)
}
-function isKeystoreV3(data, { address }) {
- const keys = ['version', 'id', 'address', 'crypto']
- expect(Object.getOwnPropertyNames(data)).to.deep.equal(keys)
+function isKeystoreV4(data, { address }) {
+ const objectKeys = ['version', 'id', 'address', 'keyring']
+ expect(Object.getOwnPropertyNames(data)).to.deep.equal(objectKeys)
+
+ expect(data.version).to.equals(4)
expect(caver.utils.isAddress(data.address)).to.equal(true)
@@ -85,19 +88,59 @@ function isWallet(data, { accounts } = {}) {
expect(data.length).to.equal(accounts.length)
for (let i = 0; i < data.length; i++) {
- let accountObj = Object.assign({}, data[i])
- delete accountObj.index
+ let accountObj = caver.klay.accounts.createWithAccountKey(data[i].address, data[i].accountKey)
- isAccount(accountObj, { privateKey: accounts[i].privateKey, address: accounts[i].address })
+ isAccount(accountObj, { keys: accounts[i].keys, address: accounts[i].address })
- accountObj = Object.assign({}, data[accountObj.address])
- delete accountObj.index
+ accountObj = caver.klay.accounts.createWithAccountKey(data[i].address, data[accountObj.address].accountKey)
- isAccount(accountObj, { privateKey: accounts[i].privateKey, address: accounts[i].address })
+ isAccount(accountObj, { keys: accounts[i].keys, address: accounts[i].address })
}
}
}
+function compareAccountKey(keyFromAccount, key) {
+ if (!keyFromAccount && !key) return
+
+ if (typeof keyFromAccount.keys === 'string') {
+ expect(isSameKeyString(keyFromAccount.keys, key)).to.be.true
+ expect(isSameKeyString(keyFromAccount.transactionKey, key)).to.be.true
+ expect(isSameKeyString(keyFromAccount.updateKey, key)).to.be.true
+ expect(isSameKeyString(keyFromAccount.feePayerKey, key)).to.be.true
+ } else if (Array.isArray(keyFromAccount.keys)) {
+ expect(isSameKeyArray(keyFromAccount.keys, key)).to.be.true
+ expect(isSameKeyArray(keyFromAccount.transactionKey, key)).to.be.true
+ expect(isSameKeyArray(keyFromAccount.updateKey, key)).to.be.true
+ expect(isSameKeyArray(keyFromAccount.feePayerKey, key)).to.be.true
+ } else {
+ expect(isSameKeyObject(keyFromAccount.keys, key)).to.be.true
+ compareAccountKey(keyFromAccount._transactionKey, key.transactionKey)
+ compareAccountKey(keyFromAccount._updateKey, key.updateKey)
+ compareAccountKey(keyFromAccount._feePayerKey, key.feePayerKey)
+ }
+}
+
+function isSameKeyString(str1, str2) {
+ return str1.toLowerCase() === str2.toLowerCase()
+}
+
+function isSameKeyArray(arr1, arr2) {
+ if (arr1.length !== arr2.length) return false
+ for (let i = 0; i < arr1.length; i ++) {
+ if (arr1[i].toLowerCase() !== arr2[i].toLowerCase()) return false
+ }
+ return true
+}
+
+function isSameKeyObject(obj1, obj2) {
+ const keys = Object.keys(obj1)
+ keys.map((r)=> {
+ if (typeof obj1[r] === 'string' && !isSameKeyString(obj1[r], obj2[r])) return false
+ if (Array.isArray(obj1[r]) && !isSameKeyArray(obj1[r], obj2[r])) return false
+ })
+ return true
+}
+
describe('caver.klay.accounts.create', () => {
context('CAVERJS-UNIT-WALLET-021 : input: no parameter', () => {
it('should return valid account', () => {
@@ -137,20 +180,35 @@ describe('caver.klay.accounts.privateKeyToAccount', () => {
})
describe('caver.klay.accounts.signTransaction', () => {
- const txObj = {
- from: setting.toAddress,
- nonce: '0x0',
- to: setting.toAddress,
- gas: setting.gas,
- gasPrice: setting.gasPrice,
- value: '0x1',
- chainId: 2019,
- }
-
- let account
+ let txObj, vtTx, account, feePayer, sender
beforeEach(() => {
account = caver.klay.accounts.create()
+ caver.klay.accounts.wallet.add(account)
+ feePayer = caver.klay.accounts.wallet.add('0x3bdc858e890c3c845ea9ca24b1e9ed183a56eb78d4bf5463da219a74f708eff6')
+ sender = caver.klay.accounts.wallet.add('0x66de1a1fa104b008c3c34c1695415d71435384f3b68df03dda82e74f9d85064d')
+
+ txObj = {
+ from: account.address,
+ nonce: '0x0',
+ to: setting.toAddress,
+ gas: setting.gas,
+ gasPrice: setting.gasPrice,
+ value: '0x1',
+ chainId: 2019,
+ }
+
+
+ vtTx = {
+ type: 'VALUE_TRANSFER',
+ from: account.address,
+ to: '0xd05c5926b0a2f31aadcc9a9cbd3868a50104d834',
+ value: '0x1',
+ gas: '0xdbba0',
+ chainId: '0x7e3',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
})
context('CAVERJS-UNIT-WALLET-023 : input: tx, privateKey', () => {
@@ -160,7 +218,7 @@ describe('caver.klay.accounts.signTransaction', () => {
account.privateKey
)
- const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash']
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures']
expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address)
@@ -174,7 +232,7 @@ describe('caver.klay.accounts.signTransaction', () => {
const result = await caver.klay.accounts.signTransaction(tx, account.privateKey)
- const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash']
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures']
expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address)
@@ -188,7 +246,7 @@ describe('caver.klay.accounts.signTransaction', () => {
const result = await caver.klay.accounts.signTransaction(tx, account.privateKey)
- const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash']
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures']
expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address)
@@ -202,7 +260,7 @@ describe('caver.klay.accounts.signTransaction', () => {
const result = await caver.klay.accounts.signTransaction(tx, account.privateKey)
- const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash']
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures']
expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address)
@@ -235,13 +293,12 @@ describe('caver.klay.accounts.signTransaction', () => {
})
context('CAVERJS-UNIT-WALLET-025 : input: tx, privateKey:invalid', () => {
- it('should throw an error', () => {
+ it('should throw an error', async () => {
const invalidPrivateKey = caver.utils.randomHex(31) // 31bytes
const errorMessage = 'Invalid private key'
- expect(() => caver.klay.accounts.signTransaction(txObj, invalidPrivateKey))
- .to.throw(errorMessage)
+ await expect(caver.klay.accounts.signTransaction(txObj, invalidPrivateKey)).to.be.rejectedWith(errorMessage)
})
})
@@ -251,7 +308,7 @@ describe('caver.klay.accounts.signTransaction', () => {
txObj,
account.privateKey,
(error, result) => {
- const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash']
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures']
expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address)
@@ -276,355 +333,4134 @@ describe('caver.klay.accounts.signTransaction', () => {
expect(result.senderTxHash).to.equal('0x1b7c0f2fc7548056e90d9690e8c397acf99eb38e622ac91ee22c2085065f8a55')
})
})
-})
-
-describe('caver.klay.accounts.recoverTransaction', () => {
- let account
- let rawTx
-
- beforeEach(async () => {
- account = caver.klay.accounts.create()
-
- const txObj = {
- from: setting.fromAddress,
- nonce: '0x0',
- to: setting.toAddress,
- gas: setting.gas,
- gasPrice: setting.gasPrice,
- value: '0x1'
- }
- const signedTx = await account.signTransaction(txObj)
- rawTx = signedTx.rawTransaction
- })
-
- context('CAVERJS-UNIT-WALLET-029 : rawTransaction', () => {
- it('should return valid address', () => {
- const result = caver.klay.accounts.recoverTransaction(rawTx)
- expect(result).to.equal(account.address)
- })
- })
- context('CAVERJS-UNIT-WALLET-030 : rawTransaction:invalid', () => {
- it('should not equal to account.address', () => {
- const invalid = rawTx.slice(0, -2)
- const result = caver.klay.accounts.recoverTransaction(invalid)
- expect(result).to.not.equal(account.addrss)
- })
- })
+ context('CAVERJS-UNIT-WALLET-122 : input: legacyTx, privateKey of decoupled account', () => {
+ it('should return signature and rawTransaction', async () => {
+ const decoupledAccount = caver.klay.accounts.privateKeyToAccount(caver.klay.accounts.create().privateKey, caver.klay.accounts.create().address)
- context('CAVERJS-UNIT-WALLET-104 : rawTransaction: leading zeroes of the signature are trimmed', () => {
- it('should equal to account.address', async () => {
- const transaction = {
- from: '0x13b0d8316F0c3cE0C3C51Ebb586A14d7d90112fD',
+ let tx = {
+ from: decoupledAccount.address,
nonce: '0x0',
- to: '0x30d8d4217145ba3f6cde24ec28c64c9120f2bdfb',
- gas: 900000,
- gasPrice: 25000000000,
+ to: setting.toAddress,
+ gas: setting.gas,
+ gasPrice: setting.gasPrice,
value: '0x1',
- chainId: 10000,
+ chainId: 2019,
}
- account.address = '0x13b0d8316F0c3cE0C3C51Ebb586A14d7d90112fD'
- account.privateKey = '0x72d72a46401220f08ccb1b17b550feb816840f2f8ce86361e7ee54ac7a9ee6d8'
-
- const signed = await caver.klay.accounts.signTransaction(transaction, account.privateKey)
- const rlpDecoded = caver.utils.rlpDecode(signed.rawTransaction)
- expect(rlpDecoded[7].length).not.to.equals(rlpDecoded[8].length)
+ const errorMessage = 'A legacy transaction must be with a legacy account key'
- const result = caver.klay.accounts.recoverTransaction(signed.rawTransaction)
- expect(result).to.not.equal(account.addrss)
+ await expect(caver.klay.accounts.signTransaction(tx, decoupledAccount.privateKey)).to.be.rejectedWith(errorMessage)
})
})
- context('CAVERJS-UNIT-WALLET-105 : rawTransaction: Non-LEGACY transactions.', () => {
- it('should throw error', async () => {
- const transaction = {
- type: 'VALUE_TRANSFER',
- from: '0x13b0d8316F0c3cE0C3C51Ebb586A14d7d90112fD',
- nonce: '0x0',
- to: '0x30d8d4217145ba3f6cde24ec28c64c9120f2bdfb',
- gas: 900000,
- gasPrice: 25000000000,
- value: '0x1',
- chainId: 10000,
- }
- account.address = '0x13b0d8316F0c3cE0C3C51Ebb586A14d7d90112fD'
- account.privateKey = '0x72d72a46401220f08ccb1b17b550feb816840f2f8ce86361e7ee54ac7a9ee6d8'
-
- const signed = await caver.klay.accounts.signTransaction(transaction, account.privateKey)
+ context('CAVERJS-UNIT-WALLET-123 : input: if there are invalid number of parameters then signTrasnaction should reject', () => {
+ it('should reject when there is no parameter', async () => {
+ const errorMessage = 'Invalid parameter: The number of parameters is invalid.'
+ await expect(caver.klay.accounts.signTransaction()).to.be.rejectedWith(errorMessage)
+ })
- const errorMessage = 'recoverTransaction only supports transactions of type "LEGACY".'
- expect(()=>caver.klay.accounts.recoverTransaction(signed.rawTransaction)).to.throws(errorMessage)
+ it('should reject when there are more than three parameters', async () => {
+ const errorMessage = 'Invalid parameter: The number of parameters is invalid.'
+ await expect(caver.klay.accounts.signTransaction({}, 'privateKey', ()=>{}, 'one more')).to.be.rejectedWith(errorMessage)
})
})
-})
-describe('caver.klay.accounts.hashMessage', () => {
- it('CAVERJS-UNIT-WALLET-031, CAVERJS-UNIT-WALLET-032 : result should be same with keccak256(MessagePrefix + originMessage.length + originMessage)', () => {
- const message = 'Hello World'
- let result = caver.klay.accounts.hashMessage(message)
- checkHashMessage(result, message)
+ context('CAVERJS-UNIT-WALLET-124 : input: if there are valid number of parameters then signTrasnaction should set properly', () => {
+ it('should sign to transaction parameter with private key in wallet', async () => {
+ const result = await caver.klay.accounts.signTransaction(txObj)
- const decoded = caver.utils.utf8ToHex(message)
- result = caver.klay.accounts.hashMessage(decoded)
- checkHashMessage(result, message)
- })
-})
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
-describe('caver.klay.accounts.sign', () => {
- let account
+ expect(typeof result.signatures[0]).to.equals('string')
- beforeEach(() => {
- account = caver.klay.accounts.create()
- })
+ expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address)
+ })
- context('CAVERJS-UNIT-WALLET-033 : input: data, privateKey', () => {
- it('should recover valid address', () => {
- const data = 'Some data'
- let result = caver.klay.accounts.sign(data, account.privateKey)
+ it('should sign to transaction parameter with private key in wallet with callback', async () => {
+ let isCalled = false
+ const result = await caver.klay.accounts.signTransaction(txObj, (error, result) => isCalled = true)
- const keys = ['message', 'messageHash', 'v', 'r', 's', 'signature']
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures']
expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
- if (data != result.message) {
- expect(data).to.equal(caver.utils.utf8ToHex(result.message))
- }
+ expect(typeof result.signatures[0]).to.equals('string')
- const decoded = caver.utils.utf8ToHex(data)
- result = caver.klay.accounts.sign(decoded, account.privateKey)
- checkHashMessage(result.messageHash, data)
+ expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address)
- expect(caver.klay.accounts.recover(result)).to.equal(account.address)
+ expect(isCalled).to.be.true
})
- })
- context('CAVERJS-UNIT-WALLET-034 : input: data, privateKey:invalid', () => {
- it('should throw an error', () => {
- const data = 'Some data'
- const invalid = caver.utils.randomHex(31) // 31bytes
+ it('should sign to transaction parameter with private key parameter', async () => {
+ const result = await caver.klay.accounts.signTransaction(vtTx, account.privateKey)
- const errorMessage = 'Invalid private key'
- expect(() => caver.klay.accounts.sign(data, invalid)).to.throw(errorMessage)
- })
- })
-})
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
-// caver.klay.accounts.recover
-describe('caver.klay.accounts.recover', () => {
- let account
+ expect(Array.isArray(result.signatures[0])).to.be.true
+ expect(result.signatures.length).to.equals(1)
+ })
- beforeEach(() => {
- account = caver.klay.accounts.create()
- })
+ it('should sign to transaction parameter with private key array', async () => {
+ const privateKeyArray = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const result = await caver.klay.accounts.signTransaction(vtTx, privateKeyArray)
- context('CAVERJS-UNIT-WALLET-035 : input: signatureObject', () => {
- it('result should be same with account.address', () => {
- const message = 'Some data'
- const sigObj = account.sign(message)
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
- let result = caver.klay.accounts.recover(sigObj)
- expect(result).to.equal(account.address)
+ expect(Array.isArray(result.signatures[0])).to.be.true
+ expect(result.signatures.length).to.equals(2)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(2)
+ expect(decoded.signatures[0][0]).to.equals(result.signatures[0][0])
+ expect(decoded.signatures[0][1]).to.equals(result.signatures[0][1])
+ expect(decoded.signatures[0][2]).to.equals(result.signatures[0][2])
+ expect(decoded.signatures[1][0]).to.equals(result.signatures[1][0])
+ expect(decoded.signatures[1][1]).to.equals(result.signatures[1][1])
+ expect(decoded.signatures[1][2]).to.equals(result.signatures[1][2])
})
})
- context('CAVERJS-UNIT-WALLET-036 : input: message, signature', () => {
- it('result should be same with account.address', () => {
- const message = 'Some data'
- const sigObj = account.sign(message)
-
- let result = caver.klay.accounts.recover(sigObj.message, sigObj.signature)
- expect(result).to.equal(account.address)
+ context('CAVERJS-UNIT-WALLET-130 : input: txObject', () => {
+ it('should sign with feePayer and return feePayerSignatures', async () => {
+ const feeDelegatedTx = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: '0x76d1cc1cdb081de8627cab2c074f02ebc7bce0d0',
+ to: '0xd05c5926b0a2f31aadcc9a9cbd3868a50104d834',
+ value: '0x1',
+ gas: '0xdbba0',
+ chainId: '0x7e3',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
+ const senderSigned = await caver.klay.accounts.signTransaction(feeDelegatedTx, '1881a973628dba6ab07b6b47c8f3fb50d8e7cbf71fef3b4739155619a3c126fa')
+
+ const feePayerTransaction = {
+ senderRawTransaction: senderSigned.rawTransaction,
+ feePayer: account.address
+ }
+ const feePayerSigned = await caver.klay.accounts.signTransaction(feePayerTransaction)
+ expect(feePayerSigned.feePayerSignatures).not.to.be.undefined
+ expect(Array.isArray(feePayerSigned.feePayerSignatures)).to.be.true
+
+ const decoded = caver.klay.decodeTransaction(feePayerSigned.rawTransaction)
+ expect(decoded.signatures.length).to.equals(1)
+ expect(decoded.signatures[0][0]).to.equals(senderSigned.signatures[0][0])
+ expect(decoded.signatures[0][1]).to.equals(senderSigned.signatures[0][1])
+ expect(decoded.signatures[0][2]).to.equals(senderSigned.signatures[0][2])
+ expect(decoded.feePayerSignatures[0][0]).to.equals(feePayerSigned.feePayerSignatures[0][0])
+ expect(decoded.feePayerSignatures[0][1]).to.equals(feePayerSigned.feePayerSignatures[0][1])
+ expect(decoded.feePayerSignatures[0][2]).to.equals(feePayerSigned.feePayerSignatures[0][2])
})
})
- context('CAVERJS-UNIT-WALLET-037 : input: message, signature, prefixed', () => {
- it('result should be same with account.address', () => {
- const message = 'Some data'
- const sigObj = account.sign(message)
- const prefixed = true
-
- const messageHash = caver.klay.accounts.hashMessage(message)
+ context('CAVERJS-UNIT-WALLET-131 : input: txObject for fee payer without feePayer field', () => {
+ it('should reject', async () => {
+ const feeDelegatedTx = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: '0x76d1cc1cdb081de8627cab2c074f02ebc7bce0d0',
+ to: '0xd05c5926b0a2f31aadcc9a9cbd3868a50104d834',
+ value: '0x1',
+ gas: '0xdbba0',
+ chainId: '0x7e3',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
+ const senderSigned = await caver.klay.accounts.signTransaction(feeDelegatedTx, '1881a973628dba6ab07b6b47c8f3fb50d8e7cbf71fef3b4739155619a3c126fa')
+
+ const feePayerTransaction = {
+ senderRawTransaction: senderSigned.rawTransaction,
+ }
- let result = caver.klay.accounts.recover(messageHash, sigObj.signature, prefixed)
- expect(result).to.equal(account.address)
+ const errorMessage = `Invalid fee payer: ${feePayerTransaction.feePayer}`
+ await expect(caver.klay.accounts.signTransaction(feePayerTransaction)).to.be.rejectedWith(errorMessage)
})
})
- context('CAVERJS-UNIT-WALLET-038 : input: message, v, r, s', () => {
- it('result should be same with account.address', () => {
- const message = 'Some data'
- const sigObj = account.sign(message)
-
- let result = caver.klay.accounts.recover(sigObj.message, sigObj.v, sigObj.r, sigObj.s)
- expect(result).to.equal(account.address)
+ context('CAVERJS-UNIT-WALLET-132 : input: txObject without private key', () => {
+ it('when fail to find account, should reject with expected error message', async () => {
+ const feeDelegatedTx = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: caver.klay.accounts.create().address,
+ to: '0xd05c5926b0a2f31aadcc9a9cbd3868a50104d834',
+ value: '0x1',
+ gas: '0xdbba0',
+ chainId: '0x7e3',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
+ const errorMessage = 'Failed to find get private key to sign. The account you want to use for signing must exist in caver.klay.accounts.wallet or you must pass the private key as a parameter.'
+ await expect(caver.klay.accounts.signTransaction(feeDelegatedTx)).to.be.rejectedWith(errorMessage)
})
})
- context('CAVERJS-UNIT-WALLET-039 : input: message, v, r, s, prefixed', () => {
- it('result should be same with account.address', () => {
- const message = 'Some data'
- const sigObj = account.sign(message)
- const prefixed = true
-
- const messageHash = caver.klay.accounts.hashMessage(message)
+ context('CAVERJS-UNIT-WALLET-225: input: rawTransaction without other signatures', () => {
+ it('should sign to transaction', async () => {
+ const rawTransaction = '0x08f83c819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194f63c07602e64ca5e2ffb325fdbe4b76015d56f1cc4c3018080'
+ const result = await caver.klay.accounts.signTransaction(rawTransaction, account.privateKey)
- let result = caver.klay.accounts.recover(messageHash, sigObj.v, sigObj.r, sigObj.s, prefixed)
- expect(result).to.equal(account.address)
+ expect(result.signatures.length).to.equals(1)
+ expect(result.feePayerSignatures).to.be.undefined
})
})
-})
-
-// caver.klay.accounts.encrypt
-describe('caver.klay.accounts.encrypt', () => {
- let account
- beforeEach(() => {
- account = caver.klay.accounts.create()
+ context('CAVERJS-UNIT-WALLET-226: input: rawTransaction with other sender signatures', () => {
+ it('should sign with private key and append to signatures', async () => {
+ const rawTransaction = '0x08f880819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194f63c07602e64ca5e2ffb325fdbe4b76015d56f1cf847f845824e44a068e480ad868cdbe509d3f6419f872d5f0bfe5c81dd6b56463df73f2225353ef0a005836c1c756bcc5262dfcb4aa1c1b69858475c389a770170f25105f58e23bc85'
+ const result = await caver.klay.accounts.signTransaction(rawTransaction, account.privateKey)
+
+ expect(result.signatures.length).to.equals(2)
+ expect(result.feePayerSignatures).to.be.undefined
+ })
})
- context('CAVERJS-UNIT-WALLET-040 : input: privateKey, password', () => {
- it('should encrypt password with privateKey', () => {
- const password = 'klaytn!@'
-
- let result = caver.klay.accounts.encrypt(account.privateKey, password)
-
- isKeystoreV3(result, account)
+ context('CAVERJS-UNIT-WALLET-227: input: rawTransaction without signatures of sender and fee payer', () => {
+ it('should sign with fee payer', async () => {
+ const rawTransaction = '0x09f842819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194127a24ec811aa1e45071a669e5d117a475e68149c4c301808080c4c3018080'
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: feePayer.address
+ }
+ const result = await caver.klay.accounts.signTransaction(feePayerTx, feePayer.privateKey)
- const decryptedAccount = caver.klay.accounts.decrypt(result, password)
- isAccount(decryptedAccount, account)
+ expect(result.signatures).to.be.undefined
+ expect(result.feePayerSignatures.length).to.equals(1)
})
})
- context('CAVERJS-UNIT-WALLET-041 : input: privateKey:invalid, password', () => {
- it('should throw an error', () => {
- const invalid = caver.utils.randomHex(31) // 31bytes
- const password = 'klaytn!@'
-
- const errorMessage = 'Invalid private key'
- expect(() => caver.klay.accounts.encrypt(invalid, password)).to.throw(errorMessage)
+ context('CAVERJS-UNIT-WALLET-228: input: rawTransaction with signatures of fee payer', () => {
+ it('should sign with sender and include existed signatures of fee payer', async () => {
+ const rawTransaction = '0x09f89a819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194127a24ec811aa1e45071a669e5d117a475e68149c4c3018080944a804669b2637b18d46e62109ed8edc0dc8526c7f847f845824e43a0113bf0986a48768e38daeff685ce56766aacf449f2aec8a0c77165777970f954a00717c4d4720fe706a075374f8eb0432f6c9f70c0a6e6267483d0b0cc8100ec07'
+ const result = await caver.klay.accounts.signTransaction(rawTransaction, account.privateKey)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+
+ expect(result.signatures.length).to.equals(1)
+ expect(result.feePayerSignatures).to.be.undefined
+ expect(decoded.signatures.length).to.equals(1)
+ expect(decoded.feePayerSignatures.length).to.equals(1)
})
})
- context('CAVERJS-UNIT-WALLET-096 : input: privateKey:KlaytnWalletKey, password', () => {
- it('should encrypt password with privateKey', () => {
- const password = 'klaytn!@'
-
- let result = caver.klay.accounts.encrypt(account.getKlaytnWalletKey(), password)
-
- isKeystoreV3(result, account)
+ context('CAVERJS-UNIT-WALLET-229: input: rawTransaction with signatures of sender and fee payer', () => {
+ it('should append signatures of sender to existed signatures', async () => {
+ const rawTransaction = '0x09f8de819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194127a24ec811aa1e45071a669e5d117a475e68149f847f845824e44a030accfbec3b577a53103c843744754a98408e7518391a31399bc757610ad1fc5a00eecc65e8f6f1795f7665513442fe30f881ddce12ceb687a8a7d9b65a0eee595944a804669b2637b18d46e62109ed8edc0dc8526c7f847f845824e43a0113bf0986a48768e38daeff685ce56766aacf449f2aec8a0c77165777970f954a00717c4d4720fe706a075374f8eb0432f6c9f70c0a6e6267483d0b0cc8100ec07'
+ const result = await caver.klay.accounts.signTransaction(rawTransaction, sender.privateKey)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+
+ expect(result.signatures.length).to.equals(2)
+ expect(result.feePayerSignatures).to.be.undefined
+ expect(decoded.signatures.length).to.equals(2)
+ expect(decoded.feePayerSignatures.length).to.equals(1)
+ })
+ })
- const decryptedAccount = caver.klay.accounts.decrypt(result, password)
- isAccount(decryptedAccount, account)
+ context('CAVERJS-UNIT-WALLET-230: input: rawTransaction with signatures of sender and fee payer', () => {
+ it('should append signatures of fee payer to existed feePayerSignatures', async () => {
+ const rawTransaction = '0x09f90125819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194127a24ec811aa1e45071a669e5d117a475e68149f88ef845824e44a030accfbec3b577a53103c843744754a98408e7518391a31399bc757610ad1fc5a00eecc65e8f6f1795f7665513442fe30f881ddce12ceb687a8a7d9b65a0eee595f845824e44a006400dc68ab85d838a02e202e2ca52c6a30f11f7fa84f4046e08a940f4c95d1ea061a09e1a2dd6b823c42552d1cf0a4c0e408b4ada2b0236ef14ba0f036e6da262944a804669b2637b18d46e62109ed8edc0dc8526c7f847f845824e43a0113bf0986a48768e38daeff685ce56766aacf449f2aec8a0c77165777970f954a00717c4d4720fe706a075374f8eb0432f6c9f70c0a6e6267483d0b0cc8100ec07'
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: feePayer.address
+ }
+ const result = await caver.klay.accounts.signTransaction(feePayerTx, account.privateKey)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+
+ expect(result.signatures).to.be.undefined
+ expect(result.feePayerSignatures.length).to.equals(2)
+ expect(decoded.signatures.length).to.equals(2)
+ expect(decoded.feePayerSignatures.length).to.equals(2)
})
})
- context('CAVERJS-UNIT-WALLET-097 : input: privateKey:KlaytnWalletKey, password, {address:valid}', () => {
- it('should encrypt password with privateKey', () => {
+ context('CAVERJS-UNIT-WALLET-231: input: rawTransaction with signatures of sender and fee payer', () => {
+ it('should remove duplicated signatures of sender', async () => {
+ const tx = {
+ type: 'VALUE_TRANSFER',
+ from: account.address,
+ to: '0xd05c5926b0a2f31aadcc9a9cbd3868a50104d834',
+ value: '0x1',
+ gas: '0xdbba0',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
+ const {rawTransaction} = await caver.klay.accounts.signTransaction(tx, [account.privateKey, caver.klay.accounts.create().privateKey])
+ const result = await caver.klay.accounts.signTransaction(rawTransaction, account.privateKey)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+
+ expect(result.signatures.length).to.equals(2)
+ expect(result.feePayerSignatures).to.be.undefined
+ expect(decoded.signatures.length).to.equals(2)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-232: input: rawTransaction with signatures of sender and fee payer', () => {
+ it('should remove duplicated signatures of fee payer', async () => {
+ const rawTransaction = '0x09f9016c819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194127a24ec811aa1e45071a669e5d117a475e68149f88ef845824e44a030accfbec3b577a53103c843744754a98408e7518391a31399bc757610ad1fc5a00eecc65e8f6f1795f7665513442fe30f881ddce12ceb687a8a7d9b65a0eee595f845824e44a006400dc68ab85d838a02e202e2ca52c6a30f11f7fa84f4046e08a940f4c95d1ea061a09e1a2dd6b823c42552d1cf0a4c0e408b4ada2b0236ef14ba0f036e6da262944a804669b2637b18d46e62109ed8edc0dc8526c7f88ef845824e43a0113bf0986a48768e38daeff685ce56766aacf449f2aec8a0c77165777970f954a00717c4d4720fe706a075374f8eb0432f6c9f70c0a6e6267483d0b0cc8100ec07f845824e43a00553c26e9e69541f7feca9484a5af8997c6f55b04bcac315be9c4888213709c4a00d0df6543f53afd0f131283c9a52f3c0a389b65b7a54ffe4c88004ddab74dd58'
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: feePayer.address,
+ chainId: 10000
+ }
+ const result = await caver.klay.accounts.signTransaction(feePayerTx, feePayer.privateKey)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+
+ expect(result.signatures).to.be.undefined
+ expect(result.feePayerSignatures.length).to.equals(2)
+ expect(decoded.signatures.length).to.equals(2)
+ expect(decoded.feePayerSignatures.length).to.equals(2)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-233: input: transaction object with signatures of sender', () => {
+ it('should append signatures when signatures is defined in transaction object', async () => {
+ vtTx.signatures = [
+ [
+ '0x4e44',
+ '0x30accfbec3b577a53103c843744754a98408e7518391a31399bc757610ad1fc5',
+ '0x0eecc65e8f6f1795f7665513442fe30f881ddce12ceb687a8a7d9b65a0eee595'
+ ]
+ ]
+ const result = await caver.klay.accounts.signTransaction(vtTx, account.privateKey)
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+
+ expect(result.signatures.length).to.equals(2)
+ expect(result.feePayerSignatures).to.be.undefined
+ expect(decoded.signatures.length).to.equals(2)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-234: input: rawTransaction with signatures of sender and fee payer', () => {
+ it('should append feePayerSignatures when feePayerSignatures is defined in transaction object', async () => {
+ const rawTransaction = '0x09f8de819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194127a24ec811aa1e45071a669e5d117a475e68149f847f845824e44a030accfbec3b577a53103c843744754a98408e7518391a31399bc757610ad1fc5a00eecc65e8f6f1795f7665513442fe30f881ddce12ceb687a8a7d9b65a0eee595944a804669b2637b18d46e62109ed8edc0dc8526c7f847f845824e43a0113bf0986a48768e38daeff685ce56766aacf449f2aec8a0c77165777970f954a00717c4d4720fe706a075374f8eb0432f6c9f70c0a6e6267483d0b0cc8100ec07'
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: feePayer.address,
+ feePayerSignatures: [
+ [
+ '0x4e44',
+ '0xe5465dd2d07aaf56a43a1ee0dd01583105d8f34f335e27e0ae5321a913871d0d',
+ '0x77f6c873a2a2d94d3501fd8ccc9c9d9cfdcedbde2ce645605c6849bb64be0fcf'
+ ]
+ ]
+ }
+ const result = await caver.klay.accounts.signTransaction(feePayerTx, account.privateKey)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+
+ expect(result.signatures).to.be.undefined
+ expect(result.feePayerSignatures.length).to.equals(3)
+ expect(decoded.signatures.length).to.equals(1)
+ expect(decoded.feePayerSignatures.length).to.equals(3)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-235: input: transaction object with from account accountKeyMultiSig', () => {
+ it('should sign with multiple private key in wallet', async () => {
+ const multiSigKey = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const multiSigAddress = caver.klay.accounts.create().address
+ const multiSigAccount = caver.klay.accounts.createWithAccountKey(multiSigAddress, multiSigKey)
+ caver.klay.accounts.wallet.add(multiSigAccount)
+
+ vtTx.from = multiSigAddress
+
+ const result = await caver.klay.accounts.signTransaction(vtTx)
+
+ expect(result.signatures.length).to.equals(2)
+ expect(result.feePayerSignatures).to.be.undefined
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-236: input: transaction object with from account accountKeyRoleBased', () => {
+ it('should sign with transactionKey', async () => {
+ const keyObject = {
+ transactionKey: [caver.klay.accounts.create().privateKey],
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey,caver.klay.accounts.create().privateKey]
+ }
+ const roleBasedAddress = caver.klay.accounts.create().address
+ const roleBasedAccount = caver.klay.accounts.createWithAccountKey(roleBasedAddress, keyObject)
+ caver.klay.accounts.wallet.add(roleBasedAccount)
+
+ vtTx.from = roleBasedAddress
+
+ const result = await caver.klay.accounts.signTransaction(vtTx)
+
+ expect(result.signatures.length).to.equals(1)
+ expect(result.feePayerSignatures).to.be.undefined
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-237: input: transaction object with from account accountKeyRoleBased', () => {
+ it('should sign with updateKey when transaction is for account update', async () => {
+ const keyObject = {
+ transactionKey: [caver.klay.accounts.create().privateKey],
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey,caver.klay.accounts.create().privateKey]
+ }
+ const roleBasedAddress = caver.klay.accounts.create().address
+ const roleBasedAccount = caver.klay.accounts.createWithAccountKey(roleBasedAddress, keyObject)
+ caver.klay.accounts.wallet.add(roleBasedAccount)
+
+ const updator = caver.klay.accounts.createAccountForUpdate(roleBasedAddress, '0x19d3e96ab579566fa7cbe735cbcad18e2382d44b5e1cb8e8284d0d6e7b37094e')
+ const updateTx = {
+ type: 'ACCOUNT_UPDATE',
+ from: roleBasedAddress,
+ key: updator,
+ gas: 90000,
+ }
+
+ const result = await caver.klay.accounts.signTransaction(updateTx)
+
+ expect(result.signatures.length).to.equals(2)
+ expect(result.feePayerSignatures).to.be.undefined
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-238: input: fee payer transaction object with fee payer account accountKeyRoleBased', () => {
+ it('should sign with feePayerKey when transaction object is fee payer format', async () => {
+ const keyObject = {
+ transactionKey: [caver.klay.accounts.create().privateKey],
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey,caver.klay.accounts.create().privateKey]
+ }
+ const roleBasedAddress = caver.klay.accounts.create().address
+ const roleBasedAccount = caver.klay.accounts.createWithAccountKey(roleBasedAddress, keyObject)
+ caver.klay.accounts.wallet.add(roleBasedAccount)
+
+ const rawTransaction = '0x09f842819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194127a24ec811aa1e45071a669e5d117a475e68149c4c301808080c4c3018080'
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: roleBasedAddress
+ }
+
+ const result = await caver.klay.accounts.signTransaction(feePayerTx)
+
+ expect(result.signatures).to.be.undefined
+ expect(result.feePayerSignatures.length).to.equals(3)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-239: input: rawTransaction with signatures of sender and fee payer with different fee payer', () => {
+ it('should remove duplicated signatures of fee payer', async () => {
+ const rawTransaction = '0x09f9016c819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194127a24ec811aa1e45071a669e5d117a475e68149f88ef845824e44a030accfbec3b577a53103c843744754a98408e7518391a31399bc757610ad1fc5a00eecc65e8f6f1795f7665513442fe30f881ddce12ceb687a8a7d9b65a0eee595f845824e44a006400dc68ab85d838a02e202e2ca52c6a30f11f7fa84f4046e08a940f4c95d1ea061a09e1a2dd6b823c42552d1cf0a4c0e408b4ada2b0236ef14ba0f036e6da262944a804669b2637b18d46e62109ed8edc0dc8526c7f88ef845824e43a0113bf0986a48768e38daeff685ce56766aacf449f2aec8a0c77165777970f954a00717c4d4720fe706a075374f8eb0432f6c9f70c0a6e6267483d0b0cc8100ec07f845824e43a00553c26e9e69541f7feca9484a5af8997c6f55b04bcac315be9c4888213709c4a00d0df6543f53afd0f131283c9a52f3c0a389b65b7a54ffe4c88004ddab74dd58'
+ const newFeePayer = caver.klay.accounts.create()
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: newFeePayer.address
+ }
+
+ const errorMessage = `Invalid feePayer: The fee payer(${feePayer.address}) included in the transaction does not match the fee payer(${newFeePayer.address}) you want to sign.`
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, newFeePayer.privateKey)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-240: input: legacy rawTransaction with signatures of sender', () => {
+ it('should throw error becuase encoded legacy transaction do not contain from', async () => {
+ const rawTransaction = '0xf867808505d21dba00830dbba09430d8d4217145ba3f6cde24ec28c64c9120f2bdfb0180820feaa03ae52bd8b105a138f179ecc85c94296c851922775ef15d9d775b6cc1971ad19ca07164eff9bf7ac3f9a80d1578ee48ccaa08fe127d21ce00a5b3110b774289695b'
+
+ const errorMessage = `"from" is missing`
+ await expect(caver.klay.accounts.signTransaction(rawTransaction, account.privateKey)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-241: input: legacy rawTransaction with signatures of sender', () => {
+ it('should throw error becuase encoded legacy transaction do not contain from', async () => {
+ txObj.signatures = [
+ '0x0fea',
+ '0x3ae52bd8b105a138f179ecc85c94296c851922775ef15d9d775b6cc1971ad19c',
+ '0x7164eff9bf7ac3f9a80d1578ee48ccaa08fe127d21ce00a5b3110b774289695b'
+ ]
+
+ const errorMessage = `Legacy transaction cannot be signed with multiple keys.`
+ await expect(caver.klay.accounts.signTransaction(txObj, account.privateKey)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-242: input: rawTransaction without fee payer in tx object', () => {
+ it('should throw error when fee payer is not defined', async () => {
+ const rawTransaction = '0x09f9016c819a8505d21dba00830dbba094d05c5926b0a2f31aadcc9a9cbd3868a50104d8340194127a24ec811aa1e45071a669e5d117a475e68149f88ef845824e44a030accfbec3b577a53103c843744754a98408e7518391a31399bc757610ad1fc5a00eecc65e8f6f1795f7665513442fe30f881ddce12ceb687a8a7d9b65a0eee595f845824e44a006400dc68ab85d838a02e202e2ca52c6a30f11f7fa84f4046e08a940f4c95d1ea061a09e1a2dd6b823c42552d1cf0a4c0e408b4ada2b0236ef14ba0f036e6da262944a804669b2637b18d46e62109ed8edc0dc8526c7f88ef845824e43a0113bf0986a48768e38daeff685ce56766aacf449f2aec8a0c77165777970f954a00717c4d4720fe706a075374f8eb0432f6c9f70c0a6e6267483d0b0cc8100ec07f845824e43a00553c26e9e69541f7feca9484a5af8997c6f55b04bcac315be9c4888213709c4a00d0df6543f53afd0f131283c9a52f3c0a389b65b7a54ffe4c88004ddab74dd58'
+ const feePayerTx = { senderRawTransaction: rawTransaction }
+
+ const errorMessage = `Invalid fee payer: undefined`
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, account.privateKey)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-243: input: update transaction object with AccountForUpdate with mismatched address', () => {
+ it('should throw error when address is not matched', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdate(caver.klay.accounts.create().address, '0x19d3e96ab579566fa7cbe735cbcad18e2382d44b5e1cb8e8284d0d6e7b37094e')
+ const updateTx = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 90000
+ }
+
+ const errorMessage = `The value of the from field of the transaction does not match the address of AccountForUpdate.`
+ await expect(caver.klay.accounts.signTransaction(updateTx)).to.be.rejectedWith(errorMessage)
+ })
+ })
+})
+
+describe('caver.klay.accounts.feePayerSignTransaction', () => {
+ let txObj
+ let sender, feePayer
+ let withoutSig = '0x09f842819a8505d21dba00830dbba094d2553e0508d481892aa1b481b3ac29aba5c7fb4d01946f9a8851feca74f6694a12d11c9684f0b5c1d3b6c4c301808080c4c3018080'
+ let withSenderSig = '0x09f90114819a8505d21dba00830dbba094d2553e0508d481892aa1b481b3ac29aba5c7fb4d01946f9a8851feca74f6694a12d11c9684f0b5c1d3b6f8d5f845820feaa06d2b6c9530a9f311a3ea42b2fc474ce0decefc65a88510161a392eef029714b8a0360fff97c9818dabb7d25ce4dc1afb4a5cca00409d79c0e3f76e151dec542701f845820feaa0fb24ef24dd6d10a9410417c56a5a8b09575d0611251f6f03b9199b4004cee087a02a1b040cc80942deda8523c2bf24364b3b2ea1a6d33165fde35d86a1c247ddfef845820fe9a0ae0d77d98aec5880efc7bd943fb58ea691e3023975e757a720586d3781284d9aa077072cfa045f872a1e33840e28ed2704f8a6d77f5077171b6b45e3ec7a671ddf80c4c3018080'
+ let withFeePayerSig = '0x09f90128819a8505d21dba00830dbba094d2553e0508d481892aa1b481b3ac29aba5c7fb4d01946f9a8851feca74f6694a12d11c9684f0b5c1d3b6c4c3018080944a804669b2637b18d46e62109ed8edc0dc8526c7f8d5f845824e43a003df110e3d328d75ac8b05ff29e3b00b65c4402bc0f2556590077e3ffd699f85a0395252d8b2bf6a5b1b997d41694bb84b6e30bc846263b6fc55a023a66ef68630f845824e44a08eb3eb4414fe1b5f0f1baaa0192a9ee018b6132b8fc965918318bdd7087acb42a0211741eae45dae25659894ada38c0c5b03483337148182d2951e7386cb2c2ab8f845824e44a0691eaea2dead54efce368395f2394a9cbc7b3d68effd5c5b3ba9bee7b57dfa59a00b7cbe6b8ebcf013a197f6ee81e3c3e180cf62c940fd8f9282d3f6814d710c9d'
+ let withBothSig = '0x09f901fa819a8505d21dba00830dbba094d2553e0508d481892aa1b481b3ac29aba5c7fb4d01946f9a8851feca74f6694a12d11c9684f0b5c1d3b6f8d5f845820feaa06d2b6c9530a9f311a3ea42b2fc474ce0decefc65a88510161a392eef029714b8a0360fff97c9818dabb7d25ce4dc1afb4a5cca00409d79c0e3f76e151dec542701f845820feaa0fb24ef24dd6d10a9410417c56a5a8b09575d0611251f6f03b9199b4004cee087a02a1b040cc80942deda8523c2bf24364b3b2ea1a6d33165fde35d86a1c247ddfef845820fe9a0ae0d77d98aec5880efc7bd943fb58ea691e3023975e757a720586d3781284d9aa077072cfa045f872a1e33840e28ed2704f8a6d77f5077171b6b45e3ec7a671ddf944a804669b2637b18d46e62109ed8edc0dc8526c7f8d5f845824e43a0e0cd799758d93f3ac9ff1fd5055bff9e7c7e664599f5615c5016c88b7c8edea5a00353e206c246a10a5ac4388924e8eb42fedbbbfb674efa8441f0b0c4957cf05df845824e43a04c5c84dcace452a5bde411d7888d116f0a993a579b11a79cc9ed7fa6e9adb421a023d33c71fced04801643d4d58c9fbb184625cbfaa8dab5a8e25ec5e84d25452af845824e44a0051fad2c19ee4936721b5985ebdf354d069f3e9e3d3c832751caf20f69202c20a03f340e42613e6868cff9b3312fa0f671523b340d469d7d69f6573724bd6f6047'
+
+ beforeEach(() => {
+ let senderRoleBasedKey = { transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
+ let feePayerRoleBasedKey = { feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
+
+ sender = caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey('0x6f9a8851feca74f6694a12d11c9684f0b5c1d3b6', senderRoleBasedKey))
+ feePayer = caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey('0x4a804669b2637b18d46e62109ed8edc0dc8526c7', feePayerRoleBasedKey))
+
+ txObj = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: sender.address,
+ to: '0xd2553e0508d481892aa1b481b3ac29aba5c7fb4d',
+ value: '0x1',
+ gas: '0xdbba0',
+ chainId: '0x7e3',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
+ })
+
+ context('CAVERJS-UNIT-WALLET-273: input: tx object without signatures and feePayer', () => {
+ it('should sign with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const result = await caver.klay.accounts.feePayerSignTransaction(txObj, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-274: input: tx object(signatures) and feePayer', () => {
+ it('should sign with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ txObj.signatures = [
+ [
+ '0x0fea',
+ '0x6d2b6c9530a9f311a3ea42b2fc474ce0decefc65a88510161a392eef029714b8',
+ '0x360fff97c9818dabb7d25ce4dc1afb4a5cca00409d79c0e3f76e151dec542701'
+ ]
+ ]
+ const result = await caver.klay.accounts.feePayerSignTransaction(txObj, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(txObj.signatures.length)
+ expect(decoded.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-275: input: tx object(feePayer/feePayerSignatures) and feePayer', () => {
+ it('should append with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ txObj.feePayer = feePayer.address
+ txObj.feePayerSignatures = [
+ [
+ '0x4e44',
+ '0x7328aa537646bfffebfd6f006f9a6e0520d077cb898225e4fa44f52c54c4c2f2',
+ '0x6302349a19b4b7b9d82798eac1d4716cdaa239e490fd8427f49c9bca4dd4b6a2'
+ ]
+ ]
+ const result = await caver.klay.accounts.feePayerSignTransaction(txObj, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length + 1)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length + 1)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-276: input: tx object(feePayerSignatures) and feePayer', () => {
+ it('should set feePayer with value of feePayer parameter and append feePayerSignatures', async () => {
+ txObj.feePayerSignatures = [
+ [
+ '0x4e44',
+ '0x7328aa537646bfffebfd6f006f9a6e0520d077cb898225e4fa44f52c54c4c2f2',
+ '0x6302349a19b4b7b9d82798eac1d4716cdaa239e490fd8427f49c9bca4dd4b6a2'
+ ]
+ ]
+ const result = await caver.klay.accounts.feePayerSignTransaction(txObj, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length + 1)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length + 1)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-277: input: tx object(signatures/feePayer/feePayerSignatures) and feePayer', () => {
+ it('should append with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ txObj.signatures = [
+ [
+ '0x0fea',
+ '0x6d2b6c9530a9f311a3ea42b2fc474ce0decefc65a88510161a392eef029714b8',
+ '0x360fff97c9818dabb7d25ce4dc1afb4a5cca00409d79c0e3f76e151dec542701'
+ ]
+ ]
+ txObj.feePayer = feePayer.address
+ txObj.feePayerSignatures = [
+ [
+ '0x4e44',
+ '0x7328aa537646bfffebfd6f006f9a6e0520d077cb898225e4fa44f52c54c4c2f2',
+ '0x6302349a19b4b7b9d82798eac1d4716cdaa239e490fd8427f49c9bca4dd4b6a2'
+ ]
+ ]
+ const result = await caver.klay.accounts.feePayerSignTransaction(txObj, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length + 1)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(txObj.signatures.length)
+ expect(decoded.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length + 1)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-278: input: tx object(signatures/feePayer/feePayerSignatures), feePayer and privateKey', () => {
+ it('should append with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ txObj.signatures = [
+ [
+ '0x0fea',
+ '0x6d2b6c9530a9f311a3ea42b2fc474ce0decefc65a88510161a392eef029714b8',
+ '0x360fff97c9818dabb7d25ce4dc1afb4a5cca00409d79c0e3f76e151dec542701'
+ ]
+ ]
+ txObj.feePayer = feePayer.address
+ txObj.feePayerSignatures = [
+ [
+ '0x4e44',
+ '0x7328aa537646bfffebfd6f006f9a6e0520d077cb898225e4fa44f52c54c4c2f2',
+ '0x6302349a19b4b7b9d82798eac1d4716cdaa239e490fd8427f49c9bca4dd4b6a2'
+ ]
+ ]
+ const result = await caver.klay.accounts.feePayerSignTransaction(txObj, feePayer.address, feePayer.feePayerKey[0])
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(2)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(txObj.signatures.length)
+ expect(decoded.feePayerSignatures.length).to.equals(2)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-279: input: tx object(feePayer), feePayer and privateKey', () => {
+ it('should throw error when feePayer is not matched', async () => {
+ txObj.feePayer = caver.klay.accounts.create().address
+
+ const errorMessage = 'Invalid parameter: The address of fee payer does not match.'
+
+ await expect(caver.klay.accounts.feePayerSignTransaction(txObj, feePayer.address)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-280: input: tx object(without nonce) and feePayer', () => {
+ it('should return signature and rawTransaction', async () => {
+ const tx = Object.assign({}, txObj)
+ delete tx.nonce
+
+ const result = await caver.klay.accounts.feePayerSignTransaction(tx, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-281: input: tx object(without nonce), feePayer and privateKey', () => {
+ it('should return signature and rawTransaction', async () => {
+ const tx = Object.assign({}, txObj)
+ delete tx.nonce
+
+ const result = await caver.klay.accounts.feePayerSignTransaction(tx, feePayer.address, feePayer.feePayerKey[0])
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(1)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.feePayerSignatures.length).to.equals(1)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-282: input: tx object(without gasPrice) and feePayer', () => {
+ it('should return signature and rawTransaction', async () => {
+ const tx = Object.assign({}, txObj)
+ delete tx.gasPrice
+
+ const result = await caver.klay.accounts.feePayerSignTransaction(tx, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-283: input: tx object(without gasPrice), feePayer and privateKey', () => {
+ it('should return signature and rawTransaction', async () => {
+ const tx = Object.assign({}, txObj)
+ delete tx.gasPrice
+
+ const result = await caver.klay.accounts.feePayerSignTransaction(tx, feePayer.address, feePayer.feePayerKey[0])
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(1)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.feePayerSignatures.length).to.equals(1)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-284: input: tx object(without chainId) and feePayer', () => {
+ it('should return signature and rawTransaction', async () => {
+ const tx = Object.assign({}, txObj)
+ delete tx.chainId
+
+ const result = await caver.klay.accounts.feePayerSignTransaction(tx, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-285: input: tx object(without chainId), feePayer and privateKey', () => {
+ it('should return signature and rawTransaction', async () => {
+ const tx = Object.assign({}, txObj)
+ delete tx.chainId
+
+ const result = await caver.klay.accounts.feePayerSignTransaction(tx, feePayer.address, feePayer.feePayerKey[0])
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(1)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.feePayerSignatures.length).to.equals(1)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-286: input: tx object, feePayer and invalid privateKey', () => {
+ it('should throw error when private key is invalid', async () => {
+ const invalid = '0x01'
+ const errorMessage = `Invalid private key(${invalid.slice(2)})`
+
+ await expect(caver.klay.accounts.feePayerSignTransaction(txObj, feePayer.address, invalid)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-287: input: tx object, invalid feePayer address', () => {
+ it('should throw error when private key is invalid', async () => {
+ const invalid = 'feePayer'
+ const errorMessage = `Invalid fee payer address : ${invalid}`
+
+ await expect(caver.klay.accounts.feePayerSignTransaction(txObj, invalid)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-288: input: tx object(without from) and feePayer', () => {
+ it('should throw error when invalid transaction', async () => {
+ const invalid = Object.assign({}, txObj)
+ delete invalid.from
+
+ const errorMessage = '"from" is missing'
+ await expect(caver.klay.accounts.feePayerSignTransaction(invalid, feePayer.address)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-289: input: tx object(without from), feePayer and privateKey', () => {
+ it('should throw error when invalid transaction', async () => {
+ const invalid = Object.assign({}, txObj)
+ delete invalid.from
+
+ const errorMessage = '"from" is missing'
+ await expect(caver.klay.accounts.feePayerSignTransaction(invalid, feePayer.address, feePayer.feePayerKey[0])).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-290: input: RLP encoded rawTransaction(without signatures) string and feePayer', () => {
+ it('should sign with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const result = await caver.klay.accounts.feePayerSignTransaction(withoutSig, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(3)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-291: input: RLP encoded rawTransaction(with signatures of sender) string and feePayer', () => {
+ it('should sign with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const result = await caver.klay.accounts.feePayerSignTransaction(withSenderSig, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(3)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-292: input: RLP encoded rawTransaction(with signatures of fee payer) string and feePayer', () => {
+ it('should append with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const result = await caver.klay.accounts.feePayerSignTransaction(withFeePayerSig, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(6)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-293: input: RLP encoded rawTransaction(with signatures of sender and fee payer) string and feePayer', () => {
+ it('should append with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const result = await caver.klay.accounts.feePayerSignTransaction(withBothSig, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(6)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(6)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-294: input: RLP encoded rawTransaction(with signatures of sender and fee payer) string, feePayer and privateKey', () => {
+ it('should append with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const result = await caver.klay.accounts.feePayerSignTransaction(withBothSig, feePayer.address, feePayer.feePayerKey[0])
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(4)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(4)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-295: input: RLP encoded rawTransaction(with signatures of sender and fee payer) string with invalid feePayer', () => {
+ it('should throw error when address of fee payer is invalid', async () => {
+ const invalid = 'feePayer'
+ const errorMessage = `Invalid fee payer address : ${invalid}`
+
+ await expect(caver.klay.accounts.feePayerSignTransaction(withBothSig, invalid)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-296: input: RLP encoded rawTransaction(with signatures of sender and fee payer) string, feePayer and invalid private key', () => {
+ it('should throw error when private key is invalid', async () => {
+ const invalid = '0x01'
+ const errorMessage = `Invalid private key(${invalid.slice(2)})`
+
+ await expect(caver.klay.accounts.feePayerSignTransaction(withBothSig, feePayer.address, invalid)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-297: input: fee payer format transaction(without signatures) string and feePayer', () => {
+ it('should sign with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const feePayerTx = {
+ senderRawTransaction: withoutSig,
+ feePayer: feePayer.address,
+ }
+ const result = await caver.klay.accounts.feePayerSignTransaction(feePayerTx, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(3)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-298: input: fee payer format transaction(with signatures of sender) string and feePayer', () => {
+ it('should sign with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const feePayerTx = {
+ senderRawTransaction: withSenderSig,
+ feePayer: feePayer.address,
+ }
+ const result = await caver.klay.accounts.feePayerSignTransaction(feePayerTx, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(3)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-299: input: fee payer format transaction(with signatures of fee payer) string and feePayer', () => {
+ it('should append with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const feePayerTx = {
+ senderRawTransaction: withFeePayerSig,
+ feePayer: feePayer.address,
+ }
+ const result = await caver.klay.accounts.feePayerSignTransaction(feePayerTx, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(6)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-300: input: fee payer format transaction(with signatures of sender and fee payer) string and feePayer', () => {
+ it('should append with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const feePayerTx = {
+ senderRawTransaction: withBothSig,
+ feePayer: feePayer.address,
+ }
+ const result = await caver.klay.accounts.feePayerSignTransaction(feePayerTx, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(6)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(6)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-301: input: fee payer format transaction(with signatures of sender and fee payer) string, feePayer and privateKey', () => {
+ it('should append with feePayerKey of feePayer and return feePayerSignatures and rawTransaction', async () => {
+ const feePayerTx = {
+ senderRawTransaction: withBothSig,
+ feePayer: feePayer.address,
+ }
+ const result = await caver.klay.accounts.feePayerSignTransaction(feePayerTx, feePayer.address, feePayer.feePayerKey[0])
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(4)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(4)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-302: input: fee payer tx object(without feePayer) and feePayer', () => {
+ it('should set feePayer information through feePayer parameter', async () => {
+ const feePayerTx = { senderRawTransaction: withoutSig }
+
+ const result = await caver.klay.accounts.feePayerSignTransaction(feePayerTx, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-303: input: fee payer tx object(with 0x feePayer) and feePayer', () => {
+ it('should set feePayer information through feePayer parameter', async () => {
+ const feePayerTx = { senderRawTransaction: withoutSig, feePayer: '0x' }
+
+ const result = await caver.klay.accounts.feePayerSignTransaction(feePayerTx, feePayer.address)
+
+ const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(result.feePayerSignatures.length).to.equals(feePayer.feePayerKey.length)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-304: input: fee payer format transaction(with signatures of sender and fee payer) string with invalid feePayer', () => {
+ it('should throw error when address of fee payer is invalid', async () => {
+ const invalid = 'feePayer'
+ const feePayerTx = {
+ senderRawTransaction: withBothSig,
+ feePayer: invalid,
+ }
+ const errorMessage = `Invalid fee payer address : ${invalid}`
+
+ await expect(caver.klay.accounts.feePayerSignTransaction(feePayerTx, invalid)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-305: input: fee payer format transaction(with signatures of sender and fee payer) string with not matched feePayer', () => {
+ it('should throw error when address of fee payer in transaction object is not matched with fee payer parameter', async () => {
+ const address = caver.klay.accounts.create().address
+ const feePayerTx = {
+ senderRawTransaction: withBothSig,
+ feePayer: caver.klay.accounts.create().address,
+ }
+ const errorMessage = `Invalid parameter: The address of fee payer does not match.`
+
+ await expect(caver.klay.accounts.feePayerSignTransaction(feePayerTx, address)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-306: input: fee payer format transaction(with signatures of sender and fee payer) string, feePayer and invalid private key', () => {
+ it('should throw error when private key is invalid', async () => {
+ const invalid = '0x01'
+ const feePayerTx = {
+ senderRawTransaction: withBothSig,
+ feePayer: feePayer.address,
+ }
+ const errorMessage = `Invalid private key(${invalid.slice(2)})`
+
+ await expect(caver.klay.accounts.feePayerSignTransaction(feePayerTx, feePayer.address, invalid)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-376: input: non fee delegated transaction, fee payer address', () => {
+ it('should throw error when private key is invalid', async () => {
+ const nonFeeDelegated = {
+ type: 'VALUE_TRANSFER',
+ from: sender.address,
+ to: '0xd2553e0508d481892aa1b481b3ac29aba5c7fb4d',
+ value: '0x1',
+ gas: '0xdbba0',
+ chainId: '0x7e3',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
+ const errorMessage = `Failed to sign transaction with fee payer: invalid transaction type(VALUE_TRANSFER)`
+
+ await expect(caver.klay.accounts.feePayerSignTransaction(nonFeeDelegated, feePayer.address)).to.be.rejectedWith(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-377: input: non fee delegated transaction, fee payer address', () => {
+ it('should throw error when private key is invalid', async () => {
+ const nonFeeDelegated = {
+ type: 'VALUE_TRANSFER',
+ from: sender.address,
+ to: '0xd2553e0508d481892aa1b481b3ac29aba5c7fb4d',
+ value: '0x1',
+ gas: '0xdbba0',
+ chainId: '0x7e3',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(nonFeeDelegated)
+ const errorMessage = `Failed to split fee payer: not a fee delegated transaction type('VALUE_TRANSFER')`
+
+ await expect(caver.klay.accounts.feePayerSignTransaction(rawTransaction, feePayer.address)).to.be.rejectedWith(errorMessage)
+ })
+ })
+})
+
+describe('caver.klay.accounts.getRawTransactionWithSignatures', () => {
+ let vtTx, feeDelegatedTx
+ let sender, feePayer
+
+ beforeEach(() => {
+ let senderRoleBasedKey = { transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
+ let feePayerRoleBasedKey = { feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
+
+ sender = caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey('0x6f9a8851feca74f6694a12d11c9684f0b5c1d3b6', senderRoleBasedKey))
+ feePayer = caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey('0x4a804669b2637b18d46e62109ed8edc0dc8526c7', feePayerRoleBasedKey))
+
+ vtTx = {
+ type: 'VALUE_TRANSFER',
+ from: sender.address,
+ to: '0xd2553e0508d481892aa1b481b3ac29aba5c7fb4d',
+ value: '0x1',
+ gas: '0xdbba0',
+ chainId: '0x7e3',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
+
+ feeDelegatedTx = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: sender.address,
+ to: '0xd2553e0508d481892aa1b481b3ac29aba5c7fb4d',
+ value: '0x1',
+ gas: '0xdbba0',
+ chainId: '0x7e3',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
+ })
+
+ context('CAVERJS-UNIT-WALLET-307: input: value transfer tx object with signatures', () => {
+ it('should return valid rawTransaction', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(vtTx)
+ vtTx.signatures = signResult.signatures
+
+ let result = await caver.klay.accounts.getRawTransactionWithSignatures(vtTx)
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'signatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(signResult.rawTransaction).to.equals(result.rawTransaction)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-308: input: fee delegated value transfer tx object with signatures', () => {
+ it('should return valid rawTransaction', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx)
+ feeDelegatedTx.signatures = signResult.signatures
+
+ let result = await caver.klay.accounts.getRawTransactionWithSignatures(feeDelegatedTx)
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'signatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ expect(signResult.rawTransaction).to.equals(result.rawTransaction)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-309: input: fee delegated value transfer tx object with feePayerSignatures', () => {
+ it('should return valid rawTransaction', async () => {
+ const tx = Object.assign({}, feeDelegatedTx)
+
+ let feePayerSignResult = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address)
+
+ tx.feePayer = feePayer.address
+ tx.feePayerSignatures = feePayerSignResult.feePayerSignatures
+
+ let result = await caver.klay.accounts.getRawTransactionWithSignatures(tx)
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+ expect(result.feePayerSignatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(caver.utils.isEmptySig(decoded.signatures)).to.be.true
+ expect(decoded.feePayerSignatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-310: input: fee delegated value transfer tx object with signatures and feePayerSignatures', () => {
+ it('should return valid rawTransaction', async () => {
+ const tx = Object.assign({}, feeDelegatedTx)
+
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx)
+
+ let feePayerSignResult = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address)
+
+ tx.signatures = signResult.signatures
+ tx.feePayer = feePayer.address
+ tx.feePayerSignatures = feePayerSignResult.feePayerSignatures
+
+ let result = await caver.klay.accounts.getRawTransactionWithSignatures(tx)
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'signatures', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+ expect(result.signatures.length).to.equals(3)
+ expect(result.feePayerSignatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-311: input: fee payer tx format(includes signatures) object with signatures', () => {
+ it('should return valid rawTransaction', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[0])
+ let signResult2 = await caver.klay.accounts.signTransaction(feeDelegatedTx, [sender.transactionKey[1], sender.transactionKey[2]])
+
+ const feePayerTx = {
+ senderRawTransaction: signResult.rawTransaction,
+ feePayer: feePayer.address,
+ signatures: signResult2.signatures
+ }
+ let result = await caver.klay.accounts.getRawTransactionWithSignatures(feePayerTx)
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'signatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+ expect(result.signatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-312: input: fee payer tx format(includes signatures and feePayerSignatures) object with signatures', () => {
+ it('should return valid rawTransaction', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[0])
+ let signResult2 = await caver.klay.accounts.signTransaction(feeDelegatedTx, [sender.transactionKey[1], sender.transactionKey[2]])
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(signResult.rawTransaction, feePayer.address, feePayer.feePayerKey[0])
+
+ const feePayerTx = {
+ senderRawTransaction: feePayerSigned.rawTransaction,
+ feePayer: feePayer.address,
+ signatures: signResult2.signatures
+ }
+ let result = await caver.klay.accounts.getRawTransactionWithSignatures(feePayerTx)
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'signatures', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+ expect(result.signatures.length).to.equals(3)
+ expect(result.feePayerSignatures.length).to.equals(1)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(1)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-313: input: fee payer tx format(includes signatures and feePayerSignatures) object with signatures and feePayerSignatures', () => {
+ it('should return valid rawTransaction', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[0])
+ let signResult2 = await caver.klay.accounts.signTransaction(feeDelegatedTx, [sender.transactionKey[1], sender.transactionKey[2]])
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(signResult.rawTransaction, feePayer.address, feePayer.feePayerKey[0])
+ let feePayerSigned2 = await caver.klay.accounts.feePayerSignTransaction(signResult.rawTransaction, feePayer.address, [feePayer.feePayerKey[1], feePayer.feePayerKey[2]])
+
+ const feePayerTx = {
+ senderRawTransaction: feePayerSigned.rawTransaction,
+ feePayer: feePayer.address,
+ signatures: signResult2.signatures,
+ feePayerSignatures: feePayerSigned2.feePayerSignatures
+ }
+ let result = await caver.klay.accounts.getRawTransactionWithSignatures(feePayerTx)
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'signatures', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+ expect(result.signatures.length).to.equals(3)
+ expect(result.feePayerSignatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-314: input: fee delegated value transfer tx object without signatures and feePayerSignatures', () => {
+ it('should throw error when there is no signatures information', async () => {
+ const errorMessage = `There are no signatures or feePayerSignatures defined in the transaction object.`
+
+ await expect(caver.klay.accounts.getRawTransactionWithSignatures(feeDelegatedTx)).to.be.rejectedWith(errorMessage)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-315: input: fee delegated value transfer tx object without feePayerSignatures only(no feePayer)', () => {
+ it('should throw error when tx defines feePayerSignatures only without feePayer', async () => {
+ const tx = Object.assign({}, feeDelegatedTx)
+ let feePayerSignResult = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address)
+ tx.feePayerSignatures = feePayerSignResult.feePayerSignatures
+
+ const errorMessage = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.getRawTransactionWithSignatures(tx)).to.be.rejectedWith(errorMessage)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-316: input: value transfer tx object with feePayer', () => {
+ it('should throw error when non-feeDelegated tx defines feePayer', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(vtTx)
+ vtTx.signatures = signResult.signatures
+ vtTx.feePayer = feePayer.address
+
+ const errorMessage = `"feePayer" cannot be used with ${vtTx.type} transaction`
+
+ await expect(caver.klay.accounts.getRawTransactionWithSignatures(vtTx)).to.be.rejectedWith(errorMessage)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-317: input: value transfer tx object with feePayerSignatures', () => {
+ it('should throw error when non-feeDelegated tx defines feePayerSignatures', async () => {
+ let feePayerSignResult = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address)
+ vtTx.feePayerSignatures = feePayerSignResult.feePayerSignatures
+
+ const errorMessage = `"feePayerSignatures" cannot be used with ${vtTx.type} transaction`
+
+ await expect(caver.klay.accounts.getRawTransactionWithSignatures(vtTx)).to.be.rejectedWith(errorMessage)
+ }).timeout(200000)
+ })
+})
+
+describe('caver.klay.accounts.combineSignatures', () => {
+ let feeDelegatedTx
+ let sender, feePayer
+
+ beforeEach(() => {
+ let senderRoleBasedKey = { transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
+ let feePayerRoleBasedKey = { feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
+
+ sender = caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey('0x6f9a8851feca74f6694a12d11c9684f0b5c1d3b6', senderRoleBasedKey))
+ feePayer = caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey('0x4a804669b2637b18d46e62109ed8edc0dc8526c7', feePayerRoleBasedKey))
+
+ feeDelegatedTx = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: sender.address,
+ to: '0xd2553e0508d481892aa1b481b3ac29aba5c7fb4d',
+ value: '0x1',
+ gas: '0xdbba0',
+ chainId: '0x7e3',
+ gasPrice: '0x5d21dba00',
+ nonce: '0x9a',
+ }
+ })
+
+ context('CAVERJS-UNIT-WALLET-318: input: RLP encoded raw transaction string(includes signatures of sender only)', () => {
+ it('should combine signatures and return valid rawTransaction', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[0])
+ let signResult2 = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[1])
+ let signResult3 = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[2])
+
+ let result = await caver.klay.accounts.combineSignatures([signResult.rawTransaction, signResult2.rawTransaction, signResult3.rawTransaction])
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'signatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+ expect(result.signatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-319: input: RLP encoded raw transaction string(includes signatures of fee payer only)', () => {
+ it('should combine signatures and return valid rawTransaction', async () => {
+ let feePayerSignResult = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address, feePayer.feePayerKey[0])
+ let feePayerSignResult2 = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address, feePayer.feePayerKey[1])
+ let feePayerSignResult3 = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address, feePayer.feePayerKey[2])
+
+ let result = await caver.klay.accounts.combineSignatures([feePayerSignResult.rawTransaction, feePayerSignResult2.rawTransaction, feePayerSignResult3.rawTransaction])
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+ expect(result.feePayerSignatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.feePayerSignatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-320: input: RLP encoded raw transaction string(includes signatures of sender and fee payer)', () => {
+ it('should combine signatures and return valid rawTransaction', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx)
+ let feePayerSignResult = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address)
+
+ let result = await caver.klay.accounts.combineSignatures([signResult.rawTransaction, feePayerSignResult.rawTransaction])
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'signatures', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+ expect(result.signatures.length).to.equals(3)
+ expect(result.feePayerSignatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-321: input: RLP encoded raw transaction string(includes duplicated signatures of sender and fee payer)', () => {
+ it('should remove duplicated signatures return valid rawTransaction', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx)
+ let signResult2 = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[0])
+ let signResult3 = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[1])
+ let signResult4 = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[2])
+
+ let feePayerSignResult = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address)
+ let feePayerSignResult2 = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address, feePayer.feePayerKey[0])
+ let feePayerSignResult3 = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address, feePayer.feePayerKey[1])
+ let feePayerSignResult4 = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedTx, feePayer.address, feePayer.feePayerKey[2])
+
+ let rawArray = [
+ signResult.rawTransaction,
+ signResult2.rawTransaction,
+ signResult3.rawTransaction,
+ signResult4.rawTransaction,
+ feePayerSignResult.rawTransaction,
+ feePayerSignResult2.rawTransaction,
+ feePayerSignResult3.rawTransaction,
+ feePayerSignResult4.rawTransaction
+ ]
+ let result = await caver.klay.accounts.combineSignatures(rawArray)
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'signatures', 'feePayerSignatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+ expect(result.signatures.length).to.equals(3)
+ expect(result.feePayerSignatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ expect(decoded.feePayerSignatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-386: input: RLP encoded raw transaction string(includes signatures of sender only)', () => {
+ it('should remove duplicated signatures return valid rawTransaction', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx)
+ let signResult2 = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[0])
+ let signResult3 = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[1])
+ let signResult4 = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[2])
+
+ let rawArray = [
+ signResult.rawTransaction,
+ signResult2.rawTransaction,
+ signResult3.rawTransaction,
+ signResult4.rawTransaction,
+ ]
+ let result = await caver.klay.accounts.combineSignatures(rawArray)
+
+ const keys = ['rawTransaction', 'txHash', 'senderTxHash', 'signatures']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+ expect(result.signatures.length).to.equals(3)
+
+ const decoded = caver.klay.decodeTransaction(result.rawTransaction)
+ expect(decoded.signatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-387: input: not array', () => {
+ it('should throw error when parameter is not array', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx)
+
+ const expectedError = 'The parameter of the combineSignatures function must be an array of RLP encoded transaction strings.'
+ await expect(caver.klay.accounts.combineSignatures(signResult.rawTransaction, (error, result) => {
+ expect(error).not.to.be.undefined
+ expect(result).to.be.undefined
+ })).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+ })
+
+ context('CAVERJS-UNIT-WALLET-388: input: different RLP encoded transaction', () => {
+ it('should throw error when contents of transaction is not same', async () => {
+ let signResult = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[0])
+ feeDelegatedTx.value = 2
+ let signResult2 = await caver.klay.accounts.signTransaction(feeDelegatedTx, sender.transactionKey[2])
+
+ const expectedError = 'Failed to combineSignatures: Signatures that sign to different transaction cannot be combined.'
+ await expect(caver.klay.accounts.combineSignatures([signResult.rawTransaction, signResult2.rawTransaction], (error, result) => {
+ expect(error).not.to.be.undefined
+ expect(result).to.be.undefined
+ })).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+ })
+})
+
+describe('caver.klay.accounts.recoverTransaction', () => {
+ let account
+ let rawTx
+
+ beforeEach(async () => {
+ account = caver.klay.accounts.create()
+
+ const txObj = {
+ from: account.address,
+ nonce: '0x0',
+ to: setting.toAddress,
+ gas: setting.gas,
+ gasPrice: setting.gasPrice,
+ value: '0x1'
+ }
+ const signedTx = await account.signTransaction(txObj)
+ rawTx = signedTx.rawTransaction
+ })
+
+ context('CAVERJS-UNIT-WALLET-029 : rawTransaction', () => {
+ it('should return valid address', () => {
+ const result = caver.klay.accounts.recoverTransaction(rawTx)
+ expect(result).to.equal(account.address)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-030 : rawTransaction:invalid', () => {
+ it('should not equal to account.address', () => {
+ const invalid = rawTx.slice(0, -2)
+ const result = caver.klay.accounts.recoverTransaction(invalid)
+ expect(result).to.not.equal(account.addrss)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-104 : rawTransaction: leading zeroes of the signature are trimmed', () => {
+ it('should equal to account.address', async () => {
+ const transaction = {
+ from: '0x13b0d8316F0c3cE0C3C51Ebb586A14d7d90112fD',
+ nonce: '0x0',
+ to: '0x30d8d4217145ba3f6cde24ec28c64c9120f2bdfb',
+ gas: 900000,
+ gasPrice: 25000000000,
+ value: '0x1',
+ chainId: 10000,
+ }
+
+ let privateKey = '0x72d72a46401220f08ccb1b17b550feb816840f2f8ce86361e7ee54ac7a9ee6d8'
+ account = caver.klay.accounts.privateKeyToAccount(privateKey)
+
+ const signed = await caver.klay.accounts.signTransaction(transaction, account.privateKey)
+
+ const rlpDecoded = caver.utils.rlpDecode(signed.rawTransaction)
+ expect(rlpDecoded[7].length).not.to.equals(rlpDecoded[8].length)
+
+ const result = caver.klay.accounts.recoverTransaction(signed.rawTransaction)
+ expect(result).to.not.equal(account.addrss)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-105 : rawTransaction: Non-LEGACY transactions.', () => {
+ it('should throw error', async () => {
+ const transaction = {
+ type: 'VALUE_TRANSFER',
+ from: '0x13b0d8316F0c3cE0C3C51Ebb586A14d7d90112fD',
+ nonce: '0x0',
+ to: '0x30d8d4217145ba3f6cde24ec28c64c9120f2bdfb',
+ gas: 900000,
+ gasPrice: 25000000000,
+ value: '0x1',
+ chainId: 10000,
+ }
+ address = '0x13b0d8316F0c3cE0C3C51Ebb586A14d7d90112fD'
+ privateKey = '0x72d72a46401220f08ccb1b17b550feb816840f2f8ce86361e7ee54ac7a9ee6d8'
+ caver.klay.accounts.privateKeyToAccount(privateKey, address)
+
+ const signed = await caver.klay.accounts.signTransaction(transaction, account.privateKey)
+
+ const errorMessage = 'recoverTransaction only supports transactions of type "LEGACY".'
+ expect(()=>caver.klay.accounts.recoverTransaction(signed.rawTransaction)).to.throws(errorMessage)
+ })
+ })
+})
+
+describe('caver.klay.accounts.hashMessage', () => {
+ it('CAVERJS-UNIT-WALLET-031, CAVERJS-UNIT-WALLET-032 : result should be same with keccak256(MessagePrefix + originMessage.length + originMessage)', () => {
+ const message = 'Hello World'
+ let result = caver.klay.accounts.hashMessage(message)
+ checkHashMessage(result, message)
+
+ const decoded = caver.utils.utf8ToHex(message)
+ result = caver.klay.accounts.hashMessage(decoded)
+ checkHashMessage(result, message)
+ })
+})
+
+describe('caver.klay.accounts.sign', () => {
+ let account
+
+ beforeEach(() => {
+ account = caver.klay.accounts.create()
+ })
+
+ context('CAVERJS-UNIT-WALLET-033 : input: data, privateKey', () => {
+ it('should recover valid address', () => {
+ const data = 'Some data'
+ let result = caver.klay.accounts.sign(data, account.privateKey)
+
+ const keys = ['message', 'messageHash', 'v', 'r', 's', 'signature']
+ expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys)
+
+ if (data != result.message) {
+ expect(data).to.equal(caver.utils.utf8ToHex(result.message))
+ }
+
+ const decoded = caver.utils.utf8ToHex(data)
+ result = caver.klay.accounts.sign(decoded, account.privateKey)
+ checkHashMessage(result.messageHash, data)
+
+ expect(caver.klay.accounts.recover(result)).to.equal(account.address)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-034 : input: data, privateKey:invalid', () => {
+ it('should throw an error', () => {
+ const data = 'Some data'
+ const invalid = caver.utils.randomHex(31) // 31bytes
+
+ const errorMessage = 'Invalid private key'
+ expect(() => caver.klay.accounts.sign(data, invalid)).to.throw(errorMessage)
+ })
+ })
+})
+
+// caver.klay.accounts.recover
+describe('caver.klay.accounts.recover', () => {
+ let account
+
+ beforeEach(() => {
+ account = caver.klay.accounts.create()
+ })
+
+ context('CAVERJS-UNIT-WALLET-035 : input: signatureObject', () => {
+ it('result should be same with account.address', () => {
+ const message = 'Some data'
+ const sigObj = account.sign(message)
+
+ let result = caver.klay.accounts.recover(sigObj)
+ expect(result).to.equal(account.address)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-036 : input: message, signature', () => {
+ it('result should be same with account.address', () => {
+ const message = 'Some data'
+ const sigObj = account.sign(message)
+
+ let result = caver.klay.accounts.recover(sigObj.message, sigObj.signature)
+ expect(result).to.equal(account.address)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-037 : input: message, signature, prefixed', () => {
+ it('result should be same with account.address', () => {
+ const message = 'Some data'
+ const sigObj = account.sign(message)
+ const prefixed = true
+
+ const messageHash = caver.klay.accounts.hashMessage(message)
+
+ let result = caver.klay.accounts.recover(messageHash, sigObj.signature, prefixed)
+ expect(result).to.equal(account.address)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-038 : input: message, v, r, s', () => {
+ it('result should be same with account.address', () => {
+ const message = 'Some data'
+ const sigObj = account.sign(message)
+
+ let result = caver.klay.accounts.recover(sigObj.message, sigObj.v, sigObj.r, sigObj.s)
+ expect(result).to.equal(account.address)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-039 : input: message, v, r, s, prefixed', () => {
+ it('result should be same with account.address', () => {
+ const message = 'Some data'
+ const sigObj = account.sign(message)
+ const prefixed = true
+
+ const messageHash = caver.klay.accounts.hashMessage(message)
+
+ let result = caver.klay.accounts.recover(messageHash, sigObj.v, sigObj.r, sigObj.s, prefixed)
+ expect(result).to.equal(account.address)
+ })
+ })
+})
+
+// caver.klay.accounts.encrypt
+describe('caver.klay.accounts.encrypt', () => {
+ let account
+
+ beforeEach(() => {
+ account = caver.klay.accounts.create()
+ })
+
+ context('CAVERJS-UNIT-WALLET-040 : input: privateKey, password', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let result = caver.klay.accounts.encrypt(account.privateKey, password)
+
+ isKeystoreV4(result, account)
+
+ const decryptedAccount = caver.klay.accounts.decrypt(result, password)
+ isAccount(decryptedAccount, {keys: account.keys, address: account.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-041 : input: privateKey:invalid, password', () => {
+ it('should throw an error', () => {
+ const invalid = caver.utils.randomHex(31) // 31bytes
+ const password = 'klaytn!@'
+
+ const errorMessage = 'Invalid private key'
+ expect(() => caver.klay.accounts.encrypt(invalid, password)).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-096 : input: privateKey:KlaytnWalletKey, password', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let result = caver.klay.accounts.encrypt(account.getKlaytnWalletKey(), password)
+
+ isKeystoreV4(result, account)
+
+ const decryptedAccount = caver.klay.accounts.decrypt(result, password)
+ isAccount(decryptedAccount, {keys: account.keys, address: account.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-097 : input: privateKey:KlaytnWalletKey, password, {address:valid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let result = caver.klay.accounts.encrypt(account.getKlaytnWalletKey(), password, {address: account.address})
+
+ isKeystoreV4(result, account)
+
+ const decryptedAccount = caver.klay.accounts.decrypt(result, password)
+ isAccount(decryptedAccount, {keys: account.keys, address: account.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-098 : input: privateKey:KlaytnWalletKey, password, {address:invalid}', () => {
+ it('should throw an error', () => {
+ const password = 'klaytn!@'
+
+ const errorMessage = 'The address extracted from the private key does not match the address received as the input value.'
+ expect(() => caver.klay.accounts.encrypt(account.getKlaytnWalletKey(), password, {address: caver.klay.accounts.create().address})).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-099 : input: privateKey:KlaytnWalletKey(decoupled), password', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, caver.klay.accounts.create().privateKey)
+
+ let result = caver.klay.accounts.encrypt(testAccount.getKlaytnWalletKey(), password)
+
+ isKeystoreV4(result, testAccount)
+
+ const decryptedAccount = caver.klay.accounts.decrypt(result, password)
+ isAccount(decryptedAccount, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-100 : input: privateKey:KlaytnWalletKey(decoupled), password, {address:valid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, caver.klay.accounts.create().privateKey)
+
+ let result = caver.klay.accounts.encrypt(testAccount.getKlaytnWalletKey(), password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+
+ const decryptedAccount = caver.klay.accounts.decrypt(result, password)
+ isAccount(decryptedAccount, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-101 : input: privateKey:KlaytnWalletKey(decoupled), password, {address:invalid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, caver.klay.accounts.create().privateKey)
+
+ const errorMessage = 'The address extracted from the private key does not match the address received as the input value.'
+ expect(() => caver.klay.accounts.encrypt(testAccount.getKlaytnWalletKey(), password, {address: caver.klay.accounts.create().address})).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-351: input: array of private key string, password, {address:valid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, key)
+
+ let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(key.length)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-352: input: array of private key string, password', () => {
+ it('should throw error when address is not defined', () => {
+ const password = 'klaytn!@'
+
+ let key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, key)
+
+ const errorMessage = 'The address must be defined inside the options object.'
+ expect(() => caver.klay.accounts.encrypt(testAccount.keys, password)).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-353: input: key object(transactionKey, updateKey and feePayerKey are defined), password, {address:valid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: caver.klay.accounts.create().privateKey,
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, key)
+
+ let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(3)
+ expect(result.keyring[0].length).to.equals(1)
+ expect(result.keyring[1].length).to.equals(1)
+ expect(result.keyring[2].length).to.equals(1)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-354: input: key object(transactionKey, updateKey and feePayerKey are defined with array of private key), password, {address:valid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let key = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ }
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, key)
+
+ let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(3)
+ expect(result.keyring[0].length).to.equals(key.transactionKey.length)
+ expect(result.keyring[1].length).to.equals(key.updateKey.length)
+ expect(result.keyring[2].length).to.equals(key.feePayerKey.length)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-355: input: key object(transactionKey is defined), password, {address:valid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ }
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, key)
+
+ let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(1)
+ expect(result.keyring[0].length).to.equals(1)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-356: input: key object(updateKey is defined), password, {address:valid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let key = {
+ updateKey: caver.klay.accounts.create().privateKey,
+ }
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, key)
+
+ let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(2)
+ expect(result.keyring[0].length).to.equals(0)
+ expect(result.keyring[1].length).to.equals(1)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-357: input: key object(feePayerKey is defined), password, {address:valid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let key = {
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, key)
+
+ let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(3)
+ expect(result.keyring[0].length).to.equals(0)
+ expect(result.keyring[1].length).to.equals(0)
+ expect(result.keyring[2].length).to.equals(1)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-358: input: key object, password', () => {
+ it('should throw error when address is not defined', () => {
+ const password = 'klaytn!@'
+
+ let key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: caver.klay.accounts.create().privateKey,
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, key)
+
+ const errorMessage = 'The address must be defined inside the options object.'
+ expect(() => caver.klay.accounts.encrypt(testAccount.keys, password)).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-359: input: AccountKeyPublic, password, {address:valid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let key = caver.klay.accounts.create().privateKey
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, accountKey)
+
+ let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(1)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-360: input: AccountKeyPublic, password', () => {
+ it('should throw error', () => {
+ const password = 'klaytn!@'
+
+ let key = caver.klay.accounts.create().privateKey
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const errorMessage = 'The address must be defined inside the options object.'
+ expect(() => caver.klay.accounts.encrypt(accountKey, password)).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-361: input: AccountKeyMultiSig, password, {address:valid}', () => {
+ it('should encrypt key with password', () => {
+ const password = 'klaytn!@'
+
+ let key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, accountKey)
+
+ let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(key.length)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-362: input: AccountKeyMultiSig, password', () => {
+ it('should throw error', () => {
+ const password = 'klaytn!@'
+
+ let key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const errorMessage = 'The address must be defined inside the options object.'
+ expect(() => caver.klay.accounts.encrypt(accountKey, password)).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-363: input: AccountKeyRoleBased, password, {address:valid}', () => {
+ it('should encrypt key with password', () => {
+ const password = 'klaytn!@'
+
+ let key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ }
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, accountKey)
+
+ let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(3)
+ expect(result.keyring[0].length).to.equals(1)
+ expect(result.keyring[1].length).to.equals(key.updateKey.length)
+ expect(result.keyring[2].length).to.equals(key.feePayerKey.length)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-364: input: AccountKeyMultiSig, password', () => {
+ it('should throw error', () => {
+ const password = 'klaytn!@'
+
+ let key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ }
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const errorMessage = 'The address must be defined inside the options object.'
+ expect(() => caver.klay.accounts.encrypt(accountKey, password)).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-365: input: Account with AccountKeyPublic, password, {address:valid}', () => {
+ it('should encrypt password with privateKey', () => {
+ const password = 'klaytn!@'
+
+ let key = caver.klay.accounts.create().privateKey
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, accountKey)
+
+ let result = caver.klay.accounts.encrypt(testAccount, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(1)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-366: input: Account with AccountKeyPublic, password, {address:different address}', () => {
+ it('should throw error when addresses are not matched', () => {
+ const password = 'klaytn!@'
+
+ let key = caver.klay.accounts.create().privateKey
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, accountKey)
+
+ const errorMessage = 'Address in account is not matched with address in options object'
+ expect(() => caver.klay.accounts.encrypt(testAccount, password, {address: caver.klay.accounts.create().address})).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-367: input: Account with AccountKeyMultiSig, password, {address:valid}', () => {
+ it('should encrypt key with password', () => {
+ const password = 'klaytn!@'
+
+ let key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, accountKey)
+
+ let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(key.length)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-368: input: Account with AccountKeyMultiSig, password, {address:different address}', () => {
+ it('should throw error when addresses are not matched', () => {
+ const password = 'klaytn!@'
+
+ let key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, accountKey)
+
+ const errorMessage = 'Address in account is not matched with address in options object'
+ expect(() => caver.klay.accounts.encrypt(testAccount, password, {address: caver.klay.accounts.create().address})).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-369: input: Account with AccountKeyRoleBased, password, {address:valid}', () => {
+ it('should encrypt key with password', () => {
+ const password = 'klaytn!@'
+
+ let key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ }
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, accountKey)
+
+ let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address})
+
+ isKeystoreV4(result, testAccount)
+ expect(result.keyring.length).to.equals(3)
+ expect(result.keyring[0].length).to.equals(1)
+ expect(result.keyring[1].length).to.equals(key.updateKey.length)
+ expect(result.keyring[2].length).to.equals(key.feePayerKey.length)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-370: input: Account with AccountKeyRoleBased, password, {address:different address}', () => {
+ it('should throw error when addresses are not matched', () => {
+ const password = 'klaytn!@'
+
+ let key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ }
+ let accountKey = caver.klay.accounts.createAccountKey(key)
+ let testAccount = caver.klay.accounts.createWithAccountKey(account.address, accountKey)
+
+ const errorMessage = 'Address in account is not matched with address in options object'
+ expect(() => caver.klay.accounts.encrypt(testAccount, password, {address: caver.klay.accounts.create().address})).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-385: input: Account with AccountKeyMultiSig, password, option', () => {
+ it('should throw error when addresses are not matched', () => {
+ const password = 'password'
+
+ let testAccount = caver.klay.accounts.createWithAccountKey('0xf725a2950dc959638fa09f9d9b5426ad3dd8cd90', {
+ transactionKey: '0x7dc66dca0e5d56940c99ad01903a8ba5fd9e1f7a51a8ab07cf81ccd1d3c4be16',
+ updateKey: ['0x5fc3216454ab841ffa2bed0933a27bcdf2965238372bff3ec4fe56cbf5389a87', '0x79fe0616e7624314611b8e9c716b8d9c0c8c8c20f654021ff5fa7c46dc50709b'],
+ feePayerKey: '0xfac188dc156ef58d529ea14ac95379f502a390d5720a9575b87545e36b3f758e',
+ })
+
+ let encryptOption = {
+ salt: 'e7c4605ad8200e0d93cd67f9d82fb9971e1a2763b22362017c2927231c2a733a',
+ iv: Buffer.from('38aa896fc128075425e512f01e4b206c', 'hex'),
+ kdf: 'scrypt',
+ dklen: 32,
+ n: 4096,
+ r: 8,
+ p: 1,
+ cipher: 'aes-128-ctr',
+ uuid: Buffer.from('e7c4605ad8200e0d93cd67f9d82fb997', 'hex'),
+ }
+
+ const expectedKeystore = {
+ version: 4,
+ id: 'e7c4605a-d820-4e0d-93cd-67f9d82fb997',
+ address: '0xf725a2950dc959638fa09f9d9b5426ad3dd8cd90',
+ keyring:[
+ [
+ {
+ ciphertext: '5e2f95f61d7af3bebf4ff9f5d5813690c80b0b5aaebd6e8b22d0f928ff06776a',
+ cipherparams: { iv: '38aa896fc128075425e512f01e4b206c' },
+ cipher: 'aes-128-ctr',
+ kdf: 'scrypt',
+ kdfparams: {
+ dklen: 32,
+ salt: 'e7c4605ad8200e0d93cd67f9d82fb9971e1a2763b22362017c2927231c2a733a',
+ n: 4096,
+ r: 8,
+ p: 1
+ },
+ mac: 'fb86255428e24ba701201d5815f2f2114214cbd34fe4bc7a24b948a8ceac9f9b'
+ }
+ ],
+ [
+ {
+ ciphertext: '7c2ad958478c213549fdb9fd7619c6f8c7034618c83e3ab229af6332d9fa53fb',
+ cipherparams: { iv: '38aa896fc128075425e512f01e4b206c' },
+ cipher: 'aes-128-ctr',
+ kdf: 'scrypt',
+ kdfparams: {
+ dklen: 32,
+ salt: 'e7c4605ad8200e0d93cd67f9d82fb9971e1a2763b22362017c2927231c2a733a',
+ n: 4096,
+ r: 8,
+ p: 1
+ },
+ mac: 'e6c3897772916c69f7c778ac2e0e60b786c55f17367c68b086486bd68fea9517'
+ },
+ {
+ ciphertext: '5a17fe2af445e63ed2cdda6834d030a9391998000941c79318ab49bff092b9e7',
+ cipherparams: { iv: '38aa896fc128075425e512f01e4b206c' },
+ cipher: 'aes-128-ctr',
+ kdf: 'scrypt',
+ kdfparams: {
+ dklen: 32,
+ salt: 'e7c4605ad8200e0d93cd67f9d82fb9971e1a2763b22362017c2927231c2a733a',
+ n: 4096,
+ r: 8,
+ p: 1
+ },
+ mac: '633f91994f33541fbf1c3c3e973e539c12f1dd98f2757f64e3b63de986f367e0'
+ }
+ ],
+ [
+ {
+ ciphertext: 'd92870e0064950a7e148f5be8ce8c4c0373684f58d1f50f95524701a47fdbcf2',
+ cipherparams: { iv: '38aa896fc128075425e512f01e4b206c' },
+ cipher: 'aes-128-ctr',
+ kdf: 'scrypt',
+ kdfparams: {
+ dklen: 32,
+ salt: 'e7c4605ad8200e0d93cd67f9d82fb9971e1a2763b22362017c2927231c2a733a',
+ n: 4096,
+ r: 8,
+ p: 1
+ },
+ mac: 'b2f0245036e7bbdea712819dfbe019c8bfb237684c67d61fa82638868a7ae752'
+ }
+ ]
+ ],
+ }
+
+ let result = caver.klay.accounts.encrypt(testAccount, password, encryptOption)
+
+ expect(result.version).to.equals(expectedKeystore.version)
+ expect(result.id).to.equals(expectedKeystore.id)
+ expect(result.address).to.equals(expectedKeystore.address)
+ compareEncrypted(result.keyring[0][0], expectedKeystore.keyring[0][0])
+ compareEncrypted(result.keyring[1][0], expectedKeystore.keyring[1][0])
+ compareEncrypted(result.keyring[1][1], expectedKeystore.keyring[1][1])
+ compareEncrypted(result.keyring[2][0], expectedKeystore.keyring[2][0])
+
+ function compareEncrypted(ret, exp) {
+ expect(ret.ciphertext).to.equals(exp.ciphertext)
+ expect(ret.cipherparams.iv).to.equals(exp.cipherparams.iv)
+ expect(ret.cipher).to.equals(exp.cipher)
+ expect(ret.kdf).to.equals(exp.kdf)
+ expect(ret.kdfparams.dklen).to.equals(exp.kdfparams.dklen)
+ expect(ret.kdfparams.salt).to.equals(exp.kdfparams.salt)
+ expect(ret.kdfparams.n).to.equals(exp.kdfparams.n)
+ expect(ret.kdfparams.r).to.equals(exp.kdfparams.r)
+ expect(ret.kdfparams.p).to.equals(exp.kdfparams.p)
+ expect(ret.mac).to.equals(exp.mac)
+ }
+
+ isKeystoreV4(result, testAccount)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-389: input: Account with AccountKeyMultiSig, password, option(pbkdf2)', () => {
+ it('should throw error when addresses are not matched', () => {
+ const password = 'password'
+
+ let testAccount = caver.klay.accounts.createWithAccountKey('0xf725a2950dc959638fa09f9d9b5426ad3dd8cd90', {
+ transactionKey: '0x7dc66dca0e5d56940c99ad01903a8ba5fd9e1f7a51a8ab07cf81ccd1d3c4be16',
+ updateKey: ['0x5fc3216454ab841ffa2bed0933a27bcdf2965238372bff3ec4fe56cbf5389a87', '0x79fe0616e7624314611b8e9c716b8d9c0c8c8c20f654021ff5fa7c46dc50709b'],
+ feePayerKey: '0xfac188dc156ef58d529ea14ac95379f502a390d5720a9575b87545e36b3f758e',
+ })
+
+ let encryptOption = {
+ salt: 'e7c4605ad8200e0d93cd67f9d82fb9971e1a2763b22362017c2927231c2a733a',
+ iv: Buffer.from('38aa896fc128075425e512f01e4b206c', 'hex'),
+ kdf: 'pbkdf2',
+ dklen: 32,
+ c: 262144,
+ cipher: 'aes-128-ctr',
+ uuid: Buffer.from('e7c4605ad8200e0d93cd67f9d82fb997', 'hex'),
+ }
+
+ let result = caver.klay.accounts.encrypt(testAccount.keys, password, Object.assign({address: testAccount.address, encryptOption}))
+
+ isKeystoreV4(result, testAccount)
+
+ expect(result.keyring.length).to.equals(3)
+ expect(result.keyring[0].length).to.equals(1)
+ expect(result.keyring[1].length).to.equals(2)
+ expect(result.keyring[2].length).to.equals(1)
+
+ const decrypted = caver.klay.accounts.decrypt(result, password)
+ isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address})
+ })
+ })
+})
+
+describe('caver.klay.accounts.decrypt', () => {
+ let account
+
+ beforeEach(() => {
+ account = caver.klay.accounts.create()
+ })
+
+ context('CAVERJS-UNIT-WALLET-042 : input: keystoreJsonV4, password', () => {
+ it('After decrypting, should return valid account', () => {
+ const password = 'klaytn!@'
+ const keystoreJsonV4 = caver.klay.accounts.encrypt(account.privateKey, password)
+
+ let result = caver.klay.accounts.decrypt(keystoreJsonV4, password)
+ isKeystoreV4(keystoreJsonV4, result)
+
+ isAccount(result, {keys: account.keys, address: account.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-103 : input: keystoreJsonV4(without 0x address format), password', () => {
+ it('After decrypting, should return valid account', () => {
+ const password = 'klaytn!@'
+ const keystoreJsonV4 = caver.klay.accounts.encrypt(account.privateKey, password)
+ keystoreJsonV4.address = keystoreJsonV4.address.replace('0x', '')
+
+ let result = caver.klay.accounts.decrypt(keystoreJsonV4, password)
+
+ expect(result.address.slice(0, 2)).to.equals('0x')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-371: input: keystoreJsonV4 that encrypts Account with AccountKeyMultiSig, password', () => {
+ it('After decrypting, should return valid account', () => {
+ const password = 'klaytn!@'
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const keystoreJsonV4 = caver.klay.accounts.encrypt(key, password, { address: account.address })
+
+ let result = caver.klay.accounts.decrypt(keystoreJsonV4, password)
+
+ isAccount(result, {keys: key, address: account.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-372: input: keystoreJsonV4 that encrypts Account with AccountKeyRoleBased, password', () => {
+ it('After decrypting, should return valid account', () => {
+ const password = 'klaytn!@'
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+ const keystoreJsonV4 = caver.klay.accounts.encrypt(key, password, { address: account.address })
+
+ let result = caver.klay.accounts.decrypt(keystoreJsonV4, password)
+
+ isAccount(result, {keys: key, address: account.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-373: input: keystoreJsonV4 that encrypts Account with AccountKeyRoleBased(transactionKey only), password', () => {
+ it('After decrypting, should return valid account', () => {
+ const password = 'klaytn!@'
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ }
+ const keystoreJsonV4 = caver.klay.accounts.encrypt(key, password, { address: account.address })
+
+ let result = caver.klay.accounts.decrypt(keystoreJsonV4, password)
+
+ isAccount(result, {keys: key, address: account.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-374: input: keystoreJsonV4 that encrypts Account with AccountKeyRoleBased(updateKey only), password', () => {
+ it('After decrypting, should return valid account', () => {
+ const password = 'klaytn!@'
+ const key = {
+ updateKey: caver.klay.accounts.create().privateKey,
+ }
+ const keystoreJsonV4 = caver.klay.accounts.encrypt(key, password, { address: account.address })
+
+ let result = caver.klay.accounts.decrypt(keystoreJsonV4, password)
+
+ isAccount(result, {keys: key, address: account.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-375: input: keystoreJsonV4 that encrypts Account with AccountKeyRoleBased(feePayerKey only), password', () => {
+ it('After decrypting, should return valid account', () => {
+ const password = 'klaytn!@'
+ const key = {
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ const keystoreJsonV4 = caver.klay.accounts.encrypt(key, password, { address: account.address })
+
+ let result = caver.klay.accounts.decrypt(keystoreJsonV4, password)
+
+ isAccount(result, {keys: key, address: account.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-378: input: keystoreJsonV4 that encrypts Account, password', () => {
+ it('After decrypting, should return valid account', () => {
const password = 'klaytn!@'
+ const key = caver.klay.accounts.create().privateKey
+ const keystore = caver.klay.accounts.encrypt(key, password, { address: account.address })
+ keystore.version = 3
+ keystore.crypto = keystore.keyring[0]
+ delete keystore.keyring
+
+ let result = caver.klay.accounts.decrypt(keystore, password)
+
+ isAccount(result, {keys: key, address: account.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-379: input: keystoreJsonV4 that encrypts Account, password', () => {
+ it('should throw error with invalid keystore v3 which not defines crypto', () => {
+ const password = 'klaytn!@'
+ const key = caver.klay.accounts.create().privateKey
+ const keystore = caver.klay.accounts.encrypt(key, password, { address: account.address })
+ keystore.version = 3
+
+ const expectedError = `Invalid keystore V3 format: 'crypto' is not defined.`
+
+ expect(() => caver.klay.accounts.decrypt(keystore, password)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-380: input: keystoreJsonV4 that encrypts Account, password', () => {
+ it('should throw error with invalid keystore v3 which defines crypto and keyring', () => {
+ const password = 'klaytn!@'
+ const key = caver.klay.accounts.create().privateKey
+ const keystore = caver.klay.accounts.encrypt(key, password, { address: account.address })
+ keystore.version = 3
+ keystore.crypto = keystore.keyring[0]
+
+ const expectedError = `Invalid key store format: 'crypto' can not be with 'keyring'`
+
+ expect(() => caver.klay.accounts.decrypt(keystore, password)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-381: input: keystoreJsonV4 that encrypts Account, password', () => {
+ it('should throw error with invalid keystore v3 which defines crypto and keyring', () => {
+ const password = 'klaytn!@'
+ const key = caver.klay.accounts.create().privateKey
+ const keystore = caver.klay.accounts.encrypt(key, password, { address: account.address })
+ keystore.crypto = keystore.keyring[0]
+
+ const expectedError = `Invalid key store format: 'crypto' can not be with 'keyring'`
+
+ expect(() => caver.klay.accounts.decrypt(keystore, password)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-382: input: keystoreJsonV4 that encrypts Account, password', () => {
+ it('should throw error with invalid length of key', () => {
+ const password = 'klaytn!@'
+ const key = caver.klay.accounts.create().privateKey
+ const keystore = caver.klay.accounts.encrypt(key, password, { address: account.address })
+ keystore.keyring = [[], [], [], []]
+
+ const expectedError = `Invalid key store format`
+
+ expect(() => caver.klay.accounts.decrypt(keystore, password)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-383: input: hard coded keystoreJsonV4 that encrypts Account, password', () => {
+ it('should decrypt and return valid account', () => {
+ const keystoreJsonV4 = {
+ version: 4,
+ id: '55da3f9c-6444-4fc1-abfa-f2eabfc57501',
+ address: '0x86bce8c859f5f304aa30adb89f2f7b6ee5a0d6e2',
+ keyring:[
+ [
+ {
+ ciphertext: '93dd2c777abd9b80a0be8e1eb9739cbf27c127621a5d3f81e7779e47d3bb22f6',
+ cipherparams: { iv: '84f90907f3f54f53d19cbd6ae1496b86' },
+ cipher: 'aes-128-ctr',
+ kdf: 'scrypt',
+ kdfparams: {
+ dklen: 32,
+ salt: '69bf176a136c67a39d131912fb1e0ada4be0ed9f882448e1557b5c4233006e10',
+ n: 4096,
+ r: 8,
+ p: 1
+ },
+ mac: '8f6d1d234f4a87162cf3de0c7fb1d4a8421cd8f5a97b86b1a8e576ffc1eb52d2'
+ },
+ {
+ ciphertext: '53d50b4e86b550b26919d9b8cea762cd3c637dfe4f2a0f18995d3401ead839a6',
+ cipherparams: { iv: 'd7a6f63558996a9f99e7daabd289aa2c' },
+ cipher: 'aes-128-ctr',
+ kdf: 'scrypt',
+ kdfparams: {
+ dklen: 32,
+ salt: '966116898d90c3e53ea09e4850a71e16df9533c1f9e1b2e1a9edec781e1ad44f',
+ n: 4096,
+ r: 8,
+ p: 1
+ },
+ mac: 'bca7125e17565c672a110ace9a25755847d42b81aa7df4bb8f5ce01ef7213295'
+ }
+ ],
+ [
+ {
+ ciphertext: 'f16def98a70bb2dae053f791882f3254c66d63416633b8d91c2848893e7876ce',
+ cipherparams: { iv: 'f5006128a4c53bc02cada64d095c15cf' },
+ cipher: 'aes-128-ctr',
+ kdf: 'scrypt',
+ kdfparams: {
+ dklen: 32,
+ salt: '0d8a2f71f79c4880e43ff0795f6841a24cb18838b3ca8ecaeb0cda72da9a72ce',
+ n: 4096,
+ r: 8,
+ p: 1
+ },
+ mac: '38b79276c3805b9d2ff5fbabf1b9d4ead295151b95401c1e54aed782502fc90a'
+ }
+ ],
+ [
+ {
+ ciphertext: '544dbcc327942a6a52ad6a7d537e4459506afc700a6da4e8edebd62fb3dd55ee',
+ cipherparams: { iv: '05dd5d25ad6426e026818b6fa9b25818' },
+ cipher: 'aes-128-ctr',
+ kdf: 'scrypt',
+ kdfparams: {
+ dklen: 32,
+ salt: '3a9003c1527f65c772c54c6056a38b0048c2e2d58dc0e584a1d867f2039a25aa',
+ n: 4096,
+ r: 8,
+ p: 1
+ },
+ mac: '19a698b51409cc9ac22d63d329b1201af3c89a04a1faea3111eec4ca97f2e00f'
+ },
+ {
+ ciphertext: 'dd6b920f02cbcf5998ed205f8867ddbd9b6b088add8dfe1774a9fda29ff3920b',
+ cipherparams: { iv: 'ac04c0f4559dad80dc86c975d1ef7067' },
+ cipher: 'aes-128-ctr',
+ kdf: 'scrypt',
+ kdfparams: {
+ dklen: 32,
+ salt: '22279c6dbcc706d7daa120022a236cfe149496dca8232b0f8159d1df999569d6',
+ n: 4096,
+ r: 8,
+ p: 1
+ },
+ mac: '1c54f7378fa279a49a2f790a0adb683defad8535a21bdf2f3dadc48a7bddf517'
+ }
+ ]
+ ],
+ }
+ const password = 'password'
+ const expectedAccount = caver.klay.accounts.createWithAccountKey('0x86bce8c859f5f304aa30adb89f2f7b6ee5a0d6e2', {
+ transactionKey: ['0xd1e9f8f00ef9f93365f5eabccccb3f3c5783001b61a40f0f74270e50158c163d', '0x4bd8d0b0c1575a7a35915f9af3ef8beb11ad571337ec9b6aca7c88ca7458ef5c'],
+ updateKey: '0xdc2690ac6017e32ef17ea219c2a2fd14a2bb73e7a0a253dfd69abba3eb8d7d91',
+ feePayerKey: ['0xf17bf8b7bee09ffc50a401b7ba8e633b9e55eedcf776782f2a55cf7cc5c40aa8', '0x4f8f1e9e1466609b836dba611a0a24628aea8ee11265f757aa346bde3d88d548']
+ })
+
+ let result = caver.klay.accounts.decrypt(keystoreJsonV4, password)
+
+ isAccount(result, {keys: expectedAccount.keys, address: expectedAccount.address})
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-384: input: hard coded keystoreJsonV3 that encrypts Account, password', () => {
+ it('should decrypt and return valid account', () => {
+ const keystoreJsonV3 = {
+ version: 3,
+ id: '7a0a8557-22a5-4c90-b554-d6f3b13783ea',
+ address: '0x86bce8c859f5f304aa30adb89f2f7b6ee5a0d6e2',
+ crypto: {
+ ciphertext: '696d0e8e8bd21ff1f82f7c87b6964f0f17f8bfbd52141069b59f084555f277b7',
+ cipherparams: { iv: '1fd13e0524fa1095c5f80627f1d24cbd' },
+ cipher: 'aes-128-ctr',
+ kdf: 'scrypt',
+ kdfparams: {
+ dklen: 32,
+ salt: '7ee980925cef6a60553cda3e91cb8e3c62733f64579f633d0f86ce050c151e26',
+ n: 4096,
+ r: 8,
+ p: 1
+ },
+ mac: '8684d8dc4bf17318cd46c85dbd9a9ec5d9b290e04d78d4f6b5be9c413ff30ea4'
+ }
+ }
+ const password = 'password'
+ const expectedAccount = caver.klay.accounts.privateKeyToAccount('0x36e0a792553f94a7660e5484cfc8367e7d56a383261175b9abced7416a5d87df', '0x86bce8c859f5f304aa30adb89f2f7b6ee5a0d6e2')
+
+ let result = caver.klay.accounts.decrypt(keystoreJsonV3, password)
+
+ isAccount(result, {keys: expectedAccount.keys, address: expectedAccount.address})
+ })
+ })
+
+
+ /*
+ it('keystoreJsonV3, password:invalid [KLAYTN-52]', () => {
+ const invalid = ''
+ const keystoreJsonV3 = caver.klay.accounts.encrypt(account.privateKey, invalid)
+
+ utils.log('input', keystoreJsonV3, invalid)
+
+ const expectedError = {
+ name: 'Error',
+ message: ''
+ }
+ validateErrorCodeblock(() => caver.klay.accounts.decrypt(keystoreJsonV3, invalid), expectedError)
+ })
+ */
+})
+
+describe('caver.klay.accounts.getLegacyAccount', () => {
+ context('CAVERJS-UNIT-WALLET-106 : input: valid privateKey', () => {
+ it('should return account which is derived from private key', () => {
+ const testAccount = caver.klay.accounts.create()
+ let result = caver.klay.accounts.getLegacyAccount(testAccount.privateKey)
+
+ expect(result.klaytnWalletKeyAddress).to.equals('')
+ expect(result.legacyAccount.address).to.equals(testAccount.address)
+ expect(result.legacyAccount.privateKey).to.equals(testAccount.privateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-107 : input: nonDecoupled valid KlaytnWalletKey format', () => {
+ it('should return account which is derived from private key and address from KlaytnWalletKey format', () => {
+ const testAccount = caver.klay.accounts.create()
+ let result = caver.klay.accounts.getLegacyAccount(testAccount.getKlaytnWalletKey())
+
+ expect(result.klaytnWalletKeyAddress).to.equals(testAccount.address)
+ expect(result.legacyAccount.address).to.equals(result.klaytnWalletKeyAddress)
+ expect(result.legacyAccount.privateKey).to.equals(testAccount.privateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-108 : input: decoupled valid KlaytnWalletKey format', () => {
+ it('should return account which is derived from private key and address from KlaytnWalletKey format', () => {
+ // decoupled
+ const privateKey = caver.klay.accounts.create().privateKey
+ const address = caver.klay.accounts.create().address
+ const testAccount = caver.klay.accounts.privateKeyToAccount(privateKey, address)
+
+ let result = caver.klay.accounts.getLegacyAccount(testAccount.getKlaytnWalletKey())
+
+ expect(result.klaytnWalletKeyAddress).to.equals(testAccount.address)
+ expect(result.legacyAccount.address).not.to.equals(result.klaytnWalletKeyAddress)
+ expect(result.legacyAccount.privateKey).to.equals(testAccount.privateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-109 : input: invalid privateKey', () => {
+ it('should throw error if input is invalid privateKey string', () => {
+ const expectedError = 'Invalid private key'
+
+ expect(() => caver.klay.accounts.getLegacyAccount('0x')).to.throws(expectedError)
+ expect(() => caver.klay.accounts.getLegacyAccount('1')).to.throws(expectedError)
+ expect(() => caver.klay.accounts.getLegacyAccount('a')).to.throws(expectedError)
+ expect(() => caver.klay.accounts.getLegacyAccount('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140FF')).to.throws(expectedError)
+ })
+
+ it('should throw error if input is invalid privateKey type', () => {
+ const expectedError = 'The private key must be of type string'
+
+ expect(() => caver.klay.accounts.getLegacyAccount(1234)).to.throws(expectedError)
+ expect(() => caver.klay.accounts.getLegacyAccount({})).to.throws(expectedError)
+ expect(() => caver.klay.accounts.getLegacyAccount()).to.throws(expectedError)
+ expect(() => caver.klay.accounts.getLegacyAccount(undefined)).to.throws(expectedError)
+ expect(() => caver.klay.accounts.getLegacyAccount(null)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-110 : input: invalid KlaytnWalletKey format', () => {
+ it('should throw error if input is invalid KlaytnWalletKey string', () => {
+ const expectedError = 'Invalid private key'
+ expect(() => caver.klay.accounts.getLegacyAccount(caver.klay.accounts.create().privateKey+'0x000x00')).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.isDecoupled', () => {
+ context('CAVERJS-UNIT-WALLET-111 : input: valid privateKey and decoupled address', () => {
+ it('should return true if input is decoupled private and address', () => {
+ const privateKey = caver.klay.accounts.create().privateKey
+ const address = caver.klay.accounts.create().address
+ const testAccount = caver.klay.accounts.privateKeyToAccount(privateKey, address)
+
+ expect(caver.klay.accounts.isDecoupled(testAccount.privateKey, testAccount.address)).to.be.true
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-112 : input: valid KlaytnWalletKey', () => {
+ it('should return true if input is decoupled KlaytnWalletKey', () => {
+ const privateKey = caver.klay.accounts.create().privateKey
+ const address = caver.klay.accounts.create().address
+ const testAccount = caver.klay.accounts.privateKeyToAccount(privateKey, address)
+
+ expect(caver.klay.accounts.isDecoupled(testAccount.getKlaytnWalletKey())).to.be.true
+ expect(caver.klay.accounts.isDecoupled(testAccount.getKlaytnWalletKey(), testAccount.address)).to.be.true
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-113 : input: valid privateKey', () => {
+ it('should return false if input is valid privateKey', () => {
+ expect(caver.klay.accounts.isDecoupled(caver.klay.accounts.create().privateKey)).to.be.false
+ expect(caver.klay.accounts.isDecoupled(caver.klay.accounts.create().privateKey.slice(2))).to.be.false
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-114 : input: valid KlaytnWalletKey', () => {
+ it('should return true if input is nonDecoupled KlaytnWalletKey', () => {
+ const testAccount = caver.klay.accounts.create()
+ expect(caver.klay.accounts.isDecoupled(testAccount.getKlaytnWalletKey())).to.be.false
+ expect(caver.klay.accounts.isDecoupled(testAccount.getKlaytnWalletKey(), testAccount.address)).to.be.false
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-115 : input: invalid privateKey', () => {
+ it('should throw error if input is invalid privateKey string', () => {
+ const expectedError = 'Invalid private key'
+
+ expect(() => caver.klay.accounts.isDecoupled('0x')).to.throws(expectedError)
+ expect(() => caver.klay.accounts.isDecoupled('1')).to.throws(expectedError)
+ expect(() => caver.klay.accounts.isDecoupled('a')).to.throws(expectedError)
+ expect(() => caver.klay.accounts.isDecoupled('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140FF')).to.throws(expectedError)
+ })
+
+ it('should throw error if input is invalid privateKey type', () => {
+ const expectedError = 'The private key must be of type string'
+
+ expect(() => caver.klay.accounts.isDecoupled(1234)).to.throws(expectedError)
+ expect(() => caver.klay.accounts.isDecoupled({})).to.throws(expectedError)
+ expect(() => caver.klay.accounts.isDecoupled()).to.throws(expectedError)
+ expect(() => caver.klay.accounts.isDecoupled(undefined)).to.throws(expectedError)
+ expect(() => caver.klay.accounts.isDecoupled(null)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-116 : input: not match address with KlaytnWalletKey and input', () => {
+ it('should throw error if input is invalid privateKey string', () => {
+ const privateKey = caver.klay.accounts.create().privateKey
+ const address = caver.klay.accounts.create().address
+ const testAccount = caver.klay.accounts.privateKeyToAccount(privateKey, address)
+
+ const expectedError = 'The address extracted from the private key does not match the address received as the input value.'
+
+ expect(() => caver.klay.accounts.isDecoupled(testAccount.getKlaytnWalletKey(), caver.klay.accounts.create().address)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts._getRoleKey', () => {
+ let account
+
+ beforeEach(() => {
+ 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],
+ }
+ account = caver.klay.accounts.createWithAccountKey(caver.klay.accounts.create().address, keyObject)
+ })
+
+ context('CAVERJS-UNIT-WALLET-133: input: legacy tx and account', () => {
+ it('should return transactionKey', () => {
+ const tx = {}
+ const roleKey = caver.klay.accounts._getRoleKey(tx, account)
+ expect(isSameKeyArray(roleKey, account.transactionKey)).to.be.true
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-134: input: update tx and account', () => {
+ it('should return updateKey', () => {
+ const tx = { type: 'FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO' }
+ const roleKey = caver.klay.accounts._getRoleKey(tx, account)
+ expect(isSameKeyArray(roleKey, account.updateKey)).to.be.true
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-135: input: tx for fee payer and account', () => {
+ it('should return feePayerKey', () => {
+ const tx = { senderRawTransaction: '0x', feePayer: account.address }
+ const roleKey = caver.klay.accounts._getRoleKey(tx, account)
+ expect(isSameKeyArray(roleKey, account.feePayerKey)).to.be.true
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-136: input: tx and account', () => {
+ it('should throw error if there is not key matched with role', () => {
+ let testAccount = {updateKey: caver.klay.accounts.create().privateKey}
+ const expectedError = `The key corresponding to the role used for signing is not defined.`
+ expect(() => caver.klay.accounts._getRoleKey({}, testAccount)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-137: input: tx and account', () => {
+ it('should throw error if there is not key matched with role', () => {
+ let testAccount = {transactionKey: caver.klay.accounts.create().privateKey}
+ const expectedError = `The key corresponding to the role used for signing is not defined.`
+ expect(() => caver.klay.accounts._getRoleKey({type: 'ACCOUNT_UPDATE'}, testAccount)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-138: input: tx and account', () => {
+ it('should throw error if there is not key matched with role', () => {
+ let testAccount = {transactionKey: caver.klay.accounts.create().privateKey}
+ const expectedError = `The key corresponding to the role used for signing is not defined.`
+ expect(() => caver.klay.accounts._getRoleKey({ senderRawTransaction: '0x', feePayer: account.address }, testAccount)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.createAccountKey', () => {
+ context('CAVERJS-UNIT-WALLET-139: input: private key string`', () => {
+ it('should return AccountKeyPublic', () => {
+ const key = caver.klay.accounts.create().privateKey
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ expect(accountKey.type).to.equals('AccountKeyPublic')
+ expect(accountKey.defaultKey).to.equals(key)
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-140: input: array of private key string', () => {
+ it('should return accountKeyMultiSig', () => {
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ expect(accountKey.type).to.equals('AccountKeyMultiSig')
+ expect(accountKey.defaultKey).to.equals(key[0])
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-141: input: keyObject(transactionKey is defined with private key string)', () => {
+ it('should return accountKeyRoleBased', () => {
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey
+ }
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ expect(accountKey.type).to.equals('AccountKeyRoleBased')
+ expect(accountKey.defaultKey).to.equals(key.transactionKey)
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-142: input: keyObject(transactionKey is defined with array of private key string)', () => {
+ it('should return accountKeyRoleBased', () => {
+ const key = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ expect(accountKey.type).to.equals('AccountKeyRoleBased')
+ expect(accountKey.defaultKey).to.equals(key.transactionKey[0])
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-143: input: keyObject(updateKey is defined with private key string)', () => {
+ it('should return accountKeyRoleBased', () => {
+ const key = {
+ updateKey: caver.klay.accounts.create().privateKey
+ }
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ expect(accountKey.type).to.equals('AccountKeyRoleBased')
+ expect(accountKey.defaultKey).to.equals(key.updateKey)
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-144: input: keyObject(updateKey is defined with array of private key string)', () => {
+ it('should return accountKeyRoleBased', () => {
+ const key = {
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ expect(accountKey.type).to.equals('AccountKeyRoleBased')
+ expect(accountKey.defaultKey).to.equals(key.updateKey[0])
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-145: input: keyObject(feePayerKey is defined with private key string)', () => {
+ it('should return accountKeyRoleBased', () => {
+ const key = {
+ feePayerKey: caver.klay.accounts.create().privateKey
+ }
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ expect(accountKey.type).to.equals('AccountKeyRoleBased')
+ expect(accountKey.defaultKey).to.equals(key.feePayerKey)
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-146: input: keyObject(feePayerKey is defined with array of private key string)', () => {
+ it('should return accountKeyRoleBased', () => {
+ const key = {
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ expect(accountKey.type).to.equals('AccountKeyRoleBased')
+ expect(accountKey.defaultKey).to.equals(key.feePayerKey[0])
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-147: input: keyObject(transactionKey, updateKey, feePayerKey are defined)', () => {
+ it('should return accountKeyRoleBased', () => {
+ const key = {
+ transactionKey: [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]
+ }
+
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ expect(accountKey.type).to.equals('AccountKeyRoleBased')
+ expect(accountKey.defaultKey).to.equals(key.transactionKey[0])
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-148: input: invalid type of parameter', () => {
+ it('should throw Error', () => {
+ let param = 1
+ let expectedError = `Invalid accountKey type: ${typeof param}`
+ expect(() => caver.klay.accounts.createAccountKey(param)).to.throws(expectedError)
+
+ param = undefined
+ expectedError = `Invalid accountKey type: ${typeof param}`
+ expect(() => caver.klay.accounts.createAccountKey(param)).to.throws(expectedError)
+
+ param = null
+ expectedError = `Invalid accountKey type: ${typeof param}`
+ expect(() => caver.klay.accounts.createAccountKey(param)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-149: input: invalid parameter', () => {
+ it('should throw Error', () => {
+ let param = 'invalidString'
+ let expectedError = `Invalid private key`
+ expect(() => caver.klay.accounts.createAccountKey(param)).to.throws(expectedError)
+
+ param = ['invalidString']
+ expectedError = `Invalid private key`
+ expect(() => caver.klay.accounts.createAccountKey(param)).to.throws(expectedError)
+
+ param = {}
+ expectedError = `Failed to create AccountKeyRoleBased: empty object`
+ expect(() => caver.klay.accounts.createAccountKey(param)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.createAccountKeyPublic', () => {
+ context('CAVERJS-UNIT-WALLET-150: input: private key string`', () => {
+ it('should return AccountKeyPublic', () => {
+ const key = caver.klay.accounts.create().privateKey
+ const accountKey = caver.klay.accounts.createAccountKeyPublic(key)
+
+ expect(accountKey.type).to.equals('AccountKeyPublic')
+ expect(accountKey.defaultKey).to.equals(key)
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-151: input: AccountKeyPublic', () => {
+ it('should return AccountKeyPublic', () => {
+ const key = caver.klay.accounts.create().privateKey
+ const accountKey = caver.klay.accounts.createAccountKeyPublic(caver.klay.accounts.createAccountKeyPublic(key))
+
+ expect(accountKey.type).to.equals('AccountKeyPublic')
+ expect(accountKey.defaultKey).to.equals(key)
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-152: input: invalid type of parameter', () => {
+ it('should throw Error', () => {
+ let param = 1
+ let expectedError = `Creating a AccountKeyPublic requires a private key string.`
+ expect(() => caver.klay.accounts.createAccountKeyPublic(param)).to.throws(expectedError)
+
+ param = []
+ expectedError = `Creating a AccountKeyPublic requires a private key string.`
+ expect(() => caver.klay.accounts.createAccountKeyPublic(param)).to.throws(expectedError)
+
+ param = {}
+ expectedError = `Creating a AccountKeyPublic requires a private key string.`
+ expect(() => caver.klay.accounts.createAccountKeyPublic(param)).to.throws(expectedError)
+
+ param = undefined
+ expectedError = `Creating a AccountKeyPublic requires a private key string.`
+ expect(() => caver.klay.accounts.createAccountKeyPublic(param)).to.throws(expectedError)
+
+ param = null
+ expectedError = `Creating a AccountKeyPublic requires a private key string.`
+ expect(() => caver.klay.accounts.createAccountKeyPublic(param)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-153: input: invalid parameter', () => {
+ it('should throw Error', () => {
+ const param = 'invalidString'
+ const expectedError = `Invalid private key`
+ expect(() => caver.klay.accounts.createAccountKeyPublic(param)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.createAccountKeyMultiSig', () => {
+ context('CAVERJS-UNIT-WALLET-154: input: private key string`', () => {
+ it('should return AccountKeyMultiSig', () => {
+ const key = [caver.klay.accounts.create().privateKey]
+ const accountKey = caver.klay.accounts.createAccountKeyMultiSig(key)
+
+ expect(accountKey.type).to.equals('AccountKeyMultiSig')
+ expect(accountKey.defaultKey).to.equals(key[0])
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-155: input: AccountKeyMultiSig', () => {
+ it('should return AccountKeyMultiSig', () => {
+ const key = [caver.klay.accounts.create().privateKey]
+ const accountKey = caver.klay.accounts.createAccountKeyMultiSig(caver.klay.accounts.createAccountKeyMultiSig(key))
+
+ expect(accountKey.type).to.equals('AccountKeyMultiSig')
+ expect(accountKey.defaultKey).to.equals(key[0])
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-156: input: invalid type of parameter', () => {
+ it('should throw Error', () => {
+ let param = 1
+ let expectedError = `Creating a AccountKeyMultiSig requires an array of private key string.`
+ expect(() => caver.klay.accounts.createAccountKeyMultiSig(param)).to.throws(expectedError)
+
+ param = 'string'
+ expectedError = `Creating a AccountKeyMultiSig requires an array of private key string.`
+ expect(() => caver.klay.accounts.createAccountKeyMultiSig(param)).to.throws(expectedError)
+
+ param = {}
+ expectedError = `Creating a AccountKeyMultiSig requires an array of private key string.`
+ expect(() => caver.klay.accounts.createAccountKeyMultiSig(param)).to.throws(expectedError)
+
+ param = undefined
+ expectedError = `Creating a AccountKeyMultiSig requires an array of private key string.`
+ expect(() => caver.klay.accounts.createAccountKeyMultiSig(param)).to.throws(expectedError)
+
+ param = null
+ expectedError = `Creating a AccountKeyMultiSig requires an array of private key string.`
+ expect(() => caver.klay.accounts.createAccountKeyMultiSig(param)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-157: input: invalid parameter', () => {
+ it('should throw Error', () => {
+ const param = ['invalidString']
+ const expectedError = `Invalid private key`
+ expect(() => caver.klay.accounts.createAccountKeyMultiSig(param)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.createAccountKeyRoleBased', () => {
+ context('CAVERJS-UNIT-WALLET-158: input: private key string', () => {
+ it('should return AccountKeyRoleBased', () => {
+ const key = {
+ transactionKey: [caver.klay.accounts.create().privateKey],
+ updateKey: caver.klay.accounts.create().privateKey,
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ const accountKey = caver.klay.accounts.createAccountKeyRoleBased(key)
+
+ expect(accountKey.type).to.equals('AccountKeyRoleBased')
+ expect(accountKey.defaultKey).to.equals(key.transactionKey[0])
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-159: input: AccountKeyRoleBased', () => {
+ it('should return AccountKeyRoleBased', () => {
+ const key = {
+ transactionKey: [caver.klay.accounts.create().privateKey],
+ updateKey: caver.klay.accounts.create().privateKey,
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ const accountKey = caver.klay.accounts.createAccountKeyRoleBased(caver.klay.accounts.createAccountKeyRoleBased(key))
+
+ expect(accountKey.type).to.equals('AccountKeyRoleBased')
+ expect(accountKey.defaultKey).to.equals(key.transactionKey[0])
+ compareAccountKey(accountKey, key)
+ expect(typeof accountKey.toPublicKey).to.equals('function')
+ expect(typeof accountKey.update).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-160: input: invalid type of parameter', () => {
+ it('should throw Error', () => {
+ let param = 1
+ let expectedError = `Creating a AccountKeyRoleBased requires an object.`
+ expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError)
+
+ param = 'string'
+ expectedError = `Creating a AccountKeyRoleBased requires an object.`
+ expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError)
+
+ param = []
+ expectedError = `Creating a AccountKeyRoleBased requires an object.`
+ expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError)
+
+ param = undefined
+ expectedError = `Creating a AccountKeyRoleBased requires an object.`
+ expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError)
+
+ param = null
+ expectedError = `Creating a AccountKeyRoleBased requires an object.`
+ expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-161: input: empty object', () => {
+ it('should throw Error', () => {
+ let param = {}
+ let expectedError = `Failed to create AccountKeyRoleBased: empty object`
+ expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-162: input: invalid role is defined', () => {
+ it('should throw Error', () => {
+ let param = { invalidRole: 'invalidString' }
+ expectedError = `Failed to create AccountKeyRoleBased. Invalid role is defined : invalidRole`
+ expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-163: input: invalid parameter', () => {
+ it('should throw Error', () => {
+ let param = { transactionKey: 'invalidString' }
+ let expectedError = `Invalid private key`
+ expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.accountKeyToPublicKey', () => {
+ context('CAVERJS-UNIT-WALLET-164: input: private key string', () => {
+ it('should return string of public key', () => {
+ const key = caver.klay.accounts.create().privateKey
+ const expectedPublicKey = caver.klay.accounts.privateKeyToPublicKey(key)
+
+ const publicKey = caver.klay.accounts.accountKeyToPublicKey(key)
+
+ expect(expectedPublicKey).to.equals(publicKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-165: input: AccountKeyPublic', () => {
+ it('should return string of public key', () => {
+ const key = caver.klay.accounts.create().privateKey
+ const accountKey = caver.klay.accounts.createAccountKeyPublic(key)
+ const expectedPublicKey = caver.klay.accounts.privateKeyToPublicKey(key)
+
+ const publicKey = caver.klay.accounts.accountKeyToPublicKey(accountKey)
+
+ expect(expectedPublicKey).to.equals(publicKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-166: input: array of private key string', () => {
+ it('should return array of public key string', () => {
+ const key = [caver.klay.accounts.create().privateKey]
+ const expectedPublicKey = [caver.klay.accounts.privateKeyToPublicKey(key[0])]
+
+ const publicKey = caver.klay.accounts.accountKeyToPublicKey(key)
+
+ expect(isSameKeyArray(expectedPublicKey, publicKey)).to.be.true
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-167: input: AccountKeyMultiSig', () => {
+ it('should return array of public key string', () => {
+ const key = [caver.klay.accounts.create().privateKey]
+ const accountKey = caver.klay.accounts.createAccountKeyMultiSig(key)
+ const expectedPublicKey = [caver.klay.accounts.privateKeyToPublicKey(key[0])]
+
+ const publicKey = caver.klay.accounts.accountKeyToPublicKey(accountKey)
+
+ expect(isSameKeyArray(expectedPublicKey, publicKey)).to.be.true
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-168: input: object defines key', () => {
+ it('should return object of public key string', () => {
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: caver.klay.accounts.create().privateKey,
+ feePayerKey: [caver.klay.accounts.create().privateKey],
+ }
+ const expectedPublicKey = {
+ transactionKey: caver.klay.accounts.privateKeyToPublicKey(key.transactionKey),
+ updateKey: caver.klay.accounts.privateKeyToPublicKey(key.updateKey),
+ feePayerKey: [caver.klay.accounts.privateKeyToPublicKey(key.feePayerKey[0])],
+ }
+
+ const publicKey = caver.klay.accounts.accountKeyToPublicKey(key)
+
+ expect(publicKey.transactionKey).to.equals(expectedPublicKey.transactionKey)
+ expect(publicKey.updateKey).to.equals(expectedPublicKey.updateKey)
+ expect(isSameKeyArray(expectedPublicKey.feePayerKey, publicKey.feePayerKey)).to.be.true
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-169: input: AccountKeyRoleBased', () => {
+ it('should return array of public key string', () => {
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: caver.klay.accounts.create().privateKey,
+ feePayerKey: [caver.klay.accounts.create().privateKey],
+ }
+ const accountKey = caver.klay.accounts.createAccountKeyRoleBased(key)
+ const expectedPublicKey = {
+ transactionKey: caver.klay.accounts.privateKeyToPublicKey(key.transactionKey),
+ updateKey: caver.klay.accounts.privateKeyToPublicKey(key.updateKey),
+ feePayerKey: [caver.klay.accounts.privateKeyToPublicKey(key.feePayerKey[0])],
+ }
+
+ const publicKey = caver.klay.accounts.accountKeyToPublicKey(accountKey)
+
+ expect(publicKey.transactionKey).to.equals(expectedPublicKey.transactionKey)
+ expect(publicKey.updateKey).to.equals(expectedPublicKey.updateKey)
+ expect(isSameKeyArray(expectedPublicKey.feePayerKey, publicKey.feePayerKey)).to.be.true
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-170: input: object defines transactionKey only', () => {
+ it('should return object of public key string', () => {
+ const key = { transactionKey: caver.klay.accounts.create().privateKey, }
+ const expectedPublicKey = {
+ transactionKey: caver.klay.accounts.privateKeyToPublicKey(key.transactionKey),
+ }
+
+ const publicKey = caver.klay.accounts.accountKeyToPublicKey(key)
+
+ expect(publicKey.transactionKey).to.equals(expectedPublicKey.transactionKey)
+ expect(publicKey.updateKey).to.be.undefined
+ expect(publicKey.feePayerKey).to.be.undefined
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-171: input: object defines updateKey only', () => {
+ it('should return object of public key string', () => {
+ const key = { updateKey: caver.klay.accounts.create().privateKey, }
+ const expectedPublicKey = {
+ updateKey: caver.klay.accounts.privateKeyToPublicKey(key.updateKey),
+ }
+
+ const publicKey = caver.klay.accounts.accountKeyToPublicKey(key)
+
+ expect(publicKey.transactionKey).to.be.undefined
+ expect(publicKey.updateKey).to.equals(expectedPublicKey.updateKey)
+ expect(publicKey.feePayerKey).to.be.undefined
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-172: input: object defines feePayerKey only', () => {
+ it('should return object of public key string', () => {
+ const key = { feePayerKey: caver.klay.accounts.create().privateKey, }
+ const expectedPublicKey = {
+ feePayerKey: caver.klay.accounts.privateKeyToPublicKey(key.feePayerKey),
+ }
+
+ const publicKey = caver.klay.accounts.accountKeyToPublicKey(key)
+
+ expect(publicKey.transactionKey).to.be.undefined
+ expect(publicKey.updateKey).to.be.undefined
+ expect(publicKey.feePayerKey).to.equals(expectedPublicKey.feePayerKey)
+ })
+ })
+})
+
+describe('caver.klay.accounts.createWithAccountKey', () => {
+ context('CAVERJS-UNIT-WALLET-173: input: address and private key string', () => {
+ it('should return Account with AccountKeyPublic', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key)
+ expect(account.accountKeyType).to.equals('AccountKeyPublic')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-174: input: address and array of private key string', () => {
+ it('should return Account with AccountKeyMultiSig', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key[0])
+ expect(account.accountKeyType).to.equals('AccountKeyMultiSig')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-175: input: address and object of private key', () => {
+ it('should return Account with AccountKeyRoleBased', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey]
+ }
+
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key.transactionKey)
+ expect(account.accountKeyType).to.equals('AccountKeyRoleBased')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-176: input: address and object defines only transactionKey', () => {
+ it('should return Account with AccountKeyRoleBased', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ }
+
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key.transactionKey)
+ expect(account.accountKeyType).to.equals('AccountKeyRoleBased')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-177: input: address and object defines only updateKey', () => {
+ it('should return Account with AccountKeyRoleBased', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ updateKey: caver.klay.accounts.create().privateKey,
+ }
+
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key.updateKey)
+ expect(account.accountKeyType).to.equals('AccountKeyRoleBased')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-178: input: address and object defines only feePayerKey', () => {
+ it('should return Account with AccountKeyRoleBased', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key.feePayerKey)
+ expect(account.accountKeyType).to.equals('AccountKeyRoleBased')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+})
+
+describe('caver.klay.accounts.createWithAccountKeyPublic', () => {
+ context('CAVERJS-UNIT-WALLET-179: input: address and private key string', () => {
+ it('should return Account with AccountKeyPublic', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+
+ const account = caver.klay.accounts.createWithAccountKeyPublic(address, key)
+
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key)
+ expect(account.accountKeyType).to.equals('AccountKeyPublic')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-180: input: address and AccountKeyPublic', () => {
+ it('should return Account with AccountKeyPublic', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const account = caver.klay.accounts.createWithAccountKeyPublic(address, accountKey)
+
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key)
+ expect(account.accountKeyType).to.equals('AccountKeyPublic')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-181: input: address and array of private key string', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+
+ const expectedError = 'Creating a AccountKeyPublic requires a private key string.'
+
+ expect(() => caver.klay.accounts.createWithAccountKeyPublic(address, key)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-182: input: address and object', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {transactionKey: caver.klay.accounts.create().privateKey}
+
+ const expectedError = 'Creating a AccountKeyPublic requires a private key string.'
+
+ expect(() => caver.klay.accounts.createWithAccountKeyPublic(address, key)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-183: input: address and AccountKeyMultiSig', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const expectedError = `Failed to create account with AccountKeyPublic. Invalid account key : ${accountKey.type}`
+
+ expect(() => caver.klay.accounts.createWithAccountKeyPublic(address, accountKey)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-184: input: address and AccountKeyRoleBased', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {transactionKey: caver.klay.accounts.create().privateKey}
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const expectedError = `Failed to create account with AccountKeyPublic. Invalid account key : ${accountKey.type}`
+
+ expect(() => caver.klay.accounts.createWithAccountKeyPublic(address, accountKey)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.createWithAccountKeyMultiSig', () => {
+ context('CAVERJS-UNIT-WALLET-185: input: address and array of private key string', () => {
+ it('should return Account with AccountKeyMultiSig', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey]
+
+ const account = caver.klay.accounts.createWithAccountKeyMultiSig(address, key)
+
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key[0])
+ expect(account.accountKeyType).to.equals('AccountKeyMultiSig')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-186: input: address and AccountKeyMultiSig', () => {
+ it('should return Account with AccountKeyMultiSig', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey]
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const account = caver.klay.accounts.createWithAccountKeyMultiSig(address, accountKey)
+
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key[0])
+ expect(account.accountKeyType).to.equals('AccountKeyMultiSig')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-187: input: address and private key string', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+
+ const expectedError = 'Creating a AccountKeyMultiSig requires an array of private key string.'
+
+ expect(() => caver.klay.accounts.createWithAccountKeyMultiSig(address, key)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-188: input: address and object', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {transactionKey: caver.klay.accounts.create().privateKey}
+
+ const expectedError = 'Creating a AccountKeyMultiSig requires an array of private key string.'
+
+ expect(() => caver.klay.accounts.createWithAccountKeyMultiSig(address, key)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-189: input: address and AccountKeyPublic', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const expectedError = `Failed to create account with AccountKeyMultiSig. Invalid account key : ${accountKey.type}`
+
+ expect(() => caver.klay.accounts.createWithAccountKeyMultiSig(address, accountKey)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-190: input: address and AccountKeyRoleBased', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {transactionKey: caver.klay.accounts.create().privateKey}
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const expectedError = `Failed to create account with AccountKeyMultiSig. Invalid account key : ${accountKey.type}`
+
+ expect(() => caver.klay.accounts.createWithAccountKeyMultiSig(address, accountKey)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.createWithAccountKeyRoleBased', () => {
+ context('CAVERJS-UNIT-WALLET-191: input: address and object of key', () => {
+ it('should return Account with AccountKeyRoleBased', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: caver.klay.accounts.create().privateKey
+ }
+
+ const account = caver.klay.accounts.createWithAccountKeyRoleBased(address, key)
+
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key.transactionKey)
+ expect(account.accountKeyType).to.equals('AccountKeyRoleBased')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-192: input: address and AccountKeyRoleBased', () => {
+ it('should return Account with AccountKeyRoleBased', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: caver.klay.accounts.create().privateKey
+ }
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const account = caver.klay.accounts.createWithAccountKeyRoleBased(address, accountKey)
+
+ isAccount(account, {keys: key, address})
+ expect(account.privateKey).to.equals(key.transactionKey)
+ expect(account.accountKeyType).to.equals('AccountKeyRoleBased')
+ expect(typeof account.toPublicKey).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-193: input: address and private key string', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+
+ const expectedError = 'Creating a AccountKeyRoleBased requires an object.'
+
+ expect(() => caver.klay.accounts.createWithAccountKeyRoleBased(address, key)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-194: input: address and array of private key string', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey]
+
+ const expectedError = 'Creating a AccountKeyRoleBased requires an object.'
+
+ expect(() => caver.klay.accounts.createWithAccountKeyRoleBased(address, key)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-195: input: address and AccountKeyPublic', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const expectedError = `Failed to create account with AccountKeyRoleBased. Invalid account key : ${accountKey.type}`
+
+ expect(() => caver.klay.accounts.createWithAccountKeyRoleBased(address, accountKey)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-196: input: address and AccountKeyMultiSig', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const accountKey = caver.klay.accounts.createAccountKey(key)
+
+ const expectedError = `Failed to create account with AccountKeyRoleBased. Invalid account key : ${accountKey.type}`
+
+ expect(() => caver.klay.accounts.createWithAccountKeyRoleBased(address, accountKey)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.createAccountForUpdate', () => {
+ context('CAVERJS-UNIT-WALLET-197: input: address and private key string', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+ const publicKey = caver.klay.accounts.privateKeyToPublicKey(key)
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, key)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.publicKey).to.equals(publicKey)
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-198: input: address and AccountKeyPublic', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+ const accountKey = caver.klay.accounts.createAccountKeyPublic(key)
+ const publicKey = caver.klay.accounts.privateKeyToPublicKey(key)
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, accountKey)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.publicKey).to.equals(publicKey)
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-199: input: address and array of private key string', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const options = { threshold: 2, weight: [1,1] }
+ const publicKey = [caver.klay.accounts.privateKeyToPublicKey(key[0]), caver.klay.accounts.privateKeyToPublicKey(key[1])]
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, key, options)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.multisig.threshold).to.equals(options.threshold)
+ expect(accountForUpdate.keyForUpdate.multisig.keys[0].weight).to.equals(options.weight[0])
+ expect(accountForUpdate.keyForUpdate.multisig.keys[0].publicKey).to.equals(publicKey[0])
+ expect(accountForUpdate.keyForUpdate.multisig.keys[1].weight).to.equals(options.weight[1])
+ expect(accountForUpdate.keyForUpdate.multisig.keys[1].publicKey).to.equals(publicKey[1])
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-200: input: address and AccountKeyMultiSig', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const accountKey = caver.klay.accounts.createAccountKeyMultiSig(key)
+ const options = { threshold: 2, weight: [1,1] }
+ const publicKey = [caver.klay.accounts.privateKeyToPublicKey(key[0]), caver.klay.accounts.privateKeyToPublicKey(key[1])]
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, accountKey, options)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.multisig.threshold).to.equals(options.threshold)
+ expect(accountForUpdate.keyForUpdate.multisig.keys[0].weight).to.equals(options.weight[0])
+ expect(accountForUpdate.keyForUpdate.multisig.keys[0].publicKey).to.equals(publicKey[0])
+ expect(accountForUpdate.keyForUpdate.multisig.keys[1].weight).to.equals(options.weight[1])
+ expect(accountForUpdate.keyForUpdate.multisig.keys[1].publicKey).to.equals(publicKey[1])
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-201: input: address and object', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ const options = { updateKey: { threshold: 2, weight: [1,1] } }
+ const publicKey = {
+ transactionKey: caver.klay.accounts.privateKeyToPublicKey(key.transactionKey),
+ updateKey: [caver.klay.accounts.privateKeyToPublicKey(key.updateKey[0]), caver.klay.accounts.privateKeyToPublicKey(key.updateKey[1])],
+ feePayerKey: caver.klay.accounts.privateKeyToPublicKey(key.feePayerKey)
+ }
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, key, options)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey.publicKey).to.equals(publicKey.transactionKey)
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.threshold).to.equals(options.updateKey.threshold)
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[0].weight).to.equals(options.updateKey.weight[0])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[0].publicKey).to.equals(publicKey.updateKey[0])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[1].weight).to.equals(options.updateKey.weight[1])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[1].publicKey).to.equals(publicKey.updateKey[1])
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey.publicKey).to.equals(publicKey.feePayerKey)
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-202: input: address and AccountKeyRoleBased', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ const accountKey = caver.klay.accounts.createAccountKeyRoleBased(key)
+ const options = { updateKey: { threshold: 2, weight: [1,1] } }
+ const publicKey = {
+ transactionKey: caver.klay.accounts.privateKeyToPublicKey(key.transactionKey),
+ updateKey: [caver.klay.accounts.privateKeyToPublicKey(key.updateKey[0]), caver.klay.accounts.privateKeyToPublicKey(key.updateKey[1])],
+ feePayerKey: caver.klay.accounts.privateKeyToPublicKey(key.feePayerKey)
+ }
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, accountKey, options)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey.publicKey).to.equals(publicKey.transactionKey)
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.threshold).to.equals(options.updateKey.threshold)
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[0].weight).to.equals(options.updateKey.weight[0])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[0].publicKey).to.equals(publicKey.updateKey[0])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[1].weight).to.equals(options.updateKey.weight[1])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[1].publicKey).to.equals(publicKey.updateKey[1])
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey.publicKey).to.equals(publicKey.feePayerKey)
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-203: input: address and object defines transactionKey only', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { transactionKey: caver.klay.accounts.create().privateKey }
+ const publicKey = { transactionKey: caver.klay.accounts.privateKeyToPublicKey(key.transactionKey) }
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, key)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey.publicKey).to.equals(publicKey.transactionKey)
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey).to.be.undefined
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey).to.be.undefined
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-204: input: address and AccountKeyRoleBased defines transactionKey only', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { transactionKey: caver.klay.accounts.create().privateKey }
+ const accountKey = caver.klay.accounts.createAccountKeyRoleBased(key)
+ const publicKey = { transactionKey: caver.klay.accounts.privateKeyToPublicKey(key.transactionKey) }
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, accountKey)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey.publicKey).to.equals(publicKey.transactionKey)
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey).to.be.undefined
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey).to.be.undefined
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-205: input: address and object defines updateKey only', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { updateKey: caver.klay.accounts.create().privateKey }
+ const publicKey = { updateKey: caver.klay.accounts.privateKeyToPublicKey(key.updateKey) }
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, key)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey).to.be.undefined
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.publicKey).to.equals(publicKey.updateKey)
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey).to.be.undefined
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-206: input: address and AccountKeyRoleBased defines updateKey only', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { updateKey: caver.klay.accounts.create().privateKey }
+ const accountKey = caver.klay.accounts.createAccountKeyRoleBased(key)
+ const publicKey = { updateKey: caver.klay.accounts.privateKeyToPublicKey(key.updateKey) }
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, accountKey)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey).to.be.undefined
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.publicKey).to.equals(publicKey.updateKey)
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey).to.be.undefined
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
- let result = caver.klay.accounts.encrypt(account.getKlaytnWalletKey(), password, {address: account.address})
+ context('CAVERJS-UNIT-WALLET-207: input: address and object defines feePayerKey only', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { feePayerKey: caver.klay.accounts.create().privateKey }
+ const publicKey = { feePayerKey: caver.klay.accounts.privateKeyToPublicKey(key.feePayerKey) }
- isKeystoreV3(result, account)
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, key)
- const decryptedAccount = caver.klay.accounts.decrypt(result, password)
- isAccount(decryptedAccount, account)
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey).to.be.undefined
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey).to.be.undefined
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey.publicKey).to.equals(publicKey.feePayerKey)
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
})
})
- context('CAVERJS-UNIT-WALLET-098 : input: privateKey:KlaytnWalletKey, password, {address:invalid}', () => {
- it('should throw an error', () => {
- const password = 'klaytn!@'
+ context('CAVERJS-UNIT-WALLET-208: input: address and AccountKeyRoleBased defines feePayerKey only', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { feePayerKey: caver.klay.accounts.create().privateKey }
+ const accountKey = caver.klay.accounts.createAccountKeyRoleBased(key)
+ const publicKey = { feePayerKey: caver.klay.accounts.privateKeyToPublicKey(key.feePayerKey) }
- const errorMessage = 'The address extracted from the private key does not match the address received as the input value.'
- expect(() => caver.klay.accounts.encrypt(account.getKlaytnWalletKey(), password, {address: caver.klay.accounts.create().address})).to.throw(errorMessage)
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, accountKey)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey).to.be.undefined
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey).to.be.undefined
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey.publicKey).to.equals(publicKey.feePayerKey)
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
})
})
- context('CAVERJS-UNIT-WALLET-099 : input: privateKey:KlaytnWalletKey(decoupled), password', () => {
- it('should encrypt password with privateKey', () => {
- const password = 'klaytn!@'
- caver.klay.accounts.wallet.add(account)
- var updatedAccount = caver.klay.accounts.wallet.updatePrivateKey(caver.klay.accounts.create().privateKey, account.address)
- let result = caver.klay.accounts.encrypt(updatedAccount.getKlaytnWalletKey(), password)
+ context('CAVERJS-UNIT-WALLET-209: input: address and array of private key without options', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
- isKeystoreV3(result, updatedAccount)
+ const expectedError = 'For AccountKeyMultiSig, threshold and weight should be defined in options object.'
- const decryptedAccount = caver.klay.accounts.decrypt(result, password)
- isAccount(decryptedAccount, updatedAccount)
+ expect(() => caver.klay.accounts.createAccountForUpdate(address, key)).to.throws(expectedError)
})
})
- context('CAVERJS-UNIT-WALLET-100 : input: privateKey:KlaytnWalletKey(decoupled), password, {address:valid}', () => {
- it('should encrypt password with privateKey', () => {
- const password = 'klaytn!@'
- caver.klay.accounts.wallet.add(account)
- var updatedAccount = caver.klay.accounts.wallet.updatePrivateKey(caver.klay.accounts.create().privateKey, account.address)
- let result = caver.klay.accounts.encrypt(updatedAccount.getKlaytnWalletKey(), password, {address: updatedAccount.address})
+ context('CAVERJS-UNIT-WALLET-210: input: address and array of private key with invalid options(weight sum < threshold)', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const options = { threshold: 4, weight: [1,1] }
- isKeystoreV3(result, updatedAccount)
+ const expectedError = 'Invalid options for AccountKeyMultiSig: The sum of weights is less than the threshold.'
- const decryptedAccount = caver.klay.accounts.decrypt(result, password)
- isAccount(decryptedAccount, updatedAccount)
+ expect(() => caver.klay.accounts.createAccountForUpdate(address, key, options)).to.throws(expectedError)
})
})
- context('CAVERJS-UNIT-WALLET-101 : input: privateKey:KlaytnWalletKey(decoupled), password, {address:invalid}', () => {
- it('should encrypt password with privateKey', () => {
- const password = 'klaytn!@'
- caver.klay.accounts.wallet.add(account)
- var updatedAccount = caver.klay.accounts.wallet.updatePrivateKey(caver.klay.accounts.create().privateKey, account.address)
+ context('CAVERJS-UNIT-WALLET-211: input: address and array of private key with invalid options(weight is not array)', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const options = { threshold: 4, weight: 1 }
- const errorMessage = 'The address extracted from the private key does not match the address received as the input value.'
- expect(() => caver.klay.accounts.encrypt(updatedAccount.getKlaytnWalletKey(), password, {address: caver.klay.accounts.create().address})).to.throw(errorMessage)
+ const expectedError = 'The weight should be defined as a array.'
+
+ expect(() => caver.klay.accounts.createAccountForUpdate(address, key, options)).to.throws(expectedError)
})
})
-})
-describe('caver.klay.accounts.decrypt', () => {
- let account
+ context('CAVERJS-UNIT-WALLET-212: input: address and array of private key with invalid options(weight length is not matched with key array)', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const options = { threshold: 2, weight: [1,1,1,1] }
- beforeEach(() => {
- account = caver.klay.accounts.create()
+ const expectedError = 'The length of keys in AccountKeyMultiSig and the length of weight array do not match.'
+
+ expect(() => caver.klay.accounts.createAccountForUpdate(address, key, options)).to.throws(expectedError)
+ })
})
- context('CAVERJS-UNIT-WALLET-042 : input: keystoreJsonV3, password', () => {
- it('After decrypting, should return valid account', () => {
- const password = 'klaytn!@'
- const keystoreJsonV3 = caver.klay.accounts.encrypt(account.privateKey, password)
+ context('CAVERJS-UNIT-WALLET-213: input: address and object has multisig without options', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
- let result = caver.klay.accounts.decrypt(keystoreJsonV3, password)
- isKeystoreV3(keystoreJsonV3, result)
+ const expectedError = 'For AccountKeyMultiSig, threshold and weight should be defined in options object.'
- isAccount(result, account)
+ expect(() => caver.klay.accounts.createAccountForUpdate(address, key)).to.throws(expectedError)
})
})
- context('CAVERJS-UNIT-WALLET-103 : input: keystoreJsonV3(without 0x address format), password', () => {
- it('After decrypting, should return valid account', () => {
- const password = 'klaytn!@'
- const keystoreJsonV3 = caver.klay.accounts.encrypt(account.privateKey, password)
- keystoreJsonV3.address = keystoreJsonV3.address.replace('0x', '')
+ context('CAVERJS-UNIT-WALLET-214: input: address and array of private key with invalid options(weight sum < threshold)', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
+ const options = { transactionKey: { threshold: 4, weight: [1,1] } }
+
+ const expectedError = 'Invalid options for AccountKeyMultiSig: The sum of weights is less than the threshold.'
+
+ expect(() => caver.klay.accounts.createAccountForUpdate(address, key, options)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-215: input: address and array of private key with invalid options(weight is not array)', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
+ const options = { transactionKey: { threshold: 4, weight: 1 } }
+
+ const expectedError = 'The weight should be defined as a array.'
+
+ expect(() => caver.klay.accounts.createAccountForUpdate(address, key, options)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-216: input: address and array of private key with invalid options(weight length is not matched with key array)', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
+ const options = { transactionKey: { threshold: 2, weight: [1,1,1,1] } }
+
+ const expectedError = 'The length of keys in AccountKeyMultiSig and the length of weight array do not match.'
+
+ expect(() => caver.klay.accounts.createAccountForUpdate(address, key, options)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-348: input: address and key object which has legacyKey and failKey', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { transactionKey: 'legacyKey', feePayerKey: 'failKey' }
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, key)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey.legacyKey).to.be.true
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey).to.be.undefined
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey.failKey).to.be.true
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-349: input: address and key object which has transactionKey(legacyKey), updateKey(multiSigKey) and feePayerKey(failKey)', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const updateKey = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const updatePublicKey = [caver.klay.accounts.privateKeyToPublicKey(updateKey[0]), caver.klay.accounts.privateKeyToPublicKey(updateKey[1])]
+ const key = { transactionKey: 'legacyKey', updateKey: updateKey ,feePayerKey: 'failKey' }
+ const options = { updateKey: { threshold: 2, weight: [1, 1] } }
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdate(address, key, options)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey.legacyKey).to.be.true
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.threshold).to.equals(options.updateKey.threshold)
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys.length).to.equals(updateKey.length)
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[0].publicKey).to.equals(updatePublicKey[0])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[1].publicKey).to.equals(updatePublicKey[1])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[0].weight).to.equals(options.updateKey.weight[0])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[1].weight).to.equals(options.updateKey.weight[1])
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey.failKey).to.be.true
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-350: input: address and key object which has legacyKey and failKey with options', () => {
+ it('should throw error', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { transactionKey: 'legacyKey', feePayerKey: 'failKey' }
+ const options = { transactionKey: { threshold: 2, weight: [1,1,1,1] } }
+
+ const expectedError = 'Failed to keyFormatter for AccountForUpdate: AccountKeyPublic/legacyKey/failKey cannot have options'
+
+ expect(() => caver.klay.accounts.createAccountForUpdate(address, key, options)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.createAccountForUpdateWithPublicKey', () => {
+ context('CAVERJS-UNIT-WALLET-217: input: address and public key string', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+ const publicKey = caver.klay.accounts.privateKeyToPublicKey(key)
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdateWithPublicKey(address, publicKey)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.publicKey).to.equals(publicKey)
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-218: input: address and array of public key string', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const options = { threshold: 2, weight: [1,1] }
+ const publicKey = [caver.klay.accounts.privateKeyToPublicKey(key[0]), caver.klay.accounts.privateKeyToPublicKey(key[1])]
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdateWithPublicKey(address, publicKey, options)
- let result = caver.klay.accounts.decrypt(keystoreJsonV3, password)
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.multisig.threshold).to.equals(options.threshold)
+ expect(accountForUpdate.keyForUpdate.multisig.keys[0].weight).to.equals(options.weight[0])
+ expect(accountForUpdate.keyForUpdate.multisig.keys[0].publicKey).to.equals(publicKey[0])
+ expect(accountForUpdate.keyForUpdate.multisig.keys[1].weight).to.equals(options.weight[1])
+ expect(accountForUpdate.keyForUpdate.multisig.keys[1].publicKey).to.equals(publicKey[1])
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-219: input: address and object of public key', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+
+ const options = { updateKey: { threshold: 2, weight: [1,1] } }
+ const publicKey = {
+ transactionKey: caver.klay.accounts.privateKeyToPublicKey(key.transactionKey),
+ updateKey: [caver.klay.accounts.privateKeyToPublicKey(key.updateKey[0]), caver.klay.accounts.privateKeyToPublicKey(key.updateKey[1])],
+ feePayerKey: caver.klay.accounts.privateKeyToPublicKey(key.feePayerKey)
+ }
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdateWithPublicKey(address, publicKey, options)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.roleTransactionKey.publicKey).to.equals(publicKey.transactionKey)
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.threshold).to.equals(options.updateKey.threshold)
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[0].weight).to.equals(options.updateKey.weight[0])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[0].publicKey).to.equals(publicKey.updateKey[0])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[1].weight).to.equals(options.updateKey.weight[1])
+ expect(accountForUpdate.keyForUpdate.roleAccountUpdateKey.multisig.keys[1].publicKey).to.equals(publicKey.updateKey[1])
+ expect(accountForUpdate.keyForUpdate.roleFeePayerKey.publicKey).to.equals(publicKey.feePayerKey)
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-220: input: address and object of public key with invalid role', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
- expect(result.address.slice(0, 2)).to.equals('0x')
+ const options = { updateKey: { threshold: 2, weight: [1,1] } }
+ const publicKey = {
+ invalidRoleKey: caver.klay.accounts.privateKeyToPublicKey(key.transactionKey),
+ updateKey: [caver.klay.accounts.privateKeyToPublicKey(key.updateKey[0]), caver.klay.accounts.privateKeyToPublicKey(key.updateKey[1])],
+ feePayerKey: caver.klay.accounts.privateKeyToPublicKey(key.feePayerKey)
+ }
+
+ const expectedError = `Invalid role is defined: invalidRoleKey`
+
+ expect(() => caver.klay.accounts.createAccountForUpdateWithPublicKey(address, publicKey, options)).to.throws(expectedError)
})
})
- /*
- it('keystoreJsonV3, password:invalid [KLAYTN-52]', () => {
- const invalid = ''
- const keystoreJsonV3 = caver.klay.accounts.encrypt(account.privateKey, invalid)
+ context('CAVERJS-UNIT-WALLET-221: input: address and array of public key string without options', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const publicKey = [caver.klay.accounts.privateKeyToPublicKey(key[0]), caver.klay.accounts.privateKeyToPublicKey(key[1])]
- utils.log('input', keystoreJsonV3, invalid)
+ const expectedError = 'For AccountKeyMultiSig, threshold and weight should be defined in options object.'
- const expectedError = {
- name: 'Error',
- message: ''
- }
- validateErrorCodeblock(() => caver.klay.accounts.decrypt(keystoreJsonV3, invalid), expectedError)
+ expect(() => caver.klay.accounts.createAccountForUpdateWithPublicKey(address, publicKey)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-222: input: address and object of public key string without options', () => {
+ it('should return AccountForUpdate', () => {
+ const address = caver.klay.accounts.create().address
+ const key = { updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] }
+ const publicKey = [caver.klay.accounts.privateKeyToPublicKey(key.updateKey[0]), caver.klay.accounts.privateKeyToPublicKey(key.updateKey[1])]
+
+ const expectedError = 'For AccountKeyMultiSig, threshold and weight should be defined in options object.'
+
+ expect(() => caver.klay.accounts.createAccountForUpdateWithPublicKey(address, publicKey)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.createAccountForUpdateWithLegacyKey', () => {
+ context('CAVERJS-UNIT-WALLET-223: input: address', () => {
+ it('should return AccountForUpdate with legacy key setting', () => {
+ const address = caver.klay.accounts.create().address
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdateWithLegacyKey(address)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.legacyKey).to.be.true
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
+ })
+})
+
+describe('caver.klay.accounts.createAccountForUpdateWithFailKey', () => {
+ context('CAVERJS-UNIT-WALLET-224: input: address', () => {
+ it('should return AccountForUpdate with fail key setting', () => {
+ const address = caver.klay.accounts.create().address
+
+ const accountForUpdate = caver.klay.accounts.createAccountForUpdateWithFailKey(address)
+
+ expect(accountForUpdate.address).to.equals(address)
+ expect(accountForUpdate.keyForUpdate.failKey).to.be.true
+ expect(typeof accountForUpdate.fillUpdateObject).to.equals('function')
+ })
})
- */
})
describe('caver.klay.accounts.wallet', () => {
@@ -651,14 +4487,11 @@ describe('caver.klay.accounts.wallet.create', () => {
isWallet(result)
expect(result.length).to.equal(numberOfAccounts)
for (let i = 0; i < result.length; i++) {
- const accountByIndex = Object.assign({}, result[i])
- const accountByAddress = Object.assign({}, result[accountByIndex.address])
+ const accountByIndex = caver.klay.accounts.createWithAccountKey(result[i].address, result[i].accountKey)
+ const accountByAddress = caver.klay.accounts.createWithAccountKey(result[accountByIndex.address].address, result[accountByIndex.address].accountKey)
- delete accountByIndex.index
- delete accountByAddress.index
-
- isAccount(accountByIndex, { privateKey: accountByAddress.privateKey, address: accountByAddress.address })
- isAccount(accountByAddress, { privateKey: accountByIndex.privateKey, address: accountByIndex.address })
+ isAccount(accountByIndex, { keys: accountByAddress.keys, address: accountByAddress.address })
+ isAccount(accountByAddress, { keys: accountByIndex.keys, address: accountByIndex.address })
}
}
@@ -693,13 +4526,12 @@ describe('caver.klay.accounts.wallet.add', () => {
const validateCheckForWalletAddition = (data, { account, wallet }) => {
const accounts = []
- accounts.push(Object.assign({}, data))
- accounts.push(Object.assign({}, wallet[data.index]))
- accounts.push(Object.assign({}, wallet[data.address]))
+ accounts.push(caver.klay.accounts.createWithAccountKey(data.address, data.accountKey))
+ accounts.push(caver.klay.accounts.createWithAccountKey(wallet[data.index].address, wallet[data.index].accountKey))
+ accounts.push(caver.klay.accounts.createWithAccountKey(wallet[data.address].address, wallet[data.address].accountKey))
for (v of accounts) {
- delete v.index
- isAccount(v, { privateKey: account.privateKey, address: account.address })
+ isAccount(v, { keys: account.keys, address: account.address })
}
}
@@ -753,52 +4585,387 @@ describe('caver.klay.accounts.wallet.add', () => {
validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet })
- account = caver.klay.accounts.create()
- address = '0x6a61736d696e652e6b6c6179746e000000000000'
- account.address = address
- result = caver.klay.accounts.wallet.add(account.privateKey, address)
+ account = caver.klay.accounts.create()
+ address = '0x6a61736d696e652e6b6c6179746e000000000000'
+ account.address = address
+ result = caver.klay.accounts.wallet.add(account.privateKey, address)
+
+ validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-053 CAVERJS-UNIT-WALLET-054 : input: KlaytnWalletKey, address', () => {
+ it('should have valid wallet instance after addition', () => {
+ klaytnWalletKey = '0xc1ad21b3da99cbb6a57cf181ec3e36af77ae37112585f700c81db19115f74b110x000xc4f88823f5030e4343c1494b502d534e9f15152d'
+ account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey)
+ result = caver.klay.accounts.wallet.add(klaytnWalletKey, account.address)
+
+ validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet })
+
+ // decoupled
+ klaytnWalletKey = '0xc1ad21b3da99cbb6a57cf181ec3e36af77ae37112585f700c81db19115f74b110x000x95e024d64534948a89748d4c3e82e02d05721beb'
+ account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey)
+ result = caver.klay.accounts.wallet.add(klaytnWalletKey, account.address)
+
+ validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-055 : input: KlaytnWalletKey, invalid address', () => {
+ it('should have valid wallet instance after addition', () => {
+ klaytnWalletKey = '0x2d21dc5d73e29177af17a1376f3e5769b94086479735e711670c2d599c3f97ab0x000x53b0e6ebd395093d83ac9b0e1e47b4b31b7c18c4'
+ account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey)
+ expect(()=> caver.klay.accounts.wallet.add(klaytnWalletKey, '0x95e024d64534948a89748d4c3e82e02d05721beb')).to.throw()
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-056 : input: invalid KlaytnWalletKey', () => {
+ it('should have valid wallet instance after addition', () => {
+ klaytnWalletKey = '0x39d87f15c695ec94d6d7107b48dee85e252f21fedd371e1c6badc4afa71efbdf0x010x167bcdef96658b7b7a94ac398a8e7275e719a10c'
+ expect(()=> caver.klay.accounts.wallet.add(klaytnWalletKey)).to.throw()
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-049 : input: account:invalid', () => {
+ it('should throw an error', () => {
+ const invalid = -1
+ const errorMessage = 'Invalid accountKey type: number'
+ expect(() => caver.klay.accounts.wallet.add(invalid)).to.throw(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-244: input: userInputAddress and AccountKeyPublic', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = caver.klay.accounts.create().privateKey
+ const address = caver.klay.accounts.create().address
+ const accountKeyPublic = caver.klay.accounts.createAccountKeyPublic(key)
+ const accountWithPublic = caver.klay.accounts.createWithAccountKey(address, accountKeyPublic)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountKeyPublic, address)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithPublic, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-245: input: userInputAddress and AccountKeyMultiSig', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const address = caver.klay.accounts.create().address
+ const accountKeyMultiSig = caver.klay.accounts.createAccountKeyMultiSig(key)
+ const accountWithMultiSig = caver.klay.accounts.createWithAccountKey(address, accountKeyMultiSig)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountKeyMultiSig, address)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithMultiSig, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-246: input: userInputAddress and AccountKeyRoleBased which defines transactionKey, updateKey and feePayerKey', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = {
+ transactionKey: [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]
+ }
+ const address = caver.klay.accounts.create().address
+ const accountKeyRoleBased = caver.klay.accounts.createAccountKeyRoleBased(key)
+ const accountWithRoleBased = caver.klay.accounts.createWithAccountKey(address, accountKeyRoleBased)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountKeyRoleBased, address)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithRoleBased, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-247: input: userInputAddress and AccountKeyRoleBased which defines transactionKey only', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+ const address = caver.klay.accounts.create().address
+ const accountKeyRoleBased = caver.klay.accounts.createAccountKeyRoleBased(key)
+ const accountWithRoleBased = caver.klay.accounts.createWithAccountKey(address, accountKeyRoleBased)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountKeyRoleBased, address)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithRoleBased, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-248: input: userInputAddress and AccountKeyRoleBased which defines updateKey only', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = {
+ updateKey: caver.klay.accounts.create().privateKey
+ }
+ const address = caver.klay.accounts.create().address
+ const accountKeyRoleBased = caver.klay.accounts.createAccountKeyRoleBased(key)
+ const accountWithRoleBased = caver.klay.accounts.createWithAccountKey(address, accountKeyRoleBased)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountKeyRoleBased, address)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithRoleBased, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-249: input: userInputAddress and AccountKeyRoleBased which defines feePayerKey only', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = {
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+ const address = caver.klay.accounts.create().address
+ const accountKeyRoleBased = caver.klay.accounts.createAccountKeyRoleBased(key)
+ const accountWithRoleBased = caver.klay.accounts.createWithAccountKey(address, accountKeyRoleBased)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountKeyRoleBased, address)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithRoleBased, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-250: input: AccountKeyPublic without userInputAddress', () => {
+ it('should throw error', () => {
+ const accountKey = caver.klay.accounts.createAccountKey(caver.klay.accounts.create().privateKey)
+
+ const expectedError = `Address is not defined. Address cannot be determined from AccountKey`
+ expect(() => caver.klay.accounts.wallet.add(accountKey)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-251: input: AccountKeyMultiSig without userInputAddress', () => {
+ it('should throw error', () => {
+ const accountKey = caver.klay.accounts.createAccountKey([caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey])
+
+ const expectedError = `Address is not defined. Address cannot be determined from AccountKey`
+ expect(() => caver.klay.accounts.wallet.add(accountKey)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-252: input: AccountKeyRoleBased without userInputAddress', () => {
+ it('should throw error', () => {
+ const accountKey = caver.klay.accounts.createAccountKey({transactionKey: caver.klay.accounts.create().privateKey})
+
+ const expectedError = `Address is not defined. Address cannot be determined from AccountKey`
+ expect(() => caver.klay.accounts.wallet.add(accountKey)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-253: input: Account with AccountKeyPublic', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = caver.klay.accounts.create().privateKey
+ const address = caver.klay.accounts.create().address
+ const accountWithPublic = caver.klay.accounts.createWithAccountKey(address, key)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountWithPublic)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithPublic, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-254: input: Account with AccountKeyMultiSig', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const address = caver.klay.accounts.create().address
+ const accountWithMultiSig = caver.klay.accounts.createWithAccountKey(address, key)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountWithMultiSig)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithMultiSig, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-255: input: Account with AccountKeyRoleBased which defines transactionKey, updateKey and feePayerKey', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = {
+ transactionKey: [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]
+ }
+ const address = caver.klay.accounts.create().address
+ const accountWithRoleBased = caver.klay.accounts.createWithAccountKey(address, key)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountWithRoleBased)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithRoleBased, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-256: input: Account with AccountKeyRoleBased which defines transactionKey only', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+ const address = caver.klay.accounts.create().address
+ const accountWithRoleBased = caver.klay.accounts.createWithAccountKey(address, key)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountWithRoleBased)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithRoleBased, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-257: input: Account with AccountKeyRoleBased which defines updateKey only', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = {
+ updateKey: caver.klay.accounts.create().privateKey
+ }
+ const address = caver.klay.accounts.create().address
+ const accountWithRoleBased = caver.klay.accounts.createWithAccountKey(address, key)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountWithRoleBased)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithRoleBased, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-258: input: Account with AccountKeyRoleBased which defines feePayerKey only', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = {
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+ const address = caver.klay.accounts.create().address
+ const accountWithRoleBased = caver.klay.accounts.createWithAccountKey(address, key)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountWithRoleBased)
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithRoleBased, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-259: input: Account with AccountKeyPublic and userInputAddress', () => {
+ it('should have valid Account instance with userInputAddress as an address in wallet after addition', () => {
+ const key = caver.klay.accounts.create().privateKey
+ const address = caver.klay.accounts.create().address
+ const accountWithPublic = caver.klay.accounts.createWithAccountKey(address, key)
+ const userInputAddrees = caver.klay.accounts.create().address
+
+ let accountInWallet = caver.klay.accounts.wallet.add(accountWithPublic, userInputAddrees)
+ accountWithPublic.address = userInputAddrees
+
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithPublic, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-260: input: object which has address and privateKey', () => {
+ it('should have valid Account instance in wallet after addition', () => {
+ const key = caver.klay.accounts.create().privateKey
+ const address = caver.klay.accounts.create().address
+ const accountWithPublic = caver.klay.accounts.createWithAccountKey(address, key)
+
+ const inputObject = {
+ address: accountWithPublic.address,
+ privateKey: accountWithPublic.privateKey,
+ }
+
+ let accountInWallet = caver.klay.accounts.wallet.add(inputObject)
+
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithPublic, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-261: input: userInputAddress and object which has address and privateKey', () => {
+ it('should have valid Account instance with userInputAddress as an address in wallet after addition', () => {
+ const key = caver.klay.accounts.create().privateKey
+ const address = caver.klay.accounts.create().address
+ const accountWithPublic = caver.klay.accounts.createWithAccountKey(address, key)
+ const userInputAddrees = caver.klay.accounts.create().address
+
+ const inputObject = {
+ address: accountWithPublic.address,
+ privateKey: accountWithPublic.privateKey,
+ }
+
+ let accountInWallet = caver.klay.accounts.wallet.add(inputObject, userInputAddrees)
+ accountWithPublic.address = userInputAddrees
+
+ validateCheckForWalletAddition(accountInWallet, { account: accountWithPublic, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-262: input: userInputAddress and array of private key string', () => {
+ it('should have valid Account instance with userInputAddress as an address in wallet after addition', () => {
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const address = caver.klay.accounts.create().address
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(key, address)
+
+ validateCheckForWalletAddition(accountInWallet, { account: account, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-263: input: userInputAddress and key object which defines transactionKey, updateKey and feePayerKey', () => {
+ it('should have valid Account instance with userInputAddress as an address in wallet after addition', () => {
+ const key = {
+ transactionKey: [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]
+ }
+ const address = caver.klay.accounts.create().address
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
- validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet })
+ let accountInWallet = caver.klay.accounts.wallet.add(key, address)
+
+ validateCheckForWalletAddition(accountInWallet, { account: account, wallet: caver.klay.accounts.wallet })
})
})
- context('CAVERJS-UNIT-WALLET-053 CAVERJS-UNIT-WALLET-054 : input: KlaytnWalletKey, address', () => {
- it('should have valid wallet instance after addition', () => {
- klaytnWalletKey = '0xc1ad21b3da99cbb6a57cf181ec3e36af77ae37112585f700c81db19115f74b110x000xc4f88823f5030e4343c1494b502d534e9f15152d'
- account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey)
- result = caver.klay.accounts.wallet.add(klaytnWalletKey, account.address)
+ context('CAVERJS-UNIT-WALLET-264: input: userInputAddress and key object which defines transactionKey only', () => {
+ it('should have valid Account instance with userInputAddress as an address in wallet after addition', () => {
+ const key = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+ const address = caver.klay.accounts.create().address
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
- validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet })
+ let accountInWallet = caver.klay.accounts.wallet.add(key, address)
+
+ validateCheckForWalletAddition(accountInWallet, { account: account, wallet: caver.klay.accounts.wallet })
+ })
+ })
- // decoupled
- klaytnWalletKey = '0xc1ad21b3da99cbb6a57cf181ec3e36af77ae37112585f700c81db19115f74b110x000x95e024d64534948a89748d4c3e82e02d05721beb'
- account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey)
- result = caver.klay.accounts.wallet.add(klaytnWalletKey, account.address)
+ context('CAVERJS-UNIT-WALLET-265: input: userInputAddress and key object which defines updateKey only', () => {
+ it('should have valid Account instance with userInputAddress as an address in wallet after addition', () => {
+ const key = {
+ updateKey: caver.klay.accounts.create().privateKey
+ }
+ const address = caver.klay.accounts.create().address
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
- validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet })
+ let accountInWallet = caver.klay.accounts.wallet.add(key, address)
+
+ validateCheckForWalletAddition(accountInWallet, { account: account, wallet: caver.klay.accounts.wallet })
})
})
- context('CAVERJS-UNIT-WALLET-055 : input: KlaytnWalletKey, invalid address', () => {
- it('should have valid wallet instance after addition', () => {
- klaytnWalletKey = '0x2d21dc5d73e29177af17a1376f3e5769b94086479735e711670c2d599c3f97ab0x000x53b0e6ebd395093d83ac9b0e1e47b4b31b7c18c4'
- account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey)
- expect(()=> caver.klay.accounts.wallet.add(klaytnWalletKey, '0x95e024d64534948a89748d4c3e82e02d05721beb')).to.throw()
+ context('CAVERJS-UNIT-WALLET-266: input: userInputAddress and key object which defines feePayerKey only', () => {
+ it('should have valid Account instance with userInputAddress as an address in wallet after addition', () => {
+ const key = {
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+ const address = caver.klay.accounts.create().address
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+
+ let accountInWallet = caver.klay.accounts.wallet.add(key, address)
+
+ validateCheckForWalletAddition(accountInWallet, { account: account, wallet: caver.klay.accounts.wallet })
})
})
- context('CAVERJS-UNIT-WALLET-056 : input: invalid KlaytnWalletKey', () => {
- it('should have valid wallet instance after addition', () => {
- klaytnWalletKey = '0x39d87f15c695ec94d6d7107b48dee85e252f21fedd371e1c6badc4afa71efbdf0x010x167bcdef96658b7b7a94ac398a8e7275e719a10c'
- expect(()=> caver.klay.accounts.wallet.add(klaytnWalletKey)).to.throw()
+ context('CAVERJS-UNIT-WALLET-267: input: invalid type parameter', () => {
+ it('should throw error', () => {
+ let invalid = {}
+
+ let expectedError = `Failed to create AccountKeyRoleBased: empty object`
+ expect(() => caver.klay.accounts.wallet.add(invalid)).to.throws(expectedError)
+
+ invalid = undefined
+ expectedError = `Invalid accountKey type: ${typeof invalid}`
+ expect(() => caver.klay.accounts.wallet.add(invalid)).to.throws(expectedError)
+
+ invalid = null
+ expectedError = `Invalid accountKey type: ${typeof invalid}`
+ expect(() => caver.klay.accounts.wallet.add(invalid)).to.throws(expectedError)
+
+ invalid = 1
+ expectedError = `Invalid accountKey type: ${typeof invalid}`
+ expect(() => caver.klay.accounts.wallet.add(invalid)).to.throws(expectedError)
})
})
- context('CAVERJS-UNIT-WALLET-049 : input: account:invalid', () => {
- it('should throw an error', () => {
- const invalid = -1
- const errorMessage = 'Invalid private key'
- expect(() => caver.klay.accounts.wallet.add(invalid)).to.throw(errorMessage)
+ context('CAVERJS-UNIT-WALLET-268: input: invalid role defined', () => {
+ it('should throw error', () => {
+ const invalid = {invalidRole: caver.klay.accounts.create().privateKey}
+
+ const expectedError = `Failed to create AccountKeyRoleBased. Invalid role is defined : invalidRole`
+ expect(() => caver.klay.accounts.wallet.add(invalid)).to.throws(expectedError)
})
})
})
@@ -845,6 +5012,73 @@ describe('caver.klay.accounts.wallet.remove', () => {
validateCheckForWalletRemove(result, { expected: false })
})
})
+
+ context('CAVERJS-UNIT-WALLET-269: input: Account with AccountKeyPublic', () => {
+ it('should remove wallet instance', () => {
+ const address = caver.klay.accounts.create().address
+ const key = caver.klay.accounts.create().privateKey
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+ let accountInWallet = caver.klay.accounts.wallet.add(account)
+
+ let result = caver.klay.accounts.wallet.remove(accountInWallet.index)
+
+ expect(accountInWallet.accountKey).to.be.null
+ validateCheckForWalletRemove(result, { account: accountInWallet, wallet: caver.klay.accounts.wallet })
+
+ accountInWallet = caver.klay.accounts.wallet.add(account)
+
+ result = caver.klay.accounts.wallet.remove(accountInWallet.address)
+
+ expect(accountInWallet.accountKey).to.be.null
+ validateCheckForWalletRemove(result, { account: accountInWallet, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-270: input: Account with AccountKeyMultiSig', () => {
+ it('should remove wallet instance', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+ let accountInWallet = caver.klay.accounts.wallet.add(account)
+
+ let result = caver.klay.accounts.wallet.remove(accountInWallet.index)
+
+ expect(accountInWallet.accountKey).to.be.null
+ validateCheckForWalletRemove(result, { account: accountInWallet, wallet: caver.klay.accounts.wallet })
+
+ accountInWallet = caver.klay.accounts.wallet.add(account)
+
+ result = caver.klay.accounts.wallet.remove(accountInWallet.address)
+
+ expect(accountInWallet.accountKey).to.be.null
+ validateCheckForWalletRemove(result, { account: accountInWallet, wallet: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-271: input: Account with AccountKeyRoleBased', () => {
+ it('should remove wallet instance', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: caver.klay.accounts.create().privateKey,
+ feePayerKey: caver.klay.accounts.create().privateKey
+ }
+ const account = caver.klay.accounts.createWithAccountKey(address, key)
+ let accountInWallet = caver.klay.accounts.wallet.add(account)
+
+ let result = caver.klay.accounts.wallet.remove(accountInWallet.index)
+
+ expect(accountInWallet.accountKey).to.be.null
+ validateCheckForWalletRemove(result, { account: accountInWallet, wallet: caver.klay.accounts.wallet })
+
+ accountInWallet = caver.klay.accounts.wallet.add(account)
+
+ result = caver.klay.accounts.wallet.remove(accountInWallet.address)
+
+ expect(accountInWallet.accountKey).to.be.null
+ validateCheckForWalletRemove(result, { account: accountInWallet, wallet: caver.klay.accounts.wallet })
+ })
+ })
})
describe('caver.klay.accounts.wallet.clear', () => {
@@ -869,7 +5103,7 @@ describe('caver.klay.accounts.wallet.clear', () => {
describe('caver.klay.accounts.wallet.encrypt', () => {
context('CAVERJS-UNIT-WALLET-062 : input: password', () => {
- it('should encrypted as v3Keystore', () => {
+ it('should encrypted as v4Keystore', () => {
const password = 'klaytn!@'
const numberOfAccounts = Math.floor(Math.random() * 5) + 1
@@ -879,13 +5113,44 @@ describe('caver.klay.accounts.wallet.encrypt', () => {
expect(result.length).to.equal(caver.klay.accounts.wallet.length)
result.forEach((v, i) => {
- isKeystoreV3(v, { address: caver.klay.accounts.wallet[i].address })
+ isKeystoreV4(v, { address: caver.klay.accounts.wallet[i].address })
+ })
+ const decryptedWallet = caver.klay.accounts.wallet.decrypt(result, password)
+ isWallet(decryptedWallet, { accounts: caver.klay.accounts.wallet })
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-272: input: password', () => {
+ it('should throw error if there is Account with AccountKeyMultiSig or AccountKeyRoleBased', () => {
+ const password = 'klaytn!@'
+
+ // AccountKeyMultiSig
+ let address = caver.klay.accounts.create().address
+ let key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey(address, key))
+
+ // AccountKeyRoleBased
+ let roleBasedaddress = caver.klay.accounts.create().address
+ let roleBasedkey = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: caver.klay.accounts.create().privateKey,
+ feePayerKey: caver.klay.accounts.create().privateKey
+ }
+ caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey(roleBasedaddress, roleBasedkey))
+
+ let result = caver.klay.accounts.wallet.encrypt(password)
+
+ expect(result.length).to.equal(caver.klay.accounts.wallet.length)
+ result.forEach((v, i) => {
+ isKeystoreV4(v, { address: caver.klay.accounts.wallet[i].address })
})
const decryptedWallet = caver.klay.accounts.wallet.decrypt(result, password)
isWallet(decryptedWallet, { accounts: caver.klay.accounts.wallet })
+
})
})
+
/*
it('password:invalid [KLAYTN-52]', () => {
const invalid = ''
@@ -907,12 +5172,26 @@ describe('caver.klay.accounts.wallet.encrypt', () => {
describe('caver.klay.accounts.wallet.decrypt', () => {
context('CAVERJS-UNIT-WALLET-063 : input: keystoreArray, password', () => {
- it('should decrypt v3Keystore to account instance', () => {
+ it('should decrypt v4Keystore to account instance', () => {
const password = 'klaytn!@'
const numberOfAccounts = Math.floor(Math.random() * 5) + 1
caver.klay.accounts.wallet.create(numberOfAccounts)
+ // AccountKeyMultiSig
+ let address = caver.klay.accounts.create().address
+ let key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey(address, key))
+
+ // AccountKeyRoleBased
+ let roleBasedaddress = caver.klay.accounts.create().address
+ let roleBasedkey = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: caver.klay.accounts.create().privateKey,
+ feePayerKey: caver.klay.accounts.create().privateKey
+ }
+ caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey(roleBasedaddress, roleBasedkey))
+
const encryptedKeystore = caver.klay.accounts.wallet.encrypt(password)
caver.klay.accounts.wallet.clear()
@@ -940,3 +5219,426 @@ describe('caver.klay.accounts.wallet.decrypt', () => {
})
*/
})
+
+describe('caver.klay.accounts.wallet.getAccount', () => {
+ context('CAVERJS-UNIT-WALLET-125 : input: number', () => {
+ it('should return Account from Wallet', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+
+ const fromWallet = caver.klay.accounts.wallet.getAccount(testAccount.index)
+
+ expect(testAccount.address).to.equals(fromWallet.address)
+ expect(testAccount.privateKey).to.equals(fromWallet.privateKey)
+ expect(testAccount.index).to.equals(fromWallet.index)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-126 : input: invalid number index', () => {
+ it('should throw Error', () => {
+ const errorMessage = `The index(${caver.klay.accounts.wallet.length}) is out of range(Wallet length : ${caver.klay.accounts.wallet.length}).`
+
+ expect(() => caver.klay.accounts.wallet.getAccount(caver.klay.accounts.wallet.length)).to.throws(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-127 : input: invalid parameter type for getAccount', () => {
+ it('should throw Error', () => {
+ const errorMessage = `Accounts in the Wallet can be searched by only index or address.`
+
+ expect(() => caver.klay.accounts.wallet.getAccount({})).to.throws(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-128 : input: invalid address for getAccount', () => {
+ it('should throw Error', () => {
+ const input = 'address'
+ const errorMessage = `Failed to getAccount from Wallet: invalid address(${input})`
+
+ expect(() => caver.klay.accounts.wallet.getAccount(input)).to.throws(errorMessage)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-129 : input: validAddress', () => {
+ it('should return Account from Wallet', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+
+ let fromWallet = caver.klay.accounts.wallet.getAccount(testAccount.address)
+
+ expect(testAccount.address).to.equals(fromWallet.address)
+ expect(testAccount.privateKey).to.equals(fromWallet.privateKey)
+ expect(testAccount.index).to.equals(fromWallet.index)
+
+ fromWallet = caver.klay.accounts.wallet.getAccount(testAccount.address.toLowerCase())
+
+ expect(testAccount.address).to.equals(fromWallet.address)
+ expect(testAccount.privateKey).to.equals(fromWallet.privateKey)
+ expect(testAccount.index).to.equals(fromWallet.index)
+
+ fromWallet = caver.klay.accounts.wallet.getAccount(testAccount.address.toUpperCase())
+
+ expect(testAccount.address).to.equals(fromWallet.address)
+ expect(testAccount.privateKey).to.equals(fromWallet.privateKey)
+ expect(testAccount.index).to.equals(fromWallet.index)
+ })
+ })
+})
+
+describe('caver.klay.accounts.wallet.updatePrivateKey', () => {
+ context('CAVERJS-UNIT-WALLET-322: input: private key string and address', () => {
+ it('should update the private key of account by updating the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const originalPrivateKey = testAccount.privateKey
+ const updatePrivateKey = caver.klay.accounts.create().privateKey
+
+ let account = caver.klay.accounts.wallet.getAccount(testAccount.address)
+ expect(account.privateKey).to.equals(originalPrivateKey)
+
+ account = caver.klay.accounts.wallet.updatePrivateKey(updatePrivateKey, testAccount.address)
+ expect(account.privateKey).to.equals(updatePrivateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-323: input: KlaytnWalletKey and address', () => {
+ it('should update the private key of account by updating the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const originalPrivateKey = testAccount.privateKey
+ const updatedAccount = caver.klay.accounts.createWithAccountKey(testAccount.address, caver.klay.accounts.create().privateKey)
+ const klaytnWalletKey = updatedAccount.getKlaytnWalletKey()
+ const updatedPrivateKey = updatedAccount.privateKey
+
+ let account = caver.klay.accounts.wallet.getAccount(testAccount.address)
+ expect(account.privateKey).to.equals(originalPrivateKey)
+
+ account = caver.klay.accounts.wallet.updatePrivateKey(klaytnWalletKey, testAccount.address)
+ expect(account.privateKey).to.equals(updatedPrivateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-324: input: private key or address are undefined', () => {
+ it('should throw error', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const updatePrivateKey = caver.klay.accounts.create().privateKey
+
+ const expectedError = `To update the privatKey in wallet, need to set both privateKey and address.`
+
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey()).to.throws(expectedError)
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(updatePrivateKey)).to.throws(expectedError)
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(undefined, testAccount.address)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-325: input: invalid type of privateKey', () => {
+ it('should throw error', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+
+ let invalid = ''
+ let expectedError = `Invalid private key(${invalid})`
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(invalid, testAccount.address)).to.throws(expectedError)
+
+ invalid = {}
+ expectedError = `The private key used for the update is not a valid string.`
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(invalid, testAccount.address)).to.throws(expectedError)
+
+ invalid = 1
+ expectedError = `The private key used for the update is not a valid string.`
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(invalid, testAccount.address)).to.throws(expectedError)
+
+ invalid = []
+ expectedError = `The private key used for the update is not a valid string.`
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(invalid, testAccount.address)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-326: input: private key string and address', () => {
+ it('should throw error when accountKey in Account is AccountKeyMultiSig', () => {
+ const address = caver.klay.accounts.create().address
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey(address, key))
+ const updatePrivateKey = caver.klay.accounts.create().privateKey
+
+ let expectedError = `Account using AccountKeyMultiSig or AccountKeyRoleBased must be updated using the caver.klay.accounts.updateAccountKey function.`
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(updatePrivateKey, testAccount.address)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-327: input: private key string and address', () => {
+ it('should throw error when accountKey in Account is AccountKeyRoleBased', () => {
+ const address = caver.klay.accounts.create().address
+ const key = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: caver.klay.accounts.create().privateKey,
+ feePayerKey: caver.klay.accounts.create().privateKey
+ }
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey(address, key))
+ const updatePrivateKey = caver.klay.accounts.create().privateKey
+
+ let expectedError = `Account using AccountKeyMultiSig or AccountKeyRoleBased must be updated using the caver.klay.accounts.updateAccountKey function.`
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(updatePrivateKey, testAccount.address)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-328: input: invalid private key string and address', () => {
+ it('should throw error', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ let invalid = '0x01'
+
+ let expectedError = `Invalid private key(${invalid.slice(2)})`
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(invalid, testAccount.address)).to.throws(expectedError)
+
+ invalid = 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364142'
+ expectedError = `Invalid private key`
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(invalid, testAccount.address)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-329: input: KlaytnWalletKey and address', () => {
+ it('should throw error when address from KlaytnWalletKey is not matched with address parameter', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const updatedAccount = caver.klay.accounts.createWithAccountKey(caver.klay.accounts.create().address, caver.klay.accounts.create().privateKey)
+ const klaytnWalletKey = updatedAccount.getKlaytnWalletKey()
+
+ let expectedError = `The address extracted from the private key does not match the address received as the input value.`
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(klaytnWalletKey, testAccount.address)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-330: input: not existed address of account', () => {
+ it('should throw error when account cannot be found with address', () => {
+ const notExistAddress = caver.klay.accounts.create().address
+ const updatePrivateKey = caver.klay.accounts.create().privateKey
+
+ const expectedError = `Failed to find account with ${notExistAddress}`
+
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(updatePrivateKey, notExistAddress)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-331: input: invalid address', () => {
+ it('should throw error when account cannot be found with address', () => {
+ const invalidAddress = 'invalidAddress'
+ const updatePrivateKey = caver.klay.accounts.create().privateKey
+
+ const expectedError = `Invalid address : ${invalidAddress}`
+
+ expect(() => caver.klay.accounts.wallet.updatePrivateKey(updatePrivateKey, invalidAddress)).to.throws(expectedError)
+ })
+ })
+})
+
+describe('caver.klay.accounts.wallet.updateAccountKey', () => {
+ context('CAVERJS-UNIT-WALLET-332: input: address and private key string', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const updatePrivateKey = caver.klay.accounts.create().privateKey
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-333: input: address and AccountKeyPublic', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const updatePrivateKey = caver.klay.accounts.createAccountKeyPublic(caver.klay.accounts.create().privateKey)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey.keys)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-334: input: address and array of private key string', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const updatePrivateKey = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-335: input: address and AccountKeyMultiSig', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const updatePrivateKey = caver.klay.accounts.createAccountKeyMultiSig([caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey])
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey.keys)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-336: input: address and key object which defines transactionKey, updateKey and feePayerKey', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const updatePrivateKey = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-337: input: address and AccountKeyRoleBased which defines transactionKey, updateKey and feePayerKey', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const keyObject = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ const updatePrivateKey = caver.klay.accounts.createAccountKeyRoleBased(keyObject)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey.keys)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-338: input: address and key object which defines transactionKey only', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const updatePrivateKey = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ }
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-339: input: address and AccountKeyRoleBased which defines transactionKey only', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const keyObject = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ }
+ const updatePrivateKey = caver.klay.accounts.createAccountKeyRoleBased(keyObject)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey.keys)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-340: input: address and key object which defines updateKey only', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const updatePrivateKey = {
+ updateKey: caver.klay.accounts.create().privateKey,
+ }
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-341: input: address and AccountKeyRoleBased which defines updateKey only', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const keyObject = {
+ updateKey: caver.klay.accounts.create().privateKey,
+ }
+ const updatePrivateKey = caver.klay.accounts.createAccountKeyRoleBased(keyObject)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey.keys)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-342: input: address and key object which defines feePayerKey only', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const updatePrivateKey = {
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-343: input: address and AccountKeyRoleBased which defines feePayerKey only', () => {
+ it('should update the accountKey', () => {
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ const keyObject = {
+ updateKey: caver.klay.accounts.create().privateKey,
+ }
+ const updatePrivateKey = caver.klay.accounts.createAccountKeyRoleBased(keyObject)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+ compareAccountKey(account.accountKey, updatePrivateKey.keys)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-344: input: address of role based account and key object which defines role key partially', () => {
+ it('should update the key defined inside the AccountKey only', () => {
+ const originalKeyObject = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey(caver.klay.accounts.create().address, originalKeyObject))
+
+ const keyObject = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ }
+
+ let updatedAccount = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, keyObject)
+
+ const expectedUpdatedKey = {
+ transactionKey: keyObject.transactionKey,
+ updateKey: keyObject.updateKey,
+ feePayerKey: originalKeyObject.feePayerKey
+ }
+ compareAccountKey(updatedAccount.accountKey, expectedUpdatedKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-345: input: address of role based account and AccountKeyRoleBased which defines role key partially', () => {
+ it('should update the key defined inside the AccountKey only', () => {
+ const originalKeyObject = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: caver.klay.accounts.create().privateKey,
+ }
+ const testAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.createWithAccountKey(caver.klay.accounts.create().address, originalKeyObject))
+
+ const keyObject = {
+ transactionKey: caver.klay.accounts.create().privateKey,
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ }
+
+ const updatePrivateKey = caver.klay.accounts.createAccountKeyRoleBased(keyObject)
+
+ let updatedAccount = caver.klay.accounts.wallet.updateAccountKey(testAccount.address, updatePrivateKey)
+
+ const expectedUpdatedKey = {
+ transactionKey: keyObject.transactionKey,
+ updateKey: keyObject.updateKey,
+ feePayerKey: originalKeyObject.feePayerKey
+ }
+ compareAccountKey(updatedAccount.accountKey, expectedUpdatedKey)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-346: input: not existed address of account', () => {
+ it('should throw error when account cannot be found with address', () => {
+ const notExistAddress = caver.klay.accounts.create().address
+ const updatePrivateKey = caver.klay.accounts.create().privateKey
+
+ const expectedError = `Failed to find account with ${notExistAddress}`
+
+ expect(() => caver.klay.accounts.wallet.updateAccountKey(notExistAddress, updatePrivateKey)).to.throws(expectedError)
+ })
+ })
+
+ context('CAVERJS-UNIT-WALLET-347: input: invalid address', () => {
+ it('should throw error when account cannot be found with address', () => {
+ const invalidAddress = 'invalidAddress'
+ const updatePrivateKey = caver.klay.accounts.create().privateKey
+
+ const expectedError = `Invalid address : ${invalidAddress}`
+
+ expect(() => caver.klay.accounts.wallet.updateAccountKey(invalidAddress, updatePrivateKey)).to.throws(expectedError)
+ })
+ })
+})
\ No newline at end of file
diff --git a/test/packages/caver.klay.utils.js b/test/packages/caver.klay.utils.js
deleted file mode 100644
index 1539540d..00000000
--- a/test/packages/caver.klay.utils.js
+++ /dev/null
@@ -1,925 +0,0 @@
-/*
- Copyright 2018 The caver-js Authors
- This file is part of the caver-js library.
-
- The caver-js library is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- The caver-js library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with the caver-js. If not, see .
-*/
-
-require('it-each')({ testPerIteration: true })
-const testRPCURL = require('../testrpc')
-const { expect } = require('../extendedChai')
-
-const setting = require('./setting')
-const utils = require('./utils')
-const Caver = require('../../index.js')
-const BN = require('bn.js')
-
-let caver
-beforeEach(() => {
- caver = new Caver(testRPCURL)
-})
-
-describe('caver.utils.randomHex', () => {
- context('input: valid value', () => {
- it.each(
- [0, 1, 2, 4, 32, 64],
- 'should match with regex',
- (size) => {
- const data = caver.utils.randomHex(size)
- const regExp = new RegExp(`^0x[0-9a-f]{${size * 2}}$`)
- expect(data).to.match(regExp)
- }
- )
- })
-
- context('input: invalid value', () => {
- it('should throw an error: Invalid size: It must be >=0 && <= 65536', () => {
- const expectedErrorMessage = 'Invalid size: It must be >=0 && <= 65536'
-
- expect(() => caver.utils.randomHex(-1)).to.throw(expectedErrorMessage)
- expect(() => caver.utils.randomHex(65537)).to.throw(expectedErrorMessage)
- })
- })
-})
-
-describe('caver.utils.isBN', () => {
- context('input: BN type', () => {
- it.each([
- ['new BN(255)', new BN(255), true],
- [`new BN('ff', 16)`, new BN('ff', 16), true],
- [`new BN('377', 8)`, new BN('377', 8), true],
- [`new BN('11111111', 2)`, new BN('11111111', 2), true],
- ],
- 'should return true',
- ([_, bn, expected]) => {
- const data = caver.utils.isBN(bn)
- expect(data).to.be.equal(expected)
- }
- )
- })
-
- context('input: not a BN type', () => {
- it.each([
- ['255', 255, false],
- ['0xff', 0xff, false],
- ['0377', 0o377, false],
- ['0b11111111', 0b11111111, false],
- ],
- 'should return false',
- ([_, bn, expected]) => {
- const data = caver.utils.isBN(bn)
- expect(data).to.be.equal(expected)
- }
- )
- })
-})
-
-describe('caver.utils.isBigNumber', () => {
- const BigNumber = require('bignumber.js')
-
- context('input: BigNumber type', () => {
- it.each([
- ['new BigNumber(1.0000000000000001)', new BigNumber(1.0000000000000001), true],
- ['new BigNumber(88259496234518.57)', new BigNumber(88259496234518.57), true],
- ['new BigNumber(99999999999999999999)', new BigNumber(99999999999999999999), true],
- ['new BigNumber(2e+308)', new BigNumber(2e+308), true],
- ],
- 'should return true',
- ([_, bigNumber, expected]) => {
- const data = caver.utils.isBigNumber(bigNumber)
- expect(data).to.be.equal(expected)
- }
- )
- })
-
- context('input: not a BigNumber type', () => {
- it.each([
- ['1.0000000000000001', 1.0000000000000001, false],
- ['88259496234518.57', 88259496234518.57, false],
- ['99999999999999999999', 99999999999999999999, false],
- ['2e+308', 2e+308, false],
- ],
- 'should return false',
- ([_, bn, expected]) => {
- const data = caver.utils.isBigNumber(bn)
- expect(data).to.be.equal(expected)
- }
- )
- })
-})
-
-describe('caver.utils.sha3', () => {
-
- context('input: BigNumber type', () => {
- it.each([
- ['new BN(\'234\')', new BN('234'), '0xc1912fee45d61c87cc5ea59dae311904cd86b84fee17cc96966216f811ce6a79'],
- ],
- 'should return 32 bytes hexstring',
- ([_, sha3Input, expected]) => {
- const data = caver.utils.sha3(sha3Input)
- expect(data).to.be.equal(expected)
- }
- )
- })
-
- context('input: number type', () => {
- it.each([
- ['234', 234, null],
- ['0xea', 0xea, null],
- ],
- 'should return null',
- ([_, sha3Input, expected]) => {
- const data = caver.utils.sha3(sha3Input)
- expect(data).to.be.equal(expected)
- }
- )
- })
-
- context('input: String | HexString type', () => {
- it.each([
- ['\'234\'', '234', '0xc1912fee45d61c87cc5ea59dae311904cd86b84fee17cc96966216f811ce6a79'],
- ['\'0xea\'', '0xea', '0x2f20677459120677484f7104c76deb6846a2c071f9b3152c103bb12cd54d1a4a'],
- ],
- 'should return 32 bytes hexstring',
- ([_, sha3Input, expected]) => {
- const data = caver.utils.sha3(sha3Input)
- expect(data).to.be.equal(expected)
- }
- )
- })
-})
-
-describe('caver.utils.soliditySha3', () => {
- it.each([
- ['\'234564535\', \'0xfff23243\', true, -10', ['234564535', '0xfff23243', true, -10], '0x3e27a893dc40ef8a7f0841d96639de2f58a132be5ae466d40087a2cfa83b7179'],
- ['\'Hello!%\'', ['Hello!%'], '0x661136a4267dba9ccdf6bfddb7c00e714de936674c4bdb065a531cf1cb15c7fc'],
- ['\'234\'', ['234'], '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'],
- ['0xea', [0xea], '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'],
- ['new BN(\'234\')', [new BN('234')], '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'],
- ['{ type: \'uint256\', value: \'234\' }', [{ type: 'uint256', value: '234' }], '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'],
- ['{ t: \'uint256\', v: \'234\' }', [{ t: 'uint', v: new BN('234') }], '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'],
- ['\'0x407D73d8a49eeb85D32Cf465507dd71d507100c1\'', ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1'], '0x4e8ebbefa452077428f93c9520d3edd60594ff452a29ac7d2ccc11d47f3ab95b'],
- ['{ t: \'bytes\', v: \'0x407D73d8a49eeb85D32Cf465507dd71d507100c1\' }', [{ t: 'bytes', v: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1' }], '0x4e8ebbefa452077428f93c9520d3edd60594ff452a29ac7d2ccc11d47f3ab95b'],
- ['{ t: \'address\', v: \'0x407D73d8a49eeb85D32Cf465507dd71d507100c1\' }', [{ t: 'address', v: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1' }], '0x4e8ebbefa452077428f93c9520d3edd60594ff452a29ac7d2ccc11d47f3ab95b'],
- ['{ t: \'bytes32\', v: \'0x407D73d8a49eeb85D32Cf465507dd71d507100c1\' }', [{ t: 'bytes32', v: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1' }], '0x3c69a194aaf415ba5d6afca734660d0a3d45acdc05d54cd1ca89a8988e7625b4'],
- ['{ t: \'string\', v: \'Hello! % \' }, { t: \'int8\', v: -23 }, { t: \'address\', v: \'0x85F43D8a49eeB85d32Cf465507DD71d507100C1d\' }', [{ t: 'string', v: 'Hello!%' }, { t: 'int8', v: -23 }, { t: 'address', v: '0x85F43D8a49eeB85d32Cf465507DD71d507100C1d' }], '0xa13b31627c1ed7aaded5aecec71baf02fe123797fffd45e662eac8e06fbe4955'],
- ],
- 'should return 32 bytes hexstring',
- ([_, soliditySha3Input, expected]) => {
- const data = caver.utils.soliditySha3(...soliditySha3Input)
- expect(data).to.be.equal(expected)
- }
- )
-})
-
-describe('caver.utils.isHex', () => {
- context('input: hexString', () => {
- it.each([
- ['\'0xc1912\'', '0xc1912', true],
- ['0xc1912', 0xc1912, true],
- ['\'c1912\'', 'c1912', true],
- ['345', 345, true],
- ],
- 'should return true',
- ([_, hex, expected]) => {
- const data = caver.utils.isHex(hex)
- expect(data).to.be.equal(expected)
- })
- })
-
- context('input: invalid hexString', () => {
- it.each([
- ['\'0xZ1912\'', '0xZ1912', false],
- ['\'Hello\'', 'Hello', false],
- ],
- 'should return false',
- ([_, hex, expected]) => {
- const data = caver.utils.isHex(hex)
- expect(data).to.be.equal(expected)
- })
- })
-})
-
-describe('caver.utils.isHexStrict', () => {
- context('input: strict hexString', () => {
- it.each([
- ['\'0xc1912\'', '0xc1912', true],
- ],
- 'should return true',
- ([_, hex, expected]) => {
- const data = caver.utils.isHexStrict(hex)
- expect(data).to.be.equal(expected)
- })
- })
-
- context('input: not strict hexString', () => {
- it.each([
- ['0xc1912', 0xc1912, false],
- ['\'c1912\'', 'c1912', false],
- ['345', 345, false],
- ['\'0xZ1912\'', '0xZ1912', false],
- ['\'Hello\'', 'Hello', false],
- ],
- 'should return false',
- ([_, hex, expected]) => {
- const data = caver.utils.isHexStrict(hex)
- expect(data).to.be.equal(expected)
- })
- })
-})
-
-describe('caver.utils.isAddress', () => {
- context('input: valid address', () => {
- it.each([
- ['0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', true],
- ['c1912fee45d61c87cc5ea59dae31190fffff232d', true],
- ['0xc1912fee45d61c87cc5ea59dae31190fffff232d', true],
- ['0XC1912FEE45D61C87CC5EA59DAE31190FFFFF232D', true],
- ],
- 'should return true',
- ([address, expected]) => {
- const data = caver.utils.isAddress(address)
- expect(data).to.be.equal(expected)
- })
- })
-
- context('input: invalid address', () => {
- it.each([
- ['0xC1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', false]
- ],
- 'should return false',
- ([address, expected]) => {
- const data = caver.utils.isAddress(address)
- expect(data).to.be.equal(expected)
- })
- })
-})
-
-describe('caver.utils.toChecksumAddress', () => {
- context('input: valid address', () => {
- it.each([
- ['0xc1912fee45d61c87cc5ea59dae31190fffff232D', '0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d'],
- ['0XC1912FEE45D61C87CC5EA59DAE31190FFFFF232D', '0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d'],
- ['0xC1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', '0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d']
- ],
- 'should return checksum address',
- ([address, expected]) => {
- const data = caver.utils.toChecksumAddress(address)
- expect(data).to.be.equal(expected)
- })
- })
-
- context('input: invalid address', () => {
- it('should throw an error', () => {
- const invalidAddress = 'zzzz'
- const errorMessage = `Given address "${invalidAddress}" is not a valid Klaytn address.`
- expect(() => caver.utils.toChecksumAddress(invalidAddress)).to.throw(errorMessage)
- })
- })
-})
-
-describe('caver.utils.checkAddressChecksum', () => {
- context('input: valid checksum address', () => {
- it.each([
- ['0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', true],
- ],
- 'should return true',
- ([address, expected]) => {
- const result = caver.utils.checkAddressChecksum(address)
- expect(result).to.be.equal(expected)
- }
- )
- })
-
- context('input: invalid checksum address', () => {
- it.each([
- ['0xc1912fee45d61c87cc5ea59dae31190fffff232d', false],
- ['c1912fee45d61c87cc5ea59dae31190fffff232d', false],
- ['0XC1912FEE45D61C87CC5EA59DAE31190FFFFF232D', false],
- ['0xC1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', false],
- ],
- 'should return false',
- ([address, expected]) => {
- const result = caver.utils.checkAddressChecksum(address)
- expect(result).to.be.equal(expected)
- }
- )
- })
-})
-
-describe('caver.utils.toHex', () => {
- const BN = require('bn.js')
- const BigNumber = require('bignumber.js')
-
- it.each([
- ['\'234\'', '234', '0xea'],
- ['234', 234, '0xea'],
- ['new BN(\'234\')', new BN('234'), '0xea'],
- ['new BigNumber(\'234\')', new BigNumber('234'), '0xea'],
- ['\'I have 100€\'', 'I have 100€', '0x49206861766520313030e282ac'],
- ],
- 'should return hexstring',
- ([_, hex, expected]) => {
- const result = caver.utils.toHex(hex)
- expect(result).to.be.equal(expected)
- }
- )
-})
-
-describe('caver.utils.toBN', () => {
- const BN = require('bn.js')
- const BigNumber = require('bignumber.js')
-
- context('input: valid value', () => {
- it.each([
- ['1234', 1234, new BN(1234)],
- ['\'1234\'', '1234', new BN('1234')],
- ['0xea', 0xea, new BN(0xea)],
- ['\'0xea\'', '0xea', new BN('ea', 16)],
- ['new BN(234)', new BN(234), new BN(234)],
- ['new BN(\'234\')', new BN('234'), new BN('234')],
- ['new BigNumber(234)', new BigNumber(234), new BN(234)],
- ['new BigNumber(\'234\')', new BigNumber('234'), new BN('234')]
- ],
- 'should return BigNumber type',
- ([_, number, expected]) => {
- const result = caver.utils.toBN(number)
- expect(result.toString()).to.be.equal(expected.toString())
- }
- )
- })
-
- context('input: invalid value', () => {
- it('should throw an error', () => {
- let invalid = 'zzzz'
- const errorMessage = `Error: [number-to-bn] while converting number "${invalid}" to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported. Given value: "${invalid}"`
- expect(() => caver.utils.toBN(invalid)).to.throw(errorMessage)
- })
- })
-})
-
-describe('caver.utils.hexToNumberString', () => {
-
- context('input: number', () => {
- it.each([
- ['1234', 1234, (1234).toString()],
- ['0x1234', 0x1234, (0x1234).toString()],
- ['0xea', 0xea, (0xea).toString()],
- ],
- 'should return numberString',
- ([_, hex, expected]) => {
- const result = caver.utils.hexToNumberString(hex)
- expect(result).to.be.equal(expected)
- }
- )
- })
-
- context('input: numberString', () => {
- it.each([
- ['\'1234\'', '1234', (1234).toString()],
- ],
- 'should return numberString',
- ([_, hex, expected]) => {
- const result = caver.utils.hexToNumberString(hex)
- expect(result).to.be.equal(expected)
- }
- )
- })
-
- context('input: hexString', () => {
- it.each([
- ['\'0x1234\'', '0x1234', (0x1234).toString()],
- ['\'0xea\'', '0xea', (0xea).toString()]
- ],
- 'should return numberString',
- ([_, hex, expected]) => {
- const result = caver.utils.hexToNumberString(hex)
- expect(result).to.be.equal(expected)
- }
- )
- })
-
- context('input: invalid hexString', () => {
- it('should throw an error', () => {
- let invalid = 'zzzz'
- const errorMessage = `Error: [number-to-bn] while converting number "${invalid}" to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported. Given value: "${invalid}"`
- expect(() => caver.utils.hexToNumberString(invalid)).to.throw(errorMessage)
- })
- })
-})
-
-
-
-// caver.utils.hexToNumber
-describe('caver.utils.hexToNumber', () => {
- context('input: valid value', () => {
- it.each([
- ['1234', 1234, 1234],
- ['\'1234\'', '1234', 1234],
- ['0x1234', 0x1234, 4660],
- ['\'0x1234\'', '0x1234', 4660],
- ['0xea', 0xea, 234],
- ['\'0xea\'', '0xea', 234]
- ],
- 'should return number',
- ([_, hex, expected]) => {
- const result = caver.utils.hexToNumber(hex)
- expect(result).to.be.equal(expected)
- }
- )
- })
-
- context('input: invalid value', () => {
- it('should throw an error', () => {
- const invalid = 'zzzz'
- const errorMessage = `Error: [number-to-bn] while converting number "${invalid}" to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported. Given value: "${invalid}"`
- expect(() => caver.utils.hexToNumber(invalid)).to.throw(errorMessage)
- })
- })
-})
-
-describe('caver.utils.numberToHex', () => {
- const BN = require('bn.js')
- const BigNumber = require('bignumber.js')
-
- const toHexStr = (number) => '0x' + number.toString(16).toLowerCase()
-
- context('input: valid number', () => {
- it.each([
- ['1234', 1234, toHexStr(1234)],
- ['\'1234\'', '1234', toHexStr(1234)],
- ['0x1234', 0x1234, toHexStr(4660)],
- ['\'0x1234\'', '0x1234', toHexStr(4660)],
- ['new BN(234)', new BN(234), toHexStr(234)],
- ['new BN(\'234\')', new BN('234'), toHexStr(234)],
- ['new BigNumber(234)', new BigNumber(234), toHexStr(234)],
- ['new BigNumber(\'234\')', new BigNumber('234'), toHexStr(234)],
- ],
- 'should return hexString',
- ([_, number, expected]) => {
- const result = caver.utils.numberToHex(number)
- expect(result).to.equal(expected)
- }
- )
- })
-
- context('input: invalid number', () => {
- it('should throw an error', () => {
- const invalid = 'zzzz'
- const errorMessage = `Given input "${invalid}" is not a number.`
-
- expect(() => caver.utils.numberToHex(invalid)).to.throw(errorMessage)
- })
- })
-})
-
-describe('caver.utils.hexToUtf8', () => {
- context('input: valid hexString', () => {
- it.each([
- ['0x49206861766520313030e282ac', 'I have 100€'],
- ['0x48656c6c6f2c204b6c6179746e', 'Hello, Klaytn']
- ],
- 'should return utf8 string',
- ([hex, expected]) => {
- const result = caver.utils.hexToUtf8(hex)
- expect(result).to.be.equal(expected)
- }
- )
- })
-
- context('input: invalid hexString', () => {
- it('should throw an error', () => {
- const invalid = 'zzzz'
- const errorMessage = `The parameter "${invalid}" must be a valid HEX string.`
-
- expect(() => caver.utils.hexToUtf8(invalid)).to.throw(errorMessage)
- })
- })
-})
-
-describe('caver.utils.hexToAscii', () => {
-
- context('input: valid hexString', () => {
- it.each([
- ['0x4920686176652031303021', 'I have 100!'],
- ['0x48656c6c6f2c204b6c6179746e', 'Hello, Klaytn'],
- ],
- 'should return Ascii string',
- ([hex, expected]) => {
- const result = caver.utils.hexToAscii(hex)
- expect(result).to.be.equal(expected)
- }
- )
- })
-
- context('input: invalid hexString', () => {
- it('should throw an error', () => {
- const invalid = 'zzzz'
- const errorMessage = `The parameter must be a valid HEX string.`
-
- expect(() => caver.utils.hexToAscii(invalid)).to.throw(errorMessage)
- })
- })
-})
-
-describe('caver.utils.utf8ToHex', () => {
- it.each([
- ['I have 100€', '0x49206861766520313030e282ac'],
- ['Hello, Klaytn', '0x48656c6c6f2c204b6c6179746e']
- ],
- 'should return hexString',
- ([string, expected]) => {
- const result = caver.utils.utf8ToHex(string)
- expect(result).to.be.equal(expected)
- }
- )
-})
-
-describe('caver.utils.asciiToHex', () => {
- it.each([
- ['I have 100!', '0x4920686176652031303021'],
- ['Hello, Klaytn', '0x48656c6c6f2c204b6c6179746e'],
- ],
- 'should return hex String',
- ([string, expected]) => {
- const result = caver.utils.asciiToHex(string)
- expect(result).to.be.equal(expected)
- }
- )
-})
-
-
-describe('caver.utils.hexToBytes', () => {
-
- context('input: hexString \'0x000000ea\'', () => {
- it('should return bytes', () => {
- const hex = '0x000000ea'
-
- const expected = [0, 0, 0, 234]
- const result = caver.utils.hexToBytes(hex)
- expect(result).to.deep.equal(expected)
- })
- })
-
- context('input: invalid hexString', () => {
- it('should throw an error', () => {
- let invalid = 0x000000ea
- let errorMessage = `Given value "${invalid.toString(16)}" is not a valid hex string.`
- expect(() => caver.utils.hexToBytes(invalid)).to.throw(errorMessage)
-
- invalid = 'zzzz'
- errorMessage = `Given value "${invalid}" is not a valid hex string.`
- expect(() => caver.utils.hexToBytes(invalid)).to.throw(errorMessage)
- })
- })
-})
-
-describe('caver.utils.bytesToHex', () => {
-
- it.each([
- ['[0, 0, 0, 234]', [0, 0, 0, 234], '0x000000ea'],
- ['[234]', [234], '0xea']
- ],
- 'should return byteArray',
- ([_, byteArray, expected]) => {
- const result = caver.utils.bytesToHex(byteArray)
- expect(result).deep.equal(expected)
- }
- )
-})
-
-describe('caver.utils.toPeb', () => {
- const BN = require('bn.js')
- const BigNumber = require('bignumber.js')
-
- const unitMap = utils.unitMap
-
- context('input: various type', () => {
- it.each([
- ['1', 1, unitMap.KLAY],
- ['\'1\'', '1', unitMap.KLAY],
- ['123456789', 123456789, (new BigNumber(unitMap.KLAY * 123456789)).toFixed(0)],
- ['\'123456789\'', '123456789', (new BigNumber(unitMap.KLAY * 123456789)).toFixed(0)],
- ['new BN(1)', new BN(1), unitMap.KLAY],
- ['new BN(\'1\')', new BN('1'), unitMap.KLAY],
- ['new BN(123456789)', new BN(123456789), (new BigNumber(unitMap.KLAY * 123456789)).toFixed(0)],
- ['new BN(\'123456789\')', new BN('123456789'), (new BigNumber(unitMap.KLAY * 123456789)).toFixed(0)]
- ],
- 'should return string',
- ([_, number, expected]) => {
- const result = caver.utils.toPeb(number)
- expect(result.toString()).to.be.equal(expected.toString())
- }
- )
- })
-
- context('input: base unitmap', () => {
- it.each([
- ['1', 'peb', 1, unitMap.peb],
- ['1', 'kpeb', 1, unitMap.kpeb],
- ['1', 'Mpeb', 1, unitMap.Mpeb],
- ['1', 'Gpeb', 1, unitMap.Gpeb],
- ['1', 'uKLAY', 1, unitMap.uKLAY],
- ['1', 'mKLAY', 1, unitMap.mKLAY],
- ['1', 'KLAY', 1, unitMap.KLAY],
- ['1', 'kKLAY', 1, unitMap.kKLAY],
- ['1', 'MKLAY', 1, unitMap.MKLAY],
- ],
- 'should return string',
- ([_, unit, number, expected]) => {
- const result = caver.utils.toPeb(number, unit)
- expect(result).to.be.equal(expected)
- }
- )
- })
-})
-
-describe('caver.utils.fromPeb', () => {
- const BN = require('bn.js')
- const BigNumber = require('bignumber.js')
-
- const unitMap = utils.unitMap
-
-
- it.each([
- ['1', 1, unitMap.KLAY],
- ['\'1\'', '1', unitMap.KLAY],
- ['123456789', 123456789, unitMap.KLAY],
- ['\'123456789\'', '123456789', unitMap.KLAY],
- ['new BN(1)', new BN(1), unitMap.KLAY],
- ['new BN(\'1\')', new BN('1'), unitMap.KLAY],
- ['new BN(123456789)', new BN(123456789), unitMap.KLAY],
- ['new BN(\'123456789\')', new BN('123456789'), unitMap.KLAY]
- ],
- 'should return string based on unitMap',
- ([_, number, peb]) => {
-
- const bn = new BigNumber(peb)
- const expected = (Math.pow(0.1, bn.e) * number).toFixed(bn.e)
-
- const result = caver.utils.fromPeb(number)
- expect(result).to.be.equal(expected)
- }
- )
-
- it.each([
- ['1', 'peb', 1, unitMap.peb],
- ['1', 'kpeb', 1, unitMap.kpeb],
- ['1', 'Mpeb', 1, unitMap.Mpeb],
- ['1', 'Gpeb', 1, unitMap.Gpeb],
- ['1', 'uKLAY', 1, unitMap.uKLAY],
- ['1', 'mKLAY', 1, unitMap.mKLAY],
- ['1', 'KLAY', 1, unitMap.KLAY],
- ['1', 'kKLAY', 1, unitMap.kKLAY],
- ['1', 'MKLAY', 1, unitMap.MKLAY]
- ],
- 'should return string based on unitMap',
- ([_, unit, number, peb]) => {
- const bn = new BigNumber(peb)
- const expected = (Math.pow(0.1, bn.e) * number).toFixed(bn.e)
-
- const result = caver.utils.fromPeb(number, unit)
- expect(result).to.be.equal(expected)
- }
- )
-})
-
-describe('caver.utils.unitMap', () => {
- const unitMap = utils.unitMap
-
- it('should return unitMap', () => {
- const result = caver.utils.unitMap
- expect(result).to.deep.equal(unitMap)
- })
-})
-
-describe('caver.utils.padLeft', () => {
- context('input: hexString', () => {
- it.each([
- ['0x3456ff', 20, '0x000000000000003456ff'],
- [0x3456ff, 20, '0x000000000000003456ff'],
- ],
- 'should be left-padded with 0',
- ([string, characterAmount, expected]) => {
- const result = caver.utils.padLeft(string, characterAmount)
- expect(result).to.equal(expected)
- }
- )
- })
-
- context('input: string', () => {
- it.each([
- ['Hello', 20, 'x', 'xxxxxxxxxxxxxxxHello'],
- ],
- 'should be left padded with x',
- ([string, characterAmount, sign, expected]) => {
- const result = caver.utils.padLeft(string, characterAmount, sign)
- expect(result).to.equal(expected)
- }
- )
- })
-})
-
-describe('caver.utils.padRight', () => {
- context('input: hexString', () => {
- it.each([
- ['0x3456ff', 20, '0x3456ff00000000000000'],
- [0x3456ff, 20, '0x3456ff00000000000000'],
- ],
- 'should be right padded with 0',
- ([string, characterAmount, expected]) => {
- const result = caver.utils.padRight(string, characterAmount)
- expect(result).to.equal(expected)
- }
- )
- })
-
- context('input: string', () => {
- it.each([
- ['Hello', 20, 'x', 'Helloxxxxxxxxxxxxxxx']
- ],
- 'should be right padded with x',
- ([string, characterAmount, sign, expected]) => {
- const result = caver.utils.padRight(string, characterAmount, sign)
- expect(result).to.equal(expected)
- }
- )
- })
-})
-
-describe('caver.utils.toTwosComplement', () => {
-
- it.each([
- ['\'-1\'', '-1', '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'],
- ['-1', -1, '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'],
- ['\'0x1\'', '0x1', '0x0000000000000000000000000000000000000000000000000000000000000001'],
- ['-15', -15, '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1'],
- ['\'-0x1\'', '-0x1', '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'],
- ],
- 'should return TwosComplement',
- ([_, number, expected]) => {
- const result = caver.utils.toTwosComplement(number)
- expect(result).to.equal(result)
- }
- )
-})
-
-describe('caver.utils.isHexPrefixed', () => {
- it('caver.utils.isHexPrefixed should return boolean depends on parameter', ()=>{
- expect(caver.utils.isHexPrefixed('0x')).to.be.true
- expect(caver.utils.isHexPrefixed('01')).to.be.false
- expect(caver.utils.isHexPrefixed({})).to.be.false
- })
-})
-
-describe('caver.utils.addHexPrefix', () => {
- it('caver.utils.addHexPrefix should return 0x hex format string', ()=>{
- expect(caver.utils.addHexPrefix('0x')).to.equals('0x')
- expect(caver.utils.addHexPrefix('01')).to.equals('0x01')
- expect(typeof(caver.utils.addHexPrefix({}))).to.equals('object')
- })
-})
-
-describe('caver.utils.stripHexPrefix', () => {
- it('caver.utils.stripHexPrefix should strip 0x prefix and return string', ()=>{
- expect(caver.utils.stripHexPrefix('0x')).to.equals('')
- expect(caver.utils.stripHexPrefix('01')).to.equals('01')
- expect(caver.utils.stripHexPrefix('0x01')).to.equals('01')
- expect(typeof(caver.utils.stripHexPrefix({}))).to.equals('object')
- })
-})
-
-describe('caver.utils.toBuffer', () => {
- it('caver.utils.toBuffer should return input when input is Buffer', ()=>{
- expect(caver.utils.toBuffer(Buffer.from('test Buffer'))).to.deep.equal(Buffer.from('test Buffer'))
- })
- it('caver.utils.toBuffer should convert null or undefined to buffer', ()=>{
- expect(caver.utils.toBuffer(null)).to.deep.equal(Buffer.alloc(0))
- expect(caver.utils.toBuffer(undefined)).to.deep.equal(Buffer.alloc(0))
- })
- it('caver.utils.toBuffer should convert Array to buffer', ()=>{
- expect(caver.utils.toBuffer([1,2,3,4,5])).to.deep.equal(Buffer.from([1,2,3,4,5]))
- expect(caver.utils.toBuffer([])).to.deep.equal(Buffer.alloc(0))
- })
- it('caver.utils.toBuffer should convert BN to buffer', ()=>{
- expect(caver.utils.toBuffer(new BN(1))).to.deep.equal(Buffer.from([1]))
- expect(caver.utils.toBuffer(new BN(255)).toString('hex')).to.deep.equal('ff')
- expect(caver.utils.toBuffer(new BN('ff', 16)).toString('hex')).to.deep.equal('ff')
- expect(caver.utils.toBuffer(new BN('377', 8)).toString('hex')).to.deep.equal('ff')
- expect(caver.utils.toBuffer(new BN('11111111', 2)).toString('hex')).to.deep.equal('ff')
- })
- it('caver.utils.toBuffer should convert Object has toArray function to buffer', ()=>{
- expect(caver.utils.toBuffer({toArray: function () {return [1, 2, 3, 4, 5]}})).to.deep.equal(Buffer.from([1,2,3,4,5]))
- })
- it('caver.utils.toBuffer should convert String to buffer', ()=>{
- expect(caver.utils.toBuffer('0x01').toString('hex')).to.deep.equal('01')
- expect(caver.utils.toBuffer('0x1').toString('hex')).to.deep.equal('01')
- expect(caver.utils.toBuffer('0x1234').toString('hex')).to.deep.equal('1234')
- expect(caver.utils.toBuffer('0x12345').toString('hex')).to.deep.equal('012345')
- expect(caver.utils.toBuffer('0x11')).to.deep.equal(Buffer.from([17]))
- expect(caver.utils.toBuffer('0x')).to.deep.equal(Buffer.from([]))
- })
- it('caver.utils.toBuffer should convert Number to buffer', ()=>{
- expect(caver.utils.toBuffer(1)).to.deep.equal(Buffer.from([1]))
- expect(caver.utils.toBuffer(1).toString('hex')).to.deep.equal('01')
- expect(caver.utils.toBuffer(100).toString('hex')).to.deep.equal('64')
- })
-
- it('caver.utils.toBuffer should throw error when input type is not supported with toBuffer function', ()=>{
- expect(()=>caver.utils.toBuffer({})).to.throw('To convert an object to a buffer, the toArray function must be implemented inside the object')
- expect(()=>caver.utils.toBuffer({toArray: [1,2,3,4,5]})).to.throw('To convert an object to a buffer, the toArray function must be implemented inside the object')
- })
- it('caver.utils.toBuffer should throw error when String is not 0x-prefixed', ()=>{
- expect(()=>caver.utils.toBuffer('010x')).to.throw(`Failed to convert string to Buffer. 'toBuffer' function only supports 0x-prefixed hex string`)
- expect(()=>caver.utils.toBuffer('01')).to.throw(`Failed to convert string to Buffer. 'toBuffer' function only supports 0x-prefixed hex string`)
- expect(()=>caver.utils.toBuffer('')).to.throw(`Failed to convert string to Buffer. 'toBuffer' function only supports 0x-prefixed hex string`)
- expect(()=>caver.utils.toBuffer('0xqwer')).to.throw(`Failed to convert string to Buffer. 'toBuffer' function only supports 0x-prefixed hex string`)
- expect(()=>caver.utils.toBuffer('qwer')).to.throw(`Failed to convert string to Buffer. 'toBuffer' function only supports 0x-prefixed hex string`)
- })
-})
-
-describe('caver.utils.numberToBuffer', () => {
- it('caver.utils.numberToBuffer should convert number to buffer', ()=>{
- expect(caver.utils.numberToBuffer(6003400).toString('hex')).to.equals('5b9ac8')
- expect(caver.utils.numberToBuffer(1).toString('hex')).to.equals('01')
- expect(caver.utils.numberToBuffer(12345).toString('hex')).to.equals('3039')
- expect(caver.utils.numberToBuffer(123456789).toString('hex')).to.equals('075bcd15')
- expect(caver.utils.numberToBuffer(100000000).toString('hex')).to.equals('05f5e100')
- expect(caver.utils.numberToBuffer(819263839023).toString('hex')).to.equals('bebfee1b2f')
- })
-})
-
-describe('caver.utils.isHexParameter', () => {
- it('caver.utils.isHexParameter should return true if input is hex string', ()=>{
- expect(caver.utils.isHexParameter('0x01')).to.be.true
- expect(caver.utils.isHexParameter('0xa')).to.be.true
- expect(caver.utils.isHexParameter('0x256d774a7a1bbd469d4fb08545d171df1c755a78')).to.be.true
- expect(caver.utils.isHexParameter('0x256d774a7a1bbd469d4fb08545d171df1c755a78171df1c755a78')).to.be.true
- })
-
- it('caver.utils.isHexParameter should return false if input is not hex string', ()=>{
- // string type input
- expect(caver.utils.isHexParameter('')).to.be.false
- expect(caver.utils.isHexParameter('1')).to.be.false
- expect(caver.utils.isHexParameter('0xqwer')).to.be.false
- expect(caver.utils.isHexParameter('10x')).to.be.false
- expect(caver.utils.isHexParameter('0x14qr')).to.be.false
- expect(caver.utils.isHexParameter('0x1!')).to.be.false
- expect(caver.utils.isHexParameter(' 0x256d774a7a1bbd469d4fb08545d171df1c755a78')).to.be.false
- // not string type input
- expect(caver.utils.isHexParameter(null)).to.be.false
- expect(caver.utils.isHexParameter(undefined)).to.be.false
- expect(caver.utils.isHexParameter(true)).to.be.false
- expect(caver.utils.isHexParameter(1)).to.be.false
- expect(caver.utils.isHexParameter({})).to.be.false
- expect(caver.utils.isHexParameter([])).to.be.false
- expect(caver.utils.isHexParameter(Buffer.alloc(0))).to.be.false
- expect(caver.utils.isHexParameter(new BN())).to.be.false
- })
-})
-
-describe('caver.utils.xyPointFromPublicKey', () => {
- it('caver.utils.xyPointFromPublicKey should return x, y point from publicKey', ()=>{
- const account = caver.klay.accounts.create()
- const publicKey = caver.klay.accounts.privateKeyToPublicKey(account.privateKey)
- const xyPoint = caver.utils.xyPointFromPublicKey(publicKey)
- expect(Array.isArray(xyPoint)).to.be.true
- expect(xyPoint.length).to.equals(2)
- expect(publicKey).to.equals(caver.utils.leftPad(xyPoint[0], 64)+caver.utils.leftPad(xyPoint[1], 64).slice(2))
- })
-
- it('caver.utils.xyPointFromPublicKey should return x, y point remove leading zeros', ()=>{
- const publicKey1 = '0x046241c7524030e5b44fff78021e35227d708c8630757b35090d56527b615f605b8d366782c86dee49356be574e1172f75ef5ce5d03b6e8c17dbf10f3fa2d9a3'
- const publicKey2 = '0xba7135b75cae89b958e7bb78009bda52f6a348150757cc078e3e5e5d25519c500ed4ccec1f78ba4e1c21c7b1e57751cec4cf42e3997a476e3ecbf360ad095336'
- const publicKey3 = '0x12b97e6756861ac0257a240d985d761cee9ca7719a29c233c644cfcc421885000c8e4c69cdb71665377b9e8ffb702355ca53917e66c7444619049c3dd0252ab6'
- const publicKey4 = '0x05b3b58259770871a1cc18534f2d438935fa2dcdb04116cbfbde8adfe858c23e50047c5aea3c2f55de7de04203f8fe8ccc3b491029338d038a7ef6d6903b302e'
-
- const xyPoint1 = caver.utils.xyPointFromPublicKey(publicKey1)
- const xyPoint2 = caver.utils.xyPointFromPublicKey(publicKey2)
- const xyPoint3 = caver.utils.xyPointFromPublicKey(publicKey3)
- const xyPoint4 = caver.utils.xyPointFromPublicKey(publicKey4)
-
- expect(xyPoint1[0]).to.equals('0x46241c7524030e5b44fff78021e35227d708c8630757b35090d56527b615f60')
- expect(xyPoint1[1]).to.equals('0x5b8d366782c86dee49356be574e1172f75ef5ce5d03b6e8c17dbf10f3fa2d9a3')
-
- expect(xyPoint2[0]).to.equals('0xba7135b75cae89b958e7bb78009bda52f6a348150757cc078e3e5e5d25519c50')
- expect(xyPoint2[1]).to.equals('0xed4ccec1f78ba4e1c21c7b1e57751cec4cf42e3997a476e3ecbf360ad095336')
-
- expect(xyPoint3[0]).to.equals('0x12b97e6756861ac0257a240d985d761cee9ca7719a29c233c644cfcc42188500')
- expect(xyPoint3[1]).to.equals('0xc8e4c69cdb71665377b9e8ffb702355ca53917e66c7444619049c3dd0252ab6')
-
- expect(xyPoint4[0]).to.equals('0x5b3b58259770871a1cc18534f2d438935fa2dcdb04116cbfbde8adfe858c23e')
- expect(xyPoint4[1]).to.equals('0x50047c5aea3c2f55de7de04203f8fe8ccc3b491029338d038a7ef6d6903b302e')
- })
-})
\ No newline at end of file
diff --git a/test/packages/caver.utils.js b/test/packages/caver.utils.js
new file mode 100644
index 00000000..96030e8d
--- /dev/null
+++ b/test/packages/caver.utils.js
@@ -0,0 +1,1130 @@
+/*
+ Copyright 2018 The caver-js Authors
+ This file is part of the caver-js library.
+
+ The caver-js library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ The caver-js library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the caver-js. If not, see .
+*/
+
+require('it-each')({ testPerIteration: true })
+const testRPCURL = require('../testrpc')
+const { expect } = require('../extendedChai')
+
+const setting = require('./setting')
+const utils = require('./utils')
+const Caver = require('../../index.js')
+const BN = require('bn.js')
+const BigNumber = require('bignumber.js')
+
+let caver
+beforeEach(() => {
+ caver = new Caver(testRPCURL)
+})
+
+describe('caver.utils.randomHex', () => {
+ context('CAVERJS-UNIT-ETC-097: input: valid value', () => {
+ const tests = [0, 1, 2, 4, 32, 64]
+ it.each(tests, 'should match with regex', (size) => {
+ const data = caver.utils.randomHex(size)
+ const regExp = new RegExp(`^0x[0-9a-f]{${size * 2}}$`)
+ expect(data).to.match(regExp)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-098: input: invalid value', () => {
+ it('should throw an error: Invalid size: It must be >=0 && <= 65536', () => {
+ const expectedErrorMessage = 'Invalid size: It must be >=0 && <= 65536'
+
+ expect(() => caver.utils.randomHex(-1)).to.throw(expectedErrorMessage)
+ expect(() => caver.utils.randomHex(65537)).to.throw(expectedErrorMessage)
+ })
+ })
+})
+
+describe('caver.utils.isBN', () => {
+ context('CAVERJS-UNIT-ETC-099: input: BN type', () => {
+ const tests = [
+ {value: new BN(255), expected: true},
+ {value: new BN('ff', 16), expected: true},
+ {value: new BN('377', 8), expected: true},
+ {value: new BN('11111111', 2), expected: true},
+ ]
+ it.each(tests, 'should return true', (test) => {
+ expect(caver.utils.isBN(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-100: input: not a BN type', () => {
+ const tests = [
+ {value: 255, expected: false},
+ {value: 0xff, expected: false},
+ {value: 0o377, expected: false},
+ {value: 0b11111111, expected: false},
+ ]
+ it.each(tests, 'should return false', (test) => {
+ expect(caver.utils.isBN(test.value)).to.be.equal(test.expected)
+ })
+ })
+})
+
+describe('caver.utils.isBigNumber', () => {
+ context('CAVERJS-UNIT-ETC-101: input: BigNumber type', () => {
+ const tests = [
+ {value: new BigNumber(1.0000000000000001), expected: true},
+ {value: new BigNumber(88259496234518.57), expected: true},
+ {value: new BigNumber(99999999999999999999), expected: true},
+ {value: new BigNumber(2e+308), expected: true},
+ ]
+ it.each(tests, 'should return true', (test) => {
+ expect(caver.utils.isBigNumber(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-102: input: not a BigNumber type', () => {
+ const tests = [
+ {value: 1.0000000000000001, expected: false},
+ {value: 88259496234518.57, expected: false},
+ {value: 99999999999999999999, expected: false},
+ {value: 2e+308, expected: false},
+ ]
+ it.each(tests, 'should return false', (test) => {
+ expect(caver.utils.isBigNumber(test.value)).to.be.equal(test.expected)
+ })
+ })
+})
+
+describe('caver.utils.sha3', () => {
+ context('CAVERJS-UNIT-ETC-103: input: BN type', () => {
+ const tests = [
+ {value: new BN('234'), expected: '0xc1912fee45d61c87cc5ea59dae311904cd86b84fee17cc96966216f811ce6a79'},
+ ]
+ it.each(tests, 'should return 32 bytes hexstring', (test) => {
+ expect(caver.utils.sha3(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-104: input: number type', () => {
+ const tests = [
+ {value: 234, expected: null},
+ {value: 0xea, expected: null},
+ ]
+ it.each(tests, 'should return null', (test) => {
+ expect(caver.utils.sha3(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-105: input: String | HexString type', () => {
+ const tests = [
+ {value: '234', expected: '0xc1912fee45d61c87cc5ea59dae311904cd86b84fee17cc96966216f811ce6a79'},
+ {value: '0xea', expected: '0x2f20677459120677484f7104c76deb6846a2c071f9b3152c103bb12cd54d1a4a'},
+ ]
+ it.each(tests, 'should return 32 bytes hexstring', (test) => {
+ expect(caver.utils.sha3(test.value)).to.be.equal(test.expected)
+ })
+ })
+})
+
+describe('CAVERJS-UNIT-ETC-106: caver.utils.soliditySha3', () => {
+ const tests = [
+ {values: ['234564535', '0xfff23243', true, -10], expected: '0x3e27a893dc40ef8a7f0841d96639de2f58a132be5ae466d40087a2cfa83b7179'},
+ {values: ['Hello!%'], expected: '0x661136a4267dba9ccdf6bfddb7c00e714de936674c4bdb065a531cf1cb15c7fc'},
+ {values: ['234'], expected: '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'},
+ {values: [0xea], expected: '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'},
+ {values: [new BN('234')], expected: '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'},
+ {values: [{ type: 'uint256', value: '234' }], expected: '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'},
+ {values: [{ t: 'uint', v: new BN('234') }], expected: '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'},
+ {values: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1'], expected: '0x4e8ebbefa452077428f93c9520d3edd60594ff452a29ac7d2ccc11d47f3ab95b'},
+ {values: [{ t: 'bytes', v: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1' }], expected: '0x4e8ebbefa452077428f93c9520d3edd60594ff452a29ac7d2ccc11d47f3ab95b'},
+ {values: [{ t: 'address', v: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1' }], expected: '0x4e8ebbefa452077428f93c9520d3edd60594ff452a29ac7d2ccc11d47f3ab95b'},
+ {values: [{ t: 'bytes32', v: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1' }], expected: '0x3c69a194aaf415ba5d6afca734660d0a3d45acdc05d54cd1ca89a8988e7625b4'},
+ {values: [{ t: 'string', v: 'Hello!%' }, { t: 'int8', v: -23 }, { t: 'address', v: '0x85F43D8a49eeB85d32Cf465507DD71d507100C1d' }], expected: '0xa13b31627c1ed7aaded5aecec71baf02fe123797fffd45e662eac8e06fbe4955'},
+ ]
+ it.each(tests, 'should return 32 bytes hexstring', (test) => {
+ expect(caver.utils.soliditySha3(...test.values)).to.be.equal(test.expected)
+ })
+})
+
+describe('caver.utils.isHex', () => {
+ context('CAVERJS-UNIT-ETC-107: input: hexString', () => {
+ const tests = [
+ {value: '0xc1912', expected: true},
+ {value: 0xc1912, expected: true},
+ {value: 'c1912', expected: true},
+ {value: 345, expected: true},
+ ]
+ it.each(tests, 'should return true', (test) => {
+ expect(caver.utils.isHex(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-108: input: invalid hexString', () => {
+ const tests = [
+ {value: '0xZ1912', expected: false},
+ {value: 'Hello', expected: false},
+ ]
+ it.each(tests, 'should return false', (test) => {
+ expect(caver.utils.isHex(test.value)).to.be.equal(test.expected)
+ })
+ })
+})
+
+describe('caver.utils.isHexStrict', () => {
+ context('CAVERJS-UNIT-ETC-109: input: strict hexString', () => {
+ const tests = [
+ {value: '0xc1912', expected: true},
+ ]
+ it.each(tests, 'should return true', (test) => {
+ expect(caver.utils.isHexStrict(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-110: input: not strict hexString', () => {
+ const tests = [
+ {value: 0xc1912, expected: false},
+ {value: 'c1912', expected: false},
+ {value: 345, expected: false},
+ {value: '0xZ1912', expected: false},
+ {value: 'Hello', expected: false},
+ ]
+ it.each(tests, 'should return false', (test) => {
+ expect(caver.utils.isHexStrict(test.value)).to.be.equal(test.expected)
+ })
+ })
+})
+
+describe('caver.utils.isAddress', () => {
+ context('CAVERJS-UNIT-ETC-111: input: valid address', () => {
+ const tests = [
+ {address: '0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', expected: true},
+ {address: 'c1912fee45d61c87cc5ea59dae31190fffff232d', expected: true},
+ {address: '0xc1912fee45d61c87cc5ea59dae31190fffff232d', expected: true},
+ {address: '0XC1912FEE45D61C87CC5EA59DAE31190FFFFF232D', expected: true},
+ ]
+ it.each(tests, 'should return true', (test) => {
+ expect(caver.utils.isAddress(test.address)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-112: input: invalid address', () => {
+ const tests = [
+ {address: '0xC1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', expected: false}
+ ]
+ it.each(tests, 'should return false', (test) => {
+ expect(caver.utils.isAddress(test.address)).to.be.equal(test.expected)
+ })
+ })
+})
+
+describe('caver.utils.toChecksumAddress', () => {
+ context('CAVERJS-UNIT-ETC-113: input: valid address', () => {
+ const tests = [
+ {address: '0xc1912fee45d61c87cc5ea59dae31190fffff232D', expected: '0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d'},
+ {address: '0XC1912FEE45D61C87CC5EA59DAE31190FFFFF232D', expected: '0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d'},
+ {address: '0xC1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', expected: '0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d'}
+ ]
+ it.each(tests, 'should return checksum address', (test) => {
+ expect(caver.utils.toChecksumAddress(test.address)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-114: input: invalid address', () => {
+ it('should throw an error', () => {
+ const invalidAddress = 'zzzz'
+ const errorMessage = `Given address "${invalidAddress}" is not a valid Klaytn address.`
+ expect(() => caver.utils.toChecksumAddress(invalidAddress)).to.throw(errorMessage)
+ })
+ })
+})
+
+describe('caver.utils.checkAddressChecksum', () => {
+ context('CAVERJS-UNIT-ETC-115: input: valid checksum address', () => {
+ const tests = [
+ {address: '0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', expected: true},
+ ]
+ it.each(tests, 'should return true', (test) => {
+ expect(caver.utils.checkAddressChecksum(test.address)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-116: input: invalid checksum address', () => {
+ const tests = [
+ {address: '0xc1912fee45d61c87cc5ea59dae31190fffff232d', expected: false},
+ {address: 'c1912fee45d61c87cc5ea59dae31190fffff232d', expected: false},
+ {address: '0XC1912FEE45D61C87CC5EA59DAE31190FFFFF232D', expected: false},
+ {address: '0xC1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', expected: false},
+ ]
+ it.each(tests,'should return false', (test) => {
+ expect(caver.utils.checkAddressChecksum(test.address)).to.be.equal(test.expected)
+ })
+ })
+})
+
+describe('CAVERJS-UNIT-ETC-117: caver.utils.toHex', () => {
+ const tests = [
+ {value: '234', expected: '0xea'},
+ {value: 234, expected: '0xea'},
+ {value: new BN('234'), expected: '0xea'},
+ {value: 'I have 100€', expected: '0x49206861766520313030e282ac'},
+ {value: '234', expected: '0xea'},
+ {value: '234', expected: '0xea'},
+ {value: 1, expected: '0x1'},
+ {value: '1', expected: '0x1'},
+ {value: '0x1', expected: '0x1'},
+ {value: '15', expected: '0xf'},
+ {value: '0xf', expected: '0xf'},
+ {value: -1, expected: '-0x1'},
+ {value: '-1', expected: '-0x1'},
+ {value: '-0x1', expected: '-0x1'},
+ {value: '-15', expected: '-0xf'},
+ {value: '-0xf', expected: '-0xf'},
+ {value: '0x657468657265756d', expected: '0x657468657265756d'},
+ {
+ value: '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd',
+ expected: '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd'
+ },
+ {
+ value: '-0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
+ expected: '-0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
+ },
+ {
+ value: '-0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd',
+ expected: '-0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd'
+ },
+ {value: 0, expected: '0x0'},
+ {value: '0', expected: '0x0'},
+ {value: '0x0', expected: '0x0'},
+ {value: -0, expected: '0x0'},
+ {value: '-0', expected: '0x0'},
+ {value: '-0x0', expected: '0x0'},
+ {value: [1, 2, 3, {test: 'data'}], expected: '0x5b312c322c332c7b2274657374223a2264617461227d5d'},
+ {value: {test: 'test'}, expected: '0x7b2274657374223a2274657374227d'},
+ {value: '{"test": "test"}', expected: '0x7b2274657374223a202274657374227d'},
+ {value: 'myString', expected: '0x6d79537472696e67'},
+ {value: 'myString 34534!', expected: '0x6d79537472696e6720333435333421'},
+ {value: new BN(15), expected: '0xf'},
+ {
+ value: 'Heeäööä👅D34ɝɣ24Єͽ-.,äü+#/',
+ expected: '0x486565c3a4c3b6c3b6c3a4f09f9185443334c99dc9a33234d084cdbd2d2e2cc3a4c3bc2b232f'
+ },
+ {value: true, expected: '0x01'},
+ {value: false, expected: '0x00'},
+ {
+ value:
+ 'ff\u0003\u0000\u0000\u00005èÆÕL]\u0012|ξ\u001a7«\u00052\u0011(ÐY\n<\u0010\u0000\u0000\u0000\u0000\u0000\u0000e!ßd/ñõì\f:z¦Î¦±ç·÷Í¢Ëß\u00076*
\bñùC1ÉUÀé2\u001aÓB',
+ expected:
+ '0x66660300000035c3a8c386c3954c5d127cc29dc38ec2bec29e1a37c2abc29b05321128c390c297590a3c100000000000006521c39f642fc3b1c3b5c3ac0c3a7ac2a6c38ec2a6c2b1c3a7c2b7c3b7c38dc2a2c38bc39f07362ac28508c28ec297c3b1c29ec3b94331c38955c380c3a9321ac393c28642c28c'
+ },
+ {
+ value:
+ '\u0003\u0000\u0000\u00005èÆÕL]\u0012|ξ\u001a7«\u00052\u0011(ÐY\n<\u0010\u0000\u0000\u0000\u0000\u0000\u0000e!ßd/ñõì\f:z¦Î¦±ç·÷Í¢Ëß\u00076*
\bñùC1ÉUÀé2\u001aÓB',
+ expected:
+ '0x0300000035c3a8c386c3954c5d127cc29dc38ec2bec29e1a37c2abc29b05321128c390c297590a3c100000000000006521c39f642fc3b1c3b5c3ac0c3a7ac2a6c38ec2a6c2b1c3a7c2b7c3b7c38dc2a2c38bc39f07362ac28508c28ec297c3b1c29ec3b94331c38955c380c3a9321ac393c28642c28c'
+ },
+ ]
+
+ it.each(tests, 'should return hexstring', (test) => {
+ expect(caver.utils.toHex(test.value)).to.be.equal(test.expected)
+ })
+})
+
+describe('caver.utils.isTxHashStrict', () => {
+ const transactionHash = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550'
+ context('CAVERJS-UNIT-ETC-162: input: valid strict transaction hex', () => {
+ const tests = [
+ {hash: transactionHash, expected: true}, // all lower
+ {hash: transactionHash.toUpperCase(), expected: true}, // all upper
+ {hash: transactionHash.slice(0, 10) + transactionHash.slice(10).toUpperCase(), expected: true}, // mixed
+ ]
+ it.each(tests, 'should return true', (test) => {
+ expect(caver.utils.isTxHashStrict(test.hash)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-163: input: invalid strict transaction hex', () => {
+ const tests = [
+ {hash: `00${transactionHash.slice(2)}`, expected: false}, // doesn't start with 0x
+ {hash: transactionHash.slice(2), expected: false}, // doesn't start with 0x
+ {hash: `${transactionHash.slice(0, 64)}ZZ`, expected: false}, // not hex
+ {hash: transactionHash.slice(0, 10), expected: false}, // length is not enough
+ ]
+ it.each(tests, 'should return false', (test) => {
+ expect(caver.utils.isTxHashStrict(test.hash)).to.be.equal(test.expected)
+ })
+ })
+})
+
+describe('caver.utils.isTxHash', () => {
+ const transactionHash = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550'
+ context('CAVERJS-UNIT-ETC-164: input: valid transaction hex', () => {
+ const tests = [
+ {hash: transactionHash, expected: true}, // all lower long
+ {hash: transactionHash.slice(2), expected: true}, // all lower short
+ {hash: transactionHash.toUpperCase(), expected: true}, // all upper long
+ {hash: transactionHash.slice(2).toUpperCase(), expected: true}, // all upper short
+ {hash: transactionHash.slice(0, 10) + transactionHash.slice(10).toUpperCase(), expected: true}, // mixed long
+ {hash: transactionHash.slice(2, 10) + transactionHash.slice(10).toUpperCase(), expected: true}, // mixed short
+ ]
+ it.each(tests, 'should return true', (test) => {
+ expect(caver.utils.isTxHash(test.hash)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-165: input: invalid transaction hex', () => {
+ const tests = [
+ {hash: transactionHash.slice(4), expected: false}, // length is not enough (62)
+ {hash: `${transactionHash.slice(0, 62)}ZZ`, expected: false}, // not hex
+ {hash: `${transactionHash.slice(2)}00`, expected: false}, // length is too long (66 without 0x)
+ {hash: `${transactionHash}00`, expected: false}, // length is too long (68)
+ ]
+ it.each(tests, 'should return false', (test) => {
+ expect(caver.utils.isTxHash(test.tx)).to.be.equal(test.expected)
+ })
+ })
+})
+
+describe('caver.utils.toBN', () => {
+ context('CAVERJS-UNIT-ETC-118: input: valid value', () => {
+ const tests = [
+ {value: 1, expected: '1'},
+ {value: '1', expected: '1'},
+ {value: '0x1', expected: '1'},
+ {value: '0x01', expected: '1'},
+ {value: 15, expected: '15'},
+ {value: '15', expected: '15'},
+ {value: '0xf', expected: '15'},
+ {value: '0x0f', expected: '15'},
+ {value: new BN('f', 16), expected: '15'},
+ {value: -1, expected: '-1'},
+ {value: '-1', expected: '-1'},
+ {value: '-0x1', expected: '-1'},
+ {value: '-0x01', expected: '-1'},
+ {value: -15, expected: '-15'},
+ {value: '-15', expected: '-15'},
+ {value: '-0xf', expected: '-15'},
+ {value: '-0x0f', expected: '-15'},
+ {
+ value: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
+ expected: '115792089237316195423570985008687907853269984665640564039457584007913129639935'
+ },
+ {
+ value: '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd',
+ expected: '115792089237316195423570985008687907853269984665640564039457584007913129639933'
+ },
+ {
+ value: '-0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
+ expected: '-115792089237316195423570985008687907853269984665640564039457584007913129639935'
+ },
+ {
+ value: '-0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd',
+ expected: '-115792089237316195423570985008687907853269984665640564039457584007913129639933'
+ },
+ {value: 0, expected: '0'},
+ {value: '0', expected: '0'},
+ {value: '0x0', expected: '0'},
+ {value: -0, expected: '0'},
+ {value: '-0', expected: '0'},
+ {value: '-0x0', expected: '0'},
+ {value: new BN(0), expected: '0'}
+ ]
+ it.each(tests, 'should return BigNumber type', (test) => {
+ const bn = caver.utils.toBN(test.value)
+ expect(caver.utils.isBN(bn)).to.be.true
+ expect(bn.toString()).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-119: input: invalid value', () => {
+ it('should throw an error', () => {
+ let invalid = 'zzzz'
+ const errorMessage = `Error: [number-to-bn] while converting number "${invalid}" to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported. Given value: "${invalid}"`
+ expect(() => caver.utils.toBN(invalid)).to.throw(errorMessage)
+ })
+ })
+})
+
+describe('caver.utils.hexToNumberString', () => {
+ context('CAVERJS-UNIT-ETC-120: input: number', () => {
+ const tests = [
+ {value: 1234, expected: (1234).toString()},
+ {value: 0x1234, expected: (0x1234).toString()},
+ {value: 0xea, expected: (0xea).toString()},
+ {value: 100000, expected: '100000'},
+ ]
+ it.each(tests, 'should return numberString', (test) => {
+ expect(caver.utils.hexToNumberString(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-121: input: numberString', () => {
+ const tests = [
+ {value: '1234', expected: (1234).toString()},
+ ]
+ it.each(tests, 'should return numberString', (test) => {
+ expect(caver.utils.hexToNumberString(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-122: input: hexString', () => {
+ const tests = [
+ {value: '0x1234', expected: (0x1234).toString()},
+ {value: '0x3e8', expected: '1000'},
+ {value: '0x1f0fe294a36', expected: '2134567897654'},
+ ]
+ it.each(tests, 'should return numberString', (test) => {
+ expect(caver.utils.hexToNumberString(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-123: input: invalid hexString', () => {
+ it('should throw an error', () => {
+ let invalid = 'zzzz'
+ const errorMessage = `Error: [number-to-bn] while converting number "${invalid}" to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported. Given value: "${invalid}"`
+ expect(() => caver.utils.hexToNumberString(invalid)).to.throw(errorMessage)
+ })
+ })
+})
+
+
+
+// caver.utils.hexToNumber
+describe('caver.utils.hexToNumber', () => {
+ context('CAVERJS-UNIT-ETC-124: input: valid value', () => {
+ const tests = [
+ {value: 1234, expected: 1234},
+ {value: '1234', expected: 1234},
+ {value: 0x1234, expected: 4660},
+ {value: 0xea, expected: 234},
+ {value: '0xea', expected: 234},
+ ]
+ it.each(tests, 'should return number', (test) => {
+ expect(caver.utils.hexToNumber(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-125: input: invalid value', () => {
+ it('should throw an error', () => {
+ const invalid = 'zzzz'
+ const errorMessage = `Error: [number-to-bn] while converting number "${invalid}" to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported. Given value: "${invalid}"`
+ expect(() => caver.utils.hexToNumber(invalid)).to.throw(errorMessage)
+ })
+ })
+})
+
+describe('caver.utils.numberToHex', () => {
+ const toHexStr = (number) => '0x' + number.toString(16).toLowerCase()
+
+ context('CAVERJS-UNIT-ETC-126: input: valid number', () => {
+ const tests = [
+ {value: 1234, expected: toHexStr(1234)},
+ {value: '1234', expected: toHexStr(1234)},
+ {value: 0x1234, expected: toHexStr(4660)},
+ {value: '0x1234', expected: toHexStr(4660)},
+ {value: new BN(234), expected: toHexStr(234)},
+ {value: new BN('234'), expected: toHexStr(234)},
+ {value: new BigNumber(234), expected: toHexStr(234)},
+ {value: new BigNumber('234'), expected: toHexStr(234)},
+ {value: 1, expected: '0x1'},
+ {value: '21345678976543214567869765432145647586', expected: '0x100f073a3d694d13d1615dc9bc3097e2'},
+ {value: '1', expected: '0x1'},
+ {value: '0x1', expected: '0x1'},
+ {value: '0x01', expected: '0x1'},
+ {value: 15, expected: '0xf'},
+ {value: '15', expected: '0xf'},
+ {value: '0xf', expected: '0xf'},
+ {value: '0x0f', expected: '0xf'},
+ {value: -1, expected: '-0x1'},
+ {value: '-1', expected: '-0x1'},
+ {value: '-0x1', expected: '-0x1'},
+ {value: '-0x01', expected: '-0x1'},
+ {value: -15, expected: '-0xf'},
+ {value: '-15', expected: '-0xf'},
+ {value: '-0xf', expected: '-0xf'},
+ {value: '-0x0f', expected: '-0xf'},
+ {
+ value: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
+ expected: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
+ },
+ {
+ value: '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd',
+ expected: '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd'
+ },
+ {
+ value: '-0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
+ expected: '-0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
+ },
+ {
+ value: '-0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd',
+ expected: '-0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd'
+ },
+ {value: 0, expected: '0x0'},
+ {value: '0', expected: '0x0'},
+ {value: '0x0', expected: '0x0'},
+ {value: -0, expected: '0x0'},
+ {value: '-0', expected: '0x0'},
+ {value: '-0x0', expected: '0x0'}
+ ]
+ it.each(tests, 'should return hexString', (test) => {
+ expect(caver.utils.numberToHex(test.value)).to.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-127: input: invalid number', () => {
+ it('should throw an error', () => {
+ const invalid = 'zzzz'
+ const errorMessage = `Given input "${invalid}" is not a number.`
+
+ expect(() => caver.utils.numberToHex(invalid)).to.throw(errorMessage)
+ })
+ })
+})
+
+describe('caver.utils.hexToUtf8', () => {
+ context('CAVERJS-UNIT-ETC-128: input: valid hexString', () => {
+ const tests = [
+ {value: '0x49206861766520313030e282ac', expected: 'I have 100€'},
+ {value: '0x48656c6c6f2c204b6c6179746e', expected: 'Hello, Klaytn'},
+ {value: '0x486565c3a4c3b6c3b6c3a4f09f9185443334c99dc9a33234d084cdbd2d2e2cc3a4c3bc2b232f', expected: 'Heeäööä👅D34ɝɣ24Єͽ-.,äü+#/'},
+ {value: '0x6d79537472696e67', expected: 'myString'},
+ {value: '0x6d79537472696e6700', expected: 'myString'},
+ {value: '0x65787065637465642076616c7565000000000000000000000000000000000000', expected: 'expected value'},
+ {value: '0x000000000000000000000000000000000000657870656374000065642076616c7565', expected: 'expect\u0000\u0000ed value'}
+ ]
+ it.each(tests, 'should return utf8 string', (test) => {
+ expect(caver.utils.hexToUtf8(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-129: input: invalid hexString', () => {
+ it('should throw an error', () => {
+ const invalid = 'zzzz'
+ const errorMessage = `The parameter "${invalid}" must be a valid HEX string.`
+
+ expect(() => caver.utils.hexToUtf8(invalid)).to.throw(errorMessage)
+ })
+ })
+})
+
+describe('caver.utils.hexToAscii', () => {
+
+ context('CAVERJS-UNIT-ETC-130: input: valid hexString', () => {
+ const tests = [
+ {value: '0x4920686176652031303021', expected: 'I have 100!'},
+ {value: '0x48656c6c6f2c204b6c6179746e', expected: 'Hello, Klaytn'},
+ {value: '0x6d79537472696e67', expected: 'myString'},
+ {value: '0x6d79537472696e6700', expected: 'myString\u0000'},
+ {
+ value: '0x0300000035e8c6d54c5d127c9dcebe9e1a37ab9b05321128d097590a3c100000000000006521df642ff1f5ec0c3a7aa6cea6b1e7b7f7cda2cbdf07362a85088e97f19ef94331c955c0e9321ad386428c',
+ expected: '\u0003\u0000\u0000\u00005èÆÕL]\u0012|ξ\u001a7«\u00052\u0011(ÐY\n<\u0010\u0000\u0000\u0000\u0000\u0000\u0000e!ßd/ñõì\f:z¦Î¦±ç·÷Í¢Ëß\u00076*
\bñùC1ÉUÀé2\u001aÓB'
+ }
+ ]
+ it.each(tests, 'should return Ascii string', (test) => {
+ expect(caver.utils.hexToAscii(test.value)).to.be.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-131: input: invalid hexString', () => {
+ it('should throw an error', () => {
+ const invalid = 'zzzz'
+ const errorMessage = `The parameter must be a valid HEX string.`
+
+ expect(() => caver.utils.hexToAscii(invalid)).to.throw(errorMessage)
+ })
+ })
+})
+
+describe('CAVERJS-UNIT-ETC-132: caver.utils.utf8ToHex', () => {
+ const tests = [
+ {value: 'I have 100€', expected: '0x49206861766520313030e282ac'},
+ {value: 'Hello, Klaytn', expected: '0x48656c6c6f2c204b6c6179746e'},
+ {value: 'Heeäööä👅D34ɝɣ24Єͽ-.,äü+#/', expected: '0x486565c3a4c3b6c3b6c3a4f09f9185443334c99dc9a33234d084cdbd2d2e2cc3a4c3bc2b232f'},
+ {value: 'myString', expected: '0x6d79537472696e67'},
+ {value: 'myString\u0000', expected: '0x6d79537472696e67'},
+ {value: 'expected value\u0000\u0000\u0000', expected: '0x65787065637465642076616c7565'},
+ {value: 'expect\u0000\u0000ed value\u0000\u0000\u0000', expected: '0x657870656374000065642076616c7565'},
+ ]
+ it.each(tests, 'should return hexString', (test) => {
+ expect(caver.utils.utf8ToHex(test.value)).to.be.equal(test.expected)
+ })
+})
+
+describe('CAVERJS-UNIT-ETC-133: caver.utils.asciiToHex', () => {
+ const tests = [
+ {value: 'I have 100!', expected: '0x4920686176652031303021'},
+ {value: 'Hello, Klaytn', expected: '0x48656c6c6f2c204b6c6179746e'},
+ {value: 'myString', expected: '0x6d79537472696e67'},
+ {value: 'myString\u0000', expected: '0x6d79537472696e6700'},
+ {
+ value: '\u0003\u0000\u0000\u00005èÆÕL]\u0012|ξ\u001a7«\u00052\u0011(ÐY\n<\u0010\u0000\u0000\u0000\u0000\u0000\u0000e!ßd/ñõì\f:z¦Î¦±ç·÷Í¢Ëß\u00076*
\bñùC1ÉUÀé2\u001aÓB',
+ expected: '0x0300000035e8c6d54c5d127c9dcebe9e1a37ab9b05321128d097590a3c100000000000006521df642ff1f5ec0c3a7aa6cea6b1e7b7f7cda2cbdf07362a85088e97f19ef94331c955c0e9321ad386428c'
+ }
+ ]
+ it.each(tests, 'should return hex String', (test) => {
+ expect(caver.utils.asciiToHex(test.value)).to.be.equal(test.expected)
+ })
+})
+
+
+describe('caver.utils.hexToBytes', () => {
+
+ context('CAVERJS-UNIT-ETC-134: input: hexString \'0x000000ea\'', () => {
+ it('should return bytes', () => {
+ const hex = '0x000000ea'
+
+ const expected = [0, 0, 0, 234]
+ const result = caver.utils.hexToBytes(hex)
+ expect(result).to.deep.equal(expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-135: input: invalid hexString', () => {
+ it('should throw an error', () => {
+ let invalid = 0x000000ea
+ let errorMessage = `Given value "${invalid.toString(16)}" is not a valid hex string.`
+ expect(() => caver.utils.hexToBytes(invalid)).to.throw(errorMessage)
+
+ invalid = 'zzzz'
+ errorMessage = `Given value "${invalid}" is not a valid hex string.`
+ expect(() => caver.utils.hexToBytes(invalid)).to.throw(errorMessage)
+ })
+ })
+})
+
+describe('CAVERJS-UNIT-ETC-136: caver.utils.bytesToHex', () => {
+ const tests = [
+ {value: [0, 0, 0, 234], expected: '0x000000ea'},
+ {value: [234], expected: '0xea'}
+ ]
+ it.each(tests, 'should return byteArray', (test) => {
+ expect(caver.utils.bytesToHex(test.value)).deep.equal(test.expected)
+ })
+})
+
+describe('caver.utils.toPeb', () => {
+ const unitMap = utils.unitMap
+
+ context('CAVERJS-UNIT-ETC-137: input: various type', () => {
+ const tests = [
+ {value: 1, expected: unitMap.KLAY},
+ {value: '1', expected: unitMap.KLAY},
+ {value: 123456789, expected: (new BigNumber(unitMap.KLAY * 123456789)).toFixed(0)},
+ {value: '123456789', expected: (new BigNumber(unitMap.KLAY * 123456789)).toFixed(0)},
+ {value: new BN(1), expected: unitMap.KLAY},
+ {value: new BN('1'), expected: unitMap.KLAY},
+ {value: new BN(123456789), expected: (new BigNumber(unitMap.KLAY * 123456789)).toFixed(0)},
+ {value: new BN('123456789'), expected: (new BigNumber(unitMap.KLAY * 123456789)).toFixed(0)}
+ ]
+ it.each(tests, 'should return string', (test) => {
+ expect(caver.utils.toPeb(test.value).toString()).to.be.equal(test.expected.toString())
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-138: input: base unitmap', () => {
+ const tests = [
+ {value: 1, unit: 'peb', expected: unitMap.peb},
+ {value: 1, unit: 'kpeb', expected: unitMap.kpeb},
+ {value: 1, unit: 'Mpeb', expected: unitMap.Mpeb},
+ {value: 1, unit: 'Gpeb', expected: unitMap.Gpeb},
+ {value: 1, unit: 'uKLAY', expected: unitMap.uKLAY},
+ {value: 1, unit: 'mKLAY', expected: unitMap.mKLAY},
+ {value: 1, unit: 'KLAY', expected: unitMap.KLAY},
+ {value: 1, unit: 'kKLAY', expected: unitMap.kKLAY},
+ {value: 1, unit: 'MKLAY', expected: unitMap.MKLAY},
+ ]
+ it.each(tests, 'should return string', (test) => {
+ expect(caver.utils.toPeb(test.value, test.unit)).to.be.equal(test.expected)
+ })
+ })
+})
+
+describe('caver.utils.fromPeb', () => {
+ const unitMap = utils.unitMap
+
+ context('CAVERJS-UNIT-ETC-139: fromPeb without unit', () => {
+ const tests = [
+ {value: 1, peb: unitMap.KLAY},
+ {value: '1', peb: unitMap.KLAY},
+ {value: 123456789, peb: unitMap.KLAY},
+ {value: '123456789', peb: unitMap.KLAY},
+ {value: new BN(1), peb: unitMap.KLAY},
+ {value: new BN('1'), peb: unitMap.KLAY},
+ {value: new BN(123456789), peb: unitMap.KLAY},
+ {value: new BN('123456789'), peb: unitMap.KLAY}
+ ]
+ it.each(tests, 'should return string based on unitMap', (test) => {
+ const bn = new BigNumber(test.peb)
+ const expected = (Math.pow(0.1, bn.e) * test.value).toFixed(bn.e)
+
+ expect(caver.utils.fromPeb(test.value)).to.be.equal(expected)
+ }
+ )
+ })
+
+ context('CAVERJS-UNIT-ETC-140: fromPeb with unit', () => {
+ const tests = [
+ {value: 1, unit: 'peb', peb: unitMap.peb},
+ {value: 1, unit: 'kpeb', peb: unitMap.kpeb},
+ {value: 1, unit: 'Mpeb', peb: unitMap.Mpeb},
+ {value: 1, unit: 'Gpeb', peb: unitMap.Gpeb},
+ {value: 1, unit: 'uKLAY', peb: unitMap.uKLAY},
+ {value: 1, unit: 'mKLAY', peb: unitMap.mKLAY},
+ {value: 1, unit: 'KLAY', peb: unitMap.KLAY},
+ {value: 1, unit: 'kKLAY', peb: unitMap.kKLAY},
+ {value: 1, unit: 'MKLAY', peb: unitMap.MKLAY},
+ ]
+ it.each(tests, 'should return string based on unitMap', (test) => {
+ const bn = new BigNumber(test.peb)
+ const expected = (Math.pow(0.1, bn.e) * test.value).toFixed(bn.e)
+
+ expect(caver.utils.fromPeb(test.value, test.unit)).to.be.equal(expected)
+ }
+ )
+ })
+})
+
+describe('caver.utils.unitMap', () => {
+ const unitMap = utils.unitMap
+
+ it('CAVERJS-UNIT-ETC-141: should return valid unitMap', () => {
+ const result = caver.utils.unitMap
+ expect(result).to.deep.equal(unitMap)
+ expect(result.peb).to.equals('1')
+ expect(result.kpeb).to.equals('1000')
+ expect(result.Mpeb).to.equals('1000000')
+ expect(result.Gpeb).to.equals('1000000000')
+ expect(result.Ston).to.equals('1000000000')
+ expect(result.uKLAY).to.equals('1000000000000')
+ expect(result.mKLAY).to.equals('1000000000000000')
+ expect(result.KLAY).to.equals('1000000000000000000')
+ expect(result.kKLAY).to.equals('1000000000000000000000')
+ expect(result.MKLAY).to.equals('1000000000000000000000000')
+ })
+})
+
+describe('caver.utils.padLeft', () => {
+ context('CAVERJS-UNIT-ETC-142: input: hex', () => {
+ const tests = [
+ {value: '0x3456ff', length: 20, expected: '0x000000000000003456ff'},
+ {value: 0x3456ff, length: 20, expected: '0x000000000000003456ff'}
+ ]
+ it.each(tests, 'should be left-padded with 0', (test) => {
+ expect(caver.utils.padLeft(test.value, test.length)).to.equal(test.expected)
+ })
+ })
+
+ context('CAVERJS-UNIT-ETC-143: input: string', () => {
+ const tests = [
+ {value: 'Hello', length: 20, sign: 'x', expected: 'xxxxxxxxxxxxxxxHello'},
+ ]
+ it.each(tests, 'should be left padded with x', (test) => {
+ expect(caver.utils.padLeft(test.value, test.length, test.sign)).to.equal(test.expected)
+ })
+ })
+})
+
+describe('caver.utils.padRight', () => {
+ context('input: hex', () => {
+ const tests = [
+ {value: '0x3456ff', length: 20, expected: '0x3456ff00000000000000'},
+ {value: 0x3456ff, length: 20, expected: '0x3456ff00000000000000'},
+ ]
+ it.each(tests, 'should be right padded with 0', (test) => {
+ expect(caver.utils.padRight(test.value, test.length)).to.equal(test.expected)
+ })
+ })
+
+ context('input: string', () => {
+ const tests = [
+ {value: 'Hello', length: 20, sign: 'x', expected: 'Helloxxxxxxxxxxxxxxx'}
+ ]
+ it.each(tests, 'should be right padded with x', (test) => {
+ expect(caver.utils.padRight(test.value, test.length, test.sign)).to.equal(test.expected)
+ })
+ })
+})
+
+describe('CAVERJS-UNIT-ETC-144: caver.utils.toTwosComplement', () => {
+ const tests = [
+ {value: '-1', expected: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'},
+ {value: -1, expected: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'},
+ {value: '0x1', expected: '0x0000000000000000000000000000000000000000000000000000000000000001'},
+ {value: -15, expected: '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1'},
+ {value: '-0x1', expected: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'},
+ {value: 1, expected: '0x0000000000000000000000000000000000000000000000000000000000000001'},
+ {value: '1', expected: '0x0000000000000000000000000000000000000000000000000000000000000001'},
+ {value: '0x01', expected: '0x0000000000000000000000000000000000000000000000000000000000000001'},
+ {value: 15, expected: '0x000000000000000000000000000000000000000000000000000000000000000f'},
+ {value: '15', expected: '0x000000000000000000000000000000000000000000000000000000000000000f'},
+ {value: '0xf', expected: '0x000000000000000000000000000000000000000000000000000000000000000f'},
+ {value: '0x0f', expected: '0x000000000000000000000000000000000000000000000000000000000000000f'},
+ {value: new BN(0), expected: '0x0000000000000000000000000000000000000000000000000000000000000000'}
+ ]
+ it.each(tests, 'should return TwosComplement', (test) => {
+ expect(caver.utils.toTwosComplement(test.value)).to.equal(test.expected)
+ })
+})
+
+describe('CAVERJS-UNIT-ETC-145: caver.utils.isHexPrefixed', () => {
+ it('caver.utils.isHexPrefixed should return boolean depends on parameter', ()=>{
+ expect(caver.utils.isHexPrefixed('0x')).to.be.true
+ expect(caver.utils.isHexPrefixed('0x0x')).to.be.true
+ expect(caver.utils.isHexPrefixed('01')).to.be.false
+ expect(caver.utils.isHexPrefixed({})).to.be.false
+ })
+})
+
+describe('CAVERJS-UNIT-ETC-146: caver.utils.addHexPrefix', () => {
+ it('caver.utils.addHexPrefix should return 0x hex format string', ()=>{
+ expect(caver.utils.addHexPrefix('0x')).to.equals('0x')
+ expect(caver.utils.addHexPrefix('01')).to.equals('0x01')
+ expect(caver.utils.addHexPrefix('x')).to.equals('0xx')
+ expect(typeof(caver.utils.addHexPrefix({}))).to.equals('object')
+ })
+})
+
+describe('CAVERJS-UNIT-ETC-147: caver.utils.stripHexPrefix', () => {
+ it('caver.utils.stripHexPrefix should strip 0x prefix and return string', ()=>{
+ expect(caver.utils.stripHexPrefix('0x')).to.equals('')
+ expect(caver.utils.stripHexPrefix('01')).to.equals('01')
+ expect(caver.utils.stripHexPrefix('0x01')).to.equals('01')
+ expect(caver.utils.stripHexPrefix('0xx')).to.equals('x')
+ expect(typeof(caver.utils.stripHexPrefix({}))).to.equals('object')
+ })
+})
+
+describe('caver.utils.toBuffer', () => {
+ it('CAVERJS-UNIT-ETC-148: caver.utils.toBuffer should return input when input is Buffer', ()=>{
+ expect(caver.utils.toBuffer(Buffer.from('test Buffer'))).to.deep.equal(Buffer.from('test Buffer'))
+ })
+ it('CAVERJS-UNIT-ETC-149: caver.utils.toBuffer should convert null or undefined to buffer', ()=>{
+ expect(caver.utils.toBuffer(null)).to.deep.equal(Buffer.alloc(0))
+ expect(caver.utils.toBuffer(undefined)).to.deep.equal(Buffer.alloc(0))
+ })
+ it('CAVERJS-UNIT-ETC-150: caver.utils.toBuffer should convert Array to buffer', ()=>{
+ expect(caver.utils.toBuffer([1,2,3,4,5])).to.deep.equal(Buffer.from([1,2,3,4,5]))
+ expect(caver.utils.toBuffer([])).to.deep.equal(Buffer.alloc(0))
+ })
+ it('CAVERJS-UNIT-ETC-151: caver.utils.toBuffer should convert BN to buffer', ()=>{
+ expect(caver.utils.toBuffer(new BN(1))).to.deep.equal(Buffer.from([1]))
+ expect(caver.utils.toBuffer(new BN(255)).toString('hex')).to.deep.equal('ff')
+ expect(caver.utils.toBuffer(new BN('ff', 16)).toString('hex')).to.deep.equal('ff')
+ expect(caver.utils.toBuffer(new BN('377', 8)).toString('hex')).to.deep.equal('ff')
+ expect(caver.utils.toBuffer(new BN('11111111', 2)).toString('hex')).to.deep.equal('ff')
+ })
+ it('CAVERJS-UNIT-ETC-152: caver.utils.toBuffer should convert Object has toArray function to buffer', ()=>{
+ expect(caver.utils.toBuffer({toArray: function () {return [1, 2, 3, 4, 5]}})).to.deep.equal(Buffer.from([1,2,3,4,5]))
+ })
+ it('CAVERJS-UNIT-ETC-153: caver.utils.toBuffer should convert String to buffer', ()=>{
+ expect(caver.utils.toBuffer('0x01').toString('hex')).to.deep.equal('01')
+ expect(caver.utils.toBuffer('0x1').toString('hex')).to.deep.equal('01')
+ expect(caver.utils.toBuffer('0x1234').toString('hex')).to.deep.equal('1234')
+ expect(caver.utils.toBuffer('0x12345').toString('hex')).to.deep.equal('012345')
+ expect(caver.utils.toBuffer('0x11')).to.deep.equal(Buffer.from([17]))
+ expect(caver.utils.toBuffer('0x')).to.deep.equal(Buffer.from([]))
+ })
+ it('CAVERJS-UNIT-ETC-154: caver.utils.toBuffer should convert Number to buffer', ()=>{
+ expect(caver.utils.toBuffer(1)).to.deep.equal(Buffer.from([1]))
+ expect(caver.utils.toBuffer(1).toString('hex')).to.deep.equal('01')
+ expect(caver.utils.toBuffer(100).toString('hex')).to.deep.equal('64')
+ })
+
+ it('CAVERJS-UNIT-ETC-155: caver.utils.toBuffer should throw error when input type is not supported with toBuffer function', ()=>{
+ expect(()=>caver.utils.toBuffer({})).to.throw('To convert an object to a buffer, the toArray function must be implemented inside the object')
+ expect(()=>caver.utils.toBuffer({toArray: [1,2,3,4,5]})).to.throw('To convert an object to a buffer, the toArray function must be implemented inside the object')
+ })
+ it('CAVERJS-UNIT-ETC-156: caver.utils.toBuffer should throw error when String is not 0x-prefixed', ()=>{
+ expect(()=>caver.utils.toBuffer('010x')).to.throw(`Failed to convert string to Buffer. 'toBuffer' function only supports 0x-prefixed hex string`)
+ expect(()=>caver.utils.toBuffer('01')).to.throw(`Failed to convert string to Buffer. 'toBuffer' function only supports 0x-prefixed hex string`)
+ expect(()=>caver.utils.toBuffer('')).to.throw(`Failed to convert string to Buffer. 'toBuffer' function only supports 0x-prefixed hex string`)
+ expect(()=>caver.utils.toBuffer('0xqwer')).to.throw(`Failed to convert string to Buffer. 'toBuffer' function only supports 0x-prefixed hex string`)
+ expect(()=>caver.utils.toBuffer('qwer')).to.throw(`Failed to convert string to Buffer. 'toBuffer' function only supports 0x-prefixed hex string`)
+ })
+})
+
+describe('CAVERJS-UNIT-ETC-157: caver.utils.numberToBuffer', () => {
+ it('caver.utils.numberToBuffer should convert number to buffer', ()=>{
+ expect(caver.utils.numberToBuffer(6003400).toString('hex')).to.equals('5b9ac8')
+ expect(caver.utils.numberToBuffer(1).toString('hex')).to.equals('01')
+ expect(caver.utils.numberToBuffer(12345).toString('hex')).to.equals('3039')
+ expect(caver.utils.numberToBuffer(123456789).toString('hex')).to.equals('075bcd15')
+ expect(caver.utils.numberToBuffer(100000000).toString('hex')).to.equals('05f5e100')
+ expect(caver.utils.numberToBuffer(819263839023).toString('hex')).to.equals('bebfee1b2f')
+ })
+})
+
+describe('caver.utils.isHexParameter', () => {
+ it('CAVERJS-UNIT-ETC-158: caver.utils.isHexParameter should return true if input is hex string', ()=>{
+ expect(caver.utils.isHexParameter('0x01')).to.be.true
+ expect(caver.utils.isHexParameter('0xa')).to.be.true
+ expect(caver.utils.isHexParameter('0x256d774a7a1bbd469d4fb08545d171df1c755a78')).to.be.true
+ expect(caver.utils.isHexParameter('0x256d774a7a1bbd469d4fb08545d171df1c755a78171df1c755a78')).to.be.true
+ })
+
+ it('CAVERJS-UNIT-ETC-159: caver.utils.isHexParameter should return false if input is not hex string', ()=>{
+ // string type input
+ expect(caver.utils.isHexParameter('')).to.be.false
+ expect(caver.utils.isHexParameter('1')).to.be.false
+ expect(caver.utils.isHexParameter('0xqwer')).to.be.false
+ expect(caver.utils.isHexParameter('10x')).to.be.false
+ expect(caver.utils.isHexParameter('0x14qr')).to.be.false
+ expect(caver.utils.isHexParameter('0x1!')).to.be.false
+ expect(caver.utils.isHexParameter(' 0x256d774a7a1bbd469d4fb08545d171df1c755a78')).to.be.false
+ // not string type input
+ expect(caver.utils.isHexParameter(null)).to.be.false
+ expect(caver.utils.isHexParameter(undefined)).to.be.false
+ expect(caver.utils.isHexParameter(true)).to.be.false
+ expect(caver.utils.isHexParameter(1)).to.be.false
+ expect(caver.utils.isHexParameter({})).to.be.false
+ expect(caver.utils.isHexParameter([])).to.be.false
+ expect(caver.utils.isHexParameter(Buffer.alloc(0))).to.be.false
+ expect(caver.utils.isHexParameter(new BN())).to.be.false
+ })
+})
+
+describe('caver.utils.xyPointFromPublicKey', () => {
+ it('CAVERJS-UNIT-ETC-160: caver.utils.xyPointFromPublicKey should return x, y point from publicKey', ()=>{
+ const account = caver.klay.accounts.create()
+ const publicKey = caver.klay.accounts.privateKeyToPublicKey(account.privateKey)
+ const xyPoint = caver.utils.xyPointFromPublicKey(publicKey)
+ expect(Array.isArray(xyPoint)).to.be.true
+ expect(xyPoint.length).to.equals(2)
+ expect(publicKey).to.equals(caver.utils.leftPad(xyPoint[0], 64)+caver.utils.leftPad(xyPoint[1], 64).slice(2))
+ })
+
+ it('CAVERJS-UNIT-ETC-161: caver.utils.xyPointFromPublicKey should return x, y point remove leading zeros', ()=>{
+ const publicKey1 = '0x046241c7524030e5b44fff78021e35227d708c8630757b35090d56527b615f605b8d366782c86dee49356be574e1172f75ef5ce5d03b6e8c17dbf10f3fa2d9a3'
+ const publicKey2 = '0xba7135b75cae89b958e7bb78009bda52f6a348150757cc078e3e5e5d25519c500ed4ccec1f78ba4e1c21c7b1e57751cec4cf42e3997a476e3ecbf360ad095336'
+ const publicKey3 = '0x12b97e6756861ac0257a240d985d761cee9ca7719a29c233c644cfcc421885000c8e4c69cdb71665377b9e8ffb702355ca53917e66c7444619049c3dd0252ab6'
+ const publicKey4 = '0x05b3b58259770871a1cc18534f2d438935fa2dcdb04116cbfbde8adfe858c23e50047c5aea3c2f55de7de04203f8fe8ccc3b491029338d038a7ef6d6903b302e'
+
+ const xyPoint1 = caver.utils.xyPointFromPublicKey(publicKey1)
+ const xyPoint2 = caver.utils.xyPointFromPublicKey(publicKey2)
+ const xyPoint3 = caver.utils.xyPointFromPublicKey(publicKey3)
+ const xyPoint4 = caver.utils.xyPointFromPublicKey(publicKey4)
+
+ expect(xyPoint1[0]).to.equals('0x46241c7524030e5b44fff78021e35227d708c8630757b35090d56527b615f60')
+ expect(xyPoint1[1]).to.equals('0x5b8d366782c86dee49356be574e1172f75ef5ce5d03b6e8c17dbf10f3fa2d9a3')
+
+ expect(xyPoint2[0]).to.equals('0xba7135b75cae89b958e7bb78009bda52f6a348150757cc078e3e5e5d25519c50')
+ expect(xyPoint2[1]).to.equals('0xed4ccec1f78ba4e1c21c7b1e57751cec4cf42e3997a476e3ecbf360ad095336')
+
+ expect(xyPoint3[0]).to.equals('0x12b97e6756861ac0257a240d985d761cee9ca7719a29c233c644cfcc42188500')
+ expect(xyPoint3[1]).to.equals('0xc8e4c69cdb71665377b9e8ffb702355ca53917e66c7444619049c3dd0252ab6')
+
+ expect(xyPoint4[0]).to.equals('0x5b3b58259770871a1cc18534f2d438935fa2dcdb04116cbfbde8adfe858c23e')
+ expect(xyPoint4[1]).to.equals('0x50047c5aea3c2f55de7de04203f8fe8ccc3b491029338d038a7ef6d6903b302e')
+ })
+})
+
+describe('caver.utils.isValidPublicKey', () => {
+ it('CAVERJS-UNIT-ETC-171: caver.utils.isValidPublicKey should true with valid uncompressed public key', ()=>{
+ const account = caver.klay.accounts.create()
+
+ const unCompressedPublicKey = caver.klay.accounts.privateKeyToPublicKey(account.privateKey)
+
+ let isValid = caver.utils.isValidPublicKey(unCompressedPublicKey)
+ expect(isValid).to.be.true
+ })
+
+ it('CAVERJS-UNIT-ETC-172: caver.utils.isValidPublicKey should true with valid compressed public key', ()=>{
+ const account = caver.klay.accounts.create()
+
+ const unCompressedPublicKey = caver.klay.accounts.privateKeyToPublicKey(account.privateKey)
+ const compressed = caver.utils.compressPublicKey(unCompressedPublicKey)
+
+ let isValid = caver.utils.isValidPublicKey(compressed)
+ expect(isValid).to.be.true
+ })
+
+ it('CAVERJS-UNIT-ETC-173: caver.utils.isValidPublicKey should false with invalid uncompressed public key', ()=>{
+ const account = caver.klay.accounts.create()
+
+ const unCompressedPublicKey = caver.klay.accounts.privateKeyToPublicKey(account.privateKey)
+
+ let isValid = caver.utils.isValidPublicKey(unCompressedPublicKey.slice(1))
+ expect(isValid).to.be.false
+ })
+
+ it('CAVERJS-UNIT-ETC-174: caver.utils.isValidPublicKey should false with invalid compressed public key', ()=>{
+ const account = caver.klay.accounts.create()
+
+ const unCompressedPublicKey = caver.klay.accounts.privateKeyToPublicKey(account.privateKey)
+ const compressed = caver.utils.compressPublicKey(unCompressedPublicKey)
+
+ let isValid = caver.utils.isValidPublicKey(compressed.slice(1))
+ expect(isValid).to.be.false
+ })
+
+ it('CAVERJS-UNIT-ETC-175: caver.utils.isValidPublicKey should false with invalid indicated compressed public key', ()=>{
+ const account = caver.klay.accounts.create()
+
+ const unCompressedPublicKey = caver.klay.accounts.privateKeyToPublicKey(account.privateKey)
+ let compressed = caver.utils.compressPublicKey(unCompressedPublicKey)
+ compressed = compressed.replace('0x', '')
+ compressed = compressed.slice(2)
+ compressed = '05' + compressed
+
+ let isValid = caver.utils.isValidPublicKey(compressed)
+ expect(isValid).to.be.false
+ })
+})
+
+describe('caver.utils.isValidRole', () => {
+ it('CAVERJS-UNIT-ETC-176: caver.utils.isValidRole should true with valid role', ()=>{
+ let isValid = caver.utils.isValidRole('transactionKey')
+ expect(isValid).to.be.true
+
+ isValid = caver.utils.isValidRole('updateKey')
+ expect(isValid).to.be.true
+
+ isValid = caver.utils.isValidRole('feePayerKey')
+ expect(isValid).to.be.true
+ })
+
+ it('CAVERJS-UNIT-ETC-177: caver.utils.isValidRole should false with invalid role', ()=>{
+ let isValid = caver.utils.isValidRole('invalid')
+ expect(isValid).to.be.false
+
+ isValid = caver.utils.isValidRole(undefined)
+ expect(isValid).to.be.false
+
+ isValid = caver.utils.isValidRole({})
+ expect(isValid).to.be.false
+ })
+})
+
+describe('caver.utils.isEmptySig', () => {
+ it('CAVERJS-UNIT-ETC-178: caver.utils.isEmptySig should true with default signatures', ()=>{
+ let isDefault = caver.utils.isEmptySig(['0x01', '0x', '0x'])
+ expect(isDefault).to.be.true
+
+ isDefault = caver.utils.isEmptySig([['0x01', '0x', '0x']])
+ expect(isDefault).to.be.true
+ })
+
+ it('CAVERJS-UNIT-ETC-179: caver.utils.isEmptySig should false if signatures is not same with default signatures', ()=>{
+ let isDefault = caver.utils.isEmptySig([['0x01', '0x', '0x'], ['0x01', '0x', '0x']])
+ expect(isDefault).to.be.false
+
+ isDefault = caver.utils.isEmptySig(['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567'])
+ expect(isDefault).to.be.false
+
+ isDefault = caver.utils.isEmptySig([['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']])
+ expect(isDefault).to.be.false
+ })
+
+ it('CAVERJS-UNIT-ETC-180: caver.utils.isEmptySig should throw error with invalid length of signatures', ()=>{
+ let expectedError = `Invalid signatures length: 6`
+ expect(() => caver.utils.isEmptySig(['0x01', '0x', '0x', '0x01', '0x', '0x'])).to.throws(expectedError)
+ expect(() => caver.utils.isEmptySig([['0x01', '0x', '0x', '0x01', '0x', '0x']])).to.throws(expectedError)
+ })
+})
\ No newline at end of file
diff --git a/test/scenarioTest/accountKeyMultiSig.js b/test/scenarioTest/accountKeyMultiSig.js
new file mode 100644
index 00000000..8dbf0d98
--- /dev/null
+++ b/test/scenarioTest/accountKeyMultiSig.js
@@ -0,0 +1,648 @@
+/*
+ Copyright 2019 The caver-js Authors
+ This file is part of the caver-js library.
+
+ The caver-js library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ The caver-js library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the caver-js. If not, see .
+*/
+
+require('it-each')({ testPerIteration: true })
+const { expect } = require('../extendedChai')
+
+const testRPCURL = require('../testrpc')
+const Caver = require('../../index.js')
+
+let caver
+let sender, payer, account
+let contractAddress
+let legacyKey
+
+describe('Scenario test with AccountWithAccountKeyMultiSig', () => {
+ before(() => {
+ caver = new Caver(testRPCURL)
+
+ let senderPrvKey = process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
+ ? '0x' + process.env.privateKey
+ : process.env.privateKey
+
+ sender = caver.klay.accounts.wallet.add(senderPrvKey)
+ })
+
+ context('1. Prepare for testing', () => {
+ it('Create test accounts', async () => {// Send KLAY to test account
+ account = caver.klay.accounts.create()
+ legacyKey = account.privateKey
+ let txObject = {
+ from: sender.address,
+ to: account.address,
+ value: caver.utils.toPeb(10, 'KLAY'),
+ gas: 900000,
+ }
+ await caver.klay.sendTransaction(txObject)
+
+ payer = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ txObject = {
+ from: sender.address,
+ to: payer.address,
+ value: caver.utils.toPeb(10, 'KLAY'),
+ gas: 900000,
+ }
+ await caver.klay.sendTransaction(txObject)
+
+ // New private key to update
+ let keyArray = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ // Create an AccountKeyMultiSig instance that contains one private key string.
+ let newAccountKeyMultiSig = caver.klay.accounts.createAccountKeyMultiSig(keyArray)
+ // Get all internal key through the 'keys' property on an instance of AccountKey.
+ let newPublicKey = [
+ caver.klay.accounts.privateKeyToPublicKey(newAccountKeyMultiSig.keys[0]),
+ caver.klay.accounts.privateKeyToPublicKey(newAccountKeyMultiSig.keys[1]),
+ caver.klay.accounts.privateKeyToPublicKey(newAccountKeyMultiSig.keys[2])
+ ]
+
+ // Create an AccountForUpdate containing about the address of account and key to update
+ let multiSigOption = { threshold: 2, weight: [1, 1, 1] }
+ let updator = caver.klay.accounts.createAccountForUpdate(account.address, newAccountKeyMultiSig, multiSigOption)
+
+ // Set AccountForUpdate instance to 'key'
+ let updateTx = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ gas: 90000,
+ key: updator,
+ }
+
+ // If the account's accountKey is AccountKeyMultiSig, the privateKey will be 0th of key array, and transactionKey, updateKey and feePayerKey are the same as an array.
+ // If the account does not exist inside the in-memory wallet, you must pass the privateKey parameter to signTransaction.
+ let signed = await caver.klay.accounts.signTransaction(updateTx, account.updateKey)
+ expect(signed.signatures.length).to.equals(1)
+ let receipt = await caver.klay.sendSignedTransaction(signed)
+ expect(receipt.status).to.be.true
+
+ // Check result of account update
+ let accountKey = await caver.klay.getAccountKey(account.address)
+ expect(accountKey.keyType).to.equals(4)
+
+ expect(accountKey.key.threshold).to.equals(multiSigOption.threshold)
+
+ expect(accountKey.key.keys[0].weight).to.equals(multiSigOption.weight[0])
+ expect(accountKey.key.keys[1].weight).to.equals(multiSigOption.weight[1])
+ expect(accountKey.key.keys[2].weight).to.equals(multiSigOption.weight[2])
+ expect(accountKey.key.keys[0].weight).to.equals(multiSigOption.weight[0])
+ expect(accountKey.key.keys[1].weight).to.equals(multiSigOption.weight[1])
+ expect(accountKey.key.keys[2].weight).to.equals(multiSigOption.weight[2])
+
+ let xyPoint = caver.utils.xyPointFromPublicKey(newPublicKey[0])
+ expect(accountKey.key.keys[0].key.x).to.equals(xyPoint[0])
+ expect(accountKey.key.keys[0].key.y).to.equals(xyPoint[1])
+ xyPoint = caver.utils.xyPointFromPublicKey(newPublicKey[1])
+ expect(accountKey.key.keys[1].key.x).to.equals(xyPoint[0])
+ expect(accountKey.key.keys[1].key.y).to.equals(xyPoint[1])
+ xyPoint = caver.utils.xyPointFromPublicKey(newPublicKey[2])
+ expect(accountKey.key.keys[2].key.x).to.equals(xyPoint[0])
+ expect(accountKey.key.keys[2].key.y).to.equals(xyPoint[1])
+
+ // Add account to in-memory wallet
+ account = caver.klay.accounts.createWithAccountKey(account.address, newAccountKeyMultiSig)
+ caver.klay.accounts.wallet.add(account)
+
+ // Get account from in-memory wallet
+ let fromWallet = caver.klay.accounts.wallet.getAccount(account.address)
+ expect(fromWallet).not.to.undefined
+
+ expect(fromWallet.address).to.equals(account.address)
+ expect(fromWallet.accountKeyType).to.equals('AccountKeyMultiSig')
+
+ expect(fromWallet.privateKey).to.equals(account.privateKey)
+ expect(fromWallet.keys.length).to.equals(account.keys.length)
+ expect(fromWallet.transactionKey.length).to.equals(account.transactionKey.length)
+ expect(fromWallet.updateKey.length).to.equals(account.updateKey.length)
+ expect(fromWallet.feePayerKey.length).to.equals(account.feePayerKey.length)
+
+ // Update payer account to AccountKeyMultiSig
+ multiSigOption = { threshold: 2, weight: [1, 1, 1] }
+ updator = caver.klay.accounts.createAccountForUpdate(payer.address, newAccountKeyMultiSig, multiSigOption)
+ updateTx = {
+ type: 'ACCOUNT_UPDATE',
+ from: payer.address,
+ gas: 90000,
+ key: updator,
+ }
+ receipt = await caver.klay.sendTransaction(updateTx)
+ expect(receipt.status).to.be.true
+ payer = caver.klay.accounts.wallet.updateAccountKey(payer.address, newAccountKeyMultiSig)
+ }).timeout(200000)
+ })
+
+ context('2. Send VALUE_TRANSFER transaction with AccountWithAccountKeyMultiSig', () => {
+ it('VALUE_TRANSFER testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'VALUE_TRANSFER',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 900000,
+ }
+ // If the account exists inside the in-memory wallet, you do not need to pass the privateKey parameter to signTransaction.
+ // The transactionKey of account will be used
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ let receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 900000,
+ }
+ // If the account exists inside the in-memory wallet, you do not need to pass the privateKey parameter to signTransaction.
+ // The transactionKey of account will be used
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payer.address, payer.feePayerKey[0])
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+ let feePayerSigned2 = await caver.klay.accounts.feePayerSignTransaction(feePayerSigned.rawTransaction, payer.address, payer.feePayerKey[1])
+ expect(feePayerSigned2.feePayerSignatures.length).to.equals(2)
+ let feePayerSigned3 = await caver.klay.accounts.feePayerSignTransaction(feePayerSigned2.rawTransaction, payer.address, payer.feePayerKey[2])
+ expect(feePayerSigned3.feePayerSignatures.length).to.equals(3)
+
+ receipt = await caver.klay.sendSignedTransaction(feePayerSigned3)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER_WITH_RATIO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 900000,
+ feeRatio: 50,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(3)
+
+ let combined = await caver.klay.accounts.combineSignatures([senderSigned.rawTransaction, feePayerSigned.rawTransaction])
+ expect(combined.signatures.length).to.equals(3)
+ expect(combined.feePayerSignatures.length).to.equals(3)
+
+ receipt = await caver.klay.sendSignedTransaction(combined)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('3. Send VALUE_TRANSFER_MEMO transaction with AccountWithAccountKeyMultiSig', () => {
+ it('VALUE_TRANSFER_MEMO testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'VALUE_TRANSFER_MEMO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ data: 'value transfer memo',
+ gas: 90000,
+ }
+ // Sign transaction with sender
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ let receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER_MEMO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ data: 'fee delegated value transfer memo',
+ gas: 900000,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[0], account.transactionKey[1]])
+ expect(senderSigned.signatures.length).to.equals(2)
+ txObject.signatures = senderSigned.signatures
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, [payer.feePayerKey[0], payer.feePayerKey[1]])
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(2)
+ let feePayerSigned2 = await caver.klay.accounts.feePayerSignTransaction(feePayerSigned.rawTransaction, payer.address, [payer.feePayerKey[1], payer.feePayerKey[2]])
+ expect(feePayerSigned2.feePayerSignatures.length).to.equals(3)
+
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned2.feePayerSignatures
+
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[2]])
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER_MEMO_WITH_RATIO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ data: 'fee delegated value transfer memo',
+ gas: 900000,
+ feeRatio: 10,
+ }
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(3)
+
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ senderSigned = await caver.klay.accounts.signTransaction(feePayerSigned.rawTransaction)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('4. Send ACCOUNT_UPDATE transaction with AccountWithAccountKeyMultiSig', () => {
+ it('ACCOUNT_UPDATE testing', async () => {// Send KLAY to test account
+ // Update AccountKeyMultiSig -> AccountKeyRoleBased
+ let newKey = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ }
+ let options = {
+ transactionKey: { threshold: 1, weight: [1, 1] },
+ updateKey: { threshold: 6, weight: [1, 2, 3] },
+ feePayerKey: { threshold: 1, weight: [1, 1] }
+ }
+ updator = caver.klay.accounts.createAccountForUpdate(account.address, newKey, options)
+
+ let txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 900000,
+ }
+
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
+
+ // Update AccountKeyRoleBased -> AccountKeyPublic
+ newKey = caver.klay.accounts.create().privateKey
+ let newPublicKey = caver.klay.accounts.privateKeyToPublicKey(newKey)
+ updator = caver.klay.accounts.createAccountForUpdateWithPublicKey(account.address, newPublicKey)
+
+ txObject = {
+ type: 'FEE_DELEGATED_ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 900000,
+ }
+
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.updateKey[0])
+ expect(senderSigned.signatures.length).to.equals(1)
+ let senderSigned2 = await caver.klay.accounts.signTransaction(txObject, account.updateKey[1])
+ expect(senderSigned2.signatures.length).to.equals(1)
+ let senderSigned3 = await caver.klay.accounts.signTransaction(txObject, account.updateKey[2])
+ expect(senderSigned3.signatures.length).to.equals(1)
+
+ let senderRawTransaction = await caver.klay.accounts.combineSignatures([senderSigned.rawTransaction, senderSigned2.rawTransaction, senderSigned3.rawTransaction])
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderRawTransaction.rawTransaction, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(3)
+
+ receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
+
+ // Update AccountKeyPublic -> AccountKeyMultiSig
+ newKey = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ newPublicKey = [
+ caver.klay.accounts.privateKeyToPublicKey(newKey[0]),
+ caver.klay.accounts.privateKeyToPublicKey(newKey[1]),
+ caver.klay.accounts.privateKeyToPublicKey(newKey[2]),
+ caver.klay.accounts.privateKeyToPublicKey(newKey[3])
+ ]
+ options = { threshold: 3, weight: [1, 1, 1, 1] }
+ updator = caver.klay.accounts.createAccountForUpdateWithPublicKey(account.address, newPublicKey, options)
+
+ txObject = {
+ type: 'FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO',
+ from: account.address,
+ key: updator,
+ gas: 900000,
+ feeRatio: 30,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.updateKey)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, payer.feePayerKey)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(3)
+
+ txObject.signatures = senderSigned.signatures
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ let rawTransaction = await caver.klay.accounts.getRawTransactionWithSignatures(txObject)
+
+ receipt = await caver.klay.sendSignedTransaction(rawTransaction)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+
+ // Update accountKey in wallet
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
+ }).timeout(200000)
+ })
+
+ context('5. Send SMART_CONTRACT_DEPLOY transaction with AccountWithAccountKeyMultiSig', () => {
+ it('SMART_CONTRACT_DEPLOY testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'SMART_CONTRACT_DEPLOY',
+ from: account.address,
+ data: '0x60806040526000805534801561001457600080fd5b5060405161016f38038061016f8339810180604052810190808051906020019092919080518201929190505050816000819055505050610116806100596000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60d2565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260d8565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060d06004803603810190808035906020019092919050505060e0565b005b60005481565b600043905090565b80600081905550505600a165627a7a723058206d2bc553736581b6387f9a0410856ca490fcdc7045a8991ad63a1fd71b651c3a00290000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000',
+ gas: 900000,
+ value: 0,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey.slice(0, 3))
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ senderSigned = await caver.klay.accounts.signTransaction(senderSigned.rawTransaction, account.transactionKey[3])
+ expect(senderSigned.signatures.length).to.equals(4)
+
+ let receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(4)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_DEPLOY',
+ from: account.address,
+ data: '0x60806040526000805534801561001457600080fd5b5060405161016f38038061016f8339810180604052810190808051906020019092919080518201929190505050816000819055505050610116806100596000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60d2565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260d8565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060d06004803603810190808035906020019092919050505060e0565b005b60005481565b600043905090565b80600081905550505600a165627a7a723058206d2bc553736581b6387f9a0410856ca490fcdc7045a8991ad63a1fd71b651c3a00290000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000',
+ gas: 900000,
+ value: 0,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(4)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(3)
+
+ txObject.signatures = senderSigned.signatures
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ receipt = await caver.klay.sendSignedTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(4)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_DEPLOY_WITH_RATIO',
+ from: account.address,
+ data: '0x60806040526000805534801561001457600080fd5b5060405161016f38038061016f8339810180604052810190808051906020019092919080518201929190505050816000819055505050610116806100596000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60d2565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260d8565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060d06004803603810190808035906020019092919050505060e0565b005b60005481565b600043905090565b80600081905550505600a165627a7a723058206d2bc553736581b6387f9a0410856ca490fcdc7045a8991ad63a1fd71b651c3a00290000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000',
+ gas: 900000,
+ value: 0,
+ feeRatio: 30,
+ }
+
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey[0])
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ let senderSigned2 = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[1], account.transactionKey[2]])
+ expect(senderSigned2.signatures.length).to.equals(2)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(3)
+
+ let combined = await caver.klay.accounts.combineSignatures([senderSigned.rawTransaction, senderSigned2.rawTransaction, feePayerSigned.rawTransaction])
+ expect(combined.signatures.length).to.equals(3)
+ expect(combined.feePayerSignatures.length).to.equals(3)
+
+ receipt = await caver.klay.sendSignedTransaction(combined)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+
+ contractAddress = receipt.contractAddress
+ }).timeout(200000)
+ })
+
+ context('6. Send SMART_CONTRACT_EXECUTION transaction with AccountWithAccountKeyMultiSig', () => {
+ it('SMART_CONTRACT_EXECUTION testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'SMART_CONTRACT_EXECUTION',
+ from: account.address,
+ to: contractAddress,
+ data: '0xd14e62b80000000000000000000000000000000000000000000000000000000000000005',
+ gas: 900000,
+ }
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(4)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_EXECUTION',
+ from: account.address,
+ to: contractAddress,
+ data: '0xd14e62b80000000000000000000000000000000000000000000000000000000000000005',
+ gas: 900000,
+ }
+ // Sign transaction with sender
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey[0])
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ senderSigned = await caver.klay.accounts.signTransaction(senderSigned.rawTransaction, [account.transactionKey[1], account.transactionKey[2]])
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ // Set signatures to transaction object
+ txObject.signatures = senderSigned.signatures
+
+ let senderRaw = await caver.klay.accounts.getRawTransactionWithSignatures(txObject)
+
+ // Send transaction object with signatures through sendSignedTransaction
+ receipt = await caver.klay.sendTransaction({
+ senderRawTransaction: senderRaw.rawTransaction,
+ feePayer: payer.address
+ })
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_EXECUTION_WITH_RATIO',
+ from: account.address,
+ to: contractAddress,
+ data: '0xd14e62b80000000000000000000000000000000000000000000000000000000000000005',
+ gas: 900000,
+ feeRatio: 50,
+ }
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(3)
+
+ senderSigned = await caver.klay.accounts.signTransaction(feePayerSigned.rawTransaction, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(4)
+
+ receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(4)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('7. Send CANCEL transaction with AccountWithAccountKeyMultiSig', () => {
+ it('CANCEL testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'CANCEL',
+ from: account.address,
+ gas: 90000,
+ }
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(4)
+
+ txObject = {
+ type: 'FEE_DELEGATED_CANCEL',
+ from: account.address,
+ gas: 900000,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[0], account.transactionKey[1]])
+ expect(senderSigned.signatures.length).to.equals(2)
+
+ let senderSigned2 = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[0], account.transactionKey[2]])
+ expect(senderSigned2.signatures.length).to.equals(2)
+
+ let senderSigned3 = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[0], account.transactionKey[3]])
+ expect(senderSigned3.signatures.length).to.equals(2)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, payer.feePayerKey)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(3)
+
+ let combined = await caver.klay.accounts.combineSignatures([senderSigned.rawTransaction, senderSigned2.rawTransaction, senderSigned3.rawTransaction, feePayerSigned.rawTransaction])
+ expect(combined.signatures.length).to.equals(4)
+ expect(combined.feePayerSignatures.length).to.equals(3)
+
+ receipt = await caver.klay.sendSignedTransaction(combined)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(4)
+ expect(receipt.feePayerSignatures.length).to.equals(3)
+
+ txObject = {
+ type: 'FEE_DELEGATED_CANCEL_WITH_RATIO',
+ from: account.address,
+ gas: 900000,
+ feeRatio: 50,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[0], account.transactionKey[1]])
+ expect(senderSigned.signatures.length).to.equals(2)
+
+ senderSigned2 = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[0], account.transactionKey[2]])
+ expect(senderSigned2.signatures.length).to.equals(2)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, [payer.feePayerKey[0], payer.feePayerKey[1]])
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(2)
+
+ // Set signatures, feePayer and feePayerSignatures to transaction object
+ txObject.signatures = senderSigned.signatures.concat(senderSigned2.signatures)
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ let rawTransaction = await caver.klay.accounts.getRawTransactionWithSignatures(txObject)
+ expect(rawTransaction.signatures.length).to.equals(3)
+ expect(rawTransaction.feePayerSignatures.length).to.equals(2)
+
+ receipt = await caver.klay.sendSignedTransaction(rawTransaction)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+ }).timeout(200000)
+ })
+
+ context('8. Send a transaction to the network with signatures that do not meet the threshold', () => {
+ it('Insufficient weight signatures testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'VALUE_TRANSFER',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 900000,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.keys[0])
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ const expectedError = 'invalid transaction v, r, s values of the sender'
+ try {
+ await caver.klay.sendSignedTransaction(senderSigned)
+ } catch (e) { expect(e.message).to.include(expectedError) }
+ }).timeout(200000)
+ })
+
+ context('9. Account update with LegacyKey', () => {
+ it('Account update with legacy key testing', async () => {// Send KLAY to test account
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(account.address)
+
+ const txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 90000,
+ }
+ // The updateKey in Account is used when signing.
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+
+ // Check result of account update
+ let accountKey = await caver.klay.getAccountKey(account.address)
+ expect(accountKey.keyType).to.equals(1)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, legacyKey)
+ expect(account.privateKey).to.equals(legacyKey)
+ }).timeout(200000)
+ })
+
+ context('10. Account update with FailKey', () => {
+ it('Account update with fail key testing', async () => {// Send KLAY to test account
+ const updator = caver.klay.accounts.createAccountForUpdateWithFailKey(account.address)
+
+ const txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 90000,
+ }
+ // The updateKey in Account is used when signing.
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+
+ // Check result of account update
+ let accountKey = await caver.klay.getAccountKey(account.address)
+ expect(accountKey.keyType).to.equals(3)
+ }).timeout(200000)
+ })
+})
\ No newline at end of file
diff --git a/test/scenarioTest/accountKeyPublic.js b/test/scenarioTest/accountKeyPublic.js
new file mode 100644
index 00000000..365c86cf
--- /dev/null
+++ b/test/scenarioTest/accountKeyPublic.js
@@ -0,0 +1,561 @@
+/*
+ Copyright 2019 The caver-js Authors
+ This file is part of the caver-js library.
+
+ The caver-js library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ The caver-js library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the caver-js. If not, see .
+*/
+
+require('it-each')({ testPerIteration: true })
+const { expect } = require('../extendedChai')
+
+const testRPCURL = require('../testrpc')
+const Caver = require('../../index.js')
+
+let caver
+let sender, payer, account
+let contractAddress
+let legacyKey
+
+describe('Scenario test with AccountWithAccountKeyPublic', () => {
+ before(() => {
+ caver = new Caver(testRPCURL)
+
+ let senderPrvKey = process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
+ ? '0x' + process.env.privateKey
+ : process.env.privateKey
+
+ sender = caver.klay.accounts.wallet.add(senderPrvKey)
+ })
+
+ context('1. Prepare for testing', () => {
+ it('Create test accounts', async () => {// Send KLAY to test account
+ // Send KLAY to test account
+ account = caver.klay.accounts.create()
+ legacyKey = account.privateKey
+ let txObject = {
+ from: sender.address,
+ to: account.address,
+ value: caver.utils.toPeb(10, 'KLAY'),
+ gas: 900000,
+ }
+ await caver.klay.sendTransaction(txObject)
+
+ payer = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ txObject = {
+ from: sender.address,
+ to: payer.address,
+ value: caver.utils.toPeb(10, 'KLAY'),
+ gas: 900000,
+ }
+ await caver.klay.sendTransaction(txObject)
+
+ // New private key to update
+ let newPrivateKey = caver.klay.accounts.create().privateKey
+ // Create an AccountKeyPublic instance that contains one private key string.
+ let newAccountKeyPublic = caver.klay.accounts.createAccountKeyPublic(newPrivateKey)
+ // Get all internal key through the 'keys' property on an instance of AccountKey.
+ let newPublicKey = caver.klay.accounts.privateKeyToPublicKey(newAccountKeyPublic.keys)
+
+ // Create an AccountForUpdate containing about the address of account and key to update
+ let updator = caver.klay.accounts.createAccountForUpdate(account.address, newAccountKeyPublic)
+
+ // Set AccountForUpdate instance to 'key'
+ let updateTx = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ gas: 90000,
+ key: updator,
+ }
+
+ // If the account's accountKey is AccountKeyPublic, the privateKey, transactionKey, updateKey and feePayerKey are the same.
+ // If the account does not exist inside the in-memory wallet, you must pass the privateKey parameter to signTransaction.
+ let signed = await caver.klay.accounts.signTransaction(updateTx, account.updateKey)
+ let receipt = await caver.klay.sendSignedTransaction(signed)
+ expect(receipt.status).to.be.true
+
+ // Check result of account update
+ let accountKey = await caver.klay.getAccountKey(account.address)
+ let xyPoint = caver.utils.xyPointFromPublicKey(newPublicKey)
+ expect(accountKey.keyType).to.equals(2)
+ expect(accountKey.key.x).to.equals(xyPoint[0])
+ expect(accountKey.key.y).to.equals(xyPoint[1])
+
+ // Add account to in-memory wallet
+ account = caver.klay.accounts.createWithAccountKey(account.address, newAccountKeyPublic)
+ expect(caver.klay.accounts.isDecoupled(account.keys, account.address)).to.be.true
+ caver.klay.accounts.wallet.add(account)
+
+ // Get account from in-memory wallet
+ let fromWallet = caver.klay.accounts.wallet.getAccount(account.address)
+ expect(fromWallet).not.to.undefined
+
+ expect(fromWallet.address).to.equals(account.address)
+ expect(fromWallet.accountKeyType).to.equals('AccountKeyPublic')
+
+ expect(fromWallet.privateKey).to.equals(account.privateKey)
+ expect(fromWallet.keys).to.equals(account.keys)
+ expect(fromWallet.transactionKey).to.equals(account.transactionKey)
+ expect(fromWallet.updateKey).to.equals(account.updateKey)
+ expect(fromWallet.feePayerKey).to.equals(account.feePayerKey)
+
+ // Update payer account to AccountKeyPublic
+ updator = caver.klay.accounts.createAccountForUpdate(payer.address, newAccountKeyPublic)
+ updateTx = {
+ type: 'ACCOUNT_UPDATE',
+ from: payer.address,
+ gas: 90000,
+ key: updator,
+ }
+ receipt = await caver.klay.sendTransaction(updateTx)
+ expect(receipt.status).to.be.true
+ payer = caver.klay.accounts.wallet.updateAccountKey(payer.address, newAccountKeyPublic)
+ }).timeout(200000)
+ })
+
+ context('2. Send VALUE_TRANSFER transaction with AccountWithAccountKeyPublic', () => {
+ it('VALUE_TRANSFER testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'VALUE_TRANSFER',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 90000,
+ }
+ // If the account exists inside the in-memory wallet, you do not need to pass the privateKey parameter to signTransaction.
+ // The transactionKey of account will be used
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ let receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 90000,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER_WITH_RATIO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 90000,
+ feeRatio: 50,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ let combined = await caver.klay.accounts.combineSignatures([senderSigned.rawTransaction, feePayerSigned.rawTransaction])
+ expect(combined.signatures.length).to.equals(1)
+ expect(combined.feePayerSignatures.length).to.equals(1)
+
+ receipt = await caver.klay.sendSignedTransaction(combined)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+ }).timeout(200000)
+ })
+
+ context('3. Send VALUE_TRANSFER_MEMO transaction with AccountWithAccountKeyPublic', () => {
+ it('VALUE_TRANSFER_MEMO testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'VALUE_TRANSFER_MEMO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ data: 'fee delegated value transfer memo',
+ gas: 90000,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ let receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER_MEMO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ data: 'fee delegated value transfer memo',
+ gas: 90000,
+ }
+ // Sign transaction with sender (The transactionKey of account will be used)
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ // Sign transaction with fee payer (The feePayerKey of account will be used)
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER_MEMO_WITH_RATIO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ data: 'fee delegated value transfer memo',
+ gas: 90000,
+ feeRatio: 10,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, payer.feePayerKey)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ txObject.signatures = senderSigned.signatures
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ receipt = await caver.klay.sendSignedTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+ }).timeout(200000)
+ })
+
+ context('4. Send ACCOUNT_UPDATE transaction with AccountWithAccountKeyPublic', () => {
+ it('ACCOUNT_UPDATE testing', async () => {// Send KLAY to test account
+ // Update AccountKeyPublic -> AccountKeyMultiSig
+ let newKey = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ let options = { threshold: 2, weight: [1, 2, 1] }
+ let updator = caver.klay.accounts.createAccountForUpdate(account.address, newKey, options)
+
+ let txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 900000,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ txObject.signatures = senderSigned.signatures
+
+ let receipt = await caver.klay.sendSignedTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+
+ // Update accountKey in wallet
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
+
+ // Update AccountKeyMultiSig -> AccountKeyRoleBased
+ newKey = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ }
+ options = {
+ transactionKey: { threshold: 1, weight: [1, 1] },
+ updateKey: { threshold: 6, weight: [1, 2, 3] },
+ feePayerKey: { threshold: 1, weight: [1, 1] }
+ }
+ updator = caver.klay.accounts.createAccountForUpdate(account.address, newKey, options)
+
+ txObject = {
+ type: 'FEE_DELEGATED_ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 900000,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+
+ // Update accountKey in wallet
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
+
+ // Update AccountKeyRoleBased -> AccountKeyPublic
+ newKey = caver.klay.accounts.create().privateKey
+ newPublicKey = caver.klay.accounts.privateKeyToPublicKey(newKey)
+ updator = caver.klay.accounts.createAccountForUpdateWithPublicKey(account.address, newPublicKey)
+
+ txObject = {
+ type: 'FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO',
+ from: account.address,
+ key: updator,
+ gas: 900000,
+ feeRatio: 30,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.updateKey)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, payer.feePayerKey)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ txObject.signatures = senderSigned.signatures
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ let rawTransaction = await caver.klay.accounts.getRawTransactionWithSignatures(txObject)
+
+ receipt = await caver.klay.sendSignedTransaction(rawTransaction)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+
+ // Update accountKey in wallet
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
+ }).timeout(200000)
+ })
+
+ context('5. Send SMART_CONTRACT_DEPLOY transaction with AccountWithAccountKeyPublic', () => {
+ it('SMART_CONTRACT_DEPLOY testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'SMART_CONTRACT_DEPLOY',
+ from: account.address,
+ data: '0x60806040526000805534801561001457600080fd5b5060405161016f38038061016f8339810180604052810190808051906020019092919080518201929190505050816000819055505050610116806100596000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60d2565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260d8565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060d06004803603810190808035906020019092919050505060e0565b005b60005481565b600043905090565b80600081905550505600a165627a7a723058206d2bc553736581b6387f9a0410856ca490fcdc7045a8991ad63a1fd71b651c3a00290000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000',
+ gas: 900000,
+ value: 0,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ let receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_DEPLOY',
+ from: account.address,
+ data: '0x60806040526000805534801561001457600080fd5b5060405161016f38038061016f8339810180604052810190808051906020019092919080518201929190505050816000819055505050610116806100596000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60d2565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260d8565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060d06004803603810190808035906020019092919050505060e0565b005b60005481565b600043905090565b80600081905550505600a165627a7a723058206d2bc553736581b6387f9a0410856ca490fcdc7045a8991ad63a1fd71b651c3a00290000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000',
+ gas: 900000,
+ value: 0,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ txObject.signatures = senderSigned.signatures
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ receipt = await caver.klay.sendSignedTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_DEPLOY_WITH_RATIO',
+ from: account.address,
+ data: '0x60806040526000805534801561001457600080fd5b5060405161016f38038061016f8339810180604052810190808051906020019092919080518201929190505050816000819055505050610116806100596000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60d2565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260d8565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060d06004803603810190808035906020019092919050505060e0565b005b60005481565b600043905090565b80600081905550505600a165627a7a723058206d2bc553736581b6387f9a0410856ca490fcdc7045a8991ad63a1fd71b651c3a00290000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000',
+ gas: 900000,
+ value: 0,
+ feeRatio: 20,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ let combined = await caver.klay.accounts.combineSignatures([senderSigned.rawTransaction, feePayerSigned.rawTransaction])
+ expect(combined.signatures.length).to.equals(1)
+ expect(combined.feePayerSignatures.length).to.equals(1)
+
+ receipt = await caver.klay.sendSignedTransaction(combined.rawTransaction)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+ contractAddress = receipt.contractAddress
+ }).timeout(200000)
+ })
+
+ context('6. Send SMART_CONTRACT_EXECUTION transaction with AccountWithAccountKeyPublic', () => {
+ it('SMART_CONTRACT_EXECUTION testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'SMART_CONTRACT_EXECUTION',
+ from: account.address,
+ to: contractAddress,
+ data: '0xd14e62b80000000000000000000000000000000000000000000000000000000000000005',
+ gas: 90000,
+ }
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_EXECUTION',
+ from: account.address,
+ to: contractAddress,
+ data: '0xd14e62b80000000000000000000000000000000000000000000000000000000000000005',
+ gas: 90000,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ receipt = await caver.klay.sendTransaction({
+ senderRawTransaction: senderSigned.rawTransaction,
+ feePayer: payer.address
+ })
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_EXECUTION_WITH_RATIO',
+ from: account.address,
+ to: contractAddress,
+ data: '0xd14e62b80000000000000000000000000000000000000000000000000000000000000005',
+ gas: 90000,
+ feeRatio: 50,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ txObject.signatures = senderSigned.signatures
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, payer.feePayerKey)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+ }).timeout(200000)
+ })
+
+ context('7. Send CANCEL transaction with AccountWithAccountKeyPublic', () => {
+ it('CANCEL testing', async () => {// Send KLAY to test account
+ let txObject = {
+ type: 'CANCEL',
+ from: account.address,
+ gas: 90000,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ let receipt = await caver.klay.sendSignedTransaction(senderSigned.rawTransaction)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+
+ txObject = {
+ type: 'FEE_DELEGATED_CANCEL',
+ from: account.address,
+ gas: 90000,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ txObject.signatures = senderSigned.signatures
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ let rawTransaction = await caver.klay.accounts.getRawTransactionWithSignatures(txObject)
+
+ receipt = await caver.klay.sendSignedTransaction(rawTransaction.rawTransaction)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+
+ txObject = {
+ type: 'FEE_DELEGATED_CANCEL_WITH_RATIO',
+ from: account.address,
+ gas: 90000,
+ feeRatio: 80,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ txObject.signatures = senderSigned.signatures
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, payer.feePayerKey)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(1)
+ }).timeout(200000)
+ })
+
+ context('8. Account update with LegacyKey', () => {
+ it('Account update with legacy key testing', async () => {// Send KLAY to test account
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(account.address)
+
+ const txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 90000,
+ }
+ // The updateKey in Account is used when signing.
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+
+ // Check result of account update
+ let accountKey = await caver.klay.getAccountKey(account.address)
+ expect(accountKey.keyType).to.equals(1)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, legacyKey)
+ expect(account.privateKey).to.equals(legacyKey)
+ }).timeout(200000)
+ })
+
+ context('9. Account update with FailKey', () => {
+ it('Account update with fail key testing', async () => {// Send KLAY to test account
+ const updator = caver.klay.accounts.createAccountForUpdateWithFailKey(account.address)
+
+ const txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 90000,
+ }
+ // The updateKey in Account is used when signing.
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+
+ // Check result of account update
+ let accountKey = await caver.klay.getAccountKey(account.address)
+ expect(accountKey.keyType).to.equals(3)
+ }).timeout(200000)
+ })
+})
\ No newline at end of file
diff --git a/test/scenarioTest/accountKeyRoleBased.js b/test/scenarioTest/accountKeyRoleBased.js
new file mode 100644
index 00000000..70c02a89
--- /dev/null
+++ b/test/scenarioTest/accountKeyRoleBased.js
@@ -0,0 +1,739 @@
+/*
+ Copyright 2019 The caver-js Authors
+ This file is part of the caver-js library.
+
+ The caver-js library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ The caver-js library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the caver-js. If not, see .
+*/
+
+require('it-each')({ testPerIteration: true })
+const { expect } = require('../extendedChai')
+
+const testRPCURL = require('../testrpc')
+const Caver = require('../../index.js')
+
+let caver
+let sender, payer, account
+let contractAddress
+let legacyKey
+
+describe('Scenario test with AccountWithAccountKeyRoleBased', () => {
+ before(() => {
+ caver = new Caver(testRPCURL)
+
+ let senderPrvKey = process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
+ ? '0x' + process.env.privateKey
+ : process.env.privateKey
+
+ sender = caver.klay.accounts.wallet.add(senderPrvKey)
+ })
+
+ context('1. Prepare for testing', () => {
+ it('Create test accounts', async () => {
+ // Send KLAY to test account
+ account = caver.klay.accounts.create()
+ legacyKey = account.privateKey
+ let txObject = {
+ from: sender.address,
+ to: account.address,
+ value: caver.utils.toPeb(10, 'KLAY'),
+ gas: 900000,
+ }
+ await caver.klay.sendTransaction(txObject)
+
+ payer = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ txObject = {
+ from: sender.address,
+ to: payer.address,
+ value: caver.utils.toPeb(10, 'KLAY'),
+ gas: 900000,
+ }
+ await caver.klay.sendTransaction(txObject)
+
+ // New private key to update
+ let keyObject = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+
+ // Create an AccountForUpdate containing about the address of account and key to update
+ let roleBasedOption = {
+ transactionKey: { threshold: 2, weight: [1, 1] },
+ updateKey: { threshold: 2, weight: [1, 1, 1] },
+ feePayerKey: { threshold: 3, weight: [1, 1, 1, 1] }
+ }
+ let updator = caver.klay.accounts.createAccountForUpdate(account.address, keyObject, roleBasedOption)
+
+ // Set AccountForUpdate instance to 'key'
+ let updateTx = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ gas: 900000,
+ key: updator,
+ }
+
+ // If the account's accountKey is AccountKeyRoleBased, the privateKey privateKey is the default key with the higher priority (transactionKey-> updateKey-> feePayerKey) of the defined role keys.
+ // transactionKey, updateKey, and feePayerKey each have different keys.
+ // If the account does not exist inside the in-memory wallet, you must pass the privateKey parameter to signTransaction.
+ let signed = await caver.klay.accounts.signTransaction(updateTx, account.updateKey)
+ let receipt = await caver.klay.sendSignedTransaction(signed)
+ expect(receipt.status).to.be.true
+
+ // Check result of account update
+ let accountKey = await caver.klay.getAccountKey(account.address)
+ expect(accountKey.keyType).to.equals(5)
+
+ // Add account to in-memory wallet
+ account = caver.klay.accounts.createWithAccountKey(account.address, keyObject)
+ caver.klay.accounts.wallet.add(account)
+
+ // Get account from in-memory wallet
+ let fromWallet = caver.klay.accounts.wallet.getAccount(account.address)
+ expect(fromWallet).not.to.undefined
+
+ expect(fromWallet.address).to.equals(account.address)
+ expect(fromWallet.accountKeyType).to.equals('AccountKeyRoleBased')
+
+ expect(fromWallet.privateKey).to.equals(account.privateKey)
+ expect(fromWallet.keys.transactionKey.length).to.equals(2)
+ expect(fromWallet.keys.updateKey.length).to.equals(3)
+ expect(fromWallet.keys.feePayerKey.length).to.equals(4)
+ expect(fromWallet.transactionKey.length).to.equals(2)
+ expect(fromWallet.updateKey.length).to.equals(3)
+ expect(fromWallet.feePayerKey.length).to.equals(4)
+
+ keyObject = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ }
+
+ roleBasedOption = {
+ transactionKey: { threshold: 3, weight: [1, 1, 1, 1] },
+ updateKey: { threshold: 2, weight: [1, 1, 1] },
+ feePayerKey: { threshold: 2, weight: [1, 1] },
+ }
+
+ updator = caver.klay.accounts.createAccountForUpdate(payer.address, keyObject, roleBasedOption)
+ updateTx = {
+ type: 'ACCOUNT_UPDATE',
+ from: payer.address,
+ gas: 900000,
+ key: updator,
+ }
+ receipt = await caver.klay.sendTransaction(updateTx)
+ expect(receipt.status).to.be.true
+ payer = caver.klay.accounts.wallet.updateAccountKey(payer.address, keyObject)
+ }).timeout(200000)
+ })
+
+ context('2. Send VALUE_TRANSFER transaction with AccountWithAccountKeyRoleBased', () => {
+ it('VALUE_TRANSFER testing', async () => {
+ let txObject = {
+ type: 'VALUE_TRANSFER',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 900000,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(2)
+
+ let receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(2)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 900000,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(2)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payer.address, payer.feePayerKey[0])
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+ let feePayerSigned2 = await caver.klay.accounts.feePayerSignTransaction(feePayerSigned.rawTransaction, payer.address, payer.feePayerKey[1])
+ expect(feePayerSigned2.feePayerSignatures.length).to.equals(2)
+
+ receipt = await caver.klay.sendSignedTransaction(feePayerSigned2)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(2)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER_WITH_RATIO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 900000,
+ feeRatio: 50,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(2)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payer.address, payer.feePayerKey[0])
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ feePayerSigned2 = await caver.klay.accounts.feePayerSignTransaction(feePayerSigned.rawTransaction, payer.address, payer.feePayerKey[1])
+ expect(feePayerSigned2.feePayerSignatures.length).to.equals(2)
+
+ receipt = await caver.klay.sendSignedTransaction(feePayerSigned2)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(2)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+ }).timeout(200000)
+ })
+
+ context('3. Send VALUE_TRANSFER_MEMO transaction with AccountWithAccountKeyRoleBased', () => {
+ it('VALUE_TRANSFER_MEMO testing', async () => {
+ let txObject = {
+ type: 'VALUE_TRANSFER_MEMO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ data: 'value transfer memo',
+ gas: 90000,
+ }
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(2)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER_MEMO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ data: 'value transfer memo',
+ gas: 90000,
+ }
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(2)
+
+ let senderSigned = await caver.klay.accounts.signTransaction(feePayerSigned.rawTransaction, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(2)
+
+ receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(2)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER_MEMO_WITH_RATIO',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ data: 'value transfer memo',
+ gas: 90000,
+ feeRatio: 10,
+ }
+ // Sign transaction with sender
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(2)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, [payer.feePayerKey[0], payer.feePayerKey[1]])
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(2)
+
+ txObject.signatures = senderSigned.signatures
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ receipt = await caver.klay.sendSignedTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(2)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+ }).timeout(200000)
+ })
+
+ context('4. Send ACCOUNT_UPDATE transaction with AccountWithAccountKeyRoleBased', () => {
+ it('ACCOUNT_UPDATE testing', async () => {
+ // Update AccountKeyRoleBased -> AccountKeyPublic
+ let newKey = caver.klay.accounts.create().privateKey
+ let newPublicKey = caver.klay.accounts.privateKeyToPublicKey(newKey)
+ let updator = caver.klay.accounts.createAccountForUpdateWithPublicKey(account.address, newPublicKey)
+
+ let txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 900000,
+ }
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
+
+ // Update AccountKeyPublic -> AccountKeyMultiSig
+ newKey = [
+ caver.klay.accounts.create().privateKey,
+ caver.klay.accounts.create().privateKey,
+ caver.klay.accounts.create().privateKey,
+ caver.klay.accounts.create().privateKey,
+ caver.klay.accounts.create().privateKey
+ ]
+ let options = { threshold: 4, weight: [1, 1, 1, 1, 1] }
+ updator = caver.klay.accounts.createAccountForUpdate(account.address, newKey, options)
+
+ txObject = {
+ type: 'FEE_DELEGATED_ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 900000,
+ }
+
+ // Sign transaction with sender
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.updateKey)
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payer.address, [payer.feePayerKey[0]])
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+ let feePayerSigned2 = await caver.klay.accounts.feePayerSignTransaction(feePayerSigned.rawTransaction, payer.address, payer.feePayerKey)
+ expect(feePayerSigned2.feePayerSignatures.length).to.equals(2)
+
+ let combined = await caver.klay.accounts.combineSignatures([senderSigned.rawTransaction, feePayerSigned.rawTransaction, feePayerSigned2.rawTransaction])
+ expect(combined.signatures.length).to.equals(1)
+ expect(combined.feePayerSignatures.length).to.equals(2)
+
+ receipt = await caver.klay.sendSignedTransaction(combined)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(1)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
+
+ // Update AccountKeyMultiSig -> AccountKeyRoleBased
+ newKey = {
+ transactionKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ updateKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ feePayerKey: [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey],
+ }
+ options = {
+ transactionKey: { threshold: 3, weight: [2, 1, 2] },
+ updateKey: { threshold: 6, weight: [1, 2, 3, 4] },
+ feePayerKey: { threshold: 1, weight: [1, 1] }
+ }
+ updator = caver.klay.accounts.createAccountForUpdate(account.address, newKey, options)
+
+ txObject = {
+ type: 'FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO',
+ from: account.address,
+ key: updator,
+ gas: 900000,
+ feeRatio: 30,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.updateKey)
+ expect(senderSigned.signatures.length).to.equals(5)
+
+ let senderSigned2 = await caver.klay.accounts.signTransaction(txObject, [account.updateKey[0], account.updateKey[1]])
+ expect(senderSigned2.signatures.length).to.equals(2)
+
+ combined = await caver.klay.accounts.combineSignatures([senderSigned.rawTransaction, senderSigned2.rawTransaction])
+ expect(combined.signatures.length).to.equals(5)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(combined.rawTransaction, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(2)
+
+ combined = await caver.klay.accounts.combineSignatures([combined.rawTransaction, feePayerSigned.rawTransaction])
+ expect(combined.signatures.length).to.equals(5)
+ expect(combined.feePayerSignatures.length).to.equals(2)
+
+ receipt = await caver.klay.sendSignedTransaction(combined)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(5)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
+
+ // Update AccountKeyRoleBased -> AccountKeyRoleBased
+ newKey = {
+ updateKey: [
+ caver.klay.accounts.create().privateKey,
+ caver.klay.accounts.create().privateKey,
+ caver.klay.accounts.create().privateKey,
+ caver.klay.accounts.create().privateKey,
+ caver.klay.accounts.create().privateKey
+ ]
+ }
+ options = { updateKey: { threshold: 4, weight: [1, 1, 1, 1, 1] } }
+ updator = caver.klay.accounts.createAccountForUpdate(account.address, newKey, options)
+
+ txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 900000,
+ }
+ receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(4)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, newKey)
+ }).timeout(200000)
+ })
+
+ context('5. Send SMART_CONTRACT_DEPLOY transaction with AccountWithAccountKeyRoleBased', () => {
+ it('SMART_CONTRACT_DEPLOY testing', async () => {
+ let txObject = {
+ type: 'SMART_CONTRACT_DEPLOY',
+ from: account.address,
+ data: '0x60806040526000805534801561001457600080fd5b5060405161016f38038061016f8339810180604052810190808051906020019092919080518201929190505050816000819055505050610116806100596000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60d2565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260d8565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060d06004803603810190808035906020019092919050505060e0565b005b60005481565b600043905090565b80600081905550505600a165627a7a723058206d2bc553736581b6387f9a0410856ca490fcdc7045a8991ad63a1fd71b651c3a00290000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000',
+ gas: 900000,
+ value: 0,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ senderSigned = await caver.klay.accounts.signTransaction(senderSigned.rawTransaction, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ let receipt = await caver.klay.sendSignedTransaction(senderSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_DEPLOY',
+ from: account.address,
+ data: '0x60806040526000805534801561001457600080fd5b5060405161016f38038061016f8339810180604052810190808051906020019092919080518201929190505050816000819055505050610116806100596000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60d2565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260d8565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060d06004803603810190808035906020019092919050505060e0565b005b60005481565b600043905090565b80600081905550505600a165627a7a723058206d2bc553736581b6387f9a0410856ca490fcdc7045a8991ad63a1fd71b651c3a00290000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000',
+ gas: 900000,
+ value: 0,
+ }
+
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[0], account.transactionKey[1]])
+ expect(senderSigned.signatures.length).to.equals(2)
+
+ let senderSigned2 = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[1], account.transactionKey[2]])
+ expect(senderSigned2.signatures.length).to.equals(2)
+
+ txObject.signatures = senderSigned.signatures.concat(senderSigned2.signatures)
+
+ let rawTransaction = await caver.klay.accounts.getRawTransactionWithSignatures(txObject)
+ expect(rawTransaction.signatures.length).to.equals(3)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction.rawTransaction, payer.address, payer.feePayerKey)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(2)
+
+ receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_DEPLOY_WITH_RATIO',
+ from: account.address,
+ data: '0x60806040526000805534801561001457600080fd5b5060405161016f38038061016f8339810180604052810190808051906020019092919080518201929190505050816000819055505050610116806100596000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14605857806342cbb15c146080578063d14e62b81460a8575b600080fd5b348015606357600080fd5b50606a60d2565b6040518082815260200191505060405180910390f35b348015608b57600080fd5b50609260d8565b6040518082815260200191505060405180910390f35b34801560b357600080fd5b5060d06004803603810190808035906020019092919050505060e0565b005b60005481565b600043905090565b80600081905550505600a165627a7a723058206d2bc553736581b6387f9a0410856ca490fcdc7045a8991ad63a1fd71b651c3a00290000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000',
+ gas: 900000,
+ value: 0,
+ feeRatio: 30,
+ }
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, payer.feePayerKey[0])
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(1)
+
+ let feePayerSigned2 = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address, payer.feePayerKey[1])
+ expect(feePayerSigned2.feePayerSignatures.length).to.equals(1)
+
+ senderSigned = await caver.klay.accounts.signTransaction(feePayerSigned.rawTransaction, [account.transactionKey[0], account.transactionKey[1]])
+ expect(senderSigned.signatures.length).to.equals(2)
+
+ senderSigned2 = await caver.klay.accounts.signTransaction(feePayerSigned2.rawTransaction, [account.transactionKey[1], account.transactionKey[2]])
+ expect(senderSigned2.signatures.length).to.equals(2)
+
+ let combined = await caver.klay.accounts.combineSignatures([senderSigned.rawTransaction, senderSigned2.rawTransaction])
+ expect(combined.signatures.length).to.equals(3)
+ expect(combined.feePayerSignatures.length).to.equals(2)
+
+ receipt = await caver.klay.sendSignedTransaction(combined)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+
+ contractAddress = receipt.contractAddress
+ }).timeout(200000)
+ })
+
+ context('6. Send SMART_CONTRACT_EXECUTION transaction with AccountWithAccountKeyRoleBased', () => {
+ it('SMART_CONTRACT_EXECUTION testing', async () => {
+ let txObject = {
+ type: 'SMART_CONTRACT_EXECUTION',
+ from: account.address,
+ to: contractAddress,
+ data: '0xd14e62b80000000000000000000000000000000000000000000000000000000000000005',
+ gas: 900000,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ txObject.signatures = senderSigned.signatures
+
+ let receipt = await caver.klay.sendSignedTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_EXECUTION',
+ from: account.address,
+ to: contractAddress,
+ data: '0xd14e62b80000000000000000000000000000000000000000000000000000000000000005',
+ gas: 900000,
+ }
+ // Sign transaction with sender
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey[0])
+ expect(senderSigned.signatures.length).to.equals(1)
+
+ senderSigned = await caver.klay.accounts.signTransaction(senderSigned.rawTransaction, [account.transactionKey[1], account.transactionKey[2]])
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ // Set signatures to transaction object
+ txObject.signatures = senderSigned.signatures
+
+ let senderRaw = await caver.klay.accounts.getRawTransactionWithSignatures(txObject)
+
+ // Send transaction object with signatures through sendSignedTransaction
+ receipt = await caver.klay.sendTransaction({
+ senderRawTransaction: senderRaw.rawTransaction,
+ feePayer: payer.address
+ })
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+
+ txObject = {
+ type: 'FEE_DELEGATED_SMART_CONTRACT_EXECUTION_WITH_RATIO',
+ from: account.address,
+ to: contractAddress,
+ data: '0xd14e62b80000000000000000000000000000000000000000000000000000000000000005',
+ gas: 900000,
+ feeRatio: 50,
+ }
+
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(2)
+
+ txObject.signatures = senderSigned.signatures
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ receipt = await caver.klay.sendSignedTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+ }).timeout(200000)
+ })
+
+ context('7. Send CANCEL transaction with AccountWithAccountKeyRoleBased', () => {
+ it('CANCEL testing', async () => {
+ let txObject = {
+ type: 'CANCEL',
+ from: account.address,
+ gas: 90000,
+ }
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+
+ txObject = {
+ type: 'FEE_DELEGATED_CANCEL',
+ from: account.address,
+ gas: 900000,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[0], account.transactionKey[2]])
+ expect(senderSigned.signatures.length).to.equals(2)
+
+ let senderSigned2 = await caver.klay.accounts.signTransaction(txObject, [account.transactionKey[0], account.transactionKey[1]])
+ expect(senderSigned2.signatures.length).to.equals(2)
+
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned2.rawTransaction, payer.address, [payer.feePayerKey[0], payer.feePayerKey[1]])
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(2)
+
+ let combined = await caver.klay.accounts.combineSignatures([senderSigned.rawTransaction, senderSigned2.rawTransaction, feePayerSigned.rawTransaction])
+ expect(combined.signatures.length).to.equals(3)
+ expect(combined.feePayerSignatures.length).to.equals(2)
+
+ receipt = await caver.klay.sendSignedTransaction(combined)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+
+ txObject = {
+ type: 'FEE_DELEGATED_CANCEL_WITH_RATIO',
+ from: account.address,
+ gas: 900000,
+ feeRatio: 50,
+ }
+ senderSigned = await caver.klay.accounts.signTransaction(txObject)
+ expect(senderSigned.signatures.length).to.equals(3)
+
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObject, payer.address)
+ expect(feePayerSigned.feePayerSignatures.length).to.equals(2)
+
+ txObject.signatures = senderSigned.signatures
+ txObject.feePayer = payer.address
+ txObject.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ let rawTransaction = await caver.klay.accounts.getRawTransactionWithSignatures(txObject)
+
+ receipt = await caver.klay.sendSignedTransaction(rawTransaction.rawTransaction)
+ expect(receipt.status).to.be.true
+ expect(receipt.signatures.length).to.equals(3)
+ expect(receipt.feePayerSignatures.length).to.equals(2)
+ }).timeout(200000)
+ })
+
+ context('8. Send a transaction to the network with invalid role', () => {
+ it('invalid role signed testing', async () => {
+ let txObject = {
+ type: 'VALUE_TRANSFER',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 900000,
+ }
+ let senderSigned = await caver.klay.accounts.signTransaction(txObject, account.updateKey)
+
+ let expectedError = 'invalid transaction v, r, s values of the sender'
+
+ try {
+ await caver.klay.sendSignedTransaction(senderSigned)
+ } catch (e) { expect(e.message).to.include(expectedError) }
+
+ // insufficient weight
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey[0])
+
+ try {
+ await caver.klay.sendSignedTransaction(senderSigned)
+ } catch (e) { expect(e.message).to.include(expectedError) }
+
+ txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: caver.klay.accounts.createAccountForUpdateWithLegacyKey(account.address),
+ gas: 900000,
+ }
+
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+
+ try {
+ await caver.klay.sendSignedTransaction(senderSigned)
+ } catch (e) { expect(e.message).to.include(expectedError) }
+
+ // insufficient weight
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.updateKey[0])
+
+ try {
+ await caver.klay.sendSignedTransaction(senderSigned)
+ } catch (e) { expect(e.message).to.include(expectedError) }
+
+ txObject = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: account.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 900000,
+ }
+
+ senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey)
+ let feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payer.address, payer.transactionKey)
+
+ expectedError = 'invalid fee payer'
+
+ try {
+ await caver.klay.sendSignedTransaction(feePayerSigned)
+ } catch (e) { expect(e.message).to.include(expectedError) }
+
+ // insufficient weight
+ feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payer.address, payer.feePayerKey[0])
+
+ try {
+ await caver.klay.sendSignedTransaction(feePayerSigned)
+ } catch (e) { expect(e.message).to.include(expectedError) }
+
+ }).timeout(200000)
+ })
+
+ context('9. Account update with RoleBased with legacyKey and failKey', () => {
+ it('Account update with roleBased with legacy key and fail key testing', async () => {
+ const keyObject = {
+ transactionKey: 'legacyKey',
+ feePayerKey: 'failKey'
+ }
+ const updator = caver.klay.accounts.createAccountForUpdate(account.address, keyObject)
+
+ const txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 90000,
+ }
+ // The updateKey in Account is used when signing.
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+
+ // Check result of account update
+ let accountKey = await caver.klay.getAccountKey(account.address)
+ expect(accountKey.keyType).to.equals(5)
+ expect(accountKey.key[0].keyType).to.equals(1)
+ expect(accountKey.key[1].keyType).to.equals(4)
+ expect(accountKey.key[2].keyType).to.equals(3)
+ }).timeout(200000)
+ })
+
+ context('10. Account update with LegacyKey', () => {
+ it('Account update with legacy key testing', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(account.address)
+
+ const txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 90000,
+ }
+ // The updateKey in Account is used when signing.
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+
+ // Check result of account update
+ let accountKey = await caver.klay.getAccountKey(account.address)
+ expect(accountKey.keyType).to.equals(1)
+
+ account = caver.klay.accounts.wallet.updateAccountKey(account.address, legacyKey)
+ expect(account.privateKey).to.equals(legacyKey)
+ }).timeout(200000)
+ })
+
+ context('11. Account update with FailKey', () => {
+ it('Account update with fail key testing', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithFailKey(account.address)
+
+ const txObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: account.address,
+ key: updator,
+ gas: 90000,
+ }
+ // The updateKey in Account is used when signing.
+ let receipt = await caver.klay.sendTransaction(txObject)
+ expect(receipt.status).to.be.true
+
+ // Check result of account update
+ let accountKey = await caver.klay.getAccountKey(account.address)
+ expect(accountKey.keyType).to.equals(3)
+ }).timeout(200000)
+ })
+})
\ No newline at end of file
diff --git a/test/sendSignedTransaction.js b/test/sendSignedTransaction.js
index bd1a664a..966d86df 100644
--- a/test/sendSignedTransaction.js
+++ b/test/sendSignedTransaction.js
@@ -22,24 +22,27 @@ const testRPCURL = require('./testrpc')
var Caver = require('../index.js')
const caver = new Caver(testRPCURL)
-var senderPrvKey
-var senderAddress
+var senderPrvKey, payerPrvKey
+var senderAddress, payerAddress
var receiver
before(() => {
- senderPrvKey = process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
+ senderPrvKey = process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
? '0x' + process.env.privateKey
: process.env.privateKey
+ payerPrvKey = process.env.privateKey2 && String(process.env.privateKey2).indexOf('0x') === -1
+ ? '0x' + process.env.privateKey2
+ : process.env.privateKey2
- caver.klay.accounts.wallet.add(senderPrvKey)
+ const sender = caver.klay.accounts.wallet.add(senderPrvKey)
+ senderAddress = sender.address
+ const payer = caver.klay.accounts.wallet.add(payerPrvKey)
+ payerAddress = payer.address
- const sender = caver.klay.accounts.privateKeyToAccount(senderPrvKey)
- senderAddress = sender.address
-
- receiver = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ receiver = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
})
-describe('caver.klay.sendSignedTransaction', (done) => {
+describe('CAVERJS-UNIT-TX-581: caver.klay.sendSignedTransaction with valid non fee delegated transaction raw string', () => {
it('should send successfully with valid rawTransaction', async () => {
const txObj = {
from: senderAddress,
@@ -52,23 +55,167 @@ describe('caver.klay.sendSignedTransaction', (done) => {
const receipt = await caver.klay.sendSignedTransaction(rawTransaction)
expect(receipt).not.to.null
- expect(receipt.blockHash).not.to.undefined
- expect(receipt.blockNumber).not.to.undefined
- expect(receipt.contractAddress).not.to.undefined
- expect(receipt.from).not.to.undefined
- expect(receipt.gas).not.to.undefined
- expect(receipt.gasPrice).not.to.undefined
- expect(receipt.gasUsed).not.to.undefined
- expect(receipt.logs).not.to.undefined
- expect(receipt.logsBloom).not.to.undefined
- expect(receipt.nonce).not.to.undefined
- expect(receipt.signatures).not.to.undefined
- expect(receipt.status).equals(true)
- expect(receipt.to).not.to.undefined
- expect(receipt.transactionHash).not.to.undefined
- expect(receipt.transactionIndex).not.to.undefined
- expect(receipt.type).not.to.undefined
- expect(receipt.typeInt).not.to.undefined
- expect(receipt.value).not.to.undefined
+
+ const keys = ['blockHash', 'blockNumber', 'contractAddress', 'from', 'gas', 'gasPrice', 'gasUsed', 'input', 'logs', 'logsBloom', 'nonce', 'senderTxHash', 'signatures', 'status', 'to', 'transactionHash', 'transactionIndex', 'type', 'typeInt', 'value']
+ expect(Object.getOwnPropertyNames(receipt)).to.deep.equal(keys)
+
+ expect(receipt.status).to.equals(true)
+ expect(receipt.senderTxHash).to.equals(receipt.transactionHash)
+ }).timeout(100000)
+})
+
+describe('CAVERJS-UNIT-TX-582: caver.klay.sendSignedTransaction with valid fee delegated transaction raw string', () => {
+ it('should send successfully with valid rawTransaction', async () => {
+ const txObj = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: senderAddress,
+ to: receiver.address,
+ value: 1,
+ gas: 900000,
+ }
+
+ const senderSigned = await caver.klay.accounts.signTransaction(txObj)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned.rawTransaction)
+
+ expect(receipt).not.to.null
+
+ const keys = ['blockHash', 'blockNumber', 'contractAddress', 'feePayer', 'feePayerSignatures', 'from', 'gas', 'gasPrice', 'gasUsed', 'logs', 'logsBloom', 'nonce', 'senderTxHash', 'signatures', 'status', 'to', 'transactionHash', 'transactionIndex', 'type', 'typeInt', 'value']
+ expect(Object.getOwnPropertyNames(receipt)).to.deep.equal(keys)
+
+ expect(receipt.status).to.equals(true)
+ expect(receipt.senderTxHash).not.to.equals(receipt.transactionHash)
+ }).timeout(100000)
+})
+
+describe('CAVERJS-UNIT-TX-583: caver.klay.sendSignedTransaction with object which has non fee delegated transaction raw string', () => {
+ it('should send successfully with valid rawTransaction', async () => {
+ const txObj = {
+ from: senderAddress,
+ to: receiver.address,
+ value: 1,
+ gas: 900000,
+ }
+
+ const senderSigned = await caver.klay.accounts.signTransaction(txObj, senderPrvKey)
+ const receipt = await caver.klay.sendSignedTransaction(senderSigned)
+
+ expect(receipt).not.to.null
+
+ const keys = ['blockHash', 'blockNumber', 'contractAddress', 'from', 'gas', 'gasPrice', 'gasUsed', 'input', 'logs', 'logsBloom', 'nonce', 'senderTxHash', 'signatures', 'status', 'to', 'transactionHash', 'transactionIndex', 'type', 'typeInt', 'value']
+ expect(Object.getOwnPropertyNames(receipt)).to.deep.equal(keys)
+
+ expect(receipt.status).to.equals(true)
+ expect(receipt.senderTxHash).to.equals(receipt.transactionHash)
+ }).timeout(100000)
+})
+
+describe('CAVERJS-UNIT-TX-584: caver.klay.sendSignedTransaction with object which has fee delegated transaction raw string', () => {
+ it('should send successfully with valid rawTransaction', async () => {
+ const txObj = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: senderAddress,
+ to: receiver.address,
+ value: 1,
+ gas: 900000,
+ }
+
+ const senderSigned = await caver.klay.accounts.signTransaction(txObj)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+
+ expect(receipt).not.to.null
+
+ const keys = ['blockHash', 'blockNumber', 'contractAddress', 'feePayer', 'feePayerSignatures', 'from', 'gas', 'gasPrice', 'gasUsed', 'logs', 'logsBloom', 'nonce', 'senderTxHash', 'signatures', 'status', 'to', 'transactionHash', 'transactionIndex', 'type', 'typeInt', 'value']
+ expect(Object.getOwnPropertyNames(receipt)).to.deep.equal(keys)
+
+ expect(receipt.status).to.equals(true)
+ expect(receipt.senderTxHash).not.to.equals(receipt.transactionHash)
}).timeout(100000)
})
+
+describe('CAVERJS-UNIT-TX-585: caver.klay.sendSignedTransaction with transaction object which defines signatures', () => {
+ it('should send successfully with valid rawTransaction', async () => {
+ const txObj = {
+ from: senderAddress,
+ to: receiver.address,
+ value: 1,
+ gas: 900000,
+ }
+
+ const senderSigned = await caver.klay.accounts.signTransaction(txObj, senderPrvKey)
+ txObj.signatures = senderSigned.signatures
+
+ const receipt = await caver.klay.sendSignedTransaction(txObj)
+
+ expect(receipt).not.to.null
+
+ const keys = ['blockHash', 'blockNumber', 'contractAddress', 'from', 'gas', 'gasPrice', 'gasUsed', 'input', 'logs', 'logsBloom', 'nonce', 'senderTxHash', 'signatures', 'status', 'to', 'transactionHash', 'transactionIndex', 'type', 'typeInt', 'value']
+ expect(Object.getOwnPropertyNames(receipt)).to.deep.equal(keys)
+
+ expect(receipt.status).to.equals(true)
+ expect(receipt.senderTxHash).to.equals(receipt.transactionHash)
+ }).timeout(100000)
+})
+
+describe('CAVERJS-UNIT-TX-586: caver.klay.sendSignedTransaction with transaction object which defines signatures and feePayerSignatrues', () => {
+ it('should send successfully with valid rawTransaction', async () => {
+ const txObj = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: senderAddress,
+ to: receiver.address,
+ value: 1,
+ gas: 900000,
+ }
+
+ const senderSigned = await caver.klay.accounts.signTransaction(txObj)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(txObj, payerAddress)
+
+ txObj.signatures = senderSigned.signatures
+ txObj.feePayer = payerAddress
+ txObj.feePayerSignatures = feePayerSigned.feePayerSignatures
+
+ const receipt = await caver.klay.sendSignedTransaction(txObj)
+
+ expect(receipt).not.to.null
+
+ const keys = ['blockHash', 'blockNumber', 'contractAddress', 'feePayer', 'feePayerSignatures', 'from', 'gas', 'gasPrice', 'gasUsed', 'logs', 'logsBloom', 'nonce', 'senderTxHash', 'signatures', 'status', 'to', 'transactionHash', 'transactionIndex', 'type', 'typeInt', 'value']
+ expect(Object.getOwnPropertyNames(receipt)).to.deep.equal(keys)
+
+ expect(receipt.status).to.equals(true)
+ expect(receipt.senderTxHash).not.to.equals(receipt.transactionHash)
+ }).timeout(100000)
+})
+
+describe('CAVERJS-UNIT-TX-587: caver.klay.sendSignedTransaction with fee payer transaction object which defines feePayerSignatrues', () => {
+ it('should send successfully with valid rawTransaction', async () => {
+ const txObj = {
+ type: 'FEE_DELEGATED_VALUE_TRANSFER',
+ from: senderAddress,
+ to: receiver.address,
+ value: 1,
+ gas: 900000,
+ }
+
+ const senderSigned = await caver.klay.accounts.signTransaction(txObj)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(senderSigned.rawTransaction, payerAddress)
+
+ const feePayerTx = {
+ senderRawTransaction: senderSigned.rawTransaction,
+ feePayer: payerAddress,
+ feePayerSignatures: feePayerSigned.feePayerSignatures
+ }
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerTx)
+
+ expect(receipt).not.to.null
+
+ const keys = ['blockHash', 'blockNumber', 'contractAddress', 'feePayer', 'feePayerSignatures', 'from', 'gas', 'gasPrice', 'gasUsed', 'logs', 'logsBloom', 'nonce', 'senderTxHash', 'signatures', 'status', 'to', 'transactionHash', 'transactionIndex', 'type', 'typeInt', 'value']
+ expect(Object.getOwnPropertyNames(receipt)).to.deep.equal(keys)
+
+ expect(receipt.status).to.equals(true)
+ expect(receipt.senderTxHash).not.to.equals(receipt.transactionHash)
+ }).timeout(100000)
+})
\ No newline at end of file
diff --git a/test/sendTransactionCallback.js b/test/sendTransactionCallback.js
new file mode 100644
index 00000000..84afc162
--- /dev/null
+++ b/test/sendTransactionCallback.js
@@ -0,0 +1,75 @@
+/*
+ Copyright 2019 The caver-js Authors
+ This file is part of the caver-js library.
+
+ The caver-js library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ The caver-js library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the caver-js. If not, see .
+*/
+
+const { expect } = require('chai')
+const assert = require('assert')
+
+var Caver = require('../index.js')
+const testRPCURL = require('./testrpc')
+const caver = new Caver(testRPCURL)
+
+var senderPrvKey, senderAddress
+var receiver
+
+before(() => {
+ senderPrvKey = process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
+ ? '0x' + process.env.privateKey
+ : process.env.privateKey
+
+ const sender = caver.klay.accounts.wallet.add(senderPrvKey)
+ senderAddress = sender.address
+
+ receiver = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+})
+
+describe('sendTransaction with callback', () => {
+ it('CAVERJS-UNIT-TX-574: sendTransaction should only call callback once with the transaction hash', async () => {
+ const txObj = {
+ from: senderAddress,
+ to: receiver.address,
+ value: 1,
+ gas: 900000,
+ }
+ await caver.klay.sendTransaction(txObj, (error, result) => {
+ expect(error).to.be.null
+ expect(typeof result).to.be.equals('string')
+ })
+ }).timeout(100000)
+
+ it('CAVERJS-UNIT-TX-575: sendTransaction should call callback with error when error is occured during signTransaction', async () => {
+ // When try account update with invalid publicKey, error is occured during signTransaction
+ let e
+ const txObj = {
+ type: 'ACCOUNT_UPDATE',
+ from: senderAddress,
+ publicKey : caver.utils.randomHex(63),
+ gas: 900000,
+ }
+
+ try {
+ await caver.klay.sendTransaction(txObj, (error, result) => {
+ e = error.message
+ expect(error).not.to.be.null
+ expect(result).to.be.undefined
+ })
+ assert(false)
+ } catch(error) {
+ expect(error.message).to.equals(e)
+ }
+ }).timeout(100000)
+})
\ No newline at end of file
diff --git a/test/setProvider.js b/test/setProvider.js
new file mode 100644
index 00000000..ba4ddfed
--- /dev/null
+++ b/test/setProvider.js
@@ -0,0 +1,112 @@
+/*
+ Copyright 2019 The caver-js Authors
+ This file is part of the caver-js library.
+
+ The caver-js library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ The caver-js library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the caver-js. If not, see .
+*/
+
+const Caver = require('../index')
+const { expect } = require('./extendedChai')
+
+const baobabHost = 'https://api.baobab.klaytn.net:8651/'
+const cypressHost = 'https://api.cypress.klaytn.net:8651/'
+const baobabProvider = new Caver.providers.HttpProvider(baobabHost)
+const cypressProvider = new Caver.providers.HttpProvider(cypressHost)
+
+describe('Test setProvider', () => {
+ it('CAVERJS-UNIT-ETC-166: If provider is not set, currentProvider must be null.', () => {
+ const caver = new Caver()
+
+ expect(caver.klay.currentProvider).to.be.null
+ expect(caver.klay.net.currentProvider).to.be.null
+ expect(caver.klay.personal.currentProvider).to.be.null
+ expect(caver.klay.Contract.currentProvider).to.be.null
+ expect(caver.klay.accounts.currentProvider).to.be.null
+ }).timeout(10000)
+
+ it('CAVERJS-UNIT-ETC-167: When passing host information as a parameter through a Caver contructor, the provider must be set.', () => {
+ const caver = new Caver(baobabHost)
+
+ expect(caver.klay.currentProvider).not.to.be.null
+ expect(caver.klay.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.net.currentProvider).not.to.be.null
+ expect(caver.klay.net.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.personal.currentProvider).not.to.be.null
+ expect(caver.klay.personal.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.Contract.currentProvider).not.to.be.null
+ expect(caver.klay.Contract.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.accounts.currentProvider).not.to.be.null
+ expect(caver.klay.accounts.currentProvider.host).to.equals(baobabHost)
+ }).timeout(10000)
+
+ it('CAVERJS-UNIT-ETC-168: When passing provider as a parameter through a Caver contructor, the provider must be set.', () => {
+ const caver = new Caver(baobabProvider)
+
+ expect(caver.klay.currentProvider).not.to.be.null
+ expect(caver.klay.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.net.currentProvider).not.to.be.null
+ expect(caver.klay.net.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.personal.currentProvider).not.to.be.null
+ expect(caver.klay.personal.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.Contract.currentProvider).not.to.be.null
+ expect(caver.klay.Contract.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.accounts.currentProvider).not.to.be.null
+ expect(caver.klay.accounts.currentProvider.host).to.equals(baobabHost)
+ }).timeout(10000)
+
+ it('CAVERJS-UNIT-ETC-169: When setting a provider with setProvider function, the currentProvider must be set appropriately.', () => {
+ const caver = new Caver()
+ caver.klay.setProvider(baobabProvider)
+
+ expect(caver.klay.currentProvider).not.to.be.null
+ expect(caver.klay.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.net.currentProvider).not.to.be.null
+ expect(caver.klay.net.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.personal.currentProvider).not.to.be.null
+ expect(caver.klay.personal.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.Contract.currentProvider).not.to.be.null
+ expect(caver.klay.Contract.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.accounts.currentProvider).not.to.be.null
+ expect(caver.klay.accounts.currentProvider.host).to.equals(baobabHost)
+ }).timeout(10000)
+
+ it('CAVERJS-UNIT-ETC-170: If provider is set already, currentProvider must change when new provider is set with setProvider function.', () => {
+ const caver = new Caver()
+ caver.klay.setProvider(baobabProvider)
+
+ expect(caver.klay.currentProvider).not.to.be.null
+ expect(caver.klay.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.net.currentProvider).not.to.be.null
+ expect(caver.klay.net.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.personal.currentProvider).not.to.be.null
+ expect(caver.klay.personal.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.Contract.currentProvider).not.to.be.null
+ expect(caver.klay.Contract.currentProvider.host).to.equals(baobabHost)
+ expect(caver.klay.accounts.currentProvider).not.to.be.null
+ expect(caver.klay.accounts.currentProvider.host).to.equals(baobabHost)
+
+ caver.klay.setProvider(cypressProvider)
+
+ expect(caver.klay.currentProvider).not.to.be.null
+ expect(caver.klay.currentProvider.host).to.equals(cypressHost)
+ expect(caver.klay.net.currentProvider).not.to.be.null
+ expect(caver.klay.net.currentProvider.host).to.equals(cypressHost)
+ expect(caver.klay.personal.currentProvider).not.to.be.null
+ expect(caver.klay.personal.currentProvider.host).to.equals(cypressHost)
+ expect(caver.klay.Contract.currentProvider).not.to.be.null
+ expect(caver.klay.Contract.currentProvider.host).to.equals(cypressHost)
+ expect(caver.klay.accounts.currentProvider).not.to.be.null
+ expect(caver.klay.accounts.currentProvider.host).to.equals(cypressHost)
+ }).timeout(10000)
+})
\ No newline at end of file
diff --git a/test/signWithMultiSig.js b/test/signWithMultiSig.js
new file mode 100644
index 00000000..b0e4974d
--- /dev/null
+++ b/test/signWithMultiSig.js
@@ -0,0 +1,90 @@
+/*
+ Copyright 2019 The caver-js Authors
+ This file is part of the caver-js library.
+
+ The caver-js library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ The caver-js library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the caver-js. If not, see .
+*/
+
+const { expect } = require('chai')
+
+const Caver = require('../index.js')
+const testRPCURL = require('./testrpc')
+const caver = new Caver(testRPCURL)
+
+let sender
+let multiSigAccount, multiSigKeys
+
+let createMultiSigAccount = async () => {
+ multiSigAccount = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
+ multiSigKeys = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+
+ const txObject = {
+ from: sender.address,
+ to: multiSigAccount.address,
+ value: caver.utils.toPeb(10, 'KLAY'),
+ gas: 900000,
+ }
+
+ await caver.klay.sendTransaction(txObject)
+
+ // account update transaction object
+ const accountUpdateObject = {
+ type: 'ACCOUNT_UPDATE',
+ from: multiSigAccount.address,
+ multisig: {
+ threshold: 2,
+ keys: [
+ { weight: 1, publicKey: caver.klay.accounts.privateKeyToPublicKey(multiSigKeys[0]) },
+ { weight: 1, publicKey: caver.klay.accounts.privateKeyToPublicKey(multiSigKeys[1]) },
+ { weight: 1, publicKey: caver.klay.accounts.privateKeyToPublicKey(multiSigKeys[2]) },
+ ],
+ },
+ gas: 900000,
+ }
+
+ return caver.klay.sendTransaction(accountUpdateObject)
+}
+
+before(function (done) {
+ this.timeout(200000)
+
+ let senderPrvKey = process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
+ ? '0x' + process.env.privateKey
+ : process.env.privateKey
+
+ sender = caver.klay.accounts.wallet.add(senderPrvKey)
+
+ createMultiSigAccount().then(() => done())
+})
+
+describe('sign transaction with multi sig account key', () => {
+ it('CAVERJS-UNIT-TX-576 : signTransaction method should sign with private key array correctly', async () => {
+ const accountKey = await caver.klay.getAccountKey(multiSigAccount.address)
+ expect(accountKey.keyType).to.equals(4)
+ expect(accountKey.key.threshold).to.equals(2)
+
+ const txObj = {
+ type: 'VALUE_TRANSFER',
+ from: multiSigAccount.address,
+ to: caver.klay.accounts.create().address,
+ value: 1,
+ gas: 900000,
+ }
+ const result = await caver.klay.accounts.signTransaction(txObj, multiSigKeys)
+
+ const tx = await caver.klay.sendSignedTransaction(result.rawTransaction)
+
+ expect(tx.signatures.length).to.equals(multiSigKeys.length)
+ }).timeout(100000)
+})
\ No newline at end of file
diff --git a/test/transactionType/accountUpdate.js b/test/transactionType/accountUpdate.js
index 2d369c29..d365b66b 100644
--- a/test/transactionType/accountUpdate.js
+++ b/test/transactionType/accountUpdate.js
@@ -1574,4 +1574,234 @@ describe('ACCOUNT_UPDATE transaction', () => {
// Throw error from formatter validation
expect(()=> caver.klay.sendTransaction(tx)).to.throws('The key parameter to be used for ACCOUNT_UPDATE is duplicated.')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-588: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-588: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // UnnecessaryFeePayerSignatures
+ it('CAVERJS-UNIT-TX-589: If transaction object has unnecessary feePayerSignatures, signTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey, feePayerSignatures: [['0x01', '0x', '0x']]}, accountUpdateObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-589: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const tx = Object.assign({publicKey, feePayerSignatures: [['0x01', '0x', '0x']]}, accountUpdateObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyPublic.
+ it('CAVERJS-UNIT-TX-672: If transaction object has key with AccountKeyPublic, update account with AccountKeyPublic', async () => {
+ const key = caver.klay.accounts.create().privateKey
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const receipt = await caver.klay.sendTransaction(tx)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(2)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyMultiSig.
+ it('CAVERJS-UNIT-TX-673: If transaction object has key with AccountKeyMultiSig, update account with AccountKeyMultiSig', async () => {
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const options = { threshold: 1, weight: [1, 1] }
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key, options)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const receipt = await caver.klay.sendTransaction(tx)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(4)
+ expect(accountKey.key.threshold).to.equals(options.threshold)
+ expect(accountKey.key.keys.length).to.equals(key.length)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyRoleBased.
+ it('CAVERJS-UNIT-TX-674: If transaction object has key with AccountKeyRoleBased, update account with AccountKeyRoleBased', async () => {
+ const key = {
+ transactionKey: [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 options = {
+ transactionKey: { threshold: 2, weight: [1, 1] },
+ feePayerKey: { threshold: 2, weight: [1, 1, 1] }
+ }
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key, options)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const receipt = await caver.klay.sendTransaction(tx)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(5)
+ expect(accountKey.key.length).to.equals(3)
+ expect(accountKey.key[0].keyType).to.equals(4)
+ expect(accountKey.key[1].keyType).to.equals(2)
+ expect(accountKey.key[2].keyType).to.equals(4)
+ expect(accountKey.key[0].key.threshold).to.equals(options.transactionKey.threshold)
+ expect(accountKey.key[2].key.threshold).to.equals(options.feePayerKey.threshold)
+ expect(accountKey.key[0].key.keys.length).to.equals(key.transactionKey.length)
+ expect(accountKey.key[2].key.keys.length).to.equals(key.feePayerKey.length)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with LegacyKey.
+ it('CAVERJS-UNIT-TX-675: If transaction object has key with LegacyKey, update account with LegacyKey', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const receipt = await caver.klay.sendTransaction(tx)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(1)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with FailKey.
+ it('CAVERJS-UNIT-TX-676: If transaction object has key with FailKey, update account with FailKey', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithFailKey(testAccount.address)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const receipt = await caver.klay.sendTransaction(tx)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(3)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyRoleBased with legacyKey and failKey.
+ it('CAVERJS-UNIT-TX-677: If transaction object has key with AccountKeyRoleBased, update account with AccountKeyRoleBased', async () => {
+ const key = {
+ transactionKey: 'legacyKey',
+ updateKey: 'failKey',
+ feePayerKey: 'legacyKey'
+ }
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const receipt = await caver.klay.sendTransaction(tx)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(5)
+ expect(accountKey.key.length).to.equals(3)
+ expect(accountKey.key[0].keyType).to.equals(1)
+ expect(accountKey.key[1].keyType).to.equals(3)
+ expect(accountKey.key[2].keyType).to.equals(1)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Duplication key check with key field
+ it('CAVERJS-UNIT-TX-678: If transaction object has key with legacyKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, legacyKey: true}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-679: If transaction object has key with publicKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, publicKey}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-680: If transaction object has key with multisig field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, multisig}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-681: If transaction object has key with roleTransactionKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, roleTransactionKey: {publicKey}}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-682: If transaction object has key with roleAccountUpdateKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, roleAccountUpdateKey: {publicKey}}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-683: If transaction object has key with roleFeePayerKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, roleFeePayerKey: {publicKey}}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-684: If transaction object has key with failKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, failKey: true}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/cancelTransaction.js b/test/transactionType/cancelTransaction.js
index 6b2480f5..e2caf6ee 100644
--- a/test/transactionType/cancelTransaction.js
+++ b/test/transactionType/cancelTransaction.js
@@ -144,7 +144,7 @@ describe('CANCEL transaction', () => {
it('CAVERJS-UNIT-TX-516 : If transaction object has unnecessary feePayer field, sendTransaction should throw error', () => {
const tx = Object.assign({feePayer : testAccount.address}, cancelObject)
- expect(()=> caver.klay.sendTransaction(tx)).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws('"feePayer" cannot be used with CANCEL transaction')
}).timeout(200000)
// UnnecessaryFeeRatio
@@ -317,4 +317,42 @@ describe('CANCEL transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with CANCEL transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-590: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-590: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, cancelObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // UnnecessaryFeePayerSignatures
+ it('CAVERJS-UNIT-TX-591: If transaction object has unnecessary feePayerSignatures, signTransaction should throw error', async () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, cancelObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-591: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, cancelObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/contractDeploy.js b/test/transactionType/contractDeploy.js
index d3d80a8e..fbe079e3 100644
--- a/test/transactionType/contractDeploy.js
+++ b/test/transactionType/contractDeploy.js
@@ -157,7 +157,7 @@ describe('SMART_CONTRACT_DEPLOY transaction', () => {
const tx = Object.assign({feePayer: testAccount.address}, deployObject)
// This error return from formatter. Because in formatter discriminate fee delegation through feePayer and senderRawTransaction
- expect(()=> caver.klay.sendTransaction(tx)).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws('"feePayer" cannot be used with SMART_CONTRACT_DEPLOY transaction')
}).timeout(200000)
// UnnecessaryFeeRatio
@@ -330,4 +330,61 @@ describe('SMART_CONTRACT_DEPLOY transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"to" cannot be used with SMART_CONTRACT_DEPLOY transaction')
}).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-577: If data field of transaction is not 0x-hex prefixed, signTransaction should formatting and sign', async() => {
+ deployObject.data = caver.utils.stripHexPrefix(deployObject.data)
+ expect(deployObject.data.slice(0, 2) !== '0x').to.be.true
+
+ let { rawTransaction } = await caver.klay.accounts.signTransaction(deployObject, senderPrvKey)
+ const receipt = await caver.klay.sendSignedTransaction(rawTransaction)
+
+ expect(receipt.status).to.be.true
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-578: If data field of transaction is not 0x-hex prefixed, sendTransaction should formatting and sign', async() => {
+ deployObject.data = caver.utils.stripHexPrefix(deployObject.data)
+ expect(deployObject.data.slice(0, 2) !== '0x').to.be.true
+
+ const receipt = await caver.klay.sendTransaction(deployObject)
+
+ expect(receipt.status).to.be.true
+ }).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-592: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-592: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, deployObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // UnnecessaryFeePayerSignatures
+ it('CAVERJS-UNIT-TX-593: If transaction object has unnecessary feePayerSignatures, signTransaction should throw error', async () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, deployObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-593: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, deployObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/contractExecution.js b/test/transactionType/contractExecution.js
index e6f1467d..55ee0f89 100644
--- a/test/transactionType/contractExecution.js
+++ b/test/transactionType/contractExecution.js
@@ -146,7 +146,7 @@ describe('SMART_CONTRACT_EXECUTION transaction', () => {
const tx = Object.assign({feePayer: testAccount.address}, executionObject)
// This error return from formatter. Because in formatter discriminate fee delegation through feePayer and senderRawTransaction
- expect(()=> caver.klay.sendTransaction(tx)).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws('"feePayer" cannot be used with SMART_CONTRACT_EXECUTION transaction')
}).timeout(200000)
// UnnecessaryFeeRatio
@@ -319,4 +319,64 @@ describe('SMART_CONTRACT_EXECUTION transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with SMART_CONTRACT_EXECUTION transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-594: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-594: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, executionObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // UnnecessaryFeePayerSignatures
+ it('CAVERJS-UNIT-TX-595: If transaction object has unnecessary feePayerSignatures, signTransaction should throw error', async () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, executionObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-595: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, executionObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // InvalidTo
+ it('CAVERJS-UNIT-TX-596: If transaction object has invalid to address, signTransaction should throw error', async () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, executionObject)
+ tx.to = invalidTo
+
+ const expectedError = `Invalid address of to: ${tx.to}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, senderPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-596: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, executionObject)
+ tx.to = invalidTo
+
+ const expectedError = `Provided address "${tx.to}" is invalid, the capitalization checksum test failed.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedAccountUpdate.js b/test/transactionType/feeDelegatedAccountUpdate.js
index 22cb3c3f..ed6d3eff 100644
--- a/test/transactionType/feeDelegatedAccountUpdate.js
+++ b/test/transactionType/feeDelegatedAccountUpdate.js
@@ -1247,11 +1247,6 @@ describe('FEE_DELEGATED_ACCOUNT_UPDATE transaction', () => {
expect(()=>caver.klay.sendTransaction({senderRawTransaction: ret.rawTransaction})).to.throws('The "feePayer" field must be defined for signing with feePayer!')
}).timeout(200000)
- // Error senderRawTransaction missing (A check on the senderRawTransaction is performed when the feePayer attempts to sign the rawTransaction after sender signed.)
- it('CAVERJS-UNIT-TX-334 : If transaction object missing senderRawTransaction, signTransaction should throw error', async () => {
- expect(()=>caver.klay.sendTransaction({feePayer: payerAddress})).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
- }).timeout(200000)
-
// UnnecessaryFeeRatio
it('CAVERJS-UNIT-TX-335 : If transaction object has feeRatio, signTransaction should throw error', async () => {
const tx = Object.assign({feeRatio: 20, publicKey}, accountUpdateObject)
@@ -1393,4 +1388,334 @@ describe('FEE_DELEGATED_ACCOUNT_UPDATE transaction', () => {
// Throw error from formatter validation
expect(()=> caver.klay.sendTransaction(tx)).to.throws('The key parameter to be used for FEE_DELEGATED_ACCOUNT_UPDATE is duplicated.')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-597: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-597: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-598: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({publicKey, feePayerSignatures}, accountUpdateObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-598: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({publicKey, feePayerSignatures}, accountUpdateObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-599: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, publicKey, feePayerSignatures}, accountUpdateObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-599: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, publicKey, feePayerSignatures}, accountUpdateObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-600: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-600: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-601: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-601: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyPublic.
+ it('CAVERJS-UNIT-TX-685: If transaction object has key with AccountKeyPublic, update account with AccountKeyPublic', async () => {
+ const key = caver.klay.accounts.create().privateKey
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(2)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyMultiSig.
+ it('CAVERJS-UNIT-TX-686: If transaction object has key with AccountKeyMultiSig, update account with AccountKeyMultiSig', async () => {
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const options = { threshold: 1, weight: [1, 1] }
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key, options)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(4)
+ expect(accountKey.key.threshold).to.equals(options.threshold)
+ expect(accountKey.key.keys.length).to.equals(key.length)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyRoleBased.
+ it('CAVERJS-UNIT-TX-687: If transaction object has key with AccountKeyRoleBased, update account with AccountKeyRoleBased', async () => {
+ const key = {
+ transactionKey: [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 options = {
+ transactionKey: { threshold: 2, weight: [1, 1] },
+ feePayerKey: { threshold: 2, weight: [1, 1, 1] }
+ }
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key, options)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(5)
+ expect(accountKey.key.length).to.equals(3)
+ expect(accountKey.key[0].keyType).to.equals(4)
+ expect(accountKey.key[1].keyType).to.equals(2)
+ expect(accountKey.key[2].keyType).to.equals(4)
+ expect(accountKey.key[0].key.threshold).to.equals(options.transactionKey.threshold)
+ expect(accountKey.key[2].key.threshold).to.equals(options.feePayerKey.threshold)
+ expect(accountKey.key[0].key.keys.length).to.equals(key.transactionKey.length)
+ expect(accountKey.key[2].key.keys.length).to.equals(key.feePayerKey.length)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with LegacyKey.
+ it('CAVERJS-UNIT-TX-688: If transaction object has key with LegacyKey, update account with LegacyKey', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(1)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with FailKey.
+ it('CAVERJS-UNIT-TX-689: If transaction object has key with FailKey, update account with FailKey', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithFailKey(testAccount.address)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(3)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyRoleBased with legacyKey and failKey.
+ it('CAVERJS-UNIT-TX-690: If transaction object has key with AccountKeyRoleBased, update account with AccountKeyRoleBased', async () => {
+ const key = {
+ transactionKey: 'legacyKey',
+ updateKey: 'failKey',
+ feePayerKey: 'legacyKey'
+ }
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(5)
+ expect(accountKey.key.length).to.equals(3)
+ expect(accountKey.key[0].keyType).to.equals(1)
+ expect(accountKey.key[1].keyType).to.equals(3)
+ expect(accountKey.key[2].keyType).to.equals(1)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Duplication key check with key field
+ it('CAVERJS-UNIT-TX-691: If transaction object has key with legacyKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, legacyKey: true}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-692: If transaction object has key with publicKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, publicKey}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-693: If transaction object has key with multisig field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, multisig}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-694: If transaction object has key with roleTransactionKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, roleTransactionKey: {publicKey}}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-695: If transaction object has key with roleAccountUpdateKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, roleAccountUpdateKey: {publicKey}}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-696: If transaction object has key with roleFeePayerKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, roleFeePayerKey: {publicKey}}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-697: If transaction object has key with failKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, failKey: true}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedAccountUpdateWithRatio.js b/test/transactionType/feeDelegatedAccountUpdateWithRatio.js
index 71f8c2e6..077dc5d9 100644
--- a/test/transactionType/feeDelegatedAccountUpdateWithRatio.js
+++ b/test/transactionType/feeDelegatedAccountUpdateWithRatio.js
@@ -1251,12 +1251,7 @@ describe('FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO transaction', () => {
const ret = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
expect(()=>caver.klay.sendTransaction({senderRawTransaction: ret.rawTransaction})).to.throws('The "feePayer" field must be defined for signing with feePayer!')
}).timeout(200000)
-
- // Error senderRawTransaction missing (A check on the senderRawTransaction is performed when the feePayer attempts to sign the rawTransaction after sender signed.)
- it('CAVERJS-UNIT-TX-413 : If transaction object missing senderRawTransaction, signTransaction should throw error', async () => {
- expect(()=>caver.klay.sendTransaction({feePayer: payerAddress})).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
- }).timeout(200000)
-
+
// MissingFeeRatio
it('CAVERJS-UNIT-TX-414 : If transaction object has feeRatio, signTransaction should throw error', async () => {
const tx = Object.assign({publicKey}, accountUpdateObject)
@@ -1400,4 +1395,334 @@ describe('FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO transaction', () => {
// Throw error from formatter validation
expect(()=> caver.klay.sendTransaction(tx)).to.throws('The key parameter to be used for FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO is duplicated.')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-602: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-602: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-603: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({publicKey, feePayerSignatures}, accountUpdateObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-603: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({publicKey, feePayerSignatures}, accountUpdateObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-604: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, publicKey, feePayerSignatures}, accountUpdateObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-604: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, publicKey, feePayerSignatures}, accountUpdateObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-605: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-605: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-606: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-606: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({publicKey}, accountUpdateObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyPublic.
+ it('CAVERJS-UNIT-TX-698: If transaction object has key with AccountKeyPublic, update account with AccountKeyPublic', async () => {
+ const key = caver.klay.accounts.create().privateKey
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(2)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyMultiSig.
+ it('CAVERJS-UNIT-TX-699: If transaction object has key with AccountKeyMultiSig, update account with AccountKeyMultiSig', async () => {
+ const key = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey]
+ const options = { threshold: 1, weight: [1, 1] }
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key, options)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(4)
+ expect(accountKey.key.threshold).to.equals(options.threshold)
+ expect(accountKey.key.keys.length).to.equals(key.length)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyRoleBased.
+ it('CAVERJS-UNIT-TX-700: If transaction object has key with AccountKeyRoleBased, update account with AccountKeyRoleBased', async () => {
+ const key = {
+ transactionKey: [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 options = {
+ transactionKey: { threshold: 2, weight: [1, 1] },
+ feePayerKey: { threshold: 2, weight: [1, 1, 1] }
+ }
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key, options)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(5)
+ expect(accountKey.key.length).to.equals(3)
+ expect(accountKey.key[0].keyType).to.equals(4)
+ expect(accountKey.key[1].keyType).to.equals(2)
+ expect(accountKey.key[2].keyType).to.equals(4)
+ expect(accountKey.key[0].key.threshold).to.equals(options.transactionKey.threshold)
+ expect(accountKey.key[2].key.threshold).to.equals(options.feePayerKey.threshold)
+ expect(accountKey.key[0].key.keys.length).to.equals(key.transactionKey.length)
+ expect(accountKey.key[2].key.keys.length).to.equals(key.feePayerKey.length)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with LegacyKey.
+ it('CAVERJS-UNIT-TX-701: If transaction object has key with LegacyKey, update account with LegacyKey', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(1)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with FailKey.
+ it('CAVERJS-UNIT-TX-702: If transaction object has key with FailKey, update account with FailKey', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithFailKey(testAccount.address)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(3)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Update with key field with AccountKeyRoleBased with legacyKey and failKey.
+ it('CAVERJS-UNIT-TX-703: If transaction object has key with AccountKeyRoleBased, update account with AccountKeyRoleBased', async () => {
+ const key = {
+ transactionKey: 'legacyKey',
+ updateKey: 'failKey',
+ feePayerKey: 'legacyKey'
+ }
+ const updator = caver.klay.accounts.createAccountForUpdate(testAccount.address, key)
+
+ var tx = Object.assign({key: updator}, accountUpdateObject)
+
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx)
+ const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, payerAddress)
+
+ const receipt = await caver.klay.sendSignedTransaction(feePayerSigned)
+ expect(receipt.from).to.equals(tx.from)
+
+ const accountKey = await caver.klay.getAccountKey(receipt.from)
+ expect(accountKey.keyType).to.equals(5)
+ expect(accountKey.key.length).to.equals(3)
+ expect(accountKey.key[0].keyType).to.equals(1)
+ expect(accountKey.key[1].keyType).to.equals(3)
+ expect(accountKey.key[2].keyType).to.equals(1)
+
+ await createTestAccount()
+ }).timeout(200000)
+
+ // Duplication key check with key field
+ it('CAVERJS-UNIT-TX-704: If transaction object has key with legacyKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, legacyKey: true}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-705: If transaction object has key with publicKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, publicKey}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-706: If transaction object has key with multisig field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, multisig}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-707: If transaction object has key with roleTransactionKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, roleTransactionKey: {publicKey}}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-708: If transaction object has key with roleAccountUpdateKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, roleAccountUpdateKey: {publicKey}}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-709: If transaction object has key with roleFeePayerKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, roleFeePayerKey: {publicKey}}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-710: If transaction object has key with failKey field, should throw error', async () => {
+ const updator = caver.klay.accounts.createAccountForUpdateWithLegacyKey(testAccount.address)
+
+ var tx = Object.assign({key: updator, failKey: true}, accountUpdateObject)
+
+ const expectedError = `The key parameter to be used for ${tx.type} is duplicated.`
+
+ expect(()=> caver.klay.signTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedCancelTransaction.js b/test/transactionType/feeDelegatedCancelTransaction.js
index 44220203..c4f7ad3b 100644
--- a/test/transactionType/feeDelegatedCancelTransaction.js
+++ b/test/transactionType/feeDelegatedCancelTransaction.js
@@ -139,11 +139,6 @@ describe('FEE_DELEGATED_CANCEL transaction', () => {
const ret = await caver.klay.accounts.signTransaction(tx, senderPrvKey)
expect(()=>caver.klay.sendTransaction({senderRawTransaction: ret.rawTransaction})).to.throws('The "feePayer" field must be defined for signing with feePayer!')
}).timeout(200000)
-
- // MissingSenderRawTransaction
- it('CAVERJS-UNIT-TX-532 : If transaction object missing senderRawTransaction field, should throw error', async() => {
- expect(()=>caver.klay.sendTransaction({feePayer: testAccount.address})).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
- }).timeout(200000)
// UnnecessaryFeeRatio
it('CAVERJS-UNIT-TX-533 : If transaction object has unnecessary feeRatio field, signTransaction should throw error', async() => {
@@ -315,4 +310,126 @@ describe('FEE_DELEGATED_CANCEL transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with FEE_DELEGATED_CANCEL transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-607: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-607: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, cancelObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-608: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, cancelObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-608: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, cancelObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-609: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, cancelObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-609: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, cancelObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-610: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-610: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-611: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-611: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedCancelTransactionWithRatio.js b/test/transactionType/feeDelegatedCancelTransactionWithRatio.js
index ebab94ac..21b9fa73 100644
--- a/test/transactionType/feeDelegatedCancelTransactionWithRatio.js
+++ b/test/transactionType/feeDelegatedCancelTransactionWithRatio.js
@@ -140,11 +140,6 @@ describe('FEE_DELEGATED_CANCEL_WITH_RATIO transaction', () => {
const ret = await caver.klay.accounts.signTransaction(tx, senderPrvKey)
expect(()=>caver.klay.sendTransaction({senderRawTransaction: ret.rawTransaction})).to.throws('The "feePayer" field must be defined for signing with feePayer!')
}).timeout(200000)
-
- // MissingSenderRawTransaction
- it('CAVERJS-UNIT-TX-548 : If transaction object missing senderRawTransaction field, should throw error', async() => {
- expect(()=>caver.klay.sendTransaction({feePayer: testAccount.address})).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
- }).timeout(200000)
// MissingFeeRatio
it('CAVERJS-UNIT-TX-549 : If transaction object missing feeRatio, signTransaction should throw error', async() => {
@@ -318,4 +313,124 @@ describe('FEE_DELEGATED_CANCEL_WITH_RATIO transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with FEE_DELEGATED_CANCEL_WITH_RATIO transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-612: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-612: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, cancelObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-613: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, cancelObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-613: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, cancelObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-614: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, cancelObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-614: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, cancelObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-615: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-615: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-616: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-616: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, cancelObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedContractDeploy.js b/test/transactionType/feeDelegatedContractDeploy.js
index c0fa253b..8108d1bf 100644
--- a/test/transactionType/feeDelegatedContractDeploy.js
+++ b/test/transactionType/feeDelegatedContractDeploy.js
@@ -24,21 +24,25 @@ const testRPCURL = require('../testrpc')
const Caver = require('../../index.js')
let caver
-var senderPrvKey
-var senderAddress
+var senderPrvKey, payerPrvKey
+var senderAddress, payerAddress
var testAccount
before(() => {
caver = new Caver(testRPCURL)
- if (process.env.privateKey) {
+ if (process.env.privateKey && process.env.privateKey2) {
senderPrvKey = process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
? '0x' + process.env.privateKey
: process.env.privateKey
+ payerPrvKey = process.env.privateKey2 && String(process.env.privateKey2).indexOf('0x') === -1
+ ? '0x' + process.env.privateKey2
+ : process.env.privateKey2
- caver.klay.accounts.wallet.add(senderPrvKey)
+ const sender = caver.klay.accounts.wallet.add(senderPrvKey)
+ const payer = caver.klay.accounts.wallet.add(payerPrvKey)
- const sender = caver.klay.accounts.privateKeyToAccount(senderPrvKey)
senderAddress = sender.address
+ payerAddress = payer.address
} else {
const sender = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
senderPrvKey = sender.privateKey
@@ -153,11 +157,6 @@ describe('FEE_DELEGATED_SMART_CONTRACT_DEPLOY transaction', () => {
expect(()=>caver.klay.sendTransaction({senderRawTransaction: ret.rawTransaction})).to.throws('The "feePayer" field must be defined for signing with feePayer!')
}).timeout(200000)
- // MissingSenderRawTransaction
- it('CAVERJS-UNIT-TX-443 : If transaction object missing senderRawTransaction field, should throw error', async() => {
- expect(()=>caver.klay.sendTransaction({feePayer: testAccount.address})).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
- }).timeout(200000)
-
// UnnecessaryFeeRatio
it('CAVERJS-UNIT-TX-444 : If transaction object has unnecessary feeRatio field, signTransaction should throw error', async() => {
const tx = Object.assign({feeRatio: 10}, deployObject)
@@ -328,4 +327,138 @@ describe('FEE_DELEGATED_SMART_CONTRACT_DEPLOY transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"to" cannot be used with FEE_DELEGATED_SMART_CONTRACT_DEPLOY transaction')
}).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-579: If data field of transaction is not 0x-hex prefixed, signTransaction should formatting and sign', async() => {
+ deployObject.data = caver.utils.stripHexPrefix(deployObject.data)
+ expect(deployObject.data.slice(0, 2) !== '0x').to.be.true
+
+ let { rawTransaction } = await caver.klay.accounts.signTransaction(deployObject, senderPrvKey)
+
+ const receipt = await caver.klay.sendTransaction({
+ senderRawTransaction: rawTransaction,
+ feePayer: payerAddress
+ })
+
+ expect(receipt.status).to.be.true
+ }).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-617: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-617: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, deployObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-618: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, deployObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-618: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, deployObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-619: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, deployObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-619: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, deployObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-620: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-620: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-621: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-621: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedContractDeployWithRatio.js b/test/transactionType/feeDelegatedContractDeployWithRatio.js
index 652382fe..7c31af41 100644
--- a/test/transactionType/feeDelegatedContractDeployWithRatio.js
+++ b/test/transactionType/feeDelegatedContractDeployWithRatio.js
@@ -24,21 +24,25 @@ const testRPCURL = require('../testrpc')
const Caver = require('../../index.js')
let caver
-var senderPrvKey
-var senderAddress
+var senderPrvKey, payerPrvKey
+var senderAddress, payerAddress
var testAccount
before(() => {
caver = new Caver(testRPCURL)
- if (process.env.privateKey) {
+ if (process.env.privateKey && process.env.privateKey2) {
senderPrvKey = process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
? '0x' + process.env.privateKey
: process.env.privateKey
+ payerPrvKey = process.env.privateKey2 && String(process.env.privateKey2).indexOf('0x') === -1
+ ? '0x' + process.env.privateKey2
+ : process.env.privateKey2
- caver.klay.accounts.wallet.add(senderPrvKey)
+ const sender = caver.klay.accounts.wallet.add(senderPrvKey)
+ const payer = caver.klay.accounts.wallet.add(payerPrvKey)
- const sender = caver.klay.accounts.privateKeyToAccount(senderPrvKey)
senderAddress = sender.address
+ payerAddress = payer.address
} else {
const sender = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
senderPrvKey = sender.privateKey
@@ -154,11 +158,6 @@ describe('FEE_DELEGATED_SMART_CONTRACT_DEPLOY_WITH_RATIO transaction', () => {
expect(()=>caver.klay.sendTransaction({senderRawTransaction: ret.rawTransaction})).to.throws('The "feePayer" field must be defined for signing with feePayer!')
}).timeout(200000)
- // MissingSenderRawTransaction
- it('CAVERJS-UNIT-TX-458 : If transaction object missing senderRawTransaction field, should throw error', async() => {
- expect(()=>caver.klay.sendTransaction({feePayer: testAccount.address})).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
- }).timeout(200000)
-
// MissingFeeRatio
it('CAVERJS-UNIT-TX-459 : If transaction object missing feeRatio field, signTransaction should throw error', async() => {
const tx = Object.assign(deployObject)
@@ -331,4 +330,138 @@ describe('FEE_DELEGATED_SMART_CONTRACT_DEPLOY_WITH_RATIO transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"to" cannot be used with FEE_DELEGATED_SMART_CONTRACT_DEPLOY_WITH_RATIO transaction')
}).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-580: If data field of transaction is not 0x-hex prefixed, signTransaction should formatting and sign', async() => {
+ deployObject.data = caver.utils.stripHexPrefix(deployObject.data)
+ expect(deployObject.data.slice(0, 2) !== '0x').to.be.true
+
+ let { rawTransaction } = await caver.klay.accounts.signTransaction(deployObject, senderPrvKey)
+
+ const receipt = await caver.klay.sendTransaction({
+ senderRawTransaction: rawTransaction,
+ feePayer: payerAddress
+ })
+
+ expect(receipt.status).to.be.true
+ }).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-622: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-622: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, deployObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-623: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, deployObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-623: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, deployObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-624: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, deployObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-624: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, deployObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-625: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-625: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-626: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-626: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, deployObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedContractExecution.js b/test/transactionType/feeDelegatedContractExecution.js
index 10a26bfb..9e49688d 100644
--- a/test/transactionType/feeDelegatedContractExecution.js
+++ b/test/transactionType/feeDelegatedContractExecution.js
@@ -140,11 +140,6 @@ describe('FEE_DELEGATED_SMART_CONTRACT_EXECUTION transaction', () => {
const ret = await caver.klay.accounts.signTransaction(tx, senderPrvKey)
expect(()=>caver.klay.sendTransaction({senderRawTransaction: ret.rawTransaction})).to.throws('The "feePayer" field must be defined for signing with feePayer!')
}).timeout(200000)
-
- // MissingSenderRawTransaction
- it('CAVERJS-UNIT-TX-486 : If transaction object missing senderRawTransaction field, should throw error', async() => {
- expect(()=>caver.klay.sendTransaction({feePayer: testAccount.address})).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
- }).timeout(200000)
// UnnecessaryFeeRatio
it('CAVERJS-UNIT-TX-487 : If transaction object has unnecessary feeRatio field, signTransaction should throw error', async() => {
@@ -316,4 +311,146 @@ describe('FEE_DELEGATED_SMART_CONTRACT_EXECUTION transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with FEE_DELEGATED_SMART_CONTRACT_EXECUTION transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-627: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-627: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, executionObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-628: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, executionObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-628: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, executionObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-629: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, executionObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-629: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, executionObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // InvalidTo
+ it('CAVERJS-UNIT-TX-630: If transaction object has invalid to address, signTransaction should throw error', async () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, executionObject)
+ tx.to = invalidTo
+
+ const expectedError = `Invalid address of to: ${tx.to}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, senderPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-630: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, executionObject)
+ tx.to = invalidTo
+
+ const expectedError = `Provided address "${tx.to}" is invalid, the capitalization checksum test failed.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-631: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-631: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-632: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-632: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedContractExecutionWithRatio.js b/test/transactionType/feeDelegatedContractExecutionWithRatio.js
index b1a1cfce..25eba158 100644
--- a/test/transactionType/feeDelegatedContractExecutionWithRatio.js
+++ b/test/transactionType/feeDelegatedContractExecutionWithRatio.js
@@ -141,11 +141,6 @@ describe('FEE_DELEGATED_SMART_CONTRACT_EXECUTION_WITH_RATIO transaction', () =>
const ret = await caver.klay.accounts.signTransaction(tx, senderPrvKey)
expect(()=>caver.klay.sendTransaction({senderRawTransaction: ret.rawTransaction})).to.throws('The "feePayer" field must be defined for signing with feePayer!')
}).timeout(200000)
-
- // MissingSenderRawTransaction
- it('CAVERJS-UNIT-TX-501 : If transaction object missing senderRawTransaction field, should throw error', async() => {
- expect(()=>caver.klay.sendTransaction({feePayer: testAccount.address})).to.throws('The "senderRawTransaction" field must be defined for signing with feePayer!')
- }).timeout(200000)
// MissingFeeRatio
it('CAVERJS-UNIT-TX-502 : If transaction object missing feeRatio, signTransaction should throw error', async() => {
@@ -319,4 +314,146 @@ describe('FEE_DELEGATED_SMART_CONTRACT_EXECUTION_WITH_RATIO transaction', () =>
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with FEE_DELEGATED_SMART_CONTRACT_EXECUTION_WITH_RATIO transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-633: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-633: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, executionObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-634: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, executionObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-634: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, executionObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-635: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, executionObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-635: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, executionObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // InvalidTo
+ it('CAVERJS-UNIT-TX-636: If transaction object has invalid to address, signTransaction should throw error', async () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, executionObject)
+ tx.to = invalidTo
+
+ const expectedError = `Invalid address of to: ${tx.to}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, senderPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-636: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, executionObject)
+ tx.to = invalidTo
+
+ const expectedError = `Provided address "${tx.to}" is invalid, the capitalization checksum test failed.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-637: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-637: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-638: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-638: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, executionObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedValueTransfer.js b/test/transactionType/feeDelegatedValueTransfer.js
index 278eddbd..1772b722 100644
--- a/test/transactionType/feeDelegatedValueTransfer.js
+++ b/test/transactionType/feeDelegatedValueTransfer.js
@@ -389,4 +389,146 @@ describe('FEE_DELEGATED_VALUE_TRANSFER transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with FEE_DELEGATED_VALUE_TRANSFER transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-639: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-639: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-640: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, feeDelegatedValueTransferObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-640: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, feeDelegatedValueTransferObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-641: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, feeDelegatedValueTransferObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-641: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, feeDelegatedValueTransferObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // InvalidTo
+ it('CAVERJS-UNIT-TX-642: If transaction object has invalid to address, signTransaction should throw error', async () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, feeDelegatedValueTransferObject)
+ tx.to = invalidTo
+
+ const expectedError = `Invalid address of to: ${tx.to}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, senderPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-642: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, feeDelegatedValueTransferObject)
+ tx.to = invalidTo
+
+ const expectedError = `Provided address "${tx.to}" is invalid, the capitalization checksum test failed.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-643: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-643: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-644: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-644: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedValueTransferMemo.js b/test/transactionType/feeDelegatedValueTransferMemo.js
index 064a32a4..8d643292 100644
--- a/test/transactionType/feeDelegatedValueTransferMemo.js
+++ b/test/transactionType/feeDelegatedValueTransferMemo.js
@@ -402,4 +402,147 @@ describe('FEE_DELEGATED_VALUE_TRANSFER_MEMO transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with FEE_DELEGATED_VALUE_TRANSFER_MEMO transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-651: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-651: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-652: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, feeDelegatedValueTransferMemoObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-652: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, feeDelegatedValueTransferMemoObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-653: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, feeDelegatedValueTransferMemoObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-653: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, feeDelegatedValueTransferMemoObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // InvalidTo
+ it('CAVERJS-UNIT-TX-654: If transaction object has invalid to address, signTransaction should throw error', async () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoObject)
+ tx.to = invalidTo
+
+ const expectedError = `Invalid address of to: ${tx.to}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, senderPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-654: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoObject)
+ tx.to = invalidTo
+
+ const expectedError = `Provided address "${tx.to}" is invalid, the capitalization checksum test failed.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-655: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-655: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-656: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-656: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedValueTransferMemoWithRatio.js b/test/transactionType/feeDelegatedValueTransferMemoWithRatio.js
index c1b43c15..a9f4a6eb 100644
--- a/test/transactionType/feeDelegatedValueTransferMemoWithRatio.js
+++ b/test/transactionType/feeDelegatedValueTransferMemoWithRatio.js
@@ -405,4 +405,147 @@ describe('FEE_DELEGATED_VALUE_TRANSFER_MEMO_WITH_RATIO transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with FEE_DELEGATED_VALUE_TRANSFER_MEMO_WITH_RATIO transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-657: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoWithRatioObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-657: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoWithRatioObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-658: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, feeDelegatedValueTransferMemoWithRatioObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-658: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, feeDelegatedValueTransferMemoWithRatioObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-659: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, feeDelegatedValueTransferMemoWithRatioObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-659: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, feeDelegatedValueTransferMemoWithRatioObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // InvalidTo
+ it('CAVERJS-UNIT-TX-660: If transaction object has invalid to address, signTransaction should throw error', async () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoWithRatioObject)
+ tx.to = invalidTo
+
+ const expectedError = `Invalid address of to: ${tx.to}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, senderPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-660: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoWithRatioObject)
+ tx.to = invalidTo
+
+ const expectedError = `Provided address "${tx.to}" is invalid, the capitalization checksum test failed.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-661: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoWithRatioObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-661: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoWithRatioObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-662: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoWithRatioObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-662: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferMemoWithRatioObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/feeDelegatedValueTransferWithRatio.js b/test/transactionType/feeDelegatedValueTransferWithRatio.js
index c3606a98..812792c0 100644
--- a/test/transactionType/feeDelegatedValueTransferWithRatio.js
+++ b/test/transactionType/feeDelegatedValueTransferWithRatio.js
@@ -405,4 +405,147 @@ describe('FEE_DELEGATED_VALUE_TRANSFER_WITH_RATIO transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with FEE_DELEGATED_VALUE_TRANSFER_WITH_RATIO transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-645: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferWithRatioObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-645: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferWithRatioObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-646: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, feeDelegatedValueTransferWithRatioObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-646: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const tx = Object.assign({feePayerSignatures}, feeDelegatedValueTransferWithRatioObject)
+
+ const expectedError = `"feePayer" is missing: feePayer must be defined with feePayerSignatures.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error with invalid feePayer missing when feePayerSignatures is defined in transaction object
+ it('CAVERJS-UNIT-TX-647: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, feeDelegatedValueTransferWithRatioObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-647: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const feePayerSignatures = [['0x26', '0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e', '0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae']]
+ const invalidFeePayer = 'feePayer'
+ const tx = Object.assign({feePayer: invalidFeePayer, feePayerSignatures}, feeDelegatedValueTransferWithRatioObject)
+
+ const expectedError = `Invalid address of fee payer: ${invalidFeePayer}`
+
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // InvalidTo
+ it('CAVERJS-UNIT-TX-648: If transaction object has invalid to address, signTransaction should throw error', async () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, feeDelegatedValueTransferWithRatioObject)
+ tx.to = invalidTo
+
+ const expectedError = `Invalid address of to: ${tx.to}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, senderPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-648: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, feeDelegatedValueTransferWithRatioObject)
+ tx.to = invalidTo
+
+ const expectedError = `Provided address "${tx.to}" is invalid, the capitalization checksum test failed.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is not defined with fee payer transaction format
+ it('CAVERJS-UNIT-TX-649: If transaction object missing feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferWithRatioObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ const expectedError = `Invalid fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-649: If transaction object missing feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferWithRatioObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: '0x',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // Error when feePayer is invalid with fee payer transaction format
+ it('CAVERJS-UNIT-TX-650: If transaction object has invalid feePayer, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferWithRatioObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ const expectedError = `Invalid address of fee payer: ${feePayerTx.feePayer}`
+
+ await expect(caver.klay.accounts.signTransaction(feePayerTx, payerPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-650: If transaction object has invalid feePayer, sendTransaction should throw error', async () => {
+ const tx = Object.assign({}, feeDelegatedValueTransferWithRatioObject)
+ const { rawTransaction } = await caver.klay.accounts.signTransaction(tx, testAccount.privateKey)
+
+ const feePayerTx = {
+ senderRawTransaction: rawTransaction,
+ feePayer: 'invalid',
+ }
+
+ // when sendTransaction, get account from wallet before calling signTransaction
+ const expectedError = `Provided address "${feePayerTx.feePayer}" is invalid, the capitalization checksum test failed.`
+
+ expect(()=> caver.klay.sendTransaction(feePayerTx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/legacyTransaction.js b/test/transactionType/legacyTransaction.js
index 54819018..0fc973d8 100644
--- a/test/transactionType/legacyTransaction.js
+++ b/test/transactionType/legacyTransaction.js
@@ -353,4 +353,64 @@ describe('LEGACY transaction', () => {
// Throw error from formatter validation
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with LEGACY transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-663: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, legacyObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-663: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, legacyObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // UnnecessaryFeePayerSignatures
+ it('CAVERJS-UNIT-TX-664: If transaction object has unnecessary feePayerSignatures, signTransaction should throw error', async () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, legacyObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with LEGACY transaction`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-664: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, legacyObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with LEGACY transaction`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // InvalidTo
+ it('CAVERJS-UNIT-TX-665: If transaction object has invalid to address, signTransaction should throw error', async () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, legacyObject)
+ tx.to = invalidTo
+
+ const expectedError = `Invalid address of to: ${tx.to}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, senderPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-665: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, legacyObject)
+ tx.to = invalidTo
+
+ const expectedError = `Provided address "${tx.to}" is invalid, the capitalization checksum test failed.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
})
diff --git a/test/transactionType/serializationTest.js b/test/transactionType/serializationTest.js
index 7c73f7cc..c7a7db9d 100644
--- a/test/transactionType/serializationTest.js
+++ b/test/transactionType/serializationTest.js
@@ -52,7 +52,7 @@ describe('Legacy: Legacy transaction', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-059: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals('LEGACY')
@@ -65,6 +65,10 @@ describe('Legacy: Legacy transaction', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0]).to.equals(txObj.v)
+ expect(txObj.signatures[1]).to.equals(txObj.r)
+ expect(txObj.signatures[2]).to.equals(txObj.s)
}).timeout(200000)
})
@@ -91,7 +95,7 @@ describe('Value transfer: Value Transfer', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-060: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -104,6 +108,10 @@ describe('Value transfer: Value Transfer', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
}).timeout(200000)
})
@@ -140,7 +148,7 @@ describe('Value transfer: Fee Delegated Value Transfer', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-055: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -153,10 +161,18 @@ describe('Value transfer: Fee Delegated Value Transfer', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
}).timeout(200000)
})
@@ -180,7 +196,7 @@ describe('Value transfer: Fee Delegated Value Transfer With Ratio', () => {
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -199,7 +215,7 @@ describe('Value transfer: Fee Delegated Value Transfer With Ratio', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-058: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -213,10 +229,18 @@ describe('Value transfer: Fee Delegated Value Transfer With Ratio', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
}).timeout(200000)
})
@@ -244,7 +268,7 @@ describe('Value transfer memo: Value Transfer With Memo', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-061: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -258,6 +282,10 @@ describe('Value transfer memo: Value Transfer With Memo', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
}).timeout(200000)
})
@@ -281,7 +309,7 @@ describe('Value transfer memo: Fee Delegated Value Transfer Memo', () => {
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -300,7 +328,7 @@ describe('Value transfer memo: Fee Delegated Value Transfer Memo', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-056: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -314,10 +342,18 @@ describe('Value transfer memo: Fee Delegated Value Transfer Memo', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
}).timeout(200000)
})
@@ -342,7 +378,7 @@ describe('Value transfer memo with ratio: Fee Delegated Value Transfer Memo With
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -361,7 +397,7 @@ describe('Value transfer memo with ratio: Fee Delegated Value Transfer Memo With
}).timeout(200000)
it('CAVERJS-UNIT-SER-057: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -376,10 +412,18 @@ describe('Value transfer memo with ratio: Fee Delegated Value Transfer Memo With
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
}).timeout(200000)
})
@@ -409,7 +453,7 @@ describe('Account: Account update', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-042: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -421,6 +465,10 @@ describe('Account: Account update', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
}).timeout(200000)
})
@@ -442,7 +490,7 @@ describe('Account: Fee Delegated Account Update', () => {
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -461,7 +509,7 @@ describe('Account: Fee Delegated Account Update', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-047: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -472,10 +520,18 @@ describe('Account: Fee Delegated Account Update', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
expect(txObj.publicKey).to.equals(caver.utils.compressPublicKey(sender_transaction.publicKey))
}).timeout(200000)
})
@@ -500,7 +556,7 @@ describe('Account: Fee Delegated Account Update with ratio', () => {
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -519,7 +575,7 @@ describe('Account: Fee Delegated Account Update with ratio', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-048: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -531,10 +587,18 @@ describe('Account: Fee Delegated Account Update with ratio', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
expect(txObj.publicKey).to.equals(caver.utils.compressPublicKey(sender_transaction.publicKey))
}).timeout(200000)
})
@@ -563,7 +627,7 @@ describe('Contract: Contract deploy', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-045: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -579,6 +643,10 @@ describe('Contract: Contract deploy', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
}).timeout(200000)
})
@@ -601,7 +669,7 @@ describe('Contract: Fee Delegated Contract Deploy', () => {
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -621,7 +689,7 @@ describe('Contract: Fee Delegated Contract Deploy', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-051: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -637,10 +705,18 @@ describe('Contract: Fee Delegated Contract Deploy', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
}).timeout(200000)
})
@@ -664,7 +740,7 @@ describe('Contract: Fee Delegated Contract Deploy With Ratio', () => {
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -683,7 +759,7 @@ describe('Contract: Fee Delegated Contract Deploy With Ratio', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-052: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -700,10 +776,18 @@ describe('Contract: Fee Delegated Contract Deploy With Ratio', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
}).timeout(200000)
})
@@ -732,7 +816,7 @@ describe('Contract: Contract execution', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-046: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -746,6 +830,10 @@ describe('Contract: Contract execution', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
}).timeout(200000)
})
@@ -769,7 +857,7 @@ describe('Contract: Fee Delegated Contract Execution', () => {
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -788,7 +876,7 @@ describe('Contract: Fee Delegated Contract Execution', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-053: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -802,10 +890,18 @@ describe('Contract: Fee Delegated Contract Execution', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
}).timeout(200000)
})
@@ -831,7 +927,7 @@ describe('Contract: Fee Delegated Contract Execution With Ratio', () => {
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -851,7 +947,7 @@ describe('Contract: Fee Delegated Contract Execution With Ratio', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-054: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -866,10 +962,18 @@ describe('Contract: Fee Delegated Contract Execution With Ratio', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
}).timeout(200000)
})
@@ -895,7 +999,7 @@ describe('Cancel: Cancel transaction', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-043: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -906,6 +1010,10 @@ describe('Cancel: Cancel transaction', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
}).timeout(200000)
})
@@ -926,7 +1034,7 @@ describe('Cancel: Fee Delegated Cancel Transaction', () => {
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -946,7 +1054,7 @@ describe('Cancel: Fee Delegated Cancel Transaction', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-049: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -957,10 +1065,18 @@ describe('Cancel: Fee Delegated Cancel Transaction', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
}).timeout(200000)
})
@@ -982,7 +1098,7 @@ describe('Cancel: Fee Delegated Cancel Transaction With Ratio', () => {
caver.klay.accounts.wallet.add(privateKey)
const { rawTransaction: senderRawTransaction } = await caver.klay.accounts.signTransaction(sender_transaction, privateKey)
- const decoded = await caver.klay.decodeTransaction(senderRawTransaction)
+ const decoded = caver.klay.decodeTransaction(senderRawTransaction)
expect(decoded.feePayer).to.equals('0x')
expect(decoded.payerV).to.equals('0x01')
expect(decoded.payerR).to.equals('0x')
@@ -1001,7 +1117,7 @@ describe('Cancel: Fee Delegated Cancel Transaction With Ratio', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-050: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -1013,10 +1129,18 @@ describe('Cancel: Fee Delegated Cancel Transaction With Ratio', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
expect(txObj.feePayer).to.equals(feePayer)
expect(txObj.payerV).not.to.be.undefined
expect(txObj.payerR).not.to.be.undefined
expect(txObj.payerS).not.to.be.undefined
+ expect(txObj.feePayerSignatures).not.to.be.undefined
+ expect(txObj.feePayerSignatures[0][0]).to.equals(txObj.payerV)
+ expect(txObj.feePayerSignatures[0][1]).to.equals(txObj.payerR)
+ expect(txObj.feePayerSignatures[0][2]).to.equals(txObj.payerS)
}).timeout(200000)
})
@@ -1045,7 +1169,7 @@ describe('ServiceChain: Chain data anchoring', () => {
}).timeout(200000)
it('CAVERJS-UNIT-SER-044: Decode raw transaction', async () => {
- const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+ const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
expect(txObj).not.to.be.undefined
expect(txObj.type).to.equals(sender_transaction.type)
@@ -1059,6 +1183,10 @@ describe('ServiceChain: Chain data anchoring', () => {
expect(txObj.v).not.to.be.undefined
expect(txObj.r).not.to.be.undefined
expect(txObj.s).not.to.be.undefined
+ expect(txObj.signatures).not.to.be.undefined
+ expect(txObj.signatures[0][0]).to.equals(txObj.v)
+ expect(txObj.signatures[0][1]).to.equals(txObj.r)
+ expect(txObj.signatures[0][2]).to.equals(txObj.s)
}).timeout(200000)
})
@@ -1091,7 +1219,7 @@ describe('ServiceChain: Chain data anchoring', () => {
// }).timeout(200000)
// it('CAVERJS-UNIT-SER-041: Decode raw transaction', async () => {
-// const txObj = await caver.klay.decodeTransaction(expectedRawTransaction)
+// const txObj = caver.klay.decodeTransaction(expectedRawTransaction)
// expect(txObj).not.to.be.undefined
// expect(txObj.type).to.equals(sender_transaction.type)
diff --git a/test/transactionType/valueTransfer.js b/test/transactionType/valueTransfer.js
index 82904ec9..654b23a5 100644
--- a/test/transactionType/valueTransfer.js
+++ b/test/transactionType/valueTransfer.js
@@ -378,4 +378,64 @@ describe('VALUE_TRANSFER transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with VALUE_TRANSFER transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-666: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, valueTransferObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-666: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, valueTransferObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // UnnecessaryFeePayerSignatures
+ it('CAVERJS-UNIT-TX-667: If transaction object has unnecessary feePayerSignatures, signTransaction should throw error', async () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, valueTransferObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-667: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, valueTransferObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // InvalidTo
+ it('CAVERJS-UNIT-TX-668: If transaction object has invalid to address, signTransaction should throw error', async () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, valueTransferObject)
+ tx.to = invalidTo
+
+ const expectedError = `Invalid address of to: ${tx.to}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, senderPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-668: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, valueTransferObject)
+ tx.to = invalidTo
+
+ const expectedError = `Provided address "${tx.to}" is invalid, the capitalization checksum test failed.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file
diff --git a/test/transactionType/valueTransferWithMemo.js b/test/transactionType/valueTransferWithMemo.js
index 4d404bf4..d6ab31c2 100644
--- a/test/transactionType/valueTransferWithMemo.js
+++ b/test/transactionType/valueTransferWithMemo.js
@@ -378,4 +378,64 @@ describe('VALUE_TRANSFER_MEMO transaction', () => {
expect(()=> caver.klay.sendTransaction(tx)).to.throws('"legacyKey" cannot be used with VALUE_TRANSFER_MEMO transaction')
}).timeout(200000)
+
+ // Invalid from address
+ it('CAVERJS-UNIT-TX-669: If transaction object has invalid from, signTransaction should throw error', async () => {
+ const tx = Object.assign({}, valueTransferMemoObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Invalid address of from: ${tx.from}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-669: If transaction object has invalid from, sendTransaction should throw error', () => {
+ const tx = Object.assign({}, valueTransferMemoObject)
+ tx.from = 'invalidAddress'
+
+ const expectedError = `Provided address "${tx.from}" is invalid, the capitalization checksum test failed`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // UnnecessaryFeePayerSignatures
+ it('CAVERJS-UNIT-TX-670: If transaction object has unnecessary feePayerSignatures, signTransaction should throw error', async () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, valueTransferMemoObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ await expect(caver.klay.accounts.signTransaction(tx, testAccount.privateKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-670: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const tx = Object.assign({feePayerSignatures: [['0x01', '0x', '0x']]}, valueTransferMemoObject)
+
+ const expectedError = `"feePayerSignatures" cannot be used with ${tx.type} transaction`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
+
+ // InvalidTo
+ it('CAVERJS-UNIT-TX-671: If transaction object has invalid to address, signTransaction should throw error', async () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, valueTransferMemoObject)
+ tx.to = invalidTo
+
+ const expectedError = `Invalid address of to: ${tx.to}`
+
+ await expect(caver.klay.accounts.signTransaction(tx, senderPrvKey)).to.be.rejectedWith(expectedError)
+ }).timeout(200000)
+
+ it('CAVERJS-UNIT-TX-671: If transaction object has unnecessary feePayerSignatures, sendTransaction should throw error', () => {
+ const invalidTo = 'invalid'
+ const tx = Object.assign({}, valueTransferMemoObject)
+ tx.to = invalidTo
+
+ const expectedError = `Provided address "${tx.to}" is invalid, the capitalization checksum test failed.`
+
+ // Throw error from formatter validation
+ expect(()=> caver.klay.sendTransaction(tx)).to.throws(expectedError)
+ }).timeout(200000)
})
\ No newline at end of file