mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 21:49:26 +00:00
add genesis liquidity implementation
This commit is contained in:
24
Cargo.lock
generated
24
Cargo.lock
generated
@@ -7526,6 +7526,28 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serai-genesis-liquidity-pallet"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"frame-support",
|
||||||
|
"frame-system",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"scale-info",
|
||||||
|
"serai-coins-pallet",
|
||||||
|
"serai-dex-pallet",
|
||||||
|
"serai-genesis-liquidity-primitives",
|
||||||
|
"serai-primitives",
|
||||||
|
"sp-std",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serai-genesis-liquidity-primitives"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"serai-primitives",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serai-in-instructions-pallet"
|
name = "serai-in-instructions-pallet"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -7536,6 +7558,7 @@ dependencies = [
|
|||||||
"scale-info",
|
"scale-info",
|
||||||
"serai-coins-pallet",
|
"serai-coins-pallet",
|
||||||
"serai-dex-pallet",
|
"serai-dex-pallet",
|
||||||
|
"serai-genesis-liquidity-pallet",
|
||||||
"serai-in-instructions-primitives",
|
"serai-in-instructions-primitives",
|
||||||
"serai-primitives",
|
"serai-primitives",
|
||||||
"serai-validator-sets-pallet",
|
"serai-validator-sets-pallet",
|
||||||
@@ -7797,6 +7820,7 @@ dependencies = [
|
|||||||
"scale-info",
|
"scale-info",
|
||||||
"serai-coins-pallet",
|
"serai-coins-pallet",
|
||||||
"serai-dex-pallet",
|
"serai-dex-pallet",
|
||||||
|
"serai-genesis-liquidity-pallet",
|
||||||
"serai-in-instructions-pallet",
|
"serai-in-instructions-pallet",
|
||||||
"serai-primitives",
|
"serai-primitives",
|
||||||
"serai-signals-pallet",
|
"serai-signals-pallet",
|
||||||
|
|||||||
46
substrate/genesis-liquidity/pallet/Cargo.toml
Normal file
46
substrate/genesis-liquidity/pallet/Cargo.toml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
[package]
|
||||||
|
name = "serai-genesis-liquidity-pallet"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Genesis liquidity pallet for Serai"
|
||||||
|
license = "AGPL-3.0-only"
|
||||||
|
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/genesis-liquidity/pallet"
|
||||||
|
authors = ["Akil Demir <aeg_asd@hotmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.77"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[package.metadata.cargo-machete]
|
||||||
|
ignored = ["scale", "scale-info"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
|
scale-info = { version = "2", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
|
frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||||
|
frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||||
|
|
||||||
|
sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||||
|
|
||||||
|
dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }
|
||||||
|
coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false }
|
||||||
|
|
||||||
|
serai-primitives = { path = "../../primitives", default-features = false }
|
||||||
|
genesis-liquidity-primitives = { package = "serai-genesis-liquidity-primitives", path = "../primitives", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = [
|
||||||
|
"frame-system/std",
|
||||||
|
"frame-support/std",
|
||||||
|
|
||||||
|
"coins-pallet/std",
|
||||||
|
"dex-pallet/std",
|
||||||
|
]
|
||||||
|
|
||||||
|
default = ["std"]
|
||||||
15
substrate/genesis-liquidity/pallet/LICENSE
Normal file
15
substrate/genesis-liquidity/pallet/LICENSE
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
AGPL-3.0-only license
|
||||||
|
|
||||||
|
Copyright (c) 2024 Luke Parker
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License Version 3 as
|
||||||
|
published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
271
substrate/genesis-liquidity/pallet/src/lib.rs
Normal file
271
substrate/genesis-liquidity/pallet/src/lib.rs
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation, clippy::no_effect_underscore_binding)]
|
||||||
|
#[frame_support::pallet]
|
||||||
|
pub mod pallet {
|
||||||
|
use super::*;
|
||||||
|
use frame_system::{pallet_prelude::*, RawOrigin};
|
||||||
|
use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion};
|
||||||
|
|
||||||
|
use sp_std::{vec, collections::btree_map::BTreeMap};
|
||||||
|
|
||||||
|
use dex_pallet::{Pallet as Dex, Config as DexConfig};
|
||||||
|
use coins_pallet::{
|
||||||
|
primitives::{OutInstructionWithBalance, OutInstruction},
|
||||||
|
Config as CoinsConfig, Pallet as Coins, AllowMint,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serai_primitives::*;
|
||||||
|
pub use genesis_liquidity_primitives as primitives;
|
||||||
|
use primitives::*;
|
||||||
|
|
||||||
|
/// LiquidityTokens Pallet as an instance of coins pallet.
|
||||||
|
pub type LiquidityTokens<T> = coins_pallet::Pallet<T, coins_pallet::Instance1>;
|
||||||
|
|
||||||
|
#[pallet::config]
|
||||||
|
pub trait Config:
|
||||||
|
frame_system::Config + DexConfig + CoinsConfig + coins_pallet::Config<coins_pallet::Instance1>
|
||||||
|
{
|
||||||
|
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pallet::error]
|
||||||
|
pub enum Error<T> {
|
||||||
|
GenesisPeriodEnded,
|
||||||
|
AmountOverflowed,
|
||||||
|
NotEnoughLiquidity,
|
||||||
|
CanOnlyRemoveFullAmount,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pallet::event]
|
||||||
|
#[pallet::generate_deposit(fn deposit_event)]
|
||||||
|
pub enum Event<T: Config> {
|
||||||
|
GenesisLiquidityAdded { by: SeraiAddress, balance: Balance },
|
||||||
|
GenesisLiquidityRemoved { by: SeraiAddress, balance: Balance },
|
||||||
|
GenesisLiquidityAddedToPool { coin1: Balance, coin2: Balance },
|
||||||
|
EconomicSecurityReached { network: NetworkId },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pallet::pallet]
|
||||||
|
pub struct Pallet<T>(PhantomData<T>);
|
||||||
|
|
||||||
|
#[pallet::storage]
|
||||||
|
pub(crate) type Liquidity<T: Config> =
|
||||||
|
StorageDoubleMap<_, Identity, Coin, Blake2_128Concat, PublicKey, SubstrateAmount, OptionQuery>;
|
||||||
|
|
||||||
|
#[pallet::storage]
|
||||||
|
pub(crate) type LiquidityTokensPerAddress<T: Config> =
|
||||||
|
StorageDoubleMap<_, Identity, Coin, Blake2_128Concat, PublicKey, SubstrateAmount, OptionQuery>;
|
||||||
|
|
||||||
|
#[pallet::storage]
|
||||||
|
pub(crate) type EconomicSecurityReached<T: Config> =
|
||||||
|
StorageMap<_, Identity, NetworkId, BlockNumberFor<T>, ValueQuery>;
|
||||||
|
|
||||||
|
#[pallet::hooks]
|
||||||
|
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||||
|
fn on_finalize(n: BlockNumberFor<T>) {
|
||||||
|
// Distribute the genesis sri to pools after a month
|
||||||
|
if n > BLOCKS_PER_MONTH.into() {
|
||||||
|
// mint the SRI
|
||||||
|
Coins::<T>::mint(
|
||||||
|
GENESIS_LIQUIDITY_ACCOUNT.into(),
|
||||||
|
Balance { coin: Coin::Serai, amount: Amount(GENESIS_SRI) },
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// get coin values & total
|
||||||
|
let mut account_values = BTreeMap::new();
|
||||||
|
let mut pool_values = BTreeMap::new();
|
||||||
|
let mut total_value: u64 = 0;
|
||||||
|
for coin in COINS {
|
||||||
|
// TODO: following line is just a place holder till we get the actual coin value
|
||||||
|
// in terms of btc.
|
||||||
|
let value = Dex::<T>::security_oracle_value(coin).unwrap_or(Amount(0)).0;
|
||||||
|
account_values.insert(coin, vec![]);
|
||||||
|
let mut pool_amount: u64 = 0;
|
||||||
|
for (account, amount) in Liquidity::<T>::iter_prefix(coin) {
|
||||||
|
pool_amount += amount;
|
||||||
|
let value_this_addr = amount * value;
|
||||||
|
account_values.get_mut(&coin).unwrap().push((account, value_this_addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
let pool_value = pool_amount * value;
|
||||||
|
total_value += pool_value;
|
||||||
|
pool_values.insert(coin, (pool_amount, pool_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the liquidity per pool
|
||||||
|
for (coin, (amount, value)) in &pool_values {
|
||||||
|
let sri_amount = (GENESIS_SRI * value) / total_value;
|
||||||
|
let origin = RawOrigin::Signed(GENESIS_LIQUIDITY_ACCOUNT.into());
|
||||||
|
Dex::<T>::add_liquidity(
|
||||||
|
origin.into(),
|
||||||
|
*coin,
|
||||||
|
*amount,
|
||||||
|
sri_amount,
|
||||||
|
*amount,
|
||||||
|
sri_amount,
|
||||||
|
GENESIS_LIQUIDITY_ACCOUNT.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// set liquidity tokens per account
|
||||||
|
let tokens = LiquidityTokens::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), *coin).0;
|
||||||
|
let mut total_tokens_this_coin: u64 = 0;
|
||||||
|
for (acc, value) in account_values.get(coin).unwrap() {
|
||||||
|
let liq_tokens_this_acc = (tokens * value) / pool_values.get(coin).unwrap().1;
|
||||||
|
total_tokens_this_coin += liq_tokens_this_acc;
|
||||||
|
LiquidityTokensPerAddress::<T>::set(coin, acc, Some(liq_tokens_this_acc));
|
||||||
|
}
|
||||||
|
assert_eq!(tokens, total_tokens_this_coin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we shouldn't have any coin left in our account at this moment, including SRI.
|
||||||
|
for coin in COINS {
|
||||||
|
assert_eq!(Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), coin), Amount(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we accept we reached economic security once we can mint smallest amount of a network's coin
|
||||||
|
for coin in COINS {
|
||||||
|
let existing = EconomicSecurityReached::<T>::get(coin.network());
|
||||||
|
if existing == 0u32.into() &&
|
||||||
|
<T as CoinsConfig>::AllowMint::is_allowed(&Balance { coin, amount: Amount(1) })
|
||||||
|
{
|
||||||
|
EconomicSecurityReached::<T>::set(coin.network(), n);
|
||||||
|
Self::deposit_event(Event::EconomicSecurityReached { network: coin.network() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config> Pallet<T> {
|
||||||
|
/// Add genesis liquidity for the given account. All accounts that provide liquidity
|
||||||
|
/// will receive the genesis SRI according to their liquidity ratio.
|
||||||
|
pub fn add_coin_liquidity(account: PublicKey, balance: Balance) -> DispatchResult {
|
||||||
|
// check we are still in genesis period
|
||||||
|
if Self::genesis_ended() {
|
||||||
|
Err(Error::<T>::GenesisPeriodEnded)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mint the coins
|
||||||
|
Coins::<T>::mint(GENESIS_LIQUIDITY_ACCOUNT.into(), balance)?;
|
||||||
|
|
||||||
|
// save
|
||||||
|
let existing = Liquidity::<T>::get(balance.coin, account).unwrap_or(0);
|
||||||
|
let new = existing.checked_add(balance.amount.0).ok_or(Error::<T>::AmountOverflowed)?;
|
||||||
|
Liquidity::<T>::set(balance.coin, account, Some(new));
|
||||||
|
|
||||||
|
Self::deposit_event(Event::GenesisLiquidityAdded { by: account.into(), balance });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the provided genesis liquidity for an account. If called pre-economic security era,
|
||||||
|
pub fn remove_coin_liquidity(
|
||||||
|
account: PublicKey,
|
||||||
|
balance: Balance,
|
||||||
|
out_address: ExternalAddress,
|
||||||
|
) -> DispatchResult {
|
||||||
|
let origin = RawOrigin::Signed(GENESIS_LIQUIDITY_ACCOUNT.into());
|
||||||
|
|
||||||
|
// check we are still in genesis period
|
||||||
|
if Self::genesis_ended() {
|
||||||
|
// check user have enough to remove
|
||||||
|
let existing = LiquidityTokensPerAddress::<T>::get(balance.coin, account).unwrap_or(0);
|
||||||
|
if balance.amount.0 > existing {
|
||||||
|
Err(Error::<T>::NotEnoughLiquidity)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove liquidity from pool
|
||||||
|
let prev_sri = Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), Coin::Serai);
|
||||||
|
let prev_coin = Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), balance.coin);
|
||||||
|
Dex::<T>::remove_liquidity(
|
||||||
|
origin.clone().into(),
|
||||||
|
balance.coin,
|
||||||
|
balance.amount.0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
GENESIS_LIQUIDITY_ACCOUNT.into(),
|
||||||
|
)?;
|
||||||
|
let current_sri = Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), Coin::Serai);
|
||||||
|
let current_coin = Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), balance.coin);
|
||||||
|
|
||||||
|
// burn the SRI if necessary
|
||||||
|
let mut sri = current_sri.0 - prev_sri.0;
|
||||||
|
let burn_sri_amount = (sri *
|
||||||
|
(GENESIS_SRI_TRICKLE_FEED - Self::blocks_since_ec_security(&balance.coin))) /
|
||||||
|
GENESIS_SRI_TRICKLE_FEED;
|
||||||
|
Coins::<T>::burn(
|
||||||
|
origin.clone().into(),
|
||||||
|
Balance { coin: Coin::Serai, amount: Amount(burn_sri_amount) },
|
||||||
|
)?;
|
||||||
|
sri -= burn_sri_amount;
|
||||||
|
|
||||||
|
// transfer to owner
|
||||||
|
let coin_out = current_coin.0 - prev_coin.0;
|
||||||
|
Coins::<T>::transfer(
|
||||||
|
origin.clone().into(),
|
||||||
|
account,
|
||||||
|
Balance { coin: balance.coin, amount: Amount(coin_out) },
|
||||||
|
)?;
|
||||||
|
Coins::<T>::transfer(
|
||||||
|
origin.into(),
|
||||||
|
account,
|
||||||
|
Balance { coin: Coin::Serai, amount: Amount(sri) },
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// save
|
||||||
|
let existing = LiquidityTokensPerAddress::<T>::get(balance.coin, account).unwrap_or(0);
|
||||||
|
let new = existing.checked_sub(balance.amount.0).ok_or(Error::<T>::AmountOverflowed)?;
|
||||||
|
LiquidityTokensPerAddress::<T>::set(balance.coin, account, Some(new));
|
||||||
|
} else {
|
||||||
|
let existing = Liquidity::<T>::get(balance.coin, account).unwrap_or(0);
|
||||||
|
if balance.amount.0 > existing || balance.amount.0 == 0 {
|
||||||
|
Err(Error::<T>::NotEnoughLiquidity)?;
|
||||||
|
}
|
||||||
|
if balance.amount.0 < existing {
|
||||||
|
Err(Error::<T>::CanOnlyRemoveFullAmount)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do internal transfer instead?
|
||||||
|
let origin = RawOrigin::Signed(GENESIS_LIQUIDITY_ACCOUNT.into());
|
||||||
|
let instruction = OutInstructionWithBalance {
|
||||||
|
instruction: OutInstruction { address: out_address, data: None },
|
||||||
|
balance,
|
||||||
|
};
|
||||||
|
Coins::<T>::burn_with_instruction(origin.into(), instruction)?;
|
||||||
|
|
||||||
|
// save
|
||||||
|
Liquidity::<T>::set(balance.coin, account, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::deposit_event(Event::GenesisLiquidityRemoved { by: account.into(), balance });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of blocks since the coin's network reached economic security first time.
|
||||||
|
// If the network is yet to be reached that threshold 0 is returned, and maximum of
|
||||||
|
// GENESIS_SRI_TRICKLE_FEED returned.
|
||||||
|
fn blocks_since_ec_security(coin: &Coin) -> u64 {
|
||||||
|
let ec_security_block =
|
||||||
|
EconomicSecurityReached::<T>::get(coin.network()).saturated_into::<u64>();
|
||||||
|
let current = <frame_system::Pallet<T>>::block_number().saturated_into::<u64>();
|
||||||
|
if ec_security_block > 0 {
|
||||||
|
let diff = current - ec_security_block;
|
||||||
|
if diff > GENESIS_SRI_TRICKLE_FEED {
|
||||||
|
return GENESIS_SRI_TRICKLE_FEED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn genesis_ended() -> bool {
|
||||||
|
<frame_system::Pallet<T>>::block_number() >= BLOCKS_PER_MONTH.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use pallet::*;
|
||||||
25
substrate/genesis-liquidity/primitives/Cargo.toml
Normal file
25
substrate/genesis-liquidity/primitives/Cargo.toml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "serai-genesis-liquidity-primitives"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Serai genesis liquidity primitives"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/genesis-liquidity/primitives"
|
||||||
|
authors = ["Akil Demir <aeg_asd@hotmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.77"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serai-primitives = { path = "../../primitives", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = [
|
||||||
|
"serai-primitives/std",
|
||||||
|
]
|
||||||
|
default = ["std"]
|
||||||
21
substrate/genesis-liquidity/primitives/LICENSE
Normal file
21
substrate/genesis-liquidity/primitives/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Luke Parker
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
17
substrate/genesis-liquidity/primitives/src/lib.rs
Normal file
17
substrate/genesis-liquidity/primitives/src/lib.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
use serai_primitives::*;
|
||||||
|
|
||||||
|
// amount of blocks in 30 days for 6s per block.
|
||||||
|
pub const BLOCKS_PER_MONTH: u32 = 10 * 60 * 24 * 30;
|
||||||
|
|
||||||
|
/// 180 days of blocks
|
||||||
|
pub const GENESIS_SRI_TRICKLE_FEED: u64 = 10 * 60 * 24 * 180;
|
||||||
|
|
||||||
|
// 100 Million SRI
|
||||||
|
pub const GENESIS_SRI: u64 = 100_000_000 * 10_u64.pow(8);
|
||||||
|
|
||||||
|
// This is the account which will be the origin for any dispatched `InInstruction`s.
|
||||||
|
pub const GENESIS_LIQUIDITY_ACCOUNT: SeraiAddress = system_address(b"Genesis-liquidity-account");
|
||||||
@@ -37,6 +37,7 @@ in-instructions-primitives = { package = "serai-in-instructions-primitives", pat
|
|||||||
coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false }
|
coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false }
|
||||||
dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }
|
dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }
|
||||||
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../../validator-sets/pallet", default-features = false }
|
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../../validator-sets/pallet", default-features = false }
|
||||||
|
genesis-liquidity-pallet = { package = "serai-genesis-liquidity-pallet", path = "../../genesis-liquidity/pallet", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = [
|
std = [
|
||||||
@@ -58,5 +59,6 @@ std = [
|
|||||||
"coins-pallet/std",
|
"coins-pallet/std",
|
||||||
"dex-pallet/std",
|
"dex-pallet/std",
|
||||||
"validator-sets-pallet/std",
|
"validator-sets-pallet/std",
|
||||||
|
"genesis-liquidity-pallet/std",
|
||||||
]
|
]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -33,10 +33,14 @@ pub mod pallet {
|
|||||||
Config as ValidatorSetsConfig, Pallet as ValidatorSets,
|
Config as ValidatorSetsConfig, Pallet as ValidatorSets,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use genesis_liquidity_pallet::{Pallet as GenesisLiq, Config as GenesisLiqConfig};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[pallet::config]
|
#[pallet::config]
|
||||||
pub trait Config: frame_system::Config + CoinsConfig + DexConfig + ValidatorSetsConfig {
|
pub trait Config:
|
||||||
|
frame_system::Config + CoinsConfig + DexConfig + ValidatorSetsConfig + GenesisLiqConfig
|
||||||
|
{
|
||||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,6 +204,14 @@ pub mod pallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InInstruction::GenesisLiquidity(ops) => match ops {
|
||||||
|
GenesisLiquidityOperation::Add(address, balance) => {
|
||||||
|
GenesisLiq::<T>::add_coin_liquidity(address.into(), balance)?;
|
||||||
|
}
|
||||||
|
GenesisLiquidityOperation::Remove(address, balance, out_address) => {
|
||||||
|
GenesisLiq::<T>::remove_coin_liquidity(address.into(), balance, out_address)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,15 @@ pub enum DexCall {
|
|||||||
Swap(Balance, OutAddress),
|
Swap(Balance, OutAddress),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||||
|
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||||
|
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
pub enum GenesisLiquidityOperation {
|
||||||
|
Add(SeraiAddress, Balance),
|
||||||
|
Remove(SeraiAddress, Balance, ExternalAddress),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||||
@@ -78,6 +87,7 @@ pub enum DexCall {
|
|||||||
pub enum InInstruction {
|
pub enum InInstruction {
|
||||||
Transfer(SeraiAddress),
|
Transfer(SeraiAddress),
|
||||||
Dex(DexCall),
|
Dex(DexCall),
|
||||||
|
GenesisLiquidity(GenesisLiquidityOperation),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug)]
|
#[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug)]
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ coins-pallet = { package = "serai-coins-pallet", path = "../coins/pallet", defau
|
|||||||
dex-pallet = { package = "serai-dex-pallet", path = "../dex/pallet", default-features = false }
|
dex-pallet = { package = "serai-dex-pallet", path = "../dex/pallet", default-features = false }
|
||||||
|
|
||||||
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets/pallet", default-features = false }
|
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets/pallet", default-features = false }
|
||||||
|
genesis-liquidity-pallet = { package = "serai-genesis-liquidity-pallet", path = "../genesis-liquidity/pallet", default-features = false }
|
||||||
|
|
||||||
in-instructions-pallet = { package = "serai-in-instructions-pallet", path = "../in-instructions/pallet", default-features = false }
|
in-instructions-pallet = { package = "serai-in-instructions-pallet", path = "../in-instructions/pallet", default-features = false }
|
||||||
|
|
||||||
@@ -112,6 +113,7 @@ std = [
|
|||||||
"dex-pallet/std",
|
"dex-pallet/std",
|
||||||
|
|
||||||
"validator-sets-pallet/std",
|
"validator-sets-pallet/std",
|
||||||
|
"genesis-liquidity-pallet/std",
|
||||||
|
|
||||||
"in-instructions-pallet/std",
|
"in-instructions-pallet/std",
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ pub use signals_pallet as signals;
|
|||||||
pub use pallet_babe as babe;
|
pub use pallet_babe as babe;
|
||||||
pub use pallet_grandpa as grandpa;
|
pub use pallet_grandpa as grandpa;
|
||||||
|
|
||||||
|
pub use genesis_liquidity_pallet as genesis_liquidity;
|
||||||
|
|
||||||
// Actually used by the runtime
|
// Actually used by the runtime
|
||||||
use sp_core::OpaqueMetadata;
|
use sp_core::OpaqueMetadata;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
@@ -288,6 +290,10 @@ impl in_instructions::Config for Runtime {
|
|||||||
type RuntimeEvent = RuntimeEvent;
|
type RuntimeEvent = RuntimeEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl genesis_liquidity::Config for Runtime {
|
||||||
|
type RuntimeEvent = RuntimeEvent;
|
||||||
|
}
|
||||||
|
|
||||||
// for publishing equivocation evidences.
|
// for publishing equivocation evidences.
|
||||||
impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime
|
impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime
|
||||||
where
|
where
|
||||||
@@ -362,6 +368,7 @@ construct_runtime!(
|
|||||||
Coins: coins,
|
Coins: coins,
|
||||||
LiquidityTokens: coins::<Instance1>::{Pallet, Call, Storage, Event<T>},
|
LiquidityTokens: coins::<Instance1>::{Pallet, Call, Storage, Event<T>},
|
||||||
Dex: dex,
|
Dex: dex,
|
||||||
|
GenesisLiquidity: genesis_liquidity,
|
||||||
|
|
||||||
ValidatorSets: validator_sets,
|
ValidatorSets: validator_sets,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user