Skip to content

commune-ai/comstable

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 

Repository files navigation

Commune EVM Integration Guide with Hardhat

Overview

Commune's EVM (Ethereum Virtual Machine) compatibility allows developers to deploy and execute smart contracts using modern development tools like Hardhat. This guide covers the setup, development, and deployment process using Hardhat on Commune's testnet.

Prerequisites

Required Global Installations

npm install -g npm@latest
npm install -g hardhat

Project Setup

  1. Clone the repo and initialize:
npm init -y
  1. Install required dependencies:
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox @openzeppelin/contracts dotenv
  1. Initialize Hardhat:
npx hardhat init

Select "Create a JavaScript project" when prompted.

Environment Setup

Create a .env file in your project root:

PRIVATE_KEY=your_private_key_here_for_your_ethereum wallet
COMMUNE_RPC_URL=https://testnet.api.communeai.net

Make sure you have COMAI testnet tokens in your wallet. You can read the first section on transferring tokens from your substrate wallet to your erc-20 address here: https://communeai.org/docs/subspace/evm then continue if you haven't done that already.

Project Configuration

Hardhat Config

Replace the contents of hardhat.config.js with:

require("@nomicfoundation/hardhat-toolbox");
require('dotenv').config();

const PRIVATE_KEY = process.env.PRIVATE_KEY;
const COMMUNE_RPC_URL = process.env.COMMUNE_RPC_URL;

module.exports = {
  solidity: "0.8.20",
  networks: {
    commune: {
      url: COMMUNE_RPC_URL,
      accounts: [PRIVATE_KEY],
      chainId: 9461,
      gasPrice: 1000000000,  // 1 gwei
    },
    hardhat: {
      chainId: 31337
    }
  },
  paths: {
    sources: "./contracts",
    tests: "./test",
    cache: "./cache",
    artifacts: "./artifacts"
  }
};

Smart Contract Development

Sample ERC-20 Token Contract

Create contracts/MyToken.sol:

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC20, Ownable {
    constructor(
        string memory name,
        string memory symbol,
        uint256 initialSupply
    ) ERC20(name, symbol) Ownable(msg.sender) {
        _mint(msg.sender, initialSupply);
    }

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}

Test Script

Create test/MyToken.test.js:

const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("MyToken", function () {
  let myToken;
  let owner;
  let addr1;
  let addr2;

  beforeEach(async function () {
    [owner, addr1, addr2] = await ethers.getSigners();
    
    const MyToken = await ethers.getContractFactory("MyToken");
    myToken = await MyToken.deploy(
      "MyToken",
      "MTK",
      ethers.parseEther("1000000") // 1 million tokens
    );
  });

  describe("Deployment", function () {
    it("Should set the right owner", async function () {
      expect(await myToken.owner()).to.equal(owner.address);
    });

    it("Should assign the total supply of tokens to the owner", async function () {
      const ownerBalance = await myToken.balanceOf(owner.address);
      expect(await myToken.totalSupply()).to.equal(ownerBalance);
    });
  });

  describe("Transactions", function () {
    it("Should transfer tokens between accounts", async function () {
      await myToken.transfer(addr1.address, 50);
      expect(await myToken.balanceOf(addr1.address)).to.equal(50);

      await myToken.connect(addr1).transfer(addr2.address, 50);
      expect(await myToken.balanceOf(addr2.address)).to.equal(50);
    });

    it("Should fail if sender doesn't have enough tokens", async function () {
      const initialOwnerBalance = await myToken.balanceOf(owner.address);
      await expect(
        myToken.connect(addr1).transfer(owner.address, 1)
      ).to.be.revertedWith("ERC20: transfer amount exceeds balance");
      expect(await myToken.balanceOf(owner.address)).to.equal(
        initialOwnerBalance
      );
    });
  });
});

Deployment Script

Create scripts/deploy.js:

const hre = require("hardhat");

async function main() {
  const [deployer] = await ethers.getSigners();
  console.log("Deploying contracts with the account:", deployer.address);

  const MyToken = await ethers.getContractFactory("MyToken");
  const myToken = await MyToken.deploy(
    "MyToken",
    "MTK",
    ethers.parseEther("1000000") // 1 million tokens
  );

  await myToken.waitForDeployment();
  const address = await myToken.getAddress();

  console.log("Token deployed to:", address);
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

Development Workflow

  1. Compile Contracts
npx hardhat compile
  1. Run Tests
npx hardhat test
  1. Run Local Node (Optional)
npx hardhat node
  1. Deploy to Commune Testnet
npx hardhat run scripts/deploy.js --network commune

Contract Verification

Create scripts/verify.js:

const hre = require("hardhat");

async function main() {
  const contractAddress = "YOUR_DEPLOYED_CONTRACT_ADDRESS";
  
  await hre.run("verify:verify", {
    address: contractAddress,
    constructorArguments: [
      "MyToken",
      "MTK",
      ethers.parseEther("1000000")
    ],
  });
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

To Check price of pegged token:

npx hardhat run scripts/check-price.js --network commune

Output:

NVIDIA Token Price Info:
------------------------
Current Price: $148.38
Last Update: 11/12/2024, 9:07:04 PM

Debug Info:
Raw price value: 14838
Raw timestamp: 1731442024

To update price of pegged token:

npx hardhat run scripts/update-price.js --network commune
Current signer: 0x27fDBEd37eca90D10e9ce2210fafC87E3B9582EF
Contract owner: 0x27fDBEd37eca90D10e9ce2210fafC87E3B9582EF
Is signer owner? true

Current price: 15
Fetching current NVIDIA stock price...
Raw Pyth price: 14837500
Price in dollars: 148.375
Adjusted price for contract: 14838
Current NVIDIA stock price: $ 148.38
Attempting to set new price to: 14838
Transaction sent: 0xdc730b884c3ec44eb976735d6a9601c4f69e0e8be9a6d215e675656d4dc3d8ae
Waiting for confirmation...

To peg any STOCK

  1. Change the contract name in deploynvidia.js and update-price-v2.js to the stock you want to peg and run the deployment script.

  2. Update the price id from pyth.network in update-price-v2.js to the price id of the stock you want to peg. The feed id for tesla for example is that erc-20 address 0x16dad506d7db8da01c87581c87ca897a012a153557d4d578c3b9c9e1bc0632f1.

  3. Run the update-price-v2.js script to update the price of the stock.

Interacting with Deployed Contracts

Create scripts/interact.js:

const hre = require("hardhat");

async function main() {
  const contractAddress = "YOUR_DEPLOYED_CONTRACT_ADDRESS";
  const MyToken = await ethers.getContractFactory("MyToken");
  const myToken = MyToken.attach(contractAddress);

  // Get total supply
  const totalSupply = await myToken.totalSupply();
  console.log("Total Supply:", ethers.formatEther(totalSupply));

  // Get balance
  const [signer] = await ethers.getSigners();
  const balance = await myToken.balanceOf(signer.address);
  console.log("Balance:", ethers.formatEther(balance));

  // Transfer tokens
  const transferAmount = ethers.parseEther("100");
  const tx = await myToken.transfer("RECIPIENT_ADDRESS", transferAmount);
  await tx.wait();
  console.log("Transfer successful!");
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

Additional Resources

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 82.8%
  • Python 10.9%
  • Solidity 6.3%