mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Stub the genesis-liquidity pallet
This commit is contained in:
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -8386,7 +8386,6 @@ dependencies = [
|
|||||||
"serai-core-pallet",
|
"serai-core-pallet",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-io",
|
"sp-io",
|
||||||
"substrate-median",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -8509,14 +8508,11 @@ dependencies = [
|
|||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
"serai-abi",
|
||||||
"serai-coins-pallet",
|
"serai-coins-pallet",
|
||||||
|
"serai-core-pallet",
|
||||||
"serai-dex-pallet",
|
"serai-dex-pallet",
|
||||||
"serai-economic-security-pallet",
|
|
||||||
"serai-primitives",
|
|
||||||
"serai-validator-sets-pallet",
|
|
||||||
"sp-application-crypto",
|
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-std",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -9028,6 +9024,7 @@ dependencies = [
|
|||||||
"serai-coins-pallet",
|
"serai-coins-pallet",
|
||||||
"serai-core-pallet",
|
"serai-core-pallet",
|
||||||
"serai-dex-pallet",
|
"serai-dex-pallet",
|
||||||
|
"serai-genesis-liquidity-pallet",
|
||||||
"serai-signals-pallet",
|
"serai-signals-pallet",
|
||||||
"serai-validator-sets-pallet",
|
"serai-validator-sets-pallet",
|
||||||
"sp-api",
|
"sp-api",
|
||||||
|
|||||||
@@ -1,23 +1,38 @@
|
|||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_primitives::{
|
use serai_primitives::{
|
||||||
crypto::Signature, address::SeraiAddress, balance::ExternalBalance, genesis::GenesisValues,
|
crypto::Signature, address::SeraiAddress, coin::ExternalCoin, balance::ExternalBalance,
|
||||||
|
genesis_liquidity::GenesisValues,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The address used for to hold genesis liquidity for a pool.
|
||||||
|
pub fn address(coin: ExternalCoin) -> SeraiAddress {
|
||||||
|
SeraiAddress::system(borsh::to_vec(&(b"GenesisLiquidity", coin)).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
/// A call to the genesis liquidity.
|
/// A call to the genesis liquidity.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub enum Call {
|
pub enum Call {
|
||||||
/// Oraclize the value of non-Bitcoin external coins relative to Bitcoin.
|
/// Oraclize the values of the coins available on genesis, relative to BTC.
|
||||||
|
///
|
||||||
|
/// This will trigger the addition of the liquidity into the pools and their initialization.
|
||||||
oraclize_values {
|
oraclize_values {
|
||||||
/// The values of the non-Bitcoin external coins.
|
/// The values of the non-Bitcoin external coins.
|
||||||
values: GenesisValues,
|
values: GenesisValues,
|
||||||
/// The signature by the genesis validators for these values.
|
/// The signature by the genesis validators for these values.
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
},
|
},
|
||||||
/// Remove liquidity.
|
/// Transfer genesis liquidity.
|
||||||
remove_liquidity {
|
transfer_genesis_liquidity {
|
||||||
|
/// The account to transfer the liquidity to.
|
||||||
|
to: SeraiAddress,
|
||||||
|
/// The genesis liquidity to transfer.
|
||||||
|
genesis_liquidity: ExternalBalance,
|
||||||
|
},
|
||||||
|
/// Remove genesis liquidity.
|
||||||
|
remove_genesis_liquidity {
|
||||||
/// The genesis liquidity to remove.
|
/// The genesis liquidity to remove.
|
||||||
balance: ExternalBalance,
|
genesis_liquidity: ExternalBalance,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +40,7 @@ impl Call {
|
|||||||
pub(crate) fn is_signed(&self) -> bool {
|
pub(crate) fn is_signed(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Call::oraclize_values { .. } => false,
|
Call::oraclize_values { .. } => false,
|
||||||
Call::remove_liquidity { .. } => true,
|
Call::transfer_genesis_liquidity { .. } | Call::remove_genesis_liquidity { .. } => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,13 +53,22 @@ pub enum Event {
|
|||||||
/// The recipient of the genesis liquidity.
|
/// The recipient of the genesis liquidity.
|
||||||
recipient: SeraiAddress,
|
recipient: SeraiAddress,
|
||||||
/// The coins added as genesis liquidity.
|
/// The coins added as genesis liquidity.
|
||||||
balance: ExternalBalance,
|
genesis_liquidity: ExternalBalance,
|
||||||
|
},
|
||||||
|
/// Genesis liquidity added.
|
||||||
|
GenesisLiquidityTransferred {
|
||||||
|
/// The address transferred from.
|
||||||
|
from: SeraiAddress,
|
||||||
|
/// The address transferred to.
|
||||||
|
to: SeraiAddress,
|
||||||
|
/// The genesis liquidity transferred.
|
||||||
|
genesis_liquidity: ExternalBalance,
|
||||||
},
|
},
|
||||||
/// Genesis liquidity removed.
|
/// Genesis liquidity removed.
|
||||||
GenesisLiquidityRemoved {
|
GenesisLiquidityRemoved {
|
||||||
/// The account which removed the genesis liquidity.
|
/// The account which removed the genesis liquidity.
|
||||||
origin: SeraiAddress,
|
from: SeraiAddress,
|
||||||
/// The amount of genesis liquidity removed.
|
/// The amount of genesis liquidity removed.
|
||||||
balance: ExternalBalance,
|
genesis_liquidity: ExternalBalance,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ rust-version = "1.85"
|
|||||||
all-features = true
|
all-features = true
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[package.metadata.cargo-machete]
|
||||||
|
ignored = ["scale"]
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
@@ -23,8 +26,6 @@ sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-fea
|
|||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
||||||
|
|
||||||
substrate-median = { path = "../median", default-features = false }
|
|
||||||
|
|
||||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||||
serai-core-pallet = { path = "../core", default-features = false }
|
serai-core-pallet = { path = "../core", default-features = false }
|
||||||
serai-coins-pallet = { path = "../coins", default-features = false }
|
serai-coins-pallet = { path = "../coins", default-features = false }
|
||||||
@@ -45,8 +46,6 @@ std = [
|
|||||||
"frame-system/std",
|
"frame-system/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
|
|
||||||
"substrate-median/std",
|
|
||||||
|
|
||||||
"serai-abi/std",
|
"serai-abi/std",
|
||||||
"serai-core-pallet/std",
|
"serai-core-pallet/std",
|
||||||
"serai-coins-pallet/std",
|
"serai-coins-pallet/std",
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ mod pallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The minimum amount of liquidity allowed to be initially added.
|
||||||
|
///
|
||||||
|
/// This should be sufficiently low it isn't inaccessible, yet sufficiently high that future
|
||||||
|
/// additions can be reasonably grained when their share of the new supply is calculated.
|
||||||
const MINIMUM_LIQUIDITY: u64 = 1 << 16;
|
const MINIMUM_LIQUIDITY: u64 = 1 << 16;
|
||||||
|
|
||||||
#[pallet::call]
|
#[pallet::call]
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serai-genesis-liquidity-pallet"
|
name = "serai-genesis-liquidity-pallet"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Genesis liquidity pallet for Serai"
|
description = "Genesis Liquidity pallet for Serai"
|
||||||
license = "AGPL-3.0-only"
|
license = "AGPL-3.0-only"
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/genesis-liquidity"
|
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/genesis-liquidity"
|
||||||
authors = ["Akil Demir <akildemir72@gmail.com>"]
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.85"
|
rust-version = "1.85"
|
||||||
|
|
||||||
@@ -21,40 +21,48 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
||||||
|
|
||||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
serai-core-pallet = { path = "../core", default-features = false }
|
||||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", default-features = false }
|
serai-coins-pallet = { path = "../coins", default-features = false }
|
||||||
|
serai-dex-pallet = { path = "../dex", default-features = false }
|
||||||
dex-pallet = { package = "serai-dex-pallet", path = "../dex", default-features = false }
|
|
||||||
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
|
||||||
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets", default-features = false }
|
|
||||||
|
|
||||||
economic-security-pallet = { package = "serai-economic-security-pallet", path = "../economic-security", default-features = false }
|
|
||||||
|
|
||||||
serai-primitives = { path = "../primitives", default-features = false }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = [
|
std = [
|
||||||
"scale/std",
|
"scale/std",
|
||||||
|
|
||||||
|
"sp-core/std",
|
||||||
|
|
||||||
"frame-system/std",
|
"frame-system/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
|
|
||||||
"sp-std/std",
|
"serai-abi/std",
|
||||||
"sp-core/std",
|
"serai-core-pallet/std",
|
||||||
"sp-application-crypto/std",
|
"serai-coins-pallet/std",
|
||||||
|
"serai-dex-pallet/std",
|
||||||
"coins-pallet/std",
|
]
|
||||||
"dex-pallet/std",
|
|
||||||
"validator-sets-pallet/std",
|
try-runtime = [
|
||||||
|
"frame-system/try-runtime",
|
||||||
"economic-security-pallet/std",
|
"frame-support/try-runtime",
|
||||||
|
|
||||||
"serai-primitives/std",
|
"serai-abi/try-runtime",
|
||||||
|
"serai-core-pallet/try-runtime",
|
||||||
|
"serai-coins-pallet/try-runtime",
|
||||||
|
"serai-dex-pallet/try-runtime",
|
||||||
|
]
|
||||||
|
|
||||||
|
runtime-benchmarks = [
|
||||||
|
"frame-system/runtime-benchmarks",
|
||||||
|
"frame-support/runtime-benchmarks",
|
||||||
|
|
||||||
|
"serai-core-pallet/runtime-benchmarks",
|
||||||
|
"serai-coins-pallet/runtime-benchmarks",
|
||||||
|
"serai-dex-pallet/runtime-benchmarks",
|
||||||
]
|
]
|
||||||
try-runtime = [] # TODO
|
|
||||||
|
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
AGPL-3.0-only license
|
AGPL-3.0-only license
|
||||||
|
|
||||||
Copyright (c) 2024-2025 Luke Parker
|
Copyright (c) 2023-2025 Luke Parker
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU Affero General Public License Version 3 as
|
||||||
|
|||||||
3
substrate/genesis-liquidity/README.md
Normal file
3
substrate/genesis-liquidity/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Genesis Liquidity Pallet
|
||||||
|
|
||||||
|
Pallet implementing the Serai protocol's genesis liquidity.
|
||||||
@@ -1,464 +1,102 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![doc = include_str!("../README.md")]
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
#![cfg_attr(not(any(feature = "std", test)), no_std)]
|
||||||
|
|
||||||
#[allow(
|
extern crate alloc;
|
||||||
unreachable_patterns,
|
|
||||||
clippy::cast_possible_truncation,
|
#[expect(clippy::cast_possible_truncation)]
|
||||||
clippy::no_effect_underscore_binding,
|
|
||||||
clippy::empty_docs
|
|
||||||
)]
|
|
||||||
#[frame_support::pallet]
|
#[frame_support::pallet]
|
||||||
pub mod pallet {
|
mod pallet {
|
||||||
|
use frame_system::pallet_prelude::*;
|
||||||
|
use frame_support::pallet_prelude::*;
|
||||||
|
|
||||||
|
use serai_abi::{
|
||||||
|
primitives::{prelude::*, crypto::Signature, genesis_liquidity::GenesisValues},
|
||||||
|
genesis_liquidity::Event,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serai_core_pallet::Pallet as Core;
|
||||||
|
type Coins<T> = serai_coins_pallet::Pallet<T, serai_coins_pallet::CoinsInstance>;
|
||||||
|
type LiquidityTokens<T> =
|
||||||
|
serai_coins_pallet::Pallet<T, serai_coins_pallet::LiquidityTokensInstance>;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use frame_system::{pallet_prelude::*, RawOrigin};
|
|
||||||
use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion};
|
|
||||||
|
|
||||||
use sp_std::{vec, vec::Vec};
|
|
||||||
use sp_core::sr25519::Signature;
|
|
||||||
use sp_application_crypto::RuntimePublic;
|
|
||||||
|
|
||||||
use dex_pallet::{Pallet as Dex, Config as DexConfig};
|
|
||||||
use coins_pallet::{Config as CoinsConfig, Pallet as Coins};
|
|
||||||
use validator_sets_pallet::{Config as VsConfig, Pallet as ValidatorSets};
|
|
||||||
|
|
||||||
use economic_security_pallet::{Config as EconomicSecurityConfig, Pallet as EconomicSecurity};
|
|
||||||
|
|
||||||
use serai_primitives::*;
|
|
||||||
use validator_sets_primitives::{ValidatorSet, musig_key};
|
|
||||||
pub use genesis_liquidity_primitives as primitives;
|
|
||||||
use primitives::*;
|
|
||||||
|
|
||||||
// TODO: Have a more robust way of accessing LiquidityTokens pallet.
|
|
||||||
/// LiquidityTokens Pallet as an instance of coins pallet.
|
|
||||||
pub type LiquidityTokens<T> = coins_pallet::Pallet<T, coins_pallet::Instance1>;
|
|
||||||
|
|
||||||
|
/// The configuration of this pallet.
|
||||||
#[pallet::config]
|
#[pallet::config]
|
||||||
pub trait Config:
|
pub trait Config:
|
||||||
frame_system::Config
|
frame_system::Config
|
||||||
+ VsConfig
|
+ serai_core_pallet::Config
|
||||||
+ DexConfig
|
+ serai_coins_pallet::Config<serai_coins_pallet::CoinsInstance>
|
||||||
+ EconomicSecurityConfig
|
+ serai_coins_pallet::Config<serai_coins_pallet::LiquidityTokensInstance>
|
||||||
+ CoinsConfig
|
+ serai_dex_pallet::Config
|
||||||
+ coins_pallet::Config<coins_pallet::Instance1>
|
|
||||||
{
|
{
|
||||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An error incurred.
|
||||||
#[pallet::error]
|
#[pallet::error]
|
||||||
pub enum Error<T> {
|
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: ExternalBalance },
|
|
||||||
GenesisLiquidityRemoved { by: SeraiAddress, balance: ExternalBalance },
|
|
||||||
GenesisLiquidityAddedToPool { coin: ExternalBalance, sri: Amount },
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// The Pallet struct.
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
pub struct Pallet<T>(PhantomData<T>);
|
pub struct Pallet<T>(_);
|
||||||
|
|
||||||
/// Keeps shares and the amount of coins per account.
|
|
||||||
#[pallet::storage]
|
|
||||||
#[pallet::getter(fn liquidity)]
|
|
||||||
pub(crate) type Liquidity<T: Config> = StorageDoubleMap<
|
|
||||||
_,
|
|
||||||
Identity,
|
|
||||||
ExternalCoin,
|
|
||||||
Blake2_128Concat,
|
|
||||||
PublicKey,
|
|
||||||
LiquidityAmount,
|
|
||||||
OptionQuery,
|
|
||||||
>;
|
|
||||||
|
|
||||||
/// Keeps the total shares and the total amount of coins per coin.
|
|
||||||
#[pallet::storage]
|
|
||||||
#[pallet::getter(fn supply)]
|
|
||||||
pub(crate) type Supply<T: Config> =
|
|
||||||
StorageMap<_, Identity, ExternalCoin, LiquidityAmount, OptionQuery>;
|
|
||||||
|
|
||||||
#[pallet::storage]
|
|
||||||
pub(crate) type Oracle<T: Config> = StorageMap<_, Identity, ExternalCoin, u64, OptionQuery>;
|
|
||||||
|
|
||||||
#[pallet::storage]
|
|
||||||
#[pallet::getter(fn genesis_complete_block)]
|
|
||||||
pub(crate) type GenesisCompleteBlock<T: Config> = StorageValue<_, u64, OptionQuery>;
|
|
||||||
|
|
||||||
#[pallet::hooks]
|
|
||||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
|
||||||
fn on_initialize(n: BlockNumberFor<T>) -> Weight {
|
|
||||||
#[cfg(feature = "fast-epoch")]
|
|
||||||
let final_block = 10u64;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "fast-epoch"))]
|
|
||||||
let final_block = MONTHS;
|
|
||||||
|
|
||||||
// Distribute the genesis sri to pools after a month
|
|
||||||
if (n.saturated_into::<u64>() >= final_block) &&
|
|
||||||
Self::oraclization_is_done() &&
|
|
||||||
GenesisCompleteBlock::<T>::get().is_none()
|
|
||||||
{
|
|
||||||
// mint the SRI
|
|
||||||
Coins::<T>::mint(
|
|
||||||
GENESIS_LIQUIDITY_ACCOUNT.into(),
|
|
||||||
Balance { coin: Coin::Serai, amount: Amount(GENESIS_SRI) },
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// get pool & total values
|
|
||||||
let mut pool_values = vec![];
|
|
||||||
let mut total_value: u128 = 0;
|
|
||||||
for coin in EXTERNAL_COINS {
|
|
||||||
// initial coin value in terms of btc
|
|
||||||
let Some(value) = Oracle::<T>::get(coin) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool_amount =
|
|
||||||
u128::from(Supply::<T>::get(coin).unwrap_or(LiquidityAmount::zero()).coins);
|
|
||||||
let pool_value = pool_amount
|
|
||||||
.checked_mul(value.into())
|
|
||||||
.unwrap()
|
|
||||||
.checked_div(10u128.pow(coin.decimals()))
|
|
||||||
.unwrap();
|
|
||||||
total_value = total_value.checked_add(pool_value).unwrap();
|
|
||||||
pool_values.push((coin, pool_amount, pool_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the liquidity per pool
|
|
||||||
let mut total_sri_distributed = 0;
|
|
||||||
let pool_values_len = pool_values.len();
|
|
||||||
for (i, (coin, pool_amount, pool_value)) in pool_values.into_iter().enumerate() {
|
|
||||||
// whatever sri left for the last coin should be ~= it's ratio
|
|
||||||
let sri_amount = if i == (pool_values_len - 1) {
|
|
||||||
GENESIS_SRI.checked_sub(total_sri_distributed).unwrap()
|
|
||||||
} else {
|
|
||||||
u64::try_from(
|
|
||||||
u128::from(GENESIS_SRI)
|
|
||||||
.checked_mul(pool_value)
|
|
||||||
.unwrap()
|
|
||||||
.checked_div(total_value)
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
total_sri_distributed = total_sri_distributed.checked_add(sri_amount).unwrap();
|
|
||||||
|
|
||||||
// actually add the liquidity to dex
|
|
||||||
let origin = RawOrigin::Signed(GENESIS_LIQUIDITY_ACCOUNT.into());
|
|
||||||
let Ok(()) = Dex::<T>::add_liquidity(
|
|
||||||
origin.into(),
|
|
||||||
coin,
|
|
||||||
u64::try_from(pool_amount).unwrap(),
|
|
||||||
sri_amount,
|
|
||||||
u64::try_from(pool_amount).unwrap(),
|
|
||||||
sri_amount,
|
|
||||||
GENESIS_LIQUIDITY_ACCOUNT.into(),
|
|
||||||
) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// let everyone know about the event
|
|
||||||
Self::deposit_event(Event::GenesisLiquidityAddedToPool {
|
|
||||||
coin: ExternalBalance { coin, amount: Amount(u64::try_from(pool_amount).unwrap()) },
|
|
||||||
sri: Amount(sri_amount),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
assert_eq!(total_sri_distributed, GENESIS_SRI);
|
|
||||||
|
|
||||||
// we shouldn't have left any coin in genesis account at this moment, including SRI.
|
|
||||||
// All transferred to the pools.
|
|
||||||
for coin in COINS {
|
|
||||||
assert_eq!(Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), coin), Amount(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
GenesisCompleteBlock::<T>::set(Some(n.saturated_into::<u64>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Weight::zero() // TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Config> Pallet<T> {
|
impl<T: Config> Pallet<T> {
|
||||||
/// Add genesis liquidity for the given account. All accounts that provide liquidity
|
fn emit_event(event: Event) {
|
||||||
/// will receive the genesis SRI according to their liquidity ratio.
|
Core::<T>::emit_event(event)
|
||||||
pub fn add_coin_liquidity(account: PublicKey, balance: ExternalBalance) -> DispatchResult {
|
|
||||||
// check we are still in genesis period
|
|
||||||
if Self::genesis_ended() {
|
|
||||||
Err(Error::<T>::GenesisPeriodEnded)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate new shares & supply
|
|
||||||
let (new_liquidity, new_supply) = if let Some(supply) = Supply::<T>::get(balance.coin) {
|
|
||||||
// calculate amount of shares for this amount
|
|
||||||
let shares = Self::mul_div(supply.shares, balance.amount.0, supply.coins)?;
|
|
||||||
|
|
||||||
// get new shares for this account
|
|
||||||
let existing =
|
|
||||||
Liquidity::<T>::get(balance.coin, account).unwrap_or(LiquidityAmount::zero());
|
|
||||||
(
|
|
||||||
LiquidityAmount {
|
|
||||||
shares: existing.shares.checked_add(shares).ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
coins: existing
|
|
||||||
.coins
|
|
||||||
.checked_add(balance.amount.0)
|
|
||||||
.ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
},
|
|
||||||
LiquidityAmount {
|
|
||||||
shares: supply.shares.checked_add(shares).ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
coins: supply
|
|
||||||
.coins
|
|
||||||
.checked_add(balance.amount.0)
|
|
||||||
.ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let first_amount =
|
|
||||||
LiquidityAmount { shares: INITIAL_GENESIS_LP_SHARES, coins: balance.amount.0 };
|
|
||||||
(first_amount, first_amount)
|
|
||||||
};
|
|
||||||
|
|
||||||
// save
|
|
||||||
Liquidity::<T>::set(balance.coin, account, Some(new_liquidity));
|
|
||||||
Supply::<T>::set(balance.coin, Some(new_supply));
|
|
||||||
Self::deposit_event(Event::GenesisLiquidityAdded { by: account.into(), balance });
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of blocks since the all networks reached economic security first time.
|
|
||||||
/// If networks is yet to be reached that threshold, None is returned.
|
|
||||||
fn blocks_since_ec_security() -> Option<u64> {
|
|
||||||
let mut min = u64::MAX;
|
|
||||||
for n in EXTERNAL_NETWORKS {
|
|
||||||
let ec_security_block =
|
|
||||||
EconomicSecurity::<T>::economic_security_block(n)?.saturated_into::<u64>();
|
|
||||||
let current = <frame_system::Pallet<T>>::block_number().saturated_into::<u64>();
|
|
||||||
let diff = current.saturating_sub(ec_security_block);
|
|
||||||
min = diff.min(min);
|
|
||||||
}
|
|
||||||
Some(min)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn genesis_ended() -> bool {
|
|
||||||
Self::oraclization_is_done() &&
|
|
||||||
<frame_system::Pallet<T>>::block_number().saturated_into::<u64>() >= MONTHS
|
|
||||||
}
|
|
||||||
|
|
||||||
fn oraclization_is_done() -> bool {
|
|
||||||
for c in EXTERNAL_COINS {
|
|
||||||
if Oracle::<T>::get(c).is_none() {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
/// The minimum amount of liquidity allowed to be initially added.
|
||||||
}
|
///
|
||||||
|
/// This should be sufficiently low it isn't inaccessible, yet sufficiently high that future
|
||||||
|
/// additions can be reasonably grained when their share of the new supply is calculated.
|
||||||
|
///
|
||||||
|
/// This constant is duplicated with `serai-dex-pallet` intentionally as while they have the same
|
||||||
|
/// value, they are distinct constants and don't require being equivalent.
|
||||||
|
const MINIMUM_LIQUIDITY: u64 = 1 << 16;
|
||||||
|
|
||||||
fn mul_div(a: u64, b: u64, c: u64) -> Result<u64, Error<T>> {
|
impl<T: Config> Pallet<T> {
|
||||||
let a = u128::from(a);
|
/// Add liquidity on behalf of the specified address.
|
||||||
let b = u128::from(b);
|
pub fn add_liquidity(to: SeraiAddress, balance: ExternalBalance) -> Result<(), Error<T>> {
|
||||||
let c = u128::from(c);
|
todo!("TODO")
|
||||||
|
|
||||||
let result = a
|
|
||||||
.checked_mul(b)
|
|
||||||
.ok_or(Error::<T>::AmountOverflowed)?
|
|
||||||
.checked_div(c)
|
|
||||||
.ok_or(Error::<T>::AmountOverflowed)?;
|
|
||||||
|
|
||||||
result.try_into().map_err(|_| Error::<T>::AmountOverflowed)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::call]
|
#[pallet::call]
|
||||||
impl<T: Config> Pallet<T> {
|
impl<T: Config> Pallet<T> {
|
||||||
/// Remove the provided genesis liquidity for an account.
|
/// Oraclize the values of the coins available on genesis, relative to BTC.
|
||||||
|
///
|
||||||
|
/// This will trigger the addition of the liquidity into the pools and their initialization.
|
||||||
#[pallet::call_index(0)]
|
#[pallet::call_index(0)]
|
||||||
#[pallet::weight((0, DispatchClass::Operational))] // TODO
|
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
||||||
pub fn remove_coin_liquidity(origin: OriginFor<T>, balance: ExternalBalance) -> DispatchResult {
|
|
||||||
let account = ensure_signed(origin)?;
|
|
||||||
let origin = RawOrigin::Signed(GENESIS_LIQUIDITY_ACCOUNT.into());
|
|
||||||
let supply = Supply::<T>::get(balance.coin).ok_or(Error::<T>::NotEnoughLiquidity)?;
|
|
||||||
|
|
||||||
// check we are still in genesis period
|
|
||||||
let (new_liquidity, new_supply) = if Self::genesis_ended() {
|
|
||||||
// see how much liq tokens we have
|
|
||||||
let total_liq_tokens =
|
|
||||||
LiquidityTokens::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), Coin::Serai).0;
|
|
||||||
|
|
||||||
// get how much user wants to remove
|
|
||||||
let LiquidityAmount { shares, coins } =
|
|
||||||
Liquidity::<T>::get(balance.coin, account).unwrap_or(LiquidityAmount::zero());
|
|
||||||
let total_shares = Supply::<T>::get(balance.coin).unwrap_or(LiquidityAmount::zero()).shares;
|
|
||||||
let user_liq_tokens = Self::mul_div(total_liq_tokens, shares, total_shares)?;
|
|
||||||
let amount_to_remove =
|
|
||||||
Self::mul_div(user_liq_tokens, balance.amount.0, INITIAL_GENESIS_LP_SHARES)?;
|
|
||||||
|
|
||||||
// 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.into());
|
|
||||||
Dex::<T>::remove_liquidity(
|
|
||||||
origin.clone().into(),
|
|
||||||
balance.coin,
|
|
||||||
amount_to_remove,
|
|
||||||
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.into());
|
|
||||||
|
|
||||||
// burn the SRI if necessary
|
|
||||||
// TODO: take into consideration movement between pools.
|
|
||||||
let mut sri: u64 = current_sri.0.saturating_sub(prev_sri.0);
|
|
||||||
let distance_to_full_pay =
|
|
||||||
GENESIS_SRI_TRICKLE_FEED.saturating_sub(Self::blocks_since_ec_security().unwrap_or(0));
|
|
||||||
let burn_sri_amount = u64::try_from(
|
|
||||||
u128::from(sri)
|
|
||||||
.checked_mul(u128::from(distance_to_full_pay))
|
|
||||||
.ok_or(Error::<T>::AmountOverflowed)?
|
|
||||||
.checked_div(u128::from(GENESIS_SRI_TRICKLE_FEED))
|
|
||||||
.ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
)
|
|
||||||
.map_err(|_| Error::<T>::AmountOverflowed)?;
|
|
||||||
Coins::<T>::burn(
|
|
||||||
origin.clone().into(),
|
|
||||||
Balance { coin: Coin::Serai, amount: Amount(burn_sri_amount) },
|
|
||||||
)?;
|
|
||||||
sri = sri.checked_sub(burn_sri_amount).ok_or(Error::<T>::AmountOverflowed)?;
|
|
||||||
|
|
||||||
// transfer to owner
|
|
||||||
let coin_out = current_coin.0.saturating_sub(prev_coin.0);
|
|
||||||
Coins::<T>::transfer(
|
|
||||||
origin.clone().into(),
|
|
||||||
account,
|
|
||||||
Balance { coin: balance.coin.into(), amount: Amount(coin_out) },
|
|
||||||
)?;
|
|
||||||
Coins::<T>::transfer(
|
|
||||||
origin.into(),
|
|
||||||
account,
|
|
||||||
Balance { coin: Coin::Serai, amount: Amount(sri) },
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// return new amounts
|
|
||||||
(
|
|
||||||
LiquidityAmount {
|
|
||||||
shares: shares.checked_sub(amount_to_remove).ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
coins: coins.checked_sub(coin_out).ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
},
|
|
||||||
LiquidityAmount {
|
|
||||||
shares: supply
|
|
||||||
.shares
|
|
||||||
.checked_sub(amount_to_remove)
|
|
||||||
.ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
coins: supply.coins.checked_sub(coin_out).ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
if balance.amount.0 != INITIAL_GENESIS_LP_SHARES {
|
|
||||||
Err(Error::<T>::CanOnlyRemoveFullAmount)?;
|
|
||||||
}
|
|
||||||
let existing =
|
|
||||||
Liquidity::<T>::get(balance.coin, account).ok_or(Error::<T>::NotEnoughLiquidity)?;
|
|
||||||
|
|
||||||
// transfer to the user
|
|
||||||
Coins::<T>::transfer(
|
|
||||||
origin.into(),
|
|
||||||
account,
|
|
||||||
Balance { coin: balance.coin.into(), amount: Amount(existing.coins) },
|
|
||||||
)?;
|
|
||||||
|
|
||||||
(
|
|
||||||
LiquidityAmount::zero(),
|
|
||||||
LiquidityAmount {
|
|
||||||
shares: supply
|
|
||||||
.shares
|
|
||||||
.checked_sub(existing.shares)
|
|
||||||
.ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
coins: supply.coins.checked_sub(existing.coins).ok_or(Error::<T>::AmountOverflowed)?,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
// save
|
|
||||||
if new_liquidity == LiquidityAmount::zero() {
|
|
||||||
Liquidity::<T>::set(balance.coin, account, None);
|
|
||||||
} else {
|
|
||||||
Liquidity::<T>::set(balance.coin, account, Some(new_liquidity));
|
|
||||||
}
|
|
||||||
Supply::<T>::set(balance.coin, Some(new_supply));
|
|
||||||
|
|
||||||
Self::deposit_event(Event::GenesisLiquidityRemoved { by: account.into(), balance });
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A call to submit the initial coin values in terms of BTC.
|
|
||||||
#[pallet::call_index(1)]
|
|
||||||
#[pallet::weight((0, DispatchClass::Operational))] // TODO
|
|
||||||
pub fn oraclize_values(
|
pub fn oraclize_values(
|
||||||
origin: OriginFor<T>,
|
origin: OriginFor<T>,
|
||||||
values: Values,
|
values: GenesisValues,
|
||||||
_signature: Signature,
|
signature: Signature,
|
||||||
) -> DispatchResult {
|
) -> DispatchResult {
|
||||||
ensure_none(origin)?;
|
todo!("TODO")
|
||||||
|
|
||||||
// set their relative values
|
|
||||||
Oracle::<T>::set(ExternalCoin::Bitcoin, Some(10u64.pow(ExternalCoin::Bitcoin.decimals())));
|
|
||||||
Oracle::<T>::set(ExternalCoin::Monero, Some(values.monero));
|
|
||||||
Oracle::<T>::set(ExternalCoin::Ether, Some(values.ether));
|
|
||||||
Oracle::<T>::set(ExternalCoin::Dai, Some(values.dai));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::validate_unsigned]
|
/// Transfer genesis liquidity.
|
||||||
impl<T: Config> ValidateUnsigned for Pallet<T> {
|
#[pallet::call_index(1)]
|
||||||
type Call = Call<T>;
|
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
||||||
|
pub fn transfer_genesis_liquidity(
|
||||||
fn validate_unsigned(_: TransactionSource, call: &Self::Call) -> TransactionValidity {
|
origin: OriginFor<T>,
|
||||||
match call {
|
to: SeraiAddress,
|
||||||
Call::oraclize_values { ref values, ref signature } => {
|
genesis_liquidity: ExternalBalance,
|
||||||
let network = NetworkId::Serai;
|
) -> DispatchResult {
|
||||||
let Some(session) = ValidatorSets::<T>::session(network) else {
|
todo!("TODO")
|
||||||
return Err(TransactionValidityError::from(InvalidTransaction::Custom(0)));
|
|
||||||
};
|
|
||||||
|
|
||||||
let set = ValidatorSet { network, session };
|
|
||||||
let signers = ValidatorSets::<T>::participants_for_latest_decided_set(network)
|
|
||||||
.expect("no participant in the current set")
|
|
||||||
.into_iter()
|
|
||||||
.map(|(p, _)| p)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// check this didn't get called before
|
|
||||||
if Self::oraclization_is_done() {
|
|
||||||
Err(InvalidTransaction::Custom(1))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure signers settings the value at the end of the genesis period.
|
/// Remove genesis liquidity.
|
||||||
// we don't need this check for tests.
|
#[pallet::call_index(2)]
|
||||||
#[cfg(not(feature = "fast-epoch"))]
|
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
||||||
if <frame_system::Pallet<T>>::block_number().saturated_into::<u64>() < MONTHS {
|
pub fn remove_genesis_liquidity(
|
||||||
Err(InvalidTransaction::Custom(2))?;
|
origin: OriginFor<T>,
|
||||||
}
|
genesis_liquidity: ExternalBalance,
|
||||||
|
) -> DispatchResult {
|
||||||
if !musig_key(set, &signers).verify(&oraclize_values_message(&set, values), signature) {
|
todo!("TODO")
|
||||||
Err(InvalidTransaction::BadProof)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValidTransaction::with_tag_prefix("GenesisLiquidity")
|
|
||||||
.and_provides((0, set))
|
|
||||||
.longevity(u64::MAX)
|
|
||||||
.propagate(true)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
Call::remove_coin_liquidity { .. } => Err(InvalidTransaction::Call)?,
|
|
||||||
Call::__Ignore(_, _) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ use crate::balance::Amount;
|
|||||||
|
|
||||||
/// The value of non-Bitcoin externals coins present at genesis, relative to Bitcoin.
|
/// The value of non-Bitcoin externals coins present at genesis, relative to Bitcoin.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "non_canonical_scale_derivations",
|
||||||
|
derive(scale::Encode, scale::Decode, scale::MaxEncodedLen, scale::DecodeWithMemTracking)
|
||||||
|
)]
|
||||||
pub struct GenesisValues {
|
pub struct GenesisValues {
|
||||||
/// The value of Ether, relative to Bitcoin.
|
/// The value of Ether, relative to Bitcoin.
|
||||||
pub ether: Amount,
|
pub ether: Amount,
|
||||||
@@ -29,8 +29,8 @@ pub mod coin;
|
|||||||
/// The `Amount`, `ExternalBalance`, and `Balance` types.
|
/// The `Amount`, `ExternalBalance`, and `Balance` types.
|
||||||
pub mod balance;
|
pub mod balance;
|
||||||
|
|
||||||
/// Types for genesis.
|
/// Types for the genesis liquidity functionality.
|
||||||
pub mod genesis;
|
pub mod genesis_liquidity;
|
||||||
|
|
||||||
/// Types for identifying networks and their properties.
|
/// Types for identifying networks and their properties.
|
||||||
pub mod network_id;
|
pub mod network_id;
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ serai-coins-pallet = { path = "../coins", default-features = false }
|
|||||||
serai-validator-sets-pallet = { path = "../validator-sets", default-features = false }
|
serai-validator-sets-pallet = { path = "../validator-sets", default-features = false }
|
||||||
serai-signals-pallet = { path = "../signals", default-features = false }
|
serai-signals-pallet = { path = "../signals", default-features = false }
|
||||||
serai-dex-pallet = { path = "../dex", default-features = false }
|
serai-dex-pallet = { path = "../dex", default-features = false }
|
||||||
|
serai-genesis-liquidity-pallet = { path = "../genesis-liquidity", default-features = false }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk" }
|
substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk" }
|
||||||
@@ -90,6 +91,7 @@ std = [
|
|||||||
"serai-validator-sets-pallet/std",
|
"serai-validator-sets-pallet/std",
|
||||||
"serai-signals-pallet/std",
|
"serai-signals-pallet/std",
|
||||||
"serai-dex-pallet/std",
|
"serai-dex-pallet/std",
|
||||||
|
"serai-genesis-liquidity-pallet/std",
|
||||||
]
|
]
|
||||||
|
|
||||||
try-runtime = [
|
try-runtime = [
|
||||||
@@ -110,6 +112,7 @@ try-runtime = [
|
|||||||
"serai-validator-sets-pallet/try-runtime",
|
"serai-validator-sets-pallet/try-runtime",
|
||||||
"serai-signals-pallet/try-runtime",
|
"serai-signals-pallet/try-runtime",
|
||||||
"serai-dex-pallet/try-runtime",
|
"serai-dex-pallet/try-runtime",
|
||||||
|
"serai-genesis-liquidity-pallet/try-runtime",
|
||||||
]
|
]
|
||||||
|
|
||||||
runtime-benchmarks = [
|
runtime-benchmarks = [
|
||||||
@@ -127,6 +130,7 @@ runtime-benchmarks = [
|
|||||||
"serai-validator-sets-pallet/runtime-benchmarks",
|
"serai-validator-sets-pallet/runtime-benchmarks",
|
||||||
"serai-signals-pallet/runtime-benchmarks",
|
"serai-signals-pallet/runtime-benchmarks",
|
||||||
"serai-dex-pallet/runtime-benchmarks",
|
"serai-dex-pallet/runtime-benchmarks",
|
||||||
|
"serai-genesis-liquidity-pallet/runtime-benchmarks",
|
||||||
]
|
]
|
||||||
|
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ mod runtime {
|
|||||||
#[runtime::pallet_index(6)]
|
#[runtime::pallet_index(6)]
|
||||||
pub type Dex = serai_dex_pallet::Pallet<Runtime>;
|
pub type Dex = serai_dex_pallet::Pallet<Runtime>;
|
||||||
|
|
||||||
|
#[runtime::pallet_index(7)]
|
||||||
|
pub type GenesisLiquidity = serai_genesis_liquidity_pallet::Pallet<Runtime>;
|
||||||
|
|
||||||
#[runtime::pallet_index(0xfd)]
|
#[runtime::pallet_index(0xfd)]
|
||||||
#[runtime::disable_inherent]
|
#[runtime::disable_inherent]
|
||||||
pub type Timestamp = pallet_timestamp::Pallet<Runtime>;
|
pub type Timestamp = pallet_timestamp::Pallet<Runtime>;
|
||||||
@@ -174,6 +177,7 @@ impl serai_coins_pallet::Config<LiquidityTokensInstance> for Runtime {
|
|||||||
type AllowMint = serai_coins_pallet::AlwaysAllowMint;
|
type AllowMint = serai_coins_pallet::AlwaysAllowMint;
|
||||||
}
|
}
|
||||||
impl serai_dex_pallet::Config for Runtime {}
|
impl serai_dex_pallet::Config for Runtime {}
|
||||||
|
impl serai_genesis_liquidity_pallet::Config for Runtime {}
|
||||||
|
|
||||||
impl pallet_timestamp::Config for Runtime {
|
impl pallet_timestamp::Config for Runtime {
|
||||||
type Moment = u64;
|
type Moment = u64;
|
||||||
@@ -329,7 +333,23 @@ impl From<serai_abi::Call> for RuntimeCall {
|
|||||||
serai_abi::Call::GenesisLiquidity(call) => {
|
serai_abi::Call::GenesisLiquidity(call) => {
|
||||||
use serai_abi::genesis_liquidity::Call;
|
use serai_abi::genesis_liquidity::Call;
|
||||||
match call {
|
match call {
|
||||||
Call::oraclize_values { .. } | Call::remove_liquidity { .. } => todo!("TODO"),
|
Call::oraclize_values { values, signature } => {
|
||||||
|
RuntimeCall::GenesisLiquidity(serai_genesis_liquidity_pallet::Call::oraclize_values {
|
||||||
|
values,
|
||||||
|
signature,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Call::transfer_genesis_liquidity { to, genesis_liquidity } => {
|
||||||
|
RuntimeCall::GenesisLiquidity(
|
||||||
|
serai_genesis_liquidity_pallet::Call::transfer_genesis_liquidity {
|
||||||
|
to,
|
||||||
|
genesis_liquidity,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Call::remove_genesis_liquidity { genesis_liquidity } => RuntimeCall::GenesisLiquidity(
|
||||||
|
serai_genesis_liquidity_pallet::Call::remove_genesis_liquidity { genesis_liquidity },
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serai_abi::Call::InInstructions(call) => {
|
serai_abi::Call::InInstructions(call) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user