From b1fb35bbc97c64f7a86540790e329eccb334a942 Mon Sep 17 00:00:00 2001 From: Moody Salem Date: Mon, 6 Jan 2025 10:44:26 -0500 Subject: [PATCH] add the function to make a syscall to l1 (#66) * add the function to make a syscall to l1 * add tests --- .codegpt/head | 1 + src/governor.cairo | 17 +++++++++++--- src/governor_test.cairo | 49 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 .codegpt/head diff --git a/.codegpt/head b/.codegpt/head new file mode 100644 index 0000000..0121b3a --- /dev/null +++ b/.codegpt/head @@ -0,0 +1 @@ +73df00a1-54a7-44b2-89fb-f7d2f68d3079 \ No newline at end of file diff --git a/src/governor.cairo b/src/governor.cairo index 06c36d3..aa46367 100644 --- a/src/governor.cairo +++ b/src/governor.cairo @@ -1,7 +1,7 @@ use governance::execution_state::{ExecutionState}; use governance::staker::{IStakerDispatcher}; use starknet::account::{Call}; -use starknet::{ClassHash, ContractAddress}; +use starknet::{ClassHash, ContractAddress, EthAddress}; #[derive(Copy, Drop, Serde, starknet::Store, PartialEq, Debug)] pub struct ProposalInfo { @@ -92,6 +92,9 @@ pub trait IGovernor { // Replaces the code at this address. This must be self-called via a proposal. fn upgrade(ref self: TContractState, class_hash: ClassHash); + // Sends a message to L1 via syscall + fn send_message_to_l1(self: @TContractState, to_address: EthAddress, payload: Span); + // Migrates to the latest version of storage layout, from the version of storage before v2.1.0 fn _migrate_old_config_storage(ref self: TContractState); } @@ -110,11 +113,11 @@ pub mod Governor { use starknet::storage_access::{Store, storage_base_address_from_felt252}; use starknet::{ AccountContract, get_block_timestamp, get_caller_address, get_contract_address, get_tx_info, - syscalls::{replace_class_syscall}, + syscalls::{replace_class_syscall, send_message_to_l1_syscall}, }; use super::{ Call, ClassHash, Config, ContractAddress, ExecutionState, IGovernor, IStakerDispatcher, - ProposalInfo, + ProposalInfo, EthAddress, }; @@ -459,6 +462,14 @@ pub mod Governor { replace_class_syscall(class_hash).unwrap(); } + fn send_message_to_l1( + self: @ContractState, to_address: EthAddress, payload: Span, + ) { + self.check_self_call(); + + send_message_to_l1_syscall(to_address.into(), payload).expect('SYSCALL_FAILED') + } + fn _migrate_old_config_storage(ref self: ContractState) { let old_config_storage_address = storage_base_address_from_felt252(selector!("config")); let old_config: Config = Store::read(0, old_config_storage_address).unwrap(); diff --git a/src/governor_test.cairo b/src/governor_test.cairo index af1fb5a..a20458c 100644 --- a/src/governor_test.cairo +++ b/src/governor_test.cairo @@ -1001,6 +1001,55 @@ fn test_upgrade_succeeds_self_call() { ); } +#[test] +#[should_panic(expected: ('SELF_CALL_ONLY', 'ENTRYPOINT_FAILED'))] +fn test_send_message_to_l1_fails_if_not_self_call() { + let (_staker, _token, governor, _config) = setup(); + governor.send_message_to_l1(123_felt252.try_into().unwrap(), array![1, 2, 3].span()); +} + + +#[test] +fn test_send_message_to_l1_succeeds_self_call() { + let (staker, token, governor, config) = setup(); + + token.approve(staker.contract_address, config.quorum.into()); + staker.stake(proposer()); + advance_time(config.voting_weight_smoothing_duration); + + let id = create_proposal_with_call( + governor, + token, + staker, + Call { + to: governor.contract_address, + selector: selector!("send_message_to_l1"), + calldata: array![0xabcd, 2, 0xdead, 0xbeef].span(), + }, + ); + + advance_time(config.voting_start_delay); + + set_contract_address(proposer()); + governor.vote(id, true); + + advance_time(config.voting_period + config.execution_delay); + + governor + .execute( + id, + array![ + Call { + to: governor.contract_address, + selector: selector!("send_message_to_l1"), + calldata: array![0xabcd, 2, 0xdead, 0xbeef].span(), + }, + ] + .span(), + ); +} + + #[test] #[should_panic(expected: ('SELF_CALL_ONLY', 'ENTRYPOINT_FAILED'))] fn test_reconfigure_fails_if_not_self_call() {