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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// This file is part of Astar.

// Copyright (C) Stake Technologies Pte.Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later

// Astar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Astar is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Astar. If not, see <http://www.gnu.org/licenses/>.

//! # Static Price Provider Pallet
//!
//! A simple pallet that provides a static price for the native currency.
//! This is a temporary solution before oracle is implemented & operational.
//!
//! ## Overview
//!
//! The Static Price Provider pallet provides functionality for setting the active native currency price via privileged call.
//! Only the root can set the price.
//!
//! Network maintainers must ensure to update the price at appropriate times so that inflation & dApp Staking rewards are calculated correctly.

#![cfg_attr(not(feature = "std"), no_std)]

use frame_support::pallet_prelude::*;
use frame_system::{ensure_root, pallet_prelude::*};
pub use pallet::*;
use sp_arithmetic::{fixed_point::FixedU128, traits::Zero};
use sp_std::marker::PhantomData;

use astar_primitives::oracle::PriceProvider;

#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;

#[frame_support::pallet]
pub mod pallet {

    use super::*;

    /// The current storage version.
    pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);

    #[pallet::pallet]
    #[pallet::storage_version(STORAGE_VERSION)]
    pub struct Pallet<T>(PhantomData<T>);

    #[pallet::config]
    pub trait Config: frame_system::Config {
        /// The overarching event type.
        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
    }

    #[pallet::event]
    #[pallet::generate_deposit(pub(crate) fn deposit_event)]
    pub enum Event<T: Config> {
        /// New static native currency price has been set.
        PriceSet { price: FixedU128 },
    }

    #[pallet::error]
    pub enum Error<T> {
        /// Zero is invalid value for the price (hopefully).
        ZeroPrice,
    }

    /// Default value handler for active price.
    /// This pallet is temporary and it's not worth bothering with genesis config.
    pub struct DefaultActivePrice;
    impl Get<FixedU128> for DefaultActivePrice {
        fn get() -> FixedU128 {
            FixedU128::from_rational(1, 10)
        }
    }

    /// Current active native currency price.
    #[pallet::storage]
    #[pallet::whitelist_storage]
    pub type ActivePrice<T: Config> = StorageValue<_, FixedU128, ValueQuery, DefaultActivePrice>;

    #[pallet::call]
    impl<T: Config> Pallet<T> {
        /// Privileged action used to set the active native currency price.
        ///
        /// This is a temporary solution before oracle is implemented & operational.
        #[pallet::call_index(0)]
        #[pallet::weight(T::DbWeight::get().writes(1))]
        pub fn force_set_price(origin: OriginFor<T>, price: FixedU128) -> DispatchResult {
            ensure_root(origin)?;
            ensure!(!price.is_zero(), Error::<T>::ZeroPrice);

            ActivePrice::<T>::put(price);

            Self::deposit_event(Event::<T>::PriceSet { price });

            Ok(().into())
        }
    }

    impl<T: Config> PriceProvider for Pallet<T> {
        fn average_price() -> FixedU128 {
            ActivePrice::<T>::get()
        }
    }
}