Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement tests according to missing test list #58 #61

Merged
merged 40 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d4071f4
Add custom proposal implementation
tensojka Apr 25, 2024
25ec5d5
Add arbitrary proposal
tensojka Apr 26, 2024
676a2e2
Polish apply_passed_proposal
tensojka Apr 26, 2024
d178036
Polish scarb fmt
tensojka Apr 26, 2024
1850814
Cherry pick setup.cairo from 1fab54f
tensojka Apr 30, 2024
4a308b9
Move test setup to src/
tensojka Apr 30, 2024
03d1ba5
Remove unrelated functions from setup.cairo
tensojka Apr 30, 2024
82d7947
Fix setup
tensojka Apr 30, 2024
6ed9c58
Polish tests
tensojka Apr 30, 2024
0ef0d64
Add airdrop tests
Nerrolol Mar 20, 2024
aa54ac2
Adding setup file with generic function which applies a proposal to u…
Nerrolol Mar 25, 2024
7f32f99
Setup environment to deploy governance, deploy gov token and distribu…
Nerrolol Apr 16, 2024
a2e7bfa
Add tests on proposals
Nerrolol Apr 26, 2024
3f5f10d
fix some issues on proposal tests
Nerrolol Apr 26, 2024
b944b09
Proposals Frontend (#66)
tomashobza Apr 30, 2024
0e0c0b7
Update README.md
tensojka Apr 30, 2024
c51f55a
Update README.md
tensojka Apr 30, 2024
04f6801
feat: default to_upgrade value (#69)
tomashobza May 3, 2024
9f14427
Telegram Notification bot for proposal (#71)
xkrivan5 May 4, 2024
b144b85
Adding proposals tests
Nerrolol May 13, 2024
d4fdf9b
Comment code for airdrop_tests and remove old setup file
Nerrolol May 13, 2024
2884f06
Add minor fixes towards compilability
tensojka May 14, 2024
89f9028
Fix all proposals tests
Nerrolol May 17, 2024
dc964b5
Fix formatting
tensojka May 20, 2024
72883ab
Proposals Frontend (#66)
tomashobza Apr 30, 2024
b7f718e
feat: default to_upgrade value (#69)
tomashobza May 3, 2024
d622ff9
Update frontend domain to konoha.vote
tensojka May 14, 2024
fc71439
Rename package from 'governance' to 'konoha'
tensojka May 14, 2024
4620dd0
Add contributor guidelines
tensojka May 20, 2024
2a12029
Update README.md with contributing info
tensojka May 20, 2024
32dbf37
Update CONTRIBUTING.md
tensojka May 22, 2024
7b4cb3c
Add mdbook scaffolding (#75)
tensojka May 22, 2024
7cf23cd
Add custom proposal implementation (#64)
tensojka May 23, 2024
9837f69
Remove mentions of Carmine in this repository (#73)
tensojka May 23, 2024
eb1181d
Rename governance:: to konoha::
tensojka May 23, 2024
9f61980
Fix proposals tests and mint tokens to admin addr before distributing…
Nerrolol May 23, 2024
d837e28
Add quorum tests
Nerrolol May 24, 2024
5135607
Move setup to testing, fix tests so they compile
tensojka May 27, 2024
9109ef3
Merge branch master
tensojka May 27, 2024
37d590d
Merge branch 'master' into missing-tests
tensojka May 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag

[lib]


# can be fixed by doing import super::testing from tests
[dev-dependencies]
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.23.0" }

[lib]

[[target.starknet-contract]]

[scripts]
Expand Down
5 changes: 0 additions & 5 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@ mod treasury_types {
mod constants;
mod contract;
mod merkle_tree;
//mod options;
mod proposals;
mod token;
mod traits;
mod treasury;
mod types;
mod upgrades;
mod vesting;
mod govtoken; // if I put this in tests/ , I seem unable to use declare('MyToken')
mod voting_token;
mod testing {
mod setup;
}
87 changes: 87 additions & 0 deletions tests/airdrop_tests.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// use core::hash::HashStateExTrait;
// use core::{ArrayTrait, SpanTrait};
// use core::debug::PrintTrait;
// use governance::airdrop::{airdrop, IAirdropDispatcher, IAirdropDispatcherTrait};
// use airdrop::STRK_ADDRESS;
// use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};
// use snforge_std::{ContractClassTrait, declare, start_prank, CheatTarget};
// use starknet::{ContractAddress, deploy_syscall};

// const ADMIN_ADDR: felt252 = 0x42;
// const CLAIMEE_1: felt252 = 0x13;
// const CLAIMEE_2: felt252 = 0x14;

// fn deploy() -> IAirdropDispatcher {
// let mut calldata = ArrayTrait::new();
// calldata.append(ADMIN_ADDR);

// let contract = declare('Airdrop');
// let address = contract.deploy().expect('unable to deploy Airdrop');
// IAirdropDispatcher { contract_address: address }
// }

// #[test]
// fn test_claim_twice_with_same_proof() {
// let airdrop_contract = deploy();
// let token_contract = deploy_token(airdrop_contract.contract_address);

// start_prank(
// CheatTarget::One(airdrop_contract.contract_address), ADMIN_ADDR.try_into().unwrap()
// );
// airdrop_contract.add_root(valid_root);

// start_prank(CheatTarget::One(airdrop_contract.contract_address), CLAIMEE_1.try_into().unwrap());
// let initial_proof = array![valid_proof_element];
// airdrop_contract.claim(CLAIMEE_1, valid_claim_amount, initial_proof.span());
// assert(
// token_contract.balance_of(CLAIMEE_1.try_into().unwrap()) == valid_claim_amount,
// "First claim failed"
// );

// airdrop_contract.claim(CLAIMEE_1, valid_claim_amount, initial_proof.span());
// assert(
// token_contract.balance_of(CLAIMEE_1.try_into().unwrap()) == valid_claim_amount,
// "Second claim modified the claimee's balance"
// );
// }

// #[test]
// #[should_panic(expected: ('INVALID PROOF',))]
// fn test_claim_invalid_proof() {
// let contract = deploy();
// deploy_token(contract.contract_address);
// start_prank(CheatTarget::One(contract.contract_address), ADMIN_ADDR.try_into().unwrap());
// contract.add_root(0xf7c8d3f309262572ad35df8ff6c33f24d8114c60eac3bc27bf42382ca82faf);

// start_prank(CheatTarget::One(contract.contract_address), CLAIMEE_1.try_into().unwrap());
// let proof = array![0x2a18afb0550a011d54ca3940648e59894c06e4c3d0a611256c0b575bd528b3b, 0x1];
// contract.claim(0x88, proof.span());
// }

// #[test]
// fn test_update_root_and_claim_attempts() {
// let contract = deploy();
// let tok = deploy_token(contract.contract_address);
// start_prank(CheatTarget::One(contract.contract_address), ADMIN_ADDR.try_into().unwrap());

// // add intial root and valid claim
// contract.add_root(initial_root);
// start_prank(CheatTarget::One(contract.contract_address), CLAIMEE_1.try_into().unwrap());
// contract.claim(claim_amount, valid_proof_for_initial_root.span());
// assert(tok.balance_of(CLAIMEE_1.try_into().unwrap()) == claim_amount, 'initial claim failed');

// // update root
// start_prank(CheatTarget::One(contract.contract_address), ADMIN_ADDR.try_into().unwrap());
// contract.add_root(new_root);

// // claim with old root + new proof, should fail
// start_prank(CheatTarget::One(contract.contract_address), CLAIMEE_2.try_into().unwrap());
// contract.claim(claim_amount, new_proof_not_matching_old_root.span());
// // check fail : to do, use should panic ?

// // claim with new root + old proof, should fail
// contract.claim(claim_amount, old_proof_not_matching_new_root.span());
// // check fail : to do
// }


2 changes: 1 addition & 1 deletion tests/basic.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn test_submit_proposal() {
let dispatcher = IProposalsDispatcher { contract_address: gov_contract_addr };
// corresponding govtoken: 0x05151bfdd47826df3669033ea7fb977d3b2d45c4f4d1c439a9edf4062bf34bfa
// has one holder, with 31 CARM: 0x0583a9d956d65628f806386ab5b12dccd74236a3c6b930ded9cf3c54efc722a1
let admin_addr: ContractAddress =
let _admin_addr: ContractAddress =
0x0583a9d956d65628f806386ab5b12dccd74236a3c6b930ded9cf3c54efc722a1
.try_into()
.unwrap();
Expand Down
4 changes: 3 additions & 1 deletion tests/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod vesting;
mod basic;
mod test_treasury;
mod proposals_tests;
mod airdrop_tests;
mod setup;
164 changes: 164 additions & 0 deletions tests/proposals_tests.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use array::ArrayTrait;
use core::traits::TryInto;
use debug::PrintTrait;
use starknet::ContractAddress;
use openzeppelin::token::erc20::interface::{
IERC20Dispatcher, IERC20DispatcherTrait, IERC20CamelOnlyDispatcher,
IERC20CamelOnlyDispatcherTrait
};
use snforge_std::{
BlockId, declare, ContractClassTrait, ContractClass, start_prank, start_warp, CheatTarget,
prank, CheatSpan
};

use super::setup::{
admin_addr, first_address, second_address, deploy_governance, deploy_and_distribute_gov_tokens,
test_vote_upgrade_root, check_if_healthy
};
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 starknet::get_block_timestamp;


const GOV_TOKEN_INITIAL_SUPPLY: felt252 = 1000000000000000000;


fn test_express_proposal() {
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(42, 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!");
}

#[test]
fn test_proposal_expiry() {
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(42, 1);

//simulate passage of time
let current_timestamp = get_block_timestamp();
let end_timestamp = current_timestamp + constants::PROPOSAL_VOTING_SECONDS;
start_warp(CheatTarget::One(gov_contract_addr), end_timestamp + 1);

let status = dispatcher.get_proposal_status(prop_id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add check that status is -1 (or 2? not sure) meaning it failed.

assert!(status == constants::MINUS_ONE, "proposal not expired!");
}

#[test]
#[should_panic(expected: ('voting concluded',))]
fn test_vote_on_expired_proposal() {
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(42, 1);

//simulate passage of time
let current_timestamp = get_block_timestamp();
let end_timestamp = current_timestamp + constants::PROPOSAL_VOTING_SECONDS;
start_warp(CheatTarget::One(gov_contract_addr), end_timestamp + 1);

prank(
CheatTarget::One(token_contract.contract_address),
admin_addr.try_into().unwrap(),
CheatSpan::TargetCalls(1)
);
token_contract.transfer(first_address.try_into().unwrap(), 100000.try_into().unwrap());
start_prank(CheatTarget::One(gov_contract_addr), first_address.try_into().unwrap());
dispatcher.vote(prop_id, 1);
}

#[test]
fn test_vote_on_quorum_not_met() {
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 };

prank(
CheatTarget::One(gov_contract_addr),
admin_addr.try_into().unwrap(),
CheatSpan::TargetCalls(1)
);
let prop_id = dispatcher.submit_proposal(42, 1);

prank(
CheatTarget::One(token_contract.contract_address),
admin_addr.try_into().unwrap(),
CheatSpan::TargetCalls(1)
);
token_contract.transfer(first_address.try_into().unwrap(), 100000.try_into().unwrap());

prank(
CheatTarget::One(gov_contract_addr),
first_address.try_into().unwrap(),
CheatSpan::TargetCalls(1)
);
dispatcher.vote(prop_id, 1);

let (yay_votes, nay_votes) = dispatcher.get_vote_counts(prop_id);
let total_votes = yay_votes + nay_votes;
let total_eligible_votes: u128 = IERC20CamelOnlyDispatcher {
contract_address: token_contract.contract_address
}
.totalSupply()
.low;
let quorum_threshold = total_eligible_votes * constants::QUORUM / 100;

assert(total_votes < quorum_threshold, 'Total votes >= quorum threshold');
let current_timestamp = get_block_timestamp();
let end_timestamp = current_timestamp + constants::PROPOSAL_VOTING_SECONDS;
start_warp(CheatTarget::One(gov_contract_addr), end_timestamp + 1);
assert(
dispatcher.get_proposal_status(prop_id) == constants::MINUS_ONE,
'Proposal pass & quorum not met'
);
}

#[test]
#[should_panic(expected: ('not enough tokens to submit',))]
fn test_submit_proposal_under_quorum() {
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 };

prank(
CheatTarget::One(token_contract.contract_address),
admin_addr.try_into().unwrap(),
CheatSpan::TargetCalls(1)
);
token_contract.transfer(first_address.try_into().unwrap(), 100000.try_into().unwrap());

prank(
CheatTarget::One(gov_contract_addr),
first_address.try_into().unwrap(),
CheatSpan::TargetCalls(1)
);
dispatcher.submit_proposal(42, 1);
}
83 changes: 83 additions & 0 deletions tests/setup.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
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: u256 = 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.low.into());
calldata.append(GOV_TOKEN_INITIAL_SUPPLY.high.into());
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');
IERC20Dispatcher { contract_address: token_addr }
}


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
}
Loading