diff --git a/docs/modules/ROOT/pages/api/erc1155.adoc b/docs/modules/ROOT/pages/api/erc1155.adoc index 865fb9b8a..83496f738 100644 --- a/docs/modules/ROOT/pages/api/erc1155.adoc +++ b/docs/modules/ROOT/pages/api/erc1155.adoc @@ -167,6 +167,17 @@ ERC1155 component implementing <> and <, values: Span)++` [.item-kind]#hook# + +Function executed at the beginning of the xref:#ERC1155Component-update[update] function prior to any other logic. + +[.contract-item] +[[ERC1155Component-after_update]] +==== `[.contract-item-name]#++after_update++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_ids: Span, values: Span)++` [.item-kind]#hook# + +Function executed at the end of the xref:#ERC1155Component-update[update] function. + ==== Embeddable functions [.contract-item] @@ -382,6 +415,9 @@ Requirements: Emits a <> event if the arrays contain one element, and <> otherwise. +NOTE: This function can be extended using the xref:ERC1155Component-ERC1155HooksTrait[ERC1155HooksTrait], to add +functionality before and/or after the transfer, mint, or burn. + NOTE: The ERC1155 acceptance check is not performed in this function. See <> instead. diff --git a/docs/modules/ROOT/pages/api/erc20.adoc b/docs/modules/ROOT/pages/api/erc20.adoc index 9a0cef17c..f352bfecd 100644 --- a/docs/modules/ROOT/pages/api/erc20.adoc +++ b/docs/modules/ROOT/pages/api/erc20.adoc @@ -436,7 +436,7 @@ Possibly emits an <> event. Transfers an `amount` of tokens from `from` to `to`, or alternatively mints (or burns) if `from` (or `to`) is the zero address. -This function can be extended using the xref:ERC20Component-ERC20HooksTrait[ERC20HooksTrait], to add +NOTE: This function can be extended using the xref:ERC20Component-ERC20HooksTrait[ERC20HooksTrait], to add functionality before and/or after the transfer, mint, or burn. Emits a <> event. diff --git a/docs/modules/ROOT/pages/erc1155.adoc b/docs/modules/ROOT/pages/erc1155.adoc index 86b90d55f..5216b931c 100644 --- a/docs/modules/ROOT/pages/erc1155.adoc +++ b/docs/modules/ROOT/pages/erc1155.adoc @@ -114,7 +114,7 @@ Here's an example of a basic contract: #[starknet::contract] mod MyERC1155 { use openzeppelin::introspection::src5::SRC5Component; - use openzeppelin::token::erc1155::ERC1155Component; + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl}; use starknet::ContractAddress; component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event); diff --git a/src/presets/erc1155.cairo b/src/presets/erc1155.cairo index b0ac768e5..8d29183e1 100644 --- a/src/presets/erc1155.cairo +++ b/src/presets/erc1155.cairo @@ -12,7 +12,7 @@ mod ERC1155Upgradeable { use openzeppelin::access::ownable::OwnableComponent; use openzeppelin::introspection::src5::SRC5Component; - use openzeppelin::token::erc1155::ERC1155Component; + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl}; use openzeppelin::upgrades::UpgradeableComponent; use openzeppelin::upgrades::interface::IUpgradeable; use starknet::{ContractAddress, ClassHash}; diff --git a/src/tests/mocks/erc1155_mocks.cairo b/src/tests/mocks/erc1155_mocks.cairo index 976050426..c4c08bb6d 100644 --- a/src/tests/mocks/erc1155_mocks.cairo +++ b/src/tests/mocks/erc1155_mocks.cairo @@ -1,7 +1,7 @@ #[starknet::contract] mod DualCaseERC1155Mock { use openzeppelin::introspection::src5::SRC5Component; - use openzeppelin::token::erc1155::ERC1155Component; + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl}; use starknet::ContractAddress; component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event); @@ -54,7 +54,7 @@ mod DualCaseERC1155Mock { #[starknet::contract] mod SnakeERC1155Mock { use openzeppelin::introspection::src5::SRC5Component; - use openzeppelin::token::erc1155::ERC1155Component; + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl}; use starknet::ContractAddress; component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event); diff --git a/src/token/erc1155.cairo b/src/token/erc1155.cairo index 43434d35d..e6d0b0e3f 100644 --- a/src/token/erc1155.cairo +++ b/src/token/erc1155.cairo @@ -5,4 +5,5 @@ mod erc1155_receiver; mod interface; use erc1155::ERC1155Component; +use erc1155::ERC1155HooksEmptyImpl; use erc1155_receiver::ERC1155ReceiverComponent; diff --git a/src/token/erc1155/erc1155.cairo b/src/token/erc1155/erc1155.cairo index f70751bda..ffe732983 100644 --- a/src/token/erc1155/erc1155.cairo +++ b/src/token/erc1155/erc1155.cairo @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.12.0 (token/erc1155/erc1155.cairo) +use starknet::ContractAddress; + /// # ERC1155 Component /// /// The ERC1155 component provides an implementation of the basic standard multi-token. @@ -94,6 +96,28 @@ mod ERC1155Component { const SAFE_TRANSFER_FAILED: felt252 = 'ERC1155: safe transfer failed'; } + // + // Hooks + // + + trait ERC1155HooksTrait { + fn before_update( + ref self: ComponentState, + from: ContractAddress, + to: ContractAddress, + token_ids: Span, + values: Span + ); + + fn after_update( + ref self: ComponentState, + from: ContractAddress, + to: ContractAddress, + token_ids: Span, + values: Span + ); + } + // // External // @@ -103,6 +127,7 @@ mod ERC1155Component { TContractState, +HasComponent, +SRC5Component::HasComponent, + +ERC1155HooksTrait, +Drop > of interface::IERC1155> { /// Returns the amount of `token_id` tokens owned by `account`. @@ -237,6 +262,7 @@ mod ERC1155Component { TContractState, +HasComponent, +SRC5Component::HasComponent, + +ERC1155HooksTrait, +Drop > of interface::IERC1155MetadataURI> { /// This implementation returns the same URI for *all* token types. It relies @@ -256,6 +282,7 @@ mod ERC1155Component { TContractState, +HasComponent, +SRC5Component::HasComponent, + +ERC1155HooksTrait, +Drop > of interface::IERC1155Camel> { fn balanceOf( @@ -316,6 +343,7 @@ mod ERC1155Component { TContractState, +HasComponent, impl SRC5: SRC5Component::HasComponent, + impl Hooks: ERC1155HooksTrait, +Drop > of InternalTrait { /// Initializes the contract by setting the `base_uri` for all tokens, @@ -338,6 +366,9 @@ mod ERC1155Component { /// /// Emits a `TransferSingle` event if the arrays contain one element, and `TransferBatch` otherwise. /// + /// NOTE: This function can be extended using the `ERC1155HooksTrait`, to add + /// functionality before and/or after the transfer, mint, or burn. + /// /// NOTE: The ERC1155 acceptance check is not performed in this function. /// See `update_with_acceptance_check` instead. fn update( @@ -347,6 +378,8 @@ mod ERC1155Component { token_ids: Span, values: Span ) { + Hooks::before_update(ref self, from, to, token_ids, values); + assert(token_ids.len() == values.len(), Errors::INVALID_ARRAY_LENGTH); let mut index = 0; @@ -378,6 +411,8 @@ mod ERC1155Component { } else { self.emit(TransferBatch { operator, from, to, ids: token_ids, values }); } + + Hooks::after_update(ref self, from, to, token_ids, values); } /// Version of `update` that performs the token acceptance check by calling @@ -554,6 +589,7 @@ mod ERC1155Component { TContractState, +HasComponent, impl SRC5: SRC5Component::HasComponent, + +ERC1155HooksTrait, +Drop > of interface::ERC1155ABI> { // IERC1155 @@ -668,3 +704,22 @@ mod ERC1155Component { } } } + +/// An empty implementation of the ERC1155 hooks to be used in basic ERC1155 preset contracts. +impl ERC1155HooksEmptyImpl of ERC1155Component::ERC1155HooksTrait { + fn before_update( + ref self: ERC1155Component::ComponentState, + from: ContractAddress, + to: ContractAddress, + token_ids: Span, + values: Span + ) {} + + fn after_update( + ref self: ERC1155Component::ComponentState, + from: ContractAddress, + to: ContractAddress, + token_ids: Span, + values: Span + ) {} +} diff --git a/src/token/erc20/erc20.cairo b/src/token/erc20/erc20.cairo index 10003fc91..2b540c88e 100644 --- a/src/token/erc20/erc20.cairo +++ b/src/token/erc20/erc20.cairo @@ -321,7 +321,7 @@ mod ERC20Component { /// Transfers an `amount` of tokens from `from` to `to`, or alternatively mints (or burns) if `from` (or `to`) is /// the zero address. /// - /// This function can be extended using the `ERC20HooksTrait`, to add + /// NOTe: This function can be extended using the `ERC20HooksTrait`, to add /// functionality before and/or after the transfer, mint, or burn. /// /// Emits a `Transfer` event.