当前位置: 首页 > news >正文

【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);}
}
  1. 部署 WETH 合约

  2. 调用 WETH 合约的 deposit 函数,设置传入的 ETH 数量,这里以 1 ETH 为例

  3. 调用 WETH 合约继承的 balanceOf 函数,传入部署 WETH 合约的地址,查看 WETH 余额

  4. 调用 WETH 合约继承的 totalSupply 函数,查看合约中存储的 ETH 总量

  5. 调用 WETH 合约的 withdraw 函数,传入提取的 WETH 数量,提取 ETH

  6. 调用 WETH 合约继承的 balanceOf 函数,查看 WETH 余额

  7. 调用 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"…...

全球海事航行通告解析辅助决策系统

“全球海事航行通告解析辅助决策系统”是一个针对海事行业设计的智能系统&#xff0c;旨在帮助海上导航和航运操作人员解析和应对全球发布的海事航行通告。 要做这样的系统我们必须要了解海事签派员的日常工作。 海事签派员&#xff0c;也称为船舶操作员或船运调度员&#xff0…...

Spring 解决bean的循环依赖

Spring循环依赖-博客园 1. 什么是循环依赖 2. 循环依赖能引发什么问题 循环依赖可能引发以下问题&#xff1a; 初始化顺序不确定&#xff1a;循环依赖导致无法确定哪个对象应该先被创建和初始化&#xff0c;从而造成初始化顺序的混乱。这可能导致错误的结果或意外的行为。死…...

鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main

阅读之前的说明 先说明&#xff0c;本篇很长&#xff0c;也很枯燥&#xff0c;若不是绝对的技术偏执狂是看不下去的.将通过一段简单代码去跟踪编译成ELF格式后的内容.看看ELF究竟长了怎样的一副花花肠子&#xff0c;用readelf命令去窥视ELF的全貌&#xff0c;最后用objdump命令…...

seq2seq编码器encoder和解码器decoder详解

编码器 在序列到序列模型中&#xff0c;编码器将输入序列&#xff08;如一个句子&#xff09;转换为一个隐藏状态序列&#xff0c;供解码器生成输出。编码层通常由嵌入层和RNN&#xff08;如GRU/LSTM)等组成 Token:是模型处理文本时的基本单元&#xff0c;可以是词,子词,字符…...

前端使用 Konva 实现可视化设计器(21)- 绘制图形(椭圆)

本章开始补充一些基础的图形绘制&#xff0c;比如绘制&#xff1a;直线、曲线、圆/椭形、矩形。这一章主要分享一下本示例是如何开始绘制一个图形的&#xff0c;并以绘制圆/椭形为实现目标。 请大家动动小手&#xff0c;给我一个免费的 Star 吧~ 大家如果发现了 Bug&#xff0c…...

Python 将单词拆分为单个字母组成的列表对象

Python 将单词拆分为单个字母组成的列表对象 正文 正文 这里介绍一个简单算法&#xff0c;将英文单词拆分为其对应字母组成的列表。 str1 ACG lst1 [i for i in str1] lst2 list(str1)# Method 1 print(lst1) # Method 2 print(lst2) """ result: [A, C, G…...

欧洲 摩纳哥税务知识

摩纳哥是一个位于法国南部的城邦国家&#xff0c;以其豪华的生活环境和宽松的税收政策而闻名。自1869年以来&#xff0c;摩纳哥取消了个人所得税的征收&#xff0c;这使得它成为富裕人士和外籍人士的理想居住地。然而&#xff0c;这并不意味着摩纳哥的税收制度完全不存在。以下…...

域控制器的四大支柱分别是车载以太网、自适应Autosar

域控制器的四大支柱分别是车载以太网、自适应Autosar、高性能处理器和集中式E/E架构。 百度安全验证 。自适应Autosar采用Proxy/Skeleton的通信架构&#xff0c;同时采用中间件SOME/IP...

写给大数据开发:如何优化临时数据查询流程

你是否曾因为频繁的临时数据查询请求而感到烦恼&#xff1f;这些看似简单的任务是否正在蚕食你的宝贵时间&#xff0c;影响你的主要工作&#xff1f;如果是&#xff0c;那么这篇文章正是为你而写。 目录 引言&#xff1a;数据开发者的困境问题剖析&#xff1a;临时数据查询的…...

【MongoDB】Java连接MongoDB

连接URI 连接 URI提供驱动程序用于连接到 MongoDB 部署的指令集。该指令集指示驱动程序应如何连接到 MongoDB&#xff0c;以及在连接时应如何运行。下图解释了示例连接 URI 的各个部分&#xff1a; 连接的URI 主要分为 以下四个部分 第一部分 连接协议 示例中使用的 连接到具有…...

nginx支持的不同事件驱动模型

Nginx 支持的不同事件驱动模型 Nginx 是一款高性能的 Web 和反向代理服务器&#xff0c;它支持多种事件驱动模型来处理网络 I/O 操作。不同的操作系统及其版本支持不同的事件驱动模型&#xff0c;这些模型对于 Nginx 的并发处理能力和性能至关重要。下面详细介绍 Nginx 支持的…...

C++ TinyWebServer项目总结(7. Linux服务器程序规范)

进程 PID 进程的PID&#xff08;Process ID&#xff09;是操作系统中用于唯一标识一个进程的整数值。每个进程在创建时&#xff0c;操作系统都会分配一个唯一的PID&#xff0c;用来区分不同的进程。 PID的特点 唯一性&#xff1a; 在操作系统运行的某一时刻&#xff0c;每个…...

基于STM32单片机设计的秒表时钟计时器仿真系统——程序源码proteus仿真图设计文档演示视频等(文末工程资料下载)

基于STM32单片机设计的秒表时钟计时器仿真系统 演示视频 基于STM32单片机设计的秒表时钟计时器仿真系统 摘要 本设计基于STM32单片机&#xff0c;设计并实现了一个秒表时钟计时器仿真系统。系统通过显示器实时显示当前时间&#xff0c;并通过定时器实现秒表计时功能。显示小时…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...