From 5b966c9db7ac63bdae04aeae50f46e89a4f58cd3 Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Mon, 28 Jul 2025 07:23:45 +0100 Subject: [PATCH 1/9] test start --- contract_/tests/test_partner_share_cap.cairo | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/contract_/tests/test_partner_share_cap.cairo b/contract_/tests/test_partner_share_cap.cairo index 91bfaf1..f36adfd 100644 --- a/contract_/tests/test_partner_share_cap.cairo +++ b/contract_/tests/test_partner_share_cap.cairo @@ -7,13 +7,13 @@ use snforge_std::{ }; use starknet::{ContractAddress, contract_address_const}; -const OWNER: felt252 = 'owner'; -const USER1: felt252 = 'user1'; -const USER2: felt252 = 'user2'; +pub const OWNER: felt252 = 'owner'; +pub const USER1: felt252 = 'user1'; +pub const USER2: felt252 = 'user2'; const USDT_INITIAL_SUPPLY: u256 = 1000000000000_u256; // 1M USDT with 6 decimals const USDC_INITIAL_SUPPLY: u256 = 1000000000000_u256; // 1M USDC with 6 decimals -fn deploy_mock_erc20( +pub fn deploy_mock_erc20( name: felt252, symbol: felt252, initial_supply: u256, recipient: ContractAddress, ) -> ContractAddress { let contract = declare("MockERC20").unwrap().contract_class(); @@ -39,7 +39,7 @@ fn deploy_mock_erc20( contract_address } -fn deploy_big_inc_genesis( +pub fn deploy_big_inc_genesis( usdt_address: ContractAddress, usdc_address: ContractAddress, ) -> ContractAddress { let contract = declare("BigIncGenesis").unwrap().contract_class(); @@ -53,7 +53,7 @@ fn deploy_big_inc_genesis( contract_address } -fn setup() -> (ContractAddress, ContractAddress, ContractAddress) { +pub fn setup() -> (ContractAddress, ContractAddress, ContractAddress) { let user1 = contract_address_const::(); let usdt_address = deploy_mock_erc20('USDT', 'USDT', USDT_INITIAL_SUPPLY, user1); let usdc_address = deploy_mock_erc20('USDC', 'USDC', USDC_INITIAL_SUPPLY, user1); @@ -62,7 +62,7 @@ fn setup() -> (ContractAddress, ContractAddress, ContractAddress) { (big_inc_address, usdt_address, usdc_address) } -#[cfg(test)] +#[test] fn test_set_partner_share_cap_success() { let (big_inc_address, usdt_address, _usdc_address) = setup(); let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; @@ -78,7 +78,7 @@ fn test_set_partner_share_cap_success() { assert(cap == 10000000_u256, 'Partner cap not set correctly'); } -#[cfg(test)] +#[test] #[should_panic(expected: ('Caller is not the owner',))] fn test_set_partner_share_cap_not_owner() { let (big_inc_address, usdt_address, _usdc_address) = setup(); @@ -91,7 +91,7 @@ fn test_set_partner_share_cap_not_owner() { stop_cheat_caller_address(big_inc_address); } -#[cfg(test)] +#[test] #[should_panic(expected: ('Invalid token address',))] fn test_set_partner_share_cap_invalid_token() { let (big_inc_address, _usdt_address, _usdc_address) = setup(); @@ -105,7 +105,7 @@ fn test_set_partner_share_cap_invalid_token() { stop_cheat_caller_address(big_inc_address); } -#[cfg(test)] +#[test] fn test_remove_partner_share_cap_success() { let (big_inc_address, usdt_address, _usdc_address) = setup(); let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; From 99aabc2b4808a29073b95445bb2b5e77c64e6023 Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Tue, 29 Jul 2025 05:37:40 +0100 Subject: [PATCH 2/9] implemented genesis_mint_share_success --- contract_/src/BigIncGenesis.cairo | 10 +-- contract_/tests/mock_erc20.cairo | 84 +++++++++++++++++++++++ contract_/tests/setup.cairo | 54 +++++++++++++++ contract_/tests/test_contract.cairo | 100 ++++++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 5 deletions(-) create mode 100644 contract_/tests/mock_erc20.cairo create mode 100644 contract_/tests/setup.cairo diff --git a/contract_/src/BigIncGenesis.cairo b/contract_/src/BigIncGenesis.cairo index 1f6c560..c66e717 100644 --- a/contract_/src/BigIncGenesis.cairo +++ b/contract_/src/BigIncGenesis.cairo @@ -109,7 +109,7 @@ pub mod BigIncGenesis { #[event] #[derive(Drop, starknet::Event)] - enum Event { + pub enum Event { #[flat] OwnableEvent: OwnableComponent::Event, #[flat] @@ -128,11 +128,11 @@ pub mod BigIncGenesis { } #[derive(Drop, starknet::Event)] - struct ShareMinted { + pub struct ShareMinted { #[key] - buyer: ContractAddress, - shares_bought: u256, - amount: u256, + pub buyer: ContractAddress, + pub shares_bought: u256, + pub amount: u256, } #[derive(Drop, starknet::Event)] diff --git a/contract_/tests/mock_erc20.cairo b/contract_/tests/mock_erc20.cairo new file mode 100644 index 0000000..d7d5e54 --- /dev/null +++ b/contract_/tests/mock_erc20.cairo @@ -0,0 +1,84 @@ +use starknet::ContractAddress; + +#[starknet::interface] +pub trait IMintable { + // Add the external mint function for testing purposes + fn mint(ref self: TContractState, recipient: ContractAddress, amount: u256); +} + +#[starknet::contract] +pub mod MockERC20 { + use openzeppelin::access::ownable::OwnableComponent; + use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl}; + use openzeppelin::upgrades::UpgradeableComponent; + use openzeppelin::upgrades::interface::IUpgradeable; + use starknet::{ClassHash, ContractAddress}; + use super::IMintable; + + component!(path: ERC20Component, storage: erc20, event: ERC20Event); + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent); + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent); + + // External + #[abi(embed_v0)] + impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl; + #[abi(embed_v0)] + impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl; + + // Internal + impl ERC20InternalImpl = ERC20Component::InternalImpl; + impl OwnableInternalImpl = OwnableComponent::InternalImpl; + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + erc20: ERC20Component::Storage, + #[substorage(v0)] + ownable: OwnableComponent::Storage, + #[substorage(v0)] + upgradeable: UpgradeableComponent::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + ERC20Event: ERC20Component::Event, + #[flat] + OwnableEvent: OwnableComponent::Event, + #[flat] + UpgradeableEvent: UpgradeableComponent::Event, + } + + #[constructor] + fn constructor( + ref self: ContractState, + owner: ContractAddress, + name: ByteArray, + symbol: ByteArray, + supply: u256, + ) { + self.erc20.initializer(name, symbol); + // Mint some initial tokens to the owner + self.erc20.mint(owner, supply); + + self.ownable.initializer(owner); + } + + #[abi(embed_v0)] + impl ITestTokensImpl of IMintable { + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { + self.ownable.assert_only_owner(); + self.erc20.mint(recipient, amount); + } + } + + #[abi(embed_v0)] + impl UpgradeableImpl of IUpgradeable { + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) { + self.ownable.assert_only_owner(); + self.upgradeable.upgrade(new_class_hash); + } + } +} diff --git a/contract_/tests/setup.cairo b/contract_/tests/setup.cairo new file mode 100644 index 0000000..21003cd --- /dev/null +++ b/contract_/tests/setup.cairo @@ -0,0 +1,54 @@ +use contract_::BigIncGenesis::IBigIncGenesisDispatcher; +use core::result::ResultTrait; +use openzeppelin::token::erc20::interface::IERC20Dispatcher; +use openzeppelin::utils::serde::SerializedAppend; +use snforge_std::{ + ContractClassTrait, DeclareResultTrait, declare, start_cheat_caller_address, + stop_cheat_caller_address, +}; +use starknet::{ContractAddress, contract_address_const}; + +pub const OWNER: felt252 = 'owner'; +pub const USER1: felt252 = 'user1'; +pub const USER2: felt252 = 'user2'; +const USDT_INITIAL_SUPPLY: u256 = 1000000000000_u256; // 1M USDT with 6 decimals +const USDC_INITIAL_SUPPLY: u256 = 1000000000000_u256; // 1M USDC with 6 decimals + +pub fn owner() -> ContractAddress { + OWNER.try_into().unwrap() +} + +pub fn deploy_mock_erc20( + name: ByteArray, symbol: ByteArray, initial_supply: u256, recipient: ContractAddress, +) -> ContractAddress { + let contract = declare("MockERC20").unwrap().contract_class(); + let mut constructor_args = array![]; + constructor_args.append_serde(name); + constructor_args.append_serde(symbol); + constructor_args.append_serde(initial_supply); + constructor_args.append_serde(recipient); + + let (contract_address, _) = contract.deploy(@constructor_args).unwrap(); + contract_address +} + +pub fn deploy_big_inc_genesis( + usdt_address: ContractAddress, usdc_address: ContractAddress, +) -> ContractAddress { + let contract = declare("BigIncGenesis").unwrap().contract_class(); + let (contract_address, _) = contract + .deploy(@array![usdt_address.into(), usdc_address.into(), OWNER.try_into().unwrap()]) + .unwrap(); + contract_address +} + +pub fn setup() -> (IBigIncGenesisDispatcher, IERC20Dispatcher, IERC20Dispatcher) { + let usdt_address = deploy_mock_erc20("USDT", "USDT", USDT_INITIAL_SUPPLY, owner()); + let usdc_address = deploy_mock_erc20("USDC", "USDC", USDC_INITIAL_SUPPLY, owner()); + let big_inc_address = deploy_big_inc_genesis(usdt_address, usdc_address); + let genesis_dispatcher = IBigIncGenesisDispatcher { contract_address: big_inc_address }; + let usdt_dispatcher = IERC20Dispatcher { contract_address: usdt_address }; + let usdc_dispatcher = IERC20Dispatcher { contract_address: usdc_address }; + + (genesis_dispatcher, usdt_dispatcher, usdc_dispatcher) +} diff --git a/contract_/tests/test_contract.cairo b/contract_/tests/test_contract.cairo index 8b13789..7a19d99 100644 --- a/contract_/tests/test_contract.cairo +++ b/contract_/tests/test_contract.cairo @@ -1 +1,101 @@ +use contract_::BigIncGenesis::{BigIncGenesis, IBigIncGenesisDispatcherTrait}; +use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; +use snforge_std::{CheatSpan, EventSpyAssertionsTrait, cheat_caller_address, spy_events}; +use starknet::{ContractAddress, contract_address_const}; +use super::setup::{owner, setup}; + + +// fn mint_share(ref self: TContractState, token_address: ContractAddress); +// fn transfer_share(ref self: TContractState, to: ContractAddress, share_amount: u256); +// fn donate(ref self: TContractState, token_address: ContractAddress, amount: u256); + +// // View functions +// fn get_available_shares(self: @TContractState) -> u256; +// fn get_shares(self: @TContractState, addr: ContractAddress) -> u256; +// fn get_shareholders(self: @TContractState) -> Array; +// fn is_shareholder(self: @TContractState, addr: ContractAddress) -> bool; +// fn get_usdt_address(self: @TContractState) -> ContractAddress; +// fn get_usdc_address(self: @TContractState) -> ContractAddress; +// fn get_total_share_valuation(self: @TContractState) -> u256; +// fn get_presale_share_valuation(self: @TContractState) -> u256; +// fn get_presale_shares(self: @TContractState) -> u256; +// fn get_shares_sold(self: @TContractState) -> u256; +// fn is_presale_active(self: @TContractState) -> bool; + +// // Owner functions +// fn withdraw(ref self: TContractState, token_address: ContractAddress, amount: u256); +// fn seize_shares(ref self: TContractState, shareholder: ContractAddress); +// fn set_partner_share_cap(ref self: TContractState, token_address: ContractAddress, cap: +// u256); +// fn remove_partner_share_cap(ref self: TContractState, token_address: ContractAddress); +// fn pause(ref self: TContractState); +// fn unpause(ref self: TContractState); + +// // Partner view functions +// fn get_partner_share_cap(self: @TContractState, token_address: ContractAddress) -> u256; +// fn get_shares_minted_by_partner(self: @TContractState, token_address: ContractAddress) -> +// u256; + +// // Ownable functions +// fn get_owner(self: @TContractState) -> ContractAddress; +// fn transfer_owner(ref self: TContractState, new_owner: ContractAddress); +// fn renounce_owner(ref self: TContractState); + +// // Partner token functions +// fn mint_partner_share( +// ref self: TContractState, token_address: ContractAddress, token_amount: u256, +// ); +// fn set_partner_token_rate( +// ref self: TContractState, token_address: ContractAddress, tokens_per_share: u256, +// ); +// fn get_partner_token_rate(self: @TContractState, token_address: ContractAddress) -> u256; + +fn alice() -> ContractAddress { + 'alice'.try_into().unwrap() +} + +fn charlie() -> ContractAddress { + 'charlie'.try_into().unwrap() +} + +fn mint(targets: Array<(ContractAddress, u256)>, dispatcher: IERC20Dispatcher) { + for i in 0..targets.len() { + let (recipient, amount) = *targets.at(i); + cheat_caller_address(dispatcher.contract_address, owner(), CheatSpan::TargetCalls(1)); + dispatcher.transfer(recipient, amount); + } +} + +#[test] +fn test_genesis_mint_share_success() { + let (genesis, usdt, _) = setup(); + let amount = 10000; + mint(array![(charlie(), amount)], usdt); + cheat_caller_address(usdt.contract_address, charlie(), CheatSpan::TargetCalls(1)); + usdt.approve(genesis.contract_address, amount); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); + let mut spy = spy_events(); + genesis.mint_share(usdt.contract_address); + + let presale_share_valuation = genesis.get_presale_share_valuation(); + let shares_bought = (amount * 100000000_u256) / presale_share_valuation; + let shares_sold = genesis.get_shares_sold(); + assert(shares_bought == shares_sold, 'SHARES VALUATION MISMATCH'); + let is_shareholder = genesis.is_shareholder(charlie()); + assert(is_shareholder, 'CHARLIE NOT SHAREHOLDER'); + + let event = BigIncGenesis::Event::ShareMinted( + BigIncGenesis::ShareMinted { buyer: charlie(), shares_bought, amount }, + ); + + spy.assert_emitted(@array![(genesis.contract_address, event)]); +} + +#[test] +#[should_panic(expected: 'Invalid token address')] +fn test_genesis_mint_share_should_panic_on_invalid_token() {} + +#[test] +#[should_panic(expected: 'Exceeds available shares')] +fn test_genesis_mint_share_should_panic_on_partner_share_cap_exceeded() {} From 820f6872939d69a4b3730446e0d6a53a9eece1bd Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Tue, 29 Jul 2025 06:04:07 +0100 Subject: [PATCH 3/9] genesis mint share should panic on invalid token tests --- contract_/tests/test_contract.cairo | 33 +++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/contract_/tests/test_contract.cairo b/contract_/tests/test_contract.cairo index 7a19d99..a8a7676 100644 --- a/contract_/tests/test_contract.cairo +++ b/contract_/tests/test_contract.cairo @@ -1,8 +1,8 @@ -use contract_::BigIncGenesis::{BigIncGenesis, IBigIncGenesisDispatcherTrait}; +use contract_::BigIncGenesis::{BigIncGenesis, IBigIncGenesisDispatcher, IBigIncGenesisDispatcherTrait}; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use snforge_std::{CheatSpan, EventSpyAssertionsTrait, cheat_caller_address, spy_events}; -use starknet::{ContractAddress, contract_address_const}; -use super::setup::{owner, setup}; +use starknet::{ContractAddress}; +use super::setup::{owner, setup, deploy_mock_erc20}; // fn mint_share(ref self: TContractState, token_address: ContractAddress); @@ -66,16 +66,20 @@ fn mint(targets: Array<(ContractAddress, u256)>, dispatcher: IERC20Dispatcher) { } } +fn feign_mint_share(genesis: IBigIncGenesisDispatcher, token: IERC20Dispatcher, amount: u256) { + mint(array![(charlie(), amount)], token); + cheat_caller_address(token.contract_address, charlie(), CheatSpan::TargetCalls(1)); + token.approve(genesis.contract_address, amount); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); + genesis.mint_share(token.contract_address); +} + #[test] fn test_genesis_mint_share_success() { let (genesis, usdt, _) = setup(); let amount = 10000; - mint(array![(charlie(), amount)], usdt); - cheat_caller_address(usdt.contract_address, charlie(), CheatSpan::TargetCalls(1)); - usdt.approve(genesis.contract_address, amount); - cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); let mut spy = spy_events(); - genesis.mint_share(usdt.contract_address); + feign_mint_share(genesis, usdt, amount); let presale_share_valuation = genesis.get_presale_share_valuation(); let shares_bought = (amount * 100000000_u256) / presale_share_valuation; @@ -93,9 +97,20 @@ fn test_genesis_mint_share_success() { #[test] #[should_panic(expected: 'Invalid token address')] -fn test_genesis_mint_share_should_panic_on_invalid_token() {} +fn test_genesis_mint_share_should_panic_on_invalid_token() { + let (genesis, _, _) = setup(); + let amount = 1000; + let contract_address = deploy_mock_erc20("TOKEN", "TKN", 1000000, owner()); + let token = IERC20Dispatcher { contract_address }; + feign_mint_share(genesis, token, amount); +} #[test] #[should_panic(expected: 'Exceeds available shares')] fn test_genesis_mint_share_should_panic_on_partner_share_cap_exceeded() {} +#[test] +fn test_genesis_transfer_share_success() { + +} + From 4b229c949d4f1c38b9d3b64c16e653b4dc228c19 Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Tue, 29 Jul 2025 10:50:39 +0100 Subject: [PATCH 4/9] tested genesis transfer share success --- contract_/src/BigIncGenesis.cairo | 8 +-- contract_/tests/test_contract.cairo | 75 ++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/contract_/src/BigIncGenesis.cairo b/contract_/src/BigIncGenesis.cairo index c66e717..55e041f 100644 --- a/contract_/src/BigIncGenesis.cairo +++ b/contract_/src/BigIncGenesis.cairo @@ -139,12 +139,12 @@ pub mod BigIncGenesis { struct PresaleEnded {} #[derive(Drop, starknet::Event)] - struct TransferShare { + pub struct TransferShare { #[key] - from: ContractAddress, + pub from: ContractAddress, #[key] - to: ContractAddress, - share_amount: u256, + pub to: ContractAddress, + pub share_amount: u256, } #[derive(Drop, starknet::Event)] diff --git a/contract_/tests/test_contract.cairo b/contract_/tests/test_contract.cairo index a8a7676..f012517 100644 --- a/contract_/tests/test_contract.cairo +++ b/contract_/tests/test_contract.cairo @@ -1,8 +1,10 @@ -use contract_::BigIncGenesis::{BigIncGenesis, IBigIncGenesisDispatcher, IBigIncGenesisDispatcherTrait}; +use contract_::BigIncGenesis::{ + BigIncGenesis, IBigIncGenesisDispatcher, IBigIncGenesisDispatcherTrait, +}; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use snforge_std::{CheatSpan, EventSpyAssertionsTrait, cheat_caller_address, spy_events}; -use starknet::{ContractAddress}; -use super::setup::{owner, setup, deploy_mock_erc20}; +use starknet::ContractAddress; +use super::setup::{deploy_mock_erc20, owner, setup}; // fn mint_share(ref self: TContractState, token_address: ContractAddress); @@ -105,12 +107,73 @@ fn test_genesis_mint_share_should_panic_on_invalid_token() { feign_mint_share(genesis, token, amount); } -#[test] -#[should_panic(expected: 'Exceeds available shares')] -fn test_genesis_mint_share_should_panic_on_partner_share_cap_exceeded() {} +fn default_mint_context() -> (IBigIncGenesisDispatcher, IERC20Dispatcher) { + let (genesis, usdt, _) = setup(); + let amount = 10000; + feign_mint_share(genesis, usdt, amount); + (genesis, usdt) +} #[test] fn test_genesis_transfer_share_success() { + let (genesis, _) = default_mint_context(); + // shares have been minted to charlie + let shares = genesis.get_shares(charlie()); + let alice_shares = genesis.get_shares(alice()); + assert(alice_shares == 0, 'ALICE SHOULD HAVE NO SHARES'); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); + let amount = shares / 2; + let remaining_amount = shares - amount; + + let mut spy = spy_events(); + genesis.transfer_share(alice(), amount); + let alice_shares = genesis.get_shares(alice()); + assert(alice_shares == amount, 'ALICE SHARES MISMATCH'); + + let shares = genesis.get_shares(charlie()); + assert(shares == remaining_amount, 'CHARLIE SHARES MISMATCH'); + + let share_holders = genesis.get_shareholders(); + assert(share_holders.len() == 2, 'INCORRECT SHARE HOLDERS'); + + let event = BigIncGenesis::Event::TransferShare( + BigIncGenesis::TransferShare { from: charlie(), to: alice(), share_amount: amount }, + ); + spy.assert_emitted(@array![(genesis.contract_address, event)]); } +#[test] +#[should_panic(expected: 'Insufficient shares')] +fn test_genesis_transfer_share_should_panic_on_insufficient_shares() {} + +#[test] +#[should_panic(expected: 'Cannot transfer to zero address')] +fn test_genesis_transfer_share_should_panic_on_zero_address() {} + +#[test] +#[should_panic(expected: 'Exceeds available shares')] +fn test_genesis_mint_share_should_panic_on_exceeded_available_shares() {} + +// let partner_cap = self.partner_share_cap.read(token_address); +// if partner_cap > 0 { +// let current_partner_shares = self.shares_minted_by_partner.read(token_address); +// assert( +// current_partner_shares + shares_received <= partner_cap, +// 'Exceeds partner share cap', +// ); +// self +// .shares_minted_by_partner +// .write(token_address, current_partner_shares + shares_received); +// } + +#[test] +#[should_panic(expected: 'Exceeds partner share cap')] +fn test_genesis_mint_share_should_panic_on_partner_share_cap_exceeded() { + let (genesis, usdt, _) = setup(); + let amount = 0; +} + +#[test] +fn test_genesis_transfer_share_success() {} + From 40ddac0ebcc5183e07ce05a03e24ff3d6fe3e2c0 Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Tue, 29 Jul 2025 16:58:20 +0100 Subject: [PATCH 5/9] test genesis donate success --- contract_/src/BigIncGenesis.cairo | 8 +++---- contract_/tests/test_contract.cairo | 37 +++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/contract_/src/BigIncGenesis.cairo b/contract_/src/BigIncGenesis.cairo index 55e041f..8aaf2a7 100644 --- a/contract_/src/BigIncGenesis.cairo +++ b/contract_/src/BigIncGenesis.cairo @@ -148,11 +148,11 @@ pub mod BigIncGenesis { } #[derive(Drop, starknet::Event)] - struct Donate { + pub struct Donate { #[key] - donor: ContractAddress, - token_address: ContractAddress, - amount: u256, + pub donor: ContractAddress, + pub token_address: ContractAddress, + pub amount: u256, } #[derive(Drop, starknet::Event)] diff --git a/contract_/tests/test_contract.cairo b/contract_/tests/test_contract.cairo index f012517..44e933d 100644 --- a/contract_/tests/test_contract.cairo +++ b/contract_/tests/test_contract.cairo @@ -1,6 +1,7 @@ use contract_::BigIncGenesis::{ BigIncGenesis, IBigIncGenesisDispatcher, IBigIncGenesisDispatcherTrait, }; +use core::num::traits::Zero; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use snforge_std::{CheatSpan, EventSpyAssertionsTrait, cheat_caller_address, spy_events}; use starknet::ContractAddress; @@ -145,11 +146,43 @@ fn test_genesis_transfer_share_success() { #[test] #[should_panic(expected: 'Insufficient shares')] -fn test_genesis_transfer_share_should_panic_on_insufficient_shares() {} +fn test_genesis_transfer_share_should_panic_on_insufficient_shares() { + let (genesis, _) = default_mint_context(); + let shares = genesis.get_shares(charlie()); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::Indefinite); + genesis.transfer_share(alice(), shares + 1); +} #[test] #[should_panic(expected: 'Cannot transfer to zero address')] -fn test_genesis_transfer_share_should_panic_on_zero_address() {} +fn test_genesis_transfer_share_should_panic_on_zero_address() { + let (genesis, _) = default_mint_context(); + let shares = genesis.get_shares(charlie()); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::Indefinite); + genesis.transfer_share(Zero::zero(), shares); +} + +#[test] +fn test_genesis_donate_success() { + let (genesis, usdt, _) = setup(); + let amount = 1000; + mint(array![(charlie(), amount)], usdt); + let mut spy = spy_events(); + let previous_balance = usdt.balance_of(genesis.contract_address); + assert(previous_balance == 0, 'PREV BALANCE SHOULD BE ZERO'); + + cheat_caller_address(usdt.contract_address, charlie(), CheatSpan::TargetCalls(1)); + usdt.approve(genesis.contract_address, amount); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); + genesis.donate(usdt.contract_address, amount); + + let new_balance = usdt.balance_of(genesis.contract_address); + assert(new_balance == amount, 'CONTRACT BALANCE MISMATCH'); + let event = BigIncGenesis::Event::Donate( + BigIncGenesis::Donate { donor: charlie(), token_address: usdt.contract_address, amount }, + ); + spy.assert_emitted(@array![(genesis.contract_address, event)]); +} #[test] #[should_panic(expected: 'Exceeds available shares')] From 6a22dbb49efbca8727d1c6662d5ca8b6a3c9d2af Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Wed, 30 Jul 2025 22:28:45 +0100 Subject: [PATCH 6/9] more tests on woner functions --- contract_/src/BigIncGenesis.cairo | 36 ++--- contract_/tests/test_contract.cairo | 215 +++++++++++++++++++--------- 2 files changed, 169 insertions(+), 82 deletions(-) diff --git a/contract_/src/BigIncGenesis.cairo b/contract_/src/BigIncGenesis.cairo index 8aaf2a7..3138a56 100644 --- a/contract_/src/BigIncGenesis.cairo +++ b/contract_/src/BigIncGenesis.cairo @@ -156,41 +156,41 @@ pub mod BigIncGenesis { } #[derive(Drop, starknet::Event)] - struct SharesSeized { + pub struct SharesSeized { #[key] - shareholder: ContractAddress, - share_amount: u256, + pub shareholder: ContractAddress, + pub share_amount: u256, } #[derive(Drop, starknet::Event)] - struct AllSharesSold {} + pub struct AllSharesSold {} #[derive(Drop, starknet::Event)] - struct Withdrawn { + pub struct Withdrawn { #[key] - token_address: ContractAddress, - amount: u256, - owner: ContractAddress, - timestamp: u256, + pub token_address: ContractAddress, + pub amount: u256, + pub owner: ContractAddress, + pub timestamp: u256, } #[derive(Drop, starknet::Event)] - struct PartnerShareCapSet { + pub struct PartnerShareCapSet { #[key] - token_address: ContractAddress, - cap: u256, + pub token_address: ContractAddress, + pub cap: u256, } #[derive(Drop, starknet::Event)] - struct PartnerShareMinted { + pub struct PartnerShareMinted { #[key] - token_address: ContractAddress, + pub token_address: ContractAddress, #[key] - buyer: ContractAddress, - amount_paid: u256, - shares_received: u256, - rate: u256, + pub buyer: ContractAddress, + pub amount_paid: u256, + pub shares_received: u256, + pub rate: u256, } #[constructor] diff --git a/contract_/tests/test_contract.cairo b/contract_/tests/test_contract.cairo index 44e933d..be2c0ff 100644 --- a/contract_/tests/test_contract.cairo +++ b/contract_/tests/test_contract.cairo @@ -3,56 +3,12 @@ use contract_::BigIncGenesis::{ }; use core::num::traits::Zero; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; -use snforge_std::{CheatSpan, EventSpyAssertionsTrait, cheat_caller_address, spy_events}; +use snforge_std::{ + CheatSpan, EventSpyAssertionsTrait, cheat_block_timestamp, cheat_caller_address, spy_events, +}; use starknet::ContractAddress; use super::setup::{deploy_mock_erc20, owner, setup}; - -// fn mint_share(ref self: TContractState, token_address: ContractAddress); -// fn transfer_share(ref self: TContractState, to: ContractAddress, share_amount: u256); -// fn donate(ref self: TContractState, token_address: ContractAddress, amount: u256); - -// // View functions -// fn get_available_shares(self: @TContractState) -> u256; -// fn get_shares(self: @TContractState, addr: ContractAddress) -> u256; -// fn get_shareholders(self: @TContractState) -> Array; -// fn is_shareholder(self: @TContractState, addr: ContractAddress) -> bool; -// fn get_usdt_address(self: @TContractState) -> ContractAddress; -// fn get_usdc_address(self: @TContractState) -> ContractAddress; -// fn get_total_share_valuation(self: @TContractState) -> u256; -// fn get_presale_share_valuation(self: @TContractState) -> u256; -// fn get_presale_shares(self: @TContractState) -> u256; -// fn get_shares_sold(self: @TContractState) -> u256; -// fn is_presale_active(self: @TContractState) -> bool; - -// // Owner functions -// fn withdraw(ref self: TContractState, token_address: ContractAddress, amount: u256); -// fn seize_shares(ref self: TContractState, shareholder: ContractAddress); -// fn set_partner_share_cap(ref self: TContractState, token_address: ContractAddress, cap: -// u256); -// fn remove_partner_share_cap(ref self: TContractState, token_address: ContractAddress); -// fn pause(ref self: TContractState); -// fn unpause(ref self: TContractState); - -// // Partner view functions -// fn get_partner_share_cap(self: @TContractState, token_address: ContractAddress) -> u256; -// fn get_shares_minted_by_partner(self: @TContractState, token_address: ContractAddress) -> -// u256; - -// // Ownable functions -// fn get_owner(self: @TContractState) -> ContractAddress; -// fn transfer_owner(ref self: TContractState, new_owner: ContractAddress); -// fn renounce_owner(ref self: TContractState); - -// // Partner token functions -// fn mint_partner_share( -// ref self: TContractState, token_address: ContractAddress, token_amount: u256, -// ); -// fn set_partner_token_rate( -// ref self: TContractState, token_address: ContractAddress, tokens_per_share: u256, -// ); -// fn get_partner_token_rate(self: @TContractState, token_address: ContractAddress) -> u256; - fn alice() -> ContractAddress { 'alice'.try_into().unwrap() } @@ -77,6 +33,13 @@ fn feign_mint_share(genesis: IBigIncGenesisDispatcher, token: IERC20Dispatcher, genesis.mint_share(token.contract_address); } +fn default_mint_context() -> (IBigIncGenesisDispatcher, IERC20Dispatcher) { + let (genesis, usdt, _) = setup(); + let amount = 10000; + feign_mint_share(genesis, usdt, amount); + (genesis, usdt) +} + #[test] fn test_genesis_mint_share_success() { let (genesis, usdt, _) = setup(); @@ -108,13 +71,6 @@ fn test_genesis_mint_share_should_panic_on_invalid_token() { feign_mint_share(genesis, token, amount); } -fn default_mint_context() -> (IBigIncGenesisDispatcher, IERC20Dispatcher) { - let (genesis, usdt, _) = setup(); - let amount = 10000; - feign_mint_share(genesis, usdt, amount); - (genesis, usdt) -} - #[test] fn test_genesis_transfer_share_success() { let (genesis, _) = default_mint_context(); @@ -186,8 +142,148 @@ fn test_genesis_donate_success() { #[test] #[should_panic(expected: 'Exceeds available shares')] -fn test_genesis_mint_share_should_panic_on_exceeded_available_shares() {} +fn test_genesis_mint_share_should_panic_on_exceeded_available_shares() { + let (genesis, usdt, _) = setup(); + let amount = genesis.get_available_shares(); + feign_mint_share(genesis, usdt, amount + 2); +} + + +// fn mint_share(ref self: TContractState, token_address: ContractAddress); +// fn transfer_share(ref self: TContractState, to: ContractAddress, share_amount: u256); +// fn donate(ref self: TContractState, token_address: ContractAddress, amount: u256); +// // View functions +// fn get_available_shares(self: @TContractState) -> u256; +// fn get_shares(self: @TContractState, addr: ContractAddress) -> u256; +// fn get_shareholders(self: @TContractState) -> Array; +// fn is_shareholder(self: @TContractState, addr: ContractAddress) -> bool; +// fn get_usdt_address(self: @TContractState) -> ContractAddress; +// fn get_usdc_address(self: @TContractState) -> ContractAddress; +// fn get_total_share_valuation(self: @TContractState) -> u256; +// fn get_presale_share_valuation(self: @TContractState) -> u256; +// fn get_presale_shares(self: @TContractState) -> u256; +// fn get_shares_sold(self: @TContractState) -> u256; +// fn is_presale_active(self: @TContractState) -> bool; + +// // Owner functions +// fn withdraw(ref self: TContractState, token_address: ContractAddress, amount: u256); +// fn seize_shares(ref self: TContractState, shareholder: ContractAddress); +// fn set_partner_share_cap(ref self: TContractState, token_address: ContractAddress, cap: +// u256); +// fn remove_partner_share_cap(ref self: TContractState, token_address: ContractAddress); +// fn pause(ref self: TContractState); +// fn unpause(ref self: TContractState); + +// // Partner view functions +// fn get_partner_share_cap(self: @TContractState, token_address: ContractAddress) -> u256; +// fn get_shares_minted_by_partner(self: @TContractState, token_address: ContractAddress) -> +// u256; + +// // Ownable functions +// fn get_owner(self: @TContractState) -> ContractAddress; +// fn transfer_owner(ref self: TContractState, new_owner: ContractAddress); +// fn renounce_owner(ref self: TContractState); + +// // Partner token functions +// fn mint_partner_share( +// ref self: TContractState, token_address: ContractAddress, token_amount: u256, +// ); +// fn set_partner_token_rate( +// ref self: TContractState, token_address: ContractAddress, tokens_per_share: u256, +// ); +// fn get_partner_token_rate(self: @TContractState, token_address: ContractAddress) -> u256; + +#[test] +#[should_panic(expected: 'Exceeds partner share cap')] +fn test_genesis_mint_share_should_panic_on_partner_share_cap_exceeded() { + let (genesis, usdt, _) = setup(); + let amount = 0; +} + +// #[derive(Drop, starknet::Event)] +// struct AllSharesSold {} + +// #[derive(Drop, starknet::Event)] +// struct PartnerShareCapSet { +// #[key] +// token_address: ContractAddress, +// cap: u256, +// } + +// #[derive(Drop, starknet::Event)] +// struct PartnerShareMinted { +// #[key] +// token_address: ContractAddress, +// #[key] +// buyer: ContractAddress, +// amount_paid: u256, +// shares_received: u256, +// rate: u256, +// } + +#[test] +#[should_panic(expected: 'Insufficient balance')] +fn test_genesis_withdraw_success_and_should_panic_on_insufficient_funds() { + let (genesis, usdt) = default_mint_context(); + let balance = usdt.balance_of(genesis.contract_address); + let owner_balance = usdt.balance_of(owner()); + cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(1)); + let timestamp = 10; + cheat_block_timestamp(genesis.contract_address, timestamp, CheatSpan::Indefinite) + let mut spy = spy_events(); + genesis.withdraw(usdt.contract_address, balance); + + let genesis_balance = usdt.balance_of(genesis.contract_address); + assert(genesis_balance == 0, 'WITHDRAWAL FAILED 1.'); + let new_balance = usdt.balance_of(owner()); + assert(new_balance == (owner_balance + balance), 'OWNER BALANCE MISMATCH'); + + let event = BigIncGenesis::Event::Withdrawn( + BigIncGenesis::Withdrawn { + token_address: usdt.contract_address, + amount: balance, + owner: owner(), + timestamp: timestamp.into(), + }, + ); + spy.assert_emitted(@array![(genesis.contract_address, event)]); + + cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(1)); + genesis.withdraw(usdt.contract_address, 1); +} + +#[test] +#[should_panic] +fn test_genesis_withdraw_should_panic_on_non_owner() { + let (genesis, usdt) = default_mint_context(); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); + genesis.withdraw(usdt.contract_address, 100); +} + +#[test] +#[should_panic(expected: 'Insufficient shares')] +fn test_genesis_seize_shares_success_and_should_panic_on_transfer() { + let (genesis, usdt) = default_mint_context(); + let mut spy = spy_events(); + cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(1)); + + let share_amount = genesis.get_available_shares(); + let shares = genesis.get_shares(charlie()); + assert(share_amount == shares, 'CHARLIE SHARES MISMATCH'); + assert(share_amount > 0, 'SHARE AMOUNT SHOULD NOT BE ZERO'); + + let event = BigIncGenesis::Event::SharesSeized( + BigIncGenesis::SharesSeized { shareholder: charlie(), share_amount }, + ); + spy.assert_emitted(@array![(genesis.contract_address, event)]); + + let shares = genesis.get_shares(charlie()); + assert(shares == 0, 'CHARLIE SHARES SHOULD BE ZERO'); + + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::Indefinite); + genesis.transfer_share(alice(), 1); +} // let partner_cap = self.partner_share_cap.read(token_address); // if partner_cap > 0 { // let current_partner_shares = self.shares_minted_by_partner.read(token_address); @@ -200,13 +296,4 @@ fn test_genesis_mint_share_should_panic_on_exceeded_available_shares() {} // .write(token_address, current_partner_shares + shares_received); // } -#[test] -#[should_panic(expected: 'Exceeds partner share cap')] -fn test_genesis_mint_share_should_panic_on_partner_share_cap_exceeded() { - let (genesis, usdt, _) = setup(); - let amount = 0; -} - -#[test] -fn test_genesis_transfer_share_success() {} From 229b808fb339326cbf1f22f3f28a3d56aa9782e1 Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Fri, 1 Aug 2025 14:24:34 +0100 Subject: [PATCH 7/9] final test modules on the genesis contract --- contract_/src/BigIncGenesis.cairo | 2 +- contract_/tests/setup.cairo | 2 +- contract_/tests/test_contract.cairo | 182 ++++++------ contract_/tests/test_partner_share_cap.cairo | 293 ------------------- 4 files changed, 90 insertions(+), 389 deletions(-) delete mode 100644 contract_/tests/test_partner_share_cap.cairo diff --git a/contract_/src/BigIncGenesis.cairo b/contract_/src/BigIncGenesis.cairo index 3138a56..057cb74 100644 --- a/contract_/src/BigIncGenesis.cairo +++ b/contract_/src/BigIncGenesis.cairo @@ -136,7 +136,7 @@ pub mod BigIncGenesis { } #[derive(Drop, starknet::Event)] - struct PresaleEnded {} + pub struct PresaleEnded {} #[derive(Drop, starknet::Event)] pub struct TransferShare { diff --git a/contract_/tests/setup.cairo b/contract_/tests/setup.cairo index 21003cd..9f25b59 100644 --- a/contract_/tests/setup.cairo +++ b/contract_/tests/setup.cairo @@ -23,10 +23,10 @@ pub fn deploy_mock_erc20( ) -> ContractAddress { let contract = declare("MockERC20").unwrap().contract_class(); let mut constructor_args = array![]; + constructor_args.append_serde(recipient); constructor_args.append_serde(name); constructor_args.append_serde(symbol); constructor_args.append_serde(initial_supply); - constructor_args.append_serde(recipient); let (contract_address, _) = contract.deploy(@constructor_args).unwrap(); contract_address diff --git a/contract_/tests/test_contract.cairo b/contract_/tests/test_contract.cairo index be2c0ff..298a808 100644 --- a/contract_/tests/test_contract.cairo +++ b/contract_/tests/test_contract.cairo @@ -29,7 +29,7 @@ fn feign_mint_share(genesis: IBigIncGenesisDispatcher, token: IERC20Dispatcher, mint(array![(charlie(), amount)], token); cheat_caller_address(token.contract_address, charlie(), CheatSpan::TargetCalls(1)); token.approve(genesis.contract_address, amount); - cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::Indefinite); genesis.mint_share(token.contract_address); } @@ -78,7 +78,7 @@ fn test_genesis_transfer_share_success() { let shares = genesis.get_shares(charlie()); let alice_shares = genesis.get_shares(alice()); assert(alice_shares == 0, 'ALICE SHOULD HAVE NO SHARES'); - cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(5)); let amount = shares / 2; let remaining_amount = shares - amount; @@ -148,80 +148,6 @@ fn test_genesis_mint_share_should_panic_on_exceeded_available_shares() { feign_mint_share(genesis, usdt, amount + 2); } - -// fn mint_share(ref self: TContractState, token_address: ContractAddress); -// fn transfer_share(ref self: TContractState, to: ContractAddress, share_amount: u256); -// fn donate(ref self: TContractState, token_address: ContractAddress, amount: u256); - -// // View functions -// fn get_available_shares(self: @TContractState) -> u256; -// fn get_shares(self: @TContractState, addr: ContractAddress) -> u256; -// fn get_shareholders(self: @TContractState) -> Array; -// fn is_shareholder(self: @TContractState, addr: ContractAddress) -> bool; -// fn get_usdt_address(self: @TContractState) -> ContractAddress; -// fn get_usdc_address(self: @TContractState) -> ContractAddress; -// fn get_total_share_valuation(self: @TContractState) -> u256; -// fn get_presale_share_valuation(self: @TContractState) -> u256; -// fn get_presale_shares(self: @TContractState) -> u256; -// fn get_shares_sold(self: @TContractState) -> u256; -// fn is_presale_active(self: @TContractState) -> bool; - -// // Owner functions -// fn withdraw(ref self: TContractState, token_address: ContractAddress, amount: u256); -// fn seize_shares(ref self: TContractState, shareholder: ContractAddress); -// fn set_partner_share_cap(ref self: TContractState, token_address: ContractAddress, cap: -// u256); -// fn remove_partner_share_cap(ref self: TContractState, token_address: ContractAddress); -// fn pause(ref self: TContractState); -// fn unpause(ref self: TContractState); - -// // Partner view functions -// fn get_partner_share_cap(self: @TContractState, token_address: ContractAddress) -> u256; -// fn get_shares_minted_by_partner(self: @TContractState, token_address: ContractAddress) -> -// u256; - -// // Ownable functions -// fn get_owner(self: @TContractState) -> ContractAddress; -// fn transfer_owner(ref self: TContractState, new_owner: ContractAddress); -// fn renounce_owner(ref self: TContractState); - -// // Partner token functions -// fn mint_partner_share( -// ref self: TContractState, token_address: ContractAddress, token_amount: u256, -// ); -// fn set_partner_token_rate( -// ref self: TContractState, token_address: ContractAddress, tokens_per_share: u256, -// ); -// fn get_partner_token_rate(self: @TContractState, token_address: ContractAddress) -> u256; - -#[test] -#[should_panic(expected: 'Exceeds partner share cap')] -fn test_genesis_mint_share_should_panic_on_partner_share_cap_exceeded() { - let (genesis, usdt, _) = setup(); - let amount = 0; -} - -// #[derive(Drop, starknet::Event)] -// struct AllSharesSold {} - -// #[derive(Drop, starknet::Event)] -// struct PartnerShareCapSet { -// #[key] -// token_address: ContractAddress, -// cap: u256, -// } - -// #[derive(Drop, starknet::Event)] -// struct PartnerShareMinted { -// #[key] -// token_address: ContractAddress, -// #[key] -// buyer: ContractAddress, -// amount_paid: u256, -// shares_received: u256, -// rate: u256, -// } - #[test] #[should_panic(expected: 'Insufficient balance')] fn test_genesis_withdraw_success_and_should_panic_on_insufficient_funds() { @@ -230,7 +156,7 @@ fn test_genesis_withdraw_success_and_should_panic_on_insufficient_funds() { let owner_balance = usdt.balance_of(owner()); cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(1)); let timestamp = 10; - cheat_block_timestamp(genesis.contract_address, timestamp, CheatSpan::Indefinite) + cheat_block_timestamp(genesis.contract_address, timestamp, CheatSpan::Indefinite); let mut spy = spy_events(); genesis.withdraw(usdt.contract_address, balance); @@ -254,7 +180,7 @@ fn test_genesis_withdraw_success_and_should_panic_on_insufficient_funds() { } #[test] -#[should_panic] +#[should_panic(expected: 'Caller is not the owner')] fn test_genesis_withdraw_should_panic_on_non_owner() { let (genesis, usdt) = default_mint_context(); cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); @@ -264,17 +190,19 @@ fn test_genesis_withdraw_should_panic_on_non_owner() { #[test] #[should_panic(expected: 'Insufficient shares')] fn test_genesis_seize_shares_success_and_should_panic_on_transfer() { - let (genesis, usdt) = default_mint_context(); + let (genesis, _) = default_mint_context(); let mut spy = spy_events(); cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(1)); - let share_amount = genesis.get_available_shares(); + let shares_sold = genesis.get_shares_sold(); let shares = genesis.get_shares(charlie()); - assert(share_amount == shares, 'CHARLIE SHARES MISMATCH'); - assert(share_amount > 0, 'SHARE AMOUNT SHOULD NOT BE ZERO'); + assert(shares == shares_sold, 'CHARLIE SHARES MISMATCH'); + + cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(1)); + genesis.seize_shares(charlie()); let event = BigIncGenesis::Event::SharesSeized( - BigIncGenesis::SharesSeized { shareholder: charlie(), share_amount }, + BigIncGenesis::SharesSeized { shareholder: charlie(), share_amount: shares }, ); spy.assert_emitted(@array![(genesis.contract_address, event)]); @@ -284,16 +212,82 @@ fn test_genesis_seize_shares_success_and_should_panic_on_transfer() { cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::Indefinite); genesis.transfer_share(alice(), 1); } -// let partner_cap = self.partner_share_cap.read(token_address); -// if partner_cap > 0 { -// let current_partner_shares = self.shares_minted_by_partner.read(token_address); -// assert( -// current_partner_shares + shares_received <= partner_cap, -// 'Exceeds partner share cap', -// ); -// self -// .shares_minted_by_partner -// .write(token_address, current_partner_shares + shares_received); -// } +#[test] +#[should_panic(expected: 'Exceeds partner share cap')] +fn test_genesis_partner_share_cap_operations_success_and_should_panic_on_exceeded_cap() { + let (genesis, usdt, _) = setup(); + let previous_cap = genesis.get_partner_share_cap(usdt.contract_address); + assert(previous_cap == 0, 'PREVIOUS CAP SHOULD BE ZERO'); + cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(2)); + let cap = 10000000; + let mut spy = spy_events(); + genesis.set_partner_share_cap(usdt.contract_address, cap); // 10M shares cap + let rate = 10; + genesis.set_partner_token_rate(usdt.contract_address, rate); + + let cap_ref = genesis.get_partner_share_cap(usdt.contract_address); + assert(cap == cap_ref, 'PRICE CAP MISMATCH'); + + let event1 = BigIncGenesis::Event::PartnerShareCapSet( + BigIncGenesis::PartnerShareCapSet { token_address: usdt.contract_address, cap }, + ); + + let amount = 10000; + mint(array![(alice(), amount)], usdt); + cheat_caller_address(usdt.contract_address, alice(), CheatSpan::TargetCalls(1)); + usdt.approve(genesis.contract_address, amount); + + // Mint partner shares + cheat_caller_address(genesis.contract_address, alice(), CheatSpan::TargetCalls(1)); + genesis.mint_partner_share(usdt.contract_address, amount); + let shares_received = genesis.get_shares_sold(); + let shares = genesis.get_shares(alice()); + assert(shares == shares_received, 'ALICE SHARES MISMATCH'); + + let event2 = BigIncGenesis::Event::PartnerShareMinted( + BigIncGenesis::PartnerShareMinted { + token_address: usdt.contract_address, + buyer: alice(), + amount_paid: amount, + shares_received, + rate, + }, + ); + + let events = array![(genesis.contract_address, event1), (genesis.contract_address, event2)]; + spy.assert_emitted(@events); + + // mint. should panic + feign_mint_share(genesis, usdt, amount); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn test_set_partner_share_cap_not_owner() { + let (genesis, usdt, _) = setup(); + cheat_caller_address(genesis.contract_address, alice(), CheatSpan::TargetCalls(1)); + genesis.set_partner_share_cap(usdt.contract_address, 1000); +} +#[test] +#[should_panic(expected: ('Invalid token address',))] +fn test_set_partner_share_cap_invalid_token() { + let (genesis, _, _) = setup(); + cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(1)); + let random_token: ContractAddress = 'random token'.try_into().unwrap(); + genesis.set_partner_share_cap(random_token, 1000); +} + +#[test] +fn test_remove_partner_share_cap_success() { + let (genesis, _, usdc) = setup(); + cheat_caller_address(genesis.contract_address, owner(), CheatSpan::Indefinite); + genesis.set_partner_share_cap(usdc.contract_address, 1000); + let shares = genesis.get_partner_share_cap(usdc.contract_address); + assert(shares == 1000, 'PARTNER SHARES MISMATCH'); + + genesis.remove_partner_share_cap(usdc.contract_address); + let shares = genesis.get_partner_share_cap(usdc.contract_address); + assert(shares == 0, 'PARTNER SHARES CAP SHOULD BE 0'); +} diff --git a/contract_/tests/test_partner_share_cap.cairo b/contract_/tests/test_partner_share_cap.cairo deleted file mode 100644 index f36adfd..0000000 --- a/contract_/tests/test_partner_share_cap.cairo +++ /dev/null @@ -1,293 +0,0 @@ -use contract_::BigIncGenesis::{IBigIncGenesisDispatcher, IBigIncGenesisDispatcherTrait}; -use core::result::ResultTrait; -use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; -use snforge_std::{ - ContractClassTrait, DeclareResultTrait, declare, start_cheat_caller_address, - stop_cheat_caller_address, -}; -use starknet::{ContractAddress, contract_address_const}; - -pub const OWNER: felt252 = 'owner'; -pub const USER1: felt252 = 'user1'; -pub const USER2: felt252 = 'user2'; -const USDT_INITIAL_SUPPLY: u256 = 1000000000000_u256; // 1M USDT with 6 decimals -const USDC_INITIAL_SUPPLY: u256 = 1000000000000_u256; // 1M USDC with 6 decimals - -pub fn deploy_mock_erc20( - name: felt252, symbol: felt252, initial_supply: u256, recipient: ContractAddress, -) -> ContractAddress { - let contract = declare("MockERC20").unwrap().contract_class(); - let (contract_address, _) = contract - .deploy( - @array![ - initial_supply.low.into(), - initial_supply.high.into(), - recipient.into(), - // ByteArray name - simple felt252 approach - 0, // data length - name, // pending word - 4, // pending word length - // ByteArray symbol - simple felt252 approach - 0, // data length - symbol, // pending word - 4, // pending word length - 6, // decimals - contract_address_const::().into(), - ], - ) - .unwrap(); - contract_address -} - -pub fn deploy_big_inc_genesis( - usdt_address: ContractAddress, usdc_address: ContractAddress, -) -> ContractAddress { - let contract = declare("BigIncGenesis").unwrap().contract_class(); - let (contract_address, _) = contract - .deploy( - @array![ - usdt_address.into(), usdc_address.into(), contract_address_const::().into(), - ], - ) - .unwrap(); - contract_address -} - -pub fn setup() -> (ContractAddress, ContractAddress, ContractAddress) { - let user1 = contract_address_const::(); - let usdt_address = deploy_mock_erc20('USDT', 'USDT', USDT_INITIAL_SUPPLY, user1); - let usdc_address = deploy_mock_erc20('USDC', 'USDC', USDC_INITIAL_SUPPLY, user1); - let big_inc_address = deploy_big_inc_genesis(usdt_address, usdc_address); - - (big_inc_address, usdt_address, usdc_address) -} - -#[test] -fn test_set_partner_share_cap_success() { - let (big_inc_address, usdt_address, _usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - let owner = contract_address_const::(); - - // Set partner share cap as owner - start_cheat_caller_address(big_inc_address, owner); - big_inc.set_partner_share_cap(usdt_address, 10000000_u256); // 10M shares cap - stop_cheat_caller_address(big_inc_address); - - // Verify the cap was set - let cap = big_inc.get_partner_share_cap(usdt_address); - assert(cap == 10000000_u256, 'Partner cap not set correctly'); -} - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn test_set_partner_share_cap_not_owner() { - let (big_inc_address, usdt_address, _usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - let user1 = contract_address_const::(); - - // Try to set partner share cap as non-owner - start_cheat_caller_address(big_inc_address, user1); - big_inc.set_partner_share_cap(usdt_address, 10000000_u256); - stop_cheat_caller_address(big_inc_address); -} - -#[test] -#[should_panic(expected: ('Invalid token address',))] -fn test_set_partner_share_cap_invalid_token() { - let (big_inc_address, _usdt_address, _usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - let owner = contract_address_const::(); - let invalid_token = contract_address_const::<'invalid_token'>(); - - // Try to set partner share cap for invalid token - start_cheat_caller_address(big_inc_address, owner); - big_inc.set_partner_share_cap(invalid_token, 10000000_u256); - stop_cheat_caller_address(big_inc_address); -} - -#[test] -fn test_remove_partner_share_cap_success() { - let (big_inc_address, usdt_address, _usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - let owner = contract_address_const::(); - - // Set partner share cap first - start_cheat_caller_address(big_inc_address, owner); - big_inc.set_partner_share_cap(usdt_address, 10000000_u256); - let cap_before = big_inc.get_partner_share_cap(usdt_address); - assert(cap_before == 10000000_u256, 'Cap should be set'); - - // Remove partner share cap - big_inc.remove_partner_share_cap(usdt_address); - stop_cheat_caller_address(big_inc_address); - - // Verify the cap was removed - let cap_after = big_inc.get_partner_share_cap(usdt_address); - assert(cap_after == 0_u256, 'Partner cap not removed'); -} - -#[cfg(test)] -#[should_panic(expected: ('Caller is not the owner',))] -fn test_remove_partner_share_cap_not_owner() { - let (big_inc_address, usdt_address, _usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - let user1 = contract_address_const::(); - - // Try to remove partner share cap as non-owner - start_cheat_caller_address(big_inc_address, user1); - big_inc.remove_partner_share_cap(usdt_address); - stop_cheat_caller_address(big_inc_address); -} - -#[cfg(test)] -fn test_get_partner_share_cap_default_zero() { - let (big_inc_address, usdt_address, usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - - // Check default cap is zero - let usdt_cap = big_inc.get_partner_share_cap(usdt_address); - let usdc_cap = big_inc.get_partner_share_cap(usdc_address); - - assert(usdt_cap == 0_u256, 'Default USDT cap should be 0'); - assert(usdc_cap == 0_u256, 'Default USDC cap should be 0'); -} - -#[cfg(test)] -fn test_get_shares_minted_by_partner_default_zero() { - let (big_inc_address, usdt_address, usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - - // Check default shares minted is zero - let usdt_shares = big_inc.get_shares_minted_by_partner(usdt_address); - let usdc_shares = big_inc.get_shares_minted_by_partner(usdc_address); - - assert(usdt_shares == 0_u256, 'Default USDT shares should be 0'); - assert(usdc_shares == 0_u256, 'Default USDC shares should be 0'); -} - -#[cfg(test)] -fn test_mint_share_respects_partner_cap() { - let (big_inc_address, usdt_address, _usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - let usdt = IERC20Dispatcher { contract_address: usdt_address }; - let owner = contract_address_const::(); - let user1 = contract_address_const::(); - - // Set partner share cap - start_cheat_caller_address(big_inc_address, owner); - big_inc.set_partner_share_cap(usdt_address, 5000000_u256); // 5M shares cap - stop_cheat_caller_address(big_inc_address); - - // Approve and mint shares within cap - small amount for 1M shares - let amount = 4571430000_u256; // Amount for ~1M shares at presale price (1M * 457143 / 100) - start_cheat_caller_address(usdt_address, user1); - usdt.approve(big_inc_address, amount); - stop_cheat_caller_address(usdt_address); - - start_cheat_caller_address(big_inc_address, user1); - big_inc.mint_share(usdt_address); - stop_cheat_caller_address(big_inc_address); - - // Verify shares were minted - let shares_minted = big_inc.get_shares_minted_by_partner(usdt_address); - assert(shares_minted > 0, 'Shares should be minted'); - assert(shares_minted <= 5000000_u256, 'Should not exceed cap'); -} - -#[cfg(test)] -#[should_panic(expected: ('Exceeds partner share cap',))] -fn test_mint_share_exceeds_partner_cap() { - let (big_inc_address, usdt_address, _usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - let usdt = IERC20Dispatcher { contract_address: usdt_address }; - let owner = contract_address_const::(); - let user1 = contract_address_const::(); - - // Set low partner share cap - start_cheat_caller_address(big_inc_address, owner); - big_inc.set_partner_share_cap(usdt_address, 500000_u256); // 500K shares cap - stop_cheat_caller_address(big_inc_address); - - // Try to mint more shares than cap allows - 1M shares - let amount = 4571430000_u256; // Amount for ~1M shares at presale price - start_cheat_caller_address(usdt_address, user1); - usdt.approve(big_inc_address, amount); - stop_cheat_caller_address(usdt_address); - - start_cheat_caller_address(big_inc_address, user1); - big_inc.mint_share(usdt_address); - stop_cheat_caller_address(big_inc_address); -} - -#[cfg(test)] -fn test_mint_share_without_partner_cap_works() { - let (big_inc_address, usdt_address, _usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - let usdt = IERC20Dispatcher { contract_address: usdt_address }; - let user1 = contract_address_const::(); - - // No partner cap set (should be 0) - let cap = big_inc.get_partner_share_cap(usdt_address); - assert(cap == 0_u256, 'Cap should be 0 by default'); - - // Should be able to mint shares without cap restriction - small amount for 1M shares - let amount = 4571430000_u256; // Amount for ~1M shares at presale price - start_cheat_caller_address(usdt_address, user1); - usdt.approve(big_inc_address, amount); - stop_cheat_caller_address(usdt_address); - - start_cheat_caller_address(big_inc_address, user1); - big_inc.mint_share(usdt_address); - stop_cheat_caller_address(big_inc_address); - - // Verify shares were minted - let user_shares = big_inc.get_shares(user1); - assert(user_shares > 0, 'Shares should be minted'); -} - -#[cfg(test)] -fn test_partner_cap_separate_for_different_tokens() { - let (big_inc_address, usdt_address, usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - let owner = contract_address_const::(); - - // Set different caps for different tokens - start_cheat_caller_address(big_inc_address, owner); - big_inc.set_partner_share_cap(usdt_address, 5000000_u256); // 5M shares cap for USDT - big_inc.set_partner_share_cap(usdc_address, 7000000_u256); // 7M shares cap for USDC - stop_cheat_caller_address(big_inc_address); - - // Verify caps are set correctly - let usdt_cap = big_inc.get_partner_share_cap(usdt_address); - let usdc_cap = big_inc.get_partner_share_cap(usdc_address); - - assert(usdt_cap == 5000000_u256, 'USDT cap incorrect'); - assert(usdc_cap == 7000000_u256, 'USDC cap incorrect'); - - // Verify shares minted are tracked separately - let usdt_shares = big_inc.get_shares_minted_by_partner(usdt_address); - let usdc_shares = big_inc.get_shares_minted_by_partner(usdc_address); - - assert(usdt_shares == 0_u256, 'USDT shares should be 0'); - assert(usdc_shares == 0_u256, 'USDC shares should be 0'); -} - -#[cfg(test)] -fn test_partner_cap_update_overrides_previous() { - let (big_inc_address, usdt_address, _usdc_address) = setup(); - let big_inc = IBigIncGenesisDispatcher { contract_address: big_inc_address }; - let owner = contract_address_const::(); - - // Set initial cap - start_cheat_caller_address(big_inc_address, owner); - big_inc.set_partner_share_cap(usdt_address, 5000000_u256); - let initial_cap = big_inc.get_partner_share_cap(usdt_address); - assert(initial_cap == 5000000_u256, 'Initial cap not set'); - - // Update cap - big_inc.set_partner_share_cap(usdt_address, 8000000_u256); - let updated_cap = big_inc.get_partner_share_cap(usdt_address); - assert(updated_cap == 8000000_u256, 'Cap not updated'); - - stop_cheat_caller_address(big_inc_address); -} From dfb2fcba63c2ae7d8f31a342bfc3429a1df48674 Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Sat, 2 Aug 2025 13:07:57 +0100 Subject: [PATCH 8/9] fix tests --- ...ntract.cairo => biginc_genesis_test.cairo} | 63 ++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) rename contract_/tests/{test_contract.cairo => biginc_genesis_test.cairo} (82%) diff --git a/contract_/tests/test_contract.cairo b/contract_/tests/biginc_genesis_test.cairo similarity index 82% rename from contract_/tests/test_contract.cairo rename to contract_/tests/biginc_genesis_test.cairo index 298a808..6658f97 100644 --- a/contract_/tests/test_contract.cairo +++ b/contract_/tests/biginc_genesis_test.cairo @@ -92,7 +92,11 @@ fn test_genesis_transfer_share_success() { assert(shares == remaining_amount, 'CHARLIE SHARES MISMATCH'); let share_holders = genesis.get_shareholders(); - assert(share_holders.len() == 2, 'INCORRECT SHARE HOLDERS'); + println!("Number of share holders: {}", share_holders.len()); + for i in 0..share_holders.len() { + println!("Share at {} is: {}", i, genesis.get_shares(*share_holders.at(i))); + } + assert(share_holders.len() == 3, 'INCORRECT SHARE HOLDERS'); // since the owner holds by default let event = BigIncGenesis::Event::TransferShare( BigIncGenesis::TransferShare { from: charlie(), to: alice(), share_amount: amount }, @@ -144,8 +148,11 @@ fn test_genesis_donate_success() { #[should_panic(expected: 'Exceeds available shares')] fn test_genesis_mint_share_should_panic_on_exceeded_available_shares() { let (genesis, usdt, _) = setup(); - let amount = genesis.get_available_shares(); - feign_mint_share(genesis, usdt, amount + 2); + let shares = genesis.get_available_shares(); + let presale_share_valuation = genesis.get_presale_share_valuation(); + println!("Available shares: {}", shares); + let amount = (shares * presale_share_valuation) / 100000000; + feign_mint_share(genesis, usdt, amount + 10000); } #[test] @@ -223,7 +230,8 @@ fn test_genesis_partner_share_cap_operations_success_and_should_panic_on_exceede let cap = 10000000; let mut spy = spy_events(); genesis.set_partner_share_cap(usdt.contract_address, cap); // 10M shares cap - let rate = 10; + + let rate = 10000; genesis.set_partner_token_rate(usdt.contract_address, rate); let cap_ref = genesis.get_partner_share_cap(usdt.contract_address); @@ -233,18 +241,27 @@ fn test_genesis_partner_share_cap_operations_success_and_should_panic_on_exceede BigIncGenesis::PartnerShareCapSet { token_address: usdt.contract_address, cap }, ); - let amount = 10000; + // let amount = 10000; + let share_precision = 100000000_u256; + // let shares_received = (amount * share_precision) / rate; + let amount = (cap * rate) / share_precision; mint(array![(alice(), amount)], usdt); cheat_caller_address(usdt.contract_address, alice(), CheatSpan::TargetCalls(1)); usdt.approve(genesis.contract_address, amount); // Mint partner shares cheat_caller_address(genesis.contract_address, alice(), CheatSpan::TargetCalls(1)); + println!("Got here, 1."); genesis.mint_partner_share(usdt.contract_address, amount); + println!("Got here, 2."); let shares_received = genesis.get_shares_sold(); let shares = genesis.get_shares(alice()); assert(shares == shares_received, 'ALICE SHARES MISMATCH'); + let shares_minted_by_partner = genesis.get_shares_minted_by_partner(usdt.contract_address); + println!("Shares minted by partner: {}", shares_minted_by_partner); + println!("Cap: {}", cap); + let event2 = BigIncGenesis::Event::PartnerShareMinted( BigIncGenesis::PartnerShareMinted { token_address: usdt.contract_address, @@ -264,7 +281,7 @@ fn test_genesis_partner_share_cap_operations_success_and_should_panic_on_exceede #[test] #[should_panic(expected: ('Caller is not the owner',))] -fn test_set_partner_share_cap_not_owner() { +fn test_genesis_set_partner_share_cap_not_owner() { let (genesis, usdt, _) = setup(); cheat_caller_address(genesis.contract_address, alice(), CheatSpan::TargetCalls(1)); genesis.set_partner_share_cap(usdt.contract_address, 1000); @@ -272,7 +289,7 @@ fn test_set_partner_share_cap_not_owner() { #[test] #[should_panic(expected: ('Invalid token address',))] -fn test_set_partner_share_cap_invalid_token() { +fn test_genesis_set_partner_share_cap_invalid_token() { let (genesis, _, _) = setup(); cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(1)); let random_token: ContractAddress = 'random token'.try_into().unwrap(); @@ -280,7 +297,7 @@ fn test_set_partner_share_cap_invalid_token() { } #[test] -fn test_remove_partner_share_cap_success() { +fn test_genesis_remove_partner_share_cap_success() { let (genesis, _, usdc) = setup(); cheat_caller_address(genesis.contract_address, owner(), CheatSpan::Indefinite); genesis.set_partner_share_cap(usdc.contract_address, 1000); @@ -291,3 +308,33 @@ fn test_remove_partner_share_cap_success() { let shares = genesis.get_partner_share_cap(usdc.contract_address); assert(shares == 0, 'PARTNER SHARES CAP SHOULD BE 0'); } + +#[test] +#[should_panic(expected: 'Pausable: paused')] +fn test_genesis_mint_should_panic_on_pause() { + let (genesis, usdt, _) = setup(); + cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(1)); + genesis.pause(); + feign_mint_share(genesis, usdt, 1000); +} + +#[test] +#[should_panic(expected: 'Pausable: paused')] +fn test_genesis_transfer_should_panic_on_pause() { + let (genesis, _) = default_mint_context(); + cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(1)); + genesis.pause(); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); + genesis.transfer_share(alice(), 1); +} + +#[test] +fn test_genesis_mint_and_transfer_success_on_unpause() { + let (genesis, usdt, _) = setup(); + cheat_caller_address(genesis.contract_address, owner(), CheatSpan::TargetCalls(2)); + genesis.pause(); + genesis.unpause(); + feign_mint_share(genesis, usdt, 100000); + cheat_caller_address(genesis.contract_address, charlie(), CheatSpan::TargetCalls(1)); + genesis.transfer_share(alice(), 1); +} From 1f59c61e3a4698df92c91787f028bff25ee30b2c Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Mon, 4 Aug 2025 04:02:49 +0100 Subject: [PATCH 9/9] tests finalized --- contract_/tests/biginc_genesis_test.cairo | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contract_/tests/biginc_genesis_test.cairo b/contract_/tests/biginc_genesis_test.cairo index 6658f97..64bbc59 100644 --- a/contract_/tests/biginc_genesis_test.cairo +++ b/contract_/tests/biginc_genesis_test.cairo @@ -261,6 +261,7 @@ fn test_genesis_partner_share_cap_operations_success_and_should_panic_on_exceede let shares_minted_by_partner = genesis.get_shares_minted_by_partner(usdt.contract_address); println!("Shares minted by partner: {}", shares_minted_by_partner); println!("Cap: {}", cap); + feign_mint_share(genesis, usdt, amount); let event2 = BigIncGenesis::Event::PartnerShareMinted( BigIncGenesis::PartnerShareMinted { @@ -276,7 +277,8 @@ fn test_genesis_partner_share_cap_operations_success_and_should_panic_on_exceede spy.assert_emitted(@events); // mint. should panic - feign_mint_share(genesis, usdt, amount); + println!("End."); + feign_mint_share(genesis, usdt, amount * amount); } #[test]