From 2eda08b035ea8f95a36d72cef8e6c49e2bae8d9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:32:38 +0100 Subject: [PATCH 1/4] Chore(deps): Bump crate-ci/typos from 1.27.1 to 1.27.2 (#1202) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.27.1 to 1.27.2. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/51e9d58a14d6c43eedf9356ab5b30ef4715d14c0...98325b27809ff86ca808bacada386a051a3515a3) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/typos.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/typos.yaml b/.github/workflows/typos.yaml index 8201ad030..52251bce2 100644 --- a/.github/workflows/typos.yaml +++ b/.github/workflows/typos.yaml @@ -10,4 +10,4 @@ jobs: uses: actions/checkout@v4 - name: Check for typos - uses: crate-ci/typos@51e9d58a14d6c43eedf9356ab5b30ef4715d14c0 + uses: crate-ci/typos@98325b27809ff86ca808bacada386a051a3515a3 From 5fec9a5cbbfc8bdaa6f29dd676d12a835faf08d2 Mon Sep 17 00:00:00 2001 From: Gustavo Gonzalez Date: Thu, 7 Nov 2024 12:52:49 -0400 Subject: [PATCH 2/4] Test token hooks (#1198) * erc20 hooks tests * add erc721 tests * use trait helper * simplify mocks * fmt * Update packages/test_common/src/mocks/erc20.cairo Co-authored-by: immrsd <103599616+immrsd@users.noreply.github.com> * remove unnecesary cheat * add erc1155 tests * rename mocks --------- Co-authored-by: immrsd <103599616+immrsd@users.noreply.github.com> --- packages/test_common/src/mocks/erc1155.cairo | 97 +++++++++++++++++++ packages/test_common/src/mocks/erc20.cairo | 81 ++++++++++++++++ packages/test_common/src/mocks/erc721.cairo | 93 ++++++++++++++++++ .../src/tests/erc1155/test_erc1155.cairo | 82 +++++++++++++++- .../token/src/tests/erc20/test_erc20.cairo | 71 +++++++++++++- .../token/src/tests/erc721/test_erc721.cairo | 69 ++++++++++++- 6 files changed, 487 insertions(+), 6 deletions(-) diff --git a/packages/test_common/src/mocks/erc1155.cairo b/packages/test_common/src/mocks/erc1155.cairo index 8c206e95e..6c98dd7b2 100644 --- a/packages/test_common/src/mocks/erc1155.cairo +++ b/packages/test_common/src/mocks/erc1155.cairo @@ -102,6 +102,103 @@ pub mod SnakeERC1155Mock { } } +/// Similar to `SnakeERC1155Mock`, but emits events for `before_update` and `after_update` hooks. +/// This is used to test that the hooks are called with the correct arguments. +#[starknet::contract] +pub mod SnakeERC1155MockWithHooks { + use openzeppelin_introspection::src5::SRC5Component; + use openzeppelin_token::erc1155::{ERC1155Component}; + use starknet::ContractAddress; + + component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + + // ERC1155 + #[abi(embed_v0)] + impl ERC1155Impl = ERC1155Component::ERC1155Impl; + #[abi(embed_v0)] + impl ERC1155MetadataURIImpl = + ERC1155Component::ERC1155MetadataURIImpl; + impl ERC1155InternalImpl = ERC1155Component::InternalImpl; + + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + + #[storage] + pub struct Storage { + #[substorage(v0)] + pub erc1155: ERC1155Component::Storage, + #[substorage(v0)] + pub src5: SRC5Component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + pub enum Event { + #[flat] + ERC1155Event: ERC1155Component::Event, + #[flat] + SRC5Event: SRC5Component::Event, + BeforeUpdate: BeforeUpdate, + AfterUpdate: AfterUpdate + } + + /// Event used to test that `before_update` hook is called. + #[derive(Drop, PartialEq, starknet::Event)] + pub struct BeforeUpdate { + pub from: ContractAddress, + pub to: ContractAddress, + pub token_ids: Span, + pub values: Span + } + + /// Event used to test that `after_update` hook is called. + #[derive(Drop, PartialEq, starknet::Event)] + pub struct AfterUpdate { + pub from: ContractAddress, + pub to: ContractAddress, + pub token_ids: Span, + pub values: Span + } + + #[constructor] + fn constructor( + ref self: ContractState, + base_uri: ByteArray, + recipient: ContractAddress, + token_id: u256, + value: u256 + ) { + self.erc1155.initializer(base_uri); + self.erc1155.mint_with_acceptance_check(recipient, token_id, value, array![].span()); + } + + impl ERC1155HooksImpl of ERC1155Component::ERC1155HooksTrait { + fn before_update( + ref self: ERC1155Component::ComponentState, + from: ContractAddress, + to: ContractAddress, + token_ids: Span, + values: Span + ) { + let mut contract_state = self.get_contract_mut(); + contract_state.emit(BeforeUpdate { from, to, token_ids, values }); + } + + fn after_update( + ref self: ERC1155Component::ComponentState, + from: ContractAddress, + to: ContractAddress, + token_ids: Span, + values: Span + ) { + let mut contract_state = self.get_contract_mut(); + contract_state.emit(AfterUpdate { from, to, token_ids, values }); + } + } +} + #[starknet::contract] pub mod DualCaseERC1155ReceiverMock { use openzeppelin_introspection::src5::SRC5Component; diff --git a/packages/test_common/src/mocks/erc20.cairo b/packages/test_common/src/mocks/erc20.cairo index a77d3275c..818dc0917 100644 --- a/packages/test_common/src/mocks/erc20.cairo +++ b/packages/test_common/src/mocks/erc20.cairo @@ -78,6 +78,87 @@ pub mod SnakeERC20Mock { } } +/// Similar to `SnakeERC20Mock`, but emits events for `before_update` and `after_update` hooks. +/// This is used to test that the hooks are called with the correct arguments. +#[starknet::contract] +pub mod SnakeERC20MockWithHooks { + use openzeppelin_token::erc20::ERC20Component; + use starknet::ContractAddress; + + component!(path: ERC20Component, storage: erc20, event: ERC20Event); + + #[abi(embed_v0)] + impl ERC20Impl = ERC20Component::ERC20Impl; + #[abi(embed_v0)] + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl; + impl InternalImpl = ERC20Component::InternalImpl; + + #[storage] + pub struct Storage { + #[substorage(v0)] + pub erc20: ERC20Component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + pub enum Event { + #[flat] + ERC20Event: ERC20Component::Event, + BeforeUpdate: BeforeUpdate, + AfterUpdate: AfterUpdate + } + + /// Event used to test that `before_update` hook is called. + #[derive(Drop, PartialEq, starknet::Event)] + pub struct BeforeUpdate { + pub from: ContractAddress, + pub recipient: ContractAddress, + pub amount: u256 + } + + /// Event used to test that `after_update` hook is called. + #[derive(Drop, PartialEq, starknet::Event)] + pub struct AfterUpdate { + pub from: ContractAddress, + pub recipient: ContractAddress, + pub amount: u256 + } + + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + initial_supply: u256, + recipient: ContractAddress + ) { + self.erc20.initializer(name, symbol); + self.erc20.mint(recipient, initial_supply); + } + + impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait { + fn before_update( + ref self: ERC20Component::ComponentState, + from: ContractAddress, + recipient: ContractAddress, + amount: u256 + ) { + let mut contract_state = self.get_contract_mut(); + contract_state.emit(BeforeUpdate { from, recipient, amount }); + } + + fn after_update( + ref self: ERC20Component::ComponentState, + from: ContractAddress, + recipient: ContractAddress, + amount: u256 + ) { + let mut contract_state = self.get_contract_mut(); + contract_state.emit(AfterUpdate { from, recipient, amount }); + } + } +} + #[starknet::contract] pub mod DualCaseERC20PermitMock { use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl}; diff --git a/packages/test_common/src/mocks/erc721.cairo b/packages/test_common/src/mocks/erc721.cairo index 3d9be74a2..054b45258 100644 --- a/packages/test_common/src/mocks/erc721.cairo +++ b/packages/test_common/src/mocks/erc721.cairo @@ -107,6 +107,99 @@ pub mod SnakeERC721Mock { } } +/// Similar as `SnakeERC721Mock`, but emits events for `before_update` and `after_update` hooks. +/// This is used to test that the hooks are called with the correct arguments. +#[starknet::contract] +pub mod SnakeERC721MockWithHooks { + use openzeppelin_introspection::src5::SRC5Component; + use openzeppelin_token::erc721::ERC721Component; + use starknet::ContractAddress; + + component!(path: ERC721Component, storage: erc721, event: ERC721Event); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + + // ERC721 + #[abi(embed_v0)] + impl ERC721Impl = ERC721Component::ERC721Impl; + #[abi(embed_v0)] + impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl; + impl ERC721InternalImpl = ERC721Component::InternalImpl; + + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + + #[storage] + pub struct Storage { + #[substorage(v0)] + pub erc721: ERC721Component::Storage, + #[substorage(v0)] + pub src5: SRC5Component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + pub enum Event { + #[flat] + ERC721Event: ERC721Component::Event, + #[flat] + SRC5Event: SRC5Component::Event, + BeforeUpdate: BeforeUpdate, + AfterUpdate: AfterUpdate + } + + /// Event used to test that `before_update` hook is called. + #[derive(Drop, PartialEq, starknet::Event)] + pub struct BeforeUpdate { + pub to: ContractAddress, + pub token_id: u256, + pub auth: ContractAddress + } + + /// Event used to test that `after_update` hook is called. + #[derive(Drop, PartialEq, starknet::Event)] + pub struct AfterUpdate { + pub to: ContractAddress, + pub token_id: u256, + pub auth: ContractAddress + } + + #[constructor] + fn constructor( + ref self: ContractState, + name: ByteArray, + symbol: ByteArray, + base_uri: ByteArray, + recipient: ContractAddress, + token_id: u256 + ) { + self.erc721.initializer(name, symbol, base_uri); + self.erc721.mint(recipient, token_id); + } + + impl ERC721HooksImpl of ERC721Component::ERC721HooksTrait { + fn before_update( + ref self: ERC721Component::ComponentState, + to: ContractAddress, + token_id: u256, + auth: ContractAddress + ) { + let mut contract_state = self.get_contract_mut(); + contract_state.emit(BeforeUpdate { to, token_id, auth }); + } + + fn after_update( + ref self: ERC721Component::ComponentState, + to: ContractAddress, + token_id: u256, + auth: ContractAddress + ) { + let mut contract_state = self.get_contract_mut(); + contract_state.emit(AfterUpdate { to, token_id, auth }); + } + } +} + #[starknet::contract] pub mod DualCaseERC721ReceiverMock { use openzeppelin_introspection::src5::SRC5Component; diff --git a/packages/token/src/tests/erc1155/test_erc1155.cairo b/packages/token/src/tests/erc1155/test_erc1155.cairo index f1bad9234..4e1bc6a3a 100644 --- a/packages/token/src/tests/erc1155/test_erc1155.cairo +++ b/packages/token/src/tests/erc1155/test_erc1155.cairo @@ -10,12 +10,14 @@ use openzeppelin_test_common::erc1155::{ use openzeppelin_test_common::erc1155::{ setup_account, deploy_another_account_at, setup_src5, setup_receiver }; -use openzeppelin_test_common::mocks::erc1155::DualCaseERC1155Mock; +use openzeppelin_test_common::mocks::erc1155::{DualCaseERC1155Mock, SnakeERC1155MockWithHooks}; use openzeppelin_testing::constants::{ EMPTY_DATA, ZERO, OWNER, RECIPIENT, OPERATOR, OTHER, TOKEN_ID, TOKEN_ID_2, TOKEN_VALUE, TOKEN_VALUE_2 }; -use snforge_std::{spy_events, test_address, start_cheat_caller_address}; +use openzeppelin_testing::events::EventSpyExt; + +use snforge_std::{EventSpy, spy_events, test_address, start_cheat_caller_address}; use starknet::ContractAddress; use starknet::storage::StoragePointerReadAccess; @@ -24,6 +26,8 @@ use starknet::storage::StoragePointerReadAccess; // type ComponentState = ERC1155Component::ComponentState; +type ComponentStateWithHooks = + ERC1155Component::ComponentState; fn CONTRACT_STATE() -> DualCaseERC1155Mock::ContractState { DualCaseERC1155Mock::contract_state_for_testing() @@ -31,6 +35,9 @@ fn CONTRACT_STATE() -> DualCaseERC1155Mock::ContractState { fn COMPONENT_STATE() -> ComponentState { ERC1155Component::component_state_for_testing() } +fn COMPONENT_STATE_WITH_HOOKS() -> ComponentStateWithHooks { + ERC1155Component::component_state_for_testing() +} fn setup() -> (ComponentState, ContractAddress) { let mut state = COMPONENT_STATE(); @@ -45,6 +52,19 @@ fn setup() -> (ComponentState, ContractAddress) { (state, owner) } +fn setup_with_hooks() -> (ComponentStateWithHooks, ContractAddress) { + let mut state = COMPONENT_STATE_WITH_HOOKS(); + state.initializer("URI"); + + let owner = setup_account(); + let token_ids = array![TOKEN_ID, TOKEN_ID_2].span(); + let values = array![TOKEN_VALUE, TOKEN_VALUE_2].span(); + + state.batch_mint_with_acceptance_check(owner, token_ids, values, array![].span()); + + (state, owner) +} + // // Initializers // @@ -811,6 +831,34 @@ fn test_update_insufficient_balance() { state.update(owner, recipient, token_ids, values); } +#[test] +fn test_update_calls_before_update_hook() { + let (mut state, owner) = setup_with_hooks(); + let recipient = RECIPIENT(); + let token_ids = array![TOKEN_ID].span(); + let values = array![TOKEN_VALUE].span(); + + let mut spy = spy_events(); + let contract_address = test_address(); + + state.update(owner, recipient, token_ids, values); + spy.assert_event_before_update(contract_address, owner, recipient, token_ids, values); +} + +#[test] +fn test_update_calls_after_update_hook() { + let (mut state, owner) = setup_with_hooks(); + let recipient = RECIPIENT(); + let token_ids = array![TOKEN_ID].span(); + let values = array![TOKEN_VALUE].span(); + + let mut spy = spy_events(); + let contract_address = test_address(); + + state.update(owner, recipient, token_ids, values); + spy.assert_event_after_update(contract_address, owner, recipient, token_ids, values); +} + // // update_with_acceptance_check @@ -1328,3 +1376,33 @@ fn assert_state_after_transfer_from_zero_batch( } } +#[generate_trait] +impl ERC1155HooksSpyHelpersImpl of ERC1155HooksSpyHelpers { + fn assert_event_before_update( + ref self: EventSpy, + contract: ContractAddress, + from: ContractAddress, + to: ContractAddress, + token_ids: Span, + values: Span + ) { + let expected = SnakeERC1155MockWithHooks::Event::BeforeUpdate( + SnakeERC1155MockWithHooks::BeforeUpdate { from, to, token_ids, values } + ); + self.assert_emitted_single(contract, expected); + } + + fn assert_event_after_update( + ref self: EventSpy, + contract: ContractAddress, + from: ContractAddress, + to: ContractAddress, + token_ids: Span, + values: Span + ) { + let expected = SnakeERC1155MockWithHooks::Event::AfterUpdate( + SnakeERC1155MockWithHooks::AfterUpdate { from, to, token_ids, values } + ); + self.assert_emitted_single(contract, expected); + } +} diff --git a/packages/token/src/tests/erc20/test_erc20.cairo b/packages/token/src/tests/erc20/test_erc20.cairo index 1d8c4451a..1d1deeb8a 100644 --- a/packages/token/src/tests/erc20/test_erc20.cairo +++ b/packages/token/src/tests/erc20/test_erc20.cairo @@ -3,11 +3,12 @@ use crate::erc20::ERC20Component::{ERC20CamelOnlyImpl, ERC20Impl}; use crate::erc20::ERC20Component::{ERC20MetadataImpl, InternalImpl}; use crate::erc20::ERC20Component; use openzeppelin_test_common::erc20::ERC20SpyHelpers; -use openzeppelin_test_common::mocks::erc20::DualCaseERC20Mock; +use openzeppelin_test_common::mocks::erc20::{DualCaseERC20Mock, SnakeERC20MockWithHooks}; use openzeppelin_testing::constants::{ ZERO, OWNER, SPENDER, RECIPIENT, NAME, SYMBOL, DECIMALS, SUPPLY, VALUE }; -use snforge_std::{spy_events, test_address, start_cheat_caller_address}; +use openzeppelin_testing::events::EventSpyExt; +use snforge_std::{EventSpy, spy_events, test_address, start_cheat_caller_address}; use starknet::ContractAddress; // @@ -15,11 +16,17 @@ use starknet::ContractAddress; // type ComponentState = ERC20Component::ComponentState; +type ComponentStateWithHooks = + ERC20Component::ComponentState; fn COMPONENT_STATE() -> ComponentState { ERC20Component::component_state_for_testing() } +fn COMPONENT_STATE_WITH_HOOKS() -> ComponentStateWithHooks { + ERC20Component::component_state_for_testing() +} + fn setup() -> ComponentState { let mut state = COMPONENT_STATE(); state.initializer(NAME(), SYMBOL()); @@ -27,6 +34,13 @@ fn setup() -> ComponentState { state } +fn setup_with_hooks() -> ComponentStateWithHooks { + let mut state = COMPONENT_STATE_WITH_HOOKS(); + state.initializer(NAME(), SYMBOL()); + state.mint(OWNER(), SUPPLY); + state +} + // // initializer & constructor // @@ -552,6 +566,30 @@ fn test_update_from_zero_to_zero() { spy.assert_only_event_transfer(contract_address, ZERO(), ZERO(), VALUE); } +#[test] +fn test_update_calls_before_update_hook() { + let mut state = setup_with_hooks(); + + let mut spy = spy_events(); + let contract_address = test_address(); + + state.update(OWNER(), RECIPIENT(), VALUE); + + spy.assert_event_before_update(contract_address, OWNER(), RECIPIENT(), VALUE); +} + +#[test] +fn test_update_calls_after_update_hook() { + let mut state = setup_with_hooks(); + + let mut spy = spy_events(); + let contract_address = test_address(); + + state.update(OWNER(), RECIPIENT(), VALUE); + + spy.assert_event_after_update(contract_address, OWNER(), RECIPIENT(), VALUE); +} + // // Helpers // @@ -611,3 +649,32 @@ fn assert_state_after_burn(account: ContractAddress, amount: u256) { assert_eq!(current_supply, initial_supply - amount); assert_eq!(state.balance_of(account), initial_supply - amount); } + +#[generate_trait] +impl ERC20HooksSpyHelpersImpl of ERC20HooksSpyHelpers { + fn assert_event_before_update( + ref self: EventSpy, + contract: ContractAddress, + from: ContractAddress, + recipient: ContractAddress, + amount: u256 + ) { + let expected = SnakeERC20MockWithHooks::Event::BeforeUpdate( + SnakeERC20MockWithHooks::BeforeUpdate { from, recipient, amount } + ); + self.assert_emitted_single(contract, expected); + } + + fn assert_event_after_update( + ref self: EventSpy, + contract: ContractAddress, + from: ContractAddress, + recipient: ContractAddress, + amount: u256 + ) { + let expected = SnakeERC20MockWithHooks::Event::AfterUpdate( + SnakeERC20MockWithHooks::AfterUpdate { from, recipient, amount } + ); + self.assert_emitted_single(contract, expected); + } +} diff --git a/packages/token/src/tests/erc721/test_erc721.cairo b/packages/token/src/tests/erc721/test_erc721.cairo index 03e9826f2..51882720a 100644 --- a/packages/token/src/tests/erc721/test_erc721.cairo +++ b/packages/token/src/tests/erc721/test_erc721.cairo @@ -5,14 +5,14 @@ use crate::erc721::ERC721Component; use crate::erc721; use openzeppelin_introspection::src5::SRC5Component::SRC5Impl; use openzeppelin_test_common::erc721::ERC721SpyHelpers; -use openzeppelin_test_common::mocks::erc721::DualCaseERC721Mock; +use openzeppelin_test_common::mocks::erc721::{DualCaseERC721Mock, SnakeERC721MockWithHooks}; use openzeppelin_testing as utils; use openzeppelin_testing::constants::{ DATA, ZERO, OWNER, CALLER, RECIPIENT, SPENDER, OPERATOR, OTHER, NAME, SYMBOL, TOKEN_ID, TOKEN_ID_2, PUBKEY, BASE_URI, BASE_URI_2 }; use openzeppelin_testing::events::EventSpyExt; -use snforge_std::{spy_events, test_address, start_cheat_caller_address}; +use snforge_std::{EventSpy, spy_events, test_address, start_cheat_caller_address}; use starknet::ContractAddress; use starknet::storage::StorageMapReadAccess; @@ -21,6 +21,8 @@ use starknet::storage::StorageMapReadAccess; // type ComponentState = ERC721Component::ComponentState; +type ComponentStateWithHooks = + ERC721Component::ComponentState; fn CONTRACT_STATE() -> DualCaseERC721Mock::ContractState { DualCaseERC721Mock::contract_state_for_testing() @@ -28,6 +30,9 @@ fn CONTRACT_STATE() -> DualCaseERC721Mock::ContractState { fn COMPONENT_STATE() -> ComponentState { ERC721Component::component_state_for_testing() } +fn COMPONENT_STATE_WITH_HOOKS() -> ComponentStateWithHooks { + ERC721Component::component_state_for_testing() +} fn setup() -> ComponentState { let mut state = COMPONENT_STATE(); @@ -36,6 +41,13 @@ fn setup() -> ComponentState { state } +fn setup_with_hooks() -> ComponentStateWithHooks { + let mut state = COMPONENT_STATE_WITH_HOOKS(); + state.initializer(NAME(), SYMBOL(), BASE_URI()); + state.mint(OWNER(), TOKEN_ID); + state +} + fn setup_receiver() -> ContractAddress { utils::declare_and_deploy("DualCaseERC721ReceiverMock", array![]) } @@ -1385,6 +1397,30 @@ fn test_update_mint_auth_not_zero() { state.update(RECIPIENT(), TOKEN_ID_2, CALLER()); } +#[test] +fn test_update_calls_before_update_hook() { + let mut state = setup_with_hooks(); + + let mut spy = spy_events(); + let contract_address = test_address(); + + state.update(RECIPIENT(), TOKEN_ID, OWNER()); + + spy.assert_event_before_update(contract_address, RECIPIENT(), TOKEN_ID, OWNER()); +} + +#[test] +fn test_update_calls_after_update_hook() { + let mut state = setup_with_hooks(); + + let mut spy = spy_events(); + let contract_address = test_address(); + + state.update(RECIPIENT(), TOKEN_ID, OWNER()); + + spy.assert_event_after_update(contract_address, RECIPIENT(), TOKEN_ID, OWNER()) +} + // // Helpers // @@ -1417,3 +1453,32 @@ fn assert_state_after_mint(recipient: ContractAddress, token_id: u256) { assert_eq!(state.balance_of(recipient), 1); assert!(state.get_approved(token_id).is_zero()); } + +#[generate_trait] +impl ERC721HooksSpyHelpersImpl of ERC721HooksSpyHelpers { + fn assert_event_before_update( + ref self: EventSpy, + contract: ContractAddress, + to: ContractAddress, + token_id: u256, + auth: ContractAddress + ) { + let expected = SnakeERC721MockWithHooks::Event::BeforeUpdate( + SnakeERC721MockWithHooks::BeforeUpdate { to, token_id, auth } + ); + self.assert_emitted_single(contract, expected); + } + + fn assert_event_after_update( + ref self: EventSpy, + contract: ContractAddress, + to: ContractAddress, + token_id: u256, + auth: ContractAddress + ) { + let expected = SnakeERC721MockWithHooks::Event::AfterUpdate( + SnakeERC721MockWithHooks::AfterUpdate { to, token_id, auth } + ); + self.assert_emitted_single(contract, expected); + } +} From 90bc3178ac75e94c3b00bef304bf97fc86640d11 Mon Sep 17 00:00:00 2001 From: immrsd <103599616+immrsd@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:21:10 +0100 Subject: [PATCH 3/4] Multisig (#1193) * Add Multisig initial implementation * Edit error messages * Change Multisig naming: quorum instead of threshold * Add Multisig mock * Refactor Multisig not to store calls * Add Multisig target mock * Cover Multisig functionality with tests * Add tests for signer management functionality * Add more test cases for Multisig * Run linter * Address review comments * Support review fixes in tests * Change quorum and confirmations types to u32 * Optimize Multisig storage usage * Solve confirmation issue when signer is removed * Update changelog * Fix review issues * Run linter * Add breaking change entry to changelog * Make review fixes * Fix review issues * Document storage helpers * Document events * Document Multisig component itself * Document all the Multisig functions * Run linter * Make minor doc fixes * Fix in-code doc according to review comments * Improve couple of comments --- CHANGELOG.md | 2 + packages/account/src/account.cairo | 4 +- packages/governance/Scarb.toml | 1 + packages/governance/src/lib.cairo | 3 + packages/governance/src/multisig.cairo | 6 + .../governance/src/multisig/interface.cairo | 65 + .../governance/src/multisig/multisig.cairo | 645 +++++++ .../src/multisig/storage_utils.cairo | 65 + packages/governance/src/tests.cairo | 1 + .../governance/src/tests/test_multisig.cairo | 1588 +++++++++++++++++ .../governance/src/tests/test_utils.cairo | 2 +- packages/governance/src/timelock.cairo | 1 - .../src/timelock/timelock_controller.cairo | 8 +- .../governance/src/{timelock => }/utils.cairo | 0 .../src/{timelock => }/utils/call_impls.cairo | 4 +- packages/test_common/src/mocks.cairo | 1 + packages/test_common/src/mocks/multisig.cairo | 61 + packages/testing/src/constants.cairo | 13 + 18 files changed, 2459 insertions(+), 11 deletions(-) create mode 100644 packages/governance/src/multisig.cairo create mode 100644 packages/governance/src/multisig/interface.cairo create mode 100644 packages/governance/src/multisig/multisig.cairo create mode 100644 packages/governance/src/multisig/storage_utils.cairo create mode 100644 packages/governance/src/tests/test_multisig.cairo rename packages/governance/src/{timelock => }/utils.cairo (100%) rename packages/governance/src/{timelock => }/utils/call_impls.cairo (91%) create mode 100644 packages/test_common/src/mocks/multisig.cairo diff --git a/CHANGELOG.md b/CHANGELOG.md index f0c630e04..2c420ba1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Multisig component (#1193) - `is_valid_p256_signature` utility function to `openzeppelin_account::utils::signature` (#1189) - `Secp256r1KeyPair` type and helpers to `openzeppelin_testing::signing` (#1189) - `all_tokens_of_owner` function to `ERC721EnumerableComponent` fetching all owner's tokens in a single call (#1196) @@ -27,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `DebugSecp256k1Point` replaced by a generic `DebugSecp256Point` - Apply underscore pattern to the internal functions of `ERC2981Component` to prevent collisions with new external functions (#1173) +- Move `Hash` and `PartialEq` impls of `Call` struct from `openzeppelin_governance::timelock::utils` to `openzeppelin_governance::utils` (#1193) ## 0.18.0 (2024-10-17) diff --git a/packages/account/src/account.cairo b/packages/account/src/account.cairo index 6582a6245..53957dbbe 100644 --- a/packages/account/src/account.cairo +++ b/packages/account/src/account.cairo @@ -16,10 +16,8 @@ pub mod AccountComponent { use openzeppelin_introspection::src5::SRC5Component::SRC5Impl; use openzeppelin_introspection::src5::SRC5Component; use starknet::account::Call; - use starknet::get_caller_address; - use starknet::get_contract_address; - use starknet::get_tx_info; use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + use starknet::{get_caller_address, get_contract_address, get_tx_info}; #[storage] pub struct Storage { diff --git a/packages/governance/Scarb.toml b/packages/governance/Scarb.toml index 5ab2fc5d2..d32d87a15 100644 --- a/packages/governance/Scarb.toml +++ b/packages/governance/Scarb.toml @@ -49,6 +49,7 @@ build-external-contracts = [ "openzeppelin_test_common::mocks::timelock::TimelockControllerMock", "openzeppelin_test_common::mocks::timelock::MockContract", "openzeppelin_test_common::mocks::timelock::TimelockAttackerMock", + "openzeppelin_test_common::mocks::multisig::MultisigTargetMock", "openzeppelin_test_common::mocks::votes::ERC721VotesMock", "openzeppelin_test_common::mocks::votes::ERC20VotesMock" ] diff --git a/packages/governance/src/lib.cairo b/packages/governance/src/lib.cairo index 0b56faddc..041e1b05e 100644 --- a/packages/governance/src/lib.cairo +++ b/packages/governance/src/lib.cairo @@ -1,5 +1,8 @@ +pub mod multisig; + #[cfg(test)] mod tests; pub mod timelock; +pub mod utils; pub mod votes; diff --git a/packages/governance/src/multisig.cairo b/packages/governance/src/multisig.cairo new file mode 100644 index 000000000..8faab868a --- /dev/null +++ b/packages/governance/src/multisig.cairo @@ -0,0 +1,6 @@ +pub mod interface; +pub mod multisig; +pub mod storage_utils; + +pub use interface::{TransactionID, TransactionState}; +pub use multisig::MultisigComponent; diff --git a/packages/governance/src/multisig/interface.cairo b/packages/governance/src/multisig/interface.cairo new file mode 100644 index 000000000..ccc872a50 --- /dev/null +++ b/packages/governance/src/multisig/interface.cairo @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.18.0 (governance/multisig/interface.cairo) + +use starknet::ContractAddress; +use starknet::account::Call; + +pub type TransactionID = felt252; + +/// Represents the possible states of a Multisig transaction. +#[derive(Copy, Drop, Serde, PartialEq, Debug)] +pub enum TransactionState { + NotFound, + Pending, + Confirmed, + Executed +} + +/// Interface of a contract providing the Multisig functionality. +#[starknet::interface] +pub trait IMultisig { + fn get_quorum(self: @TState) -> u32; + fn is_signer(self: @TState, signer: ContractAddress) -> bool; + fn get_signers(self: @TState) -> Span; + fn is_confirmed(self: @TState, id: TransactionID) -> bool; + fn is_confirmed_by(self: @TState, id: TransactionID, signer: ContractAddress) -> bool; + fn is_executed(self: @TState, id: TransactionID) -> bool; + fn get_submitted_block(self: @TState, id: TransactionID) -> u64; + fn get_transaction_state(self: @TState, id: TransactionID) -> TransactionState; + fn get_transaction_confirmations(self: @TState, id: TransactionID) -> u32; + fn hash_transaction( + self: @TState, + to: ContractAddress, + selector: felt252, + calldata: Span, + salt: felt252 + ) -> TransactionID; + fn hash_transaction_batch(self: @TState, calls: Span, salt: felt252) -> TransactionID; + + fn add_signers(ref self: TState, new_quorum: u32, signers_to_add: Span); + fn remove_signers(ref self: TState, new_quorum: u32, signers_to_remove: Span); + fn replace_signer( + ref self: TState, signer_to_remove: ContractAddress, signer_to_add: ContractAddress + ); + fn change_quorum(ref self: TState, new_quorum: u32); + fn submit_transaction( + ref self: TState, + to: ContractAddress, + selector: felt252, + calldata: Span, + salt: felt252, + ) -> TransactionID; + fn submit_transaction_batch( + ref self: TState, calls: Span, salt: felt252 + ) -> TransactionID; + fn confirm_transaction(ref self: TState, id: TransactionID); + fn revoke_confirmation(ref self: TState, id: TransactionID); + fn execute_transaction( + ref self: TState, + to: ContractAddress, + selector: felt252, + calldata: Span, + salt: felt252 + ); + fn execute_transaction_batch(ref self: TState, calls: Span, salt: felt252); +} diff --git a/packages/governance/src/multisig/multisig.cairo b/packages/governance/src/multisig/multisig.cairo new file mode 100644 index 000000000..4056a6189 --- /dev/null +++ b/packages/governance/src/multisig/multisig.cairo @@ -0,0 +1,645 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.18.0 (governance/multisig/multisig.cairo) + +/// # Multisig Component +/// +/// Component that implements a multi-signature mechanism to enhance the security and governance +/// of smart contract transactions. It requires multiple registered signers to collectively approve +/// and execute transactions, ensuring that no single signer can perform critical actions +/// unilaterally. +/// +/// By default, this component is self-administered, meaning modifications to signers or quorum must +/// be performed by the contract itself through the multisig approval process. Only registered +/// signers can submit, confirm, revoke, or execute transactions. A common use case is to secure +/// important operations by requiring multiple approvals, such as in fund management or protocol +/// governance. +#[starknet::component] +pub mod MultisigComponent { + use core::hash::{HashStateTrait, HashStateExTrait}; + use core::num::traits::Zero; + use core::panic_with_felt252; + use core::pedersen::PedersenTrait; + use crate::multisig::interface::{IMultisig, TransactionID, TransactionState}; + use crate::multisig::storage_utils::{SignersInfo, SignersInfoStorePacking}; + use crate::multisig::storage_utils::{TxInfo, TxInfoStorePacking}; + use crate::utils::call_impls::{HashCallImpl, HashCallsImpl, CallPartialEq}; + use starknet::account::Call; + use starknet::storage::{Map, StorageMapReadAccess, StorageMapWriteAccess}; + use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + use starknet::syscalls::call_contract_syscall; + use starknet::{ContractAddress, SyscallResultTrait}; + + #[storage] + pub struct Storage { + pub Multisig_signers_info: SignersInfo, + pub Multisig_is_signer: Map, + pub Multisig_signers_by_index: Map, + pub Multisig_signers_indices: Map, + pub Multisig_tx_info: Map, + pub Multisig_tx_confirmed_by: Map<(TransactionID, ContractAddress), bool> + } + + #[event] + #[derive(Drop, starknet::Event)] + pub enum Event { + SignerAdded: SignerAdded, + SignerRemoved: SignerRemoved, + QuorumUpdated: QuorumUpdated, + TransactionSubmitted: TransactionSubmitted, + TransactionConfirmed: TransactionConfirmed, + TransactionExecuted: TransactionExecuted, + ConfirmationRevoked: ConfirmationRevoked, + CallSalt: CallSalt + } + + /// Emitted when a new `signer` is added. + #[derive(Drop, starknet::Event)] + pub struct SignerAdded { + #[key] + pub signer: ContractAddress + } + + /// Emitted when a `signer` is removed. + #[derive(Drop, starknet::Event)] + pub struct SignerRemoved { + #[key] + pub signer: ContractAddress + } + + /// Emitted when the `quorum` value is updated. + #[derive(Drop, starknet::Event)] + pub struct QuorumUpdated { + pub old_quorum: u32, + pub new_quorum: u32 + } + + /// Emitted when a new transaction is submitted by a `signer`. + #[derive(Drop, starknet::Event)] + pub struct TransactionSubmitted { + #[key] + pub id: TransactionID, + #[key] + pub signer: ContractAddress + } + + /// Emitted when a transaction is confirmed by a `signer`. + #[derive(Drop, starknet::Event)] + pub struct TransactionConfirmed { + #[key] + pub id: TransactionID, + #[key] + pub signer: ContractAddress + } + + /// Emitted when a `signer` revokes his confirmation. + #[derive(Drop, starknet::Event)] + pub struct ConfirmationRevoked { + #[key] + pub id: TransactionID, + #[key] + pub signer: ContractAddress + } + + /// Emitted when a transaction is executed. + #[derive(Drop, starknet::Event)] + pub struct TransactionExecuted { + #[key] + pub id: TransactionID + } + + /// Emitted when a new transaction is submitted with non-zero salt. + #[derive(Drop, PartialEq, starknet::Event)] + pub struct CallSalt { + #[key] + pub id: felt252, + pub salt: felt252 + } + + pub mod Errors { + pub const UNAUTHORIZED: felt252 = 'Multisig: unauthorized'; + pub const NOT_A_SIGNER: felt252 = 'Multisig: not a signer'; + pub const ALREADY_A_SIGNER: felt252 = 'Multisig: already a signer'; + pub const ALREADY_CONFIRMED: felt252 = 'Multisig: already confirmed'; + pub const HAS_NOT_CONFIRMED: felt252 = 'Multisig: has not confirmed'; + pub const TX_ALREADY_EXISTS: felt252 = 'Multisig: tx already exists'; + pub const TX_NOT_FOUND: felt252 = 'Multisig: tx not found'; + pub const TX_NOT_CONFIRMED: felt252 = 'Multisig: tx not confirmed'; + pub const TX_ALREADY_EXECUTED: felt252 = 'Multisig: tx already executed'; + pub const ZERO_ADDRESS_SIGNER: felt252 = 'Multisig: zero address signer'; + pub const ZERO_QUORUM: felt252 = 'Multisig: quorum cannot be 0'; + pub const QUORUM_TOO_HIGH: felt252 = 'Multisig: quorum > signers'; + } + + #[embeddable_as(MultisigImpl)] + impl Multisig< + TContractState, +HasComponent, +Drop + > of IMultisig> { + /// Returns the current quorum value. The quorum is the minimum number + /// of confirmations required to approve a transaction. + fn get_quorum(self: @ComponentState) -> u32 { + self.Multisig_signers_info.read().quorum + } + + /// Returns whether the given `signer` is a registered signer. + /// Only registered signers can submit, confirm, or execute transactions. + fn is_signer(self: @ComponentState, signer: ContractAddress) -> bool { + self.Multisig_is_signer.read(signer) + } + + /// Returns the list of all current signers. + fn get_signers(self: @ComponentState) -> Span { + let mut result = array![]; + let signers_count = self.Multisig_signers_info.read().signers_count; + for i in 0..signers_count { + result.append(self.Multisig_signers_by_index.read(i)); + }; + result.span() + } + + /// Returns whether the transaction with the given `id` has been confirmed. + /// A confirmed transaction has received the required number of confirmations (quorum). + fn is_confirmed(self: @ComponentState, id: TransactionID) -> bool { + match self.resolve_tx_state(id) { + TransactionState::NotFound => false, + TransactionState::Pending => false, + TransactionState::Confirmed => true, + TransactionState::Executed => true + } + } + + /// Returns whether the transaction with the given `id` has been confirmed by the specified + /// `signer`. + /// + /// NOTE: Even if a `signer` is removed after confirming a transaction, this function will + /// still return true. However, their confirmation does not count toward the quorum when it + /// is checked. Therefore, this function should not be relied upon to verify legitimate + /// confirmations toward meeting the quorum. + fn is_confirmed_by( + self: @ComponentState, id: TransactionID, signer: ContractAddress + ) -> bool { + self.Multisig_tx_confirmed_by.read((id, signer)) + } + + /// Returns whether the transaction with the given `id` has been executed. + fn is_executed(self: @ComponentState, id: TransactionID) -> bool { + self.Multisig_tx_info.read(id).is_executed + } + + /// Returns the current state of the transaction with the given `id`. + /// + /// The possible states are: + /// - `NotFound`: The transaction does not exist. + /// - `Pending`: The transaction exists but hasn't reached the required confirmations. + /// - `Confirmed`: The transaction has reached the required confirmations but hasn't been + /// executed. + /// - `Executed`: The transaction has been executed. + fn get_transaction_state( + self: @ComponentState, id: TransactionID + ) -> TransactionState { + self.resolve_tx_state(id) + } + + /// Returns the number of confirmations from registered signers for the transaction with the + /// specified `id`. + fn get_transaction_confirmations( + self: @ComponentState, id: TransactionID + ) -> u32 { + let mut result = 0; + let all_signers = self.get_signers(); + for signer in all_signers { + if self.is_confirmed_by(id, *signer) { + result += 1; + } + }; + result + } + + /// Returns the block number when the transaction with the given `id` was submitted. + fn get_submitted_block(self: @ComponentState, id: TransactionID) -> u64 { + self.Multisig_tx_info.read(id).submitted_block + } + + /// Adds new signers and updates the quorum. + /// + /// Requirements: + /// + /// - The caller must be the contract itself. + /// - `new_quorum` must be less than or equal to the total number of signers after addition. + /// + /// Emits a `SignerAdded` event for each signer added. + fn add_signers( + ref self: ComponentState, + new_quorum: u32, + signers_to_add: Span + ) { + self.assert_only_self(); + self._add_signers(new_quorum, signers_to_add); + } + + /// Removes signers and updates the quorum. + /// + /// Requirements: + /// + /// - The caller must be the contract itself. + /// - `new_quorum` must be less than or equal to the total number of signers after removal. + /// + /// Emits a `SignerRemoved` event for each signer removed. + fn remove_signers( + ref self: ComponentState, + new_quorum: u32, + signers_to_remove: Span + ) { + self.assert_only_self(); + self._remove_signers(new_quorum, signers_to_remove); + } + + /// Replaces an existing signer with a new signer. + /// + /// Requirements: + /// + /// - The caller must be the contract itself. + /// - `signer_to_remove` must be an existing signer. + /// - `signer_to_add` must not be an existing signer. + /// + /// Emits a `SignerRemoved` event for the removed signer. + /// Emits a `SignerAdded` event for the new signer. + fn replace_signer( + ref self: ComponentState, + signer_to_remove: ContractAddress, + signer_to_add: ContractAddress + ) { + self.assert_only_self(); + self._replace_signer(signer_to_remove, signer_to_add); + } + + /// Updates the quorum value to `new_quorum` if it differs from the current quorum. + /// + /// Requirements: + /// + /// - The caller must be the contract itself. + /// - `new_quorum` must be non-zero. + /// - `new_quorum` must be less than or equal to the total number of signers. + /// + /// Emits a `QuorumUpdated` event if the quorum changes. + fn change_quorum(ref self: ComponentState, new_quorum: u32) { + self.assert_only_self(); + self._change_quorum(new_quorum); + } + + /// Submits a new transaction for confirmation. + /// + /// Requirements: + /// + /// - The caller must be a registered signer. + /// + /// Emits a `TransactionSubmitted` event. + /// If `salt` is not zero, emits a `CallSalt` event. + fn submit_transaction( + ref self: ComponentState, + to: ContractAddress, + selector: felt252, + calldata: Span, + salt: felt252 + ) -> TransactionID { + let call = Call { to, selector, calldata }; + self.submit_transaction_batch(array![call].span(), salt) + } + + /// Submits a new batch transaction for confirmation. + /// + /// Requirements: + /// + /// - The caller must be a registered signer. + /// + /// Emits a `TransactionSubmitted` event. + /// If `salt` is not zero, emits a `CallSalt` event. + fn submit_transaction_batch( + ref self: ComponentState, calls: Span, salt: felt252 + ) -> TransactionID { + let caller = starknet::get_caller_address(); + self.assert_one_of_signers(caller); + let id = self.hash_transaction_batch(calls, salt); + assert(self.get_submitted_block(id).is_zero(), Errors::TX_ALREADY_EXISTS); + + let tx_info = TxInfo { + is_executed: false, submitted_block: starknet::get_block_number() + }; + self.Multisig_tx_info.write(id, tx_info); + if salt.is_non_zero() { + self.emit(CallSalt { id, salt }); + } + self.emit(TransactionSubmitted { id, signer: caller }); + + id + } + + /// Confirms a transaction with the given `id`. + /// + /// Requirements: + /// + /// - The caller must be a registered signer. + /// - The transaction must exist and not be executed. + /// - The caller must not have already confirmed the transaction. + /// + /// Emits a `TransactionConfirmed` event. + fn confirm_transaction(ref self: ComponentState, id: TransactionID) { + let caller = starknet::get_caller_address(); + self.assert_one_of_signers(caller); + self.assert_tx_exists(id); + assert(!self.is_executed(id), Errors::TX_ALREADY_EXECUTED); + assert(!self.is_confirmed_by(id, caller), Errors::ALREADY_CONFIRMED); + + self.Multisig_tx_confirmed_by.write((id, caller), true); + self.emit(TransactionConfirmed { id, signer: caller }); + } + + /// Revokes a previous confirmation for a transaction with the given `id`. + /// + /// Requirements: + /// + /// - The transaction must exist and not be executed. + /// - The caller must have previously confirmed the transaction. + /// + /// Emits a `ConfirmationRevoked` event. + fn revoke_confirmation(ref self: ComponentState, id: TransactionID) { + let caller = starknet::get_caller_address(); + self.assert_tx_exists(id); + assert(!self.is_executed(id), Errors::TX_ALREADY_EXECUTED); + assert(self.is_confirmed_by(id, caller), Errors::HAS_NOT_CONFIRMED); + + self.Multisig_tx_confirmed_by.write((id, caller), false); + self.emit(ConfirmationRevoked { id, signer: caller }); + } + + /// Executes a confirmed transaction. + /// + /// Requirements: + /// + /// - The caller must be a registered signer. + /// - The transaction must be confirmed and not yet executed. + /// + /// Emits a `TransactionExecuted` event. + fn execute_transaction( + ref self: ComponentState, + to: ContractAddress, + selector: felt252, + calldata: Span, + salt: felt252 + ) { + let call = Call { to, selector, calldata }; + self.execute_transaction_batch(array![call].span(), salt) + } + + /// Executes a confirmed batch transaction. + /// + /// Requirements: + /// + /// - The caller must be a registered signer. + /// - The transaction must be confirmed and not yet executed. + /// + /// Emits a `TransactionExecuted` event. + fn execute_transaction_batch( + ref self: ComponentState, calls: Span, salt: felt252 + ) { + let id = self.hash_transaction_batch(calls, salt); + match self.resolve_tx_state(id) { + TransactionState::NotFound => panic_with_felt252(Errors::TX_NOT_FOUND), + TransactionState::Pending => panic_with_felt252(Errors::TX_NOT_CONFIRMED), + TransactionState::Executed => panic_with_felt252(Errors::TX_ALREADY_EXECUTED), + TransactionState::Confirmed => { + let caller = starknet::get_caller_address(); + self.assert_one_of_signers(caller); + let mut tx_info = self.Multisig_tx_info.read(id); + tx_info.is_executed = true; + self.Multisig_tx_info.write(id, tx_info); + for call in calls { + let Call { to, selector, calldata } = *call; + call_contract_syscall(to, selector, calldata).unwrap_syscall(); + }; + self.emit(TransactionExecuted { id }); + } + }; + } + + /// Returns the computed identifier of a transaction containing a single call. + fn hash_transaction( + self: @ComponentState, + to: ContractAddress, + selector: felt252, + calldata: Span, + salt: felt252 + ) -> TransactionID { + let call = Call { to, selector, calldata }; + self.hash_transaction_batch(array![call].span(), salt) + } + + /// Returns the computed identifier of a transaction containing a batch of calls. + fn hash_transaction_batch( + self: @ComponentState, calls: Span, salt: felt252 + ) -> TransactionID { + PedersenTrait::new(0).update_with(calls).update_with(salt).finalize() + } + } + + #[generate_trait] + pub impl InternalImpl< + TContractState, +HasComponent, +Drop + > of InternalTrait { + /// Initializes the Multisig component with the initial `quorum` and `signers`. + /// This function must be called during contract initialization to set up the initial state. + /// + /// Requirements: + /// + /// - `quorum` must be non-zero and less than or equal to the number of `signers`. + /// + /// Emits a `SignerAdded` event for each signer added. + /// Emits a `QuorumUpdated` event if the quorum changes. + fn initializer( + ref self: ComponentState, quorum: u32, signers: Span + ) { + self._add_signers(quorum, signers); + } + + /// Resolves and returns the current state of the transaction with the given `id`. + /// + /// The possible states are: + /// - `NotFound`: The transaction does not exist. + /// - `Pending`: The transaction exists but hasn't reached the required confirmations. + /// - `Confirmed`: The transaction has reached the required confirmations but hasn't been + /// executed. + /// - `Executed`: The transaction has been executed. + fn resolve_tx_state( + self: @ComponentState, id: TransactionID + ) -> TransactionState { + let TxInfo { is_executed, submitted_block } = self.Multisig_tx_info.read(id); + if submitted_block.is_zero() { + TransactionState::NotFound + } else if is_executed { + TransactionState::Executed + } else { + let is_confirmed = self.get_transaction_confirmations(id) >= self.get_quorum(); + if is_confirmed { + TransactionState::Confirmed + } else { + TransactionState::Pending + } + } + } + + /// Asserts that the `caller` is one of the registered signers. + /// + /// Requirements: + /// + /// - The `caller` must be a registered signer. + fn assert_one_of_signers(self: @ComponentState, caller: ContractAddress) { + assert(self.is_signer(caller), Errors::NOT_A_SIGNER); + } + + /// Asserts that a transaction with the given `id` exists. + /// + /// Requirements: + /// + /// - The transaction with `id` must have been submitted. + fn assert_tx_exists(self: @ComponentState, id: TransactionID) { + assert(self.get_submitted_block(id).is_non_zero(), Errors::TX_NOT_FOUND); + } + + /// Asserts that the caller is the contract itself. + /// + /// Requirements: + /// + /// - The caller must be the contract's own address. + fn assert_only_self(self: @ComponentState) { + let caller = starknet::get_caller_address(); + let self = starknet::get_contract_address(); + assert(caller == self, Errors::UNAUTHORIZED); + } + + /// Adds new signers and updates the quorum. + /// + /// Requirements: + /// + /// - Each signer address must be non-zero. + /// - `new_quorum` must be non-zero and less than or equal to the total number of signers + /// after addition. + /// + /// Emits a `SignerAdded` event for each new signer added. + /// Emits a `QuorumUpdated` event if the quorum changes. + fn _add_signers( + ref self: ComponentState, + new_quorum: u32, + signers_to_add: Span + ) { + if !signers_to_add.is_empty() { + let SignersInfo { quorum, mut signers_count } = self.Multisig_signers_info.read(); + for signer in signers_to_add { + let signer_to_add = *signer; + assert(signer_to_add.is_non_zero(), Errors::ZERO_ADDRESS_SIGNER); + if self.is_signer(signer_to_add) { + continue; + } + let index = signers_count; + self.Multisig_is_signer.write(signer_to_add, true); + self.Multisig_signers_by_index.write(index, signer_to_add); + self.Multisig_signers_indices.write(signer_to_add, index); + self.emit(SignerAdded { signer: signer_to_add }); + + signers_count += 1; + }; + self.Multisig_signers_info.write(SignersInfo { quorum, signers_count }); + } + self._change_quorum(new_quorum); + } + + /// Removes existing signers and updates the quorum. + /// + /// Requirements: + /// + /// - `new_quorum` must be non-zero and less than or equal to the total number of signers + /// after removal. + /// + /// Emits a `SignerRemoved` event for each signer removed. + /// Emits a `QuorumUpdated` event if the quorum changes. + fn _remove_signers( + ref self: ComponentState, + new_quorum: u32, + signers_to_remove: Span + ) { + if !signers_to_remove.is_empty() { + let SignersInfo { quorum, mut signers_count } = self.Multisig_signers_info.read(); + for signer in signers_to_remove { + let signer_to_remove = *signer; + if !self.is_signer(signer_to_remove) { + continue; + } + let last_index = signers_count - 1; + let index = self.Multisig_signers_indices.read(signer_to_remove); + if index != last_index { + // Swap signer to remove with the last signer + let last_signer = self.Multisig_signers_by_index.read(last_index); + self.Multisig_signers_indices.write(last_signer, index); + self.Multisig_signers_by_index.write(index, last_signer); + } + // Remove the last signer + self.Multisig_is_signer.write(signer_to_remove, false); + self.Multisig_signers_by_index.write(last_index, Zero::zero()); + self.Multisig_signers_indices.write(signer_to_remove, 0); + self.emit(SignerRemoved { signer: signer_to_remove }); + + signers_count -= 1; + }; + self.Multisig_signers_info.write(SignersInfo { quorum, signers_count }); + } + self._change_quorum(new_quorum); + } + + /// Replaces an existing signer with a new signer. + /// + /// Requirements: + /// + /// - `signer_to_remove` must be an existing signer. + /// - `signer_to_add` must not be an existing signer. + /// - `signer_to_add` must be a non-zero address. + /// + /// Emits a `SignerRemoved` event for the removed signer. + /// Emits a `SignerAdded` event for the new signer. + fn _replace_signer( + ref self: ComponentState, + signer_to_remove: ContractAddress, + signer_to_add: ContractAddress + ) { + assert(signer_to_add.is_non_zero(), Errors::ZERO_ADDRESS_SIGNER); + assert(!self.is_signer(signer_to_add), Errors::ALREADY_A_SIGNER); + assert(self.is_signer(signer_to_remove), Errors::NOT_A_SIGNER); + + self.Multisig_is_signer.write(signer_to_remove, false); + self.Multisig_is_signer.write(signer_to_add, true); + let index = self.Multisig_signers_indices.read(signer_to_remove); + self.Multisig_signers_by_index.write(index, signer_to_add); + self.Multisig_signers_indices.write(signer_to_add, index); + self.Multisig_signers_indices.write(signer_to_remove, 0); + self.emit(SignerRemoved { signer: signer_to_remove }); + self.emit(SignerAdded { signer: signer_to_add }); + } + + /// Updates the quorum value to `new_quorum` if it differs from the current quorum. + /// + /// Requirements: + /// + /// - `new_quorum` must be non-zero. + /// - `new_quorum` must be less than or equal to the total number of signers. + /// + /// Emits a `QuorumUpdated` event if the quorum changes. + fn _change_quorum(ref self: ComponentState, new_quorum: u32) { + let SignersInfo { quorum: old_quorum, signers_count } = self + .Multisig_signers_info + .read(); + if new_quorum != old_quorum { + assert(new_quorum.is_non_zero(), Errors::ZERO_QUORUM); + assert(new_quorum <= signers_count, Errors::QUORUM_TOO_HIGH); + self.Multisig_signers_info.write(SignersInfo { quorum: new_quorum, signers_count }); + self.emit(QuorumUpdated { old_quorum, new_quorum }); + } + } + } +} diff --git a/packages/governance/src/multisig/storage_utils.cairo b/packages/governance/src/multisig/storage_utils.cairo new file mode 100644 index 000000000..09ca71f35 --- /dev/null +++ b/packages/governance/src/multisig/storage_utils.cairo @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.18.0 (governance/multisig/storage_utils.cairo) + +use core::integer::u128_safe_divmod; +use starknet::storage_access::StorePacking; + +const _2_POW_32: NonZero = 0xffffffff; + +/// Helper struct for `MultisigComponent` that optimizes how transaction-related information +/// is stored, including the transaction's execution status and the block it was submitted in. +#[derive(Drop)] +pub struct TxInfo { + pub is_executed: bool, + pub submitted_block: u64 +} + +/// Packs a `TxInfo` entity into a `u128` value. +/// +/// The packing is done as follows: +/// - The boolean `is_executed` is stored as a single bit at the highest bit position (index 127). +/// - The `submitted_block` value occupies 64 bits in the range [63..126]. +pub impl TxInfoStorePacking of StorePacking { + fn pack(value: TxInfo) -> u128 { + let TxInfo { is_executed, submitted_block } = value; + let is_executed_value = if is_executed { + 1 + } else { + 0 + }; + submitted_block.into() * 2 + is_executed_value + } + + fn unpack(value: u128) -> TxInfo { + let (submitted_block, is_executed_value) = u128_safe_divmod(value, 2); + let is_executed = is_executed_value == 1; + TxInfo { is_executed, submitted_block: submitted_block.try_into().unwrap() } + } +} + +/// Helper struct for `MultisigComponent` that optimizes how the quorum +/// value and the total number of signers are stored. +#[derive(Drop)] +pub struct SignersInfo { + pub quorum: u32, + pub signers_count: u32 +} + +/// Packs a `SignersInfo` entity into a `u128` value. +/// +/// The packing is done as follows: +/// - `quorum` value occupies 32 bits in bit range [64..95]. +/// - `signers_count` value occupies the highest 32 bits in bit range [96..127]. +pub impl SignersInfoStorePacking of StorePacking { + fn pack(value: SignersInfo) -> u128 { + let SignersInfo { quorum, signers_count } = value; + quorum.into() * _2_POW_32.into() + signers_count.into() + } + + fn unpack(value: u128) -> SignersInfo { + let (quorum, signers_count) = u128_safe_divmod(value, _2_POW_32); + SignersInfo { + quorum: quorum.try_into().unwrap(), signers_count: signers_count.try_into().unwrap() + } + } +} diff --git a/packages/governance/src/tests.cairo b/packages/governance/src/tests.cairo index c71f711c4..6a51994ef 100644 --- a/packages/governance/src/tests.cairo +++ b/packages/governance/src/tests.cairo @@ -1,3 +1,4 @@ +mod test_multisig; mod test_timelock; mod test_utils; mod test_votes; diff --git a/packages/governance/src/tests/test_multisig.cairo b/packages/governance/src/tests/test_multisig.cairo new file mode 100644 index 000000000..cfdee1788 --- /dev/null +++ b/packages/governance/src/tests/test_multisig.cairo @@ -0,0 +1,1588 @@ +use core::num::traits::Zero; +use crate::multisig::MultisigComponent::{ConfirmationRevoked, TransactionExecuted}; +use crate::multisig::MultisigComponent::{MultisigImpl, InternalImpl, Event}; +use crate::multisig::MultisigComponent::{SignerAdded, SignerRemoved, QuorumUpdated, CallSalt}; +use crate::multisig::MultisigComponent::{TransactionSubmitted, TransactionConfirmed}; +use crate::multisig::{MultisigComponent, TransactionID, TransactionState}; +use openzeppelin_test_common::mocks::multisig::IMultisigTargetMockDispatcherTrait; +use openzeppelin_test_common::mocks::multisig::{MultisigWalletMock, IMultisigTargetMockDispatcher}; +use openzeppelin_testing as utils; +use openzeppelin_testing::constants::{ZERO, OTHER, ALICE, BOB, CHARLIE, SALT, BLOCK_NUMBER}; +use openzeppelin_testing::events::EventSpyExt; +use snforge_std::{EventSpy, spy_events, test_address}; +use snforge_std::{start_cheat_caller_address, start_cheat_block_number_global}; +use starknet::account::Call; +use starknet::{ContractAddress, contract_address_const}; + +// +// Setup +// + +type ComponentState = MultisigComponent::ComponentState; + +fn COMPONENT_STATE() -> ComponentState { + MultisigComponent::component_state_for_testing() +} + +fn DEFAULT_DATA() -> (u32, Span) { + let signers = array![ALICE(), BOB(), CHARLIE()]; + let quorum = signers.len() - 1; + (quorum, signers.span()) +} + +fn MOCK_ADDRESS() -> ContractAddress { + contract_address_const::<'MOCK_ADDRESS'>() +} + +fn setup_component(quorum: u32, signers: Span) -> ComponentState { + start_cheat_block_number_global(BLOCK_NUMBER); + let mut state = COMPONENT_STATE(); + state.initializer(quorum, signers); + state +} + +fn deploy_mock() -> IMultisigTargetMockDispatcher { + let contract_address = MOCK_ADDRESS(); + utils::declare_and_deploy_at("MultisigTargetMock", contract_address, array![]); + IMultisigTargetMockDispatcher { contract_address } +} + +// +// Submit tx +// + +#[test] +fn test_submit_tx() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let mut spy = spy_events(); + let contract_address = test_address(); + + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let salt = 0; + let expected_id = state.hash_transaction(to, selector, calldata, salt); + assert_tx_state(expected_id, TransactionState::NotFound); + + let signer = ALICE(); + start_cheat_caller_address(contract_address, signer); + + let id = state.submit_transaction(to, selector, calldata, salt); + assert_eq!(id, expected_id); + assert_eq!(state.get_submitted_block(id), BLOCK_NUMBER); + assert_tx_state(id, TransactionState::Pending); + spy.assert_only_event_tx_submitted(contract_address, id, signer); +} + +#[test] +fn test_submit_tx_with_salt() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let mut spy = spy_events(); + let contract_address = test_address(); + + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let salt = SALT; + let expected_id = state.hash_transaction(to, selector, calldata, salt); + assert_tx_state(expected_id, TransactionState::NotFound); + + let signer = ALICE(); + start_cheat_caller_address(contract_address, signer); + + let id = state.submit_transaction(to, selector, calldata, salt); + assert_eq!(id, expected_id); + assert_eq!(state.get_submitted_block(id), BLOCK_NUMBER); + assert_tx_state(id, TransactionState::Pending); + spy.assert_event_call_salt(contract_address, id, salt); + spy.assert_event_tx_submitted(contract_address, id, signer); +} + +#[test] +fn test_submit_same_tx_again_different_salt() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let mut spy = spy_events(); + let contract_address = test_address(); + + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let salt_1 = 0; + let expected_id_1 = state.hash_transaction(to, selector, calldata, salt_1); + let salt_2 = SALT; + let expected_id_2 = state.hash_transaction(to, selector, calldata, salt_2); + assert!(expected_id_1 != expected_id_2); + + let signer = ALICE(); + start_cheat_caller_address(contract_address, signer); + + let id_1 = state.submit_transaction(to, selector, calldata, salt_1); + assert_eq!(id_1, expected_id_1); + assert_tx_state(id_1, TransactionState::Pending); + spy.assert_only_event_tx_submitted(contract_address, id_1, signer); + + let id_2 = state.submit_transaction(to, selector, calldata, salt_2); + assert_eq!(id_2, expected_id_2); + assert_tx_state(id_2, TransactionState::Pending); + spy.assert_event_call_salt(contract_address, id_2, salt_2); + spy.assert_only_event_tx_submitted(contract_address, id_2, signer); +} + +#[test] +fn test_submit_tx_batch() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let mut spy = spy_events(); + let contract_address = test_address(); + + let calls = array![ + build_call(MockCall::AddNumber(42)), + build_call(MockCall::AddNumber(18)), + build_call(MockCall::AddNumber(40)) + ] + .span(); + let salt = 0; + let expected_id = state.hash_transaction_batch(calls, salt); + assert_tx_state(expected_id, TransactionState::NotFound); + + let signer = ALICE(); + start_cheat_caller_address(contract_address, signer); + + let id = state.submit_transaction_batch(calls, salt); + assert_eq!(id, expected_id); + assert_eq!(state.get_submitted_block(id), BLOCK_NUMBER); + assert_tx_state(id, TransactionState::Pending); + spy.assert_only_event_tx_submitted(contract_address, id, signer); +} + +#[test] +fn test_submit_tx_batch_with_salt() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let mut spy = spy_events(); + let contract_address = test_address(); + + let calls = array![ + build_call(MockCall::AddNumber(42)), + build_call(MockCall::AddNumber(18)), + build_call(MockCall::AddNumber(40)) + ] + .span(); + let salt = SALT; + let expected_id = state.hash_transaction_batch(calls, salt); + assert_tx_state(expected_id, TransactionState::NotFound); + + let signer = ALICE(); + start_cheat_caller_address(contract_address, signer); + + let id = state.submit_transaction_batch(calls, salt); + assert_eq!(id, expected_id); + assert_eq!(state.get_submitted_block(id), BLOCK_NUMBER); + assert_tx_state(id, TransactionState::Pending); + spy.assert_event_call_salt(contract_address, id, salt); + spy.assert_event_tx_submitted(contract_address, id, signer); +} + +#[test] +fn test_submit_same_tx_batch_different_salt() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let mut spy = spy_events(); + let contract_address = test_address(); + + let calls = array![ + build_call(MockCall::AddNumber(42)), + build_call(MockCall::AddNumber(18)), + build_call(MockCall::AddNumber(40)) + ] + .span(); + let salt_1 = 0; + let expected_id_1 = state.hash_transaction_batch(calls, salt_1); + let salt_2 = SALT; + let expected_id_2 = state.hash_transaction_batch(calls, salt_2); + assert!(expected_id_1 != expected_id_2); + + let signer = ALICE(); + start_cheat_caller_address(contract_address, signer); + + let id_1 = state.submit_transaction_batch(calls, salt_1); + assert_eq!(id_1, expected_id_1); + assert_tx_state(id_1, TransactionState::Pending); + spy.assert_only_event_tx_submitted(contract_address, id_1, signer); + + let id_2 = state.submit_transaction_batch(calls, salt_2); + assert_eq!(id_2, expected_id_2); + assert_tx_state(id_2, TransactionState::Pending); + spy.assert_event_call_salt(contract_address, id_2, salt_2); + spy.assert_event_tx_submitted(contract_address, id_2, signer); +} + +#[test] +#[should_panic(expected: 'Multisig: not a signer')] +fn test_cannot_submit_tx_unauthorized() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let signer = OTHER(); + start_cheat_caller_address(test_address(), signer); + state.submit_transaction(to, selector, calldata, 0); +} + +#[test] +#[should_panic(expected: 'Multisig: not a signer')] +fn test_cannot_submit_tx_batch_unauthorized() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + + let calls = array![ + build_call(MockCall::AddNumber(42)), + build_call(MockCall::AddNumber(18)), + build_call(MockCall::AddNumber(40)) + ] + .span(); + let signer = OTHER(); + start_cheat_caller_address(test_address(), signer); + state.submit_transaction_batch(calls, 0); +} + +#[test] +#[should_panic(expected: 'Multisig: tx already exists')] +fn test_cannot_submit_tx_twice() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let signer = ALICE(); + start_cheat_caller_address(test_address(), signer); + state.submit_transaction(to, selector, calldata, 0); + state.submit_transaction(to, selector, calldata, 0); +} + +#[test] +#[should_panic(expected: 'Multisig: tx already exists')] +fn test_cannot_submit_tx_batch_twice() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + + let calls = array![ + build_call(MockCall::AddNumber(42)), + build_call(MockCall::AddNumber(18)), + build_call(MockCall::AddNumber(40)) + ] + .span(); + let signer = ALICE(); + start_cheat_caller_address(test_address(), signer); + state.submit_transaction_batch(calls, 0); + state.submit_transaction_batch(calls, 0); +} + +// +// Confirm tx +// + +#[test] +fn test_confirm_tx() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let mut spy = spy_events(); + let contract_address = test_address(); + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + + // Submit by Alice + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, 0); + + // Confirm by Bob + spy.drop_all_events(); + start_cheat_caller_address(contract_address, BOB()); + assert_eq!(state.is_confirmed_by(id, BOB()), false); + state.confirm_transaction(id); + assert_eq!(state.is_confirmed_by(id, BOB()), true); + assert_tx_state(id, TransactionState::Pending); + assert_eq!(state.get_transaction_confirmations(id), 1); + spy.assert_only_event_tx_confirmed(contract_address, id, BOB()); + + // Confirm by Charlie + start_cheat_caller_address(contract_address, CHARLIE()); + assert_eq!(state.is_confirmed_by(id, CHARLIE()), false); + state.confirm_transaction(id); + assert_eq!(state.is_confirmed_by(id, CHARLIE()), true); + assert_tx_state(id, TransactionState::Confirmed); + assert_eq!(state.get_transaction_confirmations(id), 2); + spy.assert_only_event_tx_confirmed(contract_address, id, CHARLIE()); +} + +#[test] +fn test_confirmed_status_changed_when_quorum_increased() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + + // Submit by Alice + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, 0); + + // Confirm by Bob + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + + // Confirm by Charlie + start_cheat_caller_address(contract_address, CHARLIE()); + state.confirm_transaction(id); + + assert_tx_state(id, TransactionState::Confirmed); + state._change_quorum(quorum + 1); + assert_tx_state(id, TransactionState::Pending); +} + +#[test] +fn test_pending_status_changed_when_quorum_reduced() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + + // Submit by Alice + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, 0); + + // Confirm by Bob + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + + assert_tx_state(id, TransactionState::Pending); + state._change_quorum(quorum - 1); + assert_tx_state(id, TransactionState::Confirmed); +} + +#[test] +fn test_confirm_tx_batch() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let mut spy = spy_events(); + let contract_address = test_address(); + + let calls = array![ + build_call(MockCall::AddNumber(42)), + build_call(MockCall::AddNumber(18)), + build_call(MockCall::AddNumber(40)) + ] + .span(); + + // Submit by Alice + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction_batch(calls, 0); + assert_tx_state(id, TransactionState::Pending); + assert_eq!(state.get_transaction_confirmations(id), 0); + spy.drop_all_events(); + + // Confirm by Bob + start_cheat_caller_address(contract_address, BOB()); + assert_eq!(state.is_confirmed_by(id, BOB()), false); + state.confirm_transaction(id); + assert_eq!(state.is_confirmed_by(id, BOB()), true); + assert_tx_state(id, TransactionState::Pending); + assert_eq!(state.get_transaction_confirmations(id), 1); + spy.assert_only_event_tx_confirmed(contract_address, id, BOB()); + + // Confirm by Charlie + start_cheat_caller_address(contract_address, CHARLIE()); + assert_eq!(state.is_confirmed_by(id, CHARLIE()), false); + state.confirm_transaction(id); + assert_eq!(state.is_confirmed_by(id, CHARLIE()), true); + assert_tx_state(id, TransactionState::Confirmed); + assert_eq!(state.get_transaction_confirmations(id), 2); + spy.assert_only_event_tx_confirmed(contract_address, id, CHARLIE()); +} + +#[test] +#[should_panic(expected: 'Multisig: tx not found')] +fn test_cannot_confirm_nonexistent_tx() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let id = state.hash_transaction(to, selector, calldata, 0); + + start_cheat_caller_address(contract_address, ALICE()); + state.confirm_transaction(id); +} + +#[test] +#[should_panic(expected: 'Multisig: not a signer')] +fn test_cannot_confirm_tx_unauthorized() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let id = state.hash_transaction(to, selector, calldata, 0); + start_cheat_caller_address(contract_address, ALICE()); + state.submit_transaction(to, selector, calldata, 0); + + start_cheat_caller_address(contract_address, OTHER()); + state.confirm_transaction(id); +} + +#[test] +#[should_panic(expected: 'Multisig: already confirmed')] +fn test_cannot_confirm_tx_twice() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + + // Submit by Alice + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let id = state.hash_transaction(to, selector, calldata, 0); + start_cheat_caller_address(contract_address, ALICE()); + state.submit_transaction(to, selector, calldata, 0); + + // Confirm by Bob + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + assert_eq!(state.is_confirmed_by(id, BOB()), true); + assert_eq!(state.get_transaction_confirmations(id), 1); + + // Try to confirm again by Bob + state.confirm_transaction(id); +} + +// +// Revoke confirmation +// + +#[test] +fn test_revoke_confirmation() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let mut spy = spy_events(); + let contract_address = test_address(); + + // Submit by Alice + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, 0); + + // Confirm by Bob + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + + // Confirm by Charlie + start_cheat_caller_address(contract_address, CHARLIE()); + state.confirm_transaction(id); + + // Revoke confirmation by Charlie + spy.drop_all_events(); + assert_tx_state(id, TransactionState::Confirmed); + assert_eq!(state.is_confirmed_by(id, CHARLIE()), true); + assert_eq!(state.get_transaction_confirmations(id), 2); + state.revoke_confirmation(id); + assert_tx_state(id, TransactionState::Pending); + assert_eq!(state.is_confirmed_by(id, CHARLIE()), false); + assert_eq!(state.get_transaction_confirmations(id), 1); + spy.assert_only_event_confirmation_revoked(contract_address, id, CHARLIE()); +} + +#[test] +fn test_tx_not_confirmed_after_signer_removal() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + + // Submit & confirm by Alice + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, 0); + state.confirm_transaction(id); + + // Confirm by Bob + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + + // Check state before removal + assert_tx_state(id, TransactionState::Confirmed); + assert_eq!(state.is_confirmed_by(id, BOB()), true); + assert_eq!(state.get_transaction_confirmations(id), 2); + + // Remove Bob from signers + start_cheat_caller_address(contract_address, contract_address); + state.remove_signers(quorum, array![BOB()].span()); + + // Check state after removal + assert_tx_state(id, TransactionState::Pending); + assert_eq!(state.is_confirmed_by(id, BOB()), true); + assert_eq!(state.get_transaction_confirmations(id), 1); +} + +#[test] +fn test_can_revoke_confirmation_after_being_removed() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + + // Submit & confirm by Alice + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, 0); + state.confirm_transaction(id); + + // Confirm by Bob + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + + // Remove Bob from signers + start_cheat_caller_address(contract_address, contract_address); + state.remove_signers(quorum, array![BOB()].span()); + + // Check state before revocation + assert_tx_state(id, TransactionState::Pending); + assert_eq!(state.is_confirmed_by(id, BOB()), true); + assert_eq!(state.get_transaction_confirmations(id), 1); + + // Revoke confirmation by Bob + start_cheat_caller_address(contract_address, BOB()); + state.revoke_confirmation(id); + + // Check state after revocation + assert_tx_state(id, TransactionState::Pending); + assert_eq!(state.is_confirmed_by(id, BOB()), false); + assert_eq!(state.get_transaction_confirmations(id), 1); +} + +#[test] +#[should_panic(expected: 'Multisig: has not confirmed')] +fn test_cannot_revoke_confirmation_has_not_confirmed() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + + // Submit by Alice + start_cheat_caller_address(test_address(), ALICE()); + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let id = state.submit_transaction(to, selector, calldata, 0); + + // Revoke confirmation by Bob + start_cheat_caller_address(test_address(), BOB()); + state.revoke_confirmation(id); +} + +#[test] +#[should_panic(expected: 'Multisig: tx not found')] +fn test_cannot_revoke_confirmation_nonexistent_tx() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let id = state.hash_transaction(to, selector, calldata, 0); + state.revoke_confirmation(id); +} + +// +// Execute tx +// + +#[test] +fn test_execute_tx() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let mut spy = spy_events(); + let mock = deploy_mock(); + let contract_address = test_address(); + + // Submit + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let salt = 0; + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, salt); + + // Confirm + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + start_cheat_caller_address(contract_address, CHARLIE()); + state.confirm_transaction(id); + + // Check state before + assert_eq!(mock.get_current_sum(), 0); + assert_tx_state(id, TransactionState::Confirmed); + + // Execute + spy.drop_all_events(); + start_cheat_caller_address(contract_address, ALICE()); + state.execute_transaction(to, selector, calldata, salt); + + // Check state after + assert_eq!(mock.get_current_sum(), 42); + assert_tx_state(id, TransactionState::Executed); + spy.assert_only_event_tx_executed(contract_address, id); +} + +#[test] +fn test_execute_tx_batch() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + let mut spy = spy_events(); + let mock = deploy_mock(); + let calls = array![ + build_call(MockCall::AddNumber(42)), + build_call(MockCall::AddNumber(18)), + build_call(MockCall::AddNumber(40)) + ] + .span(); + let salt = 0; + + // Submit + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction_batch(calls, salt); + + // Confirm + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + start_cheat_caller_address(contract_address, CHARLIE()); + state.confirm_transaction(id); + + // Check state before + assert_eq!(mock.get_current_sum(), 0); + assert_tx_state(id, TransactionState::Confirmed); + + // Execute + spy.drop_all_events(); + start_cheat_caller_address(contract_address, ALICE()); + state.execute_transaction_batch(calls, salt); + + // Check state after + assert_eq!(mock.get_current_sum(), 100); + assert_tx_state(id, TransactionState::Executed); + spy.assert_only_event_tx_executed(contract_address, id); +} + +#[test] +#[should_panic(expected: 'Multisig: tx not found')] +fn test_cannot_execute_not_submitted_tx() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let salt = 0; + + // Try to execute + start_cheat_caller_address(contract_address, ALICE()); + state.execute_transaction(to, selector, calldata, salt); +} + +#[test] +#[should_panic(expected: 'Multisig: not a signer')] +fn test_cannot_execute_unauthorized() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let salt = 0; + + // Submit + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, salt); + + // Confirm + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + start_cheat_caller_address(contract_address, CHARLIE()); + state.confirm_transaction(id); + + // Try to execute + start_cheat_caller_address(contract_address, OTHER()); + state.execute_transaction(to, selector, calldata, salt); +} + +#[test] +#[should_panic(expected: 'Multisig: not a signer')] +fn test_cannot_execute_batch_unauthorized() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + let calls = array![ + build_call(MockCall::AddNumber(42)), + build_call(MockCall::AddNumber(18)), + build_call(MockCall::AddNumber(40)) + ] + .span(); + let salt = 0; + + // Submit + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction_batch(calls, salt); + + // Confirm + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + start_cheat_caller_address(contract_address, CHARLIE()); + state.confirm_transaction(id); + + // Try to execute + start_cheat_caller_address(contract_address, OTHER()); + state.execute_transaction_batch(calls, salt); +} + +#[test] +#[should_panic(expected: 'Multisig: tx not confirmed')] +fn test_cannot_execute_not_confirmed() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let salt = 0; + + // Submit + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, salt); + + // Confirm once + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + + // Execute + state.execute_transaction(to, selector, calldata, salt); +} + +#[test] +#[should_panic(expected: 'Multisig: tx not confirmed')] +fn test_cannot_execute_batch_not_confirmed() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let salt = 0; + + // Submit + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, salt); + + // Confirm once + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + + // Execute + state.execute_transaction(to, selector, calldata, salt); +} + +#[test] +#[should_panic(expected: 'Multisig: tx already executed')] +fn test_cannot_execute_twice() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let salt = 0; + deploy_mock(); + + // Submit + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, salt); + + // Confirm + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + start_cheat_caller_address(contract_address, CHARLIE()); + state.confirm_transaction(id); + + // Execute 1st time + state.execute_transaction(to, selector, calldata, salt); + + // Try to execute 2nd time + state.execute_transaction(to, selector, calldata, salt); +} + +#[test] +#[should_panic(expected: 'Multisig: tx already executed')] +fn test_cannot_execute_batch_twice() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + deploy_mock(); + + // Submit + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + let salt = 0; + start_cheat_caller_address(contract_address, ALICE()); + let id = state.submit_transaction(to, selector, calldata, salt); + + // Confirm + start_cheat_caller_address(contract_address, BOB()); + state.confirm_transaction(id); + start_cheat_caller_address(contract_address, CHARLIE()); + state.confirm_transaction(id); + + // Execute 1st time + state.execute_transaction(to, selector, calldata, salt); + + // Try to execute 2nd time + state.execute_transaction(to, selector, calldata, salt); +} + +// +// hash_transaction +// + +#[test] +fn test_tx_hash_depends_on_salt() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(42)); + start_cheat_caller_address(test_address(), ALICE()); + + let mut salt = 0; + while salt != 10 { + let id_from_hash = state.hash_transaction(to, selector, calldata, salt); + let id = state.submit_transaction(to, selector, calldata, salt); + assert_eq!(id_from_hash, id); + salt += 1; + }; +} + +#[test] +fn test_tx_batch_hash_depends_on_salt() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let calls = array![ + build_call(MockCall::AddNumber(42)), + build_call(MockCall::AddNumber(18)), + build_call(MockCall::AddNumber(40)) + ] + .span(); + start_cheat_caller_address(test_address(), ALICE()); + + let mut salt = 0; + while salt != 10 { + let id_from_hash = state.hash_transaction_batch(calls, salt); + let id = state.submit_transaction_batch(calls, salt); + assert_eq!(id_from_hash, id); + salt += 1; + }; +} + +#[test] +fn test_tx_hash_depends_on_calldata() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + start_cheat_caller_address(test_address(), ALICE()); + + let mut num = 0; + while num != 10 { + let Call { to, selector, calldata } = build_call(MockCall::AddNumber(num)); + let id_from_hash = state.hash_transaction(to, selector, calldata, SALT); + let id = state.submit_transaction(to, selector, calldata, SALT); + assert_eq!(id_from_hash, id); + num += 1; + }; +} + +#[test] +fn test_tx_hash_depends_on_selector() { + let (quorum, signers) = DEFAULT_DATA(); + let state = setup_component(quorum, signers); + + let to = MOCK_ADDRESS(); + let empty_calldata = array![].span(); + let id_1 = state.hash_transaction(to, selector!("selector_1"), empty_calldata, SALT); + let id_2 = state.hash_transaction(to, selector!("selector_2"), empty_calldata, SALT); + let id_3 = state.hash_transaction(to, selector!("selector_3"), empty_calldata, SALT); + assert!(id_1 != id_2); + assert!(id_2 != id_3); + assert!(id_1 != id_3); +} + +#[test] +fn test_tx_hash_depends_on_to_address() { + let (quorum, signers) = DEFAULT_DATA(); + let state = setup_component(quorum, signers); + + let Call { to: _, selector, calldata } = build_call(MockCall::AddNumber(42)); + let id_1 = state.hash_transaction(ALICE(), selector, calldata, SALT); + let id_2 = state.hash_transaction(BOB(), selector, calldata, SALT); + let id_3 = state.hash_transaction(CHARLIE(), selector, calldata, SALT); + assert!(id_1 != id_2); + assert!(id_2 != id_3); + assert!(id_1 != id_3); +} + +// +// add_signers +// + +#[test] +fn test_add_single_signer() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice].span()); + let contract_address = test_address(); + let mut spy = spy_events(); + start_cheat_caller_address(contract_address, contract_address); + + // Add Bob as signer + state.add_signers(quorum, array![bob].span()); + assert_signers_list(array![alice, bob].span()); + spy.assert_only_event_signer_added(contract_address, bob); + + // Add Charlie as signer + state.add_signers(quorum, array![charlie].span()); + assert_signers_list(array![alice, bob, charlie].span()); + spy.assert_only_event_signer_added(contract_address, charlie); +} + +#[test] +fn test_add_multiple_signers() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice].span()); + let contract_address = test_address(); + let mut spy = spy_events(); + start_cheat_caller_address(contract_address, contract_address); + + // Add Bob and Charlie as signers + state.add_signers(quorum, array![bob, charlie].span()); + assert_signers_list(array![alice, bob, charlie].span()); + spy.assert_event_signer_added(contract_address, bob); + spy.assert_only_event_signer_added(contract_address, charlie); +} + +#[test] +fn test_add_remove_add() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Add Bob and Charlie as signers + state.add_signers(quorum, array![bob, charlie].span()); + assert_signers_list(array![alice, bob, charlie].span()); + + // Remove Alice + state.remove_signers(quorum, array![alice].span()); + assert_signers_list(array![charlie, bob].span()); + + // Remove Charlie + state.remove_signers(quorum, array![charlie].span()); + assert_signers_list(array![bob].span()); + + // Add Alice + state.add_signers(quorum, array![alice].span()); + assert_signers_list(array![bob, alice].span()); + + // Add Charlie + state.add_signers(quorum, array![charlie].span()); + assert_signers_list(array![bob, alice, charlie].span()); +} + +#[test] +fn test_signers_ignored_if_added_again() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Add Bob as signer + state.add_signers(quorum, array![bob].span()); + assert_signers_list(array![alice, bob].span()); + + // Add Alice and Bob again and Charlie as a new signer + let mut spy = spy_events(); + state.add_signers(quorum, array![alice, bob, charlie].span()); + assert_signers_list(array![alice, bob, charlie].span()); + spy.assert_only_event_signer_added(contract_address, charlie); +} + +#[test] +fn test_add_signers_does_nothing_if_signers_empty() { + let (quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(quorum, signers); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Call `add_signers` with an empty list + let mut spy = spy_events(); + let empty_list = array![].span(); + state.add_signers(quorum, empty_list); + spy.assert_no_events_left_from(contract_address); +} + +#[test] +#[should_panic(expected: 'Multisig: unauthorized')] +fn test_cannot_add_when_not_multisig_itself() { + let quorum = 1; + let (alice, bob) = (ALICE(), BOB()); + let mut state = setup_component(quorum, array![alice].span()); + + // Try to add signer + start_cheat_caller_address(test_address(), OTHER()); + state.add_signers(quorum, array![bob].span()); +} + +#[test] +#[should_panic(expected: 'Multisig: zero address signer')] +fn test_cannot_add_zero_address_as_signer() { + let quorum = 1; + let mut state = setup_component(quorum, array![ALICE()].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Try to add zero address as signer + state.add_signers(quorum, array![ZERO()].span()); +} + +#[test] +#[should_panic(expected: 'Multisig: quorum cannot be 0')] +fn test_cannot_add_with_zero_quorum() { + let quorum = 1; + let (alice, bob) = (ALICE(), BOB()); + let mut state = setup_component(quorum, array![alice].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Try to add with 0 quorum value + state.add_signers(0, array![bob].span()); +} + +#[test] +#[should_panic(expected: 'Multisig: quorum > signers')] +fn test_cannot_add_with_quorum_too_high() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Try to add with quorum value > signers count + state.add_signers(4, array![bob, charlie].span()); +} + +// +// remove_signers +// + +#[test] +fn test_remove_single_signer() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice, bob, charlie].span()); + let contract_address = test_address(); + let mut spy = spy_events(); + start_cheat_caller_address(contract_address, contract_address); + + // Remove Alice from signers + assert_signers_list(array![alice, bob, charlie].span()); + state.remove_signers(quorum, array![alice].span()); + assert_signers_list(array![charlie, bob].span()); + spy.assert_only_event_signer_removed(contract_address, alice); + assert_eq!(state.is_signer(alice), false); + + // Remove Charlie from signers + state.remove_signers(quorum, array![charlie].span()); + assert_signers_list(array![bob].span()); + spy.assert_only_event_signer_removed(contract_address, charlie); + assert_eq!(state.is_signer(charlie), false); +} + +#[test] +fn test_remove_multiple_signers() { + let quorum = 1; + let (alice, bob, charlie, other) = (ALICE(), BOB(), CHARLIE(), OTHER()); + let mut state = setup_component(quorum, array![alice, bob, charlie, other].span()); + let contract_address = test_address(); + let mut spy = spy_events(); + start_cheat_caller_address(contract_address, contract_address); + + // Remove Alice and Other from signers + assert_signers_list(array![alice, bob, charlie, other].span()); + state.remove_signers(quorum, array![alice, other].span()); + assert_signers_list(array![charlie, bob].span()); + spy.assert_event_signer_removed(contract_address, alice); + spy.assert_only_event_signer_removed(contract_address, other); + assert_eq!(state.is_signer(alice), false); + assert_eq!(state.is_signer(other), false); +} + +#[test] +fn test_remove_add_remove() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice, bob, charlie].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Remove Alice from signers + state.remove_signers(quorum, array![alice].span()); + assert_signers_list(array![charlie, bob].span()); + assert_eq!(state.is_signer(alice), false); + + // Add Alice to signers + state.add_signers(quorum, array![alice].span()); + assert_signers_list(array![charlie, bob, alice].span()); + assert_eq!(state.is_signer(alice), true); + + // Remove Alice from signers + state.remove_signers(quorum, array![alice].span()); + assert_signers_list(array![charlie, bob].span()); + assert_eq!(state.is_signer(alice), false); +} + +#[test] +fn test_not_signers_ignored_when_removing() { + let quorum = 1; + let (alice, bob, charlie, other) = (ALICE(), BOB(), CHARLIE(), OTHER()); + let mut state = setup_component(quorum, array![alice, bob, charlie].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Remove Alice and Other from signers + let mut spy = spy_events(); + state.remove_signers(quorum, array![alice, other].span()); + assert_signers_list(array![charlie, bob].span()); + assert_eq!(state.is_signer(alice), false); + assert_eq!(state.is_signer(other), false); + spy.assert_only_event_signer_removed(contract_address, alice); +} + +#[test] +fn test_remove_signers_does_nothing_if_signers_empty() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice, bob, charlie].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Call `remove_signers` with an empty list + let mut spy = spy_events(); + let empty_list = array![].span(); + state.remove_signers(quorum, empty_list); + assert_signers_list(array![alice, bob, charlie].span()); + spy.assert_no_events_left_from(contract_address); +} + +#[test] +#[should_panic(expected: 'Multisig: unauthorized')] +fn test_cannot_remove_when_not_multisig_itself() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice, bob, charlie].span()); + + // Try to call 'remove_signers' from Other + start_cheat_caller_address(test_address(), OTHER()); + state.remove_signers(quorum, array![alice].span()); +} + +#[test] +#[should_panic(expected: 'Multisig: quorum cannot be 0')] +fn test_cannot_remove_with_zero_quorum() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice, bob, charlie].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Try to remove signers with 0 quorum value + state.remove_signers(0, array![bob, charlie].span()); +} + +#[test] +#[should_panic(expected: 'Multisig: quorum > signers')] +fn test_cannot_remove_with_quorum_too_high() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice, bob, charlie].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Try to remove signers with quorum value too high + state.remove_signers(3, array![bob].span()); +} + +// +// replace_signer +// + +#[test] +fn test_replace_signer() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice, bob].span()); + let contract_address = test_address(); + let mut spy = spy_events(); + start_cheat_caller_address(contract_address, contract_address); + + // Check state before + assert_signers_list(array![alice, bob].span()); + assert_eq!(state.is_signer(alice), true); + assert_eq!(state.is_signer(charlie), false); + + // Replace Alice with Charlie + state.replace_signer(alice, charlie); + spy.assert_event_signer_removed(contract_address, alice); + spy.assert_only_event_signer_added(contract_address, charlie); + + // Check state after + assert_signers_list(array![charlie, bob].span()); + assert_eq!(state.is_signer(alice), false); + assert_eq!(state.is_signer(charlie), true); +} + +#[test] +#[should_panic(expected: 'Multisig: not a signer')] +fn test_cannot_replace_not_signer() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice, bob].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Try to replace not a signer + state.replace_signer(OTHER(), charlie); +} + +#[test] +#[should_panic(expected: 'Multisig: already a signer')] +fn test_cannot_replace_with_existing_signer() { + let quorum = 1; + let (alice, bob) = (ALICE(), BOB()); + let mut state = setup_component(quorum, array![alice, bob].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Try to replace with existing signer + state.replace_signer(alice, bob); +} + +#[test] +#[should_panic(expected: 'Multisig: zero address signer')] +fn test_cannot_replace_with_zero_address() { + let quorum = 1; + let (alice, bob, charlie) = (ALICE(), BOB(), CHARLIE()); + let mut state = setup_component(quorum, array![alice, bob, charlie].span()); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Try to replace with zero address + state.replace_signer(alice, ZERO()); +} + +// +// change_quorum +// + +#[test] +fn test_change_quorum_higher_value() { + let (initial_quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(initial_quorum, signers); + let contract_address = test_address(); + let mut spy = spy_events(); + start_cheat_caller_address(contract_address, contract_address); + + // Increase quorum value + let new_quorum = initial_quorum + 1; + state.change_quorum(new_quorum); + assert_eq!(state.get_quorum(), new_quorum); + spy.assert_only_event_quorum_updated(contract_address, initial_quorum, new_quorum); +} + +#[test] +fn test_change_quorum_lower_value() { + let (initial_quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(initial_quorum, signers); + let contract_address = test_address(); + let mut spy = spy_events(); + start_cheat_caller_address(contract_address, contract_address); + + // Reduce quorum value + let new_quorum = initial_quorum - 1; + state.change_quorum(new_quorum); + assert_eq!(state.get_quorum(), new_quorum); + spy.assert_only_event_quorum_updated(contract_address, initial_quorum, new_quorum); +} + +#[test] +fn test_change_quorum_to_same_value() { + let (initial_quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(initial_quorum, signers); + let contract_address = test_address(); + let mut spy = spy_events(); + start_cheat_caller_address(contract_address, contract_address); + + // Call 'change_quorum' with the current quorum value + state.change_quorum(initial_quorum); + assert_eq!(state.get_quorum(), initial_quorum); + spy.assert_no_events_left_from(contract_address); +} + +#[test] +fn test_change_quorum_to_min_value() { + let (initial_quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(initial_quorum, signers); + let contract_address = test_address(); + let mut spy = spy_events(); + start_cheat_caller_address(contract_address, contract_address); + + // Set quorum to min allowed value (1) + let new_quorum = 1; + state.change_quorum(new_quorum); + assert_eq!(state.get_quorum(), new_quorum); + spy.assert_only_event_quorum_updated(contract_address, initial_quorum, new_quorum); +} + +#[test] +fn test_change_quorum_to_max_value() { + let (initial_quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(initial_quorum, signers); + let contract_address = test_address(); + let mut spy = spy_events(); + start_cheat_caller_address(contract_address, contract_address); + + // Set quorum to max allowed value (signers count) + let new_quorum = signers.len(); + state.change_quorum(new_quorum); + assert_eq!(state.get_quorum(), new_quorum); + spy.assert_only_event_quorum_updated(contract_address, initial_quorum, new_quorum); +} + +#[test] +#[should_panic(expected: 'Multisig: quorum cannot be 0')] +fn test_cannot_change_quorum_to_zero() { + let (initial_quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(initial_quorum, signers); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Try to set quorum to 0 + state.change_quorum(0); +} + +#[test] +#[should_panic(expected: 'Multisig: quorum > signers')] +fn test_cannot_set_quorum_too_high() { + let (initial_quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(initial_quorum, signers); + let contract_address = test_address(); + start_cheat_caller_address(contract_address, contract_address); + + // Try to set quorum to a value too high (signers count + 1) + let new_quorum = signers.len() + 1; + state.change_quorum(new_quorum); +} + +#[test] +#[should_panic(expected: 'Multisig: unauthorized')] +fn test_cannot_change_quorum_when_not_multisig_itself() { + let (initial_quorum, signers) = DEFAULT_DATA(); + let mut state = setup_component(initial_quorum, signers); + start_cheat_caller_address(test_address(), OTHER()); + + // Try to set quorum to 0 + state.change_quorum(0); +} + +// +// Helpers +// + +#[derive(Copy, Drop)] +enum MockCall { + AddNumber: felt252, + FailingFn, + BadSelector +} + +fn build_call(call: MockCall) -> Call { + let (selector, calldata) = match call { + MockCall::AddNumber(number) => (selector!("add_number"), array![number]), + MockCall::FailingFn => (selector!("failing_function"), array![]), + MockCall::BadSelector => (selector!("bad_selector"), array![]), + }; + Call { to: MOCK_ADDRESS(), selector, calldata: calldata.span() } +} + +fn assert_tx_state(id: TransactionID, expected_state: TransactionState) { + let state = COMPONENT_STATE(); + let tx_state = state.get_transaction_state(id); + let block = state.get_submitted_block(id); + let is_confirmed = state.is_confirmed(id); + let is_executed = state.is_executed(id); + let tx_confirmations = state.get_transaction_confirmations(id); + + assert_eq!(tx_state, expected_state); + match expected_state { + TransactionState::NotFound => { + assert!(block.is_zero()); + assert!(!is_confirmed); + assert!(!is_executed); + assert!(tx_confirmations.is_zero()); + }, + TransactionState::Pending => { + assert!(block.is_non_zero()); + assert!(!is_confirmed); + assert!(!is_executed); + assert!(tx_confirmations < state.get_quorum()); + }, + TransactionState::Confirmed => { + assert!(block.is_non_zero()); + assert!(is_confirmed); + assert!(!is_executed); + assert!(tx_confirmations >= state.get_quorum()); + }, + TransactionState::Executed => { + assert!(block.is_non_zero()); + assert!(is_confirmed); + assert!(is_executed); + assert!(tx_confirmations >= state.get_quorum()); + } + }; +} + +fn assert_signers_list(expected_signers: Span) { + let state = COMPONENT_STATE(); + let actual_signers = state.get_signers(); + assert_eq!(actual_signers, expected_signers); + for signer in expected_signers { + assert!(state.is_signer(*signer)); + }; +} + +// +// Events +// + +#[generate_trait] +impl MultisigSpyHelpersImpl of MultisigSpyHelpers { + // + // SignerAdded + // + + fn assert_event_signer_added( + ref self: EventSpy, contract: ContractAddress, signer: ContractAddress + ) { + let expected = Event::SignerAdded(SignerAdded { signer }); + self.assert_emitted_single(contract, expected); + } + + fn assert_only_event_signer_added( + ref self: EventSpy, contract: ContractAddress, signer: ContractAddress + ) { + self.assert_event_signer_added(contract, signer); + self.assert_no_events_left_from(contract); + } + + // + // SignerRemoved + // + + fn assert_event_signer_removed( + ref self: EventSpy, contract: ContractAddress, signer: ContractAddress + ) { + let expected = Event::SignerRemoved(SignerRemoved { signer }); + self.assert_emitted_single(contract, expected); + } + + fn assert_only_event_signer_removed( + ref self: EventSpy, contract: ContractAddress, signer: ContractAddress + ) { + self.assert_event_signer_removed(contract, signer); + self.assert_no_events_left_from(contract); + } + + // + // QuorumUpdated + // + + fn assert_event_quorum_updated( + ref self: EventSpy, contract: ContractAddress, old_quorum: u32, new_quorum: u32 + ) { + let expected = Event::QuorumUpdated(QuorumUpdated { old_quorum, new_quorum }); + self.assert_emitted_single(contract, expected); + } + + fn assert_only_event_quorum_updated( + ref self: EventSpy, contract: ContractAddress, old_quorum: u32, new_quorum: u32 + ) { + self.assert_event_quorum_updated(contract, old_quorum, new_quorum); + self.assert_no_events_left_from(contract); + } + + // + // TransactionSubmitted + // + + fn assert_event_tx_submitted( + ref self: EventSpy, contract: ContractAddress, id: TransactionID, signer: ContractAddress + ) { + let expected = Event::TransactionSubmitted(TransactionSubmitted { id, signer }); + self.assert_emitted_single(contract, expected); + } + + fn assert_only_event_tx_submitted( + ref self: EventSpy, contract: ContractAddress, id: TransactionID, signer: ContractAddress + ) { + self.assert_event_tx_submitted(contract, id, signer); + self.assert_no_events_left_from(contract); + } + + // + // TransactionConfirmed + // + + fn assert_event_tx_confirmed( + ref self: EventSpy, contract: ContractAddress, id: TransactionID, signer: ContractAddress + ) { + let expected = Event::TransactionConfirmed(TransactionConfirmed { id, signer }); + self.assert_emitted_single(contract, expected); + } + + fn assert_only_event_tx_confirmed( + ref self: EventSpy, contract: ContractAddress, id: TransactionID, signer: ContractAddress + ) { + self.assert_event_tx_confirmed(contract, id, signer); + self.assert_no_events_left_from(contract); + } + + // + // ConfirmationRevoked + // + + fn assert_event_confirmation_revoked( + ref self: EventSpy, contract: ContractAddress, id: TransactionID, signer: ContractAddress + ) { + let expected = Event::ConfirmationRevoked(ConfirmationRevoked { id, signer }); + self.assert_emitted_single(contract, expected); + } + + fn assert_only_event_confirmation_revoked( + ref self: EventSpy, contract: ContractAddress, id: TransactionID, signer: ContractAddress + ) { + self.assert_event_confirmation_revoked(contract, id, signer); + self.assert_no_events_left_from(contract); + } + + // + // TransactionExecuted + // + + fn assert_event_tx_executed(ref self: EventSpy, contract: ContractAddress, id: TransactionID) { + let expected = Event::TransactionExecuted(TransactionExecuted { id }); + self.assert_emitted_single(contract, expected); + } + + fn assert_only_event_tx_executed( + ref self: EventSpy, contract: ContractAddress, id: TransactionID + ) { + self.assert_event_tx_executed(contract, id); + self.assert_no_events_left_from(contract); + } + + // + // CallSalt + // + + fn assert_event_call_salt( + ref self: EventSpy, contract: ContractAddress, id: TransactionID, salt: felt252 + ) { + let expected = Event::CallSalt(CallSalt { id, salt }); + self.assert_emitted_single(contract, expected); + } +} diff --git a/packages/governance/src/tests/test_utils.cairo b/packages/governance/src/tests/test_utils.cairo index b19e27785..d1bf2b7c1 100644 --- a/packages/governance/src/tests/test_utils.cairo +++ b/packages/governance/src/tests/test_utils.cairo @@ -1,4 +1,4 @@ -use crate::timelock::utils::call_impls::CallPartialEq; +use crate::utils::call_impls::CallPartialEq; use starknet::account::Call; use starknet::contract_address_const; diff --git a/packages/governance/src/timelock.cairo b/packages/governance/src/timelock.cairo index 0abcf6e3b..5d7929f3a 100644 --- a/packages/governance/src/timelock.cairo +++ b/packages/governance/src/timelock.cairo @@ -1,6 +1,5 @@ pub mod interface; pub mod timelock_controller; -pub mod utils; pub use timelock_controller::OperationState; pub use timelock_controller::TimelockControllerComponent::{ diff --git a/packages/governance/src/timelock/timelock_controller.cairo b/packages/governance/src/timelock/timelock_controller.cairo index bd8fbcb38..474a50475 100644 --- a/packages/governance/src/timelock/timelock_controller.cairo +++ b/packages/governance/src/timelock/timelock_controller.cairo @@ -18,7 +18,7 @@ pub mod TimelockControllerComponent { use core::num::traits::Zero; use core::pedersen::PedersenTrait; use crate::timelock::interface::{ITimelock, TimelockABI}; - use crate::timelock::utils::call_impls::{HashCallImpl, HashCallsImpl, CallPartialEq}; + use crate::utils::call_impls::{HashCallImpl, HashCallsImpl, CallPartialEq}; use openzeppelin_access::accesscontrol::AccessControlComponent::InternalTrait as AccessControlInternalTrait; use openzeppelin_access::accesscontrol::AccessControlComponent::{ AccessControlImpl, AccessControlCamelImpl @@ -156,11 +156,11 @@ pub mod TimelockControllerComponent { self: @ComponentState, id: felt252 ) -> OperationState { let timestamp = Self::get_timestamp(self, id); - if (timestamp == 0) { + if timestamp == 0 { return OperationState::Unset; - } else if (timestamp == DONE_TIMESTAMP) { + } else if timestamp == DONE_TIMESTAMP { return OperationState::Done; - } else if (timestamp > starknet::get_block_timestamp()) { + } else if timestamp > starknet::get_block_timestamp() { return OperationState::Waiting; } else { return OperationState::Ready; diff --git a/packages/governance/src/timelock/utils.cairo b/packages/governance/src/utils.cairo similarity index 100% rename from packages/governance/src/timelock/utils.cairo rename to packages/governance/src/utils.cairo diff --git a/packages/governance/src/timelock/utils/call_impls.cairo b/packages/governance/src/utils/call_impls.cairo similarity index 91% rename from packages/governance/src/timelock/utils/call_impls.cairo rename to packages/governance/src/utils/call_impls.cairo index 6e1b1663d..c76d77fca 100644 --- a/packages/governance/src/timelock/utils/call_impls.cairo +++ b/packages/governance/src/utils/call_impls.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (governance/timelock/utils/call_impls.cairo) +// OpenZeppelin Contracts for Cairo v0.18.0 (governance/utils/call_impls.cairo) use core::hash::{HashStateTrait, HashStateExTrait, Hash}; use starknet::account::Call; @@ -36,6 +36,6 @@ pub impl CallPartialEq of PartialEq { } #[inline(always)] fn ne(lhs: @Call, rhs: @Call) -> bool { - !(lhs == rhs) + lhs != rhs } } diff --git a/packages/test_common/src/mocks.cairo b/packages/test_common/src/mocks.cairo index 027f99625..2e6901947 100644 --- a/packages/test_common/src/mocks.cairo +++ b/packages/test_common/src/mocks.cairo @@ -5,6 +5,7 @@ pub mod erc1155; pub mod erc20; pub mod erc2981; pub mod erc721; +pub mod multisig; pub mod non_implementing; pub mod nonces; pub mod security; diff --git a/packages/test_common/src/mocks/multisig.cairo b/packages/test_common/src/mocks/multisig.cairo new file mode 100644 index 000000000..c7141a04b --- /dev/null +++ b/packages/test_common/src/mocks/multisig.cairo @@ -0,0 +1,61 @@ +#[starknet::contract] +pub mod MultisigWalletMock { + use openzeppelin_governance::multisig::MultisigComponent; + use starknet::ContractAddress; + + component!(path: MultisigComponent, storage: multisig, event: MultisigEvent); + + #[abi(embed_v0)] + impl MultisigImpl = MultisigComponent::MultisigImpl; + impl InternalImpl = MultisigComponent::InternalImpl; + + #[storage] + pub struct Storage { + #[substorage(v0)] + pub multisig: MultisigComponent::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + MultisigEvent: MultisigComponent::Event + } + + #[constructor] + fn constructor(ref self: ContractState, quorum: u32, signers: Span) { + self.multisig.initializer(quorum, signers); + } +} + +#[starknet::interface] +pub trait IMultisigTargetMock { + fn add_number(ref self: TState, number: felt252); + fn get_current_sum(self: @TState) -> felt252; + fn failing_function(self: @TState); +} + +#[starknet::contract] +pub mod MultisigTargetMock { + use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + + #[storage] + pub struct Storage { + pub total_sum: felt252, + } + + #[abi(embed_v0)] + impl MockContractImpl of super::IMultisigTargetMock { + fn add_number(ref self: ContractState, number: felt252) { + self.total_sum.write(self.total_sum.read() + number); + } + + fn get_current_sum(self: @ContractState) -> felt252 { + self.total_sum.read() + } + + fn failing_function(self: @ContractState) { + core::panic_with_felt252('Expected failure'); + } + } +} diff --git a/packages/testing/src/constants.cairo b/packages/testing/src/constants.cairo index 9a4a8891c..d3cd64fdc 100644 --- a/packages/testing/src/constants.cairo +++ b/packages/testing/src/constants.cairo @@ -9,6 +9,7 @@ pub const VALUE: u256 = 300; pub const FELT_VALUE: felt252 = 'FELT_VALUE'; pub const ROLE: felt252 = 'ROLE'; pub const TIMESTAMP: u64 = 1704067200; // 2024-01-01 00:00:00 UTC +pub const BLOCK_NUMBER: u64 = 1234567; pub const OTHER_ROLE: felt252 = 'OTHER_ROLE'; pub const CHAIN_ID: felt252 = 'CHAIN_ID'; pub const TOKEN_ID: u256 = 21; @@ -101,6 +102,18 @@ pub fn DELEGATEE() -> ContractAddress { contract_address_const::<'DELEGATEE'>() } +pub fn ALICE() -> ContractAddress { + contract_address_const::<'ALICE'>() +} + +pub fn BOB() -> ContractAddress { + contract_address_const::<'BOB'>() +} + +pub fn CHARLIE() -> ContractAddress { + contract_address_const::<'CHARLIE'>() +} + pub fn DATA(success: bool) -> Span { let value = if success { SUCCESS From e1c09521330414ca0429ff5292a5fb0f5e01a993 Mon Sep 17 00:00:00 2001 From: immrsd <103599616+immrsd@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:58:03 +0100 Subject: [PATCH 4/4] Release v0.19.0 (#1204) * Create release entry in changelog * Bump version to 0.19.0 and update presets page --------- Co-authored-by: immrsd --- CHANGELOG.md | 2 + README.md | 4 +- Scarb.lock | 28 ++++++------- Scarb.toml | 2 +- docs/antora.yml | 2 +- docs/modules/ROOT/pages/api/access.adoc | 6 +-- docs/modules/ROOT/pages/api/account.adoc | 14 +++---- docs/modules/ROOT/pages/api/erc1155.adoc | 12 +++--- docs/modules/ROOT/pages/api/erc20.adoc | 10 ++--- docs/modules/ROOT/pages/api/erc721.adoc | 16 +++---- docs/modules/ROOT/pages/api/finance.adoc | 8 ++-- docs/modules/ROOT/pages/api/governance.adoc | 10 ++--- .../modules/ROOT/pages/api/introspection.adoc | 4 +- docs/modules/ROOT/pages/api/merkle-tree.adoc | 6 +-- docs/modules/ROOT/pages/api/security.adoc | 6 +-- docs/modules/ROOT/pages/api/testing.adoc | 2 +- docs/modules/ROOT/pages/api/token_common.adoc | 8 ++-- docs/modules/ROOT/pages/api/udc.adoc | 4 +- docs/modules/ROOT/pages/api/upgrades.adoc | 6 +-- docs/modules/ROOT/pages/index.adoc | 2 +- docs/modules/ROOT/pages/presets.adoc | 2 +- docs/modules/ROOT/pages/upgrades.adoc | 2 +- .../ROOT/pages/utils/_class_hashes.adoc | 2 +- docs/modules/ROOT/pages/wizard.adoc | 2 +- packages/access/README.md | 8 ++-- .../src/accesscontrol/accesscontrol.cairo | 2 +- .../access/src/accesscontrol/interface.cairo | 2 +- packages/access/src/ownable/interface.cairo | 2 +- packages/access/src/ownable/ownable.cairo | 2 +- packages/account/README.md | 12 +++--- packages/account/src/account.cairo | 2 +- packages/account/src/eth_account.cairo | 2 +- .../src/extensions/src9/interface.cairo | 2 +- .../src/extensions/src9/snip12_utils.cairo | 2 +- .../account/src/extensions/src9/src9.cairo | 2 +- packages/account/src/interface.cairo | 2 +- packages/account/src/utils.cairo | 2 +- .../account/src/utils/secp256_point.cairo | 2 +- packages/account/src/utils/signature.cairo | 2 +- packages/finance/src/vesting/interface.cairo | 2 +- packages/finance/src/vesting/vesting.cairo | 2 +- packages/governance/README.md | 10 ++--- .../governance/src/multisig/interface.cairo | 2 +- .../governance/src/multisig/multisig.cairo | 2 +- .../src/multisig/storage_utils.cairo | 2 +- .../governance/src/timelock/interface.cairo | 2 +- .../src/timelock/timelock_controller.cairo | 2 +- .../governance/src/utils/call_impls.cairo | 2 +- .../governance/src/votes/delegation.cairo | 2 +- packages/governance/src/votes/interface.cairo | 2 +- packages/governance/src/votes/votes.cairo | 4 +- packages/introspection/README.md | 6 +-- packages/introspection/src/interface.cairo | 2 +- packages/introspection/src/src5.cairo | 2 +- packages/merkle_tree/README.md | 2 +- packages/merkle_tree/src/hashes.cairo | 2 +- packages/merkle_tree/src/merkle_proof.cairo | 2 +- packages/presets/README.md | 14 +++---- packages/presets/src/account.cairo | 2 +- packages/presets/src/erc1155.cairo | 2 +- packages/presets/src/erc20.cairo | 2 +- packages/presets/src/erc721.cairo | 2 +- packages/presets/src/eth_account.cairo | 2 +- packages/presets/src/universal_deployer.cairo | 2 +- packages/presets/src/vesting.cairo | 2 +- packages/security/README.md | 8 ++-- packages/security/src/initializable.cairo | 2 +- packages/security/src/interface.cairo | 2 +- packages/security/src/pausable.cairo | 2 +- packages/security/src/reentrancyguard.cairo | 2 +- packages/testing/README.md | 10 ++--- packages/token/README.md | 42 +++++++++---------- .../token/src/common/erc2981/erc2981.cairo | 2 +- .../token/src/common/erc2981/interface.cairo | 2 +- packages/token/src/erc1155/erc1155.cairo | 2 +- .../token/src/erc1155/erc1155_receiver.cairo | 2 +- packages/token/src/erc1155/interface.cairo | 2 +- packages/token/src/erc20/erc20.cairo | 4 +- packages/token/src/erc20/interface.cairo | 2 +- .../token/src/erc20/snip12_utils/permit.cairo | 2 +- packages/token/src/erc721/erc721.cairo | 2 +- .../token/src/erc721/erc721_receiver.cairo | 2 +- .../erc721_enumerable/erc721_enumerable.cairo | 2 +- .../erc721_enumerable/interface.cairo | 2 +- packages/token/src/erc721/interface.cairo | 2 +- packages/upgrades/README.md | 8 ++-- packages/upgrades/src/interface.cairo | 2 +- packages/upgrades/src/upgradeable.cairo | 2 +- packages/utils/README.md | 16 +++---- .../utils/src/cryptography/interface.cairo | 2 +- packages/utils/src/cryptography/nonces.cairo | 2 +- packages/utils/src/cryptography/snip12.cairo | 2 +- packages/utils/src/deployments.cairo | 2 +- .../utils/src/deployments/interface.cairo | 2 +- packages/utils/src/lib.cairo | 2 +- packages/utils/src/math.cairo | 2 +- packages/utils/src/serde.cairo | 2 +- packages/utils/src/structs/checkpoint.cairo | 2 +- sncast_scripts/Scarb.lock | 20 ++++----- 99 files changed, 224 insertions(+), 222 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c420ba1c..c89671ec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.19.0 (2024-11-08) + ### Added - Multisig component (#1193) diff --git a/README.md b/README.md index bd32c4f7f..05a924eaa 100644 --- a/README.md +++ b/README.md @@ -43,14 +43,14 @@ Edit `scarb.toml` and add: ```toml [dependencies] -openzeppelin = "0.18.0" +openzeppelin = "0.19.0" ``` The previous example would import the entire library. We can also add each package as a separate dependency to improve the building time by not including modules that won't be used: ```toml [dependencies] -openzeppelin_token = "0.18.0" +openzeppelin_token = "0.19.0" ``` Build the project to download it: diff --git a/Scarb.lock b/Scarb.lock index 4b28da297..7be281b25 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -3,7 +3,7 @@ version = 1 [[package]] name = "openzeppelin" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_access", "openzeppelin_account", @@ -23,7 +23,7 @@ dependencies = [ [[package]] name = "openzeppelin_access" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_introspection", "openzeppelin_test_common", @@ -34,7 +34,7 @@ dependencies = [ [[package]] name = "openzeppelin_account" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_introspection", "openzeppelin_test_common", @@ -45,7 +45,7 @@ dependencies = [ [[package]] name = "openzeppelin_finance" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_access", "openzeppelin_test_common", @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "openzeppelin_governance" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_access", "openzeppelin_account", @@ -70,7 +70,7 @@ dependencies = [ [[package]] name = "openzeppelin_introspection" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_test_common", "snforge_std", @@ -78,14 +78,14 @@ dependencies = [ [[package]] name = "openzeppelin_merkle_tree" -version = "0.18.0" +version = "0.19.0" dependencies = [ "snforge_std", ] [[package]] name = "openzeppelin_presets" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_access", "openzeppelin_account", @@ -101,7 +101,7 @@ dependencies = [ [[package]] name = "openzeppelin_security" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_test_common", "openzeppelin_testing", @@ -110,7 +110,7 @@ dependencies = [ [[package]] name = "openzeppelin_test_common" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_access", "openzeppelin_account", @@ -127,14 +127,14 @@ dependencies = [ [[package]] name = "openzeppelin_testing" -version = "0.18.0" +version = "0.19.0" dependencies = [ "snforge_std", ] [[package]] name = "openzeppelin_token" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_access", "openzeppelin_account", @@ -147,7 +147,7 @@ dependencies = [ [[package]] name = "openzeppelin_upgrades" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_test_common", "openzeppelin_testing", @@ -156,7 +156,7 @@ dependencies = [ [[package]] name = "openzeppelin_utils" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_test_common", "openzeppelin_testing", diff --git a/Scarb.toml b/Scarb.toml index a16da9a73..d10c5dd70 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -22,7 +22,7 @@ version.workspace = true keywords.workspace = true [workspace.package] -version = "0.18.0" +version = "0.19.0" edition = "2024_07" cairo-version = "2.8.4" scarb-version = "2.8.4" diff --git a/docs/antora.yml b/docs/antora.yml index 0348166e7..8b53feb7a 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,6 +1,6 @@ name: contracts-cairo title: Contracts for Cairo -version: 0.18.0 +version: 0.19.0 nav: - modules/ROOT/nav.adoc asciidoc: diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 300814594..2b47dd86d 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -20,7 +20,7 @@ assigned each to multiple accounts. [.contract] [[OwnableComponent]] -=== `++OwnableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/access/src/ownable/ownable.cairo[{github-icon},role=heading-link] +=== `++OwnableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/access/src/ownable/ownable.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_access::ownable::OwnableComponent; @@ -255,7 +255,7 @@ Emitted when the ownership is transferred. [.contract] [[IAccessControl]] -=== `++IAccessControl++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/access/src/accesscontrol/interface.cairo[{github-icon},role=heading-link] +=== `++IAccessControl++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/access/src/accesscontrol/interface.cairo[{github-icon},role=heading-link] :grant_role: xref:#IAccessControl-grant_role[grant_role] :revoke_role: xref:#IAccessControl-revoke_role[revoke_role] @@ -388,7 +388,7 @@ Emitted when `account` is revoked `role`. [.contract] [[AccessControlComponent]] -=== `++AccessControlComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/access/src/accesscontrol/accesscontrol.cairo[{github-icon},role=heading-link] +=== `++AccessControlComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/access/src/accesscontrol/accesscontrol.cairo[{github-icon},role=heading-link] :assert_only_role: xref:#AccessControlComponent-assert_only_role :grant_role: xref:#AccessControlComponent-grant_role[grant_role] diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 2c6643bf5..d39b20d9b 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -14,7 +14,7 @@ include::../utils/_common.adoc[] [.contract] [[ISRC6]] -=== `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/account/src/interface.cairo[{github-icon},role=heading-link] +=== `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/account/src/interface.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_account::interface::ISRC6; @@ -67,7 +67,7 @@ Returns the short string `'VALID'` if valid, otherwise it reverts. [.contract] [[AccountComponent]] -=== `++AccountComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/account/src/account.cairo[{github-icon},role=heading-link] +=== `++AccountComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/account/src/account.cairo[{github-icon},role=heading-link] :OwnerAdded: xref:AccountComponent-OwnerAdded[OwnerAdded] :OwnerRemoved: xref:AccountComponent-OwnerRemoved[OwnerRemoved] @@ -317,7 +317,7 @@ Emitted when a `public_key` is removed. [.contract] [[EthAccountComponent]] -=== `++EthAccountComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/account/src/eth_account.cairo[{github-icon},role=heading-link] +=== `++EthAccountComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/account/src/eth_account.cairo[{github-icon},role=heading-link] :OwnerAdded: xref:EthAccountComponent-OwnerAdded[OwnerAdded] :OwnerRemoved: xref:EthAccountComponent-OwnerRemoved[OwnerRemoved] @@ -572,7 +572,7 @@ Emitted when a `public_key` is removed. [.contract] [[ISRC9_V2]] -=== `++ISRC9_V2++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/account/src/extensions/src9/interface.cairo[{github-icon},role=heading-link] +=== `++ISRC9_V2++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/account/src/extensions/src9/interface.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_account::extensions::src9::ISRC9_V2; @@ -622,7 +622,7 @@ Get the status of a given nonce. `true` if the nonce is available to use. [.contract] [[SRC9Component]] -=== `++SRC9Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/account/src/extensions/src9/src9.cairo[{github-icon},role=heading-link] +=== `++SRC9Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/account/src/extensions/src9/src9.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_account::extensions::SRC9Component; @@ -698,7 +698,7 @@ Initializes the account by registering the `ISRC9_V2` interface Id. [.contract] [[AccountUpgradeable]] -=== `++AccountUpgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/presets/src/account.cairo[{github-icon},role=heading-link] +=== `++AccountUpgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/presets/src/account.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_presets::AccountUpgradeable; @@ -759,7 +759,7 @@ Requirements: [.contract] [[EthAccountUpgradeable]] -=== `++EthAccountUpgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/presets/src/eth_account.cairo[{github-icon},role=heading-link] +=== `++EthAccountUpgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/presets/src/eth_account.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_presets::EthAccountUpgradeable; diff --git a/docs/modules/ROOT/pages/api/erc1155.adoc b/docs/modules/ROOT/pages/api/erc1155.adoc index eda7a36f2..22c41963e 100644 --- a/docs/modules/ROOT/pages/api/erc1155.adoc +++ b/docs/modules/ROOT/pages/api/erc1155.adoc @@ -16,7 +16,7 @@ TIP: For an overview of ERC1155, read our xref:erc1155.adoc[ERC1155 guide]. [.contract] [[IERC1155]] -=== `++IERC1155++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc1155/interface.cairo[{github-icon},role=heading-link] +=== `++IERC1155++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc1155/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -126,7 +126,7 @@ Emitted when the token URI is updated to `value` for the `id` token. [.contract] [[IERC1155MetadataURI]] -=== `++IERC1155MetadataURI++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc1155/interface.cairo[{github-icon},role=heading-link] +=== `++IERC1155MetadataURI++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc1155/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -156,7 +156,7 @@ Returns the Uniform Resource Identifier (URI) for the `token_id` token. [.contract] [[ERC1155Component]] -=== `++ERC1155Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc1155/erc1155.cairo[{github-icon},role=heading-link] +=== `++ERC1155Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc1155/erc1155.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -543,7 +543,7 @@ See <>. [.contract] [[IERC1155Receiver]] -=== `++IERC1155Receiver++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc1155/interface.cairo[{github-icon},role=heading-link] +=== `++IERC1155Receiver++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc1155/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -583,7 +583,7 @@ via <> by [.contract] [[ERC1155ReceiverComponent]] -=== `++ERC1155ReceiverComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc1155/erc1155_receiver.cairo[{github-icon},role=heading-link] +=== `++ERC1155ReceiverComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc1155/erc1155_receiver.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -660,7 +660,7 @@ Registers the `IERC1155Receiver` interface ID as supported through introspection [.contract] [[ERC1155Upgradeable]] -=== `++ERC1155Upgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/presets/src/erc1155.cairo[{github-icon},role=heading-link] +=== `++ERC1155Upgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/presets/src/erc1155.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_presets::ERC1155; diff --git a/docs/modules/ROOT/pages/api/erc20.adoc b/docs/modules/ROOT/pages/api/erc20.adoc index 43582dfc5..feda42608 100644 --- a/docs/modules/ROOT/pages/api/erc20.adoc +++ b/docs/modules/ROOT/pages/api/erc20.adoc @@ -19,7 +19,7 @@ TIP: For an overview of ERC20, read our {erc20-guide}. [.contract] [[IERC20]] -=== `++IERC20++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc20/interface.cairo[{github-icon},role=heading-link] +=== `++IERC20++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc20/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -117,7 +117,7 @@ Emitted when the allowance of a `spender` for an `owner` is set. [.contract] [[IERC20Metadata]] -=== `++IERC20Metadata++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc20/interface.cairo#L19[{github-icon},role=heading-link] +=== `++IERC20Metadata++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc20/interface.cairo#L19[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -165,7 +165,7 @@ NOTE: This information is only used for _display_ purposes: it in no way affects [.contract] [[ERC20Component]] -=== `++ERC20Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc20/erc20.cairo[{github-icon},role=heading-link] +=== `++ERC20Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc20/erc20.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -516,7 +516,7 @@ See <>. [.contract] [[IERC20Permit]] -=== `++IERC20Permit++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc20/interface.cairo#L19[{github-icon},role=heading-link] +=== `++IERC20Permit++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc20/interface.cairo#L19[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -560,7 +560,7 @@ The domain hashing logic follows the {snip-12} standard. [.contract] [[ERC20Upgradeable]] -=== `++ERC20Upgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/presets/src/erc20.cairo[{github-icon},role=heading-link] +=== `++ERC20Upgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/presets/src/erc20.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_presets::ERC20Upgradeable; diff --git a/docs/modules/ROOT/pages/api/erc721.adoc b/docs/modules/ROOT/pages/api/erc721.adoc index 6a4fb8bf8..4fccd63a5 100644 --- a/docs/modules/ROOT/pages/api/erc721.adoc +++ b/docs/modules/ROOT/pages/api/erc721.adoc @@ -16,7 +16,7 @@ TIP: For an overview of ERC721, read our xref:erc721.adoc[ERC721 guide]. [.contract] [[IERC721]] -=== `++IERC721++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc721/interface.cairo#L13-L31[{github-icon},role=heading-link] +=== `++IERC721++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc721/interface.cairo#L13-L31[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -135,7 +135,7 @@ Emitted when `token_id` token is transferred from `from` to `to`. [.contract] [[IERC721Metadata]] -=== `++IERC721Metadata++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc721/interface.cairo#L54-L59[{github-icon},role=heading-link] +=== `++IERC721Metadata++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc721/interface.cairo#L54-L59[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -181,7 +181,7 @@ If the URI is not set for `token_id`, the return value will be an empty `ByteArr [.contract] [[ERC721Component]] -=== `++ERC721Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc721/erc721.cairo#L7[{github-icon},role=heading-link] +=== `++ERC721Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc721/erc721.cairo#L7[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -693,7 +693,7 @@ See <>. [.contract] [[IERC721Receiver]] -=== `++IERC721Receiver++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc721/interface.cairo#L70-L79[{github-icon},role=heading-link] +=== `++IERC721Receiver++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc721/interface.cairo#L70-L79[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -724,7 +724,7 @@ Whenever an IERC721 `token_id` token is transferred to this non-account contract [.contract] [[ERC721ReceiverComponent]] -=== `++ERC721ReceiverComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc721/erc721_receiver.cairo[{github-icon},role=heading-link] +=== `++ERC721ReceiverComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc721/erc721_receiver.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -790,7 +790,7 @@ Registers the `IERC721Receiver` interface ID as supported through introspection. [.contract] [[IERC721Enumerable]] -=== `++IERC721Enumerable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc721/extensions/erc721_enumerable/interface.cairo[{github-icon},role=heading-link] +=== `++IERC721Enumerable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc721/extensions/erc721_enumerable/interface.cairo[{github-icon},role=heading-link] Interface for the optional enumerable functions in {eip721}. @@ -832,7 +832,7 @@ Use along with xref:#IERC721-balance_of[IERC721::balance_of] to enumerate all of [.contract] [[ERC721EnumerableComponent]] -=== `++ERC721EnumerableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/erc721/extensions/erc721_enumerable.cairo[{github-icon},role=heading-link] +=== `++ERC721EnumerableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/erc721/extensions/erc721_enumerable.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_token::erc721::extensions::ERC721EnumerableComponent; @@ -988,7 +988,7 @@ This has 0(1) time complexity but alters the indexed order by swapping `token_id [.contract] [[ERC721Upgradeable]] -=== `++ERC721Upgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/presets/src/erc721.cairo[{github-icon},role=heading-link] +=== `++ERC721Upgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/presets/src/erc721.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_presets::ERC721Upgradeable; diff --git a/docs/modules/ROOT/pages/api/finance.adoc b/docs/modules/ROOT/pages/api/finance.adoc index 833044dfe..7d3b5828d 100755 --- a/docs/modules/ROOT/pages/api/finance.adoc +++ b/docs/modules/ROOT/pages/api/finance.adoc @@ -12,7 +12,7 @@ This crate includes primitives for financial systems. [.contract] [[IVesting]] -=== `++IVesting++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/finance/src/vesting/interface.cairo[{github-icon},role=heading-link] +=== `++IVesting++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/finance/src/vesting/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -104,7 +104,7 @@ Emitted when vested tokens are released to the beneficiary. [.contract] [[VestingComponent]] -=== `++VestingComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/finance/src/vesting/vesting.cairo[{github-icon},role=heading-link] +=== `++VestingComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/finance/src/vesting/vesting.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -236,7 +236,7 @@ Returns the vested amount that's calculated using the {vesting-schedule} trait i [.contract] [[LinearVestingSchedule]] -=== `++LinearVestingSchedule++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/finance/src/vesting/vesting.cairo[{github-icon},role=heading-link] +=== `++LinearVestingSchedule++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/finance/src/vesting/vesting.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -251,7 +251,7 @@ is directly proportional to the time passed since the start of the vesting sched [.contract] [[VestingWallet]] -=== `++VestingWallet++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/presets/src/vesting.cairo[{github-icon},role=heading-link] +=== `++VestingWallet++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/presets/src/vesting.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin::presets::VestingWallet; diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 426c97edc..6d5197ec5 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -21,7 +21,7 @@ In a governance system, `TimelockControllerComponent` is in charge of introducin [.contract] [[ITimelock]] -=== `++ITimelock++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/governance/src/timelock/interface.cairo[{github-icon},role=heading-link] +=== `++ITimelock++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/governance/src/timelock/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -247,7 +247,7 @@ Emitted when the minimum delay for future operations is modified. [.contract] [[TimelockControllerComponent]] -=== `++TimelockControllerComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/governance/src/timelock/timelock_controller.cairo[{github-icon},role=heading-link] +=== `++TimelockControllerComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/governance/src/timelock/timelock_controller.cairo[{github-icon},role=heading-link] include::../utils/_common.adoc[] @@ -611,7 +611,7 @@ The `VotesComponent` provides a flexible system for tracking and delegating voti [.contract] [[IVotes]] -=== `++IVotes++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/governance/src/votes/interface.cairo[{github-icon},role=heading-link] +=== `++IVotes++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/governance/src/votes/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -676,7 +676,7 @@ Delegates votes from `delegator` to `delegatee` through a SNIP12 message signatu [.contract] [[VotesComponent]] -=== `++VotesComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/governance/src/votes/votes.cairo[{github-icon},role=heading-link] +=== `++VotesComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/governance/src/votes/votes.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -904,7 +904,7 @@ Emitted when a token transfer or delegate change results in changes to a delegat [.contract] [[VotingUnitsTrait]] -=== `++VotingUnitsTrait++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/governance/src/votes/votes.cairo[{github-icon},role=heading-link] +=== `++VotingUnitsTrait++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/governance/src/votes/votes.cairo[{github-icon},role=heading-link] ```cairo pub trait VotingUnitsTrait { diff --git a/docs/modules/ROOT/pages/api/introspection.adoc b/docs/modules/ROOT/pages/api/introspection.adoc index 0730ab4cc..98684654d 100644 --- a/docs/modules/ROOT/pages/api/introspection.adoc +++ b/docs/modules/ROOT/pages/api/introspection.adoc @@ -10,7 +10,7 @@ This crate handles https://en.wikipedia.org/wiki/Type_introspection[type introsp [.contract] [[ISRC5]] -=== `++ISRC5++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/introspection/src/interface.cairo#L7[{github-icon},role=heading-link] +=== `++ISRC5++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/introspection/src/interface.cairo#L7[{github-icon},role=heading-link] ```cairo use openzeppelin_introspection::interface::ISRC5; @@ -44,7 +44,7 @@ on how to compute this ID. [.contract] [[SRC5Component]] -=== `++SRC5Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/introspection/src/src5.cairo[{github-icon},role=heading-link] +=== `++SRC5Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/introspection/src/src5.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_introspection::src5::SRC5Component; diff --git a/docs/modules/ROOT/pages/api/merkle-tree.adoc b/docs/modules/ROOT/pages/api/merkle-tree.adoc index f909ff2eb..81fe1b7d5 100644 --- a/docs/modules/ROOT/pages/api/merkle-tree.adoc +++ b/docs/modules/ROOT/pages/api/merkle-tree.adoc @@ -23,14 +23,14 @@ NOTE: `openzeppelin_merkle_tree` doesn't have dependencies outside of `corelib`, ==== To use it as a standalone package, you can add it in your `Scarb.toml` as follows: -`openzeppelin_merkle_tree = "0.18.0"` +`openzeppelin_merkle_tree = "0.19.0"` ==== == Modules [.contract] [[merkle_proof]] -=== `++merkle_proof++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/merkle_tree/src/merkle_proof.cairo[{github-icon},role=heading-link] +=== `++merkle_proof++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/merkle_tree/src/merkle_proof.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_merkle_tree::merkle_proof; @@ -144,7 +144,7 @@ NOTE: This function expects a `CommutativeHasher` implementation. See xref:#hash [.contract] [[hashes]] -=== `++hashes++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/merkle_tree/src/hashes.cairo[{github-icon},role=heading-link] +=== `++hashes++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/merkle_tree/src/hashes.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_merkle_tree::hashes; diff --git a/docs/modules/ROOT/pages/api/security.adoc b/docs/modules/ROOT/pages/api/security.adoc index 3c19dda82..d742b6dc6 100644 --- a/docs/modules/ROOT/pages/api/security.adoc +++ b/docs/modules/ROOT/pages/api/security.adoc @@ -8,7 +8,7 @@ This crate provides components to handle common security-related tasks. [.contract] [[InitializableComponent]] -=== `++InitializableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/security/src/initializable.cairo[{github-icon},role=heading-link] +=== `++InitializableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/security/src/initializable.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_security::InitializableComponent; @@ -58,7 +58,7 @@ Requirements: [.contract] [[PausableComponent]] -=== `++PausableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/security/src/pausable.cairo[{github-icon},role=heading-link] +=== `++PausableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/security/src/pausable.cairo[{github-icon},role=heading-link] :Paused: xref:PausableComponent-Paused[Paused] :Unpaused: xref:PausableComponent-Unpaused[Unpaused] @@ -163,7 +163,7 @@ Emitted when the contract is unpaused by `account`. [.contract] [[ReentrancyGuardComponent]] -=== `++ReentrancyGuardComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/security/src/reentrancyguard.cairo[{github-icon},role=heading-link] +=== `++ReentrancyGuardComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/security/src/reentrancyguard.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_security::ReentrancyGuardComponent; diff --git a/docs/modules/ROOT/pages/api/testing.adoc b/docs/modules/ROOT/pages/api/testing.adoc index d46310582..4d570d09b 100644 --- a/docs/modules/ROOT/pages/api/testing.adoc +++ b/docs/modules/ROOT/pages/api/testing.adoc @@ -16,7 +16,7 @@ be added as a separate dependency in `Scarb.toml`: ``` [dev-dependencies] -openzeppelin_testing = "0.18.0" +openzeppelin_testing = "0.19.0" ``` == Test Utilities diff --git a/docs/modules/ROOT/pages/api/token_common.adoc b/docs/modules/ROOT/pages/api/token_common.adoc index e740467d9..37839f5b9 100644 --- a/docs/modules/ROOT/pages/api/token_common.adoc +++ b/docs/modules/ROOT/pages/api/token_common.adoc @@ -12,7 +12,7 @@ This module provides extensions and utilities that are common to multiple token [.contract] [[IERC2981]] -=== `++IERC2981++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/common/erc2981/interface.cairo[{github-icon},role=heading-link] +=== `++IERC2981++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/common/erc2981/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -46,7 +46,7 @@ unit of exchange. [.contract] [[IERC2981Info]] -=== `++IERC2981Info++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/common/erc2981/interface.cairo[{github-icon},role=heading-link] +=== `++IERC2981Info++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/common/erc2981/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -91,7 +91,7 @@ The returned tuple contains: [.contract] [[IERC2981Admin]] -=== `++IERC2981Admin++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/common/erc2981/interface.cairo[{github-icon},role=heading-link] +=== `++IERC2981Admin++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/common/erc2981/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```cairo @@ -138,7 +138,7 @@ Resets royalty information for the token id back to unset. [.contract] [[ERC2981Component]] -=== `++ERC2981Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/token/src/common/erc2981/erc2981.cairo[{github-icon},role=heading-link] +=== `++ERC2981Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/token/src/common/erc2981/erc2981.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_token::common::erc2981::ERC2981Component; diff --git a/docs/modules/ROOT/pages/api/udc.adoc b/docs/modules/ROOT/pages/api/udc.adoc index 58717593b..bb57bd977 100644 --- a/docs/modules/ROOT/pages/api/udc.adoc +++ b/docs/modules/ROOT/pages/api/udc.adoc @@ -8,7 +8,7 @@ Reference of the Universal Deployer Contract (UDC) interface and preset. [.contract] [[IUniversalDeployer]] -=== `++IUniversalDeployer++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/utils/src/deployments/interface.cairo[{github-icon},role=heading-link] +=== `++IUniversalDeployer++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/utils/src/deployments/interface.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_utils::interfaces::IUniversalDeployer; @@ -51,7 +51,7 @@ Emitted when `deployer` deploys a contract through the Universal Deployer Contra [.contract] [[UniversalDeployer]] -=== `++UniversalDeployer++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/presets/src/universal_deployer.cairo[{github-icon},role=heading-link] +=== `++UniversalDeployer++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/presets/src/universal_deployer.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_presets::UniversalDeployer; diff --git a/docs/modules/ROOT/pages/api/upgrades.adoc b/docs/modules/ROOT/pages/api/upgrades.adoc index 9f67d84c9..8a7d44b14 100644 --- a/docs/modules/ROOT/pages/api/upgrades.adoc +++ b/docs/modules/ROOT/pages/api/upgrades.adoc @@ -9,7 +9,7 @@ This crate provides interfaces and utilities related to upgradeability. [.contract] [[IUpgradeable]] -=== `++IUpgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/upgrades/src/interface.cairo[{github-icon},role=heading-link] +=== `++IUpgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/upgrades/src/interface.cairo[{github-icon},role=heading-link] :Upgraded: xref:UpgradeableComponent-Upgraded[Upgraded] @@ -38,7 +38,7 @@ NOTE: This function is usually protected by an xref:access.adoc[Access Control] [.contract] [[IUpgradeAndCall]] -=== `++IUpgradeAndCall++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/upgrades/src/interface.cairo[{github-icon},role=heading-link] +=== `++IUpgradeAndCall++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/upgrades/src/interface.cairo[{github-icon},role=heading-link] :Upgraded: xref:UpgradeableComponent-Upgraded[Upgraded] @@ -67,7 +67,7 @@ NOTE: This function is usually protected by an xref:access.adoc[Access Control] [.contract] [[UpgradeableComponent]] -=== `++UpgradeableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/upgrades/src/upgradeable.cairo[{github-icon},role=heading-link] +=== `++UpgradeableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/upgrades/src/upgradeable.cairo[{github-icon},role=heading-link] ```cairo use openzeppelin_upgrades::upgradeable::UpgradeableComponent; diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 5a920a131..234221ff4 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -58,7 +58,7 @@ Install the library by declaring it as a dependency in the project's `Scarb.toml [,text] ---- [dependencies] -openzeppelin = "0.18.0" +openzeppelin = "0.19.0" ---- WARNING: Make sure the tag matches the target release. diff --git a/docs/modules/ROOT/pages/presets.adoc b/docs/modules/ROOT/pages/presets.adoc index 1f7395468..5f6aa1332 100644 --- a/docs/modules/ROOT/pages/presets.adoc +++ b/docs/modules/ROOT/pages/presets.adoc @@ -57,7 +57,7 @@ TIP: {starkli} class-hash command can be used to compute the class hash from a S :setup_project: xref:index.adoc#set_up_your_project[setting up a project] :install_lib: xref:index.adoc#install the_library[installing the Contracts for Cairo library] -:presets_dir: link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/presets/src[presets directory] +:presets_dir: link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/presets/src[presets directory] These preset contracts are ready-to-deploy which means they should already be declared on the Sepolia network. Simply deploy the preset class hash and add the appropriate constructor arguments. diff --git a/docs/modules/ROOT/pages/upgrades.adoc b/docs/modules/ROOT/pages/upgrades.adoc index 99bd9cfb1..db90ed7af 100644 --- a/docs/modules/ROOT/pages/upgrades.adoc +++ b/docs/modules/ROOT/pages/upgrades.adoc @@ -1,7 +1,7 @@ :contract_classes: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/contract-classes/[Contract Classes] :class_hash: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/class-hash/[class hash] :replace_class_syscall: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/system-calls-cairo1/#replace_class[replace_class] -:upgradeable: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.18.0/packages/upgrades/src/upgradeable.cairo[Upgradeable] +:upgradeable: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.19.0/packages/upgrades/src/upgradeable.cairo[Upgradeable] :ownable: xref:access.adoc#ownership_and_ownable[Ownable] :i_upgradeable: xref:api/upgrades.adoc#IUpgradeable[IUpgradeable] :library_calls: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/system-calls-cairo1/#library_call[library calls] diff --git a/docs/modules/ROOT/pages/utils/_class_hashes.adoc b/docs/modules/ROOT/pages/utils/_class_hashes.adoc index 434bc9996..26ff582c3 100644 --- a/docs/modules/ROOT/pages/utils/_class_hashes.adoc +++ b/docs/modules/ROOT/pages/utils/_class_hashes.adoc @@ -6,7 +6,7 @@ :ERC721Upgradeable-class-hash: 0x03ee93221a8ca78ffca36eefcbe9eb8a601e854ce5e68086cdcf30d631090e7e :ERC1155Upgradeable-class-hash: 0x032e3666516e3c138011121baaf898e372f9b23eaae313ad8a401c9b9620d5ae :AccountUpgradeable-class-hash: 0x04a444ef8caf8fa0db05da60bf0ad9bae264c73fa7e32c61d245406f5523174b -:EthAccountUpgradeable-class-hash: 0x04bc5fe3c036a449c3e2302581aaf3c863d49a3911aa80765cf7c33886114154 +:EthAccountUpgradeable-class-hash: 0x01f342e9dddd22bf30302676d83652fdf868d97357d5872c91032b380616ea44 :UniversalDeployer-class-hash: 0x04cc44533e6a2f0612ba6b7c6cabfebf13e0d5f294504fffc2403ec0a4d1cf9d :VestingWallet-class-hash: 0x02f9206089b6256db631acef1f8ca9f60da133a363600f89b4219f6d92632afa diff --git a/docs/modules/ROOT/pages/wizard.adoc b/docs/modules/ROOT/pages/wizard.adoc index 73cdef6be..9749d63b0 100644 --- a/docs/modules/ROOT/pages/wizard.adoc +++ b/docs/modules/ROOT/pages/wizard.adoc @@ -10,5 +10,5 @@ NOTE: We strongly recommend checking the xref:components.adoc[Components] sectio ++++ - + ++++ diff --git a/packages/access/README.md b/packages/access/README.md index bc2aea8dc..c1eb7aa9d 100644 --- a/packages/access/README.md +++ b/packages/access/README.md @@ -1,6 +1,6 @@ ## Access Control -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/access](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/access) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/access](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/access) This crate provides ways to restrict who can access the functions of a contract or when they can do it. @@ -12,9 +12,9 @@ and assigned each to multiple accounts. ### Interfaces -- [`IAccessControl`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/access#IAccessControl) +- [`IAccessControl`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/access#IAccessControl) ### Components -- [`OwnableComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/access#OwnableComponent) -- [`AccessControlComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/access#AccessControlComponent) +- [`OwnableComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/access#OwnableComponent) +- [`AccessControlComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/access#AccessControlComponent) diff --git a/packages/access/src/accesscontrol/accesscontrol.cairo b/packages/access/src/accesscontrol/accesscontrol.cairo index a24eb726a..239306afe 100644 --- a/packages/access/src/accesscontrol/accesscontrol.cairo +++ b/packages/access/src/accesscontrol/accesscontrol.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (access/accesscontrol/accesscontrol.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (access/accesscontrol/accesscontrol.cairo) /// # AccessControl Component /// diff --git a/packages/access/src/accesscontrol/interface.cairo b/packages/access/src/accesscontrol/interface.cairo index c74209003..bf81051d4 100644 --- a/packages/access/src/accesscontrol/interface.cairo +++ b/packages/access/src/accesscontrol/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (access/accesscontrol/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (access/accesscontrol/interface.cairo) use starknet::ContractAddress; diff --git a/packages/access/src/ownable/interface.cairo b/packages/access/src/ownable/interface.cairo index dc7689bc5..1d9e41f63 100644 --- a/packages/access/src/ownable/interface.cairo +++ b/packages/access/src/ownable/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (access/ownable/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (access/ownable/interface.cairo) use starknet::ContractAddress; diff --git a/packages/access/src/ownable/ownable.cairo b/packages/access/src/ownable/ownable.cairo index bc37d47ff..b001e8dbd 100644 --- a/packages/access/src/ownable/ownable.cairo +++ b/packages/access/src/ownable/ownable.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (access/ownable/ownable.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (access/ownable/ownable.cairo) /// # Ownable Component /// diff --git a/packages/account/README.md b/packages/account/README.md index 2c026c914..e3a1db52a 100644 --- a/packages/account/README.md +++ b/packages/account/README.md @@ -1,6 +1,6 @@ ## Account -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/account](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/account) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/account](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/account) This crate provides components to implement account contracts that can be used for interacting with the network. @@ -12,11 +12,11 @@ This crate provides components to implement account contracts that can be used f ### Interfaces -- [`ISRC6`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/account#ISRC6) -- [`ISRC9_V2`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/account#ISRC9_V2) +- [`ISRC6`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/account#ISRC6) +- [`ISRC9_V2`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/account#ISRC9_V2) ### Components -- [`AccountComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/account#AccountComponent) -- [`EthAccountComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/account#EthAccountComponent) -- [`SRC9Component`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/account#SRC9Component) +- [`AccountComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/account#AccountComponent) +- [`EthAccountComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/account#EthAccountComponent) +- [`SRC9Component`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/account#SRC9Component) diff --git a/packages/account/src/account.cairo b/packages/account/src/account.cairo index 53957dbbe..a1a67a384 100644 --- a/packages/account/src/account.cairo +++ b/packages/account/src/account.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (account/account.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (account/account.cairo) /// # Account Component /// diff --git a/packages/account/src/eth_account.cairo b/packages/account/src/eth_account.cairo index afc8e046d..3b19610c7 100644 --- a/packages/account/src/eth_account.cairo +++ b/packages/account/src/eth_account.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (account/eth_account.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (account/eth_account.cairo) /// # EthAccount Component /// diff --git a/packages/account/src/extensions/src9/interface.cairo b/packages/account/src/extensions/src9/interface.cairo index 39e497376..604a547df 100644 --- a/packages/account/src/extensions/src9/interface.cairo +++ b/packages/account/src/extensions/src9/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (account/extensions/src9/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (account/extensions/src9/interface.cairo) use starknet::ContractAddress; use starknet::account::Call; diff --git a/packages/account/src/extensions/src9/snip12_utils.cairo b/packages/account/src/extensions/src9/snip12_utils.cairo index db8e2e49a..75d9f51af 100644 --- a/packages/account/src/extensions/src9/snip12_utils.cairo +++ b/packages/account/src/extensions/src9/snip12_utils.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (account/extensions/src9/snip12_utils.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (account/extensions/src9/snip12_utils.cairo) use core::hash::{HashStateTrait, HashStateExTrait}; use core::poseidon::{PoseidonTrait, poseidon_hash_span}; diff --git a/packages/account/src/extensions/src9/src9.cairo b/packages/account/src/extensions/src9/src9.cairo index 973008b4e..182bf4735 100644 --- a/packages/account/src/extensions/src9/src9.cairo +++ b/packages/account/src/extensions/src9/src9.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (account/extensions/src9/src9.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (account/extensions/src9/src9.cairo) /// # SRC9 Component (Outside Execution) /// diff --git a/packages/account/src/interface.cairo b/packages/account/src/interface.cairo index 9a32f50b4..cbdc9d300 100644 --- a/packages/account/src/interface.cairo +++ b/packages/account/src/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (account/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (account/interface.cairo) use starknet::account::Call; diff --git a/packages/account/src/utils.cairo b/packages/account/src/utils.cairo index efcde050c..4537a1c1f 100644 --- a/packages/account/src/utils.cairo +++ b/packages/account/src/utils.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (account/utils.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (account/utils.cairo) pub mod secp256_point; pub mod signature; diff --git a/packages/account/src/utils/secp256_point.cairo b/packages/account/src/utils/secp256_point.cairo index c9cc00294..954194b44 100644 --- a/packages/account/src/utils/secp256_point.cairo +++ b/packages/account/src/utils/secp256_point.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (account/utils/secp256_point.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (account/utils/secp256_point.cairo) use core::fmt::{Formatter, Error}; use starknet::SyscallResultTrait; diff --git a/packages/account/src/utils/signature.cairo b/packages/account/src/utils/signature.cairo index d4465dba2..dad6030f7 100644 --- a/packages/account/src/utils/signature.cairo +++ b/packages/account/src/utils/signature.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (account/utils/signature.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (account/utils/signature.cairo) use core::ecdsa::check_ecdsa_signature; use crate::interface::{EthPublicKey, P256PublicKey}; diff --git a/packages/finance/src/vesting/interface.cairo b/packages/finance/src/vesting/interface.cairo index 3c3c9ffa4..fe2d2fc84 100644 --- a/packages/finance/src/vesting/interface.cairo +++ b/packages/finance/src/vesting/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (finance/vesting/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (finance/vesting/interface.cairo) use starknet::ContractAddress; diff --git a/packages/finance/src/vesting/vesting.cairo b/packages/finance/src/vesting/vesting.cairo index 79617d2ce..c7169db6a 100644 --- a/packages/finance/src/vesting/vesting.cairo +++ b/packages/finance/src/vesting/vesting.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (finance/vesting/vesting.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (finance/vesting/vesting.cairo) use starknet::ContractAddress; diff --git a/packages/governance/README.md b/packages/governance/README.md index 9aa45e2e2..456a9d5e9 100644 --- a/packages/governance/README.md +++ b/packages/governance/README.md @@ -1,15 +1,15 @@ ## Governance -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/governance](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/governance) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/governance](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/governance) This crate includes primitives for on-chain governance. ### Interfaces -- [`ITimelock`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/governance#ITimelock) -- [`IVotes`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/governance#IVotes) +- [`ITimelock`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/governance#ITimelock) +- [`IVotes`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/governance#IVotes) ### Components -- [`TimelockControllerComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/governance#TimelockControllerComponent) -- [`VotesComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/governance#VotesComponent) +- [`TimelockControllerComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/governance#TimelockControllerComponent) +- [`VotesComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/governance#VotesComponent) diff --git a/packages/governance/src/multisig/interface.cairo b/packages/governance/src/multisig/interface.cairo index ccc872a50..9e7fe9141 100644 --- a/packages/governance/src/multisig/interface.cairo +++ b/packages/governance/src/multisig/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (governance/multisig/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (governance/multisig/interface.cairo) use starknet::ContractAddress; use starknet::account::Call; diff --git a/packages/governance/src/multisig/multisig.cairo b/packages/governance/src/multisig/multisig.cairo index 4056a6189..411824987 100644 --- a/packages/governance/src/multisig/multisig.cairo +++ b/packages/governance/src/multisig/multisig.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (governance/multisig/multisig.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (governance/multisig/multisig.cairo) /// # Multisig Component /// diff --git a/packages/governance/src/multisig/storage_utils.cairo b/packages/governance/src/multisig/storage_utils.cairo index 09ca71f35..e0385ba7e 100644 --- a/packages/governance/src/multisig/storage_utils.cairo +++ b/packages/governance/src/multisig/storage_utils.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (governance/multisig/storage_utils.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (governance/multisig/storage_utils.cairo) use core::integer::u128_safe_divmod; use starknet::storage_access::StorePacking; diff --git a/packages/governance/src/timelock/interface.cairo b/packages/governance/src/timelock/interface.cairo index f0ec3baa0..fdd20d707 100644 --- a/packages/governance/src/timelock/interface.cairo +++ b/packages/governance/src/timelock/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (governance/timelock/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (governance/timelock/interface.cairo) use crate::timelock::OperationState; use starknet::ContractAddress; diff --git a/packages/governance/src/timelock/timelock_controller.cairo b/packages/governance/src/timelock/timelock_controller.cairo index 474a50475..2d839f1ae 100644 --- a/packages/governance/src/timelock/timelock_controller.cairo +++ b/packages/governance/src/timelock/timelock_controller.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (governance/timelock/timelock_controller.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (governance/timelock/timelock_controller.cairo) /// # TimelockController Component /// diff --git a/packages/governance/src/utils/call_impls.cairo b/packages/governance/src/utils/call_impls.cairo index c76d77fca..36ba4df14 100644 --- a/packages/governance/src/utils/call_impls.cairo +++ b/packages/governance/src/utils/call_impls.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (governance/utils/call_impls.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (governance/utils/call_impls.cairo) use core::hash::{HashStateTrait, HashStateExTrait, Hash}; use starknet::account::Call; diff --git a/packages/governance/src/votes/delegation.cairo b/packages/governance/src/votes/delegation.cairo index 75feada0f..e8132c0e9 100644 --- a/packages/governance/src/votes/delegation.cairo +++ b/packages/governance/src/votes/delegation.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (governance/votes/delegation.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (governance/votes/delegation.cairo) use core::hash::{HashStateTrait, HashStateExTrait}; use core::poseidon::PoseidonTrait; diff --git a/packages/governance/src/votes/interface.cairo b/packages/governance/src/votes/interface.cairo index e6938f244..5482502cf 100644 --- a/packages/governance/src/votes/interface.cairo +++ b/packages/governance/src/votes/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (governance/votes/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (governance/votes/interface.cairo) use starknet::ContractAddress; diff --git a/packages/governance/src/votes/votes.cairo b/packages/governance/src/votes/votes.cairo index 7d97fd0c6..76a7ce458 100644 --- a/packages/governance/src/votes/votes.cairo +++ b/packages/governance/src/votes/votes.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (governance/votes/votes.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (governance/votes/votes.cairo) use starknet::ContractAddress; @@ -22,7 +22,7 @@ use starknet::ContractAddress; /// purpose, as shown in the following ERC20 example: /// /// See [the documentation] -/// (https://docs.openzeppelin.com/contracts-cairo/0.18.0/governance.html#usage_2) +/// (https://docs.openzeppelin.com/contracts-cairo/0.19.0/governance.html#usage_2) /// for examples and more details. #[starknet::component] pub mod VotesComponent { diff --git a/packages/introspection/README.md b/packages/introspection/README.md index 9335cbe09..d482d832f 100644 --- a/packages/introspection/README.md +++ b/packages/introspection/README.md @@ -1,13 +1,13 @@ ## Introspection -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/introspection](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/introspection) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/introspection](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/introspection) This crate handles [type introspection](https://en.wikipedia.org/wiki/Type_introspection) of contracts. In other words, it examines which functions can be called on a given contract. This is referred to as the contract's interface. ### Interfaces -- [`ISRC5`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/introspection#ISRC5) +- [`ISRC5`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/introspection#ISRC5) ### Components -- [`SRC5Component`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/introspection#SRC5Component) +- [`SRC5Component`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/introspection#SRC5Component) diff --git a/packages/introspection/src/interface.cairo b/packages/introspection/src/interface.cairo index 64fc71bfa..31eca0056 100644 --- a/packages/introspection/src/interface.cairo +++ b/packages/introspection/src/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (introspection/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (introspection/interface.cairo) pub const ISRC5_ID: felt252 = 0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055; diff --git a/packages/introspection/src/src5.cairo b/packages/introspection/src/src5.cairo index eef2435f3..723e6a113 100644 --- a/packages/introspection/src/src5.cairo +++ b/packages/introspection/src/src5.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (introspection/src5.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (introspection/src5.cairo) /// # SRC5 Component /// diff --git a/packages/merkle_tree/README.md b/packages/merkle_tree/README.md index df6be5eec..04c16d333 100644 --- a/packages/merkle_tree/README.md +++ b/packages/merkle_tree/README.md @@ -1,6 +1,6 @@ ## Merkle Tree -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/merkle-tree](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/merkle-tree) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/merkle-tree](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/merkle-tree) This crate provides a set of utilities for verifying Merkle Tree proofs on-chain. The tree and the proofs can be generated using this [JavaScript library](https://github.com/ericnordelo/strk-merkle-tree) both for Pedersen and Poseidon diff --git a/packages/merkle_tree/src/hashes.cairo b/packages/merkle_tree/src/hashes.cairo index 91ce6a73b..78e01d5e3 100644 --- a/packages/merkle_tree/src/hashes.cairo +++ b/packages/merkle_tree/src/hashes.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (merkle_tree/hashes.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (merkle_tree/hashes.cairo) use core::hash::HashStateTrait; use core::pedersen::PedersenTrait; diff --git a/packages/merkle_tree/src/merkle_proof.cairo b/packages/merkle_tree/src/merkle_proof.cairo index 4bec0a807..8fe78e172 100644 --- a/packages/merkle_tree/src/merkle_proof.cairo +++ b/packages/merkle_tree/src/merkle_proof.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (merkle_tree/merkle_proof.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (merkle_tree/merkle_proof.cairo) /// These functions deal with verification of Merkle Tree proofs. /// diff --git a/packages/presets/README.md b/packages/presets/README.md index 92d95be05..f016a6285 100644 --- a/packages/presets/README.md +++ b/packages/presets/README.md @@ -1,6 +1,6 @@ ## Presets -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/presets](https://docs.openzeppelin.com/contracts-cairo/0.18.0/presets) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/presets](https://docs.openzeppelin.com/contracts-cairo/0.19.0/presets) Presets are ready-to-deploy contracts provided by the library. Since presets are intended to be very simple and as generic as possible, there’s no support for custom or complex contracts such as `ERC20Pausable` or `ERC721Mintable`. @@ -10,9 +10,9 @@ For contract customization and combination of modules you can use ### Presets -- [`AccountUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/account#AccountUpgradeable) -- [`ERC20Upgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc20#ERC20Upgradeable) -- [`ERC721Upgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc721#ERC721Upgradeable) -- [`ERC1155Upgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc1155#ERC1155Upgradeable) -- [`EthAccountUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/account#EthAccountUpgradeable) -- [`UniversalDeployer`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/udc#UniversalDeployer) +- [`AccountUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/account#AccountUpgradeable) +- [`ERC20Upgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc20#ERC20Upgradeable) +- [`ERC721Upgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc721#ERC721Upgradeable) +- [`ERC1155Upgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc1155#ERC1155Upgradeable) +- [`EthAccountUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/account#EthAccountUpgradeable) +- [`UniversalDeployer`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/udc#UniversalDeployer) diff --git a/packages/presets/src/account.cairo b/packages/presets/src/account.cairo index 135573428..5aa75f29d 100644 --- a/packages/presets/src/account.cairo +++ b/packages/presets/src/account.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (presets/account.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (presets/account.cairo) /// # Account Preset /// diff --git a/packages/presets/src/erc1155.cairo b/packages/presets/src/erc1155.cairo index 42fc90c2f..0118e68d8 100644 --- a/packages/presets/src/erc1155.cairo +++ b/packages/presets/src/erc1155.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (presets/erc1155.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (presets/erc1155.cairo) /// # ERC1155Upgradeable Preset /// diff --git a/packages/presets/src/erc20.cairo b/packages/presets/src/erc20.cairo index c94a2c013..2689d501b 100644 --- a/packages/presets/src/erc20.cairo +++ b/packages/presets/src/erc20.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (presets/erc20.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (presets/erc20.cairo) /// # ERC20 Preset /// diff --git a/packages/presets/src/erc721.cairo b/packages/presets/src/erc721.cairo index c2ea9d1a7..24b8bf4e4 100644 --- a/packages/presets/src/erc721.cairo +++ b/packages/presets/src/erc721.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (presets/erc721.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (presets/erc721.cairo) /// # ERC721 Preset /// diff --git a/packages/presets/src/eth_account.cairo b/packages/presets/src/eth_account.cairo index a1a6bc36c..66954d92e 100644 --- a/packages/presets/src/eth_account.cairo +++ b/packages/presets/src/eth_account.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (presets/eth_account.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (presets/eth_account.cairo) /// # EthAccount Preset /// diff --git a/packages/presets/src/universal_deployer.cairo b/packages/presets/src/universal_deployer.cairo index d2d7e6bb5..fdc5c1f2a 100644 --- a/packages/presets/src/universal_deployer.cairo +++ b/packages/presets/src/universal_deployer.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (presets/universal_deployer.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (presets/universal_deployer.cairo) /// # UniversalDeployerContract Preset /// diff --git a/packages/presets/src/vesting.cairo b/packages/presets/src/vesting.cairo index 20c972782..f1660bda7 100644 --- a/packages/presets/src/vesting.cairo +++ b/packages/presets/src/vesting.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (presets/vesting.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (presets/vesting.cairo) #[starknet::contract] pub mod VestingWallet { diff --git a/packages/security/README.md b/packages/security/README.md index 329b5bc24..10efef972 100644 --- a/packages/security/README.md +++ b/packages/security/README.md @@ -1,11 +1,11 @@ ## Security -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/security](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/security) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/security](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/security) This crate provides components to handle common security-related tasks such as pausing a contract. ### Components -- [`InitializableComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/security#InitializableComponent) -- [`PausableComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/security#PausableComponent) -- [`ReentrancyGuardComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/security#ReentrancyGuardComponent) +- [`InitializableComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/security#InitializableComponent) +- [`PausableComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/security#PausableComponent) +- [`ReentrancyGuardComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/security#ReentrancyGuardComponent) diff --git a/packages/security/src/initializable.cairo b/packages/security/src/initializable.cairo index 52d0aa909..9b09e91d8 100644 --- a/packages/security/src/initializable.cairo +++ b/packages/security/src/initializable.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (security/initializable.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (security/initializable.cairo) /// # Initializable Component /// diff --git a/packages/security/src/interface.cairo b/packages/security/src/interface.cairo index 357708a68..37aabf6b0 100644 --- a/packages/security/src/interface.cairo +++ b/packages/security/src/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (security/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (security/interface.cairo) #[starknet::interface] pub trait IInitializable { diff --git a/packages/security/src/pausable.cairo b/packages/security/src/pausable.cairo index 62c149f54..39ff176a7 100644 --- a/packages/security/src/pausable.cairo +++ b/packages/security/src/pausable.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (security/pausable.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (security/pausable.cairo) /// # Pausable Component /// diff --git a/packages/security/src/reentrancyguard.cairo b/packages/security/src/reentrancyguard.cairo index 79345cc4a..fc3780776 100644 --- a/packages/security/src/reentrancyguard.cairo +++ b/packages/security/src/reentrancyguard.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (security/reentrancyguard.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (security/reentrancyguard.cairo) /// # ReentrancyGuard Component /// diff --git a/packages/testing/README.md b/packages/testing/README.md index eb8089b9f..f4f7a8432 100644 --- a/packages/testing/README.md +++ b/packages/testing/README.md @@ -1,13 +1,13 @@ ## Testing -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/testing](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/testing) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/testing](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/testing) This crate provides various helper functions for declaring, deploying, and testing smart contracts using the `snforge` toolchain from Starknet Foundry. ### Modules -- [`common`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/testing#testing-common) -- [`deployment`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/testing#testing-deployment) -- [`events`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/testing#testing-events) -- [`signing`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/testing#testing-signing) +- [`common`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/testing#testing-common) +- [`deployment`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/testing#testing-deployment) +- [`events`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/testing#testing-events) +- [`signing`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/testing#testing-signing) diff --git a/packages/token/README.md b/packages/token/README.md index d89bcc139..2e58ec54d 100644 --- a/packages/token/README.md +++ b/packages/token/README.md @@ -5,57 +5,57 @@ standards. ### ERC20 -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc20](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc20) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc20](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc20) #### Interfaces -- [`IERC20`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc20#IERC20) -- [`IERC20Metadata`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc20#IERC20Metadata) +- [`IERC20`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc20#IERC20) +- [`IERC20Metadata`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc20#IERC20Metadata) #### Components -- [`ERC20Component`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc20#ERC20Component) +- [`ERC20Component`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc20#ERC20Component) ### ERC721 -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc721](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc721) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc721](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc721) #### Interfaces -- [`IERC721`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc721#IERC721) -- [`IERC721Metadata`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc721#IERC721Metadata) -- [`IERC721Receiver`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc721#IERC721Receiver) -- [`IERC721Enumerable`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc721#IERC721Enumerable) +- [`IERC721`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc721#IERC721) +- [`IERC721Metadata`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc721#IERC721Metadata) +- [`IERC721Receiver`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc721#IERC721Receiver) +- [`IERC721Enumerable`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc721#IERC721Enumerable) #### Components -- [`ERC721Component`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc721#ERC721Component) -- [`ERC721ReceiverComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc721#ERC721ReceiverComponent) -- [`ERC721EnumerableComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc721#ERC721EnumerableComponent) +- [`ERC721Component`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc721#ERC721Component) +- [`ERC721ReceiverComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc721#ERC721ReceiverComponent) +- [`ERC721EnumerableComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc721#ERC721EnumerableComponent) ### ERC1155 -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc1155](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc1155) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc1155](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc1155) #### Interfaces -- [`IERC1155`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc1155#IERC1155) -- [`IERC1155MetadataURI`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc1155#IERC1155MetadataURI) -- [`IERC1155Receiver`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc1155#IERC1155Receiver) +- [`IERC1155`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc1155#IERC1155) +- [`IERC1155MetadataURI`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc1155#IERC1155MetadataURI) +- [`IERC1155Receiver`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc1155#IERC1155Receiver) #### Components -- [`ERC1155Component`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc1155#ERC1155Component) -- [`ERC1155ReceiverComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/erc1155#ERC1155ReceiverComponent) +- [`ERC1155Component`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc1155#ERC1155Component) +- [`ERC1155ReceiverComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/erc1155#ERC1155ReceiverComponent) ### Common -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/token_common](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/token_common) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/token_common](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/token_common) #### Interfaces -- [`IERC2981`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/token_common#IERC2981) +- [`IERC2981`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/token_common#IERC2981) #### Components -- [`ERC2981Component`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/token_common#ERC2981Component) +- [`ERC2981Component`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/token_common#ERC2981Component) diff --git a/packages/token/src/common/erc2981/erc2981.cairo b/packages/token/src/common/erc2981/erc2981.cairo index 729b2356e..f44ed1270 100644 --- a/packages/token/src/common/erc2981/erc2981.cairo +++ b/packages/token/src/common/erc2981/erc2981.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/common/erc2981/erc2981.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/common/erc2981/erc2981.cairo) /// # ERC2981 Component /// diff --git a/packages/token/src/common/erc2981/interface.cairo b/packages/token/src/common/erc2981/interface.cairo index efc6754b0..41a373c1f 100644 --- a/packages/token/src/common/erc2981/interface.cairo +++ b/packages/token/src/common/erc2981/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/common/erc2981/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/common/erc2981/interface.cairo) use starknet::ContractAddress; diff --git a/packages/token/src/erc1155/erc1155.cairo b/packages/token/src/erc1155/erc1155.cairo index f394d043d..4377eaaac 100644 --- a/packages/token/src/erc1155/erc1155.cairo +++ b/packages/token/src/erc1155/erc1155.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/erc1155/erc1155.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/erc1155/erc1155.cairo) /// # ERC1155 Component /// diff --git a/packages/token/src/erc1155/erc1155_receiver.cairo b/packages/token/src/erc1155/erc1155_receiver.cairo index 28463a57b..2458dd2e0 100644 --- a/packages/token/src/erc1155/erc1155_receiver.cairo +++ b/packages/token/src/erc1155/erc1155_receiver.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/erc1155/erc1155_receiver.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/erc1155/erc1155_receiver.cairo) /// # ERC1155Receiver Component /// diff --git a/packages/token/src/erc1155/interface.cairo b/packages/token/src/erc1155/interface.cairo index d4288c63f..de40ef314 100644 --- a/packages/token/src/erc1155/interface.cairo +++ b/packages/token/src/erc1155/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/erc1155/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/erc1155/interface.cairo) use starknet::ContractAddress; diff --git a/packages/token/src/erc20/erc20.cairo b/packages/token/src/erc20/erc20.cairo index 846870225..6b915e73a 100644 --- a/packages/token/src/erc20/erc20.cairo +++ b/packages/token/src/erc20/erc20.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/erc20/erc20.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/erc20/erc20.cairo) /// # ERC20 Component /// @@ -8,7 +8,7 @@ /// component is agnostic regarding how tokens are created, which means that developers /// must create their own token distribution mechanism. /// See [the documentation] -/// (https://docs.openzeppelin.com/contracts-cairo/0.18.0/guides/erc20-supply) +/// (https://docs.openzeppelin.com/contracts-cairo/0.19.0/guides/erc20-supply) /// for examples. #[starknet::component] pub mod ERC20Component { diff --git a/packages/token/src/erc20/interface.cairo b/packages/token/src/erc20/interface.cairo index a3a2eccee..c000adb70 100644 --- a/packages/token/src/erc20/interface.cairo +++ b/packages/token/src/erc20/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/erc20/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/erc20/interface.cairo) use starknet::ContractAddress; diff --git a/packages/token/src/erc20/snip12_utils/permit.cairo b/packages/token/src/erc20/snip12_utils/permit.cairo index 43b7d2f78..6e3946d26 100644 --- a/packages/token/src/erc20/snip12_utils/permit.cairo +++ b/packages/token/src/erc20/snip12_utils/permit.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/erc20/snip12_utils/permit.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/erc20/snip12_utils/permit.cairo) use core::hash::{HashStateTrait, HashStateExTrait}; use core::poseidon::PoseidonTrait; diff --git a/packages/token/src/erc721/erc721.cairo b/packages/token/src/erc721/erc721.cairo index 972dd7c85..32b89f394 100644 --- a/packages/token/src/erc721/erc721.cairo +++ b/packages/token/src/erc721/erc721.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/erc721/erc721.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/erc721/erc721.cairo) /// # ERC721 Component /// diff --git a/packages/token/src/erc721/erc721_receiver.cairo b/packages/token/src/erc721/erc721_receiver.cairo index bbfdb3457..81284a032 100644 --- a/packages/token/src/erc721/erc721_receiver.cairo +++ b/packages/token/src/erc721/erc721_receiver.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/erc721/erc721_receiver.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/erc721/erc721_receiver.cairo) /// # ERC721Receiver Component /// diff --git a/packages/token/src/erc721/extensions/erc721_enumerable/erc721_enumerable.cairo b/packages/token/src/erc721/extensions/erc721_enumerable/erc721_enumerable.cairo index 580ddb63c..0de7966ef 100644 --- a/packages/token/src/erc721/extensions/erc721_enumerable/erc721_enumerable.cairo +++ b/packages/token/src/erc721/extensions/erc721_enumerable/erc721_enumerable.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 +// OpenZeppelin Contracts for Cairo v0.19.0 // (token/erc721/extensions/erc721_enumerable/erc721_enumerable.cairo) /// # ERC721Enumerable Component diff --git a/packages/token/src/erc721/extensions/erc721_enumerable/interface.cairo b/packages/token/src/erc721/extensions/erc721_enumerable/interface.cairo index ab8ca0c96..f53b1b72e 100644 --- a/packages/token/src/erc721/extensions/erc721_enumerable/interface.cairo +++ b/packages/token/src/erc721/extensions/erc721_enumerable/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 +// OpenZeppelin Contracts for Cairo v0.19.0 // (token/erc721/extensions/erc721_enumerable/interface.cairo) use starknet::ContractAddress; diff --git a/packages/token/src/erc721/interface.cairo b/packages/token/src/erc721/interface.cairo index a1bb03d12..2215450e8 100644 --- a/packages/token/src/erc721/interface.cairo +++ b/packages/token/src/erc721/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (token/erc721/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (token/erc721/interface.cairo) use starknet::ContractAddress; diff --git a/packages/upgrades/README.md b/packages/upgrades/README.md index 030d46762..4fff5491b 100644 --- a/packages/upgrades/README.md +++ b/packages/upgrades/README.md @@ -1,14 +1,14 @@ ## Upgrades -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/upgrades](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/upgrades) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/upgrades](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/upgrades) This crate provides an interface and component used for upgradeability. ### Interfaces -- [`IUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/upgrades#IUpgradeable) -- [`IUpgradeAndCall`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/upgrades#IUpgradeAndCall) +- [`IUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/upgrades#IUpgradeable) +- [`IUpgradeAndCall`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/upgrades#IUpgradeAndCall) ### Components -- [`UpgradeableComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/upgrades#UpgradeableComponent) +- [`UpgradeableComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/upgrades#UpgradeableComponent) diff --git a/packages/upgrades/src/interface.cairo b/packages/upgrades/src/interface.cairo index 852d9cd0e..77c93a037 100644 --- a/packages/upgrades/src/interface.cairo +++ b/packages/upgrades/src/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (upgrades/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (upgrades/interface.cairo) use starknet::ClassHash; diff --git a/packages/upgrades/src/upgradeable.cairo b/packages/upgrades/src/upgradeable.cairo index 2c752d2ed..9d544349e 100644 --- a/packages/upgrades/src/upgradeable.cairo +++ b/packages/upgrades/src/upgradeable.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (upgrades/upgradeable.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (upgrades/upgradeable.cairo) /// # Upgradeable Component /// diff --git a/packages/utils/README.md b/packages/utils/README.md index a88bfe0db..5fd600648 100644 --- a/packages/utils/README.md +++ b/packages/utils/README.md @@ -1,18 +1,18 @@ ## Utils -> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/utilities](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/utilities) +> **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/utilities](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/utilities) This crate provides components and libraries containing miscellaneous utilities. ### Core utilities -- [`utils`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/utilities#utils) -- [`cryptography`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/utilities#cryptography) -- [`deployments`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/utilities#deployments) -- [`math`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/utilities#math) -- [`serde`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/utilities#serde) +- [`utils`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/utilities#utils) +- [`cryptography`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/utilities#cryptography) +- [`deployments`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/utilities#deployments) +- [`math`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/utilities#math) +- [`serde`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/utilities#serde) ### Cryptography -- [`NoncesComponent`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/utilities#NoncesComponent) -- [`snip12`](https://docs.openzeppelin.com/contracts-cairo/0.18.0/api/utilities#snip12) +- [`NoncesComponent`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/utilities#NoncesComponent) +- [`snip12`](https://docs.openzeppelin.com/contracts-cairo/0.19.0/api/utilities#snip12) diff --git a/packages/utils/src/cryptography/interface.cairo b/packages/utils/src/cryptography/interface.cairo index 8bd22fd98..1d3c9d215 100644 --- a/packages/utils/src/cryptography/interface.cairo +++ b/packages/utils/src/cryptography/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (utils/cryptography/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (utils/cryptography/interface.cairo) use starknet::ContractAddress; diff --git a/packages/utils/src/cryptography/nonces.cairo b/packages/utils/src/cryptography/nonces.cairo index 4ddf69aaa..981d96650 100644 --- a/packages/utils/src/cryptography/nonces.cairo +++ b/packages/utils/src/cryptography/nonces.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (utils/cryptography/nonces.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (utils/cryptography/nonces.cairo) /// # Nonces Component /// diff --git a/packages/utils/src/cryptography/snip12.cairo b/packages/utils/src/cryptography/snip12.cairo index e7d76d4f4..33a267250 100644 --- a/packages/utils/src/cryptography/snip12.cairo +++ b/packages/utils/src/cryptography/snip12.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (utils/cryptography/snip12.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (utils/cryptography/snip12.cairo) use core::hash::{HashStateTrait, HashStateExTrait}; use core::poseidon::PoseidonTrait; diff --git a/packages/utils/src/deployments.cairo b/packages/utils/src/deployments.cairo index cc183c861..d0efe1c82 100644 --- a/packages/utils/src/deployments.cairo +++ b/packages/utils/src/deployments.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (utils/deployments.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (utils/deployments.cairo) pub mod interface; diff --git a/packages/utils/src/deployments/interface.cairo b/packages/utils/src/deployments/interface.cairo index a9b235104..601871eb7 100644 --- a/packages/utils/src/deployments/interface.cairo +++ b/packages/utils/src/deployments/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (utils/deployments/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (utils/deployments/interface.cairo) use starknet::{ClassHash, ContractAddress}; diff --git a/packages/utils/src/lib.cairo b/packages/utils/src/lib.cairo index b828bc593..e1d443c29 100644 --- a/packages/utils/src/lib.cairo +++ b/packages/utils/src/lib.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (utils/lib.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (utils/lib.cairo) pub mod cryptography; pub mod deployments; diff --git a/packages/utils/src/math.cairo b/packages/utils/src/math.cairo index d65c93528..5acd7cc18 100644 --- a/packages/utils/src/math.cairo +++ b/packages/utils/src/math.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (utils/math.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (utils/math.cairo) use core::traits::{Into, BitAnd, BitXor}; diff --git a/packages/utils/src/serde.cairo b/packages/utils/src/serde.cairo index fe7c8f93e..289b011ee 100644 --- a/packages/utils/src/serde.cairo +++ b/packages/utils/src/serde.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (utils/serde.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (utils/serde.cairo) pub trait SerializedAppend { fn append_serde(ref self: Array, value: T); diff --git a/packages/utils/src/structs/checkpoint.cairo b/packages/utils/src/structs/checkpoint.cairo index 635da01b6..8e3fe2077 100644 --- a/packages/utils/src/structs/checkpoint.cairo +++ b/packages/utils/src/structs/checkpoint.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.18.0 (utils/structs/checkpoint.cairo) +// OpenZeppelin Contracts for Cairo v0.19.0 (utils/structs/checkpoint.cairo) use core::num::traits::Sqrt; use crate::math; diff --git a/sncast_scripts/Scarb.lock b/sncast_scripts/Scarb.lock index 90cb3ae2c..fc192541d 100644 --- a/sncast_scripts/Scarb.lock +++ b/sncast_scripts/Scarb.lock @@ -3,7 +3,7 @@ version = 1 [[package]] name = "openzeppelin_access" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_introspection", "openzeppelin_utils", @@ -11,7 +11,7 @@ dependencies = [ [[package]] name = "openzeppelin_account" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_introspection", "openzeppelin_utils", @@ -19,7 +19,7 @@ dependencies = [ [[package]] name = "openzeppelin_finance" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_access", "openzeppelin_token", @@ -27,7 +27,7 @@ dependencies = [ [[package]] name = "openzeppelin_governance" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_access", "openzeppelin_introspection", @@ -35,11 +35,11 @@ dependencies = [ [[package]] name = "openzeppelin_introspection" -version = "0.18.0" +version = "0.19.0" [[package]] name = "openzeppelin_presets" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_access", "openzeppelin_account", @@ -51,14 +51,14 @@ dependencies = [ [[package]] name = "openzeppelin_testing" -version = "0.18.0" +version = "0.19.0" dependencies = [ "snforge_std", ] [[package]] name = "openzeppelin_token" -version = "0.18.0" +version = "0.19.0" dependencies = [ "openzeppelin_account", "openzeppelin_governance", @@ -67,11 +67,11 @@ dependencies = [ [[package]] name = "openzeppelin_upgrades" -version = "0.18.0" +version = "0.19.0" [[package]] name = "openzeppelin_utils" -version = "0.18.0" +version = "0.19.0" [[package]] name = "sncast_scripts"