diff --git a/docs/web3-eth-contract.rst b/docs/web3-eth-contract.rst index 99688de..3fb9964 100644 --- a/docs/web3-eth-contract.rst +++ b/docs/web3-eth-contract.rst @@ -10,16 +10,18 @@ and web3 will auto convert all calls into low level ABI calls over RPC for you. This allows you to interact with smart contracts as if they were JavaScript objects. + ------------------------------------------------------------------------------ -contract -===================== + +new contract +========= .. index:: json interface .. code-block:: javascript - web3.eth.contract(jsonInterface[, address][, options]) + new web3.eth.contract(jsonInterface[, address][, options]) Creates a new contract instance with all its methods and events defined in its :ref:`json interface ` object. @@ -27,9 +29,9 @@ Creates a new contract instance with all its methods and events defined in its : Parameters ---------- -``Object`` - jsonInterface: The json interface for the contract to instantiate -``String`` - address (optional): The address of the smart contract to call, can be added later using `myContract.address = '0x1234..'` -``Object`` - options (optional): The fallback options used for calls and transactions made to this contract. +1. ``Object`` - jsonInterface: The json interface for the contract to instantiate +2. ``String`` - address (optional): The address of the smart contract to call, can be added later using `myContract.address = '0x1234..'` +3. ``Object`` - options (optional): The fallback options used for calls and transactions made to this contract. * ``String`` - from: The address transactions should be made from. * ``String`` - gasPrice: The gas price in wei to use for transactions. * ``Number`` - gas: The maximum gas provided for a transaction (gas limit). @@ -40,6 +42,7 @@ Returns ``Object``: The contract instance with all its methods and events. + ------- Example ------- @@ -53,3 +56,129 @@ Example ------------------------------------------------------------------------------ + + +Contract Properties +========= + + +------------------------------------------------------------------------------ + +options +========= + +.. code-block:: javascript + + myContract.options + +The options ``object`` for the contract instance. Contains mostly values which will be used as fallback values for sending transactions. + +------- +Property +------- + +``Object`` - options: + +- ``String`` - from: The address transactions should be made from. +- ``String`` - gasPrice: The gas price in wei to use for transactions. +- ``Number`` - gas: The maximum gas provided for a transaction (gas limit). + + +------- +Example +------- + +.. code-block:: javascript + + myContract.options; + > { + from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe', + gasPrice: '10000000000000' + } + + myContract.options.from = '0x1234...'; // default from address + myContract.options.gasPrice = '20000000000000'; // default gas price in wei + myContract.options.gas = 5000000; // provide as fallback always 5M gas + + +------------------------------------------------------------------------------ + + +address +========= + +.. code-block:: javascript + + myContract.address + +The address used for this contract instance. +All transactions generated by web3.js from this contract will contain this address as the "to". + +The address will be stored in lowercase. + + +------- +Property +------- + +``String|null`` - address: The address for this contract, or ``null`` if its not yet set. + + +------- +Example +------- + +.. code-block:: javascript + + myContract.address; + > '0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae' + + myContract.address = '0x1234FFDD...'; + + +------------------------------------------------------------------------------ + + +jsonInterface +========= + +.. code-block:: javascript + + myContract.jsonInterface + +The :ref:`json interface ` object derived from the `ABI `_ of this contract. + + +------- +Property +------- + +``Array`` - jsonInterface: The :ref:`json interface ` for this contract. Re-setting this will regenerate the methods and events of the contract instance. + + +------- +Example +------- + +.. code-block:: javascript + + myContract.jsonInterface; + > [{ + "type":"function", + "name":"foo", + "inputs": [{"name":"a","type":"uint256"}], + "outputs": [{"name":"b","type":"address"}] + },{ + "type":"event", + "name":"Event" + "inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}], + }] + + myContract.jsonInterface = [...]; + + +------------------------------------------------------------------------------ + + +Contract Methods +========= diff --git a/docs/web3-eth.rst b/docs/web3-eth.rst index e1ed400..e3776d9 100644 --- a/docs/web3-eth.rst +++ b/docs/web3-eth.rst @@ -19,7 +19,7 @@ When called changes the current provider for all modules. Parameters ---------- -``Object`` - myProvider : a valid provider with at least ``send``, ``on`` function +1. ``Object`` - myProvider : a valid provider with at least ``send``, ``on`` function ------- Returns diff --git a/docs/web3-utils.rst b/docs/web3-utils.rst index b40982d..40681a2 100644 --- a/docs/web3-utils.rst +++ b/docs/web3-utils.rst @@ -20,7 +20,7 @@ When called changes the current provider for all modules. Parameters ---------- -``Object`` - myProvider : a valid provider with at least ``send``, ``on`` function +1. ``Object`` - myProvider : a valid provider with at least ``send``, ``on`` function ------- Returns diff --git a/lib/web3/contract.js b/lib/web3/contract.js index 1ed9936..c9ed196 100644 --- a/lib/web3/contract.js +++ b/lib/web3/contract.js @@ -81,8 +81,17 @@ var Contract = function(jsonInterface, address, options) { // add method and event signatures, when the jsonInterface gets set Object.defineProperty(this, 'jsonInterface', { set: function(value){ + _this.methods = {}; + _this.events = {}; + _this._jsonInterface = value.map(function(method) { - var func; + var func, + funcName, + inputs = method.inputs ? method.inputs.map(function(key){ return key.type; }).join(',') : ''; + + if(method.name) + funcName = method.name +'('+ inputs +')'; + // constructor if (method.type === 'constructor') { @@ -94,7 +103,7 @@ var Contract = function(jsonInterface, address, options) { // add constructor _this.methods.constructor = func; - _this.constructor = func; + // _this.constructor = func; // function } else if (method.type === 'function') { @@ -112,14 +121,18 @@ var Contract = function(jsonInterface, address, options) { // definitely add the method based on its signature _this.methods[method.signature] = func; - // also add to the main contract object - if(!_this[method.name] || _this[method.name].name === 'bound _createTxObject') - _this[method.name] = _this.methods[method.name]; - _this[method.signature] = _this.methods[method.signature]; + // add method by name + _this.methods[funcName] = func; - // event + // also add to the main contract object + // if(!_this[method.name] || _this[method.name].name === 'bound _createTxObject') + // _this[method.name] = _this.methods[method.name]; + // _this[method.signature] = _this.methods[method.signature]; + + // event } else if (method.type === 'event') { - var event = _this.on.bind(_this, method.signature); + method.signature = '0x'+ sha3(utils.transformToFullName(method)); + var event = _this._on.bind(_this, method.signature); // add method only if not already exists if(!_this.events[method.name] || _this.events[method.name].name === 'bound ') @@ -128,12 +141,17 @@ var Contract = function(jsonInterface, address, options) { // definitely add the method based on its signature _this.events[method.signature] = event; - method.signature = '0x'+ sha3(utils.transformToFullName(method)); + // add event by name + _this.events[funcName] = event; } return method; }); + + // add allEvents + _this.events.allEvents = _this._on.bind(_this, 'allevents'); + return _this._jsonInterface; }, get: function(){ @@ -667,7 +685,7 @@ Contract.prototype.once = function(event, options, callback) { * @param {Function} callback * @return {Object} the event subscription */ -Contract.prototype.on = function(){ +Contract.prototype._on = function(){ var subOptions = this._generateEventOptions.apply(this, arguments); diff --git a/test/contract.js b/test/contract.js index c48f165..ffc868d 100644 --- a/test/contract.js +++ b/test/contract.js @@ -29,7 +29,7 @@ var abi = [{ "type": "uint256" }] }, { - "name": "send", + "name": "mySend", "type": "function", "inputs": [{ "name": "to", @@ -254,7 +254,7 @@ describe('contract', function () { it('_executeMethod should sendTransaction and check for receipts', function (done) { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - var signature = sha3('send(address,uint256)').slice(0, 8); + var signature = sha3('mySend(address,uint256)').slice(0, 8); provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_sendTransaction'); @@ -432,7 +432,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - var event = contract.on('Changed', {filter: {from: address}}, function (err, result, sub) { + var event = contract.events.Changed({filter: {from: address}}, function (err, result, sub) { assert.equal(result.returnValues.from, address); assert.equal(result.returnValues.amount, 1); assert.equal(result.returnValues.t1, 1); @@ -614,6 +614,64 @@ describe('contract', function () { }); }); + it('should create event from the events object using event name and parameters', function (done) { + var provider = new FakeHttpProvider(); + var web3 = new Web3(provider); + var signature = 'Changed(address,uint256,uint256,uint256)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_subscribe'); + assert.deepEqual(payload.params[1], { + topics: [ + '0x' + sha3(signature), + '0x000000000000000000000000'+ address.replace('0x',''), + null + ], + address: address + }); + }); + provider.injectResult('0x321'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_unsubscribe'); + done(); + }); + provider.injectResult(true); + + provider.injectNotification({ + method: 'eth_subscription', + params: { + subscription: '0x321', + result: { + address: address, + topics: [ + '0x' + sha3(signature), + '0x000000000000000000000000'+ address.replace('0x',''), + '0x0000000000000000000000000000000000000000000000000000000000000001' + ], + blockNumber: '0x3', + transactionHash: '0x1234', + blockHash: '0x1345', + logIndex: '0x4', + data: '0x0000000000000000000000000000000000000000000000000000000000000001' + + '0000000000000000000000000000000000000000000000000000000000000008' + } + } + }); + + var contract = new web3.eth.contract(abi, address); + var event = contract.events[signature]({filter: {from: address}}, function (err, result) { + assert.equal(result.returnValues.from, address); + assert.equal(result.returnValues.amount, 1); + assert.equal(result.returnValues.t1, 1); + assert.equal(result.returnValues.t2, 8); + + event.unsubscribe(); + }); + }); + it('should create all event filter and receive two logs', function (done) { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); @@ -640,7 +698,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); var count = 0; - var event = contract.on('allEvents', function (err, result) { + var event = contract.events.allEvents(function (err, result) { count++; if(count === 1) { @@ -711,7 +769,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi); - var result = contract.balance(address).encodeABI(); + var result = contract.methods.balance(address).encodeABI(); assert.equal(result, '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567891'); }); @@ -723,7 +781,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, {data: '0x1234'}); - var result = contract.constructor(address, 10).encodeABI(); + var result = contract.methods.constructor(address, 10).encodeABI(); assert.equal(result, '0x1234' + '0000000000000000000000001234567890123456789012345678901234567891'+ '000000000000000000000000000000000000000000000000000000000000000a'); }); @@ -744,7 +802,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.balance(address).estimateGas(function (err, res) { + contract.methods.balance(address).estimateGas(function (err, res) { assert.deepEqual(res, 50); done(); }); @@ -766,7 +824,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address, {data: '0x1234'}); - contract.constructor(address, 50).estimateGas(function (err, res) { + contract.methods.constructor(address, 50).estimateGas(function (err, res) { assert.deepEqual(res, 10); done(); }); @@ -788,7 +846,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.balance(address).call(function (err, res) { + contract.methods.balance(address).call(function (err, res) { assert.deepEqual(new BigNumber(0x32), res); done(); }); @@ -810,7 +868,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.balance(address).call(11) + contract.methods.balance(address).call(11) .then(function (r) { assert.deepEqual(new BigNumber(0x32), r); done(); @@ -820,7 +878,7 @@ describe('contract', function () { it('should sendTransaction to contract function', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - var signature = 'send(address,uint256)'; + var signature = 'mySend(address,uint256)'; provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_sendTransaction'); @@ -835,7 +893,49 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.send(address, 17).send({from: address}); + contract.methods.mySend(address, 17).send({from: address}); + }); + + it('should sendTransaction to contract function using the function namen incl. parameters', function () { + var provider = new FakeHttpProvider(); + var web3 = new Web3(provider); + var signature = '0x'+ sha3('mySend(address,uint256)').slice(0, 8); + + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_sendTransaction'); + assert.deepEqual(payload.params, [{ + data: signature + + '0000000000000000000000001234567890123456789012345678901234567891' + + '0000000000000000000000000000000000000000000000000000000000000011' , + from: address, + to: address + }]); + }); + + var contract = new web3.eth.contract(abi, address); + + contract.methods['mySend(address,uint256)'](address, 17).send({from: address}); + }); + + it('should sendTransaction to contract function using the signature', function () { + var provider = new FakeHttpProvider(); + var web3 = new Web3(provider); + var signature = '0x'+ sha3('mySend(address,uint256)').slice(0, 8); + + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_sendTransaction'); + assert.deepEqual(payload.params, [{ + data: signature + + '0000000000000000000000001234567890123456789012345678901234567891' + + '0000000000000000000000000000000000000000000000000000000000000011' , + from: address, + to: address + }]); + }); + + var contract = new web3.eth.contract(abi, address); + + contract.methods[signature](address, 17).send({from: address}); }); it('should make a call with optional params', function (done) { @@ -862,7 +962,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.balance(address).call({from: address, gas: 50000}) + contract.methods.balance(address).call({from: address, gas: 50000}) .on('data', function (r) { assert.deepEqual(new BigNumber(0x32), r); done(); @@ -887,7 +987,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.balance(address).call({from: address, gas: 50000}) + contract.methods.balance(address).call({from: address, gas: 50000}) .then(function (r) { assert.deepEqual(new BigNumber(0x32), r); done(); @@ -913,7 +1013,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.balance(address).call({from: address, gas: 50000}, 11) + contract.methods.balance(address).call({from: address, gas: 50000}, 11) .then(function (r) { assert.deepEqual(new BigNumber(0x32), r); done(); @@ -924,7 +1024,7 @@ describe('contract', function () { it('should sendTransaction with optional params', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - var signature = 'send(address,uint256)'; + var signature = 'mySend(address,uint256)'; provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_sendTransaction'); @@ -942,13 +1042,13 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.send(address, 17).send({from: address, gas: 50000, gasPrice: 3000, value: 10000}); + contract.methods.mySend(address, 17).send({from: address, gas: 50000, gasPrice: 3000, value: 10000}); }); it('should explicitly sendTransaction with optional params', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - var signature = 'send(address,uint256)'; + var signature = 'mySend(address,uint256)'; provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_sendTransaction'); @@ -966,13 +1066,13 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.send(address, 17).send({from: address, gas: 50000, gasPrice: 3000, value: 10000}); + contract.methods.mySend(address, 17).send({from: address, gas: 50000, gasPrice: 3000, value: 10000}); }); it('should explicitly call sendTransaction with optional params and call callback without error', function (done) { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - var signature = 'send(address,uint256)'; + var signature = 'mySend(address,uint256)'; provider.injectValidation(function (payload) { @@ -991,7 +1091,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.send(address, 17).send({from: address, gas: 50000, gasPrice: 3000, value: 10000}, function (err) { + contract.methods.mySend(address, 17).send({from: address, gas: 50000, gasPrice: 3000, value: 10000}, function (err) { assert.equal(err, null); done(); }); @@ -1000,7 +1100,7 @@ describe('contract', function () { it('should explicitly estimateGas with optional params', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - var signature = 'send(address,uint256)'; + var signature = 'mySend(address,uint256)'; provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_estimateGas'); @@ -1018,7 +1118,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.send(address, 17).estimateGas({from: address, gas: 50000, gasPrice: 3000, value: 10000}); + contract.methods.mySend(address, 17).estimateGas({from: address, gas: 50000, gasPrice: 3000, value: 10000}); }); it('getPastEvents should get past events and format them correctly', function (done) { @@ -1139,7 +1239,7 @@ describe('contract', function () { provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000005'); var contract = new web3.eth.contract(abi, address); - contract.testArr([3]).call() + contract.methods.testArr([3]).call() .then(function (result) { assert.deepEqual(new BigNumber(5), result); done(); @@ -1168,7 +1268,7 @@ describe('contract', function () { var contract = new web3.eth.contract(abi, address); - contract.testArr([3]).call(function (err, result) { + contract.methods.testArr([3]).call(function (err, result) { assert.deepEqual(new BigNumber(5), result); done(); });