Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

centrifuge: Anemoy pool currency migration #1566

Merged
merged 11 commits into from Sep 25, 2023
4 changes: 2 additions & 2 deletions libs/types/src/tokens.rs
Expand Up @@ -187,8 +187,8 @@ where
)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct TrancheCurrency {
pub(crate) pool_id: PoolId,
pub(crate) tranche_id: TrancheId,
pub pool_id: PoolId,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any objections to open these fields visibility? by having them pub(crate) I would have to import he TrancheCurrencyT trait to call generate to build an instance of this type which is quite an overkill imo. let me know if I am not overseeing any requirement 👍

pub tranche_id: TrancheId,
}

impl From<TrancheCurrency> for CurrencyId {
Expand Down
8 changes: 4 additions & 4 deletions pallets/investments/src/lib.rs
Expand Up @@ -224,7 +224,7 @@ pub mod pallet {
StorageMap<_, Blake2_128Concat, T::InvestmentId, OrderId, ValueQuery>;

#[pallet::storage]
pub(crate) type InvestOrders<T: Config> = StorageDoubleMap<
pub type InvestOrders<T: Config> = StorageDoubleMap<
NunoAlexandre marked this conversation as resolved.
Show resolved Hide resolved
_,
Blake2_128Concat,
T::AccountId,
Expand All @@ -234,7 +234,7 @@ pub mod pallet {
>;

#[pallet::storage]
pub(crate) type RedeemOrders<T: Config> = StorageDoubleMap<
pub type RedeemOrders<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
T::AccountId,
Expand All @@ -245,12 +245,12 @@ pub mod pallet {

#[pallet::storage]
#[pallet::getter(fn acc_active_invest_order)]
pub(crate) type ActiveInvestOrders<T: Config> =
pub type ActiveInvestOrders<T: Config> =
StorageMap<_, Blake2_128Concat, T::InvestmentId, TotalOrder<T::Amount>, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn acc_active_redeem_order)]
pub(crate) type ActiveRedeemOrders<T: Config> =
pub type ActiveRedeemOrders<T: Config> =
StorageMap<_, Blake2_128Concat, T::InvestmentId, TotalOrder<T::Amount>, ValueQuery>;

#[pallet::storage]
Expand Down
120 changes: 119 additions & 1 deletion runtime/centrifuge/src/migrations.rs
Expand Up @@ -9,5 +9,123 @@
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
use crate::{Runtime, Weight};

pub type UpgradeCentrifuge1021 = ();
pub type UpgradeCentrifuge1021 = anemoy_pool::Migration;

/// Migrate the Anemoy Pool's currency from LpEthUSC to Circle's USDC,
/// native on Polkadot's AssetHub.
mod anemoy_pool {
use cfg_primitives::PoolId;
use cfg_traits::PoolInspect;
use cfg_types::tokens::CurrencyId;
#[cfg(feature = "try-runtime")]
use codec::{Decode, Encode};
#[cfg(feature = "try-runtime")]
use frame_support::ensure;
use frame_support::traits::{fungibles::Inspect, OnRuntimeUpgrade};
#[cfg(feature = "try-runtime")]
use pallet_pool_system::PoolDetailsOf;
use sp_std::vec;
#[cfg(feature = "try-runtime")]
use sp_std::vec::Vec;

use super::*;
use crate::PoolSystem;

const ANEMOY_POOL_ID: PoolId = 4_139_607_887;
const LP_ETH_USDC: CurrencyId = CurrencyId::ForeignAsset(100_001);
const DOT_NATIVE_USDC: CurrencyId = CurrencyId::ForeignAsset(6);

pub struct Migration;

impl OnRuntimeUpgrade for Migration {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
let pool_details: PoolDetailsOf<Runtime> =
PoolSystem::pool(ANEMOY_POOL_ID).ok_or("Could not find Anemoy Pool")?;

ensure!(
pool_details.currency == LP_ETH_USDC,
"anemoy_pool::Migration: pre_upgrade failing as Anemoy's currency should be LpEthUSDC"
);

Ok(pool_details.encode())
}

fn on_runtime_upgrade() -> Weight {
// To be executed at 1021, reject higher spec_versions
if crate::VERSION.spec_version >= 1022 {
log::error!(
"anemoy_pool::Migration: NOT execution since VERSION.spec_version >= 1022"
);
return Weight::zero();
}

let (sanity_checks, weight) = verify_sanity_checks();
if !sanity_checks {
log::error!("anemoy_pool::Migration: Sanity checks FAILED");
return weight;
}

pallet_pool_system::Pool::<Runtime>::mutate(ANEMOY_POOL_ID, |details| {
let details = details.as_mut().unwrap();
details.currency = DOT_NATIVE_USDC;
log::info!("anemoy_pool::Migration: currency set to USDC ✓");
});

weight.saturating_add(
<Runtime as frame_system::Config>::DbWeight::get().reads_writes(1, 1),
)
}

#[cfg(feature = "try-runtime")]
fn post_upgrade(old_state: Vec<u8>) -> Result<(), &'static str> {
let mut old_pool_details = PoolDetailsOf::<Runtime>::decode(&mut old_state.as_ref())
.map_err(|_| "Error decoding pre-upgrade state")?;

let pool_details: PoolDetailsOf<Runtime> =
PoolSystem::pool(ANEMOY_POOL_ID).ok_or("Could not find Anemoy Pool")?;

// Ensure the currency set to USDC is the only mutation performed
old_pool_details.currency = DOT_NATIVE_USDC;
ensure!(
old_pool_details == pool_details,
"Corrupted migration: Only the currency of the Anemoy pool should have changed"
);

log::info!("anemoy_pool::Migration: post_upgrade succeeded ✓");
Ok(())
}
}

fn verify_sanity_checks() -> (bool, Weight) {
let res =
crate::Tokens::balance(
LP_ETH_USDC,
&<PoolSystem as PoolInspect<_, _>>::account_for(ANEMOY_POOL_ID),
) == 0 && pallet_investments::ActiveInvestOrders::<Runtime>::iter_keys()
.filter(|investment| investment.pool_id == ANEMOY_POOL_ID)
.count() == 0 && pallet_investments::ActiveRedeemOrders::<Runtime>::iter_keys()
.filter(|investment| investment.pool_id == ANEMOY_POOL_ID)
.count() == 0 && pallet_investments::InvestOrders::<Runtime>::iter_keys()
.filter(|(_, investment)| investment.pool_id == ANEMOY_POOL_ID)
.count() == 0 && pallet_investments::RedeemOrders::<Runtime>::iter_keys()
.filter(|(_, investment)| investment.pool_id == ANEMOY_POOL_ID)
.count() == 0;

let weight = <Runtime as frame_system::Config>::DbWeight::get().reads(
vec![
1, // pool account balance read
pallet_investments::ActiveInvestOrders::<Runtime>::iter_keys().count(),
pallet_investments::ActiveRedeemOrders::<Runtime>::iter_keys().count(),
pallet_investments::InvestOrders::<Runtime>::iter_keys().count(),
pallet_investments::RedeemOrders::<Runtime>::iter_keys().count(),
]
.iter()
.fold(0u64, |acc, x| acc.saturating_add(*x as u64)),
);

(res, weight)
}
}