diff --git a/lib/web3/errors.js b/lib/web3/errors.js index 72a63a5..09bd899 100644 --- a/lib/web3/errors.js +++ b/lib/web3/errors.js @@ -21,8 +21,11 @@ */ module.exports = { - InvalidNumberOfParams: function () { - return new Error('Invalid number of input parameters'); + InvalidNumberOfSolidityArgs: function () { + return new Error('Invalid number of arguments to Solidity function'); + }, + InvalidNumberOfRPCParams: function () { + return new Error('Invalid number of input parameters to RPC method'); }, InvalidConnection: function (host){ return new Error('CONNECTION ERROR: Couldn\'t connect to node '+ host +'.'); diff --git a/lib/web3/function.js b/lib/web3/function.js index 6069886..a480c86 100644 --- a/lib/web3/function.js +++ b/lib/web3/function.js @@ -22,6 +22,7 @@ var coder = require('../solidity/coder'); var utils = require('../utils/utils'); +var errors = require('./errors'); var formatters = require('./formatters'); var sha3 = require('../utils/sha3'); @@ -54,6 +55,23 @@ SolidityFunction.prototype.extractDefaultBlock = function (args) { } }; +/** + * Should be called to check if the number of arguments is correct + * + * @method validateArgs + * @param {Array} arguments + * @throws {Error} if it is not + */ +SolidityFunction.prototype.validateArgs = function (args) { + var inputArgs = args.filter(function (a) { + // filter the options object but not arguments that are arrays + return !(utils.isObject(a) === true && utils.isArray(a) === false); + }); + if (inputArgs.length !== this._inputTypes.length) { + throw errors.InvalidNumberOfSolidityArgs(); + } +}; + /** * Should be used to create payload from arguments * @@ -66,6 +84,7 @@ SolidityFunction.prototype.toPayload = function (args) { if (args.length > this._inputTypes.length && utils.isObject(args[args.length -1])) { options = args[args.length - 1]; } + this.validateArgs(args); options.to = this._address; options.data = '0x' + this.signature() + coder.encodeParams(this._inputTypes, args); return options; @@ -259,4 +278,3 @@ SolidityFunction.prototype.attachToContract = function (contract) { }; module.exports = SolidityFunction; - diff --git a/lib/web3/method.js b/lib/web3/method.js index ebedd02..2e3c796 100644 --- a/lib/web3/method.js +++ b/lib/web3/method.js @@ -69,7 +69,7 @@ Method.prototype.extractCallback = function (args) { */ Method.prototype.validateArgs = function (args) { if (args.length !== this.params) { - throw errors.InvalidNumberOfParams(); + throw errors.InvalidNumberOfRPCParams(); } }; @@ -162,4 +162,3 @@ Method.prototype.request = function () { }; module.exports = Method; - diff --git a/test/contract.js b/test/contract.js index f392dc2..a7e7247 100644 --- a/test/contract.js +++ b/test/contract.js @@ -4,6 +4,7 @@ var Web3 = require('../index'); var FakeHttpProvider = require('./helpers/FakeHttpProvider'); var FakeHttpProvider2 = require('./helpers/FakeHttpProvider2'); var utils = require('../lib/utils/utils'); +var errors = require('../lib/web3/errors'); var BigNumber = require('bignumber.js'); var sha3 = require('../lib/utils/sha3'); @@ -353,6 +354,31 @@ describe('contract', function () { }); + it('should throw if called with optional params without all args', function () { + var provider = new FakeHttpProvider(); + var web3 = new Web3(provider); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); + var signature = 'balance(address)'; + var address = '0x1234567890123456789012345678901234567891'; + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567891', + to: address, + from: address, + gas: '0xc350' + }, 'latest']); + }); + + var contract = web3.eth.contract(desc).at(address); + + var test = function() { + var r = contract.balance({from: address, gas: 50000}); + } + assert.throws(test, errors.InvalidNumberOfSolidityArgs().message); + + }); + it('should explicitly make a call with optional params', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); @@ -399,6 +425,35 @@ describe('contract', function () { }); + it('it should throw if sendTransaction with optional params without all args', function () { + var provider = new FakeHttpProvider(); + var web3 = new Web3(provider); + var signature = 'send(address,uint256)'; + var address = '0x1234567890123456789012345678901234567891'; + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_sendTransaction'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + + '0000000000000000000000001234567890123456789012345678901234567891' + + '0000000000000000000000000000000000000000000000000000000000000011' , + to: address, + from: address, + gas: '0xc350', + gasPrice: '0xbb8', + value: '0x2710' + }]); + }); + + var contract = web3.eth.contract(desc).at(address); + + var test = function() { + contract.send(address, {from: address, gas: 50000, gasPrice: 3000, value: 10000}); + } + + assert.throws(test, errors.InvalidNumberOfSolidityArgs().message); + + }); + it('should sendTransaction with optional params', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); @@ -557,4 +612,3 @@ describe('contract', function () { }); }); }); - diff --git a/test/method.validateArgs.js b/test/method.validateArgs.js index cd4882c..d3d72a0 100644 --- a/test/method.validateArgs.js +++ b/test/method.validateArgs.js @@ -39,9 +39,8 @@ describe('lib/web3/method', function () { var test2 = function () { method.validateArgs(args2); }; // then - assert.throws(test, errors.InvalidNumberOfParams().message); - assert.throws(test2, errors.InvalidNumberOfParams().message); + assert.throws(test, errors.InvalidNumberOfRPCParams().message); + assert.throws(test2, errors.InvalidNumberOfRPCParams().message); }); }); }); -