From 0621a723d13b203036b137376b99f80302da148b Mon Sep 17 00:00:00 2001 From: xilibi2003 Date: Sat, 13 Jul 2024 17:23:04 +0800 Subject: [PATCH] introduct some erc --- eth/eips/EIP712.md | 29 ++++++++++ eth/eips/ERC165.md | 77 ++++++++++++++++++++++++++ eth/eips/ERC2612.md | 128 ++++++++++++++++++++++++++++++++++++++++++++ eth/eips/ERC712.md | 0 eth/eips/ERC721.md | 90 ++++++++++++++++++++++++++++++- eth/eips/erc20.md | 74 +++++++++++++++++++++++++ 6 files changed, 396 insertions(+), 2 deletions(-) create mode 100644 eth/eips/EIP712.md delete mode 100644 eth/eips/ERC712.md diff --git a/eth/eips/EIP712.md b/eth/eips/EIP712.md new file mode 100644 index 0000000..a9ba9a2 --- /dev/null +++ b/eth/eips/EIP712.md @@ -0,0 +1,29 @@ +## EIP712 + +EIP712 是一个以太坊改进提案,用于在以太坊区块链上实现更安全、标准化的结构化数据签名。EIP712提案定义了一种方法,通过定义清晰的结构化数据格式(人类友好可读)来构建和签名数据,从而减少签名时出错的风险,并增强用户体验和安全性。 + + + +> Tip: EIP712 提案的背景 +> +> 在以太坊区块链上,签名是非常常见的操作。用户需要对交易、授权以及其他操作进行签名,以证明他们的身份并授权操作。然而,在传统的签名方法中,用户通常需要签名一串难以理解的哈希数据,这带来了以下几个问题: +> +> **可读性差**:用户签名的数据是哈希值或原始的十六进制字符串,这些数据对普通用户而言难以理解,增加了用户误签或被欺骗的风险。 +> +> **安全性问题**:由于用户难以理解签名的数据,恶意合约或应用可能诱导用户签署不安全或不合法的交易。 +> +> **开发复杂性**:开发者需要在不同的应用和场景中重复实现签名和验证逻辑,这增加了开发的复杂性和潜在的错误风险。 + + + +### EIP712 如何工作 + +1. **定义域(Domain)**:指定签名的数据所属的域信息,包括名称、版本、链 ID 和验证合约地址等。域信息确保签名数据的唯一性和防篡改性。 +2. **定义数据结构(Type Definitions)**:明确需要签名的数据类型和结构。这些类型和结构通过 EIP712 标准化,使得签名数据具有一致性和可读性。 +3. **生成哈希**:根据定义的数据结构和域信息生成数据哈希值 +4. **签名数据**:对生成的哈希值进行签名。 + + + +使用方法可参考 [详解EIP712链下签名](https://learnblockchain.cn/article/8260) 。 + diff --git a/eth/eips/ERC165.md b/eth/eips/ERC165.md index e69de29..b91cd22 100644 --- a/eth/eips/ERC165.md +++ b/eth/eips/ERC165.md @@ -0,0 +1,77 @@ + + +## ERC165 + +[ERC165](https://learnblockchain.cn/tags/ERC165?map=EVM) 是 [以太坊](https://learnblockchain.cn/tags/以太坊?map=EVM) 及相关 EVM 兼容区块链上的一个标准,用于检测智能合约是否实现了某些接口(或函数)。它定义了一个标准的方法来查询合约是否实现了某个接口,从而提高了合约的互操作性和可扩展性。 + +[ERC165](https://learnblockchain.cn/tags/ERC165?map=EVM) 通过定义一个标准函数 `supportsInterface`,允许智能合约声明它们支持的接口。其他合约或应用程序可以调用这个函数来检查合约是否支持特定的接口。 + +### ERC165 接口 + +```solidity +pragma solidity ^0.8.0; + +interface IERC165 { + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} +``` + +- **supportsInterface**:接受一个接口标识符(`interfaceId`),返回一个布尔值,指示合约是否实现了该接口。 + +### 示例实现 + +以下是一个简单的 [ERC165](https://learnblockchain.cn/tags/ERC165?map=EVM) 合约实现示例: + +```solidity +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +contract ERC165Example is IERC165 { + // Mapping of interface id to whether or not it's supported. + mapping(bytes4 => bool) private _supportedInterfaces; + + constructor() { + // Register the support of the ERC165 interface + _registerInterface(type(IERC165).interfaceId); + } + + // Implementation of the supportsInterface method as per the ERC165 standard. + function supportsInterface(bytes4 interfaceId) public view override returns (bool) { + return _supportedInterfaces[interfaceId]; + } + + // Internal method for registering interface support + function _registerInterface(bytes4 interfaceId) internal { + require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); + _supportedInterfaces[interfaceId] = true; + } +} +``` + +在这个示例中,我们实现了 `supportsInterface` 函数,并使用一个内部函数 `_registerInterface` 来注册支持的接口。 + +### 使用示例 + +假设有一个合约实现了 [ERC165](https://learnblockchain.cn/tags/ERC165?map=EVM) 接口,其他合约可以通过调用 `supportsInterface` 来检查它是否支持特定的接口。 + +```solidity +pragma solidity ^0.8.0; + +interface IERC165 { + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +contract InterfaceChecker { + function checkInterface(address contractAddress, bytes4 interfaceId) external view returns (bool) { + IERC165 erc165 = IERC165(contractAddress); + return erc165.supportsInterface(interfaceId); + } +} +``` + +在这个示例中,`InterfaceChecker` 合约包含一个 `checkInterface` 函数,用于检查给定合约地址是否支持特定的接口。 + +### 总结 + +[ERC165](https://learnblockchain.cn/tags/ERC165?map=EVM) 标准通过定义一个标准的接口检测机制,使得智能合约能够声明它们实现了哪些接口,并允许其他合约和应用程序轻松查询这些信息。这提高了合约的互操作性和可扩展性,是构建复杂和可组合智能合约系统的重要工具。 \ No newline at end of file diff --git a/eth/eips/ERC2612.md b/eth/eips/ERC2612.md index e69de29..5526739 100644 --- a/eth/eips/ERC2612.md +++ b/eth/eips/ERC2612.md @@ -0,0 +1,128 @@ +## ERC2612 + +[ERC2612](https://learnblockchain.cn/tags/ERC2612?map=EVM) 是用于增强 [ERC20](https://learnblockchain.cn/tags/ERC20?map=EVM) 代币的功能的扩展标准,具体来说,[ERC2612](https://learnblockchain.cn/tags/ERC2612?map=EVM) 为 [ERC20](https://learnblockchain.cn/tags/ERC20?map=EVM) 代币引入了签名授权(permit)功能,使得用户可以通过签名来授权代币转移,而不需要支付以太坊交易费。 + +通过链下签名授权不仅可简化用户体验,还减少了链上交易次数,从而降低了交易成本。 + +### ERC2612 接口 + +```solidity +pragma solidity ^0.8.0; + +interface IERC2612 { + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + function nonces(address owner) external view returns (uint256); + function DOMAIN_SEPARATOR() external view returns (bytes32); +} +``` + +#### 方法 + +1. **permit**:通过签名授权 `spender` 在 `owner` 的代币账户上支配 `value` 个代币。 +2. **nonces**:返回特定地址的 nonce 值,用于防止重放攻击。 +3. **DOMAIN_SEPARATOR**:返回 [EIP-712](https://learnblockchain.cn/tags/ERC712?map=EVM)) 域分隔符,用于签名消息。 + +### ERC2612 合约示例 + +以下是一个实现 ERC2612 的示例合约: + +```solidity +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; + +contract UpChainToken is ERC20, ERC20Permit { + constructor() ERC20("UpChainToken", "MTK") ERC20Permit("UpChainToken") { + _mint(msg.sender, 1000000 * 10 ** decimals()); + } +} +``` + +在这个示例中,我们继承了 OpenZeppelin 库中的 `ERC20` 和 `ERC20Permit` 合约,以实现 [ERC2612](https://learnblockchain.cn/tags/ERC2612?map=EVM) 的功能。 + +### 使用示例 + +假设我们已经部署了上述 `UpChainToken` 合约,下面展示如何通过 [ethers.js (v5)](https://learnblockchain.cn/tags/ethers.js?map=EVM) 与该合约进行交互,实现 `permit` 功能: + +#### 生成签名 + +首先,生成离线签名: + +```javascript +const { ethers } = require("ethers"); +const provider = new ethers.providers.JsonRpcProvider("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID"); +const wallet = new ethers.Wallet("YOUR_PRIVATE_KEY", provider); + +const contractAddress = "0xYourContractAddress"; +const contractABI = [ + "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external", + "function nonces(address owner) external view returns (uint256)", + "function DOMAIN_SEPARATOR() external view returns (bytes32)" +]; +const contract = new ethers.Contract(contractAddress, contractABI, wallet); + +async function createPermitSignature(owner, spender, value, deadline) { + const nonce = await contract.nonces(owner); + const domainSeparator = await contract.DOMAIN_SEPARATOR(); + + const permitData = { + owner: owner, + spender: spender, + value: value, + nonce: nonce, + deadline: deadline + }; + + const types = { + Permit: [ + { name: "owner", type: "address" }, + { name: "spender", type: "address" }, + { name: "value", type: "uint256" }, + { name: "nonce", type: "uint256" }, + { name: "deadline", type: "uint256" } + ] + }; + + const signature = await wallet._signTypedData( + { name: "UpChainToken", version: "1", chainId: 1, verifyingContract: contractAddress }, + types, + permitData + ); + + return ethers.utils.splitSignature(signature); +} +``` + +#### 执行 permit 方法 + +使用生成的签名在链上调用 `permit` 方法: + +```javascript +async function permit(owner, spender, value, deadline, v, r, s) { + const tx = await contract.permit(owner, spender, value, deadline, v, r, s); + await tx.wait(); + console.log("Permit transaction submitted: ", tx.hash); +} + +const owner = wallet.address; +const spender = "0xSpenderAddress"; +const value = ethers.utils.parseUnits("100", 18); +const deadline = Math.floor(Date.now() / 1000) + 60 * 60; // 1 hour from now + +const { v, r, s } = await createPermitSignature(owner, spender, value, deadline); +await permit(owner, spender, value, deadline, v, r, s); +``` + +### 总结 + +ERC2612 标准通过引入 `permit` 方法,增强了 [ERC20](https://learnblockchain.cn/tags/ERC20?map=EVM) 代币的功能,使得用户可以通过离线签名进行授权操作,从而简化用户体验并减少链上交易次数。上述合约示例展示了如何实现和使用 ERC2612 的功能。 \ No newline at end of file diff --git a/eth/eips/ERC712.md b/eth/eips/ERC712.md deleted file mode 100644 index e69de29..0000000 diff --git a/eth/eips/ERC721.md b/eth/eips/ERC721.md index 4874548..3c9721e 100644 --- a/eth/eips/ERC721.md +++ b/eth/eips/ERC721.md @@ -1,5 +1,6 @@ -## ERC721 -ERC721 是一种用于创建[非同质化代币(NFT)](https://learnblockchain.cn/tags/NFT)的以太坊标准。与 ERC20 标准不同,ERC721 代币是独特的,每个代币都有其独特的属性和价值。 +## ERC721 + +ERC721 是一种用于创建[非同质化代币(NFT)](https://learnblockchain.cn/tags/NFT)的以太坊标准。与 [ERC20](https://learnblockchain.cn/tags/ERC20) 标准不同,ERC721 代币是独特的,每个代币都有其独特的属性和价值。 ### ERC721 的特点 @@ -12,6 +13,91 @@ ERC721 是一种用于创建[非同质化代币(NFT)](https://learnblockchai 3. **所有权(Ownership)**: - ERC721 标准定义了代币所有权的概念,并允许代币所有者进行转移和授权。所有权信息在区块链上公开记录,确保透明和安全。 +### ERC721 主要接口和事件 + +```solidity +pragma solidity ^0.8.0; + +// IERC721 ERC721 标准要求实现 ERC165 +interface IERC721 is IERC165 { + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + 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); + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; +} + +interface IERC721Metadata { + function name() external view returns (string _name); + function symbol() external view returns (string _symbol); + // 返回 给定资产的唯一统一资源标识符(URI),通常指向一个符合“ERC721元数据JSON模式”的JSON文件。 + function tokenURI(uint256 _tokenId) external view returns (string); +} +``` + +ERC721元数据 JSON 参考模式: + +```json +{ + "title": "Asset Metadata", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Identifies the asset to which this NFT represents" + }, + "description": { + "type": "string", + "description": "Describes the asset to which this NFT represents" + }, + "image": { + "type": "string", + "description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive." + } + } +} +``` + + + +## ERC721 实现 + +以下是一个基于 [OpenZeppelin](https://learnblockchain.cn/tags/OpenZeppelin?map=EVM) 代码实现的简单的 [ERC721](https://learnblockchain.cn/tags/ERC721?map=EVM) 代币合约示例: + +```solidity +// contracts/GameItem.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; + +contract GameItem is ERC721URIStorage { + using Counters for Counters.Counter; + Counters.Counter private _tokenIds; + + constructor() ERC721("GameItem", "ITM") {} + + function awardItem(address player, string memory tokenURI) public returns (uint256) { + uint256 newItemId = _tokenIds.current(); + _mint(player, newItemId); + _setTokenURI(newItemId, tokenURI); + + _tokenIds.increment(); + return newItemId; + } +} +``` + + ### 应用 diff --git a/eth/eips/erc20.md b/eth/eips/erc20.md index e69de29..b8357ef 100644 --- a/eth/eips/erc20.md +++ b/eth/eips/erc20.md @@ -0,0 +1,74 @@ +## ERC20 + +[ERC20](https://learnblockchain.cn/tags/ERC20?map=EVM) 是 [以太坊](https://learnblockchain.cn/tags/以太坊?map=EVM) 区块链上最常用的同质化代币(Token)标准之一。它定义了一组通用接口,使得在 [以太坊](https://learnblockchain.cn/tags/以太坊?map=EVM) 区块链上创建和管理代币变得非常简单和标准化。标准的通用接口,让生态应用:包括钱包、交易所和dapp 之前具备了互操作性。使得Token可以轻松地在各种平台上进行交易和使用。 + +### ERC20 主要接口和事件 + +```solidity +pragma solidity ^0.8.0; + +interface IERC20 { + function totalSupply() external view returns (uint256); + function balanceOf(address account) external view returns (uint256); + function transfer(address recipient, uint256 amount) external returns (bool); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); +} +``` + + + +1. **totalSupply**:返回代币的总供给量。 +2. **balanceOf**:返回指定地址的代币余额。 +3. **transfer**:将指定数量的代币从调用者账户转移到另一个账户。 +4. **approve**:允许另一个账户支配指定数量的代币。 +5. **transferFrom**:从一个账户转移指定数量的代币到另一个账户(需事先授权 approve)。 +6. **allowance**:返回授权账户允许支配的代币数量。 + + + +### ERC20 代币合约示例 + +以下是一个基于 [OpenZeppelin](https://learnblockchain.cn/tags/OpenZeppelin?map=EVM) 代码实现的简单的 [ERC20](https://learnblockchain.cn/tags/ERC20?map=EVM) 代币合约示例: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract MyToken is ERC20, Ownable { + constructor() ERC20("MyToken", "MTK") { + // Initial mint: mint 1000 tokens to the contract deployer + _mint(msg.sender, 1000 * 10 ** decimals()); + } + + // Function to mint new tokens + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } +} +``` + + + +上述合约示例展示了如何实现这些接口,开发者可以根据具体需求扩展和修改该合约,构建自己的代币。通过遵循 [ERC20标准](https://eips.ethereum.org/EIPS/eip-20),可以确保代币在以太坊生态系统中的广泛互操作性和兼容性。 + +## 知名的 Token + +以下是在 [以太坊](https://learnblockchain.cn/tags/以太坊?map=EVM) 区块链上使用 [ERC-20](https://learnblockchain.cn/tags/ERC20?map=EVM) 标准的一些知名代币: + +1. **Tether([USDT](https://learnblockchain.cn/tags/USDT))**:Tether 是与美元挂钩的稳定币,在加密货币市场中被广泛用于交易和作为稳定的价值储存。网址:[tether.to](https://tether.to/) +2. **USD Coin([USDC](https://learnblockchain.cn/tags/USDC))**:USDC 是另一种与美元挂钩的稳定币,由包括 Circle 和 Coinbase 在内的 Centre 财团管理。**网站**:[centre.io/usdc](https://www.centre.io/usdc) +3. **Chainlink(LINK)**:是一个去中心化的预言机网络,为区块链上的智能合约提供现实世界数据。**网站**:[chain.link](https://chain.link/) +4. **Uniswap(UNI)**:Uniswap 是建立在 [Ethereum](https://learnblockchain.cn/tags/以太坊?map=EVM) 上的去中心化交易(DEX)协议。UNI 代币用于治理和流动性激励。**网站**:[uniswap.org](https://uniswap.org/) +5. **Wrapped Bitcoin(WBTC)**:WBTC 是在 [Ethereum](https://learnblockchain.cn/tags/以太坊?map=EVM) 区块链上代表比特币(BTC)的 ERC-20 代币。每个 WBTC 都以 1:1 的比特币作为支撑。**网站**:[wbtc.network](https://wbtc.network/) +6. **Dai(DAI)**:是一种去中心化的稳定币,与美元软挂钩,并由 MakerDAO 平台上的其他加密货币抵押支持。**网站**:[makerdao.com](https://makerdao.com/) +7. **Aave([AAVE](https://learnblockchain.cn/tags/AAVE))**:AAVE 是 Aave 协议的原生代币,是一个去中心化的借贷平台。**网站**:[aave.com](https://aave.com/) +8. **COMP**:COMP 是 [Compound ](https://learnblockchain.cn/tags/Compound)协议的治理代币,是一个允许用户借贷加密货币的去中心化货币市场平台。**网站**:[compound.finance](https://compound.finance/) +