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

Fix bugs #75

Merged
merged 25 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
330 changes: 276 additions & 54 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ members = [
[workspace.package]
edition = "2021"
license = "BSL"
version = "0.1.0"
version = "0.1.4"
repository = "https://github.com/timewave-computer/valence-services"

rust-version = "1.66"
Expand Down Expand Up @@ -51,8 +51,8 @@ valence-macros = { path = "packages/valence-macros" }
valence-package = { path = "packages/valence-package" }
auction-package = { path = "packages/auction-package" }

cosmwasm-schema = "1.5.4"
cosmwasm-std = { version = "1.5.4", features = ["ibc3"] }
cosmwasm-schema = "1.5.5"
cosmwasm-std = { version = "1.5.5", features = ["ibc3"] }
cw-storage-plus = "1.2.0"
cw-utils = "1.0.3"
cw2 = "1.1.2"
Expand All @@ -61,5 +61,5 @@ thiserror = "1.0.31"
schemars = "0.8.10"

# dev-dependencies
cw-multi-test = "1.1.0"
cw-multi-test = "1.2.0"
anyhow = { version = "1.0.51" }
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

## Code ids

- auctions manager = `1263`
- auction = `1262`
- oracle = `1261`
- rebalancer = `1260`
- services manager = `1259`
- account = `1258`
- auctions manager = `1404`
- auction = `1408`
- oracle = `1446`
- rebalancer = `1442`
- services manager = `1405`
- account = `1403`

## Owner / Admin

Expand Down
6 changes: 3 additions & 3 deletions contracts/auction/auction/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ mod admin {

// Verify the amount of funds we have to auction, is more then the start auction min amount
let manager_addr = ADMIN.load(deps.storage)?;
let min_start_acution = MIN_AUCTION_AMOUNT
let min_start_auction = MIN_AUCTION_AMOUNT
.query(&deps.querier, manager_addr, config.pair.0.clone())?
.unwrap_or_default()
.start_auction;
Expand All @@ -251,12 +251,12 @@ mod admin {
AUCTION_IDS.save(deps.storage, &auction_ids)?;

// if its less, refund the funds to the users
if total_funds < min_start_acution {
if total_funds < min_start_auction {
return do_refund(
deps,
auction_ids.curr,
config.pair.0.clone(),
min_start_acution,
min_start_auction,
total_funds,
);
}
Expand Down
16 changes: 14 additions & 2 deletions contracts/auction/price_oracle/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ use auction_package::helpers::{
approve_admin_change, cancel_admin_change, start_admin_change, verify_admin,
};
use auction_package::states::{ADMIN, PAIRS, PRICES, TWAP_PRICES};
use auction_package::Price;
use auction_package::{Pair, Price};
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{to_json_binary, Binary, Decimal, Deps, DepsMut, Env, MessageInfo, Response};
use cosmwasm_std::{
to_json_binary, Binary, Decimal, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
};
use cw2::set_contract_version;
use cw_storage_plus::Bound;
use valence_package::event_indexing::{ValenceEvent, ValenceGenericEvent};

use crate::error::ContractError;
Expand Down Expand Up @@ -311,6 +314,15 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<Binary, ContractErr

Ok(to_json_binary(&price)?)
}
QueryMsg::GetAllPrices { from, limit } => {
let from = from.map(Bound::<Pair>::exclusive);
let prices = PRICES
.range(deps.storage, from, None, cosmwasm_std::Order::Ascending)
.take(limit.unwrap_or(10) as usize)
.collect::<StdResult<Vec<_>>>()?;

Ok(to_json_binary(&prices)?)
}
QueryMsg::GetConfig => {
let config = CONFIG.load(deps.storage)?;
Ok(to_json_binary(&config)?)
Expand Down
9 changes: 7 additions & 2 deletions contracts/auction/price_oracle/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use auction_package::{helpers::GetPriceResponse, Pair};
use auction_package::{Pair, Price};

Check warning on line 1 in contracts/auction/price_oracle/src/msg.rs

View workflow job for this annotation

GitHub Actions / test

unused import: `Price`
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{Addr, Decimal};
use cw_utils::Expiration;
Expand Down Expand Up @@ -46,8 +46,13 @@
#[derive(QueryResponses)]
pub enum QueryMsg {
/// Get the minimum amount users can auction
#[returns(GetPriceResponse)]
#[returns(Price)]
GetPrice { pair: Pair },
#[returns(Vec<(Pair, Price)>)]
GetAllPrices {
from: Option<Pair>,
limit: Option<u32>,
},
#[returns(Config)]
GetConfig,
#[returns(Addr)]
Expand Down
7 changes: 7 additions & 0 deletions contracts/services/rebalancer/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use valence_package::helpers::{approve_admin_change, verify_services_manager, Op
use valence_package::services::rebalancer::{
PauseData, RebalancerExecuteMsg, SystemRebalanceStatus,
};
use valence_package::signed_decimal::SignedDecimal;
use valence_package::states::{QueryFeeAction, ADMIN, SERVICES_MANAGER, SERVICE_FEE_CONFIG};

use crate::error::ContractError;
Expand Down Expand Up @@ -302,6 +303,12 @@ pub fn execute(

if let Some(pid) = data.pid {
config.pid = pid.into_parsed()?;

// If PID is updated, we reset the last calculation because they are no longer valid
config.targets.iter_mut().for_each(|t| {
t.last_input = None;
t.last_i = SignedDecimal::zero();
});
}

if let Some(max_limit_option) = data.max_limit_bps {
Expand Down
4 changes: 3 additions & 1 deletion contracts/services/rebalancer/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Decimal, SubMsg, Uint128};
use serde::Serialize;
use valence_package::{
Expand Down Expand Up @@ -26,9 +27,10 @@ pub struct TargetHelper {
/// can either be to sell or to buy, depends on the calculation
pub value_to_trade: Decimal,
/// The minimum value we can send to the auction
pub auction_min_amount: Decimal,
pub auction_min_send_value: Decimal,
}

#[cw_serde]
pub struct RebalanceResponse<E: Serialize> {
pub config: RebalancerConfig,
pub msg: Option<SubMsg>,
Expand Down
79 changes: 50 additions & 29 deletions contracts/services/rebalancer/src/rebalance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ pub fn execute_system_rebalance(
should_pause,
}) = rebalance_res
else {
account_events.push(
Event::new("rebalancer-error")
.add_attribute("error", rebalance_res.unwrap_err().to_string()),
);
continue;
};

Expand Down Expand Up @@ -254,16 +258,22 @@ pub fn do_rebalance(
env.block.time.seconds() - config.last_rebalance.seconds(),
0,
)?;
(diff / Decimal::from_atomics(cycle_period, 0)?).min(Decimal::new(MAX_PID_DT_VALUE.into()))
(diff.checked_div(Decimal::from_atomics(cycle_period, 0)?))?
.min(Decimal::from_atomics(MAX_PID_DT_VALUE, 0)?)
};

let (mut to_sell, to_buy) = do_pid(total_value, &mut target_helpers, config.pid.clone(), dt)?;

// Save targets to our config
config.targets = target_helpers
.iter_mut()
.map(|th| th.target.clone())
.collect();
// Update targets in config only the last data we need for the next rebalance calculation
for target in config.targets.iter_mut() {
if let Some(target_helper) = target_helpers
.iter()
.find(|th| th.target.denom == target.denom)
{
target.last_i = target_helper.target.last_i;
target.last_input = target_helper.target.last_input;
}
}
stiiifff marked this conversation as resolved.
Show resolved Hide resolved

// get minimum amount we can send to each auction
set_auction_min_amounts(deps, auction_manager, &mut to_sell, min_amount_limits)?;
Expand Down Expand Up @@ -322,8 +332,8 @@ pub(crate) fn set_auction_min_amounts(
.find(|min_amount| min_amount.0 == sell_token.target.denom)
{
Some(min_amount) => {
sell_token.auction_min_amount =
Decimal::from_atomics(min_amount.1, 0)? / sell_token.price;
sell_token.auction_min_send_value =
Decimal::from_atomics(min_amount.1, 0)?.checked_div(sell_token.price)?;
}
None => {
match MIN_AUCTION_AMOUNT.query(
Expand All @@ -335,8 +345,9 @@ pub(crate) fn set_auction_min_amounts(
send: min_send_amount,
..
}) => {
sell_token.auction_min_amount =
Decimal::from_atomics(min_send_amount, 0)? / sell_token.price;
sell_token.auction_min_send_value =
Decimal::from_atomics(min_send_amount, 0)?
.checked_div(sell_token.price)?;
min_amount_limits.push((sell_token.target.denom.clone(), min_send_amount));
Ok(())
}
Expand Down Expand Up @@ -416,7 +427,8 @@ fn get_inputs(
// Get current balance of the target, and calculate the value
// safe if balance is 0, 0 / price = 0
let current_balance = deps.querier.query_balance(account, target.denom.clone())?;
let balance_value = Decimal::from_atomics(current_balance.amount, 0)? / price;
let balance_value =
Decimal::from_atomics(current_balance.amount, 0)?.checked_div(price)?;

total_value += balance_value;
targets_helpers.push(TargetHelper {
Expand All @@ -425,7 +437,7 @@ fn get_inputs(
price,
balance_value,
value_to_trade: Decimal::zero(),
auction_min_amount: Decimal::zero(),
auction_min_send_value: Decimal::zero(),
});

Ok((total_value, targets_helpers))
Expand Down Expand Up @@ -466,6 +478,7 @@ fn do_pid(
Some(last_input) => signed_input - last_input.into(),
None => SignedDecimal::zero(),
};

d = d * signed_d / signed_dt;

let output = p + i - d;
Expand Down Expand Up @@ -505,7 +518,7 @@ pub fn verify_targets(
// Safe to unwrap here, because we only enter the function is there is a min_balance target
// and we error out if we don't find the target above.
let min_balance = Decimal::from_atomics(target.target.min_balance.unwrap(), 0)?;
let min_balance_target = min_balance * target.price;
let min_balance_target = min_balance / target.price;
stiiifff marked this conversation as resolved.
Show resolved Hide resolved
let real_target = total_value * target.target.percentage;

// if the target is below the minimum balance target
Expand All @@ -516,7 +529,7 @@ pub fn verify_targets(
let (new_target_perc, mut leftover_perc) = if min_balance_target >= total_value {
(Decimal::one(), Decimal::zero())
} else {
let perc = min_balance_target / total_value;
let perc = min_balance_target.checked_div(total_value)?;
(perc, Decimal::one() - perc)
};

Expand All @@ -525,23 +538,23 @@ pub fn verify_targets(

let updated_targets = targets
.into_iter()
.map(|mut t| {
.map(|mut t| -> Result<TargetHelper, ContractError> {
// If our target is the min_balance target, we update perc, and return t.
if t.target.denom == target.target.denom {
t.target.percentage = new_target_perc;
return t;
return Ok(t);
};

// If leftover perc is 0, we set the perc as zero for this target
if leftover_perc.is_zero() {
t.target.percentage = Decimal::zero();
return t;
return Ok(t);
}

// Calc new perc based on chosen strategy and new min_balance perc
match config.target_override_strategy {
TargetOverrideStrategy::Proportional => {
let old_perc = t.target.percentage / old_leftover_perc;
let old_perc = t.target.percentage.checked_div(old_leftover_perc)?;
t.target.percentage = old_perc * leftover_perc;
}
TargetOverrideStrategy::Priority => {
Expand All @@ -555,9 +568,9 @@ pub fn verify_targets(
}

new_total_perc += t.target.percentage;
t
Ok(t)
})
.collect();
.collect::<Result<Vec<_>, ContractError>>()?;

// If the new percentage is smaller then 0.9999 or higher then 1, we have something wrong in calculation
if new_total_perc > Decimal::one()
Expand Down Expand Up @@ -638,26 +651,26 @@ fn generate_trades_msgs(
// check if the amount we intent to buy, is lower than min_amount of the sell token
// if its not, it will be handled correctly by the main loop.
// but if it is, it means we need to sell other token more then we intent to
if token_buy.value_to_trade < token_sell.auction_min_amount {
if token_buy.value_to_trade < token_sell.auction_min_send_value {
// If the amount we try to sell, is below the auction_min_amount, we need to set it to zero
// else we reduce the auction_min_amount value
if token_sell.value_to_trade < token_sell.auction_min_amount {
if token_sell.value_to_trade < token_sell.auction_min_send_value {
token_sell.value_to_trade = Decimal::zero();
} else {
token_sell.value_to_trade -= token_sell.auction_min_amount;
token_sell.value_to_trade -= token_sell.auction_min_send_value;
}

let pair = Pair::from((
token_sell.target.denom.clone(),
token_buy.target.denom.clone(),
));
let amount = (token_sell.auction_min_amount * token_sell.price).to_uint_ceil();
let amount = (token_sell.auction_min_send_value * token_sell.price).to_uint_ceil();
let trade = RebalanceTrade::new(pair, amount);

token_buy.value_to_trade = Decimal::zero();

if let Ok(msg) = construct_msg(deps, auction_manager.clone(), trade.clone()) {
max_sell -= token_sell.auction_min_amount;
max_sell -= token_sell.auction_min_send_value;
msgs.push(msg);
};
}
Expand Down Expand Up @@ -693,6 +706,10 @@ fn generate_trades_msgs(
// If our sell results in less then min_balance, we sell the difference to hit min_balance
let diff = token_sell.balance_amount - min_balance;

if diff.is_zero() {
return;
}

// Unwrap should be safe here because diff should be a small number
// and directly related to users balance
token_sell.value_to_trade =
Expand All @@ -701,18 +718,20 @@ fn generate_trades_msgs(
}

// If we intent to sell less then our minimum, we set to_trade to be 0 and continue
if token_sell.value_to_trade < token_sell.auction_min_amount {
if token_sell.value_to_trade < token_sell.auction_min_send_value {
token_sell.value_to_trade = Decimal::zero();
return;
}

// If our buy value is lower then our sell min_send value, we do nothing and continue.
if token_buy.value_to_trade < token_sell.auction_min_send_value {
return;
}

// If we hit our max sell limit, we only sell the limit left
// otherwise, we keep track of how much we already sold
if token_sell.value_to_trade > max_sell {
token_sell.value_to_trade = max_sell;
max_sell = Decimal::zero();
} else {
max_sell -= token_sell.value_to_trade;
}

let pair = Pair::from((
Expand All @@ -729,6 +748,7 @@ fn generate_trades_msgs(
token_buy.value_to_trade = Decimal::zero();

let Ok(msg) = construct_msg(deps, auction_manager.clone(), trade.clone()) else {
max_sell -= token_buy.value_to_trade;
return;
};

Expand All @@ -743,6 +763,7 @@ fn generate_trades_msgs(
token_sell.value_to_trade = Decimal::zero();

let Ok(msg) = construct_msg(deps, auction_manager.clone(), trade.clone()) else {
max_sell -= token_sell.value_to_trade;
return;
};

Expand Down
Loading
Loading