diff --git a/Cargo.lock b/Cargo.lock index 090a22160..4d5e11747 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4571,7 +4571,7 @@ dependencies = [ [[package]] name = "hydradx-adapters" -version = "1.1.1" +version = "1.2.0" dependencies = [ "cumulus-pallet-parachain-system", "cumulus-primitives-core", @@ -4586,7 +4586,9 @@ dependencies = [ "orml-utilities", "orml-vesting", "orml-xcm-support", + "pallet-asset-registry", "pallet-balances", + "pallet-bonds", "pallet-circuit-breaker", "pallet-currencies", "pallet-dynamic-fees", @@ -4619,7 +4621,7 @@ dependencies = [ [[package]] name = "hydradx-runtime" -version = "212.0.0" +version = "213.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -7194,7 +7196,7 @@ dependencies = [ [[package]] name = "pallet-bonds" -version = "2.1.0" +version = "2.2.0" dependencies = [ "frame-benchmarking", "frame-support", @@ -11331,7 +11333,7 @@ dependencies = [ [[package]] name = "runtime-integration-tests" -version = "1.18.1" +version = "1.19.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 9a9e1f811..429da4c53 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "runtime-integration-tests" -version = "1.18.1" +version = "1.19.0" description = "Integration tests" authors = ["GalacticCouncil"] edition = "2021" diff --git a/integration-tests/src/omnipool_liquidity_mining.rs b/integration-tests/src/omnipool_liquidity_mining.rs index b117f3d8d..ffe8b4693 100644 --- a/integration-tests/src/omnipool_liquidity_mining.rs +++ b/integration-tests/src/omnipool_liquidity_mining.rs @@ -26,15 +26,17 @@ use warehouse_liquidity_mining::{ }; use orml_traits::MultiCurrency; -use primitives::AssetId; +use primitives::{constants::currency::UNITS, AssetId}; use sp_runtime::{ traits::{One, Zero}, FixedPointNumber, FixedU128, Permill, Perquintill, }; use xcm_emulator::TestExt; -use hydradx_runtime::{Balance, RuntimeOrigin}; +use hydradx_runtime::{AssetRegistry, Balance, Bonds, RuntimeOrigin}; +use pallet_asset_registry::AssetType; use pretty_assertions::assert_eq; +use primitives::constants::time::unix_time::MONTH; #[macro_export] macro_rules! assert_nft_owner { @@ -113,7 +115,7 @@ fn create_yield_farm_should_work_when_asset_is_in_omnipool() { init_omnipool(); set_relaychain_block_number(100); - create_global_farm(); + create_global_farm(None); set_relaychain_block_number(200); assert_ok!(hydradx_runtime::OmnipoolLiquidityMining::create_yield_farm( @@ -152,7 +154,7 @@ fn deposit_shares_should_work_when_yield_farm_exists() { //NOTE: necessary to get oracle price. hydradx_run_to_block(100); set_relaychain_block_number(100); - create_global_farm(); + create_global_farm(None); set_relaychain_block_number(200); create_yield_farm(global_farm_id, ETH); @@ -223,8 +225,8 @@ fn redeposit_shares_multiple_times_should_work_when_shares_already_deposited() { //NOTE: necessary to get oracle price. hydradx_run_to_block(100); set_relaychain_block_number(100); - create_global_farm(); - create_global_farm(); + create_global_farm(None); + create_global_farm(None); set_relaychain_block_number(200); create_yield_farm(global_farm_1_id, ETH); @@ -314,8 +316,8 @@ fn claim_rewards_should_work_when_rewards_are_accumulated_for_deposit() { //NOTE: necessary to get oracle price. hydradx_run_to_block(100); set_relaychain_block_number(100); - create_global_farm(); - create_global_farm(); + create_global_farm(None); + create_global_farm(None); set_relaychain_block_number(200); create_yield_farm(global_farm_1_id, ETH); @@ -419,8 +421,8 @@ fn withdraw_shares_should_work_when_deposit_exists() { //NOTE: necessary to get oracle price. hydradx_run_to_block(100); set_relaychain_block_number(100); - create_global_farm(); - create_global_farm(); + create_global_farm(None); + create_global_farm(None); set_relaychain_block_number(200); create_yield_farm(global_farm_1_id, ETH); @@ -595,7 +597,7 @@ fn init_omnipool() { )); } -fn create_global_farm() { +fn create_global_farm(rewards_currency: Option) { let total_rewards = 1_000_000 * UNITS; assert_ok!(hydradx_runtime::Balances::force_set_balance( @@ -609,7 +611,7 @@ fn create_global_farm() { total_rewards, 1_000_000, 10, - HDX, + rewards_currency.unwrap_or(HDX), Treasury::account_id(), Perquintill::from_parts(570_776_255_707), 1_000, @@ -688,7 +690,7 @@ fn position_should_be_valued_correctly_when_oracle_is_used() { //NOTE: necessary to get oracle price. hydradx_run_to_block(100); set_relaychain_block_number(100); - create_global_farm(); + create_global_farm(None); set_relaychain_block_number(200); create_yield_farm(global_farm_id, ETH); @@ -767,7 +769,7 @@ fn price_adjustment_from_oracle_should_be_saved_in_global_farm_when_oracle_is_av //NOTE: necessary to get oracle price. hydradx_run_to_block(100); set_relaychain_block_number(100); - create_global_farm(); + create_global_farm(None); set_relaychain_block_number(200); create_yield_farm(global_farm_1_id, ETH); @@ -814,3 +816,128 @@ fn price_adjustment_from_oracle_should_be_saved_in_global_farm_when_oracle_is_av ); }); } + +#[test] +fn liquidity_mining_should_work_when_farm_distribute_bonds() { + TestNet::reset(); + + Hydra::execute_with(|| { + let global_farm_1_id = 1; + let yield_farm_1_id = 2; + + //Arrange + init_omnipool(); + seed_lm_pot(); + //necessary for oracle to have a price. + do_lrna_hdx_trade(); + + //Create bodns + assert_ok!(hydradx_runtime::Balances::force_set_balance( + hydradx_runtime::RuntimeOrigin::root(), + Treasury::account_id(), + 2_000_000 * UNITS, + )); + + let maturity = NOW + MONTH; + let bond_id = AssetRegistry::next_asset_id().unwrap(); + assert_ok!(Bonds::issue( + RuntimeOrigin::signed(Treasury::account_id()), + HDX, + 2_000_000 * UNITS, + maturity + )); + assert_eq!(AssetRegistry::assets(bond_id).unwrap().asset_type, AssetType::Bond); + //NOTE: make bond sufficient because treasury account is whitelisted. In this case farm + //would have to pay ED for receiving insufficicient bods and farm's account has no balance. + assert_ok!(AssetRegistry::update( + hydradx_runtime::RuntimeOrigin::root(), + bond_id, + None, + None, + None, + None, + Some(true), + None, + None, + None, + )); + + // farm's rewards in test are less than ED. + assert_ok!(hydradx_runtime::Currencies::transfer( + hydradx_runtime::RuntimeOrigin::signed(Treasury::account_id()), + CHARLIE.into(), + bond_id, + 2 * UNITS, + )); + + //NOTE: necessary to get oracle price. + hydradx_run_to_block(100); + set_relaychain_block_number(100); + create_global_farm(Some(bond_id)); + + set_relaychain_block_number(200); + create_yield_farm(global_farm_1_id, ETH); + + set_relaychain_block_number(300); + + assert_ok!(hydradx_runtime::Currencies::update_balance( + hydradx_runtime::RuntimeOrigin::root(), + CHARLIE.into(), + ETH, + 10_000 * UNITS as i128, + )); + + let position_id = omnipool_add_liquidity(CHARLIE.into(), ETH, 1_000 * UNITS); + assert_nft_owner!( + hydradx_runtime::OmnipoolCollectionId::get(), + position_id, + CHARLIE.into() + ); + + set_relaychain_block_number(400); + let deposit_id = 1; + assert_ok!(hydradx_runtime::OmnipoolLiquidityMining::deposit_shares( + RuntimeOrigin::signed(CHARLIE.into()), + global_farm_1_id, + yield_farm_1_id, + position_id + )); + + let charlie_bonds_balance_0 = hydradx_runtime::Currencies::free_balance(bond_id, &CHARLIE.into()); + set_relaychain_block_number(600); + assert_ok!(hydradx_runtime::OmnipoolLiquidityMining::claim_rewards( + RuntimeOrigin::signed(CHARLIE.into()), + deposit_id, + yield_farm_1_id + )); + + //Assert + let expected_claimed_amount = 393_607_131_u128; + assert_eq!( + hydradx_runtime::Currencies::free_balance(bond_id, &CHARLIE.into()), + charlie_bonds_balance_0 + expected_claimed_amount + ); + + set_relaychain_block_number(700); + let charlie_bonds_balance_0 = hydradx_runtime::Currencies::free_balance(bond_id, &CHARLIE.into()); + assert_ok!(hydradx_runtime::OmnipoolLiquidityMining::withdraw_shares( + RuntimeOrigin::signed(CHARLIE.into()), + deposit_id, + yield_farm_1_id + )); + + let expected_claimed_amount = 229_243_713_u128; + assert_eq!( + hydradx_runtime::Currencies::free_balance(bond_id, &CHARLIE.into()), + charlie_bonds_balance_0 + expected_claimed_amount + ); + + // NOTE: make sure oracle's price adjustment was used. + let global_farm = hydradx_runtime::OmnipoolWarehouseLM::global_farm(global_farm_1_id).unwrap(); + let price_adjustment = DefaultPriceAdjustment::get(&global_farm).unwrap(); + assert_eq!( + price_adjustment, + FixedU128::from_inner(830_817_151_946_084_689_817_u128) + ); + }); +} diff --git a/pallets/bonds/Cargo.toml b/pallets/bonds/Cargo.toml index 7556569ab..abec15d8f 100644 --- a/pallets/bonds/Cargo.toml +++ b/pallets/bonds/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-bonds" -version = "2.1.0" +version = "2.2.0" authors = ['GalacticCouncil'] edition = "2021" license = "Apache-2.0" diff --git a/pallets/bonds/src/lib.rs b/pallets/bonds/src/lib.rs index 6e443c04c..5d6aabee3 100644 --- a/pallets/bonds/src/lib.rs +++ b/pallets/bonds/src/lib.rs @@ -53,7 +53,7 @@ use frame_support::{ }; use frame_system::{ensure_signed, pallet_prelude::OriginFor}; use sp_core::MaxEncodedLen; -use sp_std::vec::Vec; +use sp_std::{mem, vec::Vec}; use hydradx_traits::{ registry::{Create, Inspect}, @@ -185,6 +185,8 @@ pub mod pallet { AssetNotFound, /// Generated name is not valid. InvalidBondName, + /// Bond's name parsing was now successful + FailToParseName, } #[pallet::call] @@ -326,4 +328,12 @@ impl Pallet { buf } + + pub fn parse_bond_name(name: Vec) -> Result> { + Ok(AssetId::from_le_bytes( + name[..mem::size_of::()] + .try_into() + .map_err(|_| Error::::FailToParseName)?, + )) + } } diff --git a/pallets/bonds/src/tests/mod.rs b/pallets/bonds/src/tests/mod.rs index 7119df845..314d45977 100644 --- a/pallets/bonds/src/tests/mod.rs +++ b/pallets/bonds/src/tests/mod.rs @@ -1,3 +1,5 @@ mod issue; pub mod mock; mod redeem; +#[allow(clippy::module_inception)] +mod tests; diff --git a/pallets/bonds/src/tests/tests.rs b/pallets/bonds/src/tests/tests.rs new file mode 100644 index 000000000..1443ef77b --- /dev/null +++ b/pallets/bonds/src/tests/tests.rs @@ -0,0 +1,37 @@ +// This file is part of HydraDX. + +// Copyright (C) 2020-2022 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::tests::mock::*; +use crate::*; + +#[test] +fn parse_name_should_work() { + let n = Pallet::::bond_name(0_u32, 1689844300000_u64); + assert_eq!(Pallet::::parse_bond_name(n), Ok(0_u32)); + + let n = Pallet::::bond_name(u32::max_value(), 1689844300000_u64); + assert_eq!(Pallet::::parse_bond_name(n), Ok(u32::max_value())); + + let n = Pallet::::bond_name(1, 1689844300000_u64); + assert_eq!(Pallet::::parse_bond_name(n), Ok(1)); + + let n = Pallet::::bond_name(13_124, 1689844300000_u64); + assert_eq!(Pallet::::parse_bond_name(n), Ok(13_124)); + + let n = Pallet::::bond_name(789_970_979, 1689844300000_u64); + assert_eq!(Pallet::::parse_bond_name(n), Ok(789_970_979)); +} diff --git a/runtime/adapters/Cargo.toml b/runtime/adapters/Cargo.toml index 33c5ad71a..7a2b14d73 100644 --- a/runtime/adapters/Cargo.toml +++ b/runtime/adapters/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-adapters" -version = "1.1.1" +version = "1.2.0" description = "Structs and other generic types for building runtimes." authors = ["GalacticCouncil"] edition = "2021" @@ -30,6 +30,8 @@ pallet-currencies = { workspace = true } pallet-stableswap = { workspace = true } pallet-referrals = { workspace = true } pallet-lbp = { workspace = true } +pallet-asset-registry = { workspace = true } +pallet-bonds = { workspace = true } # Substrate dependencies frame-support = { workspace = true } @@ -87,4 +89,7 @@ std = [ "cumulus-pallet-parachain-system/std", "polkadot-parachain/std", "orml-tokens/std", + "pallet-asset-registry/std", + "pallet-omnipool-liquidity-mining/std", + "pallet-bonds/std", ] diff --git a/runtime/adapters/src/lib.rs b/runtime/adapters/src/lib.rs index 76cd29ac9..02382533a 100644 --- a/runtime/adapters/src/lib.rs +++ b/runtime/adapters/src/lib.rs @@ -17,7 +17,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::FullCodec; +use codec::{EncodeLike, FullCodec}; use cumulus_primitives_core::relay_chain::Hash; use frame_support::{ sp_runtime::{ @@ -629,14 +629,32 @@ impl PriceAdjustment> where Runtime: warehouse_liquidity_mining::Config + pallet_ema_oracle::Config - + pallet_omnipool_liquidity_mining::Config, + + pallet_omnipool_liquidity_mining::Config + + pallet_asset_registry::Config + + pallet_bonds::Config, + u32: EncodeLike<::AssetId>, { type Error = DispatchError; type PriceAdjustment = FixedU128; fn get(global_farm: &GlobalFarmData) -> Result { + use pallet_asset_registry::AssetType; + + let asset_detail = pallet_asset_registry::Assets::::get(global_farm.reward_currency.into()) + .ok_or(pallet_omnipool_liquidity_mining::Error::::PriceAdjustmentNotAvailable)?; + + let reward_currency_id = if asset_detail.asset_type == AssetType::Bond { + let name = asset_detail + .name + .ok_or(pallet_omnipool_liquidity_mining::Error::::PriceAdjustmentNotAvailable)?; + + pallet_bonds::Pallet::::parse_bond_name(name.into())? + } else { + global_farm.reward_currency.into() + }; + let (price, _) = pallet_ema_oracle::Pallet::::get_price( - global_farm.reward_currency.into(), + reward_currency_id, global_farm.incentivized_asset.into(), //LRNA OraclePeriod::TenMinutes, OMNIPOOL_SOURCE, diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index 6d98783d9..60179b704 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-runtime" -version = "212.0.0" +version = "213.0.0" authors = ["GalacticCouncil"] edition = "2021" license = "Apache 2.0" diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 91d059731..eac6d9a40 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -107,7 +107,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("hydradx"), impl_name: create_runtime_str!("hydradx"), authoring_version: 1, - spec_version: 212, + spec_version: 213, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1,