Skip to content

Commit

Permalink
fix some pr comments
Browse files Browse the repository at this point in the history
  • Loading branch information
akildemir committed Jul 30, 2024
1 parent 3cb7386 commit e1b4a9a
Show file tree
Hide file tree
Showing 23 changed files with 362 additions and 298 deletions.
4 changes: 3 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ exceptions = [
{ allow = ["AGPL-3.0"], name = "serai-genesis-liquidity-pallet" },
{ allow = ["AGPL-3.0"], name = "serai-emissions-pallet" },

{ allow = ["AGPL-3.0"], name = "serai-genesis-liquidity-pallet" },

{ allow = ["AGPL-3.0"], name = "serai-in-instructions-pallet" },

{ allow = ["AGPL-3.0"], name = "serai-validator-sets-pallet" },
Expand Down
15 changes: 0 additions & 15 deletions substrate/abi/src/emissions.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1 @@
pub use serai_emissions_primitives as primitives;

#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Call {
// This call is just a place holder so that abi works as expected.
empty_call,
}

#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Event {
empty_event,
}
4 changes: 2 additions & 2 deletions substrate/abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub enum Call {
Dex(dex::Call),
ValidatorSets(validator_sets::Call),
GenesisLiquidity(genesis_liquidity::Call),
Emissions(emissions::Call),
Emissions,
InInstructions(in_instructions::Call),
Signals(signals::Call),
Babe(babe::Call),
Expand All @@ -58,7 +58,7 @@ pub enum Event {
Dex(dex::Event),
ValidatorSets(validator_sets::Event),
GenesisLiquidity(genesis_liquidity::Event),
Emissions(emissions::Event),
Emissions,
InInstructions(in_instructions::Event),
Signals(signals::Event),
Babe,
Expand Down
2 changes: 1 addition & 1 deletion substrate/client/src/serai/dex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl<'a> SeraiDex<'a> {
}

/// Returns the reserves of `coin:SRI` pool.
pub async fn get_reserves(&self, coin: Coin) -> Result<Option<(u64, u64)>, SeraiError> {
pub async fn get_reserves(&self, coin: Coin) -> Result<Option<(Amount, Amount)>, SeraiError> {
self.0.runtime_api("DexApi_get_reserves", (coin, Coin::Serai)).await
}

Expand Down
5 changes: 3 additions & 2 deletions substrate/client/src/serai/genesis_liquidity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ impl<'a> SeraiGenesisLiquidity<'a> {
Ok(self.0.storage(PALLET, "Supply", coin).await?.unwrap_or(LiquidityAmount::zero()))
}

pub async fn genesis_complete(&self) -> Result<Option<()>, SeraiError> {
self.0.storage(PALLET, "GenesisComplete", ()).await
pub async fn genesis_complete(&self) -> Result<bool, SeraiError> {
let result: Option<()> = self.0.storage(PALLET, "GenesisComplete", ()).await?;
Ok(result.is_some())
}
}
2 changes: 1 addition & 1 deletion substrate/client/src/serai/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ impl<'a> TemporalSerai<'a> {
let bytes = Serai::hex_decode(result.clone())?;
R::decode(&mut bytes.as_slice()).map_err(|_| {
SeraiError::InvalidRuntime(format!(
"different type than what is expected returned, raw value: {}",
"different type than what is expected to be returned, raw value: {}",
hex::encode(result)
))
})
Expand Down
139 changes: 22 additions & 117 deletions substrate/client/tests/common/genesis_liquidity.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{time::Duration, collections::HashMap};
use std::collections::HashMap;

use rand_core::{RngCore, OsRng};
use zeroize::Zeroizing;
Expand All @@ -7,58 +7,49 @@ use ciphersuite::{Ciphersuite, Ristretto};
use frost::dkg::musig::musig;
use schnorrkel::Schnorrkel;

use serai_client::{
genesis_liquidity::{
primitives::{GENESIS_LIQUIDITY_ACCOUNT, INITIAL_GENESIS_LP_SHARES},
SeraiGenesisLiquidity,
},
validator_sets::primitives::{musig_context, Session, ValidatorSet},
};
use sp_core::{sr25519::Signature, Pair as PairTrait};

use serai_abi::{
genesis_liquidity::primitives::{oraclize_values_message, Values},
primitives::COINS,
};

use sp_core::{sr25519::Signature, Pair as PairTrait};

use serai_client::{
validator_sets::primitives::{musig_context, Session, ValidatorSet},
in_instructions::primitives::{InInstruction, InInstructionWithBalance, Batch},
primitives::{
Amount, NetworkId, Coin, Balance, BlockHash, SeraiAddress, insecure_pair_from_name, GENESIS_SRI,
Amount, NetworkId, Coin, Balance, BlockHash, SeraiAddress, insecure_pair_from_name,
},
in_instructions::primitives::{InInstruction, InInstructionWithBalance, Batch},
Serai,
};

use serai_client::{Serai, SeraiGenesisLiquidity};

use crate::common::{in_instructions::provide_batch, tx::publish_tx};

#[allow(dead_code)]
pub async fn test_genesis_liquidity(serai: Serai) -> HashMap<NetworkId, u32> {
// all coins except the native
let coins = COINS.into_iter().filter(|c| *c != Coin::native()).collect::<Vec<_>>();

pub async fn set_up_genesis(
serai: &Serai,
coins: &[Coin],
values: &HashMap<Coin, u64>,
) -> (HashMap<Coin, Vec<(SeraiAddress, Amount)>>, HashMap<NetworkId, u32>) {
// make accounts with amounts
let mut accounts = HashMap::new();
for coin in coins.clone() {
for coin in coins {
// make 5 accounts per coin
let mut values = vec![];
for _ in 0 .. 5 {
let mut address = SeraiAddress::new([0; 32]);
OsRng.fill_bytes(&mut address.0);
values.push((address, Amount(OsRng.next_u64() % 10u64.pow(coin.decimals()))));
}
accounts.insert(coin, values);
accounts.insert(*coin, values);
}

// send a batch per coin
let mut batch_ids: HashMap<NetworkId, u32> = HashMap::new();
for coin in coins.clone() {
for coin in coins {
// set up instructions
let instructions = accounts[&coin]
let instructions = accounts[coin]
.iter()
.map(|(addr, amount)| InInstructionWithBalance {
instruction: InInstruction::GenesisLiquidity(*addr),
balance: Balance { coin, amount: *amount },
balance: Balance { coin: *coin, amount: *amount },
})
.collect::<Vec<_>>();

Expand All @@ -76,103 +67,17 @@ pub async fn test_genesis_liquidity(serai: Serai) -> HashMap<NetworkId, u32> {

let batch =
Batch { network: coin.network(), id: batch_ids[&coin.network()], block, instructions };
provide_batch(&serai, batch).await;
provide_batch(serai, batch).await;
}

// set values relative to each other. We can do that without checking for genesis period blocks
// since we are running in test(fast-epoch) mode.
// TODO: Random values here
let values = Values { monero: 184100, ether: 4785000, dai: 1500 };
set_values(&serai, &values).await;
let values_map = HashMap::from([
(Coin::Monero, values.monero),
(Coin::Ether, values.ether),
(Coin::Dai, values.dai),
]);

// wait until genesis is complete
while serai
.as_of_latest_finalized_block()
.await
.unwrap()
.genesis_liquidity()
.genesis_complete()
.await
.unwrap()
.is_none()
{
tokio::time::sleep(Duration::from_secs(1)).await;
}

// check total SRI supply is +100M
// there are 6 endowed accounts in dev-net. Take this into consideration when checking
// for the total sri minted at this time.
let serai = serai.as_of_latest_finalized_block().await.unwrap();
let sri = serai.coins().coin_supply(Coin::Serai).await.unwrap();
let endowed_amount: u64 = 1 << 60;
let total_sri = (6 * endowed_amount) + GENESIS_SRI;
assert_eq!(sri, Amount(total_sri));

// check genesis account has no coins, all transferred to pools.
for coin in COINS {
let amount = serai.coins().coin_balance(coin, GENESIS_LIQUIDITY_ACCOUNT).await.unwrap();
assert_eq!(amount.0, 0);
}

// check pools has proper liquidity
let mut pool_amounts = HashMap::new();
let mut total_value = 0u128;
for coin in coins.clone() {
let total_coin = accounts[&coin].iter().fold(0u128, |acc, value| acc + u128::from(value.1 .0));
let value = if coin != Coin::Bitcoin {
(total_coin * u128::from(values_map[&coin])) / 10u128.pow(coin.decimals())
} else {
total_coin
};

total_value += value;
pool_amounts.insert(coin, (total_coin, value));
}

// check distributed SRI per pool
let mut total_sri_distributed = 0u128;
for coin in coins.clone() {
let sri = if coin == *COINS.last().unwrap() {
u128::from(GENESIS_SRI).checked_sub(total_sri_distributed).unwrap()
} else {
(pool_amounts[&coin].1 * u128::from(GENESIS_SRI)) / total_value
};
total_sri_distributed += sri;

let reserves = serai.dex().get_reserves(coin).await.unwrap().unwrap();
assert_eq!(u128::from(reserves.0), pool_amounts[&coin].0); // coin side
assert_eq!(u128::from(reserves.1), sri); // SRI side
}

// check each liquidity provider got liquidity tokens proportional to their value
for coin in coins {
let liq_supply = serai.genesis_liquidity().supply(coin).await.unwrap();
for (acc, amount) in &accounts[&coin] {
let acc_liq_shares = serai.genesis_liquidity().liquidity(acc, coin).await.unwrap().shares;

// since we can't test the ratios directly(due to integer division giving 0)
// we test whether they give the same result when multiplied by another constant.
// Following test ensures the account in fact has the right amount of shares.
let mut shares_ratio = (INITIAL_GENESIS_LP_SHARES * acc_liq_shares) / liq_supply.shares;
let amounts_ratio =
(INITIAL_GENESIS_LP_SHARES * amount.0) / u64::try_from(pool_amounts[&coin].0).unwrap();

// we can tolerate 1 unit diff between them due to integer division.
if shares_ratio.abs_diff(amounts_ratio) == 1 {
shares_ratio = amounts_ratio;
}

assert_eq!(shares_ratio, amounts_ratio);
}
}
// TODO: test remove the liq before/after genesis ended.
let values =
Values { monero: values[&Coin::Monero], ether: values[&Coin::Ether], dai: values[&Coin::Dai] };
set_values(serai, &values).await;

batch_ids
(accounts, batch_ids)
}

#[allow(dead_code)]
Expand Down
60 changes: 39 additions & 21 deletions substrate/client/tests/emissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serai_client::TemporalSerai;
use serai_abi::{
emissions::primitives::{INITIAL_REWARD_PER_BLOCK, SECURE_BY},
in_instructions::primitives::Batch,
primitives::{NETWORKS, BlockHash},
primitives::{NETWORKS, Coin, BlockHash, COINS, FAST_EPOCH_DURATION, TARGET_BLOCK_TIME},
validator_sets::primitives::Session,
};

Expand All @@ -16,7 +16,7 @@ use serai_client::{
};

mod common;
use common::{genesis_liquidity::test_genesis_liquidity, in_instructions::provide_batch};
use common::{genesis_liquidity::set_up_genesis, in_instructions::provide_batch};

serai_test_fast_epoch!(
emissions: (|serai: Serai| async move {
Expand Down Expand Up @@ -45,8 +45,23 @@ async fn send_batches(serai: &Serai, ids: &mut HashMap<NetworkId, u32>) {
}

async fn test_emissions(serai: Serai) {
// provide some genesis liquidity
let mut batch_ids = test_genesis_liquidity(serai.clone()).await;
// set up the genesis
let coins = COINS.into_iter().filter(|c| *c != Coin::native()).collect::<Vec<_>>();
let values = HashMap::from([(Coin::Monero, 184100), (Coin::Ether, 4785000), (Coin::Dai, 1500)]);
let (_, mut batch_ids) = set_up_genesis(&serai, &coins, &values).await;

// wait until genesis is complete
while !serai
.as_of_latest_finalized_block()
.await
.unwrap()
.genesis_liquidity()
.genesis_complete()
.await
.unwrap()
{
tokio::time::sleep(Duration::from_secs(1)).await;
}

for _ in 0 .. 3 {
// get current stakes
Expand Down Expand Up @@ -156,23 +171,26 @@ async fn wait_for_session_change(serai: &Serai) -> u32 {
.0;
let next_session = current_session + 1;

// Epoch time is 2 mins with the fast epoch feature, so lets wait double that.
tokio::time::timeout(tokio::time::Duration::from_secs(60 * 4), async {
while serai
.as_of_latest_finalized_block()
.await
.unwrap()
.validator_sets()
.session(NetworkId::Serai)
.await
.unwrap()
.unwrap()
.0 <
next_session
{
tokio::time::sleep(Duration::from_secs(6)).await;
}
})
// lets wait double the epoch time.
tokio::time::timeout(
tokio::time::Duration::from_secs(FAST_EPOCH_DURATION * TARGET_BLOCK_TIME * 2),
async {
while serai
.as_of_latest_finalized_block()
.await
.unwrap()
.validator_sets()
.session(NetworkId::Serai)
.await
.unwrap()
.unwrap()
.0 <
next_session
{
tokio::time::sleep(Duration::from_secs(6)).await;
}
},
)
.await
.unwrap();

Expand Down
Loading

0 comments on commit e1b4a9a

Please sign in to comment.