> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chainstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy a Quorum loyalty program with Truffle

> Deploy a loyalty program smart contract on a Quorum consortium network using Truffle and Chainstack for private blockchain development. Now deprecated.

<Warning>
  ### Deprecation notice

  Consortium networks have been deprecated. This guide is for historical reference.
</Warning>

This tutorial will guide you through creating a simple loyalty program contract and deploying it on your [Quorum](/docs/about-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](https://github.com/chainstack/quorum-loyalty-program-tutorial).

## Prerequisites

* A [Chainstack account](https://console.chainstack.com/) to deploy a Quorum network
* [Truffle Suite](https://www.trufflesuite.com/) to create and deploy contracts

Install Truffle V5.0.9 with:

```bash theme={"system"}
npm i -g [email protected]
```

<Info>
  ### 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](https://consensys.io/blog/consensys-announces-the-sunset-of-truffle-and-ganache-and-new-hardhat?utm_source=github\&utm_medium=referral\&utm_campaign=2023_Sep_truffle-sunset-2023_announcement_).
</Info>

## Overview

To get from zero to a deployed Quorum network with the running contract, do the following:

<Steps>
  <Step>
    With Chainstack, create a consortium project.
  </Step>

  <Step>
    With Chainstack, deploy a Quorum network.
  </Step>

  <Step>
    With Chainstack, access your Quorum node credentials.
  </Step>

  <Step>
    With Truffle, create and compile the contract.
  </Step>

  <Step>
    With Truffle, deploy the contract to your local development network.
  </Step>

  <Step>
    With Truffle, test the contract.
  </Step>

  <Step>
    With Truffle, deploy the contract to your Quorum network running with Chainstack.
  </Step>
</Steps>

## Step-by-step

### Create a consortium project

See [Create a project](/docs/manage-your-project#create-a-project).

### Deploy a Quorum network

See [Deploy a consortium network](/docs/deploy-a-consortium-network).

### Get your Quorum node access and credentials

See [View node access details](/docs/manage-your-consortium-network#view-node-access-details).

### Create and compile the contract

1. On your machine, create a directory for the contract. Initialize Truffle in the directory:

   <CodeGroup>
     ```bash Shell theme={"system"}
     truffle init
     ```
   </CodeGroup>

This will generate the Truffle boilerplate structure:

<CodeGroup>
  ```bash Shell theme={"system"}
  .
  ├── contracts
  │   └── Migrations.sol
  ├── migrations
  │   └── 1_initial_migration.js
  ├── test
  └── truffle-config.js
  ```
</CodeGroup>

2. Go to the `contracts` directory. Create a `loyaltyProgram.sol` file in the directory.

   <CodeGroup>
     ```js JavaScript theme={"system"}
     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];
         }
     }
     ```
   </CodeGroup>

   * `join` joins the address with the program
   * `balance` returns the loyalty program balance associated with the address
   * `msg.sender` is the address that calls the function

3. In the `contracts` directory create `Migrations.sol`, which is a standard contract used in the Truffle framework for managing migration scripts.

   <CodeGroup>
     ```js JavaScript theme={"system"}
     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);
         }
     }
     ```
   </CodeGroup>

4. Create `2_deploy_contracts.js` in the `migrations` directory, This will create the `loyaltyProgram.sol` contract deployment instructions for Truffle.

   <CodeGroup>
     ```js JavaScript theme={"system"}
     var loyaltyProgram = artifacts.require("./loyaltyProgram.sol");

     module.exports = function(deployer) {
       deployer.deploy(loyaltyProgram);
     };
     ```
   </CodeGroup>

5. Create `1_initial_migration.js` in the `migrations` directory, This will create `Migrations.sol`contract deployment instructions for Truffle.

```
const Migrations = artifacts.require("Migrations");

module.exports = function(deployer) {
  deployer.deploy(Migrations);
};
```

5. Compile the contract by running:

<CodeGroup>
  ```bash Shell theme={"system"}
  truffle compile
  ```
</CodeGroup>

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

1. Start the development network on your machine:

   <CodeGroup>
     ```bash Shell theme={"system"}
     truffle develop
     ```
   </CodeGroup>

2. Without exiting the Truffle console, deploy the contract to the local development network:

   <CodeGroup>
     ```js JavaScript theme={"system"}
     truffle(develop)>  migrate
     ```
   </CodeGroup>

This will deploy the contract to the development network as specified in `truffle-config.js`.

## Test the contract

1. Navigate to the `test` directory

2. Create a `loyaltyProgramTest.js` file:

   <CodeGroup>
     ```js JavaScript theme={"system"}
     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});
       });
     });
     ```
   </CodeGroup>

<Info>
  [Truffle: Writing Tests in JavaScript](https://www.trufflesuite.com/docs/truffle/testing/writing-tests-in-javascript)
</Info>

3. Start the local development network:

   <CodeGroup>
     ```bash Shell theme={"system"}
     truffle develop
     ```
   </CodeGroup>

4. Without exiting the Truffle console, run the test:

   <CodeGroup>
     ```js JavaScript theme={"system"}
     truffle(develop)> test
     ```
   </CodeGroup>

The test run output should be `Passing`.

## Deploy the contract to your Quorum network

1. Install `HDWalletProvider`. [HDWalletProvider](https://github.com/trufflesuite/truffle/tree/develop/packages/hdwallet-provider) is Truffle's separate npm package used to sign transactions.

   Run:

   <CodeGroup>
     ```bash Shell theme={"system"}
     npm install @truffle/hdwallet-provider
     ```
   </CodeGroup>

2. Edit `truffle-config.js` to add:

   * `HDWalletProvider`
   * Your Quorum network running with Chainstack

   <CodeGroup>
     ```js JavaScript theme={"system"}
     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',
         },
       },
     };
     ```
   </CodeGroup>

   where

   * `compilers` — explicit Solidity version for Truffle to compile the contract
   * `quorum` — any network name that you will pass to the `truffle migrate --network` command.
   * `HDWalletProvider` — Truffle's custom provider to sign transactions
   * `mnemonic` — your mnemonic that generates your accounts. You can also generate a mnemonic online with [Mnemonic Code Converter](https://iancoleman.io/bip39/). 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](/docs/manage-your-consortium-network#view-node-access-details).
   * `network_id` — your Quorum network ID. See [Default network ID](/docs/default-addresses-and-network-id). You can set it to `*` for any.
   * `gasPrice` — the setting must be `0` for the Quorum network.
   * `gas` — the setting must be the default `4500000` for the Quorum network.
   * `type` — the setting must be `quorum` to instruct Truffle for the Quorum network deployment.

   Example:

   <CodeGroup>
     ```js JavaScript theme={"system"}
     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"
         }
        }
     };
     ```
   </CodeGroup>

3. Run:

   <CodeGroup>
     ```bash Shell theme={"system"}
     truffle migrate --network quorum
     ```
   </CodeGroup>

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](/docs/quorum-tooling).

## Connect to a node in your Quorum network

Run:

<CodeGroup>
  ```bash Shell theme={"system"}
  ./geth attach ENDPOINT
  ```
</CodeGroup>

where ENDPOINT — your Quorum node HTTPS endpoint. The format is `https://nd-123-456-789.p2pify.com/3c6e0b8a9c15224a8228b9a98ca1531d`.

Example:

<CodeGroup>
  ```bash Shell theme={"system"}
  ./geth attach https://nd-123-456-789.p2pify.com/3c6e0b8a9c15224a8228b9a98ca1531d
  ```
</CodeGroup>

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:

<CodeGroup>
  ```js JavaScript theme={"system"}
  var abi = JSON.parse('CONTRACT_ABI')
  ```
</CodeGroup>

where CONTRACT\_ABI — your contract's ABI in one line

ABI for `loyaltyProgram.sol`:

<CodeGroup>
  ```js JavaScript theme={"system"}
  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"}]')
  ```
</CodeGroup>

## Set the contract address

Set the address of the deployed contract.

Run:

<CodeGroup>
  ```js JavaScript theme={"system"}
  eth.contract(abi).at('CONTRACT_ADDRESS')
  ```
</CodeGroup>

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:

<CodeGroup>
  ```js JavaScript theme={"system"}
  eth.contract(abi).at('0x1bF2345B6789BcC1234567aE89cedFE1Ef2E34B5')
  ```
</CodeGroup>

## Set a variable to the contract at the address

Run:

<CodeGroup>
  ```js JavaScript theme={"system"}
  var CONTRACT_NAME = eth.contract(abi).at('CONTRACT_ADDRESS')
  ```
</CodeGroup>

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:

<CodeGroup>
  ```js JavaScript theme={"system"}
  var loyaltyProgram = eth.contract(abi).at('0x1bF2345B6789BcC1234567aE89cedFE1Ef2E34B5')
  ```
</CodeGroup>

## Set the default Quorum address to interact with the contract

Run:

<CodeGroup>
  ```js JavaScript theme={"system"}
  eth.defaultAccount = "QUORUM_ADDRESS"
  ```
</CodeGroup>

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:

<CodeGroup>
  ```js JavaScript theme={"system"}
  eth.defaultAccount = "0x12d34fe5f67ff89f1c23456c78d9123df45cb67a"
  ```
</CodeGroup>

Make sure the account is unlocked by running:

<CodeGroup>
  ```js JavaScript theme={"system"}
  web3.personal.unlockAccount(web3.personal.listAccounts[0],"", 15000)
  ```
</CodeGroup>

## Call the contract

As the `loyaltyProgram.sol` contract has the `join` function, call `join`:

<CodeGroup>
  ```js JavaScript theme={"system"}
  loyaltyProgram.join()
  ```
</CodeGroup>

This will create a transaction and give you the transaction ID.

Now check the balance:

<CodeGroup>
  ```js JavaScript theme={"system"}
  loyaltyProgram.balance()
  ```
</CodeGroup>

This will display the balance:

<CodeGroup>
  ```js JavaScript theme={"system"}
  0
  ```
</CodeGroup>

### About the author

<CardGroup>
  <Card title="Ake">
    <img src="https://mintcdn.com/chainstack/UN3rP7zhB69idvnC/images/docs/profile_images/1719912994363326464/8_Bi4fdM_400x400.jpg?fit=max&auto=format&n=UN3rP7zhB69idvnC&q=85&s=792a24ab1b4682406fa589c0ecd88e5d" alt="Ake" style={{width: '80px', height: '80px', borderRadius: '50%', objectFit: 'cover', display: 'block', margin: '0 auto'}} noZoom width="400" height="400" data-path="images/docs/profile_images/1719912994363326464/8_Bi4fdM_400x400.jpg" />

    <Icon icon="code" iconType="solid" /> Director of Developer Experience @ Chainstack
    <br /><Icon icon="screwdriver-wrench" iconType="solid" /> Talk to me all things Web3
    <br />20 years in technology | 8+ years in Web3 full time years experience

    <div style={{display: "flex", justifyContent: "center", gap: "12px"}}>
      <a href="https://github.com/akegaviar/" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="github" iconType="brands" />
      </a>

      <a href="https://twitter.com/akegaviar" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="twitter" iconType="brands" />
      </a>

      <a href="https://www.linkedin.com/in/ake/" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="linkedin" iconType="brands" />
      </a>
    </div>
  </Card>
</CardGroup>
