Skip to content

Commit

Permalink
Mint ERC777 without reception ack (#2552)
Browse files Browse the repository at this point in the history
  • Loading branch information
Amxx committed Mar 8, 2021
1 parent 5dbbda5 commit 78a9821
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* `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))
* `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

Expand Down
10 changes: 10 additions & 0 deletions contracts/mocks/ERC777Mock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ contract ERC777Mock is Context, ERC777 {
_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 {
_approve(holder, spender, value);
}
Expand Down
33 changes: 32 additions & 1 deletion contracts/token/ERC777/ERC777.sol
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,37 @@ contract ERC777 is Context, IERC777, IERC20 {
)
internal
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");

Expand All @@ -323,7 +354,7 @@ contract ERC777 is Context, IERC777, IERC20 {
_totalSupply += 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 Transfer(address(0), account, amount);
Expand Down
127 changes: 127 additions & 0 deletions test/token/ERC777/ERC777.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,133 @@ contract('ERC777', function (accounts) {
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 () {
Expand Down

0 comments on commit 78a9821

Please sign in to comment.