1

Using the following code in Nodejs - Web3 to catch event from Solidity Smart Contract:

const cron = require("node-cron");
const Web3 = require("web3");

const ABISimpleStorage = require("./build/contracts/Storage.json");
let web3 = new Web3(
  new Web3.providers.WebsocketProvider("ws://192.168.1.3:8546")
);

const go = async () => {
  try {
    // GET Info From Netwrok
    const netID = await web3.eth.net.getId();
    const contractAddress = ABISimpleStorage.networks[netID].address;

    // CREATE Contract Instance
    const contract = await new web3.eth.Contract(
      ABISimpleStorage.abi,
      contractAddress
    );

    // SET Default Account from Wallet
    const addresses = await web3.eth.accounts.wallet;
    web3.eth.defaultAccount = addresses[0].address;

    // GAS Settings
    let gasPrice = await web3.eth.getGasPrice();
    let gasEstimate = await contract.methods
      .setData(web3.utils.fromAscii("Cavolo"))
      .estimateGas({ from: web3.eth.defaultAccount });

    // WRITE-SEND data into Blockchain
    let result = await contract.methods
      .setData(web3.utils.fromAscii("Cavolo"))
      .send({
        from: web3.eth.defaultAccount,
        gasPrice: gasPrice,
        gas: gasEstimate
      });

    // READ Data From Blockchain
    let getResult = await contract.methods.getData().call({});
    console.log(getResult);

    contract.events
      .MyEvent({}, function(err, event) {
        if (err) {
          console.error;
        } else {
          // console.log(event.blockNumber);
          console.log(`BlockNumber (${event.blockNumber})`);
          console.log(`BlockHas (${event.blockHash})`);
          console.log(`TransactionHash (${event.transactionHash})`);
          // let string = web3.utils.hexToUtf8(event.returnValues.value);
        }
      })
      .on("data", async function(event) {
        console.log(event);
        console.log(event.returnValues.value);
        let check = web3.utils.isHexStrict(event.returnValues.value);
        console.log(check);
        console.log(typeof event.returnValues.value);
        console.log(
          "Hex To Ascii -->" + web3.utils.hexToAscii(event.returnValues.value)
        );
        console.log(
          "Hex to Utf8 -->" + web3.utils.hexToUtf8(event.returnValues.value)
        );
      })
      .on("error", console.error);
    gasEstimate = await contract.methods
      .setData(web3.utils.fromAscii("Cavolooooo"))
      .estimateGas({ from: web3.eth.defaultAccount });

    result = await contract.methods
      .setData(web3.utils.fromAscii("Cavolooooo"))
      .send({
        from: web3.eth.defaultAccount,
        gasPrice: gasPrice,
        gas: gasEstimate
      });
    // console.log(result.events);
    getResult = await contract.methods.getData().call({});
    console.log(getResult);
  } catch (error) {
    console.log("Error--> " + error);
  }
};


cron.schedule("*/10 * * * * *", function() {
  go();
});

and the following Solidity Contract:

pragma solidity >=0.4.21 <0.7.0;


contract Storage {
    bytes32 public data;
    event MyEvent(
        uint256 indexed id,
        uint256 indexed date,
        bytes32 indexed value
    );
    uint256 nextId;

    function setData(bytes32 _data) external {
        data = _data;
        emit MyEvent(nextId, now, _data);
        nextId++;
    }

    function getData() external view returns (bytes32) {
        return data;
    }
}

All works fine.

Using the following code, the difference is only in send method transaction:

const cron = require("node-cron");
const Web3 = require("web3");

const ABISimpleStorage = require("./build/contracts/SimpleStorage.json");
// let web3 = new Web3(new Web3.providers.HttpProvider("http://192.168.1.3:8545"));
// let web3 = new Web3("http://192.168.1.9:8545");
let web3 = new Web3(
  new Web3.providers.WebsocketProvider("ws://192.168.1.3:8546")
);

const go = async () => {
  try {
    // GET Info From Netwrok
    const netID = await web3.eth.net.getId();
    const contractAddress = ABISimpleStorage.networks[netID].address;

    // CREATE Contract Instance
    const contract = await new web3.eth.Contract(
      ABISimpleStorage.abi,
      contractAddress
    );

    // SET Default Account from Wallet
    const addresses = await web3.eth.accounts.wallet;
    web3.eth.defaultAccount = addresses[0].address;

    // GAS Settings
    const gasPrice = await web3.eth.getGasPrice();
    let gasEstimate = await contract.methods
      .setData("Cavolo")
      .estimateGas({ from: web3.eth.defaultAccount });

    // WRITE-SEND data into Blockchain
    let result = await contract.methods.setData("Cavolo").send({
      from: web3.eth.defaultAccount,
      gasPrice: gasPrice,
      gas: gasEstimate
    });

    // READ Data From Blockchain
    let getResult = await contract.methods.getData().call({});
    console.log(getResult);

    contract.events
      .MyEvent({}, function(err, event) {
        if (err) {
          console.error;
        } else {
          // console.log(event.blockNumber);
          console.log(`BlockNumber (${event.blockNumber})`);
          console.log(`BlockHas (${event.blockHash})`);
          console.log(`TransactionHash (${event.transactionHash})`);
          // let string = web3.utils.hexToUtf8(event.returnValues.value);
        }
      })
      .on("data", async function(event) {
        console.log(event);
        console.log(event.returnValues.value);
        let check = web3.utils.isHexStrict(event.returnValues.value);
        console.log(check);
        console.log(typeof event.returnValues.value);
        console.log(
          "Hex To Ascii -->" + web3.utils.hexToAscii(event.returnValues.value)
        );
        console.log(
          "Hex to Utf8 -->" + web3.utils.hexToUtf8(event.returnValues.value)
        );
      })
      .on("error", console.error);
    gasEstimate = await contract.methods
      .setData("Cavolooooo")
      .estimateGas({ from: web3.eth.defaultAccount });

    result = await contract.methods.setData("Cavolooooo").send({
      from: web3.eth.defaultAccount,
      gasPrice: gasPrice,
      gas: gasEstimate
    });
    getResult = await contract.methods.getData().call({});
    console.log(getResult);
  } catch (error) {
    console.log("Error--> " + error);
  }
};


cron.schedule("*/10 * * * * *", function() {
  go();
});

and the following solidity contract, the difference is only in the choice of solidity type for variable value in MyEvent :

pragma solidity >=0.4.21 <0.7.0;


contract SimpleStorage {
    string public data;
    event MyEvent(
        uint256 indexed id,
        uint256 indexed date,
        string indexed value
    );
    uint256 nextId;

    function setData(string calldata _data) external {
        data = _data;
        emit MyEvent(nextId, now, "Cazzo");
        nextId++;
    }

    function getData() external view returns (string memory) {
        return data;
    }
}

We encounter the "Error: Invalid UTF-8 detected" during web3.utils.* conversion:

<my_home>/node_modules/utf8/utf8.js:178 throw Error('Invalid UTF-8 detected'); Error: Invalid UTF-8 detected

Which is the difference between two approach? Thanks in advance BR

13
  • 1
    Using in my solidity contract byte32 and not string the problem during conversione is solved. What's the difference? – brunillopu Mar 30 '20 at 6:43
  • Please elaborate on Reading the value field of the Result with web3.utils. – goodvibration Mar 30 '20 at 6:55
  • The following line of code to obtain text format of value field in the object from Event Listener: let string = web3.utils.hexToUtf8(event.returnValues.value) – brunillopu Mar 30 '20 at 7:49
  • And you get the exact same value for both contracts? If it looks like a Yes, then can you please console.log(typeof event.returnValues.value) in order to check the actual type in each case? – goodvibration Mar 30 '20 at 8:10
  • The output of console.log(typeof event.returnValues.value) is "string" in both solidity contract. – brunillopu Mar 30 '20 at 9:09
2

The code uses indexed parameters. In case of a string parameter it is not stored in the event log as is, but its keccak256 value instead. See solidity documentation about that https://solidity.readthedocs.io/en/v0.6.4/abi-spec.html#encoding-of-indexed-event-parameters.

It is not possible to retrieve the value of an indexed string from the event log.

As an alternative if you want to retrieve its value you should not use the indexed type, or have two parameters one indexed and the other without it.

1
  • Really Thanks for the clarification. – brunillopu Mar 30 '20 at 15:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.