Skip to content

Commit

Permalink
liquidity-pools: Add support for DisallowInvestmentCurrency message (
Browse files Browse the repository at this point in the history
  • Loading branch information
cdamian authored Jan 10, 2024
1 parent 433211e commit 976d636
Show file tree
Hide file tree
Showing 3 changed files with 329 additions and 43 deletions.
99 changes: 72 additions & 27 deletions pallets/liquidity-pools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,33 +739,8 @@ pub mod pallet {
Error::<T>::NotPoolAdmin
);

// Ensure currency is allowed as payment and payout currency for pool
let invest_id = Self::derive_invest_id(pool_id, tranche_id)?;
// Required for increasing and collecting investments
ensure!(
T::ForeignInvestment::accepted_payment_currency(invest_id.clone(), currency_id),
Error::<T>::InvalidPaymentCurrency
);
// Required for decreasing investments as well as increasing, decreasing and
// collecting redemptions
ensure!(
T::ForeignInvestment::accepted_payout_currency(invest_id, currency_id),
Error::<T>::InvalidPayoutCurrency
);

// Ensure the currency is enabled as pool_currency
let metadata =
T::AssetRegistry::metadata(&currency_id).ok_or(Error::<T>::AssetNotFound)?;
ensure!(
metadata.additional.pool_currency,
Error::<T>::AssetMetadataNotPoolCurrency
);

// Derive GeneralIndex for currency
let currency = Self::try_get_general_index(currency_id)?;

let LiquidityPoolsWrappedToken::EVM { chain_id, .. } =
Self::try_get_wrapped_token(&currency_id)?;
let (currency, chain_id) =
Self::validate_investment_currency(pool_id, tranche_id, currency_id)?;

T::OutboundQueue::submit(
who,
Expand Down Expand Up @@ -847,6 +822,39 @@ pub mod pallet {
},
)
}

/// Disallow a currency to be used as a pool currency and to invest in a
/// pool on the domain derived from the given currency.
#[pallet::call_index(13)]
#[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())]
pub fn disallow_investment_currency(
origin: OriginFor<T>,
pool_id: T::PoolId,
tranche_id: T::TrancheId,
currency_id: CurrencyIdOf<T>,
) -> DispatchResult {
let who = ensure_signed(origin)?;

ensure!(
T::Permission::has(
PermissionScope::Pool(pool_id),
who.clone(),
Role::PoolRole(PoolRole::PoolAdmin)
),
Error::<T>::NotPoolAdmin
);

let (currency, chain_id) =
Self::validate_investment_currency(pool_id, tranche_id, currency_id)?;

T::OutboundQueue::submit(
who,
Domain::EVM(chain_id),
Message::DisallowInvestmentCurrency { pool_id, currency },
)?;

Ok(())
}
}

impl<T: Config> Pallet<T> {
Expand Down Expand Up @@ -972,6 +980,43 @@ pub mod pallet {

Ok(currency)
}

/// Performs multiple checks for the provided currency and returns its
/// general index and the EVM chain ID associated with it.
pub fn validate_investment_currency(
pool_id: T::PoolId,
tranche_id: T::TrancheId,
currency_id: CurrencyIdOf<T>,
) -> Result<(u128, EVMChainId), DispatchError> {
// Ensure currency is allowed as payment and payout currency for pool
let invest_id = Self::derive_invest_id(pool_id, tranche_id)?;
// Required for increasing and collecting investments
ensure!(
T::ForeignInvestment::accepted_payment_currency(invest_id.clone(), currency_id),
Error::<T>::InvalidPaymentCurrency
);
// Required for decreasing investments as well as increasing, decreasing and
// collecting redemptions
ensure!(
T::ForeignInvestment::accepted_payout_currency(invest_id, currency_id),
Error::<T>::InvalidPayoutCurrency
);

// Ensure the currency is enabled as pool_currency
let metadata =
T::AssetRegistry::metadata(&currency_id).ok_or(Error::<T>::AssetNotFound)?;
ensure!(
metadata.additional.pool_currency,
Error::<T>::AssetMetadataNotPoolCurrency
);

let currency = Self::try_get_general_index(currency_id)?;

let LiquidityPoolsWrappedToken::EVM { chain_id, .. } =
Self::try_get_wrapped_token(&currency_id)?;

Ok((currency, chain_id))
}
}

impl<T: Config> InboundQueue for Pallet<T>
Expand Down
39 changes: 39 additions & 0 deletions pallets/liquidity-pools/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,14 @@ where
token_name: [u8; TOKEN_NAME_SIZE],
token_symbol: [u8; TOKEN_SYMBOL_SIZE],
},
/// Disallow a currency to be used as a pool currency and to invest in a
/// pool.
///
/// Directionality: Centrifuge -> EVM Domain.
DisallowInvestmentCurrency {
pool_id: PoolId,
currency: u128,
},
}

impl<
Expand Down Expand Up @@ -404,6 +412,7 @@ impl<
Self::ScheduleUpgrade { .. } => 21,
Self::CancelUpgrade { .. } => 22,
Self::UpdateTrancheTokenMetadata { .. } => 23,
Self::DisallowInvestmentCurrency { .. } => 24,
}
}
}
Expand Down Expand Up @@ -729,6 +738,10 @@ impl<
token_symbol.encode(),
],
),
Message::DisallowInvestmentCurrency { pool_id, currency } => encoded_message(
self.call_type(),
vec![encode_be(pool_id), encode_be(currency)],
),
}
}

Expand Down Expand Up @@ -881,6 +894,10 @@ impl<
token_name: decode::<TOKEN_NAME_SIZE, _, _>(input)?,
token_symbol: decode::<TOKEN_SYMBOL_SIZE, _, _>(input)?,
}),
24 => Ok(Self::DisallowInvestmentCurrency {
pool_id: decode_be_bytes::<8, _, _>(input)?,
currency: decode_be_bytes::<16, _, _>(input)?,
}),
_ => Err(parity_scale_codec::Error::from(
"Unsupported decoding for this Message variant",
)),
Expand Down Expand Up @@ -1319,6 +1336,28 @@ mod tests {
)
}

#[test]
fn disallow_investment_currency() {
test_encode_decode_identity(
LiquidityPoolsMessage::DisallowInvestmentCurrency {
pool_id: POOL_ID,
currency: TOKEN_ID,
},
"180000000000bce1a40000000000000000000000000eb5ec7b",
)
}

#[test]
fn disallow_investment_currency_zero() {
test_encode_decode_identity(
LiquidityPoolsMessage::DisallowInvestmentCurrency {
pool_id: 0,
currency: 0,
},
"18000000000000000000000000000000000000000000000000",
)
}

/// Verify the identity property of decode . encode on a Message value and
/// that it in fact encodes to and can be decoded from a given hex string.
fn test_encode_decode_identity(
Expand Down
Loading

0 comments on commit 976d636

Please sign in to comment.