diff --git a/.tool-versions b/.tool-versions index f239fe2..5e90c60 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.6.3 +scarb 2.8.1 diff --git a/README.md b/README.md index 95da23f..d8636ba 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Contracts in this repository are designed so that they may be used together _or_ - Users call `Token#approve(staker, stake_amount)`, then `Staker#stake_amount(delegate, stake_amount)` to stake and delegate their tokens to other addresses - Users call `Staker#withdraw_amount(delegate, recipient, amount)` to remove part or all of their delegation -- The average delegation weight is computable over *any* historical period +- The average delegation weight is computable over _any_ historical period - The contract has no owner, and cannot be updated nor configured #### Governor diff --git a/Scarb.toml b/Scarb.toml index e8fee4c..a97dd3c 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -3,11 +3,11 @@ name = "governance" version = "0.1.0" description = "Contracts for governance of Starknet-native protocols" homepage = "https://ekubo.org" -cairo-version = "2.6.3" -edition = '2023_11' +cairo-version = "2.8.0" +edition = '2024_07' [dependencies] -starknet = "=2.6.3" +starknet = ">=2.7.0" [[target.starknet-contract]] allowed-libfuncs-list.name = "audited" @@ -15,3 +15,6 @@ casm = true [tool.fmt] sort-module-level-items = true + +[dev-dependencies] +cairo_test = "2.8.0" diff --git a/src/airdrop.cairo b/src/airdrop.cairo index 50c8984..93d1814 100644 --- a/src/airdrop.cairo +++ b/src/airdrop.cairo @@ -30,14 +30,16 @@ pub trait IAirdrop { fn get_config(self: @TContractState) -> Config; // Claims the given allotment of tokens. - // Because this method is idempotent, it does not revert in case of a second submission of the same claim. + // Because this method is idempotent, it does not revert in case of a second submission of the + // same claim. // This makes it simpler to batch many claims together in a single transaction. // Returns true if the claim was processed. Returns false if the claim was already claimed. // Panics if the proof is invalid. fn claim(ref self: TContractState, claim: Claim, proof: Span) -> bool; - // Claims the batch of up to 128 claims that must be aligned with a single bitmap, i.e. the id of the first must be a multiple of 128 - // and the claims should be sequentially in order. The proof verification is optimized in this method. + // Claims the batch of up to 128 claims that must be aligned with a single bitmap, i.e. the id + // of the first must be a multiple of 128 and the claims should be sequentially in order. The + // proof verification is optimized in this method. // Returns the number of claims that were executed. fn claim_128( ref self: TContractState, claims: Span, remaining_proof: Span @@ -57,7 +59,12 @@ pub mod Airdrop { use core::num::traits::zero::{Zero}; use governance::interfaces::erc20::{IERC20DispatcherTrait}; use governance::utils::exp2::{exp2}; + use starknet::storage::{ + Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerWriteAccess, + StoragePointerReadAccess + }; use starknet::{get_block_timestamp, get_contract_address}; + use super::{Config, IAirdrop, ContractAddress, Claim, IERC20Dispatcher}; pub fn hash_function(a: felt252, b: felt252) -> felt252 { @@ -69,7 +76,8 @@ pub mod Airdrop { } } - // computes the pedersen root of a merkle tree by combining the current node with each sibling up the tree + // computes the pedersen root of a merkle tree by combining the current node with each sibling + // up the tree pub fn compute_pedersen_root(current: felt252, mut proof: Span) -> felt252 { match proof.pop_front() { Option::Some(proof_element) => { @@ -83,7 +91,7 @@ pub mod Airdrop { struct Storage { token: IERC20Dispatcher, config: Config, - claimed_bitmap: LegacyMap, + claimed_bitmap: Map, } #[derive(Drop, starknet::Event)] @@ -121,35 +129,28 @@ pub mod Airdrop { let mut last_claim_id: Option = Option::None; - while let Option::Some(claim) = claims - .pop_front() { - if let Option::Some(last_id) = last_claim_id { - assert(last_id == (*claim.id - 1), 'SEQUENTIAL'); - }; - - claim_hashes.append(hash_claim(*claim)); - last_claim_id = Option::Some(*claim.id); + while let Option::Some(claim) = claims.pop_front() { + if let Option::Some(last_id) = last_claim_id { + assert(last_id == (*claim.id - 1), 'SEQUENTIAL'); }; + claim_hashes.append(hash_claim(*claim)); + last_claim_id = Option::Some(*claim.id); + }; + // will eventually contain an array of length 1 let mut current_layer: Span = claim_hashes.span(); - while current_layer - .len() - .is_non_one() { - let mut next_layer: Array = array![]; - - while let Option::Some(hash) = current_layer - .pop_front() { - next_layer - .append( - hash_function(*hash, *current_layer.pop_front().unwrap_or(hash)) - ); - }; + while current_layer.len().is_non_one() { + let mut next_layer: Array = array![]; - current_layer = next_layer.span(); + while let Option::Some(hash) = current_layer.pop_front() { + next_layer.append(hash_function(*hash, *current_layer.pop_front().unwrap_or(hash))); }; + current_layer = next_layer.span(); + }; + *current_layer.pop_front().unwrap() } @@ -192,7 +193,8 @@ pub mod Airdrop { assert(!claims.is_empty(), 'CLAIMS_EMPTY'); // groups that cross bitmap boundaries should just make multiple calls - // this code already reduces the number of pedersens in the verification by a factor of ~7 + // this code already reduces the number of pedersens in the verification by a factor of + // ~7 let (word, index_u64) = DivRem::div_rem(*claims.at(0).id, BITMAP_SIZE); assert(index_u64 == 0, 'FIRST_CLAIM_MUST_BE_MULT_128'); @@ -210,17 +212,16 @@ pub mod Airdrop { let mut index: u8 = 0; let mut unclaimed: Array = array![]; - while let Option::Some(claim) = claims - .pop_front() { - let already_claimed = (bitmap & exp2(index)).is_non_zero(); + while let Option::Some(claim) = claims.pop_front() { + let already_claimed = (bitmap & exp2(index)).is_non_zero(); - if !already_claimed { - bitmap = bitmap | exp2(index); - unclaimed.append(*claim); - } + if !already_claimed { + bitmap = bitmap | exp2(index); + unclaimed.append(*claim); + } - index += 1; - }; + index += 1; + }; self.claimed_bitmap.write(word, bitmap); @@ -229,13 +230,13 @@ pub mod Airdrop { // the event emittance and transfers are separated from the above to prevent re-entrance let token = self.token.read(); - while let Option::Some(claim) = unclaimed - .pop_front() { - token.transfer(claim.claimee, claim.amount.into()); - self.emit(Claimed { claim }); - }; + while let Option::Some(claim) = unclaimed.pop_front() { + token.transfer(claim.claimee, claim.amount.into()); + self.emit(Claimed { claim }); + }; - // never fails because we assert claims length at the beginning so we know it's less than 128 + // never fails because we assert claims length at the beginning so we know it's less + // than 128 num_claimed.try_into().unwrap() } diff --git a/src/airdrop_claim_check.cairo b/src/airdrop_claim_check.cairo index 474d97e..44fc323 100644 --- a/src/airdrop_claim_check.cairo +++ b/src/airdrop_claim_check.cairo @@ -1,5 +1,4 @@ use governance::airdrop::{IAirdropDispatcher}; -use starknet::{ContractAddress}; #[derive(Serde, Copy, Drop)] struct CheckParams { @@ -23,7 +22,7 @@ trait IAirdropClaimCheck { mod AirdropClaimCheck { use governance::airdrop::{IAirdropDispatcherTrait}; use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; - use super::{IAirdropClaimCheck, IAirdropDispatcher, CheckParams, CheckResult}; + use super::{IAirdropClaimCheck, CheckParams, CheckResult}; #[storage] struct Storage {} @@ -33,18 +32,17 @@ mod AirdropClaimCheck { fn check(self: @ContractState, mut claims: Span) -> Span { let mut result: Array = array![]; - while let Option::Some(claim_check) = claims - .pop_front() { - let token = IERC20Dispatcher { - contract_address: (*claim_check.airdrop).get_token() - }; - let claimed = (*claim_check.airdrop).is_claimed(*claim_check.claim_id); - let funded = token - .balanceOf( - *claim_check.airdrop.contract_address - ) >= ((*claim_check.amount).into()); - result.append(CheckResult { claimed, funded }); + while let Option::Some(claim_check) = claims.pop_front() { + let token = IERC20Dispatcher { + contract_address: (*claim_check.airdrop).get_token() }; + let claimed = (*claim_check.airdrop).is_claimed(*claim_check.claim_id); + let funded = token + .balanceOf( + *claim_check.airdrop.contract_address + ) >= ((*claim_check.amount).into()); + result.append(CheckResult { claimed, funded }); + }; result.span() } diff --git a/src/airdrop_test.cairo b/src/airdrop_test.cairo index bea4105..2b2ada8 100644 --- a/src/airdrop_test.cairo +++ b/src/airdrop_test.cairo @@ -1,15 +1,13 @@ -use core::hash::{LegacyHash}; use core::num::traits::zero::{Zero}; use governance::airdrop::{ IAirdropDispatcher, IAirdropDispatcherTrait, Airdrop, Config, Airdrop::{compute_pedersen_root, hash_function, hash_claim, compute_root_of_group}, Claim }; -use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; +use governance::interfaces::erc20::{IERC20DispatcherTrait}; use governance::test::test_token::{TestToken, deploy as deploy_token}; use starknet::testing::{pop_log, set_block_timestamp}; use starknet::{ - ClassHash, ContractAddress, contract_address_const, get_contract_address, - syscalls::{deploy_syscall} + ContractAddress, contract_address_const, get_contract_address, syscalls::{deploy_syscall} }; fn deploy_with_refundee( @@ -802,16 +800,12 @@ fn test_claim_128_double_claim() { assert_eq!(airdrop.claim_128(claims.span().slice(0, 128), array![s2, rr].span()), 128); let mut i: u64 = 0; - while let Option::Some(claimed) = - pop_log::< - Airdrop::Claimed - >(airdrop.contract_address) { - assert_eq!( - claimed.claim, - Claim { id: i, amount: 3, claimee: contract_address_const::<0xcdee>() } - ); - i += 1; - }; + while let Option::Some(claimed) = pop_log::(airdrop.contract_address) { + assert_eq!( + claimed.claim, Claim { id: i, amount: 3, claimee: contract_address_const::<0xcdee>() } + ); + i += 1; + }; assert_eq!(airdrop.claim_128(claims.span().slice(0, 128), array![s2, rr].span()), 0); assert_eq!(pop_log::(airdrop.contract_address).is_none(), true); @@ -820,8 +814,7 @@ fn test_claim_128_double_claim() { mod refundable { use super::{ deploy_token, deploy_with_refundee, get_contract_address, contract_address_const, - set_block_timestamp, IAirdropDispatcherTrait, IERC20DispatcherTrait, TestToken, - ContractAddress + set_block_timestamp, IAirdropDispatcherTrait, IERC20DispatcherTrait, ContractAddress }; fn refund_to() -> ContractAddress { diff --git a/src/call_trait.cairo b/src/call_trait.cairo index 67f816b..320ec53 100644 --- a/src/call_trait.cairo +++ b/src/call_trait.cairo @@ -1,4 +1,4 @@ -use core::hash::{HashStateTrait, HashStateExTrait, Hash}; +use core::hash::{HashStateTrait, Hash}; use starknet::account::{Call}; use starknet::syscalls::{call_contract_syscall}; diff --git a/src/governor.cairo b/src/governor.cairo index 72cf39a..3b091f2 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::{ContractAddress, storage_access::{StorePacking}, ClassHash}; +use starknet::{ContractAddress, ClassHash}; #[derive(Copy, Drop, Serde, starknet::Store, PartialEq, Debug)] pub struct ProposalInfo { @@ -25,7 +25,8 @@ pub struct Config { pub voting_start_delay: u64, // The period during which votes are collected pub voting_period: u64, - // Over how many seconds the voting weight is averaged for proposal voting as well as creation/cancellation + // Over how many seconds the voting weight is averaged for proposal voting as well as + // creation/cancellation pub voting_weight_smoothing_duration: u64, // How many total votes must be collected for the proposal pub quorum: u128, @@ -51,7 +52,8 @@ pub trait IGovernor { // Execute the given proposal. fn execute(ref self: TContractState, id: felt252, calls: Span) -> Span>; - // Attaches the given text to the proposal. Simply emits an event containing the proposal description. + // Attaches the given text to the proposal. Simply emits an event containing the proposal + // description. fn describe(ref self: TContractState, id: felt252, description: ByteArray); // Combines propose and describe methods. @@ -83,7 +85,8 @@ pub trait IGovernor { // - 1 means voted against fn get_vote(self: @TContractState, id: felt252, voter: ContractAddress) -> u8; - // Changes the configuration of the governor. Only affects proposals created after the configuration change. Must be called by self, e.g. via a proposal. + // Changes the configuration of the governor. Only affects proposals created after the + // configuration change. Must be called by self, e.g. via a proposal. fn reconfigure(ref self: TContractState, config: Config) -> u64; // Replaces the code at this address. This must be self-called via a proposal. @@ -100,6 +103,10 @@ pub mod Governor { use core::poseidon::{PoseidonTrait}; use governance::call_trait::{HashSerializable, CallTrait}; use governance::staker::{IStakerDispatcherTrait}; + use starknet::storage::{ + Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, + StoragePointerWriteAccess + }; use starknet::storage_access::{Store, storage_base_address_from_felt252}; use starknet::{ get_block_timestamp, get_caller_address, get_contract_address, @@ -110,6 +117,7 @@ pub mod Governor { ClassHash }; + #[derive(starknet::Event, Drop)] pub struct Proposed { pub id: felt252, @@ -163,12 +171,12 @@ pub mod Governor { #[storage] struct Storage { staker: IStakerDispatcher, - config_versions: LegacyMap, + config_versions: Map, latest_config_version: u64, nonce: u64, - proposals: LegacyMap, - latest_proposal_by_proposer: LegacyMap, - vote: LegacyMap<(felt252, ContractAddress), u8>, + proposals: Map, + latest_proposal_by_proposer: Map, + vote: Map<(felt252, ContractAddress), u8>, } #[constructor] @@ -216,7 +224,8 @@ pub mod Governor { if latest_proposal_id.is_non_zero() { let latest_proposal_state = self.get_proposal(latest_proposal_id).execution_state; - // if the proposal is not canceled, check that the voting for that proposal has ended + // if the proposal is not canceled, check that the voting for that proposal has + // ended if latest_proposal_state.canceled.is_zero() { assert( latest_proposal_state.created @@ -325,7 +334,8 @@ pub mod Governor { assert(proposal.proposer == get_caller_address(), 'PROPOSER_ONLY'); assert(proposal.execution_state.canceled.is_zero(), 'ALREADY_CANCELED'); - // this is prevented so that proposers cannot grief voters by creating proposals that they plan to cancel after the result is known + // this is prevented so that proposers cannot grief voters by creating proposals that + // they plan to cancel after the result is known assert( get_block_timestamp() < (proposal.execution_state.created + config.voting_start_delay), @@ -473,7 +483,8 @@ pub mod Governor { } } - // This implementation exists solely for the purpose of allowing simulation of calls from the governor with the flag to skip validation + // This implementation exists solely for the purpose of allowing simulation of calls from the + // governor with the flag to skip validation #[abi(embed_v0)] impl GovernorAccountContractForSimulation of AccountContract { fn __validate_declare__(self: @ContractState, class_hash: felt252) -> felt252 { diff --git a/src/governor_test.cairo b/src/governor_test.cairo index 28996ce..48fdd27 100644 --- a/src/governor_test.cairo +++ b/src/governor_test.cairo @@ -9,9 +9,8 @@ use governance::staker::{IStakerDispatcher, IStakerDispatcherTrait}; use governance::staker_test::{setup as setup_staker}; 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, pop_log, set_version}, + get_contract_address, syscalls::deploy_syscall, contract_address_const, ContractAddress, + get_block_timestamp, testing::{set_block_timestamp, set_contract_address, pop_log, set_version}, account::{AccountContractDispatcher, AccountContractDispatcherTrait} }; @@ -240,7 +239,8 @@ fn test_propose_below_threshold_should_fail() { let (_staker, token, governor, config) = setup(); set_contract_address(proposer()); - // since time starts at 0, we have to advance time by the duration just so the staker doesn't revert on time - voting_weight_smoothing_duration + // since time starts at 0, we have to advance time by the duration just so the staker doesn't + // revert on time - voting_weight_smoothing_duration advance_time(config.voting_weight_smoothing_duration); // no tokens delegated to the proposer governor.propose(array![transfer_call(token, recipient(), amount: 100)].span()); @@ -523,7 +523,7 @@ fn test_cancel_by_proposer() { proposal, ProposalInfo { calls_hash: hash_calls(@array![transfer_call(token, recipient(), amount: 100)].span()), - proposer: proposer(), + proposer: proposer, execution_state: ExecutionState { created: config.voting_weight_smoothing_duration, executed: 0, @@ -770,7 +770,8 @@ fn test_verify_votes_are_counted_over_voting_weight_smoothing_duration_from_star .propose(array![transfer_call(token: token, recipient: recipient(), amount: 100)].span()); advance_time(config.voting_start_delay - (config.voting_weight_smoothing_duration / 3)); - // undelegate 1/3rd of a duration before voting starts, so only a third of voting power is counted for voter1 + // undelegate 1/3rd of a duration before voting starts, so only a third of voting power is + // counted for voter1 set_contract_address(voter1); staker.withdraw_amount(voter1, recipient: Zero::zero(), amount: 49); diff --git a/src/staker.cairo b/src/staker.cairo index 2fa2dc1..66681f6 100644 --- a/src/staker.cairo +++ b/src/staker.cairo @@ -10,16 +10,20 @@ pub trait IStaker { self: @TContractState, staker: ContractAddress, delegate: ContractAddress ) -> u128; - // Transfers the approved amount of token from the caller into this contract and delegates it to the given address. + // Transfers the approved amount of token from the caller into this contract and delegates it to + // the given address. fn stake(ref self: TContractState, delegate: ContractAddress); - // Transfers the specified amount of token from the caller into this contract and delegates the voting weight to the specified delegate. + // Transfers the specified amount of token from the caller into this contract and delegates the + // voting weight to the specified delegate. fn stake_amount(ref self: TContractState, delegate: ContractAddress, amount: u128); - // Unstakes and withdraws all of the tokens delegated by the sender to the delegate from the contract to the given recipient address. + // Unstakes and withdraws all of the tokens delegated by the sender to the delegate from the + // contract to the given recipient address. fn withdraw(ref self: TContractState, delegate: ContractAddress, recipient: ContractAddress); - // Unstakes and withdraws the specified amount of tokens delegated by the sender to the delegate from the contract to the given recipient address. + // Unstakes and withdraws the specified amount of tokens delegated by the sender to the delegate + // from the contract to the given recipient address. fn withdraw_amount( ref self: TContractState, delegate: ContractAddress, @@ -38,7 +42,8 @@ pub trait IStaker { self: @TContractState, delegate: ContractAddress, timestamp: u64 ) -> u256; - // Gets the average amount delegated over the given period, where end > start and end <= current time. + // Gets the average amount delegated over the given period, where end > start and end <= current + // time. fn get_average_delegated( self: @TContractState, delegate: ContractAddress, start: u64, end: u64 ) -> u128; @@ -53,12 +58,17 @@ pub trait IStaker { pub mod Staker { use core::num::traits::zero::{Zero}; use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; + use starknet::storage::{ + Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, + StoragePointerWriteAccess, StoragePathEntry + }; use starknet::{ get_caller_address, get_contract_address, get_block_timestamp, storage_access::{StorePacking} }; use super::{IStaker, ContractAddress}; + #[derive(Copy, Drop, PartialEq, Debug)] pub struct DelegatedSnapshot { pub timestamp: u64, @@ -90,10 +100,10 @@ pub mod Staker { struct Storage { token: IERC20Dispatcher, // owner, delegate => amount - staked: LegacyMap<(ContractAddress, ContractAddress), u128>, - amount_delegated: LegacyMap, - delegated_cumulative_num_snapshots: LegacyMap, - delegated_cumulative_snapshot: LegacyMap<(ContractAddress, u64), DelegatedSnapshot>, + staked: Map<(ContractAddress, ContractAddress), u128>, + amount_delegated: Map, + delegated_cumulative_num_snapshots: Map, + delegated_cumulative_snapshot: Map>, } #[constructor] @@ -131,17 +141,15 @@ pub mod Staker { let amount_delegated = self.amount_delegated.read(address); let mut num_snapshots = self.delegated_cumulative_num_snapshots.read(address); + let delegate_snapshots_entry = self.delegated_cumulative_snapshot.entry(address); if num_snapshots.is_non_zero() { - let last_snapshot = self - .delegated_cumulative_snapshot - .read((address, num_snapshots - 1)); + let last_snapshot = delegate_snapshots_entry.read(num_snapshots - 1); // if we haven't just snapshotted this address if (last_snapshot.timestamp != timestamp) { - self - .delegated_cumulative_snapshot + delegate_snapshots_entry .write( - (address, num_snapshots), + num_snapshots, DelegatedSnapshot { timestamp, delegated_cumulative: last_snapshot.delegated_cumulative @@ -154,12 +162,8 @@ pub mod Staker { } } else { // record this timestamp as the first snapshot - self - .delegated_cumulative_snapshot - .write( - (address, num_snapshots), - DelegatedSnapshot { timestamp, delegated_cumulative: 0 } - ); + delegate_snapshots_entry + .write(num_snapshots, DelegatedSnapshot { timestamp, delegated_cumulative: 0 }); self.delegated_cumulative_num_snapshots.write(address, 1); }; @@ -173,13 +177,14 @@ pub mod Staker { max_index_exclusive: u64, timestamp: u64 ) -> u256 { + let snapshots_path = self.delegated_cumulative_snapshot.entry(delegate); if (min_index == (max_index_exclusive - 1)) { - let snapshot = self.delegated_cumulative_snapshot.read((delegate, min_index)); + let snapshot = snapshots_path.read(min_index); return if (snapshot.timestamp > timestamp) { 0 } else { let difference = timestamp - snapshot.timestamp; - let next = self.delegated_cumulative_snapshot.read((delegate, min_index + 1)); + let next = snapshots_path.read(min_index + 1); let delegated_amount = if (next.timestamp.is_zero()) { self.amount_delegated.read(delegate) } else { @@ -194,7 +199,7 @@ pub mod Staker { } let mid = (min_index + max_index_exclusive) / 2; - let snapshot = self.delegated_cumulative_snapshot.read((delegate, mid)); + let snapshot = snapshots_path.read(mid); if (timestamp == snapshot.timestamp) { return snapshot.delegated_cumulative; diff --git a/src/staker_test.cairo b/src/staker_test.cairo index 6f06ddb..268074b 100644 --- a/src/staker_test.cairo +++ b/src/staker_test.cairo @@ -7,10 +7,7 @@ use governance::staker::{ }; use governance::test::test_token::{TestToken, deploy as deploy_token}; use starknet::testing::{set_block_timestamp, pop_log}; -use starknet::{ - get_contract_address, syscalls::deploy_syscall, ClassHash, contract_address_const, - ContractAddress, -}; +use starknet::{get_contract_address, syscalls::deploy_syscall, contract_address_const}; pub(crate) fn setup(amount: u256) -> (IStakerDispatcher, IERC20Dispatcher) { let token = deploy_token(get_contract_address(), amount); @@ -26,8 +23,8 @@ pub(crate) fn setup(amount: u256) -> (IStakerDispatcher, IERC20Dispatcher) { mod stake_withdraw { use super::{ - setup, Staker, IStakerDispatcherTrait, IERC20Dispatcher, IERC20DispatcherTrait, pop_log, - get_contract_address, Zero, TestToken, contract_address_const + setup, Staker, IStakerDispatcherTrait, IERC20DispatcherTrait, pop_log, get_contract_address, + Zero, TestToken, contract_address_const }; #[test] diff --git a/src/test/test_token.cairo b/src/test/test_token.cairo index 7df9d4d..ef7c2b5 100644 --- a/src/test/test_token.cairo +++ b/src/test/test_token.cairo @@ -5,12 +5,13 @@ use starknet::{ContractAddress, syscalls::{deploy_syscall}}; pub(crate) mod TestToken { use core::num::traits::zero::{Zero}; use governance::interfaces::erc20::{IERC20}; + use starknet::storage::{Map, StorageMapReadAccess, StorageMapWriteAccess}; use starknet::{ContractAddress, get_caller_address}; #[storage] struct Storage { - balances: LegacyMap, - allowances: LegacyMap<(ContractAddress, ContractAddress), u256>, + balances: Map, + allowances: Map<(ContractAddress, ContractAddress), u256>, } #[derive(starknet::Event, PartialEq, Debug, Drop)]