From 5615e39617ed0472b2dce28a10caedba660566eb Mon Sep 17 00:00:00 2001 From: JayWebtech Date: Sat, 26 Apr 2025 19:49:00 +0100 Subject: [PATCH 1/4] feat : remove organization --- src/budgetchain/Budget.cairo | 16 +++++++ src/interfaces/IBudget.cairo | 1 + tests/test_budgetchain.cairo | 86 ++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) diff --git a/src/budgetchain/Budget.cairo b/src/budgetchain/Budget.cairo index 65ed71f..62cf13c 100644 --- a/src/budgetchain/Budget.cairo +++ b/src/budgetchain/Budget.cairo @@ -81,6 +81,7 @@ pub mod Budget { #[flat] SRC5Event: SRC5Component::Event, FundsRequested: FundsRequested, + OrganizationRemoved: OrganizationRemoved } #[derive(Drop, starknet::Event)] @@ -146,6 +147,11 @@ pub mod Budget { pub milestone_id: u64, } + #[derive(Drop, starknet::Event)] + pub struct OrganizationRemoved { + pub org_id: u256, + } + #[constructor] fn constructor(ref self: ContractState, default_admin: ContractAddress) { assert(default_admin != contract_address_const::<0>(), ERROR_ZERO_ADDRESS); @@ -622,6 +628,16 @@ pub mod Budget { fn is_paused(self: @ContractState) -> bool { self.is_paused.read() } + fn remove_organization(ref self: ContractState, org_id: u256) { + let caller = get_caller_address(); + assert(caller == self.admin.read(), ERROR_ONLY_ADMIN); + + let mut org = self.organizations.read(org_id); + org.is_active = false; + self.organizations.write(org_id, org); + + self.emit(OrganizationRemoved { org_id: org_id }); + } // fn request_funds( // ref self: ContractState, // requester: ContractAddress, diff --git a/src/interfaces/IBudget.cairo b/src/interfaces/IBudget.cairo index 611c078..488581a 100644 --- a/src/interfaces/IBudget.cairo +++ b/src/interfaces/IBudget.cairo @@ -42,6 +42,7 @@ pub trait IBudget { ) -> u256; fn get_organization(self: @TContractState, org_id: u256) -> Organization; fn is_authorized_organization(self: @TContractState, org: ContractAddress) -> bool; + fn remove_organization(ref self: TContractState, org_id: u256); // Fund Request Management fn get_fund_request(self: @TContractState, project_id: u64, request_id: u64) -> FundRequest; diff --git a/tests/test_budgetchain.cairo b/tests/test_budgetchain.cairo index ac1b396..fe8d046 100644 --- a/tests/test_budgetchain.cairo +++ b/tests/test_budgetchain.cairo @@ -1213,3 +1213,89 @@ fn test_get_project_budget_initial() { let remaining_budget = budget_dispatcher.get_project_budget(project_id); assert(remaining_budget == total_budget, 'Initial budget incorrect'); } + +#[test] +fn test_remove_organization_success() { + let (contract_address, admin_address) = setup(); + let dispatcher = IBudgetDispatcher { contract_address }; + + // Create an organization first + let org_name = 'Test Org'; + let org_address = contract_address_const::<'Organization'>(); + let org_mission = 'Testing Budget Chain'; + + // Set admin as caller to create organization + cheat_caller_address(contract_address, admin_address, CheatSpan::Indefinite); + let org_id = dispatcher.create_organization(org_name, org_address, org_mission); + stop_cheat_caller_address(admin_address); + + // Verify organization is active before removal + let org_before = dispatcher.get_organization(org_id); + assert(org_before.is_active == true, 'be active before removal'); + + // Remove organization as admin + cheat_caller_address(contract_address, admin_address, CheatSpan::Indefinite); + dispatcher.remove_organization(org_id); + stop_cheat_caller_address(admin_address); + + // Verify organization is inactive after removal + let org_after = dispatcher.get_organization(org_id); + assert(org_after.is_active == false, 'be inactive after removal'); +} + +#[test] +#[should_panic(expected: 'ONLY ADMIN')] +fn test_remove_organization_not_admin() { + let (contract_address, admin_address) = setup(); + let dispatcher = IBudgetDispatcher { contract_address }; + + // Create an organization first + let org_name = 'Test Org'; + let org_address = contract_address_const::<'Organization'>(); + let org_mission = 'Testing Budget Chain'; + + // Set admin as caller to create organization + cheat_caller_address(contract_address, admin_address, CheatSpan::Indefinite); + let org_id = dispatcher.create_organization(org_name, org_address, org_mission); + stop_cheat_caller_address(admin_address); + + // Try to remove organization as non-admin + let non_admin = contract_address_const::<'non_admin'>(); + cheat_caller_address(contract_address, non_admin, CheatSpan::Indefinite); + dispatcher.remove_organization(org_id); + stop_cheat_caller_address(non_admin); +} + +#[test] +fn test_remove_organization_event_emission() { + let (contract_address, admin_address) = setup(); + let dispatcher = IBudgetDispatcher { contract_address }; + let mut spy = spy_events(); + + // Create an organization first + let org_name = 'Test Org'; + let org_address = contract_address_const::<'Organization'>(); + let org_mission = 'Testing Budget Chain'; + + // Set admin as caller to create organization + cheat_caller_address(contract_address, admin_address, CheatSpan::Indefinite); + let org_id = dispatcher.create_organization(org_name, org_address, org_mission); + stop_cheat_caller_address(admin_address); + + // Remove organization as admin + cheat_caller_address(contract_address, admin_address, CheatSpan::Indefinite); + dispatcher.remove_organization(org_id); + stop_cheat_caller_address(admin_address); + + // Verify event emission + spy.assert_emitted( + @array![ + ( + contract_address, + Budget::Budget::Event::OrganizationRemoved( + Budget::Budget::OrganizationRemoved { org_id: org_id }, + ), + ), + ], + ); +} From ec9dffe602e3baff0d516a5f5b7b91ac31d2e069 Mon Sep 17 00:00:00 2001 From: JayWebtech Date: Mon, 28 Apr 2025 10:06:30 +0100 Subject: [PATCH 2/4] chore : scarb fmt --- src/budgetchain/Budget.cairo | 6 +++--- tests/test_budgetchain.cairo | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/budgetchain/Budget.cairo b/src/budgetchain/Budget.cairo index be8fd3a..5427a03 100644 --- a/src/budgetchain/Budget.cairo +++ b/src/budgetchain/Budget.cairo @@ -227,7 +227,7 @@ pub mod Budget { let fund_request = self.fund_requests.read((project_id, current_index)); fund_requests_to_return.append(fund_request); current_index += 1; - }; + } fund_requests_to_return } @@ -327,7 +327,7 @@ pub mod Budget { while i < milestone_count { sum += *milestone_amounts.at(i.into()); i += 1; - }; + } assert(sum == total_budget, ERROR_BUDGET_MISMATCH); let project_id = self.project_count.read(); @@ -355,7 +355,7 @@ pub mod Budget { }, ); j += 1; - }; + } self.project_count.write(project_id + 1); self.org_milestones.write(org, milestone_count.try_into().unwrap()); diff --git a/tests/test_budgetchain.cairo b/tests/test_budgetchain.cairo index 26adb2d..76d6837 100644 --- a/tests/test_budgetchain.cairo +++ b/tests/test_budgetchain.cairo @@ -1353,14 +1353,15 @@ fn test_remove_organization_event_emission() { stop_cheat_caller_address(admin_address); // Verify event emission - spy.assert_emitted( - @array![ - ( - contract_address, - Budget::Budget::Event::OrganizationRemoved( - Budget::Budget::OrganizationRemoved { org_id: org_id }, + spy + .assert_emitted( + @array![ + ( + contract_address, + Budget::Budget::Event::OrganizationRemoved( + Budget::Budget::OrganizationRemoved { org_id: org_id }, + ), ), - ), - ], - ); + ], + ); } From 054f26a4b7862bc7fb4ca4b9208c278aea50c85a Mon Sep 17 00:00:00 2001 From: JayWebtech Date: Wed, 30 Apr 2025 08:55:31 +0100 Subject: [PATCH 3/4] added semi-colon --- src/budgetchain/Budget.cairo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/budgetchain/Budget.cairo b/src/budgetchain/Budget.cairo index 5427a03..8c4634c 100644 --- a/src/budgetchain/Budget.cairo +++ b/src/budgetchain/Budget.cairo @@ -327,7 +327,7 @@ pub mod Budget { while i < milestone_count { sum += *milestone_amounts.at(i.into()); i += 1; - } + }; assert(sum == total_budget, ERROR_BUDGET_MISMATCH); let project_id = self.project_count.read(); @@ -355,7 +355,7 @@ pub mod Budget { }, ); j += 1; - } + }; self.project_count.write(project_id + 1); self.org_milestones.write(org, milestone_count.try_into().unwrap()); From 5ff0440f4cbdf42094b208a57efbac4f2ac8e34e Mon Sep 17 00:00:00 2001 From: JayWebtech Date: Wed, 30 Apr 2025 10:26:14 +0100 Subject: [PATCH 4/4] semicolon --- src/budgetchain/Budget.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/budgetchain/Budget.cairo b/src/budgetchain/Budget.cairo index 2c82948..13b53e9 100644 --- a/src/budgetchain/Budget.cairo +++ b/src/budgetchain/Budget.cairo @@ -282,7 +282,7 @@ pub mod Budget { let fund_request = self.fund_requests.read((project_id, current_index)); fund_requests_to_return.append(fund_request); current_index += 1; - } + }; fund_requests_to_return }