智能合约简单教程

智能合约简单教程

简介

本文主要介绍使用文昌链 EVM 模块的基本流程。

文昌链 EVM 模块完全兼容以太坊(ERC20 的转账功能根据合规要求做了限制),可直接使用以太坊生态工具进行对接。

一、Remix 教程

配置 MetaMask 连接测试网


- RPC: https://evmrpc.testnet.bianjie.ai
- Chain ID: 12231
- Symbol: gas
- Explorer: https://explorer.testnet.bianjie.ai

填写完毕后点击保存。

账户充值

在 MetaMask 中复制测试用的链账户地址,发给文昌链技术支持获取测试能量值。

Remix 操作

1. 打开 Remix

访问地址是:https://remix.ethereum.org/

2. 创建工作空间

3. 清理空间,并编写合约

4. 编译合约

默认合约是自动编译的,如果合约没有问题,可以自动编译

5.连接钱包

6. 部署合约

7. 调整费用,执行部署(irita 的话建议调整一下,我们的 gasprice 很低)

执行合约,报后点击确认,得到如下信息:

8. 操作合约

  1. 操作方法牵扯到链上状态更改需要和部署合约时一样,进行签名
  2. get的方法不需要签名,直接可以访问

二、hardhat 教程

准备工作

# 创建文件夹
mkdir contract-demo-hardhat
# 进入文件夹
cd contract-demo-hardhat

流程

1. 初始化

yarn init -y

2. 安装hardhat

yarn install -D hardhat

3. 初始化项目

yarn hardhat

选择如下的选项

会出现一堆下载依赖的过程,可能会有网络问题,挂 outline

4. 安装一些常用的依赖(可以跳过)

yarn add -D @openzeppelin/hardhat-defender @nomiclabs/hardhat-web3 @openzeppelin/hardhat-upgrades @openzeppelin/contracts-upgradeable hardhat-abi-exporter hardhat-contract-sizer

# @openzeppelin/contracts
# @openzeppelin/contracts-upgradeable

5. 整理项目

5.1 删除不必要的文件
  1. 删除 scripts文件夹中的ts 文件
  2. 删除 contracts 中的 Getter合约
  3. 删除 test 的关于 Getter 合约的测试
  4. 修改package.json脚本:
 "scripts": {
    "compile": "yarn hardhat compile",
    "clean": "yarn hardhat clean",
    "test": "hardhat test",
    "typecheck": "yarn compile && yarn test && yarn tsc --noEmit"
  },
5.2 修改 hardhat.config.ts

删除不必要的引用,改为类似的结构:

import { HardhatUserConfig, task } from "hardhat/config";
import "@nomiclabs/hardhat-etherscan";
import "@nomiclabs/hardhat-waffle";
import "@typechain/hardhat";
import "@openzeppelin/hardhat-upgrades";
import "@openzeppelin/hardhat-defender";
import "@nomiclabs/hardhat-ethers";
import "hardhat-gas-reporter";
import "hardhat-contract-sizer";
import "hardhat-abi-exporter";
import "solidity-coverage";


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

const config: HardhatUserConfig = {
  solidity: "0.8.4",
  networks: {
    testnet: {
      url: 'http://127.0.0.1:8545',
      gasPrice: 1,
      chainId: 1223,
      gas: 25000000,
      accounts: [''],
    },
  },
  gasReporter: {
    enabled: true,
    showMethodSig: true,
    maxMethodDiff: 10,
    currency: 'USD',
    gasPrice: 127,
  },
  contractSizer: {
    alphaSort: true,
    runOnCompile: true,
    disambiguatePaths: false,
  },
  paths: {
    sources: "./contracts",
    tests: "./test",
    cache: "./cache",
    artifacts: "./artifacts"
  },
  abiExporter: {
    path: './abi',
    runOnCompile: true,
    clear: true,
    spacing: 2
  }
};

export default config;

6. 创建合约

contracts 目录创建 Counter.sol文件,内容如下:

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

contract Counter {
    uint256 counter = 0;

    function add() public {
        counter++;
    }

    function subtract() public {
        counter--;
    }

    function getCounter() public view returns (uint256) {
        return counter;
    }
}

7. 编译合约
yarn compile

8. 编写测试

test 目录下新建 couter.ts 的文件,内容如下:

import { ethers } from "hardhat";
import { Signer } from "ethers";
import chai, { expect } from "chai";

import { Counter } from '../typechain';


describe("Counters", () => {
    let counterManger: Counter;

    before("Deploy Counter", async () => {
        const counterFactory = await ethers.getContractFactory("Counter");
        counterManger = await counterFactory.deploy();
        await counterManger.deployed();

    });

    it("counter should be incremented by 1 after calling add", async () => {
        const counterBefore = await counterManger.getCounter();
        await counterManger.add();
        const counterAfter = await counterManger.getCounter();
        expect(counterBefore.add(1)).to.equal(counterAfter);
    })

    it("counter should be subtracted by 1 after calling subtract", async () => {
        const counterBefore = await counterManger.getCounter();
        await counterManger.subtract();
        const counterAfter = await counterManger.getCounter();
        expect(counterBefore.sub(1)).to.equal(counterAfter);
    })

})

运行 yarn test

9. 编写部署脚本

当脚本完成后,我们就可以部署了,

创建 tasks 文件夹,并创建 :

  1. config.ts : 用来读取配置,
  2. counter.ts:部署脚本

hardhat.config.ts 中增加一行:import "./tasks/counter";

counter.ts 内容如下:

import "@nomiclabs/hardhat-web3";
import { error } from "console";
import { task, types } from "hardhat/config"
const config = require('./config')

task("deployCounter", "Deploy Counter")
    .setAction(async (taskArgs, hre) => {
        await config.load(async function (env: any) {
            const counterFactory = await hre.ethers.getContractFactory('Counter');
            const counterManager = await counterFactory.deploy();
            await counterManager.deployed();
            console.log("Counter deployed to:", counterManager.address);
            env.contract.counterAddress = counterManager.address
        }, true)
    });

task("addCounter", "Add Counter")
    .setAction(async (taskArgs, hre) => {
        await config.load(async function (env: any) {
            const counterFactory = await hre.ethers.getContractFactory('Counter');
            const counterManager = await counterFactory.attach(env.contract.counterAddress);
            for (let i = 0; i < env.params.times; i++) {
                const result = await counterManager.add();
                console.log(result);
            }

        }, true)
    });

task("subtractCounter", "Add Counter")
    .setAction(async (taskArgs, hre) => {
        await config.load(async function (env: any) {
            const counterFactory = await hre.ethers.getContractFactory('Counter');
            const counterManager = await counterFactory.attach(env.contract.counterAddress);
            for (let i = 0; i < env.params.times; i++) {
                const result = await counterManager.subtract();
                console.log(result);
            }

        }, true)
    });

task("getCount", "Get Counter")
    .setAction(async (taskArgs, hre) => {
        await config.load(async function (env: any) {
            const counterFactory = await hre.ethers.getContractFactory('Counter');
            const counterManager = await counterFactory.attach(env.contract.counterAddress);
            const result = await counterManager.getCounter();
            console.log(result);
        }, true)
    });

执行 yarn hardhat deployCounter --network testnet 完成部署

ABI 生成 Go 的文件

前置条件

安装 abigen: Downloads | go-ethereum 下载对应版本

生成 go 文件: 在 hardhat 工程文件中执行: abigen --abi abi/contracts/Counter.sol/Counter.json --pkg counter --out counter.go

把文件引入到你的项目即可

测试程序初始化

# 安装依赖
yarn install

# 编译
yarn compile

# 测试
yarn test


count add

yarn hardhat addCounter --network testnet

counter get

yarn hardhat getCount  --network testnet