From 5bcc23f62dc3767b5f92b7dc40a7e54451f79738 Mon Sep 17 00:00:00 2001 From: CryptoV8 <91189073+CryptoV8@users.noreply.github.com> Date: Thu, 13 Jan 2022 00:03:19 +0800 Subject: [PATCH 1/5] add Hooks _afterTokenTransfer --- contracts/token/ERC1155/ERC1155.sol | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/contracts/token/ERC1155/ERC1155.sol b/contracts/token/ERC1155/ERC1155.sol index ffdd8cd788d..1549de77a59 100644 --- a/contracts/token/ERC1155/ERC1155.sol +++ b/contracts/token/ERC1155/ERC1155.sol @@ -180,6 +180,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { emit TransferSingle(operator, from, to, id, amount); _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); + + _afterTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); } /** @@ -221,6 +223,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { emit TransferBatch(operator, from, to, ids, amounts); _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); + + _afterTokenTransfer(operator, from, to, ids, amounts, data); } /** @@ -273,6 +277,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { emit TransferSingle(operator, address(0), to, id, amount); _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); + + _afterTokenTransfer(operator, address(0), to, _asSingletonArray(id), _asSingletonArray(amount), data); } /** @@ -304,6 +310,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { emit TransferBatch(operator, address(0), to, ids, amounts); _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + + _afterTokenTransfer(operator, address(0), to, ids, amounts, data); } /** @@ -332,6 +340,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { } emit TransferSingle(operator, from, address(0), id, amount); + + _afterTokenTransfer(operator, from, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); } /** @@ -365,6 +375,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { } emit TransferBatch(operator, from, address(0), ids, amounts); + + _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); } /** @@ -410,6 +422,35 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { uint256[] memory amounts, bytes memory data ) internal virtual {} + + /** + * @dev Hook that is called after any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `id` and `amount` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual {} function _doSafeTransferAcceptanceCheck( address operator, From 5f18a5bab1a510b33205464e1ca9a48fad2facdd Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 3 Feb 2022 16:05:14 +0100 Subject: [PATCH 2/5] avoid duplicate call to _asSingleton --- contracts/token/ERC1155/ERC1155.sol | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/contracts/token/ERC1155/ERC1155.sol b/contracts/token/ERC1155/ERC1155.sol index 1549de77a59..bc3de9ce160 100644 --- a/contracts/token/ERC1155/ERC1155.sol +++ b/contracts/token/ERC1155/ERC1155.sol @@ -167,8 +167,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { require(to != address(0), "ERC1155: transfer to the zero address"); address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); - _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); + _beforeTokenTransfer(operator, from, to, ids, amounts, data); uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); @@ -181,7 +183,7 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); - _afterTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); + _afterTokenTransfer(operator, from, to, ids, amounts, data); } /** @@ -224,7 +226,7 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); - _afterTokenTransfer(operator, from, to, ids, amounts, data); + _afterTokenTransfer(operator, from, to, ids, amounts, data); } /** @@ -270,15 +272,17 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { require(to != address(0), "ERC1155: mint to the zero address"); address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); - _beforeTokenTransfer(operator, address(0), to, _asSingletonArray(id), _asSingletonArray(amount), data); + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); _balances[id][to] += amount; emit TransferSingle(operator, address(0), to, id, amount); _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); - _afterTokenTransfer(operator, address(0), to, _asSingletonArray(id), _asSingletonArray(amount), data); + _afterTokenTransfer(operator, address(0), to, ids, amounts, data); } /** @@ -330,8 +334,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { require(from != address(0), "ERC1155: burn from the zero address"); address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); - _beforeTokenTransfer(operator, from, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); + _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); @@ -341,7 +347,7 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { emit TransferSingle(operator, from, address(0), id, amount); - _afterTokenTransfer(operator, from, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); + _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); } /** @@ -422,7 +428,7 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { uint256[] memory amounts, bytes memory data ) internal virtual {} - + /** * @dev Hook that is called after any token transfer. This includes minting * and burning, as well as batched variants. From a377f38397f53b9072cb43c714d2ea5446512d3f Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 3 Feb 2022 16:12:12 +0100 Subject: [PATCH 3/5] add changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53a765f44fe..95ab8d8dfd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + + * `ERC1155`: Add a `_afterTokenTransfer` hook for improved expendability. ([#3104](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3104)) + ## Unreleased * `ERC2891`: add implementation of the royalty standard, and the respective extensions for `ERC721` and `ERC1155`. ([#3012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3012)) From 4bb08d737676c376b677f1e93ac2af188fc8ce0f Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 3 Feb 2022 20:31:48 +0100 Subject: [PATCH 4/5] update changelog link to PR --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95ab8d8dfd3..e26a2d7c348 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Unreleased - * `ERC1155`: Add a `_afterTokenTransfer` hook for improved expendability. ([#3104](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3104)) + * `ERC1155`: Add a `_afterTokenTransfer` hook for improved expendability. ([#3166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3166)) ## Unreleased From 52911b9bbf9cc04b0275f9127d3e68adb2ea58db Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Sun, 13 Feb 2022 15:04:28 +0100 Subject: [PATCH 5/5] Update CHANGELOG.md Co-authored-by: Francisco Giordano --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 154e742a1d5..a164a13c103 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * `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)) * `EnumerableMap`: add new `AddressToUintMap` map type. ([#3150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3150)) - * `ERC1155`: Add a `_afterTokenTransfer` hook for improved expendability. ([#3166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3166)) + * `ERC1155`: Add a `_afterTokenTransfer` hook for improved extensibility. ([#3166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3166)) ## Unreleased