Unverified Commit c75b0169 by Nicolás Venturo Committed by GitHub

Add missing requirements to ERC777 (#2212)

* Restore _approve check for zero sender

* Add non-zero operator check to _send
parent 58a33682
...@@ -23,4 +23,8 @@ contract ERC777Mock is Context, ERC777 { ...@@ -23,4 +23,8 @@ contract ERC777Mock is Context, ERC777 {
) public { ) public {
_mint(operator, to, amount, userData, operatorData); _mint(operator, to, amount, userData, operatorData);
} }
function approveInternal(address holder, address spender, uint256 value) public {
_approve(holder, spender, value);
}
} }
...@@ -352,6 +352,7 @@ contract ERC777 is Context, IERC777, IERC20 { ...@@ -352,6 +352,7 @@ contract ERC777 is Context, IERC777, IERC20 {
) )
internal internal
{ {
require(operator != address(0), "ERC777: operator is the zero address");
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");
...@@ -408,10 +409,13 @@ contract ERC777 is Context, IERC777, IERC20 { ...@@ -408,10 +409,13 @@ contract ERC777 is Context, IERC777, IERC20 {
emit Transfer(from, to, amount); emit Transfer(from, to, amount);
} }
/**
* @dev See {ERC20-_approve}.
*
* Note that accounts cannot have allowance issued by their operators.
*/
function _approve(address holder, address spender, uint256 value) internal { function _approve(address holder, address spender, uint256 value) internal {
// TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is require(holder != address(0), "ERC777: approve from the zero address");
// currently unnecessary.
//require(holder != address(0), "ERC777: approve from the zero address");
require(spender != address(0), "ERC777: approve to the zero address"); require(spender != address(0), "ERC777: approve to the zero address");
_allowances[holder][spender] = value; _allowances[holder][spender] = value;
......
const { accounts, contract, web3 } = require('@openzeppelin/test-environment'); const { accounts, contract, web3 } = require('@openzeppelin/test-environment');
const { BN, expectEvent, expectRevert, singletons } = require('@openzeppelin/test-helpers'); const { BN, constants, expectEvent, expectRevert, singletons } = require('@openzeppelin/test-helpers');
const { ZERO_ADDRESS } = constants;
const { expect } = require('chai'); const { expect } = require('chai');
...@@ -15,6 +16,7 @@ const { ...@@ -15,6 +16,7 @@ const {
const { const {
shouldBehaveLikeERC20, shouldBehaveLikeERC20,
shouldBehaveLikeERC20Approve,
} = require('../ERC20/ERC20.behavior'); } = require('../ERC20/ERC20.behavior');
const ERC777 = contract.fromArtifact('ERC777Mock'); const ERC777 = contract.fromArtifact('ERC777Mock');
...@@ -40,8 +42,24 @@ describe('ERC777', function () { ...@@ -40,8 +42,24 @@ describe('ERC777', function () {
this.token = await ERC777.new(holder, initialSupply, name, symbol, defaultOperators); this.token = await ERC777.new(holder, initialSupply, name, symbol, defaultOperators);
}); });
describe('as an ERC20 token', function () {
shouldBehaveLikeERC20('ERC777', initialSupply, holder, anyone, defaultOperatorA); shouldBehaveLikeERC20('ERC777', initialSupply, holder, anyone, defaultOperatorA);
describe('_approve', function () {
shouldBehaveLikeERC20Approve('ERC777', holder, anyone, initialSupply, function (owner, spender, amount) {
return this.token.approveInternal(owner, spender, amount);
});
describe('when the owner is the zero address', function () {
it('reverts', async function () {
await expectRevert(this.token.approveInternal(ZERO_ADDRESS, anyone, initialSupply),
'ERC777: approve from the zero address'
);
});
});
});
});
it.skip('does not emit AuthorizedOperator events for default operators', async function () { it.skip('does not emit AuthorizedOperator events for default operators', async function () {
expectEvent.not.inConstructor(this.token, 'AuthorizedOperator'); // This helper needs to be implemented expectEvent.not.inConstructor(this.token, 'AuthorizedOperator'); // This helper needs to be implemented
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment