Make ERC777 operator the caller (#2134)
* Make the sender the operator * Make hook methods private * Add changelog entry
This commit is contained in:
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)) {
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user