Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions src/base/errors.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ pub const ERROR_CONTRACT_PAUSED: felt252 = 'Contract is paused';
pub const ERROR_ALREADY_PAUSED: felt252 = 'Contract already paused';
pub const ERROR_INVALID_MILESTONE_DESCRIPTION: felt252 = 'Invalid milestone description';
pub const ERROR_INVALID_BUDGET: felt252 = 'Invalid budget';
pub const ERROR_PROJECT_ALREADY_TERMINATED: felt252 = 'Project already terminated';
pub const ERROR_PROJECT_TERMINATED: felt252 = 'Project is terminated';
58 changes: 57 additions & 1 deletion src/budgetchain/Budget.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub mod Budget {
project_owners: LegacyMap<u64, ContractAddress>,
milestone_statuses: LegacyMap<(u64, u64), bool>,
is_paused: bool,
project_status: Map<u64, bool> // project_id -> status (true = active, false = terminated)
}


Expand All @@ -85,6 +86,7 @@ pub mod Budget {
FundsRequested: FundsRequested,
OrganizationRemoved: OrganizationRemoved,
FundsReturned: FundsReturned,
ProjectTerminated: ProjectTerminated,
}

#[derive(Drop, starknet::Event)]
Expand Down Expand Up @@ -162,6 +164,11 @@ pub mod Budget {
pub org_id: u256,
}

#[derive(Drop, starknet::Event)]
pub struct ProjectTerminated {
pub project_id: u64,
}

#[constructor]
fn constructor(ref self: ContractState, default_admin: ContractAddress) {
assert(default_admin != contract_address_const::<0>(), ERROR_ZERO_ADDRESS);
Expand Down Expand Up @@ -191,6 +198,9 @@ pub mod Budget {
// Ensure the contract is not paused
self.assert_not_paused();

// Ensure project is active
self._assert_project_active(project_id);

// Generate new transaction ID
let transaction_id = self.transaction_count.read();
let sender = get_caller_address();
Expand Down Expand Up @@ -432,11 +442,13 @@ pub mod Budget {

let project_id = self.project_count.read() + 1;

// set status of project id to be true
self.project_status.write(project_id, true);

let new_project = Project {
id: project_id, org: org, owner: project_owner, total_budget: total_budget,
};
self.projects.write(project_id, new_project);

// Create milestone records
let mut j: u32 = 0;
while j < milestone_count {
Expand Down Expand Up @@ -535,6 +547,9 @@ pub mod Budget {
completed: false,
released: false,
};
// Ensure project is active
self._assert_project_active(project_id);

// // read the number of the current milestones the organization has
let current_milestone = self.org_milestones.read(org);

Expand Down Expand Up @@ -607,6 +622,9 @@ pub mod Budget {
status: FundRequestStatus::Pending,
};

// Ensure project is active
self._assert_project_active(project_id);

// Store the fund request and increase the count
let request_id = self.fund_requests_count.read(project_id) + 1;
self.fund_requests.write((project_id, request_id), fund_request);
Expand Down Expand Up @@ -649,6 +667,10 @@ pub mod Budget {
) {
// Ensure the contract is not paused
self.assert_not_paused();

// Ensure project is active
self._assert_project_active(project_id);

// Verify caller is an authorized organization
self.accesscontrol.assert_only_role(ORGANIZATION_ROLE);

Expand Down Expand Up @@ -817,6 +839,9 @@ pub mod Budget {
//Ensure the contract is not paused
self.assert_not_paused();

// Ensure project is active
self._assert_project_active(project_id);

// Verify project exists
let project = self.projects.read(project_id);
assert(project.org != contract_address_const::<0>(), ERROR_INVALID_PROJECT_ID);
Expand Down Expand Up @@ -874,6 +899,31 @@ pub mod Budget {

request_id
}

fn terminate_project(ref self: ContractState, project_id: u64) {
//Ensure the contract is not paused
self.assert_not_paused();

// Ensure only the admin can terminate the contract
let caller = get_caller_address();
assert(caller == self.admin.read(), ERROR_ONLY_ADMIN);

let mut project = self.projects.read(project_id);
assert(project.id == project_id, ERROR_INVALID_PROJECT_ID);

// Check if project is already terminated
let status = self.project_status.read(project_id);
assert(status == true, ERROR_PROJECT_ALREADY_TERMINATED);

// Now terminate project
self.project_status.write(project_id, false);
self.emit(Event::ProjectTerminated(ProjectTerminated { project_id }));
}

fn assert_status(self: @ContractState, project_id: u64) -> bool {
let status = self.project_status.read(project_id);
return status;
}
}

#[generate_trait]
Expand All @@ -884,5 +934,11 @@ pub mod Budget {
fn assert_not_paused(self: @ContractState) {
assert(!self.is_paused.read(), ERROR_CONTRACT_PAUSED);
}

fn _assert_project_active(self: @ContractState, project_id: u64) {
// Check if the project is active
let project_status = self.project_status.read(project_id);
assert(project_status == true, ERROR_PROJECT_TERMINATED);
}
}
}
2 changes: 2 additions & 0 deletions src/interfaces/IBudget.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,6 @@ pub trait IBudget<TContractState> {
fn pause_contract(ref self: TContractState);
fn unpause_contract(ref self: TContractState);
fn is_paused(self: @TContractState) -> bool;
fn terminate_project(ref self: TContractState, project_id: u64);
fn assert_status(self: @TContractState, project_id: u64) -> bool;
}
Loading
Loading