Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

refactor!: Rename Lend to Supply #1106

Merged
merged 18 commits into from
Jul 5, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

- [1029](https://github.com/umee-network/umee/pull/1029) Removed MsgSetCollateral(addr,denom,bool), and replaced with MsgAddCollateral(addr,coin) and MsgRemoveCollateral(addr,coin)
- [1023](https://github.com/umee-network/umee/pull/1023) Restrict MsgWithdraw to only uToken input (no base token auto-convert)
- [1106](https://github.com/umee-network/umee/pull/1106) Rename Lend to Supply, including MsgLendAsset, Token EnableLend, docs, and internal functions. Also QueryLoaned similar queries to QuerySupplied.

### Features

Expand Down
2 changes: 1 addition & 1 deletion app/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func IntegrationTestNetworkConfig() network.Config {
MaxBorrowRate: sdk.MustNewDecFromStr("1.50000000000000000"),
KinkUtilization: sdk.MustNewDecFromStr("0.200000000000000000"),
LiquidationIncentive: sdk.MustNewDecFromStr("0.180000000000000000"),
EnableMsgLend: true,
EnableMsgSupply: true,
EnableMsgBorrow: true,
Blacklist: false,
})
Expand Down
4 changes: 2 additions & 2 deletions docs/architecture/ADR-001-interest-stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ As an alternative, transfer of uTokens via IBC could be forbidden or unsupported

- Requirement: Umee chain stores uAsset <-> Asset exchange rate for each asset (not 1:1)

In this implementation, for each whitelisted Cosmos asset type, the Umee chain stores an "exchange rate" between the base asset and its associated uToken. The exchange rate starts equal to 1, and increases whenever interest would have been applied to uToken balances in the original implementation. Whenever a lender deposits or withdraws base assets for uToken, this exchange rate is used.
In this implementation, for each whitelisted Cosmos asset type, the Umee chain stores an "exchange rate" between the base asset and its associated uToken. The exchange rate starts equal to 1, and increases whenever interest would have been applied to uToken balances in the original implementation. Whenever a user supplies or withdraws base assets for uToken, this exchange rate is used.

Example scenario:

> Two lenders Alice and Bob provide Atoms to the asset facility at different times and earn interest. Assume that for the duration of this scenario, the interest on deposited uAtoms is 0.1 percent per week (or 1 atom per week per 1000 deposited).
> Two users Alice and Bob supply Atoms to the asset facility at different times and earn interest. Assume that for the duration of this scenario, the interest on deposited uAtoms is 0.1 percent per week (or 1 atom per week per 1000 deposited).
>
> The asset facility starts with 0 atoms in custody and 0 uAtoms in circulation. The exchange rate of Atom:uAtom starts at 1.
>
Expand Down
24 changes: 12 additions & 12 deletions docs/architecture/ADR-002-deposit-assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ Accepted

One of the base functions of the Umee universal capital facility is to allow liquidity providers to deposit assets, and earn interest on their deposits.

The associated feature “Lender deposits asset for uToken & redeems uToken for a single Cosmos asset type" was initially discussed as follows:
The associated feature “User supplies asset for uToken & redeems uToken for a single Cosmos asset type" was initially discussed as follows:

- Lender deposits (locks) a Cosmos asset (like Atoms or Umee) into asset facilities.
- User supplies (locks) a Cosmos asset (like Atoms or Umee) into asset facilities.
- Facility mints and sends u-Assets in response (u-Atom, u-umee).
- Lender redeems u-Assets for the original assets.
- User redeems u-Assets for the original assets.
- Asset facility knows its current balances of all asset types.
- Asset facility knows the amount of all u-Asset types in circulation.

Expand Down Expand Up @@ -71,41 +71,41 @@ The `sdk.Coins` type is a slice (ordered list) of `sdk.Coin` which contains a de
Asset Facility deposit functionality is provided by the two following message types:

```go
// MsgLendAsset - a lender wishes to deposit assets and receive uAssets
type MsgLendAsset struct {
Lender sdk.AccAddress `json:"lender" yaml:"lender"`
// MsgSupply - a user wishes to deposit assets and receive uAssets
type MsgSupply struct {
Supplier sdk.AccAddress `json:"supplier" yaml:"supplier"`
Amount sdk.Coin `json:"amount" yaml:"amount"`
}

// MsgWithdrawAsset - redeems uAsset for original assets
type MsgWithdrawAsset struct {
// Lender is the owner of the uAsset
Lender sdk.AccAddress `json:"lender" yaml:"lender"`
// Supplier is the owner of the uAsset
Supplier sdk.AccAddress `json:"supplier" yaml:"supplier"`
Amount sdk.Coin `json:"amount" yaml:"amount"`
}
```

This resembles the built-in MsgSend, but either ToAddress or FromAddress is removed because the module's address should be used automatically. The remaining address is that of the lender.
This resembles the built-in MsgSend, but either ToAddress or FromAddress is removed because the module's address should be used automatically. The remaining address is that of the supplier.

MsgDepositAsset must use only allow-listed, non-uToken denominations. MsgWithdrawAsset must use only uToken denominations.

These messages should trigger the appropriate reaction (disbursement of uTokens after deposit, return of assets on withdrawal). The exchange rate defined in ADR-001 must be used.

_Note: The `Coin` type seen in the `Amount` fields contains a single token denomination and amount._

It is necessary that `MsgLendAsset` and `MsgWithdrawAsset` be signed by the lender's account. According to the [Transactions Page](https://docs.cosmos.network/master/core/transactions.html)
It is necessary that `MsgSupply` and `MsgWithdrawAsset` be signed by the supplier's account. According to the [Transactions Page](https://docs.cosmos.network/master/core/transactions.html)

> Every message in a transaction must be signed by the addresses specified by its GetSigners.

Thus `MsgLendAsset.GetSigners` and `MsgWithdrawAsset.GetSigners` should return the `Lender` address.
Thus `MsgSupply.GetSigners` and `MsgWithdrawAsset.GetSigners` should return the `Supplier` address.

### API

Both CLI and gRPC must be supported when sending the above message types, and all necessary handlers must be created in order to process and validate them as transactions. As part of this initial feature, an exact list of such steps required when adding message types will be created and added to future issues.

### Testing

Assuming a placeholder token allow-list of one element (e.g. `umee`), and a uToken existing (e.g. `u-umee`), an end-to-end test can be created in which one user account sends a `MsgLendAsset` and a `MsgWithdrawAsset` of the appropriate token types.
Assuming a placeholder token allow-list of one element (e.g. `umee`), and a uToken existing (e.g. `u-umee`), an end-to-end test can be created in which one user account sends a `MsgSupply` and a `MsgWithdrawAsset` of the appropriate token types.

## Considerations

Expand Down
12 changes: 6 additions & 6 deletions docs/architecture/ADR-003-borrow-assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ collateral_utilization(tokenA) = total_collateral(tokenA) / available_supply(tok
Note: system must not allow to have available_supply to equal zero.

Intuition: we want collateral utilization to grow when there is less liquid tokenA available in the system to cover the liquidation.
Collateral utilization of tokenA is growing when lenders withdraw their tokenA collateral or when borrowers take a new loan of tokenA.
Collateral utilization of tokenA is growing when suppliers withdraw their tokenA collateral or when borrowers take a new loan of tokenA.
If a `tokenA` is not used a collateral then it's _collateral utilization_ is zero.
It is bigger than 1 when available supply is lower than the amount of `tokenA` used as a collateral.
When it is `N`, it means that only `1/N` of the collateral is available for redemption (u/tokenA -> tokenA).

#### Examples

Let's say we have 1000A (token A) provided to a system for lending. Below let's consider a state with total amount of A borrowed (B) and total amount of B used as a collateral (C) and computed collateral utilization (CU):
Let's say we have 1000A (token A) supplied to the system (for lending or collateral). Below let's consider a state with total amount of A borrowed (B) and total amount of B used as a collateral (C) and computed collateral utilization (CU):

1. B=0, C=0 → CU=0
1. B=0, C=500 → CU=0.5
Expand All @@ -88,20 +88,20 @@ Let's say we have 1000A (token A) provided to a system for lending. Below let's

High collateral utilization is dangerous for the system:

- When collateral utilization is above 1, lenders may not be able to withdraw their the liquidated collateral.
- When collateral utilization is above 1, liquidators may not be able to withdraw their the liquidated collateral.
- Liquidators, when liquidating a borrower, they get into position their _uToken_.
In case of bad market conditions and magnified liquidations, liquidators will like to redeem the _uToken_ for the principle (the underlying token).
However, when there are many `uToken` redeem operation, the collateral utilization is approaching to 1 and liquidators won't be able to get the principle and sell it to monetize their profits.
This will dramatically increase the risk of getting a profit by liquidators and could cause the system being insolvent.

Let's draw the following scenario to picture the liquidators risk:

1. Alice is providing \$1.2M USD for lending.
1. Alice is providing \$1.2M USD supply.
2. Bob is providing \$1.5M in Luna as a collateral and borrows 1M USD from Alice.
3. Charlie provides \$2M in BTC as a collateral and borrows $1.4M in Luna from Bob.
4. Charlie predicts Luna collapse and sells the Luna.
5. Luna is sinking and Bob position has to be liquidated. However:
- Lenders can liquidate Bob, but they can only redeem up to 6.6% of `u/Luna` because the rest is not available (Charlie borrowed it).
- Suppliers can liquidate Bob, but they can only redeem up to 6.6% of `u/Luna` because the rest is not available (Charlie borrowed it).
- Charlie will not pay off her borrow position - she will wait for the final collapse and buy Luna cheaply.
- Liquidators will not take the risk of obtaining and holding `u/Luna` when there is a risk of Luna sinking deep.
6. In case of the big crash, liquidators won't perform a liquidation, Bob will run away with 1M USD, system will end up with a bad debt and obligation to pay Alice.
Expand Down Expand Up @@ -184,7 +184,7 @@ In contrast, if we had put tokenDenom before borrower address, it would favor op

### Positive

- uTokens used as a collateral increase in base asset value in the same way that lends positions do. This counteracts borrow position interest.
- uTokens used as a collateral increase in base asset value in the same way that supply positions do. This counteracts borrow position interest.
- UX of enabling/disabling token types as collateral is simpler than depositing specific amounts
- `lengthPrefixed(borrowerAddress) | tokenDenom` key pattern facilitates getting open borrow and collateral positions by account address.

Expand Down
16 changes: 8 additions & 8 deletions docs/architecture/ADR-004-interest-and-reserves.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ Accepted
## Context

Borrow positions on Umee accrue interest over time.
When interest accrues, the sum of all assets owed by all users increases for each borrowed token denomination. The amount of that increase serves to benefit lenders (by increasing the token:uToken exchange rate), and also to increase the amount of base assets the Umee system holds in reserve.
When interest accrues, the sum of all assets owed by all users increases for each borrowed token denomination. The amount of that increase serves to benefit suppliers (by increasing the token:uToken exchange rate), and also to increase the amount of base assets the Umee system holds in reserve.

The mechanism by which interest is calculated, and then split between incentivizing lenders as per [ADR-001](./ADR-001-interest-stream.md) and reserves as defined in this ADR, will follow.
The mechanism by which interest is calculated, and then split between incentivizing suppliers as per [ADR-001](./ADR-001-interest-stream.md) and reserves as defined in this ADR, will follow.

## Decision

Expand Down Expand Up @@ -70,7 +70,7 @@ We modify the Compound formula to use collateral utilization rather than supply

The `x/leverage` module keeper will contain a function which accrues interest on all open borrow positions at once, which is called when `EndBlock` detects that has elapsed.

The accrued interest is split between protocol reserves and lender profits as explained in the following sections.
The accrued interest is split between protocol reserves and supplier profits as explained in the following sections.

```go
func (k Keeper) AccrueAllInterest(ctx sdk.Context) error {
Expand Down Expand Up @@ -131,13 +131,13 @@ for _, coin := range newReserves {

The token:uToken exchange rate, which would have previously been calculated by `(total tokens borrowed + module account balance) / uTokens in circulation` for a given token and associated uToken, must now be computed as `(total tokens borrowed + module account balance - reserved amount) / uTokens in circulation`.

Also, because Lend, Withdraw, Borrow, and Repay transactions don't affect the token:uToken exchange rate, it's enough to update the exchange rate during the EndBlocker `AccrueAllInterest`.
Also, because Supply, Withdraw, Borrow, and Repay transactions don't affect the token:uToken exchange rate, it's enough to update the exchange rate during the EndBlocker `AccrueAllInterest`.

### Modifications to Withdraw and Borrow

Existing functionality will be modified:

- Asset withdrawal (by lenders) will not permit withdrawals that would reduce the module account's balance of a token to below the reserved amount of that token.
- Asset withdrawal (by suppliers) will not permit withdrawals that would reduce the module account's balance of a token to below the reserved amount of that token.
- Asset borrowing (by borrowers) will not permit borrows that would do the same.

### Example Scenarios
Expand All @@ -160,18 +160,18 @@ Note that the module "reserved amount" has increased, but not the actual balance
Here is an additional example scenario, to illustrate that the module account balance of a given token _can_ become less than the reserved amount, when a token type is at or near 100% supply utilization:

> Lending pool and reserve amount of `atom` both start at zero.
> Bob, lends 1000 `atom` to the lending pool.
> Bob, supplies 1000 `atom` to the lending pool.
> Alice immediately borrows all 1000 `atom`.
>
> During the next `EndBlock`. Alice now owes 1000.001 `atom`. The amount of `uatom` the module is required to reserve increases from 0 to 50 (assuming the `ReserveFactor` parameter is 0.05 like in the previous example).
>
> The module account (lending pool + reserves) still contains 0 `uatom` due to the first two steps. Its `uatom` balance is therefore less than the required 50 `uatom` reserves.

The scenario above is not fatal to our model - Bob (lender) continues to gain value as the token:uToken exchange rate increases, and we are not storing any negative numbers in place of balances - but the next 50 `uatom` lent by a lender or repaid by a borrower will be blocked for the reserve requirements rather than being immediately available for borrowing or withdrawal.
The scenario above is not fatal to our model - Bob (supplier) continues to gain value as the token:uToken exchange rate increases, and we are not storing any negative numbers in place of balances - but the next 50 `uatom` supplied by a supplier or repaid by a borrower will be blocked for the reserve requirements rather than being immediately available for borrowing or withdrawal.

The edge case above can only occur when the available lending pool (i.e. module account balance minus reserve requirements) for a specific token denomination, is less than `ReserveFactor` times the interest accrued on all open loans for that token in a single block. In practical terms, that means ~100% supply utilization.

This is not a threatening scenario, as it resolves as soon as either a sufficient `RepayAsset` or a `LendAsset` is made in the relevant asset type, both of which are **highly** incentivized by the extreme dynamic interest rates found near 100% utilization.
This is not a threatening scenario, as it resolves as soon as either a sufficient `RepayAsset` or a `MsgSupply` is made in the relevant asset type, both of which are **highly** incentivized by the extreme dynamic interest rates found near 100% utilization.

## Consequences

Expand Down
8 changes: 4 additions & 4 deletions docs/architecture/ADR-008-borrow-tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ This change in borrow storage will be opaque to other parts of the leverage modu

As a result of efficiency gains, the parameter `InterestEpoch` will be removed, with periodic functions taking place every block.

Additionally, the values `BorrowAPY`, `LendAPY`, and `uTokenExchangeRate` will be removed from state, instead being efficiently calculated when needed.
Additionally, the values `BorrowAPY`, `SupplyAPY`, and `uTokenExchangeRate` will be removed from state, instead being efficiently calculated when needed.

## Detailed Design

Expand All @@ -48,11 +48,11 @@ This decision mainly updates existing features, rather than adding new ones. The
**State:**

- Add `InterestScalar` and `TotalAdjustedBorrows` to state, and add `Get/Set` functions
- Remove `BorrowAPY`, `LendAPY`, and `uTokenExchangeRate` from state, and remove `Set` functions
- Remove `BorrowAPY`, `SupplyAPY`, and `uTokenExchangeRate` from state, and remove `Set` functions

**Getters:**

- Modify `Get` functions for `BorrowAPY`, `LendAPY`, and `uTokenExchangeRate` to calculate values in real time.
- Modify `Get` functions for `BorrowAPY`, `SupplyAPY`, and `uTokenExchangeRate` to calculate values in real time.
- Modify `GetBorrow(addr,denom)`, `GetBorrowerBorrows(addr)`, and `GetAllBorrows()` to use `InterestScalar` and `AdjustedBorrow`
- Modify `GetTotalBorrows(denom)` to use `InterestScalar` and `TotalAdjustedBorrows`

Expand Down Expand Up @@ -104,7 +104,7 @@ This design change should address our lingering tradeoff between performance and

- Total borrows and supply utilization can be calculated in O(1) time instead of O(N) as N is the total number of borrow positions across all users
- Periodic functions can now take place every block instead of every `InterestEpoch` blocks
- Quantities like uToken exchange rates and lend APYs now update instantly to new borrow and lend activity, even between multiple transactions within the same block.
- Quantities like uToken exchange rates and supply APYs now update instantly to new borrow and supply activity, even between multiple transactions within the same block.

### Negative

Expand Down
Loading