Skip to main content

14 posts tagged with "truffle"

View All Tags
Go back

· 11 min read
Mayowa Julius Ogungbola

header

Introduction

The Celo blockchain is a proficient, fast, and lightweight platform that supports the building of innovative, complex, and client-designed mobile applications. In simple terms, it is a network that allows the development of decentralized and inventive mobile and web applications.

One of the core features of how the Celo blockchain work falls on the concept of multiple revolutionary solutions, one of which is called Proof of Stake (PoS). On completing this article, you’ll have a solid idea of the Concept of Celo’s protocols, what PoS is and how it makes Celo an efficient platform for creating indigenous, decentralized solutions.

You’ll also have all the basic information you’ll need to get started with building on the Celo blockchain.

Prerequisites

Throughout this article, you are not expected to have any prior in-depth knowledge of any technology or intricate detail about the web3 space. If you’re reading this tutorial, it means you want to know more about what a PoS is and how the Celo Blockchain integrates this verification system.

What is Consensus Mechanism

A Consensus Mechanism is a method of authentication adopted by blockchain platforms to ensure transactions are in sync and agree on which transaction is valid before adding the transaction to the blockchain.

Amongst others, one of the proven efficient and effective means of reaching consensus on the blockchain is using the Proof of Stack PoS consensus mechanism. Which is why the Celo blockchain uses it.

When a transaction is created on the Celo blockchain before it is added to the blockchain ledger it first needs to be validated by the chain’s miners, thus the need for consensus.

What is Proof of Stack (PoS)

Proof of Stack is a type of consensus mechanism that adopts the idea of staking coins to earn its node runners the right to validate a transaction before adding it to the blockchain ledger.

When a transaction occurs on a blockchain platform like Celo, there is a need to first authenticate and validate the transaction before adding the transaction to the blockchain permanently. These tasks are usually carried out by the blockchain’s miners and node runners on the Celo blockchain.

Note: Node runners or validators are individuals or companies running full blockchain network nodes. They provide the backbone of the blockchain network by providing the infrastructure that allows the network to process transactions and maintain a distributed ledger. Node runners are rewarded for their services with tokens or coins from the network.

Looking back to the technology system before the web3 revolutionary breakthrough, verifying transactions would require a centralized or automated entity that was prone to either time consumption for financial and data forgery for non-monetary transactions and a lot more.

The need for a system like the PoS for the validation of transactions, therefore came as an innovative technological breakthrough.

In a PoS system, the chances of forgery or manipulation of transactions and data would be easily spotted and penalized. The PoS means of consensus is one of the important features that make the Celo Blockchain a secure and rewarding platform for developers to build on and validators to manage and get rewarded for.

The PoS algorithm also allows its validators and node runners to carry out validation while maintaining a low computational cost and manual effort.

Other types of Consensus Mechanism

Just like the PoS is used by the Celo blockchain as a means of reaching Consensus in approving all transactions, there are also other consensus mechanisms adopted by other blockchains some of which are;

  1. Proof of Work (PoW): This type of consensus algorithm requires its miners to consume a massive amount of computational power to solve the complex cryptographic puzzle that defines each transaction. Although this algorithm is effective and adopted by popular blockchain platforms, it is not quite efficient.

  2. Delegated Proof of Stake (DPoS): This type of consensus algorithm is similar to the PoS algorithm. But unlike the PoS algorithm, a group of miners or node runners is tasked with achieving a distributed consensus. It serves more like a voting system where miners decide who should be responsible for validating a transaction.

  3. Proof Of Importance (PoI): This algorithm is also very similar to the Proof of Stake algorithm, In the mechanism rewards are given to effective network users. The algorithm allows a hierarchy of importance based on individuals who have made more contributions to the system and gives them the right to validate transactions on the platform.

  4. Proof of Activity (PoA): This algorithm is a hybrid of the Proof of Work (PoW) and the Proof of Stake (PoS) algorithms, that allow validators to stake coins as collateral, and also validate blocks using computational decryption and other resources.

  5. Proof of Captivity (PoC): Thissystem of consensus neither requires a miner si solve cryptographic puzzles like the PoW or stake coins like the PoS, but rather to prove that they have a certain amount of hard drive space to contribute to storing plots of cryptographic hashes for the blockchain.

  6. Proof of Authority (PoA): This algorithm simply pre-selects and authorizes validator nodes to validate a newly added block.

  7. Proof of Elapsed Time (PoET): This system of consensus was designed to simply select a leader from a pool of miners and validators and assigns the task of validating the next node.

These are a few other important consensus algorithms available and adopted by other blockchain platforms.

Other Core Feature Of the Celo Blockchain

  • Scalability: The Celo blockchain was built to handle a large number of users and transactions without slowing down or becoming unresponsive. Celo is a layer-1 blockchain solution that helps to scale up blockchain technology to handle a high throughput of transactions. It does this by allowing transactions to be validated off-chain and then quickly grouping them into batches for faster processing on-chain. This helps reduce overall network congestion and improves scalability.

  • Security: Transactions on the Celo Blockchain go through a set of measures taken to protect the data and transactions stored on the blockchain from tampering or unauthorized access. This includes encryption, secure protocols, and validation of transactions. Additionally, Celo's consensus protocol is designed to ensure the safety and integrity of the blockchain by maintaining a decentralized network of validators who are incentivized to keep the blockchain secure.

  • Speed: The Celo blockchain is designed to offer a high level of speed, and enables users to quickly and securely transfer value across the network in a matter of seconds. It also utilizes a sharding technology called Celo Fast Finality (CFF) that allows the network to split its transactions into multiple shards to process thousands of transactions per second. It utilizes a mechanism called instant finality that also allows the network to commit transactions.

Building on Celo

As a developer looking to build fast, secure, scalable, and innovative ideas, building on Celo is an exciting opportunity for you to create applications and services that leverage the Celo platform. Celo provides a secure, open-source platform for developers to create distributed applications and services that connect people and organizations in meaningful ways. With Celo, developers can create applications that bring new possibilities to the global economy, from unlocking financial inclusion to providing access to new markets.

Wallets

The Celo wallet enables its users to quickly and securely send and receive payments, store digital assets, and access various financial services. It allows users to view their account balances and track their transactions.

The wallet also provides developers with the tools they require to interact with the Celo Blockchain, like signing transactions, deploying and testing contracts, calling and testing functions, etc. Additionally, the Celo wallet offers enhanced security features to ensure the safety of users’ digital assets. With its suite of features, the Celo wallet is a powerful tool for building on the Celo blockchain. Indirectly you can also interact with the celo blockchain by adding the celo network to other wallets like metamask, etc. More wallet-related information and why you need one can be found here.

Smart Contract

The Celo blockchain also allows technological transactions like compiling, testing, debugging, deploying, and calling contracts on the network, which gives you the ability to create, a decentralized application and interact with a decentralized codebase on the blockchain.

Here, you will find more tutorials on creating, verifying, and deploying smart contracts, writing contract tests, and making contract call on the Celo blockchain using, Hardhat, Truffle, foundry, Remix, etc.

Connecting to Celo

When connecting to the Celo alfajores or maiNet for deploying or interacting with the network, you’re advised to use the Celo configuration file below in place of the code in your .config file.

require("@nomiclabs/hardhat-waffle");
require("dotenv").config({ path: ".env" });
require("hardhat-deploy");

// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more

// Prints the Celo accounts associated with the mnemonic in .env
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();

for (const account of accounts) {
console.log(account.address);
}
});

/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
defaultNetwork: "alfajores",
networks: {
localhost: {
url: "http://127.0.0.1:7545",
},
alfajores: {
gasPrice: 1500000000,
gas: 4100000,
url: "https://alfajores-forno.celo-testnet.org",
accounts: {
mnemonic: process.env.MNEMONIC,
path: "m/44'/52752'/0'/0",
},
//chainId: 44787
},
celo: {
url: "https://forno.celo.org",
accounts: {
mnemonic: process.env.MNEMONIC,
path: "m/44'/52752'/0'/0",
},
chainId: 42220,
},
},
solidity: "0.8.10",
};

Here is a link to the code sample above, you will also require your funded wallet’s Mnemonic phrase in an encrypted file. To know more about interacting with the Celo blockchain here are some tutorials you can read on.

Creating Dapps on the Celo blockchain

The Celo blockchain provides the infrastructure for decentralized applications (DApps) to act as a bridge between users and their data privacy. The increasing number of dApps that utilize the Celo blockchain validates its usefulness in the blockchain ecosystem.

Creating the Celo Blockchain is a revolutionary way to use blockchain technology to build secure and reliable mobile and web applications. With the Celo platform, developers can easily create decentralized applications (DApps) and smart contracts that enable users to transfer value, store information, and more. This platform is designed to be user-friendly and secure, making it an attractive option for developers looking to build the next generation of applications.

Redeploying to Celo

Redeploying your Decentralized Application (Dapp) to Celo is a necessary process that can enable you to take advantage of the Celo network’s advantages, including scalability and security. The Celo platform enables developers to create and deploy their Dapps quickly and easily, and redeploying is an important part of this process.

Redeploying your Dapp to Celo requires a Celo account, which you can create through their website or the Celo mobile app. Once you have an account, you must create a Dapp and deploy it to the Celo blockchain. This process involves setting up a smart contract, enabling the Celo network to run your Dapp. You then need to write the code for your Dapp and deploy it onto the Celo blockchain. Once your Dapp is deployed, it will be available to anyone on the Celo platform. Here you can find more information on Redeploying your Dapp to the Celo network.

Redeploying on the Celo network provides the following benefits to your decentralized application.

  1. Scalability: The Celo blockchain can scale to millions of users, with each user able to transact in a matter of seconds. This makes it ideal for large-scale applications that handle large volumes of transactions.

  2. Low Cost: Celo has committed to providing users with low-cost transactions, allowing developers to lower the cost of running their Dapps and making them more attractive to users.

  3. Security: Celo utilizes advanced cryptography to provide a secure and reliable platform for developers and users.

  4. Ease of Use: Celo has a user-friendly interface that makes it easy for developers to deploy their Dapps and for users to use them.

  5. Open Source: Celo is an open-source platform that allows developers to access and customize the code to their needs and requirements.

  6. Community Support: Celo has a vibrant and supportive community of developers and users who are always willing to help out and provide assistance.

Conclusion

Now that you have completed this tutorial, you understand the concept of one of the core concepts that make up the Celo blockchain. And you now have everything you need to start building and interacting with the celo blockchain.

Next Steps

Now that you’ve successfully grasped the lesson in this tutorial, you can also read on the following topics to help you get started on building real-world solutions and other development on Celo.

You can also consider contributing to the Celo network as a developer or as a technical writer (Celo Sage).

About the Author​

Mayowa Julius Ogungbola

A Software Engineer and technical writer who is always open to working on new ideas. I enjoy working on GitHub, and you can also find out what I tweet about and connect with me on LinkedIn

Go back

· 14 min read
Mayowa Julius Ogungbola

header

Introduction

When creating decentralized applications that leverage smart contracts, it is important to ensure that there are little or no vulnerabilities to prevent an attacker from compromising your application.

Unit testing helps you ensure that all functionalities in your contract are working as expected, and development environments like Truffle give you the same tools to help you write proficient tests for your contracts before final deployment.

In this tutorial, you’ll create an exemplary contract and learn how to write and run unit tests for your contract using the truffle development environment.

Prerequisites

Throughout this tutorial you’ll need to have worked with or have a basic knowledge of the following:

  • Truffle Suite: Truffle suite is a Development Environment that acts as a pipeline for interacting with the EVM and also provides essential features and valuable libraries for testing Ethereum smart contracts and makes it easy to interact with the blockchain.
  • Solidity: Solidity is a high-level programming language used for creating smart contracts.
  • Javascript: This tutorial will make use of Javascript, therefore you should be familiar with basic Javascript coding and algorithms.

Requirements

This tutorial also aspects that you have the following already installed or available:

  • Node & node package management npm or yarn: This tutorial will require you to use a preinstalled node package manager. You should also know about working with any package manager: npm or yarn.

Installing and setting up Truffle suite

To install the truffle suite using your terminal. Create a workspace, head over to the directory on your terminal, and run the command npm install -g truffle.

Now, run the command npx truffle init to fire up the development environment. You’ll notice a new file structure appears in your file explorer, something like the image below:

truffle_init

Running a Contract Test Simulation

To understand how unit testing works using the Truffle suite create a demo directory, different from your main directory, and run the command npx truffle unbox metacoin. The result of the successful run of the code should look like the image below.

creating_metacoin

The command starts up a demo project called <metacoin> including two contract files MetaCoin.sol and ConvertLib.sol in the contract directory and also has two testing files TestMetaCoin.sol and metacoin.js file in the test directory. For running unit tests on the metacoin contracts.

Now run the command npx truffle test and the result of the unit test should look exactly like the image below.

demo_testing

Truffle first compiles the contract, runs all the unit test in the test script, and returns the result of all the tests. The image above shows the result when it passes all the unit tests.

Creating the Smart Contract

Each contract test made is composed explicitly to test a specific contract, meaning if you have four different contract files in an application, your application should likewise have four test scripts for testing each contract. In the following steps, you'll write a simple sample contract which you'll, later be writing a for.

Note: If you’re new to solidity and creating smart contracts, check out this tutorial to get started and understand solidity code. The tutorial above also has a couple of functions that will help you learn how to write solidity code.

  1. Head back to the initial development environment directory you created; inside the contract folder, create a new file, Sample.sol. This will be the smart contract you’ll be writing unit tests for.

  2. The Sample.sol contract will have the following functionalities:

  • a. First, the contract is created, and the variables name, and age are also created and by default, have no value.
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

contract Sample {
string public name;
address public owner;


}
  • b. Next, the contract’s constructor function assigns the address of the deployer of the contract to the variable owner and assigns the string "deployer" to the name variable.

       constructor() {
    owner = msg.sender;
    name = "deployer";
    }
  • c. The next function rename accepts a string value as argument and assigns it to the variable name.

  
function rename(string memory _name) public {
name = _name;
}
  • d. The next function describe simply return the current values of the global variable, name.
  
function describe() public view returns (string memory) {
return (name);
}
  • e. Next is a modifier function ownerOnly that only allows the contract owner to call its parent function when added to any function.
    modifier ownerOnly() {
require(
msg.sender == owner,
"this function requires the owner of the contract to run"
);
_;
}
  • f. The following function changeOwner uses the previously created ownerOnly modifier to only allow the owner of the contract to change the role of the contract owner to any address by passing as an argument to the changeOwner function.
    function changeOwner(address _newOwner) public ownerOnly {
owner = _newOwner;
}
  • g. The next function deposit allows anyone to send a minimum of 1 ETH to the contract.
    function deposit() public payable {
require(
msg.value >= 0.01 * 10 ** 18,
"you need to send at least 0.01 ETH"
);
}
  • h. Finally, the last function in the Sample.sol contract allows anyone calling the contract to withdraw funds from the contract, as long as you pass in the number of tokens to withdraw as an argument. This transaction will also be terminated if the amount passed in exceeds than 10 ETH.
    function withdraw(uint256 _amount) public payable {
require(_amount <= 100000000000000000);
payable(msg.sender).transfer(_amount);
}

If you’ve completed your Sample.sol contract, Your smart contract should look exactly like the code below; You should update your contract with the code below for uniformity sake:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

contract Sample {
string public name;
address public owner;

constructor() {
owner = msg.sender;
name = "deployer";
}

function rename(string memory _name) public {
name = _name;
}

function describe() public view returns (string memory) {
return (name);
}

modifier ownerOnly() {
require(
msg.sender == owner,
"this function requires the owner of the contract to run"
);
_;
}

function changeOwner(address _newOwner) public ownerOnly {
owner = _newOwner;
}

function deposit() public payable {
require(
msg.value >= 0.01 * 10 ** 18,
"you need to send at least 0.01 ETH"
);
}

function withdraw(uint256 _amount) public payable {
require(_amount <= 100000000000000000);
payable(msg.sender).transfer(_amount);
}
}

To confirm you have no existing errors in your contract, run the command npx truffle compile on your terminal, and a successful result should look like the image below.

compiling_contract

Now that you know the different functions in the Sample.sol contract and you’re familiar with what they do. Next, you’ll learn how to create a unit test script to test subsections of the contract you just made.

Writing the Unit Test Script

Now that you have created the Sample.sol contract, you can begin writing the unit tests for the contract. After completing these tests, you’ll have a basic idea of how to create unit tests for smart contracts.

A very common pattern used when writing unit tests for smart contracts is:

a. Arrange: This is where you create dummy variables that you’ll need to run units of your test cases. They can be created globally after the contract test function s created or locally within the unit test.

b. Act: Next, is the part where you run your testing functions and store the result in a variable.

c. Assert: Since you already know the correct result of the test, then you compare your expected result with the response of the test you ran. If the test returns the expected result, it passes else, the test does not pass.

Also following the format:

 describe(<"functionName">, async function () {
beforeEach(async function() {
<what should happen before each test is run>
})
it("what the test is expected to do", async function () {
const response = <what was returned>
const result = <what should be returned>;
expect(response).to.equal(result); // compares the response to the expected result
});

Next, you’ll be creating a uint-test to test your Sample.sol contract using the previous format above, and you’ll learn how to create a basic unit test script on your own:

Testing a smart contract makes it easier to identify bugs and vulnerabilities and reduces the possibility of software errors that could lead to costly exploits. In the next few steps, you will learn the basic format of how to write unit tests based on your smart contract.

  • First, head over to the migrations folder and create a script file called 1_deploy_contract.js and copy the code below into the script.
const Sample = artifacts.require("Sample");
// const MetaCoin = artifacts.require("MetaCoin");

module.exports = function (deployer) {
// deployer.deploy(Sample);
// deployer.link(Sample, SampleTest);
// deployer.deploy(SamplTest);
deployer.deploy(Sample, { gas: 1000000 });
};

The code above is created to simply deploy your Sample.sol contract. Next, navigate to the test folder and create a new test script, SampleTest.js.

  1. Firstly, you’ll need to import the contract as a variable Sample in the first line of code.
const Sample = artifacts.require("Sample");
  1. Next, you’ll need to initialize the contract test with the following code below. This contract - Sample will cover all the unit test functions that will be carried out on the named contract.
contract("Sample", (accounts) => {
})
  1. Using the describe keyword to define a specific test for each function in the contract, you can carry out multiple tests using the it keyword for a specific function. The first test constructor tests the constructor function in the contract. Copy and add the code below.
  describe("constructor", async function () {
it("should have the correct name", async () => {
const sample = await Sample.deployed();
const name = await sample.name();
assert.equal(name, "deployer");
});

it("should have the correct owner", async () => {
const sample = await Sample.deployed();
const owner = await sample.owner();
assert.equal(owner, accounts[0]);
});
});

The function has two tests with string descriptions of what each of them is meant to do. The first test check for the initialization of the name variable and checks the value of the owner variable to the address of the deployer. The test passes if the result returns as expected and reverts with an error otherwise.

Now, run the command npx truffle test, and a successful result should look like the image below.

test(2)

  1. The next unit test describes the rename and describe function from the smart contract; the function carries out a single test on the rename and describe function. The test updates the name variable's value and checks the current the variable's current value if it has been updated. Copy and add the code below.
  describe("rename & describe", async function () {
it("should be able to rename", async () => {
const sample = await Sample.deployed();
await sample.rename("new name");
const name = await sample.describe();
assert.equal(name, "new name");
});
});

Now, run the command npx truffle test and a successful result should look like the image below.

test(1)

  1. The next unit test describes the changeOwner function in the smart contract; the test first uses the right address to attempt to change the owner, which should pass successfully. And then uses another random address to change the ownership role, which is meant to be reverted. Copy and add the code below.
describe("changeOwner", async function () {
it("should change the owner", async () => {
const sample = await Sample.deployed();
await sample.changeOwner(accounts[1], { from: accounts[0] });
const owner = await sample.owner();
assert.equal(owner, accounts[1]);
});

it("should not change the owner", async () => {
const sample = await Sample.deployed();
try {
await sample.changeOwner(accounts[2], { from: accounts[1]});
} catch (error) {
assert.equal(
error.message,
"VM Exception while processing transaction: revert"
)};
});
});

Now, run the command npx truffle test and a successful result should look like the image below.

test(3)

  1. The next function tests the deposit function of the contract. The first test will verify the deposit function works correctly which allows deposits of 0.01 ETH or greater. The second test verifies that the deposit function correctly rejects deposits of less than 0.01 ETH. Copy and paste the code below.
  describe("deposit", async function () {
it("should allow deposits", async () => {
const sample = await Sample.deployed();
await sample.deposit({ value: 0.01 * 10 ** 18 });
});
it("should not allow deposits below 0.01 ETH", async () => {
const sample = await Sample.deployed();
try {
await sample.deposit({ value: 0.009 * 10 ** 18 });
assert.fail("deposit should have failed");
} catch (error) {
assert.ok(error.message.includes("revert"));
}
});
});

Now, run the command npx truffle test and a successful result should look like the image below.

test(4)

  1. This next describe function tests the withdraw function in the contract. The first test is attempting to withdraw 0.01 ether from the contract. The second test is attempting to withdraw an amount greater than the balance to ensure that the withdrawal fails. If the test fails, it will return an error message with the word revert.
  describe("withdraw", async function () {
it("should allow withdrawals", async () => {
const sample = await Sample.deployed();
await sample.withdraw(BigInt(0.01 * 10 ** 18));
});
it("should not allow withdrawals above balance", async () => {
const sample = await Sample.deployed();
try {
await sample.withdraw(BigInt(0.01 * 10 ** 18));
assert.fail("withdrawal should have failed");
} catch (error) {
assert.ok(error.message.includes("revert"));
}
});
});

Finally, run the command npx truffle test and a successful result should look like the image below.

test(5)_

After completing your test script, your code should look exactly like the one below. For uniformity, sake replaces the entire code with this code test.

const Sample = artifacts.require("Sample");

contract("Sample", (accounts) => {
describe("constructor", async function () {
it("should have the correct name", async () => {
const sample = await Sample.deployed();
const name = await sample.name();
assert.equal(name, "deployer");
});

it("should have the correct owner", async () => {
const sample = await Sample.deployed();
const owner = await sample.owner();
assert.equal(owner, accounts[0]);
});
});

describe("rename & describe", async function () {
it("should be able to rename", async () => {
const sample = await Sample.deployed();
await sample.rename("new name");
const name = await sample.describe();
assert.equal(name, "new name");
});
});
describe("changeOwner", async function () {
it("should change the owner", async () => {
const sample = await Sample.deployed();
await sample.changeOwner(accounts[1], { from: accounts[0] });
const owner = await sample.owner();
assert.equal(owner, accounts[1]);
});

it("should not change the owner", async () => {
const sample = await Sample.deployed();
try {
await sample.changeOwner(accounts[2], { from: accounts[1] });
} catch (error) {
assert.equal(
error.message,
"VM Exception while processing transaction: revert"
);
}
});
});
describe("deposit", async function () {
it("should allow deposits", async () => {
const sample = await Sample.deployed();
await sample.deposit({ value: 0.01 * 10 ** 18 });
});
it("should not allow deposits below 0.01 ETH", async () => {
const sample = await Sample.deployed();
try {
await sample.deposit({ value: 0.009 * 10 ** 18 });
assert.fail("deposit should have failed");
} catch (error) {
assert.ok(error.message.includes("revert"));
}
});
});
describe("withdraw", async function () {
it("should allow withdrawals", async () => {
const sample = await Sample.deployed();
await sample.withdraw(BigInt(0.01 * 10 ** 18));
});
it("should not allow withdrawals above balance", async () => {
const sample = await Sample.deployed();
try {
await sample.withdraw(BigInt(0.01 * 10 ** 18));
assert.fail("withdrawal should have failed");
} catch (error) {
assert.ok(error.message.includes("revert"));
}
});
});
});

Conclusion

Writing unit tests for smart contracts can help a great deal in ensuring a secure and proficient contract, by suggesting fixes and improvements after discovering errors, issues, and security vulnerabilities in your contract. You have successfully created your unit test script for a simple sample contract using truffle. Now that you understand how unit tests are written, you can move on to writing more complex test scripts for other smart contracts. You can also read about how to run the unit test for smart contracts using Truffle.

Next Steps

Here is some other tutorial article.

Unit testing with Hardhat and Celo

How to create and Test contract calls with Celo and Hardhat

About the Author

Mayowa Julius Ogungbola

A Software Engineer and technical writer who is always open to working on new ideas. I enjoy working on GitHub, and you could also find out what I tweet about and connect with me on LinkedIn

References

Here is a link to the complete tutorial sample code on my GitHub, Leave a ⭐on the repository if you find it helpful.

Go back

· 13 min read

header

🌱 Introduction

Welcome Developers, to the Step-by-Step Guide to Deploying your First Full-Stack Dapp on Celo! In this guide, we will walk you through the process of building and deploying a full-stack decentralized application (Dapp) on the Celo platform.

Celo is a decentralized platform that enables fast, secure, and scalable transactions on a global scale. It is built on top of the Ethereum blockchain and is designed to be easily accessible to developers and users alike.

Whether you are a seasoned blockchain developer or just getting started, this guide will provide the knowledge and tools you need to build and deploy your own Dapp on Celo.

So let's get started!

🗈 Prerequisites

  • A computer with an internet connection. You will need a computer with a stable internet connection to follow along with this guide.

  • Basic knowledge of programming. While we will provide step-by-step instructions, it will be helpful to have some basic knowledge of programming languages such as JavaScript and Solidity.

  • Node.js and npm installed. You will need to have Node.js and npm (the package manager for Node.js) installed on your computer. You can check if you have them installed by running the following commands in your terminal:

node -v
npm -v
  • A code editor. You will need a code editor to write and edit your code. Some popular options include Visual Studio Code and Atom.
  • A Metamask account. You will need a Metamask account to interact with the Celo blockchain from your web browser. If you don't already have one, you can create one by installing the Metamask extension for Chrome or Firefox.

⚠️ Requirements

  • Truffle: a development environment, testing framework, and asset pipeline for Ethereum
  • Node.js: a JavaScript runtime that allows you to run JavaScript on the command line
  • Yarn: a package manager for JavaScript
  • next: Next.js is a framework for building server-rendered or statically-exported React applications.
  • CeloCli - The celocli lets you interact with the Celo Protocol smart contracts.

What are NFTs?

Non-fungible tokens (NFTs) are digital assets that represent ownership of a unique item or concept. They are stored on a blockchain and cannot be exchanged for something else of equal value, like traditional currencies. NFTs are often used to represent digital art, collectibles, and other unique items and are bought and sold in online marketplaces. Their value is determined by their rarity and perceived value to collectors. NFTs provide a way to prove ownership and authenticity of digital assets and allow for the creation of scarcity in the digital world, which can increase the value of certain items. They are created using smart contracts on a blockchain platform, such as Ethereum, and are often represented as ERC-721 tokens.

Let's start building the future together!

Steps to set up the truffle project and its configs

  1. Install Node.js by following the instructions on the official website.

  2. Install Yarn by running the following command:

npm install -g yarn
  1. Install Truffle by running the following command:
yarn global add truffle
  1. Install HDWalletProvider by running the following command:
npm install @truffle/hdwallet-provider --save

image

  1. Install Celo Command Line Interface also install dotenv
npm install -g @celo/celocli
npm install dotenv
// dotenv will help us to load .env file as environment variables

  1. Create a new Truffle project by running the following command:
mkdir NFTsmartcontract
cd NFTsmartcontract
truffle init
tip

Learn more: If you are new to Truffle check out the Truffle docs.

This will create a new directory with the following structure:

NFTsmartcontract/
├── contracts/
│ └── Migrations.sol
├── migrations/
│ └── 1_initial_migration.js
├── test/
├── truffle-config.js
└── truffle.js
  1. Navigate to the truffle-config.js file in your project directory and Replace the following configuration for the Celo testnet:
const HDWalletProvider = require("@truffle/hdwallet-provider");
require("dotenv").config();
module.exports = {
contracts_directory: "./contracts",
contracts_build_directory: "./truffle_abis",
migrations_directory: "./migrations",
networks: {
local: {
host: "127.0.0.1",
port: 7545,
network_id: "*",
},
alfajores: {
provider: function () {
return new HDWalletProvider(
process.env.PRIVATE_KEY,
"https://alfajores-forno.celo-testnet.org"
);
},
network_id: 44787,
gas: 20000000, //make sure this gas allocation isn't over 20M, which is the max
},
celo: {
provider: function () {
return new HDWalletProvider(
process.env.PRIVATE_KEY,
"https://forno.celo.org"
);
},
network_id: 42220,
gas: 20000000, //make sure this gas allocation isn't over 20M, which is the max
},
},
mocha: {
// timeout: 100000
},
compilers: {
solc: {
version: "0.8.9", // Fetch exact version from solc-bin (default: truffle's version)
docker: false, // Use "0.5.1" you've installed locally with docker (default: false)
settings: {
// See the solidity docs for advice about optimization and evmVersion
optimizer: {
enabled: false,
runs: 200,
},
evmVersion: "istanbul",
},
},
},
};
  1. Create A Celo Account using Celo Cli
celocli account:new

image

  1. Create a .env File in the root directory and add PRIVATE_KEY that we got from Celocli Command or You can use PRIVATE_KEY from Metamask.
PRIVATE_KEY="62dda1a6a6ee2dasdasdsadasdassdas1e2200095661a1b1e9dsadsdsdsadasasd"
  1. Create .gitignore file

It is important to hide your mnemonic and other important files while developing applications. When using Git or GitHub, you can populate a .gitignore file with the code below to ensure you don’t accidentally publish these files.

# dependencies
/node_modules

# Mac users
.DS_Store

#hidden files
.env

Now we are done with setting up truffle

Steps for creating ERC721 Contract and Truffle Migration File

  1. Create a NFT.sol file in contracts/ folder.

  2. Add the following code to it.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract NFT is ERC721, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;

Counters.Counter private _tokenIdCounter;
constructor() ERC721("NFTexample", "CELO") {}

function safeMint(string memory uri) public {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(msg.sender, tokenId);
_setTokenURI(tokenId, uri);
}

// The following functions are overrides required by Solidity.

function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}

function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
}
tip

Use the OpenZeppelin Wizard to easily create, deploy, and interact with smart contracts using the OpenZeppelin library.

  1. Install openzeppelin Library by running this command in the root folder.
npm install @openzeppelin/contracts
  1. Create a 2_deploy_contracts.js File in the migrations folder and follow the code.
const NFT = artifacts.require("NFT");
module.exports = function(deployer) {
deployer.deploy(NFT);
};

Now we are done creating NFT.sol And its Migration Config, next we gonna deploy it on Celo testnet Blockchain

Steps to deploy Smart Contract

  1. We need Faucet For deploying smart contracts on Celo Blockchain. Use Celo Testnet Faucet to get faucet money input your address which we got from celocli.

  2. Now we Gonna Compile the Smart Contract and Check if there are any problems with it.

truffle compile
  1. After successful Compilation We Now gonna deploy it on Celo Testnet
//Truffle migrate compiles AND migrates your contract. In the future, you can run truffle migrate to complete both steps but run only if you are deploying it on a Local server.

truffle migrate
// use truffle deploy --network network name to deploy on celo testnet
truffle deploy --network alfajores
//We can use other Chain as well by adding them in truffle-config.js

image

  1. After We Got our Smart Contract Address we can check it on Celo Blockchain explorer using Block Explorer.

ヾ(´⌣`)ノ Hurray we Deployed our First ERC721 Smart Contract Make Sure to Save the Smart Contract Address in a File We Gonna use it in Our Frontend. As For Our Smart Contract we have deployed is smart contract

Frontend using NextJS

Steps

  1. Set up a Next.js project:

Install Next.js and create a new Next.js project by running the following commands:

npm init next-app
cd next-app
npm run dev

image

  1. Install Ethers.js:

Ethers.js is a JavaScript library that allows you to interact with the Ethereum blockchain. To install it, run the following command in your terminal:

npm install ethers
  1. Install React-Bootstrap
npm install react-bootstrap bootstrap

image

  1. Now we have installed react-bootstrap we need to add its CSS to the \_app.js file.
import 'bootstrap/dist/css/bootstrap.min.css';

  1. Now We have our libraries which we gonna use. Now let's edit our pages/index.js file
import React from 'react';
import { ethers } from 'ethers';
import contractAbi from "./abi/NFT.json";
import { Button, Card, Container, Nav, Navbar } from 'react-bootstrap';

const contractAddress = '0xa5Dcc3EB1eC8E417A4eA6CA51bBE4119D323d6E4'; // Replace with your contract address
function App() {
const [walletAddress, setWalletAddress] = React.useState(null);

const connectToWallet = async () => {
try {
await window.ethereum.enable();
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
setWalletAddress(accounts[0]);
console.log('Wallet connected:', walletAddress);
} catch (error) {
console.error(error);
}
};

const mintNFT = async () => {
try {
const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer = provider.getSigner();
const contract = new ethers.Contract(contractAddress, contractAbi.abi, signer);

// Replace with Your metadata
const metadata = 'https://ipfs.io/ipfs/QmTvsVaaHTuMNmwXgbfgkrztFEazAPyzmrb4VSS2PbqLjA?filename=the-chainlink-elf.json';

const result = await contract.safeMint(metadata, { from: walletAddress });
console.log(result);
} catch (error) {
console.error(error);
}
};

const disconnectFromWallet = async () => {
try {
await window.ethereum.request({ method: 'eth_requestAccounts', accounts: [] });
setWalletAddress(null);
console.log('Wallet disconnected');
} catch (error) {
console.error(error);
}
};
React.useEffect(() => {
const checkWalletConnection = async () => {
if (window.ethereum.isConnected()) {
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
setWalletAddress(accounts[0]);
console.log('Wallet connected:', walletAddress);
} else {
console.log('Wallet not connected');
}
};
checkWalletConnection();
}, []);
return (
<div style={{ backgroundColor: 'white' }}>
<Navbar bg="light" expand="lg">
<Navbar.Brand href="/">NFT Minter</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="ml-auto">
{ !walletAddress ?
<Nav.Link href="#" onClick={connectToWallet}>Connect</Nav.Link> :
<Nav.Link href="#" onClick={disconnectFromWallet}>Disconnect</Nav.Link>
}
<Nav.Link href="viewnft">View NFTs</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
<Container>
<Card style={{ width: '18rem' }} className="mx-auto mt-5">
<Card.Img variant="top" src={`https://ipfs.io/ipfs/QmTgqnhFBMkfT9s8PHKcdXBn1f5bG3Q5hmBaR4U6hoTvb1?filename=Chainlink_Elf.png`} />
<Card.Body>
{walletAddress && (<>
<Button variant="primary" onClick={mintNFT}>Mint NFT</Button>
</>
)}
</Card.Body>
</Card>
</Container>
</div>
);
}

export default App;
  1. We need to copy the Abi Json file from our smart contract folder truffle_abis/NFT.json and Create a new folder in our pages folder named ABI and paste it over there.

  2. Now we can run Our Command to Test it out.

npm run dev

image

ヾ(´⌣`)ノ Hurray We are done with our frontend Mint Function.

Let's Complete Our Tutorial With View NFT

Steps To Create View NFT's Page

  1. Create a new file in pages with the name viewnft.js

  2. Install axios in the project to fetch data from IPFS JSON link.

npm install axios
  1. Let's import all the files which we needed
import React from 'react';
import { ethers } from 'ethers';
import contractAbi from "./abi/NFT.json";
import { Button, Card, Container, Nav, Navbar,Row,Col } from 'react-bootstrap';
import axios from 'axios';
  1. After importing all files we gonna create functions to fetch all user nfts.
async function listTokensOfOwner() {
const provider = new ethers.providers.Web3Provider(window.ethereum)

const contract = new ethers.Contract(contractAddress, contractAbi.abi, provider);
//we are using logs to fetch users nft
const sentLogs = await contract.queryFilter(
contract.filters.Transfer(walletAddress, null),
);
const receivedLogs = await contract.queryFilter(
contract.filters.Transfer(null, walletAddress),
);

const logs = sentLogs.concat(receivedLogs)
.sort(
(a, b) =>
a.blockNumber - b.blockNumber ||
a.transactionIndex - b.TransactionIndex,
);

const owned = new Set();

for (const log of logs) {
const { from, to, tokenId } = log.args;

if (addressEqual(to, walletAddress)) {
owned.add(tokenId.toString());
} else if (addressEqual(from, walletAddress)) {
owned.delete(tokenId.toString());
}
}

const uri = [];
for (const own of owned) {
const tokenuri = await tokenUri(own);
const response = await axios.get(tokenuri);

uri.push(response.data)
}
setuserNFT(uri);
};
async function tokenUri(id){
//this function is to fetch tokenUri from smart contract
const provider = new ethers.providers.Web3Provider(window.ethereum)
const contract = new ethers.Contract(contractAddress, contractAbi.abi, provider);
const url =await contract.tokenURI(id);
return url.toString()
}
function addressEqual(a, b) {
//this functoin is for checking the address match because sometime metamask and our input wallet addresses are in different Cases.
return a.toLowerCase() === b.toLowerCase();
}
  1. Let's look at our Complete `viewnft.js`` How it looks.
import React from 'react';
import { ethers } from 'ethers';
import contractAbi from "./abi/NFT.json";
import { Button, Card, Container, Nav, Navbar,Row,Col } from 'react-bootstrap';
import axios from 'axios';

const contractAddress = '0xa5Dcc3EB1eC8E417A4eA6CA51bBE4119D323d6E4'; // Replace with your contract address
function App() {
const [walletAddress, setWalletAddress] = React.useState(null);
const [userNFt,setuserNFT] = React.useState(null);
const connectToWallet = async () => {
try {
await window.ethereum.enable();
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
setWalletAddress(accounts[0]);
console.log('Wallet connected:', walletAddress);
} catch (error) {
console.error(error);
}
};

const disconnectFromWallet = async () => {
try {
await window.ethereum.request({ method: 'eth_requestAccounts', accounts: [] });
setWalletAddress(null);
console.log('Wallet disconnected');
} catch (error) {
console.error(error);
}
};
React.useEffect(() => {
const checkWalletConnection = async () => {
if (window.ethereum.isConnected()) {
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
setWalletAddress(accounts[0]);
console.log('Wallet connected:', walletAddress);
} else {
console.log('Wallet not connected');
}
};
checkWalletConnection();
if(walletAddress){
listTokensOfOwner();
}
}, [walletAddress]);
async function listTokensOfOwner() {
const provider = new ethers.providers.Web3Provider(window.ethereum)

const contract = new ethers.Contract(contractAddress, contractAbi.abi, provider);

const sentLogs = await contract.queryFilter(
contract.filters.Transfer(walletAddress, null),
);
const receivedLogs = await contract.queryFilter(
contract.filters.Transfer(null, walletAddress),
);

const logs = sentLogs.concat(receivedLogs)
.sort(
(a, b) =>
a.blockNumber - b.blockNumber ||
a.transactionIndex - b.TransactionIndex,
);

const owned = new Set();

for (const log of logs) {
const { from, to, tokenId } = log.args;

if (addressEqual(to, walletAddress)) {
owned.add(tokenId.toString());
} else if (addressEqual(from, walletAddress)) {
owned.delete(tokenId.toString());
}
}

const uri = [];
for (const own of owned) {
const tokenuri = await tokenUri(own);
const response = await axios.get(tokenuri);

uri.push(response.data)
}
setuserNFT(uri);
};
console.log(userNFt)
async function tokenUri(id){
const provider = new ethers.providers.Web3Provider(window.ethereum)

const contract = new ethers.Contract(contractAddress, contractAbi.abi, provider);
const url =await contract.tokenURI(id);
return url.toString()
}
function addressEqual(a, b) {
return a.toLowerCase() === b.toLowerCase();
}
return (
<div style={{ backgroundColor: 'white' }}>
<Navbar bg="light" expand="lg">
<Navbar.Brand href="/">NFT Minter</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="ml-auto">
{!walletAddress? <><Nav.Link href="#" onClick={connectToWallet}>Connect</Nav.Link></>:
<><Nav.Link href="#" onClick={disconnectFromWallet}>Disconnect</Nav.Link></>}
<Nav.Link href="/viewnft">View NFTs</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
<Container>
{walletAddress && (<>

<Row xs={1} md={4} className="g-4">
{userNFt && userNFt.map((item,i)=>{return(
<Col>
<Card style={{ width: '18rem' }} className="mx-auto mt-5">
<Card.Img variant="top" src={item.image}/>
<Card.Body>
<Card.Title>{item.name}</Card.Title>
<Card.Text>
{item.description}
</Card.Text>
</Card.Body>
</Card></Col>
) })}
</Row>
</>
)}
</Container>
</div>
);
}

export default App;
  1. Now we again gonna run npm run dev to start our application locally.

image

🥳🥳🥳 Congratulations! 🥳🥳🥳 You have successfully deployed your full stack Dapp on the Celo blockchain.

Conclusion

In conclusion, the full stack dApp we have built using Next.js, Ether.js, and a smart contract is a powerful tool for creating decentralized applications. The use of a smart contract on the Ethereum blockchain ensures that our dApp is transparent, secure, and immutable, while the frontend built with Next.js allows for a smooth and intuitive user experience. The combination of these technologies has allowed us to create a truly decentralized application that can be used by anyone, anywhere, at any time. With the potential to revolutionize the way we interact and transact online, the future looks bright for dApps like ours.

About Author

Hi! My name is Kunal Dawar and I am a Full Stack web2/web3 Developer. I have participated in numerous hackathons and have been fortunate enough to win many of them.

One thing that I am truly passionate about is creating things that are reliable and don't break easily. I believe that creating high-quality products is important not only for the users but also for the overall growth and success of a business.

In my free time, I enjoy learning about new technologies and staying up-to-date with the latest trends in the field. I also love to share my knowledge with others and mentor those who are interested in pursuing a career in web development.

Go back

· 10 min read

How to deploy a smart contract to Celo testnet, mainnet, or a local network using Hardhat.

header

Hello Developers 🌱

Welcome to today’s post, where we’ll break down a blockchain topic into bite-sized pieces to help you learn and apply your new skills in the real world.

Today’s topic is Deploying on Celo with Truffle.

Here’s a list of what we’ll cover 🗒

  • Step 1: Environment setup​
  • Step 2: Project setup
  • Step 3: Write project code
  • Step 4: Configure deployment settings
  • Step 5: Compile and migrate your contract
  • Step 6: Deploy your Contract
  • Step 7: View your deployed contract
  • Step 8: Verify your smart contract

By the end of this post, you’ll be able to create, deploy, and interact with your smart contract on Celo testnet, mainnet, or localhost using Truffle.

Let’s go! 🚀

Introduction to Hardhat​

Hardhat is a development environment to compile, deploy, test, and debug your Ethereum or Celo software. It helps developers manage and automate the recurring tasks that are inherent to the process of building smart contracts and dApps, as well as easily introducing more functionality around this workflow. This means compiling, running, and testing smart contracts at the very core.

image

tip

Learn more: If you are new to Hardhat check out Hardhat.org.

✅ Step 1: Environment setup​

Before getting started you’ll need to set up Celo in your local environment. You can do this on Mac or Windows and can find the details on docs.celo.org.

image

Celo projects include common dependencies like Nodejs, npm, nvm, yarn, git, and xCode. If you already have these installed you can follow this post to set up Celo specific dependencies.

Node v12.0.0

To build on Celo you’ll need to install and use node v12.0.0.

nvm install v12.0.0
nvm use v12.0.0
node --version

Celo Command Line Interface

The celocli lets you interact with the Celo Protocol smart contracts.

npm install -g @celo/celocli

image

Install Ganache (optional)

Ganache UI creates a local blockchain to help you deploy and test contracts. You can install and set up the UI from their website and can find more details in the Ganache docs.

image

tip

The @celo/ganache-cli is Celo’s version of Ganache. It doesn’t seem to be working for me but you can try installing it in your environment.

From the Ganache UI, create a new workspace on localhost:7545.

image

✅ Step 2: Project setup

Now that you have your environment setup, you’re ready to create your project! Open your terminal to create and navigate into a project folder.

mkdir celo-hardhat && cd celo-hardhat

image

Initialize an npm project

Initialize an npm project from within the project directory.

npm init -y

image

Install dotenv

Dotenv is a module that loads environment variables from a .env file. Install this now and you’ll use this to import information to your Truffle configuration file.

npm install dotenv

image

Initialize hardhat

Adding hardhat to your project allows you to easily build, test, and deploy smart contracts. You can install using npm or npx.

npm install --save-dev hardhat

or

npx hardhat

image

tip

Learn more: Follow the installation instructions and quickstart for additional details.

Customize project settings

After initializing hardhat have the chance to customize your project settings. In this post, we’ll Create a basic sample project and accept all of the default settings.

image

Open your project

Your project is set up and you’re ready to start building! Open your project in Visual Studio code or your preferred IDE.

code .

image

tip

You can launch VS Code from the command line by installing it in your shell path.

✅ Step 3: Write project code

To build your project you’ll write a smart contract, script , .env, and .gitignore file. You’ll also create an account, fund it with test tokens, and connect the account to your project.

Smart Contract Code

Hardhat provides a Greeter.sol contract to get you started. For this post, you’ll make your own files to give you a better idea of how everything works. Start by creating a file named HelloCelo.sol in the /contracts folder and add the Solidity code below.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract HelloCelo {
string public greet = "Hello Celo!";
}

image

tip

Learn more: Read the Solidity docs or Solidity by Example to learn more about the programming language for building smart contracts.

Script files

Hardhat also provides a sample-script.js file in the /scripts folder that you can use to deploy your smart contract. By default, it will deploy the Greeter.sol contract. Run the sample script to deploy this contract now!

Deploy Greeter.sol

npx hardhat run scripts/sample-script.js

image

To deploy the HelloCelo.sol contract you created, you’ll need to update the sample-script.js file to include the new smart contract information. To do this, replace lines 17–22 with the code below.

const HelloCelo = await hre.ethers.getContractFactory("HelloCelo");
const helloCelo = await HelloCelo.deploy();
await helloCelo.deployed();
console.log("HelloCelo deployed to:", helloCelo.address);

image

tip

If you created a different smart contract, update the const names, file requirement and deployment to match your new contract.

Deploy HelloCelo.sol

You can now re-run sample-script.js to deploy the HelloCelo.sol contract.

npx hardhat run scripts/sample-script.js

image

✅ Step 4: Create and fund your account

To deploy to the test or main Celo networks, you’ll need an account that is funded with CELO tokens. In this post, you’ll get set up to deploy for free on the Celo Alfajores test network!

Create an account

If you don’t already have an account you would like to use, you can run celocli account:newfrom your terminal to create one for this project.

celocli account:new

image

Fund your account

The Alfajores testnet faucet helps you fund your account with test tokens. Copy your address from the terminal and paste it into the site to fund your account. This should send you tokens within a few seconds.

image

Check account balance

If you’d like to check your new account balance, you can use celocli to make sure you received your test funds.

celocli account:balance 0xYOURADDRESS

image

Create .env file

A .env file will help you hide the sensitive information you need for your configuration file. Create a .env file in your root folder and add your account’s private key.

PRIVATE_KEY="5ead931ce4812310e31f84c471945b96a13098aa6dc8cf0d3f6f451a5dea56cc"

image

tip

See ignoring files for more information.

✅ Step 5: Configure deployment settings

The hardhat configuration file specifies the networks for your contract deployment. As of now, the sample-script.js file ​is deploying your contracts to a local blockchain on Hardhat.

Update hardhat.config

To deploy to Celo, you to update the configuration file to point to the Celo network. To do this, open hardhat-config.js in a text editor and replace its contents with this Celo configuration code.

Local network

Creating your new Ganache workspace earlier made a local blockchain at localhost:7545. The local configuration connects to this local blockchain.

localhost: {
url: "http://127.0.0.1:7545"
},
tip

If you choose to Set up a Local Development Chain, your blockchain will also be hosted on a private network on localhost. This same configuration can be used to connect to the local development chain.

Alfajores test network

The alfajores configuration uses Forno to connect you to Alfajores using the private key in your .env file.

alfajores: {
url: “https://alfajores-forno.celo-testnet.org",
accounts: [process.env.PRIVATE_KEY],
chainId: 44787,
},

Celo main network

The celo configuration uses Forno to connect you to mainnet using the private key in your .env file. This tutorial will use Alfajores but you can to deploy to the main network whenever you’d like.

celo: {
url: "https://forno.celo.org",
accounts: [process.env.PRIVATE_KEY],
chainId: 42220,
},
tip

Forno is a cLabs hosted node service for interacting with the Celo network. This allows you to connect to the Celo Blockchain without having to run your own node.

✅ Step 6: Deploy your contract

You’ve done the hard part and it’s now time to deploy your contract to Celo! Run any of the following commands from your root project directory to deploy to Celo.

Deploy to Alfajores

This post got you set up to deploy on Alfajores. Try it out now! If this works you can skip the other deployment options and move on to the next step.

npx hardhat run scripts/sample-script.js --network alfajores

Deploy to Mainnet

Replace the private key in .env with a Celo Mainnet account that has Celo. Once you’ve done that you’ll be ready to deploy to Mainnet.

npx hardhat run scripts/sample-script.js --network celo

Deploy to Local Host

Open Ganache (installation instructions at beginning of the post) and create a workspace on localhost:7545. Then you’ll be able to deploy to localhost.

npx hardhat run scripts/sample-script.js --network localhost

✅ Step 7: View your deployed contract

Now that you deployed your contract, you can view it in the Celo block explorer (known as BlockScout. Copy your contract address from the terminal and navigate to the block explorer to search for your deployed contract.

  • Switch to your network using the dropdown by the search bar.
  • Navigate to BlockScout and select the network of your deployed contract.
  • Paste your contract address from the terminal window and search for it in BlockExplorer.

image

tip

Learn more about building and deploying dApps using the HardHat documentation.

✅ Step 8: Verify your smart contract

For people to use and interact with your contract, they’ll want to be able to view the smart contract code you created. Verifying a smart contract allows people to to do this from within the Celo Block Explorer.

Using Blockscout​

Navigate to the Code tab on the Explorer page for your contract’s address Click Verify & Publish to enter the smart contract verification page

image

  • Upload your smart contract (example: HelloCelo.sol) and its .json file (example: HelloCelo.json) found in build > contracts folder.

image

  • Click Verify & Publish
  • Navigate to the Contract Address Details Page in the block explorer to, use the Code, Read Contract, and Write Contract panels to view and interact with your deployed smart contract.

Using Hardhat-deploy plugin​

You can read an in depth guide about how to deploy and verify contracts on Celo programmatically using the hardhat-deploy plugin here.

Congratulations 🎉

That wraps up today’s topic on Deploying on Celo with Hardhat. You can review each of the items we covered below and check that you’re ready to apply these new skills.

Here’s a review of what we covered 🤔

  • Step 1: Environment setup​
  • Step 2: Project setup
  • Step 3: Write project code
  • Step 4: Configure deployment settings
  • Step 5: Compile and migrate your contract
  • Step 6: Deploy your Contract
  • Step 7: View your deployed contract
  • Step 8: Verify your smart contract

If you run into any issues, try reviewing the content or searching online to explore each topic in more detail. Hopefully, you’ve learned a few things about Deploying on Celo with Hardhat that you can apply in the real world.

GN! 👋

Go back

· 10 min read

How to deploy a smart contract to Celo testnet, mainnet, or a local blockchain using Truffle.

header

Hello Developers 🌱

Welcome to today's post, where we'll break down a blockchain topic into bite-sized pieces to help you learn and apply your new skills in the real world. Today's topic is Deploying on Celo with Truffle.

Here's a list of what we'll cover 🗒

  • Step 1: Environment setup
  • Step 2: Project setup
  • Step 3: Write project code
  • Step 4: Create and fund your account
  • Step 5: Configure deployment settings
  • Step 6: Compile and migrate your contract
  • Step 7: Deploy your contract
  • Step 8: View your deployed contract
  • Step 9: Verify your smart contract

By the end of this post, you'll be able to create, deploy, and interact with your smart contract on Celo testnet, mainnet, or localhost using Truffle.

Let's go! 🚀

Introduction to Truffle​

Truffle is a world-class development environment, testing framework, and asset pipeline for blockchains using the Ethereum Virtual Machine (EVM). By creating a Truffle project and editing a few configuration settings you can easily deploy your project on Celo.

image

tip

Learn more: If you are new to Truffle check out the Truffle docs.

✅ Step 1: Environment setup

Before getting started you'll need to set up Celo in your local environment. You can do this on Mac or Windows and can find the details on docs.celo.org.

image

Celo projects include common dependencies like Nodejs, npm, nvm, yarn, git, and xCode. If you already have these installed you can follow this post to set up Celo specific dependencies.

Node v12.0.0

To build on Celo you’ll use node v12.0.0.

nvm install v12.0.0
nvm use v12.0.0
node --version

Celo Command Line Interface

The celocli lets you interact with the Celo Protocol smart contracts.

npm install -g @celo/celocli

image

Install Truffle

Truffle lets you to develop, test, and deploy dApps on Celo.

npm install -g truffle

Install Ganache

Ganache UI creates a local blockchain to help you deploy and test contracts. You can install and set up the UI from their website and can find more details in the Ganache docs.

image

tip

The @celo/ganache-cli is Celo’s version of Ganache. It doesn’t seem to be working for me but you can try installing it in your environment.

From the Ganache UI, create a new workspace on localhost:7545.

image

✅ Step 2: Project setup

Now that you have your environment setup, you’re ready to create your project! Open your terminal to create and navigate into a project folder.

mkdir celo-truffle && cd celo-truffle

image

Initialize an npm project

Initialize an npm project from within the project directory.

npm init -y

image

Install hdwallet-provider

Truffle/hdwallet-provider lets you sign Celo transactions for addresses derived from a mnemonic or private key. You can install this now and you’ll use it later when configuring your project.

npm install @truffle/hdwallet-provider --save

image

Install dotenv

Dotenv is a module that loads environment variables from a .env file. Install this now and you’ll use this to import information to your Truffle configuration file.

npm install dotenv

image

Initialize Truffle

Initializing Truffle creates your project’s truffle environment. Use truffle init to start up your truffle project!

truffle init

image

Open your project

Your project is set up and you’re ready to start building! Open your project in Visual Studio code or your preferred IDE.

code .

image

tip

You can launch VS Code from the command line by installing it in your shell path.

✅ Step 3: Build your project

To build your project you’ll write a smart contract, migrations, .env, and .gitignore file. You’ll also create an account, fund it with test tokens, and connect the account to your project.

Smart contract code

Create a file named HelloCelo.sol in the /contracts folder and add the Solidity code below.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract HelloCelo {
string public greet = "Hello Celo!";
}

image

tip

Learn more: Read the Solidity docs or Solidity by Example to learn more about the programming language for building smart contracts.

Create migrations file

Create a file named 2_deploy_contracts.js in the /migrations folder and add the code below.

var HelloCelo = artifacts.require('HelloCelo')
module.exports = function (deployer) {
deployer.deploy(HelloCelo)
}

image

tip

If you created a different smart contract, update the variable name, file requirement and deployment to match your new contract.

✅ Step 4: Create and fund your account

To deploy to the test or main Celo networks, you’ll need an account that is funded with CELO tokens. In this post, you’ll get set up to deploy for free on the Celo Alfajores test network!

Create an account

If you don’t already have an account you would like to use, you can run celocli account:new from your terminal to create one for this project.

celocli account:new

image

Fund your account

The Alfajores testnet faucet helps you fund your account with test tokens. Copy your address from the terminal and paste it into the site to fund your account. This should send you tokens within a few seconds.

image

Check account balance

If you’d like to check your new account balance, you can use celocli to make sure you received your test funds.

celocli account:balance 0xYOURADDRESS

image

Create .env file

A .env file will help you hide the sensitive information you need for your configuration file. Create a .env file in your root folder and add your account’s private key.

PRIVATE_KEY="5ead931ce4812310e31f84c471945b96a13098aa6dc8cf0d3f6f451a5dea56cc"

image

Create .gitignore file

A .gitignore file will allow you to ignore certain files if you add this project to git or GitHub. Create a .gitignore file in your root directory and add the code below to ignnore your node_modules, .DS_Store and .env files.

# dependencies
/node_modules
# Mac users
.DS_Store
#hidden files
.env

image

tip

See ignoring files for more information.

✅ Step 5: Configure deployment settings

The truffle configuration file specifies the networks for your contract deployment. By default, it is set up to deploy to the Ethereum network but you can update this information to deploy to any Celo network.

Update Truffle.config

Open truffle-config.js in a text editor and replace its contents with this Celo configuration code. This updates the truffle.config.js file to point toward Celo networks.

image

Local network

Creating your Ganache workspace earlier made a local blockchain at localhost:7545. The local configuration connects to this local blockchain.

local: {
host: "127.0.0.1",
port: 7545,
network_id: "*"
}

Remote node connections

If you’re not running your own node, you can connect to remote nodes using Forno. Forno is a Celo node service that lets you connect to the Celo Alfajores Test Network and Celo Mainnet.

Alfajores test network

The alfajores configuration uses Forno to connect you to Alfajores using HDWalletProvider and the private key in your .env file.

alfajores: {
provider: function() {
return new HDWalletProvider(process.env.MNEMONIC, "https://alfajores-forno.celo-testnet.org")
},
network_id: 44787,
gas: 20000000
}

Celo main network

The celo configuration uses Forno to connect you to mainnet using HDWalletProvider and the private key in your .env file. This tutorial will use Alfajores but you can to deploy to the main network whenever you’d like.

celo: {
provider: function() {
return new HDWalletProvider(process.env.MNEMONIC, "https://forno.celo.org")
},
network_id: 42220,
gas: 4000000
}
tip

Learn more: To deploy to Celo Mainnet, follow 3 simple steps to connect your MetaMask wallet to Celo and deploy to this account instead of your test account.

✅ Step 6: Compile and migrate your contract

Compiling and migrating your contract prepares the code to deploy on a Celo network. This will also help you catch any errors and debug your code.

Compile Contract

Compile the Solidity code into Ethereum bytecode. This command will compile any new or updated Solidity (.sol) contracts found in /contracts.

truffle compile

image

Now you should see HelloCelo.json in your /build folder.

tip

Learn more about compiling contracts with Truffle here.

Migrate Contract

Truffle migrate compiles AND migrates your contract. In the future you can run truffle migrate to complete both steps.

truffle migrate

image

✅ Step 7: Deploy your Contract​

For this post, use truffle deploy --network alfajores to deploy to Alfajores but it’s easy to deploy to local or mainnet whenever you’d like!

truffle deploy --network alfajores
truffle deploy --network celo
truffle deploy --network local

Deploy with — reset​ (optional)

You can edit contracts and redeploy at any time using the commands above. If for any reason you’d like to redeploy a contract that you didn’t edit you can use the reset flag. This will redeploy each contract to a new contract address.

truffle deploy --network NETWORK --reset
truffle migrate --network NETWORK --reset
tip

Save contract addresses for future reference. If you lose it, go to the block explorer to review your wallet transactions for contract creation and its response. Truffle saves deployment information, like transaction hashes and contract addresses, in JSON files in ./build/contracts/.

✅ Step 8: View your deployed contract

Now that you deployed your contract, you can view it in the Celo block explorer (known as BlockScout. Copy your contract address from the terminal and navigate to the block explorer to search for your deployed contract.

  • Switch to your network using the dropdown by the search bar.
  • Navigate to BlockScout and select the network of your deployed contract.
  • Paste your contract address from the terminal window and search for it in BlockExplorer.

image

tip

Learn more about exploring the Celo network and smart contract details in BlockScout here.

✅ Step 9: Verify your smart contract​

For people to use and interact with your contract, they’ll want to be able to view the smart contract code you created. Verifying a smart contract allows people to to do this from within the Celo Block Explorer.

  • Navigate to the Code tab on the Explorer page for your contract’s address
  • Click Verify & Publish to enter the smart contract verification page

image

  • Upload your smart contract (example: HelloCelo.sol) and its .json file (example: HelloCelo.json) found in build > contracts folder.

image

  • Click Verify & Publish
  • Navigate to the Contract Address Details Page in the block explorer to use the Code, Read Contract, and Write Contract panels to view and interact with your deployed smart contract.

Congratulations 🎉

That wraps up today’s topic on Deploying on Celo with Truffle. You can review each of the items we covered below and check that you’re ready to apply these new skills.

Here’s a review of what we covered 🤔

  • Step 1: Environment setup
  • Step 2: Project setup
  • Step 3: Write project code
  • Step 4: Create and fund your account
  • Step 5: Configure deployment settings
  • Step 6: Compile and migrate your contract
  • Step 7: Deploy your contract
  • Step 8: View your deployed contract
  • Step 9: Verify your smart contract

If you run into any issues, try reviewing the content or searching online to explore each topic in more detail. Hopefully, you’ve learned a few things about Deploying on Celo with Truffle that you can apply in the real world.

GN! 👋