Cómo obtener el valor de un contrato de propiedad pública usando web3.eth

usando la biblioteca javascript web3, ¿cómo se obtiene el valor actual de una propiedad pública? p.ej

contract MyContract {
    address public owner;
    ...
}

Aquí hay un fragmento de la abi:

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

He intentado varios métodos, pero fue en vano:

    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:

La última línea muestra el objeto del contrato. Aquí hay un fragmento:

{ 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...

EDITAR: Usar la versión 1.0.0-beta.4 (los paquetes posteriores no se instalan correctamente con la dependencia lerna). Documentos: http://web3js.readthedocs.io/en/1.0/web3-eth-contract.html

Respuestas (7)

Este código es correcto: myContract.methods.owner().call().then(console.log);el error es un error y se corregirá en la próxima versión.

Sí, myContract.methods.owner().call().then(console.log); ¡está funcionando a las mil maravillas!
¿Puede explicar cómo se puede mostrar el valor devuelto (de la función de llamada) en una página HTML? Su respuesta solo registra el valor de retorno en la consola que está oculto para los usuarios.

Según la documentación de la API de Web3 , la forma de recuperar una instancia de contrato y llamar a un método es:

1. Definición del contrato

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

2. Obtener la instancia del contrato en la dirección

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

3. Ejecutar una llamada

var owner = myContractInstance .owner.call();

Código completo:

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);

Funciona bien:

propietario=0x13a0674c16f6a5789bff26188c63422a764d9a39

Lo siento, debería haber especificado la versión de web3 que estoy usando: 1.0.0-beta.4 web3js.readthedocs.io/en/1.0/web3-eth-contract.html para un nuevo contrato, haga esto: new web3 .eth.Contract(jsonInterface[, dirección][, opciones])
Aún no he tocado. Pero de acuerdo con la documentación, debería sermyContract.methods.owner().call().then(console.log);
Todavía no he jugado con 1.0, pero recuerde que es un software BETA y no se ha probado bien en producción en este momento.
myContract.methods.owner().call().then(console.log);muestra un mensaje de error: TypeError: Cannot read property 'length' of undefinedy myContract.methods.owner.call().then(console.log);muestra un mensaje de error: TypeError: myContract.methods.owner.call(...).then is not a functionAsumiré que la versión beta aún no está lista para esto.
¡Gracias por la respuesta detallada! :) ¿Podría agregar cómo hacerlo de forma asíncrona?

Encontré una solución después de actualizar a la versión 1.0.0-beta.11y modificar el paquete instalado aquí:

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

cambie la línea 356 de:

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

a:

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

y cambié mi código anterior a:

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

Tienes que llamar a `call() dos veces. bueno

Iba a registrar un problema en github, pero encontré uno similar aquí: github.com/ethereum/web3.js/issues/948
El problema se resolverá en la versión1.0.0-beta.12
el error todavía existe en 1.0.0-beta.18
el error todavía existe incluso hoy (versión 1.0.0-beta.30 ) desafortunadamente... mkaj dijo que tienes que llamar a call() dos veces pero parece que realmente puedes usar myContract.methods.owner().call()... para mí funciona de maravilla. en realidad puedes usarmethods.methodName(arg).call({from:fromAccount})

Ninguna de las otras respuestas me funciona. Esto hace:

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();

Este es web3 en la versión 3.0.0-rc.5.

Esto funcionó para mí también. Yo creo que lo que faltaba eran las dos llamadas: 1. contract.methods.name()2.contract.methods.name().call()

@mkaj si está utilizando la versión 1.x, primero debe establecer las propiedades de la dirección como

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

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

Verifique su JSON ABI, por ejemplo:

{
    "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"
  },

si el tipo es function, debería poder llamarlo. estoy usandoweb3@1.6.1

contractInstance.methods.name().call();
contractInstance.methods.balanceOf(address).call();

lleva tiempo inicializar su contrato, puede usar el método setTimeout()

setTimeout(function(){ 
   var owner = myContract.methods.owner.call()
   console.log('owner = ', owner)
}, 3000);