add genesis liquidity test & misc fixes

This commit is contained in:
akildemir
2024-04-29 23:19:55 +03:00
parent 826f9986e4
commit 926ddd09db
14 changed files with 590 additions and 47 deletions

View File

@@ -56,5 +56,6 @@ std = [
"genesis-liquidity-primitives/std",
"validator-sets-primitives/std",
]
fast-epoch = []
default = ["std"]

View File

@@ -94,8 +94,14 @@ pub mod pallet {
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_finalize(n: BlockNumberFor<T>) {
#[cfg(feature = "fast-epoch")]
let final_block = 25u32;
#[cfg(not(feature = "fast-epoch"))]
let final_block = BLOCKS_PER_MONTH;
// Distribute the genesis sri to pools after a month
if n == BLOCKS_PER_MONTH.into() {
if n == final_block.into() {
// mint the SRI
Coins::<T>::mint(
GENESIS_LIQUIDITY_ACCOUNT.into(),
@@ -105,8 +111,8 @@ pub mod pallet {
// get coin values & total
let mut account_values = BTreeMap::new();
let mut pool_values = BTreeMap::new();
let mut total_value: u64 = 0;
let mut pool_values = vec![];
let mut total_value: u128 = 0;
for coin in COINS {
if coin == Coin::Serai {
continue;
@@ -117,50 +123,85 @@ pub mod pallet {
// get the pool & individual address values
account_values.insert(coin, vec![]);
let mut pool_amount: u64 = 0;
let mut pool_amount: u128 = 0;
for (account, amount) in Liquidity::<T>::iter_prefix(coin) {
pool_amount = pool_amount.saturating_add(amount);
let value_this_addr = amount.saturating_mul(value);
pool_amount = pool_amount.saturating_add(amount.into());
let value_this_addr =
u128::from(amount).saturating_mul(value.into()) / 10u128.pow(coin.decimals());
account_values.get_mut(&coin).unwrap().push((account, value_this_addr))
}
// sort, so that everyone has a consistent accounts vector per coin
account_values.get_mut(&coin).unwrap().sort();
let pool_value = pool_amount.saturating_mul(value);
let pool_value = pool_amount.saturating_mul(value.into()) / 10u128.pow(coin.decimals());
total_value = total_value.saturating_add(pool_value);
pool_values.insert(coin, (pool_amount, pool_value));
pool_values.push((coin, pool_amount, pool_value));
}
// add the liquidity per pool
for (coin, (amount, value)) in &pool_values {
let sri_amount = GENESIS_SRI.saturating_mul(*value) / total_value;
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 - total_sri_distributed
} else {
u64::try_from(u128::from(GENESIS_SRI).saturating_mul(pool_value) / total_value).unwrap()
};
total_sri_distributed += sri_amount;
// we can't add 0 liquidity
if !(pool_amount > 0 && sri_amount > 0) {
continue;
}
// actually add the liquidity to dex
let origin = RawOrigin::Signed(GENESIS_LIQUIDITY_ACCOUNT.into());
Dex::<T>::add_liquidity(
origin.into(),
*coin,
*amount,
coin,
u64::try_from(pool_amount).unwrap(),
sri_amount,
*amount,
u64::try_from(pool_amount).unwrap(),
sri_amount,
GENESIS_LIQUIDITY_ACCOUNT.into(),
)
.unwrap();
// let everyone know about the event
Self::deposit_event(Event::GenesisLiquidityAddedToPool {
coin1: Balance { coin: *coin, amount: Amount(*amount) },
coin1: Balance { coin, amount: Amount(u64::try_from(pool_amount).unwrap()) },
coin2: Balance { coin: Coin::Serai, amount: Amount(sri_amount) },
});
// 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.saturating_mul(*value) / pool_values.get(coin).unwrap().1;
let tokens =
u128::from(LiquidityTokens::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), coin).0);
let mut total_tokens_this_coin: u128 = 0;
let accounts = account_values.get(&coin).unwrap();
for (i, (acc, acc_value)) in accounts.iter().enumerate() {
// give whatever left to the last account not to have rounding errors.
let liq_tokens_this_acc = if i == accounts.len() - 1 {
tokens - total_tokens_this_coin
} else {
tokens.saturating_mul(*acc_value) / pool_value
};
total_tokens_this_coin = total_tokens_this_coin.saturating_add(liq_tokens_this_acc);
LiquidityTokensPerAddress::<T>::set(coin, acc, Some(liq_tokens_this_acc));
LiquidityTokensPerAddress::<T>::set(
coin,
acc,
Some(u64::try_from(liq_tokens_this_acc).unwrap()),
);
}
assert_eq!(tokens, total_tokens_this_coin);
}
assert_eq!(total_sri_distributed, GENESIS_SRI);
// we shouldn't have any coin left in our account at this moment, including 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));
}

View File

@@ -30,5 +30,16 @@ serai-primitives = { path = "../../primitives", default-features = false }
validator-sets-primitives = { package = "serai-validator-sets-primitives", path = "../../validator-sets/primitives", default-features = false }
[features]
std = ["serai-primitives/std", "validator-sets-primitives/std", "sp-std/std"]
std = [
"zeroize",
"scale/std",
"borsh?/std",
"serde?/std",
"scale-info/std",
"serai-primitives/std",
"validator-sets-primitives/std",
"sp-std/std"
]
default = ["std"]

View File

@@ -30,7 +30,7 @@ pub const GENESIS_SRI: u64 = 100_000_000 * 10_u64.pow(8);
// This is the account to hold and manage the genesis liquidity.
pub const GENESIS_LIQUIDITY_ACCOUNT: SeraiAddress = system_address(b"Genesis-liquidity-account");
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[derive(Clone, Copy, 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))]