Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Caviarnine v1 Adapter v1]: Optimize fees for opening positions. #9

Merged
merged 1 commit into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions packages/caviarnine-v1-adapter-v1/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ pub mod adapter {
}

let (receipt, change_x, change_y) =
pool.add_liquidity(bucket_x, bucket_y, positions);
pool.add_liquidity(bucket_x, bucket_y, positions.clone());

let receipt_global_id = {
let resource_address = receipt.resource_address();
Expand All @@ -483,14 +483,11 @@ pub mod adapter {

let adapter_specific_information =
CaviarnineV1AdapterSpecificInformation {
bin_contributions: pool
.get_redemption_bin_values(
receipt_global_id.local_id().clone(),
)
bin_contributions: positions
.into_iter()
.map(|(tick, amount_x, amount_y)| {
.map(|(bin, amount_x, amount_y)| {
(
tick,
bin,
ResourceIndexedData {
resource_x: amount_x,
resource_y: amount_y,
Expand Down
293 changes: 293 additions & 0 deletions tests/tests/caviarnine_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1466,3 +1466,296 @@ fn user_resources_are_contributed_in_full_when_oracle_price_is_lower_than_pool_p

Ok(())
}

#[test]
fn bin_amounts_reported_on_receipt_match_whats_reported_by_caviarnine(
) -> Result<(), RuntimeError> {
// Arrange
let Environment {
environment: ref mut env,
mut caviarnine_v1,
resources,
..
} = ScryptoTestEnv::new_with_configuration(Configuration {
maximum_allowed_relative_price_difference: dec!(0.05),
..Default::default()
})?;

let user_resource = resources.bitcoin;
let pool = caviarnine_v1.pools.bitcoin;

let [user_resource_bucket, xrd_bucket] =
[user_resource, XRD].map(|resource| {
ResourceManager(resource)
.mint_fungible(dec!(100), env)
.unwrap()
});

// Act
let OpenLiquidityPositionOutput {
pool_units,
adapter_specific_information,
..
} = caviarnine_v1.adapter.open_liquidity_position(
pool.try_into().unwrap(),
(user_resource_bucket, xrd_bucket),
env,
)?;

// Assert
let mut caviarnine_reported_redemption_value = pool
.get_redemption_bin_values(
pool_units
.non_fungible_local_ids(env)?
.first()
.unwrap()
.clone(),
env,
)?;
caviarnine_reported_redemption_value.sort_by(|a, b| a.0.cmp(&b.0));
let adapter_reported_redemption_value = adapter_specific_information
.as_typed::<CaviarnineV1AdapterSpecificInformation>()
.unwrap()
.bin_contributions;

assert_eq!(
caviarnine_reported_redemption_value.len(),
adapter_reported_redemption_value.len(),
);

for (
i,
(
caviarnine_reported_bin,
caviarnine_reported_amount_x,
caviarnine_reported_amount_y,
),
) in caviarnine_reported_redemption_value.into_iter().enumerate()
{
let Some(ResourceIndexedData {
resource_x: adapter_reported_amount_x,
resource_y: adapter_reported_amount_y,
}) = adapter_reported_redemption_value
.get(&caviarnine_reported_bin)
.copied()
else {
panic!(
"Bin {} does not have an entry in the adapter data",
caviarnine_reported_bin
)
};

assert_eq!(
round_down_to_5_decimal_places(caviarnine_reported_amount_x),
round_down_to_5_decimal_places(adapter_reported_amount_x),
"Failed at bin with index: {i}"
);
assert_eq!(
round_down_to_5_decimal_places(caviarnine_reported_amount_y),
round_down_to_5_decimal_places(adapter_reported_amount_y),
"Failed at bin with index: {i}"
);
}

Ok(())
}

#[test]
fn bin_amounts_reported_on_receipt_match_whats_reported_by_caviarnine_with_price_movement1(
) -> Result<(), RuntimeError> {
// Arrange
let Environment {
environment: ref mut env,
mut caviarnine_v1,
resources,
..
} = ScryptoTestEnv::new_with_configuration(Configuration {
maximum_allowed_relative_price_difference: dec!(0.05),
..Default::default()
})?;

let user_resource = resources.bitcoin;
let mut pool = caviarnine_v1.pools.bitcoin;

let _ = ResourceManager(user_resource)
.mint_fungible(dec!(1_000_000_000), env)
.and_then(|bucket| pool.swap(bucket, env))?;

let [user_resource_bucket, xrd_bucket] =
[user_resource, XRD].map(|resource| {
ResourceManager(resource)
.mint_fungible(dec!(100), env)
.unwrap()
});

// Act
let OpenLiquidityPositionOutput {
pool_units,
adapter_specific_information,
..
} = caviarnine_v1.adapter.open_liquidity_position(
pool.try_into().unwrap(),
(user_resource_bucket, xrd_bucket),
env,
)?;

// Assert
let mut caviarnine_reported_redemption_value = pool
.get_redemption_bin_values(
pool_units
.non_fungible_local_ids(env)?
.first()
.unwrap()
.clone(),
env,
)?;
caviarnine_reported_redemption_value.sort_by(|a, b| a.0.cmp(&b.0));
let adapter_reported_redemption_value = adapter_specific_information
.as_typed::<CaviarnineV1AdapterSpecificInformation>()
.unwrap()
.bin_contributions;

assert_eq!(
caviarnine_reported_redemption_value.len(),
adapter_reported_redemption_value.len(),
);

for (
i,
(
caviarnine_reported_bin,
caviarnine_reported_amount_x,
caviarnine_reported_amount_y,
),
) in caviarnine_reported_redemption_value.into_iter().enumerate()
{
let Some(ResourceIndexedData {
resource_x: adapter_reported_amount_x,
resource_y: adapter_reported_amount_y,
}) = adapter_reported_redemption_value
.get(&caviarnine_reported_bin)
.copied()
else {
panic!(
"Bin {} does not have an entry in the adapter data",
caviarnine_reported_bin
)
};

assert_eq!(
round_down_to_5_decimal_places(caviarnine_reported_amount_x),
round_down_to_5_decimal_places(adapter_reported_amount_x),
"Failed at bin with index: {i}"
);
assert_eq!(
round_down_to_5_decimal_places(caviarnine_reported_amount_y),
round_down_to_5_decimal_places(adapter_reported_amount_y),
"Failed at bin with index: {i}"
);
}

Ok(())
}

#[test]
fn bin_amounts_reported_on_receipt_match_whats_reported_by_caviarnine_with_price_movement2(
) -> Result<(), RuntimeError> {
// Arrange
let Environment {
environment: ref mut env,
mut caviarnine_v1,
resources,
..
} = ScryptoTestEnv::new_with_configuration(Configuration {
maximum_allowed_relative_price_difference: dec!(0.05),
..Default::default()
})?;

let user_resource = resources.bitcoin;
let mut pool = caviarnine_v1.pools.bitcoin;

let _ = ResourceManager(XRD)
.mint_fungible(dec!(1_000_000_000), env)
.and_then(|bucket| pool.swap(bucket, env))?;

let [user_resource_bucket, xrd_bucket] =
[user_resource, XRD].map(|resource| {
ResourceManager(resource)
.mint_fungible(dec!(100), env)
.unwrap()
});

// Act
let OpenLiquidityPositionOutput {
pool_units,
adapter_specific_information,
..
} = caviarnine_v1.adapter.open_liquidity_position(
pool.try_into().unwrap(),
(user_resource_bucket, xrd_bucket),
env,
)?;

// Assert
let mut caviarnine_reported_redemption_value = pool
.get_redemption_bin_values(
pool_units
.non_fungible_local_ids(env)?
.first()
.unwrap()
.clone(),
env,
)?;
caviarnine_reported_redemption_value.sort_by(|a, b| a.0.cmp(&b.0));
let adapter_reported_redemption_value = adapter_specific_information
.as_typed::<CaviarnineV1AdapterSpecificInformation>()
.unwrap()
.bin_contributions;

assert_eq!(
caviarnine_reported_redemption_value.len(),
adapter_reported_redemption_value.len(),
);

for (
i,
(
caviarnine_reported_bin,
caviarnine_reported_amount_x,
caviarnine_reported_amount_y,
),
) in caviarnine_reported_redemption_value.into_iter().enumerate()
{
let Some(ResourceIndexedData {
resource_x: adapter_reported_amount_x,
resource_y: adapter_reported_amount_y,
}) = adapter_reported_redemption_value
.get(&caviarnine_reported_bin)
.copied()
else {
panic!(
"Bin {} does not have an entry in the adapter data",
caviarnine_reported_bin
)
};

assert_eq!(
round_down_to_5_decimal_places(caviarnine_reported_amount_x),
round_down_to_5_decimal_places(adapter_reported_amount_x),
"Failed at bin with index: {i}"
);
assert_eq!(
round_down_to_5_decimal_places(caviarnine_reported_amount_y),
round_down_to_5_decimal_places(adapter_reported_amount_y),
"Failed at bin with index: {i}"
);
}

Ok(())
}

fn round_down_to_5_decimal_places(decimal: Decimal) -> Decimal {
decimal
.checked_round(5, RoundingMode::ToNegativeInfinity)
.unwrap()
}
Loading