From 6c2f366bf9cfc50a21530cf547d2a3ec30bc8f1b Mon Sep 17 00:00:00 2001 From: Orlando Date: Tue, 22 Aug 2023 11:34:57 +0100 Subject: [PATCH] fix: eth relayer --- starknet/src/execution_strategies.cairo | 2 + .../execution_strategies/eth_relayer.cairo | 34 ++- starknet/src/tests/test_stark_sig_auth.cairo | 260 ++++++++++++++++++ 3 files changed, 285 insertions(+), 11 deletions(-) create mode 100644 starknet/src/tests/test_stark_sig_auth.cairo diff --git a/starknet/src/execution_strategies.cairo b/starknet/src/execution_strategies.cairo index b0973e0c..907558a8 100644 --- a/starknet/src/execution_strategies.cairo +++ b/starknet/src/execution_strategies.cairo @@ -1,3 +1,5 @@ mod vanilla; mod simple_quorum; + +mod eth_relayer; diff --git a/starknet/src/execution_strategies/eth_relayer.cairo b/starknet/src/execution_strategies/eth_relayer.cairo index ccf5344a..866e47e7 100644 --- a/starknet/src/execution_strategies/eth_relayer.cairo +++ b/starknet/src/execution_strategies/eth_relayer.cairo @@ -1,10 +1,17 @@ #[starknet::contract] mod EthRelayerExecutionStrategy { + use array::ArrayTrait; + use option::OptionTrait; + use traits::TryInto; + use serde::Serde; use starknet::syscalls::send_message_to_l1_syscall; use starknet::info::get_caller_address; use sx::interfaces::IExecutionStrategy; use sx::types::{Proposal}; + #[storage] + struct Storage {} + #[external(v0)] impl EthRelayerExecutionStrategy of IExecutionStrategy { fn execute( @@ -18,19 +25,24 @@ mod EthRelayerExecutionStrategy { let space = get_caller_address(); // Decode payload - let l1_destination = payload[0]; - // keccak hash of the proposal execution payload - let execution_hash = u256 { low: payload[2], high: payload[1] }; + let mut payload = payload; + // L1 destination contract address + let l1_destination = payload.pop_front().unwrap(); + // keccak hash of the L1 proposal execution payload + let execution_hash = u256 { + low: payload.pop_front().unwrap().try_into().unwrap(), + high: payload.pop_front().unwrap().try_into().unwrap() + }; - let mut message_payload = array![]; - space.serialize(mut message_payload); - proposal.serialize(mut message_payload); - votes_for.serialize(mut message_payload); - votes_against.serialize(mut message_payload); - votes_abstain.serialize(mut message_payload); - execution_hash.serialize(mut message_payload); + let mut l1_payload = array![]; + space.serialize(ref l1_payload); + proposal.serialize(ref l1_payload); + votes_for.serialize(ref l1_payload); + votes_against.serialize(ref l1_payload); + votes_abstain.serialize(ref l1_payload); + execution_hash.serialize(ref l1_payload); - send_message_to_l1_syscall(l1_destination, message_payload); + send_message_to_l1_syscall(l1_destination, l1_payload.span()); } } } diff --git a/starknet/src/tests/test_stark_sig_auth.cairo b/starknet/src/tests/test_stark_sig_auth.cairo new file mode 100644 index 00000000..69c66afe --- /dev/null +++ b/starknet/src/tests/test_stark_sig_auth.cairo @@ -0,0 +1,260 @@ +#[cfg(test)] +mod tests { + use array::ArrayTrait; + use starknet::{ + ContractAddress, syscalls::deploy_syscall, testing, contract_address_const, info + }; + use traits::{Into, TryInto}; + use result::ResultTrait; + use option::OptionTrait; + use integer::u256_from_felt252; + use clone::Clone; + use serde::{Serde}; + use sx::space::space::{Space, ISpaceDispatcher, ISpaceDispatcherTrait}; + use sx::authenticators::stark_sig::{ + StarkSigAuthenticator, IStarkSigAuthenticatorDispatcher, + IStarkSigAuthenticatorDispatcherTrait + }; + use sx::execution_strategies::vanilla::VanillaExecutionStrategy; + use sx::voting_strategies::vanilla::VanillaVotingStrategy; + use sx::proposal_validation_strategies::vanilla::VanillaProposalValidationStrategy; + use sx::tests::setup::setup::setup::{setup, deploy}; + use sx::types::{ + UserAddress, Strategy, IndexedStrategy, Choice, FinalizationStatus, Proposal, + UpdateSettingsCalldataImpl, UpdateSettingsCalldata + }; + use sx::tests::utils::strategy_trait::{StrategyImpl}; + + fn setup_stark_sig_auth( + space: ISpaceDispatcher, owner: ContractAddress + ) -> IStarkSigAuthenticatorDispatcher { + // Deploy Stark Sig Authenticator and whitelist in Space + let (stark_sig_authenticator_address, _) = deploy_syscall( + StarkSigAuthenticator::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + ) + .unwrap(); + + let authenticator = IStarkSigAuthenticatorDispatcher { + contract_address: stark_sig_authenticator_address, + }; + let mut updateSettingsCalldata: UpdateSettingsCalldata = + UpdateSettingsCalldataImpl::default(); + updateSettingsCalldata.authenticators_to_add = array![stark_sig_authenticator_address]; + testing::set_contract_address(owner); + space.update_settings(updateSettingsCalldata); + + authenticator + } + + #[test] + #[available_gas(10000000000)] + fn test_propose_update_vote() { + let config = setup(); + let (factory, space) = deploy(@config); + let authenticator = setup_stark_sig_auth(space, config.owner); + + let quorum = u256_from_felt252(1); + let mut constructor_calldata = array![]; + quorum.serialize(ref constructor_calldata); + + let (vanilla_execution_strategy_address, _) = deploy_syscall( + VanillaExecutionStrategy::TEST_CLASS_HASH.try_into().unwrap(), + 0, + constructor_calldata.span(), + false + ) + .unwrap(); + let vanilla_execution_strategy = StrategyImpl::from_address( + vanilla_execution_strategy_address + ); + let author = contract_address_const::<0x5678>(); + + // Create Proposal + testing::set_contract_address(author); + authenticator + .authenticate_propose( + space.contract_address, author, vanilla_execution_strategy, array![], array![] + ); + + 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 = array![1]; + let new_execution_strategy = Strategy { + address: vanilla_execution_strategy_address, params: new_payload.clone() + }; + + testing::set_contract_address(author); + authenticator + .authenticate_update_proposal( + space.contract_address, author, proposal_id, new_execution_strategy, array![] + ); + + // Increasing block timestamp by 1 to pass voting delay + testing::set_block_timestamp(1_u64); + + let voter = contract_address_const::<0x8765>(); + let choice = Choice::For(()); + 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, array![] + ); + + testing::set_block_timestamp(2_u64); + + // Execute Proposal + space.execute(u256_from_felt252(1), new_payload); + } + + #[test] + #[available_gas(10000000000)] + #[should_panic(expected: ('Invalid Caller', 'ENTRYPOINT_FAILED'))] + fn test_propose_invalid_caller() { + let config = setup(); + let (factory, space) = deploy(@config); + let authenticator = setup_stark_sig_auth(space, config.owner); + + let quorum = u256_from_felt252(1); + let mut constructor_calldata = array![]; + quorum.serialize(ref constructor_calldata); + + let (vanilla_execution_strategy_address, _) = deploy_syscall( + VanillaExecutionStrategy::TEST_CLASS_HASH.try_into().unwrap(), + 0, + constructor_calldata.span(), + false + ) + .unwrap(); + let vanilla_execution_strategy = StrategyImpl::from_address( + vanilla_execution_strategy_address + ); + let author = contract_address_const::<0x5678>(); + + // Create Proposal not from author account + testing::set_contract_address(config.owner); + authenticator + .authenticate_propose( + space.contract_address, author, vanilla_execution_strategy, array![], array![] + ); + } + + #[test] + #[available_gas(10000000000)] + #[should_panic(expected: ('Invalid Caller', 'ENTRYPOINT_FAILED'))] + fn test_update_proposal_invalid_caller() { + let config = setup(); + let (factory, space) = deploy(@config); + let authenticator = setup_stark_sig_auth(space, config.owner); + + let quorum = u256_from_felt252(1); + let mut constructor_calldata = array![]; + quorum.serialize(ref constructor_calldata); + + let (vanilla_execution_strategy_address, _) = deploy_syscall( + VanillaExecutionStrategy::TEST_CLASS_HASH.try_into().unwrap(), + 0, + constructor_calldata.span(), + false + ) + .unwrap(); + let vanilla_execution_strategy = StrategyImpl::from_address( + vanilla_execution_strategy_address + ); + let author = contract_address_const::<0x5678>(); + + // Create Proposal + testing::set_contract_address(author); + authenticator + .authenticate_propose( + space.contract_address, author, vanilla_execution_strategy, array![], array![] + ); + + 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 = array![1]; + let new_execution_strategy = Strategy { + address: vanilla_execution_strategy_address, params: new_payload.clone() + }; + + // Update proposal not from author account + testing::set_contract_address(config.owner); + authenticator + .authenticate_update_proposal( + space.contract_address, author, proposal_id, new_execution_strategy, array![] + ); + } + + #[test] + #[available_gas(10000000000)] + #[should_panic(expected: ('Invalid Caller', 'ENTRYPOINT_FAILED'))] + fn test_vote_invalid_caller() { + let config = setup(); + let (factory, space) = deploy(@config); + let authenticator = setup_stark_sig_auth(space, config.owner); + + let quorum = u256_from_felt252(1); + let mut constructor_calldata = array![]; + quorum.serialize(ref constructor_calldata); + + let (vanilla_execution_strategy_address, _) = deploy_syscall( + VanillaExecutionStrategy::TEST_CLASS_HASH.try_into().unwrap(), + 0, + constructor_calldata.span(), + false + ) + .unwrap(); + let vanilla_execution_strategy = StrategyImpl::from_address( + vanilla_execution_strategy_address + ); + let author = contract_address_const::<0x5678>(); + + // Create Proposal + testing::set_contract_address(author); + authenticator + .authenticate_propose( + space.contract_address, author, vanilla_execution_strategy, array![], array![] + ); + + 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 = array![1]; + let new_execution_strategy = Strategy { + address: vanilla_execution_strategy_address, params: new_payload.clone() + }; + + testing::set_contract_address(author); + authenticator + .authenticate_update_proposal( + space.contract_address, author, proposal_id, new_execution_strategy, array![] + ); + + // Increasing block timestamp by 1 to pass voting delay + testing::set_block_timestamp(1_u64); + + let voter = contract_address_const::<0x8765>(); + let choice = Choice::For(()); + 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, array![] + ); + } +}