From df0917162bc50e54459f9a2a6e3fc50c7361b146 Mon Sep 17 00:00:00 2001 From: Frank Yin Date: Tue, 4 Jan 2022 16:32:50 -0800 Subject: [PATCH] off-by-one (#1747) * always transfer one more ksm to fix rounding issue * add integration tests Co-authored-by: Frank Yin --- runtime/integration-tests/src/lib.rs | 7 ++ runtime/integration-tests/src/setup.rs | 7 +- runtime/integration-tests/src/stable_asset.rs | 77 +++++++++++++++++++ runtime/mandala/src/lib.rs | 9 ++- 4 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 runtime/integration-tests/src/stable_asset.rs 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, }