caver-js
Version:
caver-js is a JavaScript API library that allows developers to interact with a Klaytn node
1,095 lines (907 loc) • 93.6 kB
JavaScript
/*
Copyright 2020 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 <http://www.gnu.org/licenses/>.
*/
const _ = require('lodash')
const chai = require('chai')
const sinon = require('sinon')
const sinonChai = require('sinon-chai')
chai.use(sinonChai)
const expect = chai.expect
const testRPCURL = require('../testrpc')
const Caver = require('../../index')
const SingleKeyring = require('../../packages/caver-wallet/src/keyring/singleKeyring')
const MultipleKeyring = require('../../packages/caver-wallet/src/keyring/multipleKeyring')
const RoleBasedKeyring = require('../../packages/caver-wallet/src/keyring/roleBasedKeyring')
const Account = require('../../packages/caver-account')
const AccountKeyPublic = require('../../packages/caver-account/src/accountKey/accountKeyPublic')
const AccountKeyWeightedMultiSig = require('../../packages/caver-account/src/accountKey/accountKeyWeightedMultiSig')
const AccountKeyRoleBased = require('../../packages/caver-account/src/accountKey/accountKeyRoleBased')
const PrivateKey = require('../../packages/caver-wallet/src/keyring/privateKey')
const SignatureData = require('../../packages/caver-wallet/src/keyring/signatureData')
const { generateDecoupledKeyring, generateMultiSigKeyring, generateRoleBasedKeyring } = require('./utils')
const utils = require('../../packages/caver-utils')
let caver
beforeEach(() => {
caver = new Caver(testRPCURL)
})
function validateKeyring(data, { expectedAddress, expectedKey } = {}) {
expect(data instanceof SingleKeyring || data instanceof MultipleKeyring || data instanceof RoleBasedKeyring).to.be.true
const objectKeys = ['_address']
if (data instanceof SingleKeyring) {
objectKeys.push('_key')
} else {
objectKeys.push('_keys')
}
expect(Object.getOwnPropertyNames(data)).to.deep.equal(objectKeys)
expect(caver.utils.isAddress(data.address)).to.equal(true)
if (expectedAddress !== undefined) {
expect(data.address.toLowerCase()).to.equal(expectedAddress.toLowerCase())
}
if (expectedKey !== undefined) {
if (data instanceof SingleKeyring) {
comparePrivateKey(expectedKey, data.key)
} else if (data instanceof MultipleKeyring) {
for (let i = 0; i < data.keys.length; i++) {
comparePrivateKey(expectedKey[i], data.keys[i])
}
} else {
for (let i = 0; i < data.keys.length; i++) {
for (let j = 0; j < data.keys[i].length; j++) {
comparePrivateKey(expectedKey[i][j], data.keys[i][j])
}
}
}
}
}
function comparePrivateKey(expected, actual) {
const privateKeyString = expected instanceof PrivateKey ? expected.privateKey : expected
expect(actual.privateKey.toLowerCase()).to.equal(privateKeyString.toLowerCase())
}
function validateKeystore(data, password, { address, expectedKey, keyringLength = 1 }, version = 4) {
const objectKeys = ['version', 'id', 'address']
if (version > 3) {
objectKeys.push('keyring')
} else {
objectKeys.push('crypto')
}
expect(Object.getOwnPropertyNames(data)).to.deep.equal(objectKeys)
if (version > 3) {
if (_.isArray(keyringLength)) {
for (let i = 0; i < keyringLength.length; i++) {
expect(data.keyring[i].length).to.equal(keyringLength[i])
}
} else {
expect(data.keyring.length).to.equal(keyringLength)
}
}
expect(data.version).to.equal(version)
expect(caver.utils.isAddress(data.address)).to.equal(true)
const prefixTrimmed = data.address.replace(/^(0x)*/i, '')
expect(prefixTrimmed).to.match(new RegExp(`^${address.slice(2)}$`, 'i'))
const keyring = caver.wallet.keyring.decrypt(data, password)
validateKeyring(keyring, { expectedAddress: address, expectedKey })
}
function validateAccount(data, { keyring, expectedAccountKey, exepectedOptions }) {
expect(data instanceof Account).to.be.true
const objectKeys = ['_address', '_accountKey']
expect(Object.getOwnPropertyNames(data)).to.deep.equal(objectKeys)
expect(caver.utils.isAddress(data.address)).to.equal(true)
if (keyring !== undefined) {
expect(data.address.toLowerCase()).to.equal(keyring.address.toLowerCase())
}
if (expectedAccountKey !== undefined) {
switch (expectedAccountKey) {
case 'AccountKeyPublic':
validateAccountKeyPublic(data.accountKey, keyring.key)
break
case 'AccountKeyWeightedMultiSig':
validateAccountKeyWeightedMultiSig(data.accountKey, keyring.keys, exepectedOptions)
break
case 'AccountKeyRoleBased':
expect(data.accountKey instanceof AccountKeyRoleBased).to.be.true
for (let i = 0; i < data.accountKey.accountKeys.length; i++) {
const acctKey = data.accountKey.accountKeys[i]
if (acctKey instanceof AccountKeyPublic) {
validateAccountKeyPublic(acctKey, keyring.keys[i])
} else {
validateAccountKeyWeightedMultiSig(acctKey, keyring.keys[i], exepectedOptions[i])
}
}
break
}
}
}
function validateAccountKeyPublic(key, singleKey) {
expect(key instanceof AccountKeyPublic).to.be.true
expect(key.publicKey).to.equal(singleKey.getPublicKey())
}
function validateAccountKeyWeightedMultiSig(key, multipleKeys, options) {
expect(key instanceof AccountKeyWeightedMultiSig).to.be.true
if (options) {
expect(key.threshold).to.equal(options.threshold)
}
for (let i = 0; i < key.weightedPublicKeys.length; i++) {
expect(key.weightedPublicKeys[i].publicKey).to.equal(multipleKeys[i].getPublicKey())
if (options) {
expect(key.weightedPublicKeys[i].weight).to.equal(options.weights[i])
}
}
}
describe('caver.wallet.keyring.generate', () => {
context('CAVERJS-UNIT-KEYRING-003: input: no parameter', () => {
it('should return valid private Keyring instance', () => {
const result = caver.wallet.keyring.generate()
validateKeyring(result)
})
})
context('CAVERJS-UNIT-KEYRING-004: input: entropy', () => {
it('should return valid private Keyring instance', () => {
const entropy = caver.utils.randomHex(32)
const result = caver.wallet.keyring.generate(entropy)
validateKeyring(result)
})
})
})
describe('caver.wallet.generateSingleKey', () => {
context('CAVERJS-UNIT-KEYRING-147: input: no parameter', () => {
it('should return valid private key string', () => {
const result = caver.wallet.keyring.generateSingleKey()
expect(utils.isValidPrivateKey(result)).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-148: input: entropy', () => {
it('should return valid private key string', () => {
const entropy = caver.utils.randomHex(32)
const result = caver.wallet.keyring.generateSingleKey(entropy)
expect(utils.isValidPrivateKey(result)).to.be.true
})
})
})
describe('caver.wallet.generateMultipleKeys', () => {
context('CAVERJS-UNIT-KEYRING-149: input: number of keys', () => {
it('should return valid an array of private key strings', () => {
const result = caver.wallet.keyring.generateMultipleKeys(3)
expect(result.length).to.be.equal(3)
for (const p of result) {
expect(utils.isValidPrivateKey(p)).to.be.true
}
})
})
context('CAVERJS-UNIT-KEYRING-150: input: number of keys, entropy', () => {
it('should return valid an array of private key strings', () => {
const entropy = caver.utils.randomHex(32)
const result = caver.wallet.keyring.generateMultipleKeys(3, entropy)
expect(result.length).to.be.equal(3)
for (const p of result) {
expect(utils.isValidPrivateKey(p)).to.be.true
}
})
})
context('CAVERJS-UNIT-KEYRING-151: input: no parameter', () => {
it('should return error', () => {
const expectedError = `To generate random multiple private keys, the number of keys should be defined.`
expect(() => caver.wallet.keyring.generateMultipleKeys()).to.throw(expectedError)
})
})
context('CAVERJS-UNIT-KEYRING-152: input: entropy', () => {
it('should return error', () => {
const entropy = caver.utils.randomHex(32)
const expectedError = `To generate random multiple private keys, the number of keys should be defined.`
expect(() => caver.wallet.keyring.generateMultipleKeys(entropy)).to.throw(expectedError)
})
})
})
describe('caver.wallet.generateRoleBasedKeys', () => {
context('CAVERJS-UNIT-KEYRING-153: input: an array of the number of keys(less than role)', () => {
it('should return valid a role-based private key strings', () => {
const result = caver.wallet.keyring.generateRoleBasedKeys([3])
expect(result.length).to.be.equal(3)
expect(result[0].length).to.be.equal(3)
expect(result[1].length).to.be.equal(0)
expect(result[2].length).to.be.equal(0)
for (const p of result[0]) {
expect(utils.isValidPrivateKey(p)).to.be.true
}
})
})
context('CAVERJS-UNIT-KEYRING-154: input: an array of the number of keys', () => {
it('should return valid a role-based private key strings', () => {
const result = caver.wallet.keyring.generateRoleBasedKeys([3, 1, 2])
expect(result.length).to.be.equal(3)
expect(result[0].length).to.be.equal(3)
expect(result[1].length).to.be.equal(1)
expect(result[2].length).to.be.equal(2)
for (let i = 0; i < result.length; i++) {
for (const p of result[i]) {
expect(utils.isValidPrivateKey(p)).to.be.true
}
}
})
})
context('CAVERJS-UNIT-KEYRING-155: input: number of keys, entropy', () => {
it('should return valid a role-based private key strings', () => {
const entropy = caver.utils.randomHex(32)
const result = caver.wallet.keyring.generateRoleBasedKeys([2, 2, 2], entropy)
expect(result.length).to.be.equal(3)
expect(result[0].length).to.be.equal(2)
expect(result[1].length).to.be.equal(2)
expect(result[2].length).to.be.equal(2)
for (let i = 0; i < result.length; i++) {
for (const p of result[i]) {
expect(utils.isValidPrivateKey(p)).to.be.true
}
}
})
})
context('CAVERJS-UNIT-KEYRING-156: input: no parameter', () => {
it('should return error', () => {
const expectedError = `To generate random role-based private keys, an array containing the number of keys for each role should be defined.`
expect(() => caver.wallet.keyring.generateRoleBasedKeys()).to.throw(expectedError)
})
})
context('CAVERJS-UNIT-KEYRING-157: input: entropy', () => {
it('should return error', () => {
const entropy = caver.utils.randomHex(32)
const expectedError = `To generate random role-based private keys, an array containing the number of keys for each role should be defined.`
expect(() => caver.wallet.keyring.generateRoleBasedKeys(entropy)).to.throw(expectedError)
})
})
context('CAVERJS-UNIT-KEYRING-158: input: not array', () => {
it('should return error', () => {
const expectedError = `To generate random role-based private keys, an array containing the number of keys for each role should be defined.`
expect(() => caver.wallet.keyring.generateRoleBasedKeys(3)).to.throw(expectedError)
})
})
context('CAVERJS-UNIT-KEYRING-159: input: too long array', () => {
it('should return error', () => {
const expectedError = `Unsupported role. The length of array should be less than ${caver.wallet.keyring.role.roleLast}.`
expect(() => caver.wallet.keyring.generateRoleBasedKeys([1, 1, 1, 1, 1])).to.throw(expectedError)
})
})
})
describe('caver.wallet.keyring.createFromPrivateKey', () => {
context('CAVERJS-UNIT-KEYRING-005: input: single private key', () => {
it('should create Keyring instance from private key string', () => {
const keyring = caver.wallet.keyring.generate()
const result = caver.wallet.keyring.createFromPrivateKey(keyring.key.privateKey)
validateKeyring(result, { expectedAddress: keyring.address })
})
})
context('CAVERJS-UNIT-KEYRING-006: input: single private key(without 0x-hex prefixed)', () => {
it('should create Keyring instance from private key string', () => {
const keyring = caver.wallet.keyring.generate()
const result = caver.wallet.keyring.createFromPrivateKey(utils.stripHexPrefix(keyring.key.privateKey))
validateKeyring(result, { expectedAddress: keyring.address })
})
})
context('CAVERJS-UNIT-KEYRING-007: input: KlaytnWalletKey string', () => {
it('should create Keyring instance from KlaytnWalletKey string', () => {
const keyring = generateDecoupledKeyring()
const klaytnWalletKey = keyring.getKlaytnWalletKey()
const result = caver.wallet.keyring.createFromPrivateKey(klaytnWalletKey)
validateKeyring(result, { expectedKey: keyring.key, expectedAddress: keyring.address })
})
})
context('CAVERJS-UNIT-KEYRING-008: input: KlaytnWalletKey string(without 0x-hex prefixed)', () => {
it('should create Keyring instance from KlaytnWalletKey string', () => {
const keyring = generateDecoupledKeyring()
const klaytnWalletKey = keyring.getKlaytnWalletKey()
const result = caver.wallet.keyring.createFromPrivateKey(utils.stripHexPrefix(klaytnWalletKey))
validateKeyring(result, { expectedKey: keyring.key, expectedAddress: keyring.address })
})
})
context('CAVERJS-UNIT-KEYRING-009: input: invalid private key', () => {
it('should throw error', () => {
const invalidPrivateKey = caver.utils.randomHex(31)
const errormsg = `Invalid private key: ${invalidPrivateKey}`
expect(() => caver.wallet.keyring.createFromPrivateKey(invalidPrivateKey)).to.throws(errormsg)
})
})
})
describe('caver.wallet.keyring.createFromKlaytnWalletKey', () => {
context('CAVERJS-UNIT-KEYRING-010: input: valid KlaytnWalletKey', () => {
it('should create Keyring instance from KlaytnWalletKey', () => {
const keyring = generateDecoupledKeyring()
const klaytnWalletKey = keyring.getKlaytnWalletKey()
const result = caver.wallet.keyring.createFromKlaytnWalletKey(klaytnWalletKey)
validateKeyring(result, { expectedKey: keyring.key, expectedAddress: keyring.address })
})
})
context('CAVERJS-UNIT-KEYRING-011: input: invalid KlaytnWalletKey', () => {
it('should throw error', () => {
const invalidPrivateKey = '39d87f15c695ec94d6d7107b48dee85e252f21fedd371e1c6baefbdf0x000x658b7b7a94ac398a8e7275e719a10c'
const errormsg = `Invalid KlaytnWalletKey: ${invalidPrivateKey}`
expect(() => caver.wallet.keyring.createFromKlaytnWalletKey(invalidPrivateKey)).to.throws(errormsg)
})
})
})
describe('caver.wallet.keyring.create', () => {
context('CAVERJS-UNIT-KEYRING-012: input: address, single private key string', () => {
it('should create keyring instances with parameters', () => {
const keyring = caver.wallet.keyring.generate()
const created = caver.wallet.keyring.create(keyring.address, keyring.key.privateKey)
validateKeyring(created, { expectedAddress: keyring.address, expectedKey: keyring.key })
})
})
context('CAVERJS-UNIT-KEYRING-013: input: address, multiple private key strings', () => {
it('should create keyring instances with parameters and add to in-memory wallet', () => {
const address = caver.wallet.keyring.generate().address
const multiplePrivateKeys = caver.wallet.keyring.generateMultipleKeys(3)
const created = caver.wallet.keyring.create(address, multiplePrivateKeys)
validateKeyring(created, { expectedAddress: address, expectedKey: multiplePrivateKeys })
})
})
context('CAVERJS-UNIT-KEYRING-014: input: address, private keys by roles(without empty role)', () => {
it('should create keyring instances with parameters and add to in-memory wallet', () => {
const address = caver.wallet.keyring.generate().address
const roleBasedPrivateKeys = caver.wallet.keyring.generateRoleBasedKeys([3, 1, 2])
const created = caver.wallet.keyring.create(address, roleBasedPrivateKeys)
validateKeyring(created, { expectedAddress: address, expectedKey: roleBasedPrivateKeys })
})
})
context('CAVERJS-UNIT-KEYRING-015: input: address, private keys by roles(with empty role)', () => {
it('should create keyring instances with parameters and add to in-memory wallet', () => {
const address = caver.wallet.keyring.generate().address
const roleBasedPrivateKeys = caver.wallet.keyring.generateRoleBasedKeys([0, 0, 2])
const created = caver.wallet.keyring.create(address, roleBasedPrivateKeys)
validateKeyring(created, { expectedAddress: address, expectedKey: roleBasedPrivateKeys })
})
})
context('CAVERJS-UNIT-KEYRING-016: input: address, invalid key format', () => {
it('should throw error if key is invalid format', () => {
const address = caver.wallet.keyring.generate().address
const invalidKey = [
caver.wallet.keyring.generateSingleKey(),
[],
[caver.wallet.keyring.generateSingleKey(), caver.wallet.keyring.generateSingleKey()],
]
const expectedError = `Unsupported key type: ${typeof invalidKey}`
expect(() => caver.wallet.keyring.create(address, invalidKey)).to.throw(expectedError)
})
})
})
describe('caver.wallet.keyring.createWithSingleKey', () => {
context('CAVERJS-UNIT-KEYRING-017: input: coupled address, private key', () => {
it('should create Keyring instance', () => {
const coupled = caver.wallet.keyring.generate()
const prvString = coupled.key.privateKey
const result = caver.wallet.keyring.createWithSingleKey(coupled.address, prvString)
validateKeyring(result, { expectedKey: prvString, expectedAddress: coupled.address })
})
})
context('CAVERJS-UNIT-KEYRING-018: input: decoupled address, private key', () => {
it('should create Keyring instance', () => {
const decoupled = generateDecoupledKeyring()
const prvString = decoupled.key.privateKey
const result = caver.wallet.keyring.createWithSingleKey(decoupled.address, prvString)
validateKeyring(result, { expectedKey: prvString, expectedAddress: decoupled.address })
})
})
context('CAVERJS-UNIT-KEYRING-019: input: valid address, valid KlaytnWalletKey', () => {
it('should throw error', () => {
const keyring = caver.wallet.keyring.generate()
const klaytnWalletKey = keyring.getKlaytnWalletKey()
const errormsg = `Invalid format of parameter. Use 'fromKlaytnWalletKey' to create Keyring from KlaytnWalletKey.`
expect(() => caver.wallet.keyring.createWithSingleKey(keyring.address, klaytnWalletKey)).to.throws(errormsg)
})
})
context('CAVERJS-UNIT-KEYRING-020: input: valid address, multiple private key array', () => {
it('should throw error', () => {
const keyring = caver.wallet.keyring.generate()
const arr = caver.wallet.keyring.generateMultipleKeys(2)
const errormsg = `Invalid format of parameter. Use 'fromMultipleKey' or 'fromRoleBasedKey' for two or more keys.`
expect(() => caver.wallet.keyring.createWithSingleKey(keyring.address, arr)).to.throws(errormsg)
expect(() => caver.wallet.keyring.createWithSingleKey(keyring.address, undefined)).to.throws(errormsg)
expect(() => caver.wallet.keyring.createWithSingleKey(keyring.address, {})).to.throws(errormsg)
expect(() => caver.wallet.keyring.createWithSingleKey(keyring.address, [])).to.throws(errormsg)
})
})
})
describe('caver.wallet.keyring.createWithMultipleKey', () => {
context('CAVERJS-UNIT-KEYRING-021: input: valid address, valid private key array', () => {
it('should create Keyring instance', () => {
const keyring = caver.wallet.keyring.generate()
const arr = caver.wallet.keyring.generateMultipleKeys(2)
const result = caver.wallet.keyring.createWithMultipleKey(keyring.address, arr)
validateKeyring(result, { expectedKey: arr, expectedAddress: keyring.address })
})
})
context('CAVERJS-UNIT-KEYRING-022: input: valid address, invalid private key array', () => {
it('should throw error', () => {
const keyring = caver.wallet.keyring.generate()
const arr = [caver.utils.randomHex(31), caver.utils.randomHex(31)]
const errormsg = `Invalid private key: ${arr[0]}`
expect(() => caver.wallet.keyring.createWithMultipleKey(keyring.address, arr)).to.throws(errormsg)
})
})
context('CAVERJS-UNIT-KEYRING-023: input: valid address, invalid format of private key array', () => {
it('should throw error', () => {
const keyring = caver.wallet.keyring.generate()
let arr = caver.wallet.keyring.generateRoleBasedKeys([2])
const errormsg = `Invalid format of parameter. 'keyArray' should be an array of private key strings.`
expect(() => caver.wallet.keyring.createWithMultipleKey(keyring.address, arr)).to.throws(errormsg)
arr = [caver.wallet.keyring.generateSingleKey(), [caver.wallet.keyring.generateSingleKey()]]
expect(() => caver.wallet.keyring.createWithMultipleKey(keyring.address, arr)).to.throws(errormsg)
expect(() => caver.wallet.keyring.createWithMultipleKey(keyring.address, undefined)).to.throws(errormsg)
expect(() => caver.wallet.keyring.createWithMultipleKey(keyring.address, {})).to.throws(errormsg)
})
})
})
describe('caver.wallet.keyring.createWithRoleBasedKey', () => {
context('CAVERJS-UNIT-KEYRING-024: input: valid address, valid role based private key array', () => {
it('should create Keyring instance', () => {
const keyring = caver.wallet.keyring.generate()
const arr = caver.wallet.keyring.generateRoleBasedKeys([2, 1, 1])
const result = caver.wallet.keyring.createWithRoleBasedKey(keyring.address, arr)
validateKeyring(result, { expectedKey: arr, expectedAddress: keyring.address })
})
})
context('CAVERJS-UNIT-KEYRING-025: input: valid address, invalid role based private key format', () => {
it('should throw error if the role-based key does not define the key to be used for the role in the form of an array.', () => {
const keyring = caver.wallet.keyring.generate()
const arr = [
[caver.wallet.keyring.generateSingleKey(), caver.wallet.keyring.generateSingleKey()],
caver.wallet.keyring.generateSingleKey(),
caver.wallet.keyring.generateSingleKey(),
]
const expectedError = `Invalid format of parameter. 'roledBasedKeyArray' should be in the form of an array defined as an array for the keys to be used for each role.`
expect(() => caver.wallet.keyring.createWithRoleBasedKey(keyring.address, arr)).to.throw(expectedError)
})
})
context('CAVERJS-UNIT-KEYRING-026: input: valid address, invalid private key array', () => {
it('should throw error', () => {
const keyring = caver.wallet.keyring.generate()
const arr = [[caver.utils.randomHex(31), caver.utils.randomHex(31)]]
const errormsg = `Invalid private key: ${arr[0][0]}`
expect(() => caver.wallet.keyring.createWithRoleBasedKey(keyring.address, arr)).to.throws(errormsg)
})
})
context('CAVERJS-UNIT-KEYRING-027: input: valid address, invalid format of role based private key array (1 dimensional array)', () => {
it('should throw error', () => {
const keyring = caver.wallet.keyring.generate()
const arr = caver.wallet.keyring.generateMultipleKeys(2)
const errormsg = `Invalid format of parameter. 'roledBasedKeyArray' should be in the form of an array defined as an array for the keys to be used for each role.`
expect(() => caver.wallet.keyring.createWithRoleBasedKey(keyring.address, arr)).to.throws(errormsg)
expect(() => caver.wallet.keyring.createWithRoleBasedKey(keyring.address, caver.wallet.keyring.generateSingleKey())).to.throws(
errormsg
)
})
})
})
describe('caver.wallet.keyring.decrypt', () => {
context('CAVERJS-UNIT-KEYRING-043: coupled keyring', () => {
it('should return valid keyring', () => {
const password = 'password'
const privateKey = caver.wallet.keyring.generateSingleKey()
const keyring = caver.wallet.keyring.createFromPrivateKey(privateKey)
const encrypted = keyring.encrypt(password)
const decrypted = caver.wallet.keyring.decrypt(encrypted, password)
validateKeyring(decrypted, { expectedAddress: keyring.address, expectedKey: keyring.key })
})
})
context('CAVERJS-UNIT-KEYRING-044: decoupled keyring', () => {
it('should return valid keyring', () => {
const password = 'password'
const keyring = generateDecoupledKeyring()
const encrypted = keyring.encrypt(password)
const decrypted = caver.wallet.keyring.decrypt(encrypted, password)
validateKeyring(decrypted, { expectedAddress: keyring.address, expectedKey: keyring.key })
})
})
context('CAVERJS-UNIT-KEYRING-045: keyring that uses multiple private key', () => {
it('should return valid keyring', () => {
const password = 'password'
const keyring = generateMultiSigKeyring()
const encrypted = keyring.encrypt(password)
const decrypted = caver.wallet.keyring.decrypt(encrypted, password)
validateKeyring(decrypted, { expectedAddress: keyring.address, expectedKey: keyring.keys })
})
})
context('CAVERJS-UNIT-KEYRING-046: keyring that uses different private keys by roles', () => {
it('should return valid keyring', () => {
const password = 'password'
const keyring = generateRoleBasedKeyring()
const encrypted = keyring.encrypt(password)
const decrypted = caver.wallet.keyring.decrypt(encrypted, password)
validateKeyring(decrypted, { expectedAddress: keyring.address, expectedKey: keyring.keys })
})
})
context('CAVERJS-UNIT-KEYRING-047: keyring that uses different private keys by roles with empty role', () => {
it('should return valid keyring', () => {
const password = 'password'
const keyring = generateRoleBasedKeyring([2, 0, 1])
const encrypted = keyring.encrypt(password)
const decrypted = caver.wallet.keyring.decrypt(encrypted, password)
validateKeyring(decrypted, { expectedAddress: keyring.address, expectedKey: keyring.keys })
})
})
context('CAVERJS-UNIT-KEYRING-048: input: hard coded keystoreJsonV4 that encrypts Account, password', () => {
it('should return valid keyring', () => {
const password = 'password'
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 expectedAccount = caver.wallet.keyring.createWithRoleBasedKey('0x86bce8c859f5f304aa30adb89f2f7b6ee5a0d6e2', [
[
'0xd1e9f8f00ef9f93365f5eabccccb3f3c5783001b61a40f0f74270e50158c163d',
'0x4bd8d0b0c1575a7a35915f9af3ef8beb11ad571337ec9b6aca7c88ca7458ef5c',
],
['0xdc2690ac6017e32ef17ea219c2a2fd14a2bb73e7a0a253dfd69abba3eb8d7d91'],
[
'0xf17bf8b7bee09ffc50a401b7ba8e633b9e55eedcf776782f2a55cf7cc5c40aa8',
'0x4f8f1e9e1466609b836dba611a0a24628aea8ee11265f757aa346bde3d88d548',
],
])
const decrypted = caver.wallet.keyring.decrypt(keystoreJsonV4, password)
validateKeyring(decrypted, { expectedAddress: expectedAccount.address, expectedKey: expectedAccount.keys })
})
})
context('CAVERJS-UNIT-KEYRING-049: 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.wallet.keyring.createWithSingleKey(
'0x86bce8c859f5f304aa30adb89f2f7b6ee5a0d6e2',
'0x36e0a792553f94a7660e5484cfc8367e7d56a383261175b9abced7416a5d87df'
)
const result = caver.wallet.keyring.decrypt(keystoreJsonV3, password)
validateKeyring(result, { expectedKey: expectedAccount.key, expectedAddress: expectedAccount.address })
expect(keystoreJsonV3.crypto).not.to.be.undefined
})
})
})
describe('keyring.getPublicKey', () => {
context('CAVERJS-UNIT-KEYRING-053: keyring type: coupled', () => {
it('return single public key with roled form', () => {
const keyring = caver.wallet.keyring.generate()
const pubKey = keyring.getPublicKey()
expect(pubKey).to.equal(keyring.key.getPublicKey())
})
})
context('CAVERJS-UNIT-KEYRING-054: keyring type: decoupled', () => {
it('return single public key with roled form', () => {
const keyring = generateDecoupledKeyring()
const pubKey = keyring.getPublicKey()
expect(pubKey).to.equal(keyring.key.getPublicKey())
})
})
context('CAVERJS-UNIT-KEYRING-055: keyring type: multiple keys', () => {
it('return multiple public keys with roled form', () => {
const keyring = generateMultiSigKeyring(2)
const pubKey = keyring.getPublicKey()
expect(pubKey[0]).to.equal(keyring.keys[0].getPublicKey())
expect(pubKey[1]).to.equal(keyring.keys[1].getPublicKey())
})
})
context('CAVERJS-UNIT-KEYRING-056: keyring type: role based keys', () => {
it('return role based public keys with roled form', () => {
const keyring = generateRoleBasedKeyring([2, 3, 1])
const pubKey = keyring.getPublicKey()
expect(pubKey[0][0]).to.equal(keyring.keys[0][0].getPublicKey())
expect(pubKey[0][1]).to.equal(keyring.keys[0][1].getPublicKey())
expect(pubKey[1][0]).to.equal(keyring.keys[1][0].getPublicKey())
expect(pubKey[1][1]).to.equal(keyring.keys[1][1].getPublicKey())
expect(pubKey[1][2]).to.equal(keyring.keys[1][2].getPublicKey())
expect(pubKey[2][0]).to.equal(keyring.keys[2][0].getPublicKey())
expect(pubKey[0].length).to.equal(2)
expect(pubKey[1].length).to.equal(3)
expect(pubKey[2].length).to.equal(1)
})
})
context('CAVERJS-UNIT-KEYRING-166: keyring type: coupled, compressed: true', () => {
it('return single public key with roled form', () => {
const keyring = caver.wallet.keyring.generate()
const pubKey = keyring.getPublicKey(true)
expect(pubKey).to.equal(keyring.key.getPublicKey(true))
})
})
context('CAVERJS-UNIT-KEYRING-167: keyring type: decoupled, compressed: true', () => {
it('return single public key with roled form', () => {
const keyring = generateDecoupledKeyring()
const pubKey = keyring.getPublicKey(true)
expect(pubKey).to.equal(keyring.key.getPublicKey(true))
})
})
context('CAVERJS-UNIT-KEYRING-168: keyring type: multiple keys, compressed: true', () => {
it('return multiple public keys with roled form', () => {
const keyring = generateMultiSigKeyring(2)
const pubKey = keyring.getPublicKey(true)
expect(pubKey[0]).to.equal(keyring.keys[0].getPublicKey(true))
expect(pubKey[1]).to.equal(keyring.keys[1].getPublicKey(true))
})
})
context('CAVERJS-UNIT-KEYRING-169: keyring type: role based keys, compressed: true', () => {
it('return role based public keys with roled form', () => {
const keyring = generateRoleBasedKeyring([2, 3, 1])
const pubKey = keyring.getPublicKey(true)
expect(pubKey[0][0]).to.equal(keyring.keys[0][0].getPublicKey(true))
expect(pubKey[0][1]).to.equal(keyring.keys[0][1].getPublicKey(true))
expect(pubKey[1][0]).to.equal(keyring.keys[1][0].getPublicKey(true))
expect(pubKey[1][1]).to.equal(keyring.keys[1][1].getPublicKey(true))
expect(pubKey[1][2]).to.equal(keyring.keys[1][2].getPublicKey(true))
expect(pubKey[2][0]).to.equal(keyring.keys[2][0].getPublicKey(true))
expect(pubKey[0].length).to.equal(2)
expect(pubKey[1].length).to.equal(3)
expect(pubKey[2].length).to.equal(1)
})
})
})
describe('keyring.copy', () => {
context('CAVERJS-UNIT-KEYRING-057: keyring type: coupled', () => {
it('return copied coupled keyring', () => {
const keyring = caver.wallet.keyring.generate()
const copied = keyring.copy()
validateKeyring(copied, { expectedAddress: keyring.address, expectedKey: keyring.key })
})
})
context('CAVERJS-UNIT-KEYRING-058: keyring type: decoupled', () => {
it('return copied decoupled keyring', () => {
const keyring = generateDecoupledKeyring()
const copied = keyring.copy()
validateKeyring(copied, { expectedAddress: keyring.address, expectedKey: keyring.key })
})
})
context('CAVERJS-UNIT-KEYRING-059: keyring type: multiple keys', () => {
it('return copied keyring which uses multiple keys', () => {
const keyring = generateMultiSigKeyring(2)
const copied = keyring.copy()
validateKeyring(copied, { expectedAddress: keyring.address, expectedKey: keyring.keys })
})
})
context('CAVERJS-UNIT-KEYRING-060: keyring type: role based keys', () => {
it('return copied keyring which uses different keys by roles', () => {
const keyring = generateRoleBasedKeyring([2, 3, 1])
const copied = keyring.copy()
validateKeyring(copied, { expectedAddress: keyring.address, expectedKey: keyring.keys })
})
})
})
describe('keyring.sign', () => {
let coupled
let decoupled
let multiSig
let roleBased
const hash = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550'
const chainId = 10000
beforeEach(() => {
coupled = caver.wallet.keyring.generate()
decoupled = generateDecoupledKeyring()
multiSig = generateMultiSigKeyring(3)
roleBased = generateRoleBasedKeyring([3, 0, 3])
})
context('CAVERJS-UNIT-KEYRING-061: keyring type: coupled / role: existed role / index: undefined', () => {
it('return one signature array', () => {
const signSpy = sinon.spy(coupled.key, 'sign')
const signed = coupled.sign(hash, chainId, caver.wallet.keyring.role.roleTransactionKey)
expect(signSpy).to.have.been.calledOnce
expect(_.isArray(signed)).to.be.true
expect(signed[0] instanceof SignatureData).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-062: keyring type: coupled / role: existed role / index: 0', () => {
it('return one signature array', () => {
const signSpy = sinon.spy(coupled.key, 'sign')
const signed = coupled.sign(hash, chainId, caver.wallet.keyring.role.roleTransactionKey, 0)
expect(signSpy).to.have.been.calledOnce
expect(signed instanceof SignatureData).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-063: keyring type: coupled / role: not existed role / index: 0', () => {
it('return sign with default role key and return one signature array', () => {
const signSpy = sinon.spy(coupled.key, 'sign')
const signed = coupled.sign(hash, chainId, caver.wallet.keyring.role.roleAccountUpdateKey, 0)
expect(signSpy).to.have.been.calledOnce
expect(signed instanceof SignatureData).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-064: keyring type: coupled / role: existed role / index: out of range', () => {
it('should throw error when index is out of range', () => {
const invalidIndex = 1
const expectedError = `Invalid index(${invalidIndex}): index must be less than the length of keys(1).`
expect(() => coupled.sign(hash, chainId, caver.wallet.keyring.role.roleTransactionKey, invalidIndex)).to.throw(expectedError)
})
})
context('CAVERJS-UNIT-KEYRING-065: keyring type: decoupled / role: existed role / index: undefined', () => {
it('return return one signature array', () => {
const signSpy = sinon.spy(decoupled.key, 'sign')
const signed = decoupled.sign(hash, chainId, caver.wallet.keyring.role.roleTransactionKey)
expect(signSpy).to.have.been.calledOnce
expect(_.isArray(signed)).to.be.true
expect(signed[0] instanceof SignatureData).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-066: keyring type: decoupled / role: existed role / index: 0', () => {
it('return return one signature array', () => {
const signSpy = sinon.spy(decoupled.key, 'sign')
const signed = decoupled.sign(hash, chainId, caver.wallet.keyring.role.roleTransactionKey, 0)
expect(signSpy).to.have.been.calledOnce
expect(signed instanceof SignatureData).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-067: keyring type: decoupled / role: not existed role / index: 0', () => {
it('return sign with default role key and return one signature array', () => {
const signSpy = sinon.spy(decoupled.key, 'sign')
const signed = decoupled.sign(hash, chainId, caver.wallet.keyring.role.roleAccountUpdateKey, 0)
expect(signSpy).to.have.been.calledOnce
expect(signed instanceof SignatureData).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-068: keyring type: decoupled / role: existed role / index: out of range', () => {
it('should throw error when index is out of range', () => {
const invalidIndex = 2
const expectedError = `Invalid index(${invalidIndex}): index must be less than the length of keys(1).`
expect(() => decoupled.sign(hash, chainId, caver.wallet.keyring.role.roleTransactionKey, invalidIndex)).to.throw(expectedError)
})
})
context('CAVERJS-UNIT-KEYRING-069: keyring type: multiSig / role: existed role / index: undefined', () => {
it('return return multiple signatures array', () => {
const signSpy = sinon.spy(multiSig.keys[0], 'sign')
const signed = multiSig.sign(hash, chainId, caver.wallet.keyring.role.roleTransactionKey)
expect(signSpy).to.have.been.calledOnce
expect(_.isArray(signed)).to.be.true
expect(signed[0] instanceof SignatureData).to.be.true
expect(signed.length).to.equal(multiSig.keys.length)
})
})
context('CAVERJS-UNIT-KEYRING-070: keyring type: multiSig / role: existed role / index: 2', () => {
it('return return one signature array', () => {
const signSpy = sinon.spy(multiSig.keys[2], 'sign')
const signed = multiSig.sign(hash, chainId, caver.wallet.keyring.role.roleTransactionKey, 2)
expect(signSpy).to.have.been.calledOnce
expect(signed instanceof SignatureData).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-071: keyring type: multiSig / role: not existed role / index: 0', () => {
it('return sign with default role key and return one signature array', () => {
const signSpy = sinon.spy(multiSig.keys[0], 'sign')
const signed = multiSig.sign(hash, chainId, caver.wallet.keyring.role.roleAccountUpdateKey, 0)
expect(signSpy).to.have.been.calledOnce
expect(signed instanceof SignatureData).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-072: keyring type: multiSig / role: existed role / index: out of range', () => {
it('should throw error when index is out of range', () => {
const invalidIndex = multiSig.keys.length
const expectedError = `Invalid index(${invalidIndex}): index must be less than the length of keys(${multiSig.keys.length}).`
expect(() => multiSig.sign(hash, chainId, caver.wallet.keyring.role.roleTransactionKey, invalidIndex)).to.throw(expectedError)
})
})
context('CAVERJS-UNIT-KEYRING-073: keyring type: roleBased / role: existed role / index: undefined', () => {
it('return return one signature array', () => {
const signSpy = sinon.spy(roleBased.keys[0][0], 'sign')
const signed = roleBased.sign(hash, chainId, caver.wallet.keyring.role.roleTransactionKey)
expect(signSpy).to.have.been.calledOnce
expect(_.isArray(signed)).to.be.true
expect(signed[0] instanceof SignatureData).to.be.true
expect(signed.length).to.equal(roleBased.roleTransactionKey.length)
})
})
context('CAVERJS-UNIT-KEYRING-074: keyring type: roleBased / role: existed role / index: 2', () => {
it('return return one signature array', () => {
const signSpy = sinon.spy(roleBased.keys[2][2], 'sign')
const signed = roleBased.sign(hash, chainId, caver.wallet.keyring.role.roleFeePayerKey, 2)
expect(signSpy).to.have.been.calledOnce
expect(signed instanceof SignatureData).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-075: keyring type: roleBased / role: not existed role / index: 0', () => {
it('return sign with default role key and return one signature array', () => {
const signSpy = sinon.spy(roleBased.keys[0][0], 'sign')
const signed = roleBased.sign(hash, chainId, caver.wallet.keyring.role.roleAccountUpdateKey, 0)
expect(signSpy).to.have.been.calledOnce
expect(signed instanceof SignatureData).to.be.true
})
})
context('CAVERJS-UNIT-KEYRING-076: keyring type: roleBased / role: existed role / index: out of range', () => {
it('should throw error when index is out of range', () => {
const invalidIndex = roleBased.keys[0].length
const expectedError = `Invalid index(${invalidIndex}): index