Tutorial: Loyalty program with Truffle
Deprecation notice
Consortium networks have been deprecated. This guide is for historical reference.
This tutorial will guide you through creating a simple loyalty program contract and deploying it on your Quorum network.
The loyalty program does the following:
- Joins each account that calls the contract.
- Lets each account check their loyalty program balance.
The contract and the Truffle configuration are in the GitHub repository.
Prerequisites
- A Chainstack account to deploy a Quorum network
- Truffle Suite to create and deploy contracts
Install Truffle V5.0.9 with:
npm i -g [email protected]
Important Notice: Truffle Deprecation
Please be aware that Truffle is no longer actively maintained. This tutorial is compatible with Truffle version 5.0.9, but future updates or support will not be available. For ongoing projects and new developments, it is recommended to switch to alternative frameworks such as Hardhat or Foundry, which offer continued support and updates.
For detailed information regarding the sunsetting of Truffle, please refer to Consensys' official announcement.
Overview
To get from zero to a deployed Quorum network with the running contract, do the following:
- With Chainstack, create a consortium project.
- With Chainstack, deploy a Quorum network.
- With Chainstack, access your Quorum node credentials.
- With Truffle, create and compile the contract.
- With Truffle, deploy the contract to your local development network.
- With Truffle, test the contract.
- With Truffle, deploy the contract to your Quorum network running with Chainstack.
Step-by-step
Create a consortium project
See Create a project.
Deploy a Quorum network
See Deploy a consortium network.
Get your Quorum node access and credentials
Create and compile the contract
-
On your machine, create a directory for the contract. Initialize Truffle in the directory:
truffle init
This will generate the Truffle boilerplate structure:
.
├── contracts
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
└── truffle-config.js
-
Go to the
contracts
directory. Create aloyaltyProgram.sol
file in the directory.pragma solidity ^0.5.8; contract loyaltyProgram { mapping (address => uint) private balances; address public owner; constructor() public payable { /* Set the owner to the creator of this contract */ owner = msg.sender; } /// Join a customer with the loyalty program function join() public view returns (uint){ address user = msg.sender; return user.balance; } /// Reads balance of the account requesting function balance() public view returns (uint) { return balances[msg.sender]; } }
join
joins the address with the programbalance
returns the loyalty program balance associated with the addressmsg.sender
is the address that calls the function
-
In the
contracts
directory createMigrations.sol
, which is a standard contract used in the Truffle framework for managing migration scripts.pragma solidity >=0.4.22 <0.9.0; contract Migrations { address public owner; uint public last_completed_migration; modifier restricted() { if (msg.sender == owner) _; } constructor() public { owner = msg.sender; } function setCompleted(uint completed) public restricted { last_completed_migration = completed; } function upgrade(address new_address) public restricted { Migrations upgraded = Migrations(new_address); upgraded.setCompleted(last_completed_migration); } }
-
Create
2_deploy_contracts.js
in themigrations
directory, This will create theloyaltyProgram.sol
contract deployment instructions for Truffle.var loyaltyProgram = artifacts.require("./loyaltyProgram.sol"); module.exports = function(deployer) { deployer.deploy(loyaltyProgram); };
-
Create
1_initial_migration.js
in themigrations
directory, This will createMigrations.sol
contract deployment instructions for Truffle.
const Migrations = artifacts.require("Migrations");
module.exports = function(deployer) {
deployer.deploy(Migrations);
};
- Compile the contract by running:
truffle compile
This will compile the contract and put it in your build/contracts
directory in the .json
format.
Deploy the contract to your local development network
-
Start the development network on your machine:
truffle develop
-
Without exiting the Truffle console, deploy the contract to the local development network:
truffle(develop)> migrate
This will deploy the contract to the development network as specified in truffle-config.js
.
Test the contract
-
Navigate to the
test
directory -
Create a
loyaltyProgramTest.js
file:var loyaltyProgram = artifacts.require("./loyaltyProgram.sol"); contract("loyaltyProgram", function(accounts) { const account = accounts[0] it("should join the address with the program", async () => { const program = await loyaltyProgram.deployed(); await program.join({from: account}); }); });
-
Start the local development network:
truffle develop
-
Without exiting the Truffle console, run the test:
truffle(develop)> test
The test run output should be Passing
.
Deploy the contract to your Quorum network
-
Install
HDWalletProvider
. HDWalletProvider is Truffle's separate npm package used to sign transactions.Run:
npm install @truffle/hdwallet-provider
-
Edit
truffle-config.js
to add:HDWalletProvider
- Your Quorum network running with Chainstack
const HDWalletProvider = require("@truffle/hdwallet-provider"); const mnemonic = "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12 word13 word14 word15"; module.exports = { networks: { development: { host: '127.0.0.1', port: 9545, network_id: '5777', }, compilers: { solc: { version: '0.5.9', }, }, quorum: { provider: () => new HDWalletProvider(mnemonic, 'ENDPOINT'), network_id: '*', gasPrice: 0, gas: 4500000, type: 'quorum', }, }, };
where
compilers
— explicit Solidity version for Truffle to compile the contractquorum
— any network name that you will pass to thetruffle migrate --network
command.HDWalletProvider
— Truffle's custom provider to sign transactionsmnemonic
— your mnemonic that generates your accounts. You can also generate a mnemonic online with Mnemonic Code Converter. Make sure you generate a 15 word mnemonic.- ENDPOINT — your Quorum node HTTPS endpoint. The format is
https://nd-123-456-789.p2pify.com/3c6e0b8a9c15224a8228b9a98ca1531d
. See View node access details. network_id
— your Quorum network ID. See Default network ID. You can set it to*
for any.gasPrice
— the setting must be0
for the Quorum network.gas
— the setting must be the default4500000
for the Quorum network.type
— the setting must bequorum
to instruct Truffle for the Quorum network deployment.
Example:
const HDWalletProvider = require("@truffle/hdwallet-provider"); const mnemonic = "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12 word13 word14 word15"; module.exports = { networks: { development: { host: "127.0.0.1", port: 9545, network_id: "5777" }, quorum: { provider: () => new HDWalletProvider(mnemonic, "https://nd-123-456-789.p2pify.com/3c6e0b8a9c15224a8228b9a98ca1531d"), network_id: "*", gasPrice: 0, gas: 4500000, type: "quorum" } } };
-
Run:
truffle migrate --network quorum
This will engage 2_deploy_contracts.js
and deploy the loyaltyProgram.sol
contract to your Quorum network as specified in truffle-config.js
.
You can view the deployed contract and the contract address on the Chainstack platform by navigating to your Quorum project > Explorer > Contracts.
Interact with the contract
The following contract interaction example is done with GoQuorum. For GoQuorum installation instructions, see Quorum tooling.
Connect to a node in your Quorum network
Run:
./geth attach ENDPOINT
where ENDPOINT — your Quorum node HTTPS endpoint. The format is https://nd-123-456-789.p2pify.com/3c6e0b8a9c15224a8228b9a98ca1531d
.
Example:
./geth attach https://nd-123-456-789.p2pify.com/3c6e0b8a9c15224a8228b9a98ca1531d
This will put you in the GoQuorum console interactive mode.
Set the ABI variable for the contract
Truffle creates the contract's ABI when you run truffle compile
and saves it to your project's /build/contracts
directory in .json
format. Navigate to the directory and get the ABI.
Run:
var abi = JSON.parse('CONTRACT_ABI')
where CONTRACT_ABI — your contract's ABI in one line
ABI for loyaltyProgram.sol
:
var abi = JSON.parse('[{"constant":true,"inputs":[],"name": "owner","outputs":[{"name":"","type":"address"}],"payable": false,"stateMutability":"view","type":"function"},{"inputs":[],"payable": true,"stateMutability": "payable","type": "constructor"},{"constant":false,"inputs":[],"name": "join","outputs":[{"name":"","type": "uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs": [],"name":"balance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]')
Set the contract address
Set the address of the deployed contract.
Run:
eth.contract(abi).at('CONTRACT_ADDRESS')
where CONTRACT_ADDRESS — the address of the deployed contract. Get the address by navigating on the Chainstack platform to your Quorum project > Explorer > Contracts.
Example:
eth.contract(abi).at('0x1bF2345B6789BcC1234567aE89cedFE1Ef2E34B5')
Set a variable to the contract at the address
Run:
var CONTRACT_NAME = eth.contract(abi).at('CONTRACT_ADDRESS')
where
- CONTRACT_NAME — any name you want to call the contract
- CONTRACT_ADDRESS — the address of the deployed contract. Get the address by navigating on the Chainstack platform to your Quorum project > Explorer > Contracts.
Example:
var loyaltyProgram = eth.contract(abi).at('0x1bF2345B6789BcC1234567aE89cedFE1Ef2E34B5')
Set the default Quorum address to interact with the contract
Run:
eth.defaultAccount = "QUORUM_ADDRESS"
where QUORUM_ADDRESS — an address created with one of the node deployments. Available on the Chainstack platform under Access and credentials > Default wallet > Address.
Example:
eth.defaultAccount = "0x12d34fe5f67ff89f1c23456c78d9123df45cb67a"
Make sure the account is unlocked by running:
web3.personal.unlockAccount(web3.personal.listAccounts[0],"", 15000)
Call the contract
As the loyaltyProgram.sol
contract has the join
function, call join
:
loyaltyProgram.join()
This will create a transaction and give you the transaction ID.
Now check the balance:
loyaltyProgram.balance()
This will display the balance:
0
About the author
Updated 2 months ago