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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use super::{
    errors::Error,
    events::{Paused, Unpaused}
};
use odra::{contract_env, types::event::OdraEvent, Variable};

/// A module allowing to implement an emergency stop mechanism that can be triggered by any account.
///
/// You can use this module in a custom module by adding it as a field.
///
/// It will make available `require_not_paused()` and `require_paused()` functions,
/// which can be used in the functions of your contract to ensure the contract is
/// in the correct state.
#[odra::module]
pub struct Pauseable {
    is_paused: Variable<bool>
}

impl Pauseable {
    /// Returns true if the contract is paused, and false otherwise.
    pub fn is_paused(&self) -> bool {
        self.is_paused.get_or_default()
    }

    /// Reverts with `[Error::UnpausedRequired]` if the contract is paused.
    pub fn require_not_paused(&self) {
        if self.is_paused() {
            contract_env::revert(Error::UnpausedRequired);
        }
    }

    /// Reverts with `[Error::PausedRequired]` if the contract is paused.
    pub fn require_paused(&self) {
        if !self.is_paused() {
            contract_env::revert(Error::PausedRequired);
        }
    }

    /// Changes the state to `stopped`.
    ///
    /// The contract must not be paused.
    ///
    /// Emits Paused event.
    pub fn pause(&mut self) {
        self.require_not_paused();
        self.is_paused.set(true);

        Paused {
            account: contract_env::caller()
        }
        .emit();
    }

    /// Returns the contract to normal state.
    ///
    /// The contract must be paused.
    ///
    /// Emits Unpaused event.
    pub fn unpause(&mut self) {
        self.require_paused();
        self.is_paused.set(false);

        Unpaused {
            account: contract_env::caller()
        }
        .emit();
    }
}