Pay-per-use business models from the industry – first steps with the EOSIO blockchain

In the fourth industrial revolution, existing business models are going to be turned upside down. If you want to continue to be successful, you will have to stay on the cutting edge with the help of new technologies and find new business models for yourself. We are already familiar with service-driven business models such as pay-per-use from well-known cloud providers such as Azure and AWS. If one looks at the machines and their components in the industrial environment much more as a dynamic rather than a static composition, one can draw parallels with the cloud. In networking of all components in a factory, it is important to build a manufacturer-neutral and interoperable platform for communication between components and for secure storage of data. That’s exactly where blockchain comes in.

In this blog entry, we talk about how to implement a prototype for usage-based billing of services in an industrial environment with the help of the EOSIO blockchain.

The concrete use-case

In the pay-per-use business model, the machine operators no longer buy the machines from the manufacturer, but only pay for the actual use. This brings some advantages for both the operator and the manufacturer. 1

The range of services can stretch from a simple rotation of a motor to a complex digital service. Nowadays a system in a factory can consist of several individual machines and these in turn consist of several components from different manufacturers. They interact with each other and use mutual services. This means that these components also charge each other for what has been provided. A component could be a machine, but also a tiny sensor.

For our prototype, we focus on an exemplary component: an engine that offers revolutions as a service. But how can the billing for this service be stored securely?

Why blockchain?

If each manufacturer stored their data by themselves and at a certain time send all their customers a bill, that would have disadvantages. For example, no one could check whether the manufacturer is actually billing correctly and is not cheating on its customers. This leads to a central problem that distributed ledger technologies (DLT) attempts to solve: establishing trust where none exists. Since this is all about finances, there is usually no full degree of trust between manufacturer and operator.

The DLT, and thus also the blockchain, not only establish trust through consensus algorithms and cryptographic methods, but also offer the advantage that they are decentralized. Therefore, there is no single point-of-failure. So, if a manufacturer decides that they no longer want to participate in it, or if a server has a technical failure, the data still exists, distributed among all other parties involved.

The most important features that the blockchain offers for our use case are therefore the following:

  • Decentralized data storage
  • Anti-fraud security
  • Traceability

There are also other advantages and disadvantages, which we do not go into at this point.

How to develop a Dapp

At the beginning, it’s important to know which technologies you’ll use for your app. The final selection depends strongly on the intended use, because each technology has different strengths and weaknesses. In the following scenario, we chose EOSIO technology.2

It is the underlying technology for the cryptocurrency EOS and is developed by the company as an opensource project. The Initial Coin Offering went on for a full year and holds a record with 4.1 billion USD in revenue. This will finance the development of blockchain software, as well as investments in EOSIO startups.

EOSIO is basically very modularly built and uses the plugin design pattern. So, it is relatively easy for developers to adapt the software for the nodes (called nodeos) in the blockchain network, to their wishes. But the software architecture of smart contracts on the blockchain is also highly modularized. In itself, EOSIO has a Delegated Proof of Stake Consensus mechanism. 3 This, in turn, is implemented by so-called system smart contracts. It is therefore up to the developers themselves whether they want to use this or others.


The smart contract for our use case stores requests to the engine with a certain number of revolutions. These requests can then be processed by the engine and declared as redeemed. A service request is therefore in the following status:

Service { buyer, seller, amount, state = (BOUGHT|REDEEMED) }

And can be changed with the two transactions buy and redeem.

buy(buyer, seller, amount): id

  • A new instance of the request is created on the blockchain. The buyer ordered amount (a sum) of revolutions from the seller. The transaction returns a unique ID of the instance.

redeem(id, seller)

  • This redeems a request to the seller with an id.

The smart contracts on EOSIO run on WebAssembly (WASM). EOSIO officially only supports C++; since there are now many compilers that translate to WASM, you have a wide range of possible programming languages. We decided to write the smart contract in Rust. For this purpose, you can already find an SDK ported to Rust on GitHub for developing EOSIO Smart Contracts. 4

Implementation in Rust

We create a new library with cargo.

$ cargo new --lib smartcontract

To compile the library later according to WebAssembly, we define the type of the library in our Cargo.toml. We also specify our dependencies for the EOSIO SDK there.

[lib] crate-type = ["cdylib"] [dependencies] eosio = "^0.3.1" eosio_cdt = "^0.3.1" [profile.release] lto = true

In our entry-level code, we first import the EOSIO SDK. This provides important traits and macros that reflect EOSIO’s API.

use eosio::*; use eosio_cdt::*;

We define the structure of our service request.

#[derive(NumBytes, Read, Write)] struct Service { id: u64, buyer: AccountName, seller: AccountName, amount: u64, redeemed: bool, }

The Struct implements the traits NumBytes, Read and Write from EOSIO SDK, so that this can be serialized later into the blockchain. The AccountName type comes from the EOSIO SDK and represents an account in the blockchain network.

The table implementation is realized with the Trait Tableof the SDK. This allows the struct Service to be serialized in the form of a table on the blockchain.

impl Table for Service { const NAME: TableName = TableName::new(n!("service")); type Row = Service; fn primary_key(row: &Self::Row) -> u64 { } }

This indicates that the service instances can be stored in a table on the blockchain and that the primary key is mapped to the id attribute.

An action for the smart contract itself is defined as a function.

#[eosio::action] fn buy(buyer: AccountName, seller: AccountName, amount: u64) { require_auth(&buyer); let smart_contract_account = current_receiver(); let table = Runtime::table(smart_contract_account, n!("global")); let id = table.available_primary_key().expect("There must be an available primary key!"); let runtime = Runtime { id, buyer, seller, amount, redeemed: false }; table.emplace(smart_contract_account, runtime).expect("Could not emplace new bought service."); }

We first check whether the buyer‘s account also corresponds to the account with which the transaction was made. This is important and prevents a foreign machine from creating a request on behalf of another machine. Then we get the already saved table, have the next available ID calculated and save a new instance of the request with the transferred data again in the table. The implementation for the redeem action works analogously.

Interface Definition – ABI

In addition to the WebAssembly code, the smart contract also consists of a definition that describes the structure and interaction with the smart contract. This is described in the form of an ABI file, as is common in the WebAssembly environment. When developed in C++, it is generated automatically. In the Rust SDK, however, this functionality is still missing in the current status.

The ABI describes the different types and actions of the smart contracts. It can also be written manually. For more information, see the EOSIO developer documentation. 5

The ABI for our Smart Contract looks like this:

{ "version": "eosio::abi/1.0", "types": [], "structs": [ { "name": "buy", "base": "", "fields": [ { "name": "buyer", "type": "name" }, { "name": "seller", "type": "name" }, { "name": "duration", "type": "uint64" } ] }, { "name": "redeem", "base": "", "fields": [ { "name": "id", "type": "uint64" } ] }, { "name": "runtime", "base": "", "fields": [ { "name": "id", "type": "uint64" }, { "name": "buyer", "type": "name" }, { "name": "seller", "type": "name" }, { "name": "duration", "type": "uint64" }, { "name": "redeemed", "type": "bool" } ] } ], "actions": [ { "name": "buy", "type": "buy", "ricardian_contract": "" }, { "name": "redeem", "type": "redeem", "ricardian_contract": "" } ], "tables": [ { "name": "runtime", "type": "runtime", "index_type": "i64", "key_names": ["id", "buyer", "seller"], "key_types": ["uint64", "name", "name"] } ], "ricardian_clauses": [], "abi_extensions": [] }

More detailed information on API, smart contract development and compilation can be found here:

Setting up an EOSIO Blockchain Network

EOSIO is not only used in the EOS network. You can use a second official test network to test smart contracts or set up your own private network. The EOS network is publicly accessible and therefore all stored data is freely viewable. In our use case, however, we do not want to disclose the confidential billing data publicly and therefore build up a closed network in the following.

In EOSIO you can basically classify the nodes into different classes.

  • There are Light-Nodes, i.e. nodes that only connect to other nodes but do not store data themselves.
  • The Full-Nodes store the blockchain itself but will not produce blocks themselves.
  • And then there are the Block-Producer. These are the nodes in the network that have been selected to produce the blocks.

For example, we will set up two nodes and configure both as block producers. The first node is operated by the manufacturer XITASO1 and the second by the manufacturer XITASO2. For simplicity, both nodes will run on a virtual machine running Ubuntu 18.04.

First, we will install the required binary files from EOSIO, which are available for the most common operating systems. 6

Three different programs are installed.

  • keosd – a daemon that controls a wallet, i.e. the key store.
  • nodeos – the actual software for the blockchain network nodes.
  • cleos – the CLI that allows you to address the nodes and access the wallet.

At the beginning, we start our daemon with keosd &&, as both the nodes and cleos need access to the wallet and create a wallet with cleos wallet create --to-console. The wallet must be unlocked first with cleos wallet open and then with cleos wallet unlock.

Our first block producer belongs to the account eosio. This is the default account that always exists. eosio signs the blocks with a standard key. This is also required to authorize actions with the account. This is always the same at the beginning, is for development purposes only and should be replaced as soon as possible! But first we have to import it:

$ cleos wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

Then we can start the node with the following command.

$ nodeos -e -p eosio \ --data-dir ~/.local/share/eosio/eosio \ --config-dir ~/.local/share/eosio/eosio \ --plugin eosio::producer_plugin \ --plugin eosio::producer_api_plugin \ --plugin eosio::chain_api_plugin \ --plugin eosio::http_plugin \ --plugin eosio::history_plugin \ --plugin eosio::history_api_plugin \ --filter-on="*" \ --access-control-allow-origin='*' \ --contracts-console \ --http-validate-host=false \ --verbose-http-errors \ --disable-replay-opts >> eosio.log 2>&1 &

We also specify that all data is stored in the .local/share/eosio/eosio-folder. The --data-dir and --config-dir parameters are optional, but should be specified on a multi-node network, otherwise all nodes use the same storage location. In addition, we start the node with a handful of plugins, which are necessary either for block production or for communication between cleos and nodeos. More information on the handling of nodeos can be found here:

The account system in EOSIO is tree-like. Each account can only be created from a different account and is then subdivided into it. So, for our second block producer we need a second account. To achieve this, we first create a new key pair consisting of a public and a private key.

$ cleos wallet create_key

This command outputs the public portion of the key to the console. We will assign this to our second account inita.

$ cleos create account eosio inita <PublicKey>

As already mentioned, the smart contract system is very modularly built. For example, the functionality for setting the active block producers is implemented in a low system smart contract. To install it, we need to download and compile it.

$ git clone --branch v1.7.0 --single-branch $ wget $ sudo apt install ./eosio.cdt_1.6.3-1_amd64.deb

These commands clone the open-source project of EOSIO’s system smart contracts and install the Development SDK for C++ Smart Contracts.

In addition to the build-essential, cmake is also required for compilation.

$ sudo apt install build-essential cmake -y

After the successful installation, we compile the smart contract projects.

$ cd /eosio.contracts/ $ rm -fr build $ mkdir build $ cd build $ cmake .. $ make -j$( nproc ) $ cd ..

The installation of system smart contracts must be activated with the following command. In version 2.0, this is done with the following API call.

curl -X POST -d '{"protocol_features_to_activate": ["

Then we can install the responsible smart contract eosio.bios.

$ cleos set contract eosio /build/contracts/eosio.bios

Now we specify our block producers in a schedule.json file. However, we need two new key pairs that will serve as signing keys for the blocks.

$ cleos wallet create_key # output = <PublicKeyEOSIO> $ cleos wallet create_key # output = <PublicKeyINITA>

Then we describe our active block producer

{ "schedule": [ { "producer_name": "eosio", "block_signing_key": "<PublicKeyEOSIO>" },{ "producer_name": "inita", "block_signing_key": "<PublicKeyINITA>" } ] }

We then send this schedule to the blockchain using the installed smart contract.

$ cleos push action eosio setprods "<path-to-json>/schedule.json" -p eosio@active

Thus, we have determined two active block producers, each signing the blocks with different keys. Then we start our second node inita so that it can copy the previous blockchain history from eosio. For this we also need the private share of the newly created key pair. To do this, we display the keys stored in the wallet.

$ cleos wallet private_keys
$ nodeos -e -p inita \ --data-dir ~/.local/share/eosio/inita \ --config-dir ~/.local/share/eosio/inita \ --http-server-address \ --p2p-listen-endpoint \ --p2p-peer-address \ --plugin eosio::producer_plugin \ --plugin eosio::net_api_plugin \ --plugin eosio::chain_api_plugin \ --signature-provider <PublicKeyINITA>=KEY:<PrivateKeyINITA> \ >> inita.log 2>&1 &

We only start this second node with plugins that we need, and define other ports for our own endpoints, since the default ones are already occupied by the first node.

However, the eosio node does not yet have its assigned key, so we need to restart it.

$ ps $ kill $ nodeos -e -p eosio \ --data-dir ~/.local/share/eosio/eosio \ --config-dir ~/.local/share/eosio/eosio \ --plugin eosio::producer_plugin \ --plugin eosio::producer_api_plugin \ --plugin eosio::chain_api_plugin \ --plugin eosio::http_plugin \ --plugin eosio::history_plugin \ --plugin eosio::history_api_plugin \ --filter-on="*" \ --access-control-allow-origin='*' \ --contracts-console \ --http-validate-host=false \ --verbose-http-errors \ --disable-replay-opts \ --signature-provider <PublicKeyEOSIO>=KEY:<PrivateKeyEOSIO> \ >> eosio.log 2>&1 &

This gives us a working multi-node network on which we can install our self-built smart contract. We also want to assign this to its own account. We also need at least two test accounts to test our use case.

To do this, we create three new key pairs again. One for each account.

$ cleos wallet create_key # 3x

After that, we will create the new accounts and install the smart contract on the iot account.

$ cleos create account eosio iot <PublicKeyIOT> $ cleos create account iot testbuyer <PublicKeyBuyer> $ cleos create account iot testseller <PublicKeySeller>

Then we install our smart contract. This should of course have already been compiled into WebAssembly.

$ cleos set abi iot <path-to-smart-contract>/smartcontract.abi $ cleos set code iot <path-to-smart-contracts-wasm>/smartcontract.wasm

We have thus sent a transaction with the semantic contract and the associated code to the blockchain network and stored it there.

To the account keys

EOSIO breaks down the key pairs of accounts. We have assigned a so-called owner key to all accounts. However, this can and should be subdivided into an Active key. All interactions and transactions should be performed with it, because if it is stolen or lost, it can be replaced using the Owner key. The Owner key cannot be readily changed.

The connection to the network

To test our application (DAPP), we need a client that interacts with the created system. For this purpose, EOSIO provides an official node client eos.js, which can be installed with npm.

Before we can send a transaction to the network with this client, we need the private key of an account that then signs it. To claim a service, we use the testbuyer account. To find the keys of the account, we can use cleos to query the network and connect our wallet.

$ cleos get account testbuyer # -> Owner Pulic Key $ cleos wallet private_keys # Eintrag mit Public Key finden

To connect to the network via eos.js, the client provides two classes. JsonRpc establishes the rpc connection to the node, and Api in turn uses JsonRPC and takes care of encoding and other logic. In addition, we need to transfer the private key in a SignatureProvider instance of the Api. For the prototype we use the JsSignatureProvider,which however is only intended for development purposes.

import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig'; import { JsonRpc, Api, RpcError } from 'eosjs'; import fetch = require('node-fetch'); import { TextEncoder, TextDecoder } from 'util'; const hostUrl = ''; const privateKey = ''; const signatureProvider = new JsSignatureProvider([privateKey]); const rpc = new JsonRpc(hostUrl, { fetch } ); const api = new Api({rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder()}); function buyService(amount) { const payload = { account: 'iot', name: 'buy', authorization: [{ actor: 'testbuyer', permission: 'active' }], data: { buyer: 'testbuyer', seller: 'testseller', duration: amount, } }; const options = { blocksBehind: 3, expireSeconds: 30 }; try { return await api.transact({actions: [payload]}, options); } catch(err) { console.log("Could not transact: " + err); if (err instanceof RpcError) console.log(JSON.stringify(err.json, null, 2)); } }

This is how the function for a purchase request for a service on the client side might look. eos.js also offers the possibility to demand the stored data and information about blocks. These functionalities are implemented using nodeos plugins on the nodes.


On the one hand, we dealt with how to build a multi-node network with EOSIO and how to install various smart contracts there as well as the necessary accounts with permissions. We also took a quick look at the integration of clients with eos.js. With our developed prototype, we have scratched the potential of EOSIO. With its very good documentation, EOSIO offers a smooth introduction to development with blockchain technology.

In our use case, we presented what a digital interoperable platform could look like in an industrial environment in order to implement new business models such as pay-per-use. New blockchain technologies such as EOSIO enable easy and fast implementation of secure process handling and thus offer enormous potential for the industry.

Authors & contact persons

Do you have questions, ideas or feedback on this topic? Feel free to contact us!


Michael Damböck


Jonas Geschke