Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feat/branch-apy
Browse files Browse the repository at this point in the history
* origin/main:
  Feat: Set pool fees (#4050)
  fix: don't egress empty all_batch calls (#4102)
  fix: don't abort broadcast if signers are unavailable (#4104)
  feat: add restricted balances to AccountInfoV2 (#4048)
  feat: use snake case for lp api method names (#4108)
  feat: add expiry block to liquidity channel event (#4111)

# Conflicts:
#	state-chain/custom-rpc/src/lib.rs
#	state-chain/runtime/src/lib.rs
#	state-chain/runtime/src/runtime_apis.rs
  • Loading branch information
syan095 committed Oct 12, 2023
2 parents ca9417c + 390e3d1 commit 30eb663
Show file tree
Hide file tree
Showing 26 changed files with 869 additions and 299 deletions.
4 changes: 2 additions & 2 deletions api/bin/chainflip-broker-api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ impl From<chainflip_api::SwapDepositAddress> for BrokerSwapDepositAddress {

#[rpc(server, client, namespace = "broker")]
pub trait Rpc {
#[method(name = "registerAccount")]
#[method(name = "register_account", aliases = ["broker_registerAccount"])]
async fn register_account(&self) -> Result<String, AnyhowRpcError>;

#[method(name = "requestSwapDepositAddress")]
#[method(name = "request_swap_deposit_address", aliases = ["broker_requestSwapDepositAddress"])]
async fn request_swap_deposit_address(
&self,
source_asset: Asset,
Expand Down
20 changes: 10 additions & 10 deletions api/bin/chainflip-lp-api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,31 +66,31 @@ pub mod rpc_types {

#[rpc(server, client, namespace = "lp")]
pub trait Rpc {
#[method(name = "registerAccount")]
#[method(name = "register_account")]
async fn register_account(&self) -> Result<Hash, AnyhowRpcError>;

#[method(name = "liquidityDeposit")]
#[method(name = "liquidity_deposit")]
async fn request_liquidity_deposit_address(
&self,
asset: Asset,
) -> Result<String, AnyhowRpcError>;

#[method(name = "registerLiquidityRefundAddress")]
#[method(name = "register_liquidity_refund_address")]
async fn register_liquidity_refund_address(
&self,
chain: ForeignChain,
address: &str,
) -> Result<Hash, AnyhowRpcError>;

#[method(name = "withdrawAsset")]
#[method(name = "withdraw_asset")]
async fn withdraw_asset(
&self,
amount: NumberOrHex,
asset: Asset,
destination_address: &str,
) -> Result<(ForeignChain, u64), AnyhowRpcError>;

#[method(name = "updateRangeOrder")]
#[method(name = "update_range_order")]
async fn update_range_order(
&self,
base_asset: Asset,
Expand All @@ -101,7 +101,7 @@ pub trait Rpc {
size: RangeOrderSize,
) -> Result<Vec<RangeOrderReturn>, AnyhowRpcError>;

#[method(name = "setRangeOrder")]
#[method(name = "set_range_order")]
async fn set_range_order(
&self,
base_asset: Asset,
Expand All @@ -111,7 +111,7 @@ pub trait Rpc {
size: RangeOrderSize,
) -> Result<Vec<RangeOrderReturn>, AnyhowRpcError>;

#[method(name = "updateLimitOrder")]
#[method(name = "update_limit_order")]
async fn update_limit_order(
&self,
sell_asset: Asset,
Expand All @@ -122,7 +122,7 @@ pub trait Rpc {
amount: AssetAmount,
) -> Result<Vec<LimitOrderReturn>, AnyhowRpcError>;

#[method(name = "setLimitOrder")]
#[method(name = "set_limit_order")]
async fn set_limit_order(
&self,
sell_asset: Asset,
Expand All @@ -132,10 +132,10 @@ pub trait Rpc {
amount: AssetAmount,
) -> Result<Vec<LimitOrderReturn>, AnyhowRpcError>;

#[method(name = "assetBalances")]
#[method(name = "asset_balances")]
async fn asset_balances(&self) -> Result<BTreeMap<Asset, u128>, AnyhowRpcError>;

#[method(name = "getOpenSwapChannels")]
#[method(name = "get_open_swap_channels")]
async fn get_open_swap_channels(&self) -> Result<OpenSwapChannels, AnyhowRpcError>;
}

Expand Down
12 changes: 4 additions & 8 deletions api/lib/src/lp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ fn collect_range_order_returns(
.filter_map(|event| match event {
state_chain_runtime::RuntimeEvent::LiquidityPools(
pallet_cf_pools::Event::RangeOrderUpdated {
increase_or_decrease,
liquidity_delta,
position_delta: Some((increase_or_decrease, liquidity_delta)),
liquidity_total,
assets_delta,
collected_fees,
Expand All @@ -62,8 +61,7 @@ pub struct LimitOrderReturn {
amount_total: AssetAmount,
collected_fees: AssetAmount,
bought_amount: AssetAmount,
increase_or_decrease: IncreaseOrDecrease,
amount_delta: AssetAmount,
position_delta: Option<(IncreaseOrDecrease, AssetAmount)>,
}

fn collect_limit_order_returns(
Expand All @@ -74,8 +72,7 @@ fn collect_limit_order_returns(
.filter_map(|event| match event {
state_chain_runtime::RuntimeEvent::LiquidityPools(
pallet_cf_pools::Event::LimitOrderUpdated {
increase_or_decrease,
amount_delta,
position_delta,
amount_total,
collected_fees,
bought_amount,
Expand All @@ -87,8 +84,7 @@ fn collect_limit_order_returns(
amount_total,
collected_fees,
bought_amount,
increase_or_decrease,
amount_delta,
position_delta,
}),
_ => None,
})
Expand Down
38 changes: 19 additions & 19 deletions bouncer/shared/lp_api_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ async function provideLiquidityAndTestAssetBalances() {
let retryCount = 0;
let ethBalance = 0;
do {
const balances = await lpApiRpc(`lp_assetBalances`, []);
const balances = await lpApiRpc(`lp_asset_balances`, []);
ethBalance = balances.Eth;
retryCount++;
if (retryCount > 14) {
Expand All @@ -60,12 +60,12 @@ async function testRegisterLiquidityRefundAddress() {
(event) => event.data.address.Eth === ethAddress,
);

const registerRefundAddress = await lpApiRpc(`lp_registerLiquidityRefundAddress`, [
const registerRefundAddress = await lpApiRpc(`lp_register_liquidity_refund_address`, [
'Ethereum',
ethAddress,
]);
if (!isValidHexHash(await registerRefundAddress)) {
throw new Error(`Unexpected lp_registerLiquidityRefundAddress result`);
throw new Error(`Unexpected lp_register_liquidity_refund_address result`);
}
await observeRefundAddressRegisteredEvent;

Expand All @@ -79,7 +79,7 @@ async function testLiquidityDeposit() {
(event) => event.data.depositAddress.Eth,
);
// TODO: This result will need to be updated after #3995 is merged
const liquidityDepositAddress = await lpApiRpc(`lp_liquidityDeposit`, ['Eth']);
const liquidityDepositAddress = await lpApiRpc(`lp_liquidity_deposit`, ['Eth']);
const liquidityDepositEvent = await observeLiquidityDepositAddressReadyEvent;

assert.strictEqual(
Expand Down Expand Up @@ -107,7 +107,7 @@ async function testLiquidityDeposit() {
async function testWithdrawAsset() {
const oldBalance = await getBalance('ETH', ethAddress);

const [asset, egressId] = await lpApiRpc(`lp_withdrawAsset`, [
const [asset, egressId] = await lpApiRpc(`lp_withdraw_asset`, [
testAssetAmount,
'Eth',
ethAddress,
Expand All @@ -120,18 +120,18 @@ async function testWithdrawAsset() {

async function testRegisterWithExistingLpAccount() {
try {
await lpApiRpc(`lp_registerAccount`, []);
throw new Error(`Unexpected lp_registerAccount result`);
await lpApiRpc(`lp_register_account`, []);
throw new Error(`Unexpected lp_register_account result`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
// This account is already registered, so the command will fail.
if (!error.message.includes('Could not register account role for account')) {
throw new Error(`Unexpected lp_registerAccount error: ${JSON.stringify(error)}`);
throw new Error(`Unexpected lp_register_account error: ${JSON.stringify(error)}`);
}
}
}

/// Test lp_setRangeOrder and lp_updateRangeOrder by minting, updating, and burning a range order.
/// Test lp_set_range_order and lp_update_range_order by minting, updating, and burning a range order.
async function testRangeOrder() {
const range = { start: 1, end: 2 };
const orderId = 74398; // Arbitrary order id so it does not interfere with other tests
Expand All @@ -143,10 +143,10 @@ async function testRangeOrder() {
};

// Cleanup after any unfinished previous test so it does not interfere with this test
await lpApiRpc(`lp_setRangeOrder`, ['Usdc', 'Eth', orderId, range, zeroAssetAmounts]);
await lpApiRpc(`lp_set_range_order`, ['Usdc', 'Eth', orderId, range, zeroAssetAmounts]);

// Mint a range order
const mintRangeOrder = await lpApiRpc(`lp_setRangeOrder`, [
const mintRangeOrder = await lpApiRpc(`lp_set_range_order`, [
'Usdc',
'Eth',
orderId,
Expand All @@ -171,7 +171,7 @@ async function testRangeOrder() {
);

// Update the range order
const updateRangeOrder = await lpApiRpc(`lp_updateRangeOrder`, [
const updateRangeOrder = await lpApiRpc(`lp_update_range_order`, [
'Usdc',
'Eth',
orderId,
Expand All @@ -197,7 +197,7 @@ async function testRangeOrder() {
);

// Burn the range order
const burnRangeOrder = await lpApiRpc(`lp_setRangeOrder`, [
const burnRangeOrder = await lpApiRpc(`lp_set_range_order`, [
'Usdc',
'Eth',
orderId,
Expand All @@ -220,22 +220,22 @@ async function testRangeOrder() {

async function testGetOpenSwapChannels() {
// TODO: Test with some SwapChannelInfo data
const openSwapChannels = await lpApiRpc(`lp_getOpenSwapChannels`, []);
const openSwapChannels = await lpApiRpc(`lp_get_open_swap_channels`, []);
assert(openSwapChannels.ethereum, `Missing ethereum swap channel info`);
assert(openSwapChannels.polkadot, `Missing polkadot swap channel info`);
assert(openSwapChannels.bitcoin, `Missing bitcoin swap channel info`);
}

/// Test lp_setLimitOrder and lp_updateLimitOrder by minting, updating, and burning a limit order.
/// Test lp_set_limit_order and lp_update_limit_order by minting, updating, and burning a limit order.
async function testLimitOrder() {
const orderId = 98432; // Arbitrary order id so it does not interfere with other tests
const tick = 2;

// Cleanup after any unfinished previous test so it does not interfere with this test
await lpApiRpc(`lp_setLimitOrder`, ['Eth', 'Usdc', orderId, tick, 0]);
await lpApiRpc(`lp_set_limit_order`, ['Eth', 'Usdc', orderId, tick, 0]);

// Mint a limit order
const mintLimitOrder = await lpApiRpc(`lp_setLimitOrder`, [
const mintLimitOrder = await lpApiRpc(`lp_set_limit_order`, [
'Eth',
'Usdc',
orderId,
Expand All @@ -255,7 +255,7 @@ async function testLimitOrder() {
);

// Update the limit order
const updateLimitOrder = await lpApiRpc(`lp_updateLimitOrder`, [
const updateLimitOrder = await lpApiRpc(`lp_update_limit_order`, [
'Eth',
'Usdc',
orderId,
Expand All @@ -276,7 +276,7 @@ async function testLimitOrder() {
);

// Burn the limit order
const burnLimitOrder = await lpApiRpc(`lp_setLimitOrder`, ['Eth', 'Usdc', orderId, tick, 0]);
const burnLimitOrder = await lpApiRpc(`lp_set_limit_order`, ['Eth', 'Usdc', orderId, tick, 0]);
assert(burnLimitOrder.length >= 1, `Empty burn limit order result`);
assert.strictEqual(
burnLimitOrder[0].increase_or_decrease,
Expand Down
27 changes: 17 additions & 10 deletions state-chain/amm/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use scale_info::TypeInfo;
use serde::{Deserialize, Serialize};
use sp_core::{U256, U512};

pub const ONE_IN_HUNDREDTH_PIPS: u32 = 1000000;
pub const ONE_IN_HUNDREDTH_PIPS: u32 = 1_000_000;
pub const MAX_LP_FEE: u32 = ONE_IN_HUNDREDTH_PIPS / 2;

/// Represents an amount of an asset, in its smallest unit i.e. Ethereum has 10^-18 precision, and
/// therefore an `Amount` with the literal value of `1` would represent 10^-18 Ethereum.
Expand All @@ -18,6 +19,12 @@ pub type SqrtPriceQ64F96 = U256;
/// The number of fractional bits used by `SqrtPriceQ64F96`.
pub const SQRT_PRICE_FRACTIONAL_BITS: u32 = 96;

#[derive(Debug)]
pub enum SetFeesError {
/// Fee must be between 0 - 50%
InvalidFeeAmount,
}

#[derive(
Debug,
Clone,
Expand Down Expand Up @@ -381,22 +388,22 @@ pub(super) fn sqrt_price_at_tick(tick: Tick) -> SqrtPriceQ64F96 {
}

/// Calculates the greatest tick value such that `sqrt_price_at_tick(tick) <= sqrt_price`
pub(super) fn tick_at_sqrt_price(sqrt_price: SqrtPriceQ64F96) -> Tick {
pub fn tick_at_sqrt_price(sqrt_price: SqrtPriceQ64F96) -> Tick {
assert!(is_sqrt_price_valid(sqrt_price));

let sqrt_price_q64f128 = sqrt_price << 32u128;

let (integer_log_2, mantissa) = {
let mut _bits_remaining = sqrt_price_q64f128;
let mut most_signifcant_bit = 0u8;
let mut most_significant_bit = 0u8;

// rustfmt chokes when formatting this macro.
// See: https://github.com/rust-lang/rustfmt/issues/5404
#[rustfmt::skip]
macro_rules! add_integer_bit {
($bit:literal, $lower_bits_mask:literal) => {
if _bits_remaining > U256::from($lower_bits_mask) {
most_signifcant_bit |= $bit;
most_significant_bit |= $bit;
_bits_remaining >>= $bit;
}
};
Expand All @@ -412,17 +419,17 @@ pub(super) fn tick_at_sqrt_price(sqrt_price: SqrtPriceQ64F96) -> Tick {
add_integer_bit!(1u8, 0x1u128);

(
// most_signifcant_bit is the log2 of sqrt_price_q64f128 as an integer. This
// converts most_signifcant_bit to the integer log2 of sqrt_price_q64f128 as an
// most_significant_bit is the log2 of sqrt_price_q64f128 as an integer. This
// converts most_significant_bit to the integer log2 of sqrt_price_q64f128 as an
// q64f128
((most_signifcant_bit as i16) + (-128i16)) as i8,
((most_significant_bit as i16) + (-128i16)) as i8,
// Calculate mantissa of sqrt_price_q64f128.
if most_signifcant_bit >= 128u8 {
if most_significant_bit >= 128u8 {
// The bits we possibly drop when right shifting don't contribute to the log2
// above the 14th fractional bit.
sqrt_price_q64f128 >> (most_signifcant_bit - 127u8)
sqrt_price_q64f128 >> (most_significant_bit - 127u8)
} else {
sqrt_price_q64f128 << (127u8 - most_signifcant_bit)
sqrt_price_q64f128 << (127u8 - most_significant_bit)
}
.as_u128(), // Conversion to u128 is safe as top 128 bits are always zero
)
Expand Down
23 changes: 20 additions & 3 deletions state-chain/amm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ use core::convert::Infallible;

use codec::{Decode, Encode};
use common::{
price_to_sqrt_price, sqrt_price_to_price, Amount, OneToZero, Order, Price, Side, SideMap,
SqrtPriceQ64F96, Tick, ZeroToOne,
price_to_sqrt_price, sqrt_price_to_price, Amount, OneToZero, Order, Price, SetFeesError, Side,
SideMap, SqrtPriceQ64F96, Tick, ZeroToOne,
};
use limit_orders::{Collected, PositionInfo};
use range_orders::Liquidity;
use scale_info::TypeInfo;
use sp_std::vec::Vec;
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};

pub mod common;
pub mod limit_orders;
Expand Down Expand Up @@ -343,4 +344,20 @@ impl<LiquidityProvider: Clone + Ord> PoolState<LiquidityProvider> {
),
})
}

#[allow(clippy::type_complexity)]
pub fn set_fees(
&mut self,
fee_hundredth_pips: u32,
) -> Result<SideMap<BTreeMap<(Tick, LiquidityProvider), (Collected, PositionInfo)>>, SetFeesError>
{
self.range_orders.set_fees(fee_hundredth_pips)?;
self.limit_orders.set_fees(fee_hundredth_pips)
}

// Returns if the pool fee is valid.
pub fn validate_fees(fee_hundredth_pips: u32) -> bool {
limit_orders::PoolState::<LiquidityProvider>::validate_fees(fee_hundredth_pips) &&
range_orders::PoolState::<LiquidityProvider>::validate_fees(fee_hundredth_pips)
}
}
Loading

0 comments on commit 30eb663

Please sign in to comment.