EIP-: ```markdown
Authors |
---|
Table of Contents
---
eip: 5453
title: 授权 - 任意函数的许可
description: 一个通用的协议,用于批准同一交易中的函数调用,依赖于 ERC-5750。
author: Zainan Victor Zhou (@xinbenlv)
discussions-to: https://ethereum-magicians.org/t/erc-5453-endorsement-standard/10355
status: Last Call
last-call-deadline: 2023-09-27
type: Standards Track
category: ERC
created: 2022-08-12
requires: 165, 712, 1271, 5750
---
## 摘要
本 EIP 建立了一个通用的协议,用于允许批准同一交易中的函数调用,该协议依赖于 [ERC-5750](/docs/eips/EIPS/eip-5750/)。
与之前的一些技术 ([ERC-2612](/docs/eips/EIPS/eip-2612/) 针对 [ERC-20](/docs/eips/EIPS/eip-20/),`ERC-4494` 针对 [ERC-721](/docs/eips/EIPS/eip-721/)) 不同,
它们通常只允许单一行为(ERC-20 的 `transfer` 和 ERC-721 的 `safeTransferFrom`)以及两笔交易中的单一批准者(首先是 `permit(...)` 交易,然后是类似 `transfer` 的交易),本 EIP 提供了一种方法来允许任意行为,并在同一交易中聚合来自任意数量的批准者的多个批准,从而实现多重签名或阈值签名行为。
## 动机
1. 支持与函数调用一起的 permit(approval)。
2. 支持来自另一个用户的第二次批准。
3. 支持由另一个用户支付
4. 支持多重签名
5. 支持通过授权协同行动的人员
6. 支持累积投票
7. 支持离线签名
## 规范
本文档中使用的关键词 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY" 和 "OPTIONAL" 按照 RFC 2119 和 RFC 8174 中的描述进行解释。
### 接口
此处引用的接口和结构如下
```solidity
pragma solidity ^0.8.9;
struct ValidityBound {
bytes32 functionParamStructHash;
uint256 validSince;
uint256 validBy;
uint256 nonce;
}
struct SingleEndorsementData {
address endorserAddress; // 32
bytes sig; // dynamic = 65
}
struct GeneralExtensionDataStruct {
bytes32 erc5453MagicWord;
uint256 erc5453Type;
uint256 nonce;
uint256 validSince;
uint256 validBy;
bytes endorsementPayload;
}
interface IERC5453EndorsementCore {
function eip5453Nonce(address endorser) external view returns (uint256);
function isEligibleEndorser(address endorser) external view returns (bool);
}
interface IERC5453EndorsementDigest {
function computeValidityDigest(
bytes32 _functionParamStructHash,
uint256 _validSince,
uint256 _validBy,
uint256 _nonce
) external view returns (bytes32);
function computeFunctionParamHash(
string memory _functionName,
bytes memory _functionParamPacked
) external view returns (bytes32);
}
interface IERC5453EndorsementDataTypeA {
function computeExtensionDataTypeA(
uint256 nonce,
uint256 validSince,
uint256 validBy,
address endorserAddress,
bytes calldata sig
) external view returns (bytes memory);
}
interface IERC5453EndorsementDataTypeB {
function computeExtensionDataTypeB(
uint256 nonce,
uint256 validSince,
uint256 validBy,
address[] calldata endorserAddress,
bytes[] calldata sigs
) external view returns (bytes memory);
}
参见 IERC5453.sol
。
行为规范
如 ERC-5750 方法行为的通用可扩展性 中所指定的,任何符合规范的方法,其最后一个方法具有 bytes extraData
,用于扩展行为,都可以符合 ERC-5453,以此作为指示来自特定用户的许可的方式。
- 本 EIP 的任何符合规范的方法必须是 ERC-5750 兼容的方法。
- 调用者必须传入最后一个参数
bytes extraData
,该参数符合 接口部分 中指定的GeneralExtensionDataStruct
的 solidity 内存编码布局字节。以下描述基于将bytes extraData
解码为GeneralExtensionDataStruct
时的情况。 - 在
GeneralExtensionDataStruct
-解码的extraData
中,调用者必须将GeneralExtensionDataStruct.erc5453MagicWord
的值设置为keccak256("ERC5453-ENDORSEMENT")
。 - 调用者必须将
GeneralExtensionDataStruct.erc5453Type
的值设置为支持的值之一。
uint256 constant ERC5453_TYPE_A = 1;
uint256 constant ERC5453_TYPE_B = 2;
- 如果
GeneralExtensionDataStruct.erc5453Type
的值设置为ERC5453_TYPE_A
,则GeneralExtensionDataStruct.endorsementPayload
必须是SingleEndorsementData
的 abi 编码字节。 -
如果
GeneralExtensionDataStruct.erc5453Type
的值设置为ERC5453_TYPE_B
,则GeneralExtensionDataStruct.endorsementPayload
必须是SingleEndorsementData[]
(动态数组)的 abi 编码字节。 -
每个
SingleEndorsementData
必须有一个address endorserAddress;
和一个 65 字节的bytes sig
签名。 - 每个
bytes sig
必须是使用签名者的私钥的 ECDSA (secp256k1) 签名,签名者的对应地址是endorserAddress
,用于签名validityDigest
,它是 EIP-712 的 hashTypeDataV4,表示ValidityBound
数据结构的 hashStruct,如下所示:
bytes32 validityDigest =
eip712HashTypedDataV4(
keccak256(
abi.encode(
keccak256(
"ValidityBound(bytes32 functionParamStructHash,uint256 validSince,uint256 validBy,uint256 nonce)"
),
functionParamStructHash,
_validSince,
_validBy,
_nonce
)
)
);
functionParamStructHash
必须按如下方式计算
bytes32 functionParamStructHash = keccak256(
abi.encodePacked(
keccak256(bytes(_functionStructure)),
_functionParamPacked
)
);
return functionParamStructHash;
其中
_functionStructure
必须计算为function methodName(type1 param1, type2 param2, ...)
。_functionParamPacked
必须计算为enc(param1) || enco(param2) ...
- 在验证
endorserAddress == ecrecover(validityDigest, signature)
或EIP1271(endorserAddress).isValidSignature(validityDigest, signature) == ERC1271.MAGICVALUE
之后,单个授权必须被认为是有效的。 -
符合规范的方法可以选择为同一
ERC5453_TYPE_B
类型的endorsementPayload
中需要有效的授权数量设置一个阈值。 validSince
和validBy
都包含在内。实现者可以选择使用块号或时间戳。实现者应该找到一种方法来指示validSince
和validBy
是块号还是时间戳。
理论依据
-
我们选择同时拥有
ERC5453_TYPE_A
(单次授权) 和ERC5453_TYPE_B
(多次授权,整个合约的 nonce 相同),这样我们 可以平衡更广泛的用例。例如,ERC-2612 和ERC-4494
的相同用例可以通过ERC5453_TYPE_A
来支持。阈值批准可以通过ERC5453_TYPE_B
来完成。更复杂的批准类型也可以通过定义新的ERC5453_TYPE_?
来扩展。 -
我们选择同时包含
validSince
和validBy
,以允许最大的到期灵活性。如果采用ERC-5081
,这也可以在 EVM 本机支持,但ERC-5081
不会很快被采用,我们选择在我们的协议中添加这两个数字,以允许智能合约级别的支持。
向后兼容性
该设计假定使用 bytes calldata extraData
以最大限度地提高未来扩展的灵活性。这种假设与 ERC-721、ERC-1155 和许多其他 ERC 跟踪 EIP 兼容。那些不兼容的,例如 ERC-20,也可以更新以支持它,例如使用包装器合约或代理升级。
参考实现
除了指定的验证授权人签名的算法外,我们还提供以下参考实现。
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "./IERC5453.sol";
abstract contract AERC5453Endorsible is EIP712,
IERC5453EndorsementCore, IERC5453EndorsementDigest, IERC5453EndorsementDataTypeA, IERC5453EndorsementDataTypeB {
// ...
function _validate(
bytes32 msgDigest,
SingleEndorsementData memory endersement
) internal virtual {
require(
endersement.sig.length == 65,
"AERC5453Endorsible: wrong signature length"
);
require(
SignatureChecker.isValidSignatureNow(
endersement.endorserAddress,
msgDigest,
endersement.sig
),
"AERC5453Endorsible: invalid signature"
);
}
// ...
modifier onlyEndorsed(
bytes32 _functionParamStructHash,
bytes calldata _extensionData
) {
require(_isEndorsed(_functionParamStructHash, _extensionData));
_;
}
function computeExtensionDataTypeB(
uint256 nonce,
uint256 validSince,
uint256 validBy,
address[] calldata endorserAddress,
bytes[] calldata sigs
) external pure override returns (bytes memory) {
require(endorserAddress.length == sigs.length);
SingleEndorsementData[]
memory endorsements = new SingleEndorsementData[](
endorserAddress.length
);
for (uint256 i = 0; i < endorserAddress.length; ++i) {
endorsements[i] = SingleEndorsementData(
endorserAddress[i],
sigs[i]
);
}
return
abi.encode(
GeneralExtensionDataStruct(
MAGIC_WORLD,
ERC5453_TYPE_B,
nonce,
validSince,
validBy,
abi.encode(endorsements)
)
);
}
}
参见 AERC5453.sol
EndorsableERC721
的参考实现
这是一个 EndorsableERC721
的参考实现,它实现了与 ERC-4494
类似的行为。
pragma solidity ^0.8.9;
contract EndorsableERC721 is ERC721, AERC5453Endorsible {
//...
function mint(
address _to,
uint256 _tokenId,
bytes calldata _extraData
)
external
onlyEndorsed(
_computeFunctionParamHash(
"function mint(address _to,uint256 _tokenId)",
abi.encode(_to, _tokenId)
),
_extraData
)
{
_mint(_to, _tokenId);
}
}
ThresholdMultiSigForwarder
的参考实现
这是一个 ThresholdMultiSigForwarder 的参考实现,它实现了类似于 Gnosis-Safe 钱包的多重签名阈值批准远程合约调用的行为。
pragma solidity ^0.8.9;
contract ThresholdMultiSigForwarder is AERC5453Endorsible {
//...
function forward(
address _dest,
uint256 _value,
uint256 _gasLimit,
bytes calldata _calldata,
bytes calldata _extraData
)
external
onlyEndorsed(
_computeFunctionParamHash(
"function forward(address _dest,uint256 _value,uint256 _gasLimit,bytes calldata _calldata)",
abi.encode(_dest, _value, _gasLimit, keccak256(_calldata))
),
_extraData
)
{
string memory errorMessage = "Fail to call remote contract";
(bool success, bytes memory returndata) = _dest.call{value: _value}(
_calldata
);
Address.verifyCallResult(success, returndata, errorMessage);
}
}
参见 ThresholdMultiSigForwarder.sol
安全注意事项
重放攻击
重放攻击是一种针对密码学认证的攻击类型。从狭义上讲,它通常指的是一种通过重用现有签名来再次签名消息,从而绕过密码学签名验证的攻击类型。任何依赖此 EIP 的实现都必须意识到,此处描述的所有智能授权都是 公开的 加密签名,并且可以被任何人获取。他们必须预见到不仅在同一智能合约的精确部署中,而且在类似智能合约的其他部署中,或在另一个 chainId
上的同一合约版本中,或任何其他类似攻击面上的交易重放的可能性。nonce
、validSince
和 validBy
字段旨在限制攻击面,但可能无法完全消除所有此类攻击的风险,例如,请参阅 网络钓鱼 部分。
网络钓鱼
值得指出的是一种特殊的网络钓鱼重放攻击。攻击者可以设计另一个智能合约,使用户被诱骗为看似合法的目的签署智能授权,但设计的数据与目标应用程序相匹配
版权
版权和相关权利已通过 CC0 放弃。 ```
Citation
Please cite this document as:
, "EIP-: ```markdown," Ethereum Improvement Proposals, no. , . [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-.