From 467b3936c3342306b1ccf51c0455feb02c336613 Mon Sep 17 00:00:00 2001 From: akprinciple Date: Mon, 31 Aug 2026 01:04:19 +0100 Subject: [PATCH] remove disburse_recurring and related proposal functions to streamline contract logic --- contracts/accord/src/lib.rs | 202 ------------------------------------ 1 file changed, 202 deletions(-) diff --git a/contracts/accord/src/lib.rs b/contracts/accord/src/lib.rs index f02633e8..0b899328 100644 --- a/contracts/accord/src/lib.rs +++ b/contracts/accord/src/lib.rs @@ -1506,28 +1506,6 @@ impl AccordContract { Ok(()) } - /// Disburse a recurring schedule (permissionless crank). Reject if schedule - /// is in a terminal status (Cancelled or Completed) or called too early. - pub fn disburse_recurring(env: Env, id: u64) -> Result<(), ContractError> { - let mut s = read_recurring_schedule(&env, id)?; - if !matches!(s.status, RecurringStatus::Active) { - return Err(ContractError::ProposalNotActive); - } - let now = env.ledger().timestamp(); - if s.last_disbursed_at != 0 && now < s.last_disbursed_at.saturating_add(s.interval_secs) { - return Err(ContractError::ProposalNotActive); - } - s.last_disbursed_at = now; - if s.remaining_occurrences > 0 { - s.remaining_occurrences = s.remaining_occurrences.saturating_sub(1); - } - if s.remaining_occurrences == 0 { - s.status = RecurringStatus::Completed; - } - write_recurring_schedule(&env, &s); - Ok(()) - } - /// Creates a new transfer proposal with one or more asset transfers. /// /// # Arguments @@ -2109,186 +2087,6 @@ impl AccordContract { Ok(id) } - /// Creates a proposal to remove an existing owner from the multisig. - /// - /// Automatically transitions the proposal to `Ready` when the approval count reaches threshold. - /// Records `ready_at` the first time the threshold is crossed. - pub fn approve(env: Env, approver: Address, proposal_id: u64) -> Result<(), ContractError> { - approver.require_auth(); - require_owner(&env, &approver)?; - - let proposal = Proposal { - id, - proposer: proposer.clone(), - description, - deadline, - approvals: 0, - approval_weight: 0, - status: ProposalStatus::Pending, - kind: ProposalKind::RemoveOwner(owner_to_remove), - ready_at: 0, - quorum_weight: threshold, - category: ProposalCategory::Other, - }; - write_proposal(&env, &proposal); - register_active_proposal(&env, id)?; - - let next_id = id.checked_add(1).ok_or(ContractError::ArithmeticError)?; - write_next_id(&env, next_id); - - let total_weight = read_total_weight(&env); - env.events().publish( - (symbol_short!("created"),), - ProposalCreatedEvent { - id, - proposer, - threshold, - category: ProposalCategory::Other, - transfers: Vec::new(&env), - quorum_weight: threshold, - total_weight_at_creation: total_weight, - }, - ); - - Ok(id) - } - - /// Creates a proposal to change the M-of-N approval threshold. - /// - /// # Arguments - /// * `proposer` - Owner proposing the change. Must authorize. - /// * `new_threshold` - The proposed new threshold. Must be ≥ 1 and ≤ current owner count. - pub fn create_change_threshold_proposal( - env: Env, - proposer: Address, - new_threshold: u32, - description: String, - deadline: u64, - ) -> Result { - proposer.require_auth(); - require_owner_and_weight(&env, &proposer)?; - require_not_frozen(&env)?; - - let total_weight = read_total_weight(&env); - - // The threshold is an absolute weight value. Validate it against the - // current total weight so the proposed threshold is always achievable - // given the current weight distribution. - if new_threshold == 0 || new_threshold > total_weight { - return Err(ContractError::InvalidThreshold); - } - - if description.is_empty() { - return Err(ContractError::EmptyDescription); - } - if description.len() > MAX_DESCRIPTION_LEN { - return Err(ContractError::DescriptionTooLong); - } - - let now = env.ledger().timestamp(); - if deadline <= now { - return Err(ContractError::InvalidDeadline); - } - if deadline - now > MAX_PROPOSAL_DURATION { - return Err(ContractError::InvalidDuration); - } - - let threshold = read_threshold(&env)?; - let id = read_next_id(&env); - - let proposal = Proposal { - id, - proposer: proposer.clone(), - description, - deadline, - approvals: 0, - approval_weight: 0, - status: ProposalStatus::Pending, - kind: ProposalKind::ChangeThreshold(new_threshold), - ready_at: 0, - quorum_weight: threshold, - category: ProposalCategory::Other, - }; - write_proposal(&env, &proposal); - register_active_proposal(&env, id)?; - - let next_id = id.checked_add(1).ok_or(ContractError::ArithmeticError)?; - write_next_id(&env, next_id); - - let total_weight = read_total_weight(&env); - env.events().publish( - (symbol_short!("created"),), - ProposalCreatedEvent { - id, - proposer, - threshold, - category: ProposalCategory::Other, - transfers: Vec::new(&env), - quorum_weight: threshold, - total_weight_at_creation: total_weight, - }, - ); - - Ok(id) - } - - /// Approves a proposal. The approver must be an owner and must not have already approved. - /// - /// Automatically transitions the proposal to `Ready` when the approval count reaches threshold. - /// Records `ready_at` the first time the threshold is crossed. - pub fn approve(env: Env, approver: Address, proposal_id: u64) -> Result<(), ContractError> { - approver.require_auth(); - let owners = read_owners_map(&env)?; - let raw_weight = owners.get(approver.clone()).ok_or(ContractError::Unauthorized)?; - let mut proposal = read_proposal(&env, proposal_id)?; - - // Refresh derived status so an already-expired proposal is caught here. - proposal.status = derive_status(&env, &proposal); - - if !matches!( - proposal.status, - ProposalStatus::Pending | ProposalStatus::Ready - ) { - return Err(ContractError::ProposalNotActive); - } - - if read_approval_weight(&env, proposal_id, &approver) > 0 { - return Err(ContractError::AlreadyApproved); - } - - // Count the approver's effective (delegation-aware) weight, not just - // their own raw weight — the exact value is stored per-approval so - // `revoke` can later reverse precisely this amount. - let weight = compute_effective_weight(&env, &owners, &approver, raw_weight)?; - write_approval_weight(&env, proposal_id, &approver, weight); - - proposal.approvals = checked_weight_add(proposal.approvals, weight)?; - - proposal.approval_weight = checked_weight_add(proposal.approval_weight, weight)?; - - // Record the timestamp when the proposal first crosses the threshold. - if proposal.ready_at == 0 && proposal.approvals >= proposal.quorum_weight { - proposal.ready_at = env.ledger().timestamp(); - } - - proposal.status = derive_status(&env, &proposal); - write_proposal(&env, &proposal); - - env.events().publish( - (symbol_short!("approved"),), - ProposalApprovedEvent { - id: proposal_id, - approver, - approvals: proposal.approvals, - threshold: proposal.quorum_weight, - weight, - cumulative_weight: proposal.approvals, - }, - ); - - Ok(()) - } - /// Revokes the caller's approval from a proposal that has not yet been executed. /// /// The proposal status is recalculated after the revoke: if approvals fall below