13

using web3 javascript library how do you get the current value of a public property. e.g.

contract MyContract {
    address public owner;
    ...
}

Here's a snippet of the abi:

[{
  "constant": true,
  "inputs": [],
  "name": "owner",
  "outputs": [
    {
      "name": "",
      "type": "address"
    }
  ],
  "payable": false,
  "type": "function"
},
...
]

I've tried several methods, but to no avail:

    var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
    var contract = new web3.eth.Contract([...], "0x1234...");

    // These don't work:
    var owner = contract.owner;
    console.log(owner); // "undefined"

    contract.methods.owner.call(function(error, result) {
        console.log("This doesn't get called");
    });

    contract.methods.owner(function(error, result) {
        // Displays an error to console:
        // Error: Invalid number of parameters for "owner". Got 1 expected 0!
    });

    var x = contract.methods.owner();
    console.log(x); // Displays the contract object below:

The last line displays the contract object. Here's a snippet:

{ call: { [Function: bound _executeMethod] request: [Function: bound 
_executeMethod] },
  send: { [Function: bound _executeMethod] request: [Function: bound 
_executeMethod] },
  encodeABI: [Function: bound _encodeMethodABI],
  estimateGas: [Function: bound _executeMethod],
  _method:
  { constant: true,
     inputs: [],
     name: 'owner',
     outputs: [ [Object] ],
     payable: false,
     type: 'function',
     signature: '0x8da5cb5b' },
  _parent:
   Contract {
       // etc...

EDIT: Using version 1.0.0-beta.4 (later packages don't install properly with dependency lerna). Docs: http://web3js.readthedocs.io/en/1.0/web3-eth-contract.html

mkaj
  • 517
  • 3
  • 6
  • 15

7 Answers7

12

This code is correct: myContract.methods.owner().call().then(console.log); The error is a bug, and will be fixed in the next version.

Fabian Vogelsteller
  • 1,520
  • 11
  • 12
  • Yes, myContract.methods.owner().call().then(console.log); it's working like a charm ! – Chirag Maliwal May 16 '18 at 09:12
  • Can you explain how the returned value (from the call function) can be shown on a HTML page? Your answer only logs the return value in the console which is hidden from the users. – Aydin Jan 15 '19 at 18:19
10

According to the Web3 API documentation, the way to retrieve a contract instance and to call a method is:

1. Contract Definition

var MyContract = web3.eth.contract(abi);

2. Get the instance of the contract at the address

var myContractInstance = MyContract .at('0x**********');

3. Execute a call

var owner = myContractInstance .owner.call();

Full code:

var abi = [
    {
      "constant": true,
      "inputs": [],
      "name": "owner",
      "outputs": [
        {
          "name": "",
          "type": "address"
        }
      ],
      "payable": false,
      "type": "function"
    },
    {
      "inputs": [],
      "payable": false,
      "type": "constructor"
    }
  ];


var MyContract = web3.eth.contract(abi);

// initiate contract for an address
var myContractInstance = MyContract .at('0xa07ddaff6d8b7aabf91ac6f82bf89455eb9784f4');

// call constant function (synchronous way)
var owner = myContractInstance .owner.call();

console.log("owner="+owner);

Works fine:

owner=0x13a0674c16f6a5789bff26188c63422a764d9a39

Greg Jeanmart
  • 7,207
  • 2
  • 19
  • 35
  • Sorry, I should have specified the version of web3 that I'm using: 1.0.0-beta.4 http://web3js.readthedocs.io/en/1.0/web3-eth-contract.html for a new contract you do this:
    new web3.eth.Contract(jsonInterface[, address][, options])
    
    – mkaj Jul 23 '17 at 20:05
  • 2
    Haven't touched yet. But according to the documentation, it should be myContract.methods.owner().call().then(console.log); – Greg Jeanmart Jul 23 '17 at 20:41
  • I have not played with 1.0 yet either, but please remember it is BETA software and not well tested in production at this point. – Thomas Clowes Jul 23 '17 at 21:58
  • myContract.methods.owner().call().then(console.log); displays an error message: TypeError: Cannot read property 'length' of undefined and myContract.methods.owner.call().then(console.log); displays error message: TypeError: myContract.methods.owner.call(...).then is not a function I'll assume the beta isn't ready for this yet. – mkaj Jul 24 '17 at 00:04
  • Thanks for the detailed answer! :)

    Could you add how to do it in the asynchronous way?

    – shamisen Apr 21 '18 at 01:54
3

I found a workaround after upgrading to version 1.0.0-beta.11 and modifing the installed package here:

\node_modules\web3\packages\web3-eth-contract\src\index.js

change line 356 from:

if(json.inputs.length !== args.length) {

to:

if(args && json.inputs.length !== args.length) {

and changed my code above to:

var result = myContract.methods.owner.call().call((error, result) => {
    console.log(result);
});

You have to call `call() twice. meh.

mkaj
  • 517
  • 3
  • 6
  • 15
  • I was going to log an issue on github, but found a similar one here: https://github.com/ethereum/web3.js/issues/948 – mkaj Jul 26 '17 at 05:13
  • Issue will be resolved in version 1.0.0-beta.12 – mkaj Jul 26 '17 at 19:47
  • bug still exists on 1.0.0-beta.18 – bitsanity Aug 29 '17 at 23:01
  • 1
    the bug still exists even today (version 1.0.0-beta.30) unfortunately... mkaj said that you have to call call() twice meh but it looks like you can actually use myContract.methods.owner().call() .. for me it works like a charm.. you can actually use methods.methodName(arg).call({from:fromAccount}) – Andy B. Mar 25 '18 at 23:19
2

None of the other answers work for me. This does:

import Web3 from "web3";

const address = "0xe9e7..."; const abi = "[{...";

const web3 = new Web3(); // pass your endpoint here in case const contract = new web3.eth.Contract(abi, address);

await contract.methods.name().call(); await contract.methods.symbol().call(); await contract.methods.decimals().call();

This is web3 at version 3.0.0-rc.5.

febeling
  • 121
  • 4
  • This worked for me as well. I think that what was missing was the two calls:
    1. contract.methods.name()
    2. contract.methods.name().call()
    – Nico Serrano May 17 '22 at 15:14
1

Check your JSON ABI, e.g:

{
    "inputs": [],
    "name": "name",
    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
    ],
    "name": "ownerOf",
    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
    "stateMutability": "view",
    "type": "function"
  },

if the type is function , you should able to call it. I am using web3@1.6.1

contractInstance.methods.name().call();
contractInstance.methods.balanceOf(address).call();
vanduc1102
  • 131
  • 3
1

@mkaj if you are using version 1.x firstly you have to set the address properties as

var MyContract = web3.eth.contract(abi);
myContract.options.address = '0xa07ddaff6d8b7aabf91ac6f82bf89455eb9784f4';

var output = myContract.methods.owner.call((error, result) => {
    console.log(result); 
});
Ayush Mittal
  • 111
  • 3
0

it takes time to initialize your contract, you can use setTimeout() Method

setTimeout(function(){ 
   var owner = myContract.methods.owner.call()
   console.log('owner = ', owner)
}, 3000);
Om EL
  • 1
  • 2