ERC-4886: 代理所有权注册表
一个代理所有权注册表,允许以太坊地址之间进行无需信任的所有权证明,并委托资产交付
Authors | Omnus Sunmo (@omnus) |
---|---|
Created | 2022-09-03 |
Discussion Link | https://ethereum-magicians.org/t/eip-4886-a-proxy-ownership-and-asset-delivery-register/8559 |
摘要
一个代理协议,允许用户指定一个代理地址来代表另一个钱包地址,以及一个用于接收新资产的交付地址。使用该协议的智能合约和应用程序可以使用代理地址,并查找提名人地址的持有信息。这有许多实际应用,包括允许用户将有价值的资产安全地存储在冷钱包中,并使用低价值的代理地址与智能合约交互。提名人中的资产受到保护,因为所有合约交互都通过代理地址进行。这消除了最近出现的许多漏洞,这些漏洞会导致用户的资产通过恶意合约交互被盗取。此外,注册表还保存一个交付地址,允许将新资产直接交付到冷钱包地址。
动机
为了充分利用以太坊,用户通常需要证明他们对现有资产的所有权。例如:
- Discord 社区要求用户使用他们的钱包签名消息,以证明他们持有该社区的代币或 NFT。
- 白名单活动(例如最近的空投或 NFT 铸造)要求用户使用给定的地址进行交互,以证明其资格。
- DAO 和其他协议中的投票要求用户使用持有相关资产的地址进行签名。
还有更多示例,其统一主题是用户必须使用具有资产的地址来获得平台利益。这意味着持有这些资产的地址不能是真正的“冷”地址,这是恶意开发者窃取有价值资产的礼物。例如,一个新项目可以向现有 NFT 资产的持有者提供免费 NFT。现有的持有者必须通过从具有确定资格的资产的钱包中铸造来证明所有权。这为恶意开发者提供了许多可能的攻击向量,他们知道所有与合约交互的用户都具有该类型的资产。
甚至可能更具破坏性的是对整个生态系统中用户信心的影响。用户变得不愿与应用程序和智能合约交互,因为担心将他们的资产置于风险之中。他们也可能决定不将资产存储在冷钱包地址中,因为他们需要定期证明自己拥有这些资产。一个相关的例子是用户试图决定是否“vault”他们的 NFT 并失去对 discord 频道的访问权限,或者将他们的 NFT 保留在另一个钱包中,甚至将他们的“vault”连接到 discord。
以太坊在提供无需信任的证明方面非常出色。用户应该需要使用持有资产的钱包进行交互的唯一时间是他们打算出售或转移该资产时。如果用户仅仅希望证明所有权(以访问资源、获得空投、铸造 NFT 或在 DAO 中投票),他们应该通过存储在链上的无需信任的证明来做到这一点。
此外,用户应该能够决定将新资产交付到哪里,而不是将它们交付到提供交互的钱包。这允许热钱包获取直接发送到冷钱包“vault”的资产,甚至可能是他们在资产所有权方面所代表的那个。
本 EIP 的目的是提供一种便捷的方法来避免这种安全问题,并使更多人能够放心地利用以太坊的全部功能。我们的愿景是以太坊用户为他们希望长期持有的资产设置一个新的硬件钱包,然后与该钱包进行一次单一的合约交互:提名一个热钱包代理。该用户可以始终证明他们拥有该地址上的资产,并且他们可以将其指定为新资产交付的交付地址。
规范
本文档中的关键词“必须”、“禁止”、“必需”、“应”、“不应”、“应该”、“不应该”、“推荐”、“可以”和“可选”应按照 RFC 2119 中的描述进行解释。
定义
- 交付地址:资产将交付到的当前代理记录的地址,即由代理地址铸造的代表提名人地址的新 NFT 应交付到交付地址。
- 提名:提名人提名代理地址的情况。只有在代理接受提名后才会生效。
- 提名人地址:提出代理关系的地址。此地址提名另一个地址作为其代理,在所有交互中代表它及其持有物。
- 代理地址:将在链上代表提名人的地址。
- 代理记录:包含提名人、代理和交付的活动代理关系。
- 注册表:主要的 EPS 合约,其中包含提名和代理记录的详细信息。
EPS 规范
注册表主要分为两部分 - 提名和代理记录:
Contract / Dapp Register
Nominator: 0x1234.. Nominator: 0x1234..
Proxy: 0x5678.. ---------> Proxy: 0x4567..
Delivery: 0x9876..
创建代理记录的第一步是地址提名另一个地址作为其代理。这将创建一个提名,将提名人(进行提名的地址)映射到提议的代理地址。
在此阶段,这还不是注册表上的代理记录,因为代理地址需要先接受提名。在接受提名之前,可以认为提名处于待定状态。一旦代理地址接受了提名,代理记录就会添加到注册表中。
接受提名时,代理地址会为该代理记录设置交付地址。代理地址可以根据需要更新该交付地址。提名人和代理都可以随时删除代理记录和提名。如果不删除,代理将永远继续存在 - 它是永恒的。
注册表是一个智能合约,用于存储所有提名和注册记录。每个的信息如下:
- 提名:
- 提名人的地址
- 拟议代理的地址
- 代理记录:
- 提名人的地址
- 代理的地址
- 代理交付的交付地址
任何地址都可以充当提名人或代理。必须先进行提名,地址才能接受充当代理。
不能向已作为代理或提名人处于活跃状态的地址进行提名,即该地址已处于活跃的代理关系中。
提名和代理记录的信息都以映射的形式保存。对于提名,这是 address => address,用于将提名人映射到代理地址。对于代理记录,映射是从 address => struct,用于将代理地址映射到一个包含提名人和交付地址的结构体。
如下图所示,在地址及其提名人和交付地址之间进行映射是一个简单的过程:
Contract / Dapp Register
| |
|------------- 0x4567..---------------> |
| |
| <-------nominator: 0x1234..---------- |
| delivery: 0x9876.. |
| |
该协议是完全向后兼容的。如果传递给它一个没有活动映射的地址,它将传递回接收到的地址作为提名人和交付地址,从而保留功能,因为该地址代表自己行事。
Contract / Dapp Register
| |
|------------- 0x0222..---------------> |
| |
| <-------nominator: 0x0222..---------- |
| delivery: 0x0222.. |
| |
如果将提名人的地址传递给 EPS 注册表,它将恢复。这至关重要。代理的目的是代理地址代表提名人行事。因此,代理地址可以获得与提名人相同的好处(例如,基于提名人持有的 discord 角色,或者铸造需要持有另一个 NFT 的 NFT)。因此,至关重要的是,活动代理中的提名人也不能进行交互并获得这些好处,否则两个地址代表相同的持有物。提名人当然可以随时删除代理记录并代表自己进行交互,代理地址会立即失去与代理关系相关的任何好处。
Solidity 接口定义
提名存在
function nominationExists(address _nominator) external view returns (bool);
如果指定地址存在提名,则返回 true。
调用者的提名存在
function nominationExistsForCaller() external view returns (bool);
如果 msg.sender 存在提名,则返回 true。
代理记录存在
function proxyRecordExists(address _proxy) external view returns (bool);
如果传递的代理地址存在代理记录,则返回 true。
调用者的代理记录存在
function proxyRecordExistsForCaller() external view returns (bool);
如果 msg.sender 存在代理记录,则返回 true。
提名人记录存在
function nominatorRecordExists(address _nominator) external view returns (bool);
如果传递的提名人地址存在代理记录,则返回 true。
调用者的提名人记录存在
function nominatorRecordExistsForCaller() external view returns (bool);
如果 msg.sender 存在代理记录,则返回 true。
获取代理记录
function getProxyRecord(address _proxy) external view returns (address nominator, address proxy, address delivery);
返回传递的代理地址的提名人、代理和交付地址。
获取调用者的代理记录
function getProxyRecordForCaller() external view returns (address nominator, address proxy, address delivery);
返回 msg.sender 作为代理地址的提名人、代理和交付地址。
获取提名人记录
function getNominatorRecord(address _nominator) external view returns (address nominator, address proxy, address delivery);
返回传递的提名人地址的提名人、代理和交付地址。
获取调用者的提名人记录
function getNominatorRecordForCaller() external view returns (address nominator, address proxy, address delivery);
返回 msg.sender 地址作为提名人的提名人、代理和交付地址。
地址是否处于活动状态
function addressIsActive(address _receivedAddress) external view returns (bool);
如果传递的地址是活动代理记录上的提名人或代理地址,则返回 true。
调用者的地址是否处于活动状态
function addressIsActiveForCaller() external view returns (bool);
如果 msg.sender 是活动代理记录上的提名人或代理地址,则返回 true。
获取提名
function getNomination(address _nominator) external view returns (address proxy);
当传递提名人时,返回提名的代理地址。
获取调用者的提名
function getNominationForCaller() external view returns (address proxy);
如果 msg.sender 是提名人,则返回提名的代理地址
获取地址
function getAddresses(address _receivedAddress) external view returns (address nominator, address delivery, bool isProxied);
返回传递地址的提名人、代理、交付地址和布尔值 isProxied。如果您传递一个不是代理地址的地址,它将返回 address(0) 作为提名人、代理和交付地址,并且 isProxied 为 false。如果您传递一个代理地址,它将返回相关的地址,并且 isProxied 为 true。
获取调用者的地址
function getAddressesForCaller() external view returns (address nominator, address delivery, bool isProxied);
返回 msg.sender 的提名人、代理、交付地址和布尔值 isProxied。如果 msg.sender 不是代理地址,它将返回 address(0) 作为提名人、代理和交付地址,并且 isProxied 为 false。如果 msg.sender 是代理地址,它将返回相关的地址,并且 isProxied 为 true。
获取角色
function getRole(address _roleAddress) external view returns (string memory currentRole);
返回一个字符串值,其中包含传递地址的角色。可能的角色是:
None 该地址未作为记录或提名出现在注册表上。
Nominator - Pending 该地址是提名的提名人,但尚未被提名的代理地址接受。
Nominator - Active 该地址是活动代理记录的提名人(即,提名已被接受)。
Proxy - Active 该地址是活动代理记录上的代理。
获取调用者的角色
function getRoleForCaller() external view returns (string memory currentRole);
返回一个字符串值,其中包含 msg.sender 的角色。可能的角色是:
None msg.sender 未作为记录或提名出现在注册表上。
Nominator - Pending msg.sender 是提名的提名人,但尚未被提名的代理地址接受。
Nominator - Active msg.sender 是活动代理记录的提名人(即,提名已被接受)。
Proxy - Active msg.sender 是活动代理记录上的代理。
进行提名
function makeNomination(address _proxy, uint256 _provider) external payable;
可以传递一个代理地址,以创建 msg.sender 的提名。
Provider 是一个必需的参数。如果您没有 Provider ID,则可以传递 0 作为默认的 EPS provider。有关 EPS Provider Program 的详细信息,请参阅 。
接受提名
function acceptNomination(address _nominator, address _delivery, uint256 _provider) external;
可以传递一个提名人和交付地址,以接受 msg.sender 的提名。请注意,要接受提名,提名需要存在,并且 msg.sender 作为代理。传递给函数的提名人必须与提名上的提名人匹配。
Provider 是一个必需的参数。如果您没有 Provider ID,则可以传递 0 作为默认的 EPS provider。有关 EPS Provider Program 的详细信息,请参阅 。
更新交付记录
function updateDeliveryAddress(address _delivery, uint256 _provider) external;
可以传递一个新的交付地址,其中 msg.sender 是代理记录上的代理。
Provider 是一个必需的参数。如果您没有 Provider ID,则可以传递 0 作为默认的 EPS provider。有关 EPS Provider Program 的详细信息,请参阅 。
提名人删除记录
function deleteRecordByNominator(uint256 _provider) external;
当 msg.sender 是提名人时,可以调用此函数来删除记录和提名。
注意,当记录和提名都存在时,两者都会被删除。如果不存在记录(即提名尚未被代理地址接受),则删除提名。
Provider 是一个必需的参数。如果您没有 Provider ID,则可以传递 0 作为默认的 EPS provider。有关 EPS Provider Program 的详细信息,请参阅 。
代理删除记录
function deleteRecordByProxy(uint256 _provider) external;
当 msg.sender 是代理时,可以调用此函数来删除记录和提名。
理由
本 EIP 的理由是为所有现有和未来的以太坊资产提供一种“受益所有人”(代理)与保管资产的地址不同的方式。使用注册表来实现这一点可确保无需更改现有代币。该注册表存储一个无需信任的证明,由提名人和代理签名,可以作为资产所有权的真实表示。
向后兼容性
EIP 是完全向后兼容的。
测试用例
此提案的完整 SDLC 已完成,并且在主网、ropsten 和 rinkeby 上的 0xfa3D2d059E9c0d348dB185B32581ded8E8243924 上运行。合约源代码已验证,可在 etherscan 上获得。完整的单元测试套件可在 ../assets/eip-4886/
中找到,源代码和示例实现也是如此。
参考实现
请参阅 ../assets/eip-4886/contracts
安全考虑
EIP 的核心意图是通过更好地保护资产并允许更多地使用冷钱包存储来提高用户安全性。
已考虑潜在的负面安全影响,但未设想任何影响。只有在代理地址确认提名后,代理记录才能生效,因此两个地址都提供了签名证明。
从可用性的角度来看,主要风险在于用户指定了不正确的资产交付地址,但需要注意的是,这种准确性负担与当前网络上的负担没有什么不同。
版权
版权及相关权利通过 CC0 放弃。
Citation
Please cite this document as:
Omnus Sunmo (@omnus), "ERC-4886: 代理所有权注册表 [DRAFT]," Ethereum Improvement Proposals, no. 4886, September 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-4886.