Skip to content

Commit

Permalink
Merge branch 'master' into missing-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tensojka authored May 27, 2024
2 parents 9109ef3 + 2ff13dd commit 37d590d
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ cairo-version = "2.6.3"
[dependencies]
starknet = ">=2.0.0"
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.10.0" }
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.23.0" }


# can be fixed by doing import super::testing from tests
# [dev-dependencies] sadly can't use this because we have testing in src/

[lib]


# can be fixed by doing import super::testing from tests
Expand All @@ -17,6 +24,9 @@ snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag

[[target.starknet-contract]]

[scripts]
test = "snforge test"

[[tool.snforge.fork]]
name = "MAINNET"
url = "http://34.22.208.73:6060/v0_7"
Expand Down
102 changes: 102 additions & 0 deletions src/govtoken.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use starknet::{ContractAddress, ClassHash};

#[starknet::interface]
trait IveCARM<TContractState> {
fn name(self: @TContractState) -> felt252;
fn symbol(self: @TContractState) -> felt252;
fn decimals(self: @TContractState) -> u8;
fn mint(ref self: TContractState, recipient: ContractAddress, amount: u256);
fn burn(ref self: TContractState, account: ContractAddress, amount: u256);
fn upgrade(ref self: TContractState, new_class_hash: ClassHash);
}

#[starknet::contract]
mod MyToken {
use openzeppelin::access::ownable::ownable::OwnableComponent::InternalTrait;
use starknet::ContractAddress;
use starknet::ClassHash;
use openzeppelin::token::erc20::ERC20Component;
use openzeppelin::access::ownable::ownable::OwnableComponent;

component!(path: ERC20Component, storage: erc20, event: ERC20Event);
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);

// ERC20 Component
#[abi(embed_v0)]
impl ERC20Impl = ERC20Component::ERC20Impl<ContractState>;

#[abi(embed_v0)]
impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl<ContractState>;

impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;

impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;

// Ownable Component
#[abi(embed_v0)]
impl OwnableImpl = OwnableComponent::OwnableImpl<ContractState>;


#[storage]
struct Storage {
#[substorage(v0)]
erc20: ERC20Component::Storage,
#[substorage(v0)]
ownable: OwnableComponent::Storage,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Upgraded: Upgraded,
// #[flat]
ERC20Event: ERC20Component::Event,
OwnableEvent: OwnableComponent::Event
}

#[derive(Drop, starknet::Event)]
struct Upgraded {
class_hash: ClassHash
}


#[constructor]
fn constructor(ref self: ContractState, owner: ContractAddress) {
self.ownable.initializer(owner);
}

#[abi(embed_v0)]
impl VeCARMImpl of super::IveCARM<ContractState> {
// Did not import Erc20MetaData, so we can change decimals
// so we need to define name, symbol and decimals ourselves
fn name(self: @ContractState) -> felt252 {
'vote escrowed Carmine Token'
}

fn symbol(self: @ContractState) -> felt252 {
'veCARM'
}

fn decimals(self: @ContractState) -> u8 {
18
}

fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
self.ownable.assert_only_owner();
self.erc20._mint(recipient, amount);
}

fn burn(ref self: ContractState, account: ContractAddress, amount: u256) {
self.ownable.assert_only_owner();
self.erc20._burn(account, amount);
}

fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.ownable.assert_only_owner();
assert(!new_class_hash.is_zero(), 'Class hash cannot be zero');
starknet::replace_class_syscall(new_class_hash).unwrap();
self.emit(Upgraded { class_hash: new_class_hash });
}
}
}

1 change: 0 additions & 1 deletion src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ mod treasury_types {
mod constants;
mod contract;
mod merkle_tree;
//mod options;
mod proposals;
mod token;
mod traits;
Expand Down
88 changes: 88 additions & 0 deletions src/testing/setup.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use core::traits::Into;
use array::ArrayTrait;
use core::traits::TryInto;
use debug::PrintTrait;
use starknet::ContractAddress;
use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};
use snforge_std::{
BlockId, declare, ContractClassTrait, ContractClass, start_prank, start_warp, CheatTarget
};
use core::ResultTrait;


use konoha::contract::IGovernanceDispatcher;
use konoha::contract::IGovernanceDispatcherTrait;
use konoha::proposals::IProposalsDispatcher;
use konoha::proposals::IProposalsDispatcherTrait;
use konoha::upgrades::IUpgradesDispatcher;
use konoha::upgrades::IUpgradesDispatcherTrait;
use konoha::constants;
use openzeppelin::token::erc20::interface::IERC20;
use starknet::get_block_timestamp;


const GOV_TOKEN_INITIAL_SUPPLY: felt252 = 1000000000000000000;

const first_address: felt252 = 0x1;
const second_address: felt252 = 0x2;
const admin_addr: felt252 = 0x3;

fn deploy_governance(token_address: ContractAddress) -> IGovernanceDispatcher {
let gov_contract = declare("Governance").expect('unable to declare governance');
let mut args: Array<felt252> = ArrayTrait::new();
args.append(token_address.into());
let (address, _) = gov_contract.deploy(@args).expect('unable to deploy governance');
IGovernanceDispatcher { contract_address: address }
}


fn deploy_and_distribute_gov_tokens(recipient: ContractAddress) -> IERC20Dispatcher {
let mut calldata = ArrayTrait::new();
calldata.append(GOV_TOKEN_INITIAL_SUPPLY);
calldata.append(recipient.into());

let gov_token_contract = declare("FloatingToken").expect('unable to declare FloatingToken');
let (token_addr, _) = gov_token_contract
.deploy(@calldata)
.expect('unable to deploy FloatingToken');
let token: IERC20Dispatcher = IERC20Dispatcher { contract_address: token_addr };

start_prank(CheatTarget::One(token_addr), admin_addr.try_into().unwrap());

token.transfer(first_address.try_into().unwrap(), 100000);
token.transfer(second_address.try_into().unwrap(), 100000);
token
}


fn test_vote_upgrade_root(new_merkle_root: felt252) {
let token_contract = deploy_and_distribute_gov_tokens(admin_addr.try_into().unwrap());
let gov_contract = deploy_governance(token_contract.contract_address);
let gov_contract_addr = gov_contract.contract_address;

let dispatcher = IProposalsDispatcher { contract_address: gov_contract_addr };

start_prank(CheatTarget::One(gov_contract_addr), admin_addr.try_into().unwrap());
let prop_id = dispatcher.submit_proposal(new_merkle_root, 3);

start_prank(CheatTarget::One(gov_contract_addr), first_address.try_into().unwrap());
dispatcher.vote(prop_id, 1);
start_prank(CheatTarget::One(gov_contract_addr), second_address.try_into().unwrap());
dispatcher.vote(prop_id, 1);
start_prank(CheatTarget::One(gov_contract_addr), admin_addr.try_into().unwrap());
dispatcher.vote(prop_id, 1);

assert(dispatcher.get_proposal_status(prop_id) == 1, 'proposal not passed!');

let upgrade_dispatcher = IUpgradesDispatcher { contract_address: gov_contract_addr };
upgrade_dispatcher.apply_passed_proposal(prop_id);
assert(check_if_healthy(gov_contract_addr), 'new gov not healthy');
}

fn check_if_healthy(gov_contract_addr: ContractAddress) -> bool {
// TODO
let dispatcher = IProposalsDispatcher { contract_address: gov_contract_addr };
dispatcher.get_proposal_status(0);
let prop_details = dispatcher.get_proposal_details(0);
(prop_details.payload + prop_details.to_upgrade) != 0
}

0 comments on commit 37d590d

Please sign in to comment.