Links

Deploy with Truffle

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.
To get started, you can clone our example project files from GitHub or use your own clean directory.

Requirements

  • Quai Full Node running or a remote node's RPC endpoint.
  • 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

Create a truffle directory and install dependencies

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

Environment Variable Setup

To prevent committing your private keys or RPC endpoints, create an environment file to securely store variables.
touch process.env
Set up your process.env like this:
process.env
#Localhost URL with chain specific port
ROPSTEN_URL="http://127.0.0.1:PORT"
#Remote node endpoint or Localhost url with port for a locally hosted node
MAINNET_RPC_URL="https://quai.node.endpoint.io"
#Ropsten address private key
ROPSTEN_PRIVATE_KEY="0x..."
#Mainnet address private key
MAINNET_PRIVATE_KEY="0x..."
#Ropsten address public key
ROPSTEN_PUB_KEY="0x..."
#Mainnet address public key
MAINNET_PUB_KEY="0x..."
A list of all Quai chains with their associated port can be found below for use in defining both the ROPSTEN_RPC_URL and MAINNET_RPC_URL. Your private keys can be exported from MetaMask Flask.
Make sure to include process.env in the .gitignore file when committing to a remote repository. After filling out public/private keys and RPC URLs, we're now ready to securely consume them inside of truffle-config.js.

List of HTTP Port, Network Id for each chain

Chain
HTTP Port
Prime
8546
Cyprus
8578
Paxos
8580
Hydra
8582
Cyprus1
8610
Cyprus2
8642
Cyprus3
8674
Paxos1
8612
Paxos2
8644
Paxos3
8676
Hydra1
8614
Hydra2
8646
Hydra3
8678

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.
truffle-config.js
const PrivateKeyProvider = require("@truffle/hdwallet-provider");
const dotenv = require("dotenv");
dotenv.config({ path: "process.env" });
const {
ROPSTEN_RPC_URL,
MAINNET_RPC_URL,
ROPSTEN_PRIVATE_KEY,
MAINNET_PRIVATE_KEY,
ROPSTEN_PUB_KEY,
MAINNET_PUB_KEY,
} = process.env; // consume priv/pub keys and RPC URLs from process.env
module.exports = {
networks: {
quaitestnet: {
provider: () => new PrivateKeyProvider(MAINNET_PRIVATE_KEY, MAINNET_RPC_URL),
network_id: 994, // Mainnet chainId
gas: 200000, // Arbitrary gas limit.
from: MAINNET_PUB_KEY, // Valid mainnet account to send txs from
websocket: true,
},
ropsten: {
provider: () => new PrivateKeyProvider(ROPSTEN_PRIVATE_KEY, ROPSTEN_RPC_URL),
network_id: 3, // Ropsten chainId
gas: 200000, // Arbitrary gas limit.
from: ROPSTEN_PUB_KEY, // Valid ropsten account to send txs from
websocket: true,
},
},
// include compiler version defined in your smart contract
compilers: {
solc: {
version: "0.5.0",
},
},
mocha: {
timeout: 100000,
},
};
Note that you may have to alter the gas value depending on the chain and the solc compiler based on the version defined inside of your smart contract.

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 local blockchain. 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) Define the newly set status:
truffle(quaitestnet)> let status = await instance.getStatus()
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.