UNPKG

caver-js

Version:

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

816 lines (648 loc) 48.6 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 { 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, checkSignature } = require('../utils') let caver let sender let roleBasedKeyring const sandbox = sinon.createSandbox() const byteCode = '0x60806040526000805534801561001457600080fd5b506101ea806100246000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd1461007257806342cbb15c1461009d578063767800de146100c8578063b22636271461011f578063d14e62b814610150575b600080fd5b34801561007e57600080fd5b5061008761017d565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b2610183565b6040518082815260200191505060405180910390f35b3480156100d457600080fd5b506100dd61018b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012b57600080fd5b5061014e60048036038101908080356000191690602001909291905050506101b1565b005b34801561015c57600080fd5b5061017b600480360381019080803590602001909291905050506101b4565b005b60005481565b600043905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b50565b80600081905550505600a165627a7a7230582053c65686a3571c517e2cf4f741d842e5ee6aa665c96ce70f46f9a594794f11eb0029' const txWithExpectedValues = {} before(() => { caver = new Caver(testRPCURL) sender = caver.wallet.add(caver.wallet.keyring.generate()) roleBasedKeyring = generateRoleBasedKeyring([3, 3, 3]) txWithExpectedValues.tx = { from: '0xd91aec35bea25d379e49cfe2dff5f5775cdac1a3', value: '0x0', gas: '0xdbba0', gasPrice: '0x5d21dba00', input: byteCode, chainId: '0x7e3', signatures: [ [ '0x0fe9', '0x018a9f680a74e275f1f83a5c2c45e1313c52432df4595e944240b1511a4f4ba7', '0x2d762c3417f91b81db4907db832cb28cc64df7dca3ea9be64899ab3f4812f016', ], ], humanReadable: false, codeFormat: 'EVM', nonce: '0x1f', } txWithExpectedValues.rlpEncodingForSigning = '0xf90241b90239f90236281f8505d21dba00830dbba0808094d91aec35bea25d379e49cfe2dff5f5775cdac1a3b9020e60806040526000805534801561001457600080fd5b506101ea806100246000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd1461007257806342cbb15c1461009d578063767800de146100c8578063b22636271461011f578063d14e62b814610150575b600080fd5b34801561007e57600080fd5b5061008761017d565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b2610183565b6040518082815260200191505060405180910390f35b3480156100d457600080fd5b506100dd61018b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012b57600080fd5b5061014e60048036038101908080356000191690602001909291905050506101b1565b005b34801561015c57600080fd5b5061017b600480360381019080803590602001909291905050506101b4565b005b60005481565b600043905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b50565b80600081905550505600a165627a7a7230582053c65686a3571c517e2cf4f741d842e5ee6aa665c96ce70f46f9a594794f11eb002980808207e38080' txWithExpectedValues.rlpEncodingCommon = '0xf90236281f8505d21dba00830dbba0808094d91aec35bea25d379e49cfe2dff5f5775cdac1a3b9020e60806040526000805534801561001457600080fd5b506101ea806100246000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd1461007257806342cbb15c1461009d578063767800de146100c8578063b22636271461011f578063d14e62b814610150575b600080fd5b34801561007e57600080fd5b5061008761017d565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b2610183565b6040518082815260200191505060405180910390f35b3480156100d457600080fd5b506100dd61018b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012b57600080fd5b5061014e60048036038101908080356000191690602001909291905050506101b1565b005b34801561015c57600080fd5b5061017b600480360381019080803590602001909291905050506101b4565b005b60005481565b600043905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b50565b80600081905550505600a165627a7a7230582053c65686a3571c517e2cf4f741d842e5ee6aa665c96ce70f46f9a594794f11eb00298080' txWithExpectedValues.senderTxHash = '0x523417d946221c4d12b58519580edca43662577df7e107f5ff92f115d4b3d210' txWithExpectedValues.transactionHash = '0x523417d946221c4d12b58519580edca43662577df7e107f5ff92f115d4b3d210' txWithExpectedValues.rlpEncoding = '0x28f9027e1f8505d21dba00830dbba0808094d91aec35bea25d379e49cfe2dff5f5775cdac1a3b9020e60806040526000805534801561001457600080fd5b506101ea806100246000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd1461007257806342cbb15c1461009d578063767800de146100c8578063b22636271461011f578063d14e62b814610150575b600080fd5b34801561007e57600080fd5b5061008761017d565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b2610183565b6040518082815260200191505060405180910390f35b3480156100d457600080fd5b506100dd61018b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012b57600080fd5b5061014e60048036038101908080356000191690602001909291905050506101b1565b005b34801561015c57600080fd5b5061017b600480360381019080803590602001909291905050506101b4565b005b60005481565b600043905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b50565b80600081905550505600a165627a7a7230582053c65686a3571c517e2cf4f741d842e5ee6aa665c96ce70f46f9a594794f11eb00298080f847f845820fe9a0018a9f680a74e275f1f83a5c2c45e1313c52432df4595e944240b1511a4f4ba7a02d762c3417f91b81db4907db832cb28cc64df7dca3ea9be64899ab3f4812f016' }) describe('TxTypeSmartContractDeploy', () => { let transactionObj let getGasPriceSpy let getHeaderSpy let getNonceSpy let getChainIdSpy beforeEach(() => { transactionObj = { from: sender.address, gas: '0x15f90', input: byteCode, } 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 smartContractDeploy instance', () => { it('CAVERJS-UNIT-TRANSACTION-198: If smartContractDeploy not define from, return error', () => { delete transactionObj.from const expectedError = '"from" is missing' expect(() => caver.transaction.smartContractDeploy.create(transactionObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTION-200: If smartContractDeploy not define gas, return error', () => { delete transactionObj.gas const expectedError = '"gas" is missing' expect(() => caver.transaction.smartContractDeploy.create(transactionObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTION-201: If smartContractDeploy not define input, return error', () => { delete transactionObj.input const expectedError = '"input" is missing' expect(() => caver.transaction.smartContractDeploy.create(transactionObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTION-202: If smartContractDeploy define from property with invalid address, return error', () => { transactionObj.from = 'invalid' const expectedError = `Invalid address of from: ${transactionObj.from}` expect(() => caver.transaction.smartContractDeploy.create(transactionObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTION-203: If smartContractDeploy define codeFormat property with invalid codeFormat, return error', () => { transactionObj.codeFormat = 'nonEVM' const expectedError = `The codeFormat(${transactionObj.codeFormat}) is invalid.` expect(() => caver.transaction.smartContractDeploy.create(transactionObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTION-204: If smartContractDeploy define humanReadable property with true, return error', () => { transactionObj.humanReadable = true const expectedError = `HumanReadableAddress is not supported yet.` expect(() => caver.transaction.smartContractDeploy.create(transactionObj)).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTION-205: If smartContractDeploy define unnecessary property, return error', () => { const unnecessaries = [ propertiesForUnnecessary.to, propertiesForUnnecessary.failKey, propertiesForUnnecessary.feePayer, propertiesForUnnecessary.feePayerSignatures, propertiesForUnnecessary.feeRatio, propertiesForUnnecessary.account, propertiesForUnnecessary.key, propertiesForUnnecessary.legacyKey, propertiesForUnnecessary.publicKey, propertiesForUnnecessary.failKey, propertiesForUnnecessary.multisig, propertiesForUnnecessary.roleTransactionKey, propertiesForUnnecessary.roleAccountUpdateKey, propertiesForUnnecessary.roleFeePayerKey, propertiesForUnnecessary.accessList, propertiesForUnnecessary.maxPriorityFeePerGas, propertiesForUnnecessary.maxFeePerGas, ] for (let i = 0; i < unnecessaries.length; i++) { if (i > 0) delete transactionObj[unnecessaries[i - 1].name] transactionObj[unnecessaries[i].name] = unnecessaries[i].value const expectedError = `"${unnecessaries[i].name}" cannot be used with ${caver.transaction.type.TxTypeSmartContractDeploy} transaction` expect(() => caver.transaction.smartContractDeploy.create(transactionObj)).to.throw(expectedError) } }) }) context('smartContractDeploy.getRLPEncoding', () => { it('CAVERJS-UNIT-TRANSACTION-206: Returns RLP-encoded string', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) expect(tx.getRLPEncoding()).to.equal(txWithExpectedValues.rlpEncoding) }) it('CAVERJS-UNIT-TRANSACTION-207: getRLPEncoding should throw error when nonce is undefined', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.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-TRANSACTION-208: getRLPEncoding should throw error when gasPrice is undefined', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.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('smartContractDeploy.sign', () => { const txHash = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550' let fillTransactionSpy let createFromPrivateKeySpy let senderSignSpy let appendSignaturesSpy let hasherSpy let tx beforeEach(() => { tx = caver.transaction.smartContractDeploy.create(transactionObj) fillTransactionSpy = sandbox.spy(tx, 'fillTransaction') createFromPrivateKeySpy = sandbox.spy(Keyring, 'createFromPrivateKey') senderSignSpy = sandbox.spy(sender, 'sign') appendSignaturesSpy = sandbox.spy(tx, 'appendSignatures') hasherSpy = sandbox.stub(TransactionHasher, 'getHashForSignature') hasherSpy.returns(txHash) }) afterEach(() => { sandbox.restore() }) function checkFunctionCall(customHasher = false) { expect(fillTransactionSpy).to.have.been.calledOnce expect(appendSignaturesSpy).to.have.been.calledOnce if (!customHasher) expect(hasherSpy).to.have.been.calledWith(tx) } it('CAVERJS-UNIT-TRANSACTION-210: input: keyring. should sign transaction.', async () => { await tx.sign(sender) checkFunctionCall() checkSignature(tx) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(senderSignSpy).to.have.been.calledWith(txHash, '0x7e3', 0, undefined) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-211: input: private key string. should sign transaction.', async () => { const signProtoSpy = sandbox.spy(SingleKeyring.prototype, 'sign') await tx.sign(sender.key.privateKey) checkFunctionCall() checkSignature(tx) expect(createFromPrivateKeySpy).to.have.been.calledOnce expect(signProtoSpy).to.have.been.calledWith(txHash, '0x7e3', 0, undefined) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-212: input: KlaytnWalletKey. should sign transaction.', async () => { const signProtoSpy = sandbox.spy(SingleKeyring.prototype, 'sign') await tx.sign(sender.getKlaytnWalletKey()) checkFunctionCall() checkSignature(tx) expect(createFromPrivateKeySpy).to.have.been.calledOnce expect(signProtoSpy).to.have.been.calledWith(txHash, '0x7e3', 0, undefined) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-213: input: keyring, index. should sign transaction with specific index.', async () => { const roleBasedSignSpy = sandbox.spy(roleBasedKeyring, 'sign') tx.from = roleBasedKeyring.address await tx.sign(roleBasedKeyring, 1) checkFunctionCall() checkSignature(tx) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(roleBasedSignSpy).to.have.been.calledWith(txHash, '0x7e3', 0, 1) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-214: input: keyring, custom hasher. should use custom hasher.', async () => { const hashForCustomHasher = '0x9e4b4835f6ea5ce55bd1037fe92040dd070af6154aefc30d32c65364a1123cae' const customHasher = () => hashForCustomHasher await tx.sign(sender, customHasher) checkFunctionCall(true) checkSignature(tx) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(senderSignSpy).to.have.been.calledWith(hashForCustomHasher, '0x7e3', 0, undefined) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-215: 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') tx.from = roleBasedKeyring.address await tx.sign(roleBasedKeyring, 1, customHasher) checkFunctionCall(true) checkSignature(tx) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(roleBasedSignSpy).to.have.been.calledWith(hashForCustomHasher, '0x7e3', 0, 1) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-216: input: keyring. should throw error when from is different.', async () => { transactionObj.from = roleBasedKeyring.address tx = caver.transaction.smartContractDeploy.create(transactionObj) 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-TRANSACTION-217: input: rolebased keyring, index out of range. should throw error.', async () => { transactionObj.from = roleBasedKeyring.address tx = caver.transaction.smartContractDeploy.create(transactionObj) 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) }).timeout(200000) }) context('smartContractDeploy.sign with multiple keys', () => { const txHash = '0xe9a11d9ef95fb437f75d07ce768d43e74f158dd54b106e7d3746ce29d545b550' let fillTransactionSpy let createFromPrivateKeySpy let senderSignWithKeysSpy let appendSignaturesSpy let hasherSpy let tx beforeEach(() => { tx = caver.transaction.smartContractDeploy.create(transactionObj) fillTransactionSpy = sandbox.spy(tx, 'fillTransaction') createFromPrivateKeySpy = sandbox.spy(Keyring, 'createFromPrivateKey') senderSignWithKeysSpy = sandbox.spy(sender, 'sign') appendSignaturesSpy = sandbox.spy(tx, 'appendSignatures') hasherSpy = sandbox.stub(TransactionHasher, 'getHashForSignature') hasherSpy.returns(txHash) }) afterEach(() => { sandbox.restore() }) function checkFunctionCall(customHasher = false) { expect(fillTransactionSpy).to.have.been.calledOnce expect(appendSignaturesSpy).to.have.been.calledOnce if (!customHasher) expect(hasherSpy).to.have.been.calledWith(tx) } it('CAVERJS-UNIT-TRANSACTION-218: input: keyring. should sign transaction.', async () => { await tx.sign(sender) checkFunctionCall() checkSignature(tx) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(senderSignWithKeysSpy).to.have.been.calledWith(txHash, '0x7e3', 0) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-219: input: private key string. should sign transaction.', async () => { const signProtoSpy = sandbox.spy(SingleKeyring.prototype, 'sign') await tx.sign(sender.key.privateKey) checkFunctionCall() checkSignature(tx) expect(createFromPrivateKeySpy).to.have.been.calledOnce expect(signProtoSpy).to.have.been.calledWith(txHash, '0x7e3', 0) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-220: input: KlaytnWalletKey. should sign transaction.', async () => { const signProtoSpy = sandbox.spy(SingleKeyring.prototype, 'sign') await tx.sign(sender.getKlaytnWalletKey()) checkFunctionCall() checkSignature(tx) expect(createFromPrivateKeySpy).to.have.been.calledOnce expect(signProtoSpy).to.have.been.calledWith(txHash, '0x7e3', 0) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-221: input: keyring, custom hasher. should use custom hasher when sign transaction.', async () => { const hashForCustomHasher = '0x9e4b4835f6ea5ce55bd1037fe92040dd070af6154aefc30d32c65364a1123cae' const customHasher = () => hashForCustomHasher await tx.sign(sender, customHasher) checkFunctionCall(true) checkSignature(tx) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(senderSignWithKeysSpy).to.have.been.calledWith(hashForCustomHasher, '0x7e3', 0) }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-222: input: keyring. should throw error when from is different.', async () => { transactionObj.from = roleBasedKeyring.address tx = caver.transaction.smartContractDeploy.create(transactionObj) 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-TRANSACTION-223: input: roleBased keyring. should sign with multiple keys and append signatures', async () => { const roleBasedSignWithKeysSpy = sandbox.spy(roleBasedKeyring, 'sign') tx.from = roleBasedKeyring.address await tx.sign(roleBasedKeyring) checkFunctionCall(true) checkSignature(tx, { expectedLength: roleBasedKeyring.keys[0].length }) expect(createFromPrivateKeySpy).not.to.have.been.calledOnce expect(roleBasedSignWithKeysSpy).to.have.been.calledWith(txHash, '0x7e3', 0) }).timeout(200000) }) context('smartContractDeploy.appendSignatures', () => { afterEach(() => { sandbox.restore() }) it('CAVERJS-UNIT-TRANSACTION-224: If signatures is empty, appendSignatures append signatures in transaction', () => { const tx = caver.transaction.smartContractDeploy.create(transactionObj) const sig = [ '0x0fea', '0xade9480f584fe481bf070ab758ecc010afa15debc33e1bd75af637d834073a6e', '0x38160105d78cef4529d765941ad6637d8dcf6bd99310e165fee1c39fff2aa27e', ] tx.appendSignatures(sig) checkSignature(tx) }) it('CAVERJS-UNIT-TRANSACTION-225: If signatures is empty, appendSignatures append signatures with two-dimensional signature array', () => { const tx = caver.transaction.smartContractDeploy.create(transactionObj) const sig = [ [ '0x0fea', '0xade9480f584fe481bf070ab758ecc010afa15debc33e1bd75af637d834073a6e', '0x38160105d78cef4529d765941ad6637d8dcf6bd99310e165fee1c39fff2aa27e', ], ] tx.appendSignatures(sig) checkSignature(tx) }) it('CAVERJS-UNIT-TRANSACTION-226: If signatures is not empty, appendSignatures should append signatures', () => { transactionObj.signatures = [ '0x0fea', '0xade9480f584fe481bf070ab758ecc010afa15debc33e1bd75af637d834073a6e', '0x38160105d78cef4529d765941ad6637d8dcf6bd99310e165fee1c39fff2aa27e', ] const tx = caver.transaction.smartContractDeploy.create(transactionObj) const sig = [ '0x0fea', '0x7a5011b41cfcb6270af1b5f8aeac8aeabb1edb436f028261b5add564de694700', '0x23ac51660b8b421bf732ef8148d0d4f19d5e29cb97be6bccb5ae505ebe89eb4a', ] tx.appendSignatures(sig) checkSignature(tx, { expectedLength: 2 }) }) it('CAVERJS-UNIT-TRANSACTION-227: appendSignatures should append multiple signatures', () => { const tx = caver.transaction.smartContractDeploy.create(transactionObj) const sig = [ [ '0x0fea', '0xbde66cceed35a576010966338b7ded961f2c160c96f928e193b47aaf4480aa07', '0x546eb193ec138523b7fd34c4f12a1a04d0f74470e8f3bbe91ce0b4ec16e7f0d2', ], [ '0x0fea', '0xade9480f584fe481bf070ab758ecc010afa15debc33e1bd75af637d834073a6e', '0x38160105d78cef4529d765941ad6637d8dcf6bd99310e165fee1c39fff2aa27e', ], ] tx.appendSignatures(sig) checkSignature(tx, { expectedLength: 2 }) }) }) context('smartContractDeploy.combineSignedRawTransactions', () => { beforeEach(() => { transactionObj = { from: '0x47a4caa81fe2ed8cc834aafe5b1d7ee3ddedecfa', value: 0, gas: 900000, input: byteCode, gasPrice: '0x5d21dba00', chainId: 2019, codeFormat: 'EVM', humanReadable: false, nonce: '0x1', } }) afterEach(() => { sandbox.restore() }) it('CAVERJS-UNIT-TRANSACTION-228: combineSignedRawTransactions combines single signature and sets signatures in transaction', () => { const tx = caver.transaction.smartContractDeploy.create(transactionObj) const appendSignaturesSpy = sandbox.spy(tx, 'appendSignatures') const getRLPEncodingSpy = sandbox.spy(tx, 'getRLPEncoding') const rlpEncoded = '0x28f9027e018505d21dba00830dbba080809447a4caa81fe2ed8cc834aafe5b1d7ee3ddedecfab9020e60806040526000805534801561001457600080fd5b506101ea806100246000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd1461007257806342cbb15c1461009d578063767800de146100c8578063b22636271461011f578063d14e62b814610150575b600080fd5b34801561007e57600080fd5b5061008761017d565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b2610183565b6040518082815260200191505060405180910390f35b3480156100d457600080fd5b506100dd61018b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012b57600080fd5b5061014e60048036038101908080356000191690602001909291905050506101b1565b005b34801561015c57600080fd5b5061017b600480360381019080803590602001909291905050506101b4565b005b60005481565b600043905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b50565b80600081905550505600a165627a7a7230582053c65686a3571c517e2cf4f741d842e5ee6aa665c96ce70f46f9a594794f11eb00298080f847f845820fe9a04fbefaf9da3be278403c0b69861747a4f2f530958c5f3da0b7fed8898aa02a9da010b441518b74b9cb15d86403a4c59a562a4669bc9c878d77276f0205304c3d85' const combined = tx.combineSignedRawTransactions([rlpEncoded]) const expectedSignatures = [ [ '0x0fe9', '0x4fbefaf9da3be278403c0b69861747a4f2f530958c5f3da0b7fed8898aa02a9d', '0x10b441518b74b9cb15d86403a4c59a562a4669bc9c878d77276f0205304c3d85', ], ] expect(appendSignaturesSpy).to.have.been.calledOnce expect(getRLPEncodingSpy).to.have.been.calledOnce expect(combined).to.equal(rlpEncoded) checkSignature(tx, { expectedSignatures }) }) it('CAVERJS-UNIT-TRANSACTION-229: combineSignedRawTransactions combines multiple signatures and sets signatures in transaction', () => { transactionObj.signatures = [ [ '0x0fe9', '0x4fbefaf9da3be278403c0b69861747a4f2f530958c5f3da0b7fed8898aa02a9d', '0x10b441518b74b9cb15d86403a4c59a562a4669bc9c878d77276f0205304c3d85', ], ] const tx = caver.transaction.smartContractDeploy.create(transactionObj) const rlpEncodedStrings = [ '0x28f9027e018505d21dba00830dbba080809447a4caa81fe2ed8cc834aafe5b1d7ee3ddedecfab9020e60806040526000805534801561001457600080fd5b506101ea806100246000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd1461007257806342cbb15c1461009d578063767800de146100c8578063b22636271461011f578063d14e62b814610150575b600080fd5b34801561007e57600080fd5b5061008761017d565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b2610183565b6040518082815260200191505060405180910390f35b3480156100d457600080fd5b506100dd61018b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012b57600080fd5b5061014e60048036038101908080356000191690602001909291905050506101b1565b005b34801561015c57600080fd5b5061017b600480360381019080803590602001909291905050506101b4565b005b60005481565b600043905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b50565b80600081905550505600a165627a7a7230582053c65686a3571c517e2cf4f741d842e5ee6aa665c96ce70f46f9a594794f11eb00298080f847f845820fe9a06f59d699a5dd22a653b0ed1e39cbfc52ee468607eec95b195f302680ed7f9815a03b2f3f2a7a9482edfbcc9ee8e003e284b6c4a7ecbc8d361cc486562d4bdda389', '0x28f9027e018505d21dba00830dbba080809447a4caa81fe2ed8cc834aafe5b1d7ee3ddedecfab9020e60806040526000805534801561001457600080fd5b506101ea806100246000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd1461007257806342cbb15c1461009d578063767800de146100c8578063b22636271461011f578063d14e62b814610150575b600080fd5b34801561007e57600080fd5b5061008761017d565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b2610183565b6040518082815260200191505060405180910390f35b3480156100d457600080fd5b506100dd61018b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012b57600080fd5b5061014e60048036038101908080356000191690602001909291905050506101b1565b005b34801561015c57600080fd5b5061017b600480360381019080803590602001909291905050506101b4565b005b60005481565b600043905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b50565b80600081905550505600a165627a7a7230582053c65686a3571c517e2cf4f741d842e5ee6aa665c96ce70f46f9a594794f11eb00298080f847f845820feaa04a76af831891d1050d1a0c8e7656b4ab1952ef6a1059bff994edb29a6936a909a06affc6457e9c553c5efb138a7a56dbcbed681a5bae2dceff02848341a61ab9c4', ] const appendSignaturesSpy = sandbox.spy(tx, 'appendSignatures') const getRLPEncodingSpy = sandbox.spy(tx, 'getRLPEncoding') const combined = tx.combineSignedRawTransactions(rlpEncodedStrings) const expectedRLPEncoded = '0x28f9030c018505d21dba00830dbba080809447a4caa81fe2ed8cc834aafe5b1d7ee3ddedecfab9020e60806040526000805534801561001457600080fd5b506101ea806100246000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd1461007257806342cbb15c1461009d578063767800de146100c8578063b22636271461011f578063d14e62b814610150575b600080fd5b34801561007e57600080fd5b5061008761017d565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b2610183565b6040518082815260200191505060405180910390f35b3480156100d457600080fd5b506100dd61018b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012b57600080fd5b5061014e60048036038101908080356000191690602001909291905050506101b1565b005b34801561015c57600080fd5b5061017b600480360381019080803590602001909291905050506101b4565b005b60005481565b600043905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b50565b80600081905550505600a165627a7a7230582053c65686a3571c517e2cf4f741d842e5ee6aa665c96ce70f46f9a594794f11eb00298080f8d5f845820fe9a04fbefaf9da3be278403c0b69861747a4f2f530958c5f3da0b7fed8898aa02a9da010b441518b74b9cb15d86403a4c59a562a4669bc9c878d77276f0205304c3d85f845820fe9a06f59d699a5dd22a653b0ed1e39cbfc52ee468607eec95b195f302680ed7f9815a03b2f3f2a7a9482edfbcc9ee8e003e284b6c4a7ecbc8d361cc486562d4bdda389f845820feaa04a76af831891d1050d1a0c8e7656b4ab1952ef6a1059bff994edb29a6936a909a06affc6457e9c553c5efb138a7a56dbcbed681a5bae2dceff02848341a61ab9c4' const expectedSignatures = [ [ '0x0fe9', '0x4fbefaf9da3be278403c0b69861747a4f2f530958c5f3da0b7fed8898aa02a9d', '0x10b441518b74b9cb15d86403a4c59a562a4669bc9c878d77276f0205304c3d85', ], [ '0x0fe9', '0x6f59d699a5dd22a653b0ed1e39cbfc52ee468607eec95b195f302680ed7f9815', '0x3b2f3f2a7a9482edfbcc9ee8e003e284b6c4a7ecbc8d361cc486562d4bdda389', ], [ '0x0fea', '0x4a76af831891d1050d1a0c8e7656b4ab1952ef6a1059bff994edb29a6936a909', '0x6affc6457e9c553c5efb138a7a56dbcbed681a5bae2dceff02848341a61ab9c4', ], ] expect(appendSignaturesSpy).to.have.been.callCount(rlpEncodedStrings.length) expect(getRLPEncodingSpy).to.have.been.calledOnce expect(combined).to.equal(expectedRLPEncoded) checkSignature(tx, { expectedSignatures }) }) it('CAVERJS-UNIT-TRANSACTION-230: If decode transaction has different values, combineSignedRawTransactions should throw error', () => { const tx = caver.transaction.smartContractDeploy.create(transactionObj) tx.value = 10000 const rlpEncoded = '0x28f9027e018505d21dba00830dbba080809447a4caa81fe2ed8cc834aafe5b1d7ee3ddedecfab9020e60806040526000805534801561001457600080fd5b506101ea806100246000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd1461007257806342cbb15c1461009d578063767800de146100c8578063b22636271461011f578063d14e62b814610150575b600080fd5b34801561007e57600080fd5b5061008761017d565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b2610183565b6040518082815260200191505060405180910390f35b3480156100d457600080fd5b506100dd61018b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012b57600080fd5b5061014e60048036038101908080356000191690602001909291905050506101b1565b005b34801561015c57600080fd5b5061017b600480360381019080803590602001909291905050506101b4565b005b60005481565b600043905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b50565b80600081905550505600a165627a7a7230582053c65686a3571c517e2cf4f741d842e5ee6aa665c96ce70f46f9a594794f11eb00298080f847f845820fe9a06f59d699a5dd22a653b0ed1e39cbfc52ee468607eec95b195f302680ed7f9815a03b2f3f2a7a9482edfbcc9ee8e003e284b6c4a7ecbc8d361cc486562d4bdda389' const expectedError = `Transactions containing different information cannot be combined.` expect(() => tx.combineSignedRawTransactions([rlpEncoded])).to.throw(expectedError) }) }) context('smartContractDeploy.getRawTransaction', () => { afterEach(() => { sandbox.restore() }) it('CAVERJS-UNIT-TRANSACTION-231: getRawTransaction should call getRLPEncoding function', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) const getRLPEncodingSpy = sandbox.spy(tx, 'getRLPEncoding') const expected = txWithExpectedValues.rlpEncoding const rawTransaction = tx.getRawTransaction() expect(getRLPEncodingSpy).to.have.been.calledOnce expect(rawTransaction).to.equal(expected) }) }) context('smartContractDeploy.getTransactionHash', () => { afterEach(() => { sandbox.restore() }) it('CAVERJS-UNIT-TRANSACTION-232: getTransactionHash should call getRLPEncoding function and return hash of RLPEncoding', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) const getRLPEncodingSpy = sandbox.spy(tx, 'getRLPEncoding') const expected = txWithExpectedValues.transactionHash const txHash = tx.getTransactionHash() expect(getRLPEncodingSpy).to.have.been.calledOnce expect(txHash).to.equal(expected) expect(caver.utils.isValidHashStrict(txHash)).to.be.true }) it('CAVERJS-UNIT-TRANSACTION-233: getTransactionHash should throw error when nonce is undefined', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) delete tx._nonce const expectedError = `nonce is undefined. Define nonce in transaction or use 'transaction.fillTransaction' to fill values.` expect(() => tx.getTransactionHash()).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTION-234: getTransactionHash should throw error when gasPrice is undefined', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) delete tx._gasPrice const expectedError = `gasPrice is undefined. Define gasPrice in transaction or use 'transaction.fillTransaction' to fill values.` expect(() => tx.getTransactionHash()).to.throw(expectedError) }) }) context('smartContractDeploy.getSenderTxHash', () => { afterEach(() => { sandbox.restore() }) it('CAVERJS-UNIT-TRANSACTION-236: getSenderTxHash should call getRLPEncoding function and return hash of RLPEncoding', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) const getRLPEncodingSpy = sandbox.spy(tx, 'getRLPEncoding') const expected = txWithExpectedValues.senderTxHash const senderTxHash = tx.getSenderTxHash() expect(getRLPEncodingSpy).to.have.been.calledOnce expect(senderTxHash).to.equal(expected) expect(caver.utils.isValidHashStrict(senderTxHash)).to.be.true }) it('CAVERJS-UNIT-TRANSACTION-237: getSenderTxHash should throw error when nonce is undefined', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) delete tx._nonce const expectedError = `nonce is undefined. Define nonce in transaction or use 'transaction.fillTransaction' to fill values.` expect(() => tx.getSenderTxHash()).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTION-238: getSenderTxHash should throw error when gasPrice is undefined', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) delete tx._gasPrice const expectedError = `gasPrice is undefined. Define gasPrice in transaction or use 'transaction.fillTransaction' to fill values.` expect(() => tx.getSenderTxHash()).to.throw(expectedError) }) }) context('smartContractDeploy.getRLPEncodingForSignature', () => { afterEach(() => { sandbox.restore() }) it('CAVERJS-UNIT-TRANSACTION-240: getRLPEncodingForSignature should return RLP-encoded transaction string for signing', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) const commonRLPForSigningSpy = sandbox.spy(tx, 'getCommonRLPEncodingForSignature') const expected = txWithExpectedValues.rlpEncodingForSigning const rlpEncodingForSign = tx.getRLPEncodingForSignature() expect(rlpEncodingForSign).to.equal(expected) expect(commonRLPForSigningSpy).to.have.been.calledOnce }) it('CAVERJS-UNIT-TRANSACTION-241: getRLPEncodingForSignature should throw error when nonce is undefined', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) delete tx._nonce const expectedError = `nonce is undefined. Define nonce in transaction or use 'transaction.fillTransaction' to fill values.` expect(() => tx.getRLPEncodingForSignature()).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTION-242: getRLPEncodingForSignature should throw error when gasPrice is undefined', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) delete tx._gasPrice const expectedError = `gasPrice is undefined. Define gasPrice in transaction or use 'transaction.fillTransaction' to fill values.` expect(() => tx.getRLPEncodingForSignature()).to.throw(expectedError) }) it('CAVERJS-UNIT-TRANSACTION-243: getRLPEncodingForSignature should throw error when chainId is undefined', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) delete tx._chainId const expectedError = `chainId is undefined. Define chainId in transaction or use 'transaction.fillTransaction' to fill values.` expect(() => tx.getRLPEncodingForSignature()).to.throw(expectedError) }) }) context('smartContractDeploy.getCommonRLPEncodingForSignature', () => { it('CAVERJS-UNIT-TRANSACTION-244: getRLPEncodingForSignature should return RLP-encoded transaction string for signing', () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) const commonRLPForSign = tx.getCommonRLPEncodingForSignature() expect(commonRLPForSign).to.equal(txWithExpectedValues.rlpEncodingCommon) }) }) context('smartContractDeploy.fillTransaction', () => { it('CAVERJS-UNIT-TRANSACTION-245: fillTransaction should call klay_getGasPrice to fill gasPrice when gasPrice is undefined', async () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) delete tx._gasPrice await tx.fillTransaction() expect(getGasPriceSpy).to.have.been.calledOnce expect(getHeaderSpy).not.to.have.been.calledOnce expect(getNonceSpy).not.to.have.been.calledOnce expect(getChainIdSpy).not.to.have.been.calledOnce }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-246: fillTransaction should call klay_getTransactionCount to fill nonce when nonce is undefined', async () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) delete tx._nonce await tx.fillTransaction() expect(getGasPriceSpy).not.to.have.been.calledOnce expect(getHeaderSpy).not.to.have.been.calledOnce expect(getNonceSpy).to.have.been.calledOnce expect(getChainIdSpy).not.to.have.been.calledOnce }).timeout(200000) it('CAVERJS-UNIT-TRANSACTION-247: fillTransaction should call klay_getChainid to fill chainId when chainId is undefined', async () => { const tx = caver.transaction.smartContractDeploy.create(txWithExpectedValues.tx) delete tx._chainId await tx.fillTransaction() expect(getGasPriceSpy).not.to.have.been.calledOnce expect(getHeaderSpy).not.to.have.been.calledOnce expect(getNonceSpy).not.to.have.been.calledOnce expect(getChainIdSpy).to.have.been.calledOnce }).timeout(200000) }) context('smartContractDeploy.recoverPublicKeys', () => { const expectedPublicKeyArray = [ '0x8bb6aaeb2d96d024754d3b50babf116cece68977acbe8ba6a66f14d5217c60d96af020a0568661e7c72e753e80efe084a3aed9f9ac87bf44d09ce67aad3d4e01', '0xc7751c794337a93e4db041fb5401c2c816cf0a099d8fd4b1f3f555aab5dfead2417521bb0c03d8637f350df15ef6a6cb3cdb806bd9d10bc71982dd03ff5d9ddd', '0x3919091ba17c106dd034af508cfe00b963d173dffab2c7702890e25a96d107ca1bb4f148ee1984751e57d2435468558193ce84ab9a7731b842e9672e40dc0f22', ] it('CAVERJS-UNIT-TRANSACTION-425: should return public key string recovered from signatures in SmartContractDeploy', async () => { const tx = caver.transaction.smartContractDeploy.create({ from: '0xf21460730845e3652aa3cc9bc13b345e4f53984a', value: '0x1', chainId: '0x7e3', gasPrice: '0x5d21dba00', nonce: '0x0', gas: '0x2faf080', input: '0x60806040526000805534801561001457600080fd5b506101ea806100246000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd1461007257806342cbb15c1461009d578063767800de146100c8578063b22636271461011f578063d14e62b814610150575b600080fd5b34801561007e57600080fd5b5061008761017d565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b2610183565b6040518082815260200191505060405180910390f35b3480156100d457600080fd5b506100dd61018b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012b57600080fd5b5061014e60048036038101908080356000191690602001909291905050506101b1565b005b34801561015c57600080fd5b5061017b600480360381019080803590602001909291905050506101b4565b005b60005481565b600043905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b50565b80600081905550505600a165627a7a7230582053c65686a3571c517e2cf4f741d842e5ee6aa665c96ce70f46f9a594794f11eb0029', signatures: [ [ '0x0fe9', '0xfeebbc3a1f22a6ee05ec661f2e25136c1f21923bf9208ee2b271884cf78d88d4', '0x391afac91aa0353cbab0701d412e520e7c1adba4d3283cc0dd4ea6a30f5df698', ], [ '0x0fe9', '0xddef5cd655e17979ce2252c30a54d385b34d81bfa636ab269c3d998026bbe9ac', '0x5aa38b9ebca9840fd195e6d5ff6200e66c8cd5e455ccab4d90c84a34bf51851a', ], [ '0x0fea', '0x9dd8f9110795b3fda8e924054e9d928e8b00bdf4c51fce70ac3981b231463003', '0x596f184a3fbead7bfa362cc2ca4d932ce2fc622a70e02beddac1c7a394b26e27', ], ], }) const publicKeys = tx.recoverPublicKeys() expect(publicKeys.length).to.equal(expectedPublicKeyArray.length) for (let i = 0; i < publicKeys.length; i++) { expect(publicKeys[i].toLowerCase()).to.equal(expectedPublicKeyArray[i].toLowerCase()) } }).timeout(200000) }) })