scaffold-eth 挑战:实现质押 dApp(Part1)

scaffold-eth 挑战1:实现质押 dApp

接下来,我将介绍第一个 scaffold-eth 学习项目:创建一个质押 dApp

质押dApp是干什么的

这个项目的最终目标是模仿以太坊2.0的质押合约,需求非常简单:

  • 允许任何人质押 ETH 并跟踪余额
  • 如果时间到了 deadline 或者质押金额达到阀值,用户就不能提款了(这些资金会被用于未来的项目,如以太坊 POS )

可以学到什么?

  • 设置 scaffold-eth 项目
  • 编写一个质押合约
  • 调用一个外部合约
  • 为你的 Solidity 合约创建单元测试
  • 在你的本地机器上用 React 测试合约
  • 在以太坊测试网上部署质押合约!

你可以把这看作是我们开发旅程的第一步。

一些你时常会用到的链接

设置 scaffold-eth 项目

首先,我们需要设置克隆 scaffold-eth 库,切换到 challenge 1 分支,并安装所有需要的依赖:

git clone https://github.com/austintgriffith/scaffold-eth.git challenge-1-decentralized-staking
cd challenge-1-decentralized-staking
git checkout challenge-1-decentralized-staking
yarn install

可用的 CLI 命令概述

这些命令并不是只适用于本次挑战,而是适用于每个 scaffold-eth 项目:

yarn chain

这个命令会启动本地 Hardhat 网络并配置好地址http://localhost:8545

yarn start

这个命令会启动你的本地 react 网站,地址为http://localhost:3000/

yarn deploy

这个命令会部署所有合约并刷新 react 程序。准确地说,这个命令会运行两个 javascript 脚本(部署和发布)。

打开三个不同的终端,执行这些命令。每次修改合约,你只需要重新执行deploy命令。

练习part1:实现stake()方法

在这部分练习中,我们想做到用户可以在合约中质押 ETH,并可以随时查看余额变动。

重要概念

  • Payable 方法 - 当一个函数被声明为payable时,意味着允许用户向其发送 ETH(见文档)。
  • 映射 - 这是 Solidity 支持的变量类型 之一。它可以将一个key与一个value映射起来(见文档)。
  • 事件 - 事件可以让合约通知其他实体(如:web3 应用程序等等)发生了什么。当你声明一个事件时,你最多可以指定3个索引的参数,并且可以用第三方程序为这种特殊的参数过滤事件(见文档)。

尝试实现

  • 声明一个保存余额的映射
  • 声明一个 1 ETH 的常量的阀值
  • 声明一个 Stake 事件,用来记录质押者地址和质押金额
  • 实现一个 payable 函数stake(),用来更新质押者的余额。

更新合约代码

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

import "hardhat/console.sol";
import "./ExampleExternalContract.sol";

/**
* @title Stacker Contract
* @author scaffold-eth
* @notice A contract that allow users to stack ETH
*/
contract Staker {

  // External contract that will old stacked funds
  ExampleExternalContract public exampleExternalContract;

  // Balances of the user's stacked funds
  mapping(address => uint256) public balances;

  // Staking threshold
  uint256 public constant threshold = 1 ether;

  // 合约事件
  event Stake(address indexed sender, uint256 amount);

  /**
  * @notice Contract Constructor
  * @param exampleExternalContractAddress Address of the external contract that will hold stacked funds
  */
  constructor(address exampleExternalContractAddress) public {
    exampleExternalContract = ExampleExternalContract(exampleExternalContractAddress);
  }

  /**
  * @notice Stake method that update the user's balance
  */
  function stake() public payable {
    // update the user's balance
    balances[msg.sender] += msg.value;

    // emit the event to notify the blockchain that we have correctly Staked some fund for the user
    emit Stake(msg.sender, msg.value);
  }

}

一些注意事项:

  • uintuint256是一样的(它只是别名)
  • 当声明一个 public 变量,Solidity 即自动创建一个 getter 方法。这意味着有一个yourVariableName()方法可调用
  • 如果声明的变量没有初始化,那么它会自动被初始化为变量类型的默认值
  • Solidity 还有一些实用单位,如wei, ethers, 或者 时间单位

回顾一下:

  • 我们声明了balances,可以保存每个用户的地址和其质押金额
  • 我们声明了一个阈值
  • 我们声明了一个Stake事件,当某用户质押了一定数量 ETH ,它会向区块链发出通知
  • 我们实现了一个public payable类型的 Stake函数,它会更新用户的余额,并发出 Stake 事件。

你也许会有点奇怪,我们只是简单地更新质押金额,而没有初始化balances[msg.sender]的值。这是可行的,因为当声明变量时没有初始化,Solidity 会自动初始化为其类型的默认值,这里类型是uint256,所以默认值是 0。

现在部署合约,从水龙头(Faucet)获取 ETH ,并尝试质押一些给合约。

检查下你是否完成下面所有项目,以便继续进行第二部分的练习:

  • 你能从水龙头(Faucet)获得 ETH 吗?
  • 你可以点击 Stake 按钮给合约转 0.5ETH 吗?
  • 这个事件是否通过用户界面(UI)触发的?
  • 你质押金额是否成功更新?
  • 合约余额是否更新?

以下是本次视频的演示:

https://www.youtube.com/watch?v=KfoNrlYxBKY


本翻译由 CellETF 赞助支持。


点赞 2
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
翻译小组
翻译小组
0x9e64...7c84
大家看到好的文章可以在 GitHub 提 Issue: https://github.com/lbc-team/Pioneer/issues 欢迎关注我的 Twitter: https://twitter.com/UpchainDAO