Build Your Own Crowdfunding Dapp using Infura and Linea

Build Your Own Crowdfunding Dapp using Infura and Linea

Working with Consensys' new zkEVM chain: Linea

·

8 min read

The past few months have been extremely exciting for web3 developers in the Ethereum ecosystem. While there have been several interesting developments around scalability and better user experience, arguably the biggest offering to come out this year has been Consensys' zkEVM chain Linea, which released to mainnet on July 11, 2023 and in the first few days has already processed over half a million transactions. Linea shows a lot of promise in solving the most pressing problems plaguing public blockchains: speed, scale, and cost.

Let's try it out. We'll build our very own crowdfunding dapp and deploy it to Linea using Infura, Truffle, and MetaMask.

Linea: an EVM-compliant L2

Linea is an L2 scaling solution known as a zero-knowledge rollup (or zk-rollup, for short). These rollups enable developers to offload data and computations from the main chain while guaranteeing the security of the latter. It does so by employing a cryptographic method called zero-knowledge proofs which allows Linea to prove and verify transactions, but the Ethereum blockchain still provides the security.

Effectively, this leads to the creation of a supplemental chain (an L2) where transactions are blazing fast and extremely cheap. Linea can handle more transactions per second than Ethereum while guaranteeing a faster time to finality and at a fraction of the costs.

Linea is also Ethereum Virtual Machine (EVM) compliant (a zkEVM). In other words, all the tools, programming languages, and design patterns will work and behave in exactly the same way as they do on Ethereum. It's all about high scalability and low cost all while being developer friendly.

Building on Linea is best done through Infura, which is also built by Consensys. Because these two products are well integrated, you can begin building and deploying your dapps in a matter of minutes.

The Linea testnet, which has been active for about three months, has seen over 5 million unique addresses created and over 40 million transactions. And now with the mainnet launch, projects and developer adoption should only accelerate. So let's start building that dapp.

Create a crowdfunding dapp on Linea

Step 1: Sign up for an Infura account

First we need an Infura account. We need this for two purposes: to get free lineaETH from Infura's faucet, and to get access to an RPC endpoint through which we can deploy our smart contract and conduct transactions.

If you haven't done so already, sign up for an Infura account. Next, navigate to the dashboard and create a new key from the top right.

Image description

For network, choose Web3 API. You can name your key/project anything you want.

After creating your key, you’ll be redirected to your new project’s dashboard where you will be able to see a section called Endpoints.

Here, you’ll find both the testnet and mainnet endpoints of Linea. Take note of both. In this project, we will be deploying to the testnet but we will also go through the instructions you need to follow in order to deploy a real dapp to the mainnet.

Step 2: Install a web3 wallet like MetaMask

To pay gas fees and sign transactions, we need a self-custodial crypto wallet. For this tutorial, we will use MetaMask, a free and proven wallet. At the time of writing, MetaMask is the most popular wallet in the world.

Download MetaMask as a browser extension here.

If this is your first time using MetaMask, you’ll be prompted to complete a series of steps that end with generating a wallet recovery phrase. Store this carefully. Not only will you need it later, but losing it means you will also lose access to your wallet.

After setting up your wallet, navigate to the top left and click on the Network dropdown. Here, toggle Show Test Networks. You should see the Linea Goerli network. Switch to this; we will be operating on this chain for the rest of the tutorial.

Image description

Step 3: Acquire lineaETH through the Infura faucet

To pay for gas, we need lineaETH.

Fortunately, since we’re working on a testnet, we can obtain free test ETH from Infura’s Linea faucet. You might be required to sign in with your Infura account to obtain funds.

Once this is done, you should see a small balance of lineaETH in MetaMask.

Image description

Step 4: Install node and npm using Truffle

In order to create and configure a Truffle project (which is where we will write and deploy our smart contracts), we need node and npm on our local machine. Get them here.

Once this is done, you can check that they’ve been installed correctly by checking their version numbers on the Terminal.

$ node -v
$ npm -v

Step 5: Create a Truffle project

With node and npm installed, we’re ready to create our Truffle project. Open a terminal and run these commands:

$ mkdir crowdfund && cd crowdfund
$ npm init -y
$ npm install –global truffle
$ truffle init
$ truffle test

Next, we’ll install the dotenv and the HD Wallet Provider packages. The former will help keep our credentials secret and safe, whereas the latter will allow us to integrate MetaMask with our Truffle project.

$ npm install @truffle/hdwallet-provider dotenv

Step 6: Write the Crowdfunding smart contract

Now let’s write our smart contract! We’ll keep it very simple to start, but you can add more advanced functionality to this contract as needed.

The smart contract will set a value as the goal amount, and the public will be invited to pool funds for the project.

The funding will be open for a set period of time. Once this period expires, if the amount pooled is greater than or equal to the goal, the owner of the contract will be able to withdraw the funds from the contract. Otherwise, funds will be released back to the origin wallets.

Open the Truffle project created in the previous step in your code editor. Next, create a file called Crowdfunding.sol in the folder called contracts, and add the following:

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

contract Crowdfunding {
    address public owner;
    uint public goal;
    string public description;
    uint public deadline;

    uint public totalFunds;
    bool public withdrawn;
    mapping(address => uint) public contributions;
    address[] public investors;

    constructor(uint _goal, string memory _description, uint _deadlineBlockCount) {
        // Define goal, project description, and deadline
        goal = _goal;
        description = _description;
        deadline = block.number + _deadlineBlockCount;

        // Set owner to deployer of the contract
        owner = msg.sender;
        withdrawn = false;
    }

    function contribute() public payable {
        require(block.number <= deadline, "Funding period has ended.");

        // Add amount to total funds
        totalFunds += msg.value;

        // Add wallet to investor list and amount to contributions dictionary
        contributions[msg.sender] += msg.value;
        investors.push(msg.sender);
    }

    function withdraw() public {
        require(block.number > deadline, "Cannot withdraw before the deadline.");
        require(!withdrawn, "Funds have been withdrawn.");

        withdrawn = true; // prevent re-entrancy attacks

        if(totalFunds >= goal) {
            // If goal was reached, transfer the funds to the owner
            payable(owner).transfer(totalFunds);
        } else {
            // If goal was not reached, refund investors
            for(uint i = 0; i < investors.length; i++) {
                address investor = investors[i];
                payable(investor).transfer(contributions[investor]);
            }
        }
    }

    function isGoalReached() public view returns (bool) {
        return totalFunds >= goal;
    }
}

Make sure everything is working by compiling the contract using:

$ truffle compile

If all goes well, the output should look something like this:

Compiling your contracts...
===========================
> Compiling ./contracts/CrowdFunding.sol
> Artifacts written to /Users/rounakbanik/paulie/crowdfund/build/contracts
> Compiled successfully using:
   - solc: 0.8.20+commit.a1b79de6.Emscripten.clang

Step 7: Connect your project to Infura and MetaMask

Let’s now configure our Truffle project to work with Infura and MetaMask.

As a first step, create the file .env in the root directory and add the following code:

MNEMONIC="< Metamask Wallet Recovery Phrase >"

Next, let’s configure Truffle to work with Infura. Add the following code to truffle.config.js:

require('dotenv').config();
const HDWalletProvider = require('@truffle/hdwallet-provider');
const { MNEMONIC } = process.env;

module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 8545,
      network_id: "*"
    },
    linea_goerli: {
      provider: () => new HDWalletProvider(MNEMONIC, `<INFURA LINEA TESTNET RPC>`),
      network_id: '59140',
    },
    linea_mainnet: {
      provider: () => new HDWalletProvider(MNEMONIC, `< INFURA LINEA MAINNET RPC>`),
      network_id: '59144',
    },
  }
};

Step 8: Deploy the smart contract to Linea via Infura RPC

As a final step, let’s create a deployment script in the migrations folder. Name it 1_deploy_contract.js. Add the following:

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

module.exports = function(deployer) {
  // Arguments are: contract
  deployer.deploy(
    Crowdfunding,
    // _goal
    web3.utils.toWei("10", "ether"),
    // _description
    "Test Project",
    // _deadlineBlockCount
    10000
  );
};

Now deploy the contract:

$ truffle migrate --network linea_goerli

You’ll see something like:

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'linea_goerli'
> Network id:      59140
> Block gas limit: 30000000 (0x1c9c380)


1_deploy_contract.js
====================

   Deploying 'Crowdfunding'
   ----------------------
   > transaction hash:    0x3e2889c9b6f8b05d99c482a617893cf34e...
   > Blocks: 2            Seconds: 18
   > contract address:    0x64ccE52898F5d61380D2Ec8C02F2EF16F2...
   > block number:        414030
   > block timestamp:     1680726601
   > account:             0xc361Fc33b99F88612257ac8cC2d852A5CE...
   > balance:    0.185605297028804606
   > gas used:   1704607 (0x1a029f)
   > gas price:  2.500000007 gwei
   > value sent: 0 ETH
   > total cost: 0.004261517511932249 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost: 0.004261517511932249 ETH

Summary
=======
> Total deployments:   1
> Final cost:    0.004261517511932249 ETH

Congratulations! The smart contract is now live on Linea.

Notice that we’ve done all this using tools and development environments built for the Ethereum network. Also, notice how we’ve made deployment possible at an extremely cheap transaction cost. That’s the combined beauty of Linea—EMV-compliant, fast, and cheap.

Now that your crowdfunding contract is live and working on Linea testnet, it's time to take it to mainnet! There your supporters will be able to invest in your project by paying a negligible amount of gas and still get the contract enforcement guaranteed by Ethereum.

To deploy to mainnet, simply switch the RPC endpoint when you deploy the contract:

$ truffle migrate --network linea_mainnet

Conclusion

Hopefully you’ve learned what Linea is all about, how it makes Ethereum better, and how you can deploy your own smart contract on the network. To learn more, check out the Linea site and start building!