智能合约 Hello World

以太坊发展到现在也有很多年了,17 年作为韭菜的我其实买入了不少种类的以太坊上的加密货币(包括一位创业做交易所的学长自己发的空气币🤣),当时对其原理并不了解。最近机缘巧合有机会了解了一下以太坊 (Ethereum) 的智能合约 (Smart Contracts),这里简单记录一下 实现一个智能合约 Hello World 的过程。

以太坊Vitalik 受到比特币的启发后在 2013-2014 年开发出来的一种分布式的区块链应用框架,其官方网站中文自我介绍如下:“以太坊是一种通过支付小额费用向任何人发送加密货币的技术。基于它还能创建永不停机、人人可用的各种应用。它是属于全世界的可编程区块链。

工具链介绍

类似很多编程语言 (Java, C#, etc.) 和很多编程框架 (Spring, ASP.NET, Android, iOS) 一样,以太坊发展到现在有了很多工具链如编程语言 (Solidity),IDE (Remix),本地环境搭建 (HardHat) 等,任何一个工程师都可以很容易的利用这些工具链很方便的上手以太坊智能合约的开发。我这里使用的比较简单,只用到了 VS Code (+Solidity 插件,主要用作语法高亮和格式化代码), npm (本文省略了 npm 的安装过程) 以及 HardHat (稍后解释其作用)。

详细流程

  1. [初始化项目文件夹] 新建一个文件夹命名为你的项目名,然后用 VS Code 打开此文件夹。
  2. [安装 HardHat] 在 VS Code 中打开命令行,运行如下命令来安装 HardHat。
npm install --save-dev hardhat
  1. [初始化 HardHat 本地编程环境] 继续执行如下命令并选择 “Create an empty hardhat.config.js”,到此,我们就有了最基本的本地编程环境。
npx hardhat
  1. [开始编程] 在 ./contracts/ 目录下创建你的第一个智能合约源码文件 Greeter.sol 如下:
pragma solidity ^0.8.0;

contract Greeter {
    string private greeting;

    constructor(string memory _greeting) {
        greeting = _greeting;
    }

    function greet() public view returns (string memory) {
        return greeting;
    }

    function setGreeting(string memory _greeting) public {
        greeting = _greeting;
    }
}
  1. [编译] 使用 HardHat 编译十分简单,在命令行执行如下命令:
npx hardhat compile
  1. [部署] 这里演示如何部署到测试网 (BSC testnet), 参考币安官方文档,配置 hardhat.config.js 如下:
require('@nomiclabs/hardhat-ethers');
require("@nomiclabs/hardhat-etherscan");
require("@nomiclabs/hardhat-waffle");

// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
  const accounts = await hre.ethers.getSigners();

  for (const account of accounts) {
    console.log(account.address);
  }
});

module.exports = {
  solidity: {
    version: "0.8.10",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200
      }
    }
  },

  networks: {
    hardhat: {
    },
    bsctest: {
      url: "https://data-seed-prebsc-1-s1.binance.org:8545",
      chainId: 97,
      accounts: ["0x1111111111111111111111111111111111111111111111111111111111111111"]
    },
    bscmain: {
      url: "https://bsc-dataseed.binance.org/",
      chainId: 56,
      accounts: ["0x1111111111111111111111111111111111111111111111111111111111111111"]
    }
  },

  // Config for Etherscan contract verification service.
  // https://hardhat.org/plugins/nomiclabs-hardhat-etherscan.html#usage
  // https://docs.binance.org/smart-chain/developer/deploy/hardhat-verify.html
  etherscan: {
    apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
  },

};

之后需要准备部署脚本 scripts/deploy.js

// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// When running the script with `npx hardhat run <script>` you'll find the Hardhat
// Runtime Environment's members available in the global scope.
const hre = require("hardhat");

// This is a script for deploying your contracts. You can adapt it to deploy
// yours, or create new ones.
async function main() {
  // This is just a convenience check
  if (network.name === "hardhat") {
    console.warn(
      "You are trying to deploy a contract to the Hardhat Network, which" +
      "gets automatically created and destroyed every time. Use the Hardhat" +
      " option '--network localhost'"
    );
  }

  const [deployer] = await hre.ethers.getSigners();
  console.log(
    "Deploying the contracts with the account:",
    await deployer.getAddress()
  );

  console.log("Account balance: ", (await deployer.getBalance()).toString());

  const greeterContractFactory = await hre.ethers.getContractFactory("Greeter");
  const greeterContract = await greeterContractFactory.deploy("Hello world!");
  await greeterContract.deployed();

  console.log("Greeter contract address: ", greeterContract.address);
}

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

最后执行如下命令即可:

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

可以观察到结果

Deploying the contracts with the account: 0x19E7E376E7C213B7E7e7e46cc70A5dD086DAff2A
Account balance:  3440891252400000000
Greeter contract address:  0xf2bf1f1E7B3f8d1554fEeb88B11B69830eDAc7fa
  1. [验证合约] 经过上一步我们已经可以在 Explorer (BSC Testnet Explorer) 里面查看自己刚刚部署好的合约了,但是由于合约是加密的,并没有暴露 ABI 出来所以无法使用 Explorer 直接交互,为方便测试我们可以验证合约,之后所有人都可以直接使用 Explorer 来进行合约交互。为验证合约,我们需要注册 BSC 账户并获取 API Key (链接),之后还是填在 hardhat.config.js 里面,最后执行如下命令完成验证:
npx hardhat verify --network bsctest --contract contracts/Greeter.sol:Greeter 0xf2bf1f1E7B3f8d1554fEeb88B11B69830eDAc7fa "Hello world!"

结果如下,点击最后一个链接便可直接打开 Explorer 连接 MetaMask 进行合约交互了!

Nothing to compile
Compiling 1 file with 0.8.10

Successfully submitted source code for contract
contracts/Greeter.sol:Greeter at 0xf2bf1f1E7B3f8d1554fEeb88B11B69830eDAc7fa
for verification on the block explorer. Waiting for verification result...

Successfully verified contract Greeter on Etherscan.
https://testnet.bscscan.com/address/0xf2bf1f1E7B3f8d1554fEeb88B11B69830eDAc7fa#code

总结

接触智能合约已半年有余,尝试了三四个项目之后每次还是需要重走一遍 hello world 的流程,借此机会总结在这里以便后续翻阅。

其实以太坊智能合约和使用 Spring MVC 或者 ASP.NET 写接口十分相似,以太坊内置了 User Identity / Principal 也就是区块链上的地址,任何智能合约的调用都来源于一个 signer,这个 signer 可以是用户钱包的地址也可以是一个合约地址。智能合约没有数据库,所以简单点可以理解成就是个内存程序,且内存永不销毁,上手起来可比写后端程序简单多了。

后续如果还有时间和精力可以写一些合约的高级开发技巧(比如可升级的合约,微服务合约等)并用与其相对应的后端应用的概念来解读。除了技术方面以外,目前大火的 DeFi(其实已经出现好几年了)也可以用传统金融领域的概念来类比和解读,如做市商,杠杆挖矿等等,十分有趣。

在我看来,区块链这个圈子内的创业者们目前是想要在链上重新构建一个去中心化的金融世界,这对传统中心化的金融世界是一个挑战,在效率上由于去中心化的金融绕过了中心化的金融机构大大降低了交易成本,毕竟这些金融机构左手交右手赚取了大量的利差。若是真的可以再造一个金融世界,这前景不可谓不诱人。而我,只希望作为韭菜不要被两个金融世界来回收割,若能分一杯羹就再好不过了…🤣🤣🤣

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注