In this tutorial, we will show you step-by-step how to create a new blockchain project, using the Truffle framework and Open Zeppelin smart contracts library, connected to an RSK local node or RSK testnet.
RSK is an open-source platform for Ethereum compatible smart contracts based on the Bitcoin network.
It does not matter whether you are an experienced developer, or just learning to code, you do not need to be a blockchain expert to follow along.
Here is a summary of the steps to be taken to build our project:
POSIX compliant shell
The Portable Operating System Interface (POSIX) is a family of standards specified by the IEEE Computer Society for maintaining compatibility between operating systems. POSIX defines the application programming interface (API), along with command-line shells and utility interfaces, for software compatibility with variants of Unix and other operating systems. Source: Wikipidia
This is a system command that is likely already installed on your system, which allows you to make network requests, such as HTTP requests, from your command line.
If curl --version displays an error, download curl.
You will need Java 8 in order to run RSKj.
Check if you already have Java installed:
java -version
If the above command displays an error or displays a version other than 1.8, you will need to install it.
Go to the official Java download page, download, and run the installer from there.
Node.js and NPM are needed, though both are usually installed at once.
NB: To check if Node.js and NPM are already installed, input the following commands in the terminal:
node --version
npm --version
If you got an error, go to Node.js to install it.
Note that NPM is usually installed together with Node.js, so after installing Node.js, there’s no need to install it separately.
If you want to have more than one version installed, the most fuss-free way to install and manage multiple versions of the node on your computer is nvm.
We need some software that is able to edit text files. Preferably one that has support for syntax highlighting for both Solidity and Javascript.
In this tutorial, we will use VS Code to create our project, you can download it here.
Verify if your VS Code installation was successful by typing the following command into the terminal:
code -v
Truffle is a popular development framework with a mission to make smart contract development easier for developers. Amongst its features, it has a smart contract lifecycle management, scriptable deployment & migrations, automated contract testing, and simple network management.
It also makes developing on RSK easier, with the ability to configure custom networks for RSK.
To install Truffle, input the command below into the terminal and press enter at your project location:
npm install -g truffle
When the installation is finished, close the terminal, open it again and check the Truffle version:
truffle version
When we develop a project using Truffle Framework, we need a blockchain node running locally. This is better for development and running tests. We’ll connect to the RSK network via this local node.
There are several ways to set up an RSK local node. Here, we will download a JAR file and run it using the Java SDK that has been installed.
Go to the releases page and click on the most recent to download it.
You need to click on the JAR file, at the end of the post about the latest release. Its name should be rskj-core-*.jar
When installing and running the RSKj node, it is always a good idea to verify that your copy is legitimate.
In the folder where you download the JAR file, go to a POSIX terminal and run this command:
sha256sum rskj-core-2.0.1-PAPYRUS-all.jar
For this version, it looked like this:
Note that if you are using Windows, you will need a POSIX compliant shell for this. See instructions about using Git Bash above.
For more information about verifying that your copy is legitimate, including signature verification, check out the full instructions on how to do this.
To run the node:
java -cp <PATH-TO-THE-RSKJ-JAR> -
Drpc.providers.web.cors=* co.rsk.Start --regtest
(Replace with your path to the JAR file).
I am using a Windows OS and I saved the file at C:\RSK\node, so for me the full path is C:\RSK\node\rskj-core-2.0.1-PAPYRUS-all.jar.
The commands required to run the RSK node are:
On Windows terminal
java -cp C:\RSK\node\rskj-core-2.0.1-PAPYRUS-all.jar -
Drpc.providers.web.cors=* co.rsk.Start --regtest
Using Git Bash
java -cp C:/RSK/node/rskj-core-2.0.1-PAPYRUS-all.jar -
Drpc.providers.web.cors=* co.rsk.Start --regtest
On Linux and Mac
java -cp ~/RSK/node/rskj-core-2.0.1-PAPYRUS-all.jar -
Drpc.providers.web.cors=* co.rsk.Start --regtest
If you see no output - that is a good thing: Its output is directed to a log file.
Note the flag provided above: -Drpc.providers.web.cors=* This disables cross-origin resource sharing protection, effectively allowing any web page to access it. As we want to make JSON-RPC requests from a browser, such as a DApp, we need this flag.
This is the result in the terminal in Windows OS:
Important
Do not close this terminal/console window, if closed the local node will stop running.
Open a new terminal window.
Issue a JSON-RPC request to the RSK node’s HTTP server.
This is an example using cURL:
curl localhost:4444/1.1.0/ -X POST -H "Content-Type: application/json"
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
The response should look similar to this:
{"jsonrpc":"2.0","id":1,"result":"0x2991b"}
The result property is the number of the latest block that has been synced. Note that this value (0x2991b) is the block number in hexadecimal (base 16), so the output above indicates that the current block number is 170267 in decimal (base 10).
In addition to using the local node, we want to publish smart contracts to the testnet. Before it, let’s check if the connection is working.
This is an example using cURL. Enter the following command into your terminal.
curl https://public-node.testnet.rsk.co/2.0.1/ -X POST -H "Content-Type:
application/json" --data
'{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
This is a very simple query that simply asks what the latest block number is. You should receive a response similar to the following:
{"jsonrpc":"2.0","id":1,"result":"0xc3f9b"}
The result field is presented in hexadecimal. 0xc3f9b is the block number, and it’s decimal equivalent is: 802715. You can consult the testnet explorer and verify that it is the same result for block number.
We have two options for initializing a project:
An empty project
A project based in a Truffle Box
Create a new folder. For example, myproject, and navigate to the folder in the terminal.
mkdir myproject
cd myproject
For example, I will create a folder at this location: C:\RSK\ (I’m using Windows).
My project can be located in the folder C:\RSK\myproject.
In your project folder, start an Truffle project by typing the command below into the terminal:
truffle init
Open the folder in VS Code to view the file structure like this:
./contracts: All our smart contracts will be stored in this folder.
./migrations: Deployment scripts will be stored in this folder.
./test: Test scripts will be stored in this folder.
./truffle-config.js: This is Truffle’s configuration file used to configure networks, including RSK networks.
Note that the following files were also created:
Migrations.sol: Keeps track of which migrations were done on the current network.
1_initial_migration.js: Deployment instructions for Migrations.sol.
Initialize an npm project
When we initialize an empty Truffle project, we also need to initialize an npm project.
Start an npm project in the myproject folder by typing the following commands below into the terminal:
npm init -y
Note: Only do this if you have not done option 1.
Truffle Boxes are templates. In addition to Truffle, Truffle Boxes can contain other helpful modules, such as Solidity smart contracts, libraries, front-end views, and more.
In option 1, when we use truffle init, we used a special kind of truffle box. Check out other boxes.
Also we have some of them already configured for RSK, check it out here.
Open Zeppelin Contracts is a set of libraries of Solidity smart contracts for Ethereum and other blockchains. These libraries will install not only the main libraries required for our token, but also libraries for ownership, safe math, and many other utilities. It’s worth mentioning that these libraries have been reviewed and audited to accomplish high standards of security, so contracts that depend on them are less susceptible to hacking when used correctly.
In the terminal, inside myproject folder, install Open Zeppelin libraries using this command:
npm install -E @openzeppelin/contracts@2.5.0
The option -E is to save dependencies with an exact version rather than the latest version published on npm.
Some contracts may change over time, so it is important to set the version. This tutorial was written using this specific version.
To connect to the RSK network, we are going to use a provider that allows us to connect to any network by unlocking an account locally. We are going to use @truffle/hdwallet-provider. This can be used to sign transactions for addresses derived from a 12 or 24 word mnemonic.
You need to have Node >= 7.6 installed.
In the terminal, inside the myproject folder, install the HD wallet provider with this command:
npm install -E @truffle/hdwallet-provider@1.0.34
This truffle package comes with many dependencies, and so can take a long time to complete. A successful installation message is shown if everything works fine.
To use testnet, we need tR-BTC and an address to store them. The best way is to create a wallet from a mnemonic, using the pattern defined at BIP39
There are a few ways to do this.
One is to create using a web wallet, such as Metamask or Nifty wallet. These wallets generate the mnemonic for you. If you wanted to create using Metamask, you can get the instructions here:
using Remix and Metamask with RSK testnet
Another way is using this web app:
Note: In this tutorial, the method used to store the mnemonic is not recommended to be used for any ‘real’ wallet because it’s not secure enough to generate a private key in a website, however we will use this here for learning purposes, and because we’re using the Testnet, so no real amounts are at stake.
In the Generate a random mnemonic field, select 12 words and click on the generate button.
The result appears in the BIP39 Mnemonic field. They should be 12 random words like the words in the image:
My mnemonic is:
energy knife ice mouse merge track cram brown decorate atom rule virus
Copy these 12 words, we’ll use it later in this tutorial.
Another alternative is using package mnemonics, which is a simple utility that can be used to generate BIP39 mnemonics.
To install mnemonics globally, input the command below into the terminal and press enter at your project location:
npm install -g mnemonics@1.1.3
Use this to generate a 12-word BIP39 mnemonic, by entering this command:
mnemonics > .secret
This saves a new mnemonic in the file named .secret, which is the next step.
In the terminal, inside the myproject folder, create a file named .secret.
Do you remember your mnemonic? Paste your mnemonic in this file and save it.
Open
truffle-config.js
file in your Truffle project and overwrite it with the following code:const HDWalletProvider = require('@truffle/hdwallet-provider');
const fs = require('fs');
const mnemonic = fs.readFileSync(".secret").toString().trim();
if (!mnemonic || mnemonic.split(' ').length !== 12) {
throw new Error('unable to retrieve mnemonic from .secret');
}
module.exports = {
networks: {
},
compilers: {
solc: {
}
}
}
The hdwallet-provider allows us to connect to any network by unlocking an account locally, including the RSK networks.
Also, we are loading the mnemonic stored in file .secret, and saving it at variable mnemonic.
In the truffle-config.js file, include this configuration at network section:
development: {
host: "127.0.0.1",
port: 4444,
network_id: "*"
},
This is the result:
Get the current gas price of the testnet network, and save to .gas-price-testnet.json.
In your project folder, run this cURL command:
curl https://public-node.testnet.rsk.co/2.0.1/ -X POST -H "Content-Type:
application/json" --data
'{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":1}' >
.gas-price-testnet.json
You should receive a response similar to the following in the file:
{"jsonrpc":"2.0","id":1,"result":"0x3938700"}
The result value is presented in hexadecimal.
Modify the truffle-config file again to use the updated gas price. After mnemonic part, include this:
const gasPriceTestnetRaw =
fs.readFileSync(".gas-price-testnet.json").toString().trim();
const gasPriceTestnet = parseInt(JSON.parse(gasPriceTestnetRaw).result, 16);
if (typeof gasPriceTestnet !== 'number' || isNaN(gasPriceTestnet)) {
throw new Error('unable to retrieve network gas price from
.gas-price-testnet.json');
}
console.log("Gas price Testnet: " + gasPriceTestnet);
In the truffle-config.js file, include this configuration at network section:
testnet: {
provider: () => new HDWalletProvider(mnemonic, 'https://public-node.testnet.rsk.co/2.0.1/'),
network_id: 31,
gasPrice: Math.floor(gasPriceTestnet * 1.1),
networkCheckTimeout: 1e9
},
This is the final truffle-config.js file with configurations for both networks:
const HDWalletProvider = require('@truffle/hdwallet-provider');
const fs = require('fs');
const mnemonic = fs.readFileSync(".secret").toString().trim();
if (!mnemonic || mnemonic.split(' ').length !== 12) {
throw new Error('unable to retrieve mnemonic from .secret');
}
const gasPriceTestnetRaw = fs.readFileSync(".gas-price-testnet.json").toString().trim();
const gasPriceTestnet = parseInt(JSON.parse(gasPriceTestnetRaw).result, 16);
if (typeof gasPriceTestnet !== 'number' || isNaN(gasPriceTestnet)) {
throw new Error('unable to retrieve network gas price from .gas-price-testnet.json');
}
console.log("Gas price Testnet: " + gasPriceTestnet);
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 4444,
network_id: "*"
},
testnet: {
provider: () => new HDWalletProvider(mnemonic, 'https://public-node.testnet.rsk.co/2.0.1/'),
network_id: 31,
gasPrice: Math.floor(gasPriceTestnet * 1.1),
networkCheckTimeout: 1e9
},
},
compilers: {
solc: {
}
}
}
Truffle has its own console to run commands and can be connected on any network previously configured in truffle-config.js file.
Let’s open a Truffle console to connect to our local node.
In the terminal, inside the myproject folder, run this command:
truffle console
Any network defined with the name development is considered the default network.
Thus far we have only connected to a blockchain that runs using just 1 node, that runs on your own computer. Let’s now switch to interacting with a “real” blockchain, which is running on multiple nodes distributed across multiple computers!
To connect Truffle console in another network, you need to specify the network:
In a new terminal, inside the myproject folder, run this command:
truffle console --network testnet
It takes a little longer to establish this connection when compared to the local node. This will open a new console.
On any of the networks, run this commands in the Truffle console:
Block number
Shows the last block number.
(await web3.eth.getBlockNumber()).toString()
Network ID
To get the network ID, run this command:
(await web3.eth.net.getId()).toString()
For the local node, the network ID is 33.
And for testnet, it is 31.
In the Truffle console, enter this command to exit the terminal:
.exit
We will use a special instruction in Truffle console to get the first 10 addresses in our hierarchical deterministic wallet for the RSK Testnet network, that are generated from our mnemonic.
In the terminal, inside the myproject folder, go to the Truffle console connected to testnet:
truffle console --network testnet
And run this command to save the addresses at variable accounts:
const accounts = Object.keys(web3.currentProvider.wallets)
See the addresses after it by entering the command below:
accounts
Now we will write them to a file named .accounts
await require('fs').promises.writeFile('.accounts', accounts.join('\n'))
To check the balance of an account, for example, the first account of our list (account[0]), run this command in Truffle console:
(await web3.eth.getBalance(accounts[0])).toString()
The balance is 0 and we need some tR-BTC to pay gas fees, which will be used to publish smart contracts and interact with them. We shall obtain some in the next step.
You can get some tR-BTC from the RSK Testnet faucet.
Copy the first address from .accounts file. In my case, it is
0xe16f6abdd5815f3d24b4e5c29138f863933b000a
Enter your wallet address and pass the CAPTCHA.
Wait a few seconds…
You can see my transaction hash:
0x4a2bf1f65c525219020c3a1215a29453c20f4ced90575d9a7d13f8fe666d05b4
Now I have 0.05 R-BTC!
To check balance again, run this command in the Truffle console:
(await web3.eth.getBalance(accounts[0])).toString()
Great! Now I have 50000000000000000, which means that I have 0.05 tR-BTC with 18 decimal places of precision.
Where to go from here
At this point, we have installed all requirements and created an empty project using Truffle framework and Open Zeppelin smart contracts library, connected to both an RSK local node (Regtest) and the RSK Testnet.
We have not developed anything yet, but you are now ready to move on to the next tutorials, where we will develop some very cool projects!
Author: Solange Gueiros | Reviewers: Brendan Graetz and Owanate Amachree