From cdf5f9d99be7e3226b62e5e42112adaf30081f46 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 9 Aug 2024 19:23:28 +0200 Subject: [PATCH] refactor: move erc2981 into the common module --- packages/token/src/erc2981.cairo | 5 - packages/token/src/erc2981/erc2981.cairo | 208 ------------------ packages/token/src/erc2981/interface.cairo | 11 - packages/token/src/lib.cairo | 2 +- .../src/tests/erc2981/test_erc2981.cairo | 6 +- .../token/src/tests/mocks/erc2981_mocks.cairo | 2 +- 6 files changed, 5 insertions(+), 229 deletions(-) delete mode 100644 packages/token/src/erc2981.cairo delete mode 100644 packages/token/src/erc2981/erc2981.cairo delete mode 100644 packages/token/src/erc2981/interface.cairo diff --git a/packages/token/src/erc2981.cairo b/packages/token/src/erc2981.cairo deleted file mode 100644 index 67fe22bd2..000000000 --- a/packages/token/src/erc2981.cairo +++ /dev/null @@ -1,5 +0,0 @@ -pub mod erc2981; -pub mod interface; - -pub use erc2981::{ERC2981Component, ERC2981ImmutableDefault}; -pub use interface::{IERC2981Dispatcher, IERC2981DispatcherTrait}; diff --git a/packages/token/src/erc2981/erc2981.cairo b/packages/token/src/erc2981/erc2981.cairo deleted file mode 100644 index d279530c8..000000000 --- a/packages/token/src/erc2981/erc2981.cairo +++ /dev/null @@ -1,208 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.15.0 (token/erc2981/erc2981.cairo) - -/// #ERC2981 Component -/// -/// Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment -/// information. -/// -/// Royalty information can be specified globally for all token ids via `set_default_royalty`, -/// and/or individually for specific token ids via `set_token_royalty`. The latter takes precedence -/// over the first. -/// -/// Royalty is specified as a fraction of sale price. The denominator is set by the contract by -/// using the Immutable pattern. -/// -/// IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its -/// payment. See https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the -/// ERC. Marketplaces are expected to voluntarily pay royalties together with sales. -#[starknet::component] -pub mod ERC2981Component { - use core::num::traits::Zero; - use openzeppelin_introspection::src5::SRC5Component::InternalTrait as SRC5InternalTrait; - use openzeppelin_introspection::src5::SRC5Component::SRC5Impl; - use openzeppelin_introspection::src5::SRC5Component; - use openzeppelin_token::erc2981::interface::{IERC2981, IERC2981_ID}; - use starknet::ContractAddress; - use starknet::storage::Map; - - pub const DEFAULT_FEE_DENOMINATOR: u256 = 10_000; - - #[derive(Serde, Drop, starknet::Store)] - struct RoyaltyInfo { - pub receiver: ContractAddress, - pub royalty_fraction: u256, - } - - #[storage] - struct Storage { - default_royalty_info: RoyaltyInfo, - token_royalty_info: Map, - } - - mod Errors { - pub const INVALID_ROYALTY: felt252 = 'ERC2981: invalid royalty'; - pub const INVALID_ROYALTY_RECEIVER: felt252 = 'ERC2981: invalid receiver'; - } - - /// Constants defined at the contract level used to configure the component behaviour. - /// - /// `FEE_DENOMINATOR`: The denominator with which to interpret the fee set in - /// `set_token_royalty` and `set_default_royalty` as a fraction of the sale price. - pub trait ImmutableT { - const FEE_DENOMINATOR: u256; - } - - // - // External - // - - #[embeddable_as(ERC2981Impl)] - impl ERC2981< - TContractState, - +HasComponent, - impl Immutable: ImmutableT, - impl SRC5: SRC5Component::HasComponent, - +Drop, - > of IERC2981> { - /// Returns how much royalty is owed and to whom, based on a sale price that may be - /// denominated in any unit of exchange. The royalty amount is denominated and should be - /// paid in that same unit of exchange. - /// - /// The returned tuple contains: - /// - /// `t.0`: The receiver of the royalty payment. - /// `t.1`: The amount of royalty payment. - fn royalty_info( - self: @ComponentState, token_id: u256, sale_price: u256 - ) -> (ContractAddress, u256) { - let token_royalty_info = self.token_royalty_info.read(token_id); - - // If the token has no specific royalty info, use the default. - let royalty_info = if token_royalty_info.receiver.is_zero() { - self.default_royalty_info.read() - } else { - token_royalty_info - }; - - let royalty_amount = sale_price - * royalty_info.royalty_fraction - / Immutable::FEE_DENOMINATOR; - - (royalty_info.receiver, royalty_amount) - } - } - - // - // Internal - // - - #[generate_trait] - pub impl InternalImpl< - TContractState, - +HasComponent, - impl Immutable: ImmutableT, - impl SRC5: SRC5Component::HasComponent, - +Drop - > of InternalTrait { - /// Initializes the contract by setting the default royalty. - fn initializer( - ref self: ComponentState, - default_receiver: ContractAddress, - default_royalty_fraction: u256 - ) { - let mut src5_component = get_dep_component_mut!(ref self, SRC5); - src5_component.register_interface(IERC2981_ID); - - self.set_default_royalty(default_receiver, default_royalty_fraction) - } - - /// Returns the royalty information that all ids in this contract will default to. - /// - /// The returned tuple contains: - /// - /// `t.0`: The receiver of the royalty payment. - /// `t.1`: The numerator of the royalty fraction. - /// `t.2`: The denominator of the royalty fraction. - fn default_royalty(self: @ComponentState) -> (ContractAddress, u256, u256) { - let royalty_info = self.default_royalty_info.read(); - (royalty_info.receiver, royalty_info.royalty_fraction, Immutable::FEE_DENOMINATOR) - } - - /// Sets the royalty information that all ids in this contract will default to. - /// - /// Requirements: - /// - /// - `receiver` cannot be the zero address. - /// - `fee_numerator` cannot be greater than the fee denominator. - fn set_default_royalty( - ref self: ComponentState, - receiver: ContractAddress, - fee_numerator: u256, - ) { - let fee_denominator = Immutable::FEE_DENOMINATOR; - assert(fee_numerator <= fee_denominator, Errors::INVALID_ROYALTY); - assert(receiver.is_non_zero(), Errors::INVALID_ROYALTY_RECEIVER); - self - .default_royalty_info - .write(RoyaltyInfo { receiver, royalty_fraction: fee_numerator }) - } - - /// Returns the royalty information that all ids in this contract will default to. - /// - /// The returned tuple contains: - /// - /// `t.0`: The receiver of the royalty payment. - /// `t.1`: The numerator of the royalty fraction. - /// `t.2`: The denominator of the royalty fraction. - fn token_royalty( - self: @ComponentState, token_id: u256 - ) -> (ContractAddress, u256, u256) { - let token_royalty_info = self.token_royalty_info.read(token_id); - - // If the token has no specific royalty info, use the default. - let royalty_info = if token_royalty_info.receiver.is_zero() { - self.default_royalty_info.read() - } else { - token_royalty_info - }; - - (royalty_info.receiver, royalty_info.royalty_fraction, Immutable::FEE_DENOMINATOR) - } - - /// Sets the royalty information for a specific token id, overriding the global default. - /// - /// Requirements: - /// - /// - `receiver` cannot be the zero address. - /// - `fee_numerator` cannot be greater than the fee denominator. - fn set_token_royalty( - ref self: ComponentState, - token_id: u256, - receiver: ContractAddress, - fee_numerator: u256 - ) { - let fee_denominator = Immutable::FEE_DENOMINATOR; - assert(fee_numerator <= fee_denominator, Errors::INVALID_ROYALTY); - assert(!receiver.is_zero(), Errors::INVALID_ROYALTY_RECEIVER); - - self - .token_royalty_info - .write(token_id, RoyaltyInfo { receiver, royalty_fraction: fee_numerator },) - } - - /// Resets royalty information for the token id back to unset. - fn reset_token_royalty(ref self: ComponentState, token_id: u256) { - self - .token_royalty_info - .write(token_id, RoyaltyInfo { receiver: Zero::zero(), royalty_fraction: 0 },) - } - } -} - -/// Implementation of the ERC2981 component that can be directly used in contracts. -/// -/// The default fee denominator is set to DEFAULT_FEE_DENOMINATOR. -pub impl ERC2981ImmutableDefault of ERC2981Component::ImmutableT { - const FEE_DENOMINATOR: u256 = ERC2981Component::DEFAULT_FEE_DENOMINATOR; -} diff --git a/packages/token/src/erc2981/interface.cairo b/packages/token/src/erc2981/interface.cairo deleted file mode 100644 index 1721a6f7a..000000000 --- a/packages/token/src/erc2981/interface.cairo +++ /dev/null @@ -1,11 +0,0 @@ -use starknet::ContractAddress; - -pub const IERC2981_ID: felt252 = 0x2d3414e45a8700c29f119a54b9f11dca0e29e06ddcb214018fc37340e165ed6; - -#[starknet::interface] -pub trait IERC2981 { - /// Returns how much royalty is owed and to whom, based on a sale price that may be denominated - /// in any unit of exchange. The royalty amount is denominated and should be paid in that same - /// unit of exchange. - fn royalty_info(self: @TState, token_id: u256, sale_price: u256) -> (ContractAddress, u256); -} diff --git a/packages/token/src/lib.cairo b/packages/token/src/lib.cairo index 20f889b94..68e16ed03 100644 --- a/packages/token/src/lib.cairo +++ b/packages/token/src/lib.cairo @@ -1,6 +1,6 @@ pub mod erc1155; pub mod erc20; -pub mod erc2981; +pub mod common; pub mod erc721; pub mod tests; diff --git a/packages/token/src/tests/erc2981/test_erc2981.cairo b/packages/token/src/tests/erc2981/test_erc2981.cairo index 80d4e8d92..e0be39fbb 100644 --- a/packages/token/src/tests/erc2981/test_erc2981.cairo +++ b/packages/token/src/tests/erc2981/test_erc2981.cairo @@ -1,9 +1,9 @@ use openzeppelin_introspection::interface::{ISRC5Dispatcher, ISRC5DispatcherTrait}; use openzeppelin_introspection::src5::SRC5Component::SRC5Impl; use openzeppelin_testing::constants::{OTHER, ZERO, RECIPIENT}; -use openzeppelin_token::erc2981::ERC2981Component::{ERC2981Impl, InternalImpl}; -use openzeppelin_token::erc2981::interface::IERC2981_ID; -use openzeppelin_token::erc2981::{ERC2981Component, ERC2981ImmutableDefault}; +use openzeppelin_token::common::erc2981::ERC2981Component::{ERC2981Impl, InternalImpl}; +use openzeppelin_token::common::erc2981::interface::IERC2981_ID; +use openzeppelin_token::common::erc2981::{ERC2981Component, ERC2981ImmutableDefault}; use openzeppelin_token::tests::mocks::erc2981_mocks::ERC2981Mock; use starknet::{ContractAddress, contract_address_const}; diff --git a/packages/token/src/tests/mocks/erc2981_mocks.cairo b/packages/token/src/tests/mocks/erc2981_mocks.cairo index de7daffa0..1697bbcf5 100644 --- a/packages/token/src/tests/mocks/erc2981_mocks.cairo +++ b/packages/token/src/tests/mocks/erc2981_mocks.cairo @@ -1,7 +1,7 @@ #[starknet::contract] pub(crate) mod ERC2981Mock { use openzeppelin_introspection::src5::SRC5Component; - use openzeppelin_token::erc2981::{ERC2981Component, ERC2981ImmutableDefault}; + use openzeppelin_token::common::erc2981::{ERC2981Component, ERC2981ImmutableDefault}; use starknet::ContractAddress; component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);