Using Truffle with Quai Network

Introduction

Truffle suite is a powerful tool built for testing and deploying smart contracts, which can be utilized on any of Quai Network's thirteen chains. Using Truffle you can compile smart contracts, build artifacts, run migrations and interact with deployed contracts using a custom inbuilt console.

Requirements

  • Have a Quai Full Node running.
  • Have the Quai Manager running if you are testing locally.
  • Sufficient balance in the address that you are deploying with.

Dependencies

  • NodeJS v8.9.4 or later.
  • Truffle Development Suite
  • Running Node

Create a truffle directory and install dependencies

1.) Install Truffle Suite
npm install -g truffle
2.) Create a new truffle directory and navigate there
cd path/to/directory
3.) Install required dependencies
npm install web3
npm install @truffle/hdwallet-provider
4.) Initialize Truffle
truffle init

List of HTTP Port, Network Id for each chain

Chain
HTTP Port
Network ID (Mainnet)
Network ID (Testnet)
Prime
8546
9000
12000
Cyprus
8578
9100
12100
Paxos
8580
9200
12200
Hydra
8582
9300
12300
Cyprus1
8610
9101
12101
Cyprus2
8642
9102
12102
Cyprus3
8674
9103
12103
Paxos1
8612
9201
12201
Paxos2
8644
9202
12202
Paxos3
8676
9203
12203
Hydra1
8614
9301
12301
Hydra2
8646
9302
12302
Hydra3
8678
9303
12303

Update truffle-config.js

One of the files created upon running truffle init is truffle-config.js. Paste the code below into truffle-config.js. The port and network_Id information can be found in the table above for each chain in Quai Network.
truffle-config.js
var PrivateKeyProvider = require("@truffle/hdwallet-provider");
var privateKey = "insert private key here"; // private key of the account being used to deploy contract, must be valid address in deployment chain
var protocol = "https" // http or https
var port = 8610 // Cyprus1 http port
module.exports = {
networks: {
quaitestnet: {
provider: () => new PrivateKeyProvider(privateKey, `${protocol}://cyprus1.rpc.quaiscan.io`),
network_id: 9101, // Set to valid mainnet network id, more info can be found at (https://docs.quai.network/build/truffle)
gas: 500000, // Arbitrary gas limit. Gas limits change, so make sure to update this based on the gas limit for the chain you are deploying to
from: "0x...", // Valid mainnet account to send txs from
websocket: true
},
ropsten: {
provider: () => new PrivateKeyProvider(privateKey, `${protocol}://127.0.0.1:${port}`),
network_id: 12101, // Set to valid ropsten testnet network id, more info can be found at (https://docs.quai.network/build/truffle)
gas: 749800, // Arbitrary gas limit. Gas limits change, so make sure to update this based on the gas limit for the chain you are deploying to
from: "0x...", // Valid ropsten account to send txs from
websocket: true
},
},
compilers: {
solc: {
version: "0.8.0", // Set version of solc to use based on your smart contract's version
}
},
// Set default mocha options here, use special reporters etc.
mocha: {
// timeout: 100000
},
};
The changes that must to be made to truffle-config.js are as follows:
  • To decrypt your private key from the Keystore, create a new javascript file and copy the content below. Provide your keystore and provider_url.Run the script using node getPrivateKey.js.
getPrivateKey.js
async function main() {
// keystore - Paste the keystore associated with the account below
var keystore = ''
// provider_url - URL to the node in which you want to deploy along with the right port associated
var provider_url = "" // For Ex: http://localhost:8610 for a local cyprus1 node
var Web3 = require("@quainetwork/web3");
var web3 = new Web3(provider_url);
const PRIVATE_KEY = web3.eth.accounts.decrypt(keystore, "").privateKey;
console.log("Private Key", PRIVATE_KEY);
}
main();
  • Once you have your private key and address, update the truffle-config.js. Note that you can change the protocol, host, port, address, privateKey, gas and network_id variables.

Add a simple Smart Contract inside the contracts folder

MyStatus.sol is a smart contract that stores a status. Status is initialized to be "Busy" below.
MyStatus.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity >0.5.0;
contract MyStatus {
string status;
constructor() public {
status = "Busy";
}
function getStatus() external view returns (string memory) {
return status;
}
function setStatus(string calldata _status) external {
status = _status;
}
}

Add new migration

Create a new file in the migrations directory named, 2_deploy_contracts.js, and add the following block of code. This handles deploying the MyStatus smart contract to the blockchain.
2_deploy_contracts.js
const MyStatus = artifacts.require("./MyStatus.sol");
module.exports = function (deployer) {
deployer.deploy(MyStatus);
};

Compile the Contract with Truffle

truffle compile
You should see the successful compilation
Compiling your contracts...
===========================
> Compiling ./contracts/Mystatus.sol
> Artifacts written to /path/to/build/contracts
> Compiled successfully using:
- solc: 0.5.16+commit.9c3226ce.Emscripten.clang

Migrate and Deploy the Contract

In truffle-config.js, we specified two networks: quaitestnet and ropsten. quaitestnet deploys to the live chain, and ropsten deploys to a Localhost. Below, we'll deploy to the live chain using the --network quaitestnet flag.
truffle migrate --network quaitestnet
Truffle should output this after the successful deployment:
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations...
======================
> Network name: 'quaitestnet'
> Network id: 12101
> Block gas limit: 4990346 (0x4c258a)
2_deploy_contracts.js
=====================
Deploying 'MyStatus'
--------------------
> transaction hash: 0x5b68feffceb0bf4a820eab7e4638bbadc4c58ccebe5168eaa99855fde9410f08
> Blocks: 0 Seconds: 0
> contract address: 0x76C3a4c3A6e2523c62E01163b19B14cF90a1A84c
> block number: 3401
> block timestamp: 1648346192
> account: 0x1930E0b28D3766e895dF661de871A9b8aB70a4da
> balance: 6.29814814814605221
> gas used: 233060 (0x38e64)
> gas price: 2.500000001 gwei
> value sent: 0 ETH
> total cost: 0.00058265000023306 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00058265000023306 ETH
Summary
=======
> Total deployments: 1
> Final cost: 0.00058265000023306 ETH

Interacting with your contract

The MyStatus contract is now deployed at the address above. You can now interact with the contract using the built-in truffle console.
The Truffle console can be spun using truffle console --network quaitestnet. The console is similar to the chain IPC consoles and supports all web3 functions.
Setting the contract status to "Free" can be done by:
1) Starting the truffle console:
truffle console --network quaitestnet
2) Accessing the contract by the name:
truffle(quaitestnet)> let instance = await MyStatus.deployed()
It should return:
undefined
3) Setting the status to "Free":
truffle(quaitestnet)> instance.setStatus("Free")
It should return:
{
tx: '0x7d824c725bf48b3e09a1292d30c45abe8b92016d4c7cfcc29812d629cc65c660',
receipt: {
blockHash: '0x1a753e031f917ee3d186ef8669210c62de9f068e7fc1870c2bd988e8425d0d05',
blockNumber: 3413,
contractAddress: null,
cumulativeGasUsed: 29491,
effectiveGasPrice: '0x9502f901',
from: '0x1930e0b28d3766e895df661de871a9b8ab70a4da',
gasUsed: 29491,
logs: [],
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
status: true,
to: '0x76c3a4c3a6e2523c62e01163b19b14cf90a1a84c',
transactionHash: '0x7d824c725bf48b3e09a1292d30c45abe8b92016d4c7cfcc29812d629cc65c660',
transactionIndex: 0,
type: '0x2',
rawLogs: []
},
logs: []
}
4) Accessing the newly set status:
truffle(quaitestnet)> let status = await instance.getStatus()
It should return:
undefined
5) Print the status. It should return "Free" as the new status.
truffle(quaitestnet)> status
'Free'

Summary

Now you have all the tools to compile, deploy, interact with a smart contract on any of Quai Network's thirteen chains.