Deploy with Hardhat

After connecting to the Plume testnet and funding your wallet with bridged SepoliaETH, you can easily deploy any EVM-compatible smart contract using the same tools used in Ethereum, Arbitrum, Optimism, and Polygon development.

All tools will require that you provide some or all of the Plume testnet network parameters so they can deploy to the testnet. You can refer to them here:

Hardhat Setup

Hardhat is a Node.js framework for deploying smart contracts, built by the non-profit Nomic Foundation as an open-source public good. Simply follow their "Getting Started" documentation to create a new Node.js project and install Hardhat. We'll also install the Nomic Foundation's hardhat-ethers plugin, which adds ethers.js to the Hardhat Runtime Environment and allows us to write scripts to interact with the chain.

$ npm init
$ npm install --save-dev hardhat @nomicfoundation/hardhat-ethers
$ npx hardhat init

Select "Create an empty hardhat.config.js", as we will be writing our own smart contracts from scratch. Let's write a simple one-of-one NFT contract based on OpenZeppelin's open-source ERC-721 implementation to tokenize our CBO's prized Rolex watch on Plume. First, install the dependency on OpenZeppelin:

$ npm install @openzeppelin/contracts

Make the following adjustments to the auto-generated hardhat.config.js file to prepare to deploy to the Plume testnet:

  • Import the hardhat-ethers plugin into the Hardhat Runtime Environment.

  • In order to use the latest version of the OpenZeppelin contracts, make sure that the Solidity compiler version is 0.8.20 or above.

  • Add the Plume testnet network parameters. You can store your testnet private keys directly in the configuration file, load it from an environment file using dotenv, or manually run export PRIVATE_KEY=... before executing the following commands.

require("@nomicfoundation/hardhat-ethers");

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: "0.8.25",
  settings: {
    evmVersion: "cancun"
  },
  networks: {
    hardhat: {},
    "plume-testnet": {
      url: "https://testnet-rpc.plumenetwork.xyz/http",
      chainId: 161221135,
      accounts: [process.env.PRIVATE_KEY]
    }
  }
};

Now, save the following smart contract in contracts/RolexYachtMaster40.sol. If you plan to verify this contract, insert your name into the comment on line 2 so that the uploaded source code is different from anyone else that is following this guide. Run npx hardhat compile to compile it:

// SPDX-License-Identifier: MIT
// Author: <YOUR NAME HERE>
pragma solidity ^0.8.25;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract RolexYachtMaster40 is Ownable, ERC721 {
    error NFTAlreadyMinted();
    bool private _minted;

    constructor(
        address initialOwner
    ) Ownable(initialOwner) ERC721("Rolex Yacht-Master 40", "") {}

    function mint() public onlyOwner returns (uint256) {
        if (_minted) {
            revert NFTAlreadyMinted();
        }
        _safeMint(msg.sender, 0);
        _minted = true;
        return 0;
    }
}

Deploy NFT Contract

To deploy your smart contract to the Plume testnet with Hardhat, follow the instructions in the "Deploying Your Contracts" documentation. For example, you can save the following deployment script to scripts/deploy.js:

const hre = require("hardhat");

async function main() {
  const [deployer] = await hre.ethers.getSigners();
  const nft = await hre.ethers.deployContract("RolexYachtMaster40", [deployer], {})
  await nft.waitForDeployment();
  console.log(`Successfully deployed NFT to ${nft.target}`);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

After double checking that your private key is accessible to Hardhat and plume-testnet is correctly configured in hardhat.config.js, simply run the deployment script:

$ npx hardhat compile                                                                                    
Compiled 1 Solidity file successfully (evm target: cancun).
$ npx hardhat run --network plume-testnet scripts/deploy.js
Successfully deployed NFT to 0x24fD012C1fd6c496609018e19264D30D580d2385

You can see the resulting smart contract on the Plume block explorer.

Verify NFT Contract

The Plume testnet block explorer is built using Blockscout's open-source technology, and supports verification of contracts via the hardhat-verify plugin using its Etherscan-compatible API. See the "Smart Contract Verification" section for more details.

To verify your smart contract, follow the instructions in Blockscout's "Hardhat Verification Plugin" page. Note that the hardhat-etherscan plugin in those docs has been renamed to hardhat-verify, which you will have to install:

$ npm install --save-dev @nomicfoundation/hardhat-verify

Make the following adjustments to your existing hardhat.config.js file:

  • Import the hardhat-verify plugin into the Hardhat Runtime Environment.

  • Unlike Etherscan, Blockscout does not require an API key, but the hardhat-verify plugin requires that you put in any non-empty string, so we can just use "test" as a placeholder.

  • Add the Plume testnet block explorer URLs. Make sure to add the extra \? to the end of the API URL, otherwise the verification will fail.

require("@nomicfoundation/hardhat-ethers");
require("@nomicfoundation/hardhat-verify");

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: "0.8.25",
  settings: {
    evmVersion: "cancun"
  },
  networks: {
    hardhat: {},
    "plume-testnet": {
      url: "https://testnet-rpc.plumenetwork.xyz/http",
      chainId: 161221135,
      accounts: [process.env.PRIVATE_KEY]
    }
  },
  etherscan: {
    apiKey: {
      "plume-testnet": "test"
    },
    customChains: [
      {
        network: "plume-testnet",
        chainId: 161221135,
        urls: {
          apiURL: "https://testnet-explorer.plumenetwork.xyz/api\?",
          browserURL: "https://testnet-explorer.plumenetwork.xyz"
        }
      }
    ]
  }
};

Let's verify our existing contract by saving our constructor arguments (i.e. the deployer's address) to an environment variable and running the verify command on the previously deployed contract address:

$ export DEPLOYER_ADDRESS=0x96774F9f5693dFb95c973b676DFE6EaFc6f95E6d                                
$ npx hardhat verify --network plume-testnet \
    0x24fD012C1fd6c496609018e19264D30D580d2385 $DEPLOYER_ADDRESS
Successfully submitted source code for contract
contracts/RolexYachtMaster40.sol:RolexYachtMaster40 at 0x24fD012C1fd6c496609018e19264D30D580d2385
for verification on the block explorer. Waiting for verification result...

Successfully verified contract RolexYachtMaster40 on the block explorer.
https://testnet-explorer.plumenetwork.xyz/address/0x24fD012C1fd6c496609018e19264D30D580d2385#code

You can see the resulting verified smart contract code on the Plume block explorer.

Fork Testing

To deploy smart contracts on a fork of Plume Testnet, make sure to install Hardhat with the unknown-txs tag on version 2.20.x:

$ # Install using your preferred package manager, for example:
$ yarn add -D hardhat@unknown-txs
$ npm install -D hardhat@unknown-txs
$ pnpm install -D hardhat@unknown-txs

Compile using this Hardhat version and the following to your hardhat.config.js in networks:

hardhat: {
  forking: {
    url: "https://testnet-rpc.plumenetwork.xyz/http",
  },
  chainId: 161221135
},

Run the forked node:

$ npx hardhat node --fork https://testnet-rpc.plumenetwork.xyz/http

Nothing to compile
No need to generate any newer typings.
✅ Generated documentation for 11 contracts
{
  chainId: 161221135,
  deployer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
}
Deploying to Plume-Testnet
deploying "RolexYachtMaster40" (tx: 0xf49634229a8c1f4e9b72fd57e5774afc0dbfa2feeed457592b4a8aaeb22d233a)...: deployed at 0x5FbDB2315678afecb367f032d93F642f64180aa3 with 1321634 gas
{
  Contracts: { RolexYachtMaster40: '0x5FbDB2315678afecb367f032d93F642f64180aa3' }
}
Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/

Last updated