Calling a Smart Contract With a Button

Someone asked today how to call a smart contract with a button, and I didn’t know where to send them, so I decided to write this really quickly.

In this post I’m going to give a simple but hopefully effective demonstration of how a JavaScript developer would create a web page that is able to call a smart contract, and send money (Ether) to it, with a single click.

To do this, your users are going to need to be using a web3-enabled browser, so either an installable one like Parity or Mist, or they could use a browser extension like MetaMask.

An introductory explanation of how MetaMask works, for developers.

Also, while I could teach you how to use the web3 API directly, instead I’m going to teach you how to use a new convenience library for talking to Ethereum smart contracts called EthJS.

Your website will need to wait for the ready event, and then check for a global web3 object. That looks like this:

window.addEventListener('load', function() {

// Check if Web3 has been injected by the browser:
if (typeof web3 !== 'undefined') {
    // You have a web3 browser! Continue below!
startApp(web3);
  } else {
     // Warn the user that they need to get a web3 browser
// Or install MetaMask, maybe with a nice graphic.
}

})

Copied loosely from the MetaMask Developer Guide.

Here’s a nice graphic you can use if they don’t have web3 available.

In this example, I’m going to assume you’re using a JavaScript bundler like Browserify or Webpack, and know how to install modules off NPM.

In your app setup, you’re going to use a few different ethjs modules, and you’ll initialize them with the global web3 object’s currentProvider property, which is how it talks to the blockchain anyway.

const Eth = require('ethjs-query')
const EthContract = require('ethjs-contract')

function startApp(web3) {
  const eth = new Eth(web3.currentProvider)
const contract = new EthContract(eth)
  initContract(contract)
}

Once you’ve instantiated a contract instance, you can use it to create references to live contracts on the network. To do this, you need two things:

  • The contract address.
  • The contract ABI.

The ABI is the Application Binary Interface, and it tells your JavaScript contract how to talk to the smart contract. It’s just JSON data that describes the contract methods.

Usually if you published a contract, you know how to get the ABI, and if you’re connecting to someone else’s contract, they should make the ABI available, although sometimes you can find ABIs matched to contracts on block explorers like Etherscan.

Let’s assume you have your ABI and address available, and see how we’ll create a contract object now. In this example I’ll use an ABI that includes only the transfer(to, value) method from the Token standard:

const abi = [{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
}]
const address = '0xdeadbeef123456789000000000000'
function initContract (contract) {
  const MiniToken = contract(abi)
const miniToken = MiniToken.at(address)
  listenForClicks(miniToken)
}

Now we’ve initialized a JavaScript interface for a smart contract, so we just need to create a little HTML

<button class="transferFunds">Send Money!</button>

And a little JavaScript to respond to the click, and send those funds:

function listenForClicks (miniToken) {
  var button = document.querySelector('button.transferFunds')
button.addEventListener('click', function() {
    miniTokentoken.transfer(toAddress, value, { from: addr })
    .then(function (txHash) {
console.log('Transaction sent')
console.dir(txHash)
      waitForTxToBeMined(txHash)
})
    .catch(console.error)
  })
}

Note if this transaction were to send ether also, you’d add value: '10000' to the options hash that includes the from field. The value is in the unit of wei, which is 1x10^-18 Ether. An easy way to convert is like this:

var inWei = web3.toWei('10', 'ether')

A strange part of this for a normal web developer is that the transaction response does not mean the transaction is now complete, it just means it’s been transmitted to the network. It still needs to be mined, and in Ethereum, that takes around 14 seconds on average (block time, view stats on EthStats.net).

Right now there aren’t great subscription methods for waiting for a transaction to be mined, so you’ll need to poll for it with that txHash you got back. Yes, it’s tedious, so I’ll show you how it can be a little less painful using the new JavaScript async/await pattern:

async function waitForTxToBeMined (txHash) {
  let txReceipt
while (!txReceipt) {
    try {
      txReceipt = await eth.getTransactionReceipt(txHash)
    } catch (err) {
      return indicateFailure(err)
    }
  }
  indicateSuccess()
}

That’s it! (I know, it was a lot) I hope this was enough to show you how to interact with a smart contract over the Ethereum block chain. Once you’re used to it, it’s pretty great, because it’s a sort of global API that has permissions baked in, so while you have to do a couple funny things like wait for transactions to be mined, you don’t have to do obnoxious things like manage user accounts and passwords, or manage a backend server yourself!

Please add any questions you have here, we made MetaMask to enable the easy creation of web interfaces for smart contracts, so that’s really what we’re here for. Show us what you’ve got!

Show your support

Clapping shows how much you appreciated Dan Finlay’s story.