Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 

In a previous post I explained how to deploy an Ethereum smart contract to a private Quorum blockchain on SAP Cloud Platform using a single Node.js script to help understand the basic end-to-end process of compiling and deploying a smart contract. As development goes on, a more rapid approach may be required sooner or later.


This post explains how to connect the Ethereum development framework Truffle to a Quorum Blockchain network running on SAP Cloud Platform. The instructions are based on the official Truffle tutorial BUILDING DAPPS FOR QUORUM: PRIVATE ENTERPRISE BLOCKCHAINS.



Prerequisites



Note: Some of the commands (such as tree) in the post may only work on Unix-like systems such as Linux or MacOS. Similar commands may exist for Windows.



Meet Truffle


Truffle is a command line tool that simplifies the development process of Ethereum smart contracts. A couple of the most important features are:




  • Management of multiple smart contracts

  • Smart contract deployment & migrations

  • Management of multiple blockchain networks

  • Ethereum package management


Installation of Truffle


Node.js and NPM are required to install Truffle. The following command installs the Truffle command line tool globally.



$ npm install -g truffle

Create a Truffle project


It is a good practice to put a Truffle project into a separate folder. The following commands create a directory and change the working directory.



$ mkdir my-project
$ cd my-project

Next, the Truffle tool can be used to initialize the project. The Unix command tree helps to understand which files and directories are created. For more information on the file structure, please refer to the Truffle documentation.



$ truffle init
$ tree
.
├── contracts
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
└── truffle-config.js

3 directories, 3 files

The later steps in the example require the installation of additional NPM packages. The following command initializes an NPM module and creates a package.json and a package-lock.json to track this Truffle project’s dependencies.



$ npm init

Connect Truffle to Quorum on SAP Cloud Platform


Truffle is typically connected to a local Ethereum instance using the “localhost” host name and a port. Quorum instances on SAP Cloud Platform run on a shared port and are secured with an API key. Therefore a custom “provider” is required to allow the use of a full URL.



HDWalletProvider


The HDWalletProvider (“HD” stands for Hierarchical Deterministic) is an open source provider package that was originally made for public, shared Ethereum instances (such as Infura) where the account is held separate from the Ethereum node. HDWalletProvider takes a mnemonic string (a space-separated string of twelve words a human can remember) and derives a private key that constitutes the account. Since the HDWalletProvider is simple to use, it is used for this example.


The following command installs HDWalletProvider via NPM and adds it to the project’s package.json:



$ npm install truffle-hdwallet-provider --save

Configure Truffle to use Quorum on SAP Cloud Platform


The following code snippet configures Truffle using the truffle-config.js file to use the RPC URL and the mnemonic string. The URL can be retrieved from the instance’s dashboard on SAP Cloud Platform. The mnemonic string can be arbitrarily chosen or can be generated using this website.


Please note that the code below is just an example. Never hard code the mnemonic string or the RPC URL.



// Import HDWalletProvider
const HDWalletProvider = require('truffle-hdwallet-provider')
// mnemonic string is secret, consider reading an environment variable
const mnemonic = 'idle belt cliff rough reward forest talent coffee bread describe legal fork'
// RPC URL is secret, consider reading an environment variable
const rpcUrl = 'https://...'
module.exports = {
networks: {
development: {
// Provider has to be wrapped into a function
provider: () => new HDWalletProvider(mnemonic, rpcUrl),
// Match any network id
network_id: "*",
// Since Quorum is used, gas price can be set to 0
gasPrice: 0,
// Gas limit
gas: 4500000
}
}
}

Compile, deploy and test Solidity contract


Now that Truffle is installed and set up, the contract can be created. This example uses the same SimpleStorage contract that was used in the previous post. The constructor initializes an integer value that can be changed at a later point using the set function and read using the get function.



Solidity contract compilation


Create a new file with the name SimpleStorage.sol in the contracts directory and paste the following Solidity code:



pragma solidity ^0.5.0;
contract SimpleStorage {
uint public storedData;

constructor (uint initVal) public {
storedData = initVal;
}

function set(uint x) public {
storedData = x;
}

function get() public view returns (uint retVal) {
return storedData;
}
}

Next, verify the successful local compilation of the contract:



$ truffle compile
Compiling ./contracts/Migrations.sol...
Compiling ./contracts/SimpleStorage.sol...
Writing artifacts to ./build/contracts

The SimpleStorage smart contract should now compile successfully on the local device.



Deploy smart contract to Quorum Blockchain


To deploy a contract with Truffle, a migration is required. Create a file with the name 2_deploy_simplestorage.js in the migrations folder with the following content:



const SimpleStorage = artifacts.require("SimpleStorage");

module.exports = function(deployer) {
// Pass 42 to the contract as the first constructor parameter
deployer.deploy(SimpleStorage, 42)
}

The migration script loads the SimpleStorage contract and deploys it to the configured Ethereum instance with the initial integer value “42”. To execute the migrations, run the following command:



$ truffle migrate
...
2_deploy_simplestorage.js
=========================

Deploying 'SimpleStorage'
-------------------------
> transaction hash: 0xf043d8a233f8ab0b462b93666fec79a5937359f07e7bece910d2f6ac7996c2bc
> Blocks: 0 Seconds: 0
> contract address: 0xc711e03859383294DCa9383397CaA67AEd4D030f
> account: 0xC38995a435d3A7DD6c5D7641AD6aEb197446c1b2
> balance: 0
> gas used: 122661
> gas price: 0 gwei
> value sent: 0 ETH
> total cost: 0 ETH

> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0 ETH

The transaction did not cost anything because the gasPrice was set to zero in the network configuration above. Unlike Ethereum, Quorum allows users to not pay any Ether for gas. Also note that gas was still used and the transaction would have failed if more gas than the gas limit was used (see the gas property in the network configuration).



Write unit tests for the contract


Unit tests can be written in both JavaScript and Solidity. The example uses JavaScript and leverages the Mocha framework. The async/await notation of JavaScript is used to improve readability:



const SimpleStorage = artifacts.require("SimpleStorage");
contract("SimpleStorage", async accounts => {
it("should write a value and read it back", async () => {
// Retrieve contract instance
let instance = await SimpleStorage.deployed()
// Write to contract
await instance.set.sendTransaction(9999, { from: accounts[0] })
// Read from contract
let value = await instance.get.call()
assert.equal(value.valueOf(), 9999)
})
})

The tests can be executed using the following command:



$ truffle test
Using network 'development'.

Contract: SimpleStorage
✓ should write a value and read it back (2899ms)

1 passing (3s)

Additional resources