BlogTechnology and KnowHow

Solidity and Typescript Part 1

Symphony logo
Symphony
October 18th, 2022

The goal

The goal of this series is to show bits and pieces of techniques and approaches available when building a project with solidity.

What will we achieve in this part?

First part of the short post series will go through project configuration and setup using the latest packages and compilers available (to date). Visit the GitHub repository to see a complete project for this part.

Β What to expect for the next session?

In the next session, we will be building and deploying an upgradeable contract and writing basic tests.

The beginning

Suggestion: Create a GitHub repository for this project, as we'll use GitHub actions in future parts.

Since we have already defined some objectives let's start the fun. So what we need before we even begin creating the projects are some major dependencies. First of which is, of course, Node.js, which can be downloaded from here, as well as Visual Studio Code.Β  You can use any IDE you like, I'm just used to VSC for solidity. Extensive Node.js knowledge is not required to follow along, however, some principles are good to know for a deeper understanding of whys.

To start it off, let's create a folder for our project, I'll name mine bc_blog, you can choose any name you like and then navigate to it.

> mkdir bc_blog> cd bc_blog

Next we'll need to initialize Node.js for our project as well as Hardhat, which we'll use as a main solidity tool.

> npm init -y> npx hardhat

During hardhat initialization, confirm to proceed if asked to install the package, select a typescript project, confirm project root and add .gitignore if you don't have one already. It will create a baseline for the project with example configuration, contract, deploy script, and tests. We will use these to check if our project has been set up correctly.

The setup

Let's configure our project dependencies. We'll install OpenZeppelin contract abstractions, environment configurations, type supports, and some tools to make our life easier.

> npm i --save-dev @openzeppelin/hardhat-upgrades @typechain/ethers-v5 @types/chai @types/mocha @types/node chai dotenv @nomicfoundation/hardhat-chai-matchers ethers hardhat solhint solidity-coverage@0.7.21 ts-node typechain typescript @nomicfoundation/hardhat-toolbox> npm i --save @openzeppelin/contracts @openzeppelin/contracts-upgradeable hardhat-abi-exporter keccak256 merkletreejs web3-utils

After running these two commands update package.json with some convenience scripts.

"scripts": {

    "test": "npx hardhat test",

    "compile": "npx hardhat compile",

    "deploy-rinkeby": "npx hardhat run scripts/deploy.ts --network rinkeby",

    "deploy-mainnet": "npx hardhat run scripts/deploy.ts --network mainnet"

}



Now, before we configure hardhat, let's add needed environment variables first. In project root, create a .env file like shown below.

REPORT_GAS=trueETHERSCAN_API_KEY=RINKEBY_RPC=https://rinkeby.infura.Io/v3/9aa3d95b3bc440fa88ea12eaa4456161RINKEBY_PRIVATE_KEY=

MAINNET_RPC=https://rpc.ankr.com/eth

MAINNET_PRIVATE_KEY=

COINMARKETCAP_API_KEY=

As you can see, there are some platforms like Etherscan and CoinmarketCap, as well as private keys that you need to provide. Regarding the private key, the best recommendation I can give is to create a new Metamask wallet and export its private key. Additionally, you might need a faucet to feed your testnet wallet.

There's also an odd one which is REPORT_GAS=true. This variable will tell the gas reporter plugin to include gas in the test report.

The next step would be to obtain API keys from Etherscan andΒ CoinmarketCap, and no worries, both of those have free tiers, which are quite sufficient for development purposes. After registering to both platforms and obtaining their keys, return to the .env file and update the variables.

Let's use those in hardhat.config.ts.

import * as dotenv from "dotenv";


import { HardhatUserConfig, task } from "hardhat/config";

import "@nomicfoundation/hardhat-toolbox";

import "@openzeppelin/hardhat-upgrades";

import "hardhat-abi-exporter";

import "@nomicfoundation/hardhat-chai-matchers";

dotenv.config();


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);

    }

});


const rinkebyAccount: string = process.env.RINKEBY_PRIVATE_KEY ?? "";

const mainnetAccount: string = process.env.MAINNET_PRIVATE_KEY ?? "";


const config: HardhatUserConfig = {

    solidity: "0.8.16",

    networks: {

        rinkeby: {

            url: process.env.RINKEBY_RPC,

            accounts: [rinkebyAccount]

        },

        mainnet: {

            url: process.env.MAINNET_RPC,

            accounts: [mainnetAccount]

        },

    },

    gasReporter: {

        currency: "USD",

        token: "ETH",

        gasPriceApi:

            "https://api.etherscan.io/api?module=proxy&action=eth_gasPrice",

        coinmarketcap: process.env.COINMARKETCAP_API_KEY,

        showTimeSpent: true

    },

    abiExporter: {

        path: "./data/abi",

        runOnCompile: true,

        clear: true,

        flat: true,

        spacing: 2,

        pretty: false,

    },

    etherscan: {

        apiKey: process.env.ETHERSCAN_API_KEY,

    }

};


export default config;

This setup will allow your tests to calculate gas estimates automatically and present them to you in a very readable way so that you can focus on writing optimized code.

And lastly, update our tsconfig.json.

{

  "compilerOptions": {

      "target": "es2018",

      "module": "commonjs",

      "strict": true,

      "esModuleInterop": true,

      "outDir": "dist",

      "declaration": true

  },

  "include": [

      "./scripts",

      "./test",

      "./typechain"

  ],

  "files": [

      "./hardhat.config.ts"

  ]

}

Testing

After we've configured everything it is time to test it out. Go ahead and run:

> npm run test

The result should be as seen in the image below.Β 

If you have any errors or issues you're not able to solve, feel free to tweet me, and I'll try to help out whenever possible.

Conclusion

This is it for the first part of the series. Let's summarize what we've done:

  • Installed Node.js and IDE (who needed it)
  • Created and initialized the project
  • Installed project package dependencies
  • Added npm scripts to package.json
  • Configured environment variables
    • Including creating accounts and obtaining API keys from Etherscan and CoinmarketCap
  • Updated Hardhat and Typescript configurations
  • Tested the setup

For the next part of the series, we will be creating an upgradeable contract, testing it, and deploying it to testnet using this project.

Hope you find this post useful. Keep crunching!

About the author

Srdjan Debic is a Solution Architect working in the engineering hub in Belgrade.

Srdjan is an accomplished Solution Architect experienced in leading projects by acting as an architect, developer, and programmer analyst. In terms of specific technologies, he primarily relies on .Net, Node, Solidity, and Javascript. He is proficient in supporting project deliverables and maintaining releases and is a strong leader in guiding support teams and solving complex issues.