diff --git a/starknet/src/authenticators/eth_sig.cairo b/starknet/src/authenticators/eth_sig.cairo index ae841170..cb4af620 100644 --- a/starknet/src/authenticators/eth_sig.cairo +++ b/starknet/src/authenticators/eth_sig.cairo @@ -13,6 +13,7 @@ trait IEthSigAuthenticator { author: EthAddress, execution_strategy: Strategy, user_proposal_validation_params: Array, + metadata_URI: Array, salt: u256, ); fn authenticate_vote( @@ -24,7 +25,8 @@ trait IEthSigAuthenticator { voter: EthAddress, proposal_id: u256, choice: Choice, - user_voting_strategies: Array + user_voting_strategies: Array, + metadata_URI: Array, ); fn authenticate_update_proposal( ref self: TContractState, @@ -35,6 +37,7 @@ trait IEthSigAuthenticator { author: EthAddress, proposal_id: u256, execution_strategy: Strategy, + metadata_URI: Array, salt: u256 ); } @@ -66,6 +69,7 @@ mod EthSigAuthenticator { author: EthAddress, execution_strategy: Strategy, user_proposal_validation_params: Array, + metadata_URI: Array, salt: u256, ) { signatures::verify_propose_sig( @@ -87,7 +91,8 @@ mod EthSigAuthenticator { .propose( UserAddress::Ethereum(author), execution_strategy, - user_proposal_validation_params + user_proposal_validation_params, + metadata_URI ); } @@ -100,7 +105,8 @@ mod EthSigAuthenticator { voter: EthAddress, proposal_id: u256, choice: Choice, - user_voting_strategies: Array + user_voting_strategies: Array, + metadata_URI: Array, ) { signatures::verify_vote_sig( r, @@ -111,14 +117,21 @@ mod EthSigAuthenticator { voter, proposal_id, choice, - user_voting_strategies.clone() + user_voting_strategies.clone(), ); // No need to check salts here, as double voting is prevented by the space itself. ISpaceDispatcher { contract_address: target - }.vote(UserAddress::Ethereum(voter), proposal_id, choice, user_voting_strategies); + } + .vote( + UserAddress::Ethereum(voter), + proposal_id, + choice, + user_voting_strategies, + metadata_URI + ); } fn authenticate_update_proposal( @@ -130,6 +143,7 @@ mod EthSigAuthenticator { author: EthAddress, proposal_id: u256, execution_strategy: Strategy, + metadata_URI: Array, salt: u256 ) { signatures::verify_update_proposal_sig( @@ -147,7 +161,10 @@ mod EthSigAuthenticator { ISpaceDispatcher { contract_address: target - }.update_proposal(UserAddress::Ethereum(author), proposal_id, execution_strategy); + } + .update_proposal( + UserAddress::Ethereum(author), proposal_id, execution_strategy, metadata_URI + ); } } diff --git a/starknet/src/authenticators/eth_tx.cairo b/starknet/src/authenticators/eth_tx.cairo index 07bf568f..b651383a 100644 --- a/starknet/src/authenticators/eth_tx.cairo +++ b/starknet/src/authenticators/eth_tx.cairo @@ -8,7 +8,8 @@ trait IEthTxAuthenticator { target: ContractAddress, author: EthAddress, execution_strategy: Strategy, - user_proposal_validation_params: Array + user_proposal_validation_params: Array, + metadata_URI: Array ); fn authenticate_vote( ref self: TContractState, @@ -16,14 +17,16 @@ trait IEthTxAuthenticator { voter: EthAddress, proposal_id: u256, choice: Choice, - user_voting_strategies: Array + user_voting_strategies: Array, + metadata_URI: Array ); fn authenticate_update_proposal( ref self: TContractState, target: ContractAddress, author: EthAddress, proposal_id: u256, - execution_strategy: Strategy + execution_strategy: Strategy, + metadata_URI: Array ); // TODO: Should L1 handlers be part of the interface? } @@ -55,7 +58,8 @@ mod EthTxAuthenticator { target: ContractAddress, author: EthAddress, execution_strategy: Strategy, - user_proposal_validation_params: Array + user_proposal_validation_params: Array, + metadata_URI: Array ) { let mut payload = ArrayTrait::::new(); target.serialize(ref payload); @@ -63,6 +67,7 @@ mod EthTxAuthenticator { author.serialize(ref payload); execution_strategy.serialize(ref payload); user_proposal_validation_params.serialize(ref payload); + metadata_URI.serialize(ref payload); let payload_hash = poseidon::poseidon_hash_span(payload.span()); consume_commit(ref self, payload_hash, author); @@ -73,7 +78,8 @@ mod EthTxAuthenticator { .propose( UserAddress::Ethereum(author), execution_strategy, - user_proposal_validation_params + user_proposal_validation_params, + metadata_URI ); } @@ -83,7 +89,8 @@ mod EthTxAuthenticator { voter: EthAddress, proposal_id: u256, choice: Choice, - user_voting_strategies: Array + user_voting_strategies: Array, + metadata_URI: Array ) { let mut payload = ArrayTrait::::new(); target.serialize(ref payload); @@ -92,13 +99,21 @@ mod EthTxAuthenticator { proposal_id.serialize(ref payload); choice.serialize(ref payload); user_voting_strategies.serialize(ref payload); + metadata_URI.serialize(ref payload); let payload_hash = poseidon::poseidon_hash_span(payload.span()); consume_commit(ref self, payload_hash, voter); ISpaceDispatcher { contract_address: target - }.vote(UserAddress::Ethereum(voter), proposal_id, choice, user_voting_strategies); + } + .vote( + UserAddress::Ethereum(voter), + proposal_id, + choice, + user_voting_strategies, + metadata_URI + ); } fn authenticate_update_proposal( @@ -106,7 +121,8 @@ mod EthTxAuthenticator { target: ContractAddress, author: EthAddress, proposal_id: u256, - execution_strategy: Strategy + execution_strategy: Strategy, + metadata_URI: Array ) { let mut payload = ArrayTrait::::new(); target.serialize(ref payload); @@ -114,13 +130,17 @@ mod EthTxAuthenticator { author.serialize(ref payload); proposal_id.serialize(ref payload); execution_strategy.serialize(ref payload); + metadata_URI.serialize(ref payload); let payload_hash = poseidon::poseidon_hash_span(payload.span()); consume_commit(ref self, payload_hash, author); ISpaceDispatcher { contract_address: target - }.update_proposal(UserAddress::Ethereum(author), proposal_id, execution_strategy); + } + .update_proposal( + UserAddress::Ethereum(author), proposal_id, execution_strategy, metadata_URI + ); } } diff --git a/starknet/src/space/space.cairo b/starknet/src/space/space.cairo index f88eb4ef..12e0a731 100644 --- a/starknet/src/space/space.cairo +++ b/starknet/src/space/space.cairo @@ -33,21 +33,24 @@ trait ISpace { ref self: TContractState, author: UserAddress, execution_strategy: Strategy, - user_proposal_validation_params: Array + user_proposal_validation_params: Array, + metadata_URI: Array, ); fn vote( ref self: TContractState, voter: UserAddress, proposal_id: u256, choice: Choice, - user_voting_strategies: Array + user_voting_strategies: Array, + metadata_URI: Array, ); fn execute(ref self: TContractState, proposal_id: u256, execution_payload: Array); fn update_proposal( ref self: TContractState, author: UserAddress, proposal_id: u256, - execution_strategy: Strategy + execution_strategy: Strategy, + metadata_URI: Array, ); fn cancel_proposal(ref self: TContractState, proposal_id: u256); fn upgrade(ref self: TContractState, class_hash: ClassHash); @@ -102,23 +105,39 @@ mod Space { _min_voting_duration: u32, _max_voting_duration: u32, _proposal_validation_strategy: @Strategy, + _proposal_validation_strategy_metadata_URI: @Array, _voting_strategies: @Array, - _authenticators: @Array + _voting_strategy_metadata_URIs: @Array>, + _authenticators: @Array, + _metadata_URI: @Array, + _dao_URI: @Array, ) {} #[event] fn ProposalCreated( - _proposal_id: u256, _author: UserAddress, _proposal: @Proposal, _payload: @Array + _proposal_id: u256, + _author: UserAddress, + _proposal: @Proposal, + _payload: @Array, + _metadata_URI: @Array ) {} #[event] - fn VoteCast(_proposal_id: u256, _voter: UserAddress, _choice: Choice, _voting_power: u256) {} + fn VoteCast( + _proposal_id: u256, + _voter: UserAddress, + _choice: Choice, + _voting_power: u256, + _metadata_URI: @Array + ) {} #[event] fn ProposalExecuted(_proposal_id: u256) {} #[event] - fn ProposalUpdated(_proposal_id: u256, _execution_stategy: @Strategy) {} + fn ProposalUpdated( + _proposal_id: u256, _execution_stategy: @Strategy, _metadata_URI: @Array + ) {} #[event] fn ProposalCancelled(_proposal_id: u256) {} @@ -126,7 +145,7 @@ mod Space { #[event] fn VotingStrategiesAdded( _new_voting_strategies: @Array, - _new_voting_strategy_metadata_uris: @Array> + _new_voting_strategy_metadata_URIs: @Array> ) {} #[event] @@ -139,10 +158,10 @@ mod Space { fn AuthenticatorsRemoved(_authenticators: @Array) {} #[event] - fn MetadataURIUpdated(_new_metadata_uri: @Array) {} + fn MetadataURIUpdated(_new_metadata_URI: @Array) {} #[event] - fn DaoURIUpdated(_new_dao_uri: @Array) {} + fn DaoURIUpdated(_new_dao_URI: @Array) {} #[event] fn MaxVotingDurationUpdated(_new_max_voting_duration: u32) {} @@ -168,7 +187,8 @@ mod Space { ref self: ContractState, author: UserAddress, execution_strategy: Strategy, - user_proposal_validation_params: Array + user_proposal_validation_params: Array, + metadata_URI: Array, ) { assert_only_authenticator(@self); let proposal_id = self._next_proposal_id.read(); @@ -212,7 +232,9 @@ mod Space { self._next_proposal_id.write(proposal_id + u256 { low: 1_u128, high: 0_u128 }); - ProposalCreated(proposal_id, author, snap_proposal, @execution_strategy.params); + ProposalCreated( + proposal_id, author, snap_proposal, @execution_strategy.params, @metadata_URI + ); } fn vote( @@ -220,7 +242,8 @@ mod Space { voter: UserAddress, proposal_id: u256, choice: Choice, - user_voting_strategies: Array + user_voting_strategies: Array, + metadata_URI: Array ) { assert_only_authenticator(@self); let proposal = self._proposals.read(proposal_id); @@ -255,7 +278,7 @@ mod Space { ); self._vote_registry.write((proposal_id, voter), true); - VoteCast(proposal_id, voter, choice, voting_power); + VoteCast(proposal_id, voter, choice, voting_power, @metadata_URI); } fn execute(ref self: ContractState, proposal_id: u256, execution_payload: Array) { @@ -284,7 +307,8 @@ mod Space { ref self: ContractState, author: UserAddress, proposal_id: u256, - execution_strategy: Strategy + execution_strategy: Strategy, + metadata_URI: Array, ) { assert_only_authenticator(@self); let mut proposal = self._proposals.read(proposal_id); @@ -303,7 +327,7 @@ mod Space { self._proposals.write(proposal_id, proposal); - ProposalUpdated(proposal_id, @execution_strategy); + ProposalUpdated(proposal_id, @execution_strategy, @metadata_URI); } fn cancel_proposal(ref self: ContractState, proposal_id: u256) { @@ -469,8 +493,12 @@ mod Space { _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(); @@ -490,8 +518,12 @@ mod Space { _min_voting_duration, _max_voting_duration, @_proposal_validation_strategy, + @_proposal_validation_strategy_metadata_URI, @_voting_strategies, - @_authenticators + @_voting_strategies_metadata_URIs, + @_authenticators, + @_metadata_URI, + @_dao_URI ); } diff --git a/starknet/src/tests/setup/setup.cairo b/starknet/src/tests/setup/setup.cairo index 9f145478..4ff1cb0c 100644 --- a/starknet/src/tests/setup/setup.cairo +++ b/starknet/src/tests/setup/setup.cairo @@ -115,14 +115,19 @@ mod setup { voting_strategies: @Array, 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 } diff --git a/starknet/src/tests/test_space.cairo b/starknet/src/tests/test_space.cairo index 60e2a76e..be177ef8 100644 --- a/starknet/src/tests/test_space.cairo +++ b/starknet/src/tests/test_space.cairo @@ -89,8 +89,12 @@ mod tests { 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 @@ -138,6 +142,7 @@ mod tests { author.serialize(ref propose_calldata); vanilla_execution_strategy.serialize(ref propose_calldata); ArrayTrait::::new().serialize(ref propose_calldata); + ArrayTrait::::new().serialize(ref propose_calldata); // Create Proposal authenticator.authenticate(space.contract_address, PROPOSE_SELECTOR, propose_calldata); @@ -175,6 +180,7 @@ mod tests { address: vanilla_execution_strategy.address, params: new_payload }; execution_strategy.serialize(ref update_calldata); + ArrayTrait::::new().serialize(ref update_calldata); authenticator .authenticate(space.contract_address, UPDATE_PROPOSAL_SELECTOR, update_calldata); @@ -193,6 +199,7 @@ mod tests { user_voting_strategies .append(IndexedStrategy { index: 0_u8, params: ArrayTrait::::new() }); user_voting_strategies.serialize(ref vote_calldata); + ArrayTrait::::new().serialize(ref vote_calldata); // Vote on Proposal authenticator.authenticate(space.contract_address, VOTE_SELECTOR, vote_calldata); @@ -254,6 +261,7 @@ mod tests { author.serialize(ref propose_calldata); vanilla_execution_strategy.serialize(ref propose_calldata); ArrayTrait::::new().serialize(ref propose_calldata); + ArrayTrait::::new().serialize(ref propose_calldata); // Try to create Proposal authenticator.authenticate(space.contract_address, PROPOSE_SELECTOR, propose_calldata); @@ -292,6 +300,7 @@ mod tests { author.serialize(ref propose_calldata); vanilla_execution_strategy.serialize(ref propose_calldata); ArrayTrait::::new().serialize(ref propose_calldata); + ArrayTrait::::new().serialize(ref propose_calldata); // Create Proposal authenticator.authenticate(space.contract_address, PROPOSE_SELECTOR, propose_calldata); @@ -321,6 +330,7 @@ mod tests { user_voting_strategies .append(IndexedStrategy { index: 0_u8, params: ArrayTrait::::new() }); 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_upgrade.cairo b/starknet/src/tests/test_upgrade.cairo index 5697aa26..ccad2cbd 100644 --- a/starknet/src/tests/test_upgrade.cairo +++ b/starknet/src/tests/test_upgrade.cairo @@ -105,6 +105,7 @@ mod tests { UserAddress::Starknet(contract_address_const::<0x7676>()).serialize(ref propose_calldata); execution_strategy.serialize(ref propose_calldata); ArrayTrait::::new().serialize(ref propose_calldata); + ArrayTrait::::new().serialize(ref propose_calldata); let authenticator = IVanillaAuthenticatorDispatcher { contract_address: *config.authenticators.at(0)