From 14ca06c4d5f6dab412cae2c9ba8faada0db9d503 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Fri, 20 Oct 2023 17:45:35 +0200 Subject: [PATCH 01/21] feat(custom-rpc): improve environment RPC --- state-chain/custom-rpc/src/lib.rs | 109 ++++++++++++++++++++---- state-chain/runtime/src/lib.rs | 15 ++++ state-chain/runtime/src/runtime_apis.rs | 2 + 3 files changed, 108 insertions(+), 18 deletions(-) diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 6b55f36bda..3ee906765c 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -24,7 +24,7 @@ use sp_runtime::DispatchError; use state_chain_runtime::{ chainflip::{ChainAddressConverter, Offence}, constants::common::TX_FEE_MULTIPLIER, - runtime_apis::{CustomRuntimeApi, Environment, LiquidityProviderInfo, RuntimeApiAccountInfoV2}, + runtime_apis::{CustomRuntimeApi, LiquidityProviderInfo, RuntimeApiAccountInfoV2}, }; use std::{ collections::{BTreeMap, HashMap}, @@ -178,20 +178,35 @@ impl From for RpcSwapOutput { } #[derive(Serialize, Deserialize)] -pub struct RpcEnvironment { - bitcoin_network: BitcoinNetwork, - ethereum_chain_id: cf_chains::evm::api::EvmChainId, - polkadot_genesis_hash: PolkadotHash, +pub struct BitcoinEnvironment { + pub network: BitcoinNetwork, } -impl From for RpcEnvironment { - fn from(environment: Environment) -> Self { - Self { - bitcoin_network: environment.bitcoin_network, - ethereum_chain_id: environment.ethereum_chain_id, - polkadot_genesis_hash: environment.polkadot_genesis_hash, - } - } +#[derive(Serialize, Deserialize)] +pub struct EthereumEnvironment { + pub chain_id: cf_chains::evm::api::EvmChainId, + pub contract_addresses: HashMap, +} + +#[derive(Serialize, Deserialize)] +pub struct PolkadotEnvironment { + pub genesis_hash: PolkadotHash, +} + +#[derive(Serialize, Deserialize)] +pub struct FundingEnvironment { + pub redemption_tax: NumberOrHex, + pub minimum_funding_amount: NumberOrHex, +} + +#[derive(Serialize, Deserialize)] +pub struct RpcEnvironment { + bitcoin: BitcoinEnvironment, + ethereum: EthereumEnvironment, + polkadot: PolkadotEnvironment, + minimum_deposit_amounts: HashMap>, + minimum_swap_amounts: HashMap>, + funding: FundingEnvironment, } #[rpc(server, client, namespace = "cf")] @@ -786,11 +801,69 @@ where } fn cf_environment(&self, at: Option) -> RpcResult { - self.client - .runtime_api() - .cf_environment(self.unwrap_or_best(at)) - .map_err(to_rpc_error) - .map(RpcEnvironment::from) + let runtime_api = &self.client.runtime_api(); + let hash = self.unwrap_or_best(at); + let env = runtime_api.cf_environment(hash).map_err(to_rpc_error)?; + + let mut minimum_swap_amounts = HashMap::new(); + let mut minimum_deposit_amounts = HashMap::new(); + + for asset in Asset::all() { + let swap_amount = + runtime_api.cf_min_swap_amount(hash, asset).map_err(to_rpc_error)?.into(); + minimum_swap_amounts + .entry(asset.into()) + .or_insert_with(HashMap::new) + .insert(asset, swap_amount); + let deposit_amount = + runtime_api.cf_min_deposit_amount(hash, asset).map_err(to_rpc_error)?.into(); + minimum_deposit_amounts + .entry(asset.into()) + .or_insert_with(HashMap::new) + .insert(asset, deposit_amount); + } + + Ok(RpcEnvironment { + bitcoin: BitcoinEnvironment { network: env.bitcoin_network }, + ethereum: EthereumEnvironment { + chain_id: env.ethereum_chain_id, + contract_addresses: HashMap::from([ + ( + "key_manager".into(), + format!( + "{}", + runtime_api.cf_eth_key_manager_address(hash).map_err(to_rpc_error)? + ), + ), + ( + "state_chain_gateway".into(), + format!( + "{}", + runtime_api + .cf_eth_state_chain_gateway_address(hash) + .map_err(to_rpc_error)? + ), + ), + ( + "flip_token".into(), + format!( + "{}", + runtime_api.cf_eth_flip_token_address(hash).map_err(to_rpc_error)? + ), + ), + ]), + }, + polkadot: PolkadotEnvironment { genesis_hash: env.polkadot_genesis_hash }, + minimum_deposit_amounts, + minimum_swap_amounts, + funding: FundingEnvironment { + redemption_tax: runtime_api.cf_redemption_tax(hash).map_err(to_rpc_error)?.into(), + minimum_funding_amount: runtime_api + .cf_min_funding(hash) + .map_err(to_rpc_error)? + .into(), + }, + }) } fn cf_current_compatibility_version(&self) -> RpcResult { diff --git a/state-chain/runtime/src/lib.rs b/state-chain/runtime/src/lib.rs index 3452885b4e..e2305e5aa4 100644 --- a/state-chain/runtime/src/lib.rs +++ b/state-chain/runtime/src/lib.rs @@ -1050,6 +1050,17 @@ impl_runtime_apis! { Swapping::minimum_swap_amount(asset) } + fn cf_min_deposit_amount(asset: Asset) -> AssetAmount { + use pallet_cf_ingress_egress::MinimumDeposit; + use cf_chains::assets::{eth, dot, btc}; + + match ForeignChain::from(asset) { + ForeignChain::Ethereum => MinimumDeposit::::get(eth::Asset::try_from(asset).expect("asset should convert")), + ForeignChain::Polkadot => MinimumDeposit::::get(dot::Asset::try_from(asset).expect("asset should convert")), + ForeignChain::Bitcoin => MinimumDeposit::::get(btc::Asset::try_from(asset).expect("asset should convert")).into(), + } + } + fn cf_liquidity_provider_info( account_id: AccountId, ) -> Option { @@ -1076,6 +1087,10 @@ impl_runtime_apis! { pallet_cf_account_roles::AccountRoles::::get(account_id) } + fn cf_redemption_tax() -> AssetAmount { + pallet_cf_funding::RedemptionTax::::get() + } + /// This should *not* be fully trusted as if the deposits that are pre-witnessed will definitely go through. /// This returns a list of swaps in the requested direction that are pre-witnessed in the current block. fn cf_prewitness_swaps(from: Asset, to: Asset) -> Option> { diff --git a/state-chain/runtime/src/runtime_apis.rs b/state-chain/runtime/src/runtime_apis.rs index 69fd5a98bb..68255efcb4 100644 --- a/state-chain/runtime/src/runtime_apis.rs +++ b/state-chain/runtime/src/runtime_apis.rs @@ -134,8 +134,10 @@ decl_runtime_apis!( ) -> Option, DispatchError>>; fn cf_environment() -> Environment; fn cf_min_swap_amount(asset: Asset) -> AssetAmount; + fn cf_min_deposit_amount(asset: Asset) -> AssetAmount; fn cf_prewitness_swaps(from: Asset, to: Asset) -> Option>; fn cf_liquidity_provider_info(account_id: AccountId32) -> Option; fn cf_account_role(account_id: AccountId32) -> Option; + fn cf_redemption_tax() -> AssetAmount; } ); From e2a1b86dc35c2d053e403d59a118e26aea739ae2 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Mon, 23 Oct 2023 15:40:15 +0200 Subject: [PATCH 02/21] redo --- state-chain/custom-rpc/src/lib.rs | 138 ++++++++++++------------ state-chain/runtime/src/lib.rs | 8 -- state-chain/runtime/src/runtime_apis.rs | 12 +-- 3 files changed, 69 insertions(+), 89 deletions(-) diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 3ee906765c..75a5ab4e66 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -2,10 +2,7 @@ use cf_amm::{ common::{Amount, Price, Tick}, range_orders::Liquidity, }; -use cf_chains::{ - address::AddressConverter, btc::BitcoinNetwork, dot::PolkadotHash, - eth::Address as EthereumAddress, -}; +use cf_chains::{address::AddressConverter, eth::Address as EthereumAddress}; use cf_primitives::{AccountRole, Asset, AssetAmount, ForeignChain, SemVer, SwapOutput}; use core::ops::Range; use jsonrpsee::{ @@ -178,19 +175,8 @@ impl From for RpcSwapOutput { } #[derive(Serialize, Deserialize)] -pub struct BitcoinEnvironment { - pub network: BitcoinNetwork, -} - -#[derive(Serialize, Deserialize)] -pub struct EthereumEnvironment { - pub chain_id: cf_chains::evm::api::EvmChainId, - pub contract_addresses: HashMap, -} - -#[derive(Serialize, Deserialize)] -pub struct PolkadotEnvironment { - pub genesis_hash: PolkadotHash, +pub struct IngressEgressEnvironment { + pub minimum_deposit_amounts: HashMap>, } #[derive(Serialize, Deserialize)] @@ -200,12 +186,14 @@ pub struct FundingEnvironment { } #[derive(Serialize, Deserialize)] -pub struct RpcEnvironment { - bitcoin: BitcoinEnvironment, - ethereum: EthereumEnvironment, - polkadot: PolkadotEnvironment, - minimum_deposit_amounts: HashMap>, +pub struct SwappingEnvironment { minimum_swap_amounts: HashMap>, +} + +#[derive(Serialize, Deserialize)] +pub struct RpcEnvironment { + ingress_egress: IngressEgressEnvironment, + swapping: SwappingEnvironment, funding: FundingEnvironment, } @@ -359,6 +347,21 @@ pub trait CustomApi { ) -> RpcResult>>; #[method(name = "environment")] fn cf_environment(&self, at: Option) -> RpcResult; + #[method(name = "funding_environment")] + fn cf_funding_environment( + &self, + at: Option, + ) -> RpcResult; + #[method(name = "swapping_environment")] + fn cf_swapping_environment( + &self, + at: Option, + ) -> RpcResult; + #[method(name = "ingress_egress_environment")] + fn cf_ingress_egress_environment( + &self, + at: Option, + ) -> RpcResult; #[method(name = "current_compatibility_version")] fn cf_current_compatibility_version(&self) -> RpcResult; #[method(name = "min_swap_amount")] @@ -801,12 +804,40 @@ where } fn cf_environment(&self, at: Option) -> RpcResult { + Ok(RpcEnvironment { + ingress_egress: self.cf_ingress_egress_environment(at)?, + swapping: self.cf_swapping_environment(at)?, + funding: self.cf_funding_environment(at)?, + }) + } + + fn cf_ingress_egress_environment( + &self, + at: Option, + ) -> RpcResult { let runtime_api = &self.client.runtime_api(); let hash = self.unwrap_or_best(at); - let env = runtime_api.cf_environment(hash).map_err(to_rpc_error)?; + let mut minimum_deposit_amounts = HashMap::new(); + for asset in Asset::all() { + let deposit_amount = + runtime_api.cf_min_deposit_amount(hash, asset).map_err(to_rpc_error)?.into(); + minimum_deposit_amounts + .entry(asset.into()) + .or_insert_with(HashMap::new) + .insert(asset, deposit_amount); + } + + Ok(IngressEgressEnvironment { minimum_deposit_amounts }) + } + + fn cf_swapping_environment( + &self, + at: Option, + ) -> RpcResult { + let runtime_api = &self.client.runtime_api(); + let hash = self.unwrap_or_best(at); let mut minimum_swap_amounts = HashMap::new(); - let mut minimum_deposit_amounts = HashMap::new(); for asset in Asset::all() { let swap_amount = @@ -815,54 +846,21 @@ where .entry(asset.into()) .or_insert_with(HashMap::new) .insert(asset, swap_amount); - let deposit_amount = - runtime_api.cf_min_deposit_amount(hash, asset).map_err(to_rpc_error)?.into(); - minimum_deposit_amounts - .entry(asset.into()) - .or_insert_with(HashMap::new) - .insert(asset, deposit_amount); } - Ok(RpcEnvironment { - bitcoin: BitcoinEnvironment { network: env.bitcoin_network }, - ethereum: EthereumEnvironment { - chain_id: env.ethereum_chain_id, - contract_addresses: HashMap::from([ - ( - "key_manager".into(), - format!( - "{}", - runtime_api.cf_eth_key_manager_address(hash).map_err(to_rpc_error)? - ), - ), - ( - "state_chain_gateway".into(), - format!( - "{}", - runtime_api - .cf_eth_state_chain_gateway_address(hash) - .map_err(to_rpc_error)? - ), - ), - ( - "flip_token".into(), - format!( - "{}", - runtime_api.cf_eth_flip_token_address(hash).map_err(to_rpc_error)? - ), - ), - ]), - }, - polkadot: PolkadotEnvironment { genesis_hash: env.polkadot_genesis_hash }, - minimum_deposit_amounts, - minimum_swap_amounts, - funding: FundingEnvironment { - redemption_tax: runtime_api.cf_redemption_tax(hash).map_err(to_rpc_error)?.into(), - minimum_funding_amount: runtime_api - .cf_min_funding(hash) - .map_err(to_rpc_error)? - .into(), - }, + Ok(SwappingEnvironment { minimum_swap_amounts }) + } + + fn cf_funding_environment( + &self, + at: Option, + ) -> RpcResult { + let runtime_api = &self.client.runtime_api(); + let hash = self.unwrap_or_best(at); + + Ok(FundingEnvironment { + redemption_tax: runtime_api.cf_redemption_tax(hash).map_err(to_rpc_error)?.into(), + minimum_funding_amount: runtime_api.cf_min_funding(hash).map_err(to_rpc_error)?.into(), }) } diff --git a/state-chain/runtime/src/lib.rs b/state-chain/runtime/src/lib.rs index e2305e5aa4..c00d6cfd3e 100644 --- a/state-chain/runtime/src/lib.rs +++ b/state-chain/runtime/src/lib.rs @@ -1038,14 +1038,6 @@ impl_runtime_apis! { LiquidityPools::pool_range_order_liquidity_value(base_asset, pair_asset, tick_range, liquidity) } - fn cf_environment() -> runtime_apis::Environment { - runtime_apis::Environment { - bitcoin_network: Environment::network_environment().into(), - ethereum_chain_id: Environment::ethereum_chain_id(), - polkadot_genesis_hash: Environment::polkadot_genesis_hash(), - } - } - fn cf_min_swap_amount(asset: Asset) -> AssetAmount { Swapping::minimum_swap_amount(asset) } diff --git a/state-chain/runtime/src/runtime_apis.rs b/state-chain/runtime/src/runtime_apis.rs index 68255efcb4..8d17542d80 100644 --- a/state-chain/runtime/src/runtime_apis.rs +++ b/state-chain/runtime/src/runtime_apis.rs @@ -3,9 +3,7 @@ use cf_amm::{ common::{Amount, Price, Tick}, range_orders::Liquidity, }; -use cf_chains::{ - btc::BitcoinNetwork, dot::PolkadotHash, eth::Address as EthereumAddress, ForeignChainAddress, -}; +use cf_chains::{eth::Address as EthereumAddress, ForeignChainAddress}; use cf_primitives::{ AccountRole, Asset, AssetAmount, EpochIndex, ForeignChain, SemVer, SwapOutput, }; @@ -68,13 +66,6 @@ pub struct AuctionState { pub auction_size_range: (u32, u32), } -#[derive(Encode, Decode, Eq, PartialEq, TypeInfo)] -pub struct Environment { - pub bitcoin_network: BitcoinNetwork, - pub ethereum_chain_id: cf_chains::evm::api::EvmChainId, - pub polkadot_genesis_hash: PolkadotHash, -} - #[derive(Encode, Decode, Eq, PartialEq, TypeInfo)] pub struct LiquidityProviderInfo { pub refund_addresses: Vec<(ForeignChain, Option)>, @@ -132,7 +123,6 @@ decl_runtime_apis!( tick_range: Range, liquidity: Liquidity, ) -> Option, DispatchError>>; - fn cf_environment() -> Environment; fn cf_min_swap_amount(asset: Asset) -> AssetAmount; fn cf_min_deposit_amount(asset: Asset) -> AssetAmount; fn cf_prewitness_swaps(from: Asset, to: Asset) -> Option>; From 0858939e0c858d6d627897d29938449c5a5d95c4 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Mon, 23 Oct 2023 16:51:53 +0200 Subject: [PATCH 03/21] add serialization test --- state-chain/custom-rpc/src/lib.rs | 153 ++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 75a5ab4e66..0b788ca776 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -174,6 +174,40 @@ impl From for RpcSwapOutput { } } +#[derive(Serialize, Deserialize)] +pub struct RpcAsset { + pub asset: Asset, + pub chain: ForeignChain, +} + +impl Into for Asset { + fn into(self) -> RpcAsset { + RpcAsset { asset: self, chain: self.into() } + } +} + +#[derive(Serialize, Deserialize)] +pub struct RpcPoolInfo { + pub limit_order_fee_hundredth_pips: u32, + pub range_order_fee_hundredth_pips: u32, + pub pair_asset: RpcAsset, +} + +impl From for RpcPoolInfo { + fn from(value: PoolInfo) -> Self { + Self { + limit_order_fee_hundredth_pips: value.limit_order_fee_hundredth_pips, + range_order_fee_hundredth_pips: value.range_order_fee_hundredth_pips, + pair_asset: Asset::Usdc.into(), + } + } +} + +#[derive(Serialize, Deserialize)] +pub struct PoolEnvironment { + pub fees: HashMap>, +} + #[derive(Serialize, Deserialize)] pub struct IngressEgressEnvironment { pub minimum_deposit_amounts: HashMap>, @@ -195,6 +229,7 @@ pub struct RpcEnvironment { ingress_egress: IngressEgressEnvironment, swapping: SwappingEnvironment, funding: FundingEnvironment, + pool: PoolEnvironment, } #[rpc(server, client, namespace = "cf")] @@ -362,6 +397,11 @@ pub trait CustomApi { &self, at: Option, ) -> RpcResult; + #[method(name = "pool_environment")] + fn cf_pool_environment( + &self, + at: Option, + ) -> RpcResult; #[method(name = "current_compatibility_version")] fn cf_current_compatibility_version(&self) -> RpcResult; #[method(name = "min_swap_amount")] @@ -808,6 +848,7 @@ where ingress_egress: self.cf_ingress_egress_environment(at)?, swapping: self.cf_swapping_environment(at)?, funding: self.cf_funding_environment(at)?, + pool: self.cf_pool_environment(at)?, }) } @@ -864,6 +905,25 @@ where }) } + fn cf_pool_environment( + &self, + at: Option, + ) -> RpcResult { + let mut fees = HashMap::new(); + + for asset in Asset::all() { + if asset == Asset::Usdc { + continue + } + + let info = self.cf_pool_info(asset, Asset::Usdc, at)?.expect("pool should exist"); + + fees.entry(asset.into()).or_insert_with(HashMap::new).insert(asset, info.into()); + } + + Ok(PoolEnvironment { fees }) + } + fn cf_current_compatibility_version(&self) -> RpcResult { self.client .runtime_api() @@ -1111,4 +1171,97 @@ mod test { }) ); } + + #[test] + fn test_environment_serialization() { + assert_eq!( + serde_json::to_value(&RpcEnvironment { + swapping: SwappingEnvironment { + minimum_swap_amounts: HashMap::from([ + (ForeignChain::Bitcoin, HashMap::from([(Asset::Btc, 0u32.into())])), + ( + ForeignChain::Ethereum, + HashMap::from([ + (Asset::Flip, u64::MAX.into()), + (Asset::Usdc, (u64::MAX / 2 - 1).into()), + (Asset::Eth, 0u32.into()), + ]) + ), + ]), + }, + ingress_egress: IngressEgressEnvironment { + minimum_deposit_amounts: HashMap::from([ + (ForeignChain::Bitcoin, HashMap::from([(Asset::Btc, 0u32.into())])), + ( + ForeignChain::Ethereum, + HashMap::from([ + (Asset::Flip, u64::MAX.into()), + (Asset::Usdc, (u64::MAX / 2 - 1).into()), + (Asset::Eth, 0u32.into()), + ]) + ), + ]) + }, + funding: FundingEnvironment { + redemption_tax: 0u32.into(), + minimum_funding_amount: 0u32.into(), + }, + pool: PoolEnvironment { + fees: HashMap::from([( + ForeignChain::Ethereum, + HashMap::from([( + Asset::Flip, + PoolInfo { + limit_order_fee_hundredth_pips: 0, + range_order_fee_hundredth_pips: 100, + } + .into() + ),]) + ),]) + } + }) + .unwrap(), + json!({ + "ingress_egress": { + "minimum_deposit_amounts": { + "Bitcoin": { "Btc": 0 }, + "Ethereum": { + "Eth": 0, + // TODO: u64 is still too large for JSON, we should use a string + "Flip": 18446744073709551615u64, + "Usdc": 9223372036854775806u64 + } + } + }, + "swapping": { + "minimum_swap_amounts": { + "Ethereum": { + "Eth": 0, + "Flip": 18446744073709551615u64, + "Usdc": 9223372036854775806u64 + }, + "Bitcoin": { "Btc": 0 } + } + }, + "funding": { + "redemption_tax": 0, + "minimum_funding_amount": 0 + }, + "pool": { + "fees": { + "Ethereum": { + "Flip": { + "limit_order_fee_hundredth_pips": 0, + "range_order_fee_hundredth_pips": 100, + "pair_asset": { + "asset": "Usdc", + "chain": "Ethereum" + } + } + } + } + } + }) + ); + } } From 2a11ea699da516219f94a5b9e04cc69e63e103e3 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Mon, 23 Oct 2023 17:44:44 +0200 Subject: [PATCH 04/21] update type --- state-chain/custom-rpc/src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 0b788ca776..86dc447145 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -175,14 +175,15 @@ impl From for RpcSwapOutput { } #[derive(Serialize, Deserialize)] -pub struct RpcAsset { - pub asset: Asset, - pub chain: ForeignChain, +#[serde(untagged)] +pub enum RpcAsset { + ImplicitChain { asset: Asset }, + ExplicitChain { chain: ForeignChain, asset: Asset }, } impl Into for Asset { fn into(self) -> RpcAsset { - RpcAsset { asset: self, chain: self.into() } + RpcAsset::ExplicitChain { asset: self, chain: self.into() } } } From d62db0feb9c9d1a1dcf8c0f10f3be5b7b0d2232b Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Tue, 24 Oct 2023 10:41:13 +0200 Subject: [PATCH 05/21] fix clippy --- state-chain/custom-rpc/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 0c8c7d031b..3c1aa35894 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -176,9 +176,9 @@ pub enum RpcAsset { ExplicitChain { chain: ForeignChain, asset: Asset }, } -impl Into for Asset { - fn into(self) -> RpcAsset { - RpcAsset::ExplicitChain { asset: self, chain: self.into() } +impl From for RpcAsset { + fn from(asset: Asset) -> Self { + RpcAsset::ExplicitChain { asset, chain: asset.into() } } } @@ -1162,7 +1162,7 @@ mod test { #[test] fn test_environment_serialization() { assert_eq!( - serde_json::to_value(&RpcEnvironment { + serde_json::to_value(RpcEnvironment { swapping: SwappingEnvironment { minimum_swap_amounts: HashMap::from([ (ForeignChain::Bitcoin, HashMap::from([(Asset::Btc, 0u32.into())])), From ffa449e6ecd3ba2ae3f1d1b45684925d9cbf13ca Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Tue, 24 Oct 2023 11:50:59 +0200 Subject: [PATCH 06/21] rename --- state-chain/custom-rpc/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 3c1aa35894..eb0978803e 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -200,7 +200,7 @@ impl From for RpcPoolInfo { } #[derive(Serialize, Deserialize)] -pub struct PoolEnvironment { +pub struct PoolsEnvironment { pub fees: HashMap>, } @@ -225,7 +225,7 @@ pub struct RpcEnvironment { ingress_egress: IngressEgressEnvironment, swapping: SwappingEnvironment, funding: FundingEnvironment, - pool: PoolEnvironment, + pools: PoolsEnvironment, } #[rpc(server, client, namespace = "cf")] @@ -395,7 +395,7 @@ pub trait CustomApi { fn cf_pool_environment( &self, at: Option, - ) -> RpcResult; + ) -> RpcResult; #[method(name = "current_compatibility_version")] fn cf_current_compatibility_version(&self) -> RpcResult; #[method(name = "min_swap_amount")] @@ -896,7 +896,7 @@ where fn cf_pool_environment( &self, at: Option, - ) -> RpcResult { + ) -> RpcResult { let mut fees = HashMap::new(); for asset in Asset::all() { @@ -909,7 +909,7 @@ where fees.entry(asset.into()).or_insert_with(HashMap::new).insert(asset, info.into()); } - Ok(PoolEnvironment { fees }) + Ok(PoolsEnvironment { fees }) } fn cf_current_compatibility_version(&self) -> RpcResult { @@ -1193,7 +1193,7 @@ mod test { redemption_tax: 0u32.into(), minimum_funding_amount: 0u32.into(), }, - pool: PoolEnvironment { + pools: PoolsEnvironment { fees: HashMap::from([( ForeignChain::Ethereum, HashMap::from([( From b516221794f4ead41547a4a6aa84151578a2afa2 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 24 Oct 2023 13:39:24 +0200 Subject: [PATCH 07/21] chore: use serde(flatten), more explicit conversion --- state-chain/custom-rpc/src/lib.rs | 30 ++++++++++++++---------------- state-chain/runtime/src/lib.rs | 15 ++++++++++++--- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index eb0978803e..45369e30e6 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -184,18 +184,14 @@ impl From for RpcAsset { #[derive(Serialize, Deserialize)] pub struct RpcPoolInfo { - pub limit_order_fee_hundredth_pips: u32, - pub range_order_fee_hundredth_pips: u32, + #[serde(flatten)] + pub pool_info: PoolInfo, pub pair_asset: RpcAsset, } impl From for RpcPoolInfo { - fn from(value: PoolInfo) -> Self { - Self { - limit_order_fee_hundredth_pips: value.limit_order_fee_hundredth_pips, - range_order_fee_hundredth_pips: value.range_order_fee_hundredth_pips, - pair_asset: Asset::Usdc.into(), - } + fn from(pool_info: PoolInfo) -> Self { + Self { pool_info, pair_asset: Asset::Usdc.into() } } } @@ -849,12 +845,15 @@ where let mut minimum_deposit_amounts = HashMap::new(); for asset in Asset::all() { - let deposit_amount = - runtime_api.cf_min_deposit_amount(hash, asset).map_err(to_rpc_error)?.into(); minimum_deposit_amounts - .entry(asset.into()) + .entry(ForeignChain::from(asset)) .or_insert_with(HashMap::new) - .insert(asset, deposit_amount); + .insert( + asset, + NumberOrHex::from( + runtime_api.cf_min_deposit_amount(hash, asset).map_err(to_rpc_error)?, + ), + ); } Ok(IngressEgressEnvironment { minimum_deposit_amounts }) @@ -869,12 +868,11 @@ where let mut minimum_swap_amounts = HashMap::new(); for asset in Asset::all() { - let swap_amount = - runtime_api.cf_min_swap_amount(hash, asset).map_err(to_rpc_error)?.into(); + let swap_amount = runtime_api.cf_min_swap_amount(hash, asset).map_err(to_rpc_error)?; minimum_swap_amounts .entry(asset.into()) .or_insert_with(HashMap::new) - .insert(asset, swap_amount); + .insert(asset, swap_amount.into()); } Ok(SwappingEnvironment { minimum_swap_amounts }) @@ -1234,7 +1232,7 @@ mod test { "redemption_tax": 0, "minimum_funding_amount": 0 }, - "pool": { + "pools": { "fees": { "Ethereum": { "Flip": { diff --git a/state-chain/runtime/src/lib.rs b/state-chain/runtime/src/lib.rs index 2559ac89db..57fc2ce37c 100644 --- a/state-chain/runtime/src/lib.rs +++ b/state-chain/runtime/src/lib.rs @@ -1051,9 +1051,18 @@ impl_runtime_apis! { use cf_chains::assets::{eth, dot, btc}; match ForeignChain::from(asset) { - ForeignChain::Ethereum => MinimumDeposit::::get(eth::Asset::try_from(asset).expect("asset should convert")), - ForeignChain::Polkadot => MinimumDeposit::::get(dot::Asset::try_from(asset).expect("asset should convert")), - ForeignChain::Bitcoin => MinimumDeposit::::get(btc::Asset::try_from(asset).expect("asset should convert")).into(), + ForeignChain::Ethereum => MinimumDeposit::::get( + eth::Asset::try_from(asset) + .expect("Conversion must succeed: ForeignChain checked in match clause.") + ), + ForeignChain::Polkadot => MinimumDeposit::::get( + dot::Asset::try_from(asset) + .expect("Conversion must succeed: ForeignChain checked in match clause.") + ), + ForeignChain::Bitcoin => MinimumDeposit::::get( + btc::Asset::try_from(asset) + .expect("Conversion must succeed: ForeignChain checked in match clause.") + ).into(), } } From 3e71c6f88a16c9272f26f65f329371b74b6cfade Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Tue, 24 Oct 2023 14:18:36 +0200 Subject: [PATCH 08/21] untagged --- state-chain/chains/src/address.rs | 1 + state-chain/custom-rpc/src/lib.rs | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/state-chain/chains/src/address.rs b/state-chain/chains/src/address.rs index 8e8ad5cdf6..9109b25f76 100644 --- a/state-chain/chains/src/address.rs +++ b/state-chain/chains/src/address.rs @@ -246,6 +246,7 @@ impl ToHumanreadableAddress for PolkadotAccountId { #[cfg(feature = "std")] #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] pub enum ForeignChainAddressHumanreadable { Eth(::Humanreadable), Dot(::Humanreadable), diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 45369e30e6..f3c1145930 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -1065,6 +1065,15 @@ mod test { use serde_json::json; use sp_core::H160; + /* + changing any of these serialization tests signifies a breaking change in the + API. please make sure to get approval from the product team before merging + any changes that break a serialization test. + + if approval is received and a new breaking change is introduced, please + stale the review and get a new review from someone on product. + */ + #[test] fn test_account_info_serialization() { assert_eq!( @@ -1112,9 +1121,9 @@ mod test { "Bitcoin": { "Btc": "0x0" }, }, "refund_addresses": { - "Ethereum": { "Eth" : "0x0101010101010101010101010101010101010101" }, + "Ethereum": "0x0101010101010101010101010101010101010101", "Bitcoin": null, - "Polkadot": { "Dot": "111111111111111111111111111111111HC1" } + "Polkadot": "111111111111111111111111111111111HC1" } }) ); From 0935c7f59d0783225ffa160adcbac99cb3dd94f3 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Tue, 24 Oct 2023 15:16:28 +0200 Subject: [PATCH 09/21] unimplement deserialization --- state-chain/chains/src/address.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/state-chain/chains/src/address.rs b/state-chain/chains/src/address.rs index 9109b25f76..82bcb12f0f 100644 --- a/state-chain/chains/src/address.rs +++ b/state-chain/chains/src/address.rs @@ -245,14 +245,28 @@ impl ToHumanreadableAddress for PolkadotAccountId { } #[cfg(feature = "std")] -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize)] #[serde(untagged)] +/// A type that serializes the address in a human-readable way. This can only be +/// serialized and not deserialized. +/// `deserialize` is not implemented for ForeignChainAddressHumanreadable +/// because it is not possible to deserialize a human-readable address without +/// further context around the asset and chain. pub enum ForeignChainAddressHumanreadable { Eth(::Humanreadable), Dot(::Humanreadable), Btc(::Humanreadable), } +impl<'de> Deserialize<'de> for ForeignChainAddressHumanreadable { + fn deserialize(_deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + unimplemented!("Deserialization of ForeignChainAddressHumanreadable is not implemented") + } +} + impl ToHumanreadableAddress for ForeignChainAddress { #[cfg(feature = "std")] type Humanreadable = ForeignChainAddressHumanreadable; From a1bb31d1c122778529649360ad6f52261d9f0e43 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Tue, 24 Oct 2023 17:08:41 +0200 Subject: [PATCH 10/21] fixes --- state-chain/chains/src/address.rs | 1 + state-chain/custom-rpc/src/lib.rs | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/state-chain/chains/src/address.rs b/state-chain/chains/src/address.rs index 82bcb12f0f..ea462a36bb 100644 --- a/state-chain/chains/src/address.rs +++ b/state-chain/chains/src/address.rs @@ -258,6 +258,7 @@ pub enum ForeignChainAddressHumanreadable { Btc(::Humanreadable), } +#[cfg(feature = "std")] impl<'de> Deserialize<'de> for ForeignChainAddressHumanreadable { fn deserialize(_deserializer: D) -> Result where diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index c4887e2c87..565a8e6f59 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -172,7 +172,7 @@ impl From for RpcSwapOutput { #[derive(Serialize, Deserialize)] #[serde(untagged)] pub enum RpcAsset { - ImplicitChain { asset: Asset }, + ImplicitChain(Asset), ExplicitChain { chain: ForeignChain, asset: Asset }, } @@ -197,7 +197,7 @@ impl From for RpcPoolInfo { #[derive(Serialize, Deserialize)] pub struct PoolsEnvironment { - pub fees: HashMap>, + pub fees: HashMap>>, } #[derive(Serialize, Deserialize)] @@ -905,15 +905,15 @@ where continue } - let info = self.cf_pool_info(asset, Asset::Usdc, at)?.expect("pool should exist"); + let info = self.cf_pool_info(asset, Asset::Usdc, at)?.map(Into::into); - fees.entry(asset.into()).or_insert_with(HashMap::new).insert(asset, info.into()); + fees.entry(asset.into()).or_insert_with(HashMap::new).insert(asset, info); } Ok(PoolsEnvironment { fees }) } - fn cf_environment(&self, at: Option) { + fn cf_environment(&self, at: Option) -> RpcResult { Ok(RpcEnvironment { ingress_egress: self.cf_ingress_egress_environment(at)?, swapping: self.cf_swapping_environment(at)?, @@ -1218,13 +1218,15 @@ mod test { ForeignChain::Ethereum, HashMap::from([( Asset::Flip, - PoolInfo { - limit_order_fee_hundredth_pips: 0, - range_order_fee_hundredth_pips: 100, - } - .into() - ),]) - ),]) + Some( + PoolInfo { + limit_order_fee_hundredth_pips: 0, + range_order_fee_hundredth_pips: 100, + } + .into() + ) + )]) + )]) } }) .unwrap(), From 799ff4767f0736a870feaa2729817590f1cf5056 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Tue, 24 Oct 2023 17:35:20 +0200 Subject: [PATCH 11/21] snapshot --- Cargo.lock | 21 ++++ state-chain/custom-rpc/Cargo.toml | 1 + state-chain/custom-rpc/src/lib.rs | 203 ++++++++++-------------------- 3 files changed, 86 insertions(+), 139 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6a2824d39..b32b255fc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2338,6 +2338,7 @@ dependencies = [ "cf-primitives", "futures", "hex", + "insta", "jsonrpsee 0.16.2", "pallet-cf-governance", "pallet-cf-pools", @@ -4863,6 +4864,20 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "insta" +version = "1.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d64600be34b2fcfc267740a243fa7744441bb4947a619ac4e5bb6507f35fbfc" +dependencies = [ + "console", + "lazy_static", + "linked-hash-map", + "serde", + "similar", + "yaml-rust", +] + [[package]] name = "instant" version = "0.1.12" @@ -10495,6 +10510,12 @@ dependencies = [ "wide", ] +[[package]] +name = "similar" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aeaf503862c419d66959f5d7ca015337d864e9c49485d771b732e2a20453597" + [[package]] name = "siphasher" version = "0.3.10" diff --git a/state-chain/custom-rpc/Cargo.toml b/state-chain/custom-rpc/Cargo.toml index ac1fcefb93..8670b4a30c 100644 --- a/state-chain/custom-rpc/Cargo.toml +++ b/state-chain/custom-rpc/Cargo.toml @@ -29,4 +29,5 @@ sp-runtime = { git = "https://github.com/chainflip-io/substrate.git", tag = "cha sc-client-api = { git = "https://github.com/chainflip-io/substrate.git", tag = "chainflip-monthly-2023-08+2" } [dev-dependencies] +insta = { version = "1.34.0", features = ["json"] } serde_json = "1.0.107" diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 565a8e6f59..be36847678 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -1075,7 +1075,8 @@ where mod test { use super::*; - use serde_json::json; + use insta; + use serde_json; use sp_core::H160; /* @@ -1088,16 +1089,17 @@ mod test { */ #[test] - fn test_account_info_serialization() { - assert_eq!( - serde_json::to_value(RpcAccountInfo::none(0)).unwrap(), - json!({ "role": "none", "flip_balance": "0x0" }) - ); - assert_eq!( - serde_json::to_value(RpcAccountInfo::broker(0)).unwrap(), - json!({ "role":"broker", "flip_balance": "0x0" }) - ); + fn test_no_account_serialization() { + insta::assert_json_snapshot!(serde_json::to_value(RpcAccountInfo::none(0)).unwrap()); + } + + #[test] + fn test_broker_serialization() { + insta::assert_json_snapshot!(serde_json::to_value(RpcAccountInfo::broker(0)).unwrap()); + } + #[test] + fn test_lp_serialization() { let lp = RpcAccountInfo::lp( LiquidityProviderInfo { refund_addresses: vec![ @@ -1121,26 +1123,11 @@ mod test { 0, ); - assert_eq!( - serde_json::to_value(lp).unwrap(), - json!({ - "role": "liquidity_provider", - "flip_balance": "0x0", - "balances": { - "Ethereum": { - "Flip": "0x7fffffffffffffffffffffffffffffff", - "Eth": "0xffffffffffffffffffffffffffffffff" - }, - "Bitcoin": { "Btc": "0x0" }, - }, - "refund_addresses": { - "Ethereum": "0x0101010101010101010101010101010101010101", - "Bitcoin": null, - "Polkadot": "111111111111111111111111111111111HC1" - } - }) - ); + insta::assert_json_snapshot!(serde_json::to_value(lp).unwrap()); + } + #[test] + fn test_validator_serialization() { let validator = RpcAccountInfo::validator(RuntimeApiAccountInfoV2 { balance: 10u128.pow(18), bond: 10u128.pow(18), @@ -1156,121 +1143,59 @@ mod test { apy_bp: Some(100u32), restricted_balances: BTreeMap::from_iter(vec![(H160::from([1; 20]), 10u128.pow(18))]), }); - assert_eq!( - serde_json::to_value(validator).unwrap(), - json!({ - "flip_balance": "0xde0b6b3a7640000", - "bond": "0xde0b6b3a7640000", - "bound_redeem_address": "0x0101010101010101010101010101010101010101", - "is_bidding": false, - "is_current_authority": true, - "is_current_backup": false, - "is_online": true, - "is_qualified": true, - "keyholder_epochs": [123], - "last_heartbeat": 0, - "reputation_points": 0, - "role": "validator", - "apy_bp": 100, - "restricted_balances": { - "0x0101010101010101010101010101010101010101": "0xde0b6b3a7640000" - } - }) - ); + + insta::assert_json_snapshot!(serde_json::to_value(validator).unwrap()); } #[test] fn test_environment_serialization() { - assert_eq!( - serde_json::to_value(RpcEnvironment { - swapping: SwappingEnvironment { - minimum_swap_amounts: HashMap::from([ - (ForeignChain::Bitcoin, HashMap::from([(Asset::Btc, 0u32.into())])), - ( - ForeignChain::Ethereum, - HashMap::from([ - (Asset::Flip, u64::MAX.into()), - (Asset::Usdc, (u64::MAX / 2 - 1).into()), - (Asset::Eth, 0u32.into()), - ]) - ), - ]), - }, - ingress_egress: IngressEgressEnvironment { - minimum_deposit_amounts: HashMap::from([ - (ForeignChain::Bitcoin, HashMap::from([(Asset::Btc, 0u32.into())])), - ( - ForeignChain::Ethereum, - HashMap::from([ - (Asset::Flip, u64::MAX.into()), - (Asset::Usdc, (u64::MAX / 2 - 1).into()), - (Asset::Eth, 0u32.into()), - ]) - ), - ]) - }, - funding: FundingEnvironment { - redemption_tax: 0u32.into(), - minimum_funding_amount: 0u32.into(), - }, - pools: PoolsEnvironment { - fees: HashMap::from([( + insta::assert_json_snapshot!(serde_json::to_value(RpcEnvironment { + swapping: SwappingEnvironment { + minimum_swap_amounts: HashMap::from([ + (ForeignChain::Bitcoin, HashMap::from([(Asset::Btc, 0u32.into())])), + ( ForeignChain::Ethereum, - HashMap::from([( - Asset::Flip, - Some( - PoolInfo { - limit_order_fee_hundredth_pips: 0, - range_order_fee_hundredth_pips: 100, - } - .into() - ) - )]) - )]) - } - }) - .unwrap(), - json!({ - "ingress_egress": { - "minimum_deposit_amounts": { - "Bitcoin": { "Btc": 0 }, - "Ethereum": { - "Eth": 0, - // TODO: u64 is still too large for JSON, we should use a string - "Flip": 18446744073709551615u64, - "Usdc": 9223372036854775806u64 - } - } - }, - "swapping": { - "minimum_swap_amounts": { - "Ethereum": { - "Eth": 0, - "Flip": 18446744073709551615u64, - "Usdc": 9223372036854775806u64 - }, - "Bitcoin": { "Btc": 0 } - } - }, - "funding": { - "redemption_tax": 0, - "minimum_funding_amount": 0 - }, - "pools": { - "fees": { - "Ethereum": { - "Flip": { - "limit_order_fee_hundredth_pips": 0, - "range_order_fee_hundredth_pips": 100, - "pair_asset": { - "asset": "Usdc", - "chain": "Ethereum" - } + HashMap::from([ + (Asset::Flip, u64::MAX.into()), + (Asset::Usdc, (u64::MAX / 2 - 1).into()), + (Asset::Eth, 0u32.into()), + ]) + ), + ]), + }, + ingress_egress: IngressEgressEnvironment { + minimum_deposit_amounts: HashMap::from([ + (ForeignChain::Bitcoin, HashMap::from([(Asset::Btc, 0u32.into())])), + ( + ForeignChain::Ethereum, + HashMap::from([ + (Asset::Flip, u64::MAX.into()), + (Asset::Usdc, (u64::MAX / 2 - 1).into()), + (Asset::Eth, 0u32.into()), + ]) + ), + ]) + }, + funding: FundingEnvironment { + redemption_tax: 0u32.into(), + minimum_funding_amount: 0u32.into(), + }, + pools: PoolsEnvironment { + fees: HashMap::from([( + ForeignChain::Ethereum, + HashMap::from([( + Asset::Flip, + Some( + PoolInfo { + limit_order_fee_hundredth_pips: 0, + range_order_fee_hundredth_pips: 100, } - } - } - } - }) - ); + .into() + ) + )]) + )]) + } + }) + .unwrap()); } } From b58c6c2de27a67f95e8ead185b307a4d6c3b45b1 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Tue, 24 Oct 2023 17:40:20 +0200 Subject: [PATCH 12/21] add snapshots --- ...ustom_rpc__test__broker_serialization.snap | 8 ++++ ..._rpc__test__environment_serialization.snap | 48 +++++++++++++++++++ .../custom_rpc__test__lp_serialization.snap | 22 +++++++++ ...m_rpc__test__no_account_serialization.snap | 8 ++++ ...om_rpc__test__validator_serialization.snap | 24 ++++++++++ 5 files changed, 110 insertions(+) create mode 100644 state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap create mode 100644 state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap create mode 100644 state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap create mode 100644 state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap create mode 100644 state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap new file mode 100644 index 0000000000..39fa7b3932 --- /dev/null +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap @@ -0,0 +1,8 @@ +--- +source: state-chain/custom-rpc/src/lib.rs +expression: "serde_json::to_value(RpcAccountInfo::broker(0)).unwrap()" +--- +{ + "flip_balance": "0x0", + "role": "broker" +} diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap new file mode 100644 index 0000000000..e7a5ca6525 --- /dev/null +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap @@ -0,0 +1,48 @@ +--- +source: state-chain/custom-rpc/src/lib.rs +expression: "serde_json::to_value(RpcEnvironment {\n swapping: SwappingEnvironment {\n minimum_swap_amounts: HashMap::from([(ForeignChain::Bitcoin,\n HashMap::from([(Asset::Btc, 0u32.into())])),\n (ForeignChain::Ethereum,\n HashMap::from([(Asset::Flip, u64::MAX.into()),\n (Asset::Usdc, (u64::MAX / 2 - 1).into()),\n (Asset::Eth, 0u32.into())]))]),\n },\n ingress_egress: IngressEgressEnvironment {\n minimum_deposit_amounts: HashMap::from([(ForeignChain::Bitcoin,\n HashMap::from([(Asset::Btc, 0u32.into())])),\n (ForeignChain::Ethereum,\n HashMap::from([(Asset::Flip, u64::MAX.into()),\n (Asset::Usdc, (u64::MAX / 2 - 1).into()),\n (Asset::Eth, 0u32.into())]))]),\n },\n funding: FundingEnvironment {\n redemption_tax: 0u32.into(),\n minimum_funding_amount: 0u32.into(),\n },\n pools: PoolsEnvironment {\n fees: HashMap::from([(ForeignChain::Ethereum,\n HashMap::from([(Asset::Flip,\n Some(PoolInfo {\n limit_order_fee_hundredth_pips: 0,\n range_order_fee_hundredth_pips: 100,\n }.into()))]))]),\n },\n }).unwrap()" +--- +{ + "funding": { + "minimum_funding_amount": 0, + "redemption_tax": 0 + }, + "ingress_egress": { + "minimum_deposit_amounts": { + "Bitcoin": { + "Btc": 0 + }, + "Ethereum": { + "Eth": 0, + "Flip": 18446744073709551615, + "Usdc": 9223372036854775806 + } + } + }, + "pools": { + "fees": { + "Ethereum": { + "Flip": { + "limit_order_fee_hundredth_pips": 0, + "pair_asset": { + "asset": "Usdc", + "chain": "Ethereum" + }, + "range_order_fee_hundredth_pips": 100 + } + } + } + }, + "swapping": { + "minimum_swap_amounts": { + "Bitcoin": { + "Btc": 0 + }, + "Ethereum": { + "Eth": 0, + "Flip": 18446744073709551615, + "Usdc": 9223372036854775806 + } + } + } +} diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap new file mode 100644 index 0000000000..7602b057f3 --- /dev/null +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap @@ -0,0 +1,22 @@ +--- +source: state-chain/custom-rpc/src/lib.rs +expression: "serde_json::to_value(lp).unwrap()" +--- +{ + "balances": { + "Bitcoin": { + "Btc": "0x0" + }, + "Ethereum": { + "Eth": "0xffffffffffffffffffffffffffffffff", + "Flip": "0x7fffffffffffffffffffffffffffffff" + } + }, + "flip_balance": "0x0", + "refund_addresses": { + "Bitcoin": null, + "Ethereum": "0x0101010101010101010101010101010101010101", + "Polkadot": "111111111111111111111111111111111HC1" + }, + "role": "liquidity_provider" +} diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap new file mode 100644 index 0000000000..46c938e87f --- /dev/null +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap @@ -0,0 +1,8 @@ +--- +source: state-chain/custom-rpc/src/lib.rs +expression: "serde_json::to_value(RpcAccountInfo::none(0)).unwrap()" +--- +{ + "flip_balance": "0x0", + "role": "none" +} diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap new file mode 100644 index 0000000000..fd123d02c2 --- /dev/null +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap @@ -0,0 +1,24 @@ +--- +source: state-chain/custom-rpc/src/lib.rs +expression: "serde_json::to_value(validator).unwrap()" +--- +{ + "apy_bp": 100, + "bond": "0xde0b6b3a7640000", + "bound_redeem_address": "0x0101010101010101010101010101010101010101", + "flip_balance": "0xde0b6b3a7640000", + "is_bidding": false, + "is_current_authority": true, + "is_current_backup": false, + "is_online": true, + "is_qualified": true, + "keyholder_epochs": [ + 123 + ], + "last_heartbeat": 0, + "reputation_points": 0, + "restricted_balances": { + "0x0101010101010101010101010101010101010101": "0xde0b6b3a7640000" + }, + "role": "validator" +} From ec79ab5a1690b0b444e3e69deecde983c83c32a5 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Wed, 25 Oct 2023 10:37:18 +0200 Subject: [PATCH 13/21] fix clippy --- state-chain/custom-rpc/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index be36847678..7766c9a25b 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -1075,8 +1075,6 @@ where mod test { use super::*; - use insta; - use serde_json; use sp_core::H160; /* From 676519f65e3a943a88d01a53fb0195f7f634f15f Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Wed, 25 Oct 2023 10:55:40 +0200 Subject: [PATCH 14/21] serialize to string --- state-chain/custom-rpc/src/lib.rs | 35 ++++++++------ ...ustom_rpc__test__broker_serialization.snap | 7 +-- ..._rpc__test__environment_serialization.snap | 47 +------------------ .../custom_rpc__test__lp_serialization.snap | 21 +-------- ...m_rpc__test__no_account_serialization.snap | 7 +-- ...om_rpc__test__validator_serialization.snap | 23 +-------- 6 files changed, 30 insertions(+), 110 deletions(-) diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 7766c9a25b..f1a95d9ca2 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -1088,12 +1088,16 @@ mod test { #[test] fn test_no_account_serialization() { - insta::assert_json_snapshot!(serde_json::to_value(RpcAccountInfo::none(0)).unwrap()); + insta::assert_json_snapshot!( + serde_json::to_string_pretty(&RpcAccountInfo::none(0)).unwrap() + ); } #[test] fn test_broker_serialization() { - insta::assert_json_snapshot!(serde_json::to_value(RpcAccountInfo::broker(0)).unwrap()); + insta::assert_json_snapshot!( + serde_json::to_string_pretty(&RpcAccountInfo::broker(0)).unwrap() + ); } #[test] @@ -1121,7 +1125,7 @@ mod test { 0, ); - insta::assert_json_snapshot!(serde_json::to_value(lp).unwrap()); + insta::assert_json_snapshot!(serde_json::to_string_pretty(&lp).unwrap()); } #[test] @@ -1142,12 +1146,12 @@ mod test { restricted_balances: BTreeMap::from_iter(vec![(H160::from([1; 20]), 10u128.pow(18))]), }); - insta::assert_json_snapshot!(serde_json::to_value(validator).unwrap()); + insta::assert_json_snapshot!(serde_json::to_string_pretty(&validator).unwrap()); } #[test] fn test_environment_serialization() { - insta::assert_json_snapshot!(serde_json::to_value(RpcEnvironment { + let env = RpcEnvironment { swapping: SwappingEnvironment { minimum_swap_amounts: HashMap::from([ (ForeignChain::Bitcoin, HashMap::from([(Asset::Btc, 0u32.into())])), @@ -1157,7 +1161,7 @@ mod test { (Asset::Flip, u64::MAX.into()), (Asset::Usdc, (u64::MAX / 2 - 1).into()), (Asset::Eth, 0u32.into()), - ]) + ]), ), ]), }, @@ -1170,9 +1174,9 @@ mod test { (Asset::Flip, u64::MAX.into()), (Asset::Usdc, (u64::MAX / 2 - 1).into()), (Asset::Eth, 0u32.into()), - ]) + ]), ), - ]) + ]), }, funding: FundingEnvironment { redemption_tax: 0u32.into(), @@ -1188,12 +1192,13 @@ mod test { limit_order_fee_hundredth_pips: 0, range_order_fee_hundredth_pips: 100, } - .into() - ) - )]) - )]) - } - }) - .unwrap()); + .into(), + ), + )]), + )]), + }, + }; + + insta::assert_json_snapshot!(serde_json::to_string_pretty(&env).unwrap()); } } diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap index 39fa7b3932..b99a4cae9d 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap @@ -1,8 +1,5 @@ --- source: state-chain/custom-rpc/src/lib.rs -expression: "serde_json::to_value(RpcAccountInfo::broker(0)).unwrap()" +expression: "serde_json::to_string_pretty(&RpcAccountInfo::broker(0)).unwrap()" --- -{ - "flip_balance": "0x0", - "role": "broker" -} +"{\n \"role\": \"broker\",\n \"flip_balance\": \"0x0\"\n}" diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap index e7a5ca6525..9efe4b9349 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap @@ -1,48 +1,5 @@ --- source: state-chain/custom-rpc/src/lib.rs -expression: "serde_json::to_value(RpcEnvironment {\n swapping: SwappingEnvironment {\n minimum_swap_amounts: HashMap::from([(ForeignChain::Bitcoin,\n HashMap::from([(Asset::Btc, 0u32.into())])),\n (ForeignChain::Ethereum,\n HashMap::from([(Asset::Flip, u64::MAX.into()),\n (Asset::Usdc, (u64::MAX / 2 - 1).into()),\n (Asset::Eth, 0u32.into())]))]),\n },\n ingress_egress: IngressEgressEnvironment {\n minimum_deposit_amounts: HashMap::from([(ForeignChain::Bitcoin,\n HashMap::from([(Asset::Btc, 0u32.into())])),\n (ForeignChain::Ethereum,\n HashMap::from([(Asset::Flip, u64::MAX.into()),\n (Asset::Usdc, (u64::MAX / 2 - 1).into()),\n (Asset::Eth, 0u32.into())]))]),\n },\n funding: FundingEnvironment {\n redemption_tax: 0u32.into(),\n minimum_funding_amount: 0u32.into(),\n },\n pools: PoolsEnvironment {\n fees: HashMap::from([(ForeignChain::Ethereum,\n HashMap::from([(Asset::Flip,\n Some(PoolInfo {\n limit_order_fee_hundredth_pips: 0,\n range_order_fee_hundredth_pips: 100,\n }.into()))]))]),\n },\n }).unwrap()" +expression: "serde_json::to_string_pretty(&env).unwrap()" --- -{ - "funding": { - "minimum_funding_amount": 0, - "redemption_tax": 0 - }, - "ingress_egress": { - "minimum_deposit_amounts": { - "Bitcoin": { - "Btc": 0 - }, - "Ethereum": { - "Eth": 0, - "Flip": 18446744073709551615, - "Usdc": 9223372036854775806 - } - } - }, - "pools": { - "fees": { - "Ethereum": { - "Flip": { - "limit_order_fee_hundredth_pips": 0, - "pair_asset": { - "asset": "Usdc", - "chain": "Ethereum" - }, - "range_order_fee_hundredth_pips": 100 - } - } - } - }, - "swapping": { - "minimum_swap_amounts": { - "Bitcoin": { - "Btc": 0 - }, - "Ethereum": { - "Eth": 0, - "Flip": 18446744073709551615, - "Usdc": 9223372036854775806 - } - } - } -} +"{\n \"ingress_egress\": {\n \"minimum_deposit_amounts\": {\n \"Ethereum\": {\n \"Usdc\": 9223372036854775806,\n \"Eth\": 0,\n \"Flip\": 18446744073709551615\n },\n \"Bitcoin\": {\n \"Btc\": 0\n }\n }\n },\n \"swapping\": {\n \"minimum_swap_amounts\": {\n \"Bitcoin\": {\n \"Btc\": 0\n },\n \"Ethereum\": {\n \"Usdc\": 9223372036854775806,\n \"Flip\": 18446744073709551615,\n \"Eth\": 0\n }\n }\n },\n \"funding\": {\n \"redemption_tax\": 0,\n \"minimum_funding_amount\": 0\n },\n \"pools\": {\n \"fees\": {\n \"Ethereum\": {\n \"Flip\": {\n \"limit_order_fee_hundredth_pips\": 0,\n \"range_order_fee_hundredth_pips\": 100,\n \"pair_asset\": {\n \"chain\": \"Ethereum\",\n \"asset\": \"Usdc\"\n }\n }\n }\n }\n }\n}" diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap index 7602b057f3..b2a599958a 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap @@ -1,22 +1,5 @@ --- source: state-chain/custom-rpc/src/lib.rs -expression: "serde_json::to_value(lp).unwrap()" +expression: "serde_json::to_string_pretty(&lp).unwrap()" --- -{ - "balances": { - "Bitcoin": { - "Btc": "0x0" - }, - "Ethereum": { - "Eth": "0xffffffffffffffffffffffffffffffff", - "Flip": "0x7fffffffffffffffffffffffffffffff" - } - }, - "flip_balance": "0x0", - "refund_addresses": { - "Bitcoin": null, - "Ethereum": "0x0101010101010101010101010101010101010101", - "Polkadot": "111111111111111111111111111111111HC1" - }, - "role": "liquidity_provider" -} +"{\n \"role\": \"liquidity_provider\",\n \"balances\": {\n \"Ethereum\": {\n \"Flip\": \"0x7fffffffffffffffffffffffffffffff\",\n \"Eth\": \"0xffffffffffffffffffffffffffffffff\"\n },\n \"Bitcoin\": {\n \"Btc\": \"0x0\"\n }\n },\n \"refund_addresses\": {\n \"Polkadot\": \"111111111111111111111111111111111HC1\",\n \"Bitcoin\": null,\n \"Ethereum\": \"0x0101010101010101010101010101010101010101\"\n },\n \"flip_balance\": \"0x0\"\n}" diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap index 46c938e87f..98afac8fd8 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap @@ -1,8 +1,5 @@ --- source: state-chain/custom-rpc/src/lib.rs -expression: "serde_json::to_value(RpcAccountInfo::none(0)).unwrap()" +expression: "serde_json::to_string_pretty(&RpcAccountInfo::none(0)).unwrap()" --- -{ - "flip_balance": "0x0", - "role": "none" -} +"{\n \"role\": \"none\",\n \"flip_balance\": \"0x0\"\n}" diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap index fd123d02c2..fe9ae62d82 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap @@ -1,24 +1,5 @@ --- source: state-chain/custom-rpc/src/lib.rs -expression: "serde_json::to_value(validator).unwrap()" +expression: "serde_json::to_string_pretty(&validator).unwrap()" --- -{ - "apy_bp": 100, - "bond": "0xde0b6b3a7640000", - "bound_redeem_address": "0x0101010101010101010101010101010101010101", - "flip_balance": "0xde0b6b3a7640000", - "is_bidding": false, - "is_current_authority": true, - "is_current_backup": false, - "is_online": true, - "is_qualified": true, - "keyholder_epochs": [ - 123 - ], - "last_heartbeat": 0, - "reputation_points": 0, - "restricted_balances": { - "0x0101010101010101010101010101010101010101": "0xde0b6b3a7640000" - }, - "role": "validator" -} +"{\n \"role\": \"validator\",\n \"flip_balance\": \"0xde0b6b3a7640000\",\n \"bond\": \"0xde0b6b3a7640000\",\n \"last_heartbeat\": 0,\n \"reputation_points\": 0,\n \"keyholder_epochs\": [\n 123\n ],\n \"is_current_authority\": true,\n \"is_current_backup\": false,\n \"is_qualified\": true,\n \"is_online\": true,\n \"is_bidding\": false,\n \"bound_redeem_address\": \"0x0101010101010101010101010101010101010101\",\n \"apy_bp\": 100,\n \"restricted_balances\": {\n \"0x0101010101010101010101010101010101010101\": \"0xde0b6b3a7640000\"\n }\n}" From e7b5c9af58a88bc30e1e9162edcc092fb4346cb9 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Wed, 25 Oct 2023 11:01:44 +0200 Subject: [PATCH 15/21] change serialization --- state-chain/custom-rpc/src/lib.rs | 14 +++++--------- .../custom_rpc__test__broker_serialization.snap | 4 ++-- ...ustom_rpc__test__environment_serialization.snap | 4 ++-- .../custom_rpc__test__lp_serialization.snap | 4 ++-- ...custom_rpc__test__no_account_serialization.snap | 4 ++-- .../custom_rpc__test__validator_serialization.snap | 4 ++-- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index f1a95d9ca2..7035f3566c 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -1088,16 +1088,12 @@ mod test { #[test] fn test_no_account_serialization() { - insta::assert_json_snapshot!( - serde_json::to_string_pretty(&RpcAccountInfo::none(0)).unwrap() - ); + insta::assert_display_snapshot!(serde_json::to_value(RpcAccountInfo::none(0)).unwrap()); } #[test] fn test_broker_serialization() { - insta::assert_json_snapshot!( - serde_json::to_string_pretty(&RpcAccountInfo::broker(0)).unwrap() - ); + insta::assert_display_snapshot!(serde_json::to_value(RpcAccountInfo::broker(0)).unwrap()); } #[test] @@ -1125,7 +1121,7 @@ mod test { 0, ); - insta::assert_json_snapshot!(serde_json::to_string_pretty(&lp).unwrap()); + insta::assert_display_snapshot!(serde_json::to_value(lp).unwrap()); } #[test] @@ -1146,7 +1142,7 @@ mod test { restricted_balances: BTreeMap::from_iter(vec![(H160::from([1; 20]), 10u128.pow(18))]), }); - insta::assert_json_snapshot!(serde_json::to_string_pretty(&validator).unwrap()); + insta::assert_display_snapshot!(serde_json::to_value(validator).unwrap()); } #[test] @@ -1199,6 +1195,6 @@ mod test { }, }; - insta::assert_json_snapshot!(serde_json::to_string_pretty(&env).unwrap()); + insta::assert_display_snapshot!(serde_json::to_value(env).unwrap()); } } diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap index b99a4cae9d..39803b3c8c 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__broker_serialization.snap @@ -1,5 +1,5 @@ --- source: state-chain/custom-rpc/src/lib.rs -expression: "serde_json::to_string_pretty(&RpcAccountInfo::broker(0)).unwrap()" +expression: "serde_json::to_value(RpcAccountInfo::broker(0)).unwrap()" --- -"{\n \"role\": \"broker\",\n \"flip_balance\": \"0x0\"\n}" +{"flip_balance":"0x0","role":"broker"} diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap index 9efe4b9349..8205804679 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap @@ -1,5 +1,5 @@ --- source: state-chain/custom-rpc/src/lib.rs -expression: "serde_json::to_string_pretty(&env).unwrap()" +expression: "serde_json::to_value(env).unwrap()" --- -"{\n \"ingress_egress\": {\n \"minimum_deposit_amounts\": {\n \"Ethereum\": {\n \"Usdc\": 9223372036854775806,\n \"Eth\": 0,\n \"Flip\": 18446744073709551615\n },\n \"Bitcoin\": {\n \"Btc\": 0\n }\n }\n },\n \"swapping\": {\n \"minimum_swap_amounts\": {\n \"Bitcoin\": {\n \"Btc\": 0\n },\n \"Ethereum\": {\n \"Usdc\": 9223372036854775806,\n \"Flip\": 18446744073709551615,\n \"Eth\": 0\n }\n }\n },\n \"funding\": {\n \"redemption_tax\": 0,\n \"minimum_funding_amount\": 0\n },\n \"pools\": {\n \"fees\": {\n \"Ethereum\": {\n \"Flip\": {\n \"limit_order_fee_hundredth_pips\": 0,\n \"range_order_fee_hundredth_pips\": 100,\n \"pair_asset\": {\n \"chain\": \"Ethereum\",\n \"asset\": \"Usdc\"\n }\n }\n }\n }\n }\n}" +{"funding":{"minimum_funding_amount":0,"redemption_tax":0},"ingress_egress":{"minimum_deposit_amounts":{"Bitcoin":{"Btc":0},"Ethereum":{"Eth":0,"Flip":18446744073709551615,"Usdc":9223372036854775806}}},"pools":{"fees":{"Ethereum":{"Flip":{"limit_order_fee_hundredth_pips":0,"pair_asset":{"asset":"Usdc","chain":"Ethereum"},"range_order_fee_hundredth_pips":100}}}},"swapping":{"minimum_swap_amounts":{"Bitcoin":{"Btc":0},"Ethereum":{"Eth":0,"Flip":18446744073709551615,"Usdc":9223372036854775806}}}} diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap index b2a599958a..e42c71605f 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__lp_serialization.snap @@ -1,5 +1,5 @@ --- source: state-chain/custom-rpc/src/lib.rs -expression: "serde_json::to_string_pretty(&lp).unwrap()" +expression: "serde_json::to_value(lp).unwrap()" --- -"{\n \"role\": \"liquidity_provider\",\n \"balances\": {\n \"Ethereum\": {\n \"Flip\": \"0x7fffffffffffffffffffffffffffffff\",\n \"Eth\": \"0xffffffffffffffffffffffffffffffff\"\n },\n \"Bitcoin\": {\n \"Btc\": \"0x0\"\n }\n },\n \"refund_addresses\": {\n \"Polkadot\": \"111111111111111111111111111111111HC1\",\n \"Bitcoin\": null,\n \"Ethereum\": \"0x0101010101010101010101010101010101010101\"\n },\n \"flip_balance\": \"0x0\"\n}" +{"balances":{"Bitcoin":{"Btc":"0x0"},"Ethereum":{"Eth":"0xffffffffffffffffffffffffffffffff","Flip":"0x7fffffffffffffffffffffffffffffff"}},"flip_balance":"0x0","refund_addresses":{"Bitcoin":null,"Ethereum":"0x0101010101010101010101010101010101010101","Polkadot":"111111111111111111111111111111111HC1"},"role":"liquidity_provider"} diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap index 98afac8fd8..c360439549 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__no_account_serialization.snap @@ -1,5 +1,5 @@ --- source: state-chain/custom-rpc/src/lib.rs -expression: "serde_json::to_string_pretty(&RpcAccountInfo::none(0)).unwrap()" +expression: "serde_json::to_value(RpcAccountInfo::none(0)).unwrap()" --- -"{\n \"role\": \"none\",\n \"flip_balance\": \"0x0\"\n}" +{"flip_balance":"0x0","role":"none"} diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap index fe9ae62d82..8634b5ed60 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__validator_serialization.snap @@ -1,5 +1,5 @@ --- source: state-chain/custom-rpc/src/lib.rs -expression: "serde_json::to_string_pretty(&validator).unwrap()" +expression: "serde_json::to_value(validator).unwrap()" --- -"{\n \"role\": \"validator\",\n \"flip_balance\": \"0xde0b6b3a7640000\",\n \"bond\": \"0xde0b6b3a7640000\",\n \"last_heartbeat\": 0,\n \"reputation_points\": 0,\n \"keyholder_epochs\": [\n 123\n ],\n \"is_current_authority\": true,\n \"is_current_backup\": false,\n \"is_qualified\": true,\n \"is_online\": true,\n \"is_bidding\": false,\n \"bound_redeem_address\": \"0x0101010101010101010101010101010101010101\",\n \"apy_bp\": 100,\n \"restricted_balances\": {\n \"0x0101010101010101010101010101010101010101\": \"0xde0b6b3a7640000\"\n }\n}" +{"apy_bp":100,"bond":"0xde0b6b3a7640000","bound_redeem_address":"0x0101010101010101010101010101010101010101","flip_balance":"0xde0b6b3a7640000","is_bidding":false,"is_current_authority":true,"is_current_backup":false,"is_online":true,"is_qualified":true,"keyholder_epochs":[123],"last_heartbeat":0,"reputation_points":0,"restricted_balances":{"0x0101010101010101010101010101010101010101":"0xde0b6b3a7640000"},"role":"validator"} From 332a39a2690257cfad54c2e04728358c5abd05fb Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Wed, 25 Oct 2023 11:38:52 +0200 Subject: [PATCH 16/21] delete file --- api/bin/chainflip-ingress-egress-tracker/start.sh | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100755 api/bin/chainflip-ingress-egress-tracker/start.sh diff --git a/api/bin/chainflip-ingress-egress-tracker/start.sh b/api/bin/chainflip-ingress-egress-tracker/start.sh deleted file mode 100755 index 1d7d836b27..0000000000 --- a/api/bin/chainflip-ingress-egress-tracker/start.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# export RUST_LOG=info -export ETH_WS_ENDPOINT=ws://10.2.2.91:8546/ -export ETH_HTTP_ENDPOINT=http://10.2.2.91:8545/ -export DOT_WS_ENDPOINT=ws://backspin-dot.staging:80/ -export DOT_HTTP_ENDPOINT=http://backspin-dot.staging:80/ -export SC_WS_ENDPOINT=ws://backspin-rpc.staging:80/ -export BTC_ENDPOINT=http://backspin-btc.staging:80/ -export BTC_USERNAME=flip -export BTC_PASSWORD=flip - -cargo run From a97569806f78119c49d66d85b205dc80facd186d Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Wed, 25 Oct 2023 14:21:54 +0200 Subject: [PATCH 17/21] safer serialization --- state-chain/custom-rpc/src/lib.rs | 66 +++++++++---------- state-chain/custom-rpc/src/safety.rs | 52 +++++++++++++++ ..._rpc__test__environment_serialization.snap | 2 +- 3 files changed, 86 insertions(+), 34 deletions(-) create mode 100644 state-chain/custom-rpc/src/safety.rs diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 7035f3566c..7548ea1538 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -18,10 +18,10 @@ use jsonrpsee::{ }; use pallet_cf_governance::GovCallHash; use pallet_cf_pools::{AssetsMap, PoolInfo, PoolLiquidity, PoolOrders, UnidirectionalPoolDepth}; +use safety::SafeNumberOrHex; use sc_client_api::{BlockchainEvents, HeaderBackend}; use serde::{Deserialize, Serialize}; use sp_api::BlockT; -use sp_rpc::number::NumberOrHex; use sp_runtime::DispatchError; use state_chain_runtime::{ chainflip::Offence, @@ -34,23 +34,25 @@ use std::{ sync::Arc, }; +mod safety; + #[derive(Serialize, Deserialize)] #[serde(tag = "role", rename_all = "snake_case")] pub enum RpcAccountInfo { None { - flip_balance: NumberOrHex, + flip_balance: SafeNumberOrHex, }, Broker { - flip_balance: NumberOrHex, + flip_balance: SafeNumberOrHex, }, LiquidityProvider { - balances: HashMap>, + balances: HashMap>, refund_addresses: HashMap>, - flip_balance: NumberOrHex, + flip_balance: SafeNumberOrHex, }, Validator { - flip_balance: NumberOrHex, - bond: NumberOrHex, + flip_balance: SafeNumberOrHex, + bond: SafeNumberOrHex, last_heartbeat: u32, reputation_points: i32, keyholder_epochs: Vec, @@ -61,7 +63,7 @@ pub enum RpcAccountInfo { is_bidding: bool, bound_redeem_address: Option, apy_bp: Option, - restricted_balances: BTreeMap, + restricted_balances: BTreeMap, }, } @@ -120,8 +122,8 @@ impl RpcAccountInfo { #[derive(Serialize, Deserialize)] pub struct RpcAccountInfoV2 { - pub balance: NumberOrHex, - pub bond: NumberOrHex, + pub balance: SafeNumberOrHex, + pub bond: SafeNumberOrHex, pub last_heartbeat: u32, pub reputation_points: i32, pub keyholder_epochs: Vec, @@ -148,23 +150,23 @@ pub struct RpcAuctionState { blocks_per_epoch: u32, current_epoch_started_at: u32, redemption_period_as_percentage: u8, - min_funding: NumberOrHex, + min_funding: SafeNumberOrHex, auction_size_range: (u32, u32), } #[derive(Serialize, Deserialize)] pub struct RpcSwapOutput { // Intermediary amount, if there's any - pub intermediary: Option, + pub intermediary: Option, // Final output of the swap - pub output: NumberOrHex, + pub output: SafeNumberOrHex, } impl From for RpcSwapOutput { fn from(swap_output: SwapOutput) -> Self { Self { - intermediary: swap_output.intermediary.map(NumberOrHex::from), - output: NumberOrHex::from(swap_output.output), + intermediary: swap_output.intermediary.map(Into::into), + output: swap_output.output.into(), } } } @@ -202,18 +204,18 @@ pub struct PoolsEnvironment { #[derive(Serialize, Deserialize)] pub struct IngressEgressEnvironment { - pub minimum_deposit_amounts: HashMap>, + pub minimum_deposit_amounts: HashMap>, } #[derive(Serialize, Deserialize)] pub struct FundingEnvironment { - pub redemption_tax: NumberOrHex, - pub minimum_funding_amount: NumberOrHex, + pub redemption_tax: SafeNumberOrHex, + pub minimum_funding_amount: SafeNumberOrHex, } #[derive(Serialize, Deserialize)] pub struct SwappingEnvironment { - minimum_swap_amounts: HashMap>, + minimum_swap_amounts: HashMap>, } #[derive(Serialize, Deserialize)] @@ -255,7 +257,7 @@ pub trait CustomApi { fn cf_auction_parameters(&self, at: Option) -> RpcResult<(u32, u32)>; #[method(name = "min_funding")] - fn cf_min_funding(&self, at: Option) -> RpcResult; + fn cf_min_funding(&self, at: Option) -> RpcResult; #[method(name = "current_epoch")] fn cf_current_epoch(&self, at: Option) -> RpcResult; #[method(name = "epoch_duration")] @@ -266,17 +268,17 @@ pub trait CustomApi { fn cf_authority_emission_per_block( &self, at: Option, - ) -> RpcResult; + ) -> RpcResult; #[method(name = "backup_emission_per_block")] fn cf_backup_emission_per_block( &self, at: Option, - ) -> RpcResult; + ) -> RpcResult; #[method(name = "flip_supply")] fn cf_flip_supply( &self, at: Option, - ) -> RpcResult<(NumberOrHex, NumberOrHex)>; + ) -> RpcResult<(SafeNumberOrHex, SafeNumberOrHex)>; #[method(name = "accounts")] fn cf_accounts( &self, @@ -322,7 +324,7 @@ pub trait CustomApi { &self, from: Asset, to: Asset, - amount: NumberOrHex, + amount: SafeNumberOrHex, at: Option, ) -> RpcResult; #[method(name = "required_asset_ratio_for_range_order")] @@ -509,7 +511,7 @@ where .cf_auction_parameters(self.unwrap_or_best(at)) .map_err(to_rpc_error) } - fn cf_min_funding(&self, at: Option<::Hash>) -> RpcResult { + fn cf_min_funding(&self, at: Option<::Hash>) -> RpcResult { self.client .runtime_api() .cf_min_funding(self.unwrap_or_best(at)) @@ -537,7 +539,7 @@ where fn cf_authority_emission_per_block( &self, at: Option<::Hash>, - ) -> RpcResult { + ) -> RpcResult { self.client .runtime_api() .cf_authority_emission_per_block(self.unwrap_or_best(at)) @@ -547,7 +549,7 @@ where fn cf_backup_emission_per_block( &self, at: Option<::Hash>, - ) -> RpcResult { + ) -> RpcResult { self.client .runtime_api() .cf_backup_emission_per_block(self.unwrap_or_best(at)) @@ -557,7 +559,7 @@ where fn cf_flip_supply( &self, at: Option<::Hash>, - ) -> RpcResult<(NumberOrHex, NumberOrHex)> { + ) -> RpcResult<(SafeNumberOrHex, SafeNumberOrHex)> { self.client .runtime_api() .cf_flip_supply(self.unwrap_or_best(at)) @@ -721,7 +723,7 @@ where &self, from: Asset, to: Asset, - amount: NumberOrHex, + amount: SafeNumberOrHex, at: Option, ) -> RpcResult { self.client @@ -730,7 +732,7 @@ where self.unwrap_or_best(at), from, to, - cf_utilities::try_parse_number_or_hex(amount).and_then(|amount| { + amount.try_into().and_then(|amount| { if amount == 0 { Err(anyhow::anyhow!("Swap input amount cannot be zero.")) } else { @@ -853,9 +855,7 @@ where .or_insert_with(HashMap::new) .insert( asset, - NumberOrHex::from( - runtime_api.cf_min_deposit_amount(hash, asset).map_err(to_rpc_error)?, - ), + runtime_api.cf_min_deposit_amount(hash, asset).map_err(to_rpc_error)?.into(), ); } diff --git a/state-chain/custom-rpc/src/safety.rs b/state-chain/custom-rpc/src/safety.rs new file mode 100644 index 0000000000..f9d86b129b --- /dev/null +++ b/state-chain/custom-rpc/src/safety.rs @@ -0,0 +1,52 @@ +use anyhow::anyhow; +use serde::{Deserialize, Serialize}; +use sp_core::U256; +use sp_rpc::number::NumberOrHex; + +pub struct SafeNumberOrHex(NumberOrHex); + +impl Serialize for SafeNumberOrHex { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self.0 { + NumberOrHex::Number(n) if n >= 2u64.pow(53) => U256::from(n).serialize(serializer), + NumberOrHex::Number(n) => n.serialize(serializer), + NumberOrHex::Hex(n) => n.serialize(serializer), + } + } +} + +impl<'de> Deserialize<'de> for SafeNumberOrHex { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Ok(SafeNumberOrHex(NumberOrHex::deserialize(deserializer)?)) + } +} + +macro_rules! impl_safe_number_or_hex { + ( $( $int:ident ),+ ) => { + $( + impl From<$int> for SafeNumberOrHex { + fn from(value: $int) -> Self { + SafeNumberOrHex(value.into()) + } + } + )+ + } +} + +impl_safe_number_or_hex!(u32, u64, u128); + +impl TryInto for SafeNumberOrHex { + type Error = anyhow::Error; + + fn try_into(self) -> Result { + u128::try_from(self.0).map_err(|_| { + anyhow!("Error parsing amount. Please use a valid number or hex string as input.") + }) + } +} diff --git a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap index 8205804679..436ee8b949 100644 --- a/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap +++ b/state-chain/custom-rpc/src/snapshots/custom_rpc__test__environment_serialization.snap @@ -2,4 +2,4 @@ source: state-chain/custom-rpc/src/lib.rs expression: "serde_json::to_value(env).unwrap()" --- -{"funding":{"minimum_funding_amount":0,"redemption_tax":0},"ingress_egress":{"minimum_deposit_amounts":{"Bitcoin":{"Btc":0},"Ethereum":{"Eth":0,"Flip":18446744073709551615,"Usdc":9223372036854775806}}},"pools":{"fees":{"Ethereum":{"Flip":{"limit_order_fee_hundredth_pips":0,"pair_asset":{"asset":"Usdc","chain":"Ethereum"},"range_order_fee_hundredth_pips":100}}}},"swapping":{"minimum_swap_amounts":{"Bitcoin":{"Btc":0},"Ethereum":{"Eth":0,"Flip":18446744073709551615,"Usdc":9223372036854775806}}}} +{"funding":{"minimum_funding_amount":0,"redemption_tax":0},"ingress_egress":{"minimum_deposit_amounts":{"Bitcoin":{"Btc":0},"Ethereum":{"Eth":0,"Flip":"0xffffffffffffffff","Usdc":"0x7ffffffffffffffe"}}},"pools":{"fees":{"Ethereum":{"Flip":{"limit_order_fee_hundredth_pips":0,"pair_asset":{"asset":"Usdc","chain":"Ethereum"},"range_order_fee_hundredth_pips":100}}}},"swapping":{"minimum_swap_amounts":{"Bitcoin":{"Btc":0},"Ethereum":{"Eth":0,"Flip":"0xffffffffffffffff","Usdc":"0x7ffffffffffffffe"}}}} From 076c45e4e87ad4ada4f14f4a83b36ca13f8b4bee Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Wed, 25 Oct 2023 19:18:14 +0200 Subject: [PATCH 18/21] safer number or hex --- Cargo.lock | 2 + state-chain/custom-rpc/Cargo.toml | 2 +- state-chain/custom-rpc/src/lib.rs | 56 +++++++++-------- state-chain/custom-rpc/src/safety.rs | 52 ---------------- utilities/Cargo.toml | 3 + utilities/src/with_std.rs | 1 + utilities/src/with_std/rpc.rs | 91 ++++++++++++++++++++++++++++ 7 files changed, 125 insertions(+), 82 deletions(-) delete mode 100644 state-chain/custom-rpc/src/safety.rs create mode 100644 utilities/src/with_std/rpc.rs diff --git a/Cargo.lock b/Cargo.lock index b32b255fc7..5605fd7e06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13177,6 +13177,8 @@ dependencies = [ "reqwest", "scopeguard", "serde", + "serde_json", + "sp-core 21.0.0 (git+https://github.com/chainflip-io/substrate.git?tag=chainflip-monthly-2023-08+2)", "sp-rpc", "tempfile", "tokio", diff --git a/state-chain/custom-rpc/Cargo.toml b/state-chain/custom-rpc/Cargo.toml index 8670b4a30c..cc6b7406a4 100644 --- a/state-chain/custom-rpc/Cargo.toml +++ b/state-chain/custom-rpc/Cargo.toml @@ -30,4 +30,4 @@ sc-client-api = { git = "https://github.com/chainflip-io/substrate.git", tag = " [dev-dependencies] insta = { version = "1.34.0", features = ["json"] } -serde_json = "1.0.107" +serde_json = "1.0" diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 7548ea1538..77a2076837 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -9,6 +9,7 @@ use cf_chains::{ use cf_primitives::{ AccountRole, Asset, AssetAmount, ForeignChain, NetworkEnvironment, SemVer, SwapOutput, }; +use cf_utilities::rpc::NumberOrHex; use core::ops::Range; use jsonrpsee::{ core::RpcResult, @@ -18,7 +19,6 @@ use jsonrpsee::{ }; use pallet_cf_governance::GovCallHash; use pallet_cf_pools::{AssetsMap, PoolInfo, PoolLiquidity, PoolOrders, UnidirectionalPoolDepth}; -use safety::SafeNumberOrHex; use sc_client_api::{BlockchainEvents, HeaderBackend}; use serde::{Deserialize, Serialize}; use sp_api::BlockT; @@ -34,25 +34,23 @@ use std::{ sync::Arc, }; -mod safety; - #[derive(Serialize, Deserialize)] #[serde(tag = "role", rename_all = "snake_case")] pub enum RpcAccountInfo { None { - flip_balance: SafeNumberOrHex, + flip_balance: NumberOrHex, }, Broker { - flip_balance: SafeNumberOrHex, + flip_balance: NumberOrHex, }, LiquidityProvider { - balances: HashMap>, + balances: HashMap>, refund_addresses: HashMap>, - flip_balance: SafeNumberOrHex, + flip_balance: NumberOrHex, }, Validator { - flip_balance: SafeNumberOrHex, - bond: SafeNumberOrHex, + flip_balance: NumberOrHex, + bond: NumberOrHex, last_heartbeat: u32, reputation_points: i32, keyholder_epochs: Vec, @@ -63,7 +61,7 @@ pub enum RpcAccountInfo { is_bidding: bool, bound_redeem_address: Option, apy_bp: Option, - restricted_balances: BTreeMap, + restricted_balances: BTreeMap, }, } @@ -122,8 +120,8 @@ impl RpcAccountInfo { #[derive(Serialize, Deserialize)] pub struct RpcAccountInfoV2 { - pub balance: SafeNumberOrHex, - pub bond: SafeNumberOrHex, + pub balance: NumberOrHex, + pub bond: NumberOrHex, pub last_heartbeat: u32, pub reputation_points: i32, pub keyholder_epochs: Vec, @@ -150,16 +148,16 @@ pub struct RpcAuctionState { blocks_per_epoch: u32, current_epoch_started_at: u32, redemption_period_as_percentage: u8, - min_funding: SafeNumberOrHex, + min_funding: NumberOrHex, auction_size_range: (u32, u32), } #[derive(Serialize, Deserialize)] pub struct RpcSwapOutput { // Intermediary amount, if there's any - pub intermediary: Option, + pub intermediary: Option, // Final output of the swap - pub output: SafeNumberOrHex, + pub output: NumberOrHex, } impl From for RpcSwapOutput { @@ -204,18 +202,18 @@ pub struct PoolsEnvironment { #[derive(Serialize, Deserialize)] pub struct IngressEgressEnvironment { - pub minimum_deposit_amounts: HashMap>, + pub minimum_deposit_amounts: HashMap>, } #[derive(Serialize, Deserialize)] pub struct FundingEnvironment { - pub redemption_tax: SafeNumberOrHex, - pub minimum_funding_amount: SafeNumberOrHex, + pub redemption_tax: NumberOrHex, + pub minimum_funding_amount: NumberOrHex, } #[derive(Serialize, Deserialize)] pub struct SwappingEnvironment { - minimum_swap_amounts: HashMap>, + minimum_swap_amounts: HashMap>, } #[derive(Serialize, Deserialize)] @@ -257,7 +255,7 @@ pub trait CustomApi { fn cf_auction_parameters(&self, at: Option) -> RpcResult<(u32, u32)>; #[method(name = "min_funding")] - fn cf_min_funding(&self, at: Option) -> RpcResult; + fn cf_min_funding(&self, at: Option) -> RpcResult; #[method(name = "current_epoch")] fn cf_current_epoch(&self, at: Option) -> RpcResult; #[method(name = "epoch_duration")] @@ -268,17 +266,17 @@ pub trait CustomApi { fn cf_authority_emission_per_block( &self, at: Option, - ) -> RpcResult; + ) -> RpcResult; #[method(name = "backup_emission_per_block")] fn cf_backup_emission_per_block( &self, at: Option, - ) -> RpcResult; + ) -> RpcResult; #[method(name = "flip_supply")] fn cf_flip_supply( &self, at: Option, - ) -> RpcResult<(SafeNumberOrHex, SafeNumberOrHex)>; + ) -> RpcResult<(NumberOrHex, NumberOrHex)>; #[method(name = "accounts")] fn cf_accounts( &self, @@ -324,7 +322,7 @@ pub trait CustomApi { &self, from: Asset, to: Asset, - amount: SafeNumberOrHex, + amount: NumberOrHex, at: Option, ) -> RpcResult; #[method(name = "required_asset_ratio_for_range_order")] @@ -511,7 +509,7 @@ where .cf_auction_parameters(self.unwrap_or_best(at)) .map_err(to_rpc_error) } - fn cf_min_funding(&self, at: Option<::Hash>) -> RpcResult { + fn cf_min_funding(&self, at: Option<::Hash>) -> RpcResult { self.client .runtime_api() .cf_min_funding(self.unwrap_or_best(at)) @@ -539,7 +537,7 @@ where fn cf_authority_emission_per_block( &self, at: Option<::Hash>, - ) -> RpcResult { + ) -> RpcResult { self.client .runtime_api() .cf_authority_emission_per_block(self.unwrap_or_best(at)) @@ -549,7 +547,7 @@ where fn cf_backup_emission_per_block( &self, at: Option<::Hash>, - ) -> RpcResult { + ) -> RpcResult { self.client .runtime_api() .cf_backup_emission_per_block(self.unwrap_or_best(at)) @@ -559,7 +557,7 @@ where fn cf_flip_supply( &self, at: Option<::Hash>, - ) -> RpcResult<(SafeNumberOrHex, SafeNumberOrHex)> { + ) -> RpcResult<(NumberOrHex, NumberOrHex)> { self.client .runtime_api() .cf_flip_supply(self.unwrap_or_best(at)) @@ -723,7 +721,7 @@ where &self, from: Asset, to: Asset, - amount: SafeNumberOrHex, + amount: NumberOrHex, at: Option, ) -> RpcResult { self.client diff --git a/state-chain/custom-rpc/src/safety.rs b/state-chain/custom-rpc/src/safety.rs deleted file mode 100644 index f9d86b129b..0000000000 --- a/state-chain/custom-rpc/src/safety.rs +++ /dev/null @@ -1,52 +0,0 @@ -use anyhow::anyhow; -use serde::{Deserialize, Serialize}; -use sp_core::U256; -use sp_rpc::number::NumberOrHex; - -pub struct SafeNumberOrHex(NumberOrHex); - -impl Serialize for SafeNumberOrHex { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self.0 { - NumberOrHex::Number(n) if n >= 2u64.pow(53) => U256::from(n).serialize(serializer), - NumberOrHex::Number(n) => n.serialize(serializer), - NumberOrHex::Hex(n) => n.serialize(serializer), - } - } -} - -impl<'de> Deserialize<'de> for SafeNumberOrHex { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - Ok(SafeNumberOrHex(NumberOrHex::deserialize(deserializer)?)) - } -} - -macro_rules! impl_safe_number_or_hex { - ( $( $int:ident ),+ ) => { - $( - impl From<$int> for SafeNumberOrHex { - fn from(value: $int) -> Self { - SafeNumberOrHex(value.into()) - } - } - )+ - } -} - -impl_safe_number_or_hex!(u32, u64, u128); - -impl TryInto for SafeNumberOrHex { - type Error = anyhow::Error; - - fn try_into(self) -> Result { - u128::try_from(self.0).map_err(|_| { - anyhow!("Error parsing amount. Please use a valid number or hex string as input.") - }) - } -} diff --git a/utilities/Cargo.toml b/utilities/Cargo.toml index 8097be5312..68b22e350a 100644 --- a/utilities/Cargo.toml +++ b/utilities/Cargo.toml @@ -31,6 +31,7 @@ tracing-subscriber = { version = "0.3", features = [ ], optional = true } pin-project = { version = "1.0.12", optional = true } warp = { version = "0.3.5", optional = true } +sp-core = { git = "https://github.com/chainflip-io/substrate.git", tag = "chainflip-monthly-2023-08+2", optional = true } sp-rpc = { git = "https://github.com/chainflip-io/substrate.git", tag = "chainflip-monthly-2023-08+2", optional = true } num-traits = { version = "0.2", optional = true } scopeguard = { version = "1.2.0" } @@ -43,6 +44,7 @@ regex = { version = "1", optional = true } url = { version = "2.4", optional = true } [dev-dependencies] +serde_json = "1.0" tempfile = "3.7.0" reqwest = { version = "0.11.4", features = ["rustls-tls"] } @@ -65,6 +67,7 @@ std = [ 'dep:tracing', 'dep:tracing-subscriber', 'dep:warp', + 'dep:sp-core', 'dep:sp-rpc', 'dep:num-traits', 'dep:jsonrpsee', diff --git a/utilities/src/with_std.rs b/utilities/src/with_std.rs index 6951598a11..ef51b74e11 100644 --- a/utilities/src/with_std.rs +++ b/utilities/src/with_std.rs @@ -16,6 +16,7 @@ pub mod unending_stream; pub use unending_stream::UnendingStream; pub mod logging; pub mod redact_endpoint_secret; +pub mod rpc; pub mod serde_helpers; mod cached_stream; diff --git a/utilities/src/with_std/rpc.rs b/utilities/src/with_std/rpc.rs new file mode 100644 index 0000000000..57ae093aee --- /dev/null +++ b/utilities/src/with_std/rpc.rs @@ -0,0 +1,91 @@ +use anyhow::anyhow; +use serde::{Deserialize, Serialize}; +use sp_core::U256; + +#[derive(Debug, PartialEq, Eq, Deserialize)] +#[serde(untagged)] +pub enum NumberOrHex { + Number(u64), + Hex(U256), +} + +impl Serialize for NumberOrHex { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + // JS numbers are 64-bit floats, so we need to use a string for numbers larger than 2^53 + &Self::Number(n) if n >= 2u64.pow(53) => U256::from(n).serialize(serializer), + Self::Number(n) => n.serialize(serializer), + Self::Hex(n) => n.serialize(serializer), + } + } +} + +macro_rules! impl_safe_number { + ( $( $int:ident ),+ ) => { + $( + impl From<$int> for NumberOrHex { + fn from(value: $int) -> Self { + Self::Number(value.into()) + } + } + )+ + } +} + +impl_safe_number!(u32, u64); + +macro_rules! impl_safe_hex { + ( $( $int:ident ),+ ) => { + $( + impl From<$int> for NumberOrHex { + fn from(value: $int) -> Self { + Self::Hex(value.into()) + } + } + )+ + } +} + +impl_safe_hex!(u128, U256); + +impl TryInto for NumberOrHex { + type Error = anyhow::Error; + + fn try_into(self) -> Result { + match self { + Self::Number(n) => Ok(n.into()), + Self::Hex(n) => n.try_into().map_err(|_| { + anyhow!("Error parsing amount. Please use a valid number or hex string as input.") + }), + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + fn assert_deser(string: &str, value: NumberOrHex) { + assert_eq!(serde_json::to_string(&value).unwrap(), string); + assert_eq!(serde_json::from_str::(string).unwrap(), value); + } + + #[test] + fn test_serialization() { + assert_deser("\"0x20000000000000\"", NumberOrHex::Hex(2u64.pow(53).into())); + assert_deser("9007199254740991", NumberOrHex::Number(2u64.pow(53) - 1)); + assert_deser( + "\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"", + NumberOrHex::Hex(U256::MAX), + ); + assert_deser(r#""0x1234""#, NumberOrHex::Hex(0x1234.into())); + assert_deser(r#""0x0""#, NumberOrHex::Hex(0.into())); + assert_deser(r#"5"#, NumberOrHex::Number(5)); + assert_deser(r#"10000"#, NumberOrHex::Number(10000)); + assert_deser(r#"0"#, NumberOrHex::Number(0)); + assert_deser(r#"1000000000000"#, NumberOrHex::Number(1000000000000)); + } +} From 3f4cddca2fe1aa93b856964143ae82fca48f07c8 Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Wed, 25 Oct 2023 20:36:04 +0200 Subject: [PATCH 19/21] feat: replace NumberOrHex --- api/bin/chainflip-broker-api/src/main.rs | 2 +- api/bin/chainflip-lp-api/src/main.rs | 4 +- state-chain/custom-rpc/src/lib.rs | 17 ++++---- utilities/src/with_std.rs | 2 +- utilities/src/with_std/rpc.rs | 41 ++++++++++++++----- .../with_std/serde_helpers/number_or_hex.rs | 2 +- 6 files changed, 46 insertions(+), 22 deletions(-) diff --git a/api/bin/chainflip-broker-api/src/main.rs b/api/bin/chainflip-broker-api/src/main.rs index 07f89a109d..5f20e9e0f5 100644 --- a/api/bin/chainflip-broker-api/src/main.rs +++ b/api/bin/chainflip-broker-api/src/main.rs @@ -1,4 +1,5 @@ use cf_utilities::{ + rpc::NumberOrHex, task_scope::{task_scope, Scope}, AnyhowRpcError, }; @@ -12,7 +13,6 @@ use clap::Parser; use futures::FutureExt; use jsonrpsee::{core::async_trait, proc_macros::rpc, server::ServerBuilder}; use serde::{Deserialize, Serialize}; -use sp_rpc::number::NumberOrHex; use std::path::PathBuf; use tracing::log; diff --git a/api/bin/chainflip-lp-api/src/main.rs b/api/bin/chainflip-lp-api/src/main.rs index bd3e859dd8..70a79eb1fe 100644 --- a/api/bin/chainflip-lp-api/src/main.rs +++ b/api/bin/chainflip-lp-api/src/main.rs @@ -1,4 +1,5 @@ use cf_utilities::{ + rpc::NumberOrHex, task_scope::{task_scope, Scope}, try_parse_number_or_hex, AnyhowRpcError, }; @@ -17,7 +18,6 @@ use futures::FutureExt; use jsonrpsee::{core::async_trait, proc_macros::rpc, server::ServerBuilder}; use pallet_cf_pools::{IncreaseOrDecrease, OrderId, RangeOrderSize}; use rpc_types::{OpenSwapChannels, OrderIdJson, RangeOrderSizeJson}; -use sp_rpc::number::NumberOrHex; use std::{collections::BTreeMap, ops::Range, path::PathBuf}; use tracing::log; @@ -25,10 +25,10 @@ use tracing::log; pub mod rpc_types { use super::*; use anyhow::anyhow; + use cf_utilities::rpc::NumberOrHex; use chainflip_api::queries::SwapChannelInfo; use pallet_cf_pools::AssetsMap; use serde::{Deserialize, Serialize}; - use sp_rpc::number::NumberOrHex; #[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub struct OrderIdJson(NumberOrHex); diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 77a2076837..0ed7c25159 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -730,13 +730,16 @@ where self.unwrap_or_best(at), from, to, - amount.try_into().and_then(|amount| { - if amount == 0 { - Err(anyhow::anyhow!("Swap input amount cannot be zero.")) - } else { - Ok(amount) - } - })?, + amount + .try_into() + .and_then(|amount| { + if amount == 0 { + Err("Swap input amount cannot be zero.") + } else { + Ok(amount) + } + }) + .map_err(|str| anyhow::anyhow!(str))?, ) .map_err(to_rpc_error) .and_then(|r| { diff --git a/utilities/src/with_std.rs b/utilities/src/with_std.rs index ef51b74e11..231b9c34fe 100644 --- a/utilities/src/with_std.rs +++ b/utilities/src/with_std.rs @@ -4,7 +4,7 @@ use futures::{stream, Stream}; use jsonrpsee::types::{error::CALL_EXECUTION_FAILED_CODE, ErrorObjectOwned}; #[doc(hidden)] pub use lazy_format::lazy_format as internal_lazy_format; -use sp_rpc::number::NumberOrHex; +use rpc::NumberOrHex; pub mod future_map; pub mod loop_select; diff --git a/utilities/src/with_std/rpc.rs b/utilities/src/with_std/rpc.rs index 57ae093aee..cc3afb5d88 100644 --- a/utilities/src/with_std/rpc.rs +++ b/utilities/src/with_std/rpc.rs @@ -1,8 +1,7 @@ -use anyhow::anyhow; use serde::{Deserialize, Serialize}; use sp_core::U256; -#[derive(Debug, PartialEq, Eq, Deserialize)] +#[derive(Debug, PartialEq, Eq, Deserialize, Copy, Clone)] #[serde(untagged)] pub enum NumberOrHex { Number(u64), @@ -51,15 +50,24 @@ macro_rules! impl_safe_hex { impl_safe_hex!(u128, U256); -impl TryInto for NumberOrHex { - type Error = anyhow::Error; +impl TryFrom for u128 { + type Error = &'static str; - fn try_into(self) -> Result { - match self { - Self::Number(n) => Ok(n.into()), - Self::Hex(n) => n.try_into().map_err(|_| { - anyhow!("Error parsing amount. Please use a valid number or hex string as input.") - }), + fn try_from(value: NumberOrHex) -> Result { + match value { + NumberOrHex::Number(n) => Ok(n.into()), + NumberOrHex::Hex(n) => u128::try_from(n), + } + } +} + +impl TryFrom for u64 { + type Error = &'static str; + + fn try_from(value: NumberOrHex) -> Result { + match value { + NumberOrHex::Number(n) => Ok(n), + NumberOrHex::Hex(n) => u64::try_from(n), } } } @@ -88,4 +96,17 @@ mod test { assert_deser(r#"0"#, NumberOrHex::Number(0)); assert_deser(r#"1000000000000"#, NumberOrHex::Number(1000000000000)); } + + #[test] + fn test_conversions() { + assert_eq!(u128::try_from(NumberOrHex::Hex(u128::MAX.into())).unwrap(), u128::MAX); + assert!(u128::try_from(NumberOrHex::Hex(U256::MAX / 2)).is_err()); + + assert_eq!(u64::try_from(NumberOrHex::Hex(u64::MAX.into())).unwrap(), u64::MAX); + assert_eq!(u64::try_from(NumberOrHex::Number(u64::MAX.into())).unwrap(), u64::MAX); + assert!(u64::try_from(NumberOrHex::Hex((u128::MAX / 2).into())).is_err()); + + assert_eq!(u128::try_from(NumberOrHex::Number(0)).unwrap(), 0); + assert_eq!(u128::try_from(NumberOrHex::Hex(U256::zero())).unwrap(), 0); + } } diff --git a/utilities/src/with_std/serde_helpers/number_or_hex.rs b/utilities/src/with_std/serde_helpers/number_or_hex.rs index 3c20486d33..9253f132ef 100644 --- a/utilities/src/with_std/serde_helpers/number_or_hex.rs +++ b/utilities/src/with_std/serde_helpers/number_or_hex.rs @@ -12,8 +12,8 @@ //! bar: u128, //! } /// ``` +use crate::rpc::NumberOrHex; use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; -use sp_rpc::number::NumberOrHex; pub fn serialize(value: &T, serializer: S) -> Result where From f07829b3f3b623c2aa257ef3d2b31d826a04db1c Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Thu, 26 Oct 2023 17:32:11 +0200 Subject: [PATCH 20/21] code review suggestion --- utilities/src/with_std.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/src/with_std.rs b/utilities/src/with_std.rs index 231b9c34fe..b9c65e0981 100644 --- a/utilities/src/with_std.rs +++ b/utilities/src/with_std.rs @@ -54,7 +54,7 @@ pub fn clean_hex_address>>(address_str: &str) -> Result anyhow::Result { u128::try_from(amount).map_err(|_| { - anyhow!("Error parsing amount. Please use a valid number or hex string as input.") + anyhow!("Error parsing amount to u128. Please use a valid number or hex string as input.") }) } From bcf0b8c58d716723e7c35cb10d43c20c9e862d6e Mon Sep 17 00:00:00 2001 From: Andrew Dibble Date: Thu, 26 Oct 2023 18:00:49 +0200 Subject: [PATCH 21/21] thank you clippy --- utilities/src/with_std/rpc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/src/with_std/rpc.rs b/utilities/src/with_std/rpc.rs index cc3afb5d88..a415b6e995 100644 --- a/utilities/src/with_std/rpc.rs +++ b/utilities/src/with_std/rpc.rs @@ -103,7 +103,7 @@ mod test { assert!(u128::try_from(NumberOrHex::Hex(U256::MAX / 2)).is_err()); assert_eq!(u64::try_from(NumberOrHex::Hex(u64::MAX.into())).unwrap(), u64::MAX); - assert_eq!(u64::try_from(NumberOrHex::Number(u64::MAX.into())).unwrap(), u64::MAX); + assert_eq!(u64::try_from(NumberOrHex::Number(u64::MAX)).unwrap(), u64::MAX); assert!(u64::try_from(NumberOrHex::Hex((u128::MAX / 2).into())).is_err()); assert_eq!(u128::try_from(NumberOrHex::Number(0)).unwrap(), 0);