ERC-6808: 可替代的密钥绑定代币
一种可替代密钥绑定代币的接口,也称为 FKBT。
Authors | Mihai Onila (@MihaiORO), Nick Zeman (@NickZCZ), Narcis Cotaie (@NarcisCRO) |
---|---|
Created | 2023-03-31 |
Requires | EIP-20 |
摘要
可替代密钥绑定代币 (FKBT/s) 的标准接口,是更通用的密钥绑定代币 (KBT/s) 的子集。
以下内容标准化了智能合约中代币的 API,并为 addBindings 函数提供了基本功能。此函数指定 密钥钱包1,负责执行 安全转移2。在此过程中,FKBT 会被安全地批准,以便用户或链上第三方实体可以花费它们。
FKBT 的前提是通过 allowTransfer 和 allowApproval 函数中的 allow 概念,在可替代资产中直接构建完全可选的安全功能。这些函数由其中一个 密钥钱包1 调用,并_允许_ 持有钱包3 调用 ERC-20 中已经熟悉的 transfer
和 approve
函数。因此,FKBT 的责任被分摊。持有钱包 包含资产,而 密钥钱包 拥有如何花费或批准资产的权限。可以通过简单地从不使用 addBindings 函数来实现传统可替代 ERC-20 的 默认行为4。
我们考虑将 FKBT 用于每个希望为其可替代资产增加额外安全性的个人,以及寄售给第三方钱包/经纪人/银行/保险公司。通过在自托管级别为资产本身提供额外的保护,FKBT 具有抵御攻击/盗窃的能力。
动机
在这个快速发展的技术世界中,人们以不同的速度学习和成熟。全球采用的目标必须考虑到目标人群是所有年龄和背景的人。不幸的是,对于自托管资产来说,最大的优点之一也是其最大的缺点之一。个人对其行为和充分保护其资产负全部责任。如果出现导致资金损失的错误,没有人能够保证其退还。
从 2021 年 1 月到 2022 年 3 月,美国联邦贸易委员会收到了超过 46,0005 份加密货币诈骗报告。这直接影响了加密货币用户,导致消费者净损失超过 10 亿美元6。盗窃和恶意诈骗是任何金融领域的问题,并且通常会导致更严格的监管。然而,政府强制实施的监管与该领域的核心价值观之一背道而驰。已经通过集中式和分散式手段努力提高该领域的安全性。到目前为止,还没有人提供一种解决方案,既保留两者的优势,同时消除其缺点。
我们问了自己与过去许多人相同的问题,“如何保护钱包?”。过了一段时间,意识到应该问的问题是“如何保护资产?”。创建钱包是免费的,资产才具有价值并且值得保护。这个问题促成了 KBT 的开发。一种完全可选的解决方案,可以根据用户的需求进行定制。即使种子短语或私钥被公开,只要激活了安全功能,个人资产仍然受到保护。
FKBT 发现有必要改进广泛使用的可替代 ERC-20 代币标准。可替代资产的安全性是加密货币领域中每个实体都关心的话题,因为它们当前和未来的用例正在不断探索中。FKBT 提供了一种可扩展的去中心化安全解决方案,该解决方案将安全性提升到了钱包安全性之外,专注于代币保持安全的能力。安全性位于区块链本身上,这允许每个可以访问互联网的人安全地保护他们的资产,而无需当前的硬件或集中式解决方案。为了成为一种有希望的替代方案,FKBT 继承了 ERC-20 的所有特征。这样做是为了让 FKBT 可以在每个配置为使用传统可替代代币的 dApp 上使用。
在开发过程中,KBT 探索的潜在优势是促成其创建的主要动机因素;
-
完全去中心化: 安全功能是完全去中心化的,这意味着在激活后,没有任何第三方可以访问用户资金。这样做是为了真正符合自托管资产的前提、责任和价值观。
-
无限可扩展性: 集中式解决方案需要创建帐户,并且其可用性可能会因地点而受到限制。FKBT 不受地区限制或帐户创建的限制。硬件选项等去中心化安全解决方案面临可扩展性问题,需要运输物流、安全运输和供应商。只要他们可以访问互联网,世界上任何地方的任何人都可以使用 FKBT。
-
完全可选的安全性: 安全功能是可选的、可定制的和可移除的。完全由用户决定在使用 FKBT 时他们想要的安全级别。
-
默认功能: 如果用户想将 FKBT 用作传统 ERC-20,则无需激活安全功能。由于代币继承了所有相同的特征,因此它将以传统的可替代 默认行为4 运行。但是,即使在激活安全功能后,用户仍然可以根据其期望的结果自定义各种功能的功能。用户可以通过 dApp 手动或传递一组自定义和/或 默认值7。
-
无与伦比的安全性: 通过调用 addBindings 函数,现在需要 密钥钱包1 才能调用 allowTransfer 或 allowApproval 函数。allowTransfer 函数需要 4 个参数,
_amount
8、_time
9、_address
10 和_allFunds
11,而 allowApproval 函数有 2 个参数,_time
12 和_numberOfTransfers
13。除此之外,FKBT 具有 safeFallback 和 resetBindings 函数。所有这些的组合可以防止并实际上涵盖传统 ERC-20 中存在的每个故障点(如果使用得当)。 -
安全故障保护: 使用 FKBT,用户可以确信他们的代币是安全可靠的,即使 持有钱包3 或其中一个 密钥钱包1 已被盗用。如果所有者怀疑 持有钱包 已被盗用或无法访问,他们可以从其中一个 密钥钱包 调用 safeFallback 函数。这会将资产移动到另一个 密钥钱包,从而防止出现单点故障。如果所有者怀疑其中一个 密钥钱包 已被盗用或无法访问,则所有者可以从
_keyWallet1
14 或_keyWallet2
15 调用 resetBindings 函数。这将重置 FKBT 的安全功能,并允许 持有钱包 再次调用 addBindings 函数。因此,可以添加新的 密钥钱包,并且可以防止出现单点故障。 -
匿名安全性: 通常,集中式解决方案会要求存储个人信息,并且这些信息可能会受到窥探。购买去中心化硬件解决方案容易出现相同的问题,例如,在实体现金提货期间,会记录一个送货地址、付款信息或摄像头。有些人可能会认为这侵犯了他们的隐私和资产匿名性。FKBT 确保用户保密,因为一切都可以在区块链上以化名远程完成。
-
低成本安全性: 使用 FKBT 安全功能的成本与链上费用(给定时间点的当前 GWEI)相关。作为一种独立的解决方案,它们是一种可行的、具有成本效益的安全措施,对大多数人来说都是可行的。
-
环境友好: 由于安全功能已编码到 FKBT 中,因此无需集中式服务器、运输或生产物理对象。因此,通过使用 FKBT 可以最大限度地减少碳足迹,并与以太坊转向 PoS16 网络的变化携手合作。
-
用户体验: 可以通过简单地调用 addBindings 函数来激活安全功能。用户只需要另外两个钱包(将用作
_keyWallet1
14 和_keyWallet2
15),即可获得 FKBT 提供的所有好处。可选的安全功能通过确保为那些决定使用它的人提供一张安全网,从而改善了整体用户体验和以太坊生态系统。那些不使用安全功能的人不会受到任何阻碍。这种安全网可以增加全球采用率,因为人们可以对其资产的安全性保持信心,即使在钱包被盗用的情况下也是如此。
规范
IKBT20
(代币合约)
注意:
- 以下规范使用 Solidity
0.8.0
(或更高版本)的语法 - 调用者必须处理从
returns (bool success)
返回的false
。调用者不得假定永远不会返回false
!
interface IKBT20 {
event AccountSecured(address _account, uint256 _amount);
event AccountResetBinding(address _account);
event SafeFallbackActivated(address _account);
event AccountEnabledTransfer(
address _account,
uint256 _amount,
uint256 _time,
address _to,
bool _allFunds
);
event AccountEnabledApproval(
address _account,
uint256 _time,
uint256 _numberOfTransfers
);
event Ingress(address _account, uint256 _amount);
event Egress(address _account, uint256 _amount);
struct AccountHolderBindings {
address firstWallet;
address secondWallet;
}
struct FirstAccountBindings {
address accountHolderWallet;
address secondWallet;
}
struct SecondAccountBindings {
address accountHolderWallet;
address firstWallet;
}
struct TransferConditions {
uint256 amount;
uint256 time;
address to;
bool allFunds;
}
struct ApprovalConditions {
uint256 time;
uint256 numberOfTransfers;
}
function addBindings(
address _keyWallet1,
address _keyWallet2
) external returns (bool);
function getBindings(
address _account
) external view returns (AccountHolderBindings memory);
function resetBindings() external returns (bool);
function safeFallback() external returns (bool);
function allowTransfer(
uint256 _amount,
uint256 _time,
address _to,
bool _allFunds
) external returns (bool);
function getTransferableFunds(
address _account
) external view returns (TransferConditions memory);
function allowApproval(
uint256 _time,
uint256 _numberOfTransfers
) external returns (bool);
function getApprovalConditions(
address account
) external view returns (ApprovalConditions memory);
function getNumberOfTransfersAllowed(
address _account,
address _spender
) external view returns (uint256);
function isSecureWallet(address _account) external view returns (bool);
}
事件
AccountSecured
事件
当 _account
通过调用 addBindings
函数来保护其帐户时发出。
_amount
是 _account
的当前余额。
event AccountSecured(address _account, uint256 _amount)
AccountResetBinding
事件
当持有者通过调用 resetBindings
函数来重置其 keyWallets
时发出。
event AccountResetBinding(address _account)
SafeFallbackActivated
事件
当持有人通过调用 safeFallback
函数选择将所有资金转移到其中一个 keyWallets
时发出。
event SafeFallbackActivated(address _account)
AccountEnabledTransfer
事件
当 _account
允许为 _time
数量的 block
秒转移 _amount
个代币到 _to
地址(或者如果
_account
允许通过将 _allFunds
设置为 true
来转移所有资金)时,通过调用 allowTransfer
函数发出。
event AccountEnabledTransfer(address _account, uint256 _amount, uint256 _time, address _to, bool _allFunds)
AccountEnabledApproval
事件
当 _account
允许批准时,会发出此事件,对于 _time
数量的 block
秒,并通过调用 allowApproval
函数设置允许的 _numberOfTransfers
数量。
event AccountEnabledApproval(address _account, uint256 _time, uint256 _numberOfTransfers)
Ingress
事件
当 _account
成为持有者时发出。_amount
是 _account
的当前余额。
event Ingress(address _account, uint256 _amount)
Egress
事件
当 _account
转移了他的所有代币并且不再是持有者时发出。_amount
是 _account
的先前余额。
event Egress(address _account, uint256 _amount)
接口函数
必须实现以下详细函数。
addBindings
函数
用另外两个称为 _keyWallet1
和 _keyWallet2
的钱包保护发送者帐户,并且必须触发 AccountSecured
事件。
如果满足以下条件,该函数应 revert
:
- 发送者帐户不是持有者
- 或者发送者已被保护
- 或者 keyWallets 相同
- 或者其中一个 keyWallets 与发送者相同
- 或者一个或两个 keyWallets 都是零地址 (
0x0
) - 或者一个或两个 keyWallets 已经是另一个持有者帐户的 keyWallets
function addBindings (address _keyWallet1, address _keyWallet2) external returns (bool)
getBindings
函数
该函数以 struct
格式返回 _account
的 keyWallets
。
struct AccountHolderBindings {
address firstWallet;
address secondWallet;
}
function getBindings(address _account) external view returns (AccountHolderBindings memory)
resetBindings
函数
注意: 当两个 keyWallets
之一被盗用时,此函数很有用。
从 keyWallet
调用,该函数重置 holder
帐户的 keyWallets
。必须触发 AccountResetBinding
事件。
如果发送者不是 keyWallet
,该函数应 revert
。
function resetBindings() external returns (bool)
safeFallback
函数
注意: 当 holder
帐户被盗用时,此函数很有用。
从 keyWallet
调用,此函数将所有代币从 holder
帐户转移到另一个 keyWallet
,并且必须触发 SafeFallbackActivated
事件。
如果发送者不是 keyWallet
,该函数应 revert
。
function safeFallback() external returns (bool);
allowTransfer
函数
从 keyWallet
调用,此函数在调用 transfer
函数之前调用。
它允许在指定的时间范围内将最大金额转移到特定地址。
如果金额为 0,则金额没有限制。
如果时间为 0,则时间没有限制。
如果 to 地址为零地址,则对 to 地址没有限制。
或者,如果 _allFunds
为 true
,则无论其他参数如何,它都允许转移所有资金,无论何时转移给任何人。
该函数必须触发 AccountEnabledTransfer
事件。
如果发送者不是 keyWallet
或 _amount
大于 holder
帐户余额,该函数应 revert
。
function allowTransfer(uint256 _amount, uint256 _time, address _to, bool _allFunds) external returns (bool);
getTransferableFunds
函数
该函数以 struct
格式返回 _account
的转移条件。
struct TransferConditions {
uint256 amount;
uint256 time;
address to;
bool allFunds;
}
function getTransferableFunds(address _account) external view returns (TransferConditions memory);
allowApproval
函数
从 keyWallet
调用,此函数在调用 approve
、increaseAllowance
或 decreaseAllowance
函数之一之前调用。
它允许 holder
在特定的 _time
量内执行 approve
、increaseAllowance
或 decreaseAllowance
,并限制spender可以通过 _numberOfTransfers
进行的转移数量(0 - 允许的金额限制内的无限数量的转移)。
函数必须触发 AccountEnabledApproval
事件。
如果发送者不是 keyWallet
,该函数应 revert
。
function allowApproval(uint256 _time, uint256 _numberOfTransfers) external returns (bool)
getApprovalConditions
函数
该函数以结构格式返回批准条件。其中 time 是 block.timestamp
,直到可以调用 approve
、increaseAllowance
或 decreaseAllowance
函数,并且 numberOfTransfers
是允许消费者的转移次数。
struct ApprovalConditions {
uint256 time;
uint256 numberOfTransfers;
}
function getApprovalConditions(address _account) external view returns (ApprovalConditions memory);
transfer
函数
该函数将 _amount
个代币转移到地址 _to
。
该函数必须触发 Transfer
事件。
如果发送者的帐户余额没有足够的代币可供花费,或者如果发送者是安全帐户并且尚未通过 allowTransfer
函数允许转移资金,则该函数应 revert
。
注意: 0
值的转移必须被视为正常转移并触发 Transfer
事件。
function transfer(address _to, uint256 _amount) external returns (bool)
approve
函数
该函数允许 _spender
从 holder
帐户多次转移,最多可达 _value
金额。
该函数还限制 _spender
为该 holder
帐户的 ApprovalConditions
中设置的特定转移次数。如果值为 0
,则 _spender
可以多次转移,最多可达 _value
金额。
该函数必须触发 Approval
事件。
如果再次调用此函数,它将使用 _value
覆盖当前 allowance,并且还会覆盖 allowApproval
函数中设置的 _numberOfTransfers
允许的转移次数。
如果满足以下条件,该函数应 revert
:
- 发送者帐户已受到保护并且未调用
allowApproval
函数 - 或者,如果在
allowApproval
函数中设置的_time
已过。
function approve(address _spender, uint256 _amount) external returns (bool)
increaseAllowance
函数
该函数增加授予 _spender
从您的帐户中提款的 allowance。
该函数发出一个 Approval
事件,指示更新后的 allowance。
如果满足以下条件,该函数应 revert
:
- 发送者帐户已受到保护并且未调用
allowApproval
函数 - 或者,如果
_spender
是零地址 (0x0
) - 或者,如果在
allowApproval
函数中设置的_time
已过。
function increaseAllowance(address _spender, uint256 _addedValue) external returns (bool)
decreaseAllowance
函数
该函数减少授予 _spender
从您的帐户中提款的 allowance。
该函数发出一个 Approval
事件,指示更新后的 allowance。
如果满足以下条件,该函数应 revert
:
- 发送者帐户已受到保护并且未调用
allowApproval
函数 - 或者,如果
_spender
是零地址 (0x0
) - 或者,如果在
allowApproval
函数中设置的_time
已过。 - 或者,如果
_subtractedValue
大于当前 allowance
function decreaseAllowance(address _spender, uint256 _subtractedValue) external returns (bool)
transferFrom
函数
该函数将 _amount
个代币从地址 _from
转移到地址 _to
。
该函数必须触发 Transfer
事件。
transferFrom
方法用于提款工作流程,允许合约代表您转移代币。
除非 _from
帐户故意授权发送者,否则该函数应 revert
。
每次 spender 调用该函数时,合约都会减去并检查允许的转移次数是否已达到 0,
当发生这种情况时,将使用 0 金额的批准来撤销批准。
注意: 0 值的转移必须被视为正常转移并触发 Transfer
事件。
function transferFrom(address _from, address _to, uint256 _amount) external returns (bool)
理由
在 FKBT 开发期间做出的个别技术决策的意图侧重于保持与 ERC-20 的一致性和向后兼容性,同时为用户提供自托管的安全功能。重要的是,FKBT 要继承 ERC-20 的所有特征,以符合在 dApp 中使用可替代代币的要求。通过这样做,它允许进行完美的向后兼容,并让用户选择是否希望他们的 FKBT 以 默认行为4 运行。我们希望确保 FKBT 的大规模实施和采用能够立即发生,而无需更大的集体适应并对已经蓬勃发展的去中心化生态系统进行更改。
对于开发人员和用户而言,allowTransfer 和 allowApproval 函数在成功时都返回布尔值,并在失败时恢复。这样做是有目的的,以保持与已经熟悉的 ERC-20 的一致性。与自托管安全功能相关的其他技术决策将在 安全注意事项 部分中分解和定位。
向后兼容性
KBT 旨在与现有的代币标准和钱包向后兼容。现有的代币和钱包将继续正常运行,并且不会受到 FKBT 实施的影响。
测试用例
平均 Gas 用量 (GWEI):
addBindings
- 154,991resetBindings
- 30,534safeFallback
- 51,013allowTransfer
- 49,887allowApproval
- 44,971
参考实现
该实现在 assets 目录中。还有一个包含合约交互的 图表。
安全注意事项
在设计的每一步中,FKBT 都考虑了安全性。以下是在开发过程中经过严格讨论和思考的一些设计决策。
密钥钱包1:在为 FKBT 调用 addBindings 函数时,用户必须输入 2 个钱包,这些钱包将充当 _keyWallet1
14 和 _keyWallet2
15。它们被同时添加,以减少用户费用、最大限度地减少人为错误的可能性并防止出现陷阱情况。如果用户能够添加多个钱包,不仅会导致额外的费用和可避免的混乱,还会导致潜在的灾难性 safeFallback 情况发生。因此,当安全功能被激活时,所有 KBT 都在 3 钱包系统下工作。
通常,如果钱包被盗用,其中的可替代资产就会面临风险。借助 FKBT,可以从 密钥钱包1 中调用两个不同的函数,具体取决于哪个钱包已被盗用。
场景:持有钱包3 已被盗用,请调用 safeFallback。
safeFallback:创建此函数是为了防止所有者认为 持有钱包3 已被盗用的情况。如果所有者无法访问 持有钱包,也可以使用它。在这种情况下,用户有能力从其中一个 密钥钱包1 调用 safeFallback。然后,FKBT 将从 持有钱包 重定向到另一个 密钥钱包。
通过重定向 FKBT,可以防止出现单点故障。如果攻击者要调用 safeFallback 并且 FKBT 重定向到调用该函数的 密钥钱包1,他们将可以访问所有 FKBT。
场景:密钥钱包1 已被盗用,请调用 resetBindings。
resetBindings:创建此函数是为了防止所有者认为 _keyWallet1
14 或 _keyWallet2
15 已被盗用的情况。如果所有者无法访问其中一个 密钥钱包1,也可以使用它。在这种情况下,用户有能力调用 resetBindings,删除绑定的 密钥钱包 并重置安全功能。现在,FKBT 将作为传统的 ERC-20 运行,直到再次调用 addBindings 函数并添加一组新的 密钥钱包。
之所以需要 _keyWallet1
14 或 _keyWallet2
15 调用 resetBindings 函数,是因为 持有钱包3 有能力调用 resetBindings 可能会导致 FKBT 的立即损失。攻击者只需要访问 持有钱包 并调用 resetBindings 即可。
如果在 3 个钱包中有 2 个被盗用,如果攻击是恶意的,FKBT 的所有者也无能为力。但是,与其他当前标准不同,通过允许 1 个钱包被盗用,可以使用 FKBT 标准构建的可替代代币的持有者将获得第二次机会。
allowTransfer 函数是为了保证 安全转移2 的安全,但也可以由 dApp 设置 默认值7 以模拟传统 ERC-20 的 默认行为3。它使用户能够高度指定他们即将进行的转移类型,同时允许用户将所有 FKBT 解锁给任何人,不受时间限制。所需的安全完全取决于用户。
此函数需要填写 4 个参数,并且这些参数的不同组合会导致不同的安全级别;
参数 1 _amount
8:这是将在转移中花费的 FKBT 的数量。
参数 2 _time
9:从当前区块时间戳开始可以转移 FKBT 的区块数。
参数 3 _address
10:FKBT 将被发送到的目的地。
参数 4 _allFunds
11:这是一个布尔值。如果为 false,则 transfer
函数会考虑参数 1、2 和 3。如果该值为 true,则 transfer
函数将恢复为 默认行为4,与传统的 ERC-20 相同。
allowTransfer 函数需要 _keyWallet1
14 或 _keyWallet2
15,并使 持有钱包3 能够在先前指定的参数内执行 transfer
。添加这些参数是为了通过限制 持有钱包 来提供额外的安全性,以防它在用户不知情的情况下被盗用。
allowApproval 函数在允许链上第三方代表您使用您的 FKBT 时提供额外的安全性。当用户遇到常见的恶意攻击(例如,耗尽 dApp)时,这尤其有用。
此函数需要填写 2 个参数,并且这些参数的不同组合会导致不同的安全级别;
参数 1 _time
12:第三方服务可以进行批准的区块数,从当前区块时间戳开始。
参数 2 _numberOfTransfers_
13:第三方服务可以代表用户进行的交易次数。
allowApproval 函数需要 _keyWallet1
14 或 _keyWallet2
15,并使 持有钱包3 能够通过使用 approve
函数来允许第三方服务。添加这些参数是为了在授予使用用户资产的第三方权限时提供额外的安全性。参数 1 _time
12 限制了 持有钱包 何时可以 approve
第三方服务。参数 2 _numberOfTransfers
13 限制了在撤销批准之前,批准的第三方服务可以代表用户进行的交易次数。
版权
版权和相关权利通过 CC0 放弃。
-
密钥钱包 指的是可以调用
safeFallback
、resetBindings
、allowTransfer
和allowApproval
函数的_keyWallet1
或_keyWallet2
。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 -
美国联邦贸易委员会从 2021 年 1 月到 2022 年 3 月收到的加密货币诈骗报告的数量。 ↩
-
根据美国联邦贸易委员会的数据,从 2021 年 1 月到 2022 年 3 月,通过加密货币诈骗盗取的金额。 ↩
-
_keyWallet1
是在调用addBindings
函数时设置的 2 个 密钥钱包 之一。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 -
_keyWallet2
是在调用addBindings
函数时设置的 2 个 密钥钱包 之一。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 -
PoS 协议,权益证明协议,是一种用于处理交易并在区块链中创建新区块的加密货币共识机制。 ↩
Citation
Please cite this document as:
Mihai Onila (@MihaiORO), Nick Zeman (@NickZCZ), Narcis Cotaie (@NarcisCRO), "ERC-6808: 可替代的密钥绑定代币," Ethereum Improvement Proposals, no. 6808, March 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6808.