Skip to content

Commit

Permalink
introduct some erc
Browse files Browse the repository at this point in the history
  • Loading branch information
xilibi2003 committed Jul 13, 2024
1 parent 92703ce commit 0621a72
Show file tree
Hide file tree
Showing 6 changed files with 396 additions and 2 deletions.
29 changes: 29 additions & 0 deletions eth/eips/EIP712.md
Original file line number Diff line number Diff line change
@@ -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)

77 changes: 77 additions & 0 deletions eth/eips/ERC165.md
Original file line number Diff line number Diff line change
@@ -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) 标准通过定义一个标准的接口检测机制,使得智能合约能够声明它们实现了哪些接口,并允许其他合约和应用程序轻松查询这些信息。这提高了合约的互操作性和可扩展性,是构建复杂和可组合智能合约系统的重要工具。
128 changes: 128 additions & 0 deletions eth/eips/ERC2612.md
Original file line number Diff line number Diff line change
@@ -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 的功能。
Empty file removed eth/eips/ERC712.md
Empty file.
90 changes: 88 additions & 2 deletions eth/eips/ERC721.md
Original file line number Diff line number Diff line change
@@ -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 的特点

Expand All @@ -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;
}
}
```



### 应用

Expand Down
Loading

0 comments on commit 0621a72

Please sign in to comment.