mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-14 15:09:23 +00:00
fix last pr comments
This commit is contained in:
@@ -47,7 +47,7 @@ pub mod pallet {
|
||||
pub enum Event<T: Config> {
|
||||
GenesisLiquidityAdded { by: SeraiAddress, balance: Balance },
|
||||
GenesisLiquidityRemoved { by: SeraiAddress, balance: Balance },
|
||||
GenesisLiquidityAddedToPool { coin1: Balance, coin2: Balance },
|
||||
GenesisLiquidityAddedToPool { coin1: Balance, sri: Amount },
|
||||
EconomicSecurityReached { network: NetworkId },
|
||||
}
|
||||
|
||||
@@ -56,20 +56,12 @@ pub mod pallet {
|
||||
|
||||
/// Keeps shares and the amount of coins per account.
|
||||
#[pallet::storage]
|
||||
pub(crate) type Liquidity<T: Config> = StorageDoubleMap<
|
||||
_,
|
||||
Identity,
|
||||
Coin,
|
||||
Blake2_128Concat,
|
||||
PublicKey,
|
||||
(SubstrateAmount, SubstrateAmount),
|
||||
OptionQuery,
|
||||
>;
|
||||
pub(crate) type Liquidity<T: Config> =
|
||||
StorageDoubleMap<_, Identity, Coin, Blake2_128Concat, PublicKey, LiquidityAmount, OptionQuery>;
|
||||
|
||||
/// Keeps the total shares and the total amount of coins per coin.
|
||||
#[pallet::storage]
|
||||
pub(crate) type Supply<T: Config> =
|
||||
StorageMap<_, Identity, Coin, (SubstrateAmount, SubstrateAmount), OptionQuery>;
|
||||
pub(crate) type Supply<T: Config> = StorageMap<_, Identity, Coin, LiquidityAmount, OptionQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
pub(crate) type EconomicSecurityReached<T: Config> =
|
||||
@@ -83,7 +75,7 @@ pub mod pallet {
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn on_finalize(n: BlockNumberFor<T>) {
|
||||
fn on_initialize(n: BlockNumberFor<T>) -> Weight {
|
||||
#[cfg(feature = "fast-epoch")]
|
||||
let final_block = 10u64;
|
||||
|
||||
@@ -115,9 +107,14 @@ pub mod pallet {
|
||||
continue;
|
||||
};
|
||||
|
||||
let pool_amount = u128::from(Supply::<T>::get(coin).unwrap_or((0, 0)).1);
|
||||
let pool_value = pool_amount.saturating_mul(value.into()) / 10u128.pow(coin.decimals());
|
||||
total_value = total_value.saturating_add(pool_value);
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -127,11 +124,18 @@ pub mod pallet {
|
||||
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
|
||||
GENESIS_SRI.checked_sub(total_sri_distributed).unwrap()
|
||||
} else {
|
||||
u64::try_from(u128::from(GENESIS_SRI).saturating_mul(pool_value) / total_value).unwrap()
|
||||
u64::try_from(
|
||||
u128::from(GENESIS_SRI)
|
||||
.checked_mul(pool_value)
|
||||
.unwrap()
|
||||
.checked_div(total_value)
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
total_sri_distributed += sri_amount;
|
||||
total_sri_distributed = total_sri_distributed.checked_add(sri_amount).unwrap();
|
||||
|
||||
// we can't add 0 liquidity
|
||||
if !(pool_amount > 0 && sri_amount > 0) {
|
||||
@@ -154,7 +158,7 @@ pub mod pallet {
|
||||
// let everyone know about the event
|
||||
Self::deposit_event(Event::GenesisLiquidityAddedToPool {
|
||||
coin1: Balance { coin, amount: Amount(u64::try_from(pool_amount).unwrap()) },
|
||||
coin2: Balance { coin: Coin::Serai, amount: Amount(sri_amount) },
|
||||
sri: Amount(sri_amount),
|
||||
});
|
||||
}
|
||||
assert_eq!(total_sri_distributed, GENESIS_SRI);
|
||||
@@ -169,6 +173,7 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
// we accept we reached economic security once we can mint smallest amount of a network's coin
|
||||
// TODO: move EconomicSecurity to a separate pallet
|
||||
for coin in COINS {
|
||||
let existing = EconomicSecurityReached::<T>::get(coin.network());
|
||||
if existing.is_none() &&
|
||||
@@ -178,6 +183,8 @@ pub mod pallet {
|
||||
Self::deposit_event(Event::EconomicSecurityReached { network: coin.network() });
|
||||
}
|
||||
}
|
||||
|
||||
Weight::zero() // TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,33 +197,37 @@ pub mod pallet {
|
||||
Err(Error::<T>::GenesisPeriodEnded)?;
|
||||
}
|
||||
|
||||
// mint the coins
|
||||
Coins::<T>::mint(GENESIS_LIQUIDITY_ACCOUNT.into(), balance)?;
|
||||
|
||||
// calculate new shares & supply
|
||||
let (new_shares, new_supply) = if let Some(supply) = Supply::<T>::get(balance.coin) {
|
||||
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.0, balance.amount.0, supply.1)?;
|
||||
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((0, 0));
|
||||
let existing =
|
||||
Liquidity::<T>::get(balance.coin, account).unwrap_or(LiquidityAmount::zero());
|
||||
(
|
||||
(
|
||||
existing.0.checked_add(shares).ok_or(Error::<T>::AmountOverflowed)?,
|
||||
existing.1.checked_add(balance.amount.0).ok_or(Error::<T>::AmountOverflowed)?,
|
||||
),
|
||||
(
|
||||
supply.0.checked_add(shares).ok_or(Error::<T>::AmountOverflowed)?,
|
||||
supply.1.checked_add(balance.amount.0).ok_or(Error::<T>::AmountOverflowed)?,
|
||||
),
|
||||
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_amounts = (GENESIS_LP_SHARES, balance.amount.0);
|
||||
(first_amounts, first_amounts)
|
||||
let first_amount = LiquidityAmount { shares: GENESIS_LP_SHARES, coins: balance.amount.0 };
|
||||
(first_amount, first_amount)
|
||||
};
|
||||
|
||||
// save
|
||||
Liquidity::<T>::set(balance.coin, account, Some(new_shares));
|
||||
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(())
|
||||
@@ -280,16 +291,16 @@ pub mod pallet {
|
||||
let supply = Supply::<T>::get(balance.coin).ok_or(Error::<T>::NotEnoughLiquidity)?;
|
||||
|
||||
// check we are still in genesis period
|
||||
let (new_shares, new_supply) = if Self::genesis_ended() {
|
||||
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 (user_shares, user_coins) =
|
||||
Liquidity::<T>::get(balance.coin, account).unwrap_or((0, 0));
|
||||
let total_shares = Supply::<T>::get(balance.coin).unwrap_or((0, 0)).0;
|
||||
let user_liq_tokens = Self::mul_div(total_liq_tokens, user_shares, total_shares)?;
|
||||
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, GENESIS_LP_SHARES)?;
|
||||
|
||||
// remove liquidity from pool
|
||||
@@ -308,18 +319,25 @@ pub mod pallet {
|
||||
|
||||
// burn the SRI if necessary
|
||||
// TODO: take into consideration movement between pools.
|
||||
let mut sri = current_sri.0.saturating_sub(prev_sri.0);
|
||||
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 = sri.saturating_mul(distance_to_full_pay) / GENESIS_SRI_TRICKLE_FEED;
|
||||
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 -= burn_sri_amount;
|
||||
sri = sri.checked_sub(burn_sri_amount).ok_or(Error::<T>::AmountOverflowed)?;
|
||||
|
||||
// transfer to owner
|
||||
let coin_out = current_coin.0 - prev_coin.0;
|
||||
let coin_out = current_coin.0.saturating_sub(prev_coin.0);
|
||||
Coins::<T>::transfer(
|
||||
origin.clone().into(),
|
||||
account,
|
||||
@@ -333,14 +351,17 @@ pub mod pallet {
|
||||
|
||||
// return new amounts
|
||||
(
|
||||
(
|
||||
user_shares.checked_sub(amount_to_remove).ok_or(Error::<T>::AmountOverflowed)?,
|
||||
user_coins.checked_sub(coin_out).ok_or(Error::<T>::AmountOverflowed)?,
|
||||
),
|
||||
(
|
||||
supply.0.checked_sub(amount_to_remove).ok_or(Error::<T>::AmountOverflowed)?,
|
||||
supply.1.checked_sub(coin_out).ok_or(Error::<T>::AmountOverflowed)?,
|
||||
),
|
||||
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 != GENESIS_LP_SHARES {
|
||||
@@ -353,23 +374,26 @@ pub mod pallet {
|
||||
Coins::<T>::transfer(
|
||||
origin.into(),
|
||||
account,
|
||||
Balance { coin: balance.coin, amount: Amount(existing.1) },
|
||||
Balance { coin: balance.coin, amount: Amount(existing.coins) },
|
||||
)?;
|
||||
|
||||
(
|
||||
(0, 0),
|
||||
(
|
||||
supply.0.checked_sub(existing.0).ok_or(Error::<T>::AmountOverflowed)?,
|
||||
supply.1.checked_sub(existing.1).ok_or(Error::<T>::AmountOverflowed)?,
|
||||
),
|
||||
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_shares.0 == 0 {
|
||||
if new_liquidity == LiquidityAmount::zero() {
|
||||
Liquidity::<T>::set(balance.coin, account, None);
|
||||
} else {
|
||||
Liquidity::<T>::set(balance.coin, account, Some(new_shares));
|
||||
Liquidity::<T>::set(balance.coin, account, Some(new_liquidity));
|
||||
}
|
||||
Supply::<T>::set(balance.coin, Some(new_supply));
|
||||
|
||||
@@ -380,7 +404,7 @@ pub mod pallet {
|
||||
/// A call to submit the initial coin values in terms of BTC.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight((0, DispatchClass::Operational))] // TODO
|
||||
pub fn set_initial_price(
|
||||
pub fn oraclize_values(
|
||||
origin: OriginFor<T>,
|
||||
prices: Prices,
|
||||
_signature: Signature,
|
||||
@@ -388,7 +412,7 @@ pub mod pallet {
|
||||
ensure_none(origin)?;
|
||||
|
||||
// set the prices
|
||||
Oracle::<T>::set(Coin::Bitcoin, Some(prices.bitcoin));
|
||||
Oracle::<T>::set(Coin::Bitcoin, Some(10u64.pow(8)));
|
||||
Oracle::<T>::set(Coin::Monero, Some(prices.monero));
|
||||
Oracle::<T>::set(Coin::Ether, Some(prices.ethereum));
|
||||
Oracle::<T>::set(Coin::Dai, Some(prices.dai));
|
||||
@@ -402,11 +426,14 @@ pub mod pallet {
|
||||
|
||||
fn validate_unsigned(_: TransactionSource, call: &Self::Call) -> TransactionValidity {
|
||||
match call {
|
||||
Call::set_initial_price { ref prices, ref signature } => {
|
||||
// TODO: if this is supposed to be called after a month, serai set won't still be
|
||||
// in the session 0? Ideally this should pull the session from Vs pallet?
|
||||
let set = ValidatorSet { network: NetworkId::Serai, session: Session(0) };
|
||||
let signers = ValidatorSets::<T>::participants_for_latest_decided_set(NetworkId::Serai)
|
||||
Call::oraclize_values { ref prices, ref signature } => {
|
||||
let network = NetworkId::Serai;
|
||||
let Some(session) = ValidatorSets::<T>::session(network) else {
|
||||
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)
|
||||
@@ -414,17 +441,17 @@ pub mod pallet {
|
||||
|
||||
// check this didn't get called before
|
||||
if Self::oraclization_is_done() {
|
||||
Err(InvalidTransaction::Custom(0))?;
|
||||
Err(InvalidTransaction::Custom(1))?;
|
||||
}
|
||||
|
||||
// make sure signers settings the price at the end of the genesis period.
|
||||
// we don't need this check for tests.
|
||||
#[cfg(not(feature = "fast-epoch"))]
|
||||
if <frame_system::Pallet<T>>::block_number().saturated_into::<u64>() < MONTHS {
|
||||
Err(InvalidTransaction::Custom(1))?;
|
||||
Err(InvalidTransaction::Custom(2))?;
|
||||
}
|
||||
|
||||
if !musig_key(set, &signers).verify(&set_initial_price_message(&set, prices), signature) {
|
||||
if !musig_key(set, &signers).verify(&oraclize_values_message(&set, prices), signature) {
|
||||
Err(InvalidTransaction::BadProof)?;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user