智能合约

上一篇讲了如何在本地搭建以太坊本地私链,这次就聊聊如何在自己搭建的私链上部署合约以及运行合约。本地搭建合约的好处在于,一方面可以自定义挖矿难度以及控制挖矿情况,另一方面实际上是可以对部署的合约进行断点调试,熟悉合约执行的每一步,观察存储的数据情况。

主流协议

由于有了openzeppelin的存在,写合约容易了很多,只需要选择好相应的协议,直接复用其实现就好,真可谓无脑发币和 NFT,难怪近期的 NFT 项目越来越多。

ERC20

最为使用最广泛的 token 合约,仅需几行代码就可以快速发币,以下就是最基础的发币代码。

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

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

contract MyToken is ERC20 {
    constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
      _mint(msg.sender, initialSupply);
    }
}

OpenZeppelin 的 ERC20 协议以包含了以下接口:

  • totalSupply:规定了代币的总量,外部可以通过调用这个函数来获得代币总量是多少
  • balanceOf:获取某地址的代币余额
  • transfer:调用 transfer 函数将自己的 token 转账给_to 地址,_value 为转账个数 *approve:批准_spender 账户从自己的账户转移_value 个 token。可以分多次转移
  • transferFrom:用于第三方(_spender)从被授权的账户转账到目标账户
  • allowance:返回_spender 还能提取 token 的个数

属实非常贴心,看上去只需要确定名字,就可以上手。而这里的 allowance 概念有点意思,他是允许第三方从账上划转 token,借这个功能就可以做一个 swap。另外要注意的一点是,不要直接往代币合约地址直接转账(transfer)。透过合约代码也可以发现,ERC20 在链上维护了一个 address<->Balance 的 Map 结构,记录了每个地址的余额情况。

ERC721

最近炒得很火的 NFT 基本上都是基于 ERC721 协议实现的,ERC721 和 ERC20 不同的点在于,每一个 token 都是非同质的,即独一无二的,因此在链上的储存信息是不同的,ERC721 记录的虽然也是维护了一个 Map 结构,但这里是维护 token<->address 的信息,记录每个 token 的 owner。

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

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

contract MyToken is ERC721, Ownable {
    constructor() ERC721("MyToken", "MTK") {}

    function safeMint(address to, uint256 tokenId) public onlyOwner {
        _safeMint(to, tokenId);
    }
}

最关键的部分即mint操作,mint完成了创建出一个 NFT 给对应的 address。上述只是一个简单的例子,ERC721 有很多扩展,常规的 NFT 都是使用ERC721URIStorage储存 NFT 的baseURI,在这里储存了每个 NFT 不同的 metadata。这一块可以后面细细讲解。

开发工具

在常规的开发中,remix 算是比较好用的 Web IDE,更适合部署合约并调试合约,之前也试用过Black-IDE,从编辑效果上还是 VS Code 会更加的好用。部署合约的工具可以选择使用 Truffle 或 HardHat。Truffle 里有 box 这种概念,能够提供一些常规的模板。VS Code 一定要装一下 Tabnine 和 Copilot,由于合约大部分代码都是相似的,利用自动补全,基本上可以无脑写出很多想要的代码= =。

Remix

remix 使用在线的更方便部署到 JVM 中进行模拟测试,另一方面,使用Inject Web3的方式直接吊起 Metamask 进行操作授权。

另一方面,可以在 VS Code 可以装ethereum-remix插件,也可以做到类似 Web IDE 的效果。

img

Truffle

Truffle 算是一个开发合约的脚手架,通过这个工具可以初始化一个合约项目,结合 VS Code 上的Truffle插件,可以快速的部署在本地私链或公链。

truffle 还有一个工具非常好用——truffle dashboard,通过这种方式可以在浏览器里吊起 Metamask 进行支付授权。可以参考以下的配置truffle-config.js,development 是本地私链的基本配置,需要使用下面的 dashboard 配置,从体验上可以认为是一个类似 Remix Inject Web3 的工具,通过这种方式,避免需要解锁钱包。

module.exports = {
  // Uncommenting the defaults below
  // provides for an easier quick-start with Ganache.
  // You can also follow this format for other networks.
  // See details at: https://trufflesuite.com/docs/truffle/reference/configuration
  // on how to specify configuration options!
  //
  networks: {
    development: {
      host: "127.0.0.1",
      port: 8545,
      network_id: "*",
    },
    "truffle-dashboard": {
      url: "http://localhost:24012/rpc", // where truffle dashboard run
      network_id: "77895176",
    },
  },
};

img

部署合约

刚才介绍了很多合约的背景知识和一些工具的使用,现在就可以尝试去部署一个 合约 (可以使用上述提到的 MyToken) 。部署合约的方式有多种,可以通过 remix 也可以通过 truffle 的方式,另外也可以通过truffle migration的方式,后者更像是多个合约的部署。

  • 通过 truffle for VS code 部署单个合约

img

  • 通过 remix for VS Code 部署单个合约

img

这里使用了 dashboard 而不是直接的 development 地址进行部署,在http://localhost:24012/就能看到 部署操作发起的请求。

合约交互

部署完合约就可以进行交互了,可以使用 VS Code 里的 remix 进行交互,也可以使用 Web IDE 进行交互, 还有一种方法是使用web3.pyweb3.js进行应用层的调用。这里就暂时先不展开了,之后会进行一些案例的分析。