【Solidity】代币
ERC20
ERC-20 全称 “Ethereum Request for Comment 20”,是一种标准接口,用于实现代币合约。ERC20 标准定义了一组函数和事件,使得代币可以在不同的应用和平台之间互操作。
ERC20 标准接口定义了一组必须实现的函数和事件:
interface IERC20 {// 返回代币的总供应量function totalSupply() external view returns (uint);// 返回指定地址的代币余额function balanceOf(address account) external view returns (uint);// 返回授权给 spender 的代币数量function allowance(address owner, address spender) external view returns (uint);// 将指定数量 amount 的代币从调用者的账户转移到另一个地址 recipientfunction transfer(address recipient, uint amount) external returns (bool);// 授权 spender 可以从调用者账户转移的代币数量 amountfunction approve(address spender, uint amount) external returns (bool);// 从 sender 账户转移指定数量的代币到 recipient, 需要预先通过 approve 授权function transferFrom(address sender,address recipient,uint amount) external returns (bool);
}
interface IERC20 {// 在代币转移时触发, 包括零值转移event Transfer(address indexed from, address indexed to, uint value);// 在调用 approve 时触发event Approval(address indexed owner, address indexed spender, uint value);
}
以下是一个简单的 ERC20 代币合约示例:
contract ERC20 is IERC20 {// 存储代币的名称、符号和小数位数string public name = "TestToken";string public symbol = "TTK";uint8 public decimals = 18;// 存储代币的总供应量uint public totalSupply;// 存储每个地址的代币余额; owner => balancemapping(address => uint) public balanceOf;// 存储每个地址对其他地址的授权额度; owner => spender => amountmapping(address => mapping(address => uint)) public allowance;// 定义两个事件, 用于记录代币转移和授权操作event Transfer(address indexed from, address indexed to, uint value);event Approval(address indexed owner,address indexed spender,uint value);// 将指定数量 amount 的代币从调用者的账户转移到另一个地址 recipientfunction transfer(address recipient,uint amount) external override returns (bool) {require(balanceOf[msg.sender] >= amount,"ERC20: transfer amount exceeds balance");balanceOf[msg.sender] -= amount;balanceOf[recipient] += amount;emit Transfer(msg.sender, recipient, amount);return true;}// 授权 spender 可以从调用者账户转移的代币数量 amountfunction approve(address spender,uint amount) external override returns (bool) {allowance[msg.sender][spender] = amount;emit Approval(msg.sender, spender, amount);return true;}// 从 sender 账户转移指定数量的代币到 recipient, 需要预先通过 approve 授权function transferFrom(address sender,address recipient,uint amount) external override returns (bool) {require(balanceOf[sender] >= amount,"ERC20: transfer amount exceeds balance");require(allowance[sender][msg.sender] >= amount,"ERC20: transfer amount exceeds allowance");balanceOf[sender] -= amount;balanceOf[recipient] += amount;allowance[sender][msg.sender] -= amount;emit Transfer(sender, recipient, amount);return true;}
}
使用 OpenZeppelin 库可以简化 ERC20 代币的实现。OpenZeppelin 提供了安全且经过审计的 ERC20 实现。
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";contract MyToken is ERC20 {constructor(string memory name,string memory symbol,uint256 initialSupply) ERC20(name, symbol) {_mint(msg.sender, initialSupply * 10 ** uint256(decimals()));}
}
除了上述核心方法,你可能还听过 mint & burn。它们通常用于 ERC20 代币合约中,以增加或减少代币的总供应量。
contract ERC20 is IERC20 {// ...// 创建 amount 数量的代币, 并将其分配给指定的地址function mint(uint amount) external {totalSupply += amount;balanceOf[msg.sender] += amount;emit Transfer(address(0), msg.sender, amount);}// 销毁 amount 数量的代币function burn(uint amount) external {require(balanceOf[msg.sender] >= amount,"ERC20: burn amount exceeds balance");totalSupply -= amount;balanceOf[msg.sender] -= amount;emit Transfer(msg.sender, address(0), amount);}
}
ERC721
ERC721 是以太坊上用于创建不可替代代币(NFT)的标准。与 ERC20 不同,ERC721 代币是独一无二的,每个代币都有自己的唯一标识符。
ERC721 标准定义了一组必须实现的函数和事件,使得代币可以在不同的应用和平台之间互操作。
interface IERC721 {// 返回某个地址拥有的代币数量function balanceOf(address owner) external view returns (uint256 balance);// 返回某个代币的所有者地址function ownerOf(uint256 tokenId) external view returns (address owner);// 安全地将代币从一个地址转移到另一个地址function safeTransferFrom(address from,address to,uint256 tokenId) external;// 将代币从一个地址转移到另一个地址function transferFrom(address from, address to, uint256 tokenId) external;// 批准某个地址可以转移指定的代币function approve(address to, uint256 tokenId) external;// 返回被批准可以转移指定代币的地址function getApproved(uint256 tokenId) external view returns (address operator);// 批准或撤销某个地址可以管理调用者所有的代币function setApprovalForAll(address operator, bool _approved) external;// 查询某个地址是否被批准可以管理另一个地址的所有代币function isApprovedForAll(address owner,address operator) external view returns (bool);
}
interface IERC721 {// 在代币转移时触发event Transfer(address indexed from,address indexed to,uint256 indexed tokenId);// 在调用 approve 时触发event Approval(address indexed owner,address indexed approved,uint256 indexed tokenId);// 在调用 setApprovalForAll 时触发event ApprovalForAll(address indexed owner,address indexed operator,bool approved);
}
WETH
WETH(Wrapped Ether)是以太坊(ETH)的包装版本,它遵循 ERC-20 代币标准。由于 ETH 本身并不符合 ERC-20 标准,因此在某些去中心化应用(DApp)和去中心化金融(DeFi)平台上使用时会有一些限制。WETH 的出现解决了这个问题,使 ETH 可以在这些平台上无缝使用。
contract WETH {// 代币名称、符号、小数位数string public name = "Wrapped Ether";string public symbol = "WETH";uint8 public decimals = 18;// 记录每个地址的 WETH 余额mapping(address => uint) public balanceOf;// 记录存入 ETH 的事件event Deposit(address indexed account, uint amount);// 记录提取 ETH 的事件event Withdrawal(address indexed account, uint amount);// 使合约可以接受 ETHreceive() external payable {deposit();}// 接受 ETH 并将其转换为 WETHfunction deposit() public payable {balanceOf[msg.sender] += msg.value;emit Deposit(msg.sender, msg.value);}// 将 WETH 转换回 ETH 并提取到调用者的地址function withdraw(uint amount) public {require(balanceOf[msg.sender] >= amount, "Insufficient balance");balanceOf[msg.sender] -= amount;payable(msg.sender).transfer(amount);emit Withdrawal(msg.sender, amount);}// 返回合约中存储的 ETH 总量function totalSupply() public view returns (uint) {return address(this).balance;}
}
我们可以直接使用 OpenZeppelin 的 ERC20 合约库来实现 WETH 合约:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;import "@openzeppelin/contracts/token/ERC20/ERC20.sol";contract WETH is ERC20 {// 记录存入 ETH 的事件event Deposit(address indexed account, uint amount);// 记录提取 ETH 的事件event Withdrawal(address indexed account, uint amount);// 初始化 WETH 合约constructor() ERC20("Wrapped Ether", "WETH") {}// 使合约可以接受 ETHreceive() external payable {deposit();}// 接受 ETH 并将其转换为 WETHfunction deposit() public payable {_mint(msg.sender, msg.value);emit Deposit(msg.sender, msg.value);}// 将 WETH 转换回 ETH 并提取到调用者的地址function withdraw(uint amount) public {_burn(msg.sender, amount);payable(msg.sender).transfer(amount);emit Withdrawal(msg.sender, amount);}
}
-
部署 WETH 合约
-
调用 WETH 合约的 deposit 函数,设置传入的 ETH 数量,这里以 1 ETH 为例
-
调用 WETH 合约继承的 balanceOf 函数,传入部署 WETH 合约的地址,查看 WETH 余额
-
调用 WETH 合约继承的 totalSupply 函数,查看合约中存储的 ETH 总量
-
调用 WETH 合约的 withdraw 函数,传入提取的 WETH 数量,提取 ETH
-
调用 WETH 合约继承的 balanceOf 函数,查看 WETH 余额
-
调用 WETH 合约继承的 totalSupply 函数,查看合约中存储的 ETH 总量
相关文章:
【Solidity】代币
ERC20 ERC-20 全称 “Ethereum Request for Comment 20”,是一种标准接口,用于实现代币合约。ERC20 标准定义了一组函数和事件,使得代币可以在不同的应用和平台之间互操作。 ERC20 标准接口定义了一组必须实现的函数和事件: in…...
5 - Linux YUM仓库及NFS共享服务
目录 一、YUM概述 1.YUM简介 2.软件仓库的提供方式 3.RPM软件包的来源 4. yum 命令的运用 二、搭建ftp YUM仓库 三、NFS共享服务 1.NFS简述 2.模拟NFS 一、YUM概述 1.YUM简介 YUM(Yellow dog Updater Modified)是一个专门为了解决包的依赖关系…...
上传文件,文件类型限制语法,各种媒体视频文件的Content-Type
各种媒体视频文件的Content-Type “application/x-apple-diskimage”: “DMG”, “application/epubzip”: “EPUB”, “application/java-archive”: “JAR”, “video/x-matroska”: “MKV”, “text/html”: “HTML|HTM”, “text/css”: “CSS”, “text/javascript…...
类和对象(下)(2)
类和对象(下)(2) static成员 • ⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进⾏初始化。 • 静态成员变量为当前类的所有对象所共享,不属于某个具体的对象,不存在对象中&#…...
软件测试 - 自动化测试(概念)(Java)(自动化测试分类、web自动化测试、驱动、selenium自动化测试工具的安装)
一、自动化的概念 ⾃动洒⽔机,主要通上⽔就可以⾃动化洒⽔并且可以⾃动的旋转。 ⾃动洗⼿液,免去了⼿动挤压可以⾃动感应出洗⼿液 超市⾃动闸⻔,不需要⼿动的开⻔关⻔ ⽣活中的⾃动化案例有效的减少了⼈⼒的消耗,同时也提⾼了⽣…...
wpf datagrid 实现双向绑定
前台 <DataGridAutoGenerateColumns"False"Background"White"CanUserAddRows"True"Grid.Row"1"RowEditEnding"DataGrid_OnRowEditEnding"RowHeight"60"SelectionUnit"CellOrRowHeader"x:Name"…...
使用循环在el-select下拉框中循环出-3至50
问: 使用循环在el-select下拉框中循环出-3至50 回答: <el-form-itemprop"adPosition"label"广告位置":rules"{required: true, message: 广告位置不能为空, trigger: change}" ><el-select v-model"addDataForm.adPosition"…...
全球海事航行通告解析辅助决策系统
“全球海事航行通告解析辅助决策系统”是一个针对海事行业设计的智能系统,旨在帮助海上导航和航运操作人员解析和应对全球发布的海事航行通告。 要做这样的系统我们必须要了解海事签派员的日常工作。 海事签派员,也称为船舶操作员或船运调度员࿰…...
Spring 解决bean的循环依赖
Spring循环依赖-博客园 1. 什么是循环依赖 2. 循环依赖能引发什么问题 循环依赖可能引发以下问题: 初始化顺序不确定:循环依赖导致无法确定哪个对象应该先被创建和初始化,从而造成初始化顺序的混乱。这可能导致错误的结果或意外的行为。死…...
鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main
阅读之前的说明 先说明,本篇很长,也很枯燥,若不是绝对的技术偏执狂是看不下去的.将通过一段简单代码去跟踪编译成ELF格式后的内容.看看ELF究竟长了怎样的一副花花肠子,用readelf命令去窥视ELF的全貌,最后用objdump命令…...
seq2seq编码器encoder和解码器decoder详解
编码器 在序列到序列模型中,编码器将输入序列(如一个句子)转换为一个隐藏状态序列,供解码器生成输出。编码层通常由嵌入层和RNN(如GRU/LSTM)等组成 Token:是模型处理文本时的基本单元,可以是词,子词,字符…...
前端使用 Konva 实现可视化设计器(21)- 绘制图形(椭圆)
本章开始补充一些基础的图形绘制,比如绘制:直线、曲线、圆/椭形、矩形。这一章主要分享一下本示例是如何开始绘制一个图形的,并以绘制圆/椭形为实现目标。 请大家动动小手,给我一个免费的 Star 吧~ 大家如果发现了 Bug,…...
Python 将单词拆分为单个字母组成的列表对象
Python 将单词拆分为单个字母组成的列表对象 正文 正文 这里介绍一个简单算法,将英文单词拆分为其对应字母组成的列表。 str1 ACG lst1 [i for i in str1] lst2 list(str1)# Method 1 print(lst1) # Method 2 print(lst2) """ result: [A, C, G…...
欧洲 摩纳哥税务知识
摩纳哥是一个位于法国南部的城邦国家,以其豪华的生活环境和宽松的税收政策而闻名。自1869年以来,摩纳哥取消了个人所得税的征收,这使得它成为富裕人士和外籍人士的理想居住地。然而,这并不意味着摩纳哥的税收制度完全不存在。以下…...
域控制器的四大支柱分别是车载以太网、自适应Autosar
域控制器的四大支柱分别是车载以太网、自适应Autosar、高性能处理器和集中式E/E架构。 百度安全验证 。自适应Autosar采用Proxy/Skeleton的通信架构,同时采用中间件SOME/IP...
写给大数据开发:如何优化临时数据查询流程
你是否曾因为频繁的临时数据查询请求而感到烦恼?这些看似简单的任务是否正在蚕食你的宝贵时间,影响你的主要工作?如果是,那么这篇文章正是为你而写。 目录 引言:数据开发者的困境问题剖析:临时数据查询的…...
【MongoDB】Java连接MongoDB
连接URI 连接 URI提供驱动程序用于连接到 MongoDB 部署的指令集。该指令集指示驱动程序应如何连接到 MongoDB,以及在连接时应如何运行。下图解释了示例连接 URI 的各个部分: 连接的URI 主要分为 以下四个部分 第一部分 连接协议 示例中使用的 连接到具有…...
nginx支持的不同事件驱动模型
Nginx 支持的不同事件驱动模型 Nginx 是一款高性能的 Web 和反向代理服务器,它支持多种事件驱动模型来处理网络 I/O 操作。不同的操作系统及其版本支持不同的事件驱动模型,这些模型对于 Nginx 的并发处理能力和性能至关重要。下面详细介绍 Nginx 支持的…...
C++ TinyWebServer项目总结(7. Linux服务器程序规范)
进程 PID 进程的PID(Process ID)是操作系统中用于唯一标识一个进程的整数值。每个进程在创建时,操作系统都会分配一个唯一的PID,用来区分不同的进程。 PID的特点 唯一性: 在操作系统运行的某一时刻,每个…...
基于STM32单片机设计的秒表时钟计时器仿真系统——程序源码proteus仿真图设计文档演示视频等(文末工程资料下载)
基于STM32单片机设计的秒表时钟计时器仿真系统 演示视频 基于STM32单片机设计的秒表时钟计时器仿真系统 摘要 本设计基于STM32单片机,设计并实现了一个秒表时钟计时器仿真系统。系统通过显示器实时显示当前时间,并通过定时器实现秒表计时功能。显示小时…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果 5.2 IPsec隧道模式(Tunne…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
