diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 35233908a9..7d4e6a30c7 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -20,5 +20,7 @@ bifrost-flexible-fee-rpc = { path = "../../pallets/flexible-fee/rpc" } bifrost-flexible-fee-rpc-runtime-api = { path = "../../pallets/flexible-fee/rpc/runtime-api" } bifrost-salp-rpc-api = { path = "../../pallets/salp/rpc" } bifrost-salp-rpc-runtime-api = { path = "../../pallets/salp/rpc/runtime-api" } +bifrost-liquidity-mining-rpc-api = { path = "../../pallets/liquidity-mining/rpc" } +bifrost-liquidity-mining-rpc-runtime-api = { path = "../../pallets/liquidity-mining/rpc/runtime-api" } zenlink-protocol-rpc = "*" zenlink-protocol-runtime-api = "*" \ No newline at end of file diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 24ab21490f..664be557b3 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -35,9 +35,11 @@ use std::sync::Arc; use bifrost_flexible_fee_rpc::{FeeRpcApi, FlexibleFeeStruct}; use bifrost_flexible_fee_rpc_runtime_api::FlexibleFeeRuntimeApi as FeeRuntimeApi; +use bifrost_liquidity_mining_rpc_api::{LiquidityMiningRpcApi, LiquidityMiningRpcWrapper}; +use bifrost_liquidity_mining_rpc_runtime_api::LiquidityMiningRuntimeApi; use bifrost_salp_rpc_api::{SalpRpcApi, SalpRpcWrapper}; use bifrost_salp_rpc_runtime_api::SalpRuntimeApi; -use node_primitives::{AccountId, Balance, Block, ParaId}; +use node_primitives::{AccountId, Balance, Block, ParaId, PoolId}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; pub use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::TransactionPool; @@ -69,6 +71,7 @@ where C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, C::Api: FeeRuntimeApi, C::Api: SalpRuntimeApi, + C::Api: LiquidityMiningRuntimeApi, P: TransactionPool + 'static, { let FullDeps { client, .. } = deps; @@ -81,5 +84,9 @@ where io.extend_with(SalpRpcApi::to_delegate(SalpRpcWrapper::new(client.clone()))); + io.extend_with(LiquidityMiningRpcApi::to_delegate(LiquidityMiningRpcWrapper::new( + client.clone(), + ))); + io } diff --git a/node/service/Cargo.toml b/node/service/Cargo.toml index fe41b84230..cda280f46f 100644 --- a/node/service/Cargo.toml +++ b/node/service/Cargo.toml @@ -90,7 +90,7 @@ zenlink-protocol-runtime-api = "*" # Bifrost rpc bifrost-flexible-fee-rpc-runtime-api = { path = "../../pallets/flexible-fee/rpc/runtime-api" } bifrost-salp-rpc-runtime-api = { path = "../../pallets/salp/rpc/runtime-api" } - +bifrost-liquidity-mining-rpc-runtime-api = { path = "../../pallets/liquidity-mining/rpc/runtime-api" } [features] default = [ "std" ] diff --git a/node/service/src/collator.rs b/node/service/src/collator.rs index 098e21df8f..07ab8aa433 100644 --- a/node/service/src/collator.rs +++ b/node/service/src/collator.rs @@ -21,6 +21,7 @@ use std::sync::Arc; #[cfg(feature = "with-asgard-runtime")] pub use asgard_runtime; use bifrost_flexible_fee_rpc_runtime_api::FlexibleFeeRuntimeApi as FeeRuntimeApi; +use bifrost_liquidity_mining_rpc_runtime_api::LiquidityMiningRuntimeApi; #[cfg(feature = "with-bifrost-runtime")] pub use bifrost_runtime; use bifrost_salp_rpc_runtime_api::SalpRuntimeApi; @@ -33,6 +34,7 @@ use cumulus_client_service::{ prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, }; use cumulus_primitives_core::ParaId; +use node_primitives::PoolId; pub use node_primitives::{AccountId, Block, BlockNumber, Hash, Header, ParaId as BifrostParaId}; use sc_client_api::ExecutorProvider; use sc_consensus::LongestChain; @@ -189,6 +191,7 @@ where RuntimeApi::RuntimeApi: sp_consensus_aura::AuraApi, RuntimeApi::RuntimeApi: FeeRuntimeApi, RuntimeApi::RuntimeApi: SalpRuntimeApi, + RuntimeApi::RuntimeApi: LiquidityMiningRuntimeApi, Executor: NativeExecutionDispatch + 'static, BIC: FnOnce( Arc>, @@ -348,6 +351,7 @@ where RuntimeApi::RuntimeApi: sp_consensus_aura::AuraApi, RuntimeApi::RuntimeApi: FeeRuntimeApi, RuntimeApi::RuntimeApi: SalpRuntimeApi, + RuntimeApi::RuntimeApi: LiquidityMiningRuntimeApi, Executor: NativeExecutionDispatch + 'static, { start_node_impl( diff --git a/pallets/liquidity-mining/rpc/Cargo.toml b/pallets/liquidity-mining/rpc/Cargo.toml new file mode 100644 index 0000000000..c6b28d438f --- /dev/null +++ b/pallets/liquidity-mining/rpc/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "bifrost-liquidity-mining-rpc-api" +version = "0.8.0" +authors = ["Allen Pocket "] +edition = "2018" + +[dependencies] +serde = { version = "1.0.124", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +jsonrpc-core = "15.1.0" +jsonrpc-core-client = "15.1.0" +jsonrpc-derive = "15.1.0" +sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9" } +sp-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9" } +node-primitives = { path = "../../../node/primitives", default-features = false } +bifrost-liquidity-mining-rpc-runtime-api = { path = "./runtime-api" } \ No newline at end of file diff --git a/pallets/liquidity-mining/rpc/runtime-api/Cargo.toml b/pallets/liquidity-mining/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000..099ab1551d --- /dev/null +++ b/pallets/liquidity-mining/rpc/runtime-api/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "bifrost-liquidity-mining-rpc-runtime-api" +version = "0.8.0" +authors = ["Allen Pocket "] +edition = "2018" + +[dependencies] +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9", default-features = false } +node-primitives = { path = "../../../../node/primitives", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-api/std", + "node-primitives/std", +] diff --git a/pallets/liquidity-mining/rpc/runtime-api/src/lib.rs b/pallets/liquidity-mining/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000..80ec625f9e --- /dev/null +++ b/pallets/liquidity-mining/rpc/runtime-api/src/lib.rs @@ -0,0 +1,36 @@ +// This file is part of Bifrost. + +// Copyright (C) 2019-2021 Liebi Technologies (UK) Ltd. +// 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 . + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; +use node_primitives::{Balance, CurrencyId}; +use sp_api::decl_runtime_apis; +use sp_std::vec::Vec; + +decl_runtime_apis! { + pub trait LiquidityMiningRuntimeApi where + AccountId: Codec, + PoolId: Codec, + { + fn get_rewards( + who: AccountId, + pid: PoolId, + ) -> Vec<(CurrencyId, Balance)>; + } +} diff --git a/pallets/liquidity-mining/rpc/src/lib.rs b/pallets/liquidity-mining/rpc/src/lib.rs new file mode 100644 index 0000000000..45e1d6742d --- /dev/null +++ b/pallets/liquidity-mining/rpc/src/lib.rs @@ -0,0 +1,89 @@ +// This file is part of Bifrost. + +// Copyright (C) 2019-2021 Liebi Technologies (UK) Ltd. +// 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 std::{marker::PhantomData, sync::Arc}; + +pub use bifrost_liquidity_mining_rpc_runtime_api::{ + self as runtime_api, LiquidityMiningRuntimeApi, +}; +use codec::Codec; +use jsonrpc_core::{Error as RpcError, ErrorCode, Result as JsonRpcResult}; +use jsonrpc_derive::rpc; +use node_primitives::{Balance, CurrencyId}; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_rpc::number::NumberOrHex; +use sp_runtime::{generic::BlockId, traits::Block as BlockT, SaturatedConversion}; + +#[rpc] +pub trait LiquidityMiningRpcApi { + /// rpc method for getting current rewards + #[rpc(name = "liquidityMining_getRewards")] + fn get_rewards( + &self, + who: AccountId, + pid: PoolId, + at: Option, + ) -> JsonRpcResult>; +} + +#[derive(Clone, Debug)] +pub struct LiquidityMiningRpcWrapper { + client: Arc, + _marker: PhantomData, +} + +impl LiquidityMiningRpcWrapper { + pub fn new(client: Arc) -> Self { + Self { client, _marker: PhantomData } + } +} + +impl LiquidityMiningRpcApi<::Hash, AccountId, PoolId> + for LiquidityMiningRpcWrapper +where + Block: BlockT, + C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, + C::Api: LiquidityMiningRuntimeApi, + AccountId: Codec, + PoolId: Codec, +{ + fn get_rewards( + &self, + who: AccountId, + pid: PoolId, + at: Option<::Hash>, + ) -> JsonRpcResult> { + let lm_rpc_api = self.client.runtime_api(); + let at = BlockId::::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + let rs: Result, _> = lm_rpc_api.get_rewards(&at, who, pid); + + match rs { + Ok(rewards) => Ok(rewards + .into_iter() + .map(|(token, amount)| (token, NumberOrHex::Number(amount.saturated_into()))) + .collect()), + Err(e) => Err(RpcError { + code: ErrorCode::InternalError, + message: "Failed to get lm rewards.".to_owned(), + data: Some(format!("{:?}", e).into()), + }), + } + } +} diff --git a/pallets/liquidity-mining/src/lib.rs b/pallets/liquidity-mining/src/lib.rs index c533e4f655..e1af4d344b 100644 --- a/pallets/liquidity-mining/src/lib.rs +++ b/pallets/liquidity-mining/src/lib.rs @@ -1053,6 +1053,35 @@ pub mod pallet { Ok(CurrencyId::LPToken(sym1, discr1, sym2, discr2)) } + pub fn rewards( + who: AccountIdOf, + pid: PoolId, + ) -> Result)>, ()> { + let pool: PoolInfo = Self::pool(pid).ok_or(())?.try_retire().try_update(); + let deposit_data: DepositData = + Self::user_deposit_data(pid, who.clone()).ok_or(())?; + + let mut to_rewards = Vec::<(CurrencyId, BalanceOf)>::new(); + + if let Some(_block_startup) = pool.block_startup { + for (rtoken, reward) in pool.rewards.iter() { + let v_new = reward.gain_avg; + if let Some(gain_avg) = deposit_data.gain_avgs.get(rtoken) { + let v_old = *gain_avg; + + let user_deposit: u128 = deposit_data.deposit.saturated_into(); + let amount = BalanceOf::::saturated_from( + v_new.saturating_sub(v_old).saturating_mul_int(user_deposit), + ); + + to_rewards.push((*rtoken, amount)); + } + } + } + + Ok(to_rewards) + } + #[allow(non_snake_case)] pub(crate) fn vsAssets( index: ParaId, diff --git a/runtime/asgard/Cargo.toml b/runtime/asgard/Cargo.toml index c444c565ba..ba92cc538d 100644 --- a/runtime/asgard/Cargo.toml +++ b/runtime/asgard/Cargo.toml @@ -90,6 +90,7 @@ bifrost-minter-reward = { path = "../../pallets/minter-reward", default-features bifrost-runtime-common = { package = "bifrost-runtime-common", path = "../common", default-features = false } bifrost-salp = { path = "../../pallets/salp", default-features = false } bifrost-salp-rpc-runtime-api = { path = "../../pallets/salp/rpc/runtime-api", default-features = false } +bifrost-liquidity-mining-rpc-runtime-api = { path = "../../pallets/liquidity-mining/rpc/runtime-api", default-features = false } bifrost-vsbond-auction = { path = "../../pallets/vsbond-auction", default-features = false } bifrost-vtoken-mint = { path = "../../pallets/vtoken-mint", default-features = false } pallet-vesting = { package = "bifrost-vesting", path = "../../pallets/vesting", default-features = false } @@ -180,6 +181,7 @@ std = [ "bifrost-vsbond-auction/std", "bifrost-vtoken-mint/std", "bifrost-liquidity-mining/std", + "bifrost-liquidity-mining-rpc-runtime-api/std", "xcm-support/std", "orml-currencies/std", "orml-traits/std", diff --git a/runtime/asgard/src/lib.rs b/runtime/asgard/src/lib.rs index 114eadd3cc..d4cd3a2d75 100644 --- a/runtime/asgard/src/lib.rs +++ b/runtime/asgard/src/lib.rs @@ -93,7 +93,7 @@ use frame_support::{ }; pub use node_primitives::{ AccountId, Amount, Balance, BlockNumber, CurrencyId, ExtraFeeName, Moment, Nonce, ParaId, - ParachainDerivedProxyAccountType, ParachainTransactProxyType, ParachainTransactType, + ParachainDerivedProxyAccountType, ParachainTransactProxyType, ParachainTransactType, PoolId, RpcContributionStatus, TokenSymbol, TransferOriginType, XcmBaseWeight, }; // orml imports @@ -1616,6 +1616,12 @@ impl_runtime_apis! { } } + impl bifrost_liquidity_mining_rpc_runtime_api::LiquidityMiningRuntimeApi for Runtime { + fn get_rewards(who: AccountId, pid: PoolId) -> Vec<(CurrencyId, Balance)> { + LiquidityMining::rewards(who, pid).unwrap_or(Vec::new()) + } + } + // benchmarks for asgard modules #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { diff --git a/runtime/bifrost/Cargo.toml b/runtime/bifrost/Cargo.toml index 0cc55cbcc8..bcab98de7d 100644 --- a/runtime/bifrost/Cargo.toml +++ b/runtime/bifrost/Cargo.toml @@ -86,6 +86,7 @@ bifrost-salp = { path = "../../pallets/salp", default-features = false } bifrost-salp-rpc-runtime-api = { path = "../../pallets/salp/rpc/runtime-api", default-features = false } pallet-vesting = { package = "bifrost-vesting", path = "../../pallets/vesting", default-features = false } bifrost-liquidity-mining = { path = "../../pallets/liquidity-mining", default-features = false } +bifrost-liquidity-mining-rpc-runtime-api = { path = "../../pallets/liquidity-mining/rpc/runtime-api", default-features = false } xcm-support = { path = "../../xcm-support", default-features = false } # orml @@ -163,6 +164,7 @@ std = [ "bifrost-salp/std", "bifrost-salp-rpc-runtime-api/std", "bifrost-liquidity-mining/std", + "bifrost-liquidity-mining-rpc-runtime-api/std", ] with-tracing = ["frame-executive/with-tracing"] diff --git a/runtime/bifrost/src/lib.rs b/runtime/bifrost/src/lib.rs index 88355547a0..bf47a2e94e 100644 --- a/runtime/bifrost/src/lib.rs +++ b/runtime/bifrost/src/lib.rs @@ -87,7 +87,7 @@ use frame_system::{EnsureOneOf, EnsureRoot, RawOrigin}; use hex_literal::hex; pub use node_primitives::{ AccountId, Amount, Balance, BlockNumber, CurrencyId, ExtraFeeName, Moment, Nonce, ParaId, - ParachainDerivedProxyAccountType, ParachainTransactProxyType, ParachainTransactType, + ParachainDerivedProxyAccountType, ParachainTransactProxyType, ParachainTransactType, PoolId, RpcContributionStatus, TokenSymbol, TransferOriginType, XcmBaseWeight, }; // orml imports @@ -1333,6 +1333,12 @@ impl_runtime_apis! { } } + impl bifrost_liquidity_mining_rpc_runtime_api::LiquidityMiningRuntimeApi for Runtime { + fn get_rewards(who: AccountId, pid: PoolId) -> Vec<(CurrencyId, Balance)> { + LiquidityMining::rewards(who, pid).unwrap_or(Vec::new()) + } + } + #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn benchmark_metadata(extra: bool) -> (