抱歉,您的瀏覽器無法訪問本站
本頁面需要瀏覽器支持(啟用)JavaScript
了解詳情 >

前言

前面对Solidity的语法都进行了一次了解,现在来系统学习一下合约开发最佳实践,先学习下什么是ERC20,经常听到这个协议

ChatGPT Image 2026年4月27日 00_02_23

首先写个最简单合约demo熟悉Solidity语法先

“Hello World”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// SPDX-License-Identifier: GPL-3.0 # 默认写上即可,这是开源声明

pragma solidity ^0.8.24; # 当前合约solidity的版本

error OnlyOwner(address caller); # 错误事件定义,更够节省Gas

error ZeroValue(); # 错误事件

contract SyntaxPrimer {
address public owner; # 地址类型
string public appName;
uint256 public counter;
bool public paused;

mapping(address=>uint256) private scores; # 映射 就是map

event ScoreUpdated(address indexed user,uint256 score); # 事件定义,记录每个人score更改记录


modifier onlyOwner(){ # 权限修饰函数
if (msg.sender!=owner) {
revert OnlyOwner(msg.sender);
}
_;
}

constructor(string memory initName){ # 构造
owner = msg.sender;
appName = initName;
}

function setScore(address user,uint256 score) external onlyOwner{ # 设置分数
scores[user] = score;
emit ScoreUpdated(user, score);
}

function getScore(address user) external view returns (uint256){ # 查看分数
return scores[user];
}


}

上面是一个demo合约,写完之后可以直接丢到Redmix里面编译执行,可以看到有个Compliy的按钮,点击后,即可在左边表单里进行Deploy,然后就可以通过Deployed Contracts里调用函数了,这就是一个合约的学习过程。

image-20260426162415387

ERC20

简介

ERC20可以理解为:”以太坊上同质化代币的通用接口标准“,就好像我们平常开发约定的共识,只要实现了ERC20标准指定的函数和事件,很多钱包、交易所、DEX、DeFi协议就能直接进行交互了。

一句话来说就是:统一交互接口

同质化:fungible token,每一单位的token都完全等价

比如你手里的1USDT == 我手里的1USDT

所以ERC20协议适合:

  • 稳定币
  • 治理代币
  • 平台币
  • 游戏金币
  • 质押凭证
  • LP token

数据模型

ERC20最核心是两张表,余额表和授权表

1
2
3
4
5
6
7
8
9
10
11
mapping(address => uint256) private _balances; 余额表,记录了每个地址有多少代币

address A -> 1000
address B -> 500
address C -> 0


mapping(address => mapping(address => uint256)) private _allowances; # 授权表,owner 允许 spender 使用多少 token

Alice 授权 Bob 最多花 300 个 token
allowances[Alice][Bob] = 300

标准核心函数有6个

1
2
3
4
5
6
function totalSupply() external view returns (uint256); # 总供应量
function balanceOf(address account) external view returns (uint256); # 查询某个地址有多少token
function transfer(address to, uint256 value) external returns (bool); # 转账函数,调用方转出
function allowance(address owner, address spender) external view returns (uint256); # 查询owner授权spender可以花多少额度
function approve(address spender, uint256 value) external returns (bool); # 批准spender地址可以代表你使用多少token
function transferFrom(address from, address to, uint256 value) external returns (bool); # 授权的转账,如果 Alice 已经授权 Bob 300 个 token,那么 Bob 可以调用:transferFrom(Alice, Carol, 100)

这里第一眼比较奇怪就是:为什么需要 approve + transferFrom,主要是因为在DeFi场景经常是需要某个合约帮你操作,例如当我们要在Uniswap里换币时,通常会弹出一个Approve,然后在弹一次Swap

1
2
3
4
5
6
7
8
我有 USDT
我想换成 ETH
Uniswap Router 需要从我的账户里拿走 USDT


1. 我调用 USDT.approve(UniswapRouter, 1000)
2. UniswapRouter 调用 USDT.transferFrom(我, 池子, 1000)
3. Uniswap 再把 ETH 给我

mint 和 burn

在ERC20标准里没有规定一定要有 mint 和 burn,但真实项目通常都会有

mint: 增发,总供应增加,通常就是owner才会操作

burn:销毁,总供应减少

metadata扩展

ERC20里最核心的就是转账和授权,不过实际上还会引入一个扩展协议 meta

1
2
3
function name() external view returns (string memory); # token是什么
function symbol() external view returns (string memory); # 符号是什么
function decimals() external view returns (uint8); # 显示小数点应该怎么算

decimals比较重要点,首先链上 ERC20 不存小数,只存整数,decimals函数负责告诉钱包和前端怎么把整数显示成人类可读数量。

在Solidity/EVM里没有真正的小数类型,因此就好像我们做支付系统时,有时候在数据里是直接存分单位的

1
2
价值:12.34 元
实际存储:1234分

因此在ERC20合约里,当decimals返回18,代表

1
2
3
4
1 个完整 token = 10^18 个最小单位
1 token = 1000000000000000000
2.5token = 2500000000000000000
10000000000000000 = 0.01 token