发布代币到ropsten网络

262 阅读3分钟

环境:

  1. Node.js v16.14.2

  2. 创建hardhat 项目

mkdir hardhat-tutorial 
cd hardhat-tutorial 
npm init --yes 
npm install --save-dev hardhat 

运行

npx hardhat

使用键盘选择"创建一个新的hardhat.config.js

安装 Ethers.js和Waffle插件

npm install --save-dev @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai

将高亮行require("@nomiclabs/hardhat-waffle"); 添加到你的hardhat.config.js中,

require("@nomiclabs/hardhat-waffle");

/**
 * @type import('hardhat/config').HardhatUserConfig
 */
module.exports = {
  solidity: "0.7.3",
};

这里引入hardhat-waffle,因为它依赖于hardhat-ethers,因此不需要同时添加两个。

编写合约

首先创建一个名为 contracts 的新目录,然后在目录内创建一个名为Token.sol的文件。

// Solidity files have to start with this pragma.
// It will be used by the Solidity compiler to validate its version.
pragma solidity ^0.7.0;


// This is the main building block for smart contracts.
contract Token {
    // Some string type variables to identify the token.
    // The `public` modifier makes a variable readable from outside the contract.
    string public name = "My Hardhat Token";
    string public symbol = "MBT";

    // 固定发行量,保存在一个无符号整型里
    uint256 public totalSupply = 1000000;

    // An address type variable is used to store ethereum accounts.
    address public owner;

    // A mapping is a key/value map. Here we store each account balance.
    mapping(address => uint256) balances;

    /**
     * 合约构造函数
     *
     * The `constructor` is executed only once when the contract is created.
     */
    constructor() {
        // The totalSupply is assigned to transaction sender, which is the account
        // that is deploying the contract.
        balances[msg.sender] = totalSupply;
        owner = msg.sender;
    }

    /**
     * 代币转账.
     *
     * The `external` modifier makes a function *only* callable from outside
     * the contract.
     */
    function transfer(address to, uint256 amount) external {
        // Check if the transaction sender has enough tokens.
        // If `require`'s first argument evaluates to `false` then the
        // transaction will revert.
        require(balances[msg.sender] >= amount, "Not enough tokens");

        // Transfer the amount.
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }

    /**
     * 返回账号的代币余额,只读函数。
     *
     * The `view` modifier indicates that it doesn't modify the contract's
     * state, which allows us to call it without executing a transaction.
     */
    function balanceOf(address account) external view returns (uint256) {
        return balances[account];
    }
}

编译合约

要编译合约,请在终端中运行 npx hardhat compile 。 compile任务是内置任务之一

$ npx hardhat compile
Compiling 1 file with 0.7.3
Compilation finished successfully

合约已成功编译了。

5. 测试合约

为智能合约编写自动化测试至关重要,因为事关用户资金。 为此,我们将使用Hardhat Network,这是一个内置的以太坊网络,专门为开发设计,并且是Hardhat中的默认网络。 无需进行任何设置即可使用它。 在我们的测试中,我们将使用ethers.js与前面构建的合约进行交互,并使用 Mocha 作为测试运行器。

编写测试用例

在项目根目录中创建一个名为test的新目录,并创建一个名为Token.js的新文件。

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

describe("Token contract", function() {
    let Token ;
    let hardhatToken ; 
    let owner;
    let add1 ;
    let add2 ;
    let addrs;

    beforeEach(async function(){
        Token = await ethers.getContractFactory("Token");
        [owner ,add1 ,add2 , ...addrs] = await ethers.getSigners();
        hardhatToken = await Token.deploy();
    });

    describe("部署", function(){
        it("检查owner是否正确", async function(){
            expect(await hardhatToken.owner()).to.equal(owner.address);
        });
        it("检查总量是否正确", async function(){
            const blanceCount = await hardhatToken.balanceOf(owner.address);
            expect(await hardhatToken.totalSupply()).to.equal(blanceCount);
        });
    });

    describe("交易",function(){
        it("转账账户",async function(){
            hardhatToken.transfer(add1.address,50);
            expect(await hardhatToken.balanceOf(add1.address)).to.equal(50)

            await hardhatToken.connect(add1).transfer(add2.address,50);
            expect(await hardhatToken.balanceOf(add2.address)).to.equal(50)
        })

        // it("转账余额不足",async function(){
        //     const initAmount = await hardhatToken.balanceOf(owner.address);
        //     await expect( hardhatToken.connect(add1).transfer(owner.address , 100)).to.be.revertedWith("not engouth");
        //     expect(hardhatToken.balanceOf(owner.address)).to.equal(initAmount);
        // })
    });

    describe("转账更新交易金额",function(){
        it("交易逻辑测试",async function(){
            const initAmount = await hardhatToken.balanceOf(owner.address);
            await hardhatToken.transfer(add1.address , 50);
            await hardhatToken.transfer(add2.address , 100);
            expect(await hardhatToken.balanceOf(add1.address)).to.equal(50);
            expect(await hardhatToken.balanceOf(add2.address)).to.equal(100);
            expect(await hardhatToken.balanceOf(owner.address)).to.equal(initAmount-150);

        });

    });

    it("Deployment should assign the total supply of tokens to the owner", async function() {
    const [owner] = await ethers.getSigners();

    const Token = await ethers.getContractFactory("Token");

    const hardhatToken = await Token.deploy();

    const ownerBalance = await hardhatToken.balanceOf(owner.address);
    expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
    });
});

测试成功

admin@XZA000428468 hardhat-tutorial % npx hardhat test


  Token contract
totalSupply is 1000000
totalSupply is 1000000
    ✔ Deployment should assign the total supply of tokens to the owner (129ms)
    部署
totalSupply is 1000000
      ✔ 检查owner是否正确
totalSupply is 1000000
      ✔ 检查总量是否正确
    交易
totalSupply is 1000000
sender balance is 1000000 token
try to send 50 token to 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 
sender balance is 50 token
try to send 50 token to 0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc 
      ✔ 转账账户 (55ms)
    转账更新交易金额
totalSupply is 1000000
sender balance is 1000000 token
try to send 50 token to 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 
sender balance is 999950 token
try to send 100 token to 0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc 
      ✔ 交易逻辑测试 (64ms)


  5 passing (1s)

6. 用 Hardhat Network 调试

Solidity console.log

Hardhat Network上运行合约和测试时,你可以在Solidity代码中调用console.log()打印日志信息和合约变量。 你必须先从合约代码中导入**Hardhat **的console.log再使用它。

pragma solidity ^0.6.0;

import "hardhat/console.sol";

contract Token {
  //...
}

7. 部署到真实网络

在项目根目录的目录下创建一个新的目录scripts,并将以下内容粘贴到 deploy.js文件中:

async function main() {

    const [deployer] = await ethers.getSigners();
  
    console.log(
      "Deploying contracts with the account:",
      deployer.address
    );
    
    console.log("Account balance:", (await deployer.getBalance()).toString());
  
    const Token = await ethers.getContractFactory("Token");
    const token = await Token.deploy();
  
    console.log("Token address:", token.address);
  }
  
  main()
    .then(() => process.exit(0))
    .catch(error => {
      console.error(error);
      process.exit(1);
    });

运行到hardhat 内置网络

$ npx hardhat run scripts/deploy.js
Deploying contracts with the account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Account balance: 10000000000000000000000
Token address: 0x5FbDB2315678afecb367f032d93F642f64180aa3

部署到远程网络

要部署到诸如主网或任何测试网之类的线上网络,你需要在hardhat.config.js 文件中添加一个network条目。 在此示例中,我们将使用Ropsten,但你可以类似地添加其他网络:

require("@nomiclabs/hardhat-waffle");

// Go to https://www.alchemyapi.io, sign up, create
// a new App in its dashboard, and replace "KEY" with its key
const ALCHEMY_API_KEY = "KEY";

// Replace this private key with your Ropsten account private key
// To export your private key from Metamask, open Metamask and
// go to Account Details > Export Private Key
// Be aware of NEVER putting real Ether into testing accounts
const ROPSTEN_PRIVATE_KEY = "YOUR ROPSTEN PRIVATE KEY";

module.exports = {
  solidity: "0.7.3",
  networks: {
    ropsten: {
      url: `https://eth-ropsten.alchemyapi.io/v2/${ALCHEMY_API_KEY}`,
      accounts: [`0x${ROPSTEN_PRIVATE_KEY}`]
    }
  }
};

ALCHEMY_API_KEY :在Alchemy网络上注册自己的api_key ROPSTEN_PRIVATE_KEY:你账号的私钥

最后运行:

npx hardhat run scripts/deploy.js --network ropsten

部署成功:

admin@XZA000428468 hardhat-tutorial % npx hardhat run scripts/deploy.js --network ropsten 
Deploying contracts with the account: 0xb2D709be86ADc8520192872197c36886A553cd30
Account balance: 1091208822845060326



Token address: 0xA94AE7e3b03Dd4d5F3a346DFFB3CFbACf847e877

去ether测试网络上查看部署的代币

ropsten.etherscan.io/tx/0x1bc1f9…