From 99fb79a1aefd4617d7e0fe9efbfd6a09a8477fd9 Mon Sep 17 00:00:00 2001 From: Denali Marsh Date: Mon, 22 Feb 2021 21:52:17 +0100 Subject: [PATCH] update spec, add money market deprecation steps (#841) --- x/hard/abci.go | 2 +- x/hard/alias.go | 59 ++++++++++++++++------------------- x/hard/spec/01_concepts.md | 3 +- x/hard/spec/02_state.md | 13 +++++--- x/hard/spec/03_messages.md | 9 +++--- x/hard/spec/04_events.md | 48 +++++++++++----------------- x/hard/spec/05_params.md | 57 +++++++++++++++++---------------- x/hard/spec/06_begin_block.md | 5 ++- x/hard/types/events.go | 45 ++++++++++++-------------- 9 files changed, 112 insertions(+), 129 deletions(-) diff --git a/x/hard/abci.go b/x/hard/abci.go index f66b3410..8b7c88bc 100644 --- a/x/hard/abci.go +++ b/x/hard/abci.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// BeginBlocker updates interest rates and attempts liquidations +// BeginBlocker updates interest rates func BeginBlocker(ctx sdk.Context, k Keeper) { k.ApplyInterestRateUpdates(ctx) } diff --git a/x/hard/alias.go b/x/hard/alias.go index aa9b7d1a..bb72aeb7 100644 --- a/x/hard/alias.go +++ b/x/hard/alias.go @@ -8,38 +8,33 @@ import ( ) const ( - AttributeKeyBlockHeight = types.AttributeKeyBlockHeight - AttributeKeyBorrow = types.AttributeKeyBorrow - AttributeKeyBorrowCoins = types.AttributeKeyBorrowCoins - AttributeKeyBorrower = types.AttributeKeyBorrower - AttributeKeyDeposit = types.AttributeKeyDeposit - AttributeKeyDepositCoins = types.AttributeKeyDepositCoins - AttributeKeyDepositDenom = types.AttributeKeyDepositDenom - AttributeKeyDepositor = types.AttributeKeyDepositor - AttributeKeyRepayCoins = types.AttributeKeyRepayCoins - AttributeKeyRewardsDistribution = types.AttributeKeyRewardsDistribution - AttributeKeySender = types.AttributeKeySender - AttributeValueCategory = types.AttributeValueCategory - DefaultParamspace = types.DefaultParamspace - EventTypeDeleteHardDeposit = types.EventTypeDeleteHardDeposit - EventTypeHardLiquidation = types.EventTypeHardLiquidation - EventTypeHardBorrow = types.EventTypeHardBorrow - EventTypeHardDelegatorDistribution = types.EventTypeHardDelegatorDistribution - EventTypeHardDeposit = types.EventTypeHardDeposit - EventTypeHardLPDistribution = types.EventTypeHardLPDistribution - EventTypeHardRepay = types.EventTypeHardRepay - EventTypeHardWithdrawal = types.EventTypeHardWithdrawal - ModuleAccountName = types.ModuleAccountName - ModuleName = types.ModuleName - QuerierRoute = types.QuerierRoute - QueryGetBorrows = types.QueryGetBorrows - QueryGetDeposits = types.QueryGetDeposits - QueryGetModuleAccounts = types.QueryGetModuleAccounts - QueryGetParams = types.QueryGetParams - QueryGetTotalBorrowed = types.QueryGetTotalBorrowed - QueryGetTotalDeposited = types.QueryGetTotalDeposited - RouterKey = types.RouterKey - StoreKey = types.StoreKey + AttributeKeyBorrow = types.AttributeKeyBorrow + AttributeKeyBorrowCoins = types.AttributeKeyBorrowCoins + AttributeKeyBorrower = types.AttributeKeyBorrower + AttributeKeyDeposit = types.AttributeKeyDeposit + AttributeKeyDepositCoins = types.AttributeKeyDepositCoins + AttributeKeyDepositDenom = types.AttributeKeyDepositDenom + AttributeKeyDepositor = types.AttributeKeyDepositor + AttributeKeyRepayCoins = types.AttributeKeyRepayCoins + AttributeKeySender = types.AttributeKeySender + AttributeValueCategory = types.AttributeValueCategory + DefaultParamspace = types.DefaultParamspace + EventTypeHardLiquidation = types.EventTypeHardLiquidation + EventTypeHardBorrow = types.EventTypeHardBorrow + EventTypeHardDeposit = types.EventTypeHardDeposit + EventTypeHardRepay = types.EventTypeHardRepay + EventTypeHardWithdrawal = types.EventTypeHardWithdrawal + ModuleAccountName = types.ModuleAccountName + ModuleName = types.ModuleName + QuerierRoute = types.QuerierRoute + QueryGetBorrows = types.QueryGetBorrows + QueryGetDeposits = types.QueryGetDeposits + QueryGetModuleAccounts = types.QueryGetModuleAccounts + QueryGetParams = types.QueryGetParams + QueryGetTotalBorrowed = types.QueryGetTotalBorrowed + QueryGetTotalDeposited = types.QueryGetTotalDeposited + RouterKey = types.RouterKey + StoreKey = types.StoreKey ) var ( diff --git a/x/hard/spec/01_concepts.md b/x/hard/spec/01_concepts.md index 3acc7821..1886376f 100644 --- a/x/hard/spec/01_concepts.md +++ b/x/hard/spec/01_concepts.md @@ -6,9 +6,8 @@ order: 1 ## Automated, Cross-Chain Money Markets -The hard module provides for functionality and governance of a two-sided money market protocol with autonomous interest rates and partially autonomous liquidations. The main state transitions in the hard module are composed of deposit, withdraw, borrow and repay actions. Additionally, borrow positions can be liquidated by the autonomous liquidation engine or by an external party called a "keeper". Keepers receive a fee in exchange for liquidating risk positions, and the fee rate is determined by governance. Internally, all funds are stored in a module account (the cosmos-sdk equivalent of the `address` portion of a smart contract), and can be accessed via the above actions. Each money market has governance parameters which are controlled by token-holder governance. Of particular note are the interest rate model, which determines (using a static formula) what the prevailing rate of interest will be for each block, and the loan-to-value (LTV), which determines how much borrowing power each unit of deposited collateral will count for. Initial parameterization of the hard module will stipulate that all markets are over-collateralized and that overall borrow limits for each collateral will start small and rise gradually. +The hard module provides for functionality and governance of a two-sided money market protocol with autonomous interest rates. The main state transitions in the hard module are composed of deposit, withdraw, borrow and repay actions. Borrow positions can be liquidated by an external party called a "keeper". Keepers receive a fee in exchange for liquidating risk positions, and the fee rate is determined by governance. Internally, all funds are stored in a module account (the cosmos-sdk equivalent of the `address` portion of a smart contract), and can be accessed via the above actions. Each money market has governance parameters which are controlled by token-holder governance. Of particular note are the interest rate model, which determines (using a static formula) what the prevailing rate of interest will be for each block, and the loan-to-value (LTV), which determines how much borrowing power each unit of deposited collateral will count for. Initial parameterization of the hard module will stipulate that all markets are over-collateralized and that overall borrow limits for each collateral will start small and rise gradually. ## HARD Token distribution [See Incentive Module](../../incentive/spec/01_concepts.md) - diff --git a/x/hard/spec/02_state.md b/x/hard/spec/02_state.md index 0b198b8b..6d91cf1d 100644 --- a/x/hard/spec/02_state.md +++ b/x/hard/spec/02_state.md @@ -6,13 +6,19 @@ order: 2 ## Parameters and Genesis State -`Parameters` define the governance parameters and default behavior of each money market. +`Parameters` define the governance parameters and default behavior of each money market. **Money markets should not be removed from params without careful procedures** as it will disable withdraws and liquidations. To deprecate a money market, the following steps should be observed: + +1. Borrowing: prevent new borrows by setting param MoneyMarket.BorrowLimit.MaximumLimit to 0. +2. Interest: turn off interest accumulation by setting params MoneyMarket.InterestRateModel.BaseRateAPY and MoneyMarket.InterestRateModel.Kink to 0. +3. Rewards: turn off supply side and/or borrow side rewards by removing any coins in the relevant RewardsPerSecond param in the Incentive module. + +Without financial incentives, borrowers and suppliers will withdraw their funds from the money market over time. Once the balances have reached an acceptable level the money market can be deprecated and removed from params, with any additional lingering user funds reimbursed/reallocated as appropriate via a chain upgrade. ```go // Params governance parameters for hard module type Params struct { - MoneyMarkets MoneyMarkets `json:"money_markets" yaml:"money_markets"` // defines the parameters for each money market - CheckLtvIndexCount int `json:"check_ltv_index_count" yaml:"check_ltv_index_count"` // defines the number of positions that are checked for liquidation at the beginning of each block + MoneyMarkets MoneyMarkets `json:"money_markets" yaml:"money_markets"` + MinimumBorrowUSDValue sdk.Dec `json:"minimum_borrow_usd_value" yaml:"minimum_borrow_usd_value"` } // MoneyMarket is a money market for an individual asset @@ -23,7 +29,6 @@ type MoneyMarket struct { ConversionFactor sdk.Int `json:"conversion_factor" yaml:"conversion_factor"` //the internal conversion factor for going from the smallest unit of a token to a whole unit (ie. 8 for BTC, 6 for KAVA, 18 for ETH) InterestRateModel InterestRateModel `json:"interest_rate_model" yaml:"interest_rate_model"` // the model that determines the prevailing interest rate at each block ReserveFactor sdk.Dec `json:"reserve_factor" yaml:"reserve_factor"` // the percentage of interest that is accumulated by the protocol as reserves - AuctionSize sdk.Int `json:"auction_size" yaml:"auction_size"` // the maximum size of auction for this money market. Liquidations larger than this will be broken down into multiple auctions KeeperRewardPercentage sdk.Dec `json:"keeper_reward_percentage" yaml:"keeper_reward_percentages"` // the percentage of a liquidation that is given to the keeper that liquidated the position } diff --git a/x/hard/spec/03_messages.md b/x/hard/spec/03_messages.md index 1419bd5c..15580606 100644 --- a/x/hard/spec/03_messages.md +++ b/x/hard/spec/03_messages.md @@ -39,12 +39,13 @@ This message creates a `Borrow` object is one does not exist, or updates an exis ```go // MsgRepay repays funds to the hard module. type MsgRepay struct { - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - Amount sdk.Coins `json:"amount" yaml:"amount"` + Sender sdk.AccAddress `json:"sender" yaml:"sender"` + Owner sdk.AccAddress `json:"owner" yaml:"owner"` + Amount sdk.Coins `json:"amount" yaml:"amount"` } ``` -This message decrements a `Borrow` object, or deletes one if the `Amount` specified is greater than or equal to the total borrowed amount, as well as creating/updating the necessary indexes and synchronizing any outstanding interest. For example, a message which requests to repay 100xyz tokens, if `Sender` has only deposited 50xyz tokens, will repay the full 50xyz tokens. The `Amount` of coins, or the current borrow amount, is transferred from `Sender`. The global variable for `TotalBorrowed` is updated. +This message decrements a `Borrow` object, or deletes one if the `Amount` specified is greater than or equal to the total borrowed amount, as well as creating/updating the necessary indexes and synchronizing any outstanding interest. For example, a message which requests to repay 100xyz tokens, if `Owner` has only deposited 50xyz tokens, the `Sender` will repay the full 50xyz tokens. The `Amount` of coins, or the current borrow amount, is transferred from `Sender`. The global variable for `TotalBorrowed` is updated. ```go // MsgLiquidate attempts to liquidate a borrower's borrow @@ -54,4 +55,4 @@ type MsgLiquidate struct { } ``` -This message deletes `Borrower's` `Deposit` and `Borrow` objects if they are below the required LTV ratio. The keeper (the sender of the message) is rewarded a portion of the borrow position, according to the `KeeperReward` governance parameter. The coins from the `Deposit` are then sold at auction (see [auction module](../../auction/spec/README.md)), which any remaining tokens returned to `Borrower`. After being liquidated, `Borrower` no longer must repay the borrow amount. The global variables for `TotalSupplied` and `TotalBorrowed` are updated. \ No newline at end of file +This message deletes `Borrower's` `Deposit` and `Borrow` objects if they are below the required LTV ratio. The keeper (the sender of the message) is rewarded a portion of the borrow position, according to the `KeeperReward` governance parameter. The coins from the `Deposit` are then sold at auction (see [auction module](../../auction/spec/README.md)), which any remaining tokens returned to `Borrower`. After being liquidated, `Borrower` no longer must repay the borrow amount. The global variables for `TotalSupplied` and `TotalBorrowed` are updated. diff --git a/x/hard/spec/04_events.md b/x/hard/spec/04_events.md index adfc1325..44532100 100644 --- a/x/hard/spec/04_events.md +++ b/x/hard/spec/04_events.md @@ -19,38 +19,28 @@ The hard module emits the following events: ### MsgWithdraw -| Type | Attribute Key | Attribute Value | -| ------------------- | ------------- | --------------------- | -| message | module | hard | -| message | sender | `{sender address}` | -| hard_withdrawal | amount | `{amount}` | -| hard_withdrawal | depositor | `{depositor address}` | +| Type | Attribute Key | Attribute Value | +| --------------- | ------------- | --------------------- | +| message | module | hard | +| message | sender | `{sender address}` | +| hard_withdrawal | amount | `{amount}` | +| hard_withdrawal | depositor | `{depositor address}` | ### MsgBorrow -| Type | Attribute Key | Attribute Value | -| -------------- | ------------- | --------------------- | -| message | module | hard | -| message | sender | `{sender address}` | -| hard_borrow | borrow_coins | `{amount}` | -| hard_withdrawal| borrower | `{borrower address}` | +| Type | Attribute Key | Attribute Value | +| --------------- | ------------- | -------------------- | +| message | module | hard | +| message | sender | `{sender address}` | +| hard_borrow | borrow_coins | `{amount}` | +| hard_withdrawal | borrower | `{borrower address}` | ### MsgRepay -| Type | Attribute Key | Attribute Value | -| -------------- | ------------- | --------------------- | -| message | module | hard | -| message | sender | `{sender address}` | -| hard_repay | repay_coins | `{amount}` | -| hard_repay | sender | `{borrower address}` | - -## BeginBlock - -| Type | Attribute Key | Attribute Value | -| --------------------------- | ------------------- | ----------------------- | -| hard_lp_distribution | block_height | `{block height}` | -| hard_lp_distribution | rewards_distributed | `{rewards distributed}` | -| hard_lp_distribution | deposit_denom | `{deposit denom}` | -| hard_delegator_distribution | block_height | `{block height}` | -| hard_delegator_distribution | rewards_distributed | `{rewards distributed}` | -| hard_delegator_distribution | deposit_denom | `{deposit denom}` | +| Type | Attribute Key | Attribute Value | +| ---------- | ------------- | -------------------- | +| message | module | hard | +| message | sender | `{sender address}` | +| message | owner | `{owner address}` | +| hard_repay | repay_coins | `{amount}` | +| hard_repay | sender | `{borrower address}` | diff --git a/x/hard/spec/05_params.md b/x/hard/spec/05_params.md index 4aced17f..6f4ad2c5 100644 --- a/x/hard/spec/05_params.md +++ b/x/hard/spec/05_params.md @@ -4,39 +4,38 @@ order: 5 # Parameters -The hard module has the following parameters: +Example parameters for the Hard module: -| Key | Type | Example | Description | -| ------------------------------ | ------------------------------------- | ------------- | ----------------------------------------------------------------------------| -| MoneyMarkets | array (MoneyMarket) | [{see below}] | array of params for each supported market | -| CheckLtvIndexCount | int | 6 | Number of borrow positions to check for liquidation in each begin blocker | +| Key | Type | Example | Description | +| --------------------- | ------------------- | ------------- | -------------------------------------------- | +| MoneyMarkets | array (MoneyMarket) | [{see below}] | Array of params for each supported market | +| MinimumBorrowUSDValue | sdk.Dec | 10.0 | Minimum amount an individual user can borrow | -Each `MoneyMarket` has the following parameters +Example parameters for `MoneyMarket`: -| Key | Type | Example | Description | -| ------------------------- | ------------------ | ---------------------- | --------------------------------------------------------------------- | -| Denom | string | "bnb" | coin denom of the asset which can be deposited and borrowed | -| BorrowLimit | BorrowLimit | [{see below}] | borrow limits applied to this money market | -| SpotMarketID | string | "bnb:usd" | the market id which determines the price of the asset | -| ConversionFactor | Int | "6" | conversion factor for one unit (ie BNB) to the smallest internal unit | -| InterestRateModel | InterestRateModel | [{see below}] | Model which determines the prevailing interest rate per block | -| ReserveFactor | Dec | "0.01" | Percentage of interest that is kept as protocol reserves | -| AuctionSize | Int | "1000000000" | The maximum size of an individual auction | -| KeeperRewardPercentage | Dec | "0.02" | Percentage of deposit rewarded to keeper who liquidates a position | +| Key | Type | Example | Description | +| ---------------------- | ----------------- | ------------- | --------------------------------------------------------------------- | +| Denom | string | "bnb" | Coin denom of the asset which can be deposited and borrowed | +| BorrowLimit | BorrowLimit | [{see below}] | Borrow limits applied to this money market | +| SpotMarketID | string | "bnb:usd" | The market id which determines the price of the asset | +| ConversionFactor | Int | "6" | Conversion factor for one unit (ie BNB) to the smallest internal unit | +| InterestRateModel | InterestRateModel | [{see below}] | Model which determines the prevailing interest rate per block | +| ReserveFactor | Dec | "0.01" | Percentage of interest that is kept as protocol reserves | +| KeeperRewardPercentage | Dec | "0.02" | Percentage of deposit rewarded to keeper who liquidates a position | -Each `BorrowLimit` has the following parameters +Example parameters for `BorrowLimit`: -| Key | Type | Example | Description | -| --------------------- | ------------------ | ---------------------- | ------------------------------------------------------------------------ | -| HasMaxLimit | bool | "true" | boolean for if a maximum limit is in effect | -| MaximumLimit | Dec | "10000000.0" | global maximum amount of coins that can be borrowed | -| LoanToValue | Dec | "0.5" | the percentage amount of borrow power each unit of deposit accounts for | +| Key | Type | Example | Description | +| ------------ | ---- | ------------ | ----------------------------------------------------------------------- | +| HasMaxLimit | bool | "true" | Boolean for if a maximum limit is in effect | +| MaximumLimit | Dec | "10000000.0" | Global maximum amount of coins that can be borrowed | +| LoanToValue | Dec | "0.5" | The percentage amount of borrow power each unit of deposit accounts for | -Each `InterestRateModel` has the following parameters +Example parameters for `InterestRateModel`: -| Key | Type | Example | Description | -| ---------------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------- | -| BaseRateAPY | Dec | "0.0" | the base rate of APY interest when borrows are zero. | -| BaseMultiplier | Dec | "0.01" | the percentage rate at which the interest rate APY increases for each percentage increase in borrow utilization. | -| Kink | Dec | "0.5" | the inflection point of utilization at which the BaseMultiplier no longer applies and the JumpMultiplier does. | -| JumpMultiplier | Dec | "0.5" | same as BaseMultiplier, but only applied when utilization is above the Kink | +| Key | Type | Example | Description | +| -------------- | ---- | ------- | --------------------------------------------------------------------------------------------------------------- | +| BaseRateAPY | Dec | "0.0" | The base rate of APY interest when borrows are zero | +| BaseMultiplier | Dec | "0.01" | The percentage rate at which the interest rate APY increases for each percentage increase in borrow utilization | +| Kink | Dec | "0.5" | The inflection point of utilization at which the BaseMultiplier no longer applies and the JumpMultiplier does | +| JumpMultiplier | Dec | "0.5" | Same as BaseMultiplier, but only applied when utilization is above the Kink | diff --git a/x/hard/spec/06_begin_block.md b/x/hard/spec/06_begin_block.md index 3de668e5..173fb954 100644 --- a/x/hard/spec/06_begin_block.md +++ b/x/hard/spec/06_begin_block.md @@ -4,12 +4,11 @@ order: 6 # Begin Block -At the start of each block, interest is accumulated, and automated liquidations are attempted +At the start of each block interest is accumulated ```go -// BeginBlocker updates interest rates and attempts liquidations +// BeginBlocker updates interest rates func BeginBlocker(ctx sdk.Context, k Keeper) { k.ApplyInterestRateUpdates(ctx) - k.AttemptIndexLiquidations(ctx) } ``` diff --git a/x/hard/types/events.go b/x/hard/types/events.go index 6db08778..d0b1386e 100644 --- a/x/hard/types/events.go +++ b/x/hard/types/events.go @@ -2,29 +2,24 @@ package types // Event types for hard module const ( - EventTypeHardDeposit = "hard_deposit" - EventTypeHardDelegatorDistribution = "hard_delegator_distribution" - EventTypeHardLPDistribution = "hard_lp_distribution" - EventTypeDeleteHardDeposit = "delete_hard_deposit" - EventTypeHardWithdrawal = "hard_withdrawal" - EventTypeHardBorrow = "hard_borrow" - EventTypeHardLiquidation = "hard_liquidation" - EventTypeHardRepay = "hard_repay" - AttributeValueCategory = ModuleName - AttributeKeyBlockHeight = "block_height" - AttributeKeyRewardsDistribution = "rewards_distributed" - AttributeKeyDeposit = "deposit" - AttributeKeyDepositDenom = "deposit_denom" - AttributeKeyDepositCoins = "deposit_coins" - AttributeKeyDepositor = "depositor" - AttributeKeyBorrow = "borrow" - AttributeKeyBorrower = "borrower" - AttributeKeyBorrowCoins = "borrow_coins" - AttributeKeySender = "sender" - AttributeKeyRepayCoins = "repay_coins" - AttributeKeyLiquidatedOwner = "liquidated_owner" - AttributeKeyLiquidatedCoins = "liquidated_coins" - AttributeKeyKeeper = "keeper" - AttributeKeyKeeperRewardCoins = "keeper_reward_coins" - AttributeKeyOwner = "owner" + EventTypeHardDeposit = "hard_deposit" + EventTypeHardWithdrawal = "hard_withdrawal" + EventTypeHardBorrow = "hard_borrow" + EventTypeHardLiquidation = "hard_liquidation" + EventTypeHardRepay = "hard_repay" + AttributeValueCategory = ModuleName + AttributeKeyDeposit = "deposit" + AttributeKeyDepositDenom = "deposit_denom" + AttributeKeyDepositCoins = "deposit_coins" + AttributeKeyDepositor = "depositor" + AttributeKeyBorrow = "borrow" + AttributeKeyBorrower = "borrower" + AttributeKeyBorrowCoins = "borrow_coins" + AttributeKeySender = "sender" + AttributeKeyRepayCoins = "repay_coins" + AttributeKeyLiquidatedOwner = "liquidated_owner" + AttributeKeyLiquidatedCoins = "liquidated_coins" + AttributeKeyKeeper = "keeper" + AttributeKeyKeeperRewardCoins = "keeper_reward_coins" + AttributeKeyOwner = "owner" )