diff --git a/src/airdrop_claim_check.cairo b/src/airdrop_claim_check.cairo index 4e02c06..29ee8a5 100644 --- a/src/airdrop_claim_check.cairo +++ b/src/airdrop_claim_check.cairo @@ -1,5 +1,5 @@ -use starknet::{ContractAddress}; use governance::airdrop::{IAirdropDispatcher}; +use starknet::{ContractAddress}; #[derive(Serde, Copy, Drop)] struct CheckParams { @@ -21,11 +21,11 @@ trait IAirdropClaimCheck { #[starknet::contract] mod AirdropClaimCheck { - use super::{IAirdropClaimCheck, IAirdropDispatcher, CheckParams, CheckResult}; - use governance::airdrop::{IAirdropDispatcherTrait}; - use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; use core::array::{SpanTrait}; use core::option::{OptionTrait}; + use governance::airdrop::{IAirdropDispatcherTrait}; + use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; + use super::{IAirdropClaimCheck, IAirdropDispatcher, CheckParams, CheckResult}; #[storage] struct Storage {} diff --git a/src/governor.cairo b/src/governor.cairo index 7ace3f2..b25c664 100644 --- a/src/governor.cairo +++ b/src/governor.cairo @@ -1,4 +1,5 @@ use core::array::{Array}; +use core::byte_array::{ByteArray}; use core::integer::{u128_safe_divmod}; use core::option::{Option, OptionTrait}; use core::traits::{Into, TryInto}; @@ -49,6 +50,9 @@ pub trait IGovernor { // Execute the given proposal. fn execute(ref self: TContractState, call: Call) -> Span; + // Attaches the given text to the proposal. Simply emits an event containing the proposal description. + fn describe(ref self: TContractState, id: felt252, description: ByteArray); + // Get the configuration for this governor contract. fn get_staker(self: @TContractState) -> IStakerDispatcher; @@ -68,7 +72,7 @@ pub mod Governor { use starknet::{get_block_timestamp, get_caller_address, contract_address_const}; use super::{ IStakerDispatcher, ContractAddress, Array, IGovernor, Config, ProposalInfo, Call, - ExecutionState + ExecutionState, ByteArray }; @@ -79,6 +83,12 @@ pub mod Governor { pub call: Call, } + #[derive(starknet::Event, Drop, Debug, PartialEq)] + pub struct Described { + pub id: felt252, + pub description: ByteArray, + } + #[derive(starknet::Event, Drop)] pub struct Voted { pub id: felt252, @@ -101,6 +111,7 @@ pub mod Governor { #[event] enum Event { Proposed: Proposed, + Described: Described, Voted: Voted, Canceled: Canceled, Executed: Executed, @@ -183,6 +194,15 @@ pub mod Governor { id } + fn describe(ref self: ContractState, id: felt252, description: ByteArray) { + let proposal = self.proposals.read(id); + assert(proposal.proposer.is_non_zero(), 'DOES_NOT_EXIST'); + assert(proposal.proposer == get_caller_address(), 'NOT_PROPOSER'); + assert(proposal.execution_state.executed.is_zero(), 'ALREADY_EXECUTED'); + assert(proposal.execution_state.canceled.is_zero(), 'PROPOSAL_CANCELED'); + self.emit(Described { id, description }); + } + fn vote(ref self: ContractState, id: felt252, yea: bool) { let mut proposal = self.proposals.read(id); diff --git a/src/governor_test.cairo b/src/governor_test.cairo index 3de0d35..806e231 100644 --- a/src/governor_test.cairo +++ b/src/governor_test.cairo @@ -21,7 +21,8 @@ use governance::timelock_test::{single_call, transfer_call, deploy as deploy_tim use starknet::account::{Call}; use starknet::{ get_contract_address, syscalls::deploy_syscall, ClassHash, contract_address_const, - ContractAddress, get_block_timestamp, testing::{set_block_timestamp, set_contract_address} + ContractAddress, get_block_timestamp, + testing::{set_block_timestamp, set_contract_address, pop_log} }; @@ -250,6 +251,52 @@ fn test_anyone_can_vote() { assert_eq!(proposal.nay, 0); } +#[test] +fn test_describe_proposal_successful() { + let (staker, token, governor, _config) = setup(); + let id = create_proposal(governor, token, staker); + + set_contract_address(proposer()); + governor + .describe( + id, + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + ); + pop_log::(governor.contract_address).unwrap(); + assert_eq!( + pop_log::(governor.contract_address).unwrap(), + Governor::Described { + id, + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + } + ); +} + +#[test] +#[should_panic(expected: ('NOT_PROPOSER', 'ENTRYPOINT_FAILED'))] +fn test_describe_proposal_fails_for_unknown_proposal() { + let (staker, token, governor, _config) = setup(); + let id = create_proposal(governor, token, staker); + governor.describe(id, "I am not the proposer"); +} + +#[test] +#[should_panic(expected: ('PROPOSAL_CANCELED', 'ENTRYPOINT_FAILED'))] +fn test_describe_proposal_fails_if_canceled() { + let (staker, token, governor, _config) = setup(); + let id = create_proposal(governor, token, staker); + set_contract_address(proposer()); + governor.cancel(id); + governor.describe(id, "This proposal is canceled"); +} + +#[test] +#[should_panic(expected: ('DOES_NOT_EXIST', 'ENTRYPOINT_FAILED'))] +fn test_describe_proposal_fails_if_not_proposer() { + let (_staker, _token, governor, _config) = setup(); + governor.describe(123, "This proposal does not exist"); +} + #[test] fn test_vote_no_staking_after_period_starts() { let (staker, token, governor, config) = setup(); diff --git a/src/lib.cairo b/src/lib.cairo index 2ee83c8..33a2ebd 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,5 +1,5 @@ -mod airdrop_claim_check; pub mod airdrop; +mod airdrop_claim_check; #[cfg(test)] pub(crate) mod airdrop_test;