Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions packages/macros/src/attribute/with_components/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pub enum AllowedComponents {
ERC1155Receiver,
ERC2981,
ERC4626,
ERC20Wrapper,
ERC721Wrapper,
Upgradeable,
Nonces,
Multisig,
Expand Down Expand Up @@ -62,6 +64,8 @@ impl AllowedComponents {
"ERC1155Receiver" => Ok(AllowedComponents::ERC1155Receiver),
"ERC2981" => Ok(AllowedComponents::ERC2981),
"ERC4626" => Ok(AllowedComponents::ERC4626),
"ERC20Wrapper" => Ok(AllowedComponents::ERC20Wrapper),
"ERC721Wrapper" => Ok(AllowedComponents::ERC721Wrapper),
"Upgradeable" => Ok(AllowedComponents::Upgradeable),
"Nonces" => Ok(AllowedComponents::Nonces),
"Multisig" => Ok(AllowedComponents::Multisig),
Expand Down Expand Up @@ -260,6 +264,24 @@ impl AllowedComponents {
has_immutable_config: true,
internal_impls: vec!["InternalImpl"],
},
AllowedComponents::ERC20Wrapper => ComponentInfo {
name: "ERC20WrapperComponent",
path: "openzeppelin_token::erc20::extensions::erc20_wrapper::ERC20WrapperComponent",
storage: "erc20_wrapper",
event: "ERC20WrapperEvent",
has_initializer: true,
has_immutable_config: false,
internal_impls: vec!["InternalImpl"],
},
AllowedComponents::ERC721Wrapper => ComponentInfo {
name: "ERC721WrapperComponent",
path: "openzeppelin_token::erc721::extensions::erc721_wrapper::ERC721WrapperComponent",
storage: "erc721_wrapper",
event: "ERC721WrapperEvent",
has_initializer: true,
has_immutable_config: false,
internal_impls: vec!["InternalImpl"],
},
Comment thread
ericnordelo marked this conversation as resolved.
AllowedComponents::Upgradeable => ComponentInfo {
name: "UpgradeableComponent",
path: "openzeppelin_upgrades::UpgradeableComponent",
Expand Down
18 changes: 18 additions & 0 deletions packages/macros/src/attribute/with_components/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,15 @@ pub mod warnings {
"
};

/// Warning when the ERC1155Supply hook call is missing.
pub const ERC1155_SUPPLY_HOOKS_MISSING: &str = indoc! {
"The ERC1155Supply component requires calling `self.erc1155_supply.after_update(...)`
inside the `ERC1155HooksTrait::after_update` hook, and it looks like it is missing.

This may lead to incorrect total supply tracking.
"
};

/// Warning when the Upgradeable component is not used.
pub const UPGRADEABLE_NOT_USED: &str = indoc! {
"It looks like the `self.upgradeable.upgrade(new_class_hash)` function is not used in the contract. If
Expand All @@ -124,6 +133,15 @@ pub mod warnings {
"
};

/// Warning when the ERC721Enumerable hook call is missing.
pub const ERC721_ENUMERABLE_HOOKS_MISSING: &str = indoc! {
"The ERC721Enumerable component requires calling `self.erc721_enumerable.before_update(...)`
inside the `ERC721HooksTrait::before_update` hook, and it looks like it is missing.

This may lead to incorrect token enumeration data.
"
};

/// Warning when the ERC4626 component is missing an implementation of the ERC4626HooksTrait.
pub const ERC4626_HOOKS_IMPL_MISSING: &str = indoc! {
"The ERC4626 component requires an implementation of the ERC4626HooksTrait in scope and
Expand Down
16 changes: 16 additions & 0 deletions packages/macros/src/attribute/with_components/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,14 @@ fn add_per_component_warnings(code: &str, component_info: &ComponentInfo) -> Vec
warnings.push(warning);
}
}
AllowedComponents::ERC1155Supply => {
let hook_called = code.contains("erc1155_supply.after_update(")
|| code.contains("ERC1155SupplyInternalImpl::after_update(");
if !hook_called {
let warning = Diagnostic::warn(warnings::ERC1155_SUPPLY_HOOKS_MISSING);
warnings.push(warning);
}
}
Comment on lines +311 to +318
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

AllowedComponents::Upgradeable => {
// Check that the upgrade function is called
let upgrade_function_called = code.contains("self.upgradeable.upgrade");
Expand All @@ -324,6 +332,14 @@ fn add_per_component_warnings(code: &str, component_info: &ComponentInfo) -> Vec
warnings.push(warning);
}
}
AllowedComponents::ERC721Enumerable => {
let hook_called = code.contains("erc721_enumerable.before_update(")
|| code.contains("ERC721EnumerableInternalImpl::before_update(");
if !hook_called {
let warning = Diagnostic::warn(warnings::ERC721_ENUMERABLE_HOOKS_MISSING);
warnings.push(warning);
}
}
_ => {}
}
warnings
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
source: src/tests/test_with_components.rs
expression: result
snapshot_kind: text
---
TokenStream:

#[starknet::contract]
pub mod MyToken {
use openzeppelin_token::erc20::{DefaultConfig, ERC20HooksEmptyImpl};
use starknet::ContractAddress;
#[storage]
pub struct Storage {
#[substorage(v0)]
pub erc20: ERC20Component::Storage,
#[substorage(v0)]
pub erc20_wrapper: ERC20WrapperComponent::Storage,
}
#[constructor]
fn constructor(ref self: ContractState, underlying: ContractAddress) {
self.erc20.initializer("MyToken", "MTK");
self.erc20_wrapper.initializer(underlying);
}
use openzeppelin_token::erc20::ERC20Component;
use openzeppelin_token::erc20::extensions::erc20_wrapper::ERC20WrapperComponent;

component!(path: ERC20Component, storage: erc20, event: ERC20Event);
component!(path: ERC20WrapperComponent, storage: erc20_wrapper, event: ERC20WrapperEvent);

impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;
impl ERC20WrapperInternalImpl = ERC20WrapperComponent::InternalImpl<ContractState>;

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ERC20Event: ERC20Component::Event,
#[flat]
ERC20WrapperEvent: ERC20WrapperComponent::Event,
}
}


Diagnostics:

None

AuxData:

None
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
source: src/tests/test_with_components.rs
expression: result
snapshot_kind: text
---
TokenStream:

#[starknet::contract]
pub mod MyToken {
use openzeppelin_token::erc20::{DefaultConfig, ERC20HooksEmptyImpl};
use starknet::ContractAddress;
#[storage]
pub struct Storage {
#[substorage(v0)]
pub erc20: ERC20Component::Storage,
#[substorage(v0)]
pub erc20_wrapper: ERC20WrapperComponent::Storage,
}
#[constructor]
fn constructor(ref self: ContractState) {
self.erc20.initializer("MyToken", "MTK");
}
use openzeppelin_token::erc20::ERC20Component;
use openzeppelin_token::erc20::extensions::erc20_wrapper::ERC20WrapperComponent;

component!(path: ERC20Component, storage: erc20, event: ERC20Event);
component!(path: ERC20WrapperComponent, storage: erc20_wrapper, event: ERC20WrapperEvent);

impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;
impl ERC20WrapperInternalImpl = ERC20WrapperComponent::InternalImpl<ContractState>;

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ERC20Event: ERC20Component::Event,
#[flat]
ERC20WrapperEvent: ERC20WrapperComponent::Event,
}
}


Diagnostics:

====
Warning: It looks like the initializers for the following components are missing:

ERC20Wrapper

This may lead to unexpected behavior.
We recommend adding the corresponding initializer calls to the constructor.
====

AuxData:

None
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ pub mod MyContract {

Diagnostics:

None
====
Warning: The ERC721Enumerable component requires calling `self.erc721_enumerable.before_update(...)`
inside the `ERC721HooksTrait::before_update` hook, and it looks like it is missing.

This may lead to incorrect token enumeration data.
====

AuxData:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ ERC721Enumerable

This may lead to unexpected behavior.
We recommend adding the corresponding initializer calls to the constructor.
========
Warning: The ERC721Enumerable component requires calling `self.erc721_enumerable.before_update(...)`
inside the `ERC721HooksTrait::before_update` hook, and it looks like it is missing.

This may lead to incorrect token enumeration data.
====

AuxData:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
source: src/tests/test_with_components.rs
expression: result
snapshot_kind: text
---
TokenStream:

#[starknet::contract]
pub mod MyContract {
use openzeppelin_token::erc721::ERC721Component;
use starknet::ContractAddress;
#[storage]
pub struct Storage {
#[substorage(v0)]
pub erc721_enumerable: ERC721EnumerableComponent::Storage,
}
#[constructor]
fn constructor(ref self: ContractState) {
self.erc721_enumerable.initializer();
}
impl ERC721HooksImpl of ERC721Component::ERC721HooksTrait<ContractState> {
fn before_update(
ref self: ERC721Component::ComponentState<ContractState>,
to: ContractAddress,
token_id: u256,
auth: ContractAddress,
) {
let mut contract_state = self.get_contract_mut();
contract_state.erc721_enumerable.before_update(to, token_id);
}
}
use openzeppelin_token::erc721::extensions::ERC721EnumerableComponent;

component!(
path: ERC721EnumerableComponent, storage: erc721_enumerable, event: ERC721EnumerableEvent,
);

impl ERC721EnumerableInternalImpl = ERC721EnumerableComponent::InternalImpl<ContractState>;

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ERC721EnumerableEvent: ERC721EnumerableComponent::Event,
}
}


Diagnostics:

None

AuxData:

None
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
source: src/tests/test_with_components.rs
expression: result
snapshot_kind: text
---
TokenStream:

#[starknet::contract]
pub mod MyToken {
use openzeppelin_token::erc721::ERC721HooksEmptyImpl;
use starknet::ContractAddress;
#[storage]
pub struct Storage {
#[substorage(v0)]
pub erc721: ERC721Component::Storage,
#[substorage(v0)]
pub src5: SRC5Component::Storage,
#[substorage(v0)]
pub erc721_wrapper: ERC721WrapperComponent::Storage,
}
#[constructor]
fn constructor(ref self: ContractState, underlying: ContractAddress) {
self.erc721.initializer("MyToken", "MTK", "");
self.erc721_wrapper.initializer(underlying);
}
use openzeppelin_introspection::src5::SRC5Component;
use openzeppelin_token::erc721::ERC721Component;
use openzeppelin_token::erc721::extensions::erc721_wrapper::ERC721WrapperComponent;

component!(path: ERC721Component, storage: erc721, event: ERC721Event);
component!(path: SRC5Component, storage: src5, event: SRC5Event);
component!(path: ERC721WrapperComponent, storage: erc721_wrapper, event: ERC721WrapperEvent);

impl ERC721InternalImpl = ERC721Component::InternalImpl<ContractState>;
impl SRC5InternalImpl = SRC5Component::InternalImpl<ContractState>;
impl ERC721WrapperInternalImpl = ERC721WrapperComponent::InternalImpl<ContractState>;

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ERC721Event: ERC721Component::Event,
#[flat]
SRC5Event: SRC5Component::Event,
#[flat]
ERC721WrapperEvent: ERC721WrapperComponent::Event,
}
}


Diagnostics:

None

AuxData:

None
Loading