Skip to content

Commit

Permalink
CU-1nbj6eq - Cherry develop (#384)
Browse files Browse the repository at this point in the history
* dex docs, groups for lending, api (#183)

Signed-off-by: dzmitry-lahoda <[email protected]>

* smallest possible unit for currencies + refactor + lending fixes / tests more clear (#186)

* make sure we allow liquidation if the source account has zero funds after

* introduce PriceableAsset capability

* refactor lending pallet + oracle mock to use smallest unit of an asset

* fix merge conflicts, make tests more clear

* simpler priceable type & upgrade runtime currency to handle it

* simplify and better documentation

* cleanup unused constraints

* Vault-index-configurable (#200)

* make VaultId an associated type

* Unmanle doc comment

* rent implementation (#189)

* implement rent and tombstoning

* clean up claim_surcharge

Also ensure that tombstoned vaults have funds returned by strategies.

* handle deletion_reward

* add delete_tombstoned functionality

* add add_surcharge

* fmt and fix doc comment

* Use NativeCurrency associated type instead of querying for native id (#202)

* Update Vault Readme (#207)

* describe vault

* sync readme with rustdoc

* Tests documentations & refactoring (#254)

* introduce composable-helpers

* refactor vault/lending tests to use composable-helpers

* apply advices

* Vault benchmarking (#270)

* fix missing runtime paramter

* add vault benchmarking

* Update CI config

Co-authored-by: Andrey Orlov <[email protected]>

* CU-1kjehh6 - avoid less than expected bonus by using safe maths (#289)

* CU-1kr011f - merge allocations in StrategyOverview (#290)

Both Allocations and CapitaalStructure storage map were tied.
Which mean you couldn't have an allocation without having a StrategyOverview.
This was wrong for the case of the reserve, as the vault itself has an
allocation (the reserve) but no StrategyOverview.

Because of that, one could trigger a panic by asking for `available_funds` using
the vault id.
We fix this issue by merging the allocation inside the StrategyOverview.

* fix benchmarking

* feature gate vault benchmark

* apply udeps suggestions

* update cargo.lock

Co-authored-by: Andrey Orlov <[email protected]>
  • Loading branch information
hussein-aitlahcen and andor0 authored Dec 15, 2021
1 parent 2aeb523 commit bbc7879
Show file tree
Hide file tree
Showing 60 changed files with 4,396 additions and 1,861 deletions.
2,841 changes: 1,714 additions & 1,127 deletions Cargo.lock

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions frame/composable-tests-helpers/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "composable-tests-helpers"
version = "0.0.1"
authors = ["Composable Developers"]
homepage = "https://composable.finance"
edition = "2018"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
serde = { version = "1", optional = true }
sp-arithmetic = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" }
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" }
sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" }

[dependencies.codec]
default-features = false
features = ["derive"]
package = "parity-scale-codec"
version = "2.0.0"

[features]
default = ["std"]
std = [
"serde",
"codec/std",
"sp-runtime/std",
"scale-info/std",
]
3 changes: 3 additions & 0 deletions frame/composable-tests-helpers/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#![cfg_attr(not(feature = "std"), no_std)]

pub mod test;
28 changes: 28 additions & 0 deletions frame/composable-tests-helpers/src/test/helper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use sp_runtime::{FixedPointNumber, FixedU128};

/// Default is 0.1%
pub const DEFAULT_ACCEPTABLE_DEVIATION: u128 = 1000;

/// Check that x/y ~ 1 up to a certain precision
pub fn acceptable_computation_error(x: u128, y: u128, precision: u128) -> Result<(), FixedU128> {
let delta = i128::abs(x as i128 - y as i128);
if delta > 1 {
let epsilon: u128 = 1;
let lower =
FixedU128::saturating_from_rational(precision, precision.saturating_add(epsilon));
let upper =
FixedU128::saturating_from_rational(precision, precision.saturating_sub(epsilon));
let q = FixedU128::checked_from_rational(x, y).expect("values too big; qed;");
if lower <= q && q <= upper {
Ok(())
} else {
Err(q)
}
} else {
Ok(())
}
}

pub fn default_acceptable_computation_error(x: u128, y: u128) -> Result<(), FixedU128> {
acceptable_computation_error(x, y, DEFAULT_ACCEPTABLE_DEVIATION)
}
2 changes: 2 additions & 0 deletions frame/composable-tests-helpers/src/test/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod helper;
pub mod proptest;
38 changes: 38 additions & 0 deletions frame/composable-tests-helpers/src/test/proptest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/// Equivalent of assert_ok when inside a proptest context.
#[macro_export]
macro_rules! prop_assert_ok {
($cond:expr) => {
prop_assert_ok!($cond, concat!("assertion failed: ", stringify!($cond)))
};

($cond:expr, $($fmt:tt)*) => {
if let Err(e) = $cond {
let message = format!($($fmt)*);
let message = format!("Expected Ok(_), got {:?}, {} at {}:{}", e, message, file!(), line!());
return ::std::result::Result::Err(
proptest::test_runner::TestCaseError::fail(message));
}
};
}

/// Accept a `dust` deviation.
#[macro_export]
macro_rules! prop_assert_acceptable_computation_error {
($x:expr, $y:expr, $precision:expr) => {{
match composable_tests_helpers::test::helper::acceptable_computation_error(
$x, $y, $precision,
) {
Ok(()) => {},
Err(q) => {
prop_assert!(false, "{} * {} / {} = {} != {}", $x, $precision, $y, q, $precision);
},
}
}};
($x:expr, $y:expr) => {{
prop_assert_acceptable_computation_error!(
$x,
$y,
composable_tests_helpers::test::helper::DEFAULT_ACCEPTABLE_DEVIATION
);
}};
}
1 change: 1 addition & 0 deletions frame/composable-traits/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ sp-std = { default-features = false, git = "https://github.com/paritytech/subst
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
serde = { version = '1', optional = true }
plotters = {version = "0.3.1", optional = true}
bitflags = "1.3.2"

[dev-dependencies]
proptest = { version = "1.0" }
Expand Down
33 changes: 20 additions & 13 deletions frame/composable-traits/src/auction.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
dex::Orderbook,
loans::{DurationSeconds, Timestamp},
loans::{DurationSeconds, PriceStructure, Timestamp},
};
use frame_support::pallet_prelude::*;
use scale_info::TypeInfo;
Expand Down Expand Up @@ -52,7 +52,7 @@ pub enum AuctionExchangeCallback {

#[derive(Default, Decode, Encode, Clone, TypeInfo)]
pub struct LinearDecrease {
/// Seconds after auction start when the price reaches zero
/// The number of seconds until the price reach zero.
pub total: DurationSeconds,
}

Expand All @@ -65,23 +65,30 @@ pub struct StairstepExponentialDecrease {
pub cut: Permill,
}

/// see example of it in clip.sol of makerdao
/// An object from which we can initiate a dutch auction.
// see example of it in clip.sol of makerdao
pub trait DutchAuction {
type OrderId;
type Orderbook: Orderbook;
type AccountId;
type AssetId;
type Balance;
type Order;
type GroupId;

/// Transfers asset from from provided to auction account.
/// It is up to caller to check amount he get after auction.
/// monitors `OrderBook` for possibility to start selling
/// `account_id` who owns order
/// `source_account` for specific specific `asset_id` from which `amount` is transferred
/// onto auction account.
/// `initial_price` for `total_amount`
/// `target_account` where to move account after success sell.
/// Transfer the asset from the provided account to the auction account.
/// The caller is responsible for checking the price at which the auction executed (not known in
/// advance of course).
///
/// Description.
///
/// * `account_id`: the order owner.
/// * `source_account`: the account from which we extract the `amount` of `source_asset_id`
/// from.
/// * `source_asset_id`: the asset we are interested to trade for `target_asset_id`.
/// * `target_account`: the beneficiary of the order.
/// * `total_amount`: the amount of `source_asset_id`.
/// * `price`: the initial price for `total_amount` and some rules.
#[allow(clippy::too_many_arguments)]
fn start(
account_id: &Self::AccountId,
Expand All @@ -90,14 +97,14 @@ pub trait DutchAuction {
target_asset_id: Self::AssetId,
target_account: &Self::AccountId,
total_amount: Self::Balance,
initial_price: Self::Balance,
price: PriceStructure<Self::GroupId, Self::Balance>,
function: AuctionStepFunction,
) -> Result<Self::OrderId, DispatchError>;

/// run existing auctions
/// if some auctions completed, transfer amount to target account
/// `now` current time.
fn run_auctions(now: Timestamp) -> DispatchResult;
fn off_chain_run_auctions(now: Timestamp) -> DispatchResult;

fn get_auction_state(order: &Self::OrderId) -> Option<Self::Order>;

Expand Down
18 changes: 18 additions & 0 deletions frame/composable-traits/src/currency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ use scale_info::TypeInfo;
use sp_runtime::traits::AtLeast32BitUnsigned;
use sp_std::fmt::Debug;

pub type Exponent = u32;

pub trait PriceableAsset
where
Self: Copy,
{
fn unit<T: From<u64>>(&self) -> T {
T::from(10u64.pow(self.smallest_unit_exponent()))
}
fn smallest_unit_exponent(self) -> Exponent;
}

impl PriceableAsset for u128 {
fn smallest_unit_exponent(self) -> Exponent {
0
}
}

/* NOTE(hussein-aitlahcen):
I initially added a generic type to index into the generatable sub-range but realised it was
overkill. Perhaps it will be required later if we want to differentiate multiple sub-ranges
Expand Down
53 changes: 39 additions & 14 deletions frame/composable-traits/src/dex.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
#![allow(dead_code)]
#![allow(clippy::many_single_char_names)]
use frame_support::{
codec::{Decode, Encode},
sp_runtime::Perbill,
};
use codec::{Decode, Encode};
use frame_support::sp_runtime::Perbill;
use scale_info::TypeInfo;
use sp_runtime::{DispatchError, FixedU128, Permill};

use sp_std::vec::Vec;

/// Describes a simple exchanges which does not allow advanced configurations such as slippage.
Expand Down Expand Up @@ -36,6 +31,28 @@ pub struct TakeResult<BALANCE> {
pub total_price: BALANCE,
}

#[derive(Encode, Decode, TypeInfo)]
pub struct SellOrder<OrderId, AccountId> {
pub id: OrderId,
/// account holding sell order amount.
/// if it becomes empty or non existing, and there was no direct call from seller to cancel
/// order, it means amount was sold
pub account: AccountId,
}

#[derive(Encode, Decode)]
pub enum Price<GroupId, Balance> {
Preferred(GroupId, Balance),
Both { preferred_id: GroupId, preferred_price: Balance, any_price: Balance },
Any(Balance),
}

impl<GroupId, Balance> Price<GroupId, Balance> {
pub fn new_any(price: Balance) -> Self {
Self::Any(price)
}
}

/// see for examples:
/// - https://github.com/galacticcouncil/Basilisk-node/blob/master/pallets/exchange/src/lib.rs
/// - https://github.com/Polkadex-Substrate/polkadex-aura-node/blob/master/pallets/polkadex/src/lib.rs
Expand All @@ -45,6 +62,7 @@ pub trait Orderbook {
type Balance;
type AccountId;
type OrderId;
type GroupId;

/// sell. exchanges specified amount of asset to other at specific price
/// `source_price` price per unit
Expand All @@ -55,9 +73,16 @@ pub trait Orderbook {
asset: Self::AssetId,
want: Self::AssetId,
source_amount: Self::Balance,
source_price: Self::Balance,
source_price: Price<Self::GroupId, Self::Balance>,
amm_slippage: Permill,
) -> Result<Self::OrderId, DispatchError>;
) -> Result<SellOrder<Self::OrderId, Self::AccountId>, DispatchError>;

/// updates same existing order with new price
/// to avoid overpay, use `take` with `up_to` price
fn patch(
order_id: Self::OrderId,
price: Price<Self::GroupId, Self::Balance>,
) -> Result<(), DispatchError>;

/// sell. exchanges specified amount of asset to other at market price.
fn market_sell(
Expand All @@ -68,14 +93,14 @@ pub trait Orderbook {
amm_slippage: Permill,
) -> Result<Self::OrderId, DispatchError>;

/// buy
fn take(
/// ask to take order. get not found error if order never existed or was removed. got conflict
/// error if order still on chain but was executed. please subscribe to events dispatched or
/// check your balance or check blockchain history to validate your won the order.
fn ask(
account: &Self::AccountId,
orders: impl Iterator<Item = Self::OrderId>,
up_to: Self::Balance,
) -> Result<TakeResult<Self::Balance>, DispatchError>;

fn is_order_executed(order_id: &Self::OrderId) -> bool;
) -> Result<(), DispatchError>;
}

/// Implement AMM curve from "StableSwap - efficient mechanism for Stablecoin liquidity by Micheal
Expand Down
25 changes: 13 additions & 12 deletions frame/composable-traits/src/lending.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::{loans::Timestamp, rate_model::*};
use codec::Codec;
use frame_support::{pallet_prelude::*, sp_runtime::Perquintill, sp_std::vec::Vec};
use scale_info::TypeInfo;
use sp_runtime::Percent;
Expand All @@ -9,25 +8,24 @@ pub type CollateralLpAmountOf<T> = <T as Lending>::Balance;
pub type BorrowAmountOf<T> = <T as Lending>::Balance;

#[derive(Encode, Decode, Default, TypeInfo)]
pub struct MarketConfigInput<AccountId>
where
AccountId: core::cmp::Ord,
{
pub struct MarketConfigInput<AccountId, GroupId> {
pub reserved: Perquintill,
pub manager: AccountId,
/// can pause borrow & deposits of assets
pub collateral_factor: NormalizedCollateralFactor,
pub under_collaterized_warn_percent: Percent,
pub liquidator: Option<GroupId>,
}

#[derive(Encode, Decode, Default, TypeInfo)]
pub struct MarketConfig<VaultId, AssetId, AccountId> {
pub struct MarketConfig<VaultId, AssetId, AccountId, GroupId> {
pub manager: AccountId,
pub borrow: VaultId,
pub collateral: AssetId,
pub collateral_factor: NormalizedCollateralFactor,
pub interest_rate_model: InterestRateModel,
pub under_collaterized_warn_percent: Percent,
pub liquidator: Option<GroupId>,
}

/// Basic lending with no its own wrapper (liquidity) token.
Expand All @@ -38,12 +36,13 @@ pub struct MarketConfig<VaultId, AssetId, AccountId> {
/// Lenders with be rewarded via vault.
pub trait Lending {
type AssetId;
type VaultId: Codec;
type MarketId: Codec;
type VaultId;
type MarketId;
/// (deposit VaultId, collateral VaultId) <-> MarketId
type AccountId: core::cmp::Ord + Codec;
type AccountId;
type Balance;
type BlockNumber;
type GroupId;

/// Generates the underlying owned vault that will hold borrowable asset (may be shared with
/// specific set of defined collaterals). Creates market for new pair in specified vault. if
Expand Down Expand Up @@ -85,7 +84,7 @@ pub trait Lending {
fn create(
borrow_asset: Self::AssetId,
collateral_asset_vault: Self::AssetId,
config: MarketConfigInput<Self::AccountId>,
config: MarketConfigInput<Self::AccountId, Self::GroupId>,
interest_rate_model: &InterestRateModel,
) -> Result<(Self::MarketId, Self::VaultId), DispatchError>;

Expand Down Expand Up @@ -115,8 +114,10 @@ pub trait Lending {
fn get_markets_for_borrow(vault: Self::VaultId) -> Vec<Self::MarketId>;

#[allow(clippy::type_complexity)]
fn get_all_markets(
) -> Vec<(Self::MarketId, MarketConfig<Self::VaultId, Self::AssetId, Self::AccountId>)>;
fn get_all_markets() -> Vec<(
Self::MarketId,
MarketConfig<Self::VaultId, Self::AssetId, Self::AccountId, Self::GroupId>,
)>;

/// `amount_to_borrow` is the amount of the borrow asset lendings's vault shares the user wants
/// to borrow. Normalizes amounts for calculations.
Expand Down
1 change: 1 addition & 0 deletions frame/composable-traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod liquidation;
pub mod loans;
pub mod math;
pub mod oracle;
pub mod privilege;
pub mod rate_model;
pub mod vault;
pub mod vesting;
Loading

0 comments on commit bbc7879

Please sign in to comment.