Categories: Blockchain

Node.js – smart contract integration with truffle-contract and infura.io

While running your own Ethereum node with geth by using web3js from node.js (backend) app is a common solution, connecting to a public Ethereum node such as infura.io and using [truffle-contract](https://github.com/trufflesuite/truffle-contract] gives some benefits:

  1. No need to maintain your own Ethereum node (syncing a full node requires huge storage space! (around 40 GB for Ropsten))
  2. Seamlessly integrate your node.js (backend) development workflow with Truffle Framework smart contract development
  3. Simpler smart contract API with truffle-contract

How to do it?

First, install some dependencies:

npm i --save web3@0.18.4 web3-provider-engine@8.6.1 asyncawait truffle-contract ethereumjs-wallet

asyncawait module provides async / await capabilities to make code much shorter. If you use node.js version with built-in async / await you can ignore this and just remove parentheses after each async / await in the code sample below.

Then, in a node.js file, include these dependencies:

const async = require('asyncawait/async');
const await = require('asyncawait/await');
const path = require('path'); 
const fs = require('fs'); 
const TruffleContract = require('truffle-contract'); 
const Web3 = require('web3'); 
const ethereumjsWallet = require('ethereumjs-wallet'); 
const ProviderEngine = require('web3-provider-engine'); 
const WalletSubprovider = require('web3-provider-engine/subproviders/wallet.js'); 
const Web3Subprovider = require('web3-provider-engine/subproviders/web3.js'); 
const FilterSubprovider = require('web3-provider-engine/subproviders/filters.js');

Next, define some important constants:

const RPC_SERVER = 'https://ropsten.infura.io/YOUR-INFURA-API-TOKEN'; 
const TOKEN_SALE_CONTRACT = path.resolve(__dirname, '..', '..', 'contracts', 'TokenSale.json'); 
const privateKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; 

RPC_SERVER contains path to infura.io node (in this case, I choose to connect to Ropsten for testing) and your API token (currently you can obtained for free by registering). TOKEN_SALE_CONTRACT contains the path to your smart contracts build result. Usually it is inside build/contracts subdirectory within your Truffle project directory. You can just copy them from there to your node.js project directory. While privateKey is your Ethereum wallet private key from account that you want to use sign the transaction.

Please also make sure you have some ETH in the wallet in case you are invoking transaction (which require gas). Otherwise you will hit insufficient funds error.

Then we need to setup custom provider/engine to enable implicit transaction self-signing:

const wallet = ethereumjsWallet.fromPrivateKey(new Buffer(privateKey, 'hex')); 
const engine = new ProviderEngine(); 
engine.addProvider(new FilterSubprovider()); 
engine.addProvider(new WalletSubprovider(wallet, {})); 
engine.addProvider(new Web3Subprovider(new Web3.providers.HttpProvider(RPC_SERVER))); 
engine.start(); 

Now we can write a function to load the contract using truffle-contract:

function loadContract(file, provider, address) { 
    return new Promise(function (resolve, reject) { 
        fs.readFile(file, 'utf-8', function (err, data) { 
            if (err) { 
                reject(err); 
            } else { 
                let contract = TruffleContract(JSON.parse(data)); 
                contract.setProvider(provider); 
                contract.defaults({ from: address, gas: 4500000 }); 
                resolve(contract); 
            } 
        }); 
    }); 
} 

Finally we can create functions that invoke smart contract methods:

const totalTokenIssued = async(function () { 
    let tokenSaleContract = await(loadContract(TOKEN_SALE_CONTRACT, engine, whitelistAddress)); 
    let tokenSale = await(tokenSaleContract.deployed()); 
    let totalTokenIssued = await(tokenSale.totalTokenIssued()); 
    return totalTokenIssued.toString(); 
}); 

const contributeCoins = async(function (contributorAddress, amount, whitelistAddress) { 
    let weiAmount = new web3.BigNumber(web3.toWei(amount, 'ether')); 
    let tokenSaleContract = await(loadContract(TOKEN_SALE_CONTRACT, engine, whitelistAddress)); 
    let tokenSale = await(tokenSaleContract.deployed()); 
    let contributeCoins = await(tokenSale.contributeCoins(contributorAddress, weiAmount, { from: whitelistAddress })); 
    return contributeCoins; 
}); 

Since async method return a promise, you can simply call methods above like this:

totalTokenIssued().then(function(totalToken) { 
   console.log('totalToken=' + totalToken); 
}).catch(console.error);

let contributor = '0x0718197B9Ac69127381ed0C4b5d0f724f857c4d1'; // address derived from our private key & wallet defined above 

let whitelist = '0x' + wallet.getAddress().toString('hex'); 

contributeCoins(contributor, 1, whitelist).then(function(totalToken) { 
   console.log('totalToken=' + totalToken); 
}).catch(console.error);
0 0 votes
Article Rating
yohanes.gultom@gmail.com

Share
Published by
yohanes.gultom@gmail.com

Recent Posts

Get Unverified SSL Certificate Expiry Date with Python

Getting verified SSL information with Python (3.x) is very easy. Code examples for it are…

3 years ago

Spring Data Couchbase 4 Multibuckets in Spring Boot 2

By default, Spring Data Couchbase implements single-bucket configuration. In this default implementation, all POJO (Plain…

3 years ago

Firebase Auth Emulator with Python

Last year, Google released Firebase Auth Emulator as a new component in Firebase Emulator. In…

3 years ago

Google OIDC token generation/validation

One of the authentication protocol that is supported by most of Google Cloud services is…

4 years ago

Fast geolocation query with PostGIS

If you need to to add a spatial information querying in your application, PostGIS is…

4 years ago

Auto speech-to-text (Indonesian) with AWS Transcribe and Python

Amazon Web Service Transcribe provides API to automatically convert an audio speech file (mp3/wav) into…

4 years ago