Mint ERC777 without reception ack (#2552)

pull/2533/head
Hadrien Croubois 4 years ago committed by GitHub
parent 5dbbda5435
commit 78a9821129
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 10
      contracts/mocks/ERC777Mock.sol
  3. 33
      contracts/token/ERC777/ERC777.sol
  4. 127
      test/token/ERC777/ERC777.test.js

@ -21,6 +21,7 @@
* `AccessControl`: Added ERC165 interface detection. ([#2562](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2562)) * `AccessControl`: Added ERC165 interface detection. ([#2562](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2562))
* `AccessControlEnumerable`: Fixed `renounceRole` not updated underlying set. ([#2572](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2572)) * `AccessControlEnumerable`: Fixed `renounceRole` not updated underlying set. ([#2572](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2572))
* `ERC1155`: Make `uri` public so overloading function can call it using super. ([#2576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2576)) * `ERC1155`: Make `uri` public so overloading function can call it using super. ([#2576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2576))
* `ERC777`: Make reception acquirement optional in `_mint`. ([#2552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2552))
### How to upgrade from 3.x ### How to upgrade from 3.x

@ -27,6 +27,16 @@ contract ERC777Mock is Context, ERC777 {
_mint(to, amount, userData, operatorData); _mint(to, amount, userData, operatorData);
} }
function mintInternalExtended (
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData,
bool requireReceptionAck
) public {
_mint(to, amount, userData, operatorData, requireReceptionAck);
}
function approveInternal(address holder, address spender, uint256 value) public { function approveInternal(address holder, address spender, uint256 value) public {
_approve(holder, spender, value); _approve(holder, spender, value);
} }

@ -312,6 +312,37 @@ contract ERC777 is Context, IERC777, IERC20 {
) )
internal internal
virtual virtual
{
_mint(account, amount, userData, operatorData, true);
}
/**
* @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* If `requireReceptionAck` is set to true, and if a send hook is
* registered for `account`, the corresponding function will be called with
* `operator`, `data` and `operatorData`.
*
* See {IERC777Sender} and {IERC777Recipient}.
*
* Emits {Minted} and {IERC20-Transfer} events.
*
* Requirements
*
* - `account` cannot be the zero address.
* - if `account` is a contract, it must implement the {IERC777Recipient}
* interface.
*/
function _mint(
address account,
uint256 amount,
bytes memory userData,
bytes memory operatorData,
bool requireReceptionAck
)
internal
virtual
{ {
require(account != address(0), "ERC777: mint to the zero address"); require(account != address(0), "ERC777: mint to the zero address");
@ -323,7 +354,7 @@ contract ERC777 is Context, IERC777, IERC20 {
_totalSupply += amount; _totalSupply += amount;
_balances[account] += amount; _balances[account] += amount;
_callTokensReceived(operator, address(0), account, amount, userData, operatorData, true); _callTokensReceived(operator, address(0), account, amount, userData, operatorData, requireReceptionAck);
emit Minted(operator, account, amount, userData, operatorData); emit Minted(operator, account, amount, userData, operatorData);
emit Transfer(address(0), account, amount); emit Transfer(address(0), account, amount);

@ -171,6 +171,133 @@ contract('ERC777', function (accounts) {
shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData); shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData);
}); });
}); });
describe('mint (internal extended)', function () {
const amount = new BN('5');
context('to anyone', function () {
beforeEach(async function () {
this.recipient = anyone;
});
context('with default operator', function () {
const operator = defaultOperatorA;
it('without requireReceptionAck', async function () {
await this.token.mintInternalExtended(
this.recipient,
amount,
data,
operatorData,
false,
{ from: operator },
);
});
it('with requireReceptionAck', async function () {
await this.token.mintInternalExtended(
this.recipient,
amount,
data,
operatorData,
true,
{ from: operator },
);
});
});
context('with non operator', function () {
const operator = newOperator;
it('without requireReceptionAck', async function () {
await this.token.mintInternalExtended(
this.recipient,
amount,
data,
operatorData,
false,
{ from: operator },
);
});
it('with requireReceptionAck', async function () {
await this.token.mintInternalExtended(
this.recipient,
amount,
data,
operatorData,
true,
{ from: operator },
);
});
});
});
context('to non ERC777TokensRecipient implementer', function () {
beforeEach(async function () {
this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new();
this.recipient = this.tokensRecipientImplementer.address;
});
context('with default operator', function () {
const operator = defaultOperatorA;
it('without requireReceptionAck', async function () {
await this.token.mintInternalExtended(
this.recipient,
amount,
data,
operatorData,
false,
{ from: operator },
);
});
it('with requireReceptionAck', async function () {
await expectRevert(
this.token.mintInternalExtended(
this.recipient,
amount,
data,
operatorData,
true,
{ from: operator },
),
'ERC777: token recipient contract has no implementer for ERC777TokensRecipient',
);
});
});
context('with non operator', function () {
const operator = newOperator;
it('without requireReceptionAck', async function () {
await this.token.mintInternalExtended(
this.recipient,
amount,
data,
operatorData,
false,
{ from: operator },
);
});
it('with requireReceptionAck', async function () {
await expectRevert(
this.token.mintInternalExtended(
this.recipient,
amount,
data,
operatorData,
true,
{ from: operator },
),
'ERC777: token recipient contract has no implementer for ERC777TokensRecipient',
);
});
});
});
});
}); });
describe('operator management', function () { describe('operator management', function () {

Loading…
Cancel
Save