ERC-1363: 可支付 Token
Authors | Vittorio Minacori (@vittominacori) |
---|---|
Created | 2018-08-30 |
Requires | EIP-20, EIP-165 |
简单总结
定义了一个 ERC-20 token 的 token 接口,该接口支持在 transfer
或 transferFrom
之后执行接收者代码,或在 approve
之后执行消费者的代码。
摘要
Token 合约和使用 token 的合约可以实现的标准函数,以使 token 可支付。
transferAndCall
和 transferFromAndCall
将在 ERC1363Receiver
合约上调用 onTransferReceived
。
approveAndCall
将在 ERC1363Spender
合约上调用 onApprovalReceived
。
动机
在 ERC-20 转账或批准(即进行支付)后,无法执行代码,因此要执行操作,需要发送另一笔交易并支付两次 GAS 费用。
本提案旨在使 token 支付更容易,并且无需使用任何其他监听器即可工作。它允许在单个交易中转账或批准后进行回调。
有许多提议的以太坊智能合约的用途可以接受 ERC-20 支付。
例如可以是
- 创建一个 token 可支付的众筹
- 出售 token 服务
- 支付发票
- 制定订阅
由于这些原因,它被命名为 “Payable Token”(可支付 Token)。
无论如何,您可以将其用于特定用途或任何其他需要在收到转账或批准后执行回调的目的。
本提案的灵感来自 ERC-721 的 onERC721Received
和 ERC721TokenReceiver
行为。
规范
实现合约必须实现 ERC-1363 接口以及 ERC-20 和 ERC-165 接口。
pragma solidity ^0.8.0;
interface ERC1363 /* is ERC20, ERC165 */ {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @notice 从 `msg.sender` 向另一个地址转移 token,然后在接收者上调用 `onTransferReceived`
* @param to address 您要转移到的地址
* @param value uint256 要转移的 token 数量
* @return true 除非抛出异常
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @notice 从 `msg.sender` 向另一个地址转移 token,然后在接收者上调用 `onTransferReceived`
* @param to address 您要转移到的地址
* @param value uint256 要转移的 token 数量
* @param data bytes 没有指定格式的附加数据,在调用时发送给 `to`
* @return true 除非抛出异常
*/
function transferAndCall(address to, uint256 value, bytes memory data) external returns (bool);
/**
* @notice 从一个地址向另一个地址转移 token,然后在接收者上调用 `onTransferReceived`
* @param from address 您要从中发送 token 的地址
* @param to address 您要转移到的地址
* @param value uint256 要转移的 token 数量
* @return true 除非抛出异常
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @notice 从一个地址向另一个地址转移 token,然后在接收者上调用 `onTransferReceived`
* @param from address 您要从中发送 token 的地址
* @param to address 您要转移到的地址
* @param value uint256 要转移的 token 数量
* @param data bytes 没有指定格式的附加数据,在调用时发送给 `to`
* @return true 除非抛出异常
*/
function transferFromAndCall(address from, address to, uint256 value, bytes memory data) external returns (bool);
/**
* @notice 批准传递的地址代表 msg.sender 花费指定数量的 token
* 然后在 spender 上调用 `onApprovalReceived`。
* @param spender address 将花费资金的地址
* @param value uint256 要花费的 token 数量
* @return true 除非抛出异常
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @notice 批准传递的地址代表 msg.sender 花费指定数量的 token
* 然后在 spender 上调用 `onApprovalReceived`。
* @param spender address 将花费资金的地址
* @param value uint256 要花费的 token 数量
* @param data bytes 没有指定格式的附加数据,在调用时发送给 `spender`
* @return true 除非抛出异常
*/
function approveAndCall(address spender, uint256 value, bytes memory data) external returns (bool);
}
interface ERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
interface ERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
想要通过 transferAndCall
或 transferFromAndCall
接受 token 支付的合约必须实现以下接口:
/**
* @title ERC1363Receiver interface
* @dev 用于任何想要支持来自 ERC1363 token 合约的 `transferAndCall` 或 `transferFromAndCall` 的合约的接口。
*/
interface ERC1363Receiver {
/*
* Note: the ERC-165 identifier for this interface is 0x88a7ca5c.
* 0x88a7ca5c === bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))
*/
/**
* @notice 处理 ERC1363 token 的接收
* @dev 任何 ERC1363 智能合约在 `transfer` 或 `transferFrom` 之后在接收者上调用此函数。
* 此函数可能会抛出异常以还原并拒绝转移。返回除魔术值以外的其他值必须导致
* 交易被还原。
* 注意:token 合约地址始终是消息发送者。
* @param operator address 调用 `transferAndCall` 或 `transferFromAndCall` 函数的地址
* @param from address token 从中转移的地址
* @param value uint256 转移的 token 数量
* @param data bytes 没有指定格式的附加数据
* @return `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))`
* 除非抛出异常
*/
function onTransferReceived(address operator, address from, uint256 value, bytes memory data) external returns (bytes4);
}
想要通过 approveAndCall
接受 token 支付的合约必须实现以下接口:
/**
* @title ERC1363Spender interface
* @dev 用于任何想要支持来自 ERC1363 token 合约的 `approveAndCall` 的合约的接口。
*/
interface ERC1363Spender {
/*
* Note: the ERC-165 identifier for this interface is 0x7b04a2d0.
* 0x7b04a2d0 === bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))
*/
/**
* @notice 处理 ERC1363 token 的批准
* @dev 任何 ERC1363 智能合约在 `approve` 之后在接收者上调用此函数。
* 此函数可能会抛出异常以还原并拒绝批准。返回除魔术值以外的其他值必须导致
* 交易被还原。
* 注意:token 合约地址始终是消息发送者。
* @param owner address 调用 `approveAndCall` 函数的地址
* @param value uint256 要花费的 token 数量
* @param data bytes 没有指定格式的附加数据
* @return `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))`
* 除非抛出异常
*/
function onApprovalReceived(address owner, uint256 value, bytes memory data) external returns (bytes4);
}
原理
选择使用 transferAndCall
、transferFromAndCall
和 approveAndCall
源于 ERC-20 命名。他们想要强调的是,它们具有与 transfer
、transferFrom
和 approve
相同的行为,并在接收者或消费者上添加了回调。
向后兼容性
该提议也受到了 ERC-223 和 ERC-677 的启发,但它使用了 ERC-721 方法,因此它不会覆盖 ERC-20 的 transfer
和 transferFrom
方法,并定义了要实现的接口 ID,从而保持了 ERC-20 的向后兼容性。
安全考虑
approveAndCall
和 transferFromAndCall
方法可能会受到标准 ERC-20 approve
和 transferFrom
方法的相同问题的影响。
使用 approveAndCall
方法更改 allowance 带来了风险,即某些人可能会因不幸的交易排序而同时使用旧的和新的 allowance。
缓解此竞争条件的一种可能的解决方案是首先将 spender 的 allowance 减少到 0,然后再设置所需的值 (EIP-20#issuecomment-263524729)。
版权
通过 CC0 放弃版权及相关权利。
Citation
Please cite this document as:
Vittorio Minacori (@vittominacori), "ERC-1363: 可支付 Token," Ethereum Improvement Proposals, no. 1363, August 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1363.