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: 
former_member236392
Participant
After the two very informative posts from my colleagues on how to develop Quorum smart contracts with Truffle and Remix, I'm going to show you an alternative framework for the same purpose called Embark.

This article would be of interest to the beginner level blockchain developers.

Embark is a framework that helps with developing and deploying decentralised applications on Ethereum. It contains a dashboard that helps a developer navigate their contracts, the network status and configuration. That makes it very simple to:

  • connect to different networks (private networks, testnets, mainnet)

  • deploy and update smart contracts

  • test smart contracts

  • integrate other decentralised technologies into applications, such as decentralised storage (IPFS) and decentralised communication protocols (Whisper)


For testing and development purposes, Embark uses a local, simulated blockchain so there's no need to pay gas to prototype quickly. The entire chain’s data is deleted every time we end the process.

Prerequisites



  • Node.js and npm

  • Your favourite code editor (VSCode, Sublime, Atom, Notepad++, etc)

  • (Optional) Trial SAP Cloud Platform account and a Quorum dev node


Embark installation


Once all the local prerequisite tools are set up, getting Embark can be as easy as opening your terminal and entering:
npm install -g embark

If you encounter issues with the install, if would be useful to check out the Embark Troubleshooting page and Embark's Github issues.

In order to verify the installation, run the below command, which should print the Embark version:
$ embark --version
4.1.0

Create a new project


In your terminal run:
embark new <Project Name>

This should create your test project. We can call it FioriToken. Yes, let's try to create a simple implementation of ERC20 Ethereum token based on OpenZeppelin library!

Create a smart contract


In your FioriToken -> contracts folder create a new 'FioriToken.sol' file and paste the following code into it:
pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

contract MyFioriToken is ERC20 {
string public name;
string public symbol;
uint256 public decimals;

constructor(string _name, string _symbol, uint8 _decimals)
ERC20()
public
{
name = _name;
symbol = _symbol;
decimals = _decimals;
}

function deposit() public payable returns (bool) {
uint256 value = msg.value * 10**decimals;
increaseAllowance(msg.sender, value);
return mint(msg.sender, value);
}

function mint(address to, uint256 amount) public returns (bool) {
_mint(to, amount);
return true;
}
}

Don't worry if the code looks confusing now! We will discuss in detail what this code does a bit below.

Configure local environment


Right now in order to compile the contract we need to complete several configuration actions as per below:

  • Open the embark.json file.

    • Update the Embark project to use the correct Solidity compiler. To do this open the in your Embark project. Find the line starting with "solc": and update the line to read "solc": "0.4.24",.

    • Save the embark.json file.





  • Open the contracts.js file.

    • In order to configure your local contract deployment find the following contracts section
      contracts: {
      // example:
      //SimpleStorage: {
      // args: [ 100 ]
      //}
      }

      and replace it with code below so it would look as follows:
      contracts: {
      MyFioriToken: {
      args: [ "My Fiori Token", "FIO", 0 ]
      }
      }


    • Save the contracts.js file.





  • Open the terminal.

    • Install the dependency (we've imported the openzeppelin library in the Solidity contract above). Just run the command below inside of your project folder:
      npm install openzeppelin-solidity@2.0.0





Build contract


Now run embark build in your terminal and you should see that the contract has been compiled and deployed locally. The output would contain key messages "Finished deploying" and "Finished building" highlighted in green similar to the below:


Test contract


When working with blockchains, we can't underestimate the importance of good tests. As developers, we have to make sure that code deployed on a blockchain network is as resilient as possible to bugs and unfortunate events. One of the best things we can do to ensure this is the case is to test it before we deploy it in the first place. All tests should be reproducible and as exhaustive as possible.

Tests for Ethereum (Quorum) contracts are written in JavaScript. This language offers plenty of resources to make test-driven development easy. The bridge between any Ethereum contract and a JavaScript test is called Web3.js. This library helps connecting to an Ethereum node (either local or remote) and test a contract on the network through JavaScript and its libraries.

We are going to write our tests inside of the Embark generated environment, which means that a lot of things have already been taken care of to make our life easier:

  • every time we run tests with embark test, our contract will be automatically built and deployed locally.

  • accounts for the privately deployed contracts will be returned to us, so we can use them for testing straight away.

  • web3 will be exposed for all tests as a global object and its methods can be consumed directly.

  • Node's assert will be exposed globally without additional dependencies.

  • any additional libraries for advanced assertions (Chai) can also be plugged in and used.


You can read more about Embark's testing config here.

However, in our code we are going to create a fresh contract instance manually before each test case as per below code snippet:
const MyFioriToken = require('Embark/contracts/MyFioriToken');

contract("MyFioriToken", function (accounts) {

const _name = "Fiori Token";
const _symbol = "FIO";
const _decimals = 0;
let fcInstance;

beforeEach(async function () {
fcInstance = await MyFioriToken.deploy({ arguments: [_name, _symbol, _decimals] }).send();
});

it("Should do something as Test Case 1", async function () {
...
});

it("Should do something as Test Case 2", async function () {
...
});

});

The code above is quite obvious: we import the contract definition from the project folder, instantiate the contract with initial values and predefine the test cases.

Nevertheless, there's a little catch if you haven't used the web3 before. There's a send() method call, which interacts with the blockchain network and alters its state by deploying the contract. You should use the send() every time you would like to call a contract's method, which forces execution of a transaction in the network (setter functions). On the other hand, the call() method is used for contract's methods, which don't alter the state of the network (getter functions).

Note the use of the await operator in the deploy call inside of the async function. The operator is used there in order to wait for the resolution of a JavaScript Promise. Asynchronous calls are used a lot in blockchain tests because smart contract calls changing the contract state are sent to the network as transactions and must be mined, which can take considerable time.

Tokenization


Yes, let's try to create a simple implementation of  based on OpenZeppelin library!

As you know, there have been numerous efforts of tokenizing real-world assets to trade on blockchains.

Tokenization is the concept of assigning a “token” as a unit of value to a specific asset it represents. In the blockchain domain, that means creating a digital token to represent an asset that can be held and traded swiftly over the network.

Famously known ERC specifications (stands for Ethereum Request for Comments) allow different token implementations to follow a shared programming interface. ERC20 is the definition of a basic fungible (interchangeable) token that can be sent around on Ethereum.

Several blockchain projects have sold ERC20 tokens representing shares or voting rights to raise funds in ICOs (Initial Coin Offerings). Non-fungible tokens, often in the form of ERC721 tokens, are used to represent unique items such as collectibles (e.g. Cryptokitties) and digital art (e.g. SuperRare).

There are a few safe libraries simplifying development of the ERC20 tokens. One of them is OpenZeppelin's implementation, which has already been tested properly, so that we can re-use it in our project here.

The contract itself is quite simple and bare-bones, it doesn't contain any strict rules on how the contract is instantiated and how many tokens it should supply on creation. This totally depends on us.

In the code snippet above we've already created a contract with its own supply mechanism. It does not produce any fixed amount of tokens on creation, but it's able to mint certain amount of tokens for an account with special method named deposit.

Adding a few more test cases


So in order to test our supply mechanism, we should create certain test cases.

Firstly, let's check that when a new contract is created, it has no supply of tokens and accounts' balances are 0:
it("Should create a contract with zero supply", async function () {
let result = await fcInstance.methods.totalSupply().call();
assert.equal(result, 0);
});

it("Should create a contract with zero balance for an account", async function () {
const account0 = accounts[0];
let result = await fcInstance.methods.balanceOf(account0).call();
assert.equal(result, 0);
});

Then, let's verify that tokens are minted and assigned to an account by the deposit method:
it("Should mint tokens for an account", async function () {
const account0 = accounts[0];
await fcInstance.methods.deposit().send({ from: account0, value: 10 });
const result = await fcInstance.methods.balanceOf(account0).call();
const balance = parseFloat(result);
assert.equal(balance, 10);
});

After this we can easily make sure that tokens are transferred successfully between accounts. We mint 10 tokens for each account, then transfer 2 from one to another and check balances:
it("Should pass tokens between accounts", async function () {
const account0 = accounts[0];
const account1 = accounts[1];

await fcInstance.methods.deposit().send({ from: account0, value: 10 });
const result0 = await fcInstance.methods.balanceOf(account0).call();
const balance0 = parseFloat(result0);
assert.equal(balance0, 10);

await fcInstance.methods.deposit().send({ from: account1, value: 10 });
const result1 = await fcInstance.methods.balanceOf(account1).call();
const balance1 = parseFloat(result1);
assert.equal(balance1, 10);

await fcInstance.methods.transfer(account1, 2).send({ from: account0 });
const result2 = await fcInstance.methods.balanceOf(account1).call();
const balance2 = parseFloat(result2);
assert.equal(balance2, 12);

const result3 = await fcInstance.methods.balanceOf(account0).call();
const balance3 = parseFloat(result3);
assert.equal(balance3, 8);
});

We can add another test case, which will actually fail at this stage because we haven't introduced any protection from multiple deposits:
it("Should not allow minting tokens for same account twice", async function () {
const account0 = accounts[0];
await fcInstance.methods.deposit().send({ from: account0, value: 10 });
await fcInstance.methods.deposit().send({ from: account0, value: 10 });
const result = await fcInstance.methods.balanceOf(account0).call();
const balance = parseFloat(result);
assert.equal(balance, 10);
});

So in order to keep a list of all the accounts that have been deposited with any amount of tokens at least once, we can add a mapping named _toppedUpAccounts and enhance the deposit method with an additional check:
pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

contract MyFioriToken is ERC20 {
string public name;
string public symbol;
uint256 public decimals;
mapping(address => bool) private _toppedUpAccounts;

constructor(string _name, string _symbol, uint8 _decimals)
ERC20()
public
{
name = _name;
symbol = _symbol;
decimals = _decimals;
}

function deposit() public payable returns (bool) {
bool result = false;
if (!_toppedUpAccounts[msg.sender]) {
uint256 value = msg.value * 10**decimals;
increaseAllowance(msg.sender, value);
result = mint(msg.sender, value);
if (result) {
_toppedUpAccounts[msg.sender] = result;
}
}

return result;
}

function mint(address to, uint256 amount) public returns (bool) {
_mint(to, amount);
return true;
}
}

So now all the test cases should run successfully on embark test:



You can find the source code for this project here in my public repository.

Deployment


I would recommend you to follow the official guide to deploy your contract on Quorum via Remix.

Conclusion


While the shown functionality does not have reach graphical representation, it can work as a solid foundation to quite a few interesting concepts. I hope to develop and describe it further in the nearest future.

Thank you for reading!