diff --git a/starknet/src/authenticators/eth_tx.cairo b/starknet/src/authenticators/eth_tx.cairo index 53b4a2ea..beb7c552 100644 --- a/starknet/src/authenticators/eth_tx.cairo +++ b/starknet/src/authenticators/eth_tx.cairo @@ -61,7 +61,7 @@ mod EthTxAuthenticator { user_proposal_validation_params: Array, metadata_URI: Array ) { - let mut payload = ArrayTrait::::new(); + let mut payload = array![]; target.serialize(ref payload); PROPOSE_SELECTOR.serialize(ref payload); author.serialize(ref payload); @@ -92,7 +92,7 @@ mod EthTxAuthenticator { user_voting_strategies: Array, metadata_URI: Array ) { - let mut payload = ArrayTrait::::new(); + let mut payload = array![]; target.serialize(ref payload); VOTE_SELECTOR.serialize(ref payload); voter.serialize(ref payload); @@ -124,7 +124,7 @@ mod EthTxAuthenticator { execution_strategy: Strategy, metadata_URI: Array ) { - let mut payload = ArrayTrait::::new(); + let mut payload = array![]; target.serialize(ref payload); UPDATE_PROPOSAL_SELECTOR.serialize(ref payload); author.serialize(ref payload); diff --git a/starknet/src/execution_strategies/eth_relayer.cairo b/starknet/src/execution_strategies/eth_relayer.cairo index 50a4be99..ccf5344a 100644 --- a/starknet/src/execution_strategies/eth_relayer.cairo +++ b/starknet/src/execution_strategies/eth_relayer.cairo @@ -22,7 +22,7 @@ mod EthRelayerExecutionStrategy { // keccak hash of the proposal execution payload let execution_hash = u256 { low: payload[2], high: payload[1] }; - let mut message_payload = ArrayTrait::::new(); + let mut message_payload = array![]; space.serialize(mut message_payload); proposal.serialize(mut message_payload); votes_for.serialize(mut message_payload); diff --git a/starknet/src/factory/factory.cairo b/starknet/src/factory/factory.cairo index a701e053..855327aa 100644 --- a/starknet/src/factory/factory.cairo +++ b/starknet/src/factory/factory.cairo @@ -7,7 +7,7 @@ trait IFactory { self: @TContractState, class_hash: ClassHash, contract_address_salt: felt252, - calldata: Span + initialize_calldata: Span ) -> ContractAddress; } @@ -17,9 +17,11 @@ mod Factory { use super::IFactory; use starknet::ContractAddress; use starknet::contract_address_const; - use starknet::syscalls::deploy_syscall; + use starknet::syscalls::{deploy_syscall, call_contract_syscall}; use starknet::ClassHash; use result::ResultTrait; + use array::{ArrayTrait, SpanTrait}; + use sx::utils::constants::INITIALIZE_SELECTOR; #[event] fn SpaceDeployed(class_hash: ClassHash, space_address: ContractAddress) {} @@ -33,13 +35,17 @@ mod Factory { self: @ContractState, class_hash: ClassHash, contract_address_salt: felt252, - calldata: Span + initialize_calldata: Span ) -> ContractAddress { let (space_address, _) = deploy_syscall( - class_hash, contract_address_salt, calldata, false + class_hash, contract_address_salt, array![].span(), false ) .unwrap(); + // Call initializer. + call_contract_syscall(space_address, INITIALIZE_SELECTOR, initialize_calldata) + .unwrap_syscall(); + SpaceDeployed(class_hash, space_address); space_address diff --git a/starknet/src/space/space.cairo b/starknet/src/space/space.cairo index 10003e6c..0e9ee514 100644 --- a/starknet/src/space/space.cairo +++ b/starknet/src/space/space.cairo @@ -29,6 +29,20 @@ trait ISpace { fn transfer_ownership(ref self: TContractState, new_owner: ContractAddress); fn renounce_ownership(ref self: TContractState); // Actions + fn initialize( + ref self: TContractState, + owner: ContractAddress, + min_voting_duration: u32, + max_voting_duration: u32, + voting_delay: u32, + proposal_validation_strategy: Strategy, + proposal_validation_strategy_metadata_URI: Array, + voting_strategies: Array, + voting_strategy_metadata_URIs: Array>, + authenticators: Array, + metadata_URI: Array, + dao_URI: Array, + ); fn propose( ref self: TContractState, author: UserAddress, @@ -53,14 +67,16 @@ trait ISpace { metadata_URI: Array, ); fn cancel_proposal(ref self: TContractState, proposal_id: u256); - fn upgrade(ref self: TContractState, class_hash: ClassHash); + fn upgrade( + ref self: TContractState, class_hash: ClassHash, initialize_calldata: Array + ); } #[starknet::contract] mod Space { use super::ISpace; - use starknet::{ClassHash, ContractAddress, info, Store}; use starknet::storage_access::{StorePacking, StoreUsingPacking}; + use starknet::{ClassHash, ContractAddress, info, Store, syscalls}; use zeroable::Zeroable; use array::{ArrayTrait, SpanTrait}; use clone::Clone; @@ -78,14 +94,17 @@ mod Space { PackedProposal, IndexedStrategyTrait, IndexedStrategyImpl, UpdateSettingsCalldata, NoUpdateU32, NoUpdateStrategy, NoUpdateArray }; + use sx::utils::reinitializable::Reinitializable; + use sx::utils::ReinitializableImpl; use sx::utils::bits::BitSetter; use sx::utils::legacy_hash::LegacyHashChoice; use sx::external::ownable::Ownable; + use sx::utils::constants::INITIALIZE_SELECTOR; #[storage] struct Storage { - _max_voting_duration: u32, _min_voting_duration: u32, + _max_voting_duration: u32, _next_proposal_id: u256, _voting_delay: u32, _active_voting_strategies: u256, @@ -102,9 +121,9 @@ mod Space { fn SpaceCreated( _space: ContractAddress, _owner: ContractAddress, - _voting_delay: u32, _min_voting_duration: u32, _max_voting_duration: u32, + _voting_delay: u32, _proposal_validation_strategy: @Strategy, _proposal_validation_strategy_metadata_URI: @Array, _voting_strategies: @Array, @@ -180,10 +199,56 @@ mod Space { fn VotingDelayUpdated(_new_voting_delay: u32) {} #[event] - fn Upgraded(class_hash: ClassHash) {} + fn Upgraded(class_hash: ClassHash, initialize_calldata: Array) {} #[external(v0)] impl Space of ISpace { + fn initialize( + ref self: ContractState, + owner: ContractAddress, + min_voting_duration: u32, + max_voting_duration: u32, + voting_delay: u32, + proposal_validation_strategy: Strategy, + proposal_validation_strategy_metadata_URI: Array, + voting_strategies: Array, + voting_strategy_metadata_URIs: Array>, + authenticators: Array, + metadata_URI: Array, + dao_URI: Array, + ) { + SpaceCreated( + info::get_contract_address(), + owner, + min_voting_duration, + max_voting_duration, + voting_delay, + @proposal_validation_strategy, + @proposal_validation_strategy_metadata_URI, + @voting_strategies, + @voting_strategy_metadata_URIs, + @authenticators, + @metadata_URI, + @dao_URI + ); + // Checking that the contract is not already initialized + //TODO: temporary component syntax (see imports too) + let mut state: Reinitializable::ContractState = + Reinitializable::unsafe_new_contract_state(); + ReinitializableImpl::initialize(ref state); + + //TODO: temporary component syntax + let mut state: Ownable::ContractState = Ownable::unsafe_new_contract_state(); + Ownable::initializer(ref state); + Ownable::transfer_ownership(ref state, owner); + _set_min_voting_duration(ref self, min_voting_duration); + _set_max_voting_duration(ref self, max_voting_duration); + _set_voting_delay(ref self, voting_delay); + _set_proposal_validation_strategy(ref self, proposal_validation_strategy); + _add_voting_strategies(ref self, voting_strategies); + _add_authenticators(ref self, authenticators); + self._next_proposal_id.write(1_u256); + } fn propose( ref self: ContractState, author: UserAddress, @@ -231,7 +296,7 @@ mod Space { // TODO: Lots of copying, maybe figure out how to pass snapshots to events/storage writers. self._proposals.write(proposal_id, proposal); - self._next_proposal_id.write(proposal_id + u256 { low: 1_u128, high: 0_u128 }); + self._next_proposal_id.write(proposal_id + 1_u256); ProposalCreated( proposal_id, author, snap_proposal, @execution_strategy.params, @metadata_URI @@ -270,7 +335,7 @@ mod Space { proposal.active_voting_strategies ); - assert(voting_power > u256 { low: 0_u128, high: 0_u128 }, 'User has no voting power'); + assert(voting_power > 0_u256, 'User has no voting power'); self ._vote_power .write( @@ -345,15 +410,26 @@ mod Space { ProposalCancelled(proposal_id); } - fn upgrade(ref self: ContractState, class_hash: ClassHash) { + fn upgrade( + ref self: ContractState, class_hash: ClassHash, initialize_calldata: Array + ) { let state: Ownable::ContractState = Ownable::unsafe_new_contract_state(); Ownable::assert_only_owner(@state); - assert( - class_hash.is_non_zero(), 'Class Hash cannot be zero' - ); // TODO: not sure this is needed + assert(class_hash.is_non_zero(), 'Class Hash cannot be zero'); starknet::replace_class_syscall(class_hash).unwrap_syscall(); - Upgraded(class_hash); + + // Allowing initializer to be called again. + let mut state: Reinitializable::ContractState = + Reinitializable::unsafe_new_contract_state(); + ReinitializableImpl::reinitialize(ref state); + + // Call initializer on the new version. + syscalls::call_contract_syscall( + info::get_contract_address(), INITIALIZE_SELECTOR, initialize_calldata.span() + ) + .unwrap_syscall(); + Upgraded(class_hash, initialize_calldata); } fn owner(self: @ContractState) -> ContractAddress { @@ -486,48 +562,6 @@ mod Space { } } - #[constructor] - fn constructor( - ref self: ContractState, - _owner: ContractAddress, - _max_voting_duration: u32, - _min_voting_duration: u32, - _voting_delay: u32, - _proposal_validation_strategy: Strategy, - _proposal_validation_strategy_metadata_URI: Array, - _voting_strategies: Array, - _voting_strategies_metadata_URIs: Array>, - _authenticators: Array, - _metadata_URI: Array, - _dao_URI: Array - ) { - //TODO: temporary component syntax - let mut state: Ownable::ContractState = Ownable::unsafe_new_contract_state(); - Ownable::initializer(ref state); - Ownable::transfer_ownership(ref state, _owner); - _set_max_voting_duration(ref self, _max_voting_duration); - _set_min_voting_duration(ref self, _min_voting_duration); - _set_voting_delay(ref self, _voting_delay); - _set_proposal_validation_strategy(ref self, _proposal_validation_strategy.clone()); - _add_voting_strategies(ref self, _voting_strategies.clone()); - _add_authenticators(ref self, _authenticators.clone()); - self._next_proposal_id.write(u256 { low: 1_u128, high: 0_u128 }); - SpaceCreated( - info::get_contract_address(), - _owner, - _voting_delay, - _min_voting_duration, - _max_voting_duration, - @_proposal_validation_strategy, - @_proposal_validation_strategy_metadata_URI, - @_voting_strategies, - @_voting_strategies_metadata_URIs, - @_authenticators, - @_metadata_URI, - @_dao_URI - ); - } - /// /// Internals /// @@ -549,7 +583,7 @@ mod Space { allowed_strategies: u256 ) -> u256 { user_strategies.assert_no_duplicate_indices(); - let mut total_voting_power = u256 { low: 0_u128, high: 0_u128 }; + let mut total_voting_power = 0_u256; let mut i = 0_usize; loop { if i >= user_strategies.len() { diff --git a/starknet/src/tests/mocks.cairo b/starknet/src/tests/mocks.cairo index d372cbef..8ceecdbf 100644 --- a/starknet/src/tests/mocks.cairo +++ b/starknet/src/tests/mocks.cairo @@ -1,2 +1,3 @@ mod proposal_validation_always_fail; mod executor; +mod space_v2; diff --git a/starknet/src/tests/mocks/space_v2.cairo b/starknet/src/tests/mocks/space_v2.cairo new file mode 100644 index 00000000..702d1b50 --- /dev/null +++ b/starknet/src/tests/mocks/space_v2.cairo @@ -0,0 +1,30 @@ +#[starknet::interface] +trait ISpaceV2 { + fn initialize(ref self: TContractState, var: felt252); + fn get_var(self: @TContractState) -> felt252; +} + +#[starknet::contract] +mod SpaceV2 { + use super::ISpaceV2; + use sx::utils::reinitializable::Reinitializable; + use sx::utils::ReinitializableImpl; + #[storage] + struct Storage { + _var: felt252 + } + + #[external(v0)] + impl SpaceV2 of ISpaceV2 { + fn initialize(ref self: ContractState, var: felt252) { + // TODO: Temp component syntax + let mut state: Reinitializable::ContractState = + Reinitializable::unsafe_new_contract_state(); + ReinitializableImpl::initialize(ref state); + self._var.write(var); + } + fn get_var(self: @ContractState) -> felt252 { + self._var.read() + } + } +} diff --git a/starknet/src/tests/setup/setup.cairo b/starknet/src/tests/setup/setup.cairo index 4ff1cb0c..38d4e412 100644 --- a/starknet/src/tests/setup/setup.cairo +++ b/starknet/src/tests/setup/setup.cairo @@ -44,10 +44,7 @@ mod setup { // Deploy Vanilla Authenticator let (vanilla_authenticator_address, _) = deploy_syscall( - VanillaAuthenticator::TEST_CLASS_HASH.try_into().unwrap(), - 0, - array::ArrayTrait::::new().span(), - false + VanillaAuthenticator::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false ) .unwrap(); let mut authenticators = ArrayTrait::::new(); @@ -57,7 +54,7 @@ mod setup { let (vanilla_proposal_validation_address, _) = deploy_syscall( VanillaProposalValidationStrategy::TEST_CLASS_HASH.try_into().unwrap(), 0, - array::ArrayTrait::::new().span(), + array![].span(), false ) .unwrap(); @@ -67,27 +64,20 @@ mod setup { // Deploy Vanilla Voting Strategy let (vanilla_voting_strategy_address, _) = deploy_syscall( - VanillaVotingStrategy::TEST_CLASS_HASH.try_into().unwrap(), - 0, - array::ArrayTrait::::new().span(), - false + VanillaVotingStrategy::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false ) .unwrap(); let mut voting_strategies = ArrayTrait::::new(); voting_strategies - .append( - Strategy { - address: vanilla_voting_strategy_address, params: ArrayTrait::::new() - } - ); + .append(Strategy { address: vanilla_voting_strategy_address, params: array![] }); // Deploy Vanilla Execution Strategy - let mut constructor_calldata = ArrayTrait::::new(); - quorum.serialize(ref constructor_calldata); + let mut initializer_calldata = array![]; + quorum.serialize(ref initializer_calldata); let (vanilla_execution_strategy_address, _) = deploy_syscall( VanillaExecutionStrategy::TEST_CLASS_HASH.try_into().unwrap(), 0, - constructor_calldata.span(), + initializer_calldata.span(), false ) .unwrap(); @@ -106,7 +96,7 @@ mod setup { } } - fn get_constructor_calldata( + fn get_initialize_calldata( owner: @ContractAddress, min_voting_duration: @u64, max_voting_duration: @u64, @@ -116,20 +106,20 @@ mod setup { authenticators: @Array ) -> Array { // Using empty arrays for all the metadata fields - let mut constructor_calldata = array::ArrayTrait::::new(); - constructor_calldata.append((*owner).into()); - constructor_calldata.append((*max_voting_duration).into()); - constructor_calldata.append((*min_voting_duration).into()); - constructor_calldata.append((*voting_delay).into()); - proposal_validation_strategy.serialize(ref constructor_calldata); - ArrayTrait::::new().serialize(ref constructor_calldata); - voting_strategies.serialize(ref constructor_calldata); - ArrayTrait::::new().serialize(ref constructor_calldata); - authenticators.serialize(ref constructor_calldata); - ArrayTrait::::new().serialize(ref constructor_calldata); - ArrayTrait::::new().serialize(ref constructor_calldata); - - constructor_calldata + let mut initializer_calldata = array![]; + owner.serialize(ref initializer_calldata); + min_voting_duration.serialize(ref initializer_calldata); + max_voting_duration.serialize(ref initializer_calldata); + voting_delay.serialize(ref initializer_calldata); + proposal_validation_strategy.serialize(ref initializer_calldata); + ArrayTrait::::new().serialize(ref initializer_calldata); + voting_strategies.serialize(ref initializer_calldata); + ArrayTrait::::new().serialize(ref initializer_calldata); + authenticators.serialize(ref initializer_calldata); + ArrayTrait::::new().serialize(ref initializer_calldata); + ArrayTrait::::new().serialize(ref initializer_calldata); + + initializer_calldata } fn deploy(config: @Config) -> (IFactoryDispatcher, ISpaceDispatcher) { @@ -137,16 +127,13 @@ mod setup { let contract_address_salt = 0; let (factory_address, _) = deploy_syscall( - Factory::TEST_CLASS_HASH.try_into().unwrap(), - 0, - ArrayTrait::::new().span(), - false + Factory::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false ) .unwrap(); let factory = IFactoryDispatcher { contract_address: factory_address }; - let constructor_calldata = get_constructor_calldata( + let initializer_calldata = get_initialize_calldata( config.owner, config.min_voting_duration, config.max_voting_duration, @@ -156,7 +143,7 @@ mod setup { config.authenticators ); let space_address = factory - .deploy(space_class_hash, contract_address_salt, constructor_calldata.span()); + .deploy(space_class_hash, contract_address_salt, initializer_calldata.span()); let space = ISpaceDispatcher { contract_address: space_address }; diff --git a/starknet/src/tests/test_factory.cairo b/starknet/src/tests/test_factory.cairo index 35ed60d6..8b798c76 100644 --- a/starknet/src/tests/test_factory.cairo +++ b/starknet/src/tests/test_factory.cairo @@ -10,7 +10,7 @@ mod tests { use sx::types::Strategy; use starknet::ClassHash; - use sx::tests::setup::setup::setup::{setup, get_constructor_calldata, deploy}; + use sx::tests::setup::setup::setup::{setup, get_initialize_calldata, deploy}; #[test] #[available_gas(10000000000)] @@ -26,7 +26,7 @@ mod tests { #[test] #[available_gas(10000000000)] fn test_deploy_reuse_salt() { - let mut constructor_calldata = ArrayTrait::::new(); + let mut constructor_calldata = array![]; let (factory_address, _) = deploy_syscall( Factory::TEST_CLASS_HASH.try_into().unwrap(), 0, constructor_calldata.span(), false @@ -39,7 +39,7 @@ mod tests { let contract_address_salt = 0; let config = setup(); - let constructor_calldata = get_constructor_calldata( + let constructor_calldata = get_initialize_calldata( @config.owner, @config.min_voting_duration, @config.max_voting_duration, diff --git a/starknet/src/tests/test_merkle_whitelist.cairo b/starknet/src/tests/test_merkle_whitelist.cairo index a7124049..559cd639 100644 --- a/starknet/src/tests/test_merkle_whitelist.cairo +++ b/starknet/src/tests/test_merkle_whitelist.cairo @@ -13,7 +13,7 @@ mod merkle_utils { impl SpanIntoArray, impl TDrop: Drop> of Into, Array> { fn into(self: Span) -> Array { let mut self = self; - let mut output = ArrayTrait::::new(); + let mut output = array![]; loop { match self.pop_front() { Option::Some(val) => output.append(val.clone()), @@ -28,7 +28,7 @@ mod merkle_utils { // Generates the proof for the given `index` in the `merkle_data`. fn generate_proof(mut merkle_data: Span, mut index: usize) -> Array { - let mut proof = ArrayTrait::new(); + let mut proof = array![]; loop { if merkle_data.len() == 1 { @@ -82,7 +82,7 @@ mod merkle_utils { } fn get_next_level(mut merkle_data: Span) -> Array { - let mut next_level = ArrayTrait::::new(); + let mut next_level = array![]; loop { match merkle_data.pop_front() { Option::Some(a) => { @@ -114,7 +114,7 @@ mod merkle_utils { // The `merkle_data` corresponds to the hashes leaves of the members. fn generate_merkle_data(members: Span) -> Array { let mut members_ = members; - let mut output = ArrayTrait::::new(); + let mut output = array![]; loop { match members_.pop_front() { Option::Some(leaf) => { @@ -132,7 +132,7 @@ mod merkle_utils { // address 1, 2, 3, ... // Even members will be Ethereum addresses and odd members will be Starknet addresses. fn generate_n_members(n: usize) -> Array { - let mut members = ArrayTrait::::new(); + let mut members = array![]; let mut i = 1_usize; loop { if i >= n + 1 { @@ -251,7 +251,7 @@ mod assert_valid_proof { let leaf = Leaf { address: UserAddress::Starknet(contract_address_const::<0>()), voting_power: 0 }; - let proof = ArrayTrait::new(); + let proof = array![]; assert_valid_proof(root, leaf, proof.span()); } @@ -259,37 +259,19 @@ mod assert_valid_proof { #[available_gas(10000000)] #[should_panic(expected: ('Merkle: Invalid proof', ))] fn invalid_extra_node() { - let mut members = ArrayTrait::new(); - members - .append( - Leaf { - address: UserAddress::Starknet(contract_address_const::<5>()), voting_power: 5 - } - ); - members - .append( - Leaf { - address: UserAddress::Starknet(contract_address_const::<4>()), voting_power: 4 - } - ); - members - .append( - Leaf { - address: UserAddress::Starknet(contract_address_const::<3>()), voting_power: 3 - } - ); - members - .append( - Leaf { - address: UserAddress::Starknet(contract_address_const::<2>()), voting_power: 2 - } - ); - members - .append( - Leaf { - address: UserAddress::Starknet(contract_address_const::<1>()), voting_power: 1 - } - ); + let mut members = array![ + Leaf { + address: UserAddress::Starknet(contract_address_const::<5>()), voting_power: 5 + }, Leaf { + address: UserAddress::Starknet(contract_address_const::<4>()), voting_power: 4 + }, Leaf { + address: UserAddress::Starknet(contract_address_const::<3>()), voting_power: 3 + }, Leaf { + address: UserAddress::Starknet(contract_address_const::<2>()), voting_power: 2 + }, Leaf { + address: UserAddress::Starknet(contract_address_const::<1>()), voting_power: 1 + }, + ]; let merkle_data = generate_merkle_data(members.span()); let root = generate_merkle_root(merkle_data.span()); @@ -304,37 +286,19 @@ mod assert_valid_proof { #[available_gas(10000000)] #[should_panic(expected: ('Merkle: Invalid proof', ))] fn invalid_proof() { - let mut members = ArrayTrait::new(); - members - .append( - Leaf { - address: UserAddress::Starknet(contract_address_const::<5>()), voting_power: 5 - } - ); - members - .append( - Leaf { - address: UserAddress::Starknet(contract_address_const::<4>()), voting_power: 4 - } - ); - members - .append( - Leaf { - address: UserAddress::Starknet(contract_address_const::<3>()), voting_power: 3 - } - ); - members - .append( - Leaf { - address: UserAddress::Starknet(contract_address_const::<2>()), voting_power: 2 - } - ); - members - .append( - Leaf { - address: UserAddress::Starknet(contract_address_const::<1>()), voting_power: 1 - } - ); + let mut members = array![ + Leaf { + address: UserAddress::Starknet(contract_address_const::<5>()), voting_power: 5 + }, Leaf { + address: UserAddress::Starknet(contract_address_const::<4>()), voting_power: 4 + }, Leaf { + address: UserAddress::Starknet(contract_address_const::<3>()), voting_power: 3 + }, Leaf { + address: UserAddress::Starknet(contract_address_const::<2>()), voting_power: 2 + }, Leaf { + address: UserAddress::Starknet(contract_address_const::<1>()), voting_power: 1 + }, + ]; let merkle_data = generate_merkle_data(members.span()); let root = generate_merkle_root(merkle_data.span()); @@ -373,7 +337,7 @@ mod merkle_whitelist_voting_power { let (contract, _) = deploy_syscall( MerkleWhitelistVotingStrategy::TEST_CLASS_HASH.try_into().unwrap(), 0, - array::ArrayTrait::::new().span(), + array![].span(), false, ) .unwrap(); @@ -387,10 +351,10 @@ mod merkle_whitelist_voting_power { let root = generate_merkle_root(merkle_data.span()); let proof = generate_proof(merkle_data.span(), index); - let mut params = ArrayTrait::::new(); + let mut params = array![]; root.serialize(ref params); - let mut user_params = ArrayTrait::::new(); + let mut user_params = array![]; leaf.serialize(ref user_params); proof.serialize(ref user_params); @@ -406,7 +370,7 @@ mod merkle_whitelist_voting_power { let (contract, _) = deploy_syscall( MerkleWhitelistVotingStrategy::TEST_CLASS_HASH.try_into().unwrap(), 0, - array::ArrayTrait::::new().span(), + array![].span(), false, ) .unwrap(); @@ -420,10 +384,10 @@ mod merkle_whitelist_voting_power { let root = generate_merkle_root(merkle_data.span()); let proof = generate_proof(merkle_data.span(), index); - let mut params = ArrayTrait::::new(); + let mut params = array![]; root.serialize(ref params); - let mut user_params = ArrayTrait::::new(); + let mut user_params = array![]; let fake_leaf = Leaf { address: leaf.address, voting_power: leaf.voting_power + 1, }; // lying about voting power here @@ -442,7 +406,7 @@ mod merkle_whitelist_voting_power { let (contract, _) = deploy_syscall( MerkleWhitelistVotingStrategy::TEST_CLASS_HASH.try_into().unwrap(), 0, - array::ArrayTrait::::new().span(), + array![].span(), false, ) .unwrap(); @@ -456,10 +420,10 @@ mod merkle_whitelist_voting_power { let root = generate_merkle_root(merkle_data.span()); let proof = generate_proof(merkle_data.span(), index); - let mut params = ArrayTrait::::new(); + let mut params = array![]; root.serialize(ref params); - let mut user_params = ArrayTrait::::new(); + let mut user_params = array![]; let fake_leaf = Leaf { address: UserAddress::Starknet(contract_address_const::<0x1337>()), voting_power: leaf.voting_power, diff --git a/starknet/src/tests/test_space.cairo b/starknet/src/tests/test_space.cairo index b073f777..1c36f42a 100644 --- a/starknet/src/tests/test_space.cairo +++ b/starknet/src/tests/test_space.cairo @@ -29,18 +29,92 @@ mod tests { use Space::Space as SpaceImpl; - #[test] #[available_gas(100000000)] - fn test_constructor() { + fn test_initialize() { let deployer = contract_address_const::<0xdead>(); testing::set_caller_address(deployer); testing::set_contract_address(deployer); // Space Settings let owner = contract_address_const::<0x123456789>(); + let min_voting_duration = 1_u32; let max_voting_duration = 2_u32; + let voting_delay = 1_u32; + + // Deploy Vanilla Authenticator + let (vanilla_authenticator_address, _) = deploy_syscall( + VanillaAuthenticator::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + ) + .unwrap(); + let mut authenticators = array![vanilla_authenticator_address]; + + // Deploy Vanilla Proposal Validation Strategy + let (vanilla_proposal_validation_address, _) = deploy_syscall( + VanillaProposalValidationStrategy::TEST_CLASS_HASH.try_into().unwrap(), + 0, + array![].span(), + false + ) + .unwrap(); + let vanilla_proposal_validation_strategy = StrategyImpl::from_address( + vanilla_proposal_validation_address + ); + + // Deploy Vanilla Voting Strategy + let (vanilla_voting_strategy_address, _) = deploy_syscall( + VanillaVotingStrategy::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + ) + .unwrap(); + let mut voting_strategies = array![ + Strategy { address: vanilla_voting_strategy_address, params: array![] } + ]; + + // Deploy Space + let (space_address, _) = deploy_syscall( + Space::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + ) + .unwrap(); + + let space = ISpaceDispatcher { contract_address: space_address }; + + space + .initialize( + owner, + min_voting_duration, + max_voting_duration, + voting_delay, + vanilla_proposal_validation_strategy.clone(), + array![], + voting_strategies, + array![], + authenticators, + array![], + array![] + ); + + assert(space.owner() == owner, 'owner incorrect'); + assert(space.min_voting_duration() == min_voting_duration, 'min incorrect'); + assert(space.max_voting_duration() == max_voting_duration, 'max incorrect'); + assert(space.voting_delay() == voting_delay, 'voting delay incorrect'); + assert( + space.proposal_validation_strategy() == vanilla_proposal_validation_strategy, + 'proposal validation incorrect' + ); + } + + #[test] + #[available_gas(100000000)] + #[should_panic(expected: ('Already Initialized', 'ENTRYPOINT_FAILED'))] + fn test_reinitialize() { + let deployer = contract_address_const::<0xdead>(); + + testing::set_caller_address(deployer); + testing::set_contract_address(deployer); + // Space Settings + let owner = contract_address_const::<0x123456789>(); let min_voting_duration = 1_u32; + let max_voting_duration = 2_u32; let voting_delay = 1_u32; // Deploy Vanilla Authenticator @@ -83,34 +157,43 @@ mod tests { ); // Deploy Space - let mut constructor_calldata = array::ArrayTrait::::new(); - constructor_calldata.append(owner.into()); - constructor_calldata.append(max_voting_duration.into()); - constructor_calldata.append(min_voting_duration.into()); - constructor_calldata.append(voting_delay.into()); - vanilla_proposal_validation_strategy.serialize(ref constructor_calldata); - ArrayTrait::::new().serialize(ref constructor_calldata); - voting_strategies.serialize(ref constructor_calldata); - ArrayTrait::::new().serialize(ref constructor_calldata); - authenticators.serialize(ref constructor_calldata); - ArrayTrait::::new().serialize(ref constructor_calldata); - ArrayTrait::::new().serialize(ref constructor_calldata); - let (space_address, _) = deploy_syscall( - Space::TEST_CLASS_HASH.try_into().unwrap(), 0, constructor_calldata.span(), false + Space::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false ) .unwrap(); let space = ISpaceDispatcher { contract_address: space_address }; - assert(space.owner() == owner, 'owner incorrect'); - assert(space.max_voting_duration() == max_voting_duration, 'max incorrect'); - assert(space.min_voting_duration() == min_voting_duration, 'min incorrect'); - assert(space.voting_delay() == voting_delay, 'voting delay incorrect'); - assert( - space.proposal_validation_strategy() == vanilla_proposal_validation_strategy, - 'proposal validation incorrect' - ); + space + .initialize( + owner, + min_voting_duration, + max_voting_duration, + voting_delay, + vanilla_proposal_validation_strategy.clone(), + array![], + voting_strategies.clone(), + array![], + authenticators.clone(), + array![], + array![] + ); + + // Atempting to call the initialize function again + space + .initialize( + owner, + min_voting_duration, + max_voting_duration, + voting_delay, + vanilla_proposal_validation_strategy, + array![], + voting_strategies, + array![], + authenticators, + array![], + array![] + ); } #[test] @@ -124,7 +207,7 @@ mod tests { }; let quorum = u256_from_felt252(1); - let mut constructor_calldata = ArrayTrait::::new(); + let mut constructor_calldata = array![]; quorum.serialize(ref constructor_calldata); let (vanilla_execution_strategy_address, _) = deploy_syscall( @@ -138,7 +221,7 @@ mod tests { vanilla_execution_strategy_address ); let author = UserAddress::Starknet(contract_address_const::<0x5678>()); - let mut propose_calldata = array::ArrayTrait::::new(); + let mut propose_calldata = array![]; author.serialize(ref propose_calldata); vanilla_execution_strategy.serialize(ref propose_calldata); ArrayTrait::::new().serialize(ref propose_calldata); @@ -147,10 +230,7 @@ mod tests { // Create Proposal authenticator.authenticate(space.contract_address, PROPOSE_SELECTOR, propose_calldata); - assert( - space.next_proposal_id() == u256 { low: 2_u128, high: 0_u128 }, - 'next_proposal_id should be 2' - ); + assert(space.next_proposal_id() == 2_u256, 'next_proposal_id should be 2'); let proposal = space.proposals(u256_from_felt252(1)); let timestamp = info::get_block_timestamp().try_into().unwrap(); @@ -169,13 +249,12 @@ mod tests { assert(proposal == expected_proposal, 'proposal state'); // Update Proposal - let mut update_calldata = array::ArrayTrait::::new(); + let mut update_calldata = array![]; author.serialize(ref update_calldata); let proposal_id = u256_from_felt252(1); proposal_id.serialize(ref update_calldata); // Keeping the same execution strategy contract but changing the payload - let mut new_payload = ArrayTrait::::new(); - new_payload.append(1); + let mut new_payload = array![1]; let execution_strategy = Strategy { address: vanilla_execution_strategy.address, params: new_payload }; @@ -188,16 +267,14 @@ mod tests { // Increasing block timestamp by 1 to pass voting delay testing::set_block_timestamp(1_u64); - let mut vote_calldata = array::ArrayTrait::::new(); + let mut vote_calldata = array![]; let voter = UserAddress::Starknet(contract_address_const::<0x8765>()); voter.serialize(ref vote_calldata); let proposal_id = u256_from_felt252(1); proposal_id.serialize(ref vote_calldata); let choice = Choice::For(()); choice.serialize(ref vote_calldata); - let mut user_voting_strategies = ArrayTrait::::new(); - user_voting_strategies - .append(IndexedStrategy { index: 0_u8, params: ArrayTrait::::new() }); + let mut user_voting_strategies = array![IndexedStrategy { index: 0_u8, params: array![] }]; user_voting_strategies.serialize(ref vote_calldata); ArrayTrait::::new().serialize(ref vote_calldata); @@ -221,7 +298,7 @@ mod tests { }; let quorum = u256_from_felt252(1); - let mut constructor_calldata = ArrayTrait::::new(); + let mut constructor_calldata = array![]; quorum.serialize(ref constructor_calldata); let (vanilla_execution_strategy_address, _) = deploy_syscall( @@ -235,16 +312,13 @@ mod tests { vanilla_execution_strategy_address ); - assert( - space.next_proposal_id() == u256 { low: 1_u128, high: 0_u128 }, - 'next_proposal_id should be 1' - ); + assert(space.next_proposal_id() == 1_u256, 'next_proposal_id should be 1'); // Replace proposal validation strategy with one that always fails let (strategy_address, _) = deploy_syscall( AlwaysFailProposalValidationStrategy::TEST_CLASS_HASH.try_into().unwrap(), 0, - array::ArrayTrait::::new().span(), + array![].span(), false ) .unwrap(); @@ -257,7 +331,7 @@ mod tests { space.update_settings(input); let author = UserAddress::Starknet(contract_address_const::<0x5678>()); - let mut propose_calldata = array::ArrayTrait::::new(); + let mut propose_calldata = array![]; author.serialize(ref propose_calldata); vanilla_execution_strategy.serialize(ref propose_calldata); ArrayTrait::::new().serialize(ref propose_calldata); @@ -282,7 +356,7 @@ mod tests { }; let quorum = u256_from_felt252(1); - let mut constructor_calldata = ArrayTrait::::new(); + let mut constructor_calldata = array![]; quorum.serialize(ref constructor_calldata); let (vanilla_execution_strategy_address, _) = deploy_syscall( @@ -295,7 +369,7 @@ mod tests { let vanilla_execution_strategy = StrategyImpl::from_address( vanilla_execution_strategy_address ); - let mut propose_calldata = array::ArrayTrait::::new(); + let mut propose_calldata = array![]; let author = UserAddress::Starknet(contract_address_const::<0x5678>()); author.serialize(ref propose_calldata); vanilla_execution_strategy.serialize(ref propose_calldata); @@ -320,15 +394,13 @@ mod tests { assert(proposal.finalization_status == FinalizationStatus::Cancelled(()), 'cancelled'); // Try to cast vote on Cancelled Proposal - let mut vote_calldata = array::ArrayTrait::::new(); + let mut vote_calldata = array![]; let voter = UserAddress::Starknet(contract_address_const::<0x8765>()); voter.serialize(ref vote_calldata); proposal_id.serialize(ref vote_calldata); let choice = Choice::For(()); choice.serialize(ref vote_calldata); - let mut user_voting_strategies = ArrayTrait::::new(); - user_voting_strategies - .append(IndexedStrategy { index: 0_u8, params: ArrayTrait::::new() }); + let mut user_voting_strategies = array![IndexedStrategy { index: 0_u8, params: array![] }]; user_voting_strategies.serialize(ref vote_calldata); ArrayTrait::::new().serialize(ref vote_calldata); authenticator.authenticate(space.contract_address, VOTE_SELECTOR, vote_calldata); diff --git a/starknet/src/tests/test_stark_tx_auth.cairo b/starknet/src/tests/test_stark_tx_auth.cairo index cd2051a6..96e0800e 100644 --- a/starknet/src/tests/test_stark_tx_auth.cairo +++ b/starknet/src/tests/test_stark_tx_auth.cairo @@ -53,7 +53,7 @@ mod tests { let authenticator = setup_stark_tx_auth(space, config.owner); let quorum = u256_from_felt252(1); - let mut constructor_calldata = ArrayTrait::::new(); + let mut constructor_calldata = array![]; quorum.serialize(ref constructor_calldata); let (vanilla_execution_strategy_address, _) = deploy_syscall( @@ -72,24 +72,16 @@ mod tests { testing::set_contract_address(author); authenticator .authenticate_propose( - space.contract_address, - author, - vanilla_execution_strategy, - ArrayTrait::::new(), - ArrayTrait::::new() + space.contract_address, author, vanilla_execution_strategy, array![], array![] ); - assert( - space.next_proposal_id() == u256 { low: 2_u128, high: 0_u128 }, - 'next_proposal_id should be 2' - ); + assert(space.next_proposal_id() == 2_u256, 'next_proposal_id should be 2'); // Update Proposal let proposal_id = u256_from_felt252(1); // Keeping the same execution strategy contract but changing the payload - let mut new_payload = ArrayTrait::::new(); - new_payload.append(1); + let mut new_payload = array![1]; let new_execution_strategy = Strategy { address: vanilla_execution_strategy_address, params: new_payload.clone() }; @@ -97,11 +89,7 @@ mod tests { testing::set_contract_address(author); authenticator .authenticate_update_proposal( - space.contract_address, - author, - proposal_id, - new_execution_strategy, - ArrayTrait::::new() + space.contract_address, author, proposal_id, new_execution_strategy, array![] ); // Increasing block timestamp by 1 to pass voting delay @@ -109,20 +97,13 @@ mod tests { let voter = contract_address_const::<0x8765>(); let choice = Choice::For(()); - let mut user_voting_strategies = ArrayTrait::::new(); - user_voting_strategies - .append(IndexedStrategy { index: 0_u8, params: ArrayTrait::::new() }); + let mut user_voting_strategies = array![IndexedStrategy { index: 0_u8, params: array![] }]; // Vote on Proposal testing::set_contract_address(voter); authenticator .authenticate_vote( - space.contract_address, - voter, - proposal_id, - choice, - user_voting_strategies, - ArrayTrait::::new() + space.contract_address, voter, proposal_id, choice, user_voting_strategies, array![] ); testing::set_block_timestamp(2_u64); @@ -140,7 +121,7 @@ mod tests { let authenticator = setup_stark_tx_auth(space, config.owner); let quorum = u256_from_felt252(1); - let mut constructor_calldata = ArrayTrait::::new(); + let mut constructor_calldata = array![]; quorum.serialize(ref constructor_calldata); let (vanilla_execution_strategy_address, _) = deploy_syscall( @@ -159,11 +140,7 @@ mod tests { testing::set_contract_address(config.owner); authenticator .authenticate_propose( - space.contract_address, - author, - vanilla_execution_strategy, - ArrayTrait::::new(), - ArrayTrait::::new() + space.contract_address, author, vanilla_execution_strategy, array![], array![] ); } @@ -176,7 +153,7 @@ mod tests { let authenticator = setup_stark_tx_auth(space, config.owner); let quorum = u256_from_felt252(1); - let mut constructor_calldata = ArrayTrait::::new(); + let mut constructor_calldata = array![]; quorum.serialize(ref constructor_calldata); let (vanilla_execution_strategy_address, _) = deploy_syscall( @@ -195,24 +172,16 @@ mod tests { testing::set_contract_address(author); authenticator .authenticate_propose( - space.contract_address, - author, - vanilla_execution_strategy, - ArrayTrait::::new(), - ArrayTrait::::new() + space.contract_address, author, vanilla_execution_strategy, array![], array![] ); - assert( - space.next_proposal_id() == u256 { low: 2_u128, high: 0_u128 }, - 'next_proposal_id should be 2' - ); + assert(space.next_proposal_id() == 2_u256, 'next_proposal_id should be 2'); // Update Proposal let proposal_id = u256_from_felt252(1); // Keeping the same execution strategy contract but changing the payload - let mut new_payload = ArrayTrait::::new(); - new_payload.append(1); + let mut new_payload = array![1]; let new_execution_strategy = Strategy { address: vanilla_execution_strategy_address, params: new_payload.clone() }; @@ -221,11 +190,7 @@ mod tests { testing::set_contract_address(config.owner); authenticator .authenticate_update_proposal( - space.contract_address, - author, - proposal_id, - new_execution_strategy, - ArrayTrait::::new() + space.contract_address, author, proposal_id, new_execution_strategy, array![] ); } @@ -238,7 +203,7 @@ mod tests { let authenticator = setup_stark_tx_auth(space, config.owner); let quorum = u256_from_felt252(1); - let mut constructor_calldata = ArrayTrait::::new(); + let mut constructor_calldata = array![]; quorum.serialize(ref constructor_calldata); let (vanilla_execution_strategy_address, _) = deploy_syscall( @@ -257,24 +222,16 @@ mod tests { testing::set_contract_address(author); authenticator .authenticate_propose( - space.contract_address, - author, - vanilla_execution_strategy, - ArrayTrait::::new(), - ArrayTrait::::new() + space.contract_address, author, vanilla_execution_strategy, array![], array![] ); - assert( - space.next_proposal_id() == u256 { low: 2_u128, high: 0_u128 }, - 'next_proposal_id should be 2' - ); + assert(space.next_proposal_id() == 2_u256, 'next_proposal_id should be 2'); // Update Proposal let proposal_id = u256_from_felt252(1); // Keeping the same execution strategy contract but changing the payload - let mut new_payload = ArrayTrait::::new(); - new_payload.append(1); + let mut new_payload = array![1]; let new_execution_strategy = Strategy { address: vanilla_execution_strategy_address, params: new_payload.clone() }; @@ -282,11 +239,7 @@ mod tests { testing::set_contract_address(author); authenticator .authenticate_update_proposal( - space.contract_address, - author, - proposal_id, - new_execution_strategy, - ArrayTrait::::new() + space.contract_address, author, proposal_id, new_execution_strategy, array![] ); // Increasing block timestamp by 1 to pass voting delay @@ -294,20 +247,13 @@ mod tests { let voter = contract_address_const::<0x8765>(); let choice = Choice::For(()); - let mut user_voting_strategies = ArrayTrait::::new(); - user_voting_strategies - .append(IndexedStrategy { index: 0_u8, params: ArrayTrait::::new() }); + let mut user_voting_strategies = array![IndexedStrategy { index: 0_u8, params: array![] }]; // Vote on Proposal not from voter account testing::set_contract_address(config.owner); authenticator .authenticate_vote( - space.contract_address, - voter, - proposal_id, - choice, - user_voting_strategies, - ArrayTrait::::new() + space.contract_address, voter, proposal_id, choice, user_voting_strategies, array![] ); } } diff --git a/starknet/src/tests/test_upgrade.cairo b/starknet/src/tests/test_upgrade.cairo index ccad2cbd..fe321210 100644 --- a/starknet/src/tests/test_upgrade.cairo +++ b/starknet/src/tests/test_upgrade.cairo @@ -21,7 +21,6 @@ mod tests { use sx::execution_strategies::vanilla::VanillaExecutionStrategy; use sx::voting_strategies::vanilla::VanillaVotingStrategy; use sx::proposal_validation_strategies::vanilla::VanillaProposalValidationStrategy; - use sx::tests::mocks::proposal_validation_always_fail::AlwaysFailProposalValidationStrategy; use sx::types::{ UserAddress, Strategy, IndexedStrategy, Choice, FinalizationStatus, Proposal, UpdateSettingsCalldataImpl @@ -34,6 +33,7 @@ mod tests { use sx::tests::mocks::executor::{ ExecutorExecutionStrategy, ExecutorExecutionStrategy::Transaction }; + use sx::tests::mocks::space_v2::{SpaceV2, ISpaceV2Dispatcher, ISpaceV2DispatcherTrait}; use starknet::ClassHash; use Space::Space as SpaceImpl; @@ -44,24 +44,17 @@ mod tests { let config = setup(); let (factory, space) = deploy(@config); - // New implementation is not a proposer space but a random contract (here, a proposal validation strategy). - let new_implem = AlwaysFailProposalValidationStrategy::TEST_CLASS_HASH.try_into().unwrap(); + let new_implem = SpaceV2::TEST_CLASS_HASH.try_into().unwrap(); testing::set_contract_address(config.owner); // Now upgrade the implementation - space.upgrade(new_implem); + space.upgrade(new_implem, array![7]); // Ensure it works - let new_space = IProposalValidationStrategyDispatcher { - contract_address: space.contract_address - }; + let new_space = ISpaceV2Dispatcher { contract_address: space.contract_address }; - let author = UserAddress::Starknet(contract_address_const::<0x7777777777>()); - let params = ArrayTrait::::new(); - let user_params = ArrayTrait::::new(); - let res = new_space.validate(author, params, user_params); - assert(res == false, 'Strategy did not return false'); + assert(new_space.get_var() == 7, 'New implementation did not work'); } #[test] @@ -72,14 +65,12 @@ mod tests { let proposal_id = space.next_proposal_id(); // New implementation is not a proposer space but a random contract (here, a proposal validation strategy). - let new_implem: ClassHash = AlwaysFailProposalValidationStrategy::TEST_CLASS_HASH - .try_into() - .unwrap(); + let new_implem: ClassHash = SpaceV2::TEST_CLASS_HASH.try_into().unwrap(); let (execution_contract_address, _) = deploy_syscall( ExecutorExecutionStrategy::TEST_CLASS_HASH.try_into().unwrap(), 0, - ArrayTrait::::new().span(), + array![].span(), false ) .unwrap(); @@ -90,18 +81,19 @@ mod tests { // keccak256("upgrade") & (2**250 - 1) let selector = 0xf2f7c15cbe06c8d94597cd91fd7f3369eae842359235712def5584f8d270cd; - let mut tx_calldata = ArrayTrait::new(); + let mut tx_calldata = array![]; new_implem.serialize(ref tx_calldata); + array![7].serialize(ref tx_calldata); // initialize calldata let tx = Transaction { target: space.contract_address, selector, data: tx_calldata, }; - let mut execution_params = ArrayTrait::::new(); + let mut execution_params = array![]; tx.serialize(ref execution_params); let execution_strategy = Strategy { address: execution_contract_address, params: execution_params.clone(), }; - let mut propose_calldata = ArrayTrait::::new(); + let mut propose_calldata = array![]; UserAddress::Starknet(contract_address_const::<0x7676>()).serialize(ref propose_calldata); execution_strategy.serialize(ref propose_calldata); ArrayTrait::::new().serialize(ref propose_calldata); @@ -117,14 +109,23 @@ mod tests { space.execute(proposal_id, execution_params); // Ensure it works - let new_space = IProposalValidationStrategyDispatcher { - contract_address: space.contract_address - }; + let new_space = ISpaceV2Dispatcher { contract_address: space.contract_address }; + + assert(new_space.get_var() == 7, 'New implementation did not work'); + } + + #[test] + #[available_gas(10000000000)] + #[should_panic(expected: ('Caller is not the owner', 'ENTRYPOINT_FAILED'))] + fn test_upgrade_unauthorized() { + let config = setup(); + let (factory, space) = deploy(@config); + + let new_implem = SpaceV2::TEST_CLASS_HASH.try_into().unwrap(); + + testing::set_contract_address(contract_address_const::<0xdead>()); - let author = UserAddress::Starknet(contract_address_const::<0x7777777777>()); - let params = ArrayTrait::::new(); - let user_params = ArrayTrait::::new(); - let res = new_space.validate(author, params, user_params); - assert(res == false, 'Strategy did not return false'); + // Upgrade should fail as caller is not owner + space.upgrade(new_implem, array![7]); } } diff --git a/starknet/src/tests/utils/strategy_trait.cairo b/starknet/src/tests/utils/strategy_trait.cairo index 5d68ebc8..2ac75cd0 100644 --- a/starknet/src/tests/utils/strategy_trait.cairo +++ b/starknet/src/tests/utils/strategy_trait.cairo @@ -9,12 +9,10 @@ trait StrategyTrait { impl StrategyImpl of StrategyTrait { fn test_value() -> Strategy { - Strategy { - address: contract_address_const::<0x5c011>(), params: ArrayTrait::::new(), - } + Strategy { address: contract_address_const::<0x5c011>(), params: array![], } } fn from_address(addr: ContractAddress) -> Strategy { - Strategy { address: addr, params: ArrayTrait::::new(), } + Strategy { address: addr, params: array![], } } } diff --git a/starknet/src/types/indexed_strategy.cairo b/starknet/src/types/indexed_strategy.cairo index ff691baa..d1ca8787 100644 --- a/starknet/src/types/indexed_strategy.cairo +++ b/starknet/src/types/indexed_strategy.cairo @@ -20,16 +20,16 @@ impl IndexedStrategyImpl of IndexedStrategyTrait { return (); } - let mut bit_map = u256 { low: 0_u128, high: 0_u128 }; + let mut bit_map = 0_u256; let mut i = 0_usize; loop { if i >= self.len() { break (); } // Check that bit at index `strats[i].index` is not set. - let s = math::pow(u256 { low: 2_u128, high: 0_u128 }, *self.at(i).index); + let s = math::pow(2_u256, *self.at(i).index); - assert((bit_map & s) == u256 { low: 1_u128, high: 0_u128 }, 'Duplicate Found'); + assert((bit_map & s) == 1_u256, 'Duplicate Found'); // Update aforementioned bit. bit_map = bit_map | s; i += 1; diff --git a/starknet/src/types/strategy.cairo b/starknet/src/types/strategy.cairo index 79fab588..04fb38a7 100644 --- a/starknet/src/types/strategy.cairo +++ b/starknet/src/types/strategy.cairo @@ -43,7 +43,7 @@ impl StoreFelt252Array of Store> { fn read_at_offset( address_domain: u32, base: StorageBaseAddress, mut offset: u8 ) -> SyscallResult> { - let mut arr: Array = ArrayTrait::new(); + let mut arr = array![]; // Read the stored array's length. If the length is superior to 255, the read will fail. let len: u8 = Store::::read_at_offset(address_domain, base, offset) diff --git a/starknet/src/types/update_settings_calldata.cairo b/starknet/src/types/update_settings_calldata.cairo index 1b3c7b6a..3c6588c7 100644 --- a/starknet/src/types/update_settings_calldata.cairo +++ b/starknet/src/types/update_settings_calldata.cairo @@ -69,7 +69,7 @@ impl NoUpdateStrategy of NoUpdateTrait { fn no_update() -> Strategy { Strategy { address: contract_address_const::<0xf2cda9b13ed04e585461605c0d6e804933ca828111bd94d4e6a96c75e8b048>(), - params: array::ArrayTrait::new(), + params: array![], } } @@ -82,7 +82,7 @@ impl NoUpdateStrategy of NoUpdateTrait { // TODO: find a way for "Strings" impl NoUpdateArray of NoUpdateTrait> { fn no_update() -> Array { - array::ArrayTrait::::new() + array![] } fn should_update(self: @Array) -> bool { diff --git a/starknet/src/utils.cairo b/starknet/src/utils.cairo index 29bf44f6..9cd3b565 100644 --- a/starknet/src/utils.cairo +++ b/starknet/src/utils.cairo @@ -17,3 +17,7 @@ mod single_slot_proof; mod signatures; mod stark_eip712; + +// TODO: proper component syntax will have a better way to do this +mod reinitializable; +use reinitializable::Reinitializable::Reinitializable as ReinitializableImpl; diff --git a/starknet/src/utils/bits.cairo b/starknet/src/utils/bits.cairo index 6b9a7c0b..cdc3d27d 100644 --- a/starknet/src/utils/bits.cairo +++ b/starknet/src/utils/bits.cairo @@ -12,7 +12,7 @@ impl U256BitSetter of BitSetter { /// Sets the bit at the given index to 1. #[inline(always)] fn set_bit(ref self: u256, index: u8, bit: bool) { - let mask = pow(u256 { low: 2_u128, high: 0_u128 }, index); + let mask = pow(2_u256, index); if bit { self = self | mask; } else { @@ -23,7 +23,7 @@ impl U256BitSetter of BitSetter { /// Returns true if the bit at the given index is set to 1. #[inline(always)] fn is_bit_set(self: u256, index: u8) -> bool { - let mask = pow(u256 { low: 2_u128, high: 0_u128 }, index); + let mask = pow(2_u256, index); (self & mask).is_non_zero() } } diff --git a/starknet/src/utils/constants.cairo b/starknet/src/utils/constants.cairo index 42ab1ad9..2938e212 100644 --- a/starknet/src/utils/constants.cairo +++ b/starknet/src/utils/constants.cairo @@ -1,3 +1,5 @@ +const INITIALIZE_SELECTOR: felt252 = + 0x79dc0da7c54b95f10aa182ad0a46400db63156920adb65eca2654c0945a463; const PROPOSE_SELECTOR: felt252 = 0x1bfd596ae442867ef71ca523061610682af8b00fc2738329422f4ad8d220b81; const VOTE_SELECTOR: felt252 = 0x132bdf85fc8aa10ac3c22f02317f8f53d4b4f52235ed1eabb3a4cbbe08b5c41; const UPDATE_PROPOSAL_SELECTOR: felt252 = diff --git a/starknet/src/utils/math.cairo b/starknet/src/utils/math.cairo index 535bc3ac..7315a35e 100644 --- a/starknet/src/utils/math.cairo +++ b/starknet/src/utils/math.cairo @@ -16,7 +16,7 @@ impl U64Zeroable of Zeroable { } fn pow(base: u256, mut exp: u8) -> u256 { - let mut res = u256 { low: 1_u128, high: 0_u128 }; + let mut res = 1_u256; loop { if exp == 0 { break res; diff --git a/starknet/src/utils/merkle.cairo b/starknet/src/utils/merkle.cairo index 15262955..eac03d73 100644 --- a/starknet/src/utils/merkle.cairo +++ b/starknet/src/utils/merkle.cairo @@ -21,7 +21,7 @@ trait Hash { impl HashSerde> of Hash { fn hash(self: @T) -> felt252 { - let mut serialized = ArrayTrait::new(); + let mut serialized = array![]; Serde::::serialize(self, ref serialized); let hashed = LegacyHash::hash(0, serialized.span()); hashed diff --git a/starknet/src/utils/reinitializable.cairo b/starknet/src/utils/reinitializable.cairo new file mode 100644 index 00000000..d044d172 --- /dev/null +++ b/starknet/src/utils/reinitializable.cairo @@ -0,0 +1,40 @@ +#[starknet::interface] +trait IReinitializable { + fn initialize(ref self: TContractState); + fn reinitialize(ref self: TContractState); + fn initialized(self: @TContractState); + fn not_initialized(self: @TContractState); +} + +#[starknet::contract] +mod Reinitializable { + use super::IReinitializable; + use starknet::ContractAddress; + use starknet::syscalls::call_contract_syscall; + use core::array::{ArrayTrait, SpanTrait}; + + #[storage] + struct Storage { + _initialized: bool + } + + #[external(v0)] + impl Reinitializable of IReinitializable { + fn initialize(ref self: ContractState) { + self.not_initialized(); + self._initialized.write(true); + } + + fn reinitialize(ref self: ContractState) { + self._initialized.write(false); + } + + fn initialized(self: @ContractState) { + assert(self._initialized.read() == true, 'Not Initialized'); + } + + fn not_initialized(self: @ContractState) { + assert(self._initialized.read() == false, 'Already Initialized'); + } + } +} diff --git a/starknet/src/utils/signatures.cairo b/starknet/src/utils/signatures.cairo index 35cad8bc..80d63db9 100644 --- a/starknet/src/utils/signatures.cairo +++ b/starknet/src/utils/signatures.cairo @@ -32,10 +32,11 @@ trait KeccakTypeHash { impl KeccakTypeHashStrategy of KeccakTypeHash { fn hash(self: Strategy) -> u256 { - let mut encoded_data = ArrayTrait::::new(); - encoded_data.append(u256 { low: STRATEGY_TYPEHASH_LOW, high: STRATEGY_TYPEHASH_HIGH }); - encoded_data.append(self.address.into()); - encoded_data.append(self.params.hash()); + let mut encoded_data = array![ + u256 { + low: STRATEGY_TYPEHASH_LOW, high: STRATEGY_TYPEHASH_HIGH + }, self.address.into(), self.params.hash(), + ]; keccak::keccak_u256s_le_inputs(encoded_data.span()) } } @@ -51,14 +52,12 @@ impl KeccakTypeHashArray of KeccakTypeHash> { impl KeccakTypeHashIndexedStrategy of KeccakTypeHash { fn hash(self: IndexedStrategy) -> u256 { - let mut encoded_data = ArrayTrait::::new(); - encoded_data - .append( - u256 { low: INDEXED_STRATEGY_TYPEHASH_LOW, high: INDEXED_STRATEGY_TYPEHASH_HIGH } - ); let index_felt: felt252 = self.index.into(); - encoded_data.append(index_felt.into()); - encoded_data.append(self.params.hash()); + let mut encoded_data = array![ + u256 { + low: INDEXED_STRATEGY_TYPEHASH_LOW, high: INDEXED_STRATEGY_TYPEHASH_HIGH + }, index_felt.into(), self.params.hash(), + ]; keccak::keccak_u256s_le_inputs(encoded_data.span()) } } @@ -143,13 +142,16 @@ fn get_propose_digest( user_proposal_validation_params: Array, salt: u256 ) -> u256 { - let mut encoded_data = ArrayTrait::::new(); - encoded_data.append(u256 { low: PROPOSE_TYPEHASH_LOW, high: PROPOSE_TYPEHASH_HIGH }); - encoded_data.append(space.into()); - encoded_data.append(author.into()); - encoded_data.append(execution_strategy.hash()); - encoded_data.append(user_proposal_validation_params.hash()); - encoded_data.append(salt); + let mut encoded_data = array![ + u256 { + low: PROPOSE_TYPEHASH_LOW, high: PROPOSE_TYPEHASH_HIGH + }, + space.into(), + author.into(), + execution_strategy.hash(), + user_proposal_validation_params.hash(), + salt, + ]; let message_hash = keccak::keccak_u256s_le_inputs(encoded_data.span()); hash_typed_data(domain_hash, message_hash) } @@ -162,13 +164,11 @@ fn get_vote_digest( choice: Choice, user_voting_strategies: Array ) -> u256 { - let mut encoded_data = ArrayTrait::::new(); - encoded_data.append(u256 { low: VOTE_TYPEHASH_LOW, high: VOTE_TYPEHASH_HIGH }); - encoded_data.append(space.into()); - encoded_data.append(voter.into()); - encoded_data.append(proposal_id); - encoded_data.append(choice.into()); - encoded_data.append(user_voting_strategies.hash()); + let mut encoded_data = array![ + u256 { + low: VOTE_TYPEHASH_LOW, high: VOTE_TYPEHASH_HIGH + }, space.into(), voter.into(), proposal_id, choice.into(), user_voting_strategies.hash(), + ]; let message_hash = keccak::keccak_u256s_le_inputs(encoded_data.span()); hash_typed_data(domain_hash, message_hash) } @@ -181,33 +181,32 @@ fn get_update_proposal_digest( execution_strategy: Strategy, salt: u256 ) -> u256 { - let mut encoded_data = ArrayTrait::::new(); - encoded_data - .append(u256 { low: UPDATE_PROPOSAL_TYPEHASH_LOW, high: UPDATE_PROPOSAL_TYPEHASH_HIGH }); - encoded_data.append(space.into()); - encoded_data.append(author.into()); - encoded_data.append(proposal_id); - encoded_data.append(execution_strategy.hash()); - encoded_data.append(salt); + let mut encoded_data = array![ + u256 { + low: UPDATE_PROPOSAL_TYPEHASH_LOW, high: UPDATE_PROPOSAL_TYPEHASH_HIGH + }, space.into(), author.into(), proposal_id, execution_strategy.hash(), salt, + ]; let message_hash = keccak::keccak_u256s_le_inputs(encoded_data.span()); hash_typed_data(domain_hash, message_hash) } fn get_domain_hash(name: felt252, version: felt252) -> u256 { - let mut encoded_data = ArrayTrait::::new(); - encoded_data.append(u256 { low: DOMAIN_TYPEHASH_LOW, high: DOMAIN_TYPEHASH_HIGH }); - encoded_data.append(name.into()); - encoded_data.append(version.into()); - // TODO: chain id doesnt seem like its exposed atm, so just dummy value for now - encoded_data.append(u256 { low: 'dummy', high: 0 }); - encoded_data.append(starknet::get_contract_address().into()); + let mut encoded_data = array![ + u256 { + low: DOMAIN_TYPEHASH_LOW, high: DOMAIN_TYPEHASH_HIGH + }, + name.into(), + version + .into(), // TODO: chain id doesnt seem like its exposed atm, so just dummy value for now + u256 { + low: 'dummy', high: 0 + }, starknet::get_contract_address().into(), + ]; keccak::keccak_u256s_le_inputs(encoded_data.span()) } fn hash_typed_data(domain_hash: u256, message_hash: u256) -> u256 { - let mut encoded_data = ArrayTrait::::new(); - encoded_data.append(domain_hash); - encoded_data.append(message_hash); + let mut encoded_data = array![domain_hash, message_hash, ]; let encoded_data = _add_prefix_array(encoded_data, ETHEREUM_PREFIX); keccak::keccak_u256s_le_inputs(encoded_data.span()) } @@ -215,13 +214,13 @@ fn hash_typed_data(domain_hash: u256, message_hash: u256) -> u256 { // Prefixes a 16 bit prefix to an array of 256 bit values. fn _add_prefix_array(input: Array, mut prefix: u128) -> Array { - let mut out = ArrayTrait::::new(); + let mut out = array![]; let mut i = 0_usize; loop { if i >= input.len() { // left shift so that the prefix is in the high bits let prefix_u256 = u256 { low: prefix, high: 0_u128 }; - let shifted_prefix = prefix_u256 * pow(u256 { low: 2_u128, high: 0_u128 }, 112_u8); + let shifted_prefix = prefix_u256 * pow(2_u256, 112_u8); out.append(shifted_prefix); break (); } @@ -238,14 +237,11 @@ fn _add_prefix_array(input: Array, mut prefix: u128) -> Array { // prefixes a 16 bit prefix to a 128 bit input, returning the result and a carry if it overflows 128 bits fn _add_prefix_u128(input: u128, prefix: u128) -> (u128, u128) { - let prefix_u256 = u256 { low: prefix, high: 0_u128 }; - let shifted_prefix = prefix_u256 * pow(u256 { low: 2_u128, high: 0_u128 }, 128_u8); - let with_prefix = u256 { low: input, high: 0_u128 } + shifted_prefix; - let overflow_mask = pow(u256 { low: 2_u128, high: 0_u128 }, 16_u8) - u256 { - low: 1_u128, high: 0_u128 - }; + let shifted_prefix = prefix.into() * pow(2_u256, 128_u8); + let with_prefix = input.into() + shifted_prefix; + let overflow_mask = pow(2_u256, 16_u8) - 1_u256; let carry = with_prefix & overflow_mask; // Removing the carry and shifting back. The result fits in 128 bits. - let out = ((with_prefix - carry) / pow(u256 { low: 2_u128, high: 0_u128 }, 16_u8)); + let out = ((with_prefix - carry) / pow(2_u256, 16_u8)); (out.low, carry.low) } diff --git a/starknet/src/utils/single_slot_proof.cairo b/starknet/src/utils/single_slot_proof.cairo index fffd5149..e152e64e 100644 --- a/starknet/src/utils/single_slot_proof.cairo +++ b/starknet/src/utils/single_slot_proof.cairo @@ -56,9 +56,7 @@ mod SingleSlotProof { #[internal] fn get_mapping_slot_key(slot_index: u256, mapping_key: u256) -> u256 { - let mut encoded_array = ArrayTrait::::new(); - encoded_array.append(mapping_key); - encoded_array.append(slot_index); + let mut encoded_array = array![mapping_key, slot_index]; keccak::keccak_u256s_le_inputs(encoded_array.span()) } diff --git a/starknet/src/utils/stark_eip712.cairo b/starknet/src/utils/stark_eip712.cairo index 7795dea5..97a8446c 100644 --- a/starknet/src/utils/stark_eip712.cairo +++ b/starknet/src/utils/stark_eip712.cairo @@ -84,7 +84,7 @@ fn get_propose_digest( metadata_URI: Span, salt: felt252 ) -> felt252 { - let mut encoded_data = ArrayTrait::::new(); + let mut encoded_data = array![]; PROPOSE_TYPEHASH.serialize(ref encoded_data); space.serialize(ref encoded_data); author.serialize(ref encoded_data); @@ -104,7 +104,7 @@ fn get_vote_digest( user_voting_strategies: Span, metadata_URI: Span, ) -> felt252 { - let mut encoded_data = ArrayTrait::::new(); + let mut encoded_data = array![]; VOTE_TYPEHASH.serialize(ref encoded_data); space.serialize(ref encoded_data); voter.serialize(ref encoded_data); @@ -124,7 +124,7 @@ fn get_update_proposal_digest( metadata_URI: Span, salt: felt252 ) -> felt252 { - let mut encoded_data = ArrayTrait::::new(); + let mut encoded_data = array![]; UPDATE_PROPOSAL_TYPEHASH.serialize(ref encoded_data); space.serialize(ref encoded_data); author.serialize(ref encoded_data); @@ -136,7 +136,7 @@ fn get_update_proposal_digest( } fn get_domain_hash(name: felt252, version: felt252) -> felt252 { - let mut encoded_data = ArrayTrait::::new(); + let mut encoded_data = array![]; DOMAIN_TYPEHASH.serialize(ref encoded_data); name.serialize(ref encoded_data); version.serialize(ref encoded_data); @@ -148,7 +148,7 @@ fn get_domain_hash(name: felt252, version: felt252) -> felt252 { fn hash_typed_data( domain_hash: felt252, message_hash: felt252, signer: ContractAddress ) -> felt252 { - let mut encoded_data = ArrayTrait::::new(); + let mut encoded_data = array![]; STARKNET_MESSAGE.serialize(ref encoded_data); domain_hash.serialize(ref encoded_data); signer.serialize(ref encoded_data); diff --git a/starknet/src/utils/struct_hash.cairo b/starknet/src/utils/struct_hash.cairo index f1d01653..bcbabbeb 100644 --- a/starknet/src/utils/struct_hash.cairo +++ b/starknet/src/utils/struct_hash.cairo @@ -24,7 +24,7 @@ impl StructHashSpanFelt252 of StructHash> { impl StructHashStrategy of StructHash { fn struct_hash(self: @Strategy) -> felt252 { - let mut encoded_data = ArrayTrait::::new(); + let mut encoded_data = array![]; STRATEGY_TYPEHASH.serialize(ref encoded_data); (*self.address).serialize(ref encoded_data); self.params.span().struct_hash().serialize(ref encoded_data); @@ -34,7 +34,7 @@ impl StructHashStrategy of StructHash { impl StructHashIndexedStrategy of StructHash { fn struct_hash(self: @IndexedStrategy) -> felt252 { - let mut encoded_data = ArrayTrait::::new(); + let mut encoded_data = array![]; INDEXED_STRATEGY_TYPEHASH.serialize(ref encoded_data); (*self.index).serialize(ref encoded_data); self.params.span().struct_hash().serialize(ref encoded_data); @@ -45,7 +45,7 @@ impl StructHashIndexedStrategy of StructHash { impl StructHashIndexedStrategySpan of StructHash> { fn struct_hash(self: @Span) -> felt252 { let mut self_ = *self; - let mut encoded_data = ArrayTrait::::new(); + let mut encoded_data = array![]; loop { match self_.pop_front() { Option::Some(item) => { @@ -61,7 +61,7 @@ impl StructHashIndexedStrategySpan of StructHash> { impl StructHashU256 of StructHash { fn struct_hash(self: @u256) -> felt252 { - let mut encoded_data = ArrayTrait::::new(); + let mut encoded_data = array![]; U256_TYPEHASH.serialize(ref encoded_data); self.serialize(ref encoded_data); encoded_data.span().struct_hash() diff --git a/starknet/src/voting_strategies/vanilla.cairo b/starknet/src/voting_strategies/vanilla.cairo index ee6a68cb..0e880acf 100644 --- a/starknet/src/voting_strategies/vanilla.cairo +++ b/starknet/src/voting_strategies/vanilla.cairo @@ -16,7 +16,7 @@ mod VanillaVotingStrategy { params: Array, user_params: Array, ) -> u256 { - u256 { low: 1_u128, high: 0_u128 } + 1_u256 } } }