智能合约简单教程
简介
本文主要介绍使用文昌链 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. 操作合约
- 操作方法牵扯到链上状态更改需要和部署合约时一样,进行签名
- 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 删除不必要的文件
- 删除
scripts
文件夹中的ts 文件 - 删除
contracts
中的Getter
合约 - 删除
test
的关于Getter
合约的测试 - 修改
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 文件夹,并创建 :
-
config.ts
: 用来读取配置, -
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