-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
92703ce
commit 0621a72
Showing
6 changed files
with
396 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) 。 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) 标准通过定义一个标准的接口检测机制,使得智能合约能够声明它们实现了哪些接口,并允许其他合约和应用程序轻松查询这些信息。这提高了合约的互操作性和可扩展性,是构建复杂和可组合智能合约系统的重要工具。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.