Skip to content

Commit

Permalink
feat: cf_boost_pool_details rpc (#4780)
Browse files Browse the repository at this point in the history
* feat: cf_boost_pool_details rpc

* feat: update boost rpc schema

* feat: maps -> lists in boost rpc; amounts as hex

* feat: optional asset param in boost deatils rpc

* feat: flatten asset in boost rpc response

* fix: derive serde attributes conditionally
  • Loading branch information
msgmaxim authored Apr 26, 2024
1 parent 13647ee commit 68a5d74
Show file tree
Hide file tree
Showing 10 changed files with 372 additions and 30 deletions.
165 changes: 162 additions & 3 deletions state-chain/custom-rpc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use boost_pool_details::BoostPoolDetailsRpc;
use cf_amm::{
common::{Amount, PoolPairsMap, Side, Tick},
range_orders::Liquidity,
Expand Down Expand Up @@ -35,8 +36,8 @@ use state_chain_runtime::{
chainflip::{BlockUpdate, Offence},
constants::common::TX_FEE_MULTIPLIER,
runtime_apis::{
BoostPoolDepth, BrokerInfo, CustomRuntimeApi, DispatchErrorWithMessage, EventFilter,
FailingWitnessValidators, LiquidityProviderInfo, ValidatorInfo,
BoostPoolDepth, BoostPoolDetails, BrokerInfo, CustomRuntimeApi, DispatchErrorWithMessage,
EventFilter, FailingWitnessValidators, LiquidityProviderInfo, ValidatorInfo,
},
NetworkFee,
};
Expand Down Expand Up @@ -299,6 +300,82 @@ pub struct SwapResponse {
swaps: Vec<ScheduledSwap>,
}

mod boost_pool_details {

use std::collections::BTreeSet;

use cf_primitives::PrewitnessedDepositId;
use sp_runtime::AccountId32;

use super::*;

#[derive(Serialize, Deserialize)]
struct AccountAndAmount {
account_id: AccountId32,
amount: NumberOrHex,
}

#[derive(Serialize, Deserialize)]
struct PendingBoost {
deposit_id: PrewitnessedDepositId,
owed_amounts: Vec<AccountAndAmount>,
}

#[derive(Serialize, Deserialize)]
struct PendingWithdrawal {
account_id: AccountId32,
pending_deposits: BTreeSet<PrewitnessedDepositId>,
}

#[derive(Serialize, Deserialize)]
pub struct BoostPoolDetailsRpc {
fee_tier: u16,
#[serde(flatten)]
asset: Asset,
available_amounts: Vec<AccountAndAmount>,
deposits_pending_finalization: Vec<PendingBoost>,
pending_withdrawals: Vec<PendingWithdrawal>,
}

fn map_to_vec(map: BTreeMap<AccountId32, AssetAmount>) -> Vec<AccountAndAmount> {
map.into_iter()
.map(|(account_id, amount)| AccountAndAmount {
account_id,
amount: NumberOrHex::from(amount),
})
.collect()
}

impl BoostPoolDetailsRpc {
pub fn new(asset: Asset, fee_tier: u16, details: BoostPoolDetails) -> Self {
BoostPoolDetailsRpc {
asset,
fee_tier,
available_amounts: map_to_vec(details.available_amounts),
deposits_pending_finalization: details
.pending_boosts
.into_iter()
.map(|(deposit_id, owed_amounts)| PendingBoost {
deposit_id,
owed_amounts: map_to_vec(owed_amounts),
})
.collect(),
pending_withdrawals: details
.pending_withdrawals
.into_iter()
.map(|(account_id, pending_deposits)| PendingWithdrawal {
account_id,
pending_deposits,
})
.collect(),
}
}
}
}

type BoostPoolDepthResponse = Vec<BoostPoolDepth>;
type BoostPoolDetailsResponse = Vec<boost_pool_details::BoostPoolDetailsRpc>;

#[rpc(server, client, namespace = "cf")]
/// The custom RPC endpoints for the state chain node.
pub trait CustomApi {
Expand Down Expand Up @@ -561,7 +638,10 @@ pub trait CustomApi {
) -> RpcResult<Vec<sp_core::Bytes>>;

#[method(name = "boost_pools_depth")]
fn cf_boost_pools_depth(&self) -> RpcResult<Vec<BoostPoolDepth>>;
fn cf_boost_pools_depth(&self) -> RpcResult<BoostPoolDepthResponse>;

#[method(name = "boost_pool_details")]
fn cf_boost_pool_details(&self, asset: Option<Asset>) -> RpcResult<BoostPoolDetailsResponse>;
}

/// An RPC extension for the state chain node.
Expand Down Expand Up @@ -1380,6 +1460,30 @@ where
.map(|event| event.encode().into())
.collect::<Vec<_>>())
}

fn cf_boost_pool_details(&self, asset: Option<Asset>) -> RpcResult<BoostPoolDetailsResponse> {
let get_boost_details_for_asset = |asset| {
self.client
.runtime_api()
.cf_boost_pool_details(self.client.info().best_hash, asset)
.map(|details_vec| {
details_vec
.into_iter()
.map(|(tier, details)| BoostPoolDetailsRpc::new(asset, tier, details))
.collect()
})
.map_err(to_rpc_error)
};

if let Some(asset) = asset {
get_boost_details_for_asset(asset)
} else {
let results_for_each_asset: RpcResult<Vec<_>> =
Asset::all().map(get_boost_details_for_asset).collect();

results_for_each_asset.map(|inner| inner.into_iter().flatten().collect())
}
}
}

impl<C, B> CustomRpc<C, B>
Expand Down Expand Up @@ -1468,6 +1572,8 @@ where

#[cfg(test)]
mod test {
use std::collections::BTreeSet;

use super::*;
use cf_primitives::{
chains::assets::{any, arb, btc, dot, eth},
Expand Down Expand Up @@ -1688,4 +1794,57 @@ mod test {

insta::assert_snapshot!(serde_json::to_value(env).unwrap());
}

#[test]
fn test_boost_depth_serialization() {
let val: BoostPoolDepthResponse = vec![
BoostPoolDepth {
asset: Asset::Flip,
tier: 10,
available_amount: 1_000_000_000 * FLIPPERINOS_PER_FLIP,
},
BoostPoolDepth { asset: Asset::Flip, tier: 30, available_amount: 0 },
];
insta::assert_json_snapshot!(val);
}

#[test]
fn test_boost_details_serialization() {
use sp_runtime::AccountId32;

let id1 = AccountId32::new([1; 32]);
let id2 = AccountId32::new([2; 32]);

let val: BoostPoolDetailsResponse = vec![
BoostPoolDetailsRpc::new(
Asset::ArbEth,
10,
BoostPoolDetails {
available_amounts: BTreeMap::from([(id1.clone(), 10_000)]),
pending_boosts: BTreeMap::from([
(0, BTreeMap::from([(id1.clone(), 200), (id2.clone(), 2_000)])),
(1, BTreeMap::from([(id1.clone(), 1_000)])),
]),
pending_withdrawals: Default::default(),
},
),
BoostPoolDetailsRpc::new(
Asset::Btc,
30,
BoostPoolDetails {
available_amounts: BTreeMap::from([]),
pending_boosts: BTreeMap::from([(
0,
BTreeMap::from([(id1.clone(), 1_000), (id2.clone(), 2_000)]),
)]),
pending_withdrawals: BTreeMap::from([
(id1, BTreeSet::from([0])),
(id2, BTreeSet::from([0])),
]),
},
),
];

insta::assert_json_snapshot!(val);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
source: state-chain/custom-rpc/src/lib.rs
expression: val
---
[
{
"chain": "Ethereum",
"asset": "FLIP",
"tier": 10,
"available_amount": "0x33b2e3c9fd0803ce8000000"
},
{
"chain": "Ethereum",
"asset": "FLIP",
"tier": 30,
"available_amount": "0x0"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
source: state-chain/custom-rpc/src/lib.rs
expression: val
---
[
{
"fee_tier": 10,
"chain": "Arbitrum",
"asset": "ETH",
"available_amounts": [
{
"account_id": "5C62Ck4UrFPiBtoCmeSrgF7x9yv9mn38446dhCpsi2mLHiFT",
"amount": "0x2710"
}
],
"deposits_pending_finalization": [
{
"deposit_id": 0,
"owed_amounts": [
{
"account_id": "5C62Ck4UrFPiBtoCmeSrgF7x9yv9mn38446dhCpsi2mLHiFT",
"amount": "0xc8"
},
{
"account_id": "5C7LYpP2ZH3tpKbvVvwiVe54AapxErdPBbvkYhe6y9ZBkqWt",
"amount": "0x7d0"
}
]
},
{
"deposit_id": 1,
"owed_amounts": [
{
"account_id": "5C62Ck4UrFPiBtoCmeSrgF7x9yv9mn38446dhCpsi2mLHiFT",
"amount": "0x3e8"
}
]
}
],
"pending_withdrawals": []
},
{
"fee_tier": 30,
"chain": "Bitcoin",
"asset": "BTC",
"available_amounts": [],
"deposits_pending_finalization": [
{
"deposit_id": 0,
"owed_amounts": [
{
"account_id": "5C62Ck4UrFPiBtoCmeSrgF7x9yv9mn38446dhCpsi2mLHiFT",
"amount": "0x3e8"
},
{
"account_id": "5C7LYpP2ZH3tpKbvVvwiVe54AapxErdPBbvkYhe6y9ZBkqWt",
"amount": "0x7d0"
}
]
}
],
"pending_withdrawals": [
{
"account_id": "5C62Ck4UrFPiBtoCmeSrgF7x9yv9mn38446dhCpsi2mLHiFT",
"pending_deposits": [
0
]
},
{
"account_id": "5C7LYpP2ZH3tpKbvVvwiVe54AapxErdPBbvkYhe6y9ZBkqWt",
"pending_deposits": [
0
]
}
]
}
]
34 changes: 33 additions & 1 deletion state-chain/pallets/cf-ingress-egress/src/boost_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,38 @@ where
self.available_amount.into_chain_amount()
}

pub fn get_amounts(&self) -> BTreeMap<AccountId, C::ChainAmount> {
self.amounts
.iter()
.map(|(account_id, scaled_amount)| {
(account_id.clone(), scaled_amount.into_chain_amount())
})
.collect()
}

pub fn get_pending_boosts(
&self,
) -> BTreeMap<PrewitnessedDepositId, BTreeMap<AccountId, C::ChainAmount>> {
self.pending_boosts
.iter()
.map(|(deposit_id, owed_amounts_map)| {
(
*deposit_id,
owed_amounts_map
.iter()
.map(|(account_id, scaled_amount)| {
(account_id.clone(), scaled_amount.into_chain_amount())
})
.collect(),
)
})
.collect()
}

pub fn get_pending_withdrawals(&self) -> &BTreeMap<AccountId, BTreeSet<PrewitnessedDepositId>> {
&self.pending_withdrawals
}

/// Attempt to use pool's available funds to boost up to `amount_to_boost`. Returns
/// (boosted_amount, boost_fee), where "boosted amount" is the amount provided by the pool plus
/// the boost fee. For example, in the (likely common) case of having sufficient funds in a
Expand Down Expand Up @@ -338,7 +370,7 @@ where
}

#[cfg(test)]
pub fn get_pending_boosts(&self) -> Vec<PrewitnessedDepositId> {
pub fn get_pending_boost_ids(&self) -> Vec<PrewitnessedDepositId> {
self.pending_boosts.keys().copied().collect()
}
#[cfg(test)]
Expand Down
Loading

0 comments on commit 68a5d74

Please sign in to comment.