Skip to content

Commit

Permalink
feat(fee_share): implement swap fee sharing on all pool types (#90)
Browse files Browse the repository at this point in the history
* feat(fee_share): Implement fee sharing in swap
* feat(fee_share): Implement fee sharing for stableswap
* feat(fee_share): Emit shared amount in swap response
* feat(fee_share): Implement fee sharing for PCL
* fix(fee_sharing): Bump PCL version
* fix(fee_share): Output full correct amount
* fix(fee_share): Bump versions of pairs
* fix(fee_share): Bump migration version
* fix(fee_share): Bump cosmwasm-check to 1.4.0
  • Loading branch information
donovansolms authored Sep 13, 2023
1 parent 1ee5ff2 commit 6c753c4
Show file tree
Hide file tree
Showing 32 changed files with 1,554 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check_artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ jobs:
fail-on-cache-miss: true
- name: Install cosmwasm-check
# Uses --debug for compilation speed
run: cargo install --debug --version 1.3.1 cosmwasm-check
run: cargo install --debug --version 1.4.0 cosmwasm-check
- name: Cosmwasm check
run: |
cosmwasm-check $GITHUB_WORKSPACE/artifacts/*.wasm --available-capabilities staking,cosmwasm_1_1,injective,iterator,stargate
8 changes: 4 additions & 4 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion contracts/pair/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "astroport-pair"
version = "1.4.0"
version = "1.5.0"
authors = ["Astroport"]
edition = "2021"
description = "The Astroport constant product pool contract implementation"
Expand Down
80 changes: 74 additions & 6 deletions contracts/pair/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ use astroport::asset::{
use astroport::factory::PairType;
use astroport::generator::Cw20HookMsg as GeneratorHookMsg;
use astroport::pair::{
ConfigResponse, XYKPoolConfig, XYKPoolParams, XYKPoolUpdateParams, DEFAULT_SLIPPAGE,
MAX_ALLOWED_SLIPPAGE,
ConfigResponse, FeeShareConfig, XYKPoolConfig, XYKPoolParams, XYKPoolUpdateParams,
DEFAULT_SLIPPAGE, MAX_ALLOWED_SLIPPAGE, MAX_FEE_SHARE_BPS,
};
use astroport::pair::{
CumulativePricesResponse, Cw20HookMsg, ExecuteMsg, InstantiateMsg, MigrateMsg, PoolResponse,
Expand Down Expand Up @@ -80,6 +80,7 @@ pub fn instantiate(
price0_cumulative_last: Uint128::zero(),
price1_cumulative_last: Uint128::zero(),
track_asset_balances,
fee_share: None,
};

if track_asset_balances {
Expand Down Expand Up @@ -691,12 +692,39 @@ pub fn swap(
messages.push(return_asset.into_msg(receiver.clone())?)
}

// If this pool is configured to share fees, calculate the amount to send
// to the receiver and add the transfer message
// The calculation works as follows: We take the share percentage first,
// and the remainder is then split between LPs and maker
let mut fees_commission_amount = commission_amount;
let mut fee_share_amount = Uint128::zero();
if let Some(fee_share) = config.fee_share.clone() {
// Calculate the fee share amount from the full commission amount
let share_fee_rate = Decimal::from_ratio(fee_share.bps, 10000u16);
fee_share_amount = fees_commission_amount * share_fee_rate;

if !fee_share_amount.is_zero() {
// Subtract the fee share amount from the commission
fees_commission_amount = fees_commission_amount.saturating_sub(fee_share_amount);

// Build send message for the shared amount
let fee_share_msg = Asset {
info: ask_pool.info.clone(),
amount: fee_share_amount,
}
.into_msg(fee_share.recipient)?;
messages.push(fee_share_msg);
}
}

// Compute the Maker fee
let mut maker_fee_amount = Uint128::zero();
if let Some(fee_address) = fee_info.fee_address {
if let Some(f) =
calculate_maker_fee(&ask_pool.info, commission_amount, fee_info.maker_fee_rate)
{
if let Some(f) = calculate_maker_fee(
&ask_pool.info,
fees_commission_amount,
fee_info.maker_fee_rate,
) {
maker_fee_amount = f.amount;
messages.push(f.into_msg(fee_address)?);
}
Expand All @@ -712,7 +740,7 @@ pub fn swap(
BALANCES.save(
deps.storage,
&ask_pool.info,
&(ask_pool.amount - return_amount - maker_fee_amount),
&(ask_pool.amount - return_amount - maker_fee_amount - fee_share_amount),
env.block.height,
)?;
}
Expand Down Expand Up @@ -744,6 +772,7 @@ pub fn swap(
attr("spread_amount", spread_amount),
attr("commission_amount", commission_amount),
attr("maker_fee_amount", maker_fee_amount),
attr("fee_share_amount", fee_share_amount),
]))
}

Expand Down Expand Up @@ -787,6 +816,44 @@ pub fn update_config(
"enabled".to_owned(),
));
}
XYKPoolUpdateParams::EnableFeeShare {
fee_share_bps,
fee_share_address,
} => {
// Enable fee sharing for this contract
// If fee sharing is already enabled, we should be able to overwrite
// the values currently set

// Ensure the fee share isn't 0 and doesn't exceed the maximum allowed value
if fee_share_bps == 0 || fee_share_bps > MAX_FEE_SHARE_BPS {
return Err(ContractError::FeeShareOutOfBounds {});
}

// Set sharing config
config.fee_share = Some(FeeShareConfig {
bps: fee_share_bps,
recipient: deps.api.addr_validate(&fee_share_address)?,
});

CONFIG.save(deps.storage, &config)?;

response.attributes.push(attr("action", "enable_fee_share"));
response
.attributes
.push(attr("fee_share_bps", fee_share_bps.to_string()));
response
.attributes
.push(attr("fee_share_address", fee_share_address));
}
XYKPoolUpdateParams::DisableFeeShare => {
// Disable fee sharing for this contract by setting bps and
// address back to None
config.fee_share = None;
CONFIG.save(deps.storage, &config)?;
response
.attributes
.push(attr("action", "disable_fee_share"));
}
}

Ok(response)
Expand Down Expand Up @@ -1069,6 +1136,7 @@ pub fn query_config(deps: Deps) -> StdResult<ConfigResponse> {
block_time_last: config.block_time_last,
params: Some(to_binary(&XYKPoolConfig {
track_asset_balances: config.track_asset_balances,
fee_share: config.fee_share,
})?),
owner: factory_config.owner,
factory_addr: config.factory_addr,
Expand Down
8 changes: 7 additions & 1 deletion contracts/pair/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use astroport::asset::MINIMUM_LIQUIDITY_AMOUNT;
use astroport::{asset::MINIMUM_LIQUIDITY_AMOUNT, pair::MAX_FEE_SHARE_BPS};
use cosmwasm_std::{OverflowError, StdError};
use thiserror::Error;

Expand Down Expand Up @@ -52,6 +52,12 @@ pub enum ContractError {

#[error("Failed to parse or process reply message")]
FailedToParseReply {},

#[error(
"Fee share is 0 or exceeds maximum allowed value of {} bps",
MAX_FEE_SHARE_BPS
)]
FeeShareOutOfBounds {},
}

impl From<OverflowError> for ContractError {
Expand Down
1 change: 1 addition & 0 deletions contracts/pair/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub(crate) fn add_asset_balances_tracking_flag(
price0_cumulative_last: old_config.price0_cumulative_last,
price1_cumulative_last: old_config.price1_cumulative_last,
track_asset_balances: false,
fee_share: None,
};

CONFIG.save(storage, &new_config)?;
Expand Down
7 changes: 6 additions & 1 deletion contracts/pair/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use astroport::asset::{AssetInfo, PairInfo};
use astroport::{
asset::{AssetInfo, PairInfo},
pair::FeeShareConfig,
};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Uint128};
use cw_storage_plus::{Item, SnapshotMap};
Expand All @@ -18,6 +21,8 @@ pub struct Config {
pub price1_cumulative_last: Uint128,
/// Whether asset balances are tracked over blocks or not.
pub track_asset_balances: bool,
// The config for swap fee sharing
pub fee_share: Option<FeeShareConfig>,
}

/// Stores the config struct at the given key
Expand Down
3 changes: 3 additions & 0 deletions contracts/pair/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,7 @@ fn try_native_to_token() {
attr("spread_amount", expected_spread_amount.to_string()),
attr("commission_amount", expected_commission_amount.to_string()),
attr("maker_fee_amount", expected_maker_fee_amount.to_string()),
attr("fee_share_amount", "0"),
]
);

Expand Down Expand Up @@ -1121,6 +1122,7 @@ fn try_token_to_native() {
attr("spread_amount", expected_spread_amount.to_string()),
attr("commission_amount", expected_commission_amount.to_string()),
attr("maker_fee_amount", expected_maker_fee_amount.to_string()),
attr("fee_share_amount", "0"),
]
);

Expand Down Expand Up @@ -1418,6 +1420,7 @@ fn test_accumulate_prices() {
price0_cumulative_last: Uint128::new(case.last0),
price1_cumulative_last: Uint128::new(case.last1),
track_asset_balances: false,
fee_share: None,
},
Uint128::new(case.x_amount),
Uint128::new(case.y_amount),
Expand Down
Loading

0 comments on commit 6c753c4

Please sign in to comment.