Skip to content

Commit 3dfc0a4

Browse files
AmxxCryptoV8frangio
authored
ERC1155 after token transfer hook (OpenZeppelin#3166)
* add Hooks _afterTokenTransfer * avoid duplicate call to _asSingleton * add changelog entry * update changelog link to PR * Update CHANGELOG.md Co-authored-by: Francisco Giordano <[email protected]> Co-authored-by: CryptoV8 <[email protected]> Co-authored-by: Francisco Giordano <[email protected]>
1 parent be3c5ca commit 3dfc0a4

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* `AccessControl`: add a virtual `_checkRole(bytes32)` function that can be overriden to alter the `onlyRole` modifier behavior. ([#3137](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3137))
66
* `EnumerableMap`: add new `AddressToUintMap` map type. ([#3150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3150))
7+
* `ERC1155`: Add a `_afterTokenTransfer` hook for improved extensibility. ([#3166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3166))
78

89
## 4.5.0 (2022-02-09)
910

contracts/token/ERC1155/ERC1155.sol

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
167167
require(to != address(0), "ERC1155: transfer to the zero address");
168168

169169
address operator = _msgSender();
170+
uint256[] memory ids = _asSingletonArray(id);
171+
uint256[] memory amounts = _asSingletonArray(amount);
170172

171-
_beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data);
173+
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
172174

173175
uint256 fromBalance = _balances[id][from];
174176
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
@@ -180,6 +182,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
180182
emit TransferSingle(operator, from, to, id, amount);
181183

182184
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
185+
186+
_afterTokenTransfer(operator, from, to, ids, amounts, data);
183187
}
184188

185189
/**
@@ -221,6 +225,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
221225
emit TransferBatch(operator, from, to, ids, amounts);
222226

223227
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
228+
229+
_afterTokenTransfer(operator, from, to, ids, amounts, data);
224230
}
225231

226232
/**
@@ -266,13 +272,17 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
266272
require(to != address(0), "ERC1155: mint to the zero address");
267273

268274
address operator = _msgSender();
275+
uint256[] memory ids = _asSingletonArray(id);
276+
uint256[] memory amounts = _asSingletonArray(amount);
269277

270-
_beforeTokenTransfer(operator, address(0), to, _asSingletonArray(id), _asSingletonArray(amount), data);
278+
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
271279

272280
_balances[id][to] += amount;
273281
emit TransferSingle(operator, address(0), to, id, amount);
274282

275283
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
284+
285+
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
276286
}
277287

278288
/**
@@ -304,6 +314,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
304314
emit TransferBatch(operator, address(0), to, ids, amounts);
305315

306316
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
317+
318+
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
307319
}
308320

309321
/**
@@ -322,8 +334,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
322334
require(from != address(0), "ERC1155: burn from the zero address");
323335

324336
address operator = _msgSender();
337+
uint256[] memory ids = _asSingletonArray(id);
338+
uint256[] memory amounts = _asSingletonArray(amount);
325339

326-
_beforeTokenTransfer(operator, from, address(0), _asSingletonArray(id), _asSingletonArray(amount), "");
340+
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
327341

328342
uint256 fromBalance = _balances[id][from];
329343
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
@@ -332,6 +346,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
332346
}
333347

334348
emit TransferSingle(operator, from, address(0), id, amount);
349+
350+
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
335351
}
336352

337353
/**
@@ -365,6 +381,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
365381
}
366382

367383
emit TransferBatch(operator, from, address(0), ids, amounts);
384+
385+
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
368386
}
369387

370388
/**
@@ -411,6 +429,35 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
411429
bytes memory data
412430
) internal virtual {}
413431

432+
/**
433+
* @dev Hook that is called after any token transfer. This includes minting
434+
* and burning, as well as batched variants.
435+
*
436+
* The same hook is called on both single and batched variants. For single
437+
* transfers, the length of the `id` and `amount` arrays will be 1.
438+
*
439+
* Calling conditions (for each `id` and `amount` pair):
440+
*
441+
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
442+
* of token type `id` will be transferred to `to`.
443+
* - When `from` is zero, `amount` tokens of token type `id` will be minted
444+
* for `to`.
445+
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
446+
* will be burned.
447+
* - `from` and `to` are never both zero.
448+
* - `ids` and `amounts` have the same, non-zero length.
449+
*
450+
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
451+
*/
452+
function _afterTokenTransfer(
453+
address operator,
454+
address from,
455+
address to,
456+
uint256[] memory ids,
457+
uint256[] memory amounts,
458+
bytes memory data
459+
) internal virtual {}
460+
414461
function _doSafeTransferAcceptanceCheck(
415462
address operator,
416463
address from,

0 commit comments

Comments
 (0)