diff --git a/Cargo.lock b/Cargo.lock index 5db99a6..b62e712 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,7 +74,8 @@ dependencies = [ "cosmwasm-std", "cw-multi-test", "cw-storage-plus 0.13.4", - "cw2 0.13.4", + "cw2 0.14.0", + "cw20 0.14.0", "schemars", "serde", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 75611e0..8068e7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = ["contracts/*", "packages/*", "test-contracts/*"] +resolver = "2" [profile.release.package.ultra-token] codegen-units = 1 @@ -38,4 +39,5 @@ lto = true debug-assertions = false panic = 'abort' incremental = false -overflow-checks = true \ No newline at end of file +overflow-checks = true +resolver = "2" diff --git a/contracts/borrower-operation/Cargo.toml b/contracts/borrower-operation/Cargo.toml index 3486847..48f6a0c 100644 --- a/contracts/borrower-operation/Cargo.toml +++ b/contracts/borrower-operation/Cargo.toml @@ -16,7 +16,8 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] [dependencies] -cw2 = { version = "0.13.4" } +cw2 = { version = "0.14.0" } +cw20 = { version = "0.14.0" } cosmwasm-std = { version = "1.0.0" } cw-storage-plus = { version = "0.13.4" } schemars = "0.8.1" diff --git a/contracts/borrower-operation/src/contract.rs b/contracts/borrower-operation/src/contract.rs index a8b232a..8a22caa 100644 --- a/contracts/borrower-operation/src/contract.rs +++ b/contracts/borrower-operation/src/contract.rs @@ -1,16 +1,24 @@ +use std::str::FromStr; +use std::vec; + #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - coin, to_binary, Addr, BankMsg, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError, - StdResult, Storage, Uint128, + coin, to_binary, Addr, BankMsg, Binary, CosmosMsg, Decimal, Decimal256, Deps, DepsMut, Empty, + Env, Event, MessageInfo, Response, StdError, StdResult, Storage, Uint128, Uint256, WasmMsg, }; use cw2::set_contract_version; +use ultra_base::role_provider::Role; +use ultra_base::{active_pool, reward_distributor, trove_manager}; use crate::error::ContractError; -use crate::state::{SudoParams, SUDO_PARAMS}; +use crate::state::{State, SudoParams, SUDO_PARAMS}; use ultra_base::borrower_operations::{ExecuteMsg, InstantiateMsg, ParamsResponse, QueryMsg}; -use ultra_base::querier::{query_entire_system_coll, query_entire_system_debt}; +use ultra_base::querier::{ + check_recovery_mode, fetch_price, query_borrowing_fee, query_entire_system_coll, + query_entire_system_debt, require_user_accepts_fee, +}; // version info for migration info const CONTRACT_NAME: &str = "crates.io:active-pool"; @@ -57,21 +65,25 @@ pub fn execute( info, max_fee_percentage, ultra_amount, - upper_hint, - lower_hint, + // ignoring hints for now, on the assumption we can use storage indexing instead. + // upper_hint, + // lower_hint, ), - ExecuteMsg::AdjustTrove { - borrower, - coll_withdrawal, - ultra_change, - is_debt_increase, + // called during `OpenTrove` execution + ExecuteMsg::CollectBorrowingFee { max_fee_percentage, - upper_hint, - lower_hint, - } => execute_adjust_trove( + stable_amount, + } => _execute_open_trove_collect_borrowing_fee( deps, env, info, + max_fee_percentage, + stable_amount, + // ignoring hints for now, on the assumption we can use storage indexing instead. + // upper_hint, + // lower_hint, + ), + ExecuteMsg::AdjustTrove { borrower, coll_withdrawal, ultra_change, @@ -79,18 +91,30 @@ pub fn execute( max_fee_percentage, upper_hint, lower_hint, - ), - ExecuteMsg::CloseTrove {} => execute_close_trove(deps, env, info), + } => todo!(), + // execute_adjust_trove( + // deps, + // env, + // info, + // borrower, + // coll_withdrawal, + // ultra_change, + // is_debt_increase, + // max_fee_percentage, + // upper_hint, + // lower_hint, + // ), + ExecuteMsg::CloseTrove {} => todo!(), // execute_close_trove(deps, env, info), ExecuteMsg::AddColl { upper_hint, lower_hint, - } => execute_add_coll(deps, env, info, upper_hint, lower_hint), + } => todo!(), // execute_add_coll(deps, env, info, upper_hint, lower_hint), ExecuteMsg::WithdrawColl { coll_amount, upper_hint, lower_hint, - } => execute_withdraw_coll(deps, env, info, coll_amount, upper_hint, lower_hint), - ExecuteMsg::ClaimCollateral {} => execute_claim_collateral(deps, env, info), + } => todo!(), // execute_withdraw_coll(deps, env, info, coll_amount, upper_hint, lower_hint), + ExecuteMsg::ClaimCollateral {} => todo!(), // execute_claim_collateral(deps, env, info), ExecuteMsg::RepayULTRA { active_pool_addr, ultra_token_addr, @@ -98,50 +122,191 @@ pub fn execute( ultra_amount, upper_hint, lower_hint, - } => execute_repay_ultra( - deps, - env, - info, - active_pool_addr, - ultra_token_addr, - account, - ultra_amount, - upper_hint, - lower_hint, - ), + } => todo!(), + // execute_repay_ultra( + // deps, + // env, + // info, + // active_pool_addr, + // ultra_token_addr, + // account, + // ultra_amount, + // upper_hint, + // lower_hint, + // ), ExecuteMsg::WithdrawULTRA { max_fee_percentage, ultra_amount, upper_hint, lower_hint, - } => execute_withdraw_ultra( - deps, - env, - info, - max_fee_percentage, - ultra_amount, - upper_hint, - lower_hint, - ), + } => todo!(), + // execute_withdraw_ultra( + // deps, + // env, + // info, + // max_fee_percentage, + // ultra_amount, + // upper_hint, + // lower_hint, + // ), ExecuteMsg::MoveJUNOGainToTrove { borrower, upper_hint, lower_hint, - } => execute_move_juno_gain_to_trove(deps, env, info, borrower, upper_hint, lower_hint), + } => todo!(), // execute_move_juno_gain_to_trove(deps, env, info, borrower, upper_hint, lower_hint), } } +// liquity source: https://github.com/liquity/dev/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L156 pub fn execute_open_trove( deps: DepsMut, - _env: Env, + env: Env, info: MessageInfo, - amount: Uint128, + max_fee_percentage: Decimal256, + amount: Uint256, ) -> Result { - let res = Response::new().add_attribute("action", "open_trove"); + let state = State::default(); + // fetch price from pricefeed. + let price_feed_addr = state + .roles + .load_role_address(deps.as_ref(), Role::PriceFeed)?; + let active_pool_addr = state + .roles + .load_role_address(deps.as_ref(), Role::ActivePool)?; + let default_pool_addr = state + .roles + .load_role_address(deps.as_ref(), Role::DefaultPool)?; + let trove_manager_addr = state + .roles + .load_role_address(deps.as_ref(), Role::TroveManager)?; + + let price = fetch_price(&deps.querier, price_feed_addr)?; + // 2. check if in recovery mode. + let is_recovery_mode = + check_recovery_mode(&deps.querier, price, active_pool_addr, default_pool_addr)?; + // 3. require max fee percentage! + require_valid_max_fee_percentage(max_fee_percentage)?; + // 4. require that trove is not active! + require_trove_is_not_active(deps.storage, &trove_manager_addr, &info.sender)?; + + state.temp.net_debt.save(deps.storage, &amount.clone())?; + + let mut msgs: Vec> = vec![]; + if !is_recovery_mode { + // Update Decay Rate for Trove Manager + let decay_wasm_msg = to_binary(&trove_manager::ExecuteMsg::DecayBaseRateFromBorrowing {})?; + let decay_base_rate_msg: CosmosMsg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: trove_manager_addr.to_string(), + msg: decay_wasm_msg, + funds: vec![], + }); + msgs.push(decay_base_rate_msg); + + // Attempt to Collect Fee from Sender + let collect_borrowing_fee_wasm_msg = to_binary(&ExecuteMsg::CollectBorrowingFee { + max_fee_percentage, + stable_amount: amount, + })?; + let collect_borrowing_fee_msg: CosmosMsg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: env.contract.address.to_string(), + msg: collect_borrowing_fee_wasm_msg, + funds: vec![], + }); + msgs.push(collect_borrowing_fee_msg); + } + + // TODO: Add descriptive attributes + let res = Response::new() + .add_messages(msgs) + .add_attribute("action", "open_trove"); Ok(res) } -/// Checks to enfore only borrower o can call +// liquity source https://github.com/liquity/dev/blob/e76b000e9558640e9479b8080786a9fbc47ed570/packages/contracts/contracts/BorrowerOperations.sol#L363-L374 +pub fn _execute_open_trove_collect_borrowing_fee( + deps: DepsMut, + env: Env, + info: MessageInfo, + max_fee_percentage: Decimal256, + stable_amount: Uint256, +) -> Result { + // can only be called by itself + if info.sender != env.contract.address { + return Err(ContractError::Unauthorized {}); + } + // already decayed base rate. + // get borrowing fee. + let state = State::default(); + let trove_manager_addr = state + .roles + .load_role_address(deps.as_ref(), Role::TroveManager)?; + let borrowing_fee = query_borrowing_fee(&deps.querier, trove_manager_addr, stable_amount)?; + + // ensure user accepts fee. + require_user_accepts_fee( + &deps.querier, + borrowing_fee, + stable_amount, + max_fee_percentage, + )?; + + // setting temp states https://github.com/liquity/dev/blob/e76b000e9558640e9479b8080786a9fbc47ed570/packages/contracts/contracts/BorrowerOperations.sol#L170-L171 + state + .temp + .borrowing_fee + .save(deps.storage, &borrowing_fee)?; + + state + .temp + .net_debt + .update(deps.storage, |net_debt| Ok(net_debt + &borrowing_fee)) + .map_err(ContractError::Std)?; + + // Mint borrowing fee amount as stablecoin. + let stable_token_address = state + .roles + .load_role_address(deps.as_ref(), Role::UltraToken)?; + let mint_cw20_msg = cw20::Cw20ExecuteMsg::Mint { + amount: borrowing_fee.try_into().map_err(StdError::from)?, + recipient: env.contract.address.to_string(), + }; + let mint_cosmos_msg: CosmosMsg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: stable_token_address.to_string(), + msg: to_binary(&mint_cw20_msg)?, + funds: vec![], + }); + + // idea being this is, or emulates a DAODAO reward distributor contract. + let distributor_contract_address = state + .roles + .load_role_address(deps.as_ref(), Role::BorrowerFeeDistributor)?; + // TODO: Migrate to TokenFactory cosmos messages + let send_and_fund_cw20_msg = cw20::Cw20ExecuteMsg::Send { + amount: borrowing_fee.try_into().map_err(StdError::from)?, + contract: distributor_contract_address.to_string(), + msg: to_binary(&reward_distributor::ExecuteMsg::Fund {})?, + }; + let send_and_fund_cosmos_msg: CosmosMsg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: stable_token_address.to_string(), + msg: to_binary(&send_and_fund_cw20_msg)?, + funds: vec![], + }); + + // prefer events over attibutes here, as attributes can get messy in the root wasm event. + let fee_collection_event = Event::new("ultra/borrower_operations/borrowing_fee_collected") + .add_attribute("amount", borrowing_fee.to_string()) + .add_attribute("stable_amount", stable_amount.to_string()) + .add_attribute("max_fee_percentage", max_fee_percentage.to_string()) + .add_attribute("borrowing_fee", borrowing_fee.to_string()); + // TODO: Add detailed response attributes + Ok(Response::new() + .add_attribute("action", "collect_borrowing_fee") + .add_event(fee_collection_event) + .add_message(mint_cosmos_msg) + .add_message(send_and_fund_cosmos_msg)) +} + +/// Checks to enfore only borrower can call fn only_borrower(store: &dyn Storage, info: &MessageInfo) -> Result { return Err(ContractError::CallerIsNotBorrower {}); } @@ -154,8 +319,17 @@ fn only_owner(store: &dyn Storage, info: &MessageInfo) -> Result Result<(), ContractError> { + if max_fee_percentage <= Decimal256::percent(100) { + return Err(ContractError::InvalidMaxFeePercentage {}); + } + Ok(()) +} + /// fn require_trove_is_active(store: &dyn Storage, info: &MessageInfo) -> Result { + todo!("Implement with https://github.com/liquity/dev/blob/e76b000e9558640e9479b8080786a9fbc47ed570/packages/contracts/contracts/BorrowerOperations.sol#L477"); let params = SUDO_PARAMS.load(store)?; if params.owner != info.sender.as_ref() { return Err(ContractError::UnauthorizedOwner {}); @@ -166,13 +340,15 @@ fn require_trove_is_active(store: &dyn Storage, info: &MessageInfo) -> Result Result { + trove_manager: &Addr, + borrower: &Addr, +) -> Result<(), ContractError> { + todo!("Implement with https://github.com/liquity/dev/blob/e76b000e9558640e9479b8080786a9fbc47ed570/packages/contracts/contracts/BorrowerOperations.sol#L482"); let params = SUDO_PARAMS.load(store)?; - if params.owner != info.sender.as_ref() { + if params.owner != borrower.as_ref() { return Err(ContractError::UnauthorizedOwner {}); } - Ok(info.sender.clone()) + Ok(()) } #[cfg_attr(not(feature = "library"), entry_point)] diff --git a/contracts/borrower-operation/src/error.rs b/contracts/borrower-operation/src/error.rs index e672b9e..094dc63 100644 --- a/contracts/borrower-operation/src/error.rs +++ b/contracts/borrower-operation/src/error.rs @@ -1,14 +1,24 @@ use cosmwasm_std::StdError; use thiserror::Error; +use ultra_controllers::roles::RolesError; #[derive(Error, Debug, PartialEq)] pub enum ContractError { #[error("{0}")] Std(#[from] StdError), + #[error("{0}")] + RolesError(#[from] RolesError), + #[error("UnauthorizedOwner")] UnauthorizedOwner {}, + #[error("Unauthorized.")] + Unauthorized {}, + + #[error("Invalid max fee percentage. Must be <= 100%")] + InvalidMaxFeePercentage {}, + #[error("BorrowerOperation: Caller is not borrower")] CallerIsNotBorrower {}, } diff --git a/contracts/borrower-operation/src/helpers.rs b/contracts/borrower-operation/src/helpers.rs new file mode 100644 index 0000000..f60618b --- /dev/null +++ b/contracts/borrower-operation/src/helpers.rs @@ -0,0 +1,25 @@ +use cosmwasm_std::{Addr, Decimal256, DepsMut, StdResult, Uint256}; + +pub fn trigger_borrowing_fee( + deps: DepsMut, + trove_manager_addr: Addr, + stable_token_addr: Addr, + stable_token_amount: Addr, + max_fee_percentage: Decimal256, +) -> StdResult { + // decay trove manager's base rate state variable + todo!(); +} + +// function _triggerBorrowingFee(ITroveManager _troveManager, ILUSDToken _lusdToken, uint _LUSDAmount, uint _maxFeePercentage) internal returns (uint) { +// _troveManager.decayBaseRateFromBorrowing(); // decay the baseRate state variable +// uint LUSDFee = _troveManager.getBorrowingFee(_LUSDAmount); + +// _requireUserAcceptsFee(LUSDFee, _LUSDAmount, _maxFeePercentage); + +// // Send fee to LQTY staking contract +// lqtyStaking.increaseF_LUSD(LUSDFee); +// _lusdToken.mint(lqtyStakingAddress, LUSDFee); + +// return LUSDFee; +// } diff --git a/contracts/borrower-operation/src/lib.rs b/contracts/borrower-operation/src/lib.rs index 88f6fd0..af61525 100644 --- a/contracts/borrower-operation/src/lib.rs +++ b/contracts/borrower-operation/src/lib.rs @@ -1,5 +1,6 @@ pub mod contract; mod error; +pub mod helpers; pub mod state; pub mod sudo; #[cfg(test)] diff --git a/contracts/borrower-operation/src/state.rs b/contracts/borrower-operation/src/state.rs index f908fe4..7500fde 100644 --- a/contracts/borrower-operation/src/state.rs +++ b/contracts/borrower-operation/src/state.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, Decimal256, Uint128}; +use cosmwasm_std::{Addr, Decimal256, Uint128, Uint256}; use cw_storage_plus::Item; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -21,14 +21,25 @@ pub struct SudoParams { pub owner: Addr, } +// temp state only lives for the duration of a single execution +pub struct TempState<'a> { + pub borrowing_fee: Item<'a, Uint256>, + pub net_debt: Item<'a, Uint256>, +} + pub struct State<'a> { pub roles: RoleConsumer<'a>, + pub temp: TempState<'a>, } impl<'a> Default for State<'a> { fn default() -> Self { State { roles: RoleConsumer::new("role_provider_address"), + temp: TempState { + borrowing_fee: Item::new("temp_borrowing_fee"), + net_debt: Item::new("temp_net_debt"), + }, } } } diff --git a/packages/ultra-base/src/borrower_operations.rs b/packages/ultra-base/src/borrower_operations.rs index 8ef2b77..7acab5a 100644 --- a/packages/ultra-base/src/borrower_operations.rs +++ b/packages/ultra-base/src/borrower_operations.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, Decimal256, Uint128}; +use cosmwasm_std::{Addr, Decimal256, Uint128, Uint256}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -37,10 +37,15 @@ pub enum ExecuteMsg { }, OpenTrove { max_fee_percentage: Decimal256, - ultra_amount: Uint128, + ultra_amount: Uint256, upper_hint: Addr, lower_hint: Addr, }, + // called during OpenTrove + CollectBorrowingFee { + max_fee_percentage: Decimal256, + stable_amount: Uint256, + }, /// Burn the specified amount of ULTRA from `account` and decreases the total active debt RepayULTRA { active_pool_addr: Addr, diff --git a/packages/ultra-base/src/lib.rs b/packages/ultra-base/src/lib.rs index 079abee..11117d4 100644 --- a/packages/ultra-base/src/lib.rs +++ b/packages/ultra-base/src/lib.rs @@ -5,9 +5,11 @@ pub mod coll_surplus_pool; pub mod default_pool; pub mod hint_helpers; pub mod oracle; +pub mod price_feed; pub mod querier; +pub mod reward_distributor; +pub mod role_provider; pub mod sorted_troves; pub mod stability_pool; pub mod trove_manager; pub mod ultra_math; -pub mod role_provider; \ No newline at end of file diff --git a/packages/ultra-base/src/price_feed.rs b/packages/ultra-base/src/price_feed.rs new file mode 100644 index 0000000..b2fef3a --- /dev/null +++ b/packages/ultra-base/src/price_feed.rs @@ -0,0 +1,27 @@ +use cosmwasm_std::{Addr, Decimal256, Uint128}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] +pub struct InstantiateMsg { + pub name: String, + pub owner: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum ExecuteMsg { + UpdatePrice {}, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum QueryMsg { + GetPrice {}, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct GetPriceResponse { + pub price: Decimal256, +} diff --git a/packages/ultra-base/src/querier.rs b/packages/ultra-base/src/querier.rs index 5ff363f..de588ea 100644 --- a/packages/ultra-base/src/querier.rs +++ b/packages/ultra-base/src/querier.rs @@ -1,7 +1,8 @@ use crate::active_pool::QueryMsg as ActivePoolQueryMsg; use crate::asset::{AssetInfo, PoolInfo}; use crate::default_pool::QueryMsg as DefaultPoolQueryMsg; -use crate::ultra_math; +use crate::ultra_math::{self, DECIMAL_PRECISION}; +use crate::{price_feed, trove_manager}; use cosmwasm_std::{ Addr, AllBalanceResponse, BankQuery, Coin, Decimal256, QuerierWrapper, QueryRequest, StdError, @@ -180,7 +181,64 @@ pub fn check_recovery_mode( price: Decimal256, active_pool_addr: Addr, default_pool_addr: Addr, -) -> bool { - let tcr = get_tcr(querier, price, active_pool_addr, default_pool_addr).unwrap(); - tcr < CCR +) -> StdResult { + let tcr = get_tcr(querier, price, active_pool_addr, default_pool_addr)?; + Ok(tcr < CCR) +} + +pub fn fetch_price(querier: &QuerierWrapper, price_feed_addr: Addr) -> StdResult { + let price: price_feed::GetPriceResponse = + querier.query_wasm_smart(price_feed_addr, &price_feed::QueryMsg::GetPrice {})?; + Ok(price.price) +} + +pub fn query_borrowing_fee( + querier: &QuerierWrapper, + trove_manager_addr: Addr, + stable_debt: Uint256, +) -> StdResult { + let trove_manager::GetBorrowingFeeResponse { fee } = querier.query_wasm_smart( + trove_manager_addr, + &trove_manager::QueryMsg::GetBorrowingFee { + ultra_debt: stable_debt, + }, + )?; + Ok(fee) +} + +// function _requireUserAcceptsFee(uint _fee, uint _amount, uint _maxFeePercentage) internal pure { +// uint feePercentage = _fee.mul(DECIMAL_PRECISION).div(_amount); +// require(feePercentage <= _maxFeePercentage, "Fee exceeded provided maximum"); +// } +// liquity source: https://github.com/liquity/dev/blob/7e5c38eff92c7de7b366ec791fd86abc2012952c/packages/contracts/contracts/Dependencies/LiquityBase.sol#L89-L93 +pub fn require_user_accepts_fee( + _querier: &QuerierWrapper, + fee: Uint256, + amount: Uint256, + max_fee_percentage: Decimal256, +) -> StdResult<()> { + let fee_with_precision = fee + .checked_mul(DECIMAL_PRECISION.into()) + .map_err(StdError::overflow)?; + let fee_percentage = Decimal256::from_ratio(fee_with_precision, amount); + + if fee_percentage > max_fee_percentage { + return Err(StdError::generic_err("Fee exceeded provided maximum")); + } + + Ok(()) +} + +// function _requireAtLeastMinNetDebt(uint _netDebt) internal pure { +// require (_netDebt >= MIN_NET_DEBT, "BorrowerOps: Trove's net debt must be greater than minimum"); +// } +// liquity source: https://github.com/liquity/dev/blob/e76b000e9558640e9479b8080786a9fbc47ed570/packages/contracts/contracts/BorrowerOperations.sol#L551-L553 +pub fn require_at_least_min_net_debt(net_debt: Uint256) -> StdResult<()> { + if net_debt < MIN_NET_DEBT.into() { + return Err(StdError::generic_err( + "BorrowerOps: Trove's net debt must be greater than minimum", + )); + } + + Ok(()) } diff --git a/packages/ultra-base/src/reward_distributor.rs b/packages/ultra-base/src/reward_distributor.rs new file mode 100644 index 0000000..fb24698 --- /dev/null +++ b/packages/ultra-base/src/reward_distributor.rs @@ -0,0 +1,8 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum ExecuteMsg { + Fund {}, +} diff --git a/packages/ultra-base/src/role_provider.rs b/packages/ultra-base/src/role_provider.rs index ca2c576..a112596 100644 --- a/packages/ultra-base/src/role_provider.rs +++ b/packages/ultra-base/src/role_provider.rs @@ -15,6 +15,7 @@ pub enum Role { PriceFeed, SortedTroves, RewardPool, + BorrowerFeeDistributor, } impl ToString for Role { @@ -31,6 +32,7 @@ impl ToString for Role { Role::PriceFeed => "price_feed", Role::SortedTroves => "sorted_troves", Role::RewardPool => "reward_pool", + Role::BorrowerFeeDistributor => "borrower_fee_distributor", } .into() } diff --git a/packages/ultra-base/src/trove_manager.rs b/packages/ultra-base/src/trove_manager.rs index 475c636..0954001 100644 --- a/packages/ultra-base/src/trove_manager.rs +++ b/packages/ultra-base/src/trove_manager.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, Uint128}; +use cosmwasm_std::{Addr, Decimal256, Uint128, Uint256}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -96,8 +96,8 @@ pub enum QueryMsg { GetPendingULTRADebtReward {}, GetEntireDebtAndColl { borrower: String }, GetTCR {}, - GetBorrowingFee { ultra_debt: Uint128 }, - GetBorrowingFeeWithDecay { ultra_debt: Uint128 }, + GetBorrowingFee { ultra_debt: Uint256 }, + GetBorrowingFeeWithDecay { ultra_debt: Uint256 }, GetBorrowingRate {}, GetBorrowingRateWithDecay {}, GetRedemptionRate {}, @@ -131,3 +131,8 @@ pub struct ParamsResponse { pub name: String, pub owner: Addr, } + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct GetBorrowingFeeResponse { + pub fee: Uint256, +} diff --git a/packages/ultra-base/src/ultra_math.rs b/packages/ultra-base/src/ultra_math.rs index 7b543c4..2239ea2 100644 --- a/packages/ultra-base/src/ultra_math.rs +++ b/packages/ultra-base/src/ultra_math.rs @@ -1,4 +1,7 @@ -use cosmwasm_std::{Decimal256, StdError, StdResult, Uint128}; +use cosmwasm_std::{Decimal256, StdError, StdResult, Uint128, Uint256}; + +// 6 decimal cosmos standard precision +pub const DECIMAL_PRECISION: u128 = 1_000_000_u128; pub fn compute_cr(coll: Uint128, debt: Uint128, price: Decimal256) -> StdResult { if debt != Uint128::zero() {