From 99ad0192a6c42fe973430a0ebb1c6e90287fb83b Mon Sep 17 00:00:00 2001 From: Moody Salem Date: Tue, 23 Jan 2024 04:08:36 -0500 Subject: [PATCH] 2.5.0 latest edition --- .tool-versions | 2 +- Scarb.toml | 6 +-- src/airdrop.cairo | 21 +++++------ src/airdrop_test.cairo | 8 ++-- src/call_trait.cairo | 14 +++---- src/call_trait_test.cairo | 25 ++++++------- src/factory.cairo | 38 +++++++++---------- src/factory_test.cairo | 4 +- src/governance_token.cairo | 50 ++++++++++++------------- src/governance_token_test.cairo | 47 ++++++++++++----------- src/governor.cairo | 66 ++++++++++++++++----------------- src/governor_test.cairo | 34 +++++++---------- src/interfaces.cairo | 1 - src/interfaces/erc20.cairo | 2 +- src/lib.cairo | 34 +++++++++-------- src/test_utils.cairo | 31 +++++++--------- src/timelock.cairo | 48 ++++++++++++------------ src/timelock_test.cairo | 18 ++++----- src/utils/timestamps.cairo | 6 +-- 19 files changed, 221 insertions(+), 234 deletions(-) delete mode 100644 src/interfaces.cairo diff --git a/.tool-versions b/.tool-versions index b100888..9b86cbf 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.4.3 +scarb 2.5.0 diff --git a/Scarb.toml b/Scarb.toml index ec20136..7fdcf62 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -3,13 +3,13 @@ name = "governance" version = "0.1.0" description = "Contracts for governance of Starknet-native protocols" homepage = "https://ekubo.org" -cairo-version = "2.4.3" -edition = '2023_10' +cairo-version = "2.5.0" +edition = '2023_11' [dependencies] -starknet = "=2.4.3" +starknet = "=2.5.0" [[target.starknet-contract]] allowed-libfuncs-list.name = "audited" diff --git a/src/airdrop.cairo b/src/airdrop.cairo index 43d0682..f7c3a2c 100644 --- a/src/airdrop.cairo +++ b/src/airdrop.cairo @@ -3,13 +3,13 @@ use governance::interfaces::erc20::{IERC20Dispatcher}; use starknet::{ContractAddress}; #[derive(Copy, Drop, Serde, Hash, PartialEq)] -struct Claim { - claimee: ContractAddress, - amount: u128, +pub struct Claim { + pub claimee: ContractAddress, + pub amount: u128, } #[starknet::interface] -trait IAirdrop { +pub trait IAirdrop { // Claims the given allotment of tokens fn claim(ref self: TStorage, claim: Claim, proof: Array); @@ -24,21 +24,20 @@ trait IAirdrop { } #[starknet::contract] -mod Airdrop { +pub mod Airdrop { use core::array::{ArrayTrait, SpanTrait}; use core::hash::{LegacyHash}; use governance::interfaces::erc20::{IERC20DispatcherTrait}; - use starknet::{ContractAddressIntoFelt252}; use super::{IAirdrop, ContractAddress, Claim, IERC20Dispatcher}; - fn lt, +Into>(lhs: @X, rhs: @X) -> bool { + pub(crate) fn lt, +Into>(lhs: @X, rhs: @X) -> bool { let a: u256 = (*lhs).into(); let b: u256 = (*rhs).into(); return a < b; } // Compute the pedersen root of a merkle tree by combining the current node with each sibling up the tree - fn compute_pedersen_root(current: felt252, mut proof: Span) -> felt252 { + pub(crate) fn compute_pedersen_root(current: felt252, mut proof: Span) -> felt252 { match proof.pop_front() { Option::Some(proof_element) => { compute_pedersen_root( @@ -62,8 +61,8 @@ mod Airdrop { } #[derive(Drop, starknet::Event)] - struct Claimed { - claim: Claim + pub(crate) struct Claimed { + pub claim: Claim } #[derive(starknet::Event, Drop)] @@ -78,7 +77,7 @@ mod Airdrop { self.token.write(token); } - #[external(v0)] + #[abi(embed_v0)] impl AirdropImpl of IAirdrop { fn claim(ref self: ContractState, claim: Claim, proof: Array::) { let leaf = LegacyHash::hash(0, claim); diff --git a/src/airdrop_test.cairo b/src/airdrop_test.cairo index 8e51368..5f48608 100644 --- a/src/airdrop_test.cairo +++ b/src/airdrop_test.cairo @@ -13,10 +13,10 @@ use governance::governance_token::{ }; use governance::governance_token_test::{deploy as deploy_token}; use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; -use starknet::class_hash::Felt252TryIntoClassHash; use starknet::testing::{pop_log}; use starknet::{ - get_contract_address, deploy_syscall, ClassHash, contract_address_const, ContractAddress + get_contract_address, syscalls::{deploy_syscall}, ClassHash, contract_address_const, + ContractAddress }; fn deploy(token: ContractAddress, root: felt252) -> IAirdropDispatcher { @@ -99,8 +99,8 @@ fn test_claim_single_recipient() { let log = pop_log::(airdrop.contract_address).unwrap(); assert(log.claim == claim, 'claim'); - pop_log::(token.contract_address); - pop_log::(token.contract_address); + pop_log::(token.contract_address).unwrap(); + pop_log::(token.contract_address).unwrap(); let log = pop_log::(token.contract_address).unwrap(); assert(log.from == airdrop.contract_address, 'from'); assert(log.to == claim.claimee, 'to'); diff --git a/src/call_trait.cairo b/src/call_trait.cairo index 852e221..65cfb25 100644 --- a/src/call_trait.cairo +++ b/src/call_trait.cairo @@ -1,16 +1,16 @@ use core::array::{ArrayTrait, SpanTrait}; -use core::hash::{LegacyHash, HashStateTrait, Hash}; +use core::hash::{LegacyHash, HashStateTrait, HashStateExTrait, Hash}; use core::result::{ResultTrait}; use core::traits::{Into}; use starknet::account::{Call}; -use starknet::{ContractAddress, ContractAddressIntoFelt252}; +use starknet::{ContractAddress}; use starknet::{SyscallResult, syscalls::call_contract_syscall}; -impl HashCall, +Drop, +Copy> of Hash<@Call, S> { +pub impl HashCall, +Drop, +Copy> of Hash<@Call, S> { fn update_state(state: S, value: @Call) -> S { - let mut s = state.update((*value.to).into()).update(*value.selector); + let mut s = state.update_with((*value.to)).update_with(*value.selector); - let mut data_span = value.calldata.span(); + let mut data_span: Span = *value.calldata; loop { match data_span.pop_front() { Option::Some(word) => { s = s.update(*word); }, @@ -23,9 +23,9 @@ impl HashCall, +Drop, +Copy> of Hash<@Call, S> { } #[generate_trait] -impl CallTraitImpl of CallTrait { +pub impl CallTraitImpl of CallTrait { fn execute(self: @Call) -> Span { - let result = call_contract_syscall(*self.to, *self.selector, self.calldata.span()); + let result = call_contract_syscall(*self.to, *self.selector, *self.calldata); if (result.is_err()) { panic(result.unwrap_err()); diff --git a/src/call_trait_test.cairo b/src/call_trait_test.cairo index ebcd117..2f4a710 100644 --- a/src/call_trait_test.cairo +++ b/src/call_trait_test.cairo @@ -8,7 +8,7 @@ use starknet::{contract_address_const, account::{Call}}; #[test] #[available_gas(300000000)] fn test_hash_empty() { - let call = Call { to: contract_address_const::<0>(), selector: 0, calldata: ArrayTrait::new() }; + let call = Call { to: contract_address_const::<0>(), selector: 0, calldata: array![].span() }; assert( LegacyHash::hash( 0, @call @@ -20,7 +20,7 @@ fn test_hash_empty() { #[test] #[available_gas(300000000)] fn test_hash_address_one() { - let call = Call { to: contract_address_const::<1>(), selector: 0, calldata: ArrayTrait::new() }; + let call = Call { to: contract_address_const::<1>(), selector: 0, calldata: array![].span() }; assert( LegacyHash::hash( 0, @call @@ -32,7 +32,7 @@ fn test_hash_address_one() { #[test] #[available_gas(300000000)] fn test_hash_address_entry_point_one() { - let call = Call { to: contract_address_const::<0>(), selector: 1, calldata: ArrayTrait::new() }; + let call = Call { to: contract_address_const::<0>(), selector: 1, calldata: array![].span() }; assert( LegacyHash::hash( 0, @call @@ -44,7 +44,7 @@ fn test_hash_address_entry_point_one() { #[test] #[available_gas(300000000)] fn test_hash_address_data_one() { - let call = Call { to: contract_address_const::<0>(), selector: 0, calldata: array![1] }; + let call = Call { to: contract_address_const::<0>(), selector: 0, calldata: array![1].span() }; assert( LegacyHash::hash( @@ -57,7 +57,9 @@ fn test_hash_address_data_one() { #[test] #[available_gas(300000000)] fn test_hash_address_data_one_two() { - let call = Call { to: contract_address_const::<0>(), selector: 0, calldata: array![1, 2] }; + let call = Call { + to: contract_address_const::<0>(), selector: 0, calldata: array![1, 2].span() + }; assert( LegacyHash::hash( @@ -71,8 +73,7 @@ fn test_hash_address_data_one_two() { #[available_gas(300000000)] #[should_panic(expected: ('CONTRACT_NOT_DEPLOYED',))] fn test_execute_contract_not_deployed() { - let mut calldata: Array = ArrayTrait::new(); - let call = Call { to: contract_address_const::<0>(), selector: 0, calldata: calldata }; + let call = Call { to: contract_address_const::<0>(), selector: 0, calldata: array![].span() }; call.execute(); } @@ -83,8 +84,7 @@ fn test_execute_contract_not_deployed() { fn test_execute_invalid_entry_point() { let (token, _) = deploy_token('TIMELOCK', 'TL', 1); - let mut calldata: Array = ArrayTrait::new(); - let call = Call { to: token.contract_address, selector: 0, calldata: calldata }; + let call = Call { to: token.contract_address, selector: 0, calldata: array![].span() }; call.execute(); } @@ -96,12 +96,11 @@ fn test_execute_invalid_entry_point() { fn test_execute_invalid_call_data_too_short() { let (token, _) = deploy_token('TIMELOCK', 'TL', 1); - let mut calldata: Array = ArrayTrait::new(); let call = Call { to: token.contract_address, // transfer selector: 0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e, - calldata: calldata + calldata: array![].span() }; call.execute(); @@ -113,14 +112,14 @@ fn test_execute_invalid_call_data_too_short() { fn test_execute_valid_call_data() { let (token, _) = deploy_token('TIMELOCK', 'TL', 1); - let mut calldata: Array = ArrayTrait::new(); + let mut calldata: Array = array![]; Serde::serialize(@(contract_address_const::<1>(), 1_u256), ref calldata); let call = Call { to: token.contract_address, // transfer selector: 0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e, - calldata: calldata + calldata: calldata.span() }; call.execute(); diff --git a/src/factory.cairo b/src/factory.cairo index 7ab3d54..6a6501f 100644 --- a/src/factory.cairo +++ b/src/factory.cairo @@ -6,40 +6,40 @@ use governance::timelock::{ITimelockDispatcher, TimelockConfig}; use starknet::{ContractAddress}; #[derive(Copy, Drop, Serde)] -struct AirdropConfig { - root: felt252, - total: u128, +pub struct AirdropConfig { + pub root: felt252, + pub total: u128, } #[derive(Copy, Drop, Serde)] -struct DeploymentParameters { - name: felt252, - symbol: felt252, - total_supply: u128, - governor_config: GovernorConfig, - timelock_config: TimelockConfig, - airdrop_config: Option, +pub struct DeploymentParameters { + pub name: felt252, + pub symbol: felt252, + pub total_supply: u128, + pub governor_config: GovernorConfig, + pub timelock_config: TimelockConfig, + pub airdrop_config: Option, } #[derive(Copy, Drop, Serde)] -struct DeploymentResult { - token: IGovernanceTokenDispatcher, - governor: IGovernorDispatcher, - timelock: ITimelockDispatcher, - airdrop: Option, +pub struct DeploymentResult { + pub token: IGovernanceTokenDispatcher, + pub governor: IGovernorDispatcher, + pub timelock: ITimelockDispatcher, + pub airdrop: Option, } // This contract makes it easy to deploy a set of governance contracts from a block explorer just by specifying parameters #[starknet::interface] -trait IFactory { +pub trait IFactory { fn deploy(self: @TContractState, params: DeploymentParameters) -> DeploymentResult; } #[starknet::contract] -mod Factory { +pub mod Factory { use core::result::{ResultTrait}; use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; - use starknet::{ClassHash, deploy_syscall, get_caller_address, get_contract_address}; + use starknet::{ClassHash, syscalls::{deploy_syscall}, get_caller_address, get_contract_address}; use super::{ IFactory, DeploymentParameters, DeploymentResult, ContractAddress, IGovernanceTokenDispatcher, IAirdropDispatcher, IGovernorDispatcher, ITimelockDispatcher @@ -67,7 +67,7 @@ mod Factory { self.timelock.write(timelock); } - #[external(v0)] + #[abi(embed_v0)] impl FactoryImpl of IFactory { fn deploy(self: @ContractState, params: DeploymentParameters) -> DeploymentResult { let mut token_constructor_args: Array = ArrayTrait::new(); diff --git a/src/factory_test.cairo b/src/factory_test.cairo index 1566df0..d5bd57e 100644 --- a/src/factory_test.cairo +++ b/src/factory_test.cairo @@ -15,10 +15,10 @@ use governance::governor::{Governor}; use governance::governor::{IGovernorDispatcherTrait}; use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; use governance::timelock::{Timelock, ITimelockDispatcherTrait, TimelockConfig}; -use starknet::class_hash::{Felt252TryIntoClassHash}; use starknet::testing::{set_contract_address, set_block_timestamp, pop_log}; use starknet::{ - get_contract_address, deploy_syscall, ClassHash, contract_address_const, ContractAddress, + get_contract_address, syscalls::deploy_syscall, ClassHash, contract_address_const, + ContractAddress, }; fn deploy() -> IFactoryDispatcher { diff --git a/src/governance_token.cairo b/src/governance_token.cairo index 7e9497d..4f4f34f 100644 --- a/src/governance_token.cairo +++ b/src/governance_token.cairo @@ -1,7 +1,7 @@ use starknet::{ContractAddress}; #[starknet::interface] -trait IGovernanceToken { +pub trait IGovernanceToken { // Delegate tokens from the caller to the given delegate address fn delegate(ref self: TStorage, to: ContractAddress); @@ -26,24 +26,23 @@ trait IGovernanceToken { } #[starknet::contract] -mod GovernanceToken { - use core::integer::{u256_safe_divmod, u256_as_non_zero}; +pub mod GovernanceToken { use core::num::traits::zero::{Zero}; use core::option::{OptionTrait}; use core::traits::{Into, TryInto}; use governance::interfaces::erc20::{IERC20}; - use starknet::{get_caller_address, get_block_timestamp, StorePacking}; + use starknet::{get_caller_address, get_block_timestamp, storage_access::{StorePacking}}; use super::{IGovernanceToken, ContractAddress}; #[derive(Copy, Drop, PartialEq)] - struct DelegatedSnapshot { - timestamp: u64, - delegated_cumulative: u256, + pub struct DelegatedSnapshot { + pub timestamp: u64, + pub delegated_cumulative: u256, } const TWO_POW_64: u128 = 0x10000000000000000_u128; - impl DelegatedSnapshotStorePacking of StorePacking { + pub(crate) impl DelegatedSnapshotStorePacking of StorePacking { fn pack(value: DelegatedSnapshot) -> felt252 { (value.delegated_cumulative + u256 { high: value.timestamp.into() * TWO_POW_64, low: 0 }) @@ -51,9 +50,9 @@ mod GovernanceToken { .unwrap() } fn unpack(value: felt252) -> DelegatedSnapshot { - let (timestamp, delegated_cumulative, _) = u256_safe_divmod( - value.into(), u256_as_non_zero(u256 { low: 0, high: TWO_POW_64 }) - ); + let (timestamp, delegated_cumulative) = DivRem::< + u256 + >::div_rem(value.into(), u256 { low: 0, high: TWO_POW_64 }.into().try_into().unwrap()); DelegatedSnapshot { timestamp: timestamp.low.try_into().unwrap(), delegated_cumulative } } } @@ -88,23 +87,23 @@ mod GovernanceToken { } #[derive(starknet::Event, Drop)] - struct Transfer { - from: ContractAddress, - to: ContractAddress, - value: u256, + pub struct Transfer { + pub from: ContractAddress, + pub to: ContractAddress, + pub value: u256, } #[derive(starknet::Event, Drop)] - struct Approval { - owner: ContractAddress, - spender: ContractAddress, - value: u256 + pub struct Approval { + pub owner: ContractAddress, + pub spender: ContractAddress, + pub value: u256 } #[derive(starknet::Event, Drop)] - struct Delegate { - from: ContractAddress, - to: ContractAddress, + pub struct Delegate { + pub from: ContractAddress, + pub to: ContractAddress, } #[derive(starknet::Event, Drop)] @@ -181,8 +180,7 @@ mod GovernanceToken { .unwrap() }; - snapshot.delegated_cumulative - + ((timestamp - snapshot.timestamp).into() * delegated_amount).into() + snapshot.delegated_cumulative + (difference.into() * delegated_amount).into() }; } let mid = (min_index + max_index_exclusive) / 2; @@ -220,7 +218,7 @@ mod GovernanceToken { } } - #[external(v0)] + #[abi(embed_v0)] impl ERC20Impl of IERC20 { fn name(self: @ContractState) -> felt252 { self.name.read() @@ -314,7 +312,7 @@ mod GovernanceToken { } } - #[external(v0)] + #[abi(embed_v0)] impl TokenImpl of IGovernanceToken { fn delegate(ref self: ContractState, to: ContractAddress) { let caller = get_caller_address(); diff --git a/src/governance_token_test.cairo b/src/governance_token_test.cairo index bd25a07..5821473 100644 --- a/src/governance_token_test.cairo +++ b/src/governance_token_test.cairo @@ -9,13 +9,13 @@ use governance::governance_token::{ GovernanceToken::{DelegatedSnapshotStorePacking, DelegatedSnapshot}, }; use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; -use starknet::class_hash::Felt252TryIntoClassHash; use starknet::testing::{set_contract_address, set_block_timestamp, pop_log}; use starknet::{ - get_contract_address, deploy_syscall, ClassHash, contract_address_const, ContractAddress, + get_contract_address, syscalls::deploy_syscall, ClassHash, contract_address_const, + ContractAddress, }; -fn deploy( +pub fn deploy( name: felt252, symbol: felt252, supply: u128 ) -> (IGovernanceTokenDispatcher, IERC20Dispatcher) { let mut constructor_args: Array = ArrayTrait::new(); @@ -129,14 +129,14 @@ fn test_deploy_constructor() { #[test] #[available_gas(3000000)] fn test_transfer_entire_balance() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (_, erc20) = deploy('Governor Token', 'GT', 12345); let recipient = contract_address_const::<12345>(); erc20.transfer(recipient, 12345); assert(erc20.balance_of(get_contract_address()) == 0, 'zero after'); assert(erc20.balance_of(recipient) == 12345, '12345 after'); - pop_log::(erc20.contract_address); + pop_log::(erc20.contract_address).unwrap(); let log = pop_log::(erc20.contract_address).unwrap(); assert(log.from == get_contract_address(), 'from'); assert(log.to == recipient, 'to'); @@ -155,7 +155,7 @@ fn test_transfer_lt_total_balance() { assert(erc20.balance_of(recipient) == 45, '45 transferred'); assert(erc20.balanceOf(recipient) == 45, '45 transferred'); - pop_log::(erc20.contract_address); + pop_log::(erc20.contract_address).unwrap(); let log = pop_log::(erc20.contract_address).unwrap(); assert(log.from == get_contract_address(), 'from'); assert(log.to == recipient, 'to'); @@ -176,7 +176,7 @@ fn test_transfer_gt_total_balance() { #[available_gas(3000000)] #[should_panic(expected: ('TRANSFER_AMOUNT_OVERFLOW', 'ENTRYPOINT_FAILED'))] fn test_transfer_overflow() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (_, erc20) = deploy('Governor Token', 'GT', 12345); let recipient = contract_address_const::<12345>(); erc20.transfer(recipient, u256 { high: 1, low: 0 }); @@ -186,7 +186,7 @@ fn test_transfer_overflow() { #[available_gas(3000000)] #[should_panic(expected: ('ORDER', 'ENTRYPOINT_FAILED'))] fn test_get_average_delegated_order_same() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); token.get_average_delegated(contract_address_const::<12345>(), 0, 0); } @@ -195,7 +195,7 @@ fn test_get_average_delegated_order_same() { #[available_gas(3000000)] #[should_panic(expected: ('ORDER', 'ENTRYPOINT_FAILED'))] fn test_get_average_delegated_order_backwards() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); token.get_average_delegated(contract_address_const::<12345>(), 1, 0); } @@ -204,7 +204,7 @@ fn test_get_average_delegated_order_backwards() { #[available_gas(3000000)] #[should_panic(expected: ('FUTURE', 'ENTRYPOINT_FAILED'))] fn test_get_average_delegated_future() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); token.get_average_delegated(contract_address_const::<12345>(), 0, 1); } @@ -213,7 +213,7 @@ fn test_get_average_delegated_future() { #[available_gas(3000000)] #[should_panic(expected: ('FUTURE', 'ENTRYPOINT_FAILED'))] fn test_get_average_delegated_future_non_zero() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); set_block_timestamp(5); @@ -223,7 +223,7 @@ fn test_get_average_delegated_future_non_zero() { #[test] #[available_gas(3000000)] fn test_approve_sets_allowance() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (_, erc20) = deploy('Governor Token', 'GT', 12345); let spender = contract_address_const::<12345>(); erc20.approve(spender, 5151); @@ -233,7 +233,7 @@ fn test_approve_sets_allowance() { #[test] #[available_gas(3000000)] fn test_approve_allows_transfer_from() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (_, erc20) = deploy('Governor Token', 'GT', 12345); let owner = get_contract_address(); let spender = contract_address_const::<12345>(); @@ -251,7 +251,7 @@ fn test_approve_allows_transfer_from() { #[available_gas(3000000)] #[should_panic(expected: ('TRANSFER_FROM_ALLOWANCE', 'ENTRYPOINT_FAILED'))] fn test_transfer_from_insufficient_allowance() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (_, erc20) = deploy('Governor Token', 'GT', 12345); let owner = get_contract_address(); let spender = contract_address_const::<12345>(); @@ -265,17 +265,16 @@ fn test_transfer_from_insufficient_allowance() { #[available_gas(3000000)] #[should_panic(expected: ('APPROVE_AMOUNT_OVERFLOW', 'ENTRYPOINT_FAILED'))] fn test_approve_overflow() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (_, erc20) = deploy('Governor Token', 'GT', 12345); let spender = contract_address_const::<12345>(); - let recipient = contract_address_const::<12346>(); erc20.approve(spender, u256 { high: 1, low: 0 }); } #[test] #[available_gas(30000000)] fn test_delegate_count_lags() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); let delegatee = contract_address_const::<12345>(); set_block_timestamp(2); @@ -296,7 +295,7 @@ fn test_delegate_count_lags() { #[test] #[available_gas(30000000)] fn test_get_delegated_cumulative() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); let delegatee = contract_address_const::<12345>(); set_block_timestamp(2); @@ -313,7 +312,7 @@ fn test_get_delegated_cumulative() { #[available_gas(30000000)] #[should_panic(expected: ('FUTURE', 'ENTRYPOINT_FAILED'))] fn test_get_delegated_cumulative_fails_future() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); token.get_delegated_cumulative(delegate: contract_address_const::<12345>(), timestamp: 1); } @@ -322,7 +321,7 @@ fn test_get_delegated_cumulative_fails_future() { #[available_gas(30000000)] #[should_panic(expected: ('FUTURE', 'ENTRYPOINT_FAILED'))] fn test_get_delegated_cumulative_fails_future_non_zero_ts() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); set_block_timestamp(5); @@ -333,7 +332,7 @@ fn test_get_delegated_cumulative_fails_future_non_zero_ts() { #[available_gas(30000000)] #[should_panic(expected: ('FUTURE', 'ENTRYPOINT_FAILED'))] fn test_get_delegated_at_fails_future() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); token.get_delegated_at(delegate: contract_address_const::<12345>(), timestamp: 1); } @@ -342,7 +341,7 @@ fn test_get_delegated_at_fails_future() { #[available_gas(30000000)] #[should_panic(expected: ('FUTURE', 'ENTRYPOINT_FAILED'))] fn test_get_delegated_at_fails_future_non_zero_ts() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); set_block_timestamp(5); @@ -352,7 +351,7 @@ fn test_get_delegated_at_fails_future_non_zero_ts() { #[test] #[available_gas(30000000)] fn test_get_average_delegated() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); let delegatee = contract_address_const::<12345>(); set_block_timestamp(10); @@ -407,7 +406,7 @@ fn test_transfer_delegates_moved() { #[test] #[available_gas(30000000)] fn test_delegate_undelegate() { - let (token, erc20) = deploy('Governor Token', 'GT', 12345); + let (token, _) = deploy('Governor Token', 'GT', 12345); let delegatee = contract_address_const::<12345>(); set_block_timestamp(2); diff --git a/src/governor.cairo b/src/governor.cairo index 5e35ef6..ca8bc40 100644 --- a/src/governor.cairo +++ b/src/governor.cairo @@ -1,17 +1,17 @@ use core::array::{Array}; -use core::integer::{u128_safe_divmod, u128_as_non_zero}; +use core::integer::{u128_safe_divmod}; use core::option::{Option, OptionTrait}; use core::traits::{Into, TryInto}; use governance::governance_token::{IGovernanceTokenDispatcher, IGovernanceTokenDispatcherTrait}; use starknet::account::{Call}; -use starknet::{ContractAddress, StorePacking}; +use starknet::{ContractAddress, storage_access::{StorePacking}}; #[derive(Copy, Drop, Serde, PartialEq)] -struct ProposalTimestamps { +pub struct ProposalTimestamps { // the timestamp when the proposal was created - creation: u64, + pub creation: u64, // the timestamp when the proposal was executed - executed: u64, + pub executed: u64, } const TWO_POW_64: u128 = 0x10000000000000000_u128; @@ -22,7 +22,7 @@ impl ProposalTimestampsStorePacking of StorePacking { } fn unpack(value: u128) -> ProposalTimestamps { - let (executed, creation) = u128_safe_divmod(value, u128_as_non_zero(TWO_POW_64)); + let (executed, creation) = u128_safe_divmod(value, TWO_POW_64.try_into().unwrap()); ProposalTimestamps { creation: creation.try_into().unwrap(), executed: executed.try_into().unwrap() } @@ -30,33 +30,33 @@ impl ProposalTimestampsStorePacking of StorePacking { } #[derive(Copy, Drop, Serde, starknet::Store, PartialEq)] -struct ProposalInfo { +pub struct ProposalInfo { // the address of the proposer - proposer: ContractAddress, + pub proposer: ContractAddress, // the relevant timestamps - timestamps: ProposalTimestamps, + pub timestamps: ProposalTimestamps, // how many yes votes have been collected - yea: u128, + pub yea: u128, // how many no votes have been collected - nay: u128, + pub nay: u128, } #[derive(Copy, Drop, Serde, starknet::Store, PartialEq)] -struct Config { +pub struct Config { // how long after a proposal is created does voting start - voting_start_delay: u64, + pub voting_start_delay: u64, // the period during which votes are collected - voting_period: u64, + pub voting_period: u64, // over how many seconds the voting weight is averaged for proposal voting as well as creation/cancellation - voting_weight_smoothing_duration: u64, + pub voting_weight_smoothing_duration: u64, // how many total votes must be collected for the proposal - quorum: u128, + pub quorum: u128, // the minimum amount of average votes required to create a proposal - proposal_creation_threshold: u128, + pub proposal_creation_threshold: u128, } #[starknet::interface] -trait IGovernor { +pub trait IGovernor { // Propose executing the given call from this contract. fn propose(ref self: TStorage, call: Call) -> felt252; @@ -80,7 +80,7 @@ trait IGovernor { } #[starknet::contract] -mod Governor { +pub mod Governor { use core::hash::{LegacyHash}; use core::num::traits::zero::{Zero}; use governance::call_trait::{HashCall, CallTrait}; @@ -93,28 +93,28 @@ mod Governor { #[derive(starknet::Event, Drop)] - struct Proposed { - id: felt252, - proposer: ContractAddress, - call: Call, + pub struct Proposed { + pub id: felt252, + pub proposer: ContractAddress, + pub call: Call, } #[derive(starknet::Event, Drop)] - struct Voted { - id: felt252, - voter: ContractAddress, - weight: u128, - yea: bool, + pub struct Voted { + pub id: felt252, + pub voter: ContractAddress, + pub weight: u128, + pub yea: bool, } #[derive(starknet::Event, Drop)] - struct Canceled { - id: felt252, + pub struct Canceled { + pub id: felt252, } #[derive(starknet::Event, Drop)] - struct Executed { - id: felt252, + pub struct Executed { + pub id: felt252, } #[derive(starknet::Event, Drop)] @@ -142,7 +142,7 @@ mod Governor { self.config.write(config); } - #[external(v0)] + #[abi(embed_v0)] impl GovernorImpl of IGovernor { fn propose(ref self: ContractState, call: Call) -> felt252 { let id = LegacyHash::hash(0, @call); diff --git a/src/governor_test.cairo b/src/governor_test.cairo index 7611856..d587b7d 100644 --- a/src/governor_test.cairo +++ b/src/governor_test.cairo @@ -19,10 +19,9 @@ use governance::timelock::{ITimelockDispatcher, ITimelockDispatcherTrait}; use governance::timelock_test::{single_call, transfer_call, deploy as deploy_timelock}; use governance::{test_utils as utils}; use starknet::account::{Call}; -use starknet::class_hash::Felt252TryIntoClassHash; use starknet::{ - get_contract_address, deploy_syscall, ClassHash, contract_address_const, ContractAddress, - get_block_timestamp, testing::{set_block_timestamp, set_contract_address} + get_contract_address, syscalls::deploy_syscall, ClassHash, contract_address_const, + ContractAddress, get_block_timestamp, testing::{set_block_timestamp, set_contract_address} }; @@ -49,7 +48,7 @@ fn create_proposal(governance: IGovernorDispatcher, token: IGovernanceTokenDispa set_block_timestamp(start_time); set_contract_address(proposer); let id = governance.propose(transfer_call); - set_contract_address(utils::zero_address()); + set_contract_address(Zero::zero()); id } @@ -258,7 +257,6 @@ fn test_vote_before_voting_start_should_fail() { } ); let id = create_proposal(governance, token); - let start_time = utils::timestamp(); let voter = utils::voter(); // Delegate token to the voter to give him voting power. @@ -348,7 +346,6 @@ fn test_cancel_by_proposer() { } ); let proposer = utils::proposer(); - let start_time = utils::timestamp(); let id = create_proposal(governance, token); @@ -383,14 +380,13 @@ fn test_cancel_by_non_proposer() { } ); let user = utils::user(); - let proposer = utils::proposer(); let mut current_timestamp = utils::timestamp(); let id = create_proposal(governance, token); // Delegate token to user so that proposer looses his threshold. - set_contract_address(utils::zero_address()); - token.delegate(utils::zero_address()); + set_contract_address(Zero::zero()); + token.delegate(Zero::zero()); // Fast forward one smoothing duration current_timestamp += 30; @@ -429,8 +425,6 @@ fn test_cancel_by_non_proposer_threshold_not_breached_should_fail() { } ); let user = utils::user(); - let proposer = utils::proposer(); - let mut current_timestamp = utils::timestamp(); let id = create_proposal(governance, token); @@ -496,12 +490,12 @@ fn test_execute_valid_proposal() { set_block_timestamp(current_timestamp); // voting period ends // Execute the proposal. Caller address should be 0. - set_contract_address(utils::zero_address()); + set_contract_address(Zero::zero()); // Send 100 tokens to the gov contract - this is because // the proposal calls transfer() which requires gov to have tokens. erc20.transfer(governance.contract_address, 100); - // set_caller_address(utils::zero_address()); + // set_caller_address(Zero::zero()); let transfer_call = transfer_call(token: token, recipient: utils::recipient(), amount: 100); governance.execute(transfer_call); @@ -526,7 +520,7 @@ fn test_execute_before_voting_ends_should_fail() { proposal_creation_threshold: 50, } ); - let id = create_proposal(governance, token); + create_proposal(governance, token); let mut current_timestamp = utils::timestamp(); current_timestamp += 3601; @@ -553,7 +547,7 @@ fn test_execute_quorum_not_met_should_fail() { proposal_creation_threshold: 50, } ); - let id = create_proposal(governance, token); + create_proposal(governance, token); let mut current_timestamp = utils::timestamp(); current_timestamp += 3661; @@ -569,7 +563,6 @@ fn test_execute_quorum_not_met_should_fail() { #[available_gas(100000000)] #[should_panic(expected: ('NO_MAJORITY', 'ENTRYPOINT_FAILED'))] fn test_execute_no_majority_should_fail() { - let deployer = get_contract_address(); let (token, erc20) = deploy_token('Governor', 'GT', 1000); let governance = deploy( voting_token: token, @@ -630,7 +623,6 @@ fn test_execute_no_majority_should_fail() { #[available_gas(100000000)] #[should_panic(expected: ('QUORUM_NOT_MET', 'ENTRYPOINT_FAILED'))] fn test_verify_votes_are_counted_over_voting_weight_smoothing_duration_from_start() { - let deployer = get_contract_address(); let (token, erc20) = deploy_token('Governor', 'GT', 1000); let governance = deploy( voting_token: token, @@ -719,12 +711,12 @@ fn test_execute_already_executed_should_fail() { set_block_timestamp(current_timestamp); // voting period ends // Execute the proposal. Caller address should be 0. - set_contract_address(utils::zero_address()); + set_contract_address(Zero::zero()); // Send 100 tokens to the gov contract - this is because // the proposal calls transfer() which requires gov to have tokens. erc20.transfer(governance.contract_address, 100); - // set_caller_address(utils::zero_address()); + // set_caller_address(Zero::zero()); let transfer_call = transfer_call(token: token, recipient: utils::recipient(), amount: 100); governance.execute(transfer_call); @@ -743,7 +735,7 @@ fn queue_with_timelock_call(timelock: ITimelockDispatcher, calls: Span) -> to: timelock.contract_address, // queue selector: 0x2c5ecd2faa027574e2101f9b6bdc19dec3f76beff12aa506ac3391be0022e46, - calldata: calldata + calldata: calldata.span() } } @@ -786,7 +778,7 @@ fn test_proposal_e2e() { set_block_timestamp(start_time + 5 + 3600 + 60); let mut result = governance.execute(queue_with_timelock_call(timelock, timelock_calls)); assert(result.len() == 1, '1 result'); - let queued_call_id = result.pop_front(); + result.pop_front().unwrap(); set_block_timestamp(start_time + 5 + 3600 + 60 + 60); assert(erc20.balance_of(timelock.contract_address) == 200, 'balance before t'); assert(erc20.balance_of(recipient) == 0, 'balance before r'); diff --git a/src/interfaces.cairo b/src/interfaces.cairo deleted file mode 100644 index bfe4665..0000000 --- a/src/interfaces.cairo +++ /dev/null @@ -1 +0,0 @@ -mod erc20; diff --git a/src/interfaces/erc20.cairo b/src/interfaces/erc20.cairo index 50e1dd4..869888c 100644 --- a/src/interfaces/erc20.cairo +++ b/src/interfaces/erc20.cairo @@ -1,7 +1,7 @@ use starknet::{ContractAddress}; #[starknet::interface] -trait IERC20 { +pub trait IERC20 { fn name(self: @TStorage) -> felt252; fn symbol(self: @TStorage) -> felt252; fn decimals(self: @TStorage) -> u8; diff --git a/src/lib.cairo b/src/lib.cairo index 90dd1f1..b318bca 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,23 +1,27 @@ -mod airdrop; +pub mod airdrop; #[cfg(test)] -mod airdrop_test; -mod call_trait; +pub(crate) mod airdrop_test; +pub mod call_trait; #[cfg(test)] -mod call_trait_test; -mod factory; +pub(crate) mod call_trait_test; +pub mod factory; #[cfg(test)] -mod factory_test; -mod governance_token; +pub(crate) mod factory_test; +pub mod governance_token; #[cfg(test)] -mod governance_token_test; -mod governor; +pub(crate) mod governance_token_test; +pub mod governor; #[cfg(test)] -mod governor_test; -mod interfaces; +pub(crate) mod governor_test; #[cfg(test)] -mod test_utils; -mod timelock; +pub(crate) mod test_utils; +pub mod timelock; #[cfg(test)] -mod timelock_test; -mod utils; +pub(crate) mod timelock_test; +pub(crate) mod interfaces { + pub(crate) mod erc20; +} +pub(crate) mod utils { + pub(crate) mod timestamps; +} diff --git a/src/test_utils.cairo b/src/test_utils.cairo index e4bd7af..638e30d 100644 --- a/src/test_utils.cairo +++ b/src/test_utils.cairo @@ -1,34 +1,31 @@ use core::option::OptionTrait; -use starknet::{contract_address_try_from_felt252, ContractAddress}; +use starknet::{ContractAddress}; -fn recipient() -> ContractAddress { - contract_address_try_from_felt252('recipient').unwrap() +pub(crate) fn recipient() -> ContractAddress { + 'recipient'.try_into().unwrap() } -fn proposer() -> ContractAddress { - contract_address_try_from_felt252('proposer').unwrap() +pub(crate) fn proposer() -> ContractAddress { + 'proposer'.try_into().unwrap() } -fn delegate() -> ContractAddress { - contract_address_try_from_felt252('delegate').unwrap() +pub(crate) fn delegate() -> ContractAddress { + 'delegate'.try_into().unwrap() } -fn voter() -> ContractAddress { - contract_address_try_from_felt252('voter').unwrap() +pub(crate) fn voter() -> ContractAddress { + 'voter'.try_into().unwrap() } -fn voter2() -> ContractAddress { - contract_address_try_from_felt252('user2').unwrap() +pub(crate) fn voter2() -> ContractAddress { + 'user2'.try_into().unwrap() } -fn user() -> ContractAddress { - contract_address_try_from_felt252('user').unwrap() +pub(crate) fn user() -> ContractAddress { + 'user'.try_into().unwrap() } -fn zero_address() -> ContractAddress { - contract_address_try_from_felt252(0).unwrap() -} -fn timestamp() -> u64 { +pub(crate) fn timestamp() -> u64 { 1688122125 } diff --git a/src/timelock.cairo b/src/timelock.cairo index 887670c..3ed2b9b 100644 --- a/src/timelock.cairo +++ b/src/timelock.cairo @@ -7,13 +7,13 @@ use starknet::contract_address::{ContractAddress}; use starknet::storage_access::{StorePacking}; #[derive(Copy, Drop, Serde)] -struct ExecutionState { - started: u64, - executed: u64, - canceled: u64 +pub struct ExecutionState { + pub started: u64, + pub executed: u64, + pub canceled: u64 } -impl ExecutionStateStorePacking of StorePacking { +pub(crate) impl ExecutionStateStorePacking of StorePacking { #[inline(always)] fn pack(value: ExecutionState) -> felt252 { ThreeU64TupleStorePacking::pack((value.started, value.executed, value.canceled)) @@ -26,12 +26,12 @@ impl ExecutionStateStorePacking of StorePacking { } #[derive(Copy, Drop, Serde)] -struct TimelockConfig { - delay: u64, - window: u64, +pub struct TimelockConfig { + pub delay: u64, + pub window: u64, } -impl TimelockConfigStorePacking of StorePacking { +pub(crate) impl TimelockConfigStorePacking of StorePacking { #[inline(always)] fn pack(value: TimelockConfig) -> u128 { TwoU64TupleStorePacking::pack((value.delay, value.window)) @@ -44,7 +44,7 @@ impl TimelockConfigStorePacking of StorePacking { } #[starknet::interface] -trait ITimelock { +pub trait ITimelock { // Queue a list of calls to be executed after the delay. Only the owner may call this. fn queue(ref self: TStorage, calls: Span) -> felt252; @@ -70,19 +70,19 @@ trait ITimelock { } #[derive(Copy, Drop, Serde)] -struct ExecutionWindow { - earliest: u64, - latest: u64 +pub struct ExecutionWindow { + pub earliest: u64, + pub latest: u64 } #[starknet::contract] -mod Timelock { +pub mod Timelock { use core::hash::LegacyHash; use core::num::traits::zero::{Zero}; use governance::call_trait::{CallTrait, HashCall}; use starknet::{ get_caller_address, get_contract_address, SyscallResult, syscalls::call_contract_syscall, - ContractAddressIntoFelt252, get_block_timestamp + get_block_timestamp }; use super::{ ITimelock, ContractAddress, Call, TimelockConfig, ExecutionState, @@ -91,19 +91,19 @@ mod Timelock { #[derive(starknet::Event, Drop)] - struct Queued { - id: felt252, - calls: Span, + pub struct Queued { + pub id: felt252, + pub calls: Span, } #[derive(starknet::Event, Drop)] - struct Canceled { - id: felt252, + pub struct Canceled { + pub id: felt252, } #[derive(starknet::Event, Drop)] - struct Executed { - id: felt252, + pub struct Executed { + pub id: felt252, } #[derive(starknet::Event, Drop)] @@ -131,7 +131,7 @@ mod Timelock { // Take a list of calls and convert it to a unique identifier for the execution // Two lists of calls will always have the same ID if they are equivalent // A list of calls can only be queued and executed once. To make 2 different calls, add an empty call. - fn to_id(mut calls: Span) -> felt252 { + pub fn to_id(mut calls: Span) -> felt252 { let mut state = 0; loop { match calls.pop_front() { @@ -152,7 +152,7 @@ mod Timelock { } } - #[external(v0)] + #[abi(embed_v0)] impl TimelockImpl of ITimelock { fn queue(ref self: ContractState, calls: Span) -> felt252 { self.check_owner(); diff --git a/src/timelock_test.cairo b/src/timelock_test.cairo index 4814852..51fc140 100644 --- a/src/timelock_test.cairo +++ b/src/timelock_test.cairo @@ -1,18 +1,18 @@ use core::array::{Array, ArrayTrait, SpanTrait}; -use governance::governance_token_test::{deploy as deploy_token, IGovernanceTokenDispatcher}; +use governance::governance_token::{IGovernanceTokenDispatcher}; +use governance::governance_token_test::{deploy as deploy_token}; use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; use governance::timelock::{ ITimelockDispatcher, ITimelockDispatcherTrait, Timelock, TimelockConfig, TimelockConfigStorePacking, ExecutionState, ExecutionStateStorePacking }; use starknet::account::{Call}; -use starknet::class_hash::Felt252TryIntoClassHash; use starknet::{ - get_contract_address, deploy_syscall, ClassHash, contract_address_const, ContractAddress, - get_block_timestamp, testing::set_block_timestamp + get_contract_address, syscalls::{deploy_syscall}, ClassHash, contract_address_const, + ContractAddress, get_block_timestamp, testing::set_block_timestamp }; -fn deploy(owner: ContractAddress, delay: u64, window: u64) -> ITimelockDispatcher { +pub(crate) fn deploy(owner: ContractAddress, delay: u64, window: u64) -> ITimelockDispatcher { let mut constructor_args: Array = ArrayTrait::new(); Serde::serialize(@(owner, delay, window), ref constructor_args); @@ -35,7 +35,7 @@ fn test_deploy() { assert(owner == contract_address_const::<2300>(), 'owner'); } -fn transfer_call( +pub(crate) fn transfer_call( token: IGovernanceTokenDispatcher, recipient: ContractAddress, amount: u256 ) -> Call { let mut calldata: Array = ArrayTrait::new(); @@ -45,11 +45,11 @@ fn transfer_call( to: token.contract_address, // transfer selector: 0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e, - calldata: calldata + calldata: calldata.span() } } -fn single_call(call: Call) -> Span { +pub(crate) fn single_call(call: Call) -> Span { return array![call].span(); } @@ -108,7 +108,7 @@ fn test_queue_execute_twice() { let recipient = contract_address_const::<12345>(); - let id = timelock.queue(single_call(transfer_call(token, recipient, 500_u256))); + timelock.queue(single_call(transfer_call(token, recipient, 500_u256))); set_block_timestamp(86401); diff --git a/src/utils/timestamps.cairo b/src/utils/timestamps.cairo index 7c275f0..efaf725 100644 --- a/src/utils/timestamps.cairo +++ b/src/utils/timestamps.cairo @@ -1,9 +1,9 @@ -use core::integer::{u128_to_felt252, u64_try_from_felt252, u128_safe_divmod}; +use core::integer::{u128_safe_divmod}; use starknet::storage_access::{StorePacking}; const TWO_POW_64: u128 = 0x10000000000000000; -impl ThreeU64TupleStorePacking of StorePacking<(u64, u64, u64), felt252> { +pub(crate) impl ThreeU64TupleStorePacking of StorePacking<(u64, u64, u64), felt252> { #[inline(always)] fn pack(value: (u64, u64, u64)) -> felt252 { let (a, b, c) = value; @@ -17,7 +17,7 @@ impl ThreeU64TupleStorePacking of StorePacking<(u64, u64, u64), felt252> { } } -impl TwoU64TupleStorePacking of StorePacking<(u64, u64), u128> { +pub(crate) impl TwoU64TupleStorePacking of StorePacking<(u64, u64), u128> { #[inline(always)] fn pack(value: (u64, u64)) -> u128 { let (a, b) = value;