Make ERC777 operator the caller (#2134)

* Make the sender the operator

* Make hook methods private

* Add changelog entry
This commit is contained in:
Nicolás Venturo
2020-03-16 19:49:17 -03:00
committed by GitHub
parent 90058040f0
commit e7b22483af
5 changed files with 23 additions and 19 deletions

View File

@ -22,6 +22,8 @@
* `Escrow`, `ConditionalEscrow`, `RefundEscrow`: these now use `Ownable` instead of `Secondary`, their external API changed accordingly. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) * `Escrow`, `ConditionalEscrow`, `RefundEscrow`: these now use `Ownable` instead of `Secondary`, their external API changed accordingly. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120))
* `ERC20`: removed `_burnFrom`. ([#2119](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2119)) * `ERC20`: removed `_burnFrom`. ([#2119](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2119))
* `Address`: removed `toPayable`, use `payable(address)` instead. ([#2133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2133)) * `Address`: removed `toPayable`, use `payable(address)` instead. ([#2133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2133))
* `ERC777`: `_send`, `_mint` and `_burn` now use the caller as the operator. ([#2134](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2134))
* `ERC777`: removed `_callsTokensToSend` and `_callTokensReceived`. ([#2134](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2134))
## 2.5.0 (2020-02-04) ## 2.5.0 (2020-02-04)

View File

@ -11,16 +11,15 @@ contract ERC777Mock is Context, ERC777 {
string memory symbol, string memory symbol,
address[] memory defaultOperators address[] memory defaultOperators
) public ERC777(name, symbol, defaultOperators) { ) public ERC777(name, symbol, defaultOperators) {
_mint(_msgSender(), initialHolder, initialBalance, "", ""); _mint(initialHolder, initialBalance, "", "");
} }
function mintInternal ( function mintInternal (
address operator,
address to, address to,
uint256 amount, uint256 amount,
bytes memory userData, bytes memory userData,
bytes memory operatorData bytes memory operatorData
) public { ) public {
_mint(operator, to, amount, userData, operatorData); _mint(to, amount, userData, operatorData);
} }
} }

View File

@ -135,7 +135,7 @@ contract ERC777 is Context, IERC777, IERC20 {
* Also emits a {IERC20-Transfer} event for ERC20 compatibility. * Also emits a {IERC20-Transfer} event for ERC20 compatibility.
*/ */
function send(address recipient, uint256 amount, bytes memory data) public override { function send(address recipient, uint256 amount, bytes memory data) public override {
_send(_msgSender(), _msgSender(), recipient, amount, data, "", true); _send(_msgSender(), recipient, amount, data, "", true);
} }
/** /**
@ -166,7 +166,7 @@ contract ERC777 is Context, IERC777, IERC20 {
* Also emits a {IERC20-Transfer} event for ERC20 compatibility. * Also emits a {IERC20-Transfer} event for ERC20 compatibility.
*/ */
function burn(uint256 amount, bytes memory data) public override { function burn(uint256 amount, bytes memory data) public override {
_burn(_msgSender(), _msgSender(), amount, data, ""); _burn(_msgSender(), amount, data, "");
} }
/** /**
@ -233,7 +233,7 @@ contract ERC777 is Context, IERC777, IERC20 {
public override public override
{ {
require(isOperatorFor(_msgSender(), sender), "ERC777: caller is not an operator for holder"); require(isOperatorFor(_msgSender(), sender), "ERC777: caller is not an operator for holder");
_send(_msgSender(), sender, recipient, amount, data, operatorData, true); _send(sender, recipient, amount, data, operatorData, true);
} }
/** /**
@ -243,7 +243,7 @@ contract ERC777 is Context, IERC777, IERC20 {
*/ */
function operatorBurn(address account, uint256 amount, bytes memory data, bytes memory operatorData) public override { function operatorBurn(address account, uint256 amount, bytes memory data, bytes memory operatorData) public override {
require(isOperatorFor(_msgSender(), account), "ERC777: caller is not an operator for holder"); require(isOperatorFor(_msgSender(), account), "ERC777: caller is not an operator for holder");
_burn(_msgSender(), account, amount, data, operatorData); _burn(account, amount, data, operatorData);
} }
/** /**
@ -311,7 +311,6 @@ contract ERC777 is Context, IERC777, IERC20 {
* interface. * interface.
*/ */
function _mint( function _mint(
address operator,
address account, address account,
uint256 amount, uint256 amount,
bytes memory userData, bytes memory userData,
@ -321,6 +320,8 @@ contract ERC777 is Context, IERC777, IERC20 {
{ {
require(account != address(0), "ERC777: mint to the zero address"); require(account != address(0), "ERC777: mint to the zero address");
address operator = _msgSender();
// Update state variables // Update state variables
_totalSupply = _totalSupply.add(amount); _totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount); _balances[account] = _balances[account].add(amount);
@ -333,7 +334,6 @@ contract ERC777 is Context, IERC777, IERC20 {
/** /**
* @dev Send tokens * @dev Send tokens
* @param operator address operator requesting the transfer
* @param from address token holder address * @param from address token holder address
* @param to address recipient address * @param to address recipient address
* @param amount uint256 amount of tokens to transfer * @param amount uint256 amount of tokens to transfer
@ -342,7 +342,6 @@ contract ERC777 is Context, IERC777, IERC20 {
* @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient
*/ */
function _send( function _send(
address operator,
address from, address from,
address to, address to,
uint256 amount, uint256 amount,
@ -355,6 +354,8 @@ contract ERC777 is Context, IERC777, IERC20 {
require(from != address(0), "ERC777: send from the zero address"); require(from != address(0), "ERC777: send from the zero address");
require(to != address(0), "ERC777: send to the zero address"); require(to != address(0), "ERC777: send to the zero address");
address operator = _msgSender();
_callTokensToSend(operator, from, to, amount, userData, operatorData); _callTokensToSend(operator, from, to, amount, userData, operatorData);
_move(operator, from, to, amount, userData, operatorData); _move(operator, from, to, amount, userData, operatorData);
@ -364,14 +365,12 @@ contract ERC777 is Context, IERC777, IERC20 {
/** /**
* @dev Burn tokens * @dev Burn tokens
* @param operator address operator requesting the operation
* @param from address token holder address * @param from address token holder address
* @param amount uint256 amount of tokens to burn * @param amount uint256 amount of tokens to burn
* @param data bytes extra information provided by the token holder * @param data bytes extra information provided by the token holder
* @param operatorData bytes extra information provided by the operator (if any) * @param operatorData bytes extra information provided by the operator (if any)
*/ */
function _burn( function _burn(
address operator,
address from, address from,
uint256 amount, uint256 amount,
bytes memory data, bytes memory data,
@ -381,6 +380,8 @@ contract ERC777 is Context, IERC777, IERC20 {
{ {
require(from != address(0), "ERC777: burn from the zero address"); require(from != address(0), "ERC777: burn from the zero address");
address operator = _msgSender();
_callTokensToSend(operator, from, address(0), amount, data, operatorData); _callTokensToSend(operator, from, address(0), amount, data, operatorData);
// Update state variables // Update state variables
@ -437,7 +438,7 @@ contract ERC777 is Context, IERC777, IERC20 {
bytes memory userData, bytes memory userData,
bytes memory operatorData bytes memory operatorData
) )
internal private
{ {
address implementer = ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH); address implementer = ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH);
if (implementer != address(0)) { if (implementer != address(0)) {
@ -465,7 +466,7 @@ contract ERC777 is Context, IERC777, IERC20 {
bytes memory operatorData, bytes memory operatorData,
bool requireReceptionAck bool requireReceptionAck
) )
internal private
{ {
address implementer = ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH); address implementer = ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH);
if (implementer != address(0)) { if (implementer != address(0)) {

View File

@ -281,7 +281,9 @@ function shouldBehaveLikeERC777InternalMint (recipient, operator, amount, data,
shouldInternalMintTokens(operator, recipient, amount, data, operatorData); shouldInternalMintTokens(operator, recipient, amount, data, operatorData);
it('reverts when minting tokens for the zero address', async function () { it('reverts when minting tokens for the zero address', async function () {
await expectRevert.unspecified(this.token.mintInternal(operator, ZERO_ADDRESS, amount, data, operatorData)); await expectRevert.unspecified(
this.token.mintInternal(ZERO_ADDRESS, amount, data, operatorData, { from: operator })
);
}); });
} }
@ -290,7 +292,7 @@ function shouldInternalMintTokens (operator, to, amount, data, operatorData) {
const initialTotalSupply = await this.token.totalSupply(); const initialTotalSupply = await this.token.totalSupply();
const initialToBalance = await this.token.balanceOf(to); const initialToBalance = await this.token.balanceOf(to);
const { logs } = await this.token.mintInternal(operator, to, amount, data, operatorData); const { logs } = await this.token.mintInternal(to, amount, data, operatorData, { from: operator });
expectEvent.inLogs(logs, 'Minted', { expectEvent.inLogs(logs, 'Minted', {
operator, operator,
@ -332,7 +334,7 @@ function shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook (operator, am
it('mint (internal) reverts', async function () { it('mint (internal) reverts', async function () {
await expectRevert.unspecified( await expectRevert.unspecified(
this.token.mintInternal(operator, this.recipient, amount, data, operatorData) this.token.mintInternal(this.recipient, amount, data, operatorData, { from: operator })
); );
}); });
}); });
@ -387,7 +389,7 @@ function shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook (operator, am
it('TokensRecipient receives mint (internal) data and is called after state mutation', async function () { it('TokensRecipient receives mint (internal) data and is called after state mutation', async function () {
const { tx } = await this.token.mintInternal( const { tx } = await this.token.mintInternal(
operator, this.recipient, amount, data, operatorData, this.recipient, amount, data, operatorData, { from: operator }
); );
const postRecipientBalance = await this.token.balanceOf(this.recipient); const postRecipientBalance = await this.token.balanceOf(this.recipient);

View File

@ -300,7 +300,7 @@ describe('ERC777', function () {
it('mint (internal) reverts', async function () { it('mint (internal) reverts', async function () {
await expectRevert( await expectRevert(
this.token.mintInternal(operator, this.recipient, amount, data, operatorData), this.token.mintInternal(this.recipient, amount, data, operatorData, { from: operator }),
'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient',
); );
}); });