Skip to content

Commit

Permalink
Migrate Initializable to component (#764)
Browse files Browse the repository at this point in the history
* update Scarb

* remove internal attr

* update initializable

* fix formatting

* fix spdx doc style

* use generate_trait attr

* change _comp to _component

* add blank line between component! and impl

* Apply suggestions from code review

Co-authored-by: Eric Nordelo <[email protected]>

---------

Co-authored-by: Eric Nordelo <[email protected]>
  • Loading branch information
andrew-fleming and ericnordelo authored Oct 12, 2023
1 parent b08d0e0 commit 0b77977
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 12 deletions.
17 changes: 13 additions & 4 deletions src/security/initializable.cairo
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts for Cairo v0.7.0 (security/initializable.cairo)

#[starknet::contract]
/// # Initializable Component
///
/// The Initializable component provides a simple mechanism that executes
/// logic once and only once. This can be useful for setting a contract's
/// initial state in scenarios where a constructor cannot be used.
#[starknet::component]
mod Initializable {
#[storage]
struct Storage {
Expand All @@ -13,12 +18,16 @@ mod Initializable {
}

#[generate_trait]
impl InternalImpl of InternalTrait {
fn is_initialized(self: @ContractState) -> bool {
impl InternalImpl<
TContractState, +HasComponent<TContractState>
> of InternalTrait<TContractState> {
/// Returns true if the using contract executed `initialize`.
fn is_initialized(self: @ComponentState<TContractState>) -> bool {
self.Initializable_initialized.read()
}

fn initialize(ref self: ContractState) {
/// Ensures the calling function can only be called once.
fn initialize(ref self: ComponentState<TContractState>) {
assert(!self.is_initialized(), Errors::INITIALIZED);
self.Initializable_initialized.write(true);
}
Expand Down
1 change: 1 addition & 0 deletions src/tests/mocks.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod dual721_receiver_mocks;
mod erc20_panic;
mod erc721_panic_mock;
mod erc721_receiver;
mod initializable_mock;
mod non_implementing_mock;
mod ownable_mocks;
mod reentrancy_attacker_mock;
Expand Down
20 changes: 20 additions & 0 deletions src/tests/mocks/initializable_mock.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#[starknet::contract]
mod InitializableMock {
use openzeppelin::security::initializable::Initializable as initializable_component;

component!(path: initializable_component, storage: initializable, event: InitializableEvent);

impl InternalImpl = initializable_component::InternalImpl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
initializable: initializable_component::Storage
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
InitializableEvent: initializable_component::Event
}
}
16 changes: 8 additions & 8 deletions src/tests/security/test_initializable.cairo
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
use openzeppelin::security::initializable::Initializable::InternalImpl;
use openzeppelin::security::initializable::Initializable;
use openzeppelin::tests::mocks::initializable_mock::InitializableMock;

fn STATE() -> Initializable::ContractState {
Initializable::contract_state_for_testing()
fn STATE() -> InitializableMock::ContractState {
InitializableMock::contract_state_for_testing()
}

#[test]
#[available_gas(2000000)]
fn test_initialize() {
let mut state = STATE();
assert(!InternalImpl::is_initialized(@state), 'Should not be initialized');
InternalImpl::initialize(ref state);
assert(InternalImpl::is_initialized(@state), 'Should be initialized');
assert(!state.initializable.is_initialized(), 'Should not be initialized');
state.initializable.initialize();
assert(state.initializable.is_initialized(), 'Should be initialized');
}

#[test]
#[available_gas(2000000)]
#[should_panic(expected: ('Initializable: is initialized',))]
fn test_initialize_when_initialized() {
let mut state = STATE();
InternalImpl::initialize(ref state);
InternalImpl::initialize(ref state);
state.initializable.initialize();
state.initializable.initialize();
}

0 comments on commit 0b77977

Please sign in to comment.