Skip to main content

drive/state_transition_action/contract/
moderators_pot_settlement.rs

1use crate::error::fee::FeeError;
2use crate::error::Error;
3use crate::util::batch::DriveOperation::{
4    ContractFeePotOperation, ContractModerationOperation, IdentityOperation,
5};
6use crate::util::batch::{
7    ContractFeePotOperationType, ContractModerationOperationType, DriveOperation,
8    IdentityOperationType,
9};
10use dpp::data_contract::document_type::action_fees::ContractFeePot;
11use dpp::fee::Credits;
12use dpp::identifier::Identifier;
13use std::collections::BTreeMap;
14
15/// A settle of the moderators pot of a contract with a seated moderation team, as settled when
16/// the transition was validated: what each identity of the team is paid by its proposal's
17/// reward split, and whose moderation action counts the settle resets. A claim of the pot
18/// settles it, and so does every change of the team, beforehand.
19#[derive(Debug, Clone, Default, PartialEq, Eq)]
20pub struct ModeratorsPotSettlement {
21    /// The elected contract whose moderators pot is settled.
22    pub contract_id: Identifier,
23    /// What each identity is paid: every amount is above zero, and they add up to at most
24    /// the pot. May be empty when the pot holds too little to pay anyone a credit.
25    pub payouts: BTreeMap<Identifier, Credits>,
26    /// The members whose moderation action counts exist and are deleted by the settle.
27    pub settled_action_counts: Vec<Identifier>,
28}
29
30impl ModeratorsPotSettlement {
31    /// Whether the settle changes nothing: nobody is paid and no count is reset.
32    pub fn is_empty(&self) -> bool {
33        self.payouts.is_empty() && self.settled_action_counts.is_empty()
34    }
35
36    /// What is taken out of the pot: the sum of the payouts.
37    pub fn paid_out(&self) -> Result<Credits, Error> {
38        self.payouts
39            .values()
40            .try_fold(0 as Credits, |total, amount| total.checked_add(*amount))
41            .ok_or(Error::Fee(FeeError::Overflow(
42                "the payouts of a moderators pot settle overflow credits",
43            )))
44    }
45
46    /// The operations of the settle: the credits paid out leave the pot and reach the
47    /// balances of the team, so they only move, and the counts the payouts were split by are
48    /// deleted.
49    pub fn into_drive_operations<'a>(self) -> Result<Vec<DriveOperation<'a>>, Error> {
50        let paid_out = self.paid_out()?;
51        let ModeratorsPotSettlement {
52            contract_id,
53            payouts,
54            settled_action_counts,
55        } = self;
56        let mut operations = vec![];
57        if paid_out > 0 {
58            operations.push(ContractFeePotOperation(
59                ContractFeePotOperationType::DeductFromPot {
60                    contract_id,
61                    pot: ContractFeePot::Moderators,
62                    amount: paid_out,
63                },
64            ));
65        }
66        operations.extend(payouts.into_iter().map(|(identity_id, added_balance)| {
67            IdentityOperation(IdentityOperationType::AddToIdentityBalance {
68                identity_id: identity_id.to_buffer(),
69                added_balance,
70            })
71        }));
72        if !settled_action_counts.is_empty() {
73            operations.push(ContractModerationOperation(
74                ContractModerationOperationType::RemoveActionCounts {
75                    contract_id,
76                    identity_ids: settled_action_counts,
77                },
78            ));
79        }
80        Ok(operations)
81    }
82}