Skip to content

Commit 78a9821

Browse files
authored
Mint ERC777 without reception ack (#2552)
1 parent 5dbbda5 commit 78a9821

File tree

4 files changed

+170
-1
lines changed

4 files changed

+170
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* `AccessControl`: Added ERC165 interface detection. ([#2562](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2562))
2222
* `AccessControlEnumerable`: Fixed `renounceRole` not updated underlying set. ([#2572](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2572))
2323
* `ERC1155`: Make `uri` public so overloading function can call it using super. ([#2576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2576))
24+
* `ERC777`: Make reception acquirement optional in `_mint`. ([#2552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2552))
2425

2526
### How to upgrade from 3.x
2627

contracts/mocks/ERC777Mock.sol

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ contract ERC777Mock is Context, ERC777 {
2727
_mint(to, amount, userData, operatorData);
2828
}
2929

30+
function mintInternalExtended (
31+
address to,
32+
uint256 amount,
33+
bytes memory userData,
34+
bytes memory operatorData,
35+
bool requireReceptionAck
36+
) public {
37+
_mint(to, amount, userData, operatorData, requireReceptionAck);
38+
}
39+
3040
function approveInternal(address holder, address spender, uint256 value) public {
3141
_approve(holder, spender, value);
3242
}

contracts/token/ERC777/ERC777.sol

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,37 @@ contract ERC777 is Context, IERC777, IERC20 {
312312
)
313313
internal
314314
virtual
315+
{
316+
_mint(account, amount, userData, operatorData, true);
317+
}
318+
319+
/**
320+
* @dev Creates `amount` tokens and assigns them to `account`, increasing
321+
* the total supply.
322+
*
323+
* If `requireReceptionAck` is set to true, and if a send hook is
324+
* registered for `account`, the corresponding function will be called with
325+
* `operator`, `data` and `operatorData`.
326+
*
327+
* See {IERC777Sender} and {IERC777Recipient}.
328+
*
329+
* Emits {Minted} and {IERC20-Transfer} events.
330+
*
331+
* Requirements
332+
*
333+
* - `account` cannot be the zero address.
334+
* - if `account` is a contract, it must implement the {IERC777Recipient}
335+
* interface.
336+
*/
337+
function _mint(
338+
address account,
339+
uint256 amount,
340+
bytes memory userData,
341+
bytes memory operatorData,
342+
bool requireReceptionAck
343+
)
344+
internal
345+
virtual
315346
{
316347
require(account != address(0), "ERC777: mint to the zero address");
317348

@@ -323,7 +354,7 @@ contract ERC777 is Context, IERC777, IERC20 {
323354
_totalSupply += amount;
324355
_balances[account] += amount;
325356

326-
_callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);
357+
_callTokensReceived(operator, address(0), account, amount, userData, operatorData, requireReceptionAck);
327358

328359
emit Minted(operator, account, amount, userData, operatorData);
329360
emit Transfer(address(0), account, amount);

test/token/ERC777/ERC777.test.js

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,133 @@ contract('ERC777', function (accounts) {
171171
shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData);
172172
});
173173
});
174+
175+
describe('mint (internal extended)', function () {
176+
const amount = new BN('5');
177+
178+
context('to anyone', function () {
179+
beforeEach(async function () {
180+
this.recipient = anyone;
181+
});
182+
183+
context('with default operator', function () {
184+
const operator = defaultOperatorA;
185+
186+
it('without requireReceptionAck', async function () {
187+
await this.token.mintInternalExtended(
188+
this.recipient,
189+
amount,
190+
data,
191+
operatorData,
192+
false,
193+
{ from: operator },
194+
);
195+
});
196+
197+
it('with requireReceptionAck', async function () {
198+
await this.token.mintInternalExtended(
199+
this.recipient,
200+
amount,
201+
data,
202+
operatorData,
203+
true,
204+
{ from: operator },
205+
);
206+
});
207+
});
208+
209+
context('with non operator', function () {
210+
const operator = newOperator;
211+
212+
it('without requireReceptionAck', async function () {
213+
await this.token.mintInternalExtended(
214+
this.recipient,
215+
amount,
216+
data,
217+
operatorData,
218+
false,
219+
{ from: operator },
220+
);
221+
});
222+
223+
it('with requireReceptionAck', async function () {
224+
await this.token.mintInternalExtended(
225+
this.recipient,
226+
amount,
227+
data,
228+
operatorData,
229+
true,
230+
{ from: operator },
231+
);
232+
});
233+
});
234+
});
235+
236+
context('to non ERC777TokensRecipient implementer', function () {
237+
beforeEach(async function () {
238+
this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new();
239+
this.recipient = this.tokensRecipientImplementer.address;
240+
});
241+
242+
context('with default operator', function () {
243+
const operator = defaultOperatorA;
244+
245+
it('without requireReceptionAck', async function () {
246+
await this.token.mintInternalExtended(
247+
this.recipient,
248+
amount,
249+
data,
250+
operatorData,
251+
false,
252+
{ from: operator },
253+
);
254+
});
255+
256+
it('with requireReceptionAck', async function () {
257+
await expectRevert(
258+
this.token.mintInternalExtended(
259+
this.recipient,
260+
amount,
261+
data,
262+
operatorData,
263+
true,
264+
{ from: operator },
265+
),
266+
'ERC777: token recipient contract has no implementer for ERC777TokensRecipient',
267+
);
268+
});
269+
});
270+
271+
context('with non operator', function () {
272+
const operator = newOperator;
273+
274+
it('without requireReceptionAck', async function () {
275+
await this.token.mintInternalExtended(
276+
this.recipient,
277+
amount,
278+
data,
279+
operatorData,
280+
false,
281+
{ from: operator },
282+
);
283+
});
284+
285+
it('with requireReceptionAck', async function () {
286+
await expectRevert(
287+
this.token.mintInternalExtended(
288+
this.recipient,
289+
amount,
290+
data,
291+
operatorData,
292+
true,
293+
{ from: operator },
294+
),
295+
'ERC777: token recipient contract has no implementer for ERC777TokensRecipient',
296+
);
297+
});
298+
});
299+
});
300+
});
174301
});
175302

176303
describe('operator management', function () {

0 commit comments

Comments
 (0)