Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subscribing to a Solidity event from frontend

Tags:

ethereum

I am trying to subscribe to a PurchaseMade event defined in Solidty from the frontend. I am not getting the expected results and need help with what I'm doing wrong.

Environment:

  • ganache-cli, Truffle
  • web3.js, React.js

Initialing contract Instance:

export const getContractInstance = () => {
    let web3Provider

    if (typeof window.web3 !== 'undefined') {
        // if metamask is on, web3 is injected...
    web3Provider = web3.currentProvider
    } else {
        // otherwise, use ganache-cli...
    web3Provider = new Web3.providers.HttpProvider('http://localhost:8545')
    }

    web3 = new Web3(web3Provider)

    return new web3.eth.Contract(CryptoKpopAbi, CONTRACT_ADDRESS)
}

Subscribing to PurchaseMade event

onBuy = (obj) => {
    web3.eth.subscribe("PurchaseMade", {}, () => {
        debugger
    });

    this.ContractInstance.methods.buy(1).send({
        from: this.state.currentUserAddress,
        gas: GAS_LIMIT,
        value: web3.utils.toWei(price.toString(), "ether"),
    }).then((receipt) => {
        console.log(receipt)
    }).catch((err) => {
        console.log(err.message)
    })
}

I get this warning when I call web3.eth.subscribe:

Subscription "PurchaseMade" doesn't exist. Subscribing anyway.

I get this error on tx receipt (after send()` succeeds

Uncaught TypeError: Cannot read property 'subscriptionName' of undefined

I used this official doc to setup the subscription

http://web3js.readthedocs.io/en/1.0/web3-eth-subscribe.html

Thank you in advance!

UPDATE:

Event declaration in contract

event PurchaseMade(uint objId, uint oldPrice, uint newPrice, string objName, address prevOwner, address newOwner);

Event call in contract

function buy(uint _tokenId) payable public {
  address prevOwner = ownerOf(_tokenId);
  uint currentPrice = tokenIdToPrice[_tokenId];

  ...

  PurchaseMade(_tokenId, currentPrice, newPrice,
    tokens[_tokenId].name, prevOwner, msg.sender);
}
like image 253
Maximus S Avatar asked Feb 04 '18 13:02

Maximus S


People also ask

How do I listen to an event in Solidity?

Here is a complete create and emit events in Solidity. It creates a transfer event with all the properties. Created a function transferTo which contains logic as well as emits an event Emit an event to client web applications. You have to write a front-end web app to listen to the events using web3 API.

How smart contract communicates about event to front-end?

Smart contract events are a way for your contract to communicate that something happened (i.e. there was an event) on the blockchain to your front-end application, which can be 'listening' for specific events and take action when they happen.

Where are Solidity events stored?

Events are not stored in the transaction nor on the blockchain. They are stored within the transaction receipt. TX receipts are stored in the Receipts Trie by the node.


1 Answers

You're attempting to subscribe to the event itself. The API lets you subscribe to an event type and add filters. The valid event types are:

  • pendingTransactions: Receive a subset of new transactions sent to the blockchain (Primarily used for miners who want to be selective of the transactions they process)
  • newBlockHeaders: Receive notification when a new block has been added to the blockchain.
  • syncing: Receive notification when node syncing starts/stops
  • logs: Receive notification on log updates on the blockchain. These are the events you're interested in.

Look at the API documentation for examples on how to use subscribe("logs").

The subscribe API is usually used to listen to events occurring across the blockchain. An easier approach for listening to events for a specific contract is to use events for the deployed contract (documentation). It's not much different than using subscribe above, but it already has the contract address and topic filters.

this.ContractInstance.events.PurchaseMade({}, (error, data) => {
  if (error)
    console.log("Error: " + error);
  else 
    console.log("Log data: " + data);
});

There's one important note, though. With web3 1.0, listening to events is not supported using HttpProvider. You have to use Websockets or IPC.

EDIT - I forgot to mention you can also get the events from the transaction receipt:

contractInstance.events.eventName.returnValues;
like image 190
Adam Kipnis Avatar answered Sep 24 '22 14:09

Adam Kipnis