Skip to main content

dpp/withdrawal/daily_withdrawal_limit/
mod.rs

1use crate::fee::Credits;
2use crate::withdrawal::daily_withdrawal_limit::v0::daily_withdrawal_limit_v0;
3use crate::ProtocolError;
4use platform_version::version::PlatformVersion;
5
6mod v0;
7mod v1;
8mod v2;
9
10/// Returns the maximum amount of credits Platform may pool into asset unlock
11/// transactions per 24 hours.
12///
13/// `reference_total_credits` is the base the limit is derived from: the current
14/// total credits in Platform for version 0 (10% of it, bounded; required), ignored
15/// by version 1 (a flat 2000 Dash), and the total credits Platform held a day ago
16/// for version 2 (`daily_withdrawal_limit_percent` of it, never below one maximal
17/// withdrawal nor above `max_daily_withdrawal_amount`; the flat limit of version 1
18/// while that day-old total is not known yet).
19pub fn daily_withdrawal_limit(
20    reference_total_credits: Option<Credits>,
21    platform_version: &PlatformVersion,
22) -> Result<Credits, ProtocolError> {
23    match platform_version.dpp.methods.daily_withdrawal_limit {
24        0 => reference_total_credits
25            .map(daily_withdrawal_limit_v0)
26            .ok_or_else(|| {
27                ProtocolError::CorruptedCodeExecution(
28                    "daily_withdrawal_limit v0 requires the current total credits in Platform"
29                        .to_string(),
30                )
31            }),
32        1 => Ok(v1::daily_withdrawal_limit_v1()),
33        2 => v2::daily_withdrawal_limit_v2(reference_total_credits, platform_version),
34        v => Err(ProtocolError::UnknownVersionError(format!(
35            "Unknown daily_withdrawal_limit version {v}"
36        ))),
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43    use crate::dash_to_credits;
44
45    #[test]
46    fn should_switch_from_flat_to_relative_daily_withdrawal_limit_at_protocol_version_14() {
47        let v13 = PlatformVersion::get(13).expect("expected protocol version 13");
48        let v14 = PlatformVersion::get(14).expect("expected protocol version 14");
49
50        for (total_credits_a_day_ago, expected_v14) in [
51            // Below one maximal withdrawal (500 Dash) the limit is floored there.
52            (dash_to_credits!(50), dash_to_credits!(500)),
53            (dash_to_credits!(2000), dash_to_credits!(500)),
54            (dash_to_credits!(20000), dash_to_credits!(3000)),
55            // Above Core's unlock capacity per day (4000 Dash) the limit is capped there.
56            (dash_to_credits!(30000), dash_to_credits!(4000)),
57            (dash_to_credits!(1000000), dash_to_credits!(4000)),
58        ] {
59            // v13 keeps the flat 2000 Dash whatever the total is.
60            assert_eq!(
61                daily_withdrawal_limit(Some(total_credits_a_day_ago), v13)
62                    .expect("expected v13 limit"),
63                dash_to_credits!(2000)
64            );
65            // v14 allows 15% of the total credits a day ago.
66            assert_eq!(
67                daily_withdrawal_limit(Some(total_credits_a_day_ago), v14)
68                    .expect("expected v14 limit"),
69                expected_v14
70            );
71        }
72
73        // Until the total credits a day ago are known, v14 keeps v13's flat limit.
74        assert_eq!(
75            daily_withdrawal_limit(None, v14).expect("expected v14 bootstrap limit"),
76            dash_to_credits!(2000)
77        );
78    }
79}