1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
use crate::rules::validation::Validation;
use crate::utils::Error;
use macros::Rule;
use odra::contract_env::attached_value;
use odra::types::Balance;

/// Verifies if the worker's stake is correct.
/// May return [Error::NotOnboardedWorkerMustStakeCSPR], [Error::ZeroStake],
/// [Error::OnboardedWorkerCannotStakeCSPR], [Error::CannotStakeBothCSPRAndReputation],
/// or [Error::AttachedValueMismatch].
#[derive(Rule)]
pub struct IsBidStakeCorrect {
    is_worker_va: bool,
    cspr_stake: Option<Balance>,
    reputation_stake: Balance,
}

impl Validation for IsBidStakeCorrect {
    fn validate(&self) -> Result<(), Error> {
        match self.cspr_stake {
            None => {
                // Worker doesn't stake cspr, so it must be a VA and must stake reputation.
                if !self.is_worker_va {
                    return Err(Error::NotOnboardedWorkerMustStakeCSPR);
                }
                if self.reputation_stake == Balance::zero() {
                    return Err(Error::ZeroStake);
                }
            }
            Some(cspr_stake) => {
                // Worker staked cspr, so it must not be a VA and must not stake reputation.
                if self.is_worker_va {
                    return Err(Error::OnboardedWorkerCannotStakeCSPR);
                }
                if self.reputation_stake > Balance::zero() {
                    return Err(Error::CannotStakeBothCSPRAndReputation);
                }
                if cspr_stake == Balance::zero() {
                    return Err(Error::ZeroStake);
                }
                if attached_value() != cspr_stake {
                    return Err(Error::AttachedValueMismatch);
                }
            }
        }

        Ok(())
    }
}