From 8b940a2de87b5e039e3d50304b8afc32154e83c9 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 27 Aug 2019 17:25:03 +0900 Subject: [PATCH 001/123] Add caver.utils test case numbering and test cases --- test/packages/caver.klay.utils.js | 1131 +++++++++++++++-------------- 1 file changed, 587 insertions(+), 544 deletions(-) diff --git a/test/packages/caver.klay.utils.js b/test/packages/caver.klay.utils.js index 1539540d..a85a8653 100644 --- a/test/packages/caver.klay.utils.js +++ b/test/packages/caver.klay.utils.js @@ -24,6 +24,7 @@ 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(() => { @@ -31,19 +32,16 @@ beforeEach(() => { }) 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('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('input: invalid value', () => { + 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' @@ -54,233 +52,192 @@ describe('caver.utils.randomHex', () => { }) 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('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('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) - } - ) + 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', () => { - 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('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('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) - } - ) + 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('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('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('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('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('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) - } - ) + 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('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('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('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('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('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) - }) + 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('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('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('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) - }) + 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('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('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('input: invalid address', () => { - it.each([ - ['0xC1912fEE45d61C87Cc5EA59DaE31190FFFFf232d', false] - ], - 'should return false', - ([address, expected]) => { - const data = caver.utils.isAddress(address) - expect(data).to.be.equal(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('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('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('input: invalid address', () => { + 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.` @@ -290,77 +247,148 @@ describe('caver.utils.toChecksumAddress', () => { }) 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('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('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) - } - ) + 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('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('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.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('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('input: invalid value', () => { + 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}"` @@ -370,47 +398,39 @@ describe('caver.utils.toBN', () => { }) 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('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('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('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('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('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('input: invalid hexString', () => { + 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}"` @@ -423,24 +443,20 @@ describe('caver.utils.hexToNumberString', () => { // 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('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('input: invalid value', () => { + 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}"` @@ -450,31 +466,64 @@ describe('caver.utils.hexToNumber', () => { }) 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('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('input: invalid number', () => { + 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.` @@ -485,20 +534,22 @@ describe('caver.utils.numberToHex', () => { }) 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('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('input: invalid hexString', () => { + 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.` @@ -510,20 +561,23 @@ describe('caver.utils.hexToUtf8', () => { 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('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('input: invalid hexString', () => { + 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.` @@ -533,36 +587,41 @@ describe('caver.utils.hexToAscii', () => { }) }) -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('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('input: hexString \'0x000000ea\'', () => { + context('CAVERJS-UNIT-ETC-134: input: hexString \'0x000000ea\'', () => { it('should return bytes', () => { const hex = '0x000000ea' @@ -572,7 +631,7 @@ describe('caver.utils.hexToBytes', () => { }) }) - context('input: invalid hexString', () => { + 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.` @@ -585,197 +644,181 @@ describe('caver.utils.hexToBytes', () => { }) }) -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('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 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('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('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) - } - ) + 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 BN = require('bn.js') - const BigNumber = require('bignumber.js') - 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) + } + ) + }) - 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) - } - ) + 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('should return 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('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('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('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) - } - ) + 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: 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: 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', () => { - 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) - } - ) + 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('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('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('caver.utils.isHexPrefixed', () => { +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('01')).to.be.false @@ -783,7 +826,7 @@ describe('caver.utils.isHexPrefixed', () => { }) }) -describe('caver.utils.addHexPrefix', () => { +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') @@ -791,7 +834,7 @@ describe('caver.utils.addHexPrefix', () => { }) }) -describe('caver.utils.stripHexPrefix', () => { +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') @@ -801,28 +844,28 @@ describe('caver.utils.stripHexPrefix', () => { }) describe('caver.utils.toBuffer', () => { - it('caver.utils.toBuffer should return input when input is Buffer', ()=>{ + 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('caver.utils.toBuffer should convert null or undefined to 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('caver.utils.toBuffer should convert Array to buffer', ()=>{ + 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('caver.utils.toBuffer should convert BN to buffer', ()=>{ + 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('caver.utils.toBuffer should convert Object has toArray function to buffer', ()=>{ + 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('caver.utils.toBuffer should convert String to buffer', ()=>{ + 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') @@ -830,17 +873,17 @@ describe('caver.utils.toBuffer', () => { 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', ()=>{ + 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('caver.utils.toBuffer should throw error when input type is not supported with toBuffer function', ()=>{ + 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('caver.utils.toBuffer should throw error when String is not 0x-prefixed', ()=>{ + 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`) @@ -849,7 +892,7 @@ describe('caver.utils.toBuffer', () => { }) }) -describe('caver.utils.numberToBuffer', () => { +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') @@ -861,14 +904,14 @@ describe('caver.utils.numberToBuffer', () => { }) describe('caver.utils.isHexParameter', () => { - it('caver.utils.isHexParameter should return true if input is hex string', ()=>{ + 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('caver.utils.isHexParameter should return false if input is not hex string', ()=>{ + 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 @@ -890,7 +933,7 @@ describe('caver.utils.isHexParameter', () => { }) describe('caver.utils.xyPointFromPublicKey', () => { - it('caver.utils.xyPointFromPublicKey should return x, y point from publicKey', ()=>{ + 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) @@ -899,7 +942,7 @@ describe('caver.utils.xyPointFromPublicKey', () => { 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', ()=>{ + 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' From 8144cbb0a26e4a5a07c3c8b124b8d3f021adcdf2 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 27 Aug 2019 17:26:49 +0900 Subject: [PATCH 002/123] Add script to etcTest --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d9593a06..91942f77 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "serTest": "mocha test/transactionType/serializationTest.js && mocha test/compressPublicKey.js && mocha test/encodeContractDeploy.js && mocha test/isCompressedPublicKey.js && mocha test/parseAccountKey.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", + "etcTest": "mocha test/packages/caver.klay.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", "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", From 1417665574ed54f1b26460dba5e6f140058ef8ed Mon Sep 17 00:00:00 2001 From: "Jenny(Yirey Suh)" Date: Wed, 28 Aug 2019 10:20:26 +0900 Subject: [PATCH 003/123] add isTxHash function --- packages/caver-utils/src/index.js | 1 + packages/caver-utils/src/utils.js | 11 +++++++++++ test/packages/caver.klay.utils.js | 33 +++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/packages/caver-utils/src/index.js b/packages/caver-utils/src/index.js index 107d86af..f4f79e6d 100644 --- a/packages/caver-utils/src/index.js +++ b/packages/caver-utils/src/index.js @@ -505,6 +505,7 @@ module.exports = { padRight: utils.rightPad, rightPad: utils.rightPad, toTwosComplement: utils.toTwosComplement, + isTxHash: utils.isTxHash, // Moved promiEvent to utils, promiEvent: promiEvent, Iban: Iban, diff --git a/packages/caver-utils/src/utils.js b/packages/caver-utils/src/utils.js index c4fc3d55..374559ce 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,14 @@ 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) + /** * Returns true if given string is a valid Klaytn block header bloom. @@ -717,4 +727,5 @@ module.exports = { txTypeToString, isCompressedPublicKey, compressPublicKey, + isTxHash, }; diff --git a/test/packages/caver.klay.utils.js b/test/packages/caver.klay.utils.js index a85a8653..9d339f6c 100644 --- a/test/packages/caver.klay.utils.js +++ b/test/packages/caver.klay.utils.js @@ -337,6 +337,39 @@ describe('CAVERJS-UNIT-ETC-117: caver.utils.toHex', () => { }) }) +describe('caver.utils.isTxHash', () => { + const example = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550' + context('input: valid transaction hex', () => { + it.each([ + [example, true], // all lower long + [example.slice(2), true], // all lower short + [example.toUpperCase(), true], // all upper long + [example.slice(2).toUpperCase(), true], // all upper short + [example.slice(0, 10) + example.slice(10).toUpperCase(), true], // mixed long + [example.slice(2, 10) + example.slice(10).toUpperCase(), true], // mixed short + ], + 'should return true', + ([tx, expected]) => { + const result = caver.utils.isTxHash(tx) + expect(result).to.be.equal(expected) + }) + }) + + context('input: invalid transaction hex', () => { + it.each([ + [example.slice(4), false], // length is not enough (62) + [`${example.slice(0, 62)}ZZ`, false], // not hex + [`${example.slice(2)}00`, false], // length is too long (66 without 0x) + [`${example}00`, false], // length is too long (68) + ], + 'should return false', + ([tx, expected]) => { + const result = caver.utils.isTxHash(tx) + expect(result).to.be.equal(expected) + }) + }) +}) + describe('caver.utils.toBN', () => { context('CAVERJS-UNIT-ETC-118: input: valid value', () => { const tests = [ From 3876752c955d62102a9874a9ec34f82bd5cc62d1 Mon Sep 17 00:00:00 2001 From: "Jenny(Yirey Suh)" Date: Wed, 28 Aug 2019 10:20:55 +0900 Subject: [PATCH 004/123] add isTxHashStrict function --- packages/caver-utils/src/index.js | 1 + packages/caver-utils/src/utils.js | 8 ++++++++ test/packages/caver.klay.utils.js | 30 ++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/packages/caver-utils/src/index.js b/packages/caver-utils/src/index.js index f4f79e6d..1d15423c 100644 --- a/packages/caver-utils/src/index.js +++ b/packages/caver-utils/src/index.js @@ -506,6 +506,7 @@ module.exports = { rightPad: utils.rightPad, toTwosComplement: utils.toTwosComplement, isTxHash: utils.isTxHash, + isTxHashStrict: utils.isTxHashStrict, // Moved promiEvent to utils, promiEvent: promiEvent, Iban: Iban, diff --git a/packages/caver-utils/src/utils.js b/packages/caver-utils/src/utils.js index 374559ce..a4012a7b 100644 --- a/packages/caver-utils/src/utils.js +++ b/packages/caver-utils/src/utils.js @@ -408,6 +408,13 @@ var isHex = function (hex) { */ 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. @@ -728,4 +735,5 @@ module.exports = { isCompressedPublicKey, compressPublicKey, isTxHash, + isTxHashStrict, }; diff --git a/test/packages/caver.klay.utils.js b/test/packages/caver.klay.utils.js index 9d339f6c..d0b9c38c 100644 --- a/test/packages/caver.klay.utils.js +++ b/test/packages/caver.klay.utils.js @@ -337,6 +337,36 @@ describe('CAVERJS-UNIT-ETC-117: caver.utils.toHex', () => { }) }) +describe('caver.utils.isTxHashStrict', () => { + const example = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550' + context('input: valid strict transaction hex', () => { + it.each([ + [example, true], // all lower + [example.toUpperCase(), true], // all upper + [example.slice(0, 10) + example.slice(10).toUpperCase(), true], // mixed + ], + 'should return true', + ([tx, expected]) => { + const result = caver.utils.isTxHashStrict(tx) + expect(result).to.be.equal(expected) + }) + }) + + context('input: invalid strict transaction hex', () => { + it.each([ + [`00${example.slice(2)}`, false], // doesn't start with 0x + [example.slice(2), false], // doesn't start with 0x + [`${example.slice(0, 64)}ZZ`, false], // not hex + [example.slice(0, 10), false], // length is not enough + ], + 'should return false', + ([tx, expected]) => { + const result = caver.utils.isTxHashStrict(tx) + expect(result).to.be.equal(expected) + }) + }) +}) + describe('caver.utils.isTxHash', () => { const example = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550' context('input: valid transaction hex', () => { From 8046d46732273914b0d20bf5f3f04f0c44a8a61a Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 28 Aug 2019 11:34:17 +0900 Subject: [PATCH 005/123] Numbering additional test case with caver.utils --- test/packages/caver.klay.utils.js | 86 ++++++++++++++----------------- 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/test/packages/caver.klay.utils.js b/test/packages/caver.klay.utils.js index d0b9c38c..d87869d3 100644 --- a/test/packages/caver.klay.utils.js +++ b/test/packages/caver.klay.utils.js @@ -338,64 +338,56 @@ describe('CAVERJS-UNIT-ETC-117: caver.utils.toHex', () => { }) describe('caver.utils.isTxHashStrict', () => { - const example = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550' - context('input: valid strict transaction hex', () => { - it.each([ - [example, true], // all lower - [example.toUpperCase(), true], // all upper - [example.slice(0, 10) + example.slice(10).toUpperCase(), true], // mixed - ], - 'should return true', - ([tx, expected]) => { - const result = caver.utils.isTxHashStrict(tx) - expect(result).to.be.equal(expected) + 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('input: invalid strict transaction hex', () => { - it.each([ - [`00${example.slice(2)}`, false], // doesn't start with 0x - [example.slice(2), false], // doesn't start with 0x - [`${example.slice(0, 64)}ZZ`, false], // not hex - [example.slice(0, 10), false], // length is not enough - ], - 'should return false', - ([tx, expected]) => { - const result = caver.utils.isTxHashStrict(tx) - expect(result).to.be.equal(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 example = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550' - context('input: valid transaction hex', () => { - it.each([ - [example, true], // all lower long - [example.slice(2), true], // all lower short - [example.toUpperCase(), true], // all upper long - [example.slice(2).toUpperCase(), true], // all upper short - [example.slice(0, 10) + example.slice(10).toUpperCase(), true], // mixed long - [example.slice(2, 10) + example.slice(10).toUpperCase(), true], // mixed short - ], - 'should return true', - ([tx, expected]) => { - const result = caver.utils.isTxHash(tx) - expect(result).to.be.equal(expected) + 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('input: invalid transaction hex', () => { - it.each([ - [example.slice(4), false], // length is not enough (62) - [`${example.slice(0, 62)}ZZ`, false], // not hex - [`${example.slice(2)}00`, false], // length is too long (66 without 0x) - [`${example}00`, false], // length is too long (68) - ], - 'should return false', - ([tx, expected]) => { - const result = caver.utils.isTxHash(tx) - expect(result).to.be.equal(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) }) }) }) From 3c2e00c976ba830055934ab47685c0e792ba44ef Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 28 Aug 2019 15:34:47 +0900 Subject: [PATCH 006/123] Change file name with caver.utils --- test/packages/{caver.klay.utils.js => caver.utils.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/packages/{caver.klay.utils.js => caver.utils.js} (100%) diff --git a/test/packages/caver.klay.utils.js b/test/packages/caver.utils.js similarity index 100% rename from test/packages/caver.klay.utils.js rename to test/packages/caver.utils.js From e511256d4ce1d189fe5adbdc113790871341f8d2 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 28 Aug 2019 15:35:02 +0900 Subject: [PATCH 007/123] Modify script with modificated file name --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 91942f77..f7367b4e 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,13 @@ "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", "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/packages/caver.klay.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", + "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", "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", From 218609a60785bc4939930852dcbaa90c38dd68cb Mon Sep 17 00:00:00 2001 From: Albert Nah Date: Mon, 2 Sep 2019 11:35:42 +0900 Subject: [PATCH 008/123] Update package.json for git repo --- package.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/package.json b/package.json index 8650fa73..355e8ed2 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,14 @@ "klaytn sdk", "klaytn api" ], + "repository": { + "type": "git", + "url": "git+https://github.com/klaytn/caver-js.git" + }, + "bugs": { + "url": "https://github.com/klaytn/caver-js/issues" + }, + "homepage": "https://github.com/klaytn/caver-js#readme", "author": "Klaytn Team", "license": "LGPL", "dependencies": { From d1b9548448409f12e28785fb939509031c399270 Mon Sep 17 00:00:00 2001 From: Jeongho Albert Nah Date: Mon, 2 Sep 2019 16:26:56 +0900 Subject: [PATCH 009/123] Update package.json Co-Authored-By: Jasmine <32922423+jimni1222@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 355e8ed2..746d724e 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "bugs": { "url": "https://github.com/klaytn/caver-js/issues" }, - "homepage": "https://github.com/klaytn/caver-js#readme", + "homepage": "https://github.com/klaytn/caver-js", "author": "Klaytn Team", "license": "LGPL", "dependencies": { From 16565b3ea73487ec827069c5a71ddedf4f41da54 Mon Sep 17 00:00:00 2001 From: Jeongho Albert Nah Date: Mon, 2 Sep 2019 16:27:01 +0900 Subject: [PATCH 010/123] Update package.json Co-Authored-By: Jasmine <32922423+jimni1222@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 746d724e..3955412f 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ ], "repository": { "type": "git", - "url": "git+https://github.com/klaytn/caver-js.git" + "url": "https://github.com/klaytn/caver-js.git" }, "bugs": { "url": "https://github.com/klaytn/caver-js/issues" From ea870be979311f5de92bd0810e9193305e7aff83 Mon Sep 17 00:00:00 2001 From: Jongsic Date: Mon, 2 Sep 2019 20:11:59 +0900 Subject: [PATCH 011/123] Fix setProvider bug --- packages/caver-klay/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From 642bcfc7483c7790a6bd54749b720a1b56f69c39 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 3 Sep 2019 10:53:58 +0900 Subject: [PATCH 012/123] Change library scrypt.js to scryptsy --- package.json | 2 +- .../caver-klay-accounts/src/index.js | 6 +- .../caver-klay-accounts/src/scrypt.js | 92 +++++++++++++++++++ 3 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 packages/caver-klay/caver-klay-accounts/src/scrypt.js diff --git a/package.json b/package.json index 3a0824cd..3eb69900 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,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-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 060792a6..97335207 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -35,7 +35,7 @@ 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'); @@ -470,7 +470,7 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) { kdfparams = json.crypto.kdfparams; // FIXME: support progress reporting callback - derivedKey = scryptsy(new Buffer(password), new Buffer(kdfparams.salt, 'hex'), kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen); + derivedKey = scrypt(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; @@ -589,7 +589,7 @@ Accounts.prototype.encrypt = function (privateKey, password, options) { 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); + derivedKey = scrypt(new Buffer(password), salt, kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen); } else { throw new Error('Unsupported kdf'); } 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; From 5f5b38fe044f28d6c0c13e58ec7253b8ea660fb4 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 4 Sep 2019 13:37:40 +0900 Subject: [PATCH 013/123] Handle multi signature in decodeTransaction --- .../src/makeRawTransaction.js | 88 ++++++++++--------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js index 1e019c9c..08156685 100644 --- a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js +++ b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js @@ -138,7 +138,7 @@ 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.signature) } return _combineSenderRawTransaction(rlpEncoded, sig) } @@ -155,7 +155,8 @@ function _combineSenderRawTransaction(rlpEncoded, sig) { let [data] = decodedValues let [txType, ...rawTx] = RLP.decode(data) - rawTx = [...rawTx, [sig]] + if (!Array.isArray(sig[0])) sig = [sig] + rawTx = [...rawTx, sig] // set default feepayer's information in rawTx const typeString = utils.getTxTypeStringFromRawTransaction(txType) @@ -164,13 +165,14 @@ function _combineSenderRawTransaction(rlpEncoded, sig) { return txType + RLP.encode(rawTx).slice(2) } -function _combineFeePayerRawTransaction(rlpEncoded, sig, transaction, [senderV, senderR, senderS]) { +function _combineFeePayerRawTransaction(rlpEncoded, sig, 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(sig[0])) sig = [sig] + rawTx = [...rawTx, senderSignature, transaction.feePayer.toLowerCase(), sig] return txType + RLP.encode(rawTx).slice(2) } @@ -189,86 +191,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, signature: [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, signature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, feeRatio, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } } 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, signature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, data, feeRatio, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } } 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, signature ] = RLP.decode(rawTransaction) + return parseAccountKey({ type: typeString, nonce, gasPrice, gas, from, accountKey, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature }) } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return parseAccountKey({ type: typeString, nonce, gasPrice, gas, from, accountKey, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature }) } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return parseAccountKey({ type: typeString, nonce, gasPrice, gas, from, accountKey, feeRatio, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature }) } 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, signature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, codeFormat, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, codeFormat, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, feeRatio, codeFormat, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } } 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, signature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, data, feeRatio, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } } 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, signature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, from, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, from, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } } 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, from, feeRatio, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } } 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, signature ] = RLP.decode(rawTransaction) + return { type: typeString, nonce, gasPrice, gas, to, value, from, anchoredData:data, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } } } } From 662fb669588e94b8f104408191246761714468d2 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 4 Sep 2019 13:38:00 +0900 Subject: [PATCH 014/123] Add multi signature decode test case --- test/decodeTransaction.js | 70 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/test/decodeTransaction.js b/test/decodeTransaction.js index 74da64be..75e12b17 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.signature).not.to.be.undefined + expect(decodedTx.signature[0][0]).to.equals(decodedTx.v) + expect(decodedTx.signature[0][1]).to.equals(decodedTx.r) + expect(decodedTx.signature[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.signature).not.to.be.undefined + expect(decodedTx.signature[0][0]).to.equals(decodedTx.v) + expect(decodedTx.signature[0][1]).to.equals(decodedTx.r) + expect(decodedTx.signature[0][2]).to.equals(decodedTx.s) expect(decodedTx.feePayer).to.equals(payer.address) expect(decodedTx.payerV).not.to.undefined expect(decodedTx.payerR).not.to.undefined expect(decodedTx.payerS).not.to.undefined + expect(decodedTx.feePayerSignature).not.to.be.undefined + expect(decodedTx.feePayerSignature[0][0]).to.equals(decodedTx.payerV) + expect(decodedTx.feePayerSignature[0][1]).to.equals(decodedTx.payerR) + expect(decodedTx.feePayerSignature[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.signature).not.to.be.undefined + expect(Array.isArray(decodedTx.signature)).to.be.true + expect(decodedTx.signature.length).to.equals(2) + expect(decodedTx.signature[0][0]).to.equals(decodedTx.v) + expect(decodedTx.signature[0][1]).to.equals(decodedTx.r) + expect(decodedTx.signature[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.signature).not.to.be.undefined + expect(Array.isArray(decodedTx.signature)).to.be.true + expect(decodedTx.signature.length).to.equals(2) + expect(decodedTx.signature[0][0]).to.equals(decodedTx.v) + expect(decodedTx.signature[0][1]).to.equals(decodedTx.r) + expect(decodedTx.signature[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.feePayerSignature).not.to.be.undefined + expect(Array.isArray(decodedTx.feePayerSignature)).to.be.true + expect(decodedTx.feePayerSignature.length).to.equals(2) + expect(decodedTx.feePayerSignature[0][0]).to.equals(decodedTx.payerV) + expect(decodedTx.feePayerSignature[0][1]).to.equals(decodedTx.payerR) + expect(decodedTx.feePayerSignature[0][2]).to.equals(decodedTx.payerS) }).timeout(10000) }) \ No newline at end of file From e854b936b21bfa61bd2aac2ef54d04d60d19e71c Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 4 Sep 2019 13:40:13 +0900 Subject: [PATCH 015/123] Remove useless await and add check for test result --- test/intTest.js | 6 +- test/transactionType/serializationTest.js | 192 ++++++++++++++++++---- 2 files changed, 163 insertions(+), 35 deletions(-) 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/transactionType/serializationTest.js b/test/transactionType/serializationTest.js index 7c73f7cc..70180248 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.signature).not.to.be.undefined + expect(txObj.signature[0]).to.equals(txObj.v) + expect(txObj.signature[1]).to.equals(txObj.r) + expect(txObj.signature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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.feePayerSignature).not.to.be.undefined + expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) + expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) + expect(txObj.feePayerSignature[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.signature).not.to.be.undefined + expect(txObj.signature[0][0]).to.equals(txObj.v) + expect(txObj.signature[0][1]).to.equals(txObj.r) + expect(txObj.signature[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) From 2ab37d0a70d7e56caff502adfab435c491221e94 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 3 Sep 2019 15:05:05 +0900 Subject: [PATCH 016/123] Define currentProvider property in each package --- packages/caver-core/src/index.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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 From 9077a7e2efd72787d43c54367544a8b6c6709ef8 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 3 Sep 2019 15:05:33 +0900 Subject: [PATCH 017/123] Add test code for setProvider function --- package.json | 2 +- test/setProvider.js | 112 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 test/setProvider.js diff --git a/package.json b/package.json index 3eb69900..edb6f4be 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "serTest": "mocha test/transactionType/serializationTest.js && mocha test/compressPublicKey.js && mocha test/encodeContractDeploy.js && mocha test/isCompressedPublicKey.js && mocha test/parseAccountKey.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/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", + "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", "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", 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 From 5144b00e8c41fbaf2393eacff66ed08c6528aaf4 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 16 Sep 2019 09:19:50 +0900 Subject: [PATCH 018/123] Modify functions related with HexPrefix to work with prefix only --- packages/caver-utils/src/index.js | 7 ++++--- test/packages/caver.utils.js | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/caver-utils/src/index.js b/packages/caver-utils/src/index.js index 1d15423c..2b4f0b50 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 } /** diff --git a/test/packages/caver.utils.js b/test/packages/caver.utils.js index d87869d3..9de94d80 100644 --- a/test/packages/caver.utils.js +++ b/test/packages/caver.utils.js @@ -876,6 +876,7 @@ describe('CAVERJS-UNIT-ETC-144: caver.utils.toTwosComplement', () => { 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 }) @@ -885,6 +886,7 @@ 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') }) }) @@ -894,6 +896,7 @@ describe('CAVERJS-UNIT-ETC-147: caver.utils.stripHexPrefix', () => { 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') }) }) From d20995b84c508d71aef5c4be6cfcdf72443747aa Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 16 Sep 2019 13:43:29 +0900 Subject: [PATCH 019/123] Modify logic for callback with sendTransaction --- packages/caver-core-method/src/index.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/caver-core-method/src/index.js b/packages/caver-core-method/src/index.js index adcde298..e93cec54 100644 --- a/packages/caver-core-method/src/index.js +++ b/packages/caver-core-method/src/index.js @@ -289,7 +289,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) } @@ -325,7 +325,12 @@ const buildSendRequestFunc = (defer, sendSignedTx, sendTxCallback) => (payload, if (wallet && wallet.privateKey) { // 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, wallet.privateKey) + .then(sendSignedTx) + .catch((e)=>{ + sendTxCallback(e) + return Promise.reject(e) + }) } // If wallet was not found in caver-js wallet, then it has to use wallet in Node. From d40be0abffa03530687526724425b67b73809380 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 16 Sep 2019 13:44:17 +0900 Subject: [PATCH 020/123] Implement test for sendTransaction with callback --- test/sendTransactionCallback.js | 75 +++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 test/sendTransactionCallback.js 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 From bbc6fc94a09b5b4e9f6f33c045304c981f8f7dff Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 16 Sep 2019 13:54:35 +0900 Subject: [PATCH 021/123] Add test code to script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index edb6f4be..79c15afb 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "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", "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*", + "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/sendTransactionCallback.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", "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", From becc365735af117dba151f883dbcb873c1407498 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 17 Sep 2019 13:11:19 +0900 Subject: [PATCH 022/123] Implement isDecoupled getNonDecoupledAccount determineAddress in Account package --- .../caver-klay-accounts/src/index.js | 49 +++-- packages/caver-utils/src/utils.js | 2 + test/packages/caver.klay.accounts.js | 185 +++++++++++++++++- 3 files changed, 218 insertions(+), 18 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 97335207..322bdf15 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -110,38 +110,53 @@ Accounts.prototype.create = function create(entropy) { }; Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(privateKey, targetAddressRaw) { - var { privateKey: prvKey, address, isHumanReadable } = utils.parsePrivateKey(privateKey) + let {nonDecoupledAccount: account, klaytnWalletKeyAddress} = this.getNonDecoupledAccount(privateKey) + + account.address = this.determineAddress(account, klaytnWalletKeyAddress, targetAddressRaw) + account.address = account.address.toLowerCase() + account.address = utils.addHexPrefix(account.address) + + return this._addAccountFunctions(account) +} + +Accounts.prototype.isDecoupled = function isDecoupled(privateKey, userInputAddress) { + let { nonDecoupledAccount, klaytnWalletKeyAddress } = this.getNonDecoupledAccount(privateKey) + let actualAddress = this.determineAddress(nonDecoupledAccount, klaytnWalletKeyAddress, userInputAddress) + + return nonDecoupledAccount.address.toLowerCase() !== actualAddress.toLowerCase() +} + +Accounts.prototype.getNonDecoupledAccount = function getNonDecoupledAccount(privateKey) { + var { privateKey: prvKey, address: klaytnWalletKeyAddress, isHumanReadable } = utils.parsePrivateKey(privateKey) if (!utils.isValidPrivateKey(prvKey)) throw new Error('Invalid private key') - if (prvKey.slice(0, 2) !== '0x') { - prvKey = `0x${prvKey}` - } + prvKey = utils.addHexPrefix(prvKey) - let account = Account.fromPrivate(prvKey) + return { nonDecoupledAccount: Account.fromPrivate(prvKey), klaytnWalletKeyAddress } +} - if (targetAddressRaw) { - if(address && address !== targetAddressRaw) { +// The determineAddress function determines the priority of the parameters entered +// and returns the address that should be used for the account. +Accounts.prototype.determineAddress = function determineAddress(nonDecoupledAccount, 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 + return addressFromKey } - - account.address = account.address.toLowerCase() - account.address = '0x' + account.address.replace('0x', '') - - return this._addAccountFunctions(account) + return nonDecoupledAccount.address } Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, callback) { diff --git a/packages/caver-utils/src/utils.js b/packages/caver-utils/src/utils.js index a4012a7b..30b0e2ce 100644 --- a/packages/caver-utils/src/utils.js +++ b/packages/caver-utils/src/utils.js @@ -518,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 diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index af49e013..a72bc8ec 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -627,6 +627,189 @@ describe('caver.klay.accounts.decrypt', () => { */ }) +describe('caver.klay.accounts.getNonDecoupledAccount', () => { + 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.getNonDecoupledAccount(testAccount.privateKey) + + expect(result.klaytnWalletKeyAddress).to.equals('') + expect(result.nonDecoupledAccount.address).to.equals(testAccount.address) + expect(result.nonDecoupledAccount.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.getNonDecoupledAccount(testAccount.getKlaytnWalletKey()) + + expect(result.klaytnWalletKeyAddress).to.equals(testAccount.address) + expect(result.nonDecoupledAccount.address).to.equals(result.klaytnWalletKeyAddress) + expect(result.nonDecoupledAccount.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 testAccount = caver.klay.accounts.create() + testAccount.privateKey = caver.klay.accounts.create().privateKey + + let result = caver.klay.accounts.getNonDecoupledAccount(testAccount.getKlaytnWalletKey()) + + expect(result.klaytnWalletKeyAddress).to.equals(testAccount.address) + expect(result.nonDecoupledAccount.address).not.to.equals(result.klaytnWalletKeyAddress) + expect(result.nonDecoupledAccount.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.getNonDecoupledAccount('0x')).to.throws(expectedError) + expect(() => caver.klay.accounts.getNonDecoupledAccount('1')).to.throws(expectedError) + expect(() => caver.klay.accounts.getNonDecoupledAccount('a')).to.throws(expectedError) + expect(() => caver.klay.accounts.getNonDecoupledAccount('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.getNonDecoupledAccount(1234)).to.throws(expectedError) + expect(() => caver.klay.accounts.getNonDecoupledAccount({})).to.throws(expectedError) + expect(() => caver.klay.accounts.getNonDecoupledAccount()).to.throws(expectedError) + expect(() => caver.klay.accounts.getNonDecoupledAccount(undefined)).to.throws(expectedError) + expect(() => caver.klay.accounts.getNonDecoupledAccount(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.getNonDecoupledAccount(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 testAccount = caver.klay.accounts.create() + testAccount.privateKey = caver.klay.accounts.create().privateKey + 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 testAccount = caver.klay.accounts.create() + testAccount.privateKey = caver.klay.accounts.create().privateKey + 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 testAccount = caver.klay.accounts.create() + testAccount.privateKey = caver.klay.accounts.create().privateKey + + 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.determineAddress', () => { + context('CAVERJS-UNIT-WALLET-117 : input: valid nonDecoupledAccount', () => { + it('should return address of nonDecoupledAccount', () => { + const testAccount = caver.klay.accounts.create() + + expect(caver.klay.accounts.determineAddress(testAccount)).to.equals(testAccount.address) + }) + }) + + context('CAVERJS-UNIT-WALLET-118 : input: valid nonDecoupledAccount and addressFromKey', () => { + it('should return address of account', () => { + const testAccount = caver.klay.accounts.create() + const addressFromKey = caver.klay.accounts.create().address + + expect(caver.klay.accounts.determineAddress(testAccount, addressFromKey)).to.equals(addressFromKey) + }) + }) + + context('CAVERJS-UNIT-WALLET-119 : input: valid nonDecoupledAccount, addressFromKey and userInputAddress', () => { + it('should return address of account', () => { + const testAccount = caver.klay.accounts.create() + const addressFromKey = '' + const userInputAddress = caver.klay.accounts.create().address + + expect(caver.klay.accounts.determineAddress(testAccount, addressFromKey, userInputAddress)).to.equals(userInputAddress) + }) + }) + + context('CAVERJS-UNIT-WALLET-120 : input: valid nonDecoupledAccount, addressFromKey and userInputAddress', () => { + it('should return address of account', () => { + const testAccount = caver.klay.accounts.create() + const addressFromKey = caver.klay.accounts.create().address + const userInputAddress = addressFromKey + + expect(caver.klay.accounts.determineAddress(testAccount, addressFromKey, userInputAddress)).to.equals(userInputAddress) + }) + }) + + context('CAVERJS-UNIT-WALLET-121 : input: valid nonDecoupledAccount, addressFromKey and userInputAddress', () => { + it('should throw error if addressFromKey and userInputAddress is not matched', () => { + const testAccount = caver.klay.accounts.create() + const addressFromKey = caver.klay.accounts.create().address + const userInputAddress = caver.klay.accounts.create().address + + const expectedError = 'The address extracted from the private key does not match the address received as the input value.' + + expect(() => caver.klay.accounts.determineAddress(testAccount, addressFromKey, userInputAddress)).to.throws(expectedError) + }) + }) +}) + describe('caver.klay.accounts.wallet', () => { it('CAVERJS-UNIT-WALLET-043 : should return valid wallet instance', () => { @@ -939,4 +1122,4 @@ describe('caver.klay.accounts.wallet.decrypt', () => { validateErrorCodeblock(() => caver.klay.accounts.wallet.decrypt(encryptedKeystore, invalid), expectedError) }) */ -}) +}) \ No newline at end of file From ecc30693ede3fdd4af5135beea2bf1487dcafa36 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 17 Sep 2019 13:32:40 +0900 Subject: [PATCH 023/123] Rename of nonDecoupledAccount to legacyAccount --- .../caver-klay-accounts/src/index.js | 16 ++++---- test/packages/caver.klay.accounts.js | 40 +++++++++---------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 322bdf15..99a4ff20 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -110,7 +110,7 @@ Accounts.prototype.create = function create(entropy) { }; Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(privateKey, targetAddressRaw) { - let {nonDecoupledAccount: account, klaytnWalletKeyAddress} = this.getNonDecoupledAccount(privateKey) + let {legacyAccount: account, klaytnWalletKeyAddress} = this.getLegacyAccount(privateKey) account.address = this.determineAddress(account, klaytnWalletKeyAddress, targetAddressRaw) account.address = account.address.toLowerCase() @@ -120,25 +120,25 @@ Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(privateKey } Accounts.prototype.isDecoupled = function isDecoupled(privateKey, userInputAddress) { - let { nonDecoupledAccount, klaytnWalletKeyAddress } = this.getNonDecoupledAccount(privateKey) - let actualAddress = this.determineAddress(nonDecoupledAccount, klaytnWalletKeyAddress, userInputAddress) + let { legacyAccount, klaytnWalletKeyAddress } = this.getLegacyAccount(privateKey) + let actualAddress = this.determineAddress(legacyAccount, klaytnWalletKeyAddress, userInputAddress) - return nonDecoupledAccount.address.toLowerCase() !== actualAddress.toLowerCase() + return legacyAccount.address.toLowerCase() !== actualAddress.toLowerCase() } -Accounts.prototype.getNonDecoupledAccount = function getNonDecoupledAccount(privateKey) { +Accounts.prototype.getLegacyAccount = function getLegacyAccount(privateKey) { var { privateKey: prvKey, address: klaytnWalletKeyAddress, isHumanReadable } = utils.parsePrivateKey(privateKey) if (!utils.isValidPrivateKey(prvKey)) throw new Error('Invalid private key') prvKey = utils.addHexPrefix(prvKey) - return { nonDecoupledAccount: Account.fromPrivate(prvKey), klaytnWalletKeyAddress } + return { legacyAccount: Account.fromPrivate(prvKey), klaytnWalletKeyAddress } } // The determineAddress function determines the priority of the parameters entered // and returns the address that should be used for the account. -Accounts.prototype.determineAddress = function determineAddress(nonDecoupledAccount, addressFromKey, userInputAddress) { +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.') @@ -156,7 +156,7 @@ Accounts.prototype.determineAddress = function determineAddress(nonDecoupledAcco // If targetAddressRaw is undefined and address which is came from private is existed, set address in account. return addressFromKey } - return nonDecoupledAccount.address + return legacyAccount.address } Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, callback) { diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index a72bc8ec..e2eaecb4 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -627,26 +627,26 @@ describe('caver.klay.accounts.decrypt', () => { */ }) -describe('caver.klay.accounts.getNonDecoupledAccount', () => { +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.getNonDecoupledAccount(testAccount.privateKey) + let result = caver.klay.accounts.getLegacyAccount(testAccount.privateKey) expect(result.klaytnWalletKeyAddress).to.equals('') - expect(result.nonDecoupledAccount.address).to.equals(testAccount.address) - expect(result.nonDecoupledAccount.privateKey).to.equals(testAccount.privateKey) + 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.getNonDecoupledAccount(testAccount.getKlaytnWalletKey()) + let result = caver.klay.accounts.getLegacyAccount(testAccount.getKlaytnWalletKey()) expect(result.klaytnWalletKeyAddress).to.equals(testAccount.address) - expect(result.nonDecoupledAccount.address).to.equals(result.klaytnWalletKeyAddress) - expect(result.nonDecoupledAccount.privateKey).to.equals(testAccount.privateKey) + expect(result.legacyAccount.address).to.equals(result.klaytnWalletKeyAddress) + expect(result.legacyAccount.privateKey).to.equals(testAccount.privateKey) }) }) @@ -656,11 +656,11 @@ describe('caver.klay.accounts.getNonDecoupledAccount', () => { const testAccount = caver.klay.accounts.create() testAccount.privateKey = caver.klay.accounts.create().privateKey - let result = caver.klay.accounts.getNonDecoupledAccount(testAccount.getKlaytnWalletKey()) + let result = caver.klay.accounts.getLegacyAccount(testAccount.getKlaytnWalletKey()) expect(result.klaytnWalletKeyAddress).to.equals(testAccount.address) - expect(result.nonDecoupledAccount.address).not.to.equals(result.klaytnWalletKeyAddress) - expect(result.nonDecoupledAccount.privateKey).to.equals(testAccount.privateKey) + expect(result.legacyAccount.address).not.to.equals(result.klaytnWalletKeyAddress) + expect(result.legacyAccount.privateKey).to.equals(testAccount.privateKey) }) }) @@ -668,27 +668,27 @@ describe('caver.klay.accounts.getNonDecoupledAccount', () => { it('should throw error if input is invalid privateKey string', () => { const expectedError = 'Invalid private key' - expect(() => caver.klay.accounts.getNonDecoupledAccount('0x')).to.throws(expectedError) - expect(() => caver.klay.accounts.getNonDecoupledAccount('1')).to.throws(expectedError) - expect(() => caver.klay.accounts.getNonDecoupledAccount('a')).to.throws(expectedError) - expect(() => caver.klay.accounts.getNonDecoupledAccount('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140FF')).to.throws(expectedError) + 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.getNonDecoupledAccount(1234)).to.throws(expectedError) - expect(() => caver.klay.accounts.getNonDecoupledAccount({})).to.throws(expectedError) - expect(() => caver.klay.accounts.getNonDecoupledAccount()).to.throws(expectedError) - expect(() => caver.klay.accounts.getNonDecoupledAccount(undefined)).to.throws(expectedError) - expect(() => caver.klay.accounts.getNonDecoupledAccount(null)).to.throws(expectedError) + 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.getNonDecoupledAccount(caver.klay.accounts.create().privateKey+'0x000x00')).to.throws(expectedError) + expect(() => caver.klay.accounts.getLegacyAccount(caver.klay.accounts.create().privateKey+'0x000x00')).to.throws(expectedError) }) }) }) From 74a1af09ba3402b5c52d50af7836a7dcbf5ca18a Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 17 Sep 2019 13:47:06 +0900 Subject: [PATCH 024/123] Rename parameter of privateKey to key --- .../caver-klay-accounts/src/index.js | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 99a4ff20..0e7565bc 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -109,8 +109,9 @@ Accounts.prototype.create = function create(entropy) { return this._addAccountFunctions(Account.create(entropy || utils.randomHex(32))); }; -Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(privateKey, targetAddressRaw) { - let {legacyAccount: account, klaytnWalletKeyAddress} = this.getLegacyAccount(privateKey) +// The key parameter can be either normal private key or klaytnWalletKey format. +Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(key, targetAddressRaw) { + let {legacyAccount: account, klaytnWalletKeyAddress} = this.getLegacyAccount(key) account.address = this.determineAddress(account, klaytnWalletKeyAddress, targetAddressRaw) account.address = account.address.toLowerCase() @@ -119,21 +120,23 @@ Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(privateKey return this._addAccountFunctions(account) } -Accounts.prototype.isDecoupled = function isDecoupled(privateKey, userInputAddress) { - let { legacyAccount, klaytnWalletKeyAddress } = this.getLegacyAccount(privateKey) +// The key parameter can be either normal private key or klaytnWalletKey format. +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() } -Accounts.prototype.getLegacyAccount = function getLegacyAccount(privateKey) { - var { privateKey: prvKey, address: klaytnWalletKeyAddress, isHumanReadable } = utils.parsePrivateKey(privateKey) +// The key parameter can be either normal private key or klaytnWalletKey format. +Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { + var { privateKey, address: klaytnWalletKeyAddress, isHumanReadable } = utils.parsePrivateKey(key) - if (!utils.isValidPrivateKey(prvKey)) throw new Error('Invalid private key') + if (!utils.isValidPrivateKey(privateKey)) throw new Error('Invalid private key') - prvKey = utils.addHexPrefix(prvKey) + privateKey = utils.addHexPrefix(privateKey) - return { legacyAccount: Account.fromPrivate(prvKey), klaytnWalletKeyAddress } + return { legacyAccount: Account.fromPrivate(privateKey), klaytnWalletKeyAddress } } // The determineAddress function determines the priority of the parameters entered @@ -559,7 +562,8 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) { "id":"dfde6a32-4b0e-404f-8b9f-2b18f279fe21", } */ -Accounts.prototype.encrypt = function (privateKey, password, options) { +// The key parameter can be either normal private key or klaytnWalletKey format. +Accounts.prototype.encrypt = function (key, password, options) { /** * options can include below * { @@ -578,7 +582,7 @@ Accounts.prototype.encrypt = function (privateKey, password, options) { */ options = options || {}; - var account = this.privateKeyToAccount(privateKey, options.address); + var account = this.privateKeyToAccount(key, options.address); var salt = options.salt || cryp.randomBytes(32); var iv = options.iv || cryp.randomBytes(16); From f86d854ad1627577df8dcc0456ccf457272d65a5 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 17 Sep 2019 14:02:08 +0900 Subject: [PATCH 025/123] Add description of funciton and rename targetAddressRaw --- .../caver-klay-accounts/src/index.js | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 0e7565bc..dde0f255 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -109,18 +109,32 @@ Accounts.prototype.create = function create(entropy) { return this._addAccountFunctions(Account.create(entropy || utils.randomHex(32))); }; -// The key parameter can be either normal private key or klaytnWalletKey format. -Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(key, targetAddressRaw) { +/** + * The privateKeyToAccount function 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) - account.address = this.determineAddress(account, klaytnWalletKeyAddress, targetAddressRaw) + account.address = this.determineAddress(account, klaytnWalletKeyAddress, userInputAddress) account.address = account.address.toLowerCase() account.address = utils.addHexPrefix(account.address) return this._addAccountFunctions(account) } -// The key parameter can be either normal private key or klaytnWalletKey format. +/** + * The isDecoupled function 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) @@ -128,7 +142,14 @@ Accounts.prototype.isDecoupled = function isDecoupled(key, userInputAddress) { return legacyAccount.address.toLowerCase() !== actualAddress.toLowerCase() } -// The key parameter can be either normal private key or klaytnWalletKey format. +/** + * The getLegacyAccount function extracts the privateKey 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) @@ -139,8 +160,15 @@ Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { return { legacyAccount: Account.fromPrivate(privateKey), klaytnWalletKeyAddress } } -// The determineAddress function determines the priority of the parameters entered -// and returns the address that should be used for the account. +/** + * The determineAddress function 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 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) { @@ -156,7 +184,7 @@ Accounts.prototype.determineAddress = function determineAddress(legacyAccount, a 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. + // If userInputAddress is undefined and address which is came from private is existed, set address in account. return addressFromKey } return legacyAccount.address @@ -746,7 +774,7 @@ Wallet.prototype.create = function (numberOfAccounts, entropy) { encrypt: function(password){...} } */ -Wallet.prototype.add = function (account, targetAddressRaw) { +Wallet.prototype.add = function (account, userInputAddress) { var klaytnWalletKey /** * cav.klay.accounts.wallet.add('0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318'); @@ -757,7 +785,7 @@ Wallet.prototype.add = function (account, targetAddressRaw) { * }); */ if (_.isString(account)) { - account = this._accounts.privateKeyToAccount(account, targetAddressRaw); + account = this._accounts.privateKeyToAccount(account, userInputAddress); } else if(!_.isObject(account)) { throw new Error('Invalid private key') } @@ -768,7 +796,7 @@ Wallet.prototype.add = function (account, targetAddressRaw) { throw new Error('Account exists with ' + account.address) } - account = this._accounts.privateKeyToAccount(account.privateKey, targetAddressRaw || account.address) + account = this._accounts.privateKeyToAccount(account.privateKey, userInputAddress || account.address) account.index = this._findSafeIndex() this[account.index] = account From 83a60ef19cdce165a36cdbd346bc959a8517291a Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 17 Sep 2019 14:15:05 +0900 Subject: [PATCH 026/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index dde0f255..69b49ce9 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -110,7 +110,7 @@ Accounts.prototype.create = function create(entropy) { }; /** - * The privateKeyToAccount function creates and returns an Account through the input passed as parameters. + * 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. From 3b6d691da0ccde6c878567e4d6ca116967e85a12 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 17 Sep 2019 14:15:12 +0900 Subject: [PATCH 027/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 69b49ce9..a70dc025 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -128,7 +128,7 @@ Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(key, userI } /** - * The isDecoupled function determines whether or not it is decoupled based on the input value. + * 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. From 140730c9a5c704bd9a592df7b1ea262cfa5ae30c Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 17 Sep 2019 14:15:30 +0900 Subject: [PATCH 028/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index a70dc025..17a877a2 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -113,7 +113,7 @@ Accounts.prototype.create = function create(entropy) { * 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} 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} */ From 2c44ade270c0bbe754a8f693222457414f239b49 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 17 Sep 2019 14:15:48 +0900 Subject: [PATCH 029/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 17a877a2..1e9ed580 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -131,7 +131,7 @@ Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(key, userI * 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} 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} */ From ec88107dafa9bd6d3e9016802429b7b0e73ea936 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 17 Sep 2019 14:17:16 +0900 Subject: [PATCH 030/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 1e9ed580..513122be 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -143,7 +143,7 @@ Accounts.prototype.isDecoupled = function isDecoupled(key, userInputAddress) { } /** - * The getLegacyAccount function extracts the privateKey from the input key and returns an Account with the corresponding legacy account key. + * 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 From a2e8536d246ee7851ea37f014e32e8d85f61c54e Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 17 Sep 2019 14:17:22 +0900 Subject: [PATCH 031/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 513122be..8360899f 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -147,7 +147,7 @@ Accounts.prototype.isDecoupled = function isDecoupled(key, userInputAddress) { * 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. + * @param {String} key The key parameter can be either normal private key or KlaytnWalletKey format. * @return {Object} */ Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { From 6802462e93603326e10fbf4602b3e7bd2df57eff Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 17 Sep 2019 14:17:52 +0900 Subject: [PATCH 032/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 8360899f..0757783c 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -161,7 +161,7 @@ Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { } /** - * The determineAddress function determines the priority of the parameters entered and returns the address that should be used for the account. + * 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 legacy account key extracted from private key to be used for address determination. From f52711ea51aaced3f4159ffb6b2a3bc78c496129 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 17 Sep 2019 14:23:12 +0900 Subject: [PATCH 033/123] Add description for encrypt function --- packages/caver-klay/caver-klay-accounts/src/index.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 0757783c..8826b50b 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -590,7 +590,15 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) { "id":"dfde6a32-4b0e-404f-8b9f-2b18f279fe21", } */ -// The key parameter can be either normal private key or klaytnWalletKey format. +/** + * encrypt encrypts an account and returns key store. + * + * @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 From 1520e70d5dd984e2e51a1e3392fa1429ac171610 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 17 Sep 2019 14:33:09 +0900 Subject: [PATCH 034/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 8826b50b..1b994178 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -591,7 +591,7 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) { } */ /** - * encrypt encrypts an account and returns key store. + * 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. From f7f0f075429eec41ac9cc97d376cdd68449cf75c Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 17 Sep 2019 14:33:43 +0900 Subject: [PATCH 035/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 1b994178..90a7a964 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -164,7 +164,7 @@ Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { * 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 legacy account key extracted from private key to be used for address determination. + * @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} From 94a91312c30825bcb455aaa0b45c19273c75ed34 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 17 Sep 2019 14:41:18 +0900 Subject: [PATCH 036/123] Throw error when sign legacy tx with decoupled account --- .../caver-klay-accounts/src/index.js | 5 +++ test/packages/caver.klay.accounts.js | 42 +++++++++++++------ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 90a7a964..63cd306e 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -193,6 +193,7 @@ Accounts.prototype.determineAddress = function determineAddress(legacyAccount, a Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, callback) { var _this = this, error = false, + isLegacy = false, result callback = callback || function () {} @@ -214,6 +215,10 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca if (!tx.senderRawTransaction) { error = helpers.validateFunction.validateParams(tx) + + // Attempting to sign with decoupled account into a legacy type transaction throw an error. + isLegacy = tx.type === undefined || tx.type === 'LEGACY' ? true : false + if (isLegacy && _this.isDecoupled(privateKey, tx.from)) throw new Error('A legacy transaction must be with a legacy account key') } if (error) { callback(error); diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index e2eaecb4..676e2037 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -137,20 +137,19 @@ 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, account beforeEach(() => { account = caver.klay.accounts.create() + txObj = { + from: account.address, + nonce: '0x0', + to: setting.toAddress, + gas: setting.gas, + gasPrice: setting.gasPrice, + value: '0x1', + chainId: 2019, + } }) context('CAVERJS-UNIT-WALLET-023 : input: tx, privateKey', () => { @@ -276,6 +275,25 @@ describe('caver.klay.accounts.signTransaction', () => { expect(result.senderTxHash).to.equal('0x1b7c0f2fc7548056e90d9690e8c397acf99eb38e622ac91ee22c2085065f8a55') }) }) + + context('CAVERJS-UNIT-WALLET-122 : input: legacyTx, privateKey of decoupled account', () => { + it('should return signature and rawTransaction', () => { + const decoupledAccount = caver.klay.accounts.create() + decoupledAccount.privateKey = caver.klay.accounts.create().privateKey + + let tx = { + from: decoupledAccount.address, + nonce: '0x0', + to: setting.toAddress, + gas: setting.gas, + gasPrice: setting.gasPrice, + value: '0x1', + chainId: 2019, + } + + expect(()=>caver.klay.accounts.signTransaction(tx, decoupledAccount.privateKey)).to.throws('A legacy transaction must be with a legacy account key') + }) + }) }) describe('caver.klay.accounts.recoverTransaction', () => { @@ -286,7 +304,7 @@ describe('caver.klay.accounts.recoverTransaction', () => { account = caver.klay.accounts.create() const txObj = { - from: setting.fromAddress, + from: account.address, nonce: '0x0', to: setting.toAddress, gas: setting.gas, From d40b4c74b7b5208d47c099edb715405655c4b6e7 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 17 Sep 2019 16:48:46 +0900 Subject: [PATCH 037/123] Version upgrade to 1.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 79c15afb..9c0915b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "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": { From 7ce1cc75a5bab1afa70c2525239a70024a829f20 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 18 Sep 2019 11:13:27 +0900 Subject: [PATCH 038/123] Remove unnecessary statement for avoiding unhandled --- packages/caver-core-method/src/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/caver-core-method/src/index.js b/packages/caver-core-method/src/index.js index e93cec54..86355492 100644 --- a/packages/caver-core-method/src/index.js +++ b/packages/caver-core-method/src/index.js @@ -327,9 +327,8 @@ const buildSendRequestFunc = (defer, sendSignedTx, sendTxCallback) => (payload, // If wallet was found, sign tx, and send using sendRawTransaction return method.accounts.signTransaction(tx, wallet.privateKey) .then(sendSignedTx) - .catch((e)=>{ + .catch((e) => { sendTxCallback(e) - return Promise.reject(e) }) } From 259ddbad49da27ba26a4e5e9500c804b3e516698 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 18 Sep 2019 11:15:04 +0900 Subject: [PATCH 039/123] Use same error strategy in signTransaction --- .../caver-klay-accounts/src/index.js | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 63cd306e..97690503 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -194,23 +194,32 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca var _this = this, error = false, isLegacy = false, + parsed, result callback = callback || function () {} - const parsed = utils.parsePrivateKey(privateKey) - privateKey = parsed.privateKey - - if (!utils.isValidPrivateKey(privateKey)) throw new Error('Invalid private key') - privateKey = privateKey.startsWith('0x') ? privateKey : '0x' + privateKey - if (!tx) { error = new Error('No transaction object given!') + callback(error) + return Promise.reject(error) + } + try { + parsed = utils.parsePrivateKey(privateKey) + privateKey = parsed.privateKey + } catch(e) { + callback(e) + return Promise.reject(e) + } + if (!utils.isValidPrivateKey(privateKey)) { + error = new Error('Invalid private key') callback(error) return Promise.reject(error) } + privateKey = utils.addHexPrefix(privateKey) + function signed(tx) { if (!tx.senderRawTransaction) { @@ -218,7 +227,7 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca // Attempting to sign with decoupled account into a legacy type transaction throw an error. isLegacy = tx.type === undefined || tx.type === 'LEGACY' ? true : false - if (isLegacy && _this.isDecoupled(privateKey, tx.from)) throw new Error('A legacy transaction must be with a legacy account key') + if (!error && isLegacy && _this.isDecoupled(privateKey, tx.from)) error = new Error('A legacy transaction must be with a legacy account key') } if (error) { callback(error); From cac6b3e6a6c76e32aed783d410ff02259b37cbf8 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 18 Sep 2019 11:26:18 +0900 Subject: [PATCH 040/123] Modify test code for checking reject --- test/packages/caver.klay.accounts.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 676e2037..621a21e2 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -239,8 +239,8 @@ describe('caver.klay.accounts.signTransaction', () => { const errorMessage = 'Invalid private key' - expect(() => caver.klay.accounts.signTransaction(txObj, invalidPrivateKey)) - .to.throw(errorMessage) + expect(caver.klay.accounts.signTransaction(txObj, invalidPrivateKey)) + .to.be.rejectedWith(errorMessage) }) }) @@ -291,7 +291,8 @@ describe('caver.klay.accounts.signTransaction', () => { chainId: 2019, } - expect(()=>caver.klay.accounts.signTransaction(tx, decoupledAccount.privateKey)).to.throws('A legacy transaction must be with a legacy account key') + expect(caver.klay.accounts.signTransaction(tx, decoupledAccount.privateKey)) + .to.be.rejectedWith('A legacy transaction must be with a legacy account key') }) }) }) From e75251e8727b467271234da968e5dc2dd852137e Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Thu, 19 Sep 2019 16:44:05 +0900 Subject: [PATCH 041/123] Rename determineAddress to _determineAddress --- .../caver-klay-accounts/src/index.js | 65 ++++++++++--------- test/packages/caver.klay.accounts.js | 51 --------------- 2 files changed, 33 insertions(+), 83 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 97690503..f805528e 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -105,6 +105,37 @@ Accounts.prototype._addAccountFunctions = function (account) { return account; }; + +/** + * _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(userInputAddress)) { + throw new Error('The address received as the input value is invalid.') + } + return userInputAddress + + } else if (addressFromKey){ + if(!utils.isAddress(addressFromKey)) { + throw new Error('The address extracted from the private key is invalid.') + } + // If userInputAddress is undefined and address which is came from private is existed, set address in account. + return addressFromKey + } + return legacyAccount.address +} + Accounts.prototype.create = function create(entropy) { return this._addAccountFunctions(Account.create(entropy || utils.randomHex(32))); }; @@ -120,7 +151,7 @@ Accounts.prototype.create = function create(entropy) { Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(key, userInputAddress) { let {legacyAccount: account, klaytnWalletKeyAddress} = this.getLegacyAccount(key) - account.address = this.determineAddress(account, klaytnWalletKeyAddress, userInputAddress) + account.address = this._determineAddress(account, klaytnWalletKeyAddress, userInputAddress) account.address = account.address.toLowerCase() account.address = utils.addHexPrefix(account.address) @@ -137,7 +168,7 @@ Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(key, userI */ Accounts.prototype.isDecoupled = function isDecoupled(key, userInputAddress) { let { legacyAccount, klaytnWalletKeyAddress } = this.getLegacyAccount(key) - let actualAddress = this.determineAddress(legacyAccount, klaytnWalletKeyAddress, userInputAddress) + let actualAddress = this._determineAddress(legacyAccount, klaytnWalletKeyAddress, userInputAddress) return legacyAccount.address.toLowerCase() !== actualAddress.toLowerCase() } @@ -160,36 +191,6 @@ Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { return { legacyAccount: Account.fromPrivate(privateKey), klaytnWalletKeyAddress } } -/** - * 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(userInputAddress)) { - throw new Error('The address received as the input value is invalid.') - } - return userInputAddress - - } else if (addressFromKey){ - if(!utils.isAddress(addressFromKey)) { - throw new Error('The address extracted from the private key is invalid.') - } - // If userInputAddress is undefined and address which is came from private is existed, set address in account. - return addressFromKey - } - return legacyAccount.address -} - Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, callback) { var _this = this, error = false, diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 621a21e2..5756865a 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -778,57 +778,6 @@ describe('caver.klay.accounts.isDecoupled', () => { }) }) -describe('caver.klay.accounts.determineAddress', () => { - context('CAVERJS-UNIT-WALLET-117 : input: valid nonDecoupledAccount', () => { - it('should return address of nonDecoupledAccount', () => { - const testAccount = caver.klay.accounts.create() - - expect(caver.klay.accounts.determineAddress(testAccount)).to.equals(testAccount.address) - }) - }) - - context('CAVERJS-UNIT-WALLET-118 : input: valid nonDecoupledAccount and addressFromKey', () => { - it('should return address of account', () => { - const testAccount = caver.klay.accounts.create() - const addressFromKey = caver.klay.accounts.create().address - - expect(caver.klay.accounts.determineAddress(testAccount, addressFromKey)).to.equals(addressFromKey) - }) - }) - - context('CAVERJS-UNIT-WALLET-119 : input: valid nonDecoupledAccount, addressFromKey and userInputAddress', () => { - it('should return address of account', () => { - const testAccount = caver.klay.accounts.create() - const addressFromKey = '' - const userInputAddress = caver.klay.accounts.create().address - - expect(caver.klay.accounts.determineAddress(testAccount, addressFromKey, userInputAddress)).to.equals(userInputAddress) - }) - }) - - context('CAVERJS-UNIT-WALLET-120 : input: valid nonDecoupledAccount, addressFromKey and userInputAddress', () => { - it('should return address of account', () => { - const testAccount = caver.klay.accounts.create() - const addressFromKey = caver.klay.accounts.create().address - const userInputAddress = addressFromKey - - expect(caver.klay.accounts.determineAddress(testAccount, addressFromKey, userInputAddress)).to.equals(userInputAddress) - }) - }) - - context('CAVERJS-UNIT-WALLET-121 : input: valid nonDecoupledAccount, addressFromKey and userInputAddress', () => { - it('should throw error if addressFromKey and userInputAddress is not matched', () => { - const testAccount = caver.klay.accounts.create() - const addressFromKey = caver.klay.accounts.create().address - const userInputAddress = caver.klay.accounts.create().address - - const expectedError = 'The address extracted from the private key does not match the address received as the input value.' - - expect(() => caver.klay.accounts.determineAddress(testAccount, addressFromKey, userInputAddress)).to.throws(expectedError) - }) - }) -}) - describe('caver.klay.accounts.wallet', () => { it('CAVERJS-UNIT-WALLET-043 : should return valid wallet instance', () => { From fdc38cb51c03505df3364e6b75c228466ed0f059 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 23 Sep 2019 09:57:50 +0900 Subject: [PATCH 042/123] Replace deprecated new Buffer to Buffer.from --- .../caver-klay-accounts/src/index.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index f805528e..51a9fff0 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -497,8 +497,8 @@ Accounts.prototype.recover = function recover(message, signature, preFixed) { * 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; @@ -531,7 +531,7 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) { kdfparams = json.crypto.kdfparams; // FIXME: support progress reporting callback - derivedKey = scrypt(new Buffer(password), new Buffer(kdfparams.salt, 'hex'), kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen); + derivedKey = scrypt(Buffer.from(password), Buffer.from(kdfparams.salt, 'hex'), kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen); } else if (json.crypto.kdf === 'pbkdf2') { kdfparams = json.crypto.kdfparams; @@ -539,19 +539,19 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) { throw new Error('Unsupported parameters to PBKDF2'); } - derivedKey = cryp.pbkdf2Sync(new Buffer(password), new Buffer(kdfparams.salt, 'hex'), kdfparams.c, kdfparams.dklen, 'sha256'); + 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 ciphertext = new Buffer(json.crypto.ciphertext, 'hex'); + var ciphertext = Buffer.from(json.crypto.ciphertext, 'hex'); 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 decipher = cryp.createDecipheriv(json.crypto.cipher, derivedKey.slice(0, 16), new Buffer(json.crypto.cipherparams.iv, 'hex')); + var decipher = cryp.createDecipheriv(json.crypto.cipher, derivedKey.slice(0, 16), Buffer.from(json.crypto.cipherparams.iv, 'hex')); var seed = '0x'+ Buffer.concat([ decipher.update(ciphertext), decipher.final() ]).toString('hex'); return this.privateKeyToAccount(seed, json.address); @@ -653,13 +653,13 @@ Accounts.prototype.encrypt = function (key, password, options) { if (kdf === 'pbkdf2') { kdfparams.c = options.c || 262144; kdfparams.prf = 'hmac-sha256'; - derivedKey = cryp.pbkdf2Sync(new Buffer(password), salt, kdfparams.c, kdfparams.dklen, '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(new Buffer(password), salt, kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen); + derivedKey = scrypt(Buffer.from(password), salt, kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen); } else { throw new Error('Unsupported kdf'); } @@ -669,9 +669,9 @@ Accounts.prototype.encrypt = function (key, password, options) { throw new Error('Unsupported cipher'); } - var ciphertext = Buffer.concat([ cipher.update(new Buffer(account.privateKey.replace('0x',''), 'hex')), cipher.final() ]); + var ciphertext = Buffer.concat([ cipher.update(Buffer.from(account.privateKey.replace('0x',''), 'hex')), cipher.final() ]); - var mac = utils.sha3(Buffer.concat([ derivedKey.slice(16, 32), new Buffer(ciphertext, 'hex') ])).replace('0x',''); + var mac = utils.sha3(Buffer.concat([ derivedKey.slice(16, 32), Buffer.from(ciphertext, 'hex') ])).replace('0x',''); return { version: 3, @@ -698,7 +698,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 From c4e1194fb96acd42834beb49ad1e932ad61488fa Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 23 Sep 2019 14:36:03 +0900 Subject: [PATCH 043/123] Modify decodeTransaction return field name --- package.json | 2 +- .../src/makeRawTransaction.js | 80 +++--- test/decodeTransaction.js | 60 ++-- test/transactionType/serializationTest.js | 256 +++++++++--------- 4 files changed, 199 insertions(+), 199 deletions(-) diff --git a/package.json b/package.json index 9c0915b3..9fd4d5d7 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "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/sendTransactionCallback.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", diff --git a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js index 08156685..924800c3 100644 --- a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js +++ b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js @@ -138,7 +138,7 @@ 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.signature) + return _combineFeePayerRawTransaction(rlpEncoded, sig, transaction, decoded.signatures) } return _combineSenderRawTransaction(rlpEncoded, sig) } @@ -191,86 +191,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, signature: [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, signature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } + 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } + 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, feeRatio, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } + 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, signature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } + 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } + 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, data, feeRatio, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } + 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, signature ] = RLP.decode(rawTransaction) - return parseAccountKey({ type: typeString, nonce, gasPrice, gas, from, accountKey, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature }) + const [ nonce, gasPrice, gas, from, accountKey, signatures ] = RLP.decode(rawTransaction) + return parseAccountKey({ 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return parseAccountKey({ type: typeString, nonce, gasPrice, gas, from, accountKey, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature }) + const [ nonce, gasPrice, gas, from, accountKey, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction) + return parseAccountKey({ 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return parseAccountKey({ type: typeString, nonce, gasPrice, gas, from, accountKey, feeRatio, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature }) + const [ nonce, gasPrice, gas, from, accountKey, feeRatio, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction) + return parseAccountKey({ 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, signature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, codeFormat, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } + 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, codeFormat, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } + 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, data, humanReadable: humanReadable === '0x01'? true: false, feeRatio, codeFormat, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } + 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, signature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } + 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, data, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } + 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, data, feeRatio, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } + 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, signature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, from, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } + 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, from, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } + 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, signature, feePayer, feePayerSignature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, from, feeRatio, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature, feePayer, payerV: feePayerSignature[0][0], payerR: feePayerSignature[0][1], payerS: feePayerSignature[0][2], feePayerSignature } + 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, signature ] = RLP.decode(rawTransaction) - return { type: typeString, nonce, gasPrice, gas, to, value, from, anchoredData:data, v: signature[0][0], r: signature[0][1], s: signature[0][2], signature } + 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 } } } } diff --git a/test/decodeTransaction.js b/test/decodeTransaction.js index 75e12b17..e4c2f4f4 100644 --- a/test/decodeTransaction.js +++ b/test/decodeTransaction.js @@ -58,10 +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.signature).not.to.be.undefined - expect(decodedTx.signature[0][0]).to.equals(decodedTx.v) - expect(decodedTx.signature[0][1]).to.equals(decodedTx.r) - expect(decodedTx.signature[0][2]).to.equals(decodedTx.s) + 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') @@ -84,18 +84,18 @@ describe('Decode Transaction', () => { expect(decodedTx.v).not.to.undefined expect(decodedTx.r).not.to.undefined expect(decodedTx.s).not.to.undefined - expect(decodedTx.signature).not.to.be.undefined - expect(decodedTx.signature[0][0]).to.equals(decodedTx.v) - expect(decodedTx.signature[0][1]).to.equals(decodedTx.r) - expect(decodedTx.signature[0][2]).to.equals(decodedTx.s) + 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(payer.address) expect(decodedTx.payerV).not.to.undefined expect(decodedTx.payerR).not.to.undefined expect(decodedTx.payerS).not.to.undefined - expect(decodedTx.feePayerSignature).not.to.be.undefined - expect(decodedTx.feePayerSignature[0][0]).to.equals(decodedTx.payerV) - expect(decodedTx.feePayerSignature[0][1]).to.equals(decodedTx.payerR) - expect(decodedTx.feePayerSignature[0][2]).to.equals(decodedTx.payerS) + 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', () => { @@ -112,12 +112,12 @@ describe('Decode Transaction', () => { expect(decodedTx.v).not.to.undefined expect(decodedTx.r).not.to.undefined expect(decodedTx.s).not.to.undefined - expect(decodedTx.signature).not.to.be.undefined - expect(Array.isArray(decodedTx.signature)).to.be.true - expect(decodedTx.signature.length).to.equals(2) - expect(decodedTx.signature[0][0]).to.equals(decodedTx.v) - expect(decodedTx.signature[0][1]).to.equals(decodedTx.r) - expect(decodedTx.signature[0][2]).to.equals(decodedTx.s) + 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', () => { @@ -134,21 +134,21 @@ describe('Decode Transaction', () => { expect(decodedTx.v).not.to.undefined expect(decodedTx.r).not.to.undefined expect(decodedTx.s).not.to.undefined - expect(decodedTx.signature).not.to.be.undefined - expect(Array.isArray(decodedTx.signature)).to.be.true - expect(decodedTx.signature.length).to.equals(2) - expect(decodedTx.signature[0][0]).to.equals(decodedTx.v) - expect(decodedTx.signature[0][1]).to.equals(decodedTx.r) - expect(decodedTx.signature[0][2]).to.equals(decodedTx.s) + 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.feePayerSignature).not.to.be.undefined - expect(Array.isArray(decodedTx.feePayerSignature)).to.be.true - expect(decodedTx.feePayerSignature.length).to.equals(2) - expect(decodedTx.feePayerSignature[0][0]).to.equals(decodedTx.payerV) - expect(decodedTx.feePayerSignature[0][1]).to.equals(decodedTx.payerR) - expect(decodedTx.feePayerSignature[0][2]).to.equals(decodedTx.payerS) + 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/transactionType/serializationTest.js b/test/transactionType/serializationTest.js index 70180248..c7a7db9d 100644 --- a/test/transactionType/serializationTest.js +++ b/test/transactionType/serializationTest.js @@ -65,10 +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.signature).not.to.be.undefined - expect(txObj.signature[0]).to.equals(txObj.v) - expect(txObj.signature[1]).to.equals(txObj.r) - expect(txObj.signature[2]).to.equals(txObj.s) + 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) }) @@ -108,10 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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) }) @@ -161,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -229,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -282,10 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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) }) @@ -342,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -412,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -465,10 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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) }) @@ -520,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -587,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -643,10 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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) }) @@ -705,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -776,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -830,10 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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) }) @@ -890,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -962,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -1010,10 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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) }) @@ -1065,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -1129,18 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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.feePayerSignature).not.to.be.undefined - expect(txObj.feePayerSignature[0][0]).to.equals(txObj.payerV) - expect(txObj.feePayerSignature[0][1]).to.equals(txObj.payerR) - expect(txObj.feePayerSignature[0][2]).to.equals(txObj.payerS) + 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) }) @@ -1183,10 +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.signature).not.to.be.undefined - expect(txObj.signature[0][0]).to.equals(txObj.v) - expect(txObj.signature[0][1]).to.equals(txObj.r) - expect(txObj.signature[0][2]).to.equals(txObj.s) + 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) }) From 67997eb14c206f0fc355d08913d4aa4e0478d304 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 20 Sep 2019 17:20:59 +0900 Subject: [PATCH 044/123] Make privateKey optional in signTransaction --- packages/caver-core-method/src/index.js | 29 +-- .../caver-klay-accounts/src/index.js | 128 +++++++++---- .../src/makeRawTransaction.js | 2 +- test/packages/caver.klay.accounts.js | 169 ++++++++++++++++-- 4 files changed, 257 insertions(+), 71 deletions(-) diff --git a/packages/caver-core-method/src/index.js b/packages/caver-core-method/src/index.js index 86355492..a486ff81 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) { @@ -316,12 +297,18 @@ const buildSendRequestFunc = (defer, sendSignedTx, sendTxCallback) => (payload, // return method.accounts.sendTransactionWithSignature(tx).then(sendSignedTx) // } + if (!_.isObject(tx)) { + let error = new Error('The transaction must be defined as an object.') + sendTxCallback(error) + return Promise.reject(error) + } + if (tx.senderRawTransaction && tx.from && tx.feePayer){ 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) + const wallet = method.accounts.wallet.getAccount(tx.from || tx.feePayer) if (wallet && wallet.privateKey) { // If wallet was found, sign tx, and send using sendRawTransaction @@ -351,7 +338,7 @@ const buildSendRequestFunc = (defer, sendSignedTx, sendTxCallback) => (payload, } 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-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 51a9fff0..1aabf93e 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -191,50 +191,85 @@ Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { return { legacyAccount: Account.fromPrivate(privateKey), klaytnWalletKeyAddress } } -Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, callback) { +Accounts.prototype.signTransaction = function signTransaction() { var _this = this, - error = false, isLegacy = false, - parsed, - result + result, + callback - callback = callback || function () {} + let handleError = (e) => { + e = e instanceof Error? e : new Error(e) + if (callback) callback(e) + return Promise.reject(e) + } - if (!tx) { - error = new Error('No transaction object given!') - callback(error) - return Promise.reject(error) + if (arguments.length === 0 || arguments.length > 3) { + return handleError('Inavlid parameter: The number of parameter is invalid.') } + + // privateKey and callback are optional parameter + // "arguments.length === 2" means that user sent parameter privateKey or callback + let tx = arguments[0], privateKey - try { - parsed = utils.parsePrivateKey(privateKey) - privateKey = parsed.privateKey - } catch(e) { - callback(e) - return Promise.reject(e) + if (!tx || !_.isObject(tx)) { + return handleError('Invalid paramter: The transaction must be defined as an object') } - if (!utils.isValidPrivateKey(privateKey)) { - error = new Error('Invalid private key') - callback(error) - return Promise.reject(error) + + if (arguments.length === 2) { + if (_.isFunction(arguments[1])) { + callback = arguments[1] + } else { + privateKey = arguments[1] + } + } else if (arguments.length === 3) { + if (typeof arguments[1] !== 'string' && !_.isArray(arguments[1])){ + return handleError('Invalid paramter: The parameter for the private key is invalid') + } + privateKey = arguments[1] + callback = arguments[2] } - privateKey = utils.addHexPrefix(privateKey) + // For handling when callback is undefined. + callback = callback || function () {} - function signed(tx) { + // Validate tx object + if (!tx.senderRawTransaction) { + const error = helpers.validateFunction.validateParams(tx) + if (error) return handleError(error) + } - if (!tx.senderRawTransaction) { - error = helpers.validateFunction.validateParams(tx) - - // Attempting to sign with decoupled account into a legacy type transaction throw an error. - isLegacy = tx.type === undefined || tx.type === 'LEGACY' ? true : false - if (!error && isLegacy && _this.isDecoupled(privateKey, tx.from)) error = new Error('A legacy transaction must be with a legacy account key') + // When privateKey is undefined, find Account from Wallet. + if (privateKey === undefined) { + try { + const account = this.wallet.getAccount(tx.from || tx.feePayer) + privateKey = account.privateKey + } catch(e) { + return handleError(e) } - if (error) { - callback(error); - return Promise.reject(error); + } + + 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 decoupled account into a legacy type transaction should be rejected. + if (!tx.senderRawTransaction) { + isLegacy = tx.type === undefined || tx.type === 'LEGACY' ? true : false + if (isLegacy && privateKeys.length > 1) return handleError('Legacy transaction cannot signed with multiple keys') + if (isLegacy && _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) @@ -245,16 +280,22 @@ 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 signatrues = [] - const rawTransaction = makeRawTransaction(rlpEncoded, [v, r, s], transaction) + for(const privateKey of privateKeys) { + 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))) + signatrues.push([v, r, s]) + } + + const rawTransaction = makeRawTransaction(rlpEncoded, signatrues, transaction) result = { messageHash: messageHash, - v: v, - r: r, - s: s, + v: signatrues[0][0], + r: signatrues[0][1], + s: signatrues[0][2], + signature: isLegacy? signatrues[0] : signatrues, rawTransaction: rawTransaction, txHash: Hash.keccak256(rawTransaction), senderTxHash: getSenderTxHash(rawTransaction), @@ -289,7 +330,7 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca 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)); @@ -1053,6 +1094,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.`) + + 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 924800c3..ea11904c 100644 --- a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js +++ b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js @@ -144,7 +144,7 @@ function makeRawTransaction(rlpEncoded, sig, transaction) { } case 'LEGACY': default: - rawTx = decodedValues.slice(0, 6).concat(sig) + rawTx = decodedValues.slice(0, 6).concat(sig[0]) return RLP.encode(rawTx) } } diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 5756865a..0c4feb76 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -137,10 +137,12 @@ describe('caver.klay.accounts.privateKeyToAccount', () => { }) describe('caver.klay.accounts.signTransaction', () => { - let txObj, account + let txObj, vtTx, account beforeEach(() => { account = caver.klay.accounts.create() + caver.klay.accounts.wallet.add(account) + txObj = { from: account.address, nonce: '0x0', @@ -150,6 +152,18 @@ describe('caver.klay.accounts.signTransaction', () => { 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', () => { @@ -159,7 +173,7 @@ describe('caver.klay.accounts.signTransaction', () => { account.privateKey ) - const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash'] + const keys = ['messageHash', 'v', 'r', 's', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address) @@ -173,7 +187,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', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address) @@ -187,7 +201,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', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address) @@ -201,7 +215,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', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address) @@ -234,13 +248,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.be.rejectedWith(errorMessage) + await expect(caver.klay.accounts.signTransaction(txObj, invalidPrivateKey)).to.be.rejectedWith(errorMessage) }) }) @@ -250,7 +263,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', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address) @@ -277,7 +290,7 @@ describe('caver.klay.accounts.signTransaction', () => { }) context('CAVERJS-UNIT-WALLET-122 : input: legacyTx, privateKey of decoupled account', () => { - it('should return signature and rawTransaction', () => { + it('should return signature and rawTransaction', async () => { const decoupledAccount = caver.klay.accounts.create() decoupledAccount.privateKey = caver.klay.accounts.create().privateKey @@ -291,8 +304,77 @@ describe('caver.klay.accounts.signTransaction', () => { chainId: 2019, } - expect(caver.klay.accounts.signTransaction(tx, decoupledAccount.privateKey)) - .to.be.rejectedWith('A legacy transaction must be with a legacy account key') + const errorMessage = 'A legacy transaction must be with a legacy account key' + + await expect(caver.klay.accounts.signTransaction(tx, decoupledAccount.privateKey)).to.be.rejectedWith(errorMessage) + }) + }) + + 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 = 'Inavlid parameter: The number of parameter is invalid.' + await expect(caver.klay.accounts.signTransaction()).to.be.rejectedWith(errorMessage) + }) + + it('should reject when there are more than three parameters', async () => { + const errorMessage = 'Inavlid parameter: The number of parameter is invalid.' + await expect(caver.klay.accounts.signTransaction({}, 'privateKey', ()=>{}, 'one more')).to.be.rejectedWith(errorMessage) + }) + }) + + 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 keys = ['messageHash', 'v', 'r', 's', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] + expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) + + expect(typeof result.signature[0]).to.equals('string') + + expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address) + }) + + 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 = ['messageHash', 'v', 'r', 's', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] + expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) + + expect(typeof result.signature[0]).to.equals('string') + + expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address) + + expect(isCalled).to.be.true + }) + + it('should sign to transaction parameter with private key parameter', async () => { + const result = await caver.klay.accounts.signTransaction(vtTx, account.privateKey) + + const keys = ['messageHash', 'v', 'r', 's', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] + expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) + + expect(Array.isArray(result.signature[0])).to.be.true + expect(result.signature.length).to.equals(1) + }) + + it('should sign to transaction parameter with private key array', async () => { + const result = await caver.klay.accounts.signTransaction(vtTx, [account.privateKey.slice(2), account.privateKey]) + + const keys = ['messageHash', 'v', 'r', 's', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] + expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) + + expect(Array.isArray(result.signature[0])).to.be.true + expect(result.signature.length).to.equals(2) + + const decoded = caver.klay.decodeTransaction(result.rawTransaction) + expect(decoded.signature.length).to.equals(2) + expect(decoded.signature[0][0]).to.equals(result.signature[0][0]) + expect(decoded.signature[0][1]).to.equals(result.signature[0][1]) + expect(decoded.signature[0][2]).to.equals(result.signature[0][2]) + expect(decoded.signature[1][0]).to.equals(result.signature[1][0]) + expect(decoded.signature[1][1]).to.equals(result.signature[1][1]) + expect(decoded.signature[1][2]).to.equals(result.signature[1][2]) }) }) }) @@ -1090,4 +1172,67 @@ describe('caver.klay.accounts.wallet.decrypt', () => { validateErrorCodeblock(() => caver.klay.accounts.wallet.decrypt(encryptedKeystore, invalid), expectedError) }) */ +}) + +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) + }) + }) }) \ No newline at end of file From 7dcfc1dfa83ff264bbe9df9476e37065a5b0d017 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Mon, 23 Sep 2019 11:12:50 +0900 Subject: [PATCH 045/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 1aabf93e..1445ea0e 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -204,7 +204,7 @@ Accounts.prototype.signTransaction = function signTransaction() { } if (arguments.length === 0 || arguments.length > 3) { - return handleError('Inavlid parameter: The number of parameter is invalid.') + return handleError('Invalid parameter: The number of parameters is invalid.') } // privateKey and callback are optional parameter From 1e31cf9b22c06abcfabf827e4f7f1d09ed949116 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Mon, 23 Sep 2019 11:13:24 +0900 Subject: [PATCH 046/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 1445ea0e..503ef67d 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -212,7 +212,7 @@ Accounts.prototype.signTransaction = function signTransaction() { let tx = arguments[0], privateKey if (!tx || !_.isObject(tx)) { - return handleError('Invalid paramter: The transaction must be defined as an object') + return handleError('Invalid parameter: The transaction must be defined as an object') } if (arguments.length === 2) { From 95cf1d2eea176815d68de79f648ab1582ea24281 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Mon, 23 Sep 2019 11:13:54 +0900 Subject: [PATCH 047/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 503ef67d..17a8d8fd 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -223,7 +223,7 @@ Accounts.prototype.signTransaction = function signTransaction() { } } else if (arguments.length === 3) { if (typeof arguments[1] !== 'string' && !_.isArray(arguments[1])){ - return handleError('Invalid paramter: The parameter for the private key is invalid') + return handleError('Invalid parameter: The parameter for the private key is invalid') } privateKey = arguments[1] callback = arguments[2] From 503f47c13f94a7699dab37061d812e8f44168d6b Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 23 Sep 2019 11:15:49 +0900 Subject: [PATCH 048/123] Modify test code --- test/packages/caver.klay.accounts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 0c4feb76..29040dfd 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -312,12 +312,12 @@ describe('caver.klay.accounts.signTransaction', () => { 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 = 'Inavlid parameter: The number of parameter is invalid.' + const errorMessage = 'Invalid parameter: The number of parameters is invalid.' await expect(caver.klay.accounts.signTransaction()).to.be.rejectedWith(errorMessage) }) it('should reject when there are more than three parameters', async () => { - const errorMessage = 'Inavlid parameter: The number of parameter is invalid.' + const errorMessage = 'Invalid parameter: The number of parameters is invalid.' await expect(caver.klay.accounts.signTransaction({}, 'privateKey', ()=>{}, 'one more')).to.be.rejectedWith(errorMessage) }) }) From 6d23556d8dd8f203bcc2a410eb9bfe1a667b2f3f Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Mon, 23 Sep 2019 11:20:57 +0900 Subject: [PATCH 049/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 17a8d8fd..9bd9f44b 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -262,7 +262,7 @@ Accounts.prototype.signTransaction = function signTransaction() { return handleError(e) } - // Attempting to sign with decoupled account into a legacy type transaction should be rejected. + // Attempting to sign with a decoupled account into a legacy type transaction should be rejected. if (!tx.senderRawTransaction) { isLegacy = tx.type === undefined || tx.type === 'LEGACY' ? true : false if (isLegacy && privateKeys.length > 1) return handleError('Legacy transaction cannot signed with multiple keys') From 50baa4cc5452779eb0c4da4766ab575b5335e0df Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Mon, 23 Sep 2019 11:22:48 +0900 Subject: [PATCH 050/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 9bd9f44b..1a86cf7b 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -280,7 +280,7 @@ Accounts.prototype.signTransaction = function signTransaction() { const messageHash = Hash.keccak256(rlpEncoded) - let signatrues = [] + let signatures = [] for(const privateKey of privateKeys) { const signature = Account.makeSigner(Nat.toNumber(transaction.chainId || "0x1") * 2 + 35)(messageHash, privateKey) From 6c923d0518efd9451e10586db62616fd565650d3 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 23 Sep 2019 11:24:11 +0900 Subject: [PATCH 051/123] Edit mistypo --- packages/caver-klay/caver-klay-accounts/src/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 1a86cf7b..821f4bae 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -285,17 +285,17 @@ Accounts.prototype.signTransaction = function signTransaction() { for(const privateKey of privateKeys) { 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))) - signatrues.push([v, r, s]) + signatures.push([v, r, s]) } - const rawTransaction = makeRawTransaction(rlpEncoded, signatrues, transaction) + const rawTransaction = makeRawTransaction(rlpEncoded, signatures, transaction) result = { messageHash: messageHash, - v: signatrues[0][0], - r: signatrues[0][1], - s: signatrues[0][2], - signature: isLegacy? signatrues[0] : signatrues, + v: signatures[0][0], + r: signatures[0][1], + s: signatures[0][2], + signature: isLegacy? signatures[0] : signatures, rawTransaction: rawTransaction, txHash: Hash.keccak256(rawTransaction), senderTxHash: getSenderTxHash(rawTransaction), From 8eeab03509b540e7f582142cde608cd8d3812c82 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 23 Sep 2019 14:07:32 +0900 Subject: [PATCH 052/123] Send signedTransaction with multisig --- test/signWithMultiSig.js | 90 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 test/signWithMultiSig.js 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 From 242ee0b425c1661646494e323a12b0f4d27ac1a9 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 23 Sep 2019 14:12:47 +0900 Subject: [PATCH 053/123] Add test script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9fd4d5d7..25333301 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "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 && 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/sendTransactionCallback.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*", + "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/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", "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", From 57707632d8f526d23c0cf6bfe3b3877068c89ac9 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 23 Sep 2019 15:10:08 +0900 Subject: [PATCH 054/123] Seperate feePayerSignatures return field --- .../caver-klay-accounts/src/index.js | 7 +- test/packages/caver.klay.accounts.js | 75 +++++++++++++------ 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 821f4bae..a498edcb 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -295,12 +295,17 @@ Accounts.prototype.signTransaction = function signTransaction() { v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], - signature: isLegacy? signatures[0] : signatures, rawTransaction: rawTransaction, txHash: Hash.keccak256(rawTransaction), senderTxHash: getSenderTxHash(rawTransaction), } + if (tx.senderRawTransaction && tx.feePayer) { + result.feePayerSignatures = signatures + } else { + result.signatures = isLegacy? signatures[0] : signatures + } + } catch(e) { callback(e) return Promise.reject(e) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 29040dfd..9e636e21 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -173,7 +173,7 @@ describe('caver.klay.accounts.signTransaction', () => { account.privateKey ) - const keys = ['messageHash', 'v', 'r', 's', 'signature', '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) @@ -187,7 +187,7 @@ describe('caver.klay.accounts.signTransaction', () => { const result = await caver.klay.accounts.signTransaction(tx, account.privateKey) - const keys = ['messageHash', 'v', 'r', 's', 'signature', '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) @@ -201,7 +201,7 @@ describe('caver.klay.accounts.signTransaction', () => { const result = await caver.klay.accounts.signTransaction(tx, account.privateKey) - const keys = ['messageHash', 'v', 'r', 's', 'signature', '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) @@ -215,7 +215,7 @@ describe('caver.klay.accounts.signTransaction', () => { const result = await caver.klay.accounts.signTransaction(tx, account.privateKey) - const keys = ['messageHash', 'v', 'r', 's', 'signature', '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) @@ -263,7 +263,7 @@ describe('caver.klay.accounts.signTransaction', () => { txObj, account.privateKey, (error, result) => { - const keys = ['messageHash', 'v', 'r', 's', 'signature', '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) @@ -326,10 +326,10 @@ describe('caver.klay.accounts.signTransaction', () => { it('should sign to transaction parameter with private key in wallet', async () => { const result = await caver.klay.accounts.signTransaction(txObj) - const keys = ['messageHash', 'v', 'r', 's', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] + const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures'] expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) - expect(typeof result.signature[0]).to.equals('string') + expect(typeof result.signatures[0]).to.equals('string') expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address) }) @@ -338,10 +338,10 @@ describe('caver.klay.accounts.signTransaction', () => { let isCalled = false const result = await caver.klay.accounts.signTransaction(txObj, (error, result) => isCalled = true) - const keys = ['messageHash', 'v', 'r', 's', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] + const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures'] expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) - expect(typeof result.signature[0]).to.equals('string') + expect(typeof result.signatures[0]).to.equals('string') expect(caver.klay.accounts.recoverTransaction(result.rawTransaction)).to.equal(account.address) @@ -351,30 +351,63 @@ describe('caver.klay.accounts.signTransaction', () => { it('should sign to transaction parameter with private key parameter', async () => { const result = await caver.klay.accounts.signTransaction(vtTx, account.privateKey) - const keys = ['messageHash', 'v', 'r', 's', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] + const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures'] expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) - expect(Array.isArray(result.signature[0])).to.be.true - expect(result.signature.length).to.equals(1) + expect(Array.isArray(result.signatures[0])).to.be.true + expect(result.signatures.length).to.equals(1) }) it('should sign to transaction parameter with private key array', async () => { const result = await caver.klay.accounts.signTransaction(vtTx, [account.privateKey.slice(2), account.privateKey]) - const keys = ['messageHash', 'v', 'r', 's', 'signature', 'rawTransaction', 'txHash', 'senderTxHash'] + const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures'] expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) - expect(Array.isArray(result.signature[0])).to.be.true - expect(result.signature.length).to.equals(2) + 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.signature.length).to.equals(2) - expect(decoded.signature[0][0]).to.equals(result.signature[0][0]) - expect(decoded.signature[0][1]).to.equals(result.signature[0][1]) - expect(decoded.signature[0][2]).to.equals(result.signature[0][2]) - expect(decoded.signature[1][0]).to.equals(result.signature[1][0]) - expect(decoded.signature[1][1]).to.equals(result.signature[1][1]) - expect(decoded.signature[1][2]).to.equals(result.signature[1][2]) + expect(decoded.signature[0][0]).to.equals(result.signatures[0][0]) + expect(decoded.signature[0][1]).to.equals(result.signatures[0][1]) + expect(decoded.signature[0][2]).to.equals(result.signatures[0][2]) + expect(decoded.signature[1][0]).to.equals(result.signatures[1][0]) + expect(decoded.signature[1][1]).to.equals(result.signatures[1][1]) + expect(decoded.signature[1][2]).to.equals(result.signatures[1][2]) + }) + }) + + 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.signature.length).to.equals(1) + expect(decoded.signature[0][0]).to.equals(senderSigned.signatures[0][0]) + expect(decoded.signature[0][1]).to.equals(senderSigned.signatures[0][1]) + expect(decoded.signature[0][2]).to.equals(senderSigned.signatures[0][2]) + expect(decoded.feePayerSignature[0][0]).to.equals(feePayerSigned.feePayerSignatures[0][0]) + expect(decoded.feePayerSignature[0][1]).to.equals(feePayerSigned.feePayerSignatures[0][1]) + expect(decoded.feePayerSignature[0][2]).to.equals(feePayerSigned.feePayerSignatures[0][2]) }) }) }) From 308dfc19d2730f2d81e3e54efec25e98c7a38f1e Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 23 Sep 2019 15:19:46 +0900 Subject: [PATCH 055/123] Check feePayer field when senderRawTransaction is defined --- .../caver-klay-accounts/src/index.js | 2 +- test/packages/caver.klay.accounts.js | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index a498edcb..7719cd32 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -236,7 +236,7 @@ Accounts.prototype.signTransaction = function signTransaction() { if (!tx.senderRawTransaction) { const error = helpers.validateFunction.validateParams(tx) if (error) return handleError(error) - } + } else if (!tx.feePayer) { return handleError('To sign with fee payer, senderRawTransaction and feePayer must be defined in the transaction object.') } // When privateKey is undefined, find Account from Wallet. if (privateKey === undefined) { diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 9e636e21..879efcbf 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -410,6 +410,29 @@ describe('caver.klay.accounts.signTransaction', () => { expect(decoded.feePayerSignature[0][2]).to.equals(feePayerSigned.feePayerSignatures[0][2]) }) }) + + 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, + } + + const errorMessage = 'To sign with fee payer, senderRawTransaction and feePayer must be defined in the transaction object.' + await expect(caver.klay.accounts.signTransaction(feePayerTransaction)).to.be.rejectedWith(errorMessage) + }) + }) }) describe('caver.klay.accounts.recoverTransaction', () => { From 0789b13bee779be6a1901fef12d0088423ed4bf2 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 23 Sep 2019 15:44:13 +0900 Subject: [PATCH 056/123] Apply modification of decodeTransaction --- test/packages/caver.klay.accounts.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 879efcbf..b9074afc 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -368,13 +368,13 @@ describe('caver.klay.accounts.signTransaction', () => { expect(result.signatures.length).to.equals(2) const decoded = caver.klay.decodeTransaction(result.rawTransaction) - expect(decoded.signature.length).to.equals(2) - expect(decoded.signature[0][0]).to.equals(result.signatures[0][0]) - expect(decoded.signature[0][1]).to.equals(result.signatures[0][1]) - expect(decoded.signature[0][2]).to.equals(result.signatures[0][2]) - expect(decoded.signature[1][0]).to.equals(result.signatures[1][0]) - expect(decoded.signature[1][1]).to.equals(result.signatures[1][1]) - expect(decoded.signature[1][2]).to.equals(result.signatures[1][2]) + 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]) }) }) @@ -401,13 +401,13 @@ describe('caver.klay.accounts.signTransaction', () => { expect(Array.isArray(feePayerSigned.feePayerSignatures)).to.be.true const decoded = caver.klay.decodeTransaction(feePayerSigned.rawTransaction) - expect(decoded.signature.length).to.equals(1) - expect(decoded.signature[0][0]).to.equals(senderSigned.signatures[0][0]) - expect(decoded.signature[0][1]).to.equals(senderSigned.signatures[0][1]) - expect(decoded.signature[0][2]).to.equals(senderSigned.signatures[0][2]) - expect(decoded.feePayerSignature[0][0]).to.equals(feePayerSigned.feePayerSignatures[0][0]) - expect(decoded.feePayerSignature[0][1]).to.equals(feePayerSigned.feePayerSignatures[0][1]) - expect(decoded.feePayerSignature[0][2]).to.equals(feePayerSigned.feePayerSignatures[0][2]) + 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]) }) }) From df0880179bd6331e9ae0dcaf656a1f36416f15d8 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 23 Sep 2019 10:04:31 +0900 Subject: [PATCH 057/123] Rename Account to AccountLib --- .../caver-klay-accounts/src/index.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 7719cd32..c2e209e8 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -29,7 +29,7 @@ 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"); @@ -137,7 +137,7 @@ Accounts.prototype._determineAddress = function _determineAddress(legacyAccount, } Accounts.prototype.create = function create(entropy) { - return this._addAccountFunctions(Account.create(entropy || utils.randomHex(32))); + return this._addAccountFunctions(AccountLib.create(entropy || utils.randomHex(32))); }; /** @@ -188,7 +188,7 @@ Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { privateKey = utils.addHexPrefix(privateKey) - return { legacyAccount: Account.fromPrivate(privateKey), klaytnWalletKeyAddress } + return { legacyAccount: AccountLib.fromPrivate(privateKey), klaytnWalletKeyAddress } } Accounts.prototype.signTransaction = function signTransaction() { @@ -283,8 +283,8 @@ Accounts.prototype.signTransaction = function signTransaction() { let signatures = [] for(const privateKey of privateKeys) { - 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))) + 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))) signatures.push([v, r, s]) } @@ -447,13 +447,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); }; /** @@ -499,8 +499,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, @@ -523,7 +523,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, ) } @@ -536,7 +536,7 @@ 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 @@ -550,7 +550,7 @@ Accounts.prototype.recover = function recover(message, signature, preFixed) { * return address; * }; */ - return Account.recover(message, signature); + return AccountLib.recover(message, signature); }; // Taken from https://github.com/ethereumjs/ethereumjs-wallet From f44dcfbe4bba3e5b8ca9c332dc8d1b4a7a004ae6 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 24 Sep 2019 08:49:02 +0900 Subject: [PATCH 058/123] Add error handling when fail to find account to sign --- .../caver-klay/caver-klay-accounts/src/index.js | 1 + test/packages/caver.klay.accounts.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index c2e209e8..b1118be7 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -242,6 +242,7 @@ Accounts.prototype.signTransaction = function signTransaction() { if (privateKey === undefined) { try { const account = this.wallet.getAccount(tx.from || tx.feePayer) + 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 = account.privateKey } catch(e) { return handleError(e) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index b9074afc..1e6b08d1 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -433,6 +433,23 @@ describe('caver.klay.accounts.signTransaction', () => { await expect(caver.klay.accounts.signTransaction(feePayerTransaction)).to.be.rejectedWith(errorMessage) }) }) + + 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) + }) + }) }) describe('caver.klay.accounts.recoverTransaction', () => { From 4b95882ab070e4d687b4a9d1b4744b413cd75a57 Mon Sep 17 00:00:00 2001 From: Jongsic Date: Mon, 30 Sep 2019 16:51:01 +0900 Subject: [PATCH 059/123] Allow a custom client configuration on WS connection --- .../caver-providers-ws/src/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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(); From 9caf8c08e91219f14821f303bf5b7a98a6f19d91 Mon Sep 17 00:00:00 2001 From: "J Drunken(Hoon.shin)" Date: Fri, 4 Oct 2019 14:43:28 +0900 Subject: [PATCH 060/123] change tutorial address --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7a78a08b..fb364a5b 100644 --- a/README.md +++ b/README.md @@ -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 ================= From a407714ea2ef215d11f0cf4cf9fd8731c88644a7 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 8 Oct 2019 14:47:03 +0900 Subject: [PATCH 061/123] Add data 0x prefix formatter for signTransaction --- packages/caver-core-helpers/src/formatters.js | 8 +++--- .../caver-klay-accounts/src/index.js | 2 +- test/transactionType/contractDeploy.js | 19 +++++++++++++ .../feeDelegatedContractDeploy.js | 28 +++++++++++++++---- .../feeDelegatedContractDeployWithRatio.js | 28 +++++++++++++++---- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/packages/caver-core-helpers/src/formatters.js b/packages/caver-core-helpers/src/formatters.js index d2c5e3a1..6fa4eb28 100644 --- a/packages/caver-core-helpers/src/formatters.js +++ b/packages/caver-core-helpers/src/formatters.js @@ -164,8 +164,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 +198,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; diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index b1118be7..2276fa48 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -53,7 +53,7 @@ var isNot = function(value) { function coverInitialTxValue(tx) { if (typeof tx !== 'object') throw ('Invalid transaction') tx.to = tx.to || '0x' - tx.data = tx.data || '0x' + tx.data = utils.addHexPrefix(tx.data || '0x') tx.chainId = utils.numberToHex(tx.chainId) return tx } diff --git a/test/transactionType/contractDeploy.js b/test/transactionType/contractDeploy.js index d3d80a8e..4125ea07 100644 --- a/test/transactionType/contractDeploy.js +++ b/test/transactionType/contractDeploy.js @@ -330,4 +330,23 @@ 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) }) \ No newline at end of file diff --git a/test/transactionType/feeDelegatedContractDeploy.js b/test/transactionType/feeDelegatedContractDeploy.js index c0fa253b..0c6c1686 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 @@ -328,4 +332,18 @@ 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) }) \ No newline at end of file diff --git a/test/transactionType/feeDelegatedContractDeployWithRatio.js b/test/transactionType/feeDelegatedContractDeployWithRatio.js index 652382fe..839bc364 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 @@ -331,4 +335,18 @@ 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) }) \ No newline at end of file From dda07a75ca45cca5b8c6305588ec22604b15e6c3 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 14 Oct 2019 08:28:32 +0900 Subject: [PATCH 062/123] Implement structures for Account/AccountForUpdate --- .../src/account/account.js | 70 +++++++++++++++++++ .../src/account/accountForUpdate.js | 69 ++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 packages/caver-klay/caver-klay-accounts/src/account/account.js create mode 100644 packages/caver-klay/caver-klay-accounts/src/account/accountForUpdate.js 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..98cb84a1 --- /dev/null +++ b/packages/caver-klay/caver-klay-accounts/src/account/account.js @@ -0,0 +1,70 @@ +const AccountKeyPublic = require('../accountKey/accountKeyPublic') +const AccountKeyMultiSig = require('../accountKey/accountKeyMultiSig') +const AccountKeyRoleBased = require('../accountKey/accountKeyRoleBased') +const isAddress = require('../../../../caver-utils/src/utils').isAddress + +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.`) + + Object.defineProperty(this, 'address', { + get: function () { return address }, + set: function (addressInput) { + if (!isAddress(addressInput)) throw new Error(`Invalid address : ${addressInput}`) + address = 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 (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..6e230af4 --- /dev/null +++ b/packages/caver-klay/caver-klay-accounts/src/account/accountForUpdate.js @@ -0,0 +1,69 @@ +const isValidRole = require('../../../../caver-utils').isValidRole + +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: + 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] + 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 From 4da335f58b8884bf24f3289c0c27b4edbf208ca8 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 14 Oct 2019 08:28:51 +0900 Subject: [PATCH 063/123] Define AccountKeyEnum --- .../caver-klay-accounts/src/accountKey/accountKeyEnum.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyEnum.js 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 From 48e61a00d578116cea39b839f6cfa6890ae81173 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 14 Oct 2019 08:29:30 +0900 Subject: [PATCH 064/123] Implement AccountKey classes --- .../src/accountKey/accountKeyMultiSig.js | 50 ++++++++++++ .../src/accountKey/accountKeyPublic.js | 28 +++++++ .../src/accountKey/accountKeyRoleBased.js | 76 +++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js create mode 100644 packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyPublic.js create mode 100644 packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyRoleBased.js 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..e64aa492 --- /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 \ No newline at end of file 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..63dfbab9 --- /dev/null +++ b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyRoleBased.js @@ -0,0 +1,76 @@ +const AccountKeyEnum = require('./accountKeyEnum').AccountKeyEnum +const AccountKeyPublic = require('./accountKeyPublic') +const AccountKeyMultiSig = require('./accountKeyMultiSig') + +class AccountKeyRoleBased { + constructor(keyObj = {}) { + if (keyObj instanceof AccountKeyRoleBased) keyObj = keyObj.keys + + if (typeof keyObj !== 'object') throw new Error('RoleBasedKey should be created with Object') + + 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) +} + +module.exports = AccountKeyRoleBased \ No newline at end of file From 62333b9eb354bbc4cc9d4ebb138352b1d082e522 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 15 Oct 2019 08:26:18 +0900 Subject: [PATCH 065/123] Update packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js --- .../caver-klay-accounts/src/accountKey/accountKeyMultiSig.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js index e64aa492..1a96724f 100644 --- a/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js +++ b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js @@ -23,7 +23,7 @@ class AccountKeyMultiSig { get feePayerKey() { return this._keys } toPublicKey(toPublicKeyFunc) { - const keys = [] + const keys = [] for (let i = 0; i < this._keys.length; i ++) { let key = this._keys[i] @@ -47,4 +47,4 @@ function isDuple(keys) { return false } -module.exports = AccountKeyMultiSig \ No newline at end of file +module.exports = AccountKeyMultiSig From eccde427e789224fca487ae0a19dd93676764b97 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 08:29:06 +0900 Subject: [PATCH 066/123] For fix wrong indentation --- .../caver-klay-accounts/src/accountKey/accountKeyMultiSig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js index 1a96724f..d3e5a340 100644 --- a/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js +++ b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyMultiSig.js @@ -23,7 +23,7 @@ class AccountKeyMultiSig { get feePayerKey() { return this._keys } toPublicKey(toPublicKeyFunc) { - const keys = [] + const keys = [] for (let i = 0; i < this._keys.length; i ++) { let key = this._keys[i] From 129edc4ff48f96c4a70cd74c771c7275372f4e17 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 08:37:47 +0900 Subject: [PATCH 067/123] Handle when accountKey is null --- .../caver-klay/caver-klay-accounts/src/account/account.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/account/account.js b/packages/caver-klay/caver-klay-accounts/src/account/account.js index 98cb84a1..1306e84a 100644 --- a/packages/caver-klay/caver-klay-accounts/src/account/account.js +++ b/packages/caver-klay/caver-klay-accounts/src/account/account.js @@ -5,7 +5,7 @@ const isAddress = require('../../../../caver-utils/src/utils').isAddress 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 @@ -35,7 +35,7 @@ class Account { set: function (accountKeyInput) { if (!Account.isAccountKey(accountKeyInput) && accountKeyInput !== null) throw new Error(`Invalid accountKey.`) - if (accountKeyInput === null) { + if (accountKey === null || accountKeyInput === null) { accountKey = accountKeyInput } else if (accountKey.type !== accountKeyInput.type) { accountKey = accountKeyInput From b9be39c42a48087b28025dfcab7177188e8912ca Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 08:56:48 +0900 Subject: [PATCH 068/123] Added validate function for public key --- .../src/account/accountForUpdate.js | 3 +++ packages/caver-utils/src/index.js | 1 + packages/caver-utils/src/utils.js | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/packages/caver-klay/caver-klay-accounts/src/account/accountForUpdate.js b/packages/caver-klay/caver-klay-accounts/src/account/accountForUpdate.js index 6e230af4..f2069107 100644 --- a/packages/caver-klay/caver-klay-accounts/src/account/accountForUpdate.js +++ b/packages/caver-klay/caver-klay-accounts/src/account/accountForUpdate.js @@ -1,4 +1,5 @@ const isValidRole = require('../../../../caver-utils').isValidRole +const isValidPublicKey = require('../../../../caver-utils').isValidPublicKey class AccountForUpdate { constructor(address, keyForUpdate, options) { @@ -25,6 +26,7 @@ function keyFormatter(keyForUpdate, options) { keyObject.failKey = true break default: + if (!isValidPublicKey(keyForUpdate)) throw new Error(`Invalid public key`) keyObject.publicKey = keyForUpdate break } @@ -42,6 +44,7 @@ function keyFormatter(keyForUpdate, options) { 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] } diff --git a/packages/caver-utils/src/index.js b/packages/caver-utils/src/index.js index 2b4f0b50..90cb6c1d 100644 --- a/packages/caver-utils/src/index.js +++ b/packages/caver-utils/src/index.js @@ -535,6 +535,7 @@ module.exports = { txTypeToString: utils.txTypeToString, trimLeadingZero: utils.trimLeadingZero, makeEven: utils.makeEven, + isValidPublicKey: utils.isValidPublicKey, isCompressedPublicKey: utils.isCompressedPublicKey, compressPublicKey: utils.compressPublicKey, }; diff --git a/packages/caver-utils/src/utils.js b/packages/caver-utils/src/utils.js index 30b0e2ce..4e6f90f9 100644 --- a/packages/caver-utils/src/utils.js +++ b/packages/caver-utils/src/utils.js @@ -651,6 +651,21 @@ 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)) @@ -734,6 +749,7 @@ module.exports = { trimLeadingZero, makeEven, txTypeToString, + isValidPublicKey, isCompressedPublicKey, compressPublicKey, isTxHash, From a225d6b030b386a974a6e8f121009fc842ff37e8 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 10:07:35 +0900 Subject: [PATCH 069/123] Change validation with senderRawTransaction --- .../caver-klay-accounts/src/transactionType/account.js | 4 ++-- .../caver-klay-accounts/src/transactionType/cancel.js | 4 ++-- .../caver-klay-accounts/src/transactionType/contract.js | 8 ++++---- .../src/transactionType/valueTransfer.js | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) 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..f9a09243 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) 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) From 479510ae755df7d832549a82e996630008a42c93 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 10:13:42 +0900 Subject: [PATCH 070/123] Add logic in resolveRawKeyToAccountKey --- .../src/transactionType/account.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) 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..79323b1e 100644 --- a/packages/caver-klay/caver-klay-accounts/src/transactionType/account.js +++ b/packages/caver-klay/caver-klay-accounts/src/transactionType/account.js @@ -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) } From 1648ef433d0446904514be567542ecd6203ce27b Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 10:44:44 +0900 Subject: [PATCH 071/123] Modify isCompressedPublicKey to handle without prefix --- packages/caver-utils/src/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/caver-utils/src/utils.js b/packages/caver-utils/src/utils.js index 4e6f90f9..f1e050cd 100644 --- a/packages/caver-utils/src/utils.js +++ b/packages/caver-utils/src/utils.js @@ -668,7 +668,8 @@ const isValidPublicKey = (publicKey) => { 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) => { From e2c9a5ad1fdaee57a0e0f58f5176ff054bb5b233 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 10:45:00 +0900 Subject: [PATCH 072/123] Added test case for isValidPublicKey --- test/packages/caver.utils.js | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/test/packages/caver.utils.js b/test/packages/caver.utils.js index 9de94d80..5296c438 100644 --- a/test/packages/caver.utils.js +++ b/test/packages/caver.utils.js @@ -1023,4 +1023,57 @@ describe('caver.utils.xyPointFromPublicKey', () => { 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 + }) }) \ No newline at end of file From 6d07128b41cf5629161ec5de0dbde87fa59bf5ce Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 10:48:19 +0900 Subject: [PATCH 073/123] Add test for isCompressedPublicKey --- test/isCompressedPublicKey.js | 6 ++++++ 1 file changed, 6 insertions(+) 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 }) }) From ab8e67c2c7f968f9f7a269bf951f27311dcabbae Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 10:55:37 +0900 Subject: [PATCH 074/123] Modified formatter for default address --- packages/caver-core-helpers/src/formatters.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/caver-core-helpers/src/formatters.js b/packages/caver-core-helpers/src/formatters.js index 6fa4eb28..ebb39792 100644 --- a/packages/caver-core-helpers/src/formatters.js +++ b/packages/caver-core-helpers/src/formatters.js @@ -474,6 +474,8 @@ var outputPostFormatter = function(post){ }; var inputAddressFormatter = function (address) { + // For handling coverInitialTxValue to value + if (address === '0x') return address var iban = new utils.Iban(address); if (iban.isValid() && iban.isDirect()) { From 0b0d82311c738a86ae60795f7615d14a9c44d790 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 10:53:37 +0900 Subject: [PATCH 075/123] New util functions named isValidRole and isDefaultSig --- packages/caver-utils/src/index.js | 5 ++++ packages/caver-utils/src/utils.js | 33 ++++++++++++++++++++ test/packages/caver.utils.js | 50 +++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/packages/caver-utils/src/index.js b/packages/caver-utils/src/index.js index 90cb6c1d..60506998 100644 --- a/packages/caver-utils/src/index.js +++ b/packages/caver-utils/src/index.js @@ -538,4 +538,9 @@ module.exports = { isValidPublicKey: utils.isValidPublicKey, isCompressedPublicKey: utils.isCompressedPublicKey, compressPublicKey: utils.compressPublicKey, + + // For account key + isValidRole: utils.isValidRole, + + isDefaultSig: utils.isDefaultSig, }; diff --git a/packages/caver-utils/src/utils.js b/packages/caver-utils/src/utils.js index f1e050cd..cafe4f96 100644 --- a/packages/caver-utils/src/utils.js +++ b/packages/caver-utils/src/utils.js @@ -710,6 +710,35 @@ const isContractDeployment = (txObject) => { } +const isValidRole = (role) => { + switch(role) { + case 'transactionKey': + case 'updateKey': + case 'feePayerKey': + return true + } + return false +} + +const isDefaultSig = (sig) => { + if (!Array.isArray(sig)) return false + + function isDefault (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 isDefault(sig[0]) + } + + return isDefault(sig) +} + module.exports = { BN: BN, isBN: isBN, @@ -755,4 +784,8 @@ module.exports = { compressPublicKey, isTxHash, isTxHashStrict, + + isValidRole: isValidRole, + + isDefaultSig: isDefaultSig, }; diff --git a/test/packages/caver.utils.js b/test/packages/caver.utils.js index 5296c438..e391e579 100644 --- a/test/packages/caver.utils.js +++ b/test/packages/caver.utils.js @@ -1025,6 +1025,56 @@ describe('caver.utils.xyPointFromPublicKey', () => { }) }) +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.isDefaultSig', () => { + it('CAVERJS-UNIT-ETC-178: caver.utils.isDefaultSig should true with default signatures', ()=>{ + let isDefault = caver.utils.isDefaultSig(['0x01', '0x', '0x']) + expect(isDefault).to.be.true + + isDefault = caver.utils.isDefaultSig([['0x01', '0x', '0x']]) + expect(isDefault).to.be.true + }) + + it('CAVERJS-UNIT-ETC-179: caver.utils.isDefaultSig should false if signatures is not same with default signatures', ()=>{ + let isDefault = caver.utils.isDefaultSig([['0x01', '0x', '0x'], ['0x01', '0x', '0x']]) + expect(isDefault).to.be.false + + isDefault = caver.utils.isDefaultSig(['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']) + expect(isDefault).to.be.false + + isDefault = caver.utils.isDefaultSig([['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']]) + expect(isDefault).to.be.false + }) + + it('CAVERJS-UNIT-ETC-180: caver.utils.isDefaultSig should throw error with invalid length of signatures', ()=>{ + let expectedError = `Invalid signatures length: 6` + expect(() => caver.utils.isDefaultSig(['0x01', '0x', '0x', '0x01', '0x', '0x'])).to.throws(expectedError) + expect(() => caver.utils.isDefaultSig([['0x01', '0x', '0x', '0x01', '0x', '0x']])).to.throws(expectedError) + }) +}) 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() From 23a7bc9b268878a73dcd003756ee51626658af46 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 11:01:36 +0900 Subject: [PATCH 076/123] Rebased on dev --- test/packages/caver.utils.js | 101 ++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/test/packages/caver.utils.js b/test/packages/caver.utils.js index e391e579..1e74ae1d 100644 --- a/test/packages/caver.utils.js +++ b/test/packages/caver.utils.js @@ -1025,56 +1025,6 @@ describe('caver.utils.xyPointFromPublicKey', () => { }) }) -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.isDefaultSig', () => { - it('CAVERJS-UNIT-ETC-178: caver.utils.isDefaultSig should true with default signatures', ()=>{ - let isDefault = caver.utils.isDefaultSig(['0x01', '0x', '0x']) - expect(isDefault).to.be.true - - isDefault = caver.utils.isDefaultSig([['0x01', '0x', '0x']]) - expect(isDefault).to.be.true - }) - - it('CAVERJS-UNIT-ETC-179: caver.utils.isDefaultSig should false if signatures is not same with default signatures', ()=>{ - let isDefault = caver.utils.isDefaultSig([['0x01', '0x', '0x'], ['0x01', '0x', '0x']]) - expect(isDefault).to.be.false - - isDefault = caver.utils.isDefaultSig(['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']) - expect(isDefault).to.be.false - - isDefault = caver.utils.isDefaultSig([['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']]) - expect(isDefault).to.be.false - }) - - it('CAVERJS-UNIT-ETC-180: caver.utils.isDefaultSig should throw error with invalid length of signatures', ()=>{ - let expectedError = `Invalid signatures length: 6` - expect(() => caver.utils.isDefaultSig(['0x01', '0x', '0x', '0x01', '0x', '0x'])).to.throws(expectedError) - expect(() => caver.utils.isDefaultSig([['0x01', '0x', '0x', '0x01', '0x', '0x']])).to.throws(expectedError) - }) -}) 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() @@ -1126,4 +1076,55 @@ describe('caver.utils.isValidPublicKey', () => { 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.isDefaultSig', () => { + it('CAVERJS-UNIT-ETC-178: caver.utils.isDefaultSig should true with default signatures', ()=>{ + let isDefault = caver.utils.isDefaultSig(['0x01', '0x', '0x']) + expect(isDefault).to.be.true + + isDefault = caver.utils.isDefaultSig([['0x01', '0x', '0x']]) + expect(isDefault).to.be.true + }) + + it('CAVERJS-UNIT-ETC-179: caver.utils.isDefaultSig should false if signatures is not same with default signatures', ()=>{ + let isDefault = caver.utils.isDefaultSig([['0x01', '0x', '0x'], ['0x01', '0x', '0x']]) + expect(isDefault).to.be.false + + isDefault = caver.utils.isDefaultSig(['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']) + expect(isDefault).to.be.false + + isDefault = caver.utils.isDefaultSig([['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']]) + expect(isDefault).to.be.false + }) + + it('CAVERJS-UNIT-ETC-180: caver.utils.isDefaultSig should throw error with invalid length of signatures', ()=>{ + let expectedError = `Invalid signatures length: 6` + expect(() => caver.utils.isDefaultSig(['0x01', '0x', '0x', '0x01', '0x', '0x'])).to.throws(expectedError) + expect(() => caver.utils.isDefaultSig([['0x01', '0x', '0x', '0x01', '0x', '0x']])).to.throws(expectedError) + }) }) \ No newline at end of file From d51391b7e846a809902e4212fc5361da1bec6778 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 11:06:01 +0900 Subject: [PATCH 077/123] Compare address with lower case of address --- test/decodeTransaction.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/decodeTransaction.js b/test/decodeTransaction.js index e4c2f4f4..fb172653 100644 --- a/test/decodeTransaction.js +++ b/test/decodeTransaction.js @@ -88,7 +88,7 @@ describe('Decode Transaction', () => { 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(payer.address) + 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 From 24b5fc6c0207333c2d400fcf4216446c5869a123 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 12:19:43 +0900 Subject: [PATCH 078/123] Implemented functions for extract signatures and make fee payer format --- .../src/makeRawTransaction.js | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js index ea11904c..c4e416d6 100644 --- a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js +++ b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js @@ -177,7 +177,44 @@ function _combineFeePayerRawTransaction(rlpEncoded, sig, transaction, senderSign return txType + RLP.encode(rawTx).slice(2) } +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 decodeTxForFeePayer(rawTransaction) { + 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) @@ -222,15 +259,15 @@ function decodeFromRawTransaction (rawTransaction, type) { } case 'ACCOUNT_UPDATE': { const [ nonce, gasPrice, gas, from, accountKey, signatures ] = RLP.decode(rawTransaction) - return parseAccountKey({ type: typeString, nonce, gasPrice, gas, from, accountKey, v: signatures[0][0], r: signatures[0][1], s: signatures[0][2], signatures }) + 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, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction) - return parseAccountKey({ 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 }) + 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, signatures, feePayer, feePayerSignatures ] = RLP.decode(rawTransaction) - return parseAccountKey({ 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 }) + 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, signatures ] = RLP.decode(rawTransaction) @@ -321,4 +358,6 @@ module.exports = { decodeFromRawTransaction, overwriteSignature, getSenderTxHash, + decodeTxForFeePayer, + extractSignatures, } \ No newline at end of file From e5e7887080fd510dee7852181801d5cb7c408ac6 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Tue, 15 Oct 2019 13:15:01 +0900 Subject: [PATCH 079/123] Update packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js Co-Authored-By: Junghyun Colin Kim --- .../caver-klay/caver-klay-accounts/src/makeRawTransaction.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js index c4e416d6..4db83e70 100644 --- a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js +++ b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js @@ -213,7 +213,6 @@ function decodeFromRawTransaction (rawTransaction, type) { return decodeResult } - function _decodeFromRawTransaction(rawTransaction, type) { var typeString = type if (typeString === undefined || typeString !== 'LEGACY') { @@ -360,4 +359,4 @@ module.exports = { getSenderTxHash, decodeTxForFeePayer, extractSignatures, -} \ No newline at end of file +} From 58fcecc501416b02a81364cc5da6c83099496f3f Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 13:28:04 +0900 Subject: [PATCH 080/123] Add check logic for checking type string --- .../caver-klay/caver-klay-accounts/src/makeRawTransaction.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js index 4db83e70..37ce4377 100644 --- a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js +++ b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js @@ -190,6 +190,10 @@ function extractSignatures(rawTransaction) { } function decodeTxForFeePayer(rawTransaction) { + const typeString = utils.getTxTypeStringFromRawTransaction(rawTransaction) + + if (!typeString || !typeString.includes('FEE_DELEGATED')) throw new Error(`The RLP encoded transaction is not a fee delegated transaction type: '${typeString? typeString : 'LEGACY'}'`) + const txType = rawTransaction.slice(0, 4) const decodedValues = RLP.decode(utils.addHexPrefix(rawTransaction.slice(4))) From 054f73a612b68d30730426d91b85c8bcf8a109f7 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 13:33:14 +0900 Subject: [PATCH 081/123] Change name to isEmptySig --- packages/caver-utils/src/index.js | 2 +- packages/caver-utils/src/utils.js | 10 +++++----- test/packages/caver.utils.js | 22 +++++++++++----------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/caver-utils/src/index.js b/packages/caver-utils/src/index.js index 60506998..26da72ff 100644 --- a/packages/caver-utils/src/index.js +++ b/packages/caver-utils/src/index.js @@ -542,5 +542,5 @@ module.exports = { // For account key isValidRole: utils.isValidRole, - isDefaultSig: utils.isDefaultSig, + isEmptySig: utils.isEmptySig, }; diff --git a/packages/caver-utils/src/utils.js b/packages/caver-utils/src/utils.js index cafe4f96..b743ddff 100644 --- a/packages/caver-utils/src/utils.js +++ b/packages/caver-utils/src/utils.js @@ -720,10 +720,10 @@ const isValidRole = (role) => { return false } -const isDefaultSig = (sig) => { +const isEmptySig = (sig) => { if (!Array.isArray(sig)) return false - function isDefault (s) { + 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 @@ -733,10 +733,10 @@ const isDefaultSig = (sig) => { if (Array.isArray(sig[0])) { // [[v,r,s]] if (sig.length !== 1) return false - return isDefault(sig[0]) + return isEmpty(sig[0]) } - return isDefault(sig) + return isEmpty(sig) } module.exports = { @@ -787,5 +787,5 @@ module.exports = { isValidRole: isValidRole, - isDefaultSig: isDefaultSig, + isEmptySig: isEmptySig, }; diff --git a/test/packages/caver.utils.js b/test/packages/caver.utils.js index 1e74ae1d..96030e8d 100644 --- a/test/packages/caver.utils.js +++ b/test/packages/caver.utils.js @@ -1102,29 +1102,29 @@ describe('caver.utils.isValidRole', () => { }) }) -describe('caver.utils.isDefaultSig', () => { - it('CAVERJS-UNIT-ETC-178: caver.utils.isDefaultSig should true with default signatures', ()=>{ - let isDefault = caver.utils.isDefaultSig(['0x01', '0x', '0x']) +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.isDefaultSig([['0x01', '0x', '0x']]) + isDefault = caver.utils.isEmptySig([['0x01', '0x', '0x']]) expect(isDefault).to.be.true }) - it('CAVERJS-UNIT-ETC-179: caver.utils.isDefaultSig should false if signatures is not same with default signatures', ()=>{ - let isDefault = caver.utils.isDefaultSig([['0x01', '0x', '0x'], ['0x01', '0x', '0x']]) + 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.isDefaultSig(['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']) + isDefault = caver.utils.isEmptySig(['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']) expect(isDefault).to.be.false - isDefault = caver.utils.isDefaultSig([['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']]) + isDefault = caver.utils.isEmptySig([['0x25', '0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9', '0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567']]) expect(isDefault).to.be.false }) - it('CAVERJS-UNIT-ETC-180: caver.utils.isDefaultSig should throw error with invalid length of signatures', ()=>{ + 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.isDefaultSig(['0x01', '0x', '0x', '0x01', '0x', '0x'])).to.throws(expectedError) - expect(() => caver.utils.isDefaultSig([['0x01', '0x', '0x', '0x01', '0x', '0x']])).to.throws(expectedError) + 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 From 8ed8743eab66b9440d1141a95de412768050ed2f Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 13:44:57 +0900 Subject: [PATCH 082/123] Changed name to splitFeePayer --- .../caver-klay/caver-klay-accounts/src/makeRawTransaction.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js index 37ce4377..83eb8d53 100644 --- a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js +++ b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js @@ -189,7 +189,7 @@ function extractSignatures(rawTransaction) { return { senderSignatures, feePayerSignatures, decodedTransaction: decoded } } -function decodeTxForFeePayer(rawTransaction) { +function splitFeePayer(rawTransaction) { const typeString = utils.getTxTypeStringFromRawTransaction(rawTransaction) if (!typeString || !typeString.includes('FEE_DELEGATED')) throw new Error(`The RLP encoded transaction is not a fee delegated transaction type: '${typeString? typeString : 'LEGACY'}'`) @@ -361,6 +361,6 @@ module.exports = { decodeFromRawTransaction, overwriteSignature, getSenderTxHash, - decodeTxForFeePayer, + splitFeePayer, extractSignatures, } From c8ecc2b1cdd0dec1dc64271f9db09b9604d4480f Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Tue, 15 Oct 2019 14:19:19 +0900 Subject: [PATCH 083/123] Modified validateParams function --- .../src/validateFunction.js | 58 ++++++++++++++++--- 1 file changed, 51 insertions(+), 7 deletions(-) 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') From 9ea4f418e1349232d632d2c3ebab3bb6e7522e36 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 16 Oct 2019 09:01:15 +0900 Subject: [PATCH 084/123] Add hex prefix to address with Account --- .../caver-klay/caver-klay-accounts/src/account/account.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/account/account.js b/packages/caver-klay/caver-klay-accounts/src/account/account.js index 1306e84a..60b7f7e4 100644 --- a/packages/caver-klay/caver-klay-accounts/src/account/account.js +++ b/packages/caver-klay/caver-klay-accounts/src/account/account.js @@ -2,6 +2,7 @@ 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)) } @@ -21,11 +22,13 @@ class 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 = addressInput + address = addHexPrefix(addressInput) }, enumerable: true }) From 1433d9845fde0273d28289f4acfb837b26181dc8 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 16 Oct 2019 13:04:04 +0900 Subject: [PATCH 085/123] Modify determination of fee payer format --- packages/caver-core-helpers/src/formatters.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/caver-core-helpers/src/formatters.js b/packages/caver-core-helpers/src/formatters.js index ebb39792..aa370cd9 100644 --- a/packages/caver-core-helpers/src/formatters.js +++ b/packages/caver-core-helpers/src/formatters.js @@ -140,12 +140,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!'); } From 1cd03f9f7594933c0c222a5e36d63c48db3dd4ea Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 16 Oct 2019 13:38:35 +0900 Subject: [PATCH 086/123] Remove logic for handling default feePayer address --- packages/caver-core-helpers/src/formatters.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/caver-core-helpers/src/formatters.js b/packages/caver-core-helpers/src/formatters.js index aa370cd9..5a52da8c 100644 --- a/packages/caver-core-helpers/src/formatters.js +++ b/packages/caver-core-helpers/src/formatters.js @@ -471,9 +471,6 @@ var outputPostFormatter = function(post){ }; var inputAddressFormatter = function (address) { - // For handling coverInitialTxValue to value - if (address === '0x') return address - var iban = new utils.Iban(address); if (iban.isValid() && iban.isDirect()) { return iban.toAddress().toLowerCase(); From e4c9759291e6f29af40cd357ebe2504a806bddf1 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 16 Oct 2019 13:39:59 +0900 Subject: [PATCH 087/123] Remove unnecessary check statement for validation --- packages/caver-core-method/src/index.js | 41 +++++++++++-------- .../caver-klay-accounts/src/index.js | 13 ++---- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/packages/caver-core-method/src/index.js b/packages/caver-core-method/src/index.js index a486ff81..73407454 100644 --- a/packages/caver-core-method/src/index.js +++ b/packages/caver-core-method/src/index.js @@ -287,6 +287,7 @@ const buildSendSignedTxFunc = (method, payload, sendTxCallback) => (sign) => { const buildSendRequestFunc = (defer, sendSignedTx, sendTxCallback) => (payload, method) => { if (method && method.accounts && method.accounts.wallet && method.accounts.wallet.length) { + let error switch (payload.method) { case 'klay_sendTransaction': { var tx = payload.params[0] @@ -298,41 +299,47 @@ const buildSendRequestFunc = (defer, sendSignedTx, sendTxCallback) => (payload, // } if (!_.isObject(tx)) { - let error = new Error('The transaction must be defined as an object.') + error = new Error('The transaction must be defined as an object.') sendTxCallback(error) return Promise.reject(error) } - if (tx.senderRawTransaction && tx.from && tx.feePayer){ - console.log('"from" is ignored for a fee-delegated transaction.') - delete tx.from + 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 = method.accounts.wallet.getAccount(tx.from || tx.feePayer) + let wallet + + try { + wallet = method.accounts.wallet.getAccount(addressToUse) + } catch (e) { + sendTxCallback(e) + return Promise.reject(e) + } if (wallet && wallet.privateKey) { // If wallet was found, sign tx, and send using sendRawTransaction - return method.accounts.signTransaction(tx, wallet.privateKey) - .then(sendSignedTx) - .catch((e) => { - sendTxCallback(e) - }) + return method.accounts.signTransaction(tx, wallet.privateKey).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 } diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 2276fa48..6d14ab63 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -232,11 +232,8 @@ Accounts.prototype.signTransaction = function signTransaction() { // For handling when callback is undefined. callback = callback || function () {} - // Validate tx object - if (!tx.senderRawTransaction) { - const error = helpers.validateFunction.validateParams(tx) - if (error) return handleError(error) - } else if (!tx.feePayer) { return handleError('To sign with fee payer, senderRawTransaction and feePayer must be defined in the transaction object.') } + let error = helpers.validateFunction.validateParams(tx) + if (error) return handleError(error) // When privateKey is undefined, find Account from Wallet. if (privateKey === undefined) { @@ -367,9 +364,7 @@ Accounts.prototype.signTransactionWithSignature = function signTransactionWithSi } function signed(tx) { - if (!tx.senderRawTransaction) { - error = helpers.validateFunction.validateParams(tx) - } + error = helpers.validateFunction.validateParams(tx) if (error) { callback(error) return Promise.reject(error) @@ -1106,7 +1101,7 @@ Wallet.prototype.getAccount = function (input) { return this[input] } - if (!_.isString(input)) throw new Error(`Accounts in the Wallet can be searched by only index or address.`) + 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})`) From be11fa63b1cb0d3796d2c2e5fbc0d3eba20863cd Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 16 Oct 2019 14:10:10 +0900 Subject: [PATCH 088/123] Added test case for new logic in validateParams --- test/transactionType/accountUpdate.js | 38 +++++ test/transactionType/cancelTransaction.js | 40 ++++- test/transactionType/contractDeploy.js | 40 ++++- test/transactionType/contractExecution.js | 62 +++++++- .../feeDelegatedAccountUpdate.js | 125 ++++++++++++++- .../feeDelegatedAccountUpdateWithRatio.js | 127 ++++++++++++++- .../feeDelegatedCancelTransaction.js | 127 ++++++++++++++- .../feeDelegatedCancelTransactionWithRatio.js | 125 ++++++++++++++- .../feeDelegatedContractDeploy.js | 125 ++++++++++++++- .../feeDelegatedContractDeployWithRatio.js | 125 ++++++++++++++- .../feeDelegatedContractExecution.js | 147 +++++++++++++++++- .../feeDelegatedContractExecutionWithRatio.js | 147 +++++++++++++++++- .../feeDelegatedValueTransfer.js | 142 +++++++++++++++++ .../feeDelegatedValueTransferMemo.js | 143 +++++++++++++++++ .../feeDelegatedValueTransferMemoWithRatio.js | 143 +++++++++++++++++ .../feeDelegatedValueTransferWithRatio.js | 143 +++++++++++++++++ test/transactionType/legacyTransaction.js | 60 +++++++ test/transactionType/valueTransfer.js | 60 +++++++ test/transactionType/valueTransferWithMemo.js | 60 +++++++ 19 files changed, 1935 insertions(+), 44 deletions(-) diff --git a/test/transactionType/accountUpdate.js b/test/transactionType/accountUpdate.js index 2d369c29..41dc9b10 100644 --- a/test/transactionType/accountUpdate.js +++ b/test/transactionType/accountUpdate.js @@ -1574,4 +1574,42 @@ 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) }) \ 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 4125ea07..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 @@ -349,4 +349,42 @@ describe('SMART_CONTRACT_DEPLOY transaction', () => { 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..b4043170 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,124 @@ 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) }) \ No newline at end of file diff --git a/test/transactionType/feeDelegatedAccountUpdateWithRatio.js b/test/transactionType/feeDelegatedAccountUpdateWithRatio.js index 71f8c2e6..d7efe1ef 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,124 @@ 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) }) \ 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 0c6c1686..8108d1bf 100644 --- a/test/transactionType/feeDelegatedContractDeploy.js +++ b/test/transactionType/feeDelegatedContractDeploy.js @@ -157,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) @@ -346,4 +341,124 @@ describe('FEE_DELEGATED_SMART_CONTRACT_DEPLOY transaction', () => { 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 839bc364..7c31af41 100644 --- a/test/transactionType/feeDelegatedContractDeployWithRatio.js +++ b/test/transactionType/feeDelegatedContractDeployWithRatio.js @@ -158,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) @@ -349,4 +344,124 @@ describe('FEE_DELEGATED_SMART_CONTRACT_DEPLOY_WITH_RATIO transaction', () => { 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/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 From 2a705ea6c4f7e71b0bbe4cd06506601ecf817392 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Wed, 16 Oct 2019 14:19:29 +0900 Subject: [PATCH 089/123] Modify test code for appliance --- test/packages/caver.klay.accounts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 1e6b08d1..67afd828 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -429,7 +429,7 @@ describe('caver.klay.accounts.signTransaction', () => { senderRawTransaction: senderSigned.rawTransaction, } - const errorMessage = 'To sign with fee payer, senderRawTransaction and feePayer must be defined in the transaction object.' + const errorMessage = `Invalid fee payer: ${feePayerTransaction.feePayer}` await expect(caver.klay.accounts.signTransaction(feePayerTransaction)).to.be.rejectedWith(errorMessage) }) }) From c014d16adedd2e0be364eee04983120026cf5859 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Thu, 17 Oct 2019 10:24:36 +0900 Subject: [PATCH 090/123] New Account and AccountKey in Accounts package --- .../caver-klay-accounts/src/index.js | 472 ++- test/packages/caver.klay.accounts.js | 2599 +++++++++++++++-- 2 files changed, 2767 insertions(+), 304 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 6d14ab63..1482abfd 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -44,6 +44,14 @@ const { encodeRLPByTxType, makeRawTransaction, getSenderTxHash } = require('./ma 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,8 +60,10 @@ var isNot = function(value) { function coverInitialTxValue(tx) { if (typeof tx !== 'object') throw ('Invalid transaction') - tx.to = tx.to || '0x' - tx.data = utils.addHexPrefix(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 } @@ -94,7 +104,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() { @@ -136,10 +146,187 @@ Accounts.prototype._determineAddress = function _determineAddress(legacyAccount, return legacyAccount.address } +/** + * 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(AccountLib.create(entropy || utils.randomHex(32))); + return this._addAccountFunctions(Account.fromObject(AccountLib.create(entropy || utils.randomHex(32)))); }; +/** + * createAccountKey creates AccountKeyPublic or 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 key. + * + * @method createAccountKeyMultiSig + * @param {Array} privateKeys An Array of private key string 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.') + + 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]}`) + } + }) + 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) +} + +/** + * 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) + + 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 account = new Account(address, keyObject) + return this._addAccountFunctions(account) +} + /** * privateKeyToAccount creates and returns an Account through the input passed as parameters. * @@ -155,7 +342,77 @@ Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(key, userI account.address = account.address.toLowerCase() account.address = utils.addHexPrefix(account.address) - return this._addAccountFunctions(account) + return account +} + + +/** + * createAccountForUpdate creates 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) + } + + 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') } /** @@ -188,7 +445,9 @@ Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { privateKey = utils.addHexPrefix(privateKey) - return { legacyAccount: AccountLib.fromPrivate(privateKey), klaytnWalletKeyAddress } + const account = this._addAccountFunctions(Account.fromObject(AccountLib.fromPrivate(privateKey))) + + return { legacyAccount: account, klaytnWalletKeyAddress } } Accounts.prototype.signTransaction = function signTransaction() { @@ -840,112 +1099,155 @@ Wallet.prototype.create = function (numberOfAccounts, entropy) { } */ Wallet.prototype.add = function (account, userInputAddress) { - 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, userInputAddress); - } else if(!_.isObject(account)) { - throw new Error('Invalid private key') - } + 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) + } - const accountAlreadyExists = !!this[account.address] + if (!!this[accountForWallet.address]) throw new Error('Account exists with ' + accountForWallet.address) - if (accountAlreadyExists) { - throw new Error('Account exists with ' + account.address) - } + accountForWallet.index = this._findSafeIndex() + this[accountForWallet.index] = accountForWallet - account = this._accounts.privateKeyToAccount(account.privateKey, userInputAddress || account.address) + this[accountForWallet.address] = accountForWallet + this[accountForWallet.address.toLowerCase()] = accountForWallet + this[accountForWallet.address.toUpperCase()] = accountForWallet + try { + this[utils.toChecksumAddress(accountForWallet.address)] = accountForWallet + } catch (e) {} - account.index = this._findSafeIndex() - this[account.index] = account + this.length++ - this[account.address] = account - this[account.address.toLowerCase()] = account - this[account.address.toUpperCase()] = account - try { - this[utils.toChecksumAddress(account.address)] = account - } catch (e) {} + return accountForWallet +} - this.length++ +Wallet.prototype.updatePrivateKey = function (privateKey, address) { +if (privateKey === undefined || address === undefined) { + throw new Error('To update the privatKey in wallet, need to set both privateKey and address.') +} - return account +// If privateKey parameter is not string type, return error +if (!_.isString(privateKey)) { + throw new Error('The private key used for the update is not a valid string.') } -Wallet.prototype.updatePrivateKey = function (privateKey, address) { - if (privateKey === undefined || address === undefined) { - throw new Error('To update the privatKey in wallet, need to set both privateKey and address.') - } +if (!utils.isAddress(address)) throw new Error(`Invalid address : ${address}`) - // If privateKey parameter is not string type, return error - if (!_.isString(privateKey)) { - throw new Error('The private key used for the update is not a valid string.') - } +// If failed to find account through address, return error +const accountExists = !!this[address] +if (!accountExists) throw new Error('Failed to find account with ' + 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] - 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.') +const parsed = utils.parsePrivateKey(privateKey) +if (!utils.isValidPrivateKey(parsed.privateKey)) throw new Error('Invalid private key') - 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.') +} - 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 - } catch (e) {} +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 - return account +try { + this[utils.toChecksumAddress(account.address)].accountKey = newAccountKeyPublic +} catch (e) {} + +return account +} + +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.isAccountKey(accountKey)) { + accountKey = this._accounts.createAccountKey(accountKey) } - Wallet.prototype.remove = function (addressOrIndex) { - var account = this[addressOrIndex] +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) - if (account && account.address) { - // address - this[account.address].privateKey = null - delete this[account.address] +const account = this[address] - if (this[account.address.toLowerCase()]) { - // address lowercase - this[account.address.toLowerCase()].privateKey = null - delete this[account.address.toLowerCase()] - } +this[account.index].accountKey = accountKey +this[account.address].accountKey = accountKey +this[account.address.toLowerCase()].accountKey = accountKey +this[account.address.toUpperCase()].accountKey = accountKey - if (this[account.address.toUpperCase()]) { - // address uppercase - this[account.address.toUpperCase()].privateKey = null - delete this[account.address.toUpperCase()] - } +try { + this[utils.toChecksumAddress(account.address)].accountKey = accountKey +} catch (e) {} - try { - this[utils.toChecksumAddress(account.address)].privateKey = null - delete this[utils.toChecksumAddress(account.address)] - } catch (e) {} +return account +} - // index - this[account.index].privateKey = null - delete this[account.index] +Wallet.prototype.remove = function (addressOrIndex) { + var account = this[addressOrIndex] - this.length-- + 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; diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 67afd828..f073e2ee 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()) } } @@ -85,19 +86,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', () => { @@ -142,6 +183,8 @@ describe('caver.klay.accounts.signTransaction', () => { 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, @@ -291,8 +334,7 @@ describe('caver.klay.accounts.signTransaction', () => { context('CAVERJS-UNIT-WALLET-122 : input: legacyTx, privateKey of decoupled account', () => { it('should return signature and rawTransaction', async () => { - const decoupledAccount = caver.klay.accounts.create() - decoupledAccount.privateKey = caver.klay.accounts.create().privateKey + const decoupledAccount = caver.klay.accounts.privateKeyToAccount(caver.klay.accounts.create().privateKey, caver.klay.accounts.create().address) let tx = { from: decoupledAccount.address, @@ -359,7 +401,8 @@ describe('caver.klay.accounts.signTransaction', () => { }) it('should sign to transaction parameter with private key array', async () => { - const result = await caver.klay.accounts.signTransaction(vtTx, [account.privateKey.slice(2), account.privateKey]) + const privateKeyArray = [caver.klay.accounts.create().privateKey, caver.klay.accounts.create().privateKey] + const result = await caver.klay.accounts.signTransaction(vtTx, privateKeyArray) const keys = ['messageHash', 'v', 'r', 's', 'rawTransaction', 'txHash', 'senderTxHash', 'signatures'] expect(Object.getOwnPropertyNames(result)).to.deep.equal(keys) @@ -497,8 +540,9 @@ describe('caver.klay.accounts.recoverTransaction', () => { value: '0x1', chainId: 10000, } - account.address = '0x13b0d8316F0c3cE0C3C51Ebb586A14d7d90112fD' - account.privateKey = '0x72d72a46401220f08ccb1b17b550feb816840f2f8ce86361e7ee54ac7a9ee6d8' + + let privateKey = '0x72d72a46401220f08ccb1b17b550feb816840f2f8ce86361e7ee54ac7a9ee6d8' + account = caver.klay.accounts.privateKeyToAccount(privateKey) const signed = await caver.klay.accounts.signTransaction(transaction, account.privateKey) @@ -522,8 +566,9 @@ describe('caver.klay.accounts.recoverTransaction', () => { value: '0x1', chainId: 10000, } - account.address = '0x13b0d8316F0c3cE0C3C51Ebb586A14d7d90112fD' - account.privateKey = '0x72d72a46401220f08ccb1b17b550feb816840f2f8ce86361e7ee54ac7a9ee6d8' + address = '0x13b0d8316F0c3cE0C3C51Ebb586A14d7d90112fD' + privateKey = '0x72d72a46401220f08ccb1b17b550feb816840f2f8ce86361e7ee54ac7a9ee6d8' + caver.klay.accounts.privateKeyToAccount(privateKey, address) const signed = await caver.klay.accounts.signTransaction(transaction, account.privateKey) @@ -665,7 +710,7 @@ describe('caver.klay.accounts.encrypt', () => { isKeystoreV3(result, account) const decryptedAccount = caver.klay.accounts.decrypt(result, password) - isAccount(decryptedAccount, account) + isAccount(decryptedAccount, {keys: account.keys, address: account.address}) }) }) @@ -688,7 +733,7 @@ describe('caver.klay.accounts.encrypt', () => { isKeystoreV3(result, account) const decryptedAccount = caver.klay.accounts.decrypt(result, password) - isAccount(decryptedAccount, account) + isAccount(decryptedAccount, {keys: account.keys, address: account.address}) }) }) @@ -701,7 +746,7 @@ describe('caver.klay.accounts.encrypt', () => { isKeystoreV3(result, account) const decryptedAccount = caver.klay.accounts.decrypt(result, password) - isAccount(decryptedAccount, account) + isAccount(decryptedAccount, {keys: account.keys, address: account.address}) }) }) @@ -717,39 +762,41 @@ describe('caver.klay.accounts.encrypt', () => { 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) - isKeystoreV3(result, updatedAccount) + let testAccount = caver.klay.accounts.createWithAccountKey(account.address, caver.klay.accounts.create().privateKey) + + let result = caver.klay.accounts.encrypt(testAccount.getKlaytnWalletKey(), password) + + isKeystoreV3(result, testAccount) const decryptedAccount = caver.klay.accounts.decrypt(result, password) - isAccount(decryptedAccount, updatedAccount) + 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!@' - 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}) + + let testAccount = caver.klay.accounts.createWithAccountKey(account.address, caver.klay.accounts.create().privateKey) - isKeystoreV3(result, updatedAccount) + let result = caver.klay.accounts.encrypt(testAccount.getKlaytnWalletKey(), password, {address: testAccount.address}) + + isKeystoreV3(result, testAccount) const decryptedAccount = caver.klay.accounts.decrypt(result, password) - isAccount(decryptedAccount, updatedAccount) + 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!@' - caver.klay.accounts.wallet.add(account) - var updatedAccount = caver.klay.accounts.wallet.updatePrivateKey(caver.klay.accounts.create().privateKey, account.address) + + 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(updatedAccount.getKlaytnWalletKey(), password, {address: caver.klay.accounts.create().address})).to.throw(errorMessage) + expect(() => caver.klay.accounts.encrypt(testAccount.getKlaytnWalletKey(), password, {address: caver.klay.accounts.create().address})).to.throw(errorMessage) }) }) }) @@ -769,7 +816,7 @@ describe('caver.klay.accounts.decrypt', () => { let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) isKeystoreV3(keystoreJsonV3, result) - isAccount(result, account) + isAccount(result, {keys: account.keys, address: account.address}) }) }) @@ -827,8 +874,9 @@ describe('caver.klay.accounts.getLegacyAccount', () => { 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 testAccount = caver.klay.accounts.create() - testAccount.privateKey = caver.klay.accounts.create().privateKey + 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()) @@ -870,16 +918,20 @@ describe('caver.klay.accounts.getLegacyAccount', () => { 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 testAccount = caver.klay.accounts.create() - testAccount.privateKey = caver.klay.accounts.create().privateKey + 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 testAccount = caver.klay.accounts.create() - testAccount.privateKey = caver.klay.accounts.create().privateKey + 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 }) @@ -923,8 +975,9 @@ describe('caver.klay.accounts.isDecoupled', () => { context('CAVERJS-UNIT-WALLET-116 : input: not match address with KlaytnWalletKey and input', () => { it('should throw error if input is invalid privateKey string', () => { - const testAccount = caver.klay.accounts.create() - testAccount.privateKey = caver.klay.accounts.create().privateKey + 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.' @@ -933,266 +986,2014 @@ describe('caver.klay.accounts.isDecoupled', () => { }) }) -describe('caver.klay.accounts.wallet', () => { +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) - it('CAVERJS-UNIT-WALLET-043 : should return valid wallet instance', () => { - let result = caver.klay.accounts.wallet - isWallet(result) + 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') + }) + }) - const accounts = [] - const accountCount = Math.floor(Math.random() * 10) + 1 - for (let i = 0; i < accountCount; i++) { - const account = caver.klay.accounts.create() - accounts.push(account) - caver.klay.accounts.wallet.add(account) - } + 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') + }) + }) - isWallet(result, { accounts }) + 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') + }) }) -}) -describe('caver.klay.accounts.wallet.create', () => { + 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') + }) + }) - const validateCheckForWalletCreation = (result, numberOfAccounts) => { - 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]) + 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') + }) + }) - delete accountByIndex.index - delete accountByAddress.index + 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') + }) + }) - isAccount(accountByIndex, { privateKey: accountByAddress.privateKey, address: accountByAddress.address }) - isAccount(accountByAddress, { privateKey: accountByIndex.privateKey, address: accountByIndex.address }) - } - } + 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-044 : input: numberOfAccounts', () => { - it('should return valid wallet instance', () => { - const numberOfAccounts = Math.floor(Math.random() * 5) + 1 - let result = caver.klay.accounts.wallet.create(numberOfAccounts) - validateCheckForWalletCreation(result, numberOfAccounts) + 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-045 : input: numberOfAccounts:invalid', () => { - it('should return 0 wallet', () => { - const invalid = -1 - let result = caver.klay.accounts.wallet.create(invalid) - validateCheckForWalletCreation(result, 0) + 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-046 : input: numberOfAccounts, entropy', () => { - it('should return valid wallet instance', () => { - const numberOfAccounts = Math.floor(Math.random() * 5) + 1 - const entropy = caver.utils.randomHex(32) + 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) - let result = caver.klay.accounts.wallet.create(numberOfAccounts, entropy) - validateCheckForWalletCreation(result, numberOfAccounts) + 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) }) }) -}) -describe('caver.klay.accounts.wallet.add', () => { - const validateCheckForWalletAddition = (data, { account, wallet }) => { - const accounts = [] + 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) - accounts.push(Object.assign({}, data)) - accounts.push(Object.assign({}, wallet[data.index])) - accounts.push(Object.assign({}, wallet[data.address])) + param = ['invalidString'] + expectedError = `Invalid private key` + expect(() => caver.klay.accounts.createAccountKey(param)).to.throws(expectedError) - for (v of accounts) { - delete v.index - isAccount(v, { privateKey: account.privateKey, address: account.address }) - } - } + param = {} + expectedError = `Failed to create AccountKeyRoleBased: empty object` + expect(() => caver.klay.accounts.createAccountKey(param)).to.throws(expectedError) + }) + }) +}) - context('CAVERJS-UNIT-WALLET-047 : input: account', () => { - it('should have valid wallet instance after addition', () => { - let account = caver.klay.accounts.create() - let result = caver.klay.accounts.wallet.add(account) +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) - validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + 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-048 : input: privateKey', () => { - it('should have valid wallet instance after addition', () => { - account = caver.klay.accounts.create() - result = caver.klay.accounts.wallet.add(account.privateKey) + 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)) - validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + 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-052 : input: KlaytnWalletKey', () => { - it('should have valid wallet instance after addition', () => { - // KlaytnWalletkey with nonHumanReadableAddress - var klaytnWalletKey = '0x600dfc414fe433881f6606c24955e4143df9d203ccb3e335efe970a4ad017d040x000xee135d0b57c7ff81b198763cfd7c43f03a5f7622' - account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey) - result = caver.klay.accounts.wallet.add(klaytnWalletKey) + 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) - validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + param = [] + expectedError = `Creating a AccountKeyPublic requires a private key string.` + expect(() => caver.klay.accounts.createAccountKeyPublic(param)).to.throws(expectedError) - // KlaytnWalletkey with nonHumanReadableAddress (decoupled) - var klaytnWalletKey = '0x600dfc414fe433881f6606c24955e4143df9d203ccb3e335efe970a4ad017d040x000x34ef488daef1da6fcc3470be0a5351dc223e20d0' - account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey) - result = caver.klay.accounts.wallet.add(klaytnWalletKey) + param = {} + expectedError = `Creating a AccountKeyPublic requires a private key string.` + expect(() => caver.klay.accounts.createAccountKeyPublic(param)).to.throws(expectedError) - validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + 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-050, CAVERJS-UNIT-WALLET-051 : input: privateKey, address', () => { - it('should have valid wallet instance after addition', () => { - account = caver.klay.accounts.create() - result = caver.klay.accounts.wallet.add(account.privateKey, account.address) - - validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + 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) + }) + }) +}) - account = caver.klay.accounts.create() - var address = '0xc98e2616b445d0b7ff2bcc45adc554ebbf5fd576' - account.address = address - result = caver.klay.accounts.wallet.add(account.privateKey, address) +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) - validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + 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') + }) + }) - account = caver.klay.accounts.create() - address = '0x6a61736d696e652e6b6c6179746e000000000000' - account.address = address - result = caver.klay.accounts.wallet.add(account.privateKey, address) + 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)) - validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + 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-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-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) - validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + param = 'string' + expectedError = `Creating a AccountKeyMultiSig requires an array of private key string.` + expect(() => caver.klay.accounts.createAccountKeyMultiSig(param)).to.throws(expectedError) - // decoupled - klaytnWalletKey = '0xc1ad21b3da99cbb6a57cf181ec3e36af77ae37112585f700c81db19115f74b110x000x95e024d64534948a89748d4c3e82e02d05721beb' - account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey) - result = caver.klay.accounts.wallet.add(klaytnWalletKey, account.address) + param = {} + expectedError = `Creating a AccountKeyMultiSig requires an array of private key string.` + expect(() => caver.klay.accounts.createAccountKeyMultiSig(param)).to.throws(expectedError) - validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + 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-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-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) }) }) +}) - 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() +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-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-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') }) }) -}) -describe('caver.klay.accounts.wallet.remove', () => { + 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) - const validateCheckForWalletRemove = (data, { expected=true, account, wallet }) => { - expect(data).to.equal(expected) + param = 'string' + expectedError = `Creating a AccountKeyRoleBased requires an object.` + expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError) - if (data) { - expect(typeof wallet[account.address]).to.equal('undefined') - } - } + param = [] + expectedError = `Creating a AccountKeyRoleBased requires an object.` + expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError) - context('CAVERJS-UNIT-WALLET-057, CAVERJS-UNIT-WALLET-058, CAVERJS-UNIT-WALLET-059 : input: account', () => { - it('should remove wallet instance', () => { - const numberOfAccounts = Math.floor(Math.random() * 5) + 1 - caver.klay.accounts.wallet.create(numberOfAccounts) + param = undefined + expectedError = `Creating a AccountKeyRoleBased requires an object.` + expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError) - let account = caver.klay.accounts.wallet[Math.floor(Math.random() * numberOfAccounts)] + param = null + expectedError = `Creating a AccountKeyRoleBased requires an object.` + expect(() => caver.klay.accounts.createAccountKeyRoleBased(param)).to.throws(expectedError) + }) + }) - let result = caver.klay.accounts.wallet.remove(account.index) - validateCheckForWalletRemove(result, { account: account, wallet: caver.klay.accounts.wallet }) + 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) + }) + }) - account = caver.klay.accounts.create() - caver.klay.accounts.wallet.add(account.privateKey) + 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) + }) + }) - result = caver.klay.accounts.wallet.remove(account.address) - validateCheckForWalletRemove(result, { account: account, wallet: caver.klay.accounts.wallet }) + 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) }) }) +}) - context('CAVERJS-UNIT-WALLET-060 : input: account:invalid', () => { - it('should return false for removing invalid wallet instance index', () => { - const numberOfAccounts = Math.floor(Math.random() * 5) + 1 - caver.klay.accounts.wallet.create(numberOfAccounts) +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) - let invalid = -1 - let result = caver.klay.accounts.wallet.remove(invalid) - validateCheckForWalletRemove(result, { expected: false }) + const publicKey = caver.klay.accounts.accountKeyToPublicKey(key) - invalid = numberOfAccounts - result = caver.klay.accounts.wallet.remove(invalid) - validateCheckForWalletRemove(result, { expected: false }) + expect(expectedPublicKey).to.equals(publicKey) }) }) -}) -describe('caver.klay.accounts.wallet.clear', () => { - context('CAVERJS-UNIT-WALLET-061 : input: no parameter', () => { - it('should clear all wallet instance', () => { - const numberOfAccounts = Math.floor(Math.random() * 5) + 1 - caver.klay.accounts.wallet.create(numberOfAccounts) + 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) - let result = caver.klay.accounts.wallet.clear() - isWallet(result) - expect(result.length).to.equal(0) - expect(caver.klay.accounts.wallet.length).to.equal(0) + const publicKey = caver.klay.accounts.accountKeyToPublicKey(accountKey) - result = caver.klay.accounts.wallet.clear() - isWallet(result) - expect(result.length).to.equal(0) - expect(caver.klay.accounts.wallet.length).to.equal(0) + expect(expectedPublicKey).to.equals(publicKey) }) }) -}) -describe('caver.klay.accounts.wallet.encrypt', () => { + 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])] - context('CAVERJS-UNIT-WALLET-062 : input: password', () => { - it('should encrypted as v3Keystore', () => { - const password = 'klaytn!@' + const publicKey = caver.klay.accounts.accountKeyToPublicKey(key) - const numberOfAccounts = Math.floor(Math.random() * 5) + 1 - caver.klay.accounts.wallet.create(numberOfAccounts) + expect(isSameKeyArray(expectedPublicKey, publicKey)).to.be.true + }) + }) - let result = caver.klay.accounts.wallet.encrypt(password) + 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])] - expect(result.length).to.equal(caver.klay.accounts.wallet.length) - result.forEach((v, i) => { - isKeystoreV3(v, { address: caver.klay.accounts.wallet[i].address }) - }) - const decryptedWallet = caver.klay.accounts.wallet.decrypt(result, password) - isWallet(decryptedWallet, { accounts: caver.klay.accounts.wallet }) + 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') + }) + }) + + 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) } + + 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).to.be.undefined + expect(accountForUpdate.keyForUpdate.roleFeePayerKey.publicKey).to.equals(publicKey.feePayerKey) + expect(typeof accountForUpdate.fillUpdateObject).to.equals('function') + }) + }) + + 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 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-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] + + const expectedError = 'For AccountKeyMultiSig, threshold and weight should be defined in options object.' + + expect(() => caver.klay.accounts.createAccountForUpdate(address, key)).to.throws(expectedError) + }) + }) + + 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] } + + 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-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 expectedError = 'The weight should be defined as a array.' + + expect(() => caver.klay.accounts.createAccountForUpdate(address, key, options)).to.throws(expectedError) + }) + }) + + 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] } + + 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-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] } + + const expectedError = 'For AccountKeyMultiSig, threshold and weight should be defined in options object.' + + expect(() => caver.klay.accounts.createAccountForUpdate(address, key)).to.throws(expectedError) + }) + }) + + 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) + + 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, + } + + 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) + }) + }) + + 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])] + + const expectedError = 'For AccountKeyMultiSig, threshold and weight should be defined in options object.' + + 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', () => { + + it('CAVERJS-UNIT-WALLET-043 : should return valid wallet instance', () => { + let result = caver.klay.accounts.wallet + isWallet(result) + + const accounts = [] + const accountCount = Math.floor(Math.random() * 10) + 1 + for (let i = 0; i < accountCount; i++) { + const account = caver.klay.accounts.create() + accounts.push(account) + caver.klay.accounts.wallet.add(account) + } + + isWallet(result, { accounts }) + }) +}) + +describe('caver.klay.accounts.wallet.create', () => { + + const validateCheckForWalletCreation = (result, numberOfAccounts) => { + isWallet(result) + expect(result.length).to.equal(numberOfAccounts) + for (let i = 0; i < result.length; i++) { + 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) + + isAccount(accountByIndex, { keys: accountByAddress.keys, address: accountByAddress.address }) + isAccount(accountByAddress, { keys: accountByIndex.keys, address: accountByIndex.address }) + } + } + + context('CAVERJS-UNIT-WALLET-044 : input: numberOfAccounts', () => { + it('should return valid wallet instance', () => { + const numberOfAccounts = Math.floor(Math.random() * 5) + 1 + let result = caver.klay.accounts.wallet.create(numberOfAccounts) + validateCheckForWalletCreation(result, numberOfAccounts) + }) + }) + + context('CAVERJS-UNIT-WALLET-045 : input: numberOfAccounts:invalid', () => { + it('should return 0 wallet', () => { + const invalid = -1 + let result = caver.klay.accounts.wallet.create(invalid) + validateCheckForWalletCreation(result, 0) + }) + }) + + context('CAVERJS-UNIT-WALLET-046 : input: numberOfAccounts, entropy', () => { + it('should return valid wallet instance', () => { + const numberOfAccounts = Math.floor(Math.random() * 5) + 1 + const entropy = caver.utils.randomHex(32) + + let result = caver.klay.accounts.wallet.create(numberOfAccounts, entropy) + validateCheckForWalletCreation(result, numberOfAccounts) + }) + }) +}) + +describe('caver.klay.accounts.wallet.add', () => { + const validateCheckForWalletAddition = (data, { account, wallet }) => { + const accounts = [] + + 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) { + isAccount(v, { keys: account.keys, address: account.address }) + } + } + + context('CAVERJS-UNIT-WALLET-047 : input: account', () => { + it('should have valid wallet instance after addition', () => { + let account = caver.klay.accounts.create() + let result = caver.klay.accounts.wallet.add(account) + + validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + }) + }) + + context('CAVERJS-UNIT-WALLET-048 : input: privateKey', () => { + it('should have valid wallet instance after addition', () => { + account = caver.klay.accounts.create() + result = caver.klay.accounts.wallet.add(account.privateKey) + + validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + }) + }) + + context('CAVERJS-UNIT-WALLET-052 : input: KlaytnWalletKey', () => { + it('should have valid wallet instance after addition', () => { + // KlaytnWalletkey with nonHumanReadableAddress + var klaytnWalletKey = '0x600dfc414fe433881f6606c24955e4143df9d203ccb3e335efe970a4ad017d040x000xee135d0b57c7ff81b198763cfd7c43f03a5f7622' + account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey) + result = caver.klay.accounts.wallet.add(klaytnWalletKey) + + validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + + // KlaytnWalletkey with nonHumanReadableAddress (decoupled) + var klaytnWalletKey = '0x600dfc414fe433881f6606c24955e4143df9d203ccb3e335efe970a4ad017d040x000x34ef488daef1da6fcc3470be0a5351dc223e20d0' + account = caver.klay.accounts.privateKeyToAccount(klaytnWalletKey) + result = caver.klay.accounts.wallet.add(klaytnWalletKey) + + validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + }) + }) + + context('CAVERJS-UNIT-WALLET-050, CAVERJS-UNIT-WALLET-051 : input: privateKey, address', () => { + it('should have valid wallet instance after addition', () => { + account = caver.klay.accounts.create() + result = caver.klay.accounts.wallet.add(account.privateKey, account.address) + + validateCheckForWalletAddition(result, { account: account, wallet: caver.klay.accounts.wallet }) + + account = caver.klay.accounts.create() + var address = '0xc98e2616b445d0b7ff2bcc45adc554ebbf5fd576' + account.address = address + result = caver.klay.accounts.wallet.add(account.privateKey, address) + + 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) + + 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) + + let accountInWallet = caver.klay.accounts.wallet.add(key, address) + + validateCheckForWalletAddition(accountInWallet, { account: account, wallet: caver.klay.accounts.wallet }) + }) + }) + + 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) + + let accountInWallet = caver.klay.accounts.wallet.add(key, address) + + validateCheckForWalletAddition(accountInWallet, { account: account, wallet: caver.klay.accounts.wallet }) + }) + }) + + 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) + + let accountInWallet = caver.klay.accounts.wallet.add(key, address) + + validateCheckForWalletAddition(accountInWallet, { account: account, wallet: caver.klay.accounts.wallet }) + }) + }) + + 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-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-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) + }) + }) +}) + +describe('caver.klay.accounts.wallet.remove', () => { + + const validateCheckForWalletRemove = (data, { expected=true, account, wallet }) => { + expect(data).to.equal(expected) + + if (data) { + expect(typeof wallet[account.address]).to.equal('undefined') + } + } + + context('CAVERJS-UNIT-WALLET-057, CAVERJS-UNIT-WALLET-058, CAVERJS-UNIT-WALLET-059 : input: account', () => { + it('should remove wallet instance', () => { + const numberOfAccounts = Math.floor(Math.random() * 5) + 1 + caver.klay.accounts.wallet.create(numberOfAccounts) + + let account = caver.klay.accounts.wallet[Math.floor(Math.random() * numberOfAccounts)] + + let result = caver.klay.accounts.wallet.remove(account.index) + validateCheckForWalletRemove(result, { account: account, wallet: caver.klay.accounts.wallet }) + + account = caver.klay.accounts.create() + caver.klay.accounts.wallet.add(account.privateKey) + + result = caver.klay.accounts.wallet.remove(account.address) + validateCheckForWalletRemove(result, { account: account, wallet: caver.klay.accounts.wallet }) + }) + }) + + context('CAVERJS-UNIT-WALLET-060 : input: account:invalid', () => { + it('should return false for removing invalid wallet instance index', () => { + const numberOfAccounts = Math.floor(Math.random() * 5) + 1 + caver.klay.accounts.wallet.create(numberOfAccounts) + + let invalid = -1 + let result = caver.klay.accounts.wallet.remove(invalid) + validateCheckForWalletRemove(result, { expected: false }) + + invalid = numberOfAccounts + result = caver.klay.accounts.wallet.remove(invalid) + 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', () => { + context('CAVERJS-UNIT-WALLET-061 : input: no parameter', () => { + it('should clear all wallet instance', () => { + const numberOfAccounts = Math.floor(Math.random() * 5) + 1 + caver.klay.accounts.wallet.create(numberOfAccounts) + + let result = caver.klay.accounts.wallet.clear() + isWallet(result) + expect(result.length).to.equal(0) + expect(caver.klay.accounts.wallet.length).to.equal(0) + + result = caver.klay.accounts.wallet.clear() + isWallet(result) + expect(result.length).to.equal(0) + expect(caver.klay.accounts.wallet.length).to.equal(0) + }) + }) +}) + +describe('caver.klay.accounts.wallet.encrypt', () => { + + context('CAVERJS-UNIT-WALLET-062 : input: password', () => { + it('should encrypted as v3Keystore', () => { + const password = 'klaytn!@' + + const numberOfAccounts = Math.floor(Math.random() * 5) + 1 + caver.klay.accounts.wallet.create(numberOfAccounts) + + let result = caver.klay.accounts.wallet.encrypt(password) + + expect(result.length).to.equal(caver.klay.accounts.wallet.length) + result.forEach((v, i) => { + isKeystoreV3(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 = '' @@ -1308,4 +3109,364 @@ describe('caver.klay.accounts.wallet.getAccount', () => { 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 From 5782e98e3835e5415da6b014b7fe013603ee6f69 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Thu, 17 Oct 2019 11:07:39 +0900 Subject: [PATCH 091/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 1482abfd..e30d37f1 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -158,7 +158,7 @@ Accounts.prototype.create = function create(entropy) { }; /** - * createAccountKey creates AccountKeyPublic or AccountKeyMultiSig or AccountKeyRoleBased instance with parameter. + * createAccountKey creates AccountKeyPublic, AccountKeyMultiSig or AccountKeyRoleBased instance with parameter. * * @method createAccountKey * @param {String|Array|Object} accountKey Parameters to be used when creating the AccountKey. From 89097769f27ddc4cd1054801d1ee05da34122227 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Thu, 17 Oct 2019 11:08:09 +0900 Subject: [PATCH 092/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index e30d37f1..7eb4be26 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -200,7 +200,7 @@ Accounts.prototype.createAccountKeyPublic = function createAccountKeyPublic(priv } /** - * createAccountKeyMultiSig creates AccountKeyMultiSig with an array of private key. + * createAccountKeyMultiSig creates AccountKeyMultiSig with an array of private keys. * * @method createAccountKeyMultiSig * @param {Array} privateKeys An Array of private key string that will be used to create AccountKeyMultiSig. From cbc7ce6d81f62080d33a51aba284df7b544d4aaa Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Thu, 17 Oct 2019 11:08:16 +0900 Subject: [PATCH 093/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 7eb4be26..2a796f5e 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -203,7 +203,7 @@ Accounts.prototype.createAccountKeyPublic = function createAccountKeyPublic(priv * createAccountKeyMultiSig creates AccountKeyMultiSig with an array of private keys. * * @method createAccountKeyMultiSig - * @param {Array} privateKeys An Array of private key string that will be used to create AccountKeyMultiSig. + * @param {Array} privateKeys An Array of private key strings that will be used to create AccountKeyMultiSig. * @return {Object} */ Accounts.prototype.createAccountKeyMultiSig = function createAccountKeyMultiSig(privateKeys) { From 335fa6da3db9f08c9bb1cea4f4c6d22a7eff4df3 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Thu, 17 Oct 2019 11:19:30 +0900 Subject: [PATCH 094/123] Validation in accountKeyRoleBased --- .../src/accountKey/accountKeyRoleBased.js | 22 +++++++++++++++++++ .../caver-klay-accounts/src/index.js | 16 -------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyRoleBased.js b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyRoleBased.js index 63dfbab9..ab80eac9 100644 --- a/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyRoleBased.js +++ b/packages/caver-klay/caver-klay-accounts/src/accountKey/accountKeyRoleBased.js @@ -1,6 +1,7 @@ const AccountKeyEnum = require('./accountKeyEnum').AccountKeyEnum const AccountKeyPublic = require('./accountKeyPublic') const AccountKeyMultiSig = require('./accountKeyMultiSig') +const utils = require('../../../../caver-utils') class AccountKeyRoleBased { constructor(keyObj = {}) { @@ -8,6 +9,8 @@ class AccountKeyRoleBased { 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) @@ -73,4 +76,23 @@ function makeAccountKey(key) { 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 2a796f5e..afa5c1e9 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -231,23 +231,7 @@ Accounts.prototype.createAccountKeyRoleBased = function createAccountKeyRoleBase if (keyObject instanceof AccountKeyRoleBased) return keyObject if (!_.isObject(keyObject) || _.isArray(keyObject)) throw new Error('Creating a AccountKeyRoleBased requires an object.') - - 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]}`) - } - }) return new AccountKeyRoleBased(keyObject) } From de7c357699bc8e59707bc3e27e0da97162be82d0 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Thu, 17 Oct 2019 11:20:23 +0900 Subject: [PATCH 095/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index afa5c1e9..19e201f6 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -331,7 +331,7 @@ Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(key, userI /** - * createAccountForUpdate creates AccountForUpdate instance. + * 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 From 98aef095b73a9b81d2f272588f8b4f8ab4ed6c83 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Thu, 17 Oct 2019 11:35:10 +0900 Subject: [PATCH 096/123] Indentation --- .../caver-klay-accounts/src/index.js | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 19e201f6..53e90128 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -1126,74 +1126,74 @@ Wallet.prototype.add = function (account, userInputAddress) { } Wallet.prototype.updatePrivateKey = function (privateKey, address) { -if (privateKey === undefined || address === undefined) { - throw new Error('To update the privatKey in wallet, need to set both privateKey and address.') -} + if (privateKey === undefined || address === undefined) { + throw new Error('To update the privatKey in wallet, need to set both privateKey and address.') + } -// If privateKey parameter is not string type, return error -if (!_.isString(privateKey)) { - throw new Error('The private key used for the update is not a valid string.') -} + // If privateKey parameter is not string type, return error + if (!_.isString(privateKey)) { + 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 (!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) + // 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] + 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.') -} + 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') + 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.') -} + 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 + 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 -try { - this[utils.toChecksumAddress(account.address)].accountKey = newAccountKeyPublic -} catch (e) {} + try { + this[utils.toChecksumAddress(account.address)].accountKey = newAccountKeyPublic + } catch (e) {} -return account + return account } 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 (address === undefined || accountKey === undefined) { + throw new Error('To update the accountKey in wallet, need to set both address and accountKey.') + } -if (!Account.isAccountKey(accountKey)) { - accountKey = this._accounts.createAccountKey(accountKey) -} + if (!Account.isAccountKey(accountKey)) { + accountKey = this._accounts.createAccountKey(accountKey) + } -if (!utils.isAddress(address)) throw new Error(`Invalid address : ${address}`) + 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) + // 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] + const account = this[address] -this[account.index].accountKey = accountKey -this[account.address].accountKey = accountKey -this[account.address.toLowerCase()].accountKey = accountKey -this[account.address.toUpperCase()].accountKey = accountKey + this[account.index].accountKey = accountKey + this[account.address].accountKey = accountKey + this[account.address.toLowerCase()].accountKey = accountKey + this[account.address.toUpperCase()].accountKey = accountKey -try { - this[utils.toChecksumAddress(account.address)].accountKey = accountKey -} catch (e) {} + try { + this[utils.toChecksumAddress(account.address)].accountKey = accountKey + } catch (e) {} -return account + return account } Wallet.prototype.remove = function (addressOrIndex) { From 53d73d99f5c72ccf879ad1a81184be34abae573e Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Thu, 17 Oct 2019 17:00:47 +0900 Subject: [PATCH 097/123] Modified encrypt decrypt for AccountKey --- .../caver-klay-accounts/src/index.js | 224 ++++--- test/packages/caver.klay.accounts.js | 557 +++++++++++++++++- 2 files changed, 707 insertions(+), 74 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 53e90128..da455c55 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -800,47 +800,82 @@ 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 = scrypt(Buffer.from(password), Buffer.from(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 (json.keyRing.length !== 1 && json.keyRing.length !== 3) throw new Error(`Invalid key store format`) - derivedKey = cryp.pbkdf2Sync(Buffer.from(password), Buffer.from(kdfparams.salt, 'hex'), kdfparams.c, kdfparams.dklen, 'sha256'); + let accountKey = {} + if (json.keyRing.length === 3) { + let transactionKey = decryptKey(json.keyRing[0]) + if (transactionKey) accountKey.transactionKey = transactionKey + + let updateKey = decryptKey(json.keyRing[1]) + if (updateKey) accountKey.updateKey = updateKey + + let feePayerKey = decryptKey(json.keyRing[2]) + if (feePayerKey) accountKey.feePayerKey = feePayerKey } else { - throw new Error('Unsupported key derivation scheme'); + accountKey = decryptKey(json.keyRing[0]) } - var ciphertext = Buffer.from(json.crypto.ciphertext, 'hex'); + function decryptKey(encryptedArray) { + if (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 ciphertext = Buffer.from(encrypted.ciphertext, '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'); + } - 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 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 } - var decipher = cryp.createDecipheriv(json.crypto.cipher, derivedKey.slice(0, 16), Buffer.from(json.crypto.cipherparams.iv, 'hex')); - var seed = '0x'+ Buffer.concat([ decipher.update(ciphertext), decipher.final() ]).toString('hex'); - - return this.privateKeyToAccount(seed, json.address); -}; + return this.createWithAccountKey(json.address, accountKey); + }; /** * cav.klay.accounts.encrypt(privateKey, password); @@ -918,60 +953,105 @@ Accounts.prototype.encrypt = function (key, password, options) { */ options = options || {}; - var account = this.privateKeyToAccount(key, options.address); - - 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') - }; + let address, account - /** - * 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); + 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.push(encryptKey(account.keys)) + break + case AccountKeyEnum.ACCOUNT_KEY_ROLEBASED: + let transactionKey = encryptKey(account.transactionKey) + keyRing.push(transactionKey) + let updateKey = encryptKey(account.updateKey) + keyRing.push(updateKey) + let feePayerKey = encryptKey(account.feePayerKey) + keyRing.push(feePayerKey) + break } - var ciphertext = Buffer.concat([ cipher.update(Buffer.from(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), Buffer.from(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 }; }; diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index f073e2ee..c93d54db 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -64,8 +64,8 @@ function checkHashMessage(hashed, originMessage) { } function isKeystoreV3(data, { address }) { - const keys = ['version', 'id', 'address', 'crypto'] - expect(Object.getOwnPropertyNames(data)).to.deep.equal(keys) + const objectKeys = ['version', 'id', 'address', 'keyRing'] + expect(Object.getOwnPropertyNames(data)).to.deep.equal(objectKeys) expect(caver.utils.isAddress(data.address)).to.equal(true) @@ -799,6 +799,375 @@ describe('caver.klay.accounts.encrypt', () => { 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}) + + isKeystoreV3(result, testAccount) + expect(result.keyRing.length).to.equals(1) + expect(result.keyRing[0].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}) + + isKeystoreV3(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}) + + isKeystoreV3(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}) + + isKeystoreV3(result, testAccount) + expect(result.keyRing.length).to.equals(3) + expect(result.keyRing[0].length).to.equals(1) + expect(result.keyRing[1].length).to.equals(0) + expect(result.keyRing[2].length).to.equals(0) + + 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}) + + isKeystoreV3(result, testAccount) + expect(result.keyRing.length).to.equals(3) + expect(result.keyRing[0].length).to.equals(0) + expect(result.keyRing[1].length).to.equals(1) + expect(result.keyRing[2].length).to.equals(0) + + 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}) + + isKeystoreV3(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}) + + isKeystoreV3(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-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}) + + isKeystoreV3(result, testAccount) + expect(result.keyRing.length).to.equals(1) + expect(result.keyRing[0].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}) + + isKeystoreV3(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}) + + isKeystoreV3(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-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}) + + isKeystoreV3(result, testAccount) + expect(result.keyRing.length).to.equals(1) + expect(result.keyRing[0].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}) + + isKeystoreV3(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 AccountKeyMultiSig, 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) + }) + }) }) describe('caver.klay.accounts.decrypt', () => { @@ -832,6 +1201,145 @@ describe('caver.klay.accounts.decrypt', () => { }) }) + context('CAVERJS-UNIT-WALLET-371: input: keystoreJsonV3 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 keystoreJsonV3 = caver.klay.accounts.encrypt(key, password, { address: account.address }) + + let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + + isAccount(result, {keys: key, address: account.address}) + }) + }) + + context('CAVERJS-UNIT-WALLET-372: input: keystoreJsonV3 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 keystoreJsonV3 = caver.klay.accounts.encrypt(key, password, { address: account.address }) + + let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + + isAccount(result, {keys: key, address: account.address}) + }) + }) + + context('CAVERJS-UNIT-WALLET-373: input: keystoreJsonV3 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 keystoreJsonV3 = caver.klay.accounts.encrypt(key, password, { address: account.address }) + + let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + + isAccount(result, {keys: key, address: account.address}) + }) + }) + + context('CAVERJS-UNIT-WALLET-374: input: keystoreJsonV3 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 keystoreJsonV3 = caver.klay.accounts.encrypt(key, password, { address: account.address }) + + let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + + isAccount(result, {keys: key, address: account.address}) + }) + }) + + context('CAVERJS-UNIT-WALLET-375: input: keystoreJsonV3 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 keystoreJsonV3 = caver.klay.accounts.encrypt(key, password, { address: account.address }) + + let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + + isAccount(result, {keys: key, address: account.address}) + }) + }) + + context('CAVERJS-UNIT-WALLET-378: input: keystoreJsonV3 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][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: keystoreJsonV3 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: keystoreJsonV3 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][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][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) + }) + }) + + /* it('keystoreJsonV3, password:invalid [KLAYTN-52]', () => { const invalid = '' @@ -2993,6 +3501,37 @@ describe('caver.klay.accounts.wallet.encrypt', () => { }) }) + 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) => { + isKeystoreV3(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 = '' @@ -3020,6 +3559,20 @@ describe('caver.klay.accounts.wallet.decrypt', () => { 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() From 3e8b850bb9d23eef1cfacf48963f8c2abd7dd471 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Thu, 17 Oct 2019 17:02:17 +0900 Subject: [PATCH 098/123] Implemented _getRoleKey in accounts package --- .../caver-klay-accounts/src/index.js | 26 ++++++++ test/packages/caver.klay.accounts.js | 61 +++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index da455c55..3dc5bb18 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -146,6 +146,32 @@ Accounts.prototype._determineAddress = function _determineAddress(legacyAccount, return legacyAccount.address } +/** + * _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. * diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index c93d54db..30427e7f 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -1494,6 +1494,67 @@ describe('caver.klay.accounts.isDecoupled', () => { }) }) +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', () => { From 0209918975adab111f9ed83e5985e7dc211c0805 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 08:09:15 +0900 Subject: [PATCH 099/123] Change the test function name --- test/packages/caver.klay.accounts.js | 44 +++++++++++++++------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 30427e7f..aff3382b 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -63,10 +63,12 @@ function checkHashMessage(hashed, originMessage) { expect(hashed).to.equal(originHashed) } -function isKeystoreV3(data, { address }) { +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) prefixTrimmed = data.address.replace(/^(0x)*/i, '') @@ -707,7 +709,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(account.privateKey, password) - isKeystoreV3(result, account) + isKeystoreV4(result, account) const decryptedAccount = caver.klay.accounts.decrypt(result, password) isAccount(decryptedAccount, {keys: account.keys, address: account.address}) @@ -730,7 +732,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(account.getKlaytnWalletKey(), password) - isKeystoreV3(result, account) + isKeystoreV4(result, account) const decryptedAccount = caver.klay.accounts.decrypt(result, password) isAccount(decryptedAccount, {keys: account.keys, address: account.address}) @@ -743,7 +745,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(account.getKlaytnWalletKey(), password, {address: account.address}) - isKeystoreV3(result, account) + isKeystoreV4(result, account) const decryptedAccount = caver.klay.accounts.decrypt(result, password) isAccount(decryptedAccount, {keys: account.keys, address: account.address}) @@ -767,7 +769,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount.getKlaytnWalletKey(), password) - isKeystoreV3(result, testAccount) + isKeystoreV4(result, testAccount) const decryptedAccount = caver.klay.accounts.decrypt(result, password) isAccount(decryptedAccount, {keys: testAccount.keys, address: testAccount.address}) @@ -782,7 +784,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount.getKlaytnWalletKey(), password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + isKeystoreV4(result, testAccount) const decryptedAccount = caver.klay.accounts.decrypt(result, password) isAccount(decryptedAccount, {keys: testAccount.keys, address: testAccount.address}) @@ -809,7 +811,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + isKeystoreV4(result, testAccount) expect(result.keyRing.length).to.equals(1) expect(result.keyRing[0].length).to.equals(key.length) @@ -843,7 +845,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + 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) @@ -867,7 +869,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + 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) @@ -889,7 +891,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + 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(0) @@ -911,7 +913,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + 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(1) @@ -933,7 +935,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + 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) @@ -970,7 +972,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + isKeystoreV4(result, testAccount) expect(result.keyRing.length).to.equals(1) expect(result.keyRing[0].length).to.equals(1) @@ -1001,7 +1003,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + isKeystoreV4(result, testAccount) expect(result.keyRing.length).to.equals(1) expect(result.keyRing[0].length).to.equals(key.length) @@ -1036,7 +1038,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + 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) @@ -1073,7 +1075,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + isKeystoreV4(result, testAccount) expect(result.keyRing.length).to.equals(1) expect(result.keyRing[0].length).to.equals(1) @@ -1105,7 +1107,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + isKeystoreV4(result, testAccount) expect(result.keyRing.length).to.equals(1) expect(result.keyRing[0].length).to.equals(key.length) @@ -1141,7 +1143,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address}) - isKeystoreV3(result, testAccount) + 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) @@ -1183,7 +1185,7 @@ describe('caver.klay.accounts.decrypt', () => { const keystoreJsonV3 = caver.klay.accounts.encrypt(account.privateKey, password) let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) - isKeystoreV3(keystoreJsonV3, result) + isKeystoreV4(keystoreJsonV3, result) isAccount(result, {keys: account.keys, address: account.address}) }) @@ -3555,7 +3557,7 @@ 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 }) @@ -3584,7 +3586,7 @@ 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 }) From c8bed975e89a2f5dc4449d9f521d06acb8ec47b8 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 08:38:56 +0900 Subject: [PATCH 100/123] Add test case for hard coded json format --- test/packages/caver.klay.accounts.js | 184 +++++++++++++++++++++++---- 1 file changed, 156 insertions(+), 28 deletions(-) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index aff3382b..b7bf85f6 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -1179,43 +1179,43 @@ describe('caver.klay.accounts.decrypt', () => { account = caver.klay.accounts.create() }) - context('CAVERJS-UNIT-WALLET-042 : input: keystoreJsonV3, password', () => { + context('CAVERJS-UNIT-WALLET-042 : input: keystoreJsonV4, password', () => { it('After decrypting, should return valid account', () => { const password = 'klaytn!@' - const keystoreJsonV3 = caver.klay.accounts.encrypt(account.privateKey, password) + const keystoreJsonV4 = caver.klay.accounts.encrypt(account.privateKey, password) - let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) - isKeystoreV4(keystoreJsonV3, result) + 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: keystoreJsonV3(without 0x address format), password', () => { + context('CAVERJS-UNIT-WALLET-103 : input: keystoreJsonV4(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', '') + const keystoreJsonV4 = caver.klay.accounts.encrypt(account.privateKey, password) + keystoreJsonV4.address = keystoreJsonV4.address.replace('0x', '') - let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + let result = caver.klay.accounts.decrypt(keystoreJsonV4, password) expect(result.address.slice(0, 2)).to.equals('0x') }) }) - context('CAVERJS-UNIT-WALLET-371: input: keystoreJsonV3 that encrypts Account with AccountKeyMultiSig, password', () => { + 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 keystoreJsonV3 = caver.klay.accounts.encrypt(key, password, { address: account.address }) + const keystoreJsonV4 = caver.klay.accounts.encrypt(key, password, { address: account.address }) - let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + let result = caver.klay.accounts.decrypt(keystoreJsonV4, password) isAccount(result, {keys: key, address: account.address}) }) }) - context('CAVERJS-UNIT-WALLET-372: input: keystoreJsonV3 that encrypts Account with AccountKeyRoleBased, password', () => { + 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 = { @@ -1223,57 +1223,57 @@ describe('caver.klay.accounts.decrypt', () => { 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 keystoreJsonV3 = caver.klay.accounts.encrypt(key, password, { address: account.address }) + const keystoreJsonV4 = caver.klay.accounts.encrypt(key, password, { address: account.address }) - let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + let result = caver.klay.accounts.decrypt(keystoreJsonV4, password) isAccount(result, {keys: key, address: account.address}) }) }) - context('CAVERJS-UNIT-WALLET-373: input: keystoreJsonV3 that encrypts Account with AccountKeyRoleBased(transactionKey only), password', () => { + 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 keystoreJsonV3 = caver.klay.accounts.encrypt(key, password, { address: account.address }) + const keystoreJsonV4 = caver.klay.accounts.encrypt(key, password, { address: account.address }) - let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + let result = caver.klay.accounts.decrypt(keystoreJsonV4, password) isAccount(result, {keys: key, address: account.address}) }) }) - context('CAVERJS-UNIT-WALLET-374: input: keystoreJsonV3 that encrypts Account with AccountKeyRoleBased(updateKey only), password', () => { + 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 keystoreJsonV3 = caver.klay.accounts.encrypt(key, password, { address: account.address }) + const keystoreJsonV4 = caver.klay.accounts.encrypt(key, password, { address: account.address }) - let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + let result = caver.klay.accounts.decrypt(keystoreJsonV4, password) isAccount(result, {keys: key, address: account.address}) }) }) - context('CAVERJS-UNIT-WALLET-375: input: keystoreJsonV3 that encrypts Account with AccountKeyRoleBased(feePayerKey only), password', () => { + 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 keystoreJsonV3 = caver.klay.accounts.encrypt(key, password, { address: account.address }) + const keystoreJsonV4 = caver.klay.accounts.encrypt(key, password, { address: account.address }) - let result = caver.klay.accounts.decrypt(keystoreJsonV3, password) + let result = caver.klay.accounts.decrypt(keystoreJsonV4, password) isAccount(result, {keys: key, address: account.address}) }) }) - context('CAVERJS-UNIT-WALLET-378: input: keystoreJsonV3 that encrypts Account, password', () => { + 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 @@ -1288,7 +1288,7 @@ describe('caver.klay.accounts.decrypt', () => { }) }) - context('CAVERJS-UNIT-WALLET-379: input: keystoreJsonV3 that encrypts Account, password', () => { + 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 @@ -1301,7 +1301,7 @@ describe('caver.klay.accounts.decrypt', () => { }) }) - context('CAVERJS-UNIT-WALLET-380: input: keystoreJsonV3 that encrypts Account, password', () => { + 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 @@ -1341,6 +1341,134 @@ describe('caver.klay.accounts.decrypt', () => { }) }) + 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]', () => { @@ -3547,7 +3675,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 @@ -3616,7 +3744,7 @@ 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 From 6da85f974a3c9f1dbcda86d4a53e2f5a526b4d67 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 09:45:03 +0900 Subject: [PATCH 101/123] Changed format of keystore --- .../caver-klay-accounts/src/index.js | 27 ++++++++---- test/packages/caver.klay.accounts.js | 43 +++++++++++-------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 3dc5bb18..ea9bf03d 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -838,14 +838,18 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) { if (json.crypto) { if (json.keyRing) throw new Error(`Invalid key store format: 'crypto' can not be with 'keyRing'`) - json.keyRing = [[json.crypto]] + json.keyRing = [json.crypto] delete json.crypto } - if (json.keyRing.length !== 1 && json.keyRing.length !== 3) throw new Error(`Invalid key store format`) + if (_.isArray(json.keyRing[0]) && json.keyRing.length > 3) { + throw new Error(`Invalid key store format`) + } let accountKey = {} - if (json.keyRing.length === 3) { + + // AccountKeyRoleBased format + if (_.isArray(json.keyRing[0])) { let transactionKey = decryptKey(json.keyRing[0]) if (transactionKey) accountKey.transactionKey = transactionKey @@ -855,11 +859,11 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) { let feePayerKey = decryptKey(json.keyRing[2]) if (feePayerKey) accountKey.feePayerKey = feePayerKey } else { - accountKey = decryptKey(json.keyRing[0]) + accountKey = decryptKey(json.keyRing) } function decryptKey(encryptedArray) { - if (encryptedArray.length === 0) return undefined + if (!encryptedArray || encryptedArray.length === 0) return undefined let decryptedArray = [] for (const encrypted of encryptedArray) { @@ -995,20 +999,25 @@ Accounts.prototype.encrypt = function (key, password, options) { if (!account) account = this.createWithAccountKey(address, key) - let keyRing = [] + let keyRing switch(account.accountKeyType) { case AccountKeyEnum.ACCOUNT_KEY_PUBLIC: case AccountKeyEnum.ACCOUNT_KEY_MULTISIG: - keyRing.push(encryptKey(account.keys)) + keyRing = encryptKey(account.keys) break case AccountKeyEnum.ACCOUNT_KEY_ROLEBASED: + keyRing = [] let transactionKey = encryptKey(account.transactionKey) - keyRing.push(transactionKey) let updateKey = encryptKey(account.updateKey) - keyRing.push(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 } diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index b7bf85f6..cccbd124 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -812,8 +812,7 @@ describe('caver.klay.accounts.encrypt', () => { 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(key.length) + expect(result.keyRing.length).to.equals(key.length) const decrypted = caver.klay.accounts.decrypt(result, password) isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address}) @@ -892,10 +891,8 @@ describe('caver.klay.accounts.encrypt', () => { 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.length).to.equals(1) expect(result.keyRing[0].length).to.equals(1) - expect(result.keyRing[1].length).to.equals(0) - expect(result.keyRing[2].length).to.equals(0) const decrypted = caver.klay.accounts.decrypt(result, password) isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address}) @@ -914,10 +911,9 @@ describe('caver.klay.accounts.encrypt', () => { 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.length).to.equals(2) expect(result.keyRing[0].length).to.equals(0) expect(result.keyRing[1].length).to.equals(1) - expect(result.keyRing[2].length).to.equals(0) const decrypted = caver.klay.accounts.decrypt(result, password) isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address}) @@ -974,7 +970,6 @@ describe('caver.klay.accounts.encrypt', () => { 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}) @@ -1004,8 +999,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address}) isKeystoreV4(result, testAccount) - expect(result.keyRing.length).to.equals(1) - expect(result.keyRing[0].length).to.equals(key.length) + expect(result.keyRing.length).to.equals(key.length) const decrypted = caver.klay.accounts.decrypt(result, password) isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address}) @@ -1077,7 +1071,6 @@ describe('caver.klay.accounts.encrypt', () => { 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}) @@ -1108,8 +1101,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address}) isKeystoreV4(result, testAccount) - expect(result.keyRing.length).to.equals(1) - expect(result.keyRing[0].length).to.equals(key.length) + expect(result.keyRing.length).to.equals(key.length) const decrypted = caver.klay.accounts.decrypt(result, password) isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address}) @@ -1154,7 +1146,24 @@ describe('caver.klay.accounts.encrypt', () => { }) }) - context('CAVERJS-UNIT-WALLET-370: input: Account with AccountKeyMultiSig, password, {address:different 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('input: Account with AccountKeyMultiSig, password, option', () => { it('should throw error when addresses are not matched', () => { const password = 'klaytn!@' @@ -1279,7 +1288,7 @@ describe('caver.klay.accounts.decrypt', () => { 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][0] + keystore.crypto = keystore.keyRing[0] delete keystore.keyRing let result = caver.klay.accounts.decrypt(keystore, password) @@ -1307,7 +1316,7 @@ describe('caver.klay.accounts.decrypt', () => { 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][0] + keystore.crypto = keystore.keyRing[0] const expectedError = `Invalid key store format: 'crypto' can not be with 'keyRing'` @@ -1320,7 +1329,7 @@ describe('caver.klay.accounts.decrypt', () => { 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][0] + keystore.crypto = keystore.keyRing[0] const expectedError = `Invalid key store format: 'crypto' can not be with 'keyRing'` From 787dee110e66022cd4cba8c8f5f1174b6757fa13 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 10:07:42 +0900 Subject: [PATCH 102/123] Add test case with expected keystore --- test/packages/caver.klay.accounts.js | 120 +++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 9 deletions(-) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index cccbd124..475741bf 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -1165,18 +1165,120 @@ describe('caver.klay.accounts.encrypt', () => { context('input: Account with AccountKeyMultiSig, password, option', () => { it('should throw error when addresses are not matched', () => { - const password = 'klaytn!@' + const password = 'password' - 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 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'), } - 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) + 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) }) }) }) From ec04f9138eb3815e8beaebe0f996ab9d2be8686b Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 10:13:06 +0900 Subject: [PATCH 103/123] Add numbering --- test/packages/caver.klay.accounts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 475741bf..b4c179c3 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -1163,7 +1163,7 @@ describe('caver.klay.accounts.encrypt', () => { }) }) - context('input: Account with AccountKeyMultiSig, password, option', () => { + context('CAVERJS-UNIT-WALLET-385: input: Account with AccountKeyMultiSig, password, option', () => { it('should throw error when addresses are not matched', () => { const password = 'password' From abf33c6d66e16a1506646e86e0d2df24578932ab Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 14:05:15 +0900 Subject: [PATCH 104/123] Modified signTransaction logic and implemented feePayerSignTransaction --- packages/caver-core-helpers/src/formatters.js | 4 +- .../caver-klay-accounts/src/index.js | 269 +++++- .../src/makeRawTransaction.js | 41 +- test/packages/caver.klay.accounts.js | 901 +++++++++++++++++- 4 files changed, 1154 insertions(+), 61 deletions(-) diff --git a/packages/caver-core-helpers/src/formatters.js b/packages/caver-core-helpers/src/formatters.js index 5a52da8c..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) { diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index ea9bf03d..782076d1 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -39,7 +39,7 @@ 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') @@ -68,6 +68,70 @@ function coverInitialTxValue(tx) { return tx } +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 } +} + +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; @@ -460,11 +524,20 @@ Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { return { legacyAccount: account, klaytnWalletKeyAddress } } +/** + * signTransaction signs to transaction with private key. + * + * @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() { - var _this = this, - isLegacy = false, - result, - callback + 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) @@ -472,57 +545,74 @@ Accounts.prototype.signTransaction = function signTransaction() { return Promise.reject(e) } - if (arguments.length === 0 || arguments.length > 3) { - return handleError('Invalid parameter: The number of parameters is invalid.') + 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) } - - // privateKey and callback are optional parameter - // "arguments.length === 2" means that user sent parameter privateKey or callback - let tx = arguments[0], privateKey - if (!tx || !_.isObject(tx)) { - return handleError('Invalid parameter: The transaction must be defined as an object') - } + // Validate tx object + const error = helpers.validateFunction.validateParams(tx) + if (error) return handleError(error) - if (arguments.length === 2) { - if (_.isFunction(arguments[1])) { - callback = arguments[1] - } else { - privateKey = arguments[1] - } - } else if (arguments.length === 3) { - if (typeof arguments[1] !== 'string' && !_.isArray(arguments[1])){ - return handleError('Invalid parameter: The parameter for the private key is invalid') + if (tx.senderRawTransaction) { + if (tx.feePayerSignatures) { + existedFeePayerSignatures = existedFeePayerSignatures.concat(tx.feePayerSignatures) } - privateKey = arguments[1] - callback = arguments[2] - } - // For handling when callback is undefined. - callback = callback || function () {} + 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) + } - let error = helpers.validateFunction.validateParams(tx) - if (error) return handleError(error) + tx.senderRawTransaction = senderRawTransaction + isFeePayer = true + } catch(e) { + return handleError(e) + } + + } 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(tx.from || tx.feePayer) + 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 = account.privateKey + 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) { @@ -530,10 +620,9 @@ Accounts.prototype.signTransaction = function signTransaction() { } // Attempting to sign with a decoupled account into a legacy type transaction should be rejected. - if (!tx.senderRawTransaction) { - isLegacy = tx.type === undefined || tx.type === 'LEGACY' ? true : false - if (isLegacy && privateKeys.length > 1) return handleError('Legacy transaction cannot signed with multiple keys') - if (isLegacy && _this.isDecoupled(privateKeys[0], tx.from)) return handleError('A legacy transaction must be with a legacy account key') + 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) { @@ -547,30 +636,30 @@ Accounts.prototype.signTransaction = function signTransaction() { const messageHash = Hash.keccak256(rlpEncoded) - let signatures = [] + let sigs = isFeePayer? existedFeePayerSignatures : existedSenderSignatures 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))) - signatures.push([v, r, s]) + sigs.push([v, r, s]) } - - const rawTransaction = makeRawTransaction(rlpEncoded, signatures, transaction) + // makeRawTransaction will return signatures and feePayerSignatures with duplicates removed. + let { rawTransaction, signatures, feePayerSignatures } = makeRawTransaction(rlpEncoded, sigs, transaction) result = { messageHash: messageHash, - v: signatures[0][0], - r: signatures[0][1], - s: signatures[0][2], + v: sigs[0][0], + r: sigs[0][1], + s: sigs[0][2], rawTransaction: rawTransaction, txHash: Hash.keccak256(rawTransaction), senderTxHash: getSenderTxHash(rawTransaction), } - if (tx.senderRawTransaction && tx.feePayer) { - result.feePayerSignatures = signatures + if (isFeePayer) { + result.feePayerSignatures = feePayerSignatures } else { - result.signatures = isLegacy? signatures[0] : signatures + result.signatures = signatures } } catch(e) { @@ -587,7 +676,7 @@ Accounts.prototype.signTransaction = function signTransaction() { } // 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) { @@ -595,7 +684,7 @@ Accounts.prototype.signTransaction = function signTransaction() { 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 @@ -608,8 +697,84 @@ Accounts.prototype.signTransaction = function signTransaction() { 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. +* +* @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.`) + } + + 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) + }) +} Accounts.prototype.signTransactionWithSignature = function signTransactionWithSignature(tx, callback) { var _this = this, diff --git a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js index 83eb8d53..7407c0e8 100644 --- a/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js +++ b/packages/caver-klay/caver-klay-accounts/src/makeRawTransaction.js @@ -140,12 +140,15 @@ function makeRawTransaction(rlpEncoded, sig, transaction) { const decoded = decodeFromRawTransaction(transaction.senderRawTransaction) 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[0]) - return RLP.encode(rawTx) + return { rawTransaction: RLP.encode(rawTx), signatures: sig[0], feePayerSignatures: undefined } } } @@ -156,25 +159,49 @@ function _combineSenderRawTransaction(rlpEncoded, sig) { let [txType, ...rawTx] = RLP.decode(data) 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, senderSignature) { +function _combineFeePayerRawTransaction(rlpEncoded, feePayerSignatures, transaction, senderSignature) { const decodedValues = RLP.decode(rlpEncoded) let [data] = decodedValues let [txType, ...rawTx] = RLP.decode(data) - if (!Array.isArray(sig[0])) sig = [sig] - rawTx = [...rawTx, senderSignature, transaction.feePayer.toLowerCase(), sig] + if (!Array.isArray(feePayerSignatures[0])) feePayerSignatures = [feePayerSignatures] + senderSignature = refineSignatures(senderSignature) + feePayerSignatures = refineSignatures(feePayerSignatures) + + 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 txType + RLP.encode(rawTx).slice(2) + return result } function extractSignatures(rawTransaction) { @@ -192,7 +219,7 @@ function extractSignatures(rawTransaction) { function splitFeePayer(rawTransaction) { const typeString = utils.getTxTypeStringFromRawTransaction(rawTransaction) - if (!typeString || !typeString.includes('FEE_DELEGATED')) throw new Error(`The RLP encoded transaction is not a fee delegated transaction type: '${typeString? typeString : 'LEGACY'}'`) + 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))) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index b4c179c3..7dfb3cb7 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -180,7 +180,7 @@ describe('caver.klay.accounts.privateKeyToAccount', () => { }) describe('caver.klay.accounts.signTransaction', () => { - let txObj, vtTx, account + let txObj, vtTx, account, feePayer, sender beforeEach(() => { account = caver.klay.accounts.create() @@ -495,6 +495,905 @@ describe('caver.klay.accounts.signTransaction', () => { await expect(caver.klay.accounts.signTransaction(feeDelegatedTx)).to.be.rejectedWith(errorMessage) }) }) + + 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) + + expect(result.signatures.length).to.equals(1) + expect(result.feePayerSignatures).to.be.undefined + }) + }) + + 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-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) + + expect(result.signatures).to.be.undefined + expect(result.feePayerSignatures.length).to.equals(1) + }) + }) + + 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-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) + }) + }) + + 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-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.recoverTransaction', () => { From 355ea4117ae5f620403655683d11644ff1541516 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 14:49:36 +0900 Subject: [PATCH 105/123] Add description for resolve functions --- .../caver-klay/caver-klay-accounts/src/index.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 782076d1..c29c95ce 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -68,6 +68,13 @@ function coverInitialTxValue(tx) { 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.') @@ -99,6 +106,13 @@ function resolveArgsForSignTransaction(args) { 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.') From 47d29db17c35220db94c67f6acbac0c6b3014a64 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 15:10:44 +0900 Subject: [PATCH 106/123] Fixed broken link of Klaytn docs --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index fb364a5b..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 From 13818b3faf3343c70ef8da909cfcc0eae9e7bb9a Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 15:16:12 +0900 Subject: [PATCH 107/123] Add description about appending --- packages/caver-klay/caver-klay-accounts/src/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index c29c95ce..2ac73fe0 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -540,6 +540,8 @@ Accounts.prototype.getLegacyAccount = function getLegacyAccount(key) { /** * 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. @@ -716,6 +718,7 @@ Accounts.prototype.signTransaction = function signTransaction() { /** * 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. From 6de8fbb092c107c801d86209ddf86f924104f48d Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 15:39:19 +0900 Subject: [PATCH 108/123] Implemented getRawTransactionWithSignatures and combineSignatures --- .../caver-klay-accounts/src/index.js | 141 ++++++-- test/packages/caver.klay.accounts.js | 334 ++++++++++++++++++ 2 files changed, 444 insertions(+), 31 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 2ac73fe0..ace81de4 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -793,33 +793,50 @@ Accounts.prototype.feePayerSignTransaction = function feePayerSignTransaction() }) } -Accounts.prototype.signTransactionWithSignature = function signTransactionWithSignature(tx, 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) { - error = helpers.validateFunction.validateParams(tx) - if (error) { - callback(error) - return Promise.reject(error) - } try { // Guarantee all property in transaction is hex. @@ -829,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) { @@ -861,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)); @@ -875,6 +892,68 @@ Accounts.prototype.signTransactionWithSignature = function signTransactionWithSi }); }; +/** + * combineSignatures combines RLP encoded raw transaction strings. + * + * @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) { + let decodedTx + let senders = [] + let feePayers = [] + let feePayer + + if (!_.isArray(rawTransactions)) throw new Error(`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 + } + + if (key === 'feePayer') { + if (decodedTx[key] === '0x') { + decodedTx[key] = decodedTransaction[key] + feePayer = decodedTx[key] + } else if (decodedTransaction[key] === '0x') { + continue + } + } + + if (decodedTransaction[key] === undefined || decodedTx[key] !== decodedTransaction[key]) { + isSame = false + break + } + } + if (!isSame) throw new Error(`Failed to combineSignatures: Signatures that sign to different transaction cannot be combined.`) + } else { + decodedTx = decodedTransaction + } + } + + + const parsedTxObject = decodeFromRawTransaction(rawTransactions[0]) + if (feePayer) parsedTxObject.feePayer = feePayer + + parsedTxObject.signatures = senders + if (parsedTxObject.feePayer && parsedTxObject.feePayer !== '0x' && parsedTxObject.feePayerSignatures) { + parsedTxObject.feePayerSignatures = feePayers + } + + return this.getRawTransactionWithSignatures(parsedTxObject) +} + /** * cav.klay.accounts.recoverTransaction('0xf86180808401ef364594f0109fc8df283027b6285cc889f5aa624eac1f5580801ca031573280d608f75137e33fc14655f097867d691d5c4c44ebe5ae186070ac3d5ea0524410802cdc025034daefcdfa08e7d2ee3f0b9d9ae184b2001fe0aff07603d9'); * > "0xF0109fC8DF283027b6285cc889F5aA624EaC1F55" diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 7dfb3cb7..41757ef0 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -1396,6 +1396,340 @@ describe('caver.klay.accounts.feePayerSignTransaction', () => { }) }) +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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) +}) + +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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) + + 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) + }) + }) +}) + describe('caver.klay.accounts.recoverTransaction', () => { let account let rawTx From fd96178777629560696fc98d7bc1bd0bf880aeff Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 15:50:14 +0900 Subject: [PATCH 109/123] Add timeout --- test/packages/caver.klay.accounts.js | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 41757ef0..2a2d5131 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -1441,7 +1441,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { 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', () => { @@ -1455,7 +1455,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { 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', () => { @@ -1476,7 +1476,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { 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', () => { @@ -1501,7 +1501,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { 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', () => { @@ -1522,7 +1522,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { 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', () => { @@ -1546,7 +1546,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { 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', () => { @@ -1572,7 +1572,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { 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', () => { @@ -1580,7 +1580,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { 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)', () => { @@ -1592,7 +1592,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { 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', () => { @@ -1604,7 +1604,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { 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', () => { @@ -1615,7 +1615,7 @@ describe('caver.klay.accounts.getRawTransactionWithSignatures', () => { const errorMessage = `"feePayerSignatures" cannot be used with ${vtTx.type} transaction` await expect(caver.klay.accounts.getRawTransactionWithSignatures(vtTx)).to.be.rejectedWith(errorMessage) - }) + }).timeout(200000) }) }) @@ -1656,7 +1656,7 @@ describe('caver.klay.accounts.combineSignatures', () => { 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)', () => { @@ -1673,7 +1673,7 @@ describe('caver.klay.accounts.combineSignatures', () => { 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)', () => { @@ -1691,7 +1691,7 @@ describe('caver.klay.accounts.combineSignatures', () => { 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)', () => { @@ -1726,7 +1726,7 @@ describe('caver.klay.accounts.combineSignatures', () => { const decoded = caver.klay.decodeTransaction(result.rawTransaction) expect(decoded.signatures.length).to.equals(3) expect(decoded.feePayerSignatures.length).to.equals(3) - }) + }).timeout(200000) }) }) From 3ff748fd91cf5cd5cbbabd088279778e48754cd5 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 15:56:29 +0900 Subject: [PATCH 110/123] Added test cases for key field --- test/transactionType/accountUpdate.js | 192 ++++++++++++++++ .../feeDelegatedAccountUpdate.js | 210 ++++++++++++++++++ .../feeDelegatedAccountUpdateWithRatio.js | 210 ++++++++++++++++++ 3 files changed, 612 insertions(+) diff --git a/test/transactionType/accountUpdate.js b/test/transactionType/accountUpdate.js index 41dc9b10..d365b66b 100644 --- a/test/transactionType/accountUpdate.js +++ b/test/transactionType/accountUpdate.js @@ -1612,4 +1612,196 @@ describe('ACCOUNT_UPDATE 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/feeDelegatedAccountUpdate.js b/test/transactionType/feeDelegatedAccountUpdate.js index b4043170..ed6d3eff 100644 --- a/test/transactionType/feeDelegatedAccountUpdate.js +++ b/test/transactionType/feeDelegatedAccountUpdate.js @@ -1508,4 +1508,214 @@ describe('FEE_DELEGATED_ACCOUNT_UPDATE transaction', () => { 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 d7efe1ef..077dc5d9 100644 --- a/test/transactionType/feeDelegatedAccountUpdateWithRatio.js +++ b/test/transactionType/feeDelegatedAccountUpdateWithRatio.js @@ -1515,4 +1515,214 @@ describe('FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO transaction', () => { 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 From e86d4dba451042c5f11123f212a3929756cdae63 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 16:13:10 +0900 Subject: [PATCH 111/123] Modified sendSignedTransaction logic to handle object --- package.json | 2 +- packages/caver-core-method/src/index.js | 30 +++- test/sendSignedTransaction.js | 201 ++++++++++++++++++++---- 3 files changed, 197 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 25333301..6d7cb757 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "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 && 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/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*", + "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", "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", diff --git a/packages/caver-core-method/src/index.js b/packages/caver-core-method/src/index.js index 73407454..edfde3f9 100644 --- a/packages/caver-core-method/src/index.js +++ b/packages/caver-core-method/src/index.js @@ -286,18 +286,27 @@ 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 + // 2. A transaction object containing signatures or feePayerSignatures + 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) - // } - + + let error if (!_.isObject(tx)) { error = new Error('The transaction must be defined as an object.') sendTxCallback(error) @@ -324,8 +333,13 @@ const buildSendRequestFunc = (defer, sendSignedTx, sendTxCallback) => (payload, } 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).then(sendSignedTx).catch((e) => { sendTxCallback(e) }) + 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. 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 From e655e39e913b3297b1762b45976d5ccdaea909a6 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Sat, 19 Oct 2019 23:55:43 +0900 Subject: [PATCH 112/123] Add descriptions for combineSignatures --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index ace81de4..f4728e10 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -894,10 +894,10 @@ Accounts.prototype.getRawTransactionWithSignatures = function getRawTransactionW /** * combineSignatures combines RLP encoded raw transaction strings. + * combineSignatures compares transaction before combining, and if values in field are not same(except default value), this throws error. * * @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) { From f7ee0ee7bcdb208d8e050fec39b6d1a6f3a9b397 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Sat, 19 Oct 2019 23:57:23 +0900 Subject: [PATCH 113/123] Add comments for specific condition --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index f4728e10..2891ec47 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -922,6 +922,8 @@ Accounts.prototype.combineSignatures = function combineSignatures(rawTransaction 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 (decodedTx[key] === '0x') { decodedTx[key] = decodedTransaction[key] From 7d404f770c02216064469b56e273284b181ed221 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Sun, 20 Oct 2019 00:00:42 +0900 Subject: [PATCH 114/123] Add comments for sendSignedTransaction --- packages/caver-core-method/src/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/caver-core-method/src/index.js b/packages/caver-core-method/src/index.js index edfde3f9..d4497e9b 100644 --- a/packages/caver-core-method/src/index.js +++ b/packages/caver-core-method/src/index.js @@ -288,7 +288,9 @@ 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)) { From c72bfdc11b8fef0f219211322161d2bb33d3a822 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Sun, 20 Oct 2019 00:07:11 +0900 Subject: [PATCH 115/123] Added description for feePayer --- packages/caver-klay/caver-klay-accounts/src/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 2891ec47..38738524 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -894,8 +894,10 @@ Accounts.prototype.getRawTransactionWithSignatures = function getRawTransactionW /** * combineSignatures combines RLP encoded raw transaction strings. - * combineSignatures compares transaction before combining, and if values in field are not same(except default value), this throws error. - * + * combineSignatures compares transaction before combining, and if values in field are not same, this throws error. + * The result of deocdeTransaction, feePayer can be '0x'(default value) when there is not fee payer's information(address of feePayer and feePayerSignatures) + * 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. * @return {Object} From 9a70edff187b32d2235a9eff47cd356dcb3bce87 Mon Sep 17 00:00:00 2001 From: Jasmine <32922423+jimni1222@users.noreply.github.com> Date: Sun, 20 Oct 2019 00:23:55 +0900 Subject: [PATCH 116/123] Update packages/caver-klay/caver-klay-accounts/src/index.js Co-Authored-By: Junghyun Colin Kim --- packages/caver-klay/caver-klay-accounts/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index 38738524..ce03ac95 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -895,7 +895,7 @@ Accounts.prototype.getRawTransactionWithSignatures = function getRawTransactionW /** * combineSignatures combines RLP encoded raw transaction strings. * combineSignatures compares transaction before combining, and if values in field are not same, this throws error. - * The result of deocdeTransaction, feePayer can be '0x'(default value) when there is not fee payer's information(address of feePayer and feePayerSignatures) + * 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 From f22abe3c780de2118b7c135c0013249ac56e834d Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 21 Oct 2019 08:34:59 +0900 Subject: [PATCH 117/123] Modified if statement for feePayer and feePayerSignatures in combineSignatures --- .../caver-klay-accounts/src/index.js | 23 +++++++++++------- test/packages/caver.klay.accounts.js | 24 +++++++++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index ce03ac95..ec0a7fbb 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -927,11 +927,15 @@ Accounts.prototype.combineSignatures = function combineSignatures(rawTransaction // 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 (decodedTx[key] === '0x') { - decodedTx[key] = decodedTransaction[key] - feePayer = decodedTx[key] - } else if (decodedTransaction[key] === '0x') { + 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] + } } } @@ -948,13 +952,14 @@ Accounts.prototype.combineSignatures = function combineSignatures(rawTransaction const parsedTxObject = decodeFromRawTransaction(rawTransactions[0]) - if (feePayer) parsedTxObject.feePayer = feePayer - parsedTxObject.signatures = senders - if (parsedTxObject.feePayer && parsedTxObject.feePayer !== '0x' && parsedTxObject.feePayerSignatures) { - parsedTxObject.feePayerSignatures = feePayers - } + if (feePayer) { + parsedTxObject.feePayer = feePayer + if (feePayers.length > 0) { + parsedTxObject.feePayerSignatures = feePayers + } + } return this.getRawTransactionWithSignatures(parsedTxObject) } diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 2a2d5131..8a341b6b 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -1728,6 +1728,30 @@ describe('caver.klay.accounts.combineSignatures', () => { 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) + }) }) describe('caver.klay.accounts.recoverTransaction', () => { From 251d92d0c7b10b9c95986fee1d4dffda02b7e7d1 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 15:54:18 +0900 Subject: [PATCH 118/123] Added scenario test files --- test/scenarioTest/accountKeyMultiSig.js | 648 ++++++++++++++++++++ test/scenarioTest/accountKeyPublic.js | 561 +++++++++++++++++ test/scenarioTest/accountKeyRoleBased.js | 739 +++++++++++++++++++++++ 3 files changed, 1948 insertions(+) create mode 100644 test/scenarioTest/accountKeyMultiSig.js create mode 100644 test/scenarioTest/accountKeyPublic.js create mode 100644 test/scenarioTest/accountKeyRoleBased.js diff --git a/test/scenarioTest/accountKeyMultiSig.js b/test/scenarioTest/accountKeyMultiSig.js new file mode 100644 index 00000000..dfe35c45 --- /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(feePayerSigned) + } 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..18231c0d --- /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(feePayerSigned) + } 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(feePayerSigned) + } 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(feePayerSigned) + } 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(feePayerSigned) + } 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 From a8822c7f22bc0ea065de5aed7ee44d9d9cbcba85 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Fri, 18 Oct 2019 16:16:32 +0900 Subject: [PATCH 119/123] Added script for scenario test --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 6d7cb757..692cde29 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "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/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", From 891699b1f627ae984e8a9c715110365875b3850c Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 21 Oct 2019 09:33:21 +0900 Subject: [PATCH 120/123] Added callback function for combineSignatures --- .../caver-klay-accounts/src/index.js | 17 +++++++++--- test/packages/caver.klay.accounts.js | 26 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index ec0a7fbb..da2b5661 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -900,15 +900,24 @@ Accounts.prototype.getRawTransactionWithSignatures = function getRawTransactionW * * @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) { +Accounts.prototype.combineSignatures = function combineSignatures(rawTransactions, callback) { let decodedTx let senders = [] let feePayers = [] let feePayer - if (!_.isArray(rawTransactions)) throw new Error(`The parameter of the combineSignatures function must be an array of RLP encoded transaction strings.`) + 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) @@ -944,7 +953,7 @@ Accounts.prototype.combineSignatures = function combineSignatures(rawTransaction break } } - if (!isSame) throw new Error(`Failed to combineSignatures: Signatures that sign to different transaction cannot be combined.`) + if (!isSame) return handleError(`Failed to combineSignatures: Signatures that sign to different transaction cannot be combined.`) } else { decodedTx = decodedTransaction } @@ -960,7 +969,7 @@ Accounts.prototype.combineSignatures = function combineSignatures(rawTransaction parsedTxObject.feePayerSignatures = feePayers } } - return this.getRawTransactionWithSignatures(parsedTxObject) + return this.getRawTransactionWithSignatures(parsedTxObject, callback) } /** diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 8a341b6b..50954375 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -1752,6 +1752,32 @@ describe('caver.klay.accounts.combineSignatures', () => { 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', () => { From 43a910899e9363dff43ff75743ec5094df063b94 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 21 Oct 2019 09:35:13 +0900 Subject: [PATCH 121/123] Fixed scenario test error --- test/scenarioTest/accountKeyMultiSig.js | 2 +- test/scenarioTest/accountKeyRoleBased.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/scenarioTest/accountKeyMultiSig.js b/test/scenarioTest/accountKeyMultiSig.js index dfe35c45..8dbf0d98 100644 --- a/test/scenarioTest/accountKeyMultiSig.js +++ b/test/scenarioTest/accountKeyMultiSig.js @@ -598,7 +598,7 @@ describe('Scenario test with AccountWithAccountKeyMultiSig', () => { const expectedError = 'invalid transaction v, r, s values of the sender' try { - await caver.klay.sendSignedTransaction(feePayerSigned) + await caver.klay.sendSignedTransaction(senderSigned) } catch (e) { expect(e.message).to.include(expectedError) } }).timeout(200000) }) diff --git a/test/scenarioTest/accountKeyRoleBased.js b/test/scenarioTest/accountKeyRoleBased.js index 18231c0d..70c02a89 100644 --- a/test/scenarioTest/accountKeyRoleBased.js +++ b/test/scenarioTest/accountKeyRoleBased.js @@ -610,14 +610,14 @@ describe('Scenario test with AccountWithAccountKeyRoleBased', () => { let expectedError = 'invalid transaction v, r, s values of the sender' try { - await caver.klay.sendSignedTransaction(feePayerSigned) + 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(feePayerSigned) + await caver.klay.sendSignedTransaction(senderSigned) } catch (e) { expect(e.message).to.include(expectedError) } txObject = { @@ -630,14 +630,14 @@ describe('Scenario test with AccountWithAccountKeyRoleBased', () => { senderSigned = await caver.klay.accounts.signTransaction(txObject, account.transactionKey) try { - await caver.klay.sendSignedTransaction(feePayerSigned) + 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(feePayerSigned) + await caver.klay.sendSignedTransaction(senderSigned) } catch (e) { expect(e.message).to.include(expectedError) } txObject = { From bfa7f7fc694b0187c786f85152b9de3f8fb833f4 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 21 Oct 2019 14:07:28 +0900 Subject: [PATCH 122/123] Changed keyRing to keyring --- .../caver-klay-accounts/src/index.js | 36 ++++---- test/packages/caver.klay.accounts.js | 92 +++++++++---------- 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/packages/caver-klay/caver-klay-accounts/src/index.js b/packages/caver-klay/caver-klay-accounts/src/index.js index da2b5661..0eb14647 100644 --- a/packages/caver-klay/caver-klay-accounts/src/index.js +++ b/packages/caver-klay/caver-klay-accounts/src/index.js @@ -1116,29 +1116,29 @@ Accounts.prototype.decrypt = function (v3Keystore, password, nonStrict) { } if (json.crypto) { - if (json.keyRing) throw new Error(`Invalid key store format: 'crypto' can not be with 'keyRing'`) - json.keyRing = [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 (_.isArray(json.keyRing[0]) && json.keyRing.length > 3) { + 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 (_.isArray(json.keyring[0])) { + let transactionKey = decryptKey(json.keyring[0]) if (transactionKey) accountKey.transactionKey = transactionKey - let updateKey = decryptKey(json.keyRing[1]) + let updateKey = decryptKey(json.keyring[1]) if (updateKey) accountKey.updateKey = updateKey - let feePayerKey = decryptKey(json.keyRing[2]) + let feePayerKey = decryptKey(json.keyring[2]) if (feePayerKey) accountKey.feePayerKey = feePayerKey } else { - accountKey = decryptKey(json.keyRing) + accountKey = decryptKey(json.keyring) } function decryptKey(encryptedArray) { @@ -1278,24 +1278,24 @@ Accounts.prototype.encrypt = function (key, password, options) { if (!account) account = this.createWithAccountKey(address, key) - let keyRing + let keyring switch(account.accountKeyType) { case AccountKeyEnum.ACCOUNT_KEY_PUBLIC: case AccountKeyEnum.ACCOUNT_KEY_MULTISIG: - keyRing = encryptKey(account.keys) + keyring = encryptKey(account.keys) break case AccountKeyEnum.ACCOUNT_KEY_ROLEBASED: - keyRing = [] + 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) + 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 } @@ -1365,7 +1365,7 @@ Accounts.prototype.encrypt = function (key, password, options) { version: 4, id: uuid.v4({ random: options.uuid || cryp.randomBytes(16) }), address: account.address.toLowerCase(), - keyRing + keyring }; }; diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index 50954375..d71f7d8b 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -64,7 +64,7 @@ function checkHashMessage(hashed, originMessage) { } function isKeystoreV4(data, { address }) { - const objectKeys = ['version', 'id', 'address', 'keyRing'] + const objectKeys = ['version', 'id', 'address', 'keyring'] expect(Object.getOwnPropertyNames(data)).to.deep.equal(objectKeys) expect(data.version).to.equals(4) @@ -2095,7 +2095,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount.keys, password, {address: testAccount.address}) isKeystoreV4(result, testAccount) - expect(result.keyRing.length).to.equals(key.length) + expect(result.keyring.length).to.equals(key.length) const decrypted = caver.klay.accounts.decrypt(result, password) isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address}) @@ -2128,10 +2128,10 @@ describe('caver.klay.accounts.encrypt', () => { 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) + 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}) @@ -2152,10 +2152,10 @@ describe('caver.klay.accounts.encrypt', () => { 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) + 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}) @@ -2174,8 +2174,8 @@ describe('caver.klay.accounts.encrypt', () => { 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) + 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}) @@ -2194,9 +2194,9 @@ describe('caver.klay.accounts.encrypt', () => { 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) + 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}) @@ -2215,10 +2215,10 @@ describe('caver.klay.accounts.encrypt', () => { 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) + 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}) @@ -2252,7 +2252,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address}) isKeystoreV4(result, testAccount) - expect(result.keyRing.length).to.equals(1) + expect(result.keyring.length).to.equals(1) const decrypted = caver.klay.accounts.decrypt(result, password) isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address}) @@ -2282,7 +2282,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address}) isKeystoreV4(result, testAccount) - expect(result.keyRing.length).to.equals(key.length) + expect(result.keyring.length).to.equals(key.length) const decrypted = caver.klay.accounts.decrypt(result, password) isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address}) @@ -2316,10 +2316,10 @@ describe('caver.klay.accounts.encrypt', () => { 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) + 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}) @@ -2353,7 +2353,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(testAccount, password, {address: testAccount.address}) isKeystoreV4(result, testAccount) - expect(result.keyRing.length).to.equals(1) + expect(result.keyring.length).to.equals(1) const decrypted = caver.klay.accounts.decrypt(result, password) isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address}) @@ -2384,7 +2384,7 @@ describe('caver.klay.accounts.encrypt', () => { let result = caver.klay.accounts.encrypt(accountKey, password, {address: testAccount.address}) isKeystoreV4(result, testAccount) - expect(result.keyRing.length).to.equals(key.length) + expect(result.keyring.length).to.equals(key.length) const decrypted = caver.klay.accounts.decrypt(result, password) isAccount(decrypted, {keys: testAccount.keys, address: testAccount.address}) @@ -2419,10 +2419,10 @@ describe('caver.klay.accounts.encrypt', () => { 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) + 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}) @@ -2472,7 +2472,7 @@ describe('caver.klay.accounts.encrypt', () => { version: 4, id: 'e7c4605a-d820-4e0d-93cd-67f9d82fb997', address: '0xf725a2950dc959638fa09f9d9b5426ad3dd8cd90', - keyRing:[ + keyring:[ [ { ciphertext: '5e2f95f61d7af3bebf4ff9f5d5813690c80b0b5aaebd6e8b22d0f928ff06776a', @@ -2543,10 +2543,10 @@ describe('caver.klay.accounts.encrypt', () => { 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]) + 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) @@ -2673,8 +2673,8 @@ describe('caver.klay.accounts.decrypt', () => { 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 + keystore.crypto = keystore.keyring[0] + delete keystore.keyring let result = caver.klay.accounts.decrypt(keystore, password) @@ -2696,27 +2696,27 @@ describe('caver.klay.accounts.decrypt', () => { }) context('CAVERJS-UNIT-WALLET-380: input: keystoreJsonV4 that encrypts Account, password', () => { - it('should throw error with invalid keystore v3 which defines crypto and keyRing', () => { + 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] + keystore.crypto = keystore.keyring[0] - const expectedError = `Invalid key store format: 'crypto' can not be with 'keyRing'` + 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', () => { + 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] + keystore.crypto = keystore.keyring[0] - const expectedError = `Invalid key store format: 'crypto' can not be with 'keyRing'` + const expectedError = `Invalid key store format: 'crypto' can not be with 'keyring'` expect(() => caver.klay.accounts.decrypt(keystore, password)).to.throws(expectedError) }) @@ -2727,7 +2727,7 @@ describe('caver.klay.accounts.decrypt', () => { const password = 'klaytn!@' const key = caver.klay.accounts.create().privateKey const keystore = caver.klay.accounts.encrypt(key, password, { address: account.address }) - keystore.keyRing = [[], [], [], []] + keystore.keyring = [[], [], [], []] const expectedError = `Invalid key store format` @@ -2741,7 +2741,7 @@ describe('caver.klay.accounts.decrypt', () => { version: 4, id: '55da3f9c-6444-4fc1-abfa-f2eabfc57501', address: '0x86bce8c859f5f304aa30adb89f2f7b6ee5a0d6e2', - keyRing:[ + keyring:[ [ { ciphertext: '93dd2c777abd9b80a0be8e1eb9739cbf27c127621a5d3f81e7779e47d3bb22f6', From 5a15c40a229ac1bf744fb74b7803236a0c51a734 Mon Sep 17 00:00:00 2001 From: Jasmine/kimjimin Date: Mon, 21 Oct 2019 14:11:56 +0900 Subject: [PATCH 123/123] Added one more test case for pbkdf2 --- test/packages/caver.klay.accounts.js | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/packages/caver.klay.accounts.js b/test/packages/caver.klay.accounts.js index d71f7d8b..d33f5797 100644 --- a/test/packages/caver.klay.accounts.js +++ b/test/packages/caver.klay.accounts.js @@ -2564,6 +2564,40 @@ describe('caver.klay.accounts.encrypt', () => { 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', () => {