diff --git a/runtime/integration-tests/src/lib.rs b/runtime/integration-tests/src/lib.rs
index 425b7d746a..0dd7d73f17 100644
--- a/runtime/integration-tests/src/lib.rs
+++ b/runtime/integration-tests/src/lib.rs
@@ -88,6 +88,13 @@ mod runtime;
))]
mod session_manager;
+#[cfg(any(
+ feature = "with-mandala-runtime",
+ feature = "with-karura-runtime",
+ feature = "with-acala-runtime"
+))]
+mod stable_asset;
+
#[cfg(any(
feature = "with-mandala-runtime",
feature = "with-karura-runtime",
diff --git a/runtime/integration-tests/src/setup.rs b/runtime/integration-tests/src/setup.rs
index 60d717671b..12d525ed59 100644
--- a/runtime/integration-tests/src/setup.rs
+++ b/runtime/integration-tests/src/setup.rs
@@ -52,11 +52,12 @@ mod mandala_imports {
HomaXcm, Honzon, IdleScheduler, Loans, MaxTipsOfPriority, MinRewardDistributeAmount, MinimumDebitValue,
MultiLocation, NativeTokenExistentialDeposit, NetworkId, NftPalletId, OneDay, Origin, OriginCaller,
PalletCurrency, ParachainInfo, ParachainSystem, Proxy, ProxyType, Runtime, Scheduler, Session, SessionKeys,
- SessionManager, SevenDays, System, Timestamp, TipPerWeightStep, TokenSymbol, Tokens, TransactionPayment,
- TreasuryAccount, TreasuryPalletId, UncheckedExtrinsic, Utility, Vesting, XcmConfig, XcmExecutor, EVM, NFT,
+ SessionManager, SevenDays, StableAsset, StableAssetPalletId, System, Timestamp, TipPerWeightStep, TokenSymbol,
+ Tokens, TransactionPayment, TreasuryAccount, TreasuryPalletId, UncheckedExtrinsic, Utility, Vesting, XcmConfig,
+ XcmExecutor, EVM, NFT,
};
- pub use runtime_common::{cent, dollar, millicent, ACA, AUSD, DOT, LDOT};
+ pub use runtime_common::{cent, dollar, millicent, ACA, AUSD, DOT, KSM, LDOT, LKSM};
pub const NATIVE_CURRENCY: CurrencyId = ACA;
pub const LIQUID_CURRENCY: CurrencyId = LDOT;
pub const RELAY_CHAIN_CURRENCY: CurrencyId = DOT;
diff --git a/runtime/integration-tests/src/stable_asset.rs b/runtime/integration-tests/src/stable_asset.rs
new file mode 100644
index 0000000000..4f7c79834d
--- /dev/null
+++ b/runtime/integration-tests/src/stable_asset.rs
@@ -0,0 +1,77 @@
+// This file is part of Acala.
+
+// Copyright (C) 2020-2021 Acala Foundation.
+// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// 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.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+use crate::setup::*;
+use module_asset_registry::AssetMetadata;
+
+#[cfg(feature = "with-mandala-runtime")]
+#[test]
+fn test_mint() {
+ ExtBuilder::default()
+ .balances(vec![
+ (
+ // NetworkContractSource
+ MockAddressMapping::get_account_id(&H160::from_low_u64_be(0)),
+ NATIVE_CURRENCY,
+ 1_000_000_000 * dollar(NATIVE_CURRENCY),
+ ),
+ (AccountId::from(ALICE), KSM, 1_000_000_000 * dollar(NATIVE_CURRENCY)),
+ (AccountId::from(ALICE), LKSM, 12_000_000_000 * dollar(NATIVE_CURRENCY)),
+ ])
+ .build()
+ .execute_with(|| {
+ let pool_asset = CurrencyId::StableAssetPoolToken(0);
+ assert_ok!(StableAsset::create_pool(
+ Origin::root(),
+ pool_asset,
+ vec![KSM, LKSM],
+ vec![1u128, 1u128],
+ 10_000_000u128,
+ 20_000_000u128,
+ 50_000_000u128,
+ 1_000u128,
+ AccountId::from(BOB),
+ AccountId::from(CHARLIE),
+ 1_000_000_000_000u128,
+ ));
+ let asset_metadata = AssetMetadata {
+ name: b"Token Name".to_vec(),
+ symbol: b"TN".to_vec(),
+ decimals: 12,
+ minimal_balance: 1,
+ };
+ assert_ok!(AssetRegistry::register_stable_asset(
+ RawOrigin::Root.into(),
+ Box::new(asset_metadata.clone())
+ ));
+ let ksm_target_amount = 10_000_123u128;
+ let lksm_target_amount = 10_000_456u128;
+ let exchange_rate = Homa::current_exchange_rate();
+ let account_id: AccountId = StableAssetPalletId::get().into_sub_account(0);
+ assert_ok!(StableAsset::mint(
+ Origin::signed(AccountId::from(ALICE)),
+ 0,
+ vec![ksm_target_amount, lksm_target_amount],
+ 0u128
+ ));
+ assert_eq!(Currencies::free_balance(KSM, &account_id), ksm_target_amount);
+ let lksm_balance = Currencies::free_balance(LKSM, &account_id);
+ let converted_lksm_balance = exchange_rate.checked_mul_int(lksm_balance).unwrap_or_default();
+ assert_eq!(converted_lksm_balance >= lksm_target_amount, true);
+ });
+}
diff --git a/runtime/mandala/src/lib.rs b/runtime/mandala/src/lib.rs
index 9079268ba7..a37eea1b87 100644
--- a/runtime/mandala/src/lib.rs
+++ b/runtime/mandala/src/lib.rs
@@ -1855,11 +1855,16 @@ impl orml_tokens::ConvertBalance for ConvertBalanceHoma {
}
fn convert_balance_back(balance: Balance, asset_id: CurrencyId) -> Balance {
+ /*
+ * When overflow occurs, it's better to return 0 than max because returning zero will fail the
+ * current transaction. If returning max here, the current transaction won't fail but latter
+ * transactions have a possibility to fail, and this is undesirable.
+ */
match asset_id {
CurrencyId::Token(TokenSymbol::LKSM) => Homa::get_exchange_rate()
.reciprocal()
- .unwrap_or_default()
- .checked_mul_int(balance)
+ .and_then(|x| x.checked_mul_int(balance))
+ .and_then(|x| x.checked_add(1))
.unwrap_or_default(),
_ => balance,
}