diff --git a/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626.snap b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626.snap index 9ea0df5a8..f6b44160c 100644 --- a/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626.snap +++ b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626.snap @@ -7,11 +7,11 @@ TokenStream: #[starknet::contract] pub mod ERC4626Mock { - use openzeppelin_token::erc20::ERC20HooksEmptyImpl; use openzeppelin_token::erc20::extensions::erc4626::{ DefaultConfig, ERC4626DefaultNoFees, ERC4626DefaultNoLimits, ERC4626EmptyHooks, ERC4626SelfAssetsManagement, }; + use openzeppelin_token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20HooksEmptyImpl}; use starknet::ContractAddress; #[abi(embed_v0)] impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; @@ -63,14 +63,7 @@ pub mod ERC4626Mock { Diagnostics: -==== -Warning: The ERC20 component requires an ImmutableConfig implementation in scope and -it looks like it is missing. - -You can use the default implementation by importing it: - -`use openzeppelin_token::erc20::DefaultConfig;` -==== +None AuxData: diff --git a/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_assets_management_trait.snap b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_assets_management_trait.snap new file mode 100644 index 000000000..29b219f1f --- /dev/null +++ b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_assets_management_trait.snap @@ -0,0 +1,76 @@ +--- +source: src/tests/test_with_components.rs +expression: result +snapshot_kind: text +--- +TokenStream: + +#[starknet::contract] +pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + DefaultConfig, ERC4626DefaultNoFees, ERC4626DefaultNoLimits, ERC4626EmptyHooks, + }; + use openzeppelin_token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20HooksEmptyImpl}; + use starknet::ContractAddress; + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + #[storage] + pub struct Storage { + #[substorage(v0)] + pub erc20: ERC20Component::Storage, + #[substorage(v0)] + pub erc4626: ERC4626Component::Storage, + } + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + self.erc4626.initializer(underlying_asset); + } + use openzeppelin_token::erc20::ERC20Component; + use openzeppelin_token::erc20::extensions::erc4626::ERC4626Component; + + component!(path: ERC20Component, storage: erc20, event: ERC20Event); + component!(path: ERC4626Component, storage: erc4626, event: ERC4626Event); + + impl ERC20InternalImpl = ERC20Component::InternalImpl; + impl ERC4626InternalImpl = ERC4626Component::InternalImpl; + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + ERC20Event: ERC20Component::Event, + #[flat] + ERC4626Event: ERC4626Component::Event, + } +} + + +Diagnostics: + +==== +Warning: The ERC4626 component requires an implementation of the AssetsManagementTrait in scope and +it looks like it is missing. + +You can use the ERC4626SelfAssetsManagement implementation by importing it: + +`use openzeppelin_token::erc20::extensions::erc4626::ERC4626SelfAssetsManagement;` +==== + +AuxData: + +None diff --git a/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_config.snap b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_config.snap new file mode 100644 index 000000000..8a5bb8818 --- /dev/null +++ b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_config.snap @@ -0,0 +1,77 @@ +--- +source: src/tests/test_with_components.rs +expression: result +snapshot_kind: text +--- +TokenStream: + +#[starknet::contract] +pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + ERC4626DefaultNoFees, ERC4626DefaultNoLimits, ERC4626EmptyHooks, + ERC4626SelfAssetsManagement, + }; + use openzeppelin_token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20HooksEmptyImpl}; + use starknet::ContractAddress; + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + #[storage] + pub struct Storage { + #[substorage(v0)] + pub erc20: ERC20Component::Storage, + #[substorage(v0)] + pub erc4626: ERC4626Component::Storage, + } + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + self.erc4626.initializer(underlying_asset); + } + use openzeppelin_token::erc20::ERC20Component; + use openzeppelin_token::erc20::extensions::erc4626::ERC4626Component; + + component!(path: ERC20Component, storage: erc20, event: ERC20Event); + component!(path: ERC4626Component, storage: erc4626, event: ERC4626Event); + + impl ERC20InternalImpl = ERC20Component::InternalImpl; + impl ERC4626InternalImpl = ERC4626Component::InternalImpl; + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + ERC20Event: ERC20Component::Event, + #[flat] + ERC4626Event: ERC4626Component::Event, + } +} + + +Diagnostics: + +==== +Warning: The ERC4626 component requires an ImmutableConfig implementation in scope and +it looks like it is missing. + +You can use the default implementation by importing it: + +`use openzeppelin_token::erc20::extensions::erc4626::DefaultConfig;` +==== + +AuxData: + +None diff --git a/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_fees_trait.snap b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_fees_trait.snap new file mode 100644 index 000000000..511efa0c7 --- /dev/null +++ b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_fees_trait.snap @@ -0,0 +1,76 @@ +--- +source: src/tests/test_with_components.rs +expression: result +snapshot_kind: text +--- +TokenStream: + +#[starknet::contract] +pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + DefaultConfig, ERC4626DefaultNoLimits, ERC4626EmptyHooks, ERC4626SelfAssetsManagement, + }; + use openzeppelin_token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20HooksEmptyImpl}; + use starknet::ContractAddress; + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + #[storage] + pub struct Storage { + #[substorage(v0)] + pub erc20: ERC20Component::Storage, + #[substorage(v0)] + pub erc4626: ERC4626Component::Storage, + } + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + self.erc4626.initializer(underlying_asset); + } + use openzeppelin_token::erc20::ERC20Component; + use openzeppelin_token::erc20::extensions::erc4626::ERC4626Component; + + component!(path: ERC20Component, storage: erc20, event: ERC20Event); + component!(path: ERC4626Component, storage: erc4626, event: ERC4626Event); + + impl ERC20InternalImpl = ERC20Component::InternalImpl; + impl ERC4626InternalImpl = ERC4626Component::InternalImpl; + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + ERC20Event: ERC20Component::Event, + #[flat] + ERC4626Event: ERC4626Component::Event, + } +} + + +Diagnostics: + +==== +Warning: The ERC4626 component requires an implementation of the FeeConfigTrait in scope and +it looks like it is missing. + +You can use the ERC4626DefaultNoFees implementation by importing it: + +`use openzeppelin_token::erc20::extensions::erc4626::ERC4626DefaultNoFees;` +==== + +AuxData: + +None diff --git a/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_hooks.snap b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_hooks.snap new file mode 100644 index 000000000..d8ae188e5 --- /dev/null +++ b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_hooks.snap @@ -0,0 +1,76 @@ +--- +source: src/tests/test_with_components.rs +expression: result +snapshot_kind: text +--- +TokenStream: + +#[starknet::contract] +pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + DefaultConfig, ERC4626DefaultNoFees, ERC4626DefaultNoLimits, ERC4626SelfAssetsManagement, + }; + use openzeppelin_token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20HooksEmptyImpl}; + use starknet::ContractAddress; + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + #[storage] + pub struct Storage { + #[substorage(v0)] + pub erc20: ERC20Component::Storage, + #[substorage(v0)] + pub erc4626: ERC4626Component::Storage, + } + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + self.erc4626.initializer(underlying_asset); + } + use openzeppelin_token::erc20::ERC20Component; + use openzeppelin_token::erc20::extensions::erc4626::ERC4626Component; + + component!(path: ERC20Component, storage: erc20, event: ERC20Event); + component!(path: ERC4626Component, storage: erc4626, event: ERC4626Event); + + impl ERC20InternalImpl = ERC20Component::InternalImpl; + impl ERC4626InternalImpl = ERC4626Component::InternalImpl; + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + ERC20Event: ERC20Component::Event, + #[flat] + ERC4626Event: ERC4626Component::Event, + } +} + + +Diagnostics: + +==== +Warning: The ERC4626 component requires an implementation of the ERC4626HooksTrait in scope and +it looks like it is missing. + +You can use the ERC4626EmptyHooks implementation by importing it: + +`use openzeppelin_token::erc20::extensions::erc4626::ERC4626EmptyHooks;` +==== + +AuxData: + +None diff --git a/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_initializer.snap b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_initializer.snap new file mode 100644 index 000000000..eae9a8573 --- /dev/null +++ b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_initializer.snap @@ -0,0 +1,76 @@ +--- +source: src/tests/test_with_components.rs +expression: result +snapshot_kind: text +--- +TokenStream: + +#[starknet::contract] +pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + DefaultConfig, ERC4626DefaultNoFees, ERC4626DefaultNoLimits, ERC4626EmptyHooks, + ERC4626SelfAssetsManagement, + }; + use openzeppelin_token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20HooksEmptyImpl}; + use starknet::ContractAddress; + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + #[storage] + pub struct Storage { + #[substorage(v0)] + pub erc20: ERC20Component::Storage, + #[substorage(v0)] + pub erc4626: ERC4626Component::Storage, + } + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + } + use openzeppelin_token::erc20::ERC20Component; + use openzeppelin_token::erc20::extensions::erc4626::ERC4626Component; + + component!(path: ERC20Component, storage: erc20, event: ERC20Event); + component!(path: ERC4626Component, storage: erc4626, event: ERC4626Event); + + impl ERC20InternalImpl = ERC20Component::InternalImpl; + impl ERC4626InternalImpl = ERC4626Component::InternalImpl; + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + ERC20Event: ERC20Component::Event, + #[flat] + ERC4626Event: ERC4626Component::Event, + } +} + + +Diagnostics: + +==== +Warning: It looks like the initializers for the following components are missing: + +ERC4626 + +This may lead to unexpected behavior. +We recommend adding the corresponding initializer calls to the constructor. +==== + +AuxData: + +None diff --git a/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_limits_trait.snap b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_limits_trait.snap new file mode 100644 index 000000000..6305e6f57 --- /dev/null +++ b/packages/macros/src/tests/snapshots/openzeppelin_macros__tests__test_with_components__with_erc4626_no_limits_trait.snap @@ -0,0 +1,76 @@ +--- +source: src/tests/test_with_components.rs +expression: result +snapshot_kind: text +--- +TokenStream: + +#[starknet::contract] +pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + DefaultConfig, ERC4626DefaultNoFees, ERC4626EmptyHooks, ERC4626SelfAssetsManagement, + }; + use openzeppelin_token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20HooksEmptyImpl}; + use starknet::ContractAddress; + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + #[storage] + pub struct Storage { + #[substorage(v0)] + pub erc20: ERC20Component::Storage, + #[substorage(v0)] + pub erc4626: ERC4626Component::Storage, + } + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + self.erc4626.initializer(underlying_asset); + } + use openzeppelin_token::erc20::ERC20Component; + use openzeppelin_token::erc20::extensions::erc4626::ERC4626Component; + + component!(path: ERC20Component, storage: erc20, event: ERC20Event); + component!(path: ERC4626Component, storage: erc4626, event: ERC4626Event); + + impl ERC20InternalImpl = ERC20Component::InternalImpl; + impl ERC4626InternalImpl = ERC4626Component::InternalImpl; + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + ERC20Event: ERC20Component::Event, + #[flat] + ERC4626Event: ERC4626Component::Event, + } +} + + +Diagnostics: + +==== +Warning: The ERC4626 component requires an implementation of the LimitConfigTrait in scope and +it looks like it is missing. + +You can use the ERC4626DefaultNoLimits implementation by importing it: + +`use openzeppelin_token::erc20::extensions::erc4626::ERC4626DefaultNoLimits;` +==== + +AuxData: + +None diff --git a/packages/macros/src/tests/test_with_components.rs b/packages/macros/src/tests/test_with_components.rs index 82b12aaa5..ed5c01fb1 100644 --- a/packages/macros/src/tests/test_with_components.rs +++ b/packages/macros/src/tests/test_with_components.rs @@ -1143,7 +1143,294 @@ fn test_with_erc4626() { DefaultConfig, ERC4626DefaultNoLimits, ERC4626DefaultNoFees, ERC4626EmptyHooks, ERC4626SelfAssetsManagement, }; - use openzeppelin_token::erc20::ERC20HooksEmptyImpl; + use openzeppelin_token::erc20::{ERC20HooksEmptyImpl, DefaultConfig as ERC20DefaultConfig}; + use starknet::ContractAddress; + + // ERC4626 + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + // ERC4626MetadataImpl is a custom impl of IERC20Metadata + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + + // ERC20 + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + + #[storage] + pub struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + self.erc4626.initializer(underlying_asset); + } + } + }; + let result = get_string_result(attribute, item); + assert_snapshot!(result); +} + +#[test] +fn test_with_erc4626_no_initializer() { + let attribute = quote! { (ERC20, ERC4626) }; + let item = quote! { + #[starknet::contract] + pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + DefaultConfig, ERC4626DefaultNoLimits, ERC4626DefaultNoFees, + ERC4626EmptyHooks, ERC4626SelfAssetsManagement, + }; + use openzeppelin_token::erc20::{ERC20HooksEmptyImpl, DefaultConfig as ERC20DefaultConfig}; + use starknet::ContractAddress; + + // ERC4626 + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + // ERC4626MetadataImpl is a custom impl of IERC20Metadata + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + + // ERC20 + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + + #[storage] + pub struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + } + } + }; + let result = get_string_result(attribute, item); + assert_snapshot!(result); +} + +#[test] +fn test_with_erc4626_no_config() { + let attribute = quote! { (ERC20, ERC4626) }; + let item = quote! { + #[starknet::contract] + pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + ERC4626DefaultNoLimits, ERC4626DefaultNoFees, + ERC4626EmptyHooks, ERC4626SelfAssetsManagement, + }; + use openzeppelin_token::erc20::{ERC20HooksEmptyImpl, DefaultConfig as ERC20DefaultConfig}; + use starknet::ContractAddress; + + // ERC4626 + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + // ERC4626MetadataImpl is a custom impl of IERC20Metadata + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + + // ERC20 + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + + #[storage] + pub struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + self.erc4626.initializer(underlying_asset); + } + } + }; + let result = get_string_result(attribute, item); + assert_snapshot!(result); +} + +#[test] +fn test_with_erc4626_no_hooks() { + let attribute = quote! { (ERC20, ERC4626) }; + let item = quote! { + #[starknet::contract] + pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + DefaultConfig, ERC4626DefaultNoLimits, ERC4626DefaultNoFees, + ERC4626SelfAssetsManagement, + }; + use openzeppelin_token::erc20::{ERC20HooksEmptyImpl, DefaultConfig as ERC20DefaultConfig}; + use starknet::ContractAddress; + + // ERC4626 + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + // ERC4626MetadataImpl is a custom impl of IERC20Metadata + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + + // ERC20 + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + + #[storage] + pub struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + self.erc4626.initializer(underlying_asset); + } + } + }; + let result = get_string_result(attribute, item); + assert_snapshot!(result); +} + +#[test] +fn test_with_erc4626_no_fees_trait() { + let attribute = quote! { (ERC20, ERC4626) }; + let item = quote! { + #[starknet::contract] + pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + DefaultConfig, ERC4626DefaultNoLimits, + ERC4626EmptyHooks, ERC4626SelfAssetsManagement, + }; + use openzeppelin_token::erc20::{ERC20HooksEmptyImpl, DefaultConfig as ERC20DefaultConfig}; + use starknet::ContractAddress; + + // ERC4626 + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + // ERC4626MetadataImpl is a custom impl of IERC20Metadata + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + + // ERC20 + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + + #[storage] + pub struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + self.erc4626.initializer(underlying_asset); + } + } + }; + let result = get_string_result(attribute, item); + assert_snapshot!(result); +} + +#[test] +fn test_with_erc4626_no_limits_trait() { + let attribute = quote! { (ERC20, ERC4626) }; + let item = quote! { + #[starknet::contract] + pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + DefaultConfig, ERC4626DefaultNoFees, + ERC4626EmptyHooks, ERC4626SelfAssetsManagement, + }; + use openzeppelin_token::erc20::{ERC20HooksEmptyImpl, DefaultConfig as ERC20DefaultConfig}; + use starknet::ContractAddress; + + // ERC4626 + #[abi(embed_v0)] + impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl; + // ERC4626MetadataImpl is a custom impl of IERC20Metadata + #[abi(embed_v0)] + impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl; + + // ERC20 + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + + #[storage] + pub struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + underlying_asset: ContractAddress, + initial_supply: u256, + recipient: ContractAddress, + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + self.erc4626.initializer(underlying_asset); + } + } + }; + let result = get_string_result(attribute, item); + assert_snapshot!(result); +} + +#[test] +fn test_with_erc4626_no_assets_management_trait() { + let attribute = quote! { (ERC20, ERC4626) }; + let item = quote! { + #[starknet::contract] + pub mod ERC4626Mock { + use openzeppelin_token::erc20::extensions::erc4626::{ + DefaultConfig, ERC4626DefaultNoLimits, ERC4626DefaultNoFees, + ERC4626EmptyHooks, + }; + use openzeppelin_token::erc20::{ERC20HooksEmptyImpl, DefaultConfig as ERC20DefaultConfig}; use starknet::ContractAddress; // ERC4626