UNPKG

caver-js

Version:

caver-js is a JavaScript API library that allows developers to interact with a Klaytn node

916 lines (764 loc) 95.5 kB
/* Copyright 2020 The caver-js Authors This file is part of the caver-js library. The caver-js library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The caver-js library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the caver-js. If not, see <http://www.gnu.org/licenses/>. */ const chai = require('chai') const sinon = require('sinon') const sinonChai = require('sinon-chai') const chaiAsPromised = require('chai-as-promised') chai.use(chaiAsPromised) chai.use(sinonChai) const expect = chai.expect const RLP = require('eth-lib/lib/rlp') const { propertiesForUnnecessary } = require('../utils') const testRPCURL = require('../../testrpc') const Caver = require('../../../index') const Keyring = require('../../../packages/caver-wallet/src/keyring/keyringFactory') const SingleKeyring = require('../../../packages/caver-wallet/src/keyring/singleKeyring') const TransactionHasher = require('../../../packages/caver-transaction/src/transactionHasher/transactionHasher') const { generateRoleBasedKeyring, makeAccount, accountKeyTestCases, checkSignature, checkFeePayerSignature } = require('../utils') let caver let sender let feePayer let roleBasedKeyring let txObjWithLegacy let txObjWithPublic let txObjWithFail let txObjWithMultiSig let txObjWithRoleBased const expectedValues = [] let txsByAccountKeys = [] const sandbox = sinon.createSandbox() function makeAccountUpdateObjectWithExpectedValues() { { const testAddress = '0x5c525570f2b8e7e25f3a6b5e17f2cc63b872ece7' const account = caver.account.createWithAccountKeyLegacy(testAddress) const tx = { from: testAddress, account, gas: '0x493e0', nonce: '0x0', gasPrice: '0x5d21dba00', feeRatio: 30, signatures: [ [ '0x0fea', '0x8d45728ca7a288d27f70c6b7153624b6c3dabd8f345e63049048b2b1787aae1e', '0x370d2c5cf3cd99dc0a6ecaca75e30cc5e030ea71bf72fada047ace020c7410f0', ], ], feePayer: '0x294f5bc8fadbd1079b191d9c47e1f217d6c987b4', feePayerSignatures: [ [ '0x0fe9', '0x550440015be09e0020f3cf6173c862420e2982c77f6a0a43d607b153bb7abd6c', '0x67ca2a849a5e14992d3e9dff3562b1ac9856ff89f383c34645925fec12b3fdf9', ], ], chainId: '0x7e3', } expectedValues.push({}) expectedValues[accountKeyTestCases.LEGACY].tx = tx expectedValues[accountKeyTestCases.LEGACY].rlpEncodingForSigning = '0xeca6e522808505d21dba00830493e0945c525570f2b8e7e25f3a6b5e17f2cc63b872ece78201c01e8207e38080' expectedValues[accountKeyTestCases.LEGACY].rlpEncodingForFeePayerSigning = '0xf841a6e522808505d21dba00830493e0945c525570f2b8e7e25f3a6b5e17f2cc63b872ece78201c01e94294f5bc8fadbd1079b191d9c47e1f217d6c987b48207e38080' expectedValues[accountKeyTestCases.LEGACY].senderTxHash = '0x64e837cb9b7bdc3bffc8c37731ba60de47570da931b817139cf11b4fb1cc3a5e' expectedValues[accountKeyTestCases.LEGACY].transactionHash = '0xbfc73185429a9b5310dd159d16e44e6d63f2e278bf1aaa12be48827f2dee9d43' expectedValues[accountKeyTestCases.LEGACY].rlpEncoding = '0x22f8cb808505d21dba00830493e0945c525570f2b8e7e25f3a6b5e17f2cc63b872ece78201c01ef847f845820feaa08d45728ca7a288d27f70c6b7153624b6c3dabd8f345e63049048b2b1787aae1ea0370d2c5cf3cd99dc0a6ecaca75e30cc5e030ea71bf72fada047ace020c7410f094294f5bc8fadbd1079b191d9c47e1f217d6c987b4f847f845820fe9a0550440015be09e0020f3cf6173c862420e2982c77f6a0a43d607b153bb7abd6ca067ca2a849a5e14992d3e9dff3562b1ac9856ff89f383c34645925fec12b3fdf9' } { const testAddress = '0x5c525570f2b8e7e25f3a6b5e17f2cc63b872ece7' const pubKey = '0xa1d2af887950891813bf7d851bce55f47246a5269a5d4be1fc0ab78d78ae0f5a5cce7537f5a3776df303d240c0f730301df6be668907a1106adb0dbbef0beb3c' const account = caver.account.createWithAccountKeyPublic(testAddress, pubKey) const tx = { from: testAddress, account, gas: '0x493e0', nonce: '0x1', gasPrice: '0x5d21dba00', feeRatio: 30, signatures: [ [ '0x0fea', '0x8553a692cd8f86af4d335785468a5b4527ee1a2d0c5e18517fe39375e4e82d85', '0x698db3a07cc81427eb8ea877bb8af33d66abfb29526f58db6997eb99010be4fd', ], ], feePayer: '0x294f5bc8fadbd1079b191d9c47e1f217d6c987b4', feePayerSignatures: [ [ '0x0fea', '0xa44cbc6e30f9df61633ed1714014924b8b614b315288cdfd795c5ba18d36d5d8', '0x011611104f18e3bb3d32508317a0ce6d31f0a71d55e2363b02a47aabbc7bf9d4', ], ], chainId: '0x7e3', } expectedValues.push({}) expectedValues[accountKeyTestCases.PUBLIC].tx = tx expectedValues[accountKeyTestCases.PUBLIC].rlpEncodingForSigning = '0xf84fb848f84622018505d21dba00830493e0945c525570f2b8e7e25f3a6b5e17f2cc63b872ece7a302a102a1d2af887950891813bf7d851bce55f47246a5269a5d4be1fc0ab78d78ae0f5a1e8207e38080' expectedValues[accountKeyTestCases.PUBLIC].rlpEncodingForFeePayerSigning = '0xf864b848f84622018505d21dba00830493e0945c525570f2b8e7e25f3a6b5e17f2cc63b872ece7a302a102a1d2af887950891813bf7d851bce55f47246a5269a5d4be1fc0ab78d78ae0f5a1e94294f5bc8fadbd1079b191d9c47e1f217d6c987b48207e38080' expectedValues[accountKeyTestCases.PUBLIC].senderTxHash = '0xa9b2afdc79d7a647b1b8d38d552141f785ae8d37448aef1487a4dbd262165da0' expectedValues[accountKeyTestCases.PUBLIC].transactionHash = '0x265ad666c91db8355a620831698b26e6504a5770a5d0d1d7f5a6706ee2387616' expectedValues[accountKeyTestCases.PUBLIC].rlpEncoding = '0x22f8ec018505d21dba00830493e0945c525570f2b8e7e25f3a6b5e17f2cc63b872ece7a302a102a1d2af887950891813bf7d851bce55f47246a5269a5d4be1fc0ab78d78ae0f5a1ef847f845820feaa08553a692cd8f86af4d335785468a5b4527ee1a2d0c5e18517fe39375e4e82d85a0698db3a07cc81427eb8ea877bb8af33d66abfb29526f58db6997eb99010be4fd94294f5bc8fadbd1079b191d9c47e1f217d6c987b4f847f845820feaa0a44cbc6e30f9df61633ed1714014924b8b614b315288cdfd795c5ba18d36d5d8a0011611104f18e3bb3d32508317a0ce6d31f0a71d55e2363b02a47aabbc7bf9d4' } { const testAddress = '0x5c525570f2b8e7e25f3a6b5e17f2cc63b872ece7' const account = caver.account.createWithAccountKeyFail(testAddress) const tx = { from: testAddress, account, gas: '0x186a0', nonce: '0x4', gasPrice: '0x5d21dba00', feeRatio: 30, signatures: [ [ '0x0fe9', '0xfe43c4044a682a0f14489a4dabc94efdbf2838cff255911b059baf53511050e6', '0x2fde2475ca919e313a6bb5cafe8ed3b61651c8cc6ff939f88c36c11b805d6530', ], [ '0x0fea', '0x0b17cb389f0dbc9f65d22255b82a0c440f6033f2cc5ec0deff11da3e2e515d14', '0x1ba420aa515ac311812724a441e3f772b19536735ced7a0d989c50063d73aa58', ], [ '0x0fe9', '0xdc7fac293ee42ef4f113414bc391b8f976c95e10ff364a74a4564b8c9bd6af7a', '0x4e0513eb4ee7359d631be46f8b7f44c0049b9f4752565b1978fcd2260fc8103d', ], ], feePayer: '0x294f5bc8fadbd1079b191d9c47e1f217d6c987b4', feePayerSignatures: [ [ '0x0fea', '0x409bdfe4239de15901ca37e54ab632a95cbced6a17ff85203d5c15ae140405f9', '0x464cd266e2a207589508d9d6241e93fe637476e8562e755c4d133875d7afe0dc', ], ], chainId: '0x7e3', } expectedValues.push({}) expectedValues[accountKeyTestCases.FAIL].tx = tx expectedValues[accountKeyTestCases.FAIL].rlpEncodingForSigning = '0xeca6e522048505d21dba00830186a0945c525570f2b8e7e25f3a6b5e17f2cc63b872ece78203c01e8207e38080' expectedValues[accountKeyTestCases.FAIL].rlpEncodingForFeePayerSigning = '0xf841a6e522048505d21dba00830186a0945c525570f2b8e7e25f3a6b5e17f2cc63b872ece78203c01e94294f5bc8fadbd1079b191d9c47e1f217d6c987b48207e38080' expectedValues[accountKeyTestCases.FAIL].senderTxHash = '0xfff1eba87cac6c60316441b05af9cf920612a3471fa188686bc6b8ee7ef120be' expectedValues[accountKeyTestCases.FAIL].transactionHash = '0xe36dbee2c9c52a1d108794b69deb56efd40c250ef686b895ee9410b815d7eee4' expectedValues[accountKeyTestCases.FAIL].rlpEncoding = '0x22f90159048505d21dba00830186a0945c525570f2b8e7e25f3a6b5e17f2cc63b872ece78203c01ef8d5f845820fe9a0fe43c4044a682a0f14489a4dabc94efdbf2838cff255911b059baf53511050e6a02fde2475ca919e313a6bb5cafe8ed3b61651c8cc6ff939f88c36c11b805d6530f845820feaa00b17cb389f0dbc9f65d22255b82a0c440f6033f2cc5ec0deff11da3e2e515d14a01ba420aa515ac311812724a441e3f772b19536735ced7a0d989c50063d73aa58f845820fe9a0dc7fac293ee42ef4f113414bc391b8f976c95e10ff364a74a4564b8c9bd6af7aa04e0513eb4ee7359d631be46f8b7f44c0049b9f4752565b1978fcd2260fc8103d94294f5bc8fadbd1079b191d9c47e1f217d6c987b4f847f845820feaa0409bdfe4239de15901ca37e54ab632a95cbced6a17ff85203d5c15ae140405f9a0464cd266e2a207589508d9d6241e93fe637476e8562e755c4d133875d7afe0dc' } { const testAddress = '0x5c525570f2b8e7e25f3a6b5e17f2cc63b872ece7' const pubArray = [ '0xabbd10c55f629098d594b5c2b2967198bc5eccdf20a35e4e9c2896b0db6c7a8d1255629bc54d3e52ddfd16202e1820034630c8a2c2a0d4a1561aa1a9a1a9cb2b', '0x1f1d4186a795070bc519c7e297eed00d466106718a8e68abe43d37e65da0254f5968d5f789284099e11fd65b300c97ff6df543ba9b212f18a71e17adf8fbcdeb', '0x1ec395b3de087980e4a6ae2cb6e9d1acb469c0e54577267f2c4a5b4809f9d9118b691c79b8b5a1d07ececa6cfe5c8be0ebd622f240558bd776e4e73fbc57932d', ] const options = new caver.account.weightedMultiSigOptions(2, [1, 2, 3]) const account = caver.account.createWithAccountKeyWeightedMultiSig(testAddress, pubArray, options) const tx = { from: testAddress, account, gas: '0x55730', nonce: '0x2', gasPrice: '0x5d21dba00', feeRatio: 30, signatures: [ [ '0x0fe9', '0xc1d45ae52a2de256d3da5086ab7769bccc3611243fdf3b1d0186617e3c782df7', '0x26fcae8a34404ecc1e21a1a1a749c40cf667add4dc99986064d6097a95a59031', ], ], feePayer: '0x294f5bc8fadbd1079b191d9c47e1f217d6c987b4', feePayerSignatures: [ [ '0x0fea', '0x1b14fdbc76f6870943ebef563092324ef8743bf8ee5a7c76fe3faa2d60f74624', '0x707502cd4225aa08f4990c5a564152ec55724d8ce4ea497ac1885c6791432899', ], ], chainId: '0x7e3', } expectedValues.push({}) expectedValues[accountKeyTestCases.MULTISIG].tx = tx expectedValues[accountKeyTestCases.MULTISIG].rlpEncodingForSigning = '0xf89fb898f89622028505d21dba0083055730945c525570f2b8e7e25f3a6b5e17f2cc63b872ece7b87204f86f02f86ce301a103abbd10c55f629098d594b5c2b2967198bc5eccdf20a35e4e9c2896b0db6c7a8de302a1031f1d4186a795070bc519c7e297eed00d466106718a8e68abe43d37e65da0254fe303a1031ec395b3de087980e4a6ae2cb6e9d1acb469c0e54577267f2c4a5b4809f9d9111e8207e38080' expectedValues[accountKeyTestCases.MULTISIG].rlpEncodingForFeePayerSigning = '0xf8b4b898f89622028505d21dba0083055730945c525570f2b8e7e25f3a6b5e17f2cc63b872ece7b87204f86f02f86ce301a103abbd10c55f629098d594b5c2b2967198bc5eccdf20a35e4e9c2896b0db6c7a8de302a1031f1d4186a795070bc519c7e297eed00d466106718a8e68abe43d37e65da0254fe303a1031ec395b3de087980e4a6ae2cb6e9d1acb469c0e54577267f2c4a5b4809f9d9111e94294f5bc8fadbd1079b191d9c47e1f217d6c987b48207e38080' expectedValues[accountKeyTestCases.MULTISIG].senderTxHash = '0x083d4a460b19988a34dfc1e3e458df84e2c97c8693389a13931a4c740746b746' expectedValues[accountKeyTestCases.MULTISIG].transactionHash = '0x797a418893c6f3ac0cad2284707b716ef826e5fd09c5c1a5efddff897acefb1d' expectedValues[accountKeyTestCases.MULTISIG].rlpEncoding = '0x22f9013c028505d21dba0083055730945c525570f2b8e7e25f3a6b5e17f2cc63b872ece7b87204f86f02f86ce301a103abbd10c55f629098d594b5c2b2967198bc5eccdf20a35e4e9c2896b0db6c7a8de302a1031f1d4186a795070bc519c7e297eed00d466106718a8e68abe43d37e65da0254fe303a1031ec395b3de087980e4a6ae2cb6e9d1acb469c0e54577267f2c4a5b4809f9d9111ef847f845820fe9a0c1d45ae52a2de256d3da5086ab7769bccc3611243fdf3b1d0186617e3c782df7a026fcae8a34404ecc1e21a1a1a749c40cf667add4dc99986064d6097a95a5903194294f5bc8fadbd1079b191d9c47e1f217d6c987b4f847f845820feaa01b14fdbc76f6870943ebef563092324ef8743bf8ee5a7c76fe3faa2d60f74624a0707502cd4225aa08f4990c5a564152ec55724d8ce4ea497ac1885c6791432899' } { const testAddress = '0x5c525570f2b8e7e25f3a6b5e17f2cc63b872ece7' const pubArray = [ [ '0x82d11080d64faed9b9cc0e50664175012d43491d430ed1c0c6d1e610c71155a9ec310c868f6873c539507602fd5df5a80e09c9a0b541d408fbdbc89553329c4b', '0xc4a93d90ae50bb1234230b419ea3dcbb196d4619c36cacb1d6494d10832441b9902d8e67b22dd07fc561c07178edde33fe2554661d8c75af20058a2689b82d30', '0xe7deb2e2b19c1fdb21163d7a3d4e861cdd59fa3df0e0e04420b8173b2545e546e979e26799a016d3f19e86601954e1609226297dd19b735a9e567ff76a4f3499', ], [ '0xfc08c1f60bd819090a710397d008f7fe9484d434d61d156074591ab1f8bce6b779432d7e744314e7204a68b6d2827e43ad8cbb7f819c0681d0581217e15ba654', '0x281f3ae3b67ff556052338e27d9f9ce1d0175cce78b45b98338123a4baa0d2bd5815a4691b39ed893b943f8b2ed3104e3c5d09873df7ef9859070cc1c43b27e1', '0xd347eec75998b6b5ac6cc9bb77a771a292c533fb043464462f9c37e9f3a84760de8d916eae476155bb09e51a63d557f46a259f6c4b0874acf58e362a1f59979a', ], [ '0x748d779bc3b06f83eb28636e6ab98838cb4b2ceb0c066ec6b5f3161a8f242e82374d599dd1f5296bf42404018fc2c4095cd2046aa7cfd8c11de1376ab1b26e6b', '0x9e9c3e95386e71835a839c504e19b3ed36d1aff87892b6414b513525f6bd6a422685708d591fe8dc3b410459b90bf74cfbb5fffff26eebc4733aeca45a101536', '0x1d965ec526e1d588d40b9c99fefa4763f2cebde74103a300778cb7c212474b49f88760495cb258441b19a8fd130aafc4ddc9d0786ab2922272c5f6b0501805a6', ], ] const account = caver.account.createWithAccountKeyRoleBased(testAddress, pubArray) const transactionWithRolebased = { from: testAddress, account, gas: '0x61a80', nonce: '0x3', gasPrice: '0x5d21dba00', feeRatio: 30, signatures: [ [ '0x0fea', '0xa2a8fe5dc3e5c6d01cde5b11ddd6a9fd8c419c4aa96100162f50e307660979b6', '0x0e22cdfc93744a70403299e497618b8102f03a34773987ad80ae454fc8f97287', ], [ '0x0fea', '0x48d6e5567961fd86fd8cdbd46a81eec5336c76772d6644cb944eb995959af521', '0x306064709347bc74177595e6f48fbe8665fe6772cdaff4885f640dbb4a820161', ], [ '0x0fe9', '0x0e335413896be3f75f9accbfee2a99b825a33d2513893d6ade0b18105d110245', '0x085cfd94bd82c916ddcac4ca41b51d691b48073fa840752c166e470a9db9f7e9', ], ], feePayer: '0x294f5bc8fadbd1079b191d9c47e1f217d6c987b4', feePayerSignatures: [ [ '0x0fea', '0x7a8af8836035be491b86719c270375ddc1cefc2bcf19f2dfcd00e54173096e86', '0x79d079ba796d28d24168a5eb10556620cc2a222f35691d19ed6ed85c245ffb8f', ], ], chainId: '0x7e3', } expectedValues.push({}) expectedValues[accountKeyTestCases.ROLEBAED].tx = transactionWithRolebased expectedValues[accountKeyTestCases.ROLEBAED].rlpEncodingForSigning = '0xf90190b90188f9018522038505d21dba0083061a80945c525570f2b8e7e25f3a6b5e17f2cc63b872ece7b9016005f9015cb87204f86f01f86ce301a10382d11080d64faed9b9cc0e50664175012d43491d430ed1c0c6d1e610c71155a9e301a102c4a93d90ae50bb1234230b419ea3dcbb196d4619c36cacb1d6494d10832441b9e301a103e7deb2e2b19c1fdb21163d7a3d4e861cdd59fa3df0e0e04420b8173b2545e546b87204f86f01f86ce301a102fc08c1f60bd819090a710397d008f7fe9484d434d61d156074591ab1f8bce6b7e301a103281f3ae3b67ff556052338e27d9f9ce1d0175cce78b45b98338123a4baa0d2bde301a102d347eec75998b6b5ac6cc9bb77a771a292c533fb043464462f9c37e9f3a84760b87204f86f01f86ce301a103748d779bc3b06f83eb28636e6ab98838cb4b2ceb0c066ec6b5f3161a8f242e82e301a1029e9c3e95386e71835a839c504e19b3ed36d1aff87892b6414b513525f6bd6a42e301a1021d965ec526e1d588d40b9c99fefa4763f2cebde74103a300778cb7c212474b491e8207e38080' expectedValues[accountKeyTestCases.ROLEBAED].rlpEncodingForFeePayerSigning = '0xf901a5b90188f9018522038505d21dba0083061a80945c525570f2b8e7e25f3a6b5e17f2cc63b872ece7b9016005f9015cb87204f86f01f86ce301a10382d11080d64faed9b9cc0e50664175012d43491d430ed1c0c6d1e610c71155a9e301a102c4a93d90ae50bb1234230b419ea3dcbb196d4619c36cacb1d6494d10832441b9e301a103e7deb2e2b19c1fdb21163d7a3d4e861cdd59fa3df0e0e04420b8173b2545e546b87204f86f01f86ce301a102fc08c1f60bd819090a710397d008f7fe9484d434d61d156074591ab1f8bce6b7e301a103281f3ae3b67ff556052338e27d9f9ce1d0175cce78b45b98338123a4baa0d2bde301a102d347eec75998b6b5ac6cc9bb77a771a292c533fb043464462f9c37e9f3a84760b87204f86f01f86ce301a103748d779bc3b06f83eb28636e6ab98838cb4b2ceb0c066ec6b5f3161a8f242e82e301a1029e9c3e95386e71835a839c504e19b3ed36d1aff87892b6414b513525f6bd6a42e301a1021d965ec526e1d588d40b9c99fefa4763f2cebde74103a300778cb7c212474b491e94294f5bc8fadbd1079b191d9c47e1f217d6c987b48207e38080' expectedValues[accountKeyTestCases.ROLEBAED].senderTxHash = '0x14e68510db84f82075fa367bbd4dada2b1024cb985fce70b4ae72ee9cc421b2a' expectedValues[accountKeyTestCases.ROLEBAED].transactionHash = '0xd6f78a65f3de0dc2e4974a739bec097e54543c68beb5106bb1fc24d4290ec318' expectedValues[accountKeyTestCases.ROLEBAED].rlpEncoding = '0x22f902b9038505d21dba0083061a80945c525570f2b8e7e25f3a6b5e17f2cc63b872ece7b9016005f9015cb87204f86f01f86ce301a10382d11080d64faed9b9cc0e50664175012d43491d430ed1c0c6d1e610c71155a9e301a102c4a93d90ae50bb1234230b419ea3dcbb196d4619c36cacb1d6494d10832441b9e301a103e7deb2e2b19c1fdb21163d7a3d4e861cdd59fa3df0e0e04420b8173b2545e546b87204f86f01f86ce301a102fc08c1f60bd819090a710397d008f7fe9484d434d61d156074591ab1f8bce6b7e301a103281f3ae3b67ff556052338e27d9f9ce1d0175cce78b45b98338123a4baa0d2bde301a102d347eec75998b6b5ac6cc9bb77a771a292c533fb043464462f9c37e9f3a84760b87204f86f01f86ce301a103748d779bc3b06f83eb28636e6ab98838cb4b2ceb0c066ec6b5f3161a8f242e82e301a1029e9c3e95386e71835a839c504e19b3ed36d1aff87892b6414b513525f6bd6a42e301a1021d965ec526e1d588d40b9c99fefa4763f2cebde74103a300778cb7c212474b491ef8d5f845820feaa0a2a8fe5dc3e5c6d01cde5b11ddd6a9fd8c419c4aa96100162f50e307660979b6a00e22cdfc93744a70403299e497618b8102f03a34773987ad80ae454fc8f97287f845820feaa048d6e5567961fd86fd8cdbd46a81eec5336c76772d6644cb944eb995959af521a0306064709347bc74177595e6f48fbe8665fe6772cdaff4885f640dbb4a820161f845820fe9a00e335413896be3f75f9accbfee2a99b825a33d2513893d6ade0b18105d110245a0085cfd94bd82c916ddcac4ca41b51d691b48073fa840752c166e470a9db9f7e994294f5bc8fadbd1079b191d9c47e1f217d6c987b4f847f845820feaa07a8af8836035be491b86719c270375ddc1cefc2bcf19f2dfcd00e54173096e86a079d079ba796d28d24168a5eb10556620cc2a222f35691d19ed6ed85c245ffb8f' } } before(() => { caver = new Caver(testRPCURL) sender = caver.wallet.add(caver.wallet.keyring.generate()) feePayer = caver.wallet.add(caver.wallet.keyring.generate()) roleBasedKeyring = generateRoleBasedKeyring([3, 3, 3]) const commonObj = { from: sender.address, gas: '0x3b9ac9ff', feePayer: feePayer.address, feeRatio: 30, } txObjWithLegacy = { account: makeAccount(sender.address, accountKeyTestCases.LEGACY), ...commonObj } txObjWithPublic = { account: makeAccount(sender.address, accountKeyTestCases.PUBLIC), ...commonObj } txObjWithFail = { account: makeAccount(sender.address, accountKeyTestCases.FAIL), ...commonObj } txObjWithMultiSig = { account: makeAccount(sender.address, accountKeyTestCases.MULTISIG), ...commonObj } txObjWithRoleBased = { account: makeAccount(sender.address, accountKeyTestCases.ROLEBAED, [ { threshold: 2, weights: [1, 1, 1] }, {}, { threshold: 1, weights: [1, 1] }, ]), ...commonObj, } makeAccountUpdateObjectWithExpectedValues() }) describe('TxTypeFeeDelegatedAccountUpdateWithRatio', () => { let getGasPriceSpy let getHeaderSpy let getNonceSpy let getChainIdSpy beforeEach(() => { txsByAccountKeys = [] txsByAccountKeys.push(caver.transaction.feeDelegatedAccountUpdateWithRatio.create(txObjWithLegacy)) txsByAccountKeys.push(caver.transaction.feeDelegatedAccountUpdateWithRatio.create(txObjWithPublic)) txsByAccountKeys.push(caver.transaction.feeDelegatedAccountUpdateWithRatio.create(txObjWithFail)) txsByAccountKeys.push(caver.transaction.feeDelegatedAccountUpdateWithRatio.create(txObjWithMultiSig)) txsByAccountKeys.push(caver.transaction.feeDelegatedAccountUpdateWithRatio.create(txObjWithRoleBased)) getGasPriceSpy = sandbox.stub(caver.transaction.klaytnCall, 'getGasPrice') getGasPriceSpy.returns('0x5d21dba00') getHeaderSpy = sandbox.stub(caver.transaction.klaytnCall, 'getHeaderByNumber') getHeaderSpy.returns({ baseFeePerGas: '0x5d21dba00' }) getNonceSpy = sandbox.stub(caver.transaction.klaytnCall, 'getTransactionCount') getNonceSpy.returns('0x3a') getChainIdSpy = sandbox.stub(caver.transaction.klaytnCall, 'getChainId') getChainIdSpy.returns('0x7e3') }) afterEach(() => { sandbox.restore() }) context('create feeDelegatedAccountUpdateWithRatio instance', () => { it('CAVERJS-UNIT-TRANSACTIONFDR-152: If feeDelegatedAccountUpdateWithRatio not define from, return error', () => { const testUpdateObj = { ...txObjWithPublic } delete testUpdateObj.from const expectedError = '"from" is missing' expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTIONFDR-153: If feeDelegatedAccountUpdateWithRatio not define gas, return error', () => { const testUpdateObj = { ...txObjWithPublic } delete testUpdateObj.gas const expectedError = '"gas" is missing' expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTIONFDR-154: If accountUpdate not define gas, return error', () => { const testUpdateObj = { ...txObjWithPublic } delete testUpdateObj.account const expectedError = 'Missing account information with TxTypeFeeDelegatedAccountUpdateWithRatio transaction' expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTIONFDR-155: If feeDelegatedAccountUpdateWithRatio not define feeRatio, return error', () => { const testUpdateObj = { ...txObjWithPublic } delete testUpdateObj.feeRatio const expectedError = '"feeRatio" is missing' expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTIONFDR-156: If feeDelegatedAccountUpdateWithRatio define from property with invalid address, return error', () => { const testUpdateObj = { ...txObjWithPublic } testUpdateObj.from = 'invalid' const expectedError = `Invalid address of from: ${testUpdateObj.from}` expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTIONFDR-157: If feeDelegatedAccountUpdateWithRatio define feePayer property with invalid address, return error', () => { const testUpdateObj = { ...txObjWithPublic } testUpdateObj.feePayer = 'invalid' const expectedError = `Invalid address of fee payer: ${testUpdateObj.feePayer}` expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTIONFDR-521: If feeDelegatedAccountUpdateWithRatio define feeRatio property with invalid value, return error', () => { const testUpdateObj = { ...txObjWithPublic } testUpdateObj.feeRatio = 'nonHexString' let expectedError = `Invalid type fo feeRatio: feeRatio should be number type or hex number string.` expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) testUpdateObj.feeRatio = {} expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) testUpdateObj.feeRatio = [] expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) testUpdateObj.feeRatio = 0 expectedError = `Invalid feeRatio: feeRatio is out of range. [1, 99]` expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) testUpdateObj.feeRatio = 100 expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) testUpdateObj.feeRatio = -1 expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) testUpdateObj.feeRatio = 101 expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTIONFDR-158: If feeDelegatedAccountUpdateWithRatio define feePayerSignatures property without feePayer, return error', () => { const testUpdateObj = { ...txObjWithPublic } testUpdateObj.feePayer = '0x' testUpdateObj.feePayerSignatures = [ [ '0x26', '0xf45cf8d7f88c08e6b6ec0b3b562f34ca94283e4689021987abb6b0772ddfd80a', '0x298fe2c5aeabb6a518f4cbb5ff39631a5d88be505d3923374f65fdcf63c2955b', ], ] const expectedError = '"feePayer" is missing: feePayer must be defined with feePayerSignatures.' expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTIONFDR-159: If feeDelegatedAccountUpdateWithRatio define unnecessary property, return error', () => { const testUpdateObj = { ...txObjWithPublic } const unnecessaries = [ propertiesForUnnecessary.data, propertiesForUnnecessary.input, propertiesForUnnecessary.to, propertiesForUnnecessary.value, propertiesForUnnecessary.codeFormat, propertiesForUnnecessary.failKey, propertiesForUnnecessary.key, propertiesForUnnecessary.legacyKey, propertiesForUnnecessary.publicKey, propertiesForUnnecessary.failKey, propertiesForUnnecessary.multisig, propertiesForUnnecessary.roleTransactionKey, propertiesForUnnecessary.roleAccountUpdateKey, propertiesForUnnecessary.roleFeePayerKey, propertiesForUnnecessary.humanReadable, propertiesForUnnecessary.accessList, propertiesForUnnecessary.maxPriorityFeePerGas, propertiesForUnnecessary.maxFeePerGas, ] for (let i = 0; i < unnecessaries.length; i++) { if (i > 0) delete testUpdateObj[unnecessaries[i - 1].name] testUpdateObj[unnecessaries[i].name] = unnecessaries[i].value const expectedError = `"${unnecessaries[i].name}" cannot be used with ${caver.transaction.type.TxTypeFeeDelegatedAccountUpdateWithRatio} transaction` expect(() => caver.transaction.feeDelegatedAccountUpdateWithRatio.create(testUpdateObj)).to.throw(expectedError) } }) }) context('feeDelegatedAccountUpdateWithRatio.getRLPEncoding', () => { it('CAVERJS-UNIT-TRANSACTIONFDR-160: returns RLP-encoded string.', () => { for (let i = 0; i < expectedValues.length; i++) { const tx = caver.transaction.feeDelegatedAccountUpdateWithRatio.create(expectedValues[i].tx) expect(tx.getRLPEncoding()).to.equal(expectedValues[i].rlpEncoding) } }) it('CAVERJS-UNIT-TRANSACTIONFDR-161: getRLPEncoding should throw error when nonce is undefined', () => { for (let i = 0; i < expectedValues.length; i++) { const tx = caver.transaction.feeDelegatedAccountUpdateWithRatio.create(expectedValues[i].tx) delete tx._nonce const expectedError = `nonce is undefined. Define nonce in transaction or use 'transaction.fillTransaction' to fill values.` expect(() => tx.getRLPEncoding()).to.throw(expectedError) } }) it('CAVERJS-UNIT-TRANSACTIONFDR-162: getRLPEncoding should throw error when gasPrice is undefined', () => { for (let i = 0; i < expectedValues.length; i++) { const tx = caver.transaction.feeDelegatedAccountUpdateWithRatio.create(expectedValues[i].tx) delete tx._gasPrice const expectedError = `gasPrice is undefined. Define gasPrice in transaction or use 'transaction.fillTransaction' to fill values.` expect(() => tx.getRLPEncoding()).to.throw(expectedError) } }) }) context('feeDelegatedAccountUpdateWithRatio.sign', () => { const txHash = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550' const fillTransactionSpys = [] const appendSignaturesSpys = [] let createFromPrivateKeySpy let senderSignSpy let hasherSpy beforeEach(() => { for (let i = 0; i < txsByAccountKeys.length; i++) { fillTransactionSpys.push(sandbox.spy(txsByAccountKeys[i], 'fillTransaction')) appendSignaturesSpys.push(sandbox.spy(txsByAccountKeys[i], 'appendSignatures')) } createFromPrivateKeySpy = sandbox.spy(Keyring, 'createFromPrivateKey') senderSignSpy = sandbox.spy(sender, 'sign') hasherSpy = sandbox.stub(TransactionHasher, 'getHashForSignature') hasherSpy.returns(txHash) }) afterEach(() => { sandbox.restore() }) function checkFunctionCall(idx, customHasher = false) { expect(fillTransactionSpys[idx]).to.have.been.calledOnce expect(appendSignaturesSpys[idx]).to.have.been.calledOnce if (!customHasher) expect(hasherSpy).to.have.been.calledWith(txsByAccountKeys[idx]) } it('CAVERJS-UNIT-TRANSACTIONFDR-164: input: keyring. should sign transaction.', async () => { for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] await tx.sign(sender) checkFunctionCall(i) checkSignature(tx) expect(senderSignSpy).to.have.been.calledWith(txHash, '0x7e3', 1, undefined) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-165: input: private key string. should sign transaction.', async () => { const signProtoSpy = sandbox.spy(SingleKeyring.prototype, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] await tx.sign(sender.key.privateKey) checkFunctionCall(i) checkSignature(tx) expect(signProtoSpy).to.have.been.calledWith(txHash, '0x7e3', 1, undefined) } expect(createFromPrivateKeySpy).to.have.been.callCount(Object.keys(txsByAccountKeys).length) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-166: input: KlaytnWalletKey. should sign transaction.', async () => { const signProtoSpy = sandbox.spy(SingleKeyring.prototype, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] await tx.sign(sender.getKlaytnWalletKey()) checkFunctionCall(i) checkSignature(tx) expect(signProtoSpy).to.have.been.calledWith(txHash, '0x7e3', 1, undefined) } expect(createFromPrivateKeySpy).to.have.been.callCount(Object.keys(txsByAccountKeys).length) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-167: input: keyring, index. should sign transaction with specific index.', async () => { const roleBasedSignSpy = sandbox.spy(roleBasedKeyring, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.from = roleBasedKeyring.address await tx.sign(roleBasedKeyring, 1) checkFunctionCall(i) checkSignature(tx) expect(roleBasedSignSpy).to.have.been.calledWith(txHash, '0x7e3', 1, 1) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-168: input: keyring, custom hasher. should use custom hasher.', async () => { const hashForCustomHasher = '0x9e4b4835f6ea5ce55bd1037fe92040dd070af6154aefc30d32c65364a1123cae' const customHasher = () => hashForCustomHasher const roleBasedSignSpy = sandbox.spy(roleBasedKeyring, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.from = roleBasedKeyring.address await tx.sign(roleBasedKeyring, customHasher) checkFunctionCall(i, true) checkSignature(tx, { expectedLength: roleBasedKeyring.roleAccountUpdateKey.length }) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(roleBasedSignSpy).to.have.been.calledWith(hashForCustomHasher, '0x7e3', 1, undefined) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-169: input: keyring, index, custom hasher. should use custom hasher when sign transaction.', async () => { const hashForCustomHasher = '0x9e4b4835f6ea5ce55bd1037fe92040dd070af6154aefc30d32c65364a1123cae' const customHasher = () => hashForCustomHasher const roleBasedSignSpy = sandbox.spy(roleBasedKeyring, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.from = roleBasedKeyring.address await tx.sign(roleBasedKeyring, 1, customHasher) checkFunctionCall(i, true) checkSignature(tx) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(roleBasedSignSpy).to.have.been.calledWith(hashForCustomHasher, '0x7e3', 1, 1) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-170: input: keyring. should throw error when from is different.', async () => { for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.from = roleBasedKeyring.address const expectedError = `The from address of the transaction is different with the address of the keyring to use.` await expect(tx.sign(sender)).to.be.rejectedWith(expectedError) } }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-171: input: rolebased keyring, index out of range. should throw error.', async () => { for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.from = roleBasedKeyring.address const expectedError = `Invalid index(10): index must be less than the length of keys(${roleBasedKeyring.keys[0].length}).` await expect(tx.sign(roleBasedKeyring, 10)).to.be.rejectedWith(expectedError) } }) }) context('feeDelegatedAccountUpdateWithRatio.signAsFeePayer', () => { const txHash = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550' const fillTransactionSpys = [] const appendSignaturesSpys = [] let createFromPrivateKeySpy let feePayerSignSpy let hasherSpy beforeEach(() => { for (let i = 0; i < txsByAccountKeys.length; i++) { fillTransactionSpys.push(sandbox.spy(txsByAccountKeys[i], 'fillTransaction')) appendSignaturesSpys.push(sandbox.spy(txsByAccountKeys[i], 'appendFeePayerSignatures')) } createFromPrivateKeySpy = sandbox.spy(Keyring, 'createFromPrivateKey') feePayerSignSpy = sandbox.spy(feePayer, 'sign') hasherSpy = sandbox.stub(TransactionHasher, 'getHashForFeePayerSignature') hasherSpy.returns(txHash) }) afterEach(() => { sandbox.restore() }) function checkFunctionCall(idx, customHasher = false) { expect(fillTransactionSpys[idx]).to.have.been.calledOnce expect(appendSignaturesSpys[idx]).to.have.been.calledOnce if (!customHasher) expect(hasherSpy).to.have.been.calledWith(txsByAccountKeys[idx]) } it('CAVERJS-UNIT-TRANSACTIONFDR-172: input: keyring. If feePayer is not defined, should be set with keyring address.', async () => { for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.feePayer = '0x' await tx.signAsFeePayer(feePayer) expect(tx.feePayer.toLowerCase()).to.equal(feePayer.address.toLowerCase()) checkFunctionCall(i) checkFeePayerSignature(tx) expect(feePayerSignSpy).to.have.been.calledWith(txHash, '0x7e3', 2, undefined) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-173: input: keyring. should sign transaction.', async () => { for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] await tx.signAsFeePayer(feePayer) checkFunctionCall(i) checkFeePayerSignature(tx) expect(feePayerSignSpy).to.have.been.calledWith(txHash, '0x7e3', 2, undefined) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-174: input: private key string. should sign transaction.', async () => { const signProtoSpy = sandbox.spy(SingleKeyring.prototype, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] await tx.signAsFeePayer(feePayer.key.privateKey) checkFunctionCall(i) checkFeePayerSignature(tx) expect(signProtoSpy).to.have.been.calledWith(txHash, '0x7e3', 2, undefined) } expect(createFromPrivateKeySpy).to.have.been.callCount(Object.keys(txsByAccountKeys).length) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-175: input: KlaytnWalletKey. should sign transaction.', async () => { const signProtoSpy = sandbox.spy(SingleKeyring.prototype, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] await tx.signAsFeePayer(feePayer.getKlaytnWalletKey()) checkFunctionCall(i) checkFeePayerSignature(tx) expect(signProtoSpy).to.have.been.calledWith(txHash, '0x7e3', 2, undefined) } expect(createFromPrivateKeySpy).to.have.been.callCount(Object.keys(txsByAccountKeys).length) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-176: input: keyring, index. should sign transaction with specific index.', async () => { const roleBasedSignSpy = sandbox.spy(roleBasedKeyring, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.feePayer = roleBasedKeyring.address await tx.signAsFeePayer(roleBasedKeyring, 1) checkFunctionCall(i) checkFeePayerSignature(tx) expect(roleBasedSignSpy).to.have.been.calledWith(txHash, '0x7e3', 2, 1) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-177: input: keyring, custom hasher. should use custom hasher.', async () => { const hashForCustomHasher = '0x9e4b4835f6ea5ce55bd1037fe92040dd070af6154aefc30d32c65364a1123cae' const customHasher = () => hashForCustomHasher const roleBasedSignSpy = sandbox.spy(roleBasedKeyring, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.feePayer = roleBasedKeyring.address await tx.signAsFeePayer(roleBasedKeyring, customHasher) checkFunctionCall(i, true) checkFeePayerSignature(tx, { expectedLength: roleBasedKeyring.roleFeePayerKey.length }) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(roleBasedSignSpy).to.have.been.calledWith(hashForCustomHasher, '0x7e3', 2, undefined) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-178: input: keyring, index, custom hasher. should use custom hasher when sign transaction.', async () => { const hashForCustomHasher = '0x9e4b4835f6ea5ce55bd1037fe92040dd070af6154aefc30d32c65364a1123cae' const customHasher = () => hashForCustomHasher const roleBasedSignSpy = sandbox.spy(roleBasedKeyring, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.feePayer = roleBasedKeyring.address await tx.signAsFeePayer(roleBasedKeyring, 1, customHasher) checkFunctionCall(i, true) checkFeePayerSignature(tx) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(roleBasedSignSpy).to.have.been.calledWith(hashForCustomHasher, '0x7e3', 2, 1) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-179: input: keyring. should throw error when feePayer is different.', async () => { for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.feePayer = roleBasedKeyring.address const expectedError = `The feePayer address of the transaction is different with the address of the keyring to use.` await expect(tx.signAsFeePayer(sender)).to.be.rejectedWith(expectedError) } }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-180: input: rolebased keyring, index out of range. should throw error.', async () => { for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] tx.feePayer = roleBasedKeyring.address const expectedError = `Invalid index(10): index must be less than the length of keys(${roleBasedKeyring.keys[0].length}).` await expect(tx.signAsFeePayer(roleBasedKeyring, 10)).to.be.rejectedWith(expectedError) } }).timeout(200000) }) context('feeDelegatedAccountUpdateWithRatio.sign with multiple keys', () => { const txHash = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550' const fillTransactionSpys = [] const appendSignaturesSpys = [] let createFromPrivateKeySpy let senderSignWithKeysSpy let hasherSpy beforeEach(() => { for (let i = 0; i < txsByAccountKeys.length; i++) { fillTransactionSpys.push(sandbox.spy(txsByAccountKeys[i], 'fillTransaction')) appendSignaturesSpys.push(sandbox.spy(txsByAccountKeys[i], 'appendSignatures')) } createFromPrivateKeySpy = sandbox.spy(Keyring, 'createFromPrivateKey') senderSignWithKeysSpy = sandbox.spy(sender, 'sign') hasherSpy = sandbox.stub(TransactionHasher, 'getHashForSignature') hasherSpy.returns(txHash) }) afterEach(() => { sandbox.restore() }) function checkFunctionCall(idx, customHasher = false) { expect(fillTransactionSpys[idx]).to.have.been.calledOnce expect(appendSignaturesSpys[idx]).to.have.been.calledOnce if (!customHasher) expect(hasherSpy).to.have.been.calledWith(txsByAccountKeys[idx]) } it('CAVERJS-UNIT-TRANSACTIONFDR-181: input: keyring. should sign transaction.', async () => { for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] await tx.sign(sender) checkFunctionCall(i) checkSignature(tx) expect(senderSignWithKeysSpy).to.have.been.calledWith(txHash, '0x7e3', 1) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-182: input: private key string. should sign transaction.', async () => { const signProtoSpy = sandbox.spy(SingleKeyring.prototype, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] await tx.sign(sender.key.privateKey) checkFunctionCall(i) checkSignature(tx) expect(signProtoSpy).to.have.been.calledWith(txHash, '0x7e3', 1) } expect(createFromPrivateKeySpy).to.have.been.callCount(Object.keys(txsByAccountKeys).length) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-183: input: KlaytnWalletKey. should sign transaction.', async () => { const signProtoSpy = sandbox.spy(SingleKeyring.prototype, 'sign') for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] await tx.sign(sender.getKlaytnWalletKey()) checkFunctionCall(i) checkSignature(tx) expect(signProtoSpy).to.have.been.calledWith(txHash, '0x7e3', 1) } expect(createFromPrivateKeySpy).to.have.been.callCount(Object.keys(txsByAccountKeys).length) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTIONFDR-184: input: keyring, custom hasher. should use custom hasher when sign transaction.', async () => { const hashForCustomHasher = '0x9e4b4835f6ea5ce55bd1037fe92040dd070af6154aefc30d32c65364a1123cae' const customHasher = () => hashForCustomHasher for (let i = 0; i < txsByAccountKeys.length; i++) { const tx = txsByAccountKeys[i] await tx.sign(sender, customHasher) checkFunctionCall(i, true) checkSignature(tx) expect(senderSignWithKeysSpy).to.have.been.calledWith(hashForCustomHasher, '0x7e3', 1) } expect(createFromPrivateKeySpy).not.to.have.been.called }).timeout(200000) it('CAVERJS-U