Skip to content

Commit

Permalink
Add vtoken exchange rate rpc (#1260)
Browse files Browse the repository at this point in the history
  • Loading branch information
SunTiebing committed Jun 11, 2024
1 parent 5b892b4 commit 66b0ab0
Show file tree
Hide file tree
Showing 26 changed files with 270 additions and 4 deletions.
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ pallet-traits = { path = "pallets/traits", default-featur
leverage-staking = { path = "pallets/leverage-staking", default-features = false }
bifrost-channel-commission = { path = "pallets/channel-commission", default-features = false }
bifrost-clouds-convert = { path = "pallets/clouds-convert", default-features = false }
bifrost-vtoken-minting-rpc-runtime-api = { path = "pallets/vtoken-minting/rpc/runtime-api", default-features = false }

# Zenlink
merkle-distributor = { git = "https://github.com/bifrost-finance/Zenlink-DEX-Module", branch = "release-polkadot-v1.6.0", default-features = false }
Expand Down
4 changes: 4 additions & 0 deletions pallets/asset-registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,10 @@ impl<T: Config> CurrencyIdMapping<CurrencyId, MultiLocation, AssetMetadata<Balan
Pallet::<T>::currency_metadatas(currency_id)
}

fn get_all_currency() -> Vec<CurrencyId> {
CurrencyMetadatas::<T>::iter_keys().collect()
}

fn get_multi_location(currency_id: CurrencyId) -> Option<MultiLocation> {
Pallet::<T>::currency_id_to_locations(currency_id)
}
Expand Down
1 change: 1 addition & 0 deletions pallets/buy-back/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ impl bifrost_vtoken_minting::Config for Runtime {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Runtime>;
}

parameter_types! {
Expand Down
1 change: 1 addition & 0 deletions pallets/fee-share/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ impl bifrost_vtoken_minting::Config for Runtime {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Runtime>;
}

parameter_types! {
Expand Down
1 change: 1 addition & 0 deletions pallets/leverage-staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ impl bifrost_vtoken_minting::Config for Test {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Test>;
}

pub struct Slp;
Expand Down
1 change: 1 addition & 0 deletions pallets/salp/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ impl bifrost_vtoken_minting::Config for Test {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Test>;
}

parameter_types! {
Expand Down
1 change: 1 addition & 0 deletions pallets/slp/src/mocks/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ impl bifrost_vtoken_minting::Config for Runtime {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Runtime>;
}

parameter_types! {
Expand Down
1 change: 1 addition & 0 deletions pallets/slp/src/mocks/mock_kusama.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ impl bifrost_vtoken_minting::Config for Runtime {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Runtime>;
}

parameter_types! {
Expand Down
1 change: 1 addition & 0 deletions pallets/slpx/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ impl bifrost_vtoken_minting::Config for Test {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Test>;
}
// Below is the implementation of tokens manipulation functions other than native token.
pub struct LocalAssetAdaptor<Local>(PhantomData<Local>);
Expand Down
1 change: 1 addition & 0 deletions pallets/stable-pool/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ impl bifrost_vtoken_minting::Config for Test {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Test>;
}

pub struct Slp;
Expand Down
1 change: 1 addition & 0 deletions pallets/system-maker/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ impl bifrost_vtoken_minting::Config for Runtime {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Runtime>;
}

parameter_types! {
Expand Down
1 change: 1 addition & 0 deletions pallets/system-staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ impl bifrost_vtoken_minting::Config for Runtime {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Runtime>;
}

ord_parameter_types! {
Expand Down
1 change: 1 addition & 0 deletions pallets/ve-minting/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ impl bifrost_vtoken_minting::Config for Runtime {
type MaxLockRecords = ConstU32<100>;
type IncentivePoolAccount = IncentivePoolAccount;
type VeMinting = ();
type AssetIdMaps = AssetIdMaps<Runtime>;
}

ord_parameter_types! {
Expand Down
1 change: 1 addition & 0 deletions pallets/vtoken-minting/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ cumulus-primitives-core = { workspace = true }
sp-core = { workspace = true }
sp-runtime = { workspace = true }
bifrost-ve-minting = { workspace = true }
bifrost-asset-registry = { workspace = true }

[dev-dependencies]
orml-tokens = { workspace = true }
Expand Down
17 changes: 17 additions & 0 deletions pallets/vtoken-minting/rpc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "bifrost-vtoken-minting-rpc"
version = "0.8.0"
authors = ["Tiebing <[email protected]>"]
edition = "2021"

[dependencies]
serde = { workspace = true, features = ["derive"] }
parity-scale-codec = { workspace = true, features = ["derive"] }
jsonrpsee = { workspace = true, features = ["server", "macros"] }
sp-api = { workspace = true }
sp-runtime = { workspace = true }
sp-blockchain = { workspace = true }
sp-core = { workspace = true }
sp-rpc = { workspace = true }
bifrost-primitives = { workspace = true }
bifrost-ve-minting-rpc-runtime-api = { workspace = true }
20 changes: 20 additions & 0 deletions pallets/vtoken-minting/rpc/runtime-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "bifrost-vtoken-minting-rpc-runtime-api"
version = "0.8.0"
authors = ["Tiebing <[email protected]>"]
edition = "2021"

[dependencies]
parity-scale-codec = { workspace = true, features = ["derive"] }
sp-std = { workspace = true }
sp-api = { workspace = true }
sp-core = { workspace = true }
bifrost-primitives = { workspace = true }

[features]
default = ["std"]
std = [
"parity-scale-codec/std",
"sp-api/std",
"bifrost-primitives/std",
]
30 changes: 30 additions & 0 deletions pallets/vtoken-minting/rpc/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// This file is part of Bifrost.

// Copyright (C) Liebi Technologies PTE. 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 <https://www.gnu.org/licenses/>.

#![cfg_attr(not(feature = "std"), no_std)]

use parity_scale_codec::Codec;
use sp_api::decl_runtime_apis;
use sp_core::U256;

decl_runtime_apis! {
pub trait VtokenMintingRuntimeApi<CurrencyId> where CurrencyId: Codec
{
fn get_exchange_rate(token_id: Option<CurrencyId>) -> Vec<(CurrencyId, U256)>;
}
}
95 changes: 95 additions & 0 deletions pallets/vtoken-minting/rpc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// This file is part of Bifrost.

// Copyright (C) Liebi Technologies PTE. 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 <https://www.gnu.org/licenses/>.

use std::{marker::PhantomData, sync::Arc};

use bifrost_primitives::Balance;
pub use bifrost_vtoken_minting_rpc_runtime_api::{self as runtime_api, VtokenMintingRuntimeApi};
use jsonrpsee::{
core::{async_trait, RpcResult},
proc_macros::rpc,
types::error::{CallError, ErrorCode, ErrorObject},
};
use parity_scale_codec::Codec;
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_core::U256;
use sp_rpc::number::NumberOrHex;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, BlockIdTo},
SaturatedConversion,
};

#[rpc(client, server)]
pub trait VtokenMintingRpcApi<CurrencyId, BlockHash> {
/// rpc method for getting vtoken exchange rate
#[method(name = "vtoken_minting_getExchangeRate")]
fn get_exchange_rate(
&self,
asset_id: Option<CurrencyId>,
at: Option<BlockHash>,
) -> RpcResult<Vec<(CurrencyId, NumberOrHex)>>;
}

#[derive(Clone, Debug)]
pub struct VtokenMintingRpc<C, Block> {
client: Arc<C>,
_marker: PhantomData<Block>,
}

impl<C, Block> VtokenMintingRpc<C, Block>
where
Block: BlockT,
C: BlockIdTo<Block>,
{
pub fn new(client: Arc<C>) -> Self {
Self { client, _marker: PhantomData }
}
}

#[async_trait]
impl<C, Block, CurrencyId> VtokenMintingRpcApiServer<<Block as BlockT>::Hash, AccountId>
for VtokenMintingRpc<C, Block>
where
Block: BlockT,
C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block> + BlockIdTo<Block>,
C::Api: VeMintingRuntimeApi<Block, AccountId>,
CurrencyId: Codec,
{
fn get_exchange_rate(
&self,
token_id: Option<CurrencyId>,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<Vec<(CurrencyId, NumberOrHex)>> {
let lm_rpc_api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

let rs: Result<U256, _> = lm_rpc_api.get_exchange_rate(at, token_id, max_epoch);

match rs {
Ok(epoch) => Ok(NumberOrHex::Hex(epoch.into())),
Err(e) => Err(CallError::Custom(ErrorObject::owned(
ErrorCode::InternalError.code(),
"Failed to get exchange rate.",
Some(format!("{:?}", e)),
))),
}
.map_err(|e| jsonrpsee::core::Error::Call(e))
}
}
59 changes: 56 additions & 3 deletions pallets/vtoken-minting/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ pub mod traits;
pub mod weights;
pub use weights::WeightInfo;

use bifrost_asset_registry::AssetMetadata;
use bifrost_primitives::{
CurrencyId, CurrencyIdConversion, CurrencyIdExt, CurrencyIdRegister, RedeemType, SlpOperator,
SlpxOperator, TimeUnit, VTokenMintRedeemProvider, VTokenSupplyProvider, VtokenMintingInterface,
VtokenMintingOperator,
CurrencyId, CurrencyIdConversion, CurrencyIdExt, CurrencyIdMapping, CurrencyIdRegister,
RedeemType, SlpOperator, SlpxOperator, TimeUnit, VTokenMintRedeemProvider,
VTokenSupplyProvider, VtokenMintingInterface, VtokenMintingOperator,
};
use bifrost_ve_minting::traits::VeMintingInterface;
use frame_support::{
Expand Down Expand Up @@ -165,6 +166,12 @@ pub mod pallet {

type ChannelCommission: VTokenMintRedeemProvider<CurrencyId, BalanceOf<Self>>;

type AssetIdMaps: CurrencyIdMapping<
CurrencyId,
MultiLocation,
AssetMetadata<BalanceOf<Self>>,
>;

/// Set default weight.
type WeightInfo: WeightInfo;
}
Expand Down Expand Up @@ -1918,6 +1925,52 @@ pub mod pallet {

Ok(incentive_amount)
}

pub fn get_exchange_rate(
token_id: Option<CurrencyId>,
) -> Result<Vec<(CurrencyIdOf<T>, U256)>, DispatchError> {
let mut result: Vec<(CurrencyIdOf<T>, U256)> = Vec::new();

match token_id {
Some(token_id) => {
let vtoken_amount = Self::get_vtoken_amount(token_id, 1u128)?;
result.push((token_id, vtoken_amount));
},
None =>
for token_id in T::AssetIdMaps::get_all_currency() {
if token_id.is_vtoken() {
let vtoken_id = token_id;
let token_id = T::CurrencyIdConversion::convert_to_token(vtoken_id)
.map_err(|_| Error::<T>::NotSupportTokenType)?;

let vtoken_amount = Self::get_vtoken_amount(token_id, 1u128)?;
result.push((token_id, vtoken_amount));
}
},
}
Ok(result)
}

fn get_vtoken_amount(token: CurrencyIdOf<T>, amount: u128) -> Result<U256, DispatchError> {
let vtoken_id = T::CurrencyIdConversion::convert_to_vtoken(token)
.map_err(|_| Error::<T>::NotSupportTokenType)?;

let token_pool_amount = Self::token_pool(token);
let vtoken_total_issuance = T::MultiCurrency::total_issuance(vtoken_id);

let mut vtoken_amount = U256::from(amount);
if token_pool_amount != BalanceOf::<T>::zero() {
let vtoken_total_issuance_u256 =
U256::from(vtoken_total_issuance.saturated_into::<u128>());
let token_pool_amount_u256 = U256::from(token_pool_amount.saturated_into::<u128>());

vtoken_amount = vtoken_amount
.saturating_mul(vtoken_total_issuance_u256)
.checked_div(token_pool_amount_u256)
.ok_or(Error::<T>::CalculationOverflow)?;
}
Ok(vtoken_amount)
}
}
}

Expand Down
Loading

0 comments on commit 66b0ab0

Please sign in to comment.