Where are my Contracts and Events on Ganache?

Hi, There!

Ganache is a great, almost one-click development Ethereum you can use on desktop. One thing many folks complain about is not being able to see Events and Contracts in Ganache when they are expected.

No events or contracts show up without truffle project defined

Actually, if a Truffle project is configured, the Contracts and Events will show up in the Ganache dashboard.

Add a truffle project and restart
Contracts are shown deployed after truffle migrate
Events are showing up after emitted
Details of an Event

These are very handy to get Contract and Events, a lot easier than using truffle console and web3.js.

contract MyContract {
  event MyEvent(address indexed from, string message);
  constructor() public {
  }
  function foo() public {
    emit MyEvent(msg.sender, 'hello foo');
  }
}

truffle-config.js should have interface and sol files directories, such as:

  contracts_directory: './src/contracts/',
  contracts_build_directory: './src/abis/',
  compilers: {
    solc: {
      version: ">=0.6.0 <0.8.0",
      optimizer: {
        enabled: true,
        runs: 200
      }
    }

Cheers! ~T

Calling contract from a contract on Ethereum

Hi, there:

One can call a contract from a contract on the Ethereum by the address. This allows function reusability. A simple example as below:

Contract A: Tickers contains company names and their stock tickers.

contract Tickers {
    
    mapping (string => string) tickers;
    using Utils for *;

    constructor (){
        tickers['AMAZON'] = 'AMZN';
        tickers['APPLE'] = 'AAPL';
        tickers['MERCK'] = 'MRK';
    }
    
    function getTicker(string memory n) public view returns (string memory t) { 
        return tickers[Utils._toUpperCase(n)];
    }
	
}

library Utils {
    
    function _toUpperCase(string memory str) public pure returns (string memory) {
		bytes memory bStr = bytes(str);
		bytes memory bOutput = new bytes(bStr.length);
		
		for (uint i = 0; i < bStr.length; i++) {
	                 bytes1 _b1 = bStr[i];
			 if (_b1 >= 0x61 && _b1 <= 0x7A) {
				bOutput[i] = bytes1(uint8(_b1) - 32);
			} else {
				bOutput[i] = _b1;
			}
		}
		return string(bOutput);
	}
}

Contract B: StockTest to use Contract A.

contract StockTest {
    
    Tickers private tickers = new Tickers();
    Tickers private contractTickers;

    function registerTickersContract(address a) public returns(bool) {
        contractTickers = Tickers(a);
        return true;
    }
 
    function getStock(string memory name) 
        public view returns(string memory, string memory) {
        
        string memory ticker;
        if (address(contractTickers) == address(0)){
            ticker = tickers.getTicker(name);  // in case address not set, call local
        } else {
            ticker = contractTickers.getTicker(name);
        }
        return (name, ticker);
    }
}

registerTickersContract() allows injection of Contract A’s address before Contract B can call it.

The client web3 code is straightforward:

        const abi = [....];
        
        const Web3 = require('web3');
        const url = 'http://localhost:8545/';
        const web3 = new Web3(new Web3.providers.HttpProvider(url));
        const callerAccount  = '0x0eCF7fED2d0ADEFb32CD87DF574289133c1e7D5f';
        const contractAddress = '0xF7992417f14D4020322621E2dDafC91DB4841037';

        // instantiate a new web3 Contract object
        let contract = new web3.eth.Contract(abi, contractAddress);

        contract.methods.registerTickersContract('0xD33c17761B537ecdfE7747725BC1F3D96BB63042')
        .call().then((result)=>{
            if (result) {
                contract.methods.getStock('amazon').call().then((result)=>{
                    console.log(result);
                });
            } 
        });

That’s pretty much it. Cheers!

~T

Subscribe and listen to events on Ethereum

Hi, There!

You would often want to monitor what’s going on with the contract on the Ethereum network, especially your own contract. For this, you need to do (1) emit some events on the network (2) subscribe to the event based on address and /or topics.

  • Emit event in Solidity
pragma solidity >=0.7.0 <0.8.0;
contract LogEventExample {
    event MyEvent(address indexed a, uint256 v); // indexed will be in topic
    function triggerEvent() public payable {
        emit MyEvent(msg.sender, 1);
    }
}
  • Make sure –ws is enabled if using geth. Websocket allows monitoring of the event after subscribe.
geth --datadir test-chain-dir --http --ws --dev --http.corsdomain "https://remix.ethereum.org,http://remix.ethereum.org"
  • Subscribe by Web3
const Web3 = require('web3');
const url = 'ws://127.0.0.1:8546';
const web3 = new Web3(url);

var options = {
    address: '0xfbBE8f06FAda977Ea1E177da391C370EFbEE3D25',
    topics: [
        '0xdf50c7bb3b25f812aedef81bc334454040e7b27e27de95a79451d663013b7e17',
        //'0x0000000000000000000000000d8a3f5e71560982fb0eb5959ecf84412be6ae3e'
      ]
};

var subscription = web3.eth.subscribe('logs', options, function(error, result){
    if (!error) console.log('got result');
    else console.log(error);
}).on("data", function(log){
    console.log('got data', log);
}).on("changed", function(log){
    console.log('changed');
});

The subscribing options filter out events based on contract address, topics. If you want to subscribe to all events on the network, comment them out.

  • call triggerEvent() on the contract in the network and watch the event show up in Web3

A detailed nice explanation about event data can be found in this article https://medium.com/mycrypto/understanding-event-logs-on-the-ethereum-blockchain-f4ae7ba50378

Cheers!

~T

Use web3.js to connect to Ethereum mainnet via Infura

Hi, There:

Long time again!

When you play with web3.js, if you want to connect to Ethereum mainnet quickly without using real account, you can use the Infura as the bridge to get into the ETH2. Infura provides a nice layer to manage/monitor the access to Ethereum.

A few main steps:

  1. Go to Infura.io to register for free (with limited daily requests).
  2. Create a new project called Dapp1, or whatever you like.
  3. Get a https or websocket URL which comes with API token, such as:
  4. Run node.js code. Example as below:

const Web3 = require('web3');

const url = 'https://mainnet.infura.io/v3/b0bb******';

const web3 = new Web3(url);

// OR const web3 = new Web3(new Web3.providers.HttpProvider(url));

(async() => {   

try {        

const abi = [{ "constant": true, "inputs": ............ ];

const contractAddress = '0xdac17f958d2ee523a2206206994597c13d831ec7';

let contract = new web3.eth.Contract(abi, contractAddress);
  let name = await contract.methods.name().call();  

console.log(name);   

} catch (e) {       

console.log(e.message);

}  
})();

The output should be a value like Tether USD which is contract’s return value of function name().

Cheers!

~T