Skip to content

Commit

Permalink
feat: automatically clear blacklisted collateral (#1343)
Browse files Browse the repository at this point in the history
## Description

closes: #1223 

---

### Author Checklist

_All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues._

I have...

- [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [x] added `!` to the type prefix if API or client breaking change
- [x] added appropriate labels to the PR
- [x] targeted the correct branch (see [PR Targeting](https://github.com/umee-network/umee/blob/main/CONTRIBUTING.md#pr-targeting))
- [x] provided a link to the relevant issue or specification
- [x] added a changelog entry to `CHANGELOG.md`
- [x] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

_All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items._

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed all author checklist items have been addressed
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
  • Loading branch information
toteki authored Sep 9, 2022
1 parent a55c554 commit 902ebae
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 36 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
- [1330](https://github.com/umee-network/umee/pull/1330) Implemented MaxSupplyUtilization.
- [1319](https://github.com/umee-network/umee/pull/1319) Implemented MaxSupply.
- [1331](https://github.com/umee-network/umee/pull/1331) Implemented MinCollateralLiquidity.
- [1343](https://github.com/umee-network/umee/pull/1343) RepayBadDebt and Liquidate automatically clear blacklisted collateral.

### Improvements

Expand Down
10 changes: 0 additions & 10 deletions x/leverage/keeper/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,3 @@ func (k Keeper) filterAcceptedCoins(ctx sdk.Context, coins sdk.Coins) sdk.Coins
},
)
}

// filterAcceptedUTokens returns the subset of an sdk.Coins that are accepted, non-blacklisted uTokens
func (k Keeper) filterAcceptedUTokens(ctx sdk.Context, coins sdk.Coins) sdk.Coins {
return k.filterCoins(
coins,
func(c sdk.Coin) bool {
return k.validateAcceptedUToken(ctx, c) == nil
},
)
}
10 changes: 6 additions & 4 deletions x/leverage/keeper/iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,13 @@ func (k Keeper) SweepBadDebts(ctx sdk.Context) error {
addr := types.AddressFromKey(key, prefix)
denom := types.DenomFromKeyWithAddress(key, prefix)

// first check if the borrower has gained collateral since the bad debt was identified
done := k.HasCollateral(ctx, addr)
// TODO #1223: Decollateralize any blacklisted collateral and proceed
// clear blacklisted collateral while checking for any remaining (valid) collateral
done, err := k.clearBlacklistedCollateral(ctx, addr)
if err != nil {
return err
}

// if collateral is still zero, attempt to repay a single address's debt in this denom
// if remaining collateral is zero, attempt to repay this bad debt
if !done {
var err error
done, err = k.RepayBadDebt(ctx, addr, denom)
Expand Down
42 changes: 38 additions & 4 deletions x/leverage/keeper/reserves.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,46 @@ import (
"github.com/umee-network/umee/v3/x/leverage/types"
)

// clearBlacklistedCollateral decollateralizes any blacklisted uTokens
// from a borrower's collateral. It is used during liquidations and before
// repaying bad debts with reserves to make any subsequent checks for
// remaining collateral on the borrower's address more efficient.
// Also returns a boolean indicating whether valid collateral remains.
func (k Keeper) clearBlacklistedCollateral(ctx sdk.Context, borrowerAddr sdk.AccAddress) (bool, error) {
collateral := k.GetBorrowerCollateral(ctx, borrowerAddr)
hasCollateral := false
for _, coin := range collateral {
denom := types.ToTokenDenom(coin.Denom)
token, err := k.GetTokenSettings(ctx, denom)
if err != nil {
return false, err
}
if token.Blacklist {
// Decollateralize any blacklisted uTokens encountered
err := k.decollateralize(ctx, borrowerAddr, borrowerAddr, coin)
if err != nil {
return false, err
}
} else {
// At least one non-blacklisted uToken was found
hasCollateral = true
}
}
// Any remaining collateral is non-blacklisted
return hasCollateral, nil
}

// checkBadDebt detects if a borrower has zero non-blacklisted collateral,
// and marks any remaining borrowed tokens as bad debt.
func (k Keeper) checkBadDebt(ctx sdk.Context, borrowerAddr sdk.AccAddress) error {
// get remaining collateral uTokens, ignoring blacklisted
remainingCollateral := k.filterAcceptedUTokens(ctx, k.GetBorrowerCollateral(ctx, borrowerAddr))
// clear blacklisted collateral while checking for any remaining (valid) collateral
hasCollateral, err := k.clearBlacklistedCollateral(ctx, borrowerAddr)
if err != nil {
return err
}

// detect bad debt if collateral is completely exhausted
if remainingCollateral.IsZero() {
// mark bad debt if collateral is completely exhausted
if !hasCollateral {
for _, coin := range k.GetBorrowerBorrows(ctx, borrowerAddr) {
// set a bad debt flag for each borrowed denom
if err := k.setBadDebtAddress(ctx, borrowerAddr, coin.Denom, true); err != nil {
Expand All @@ -27,6 +59,8 @@ func (k Keeper) checkBadDebt(ctx sdk.Context, borrowerAddr sdk.AccAddress) error

// RepayBadDebt uses reserves to repay borrower's debts of a given denom.
// It returns a boolean representing whether full repayment was achieved.
// This function assumes the borrower has already been verified to have
// no collateral remaining.
func (k Keeper) RepayBadDebt(ctx sdk.Context, borrowerAddr sdk.AccAddress, denom string) (bool, error) {
borrowed := k.GetBorrow(ctx, borrowerAddr, denom)
borrower := borrowerAddr.String()
Expand Down
18 changes: 0 additions & 18 deletions x/leverage/keeper/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,6 @@ func (k Keeper) validateAcceptedDenom(ctx sdk.Context, denom string) error {
return token.AssertNotBlacklisted()
}

// validateAcceptedUTokenDenom validates an sdk.Coin and ensures it is a uToken
// associated with a registered Token with Blacklisted == false
func (k Keeper) validateAcceptedUTokenDenom(ctx sdk.Context, udenom string) error {
if !types.HasUTokenPrefix(udenom) {
return types.ErrNotUToken.Wrap(udenom)
}
return k.validateAcceptedDenom(ctx, types.ToTokenDenom(udenom))
}

// validateAcceptedAsset validates an sdk.Coin and ensures it is a registered Token
// with Blacklisted == false
func (k Keeper) validateAcceptedAsset(ctx sdk.Context, coin sdk.Coin) error {
Expand All @@ -37,15 +28,6 @@ func (k Keeper) validateAcceptedAsset(ctx sdk.Context, coin sdk.Coin) error {
return k.validateAcceptedDenom(ctx, coin.Denom)
}

// validateAcceptedUToken validates an sdk.Coin and ensures it is a uToken
// associated with a registered Token with Blacklisted == false
func (k Keeper) validateAcceptedUToken(ctx sdk.Context, coin sdk.Coin) error {
if err := coin.Validate(); err != nil {
return err
}
return k.validateAcceptedUTokenDenom(ctx, coin.Denom)
}

// validateSupply validates an sdk.Coin and ensures its Denom is a Token with EnableMsgSupply
func (k Keeper) validateSupply(ctx sdk.Context, coin sdk.Coin) error {
if err := validateBaseToken(coin); err != nil {
Expand Down

0 comments on commit 902ebae

Please sign in to comment.