Skip to content

Commit

Permalink
Merge branch 'dev' of https://github.com/onomyprotocol/reserve into n…
Browse files Browse the repository at this point in the history
…han/oracle_module
  • Loading branch information
ThanhNhann committed Oct 3, 2024
2 parents 4134eca + f64f668 commit d0599dc
Show file tree
Hide file tree
Showing 10 changed files with 612 additions and 91 deletions.
17 changes: 17 additions & 0 deletions proto/reserve/vaults/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ service Msg {

// Repay defines a method for reducing debt by burning tokens
rpc Repay(MsgRepay) returns (MsgRepayResponse);

// Close defines a method for close vault
rpc Close(MsgClose) returns (MsgCloseResponse);
}

message MsgUpdateParams {
Expand Down Expand Up @@ -182,3 +185,17 @@ message MsgRepay {

// MsgRepayResponse defines the Msg/Mint response type.
message MsgRepayResponse {}

// MsgClose defines a SDK message for closing vault.
message MsgClose {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
option (cosmos.msg.v1.signer) = "sender";

uint64 vault_id = 1;

string sender = 2 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
}

// MsgRepayResponse defines the Msg/Mint response type.
message MsgCloseResponse {}
9 changes: 5 additions & 4 deletions x/vaults/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
storetypes "cosmossdk.io/core/store"
"cosmossdk.io/math"
"github.com/onomyprotocol/reserve/x/vaults/types"
oraclekeeper "github.com/onomyprotocol/reserve/x/oracle/keeper"

"github.com/cosmos/cosmos-sdk/codec"
)
Expand All @@ -18,7 +17,9 @@ type Keeper struct {
storeService storetypes.KVStoreService
bankKeeper types.BankKeeper
accountKeeper types.AccountKeeper
oracleKeeper oraclekeeper.Keeper
// Temporarily leave it public to easily replace it with mocks.
// TODO: Make it private
OracleKeeper types.OracleKeeper

// the address capable of executing a MsgUpdateParams message. Typically, this
// should be the x/gov module account.
Expand All @@ -37,7 +38,7 @@ func NewKeeper(
storeService storetypes.KVStoreService,
ak types.AccountKeeper,
bk types.BankKeeper,
ok oraclekeeper.Keeper,
ok types.OracleKeeper,
authority string,
) *Keeper {
sb := collections.NewSchemaBuilder(storeService)
Expand All @@ -46,7 +47,7 @@ func NewKeeper(
cdc: cdc,
storeService: storeService,
accountKeeper: ak,
oracleKeeper: ok,
OracleKeeper: ok,
bankKeeper: bk,
Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)),
VaultsManager: collections.NewMap(sb, types.VaultManagerKeyPrefix, "vaultmanagers", collections.StringKey, codec.CollValue[types.VaultMamager](cdc)),
Expand Down
5 changes: 5 additions & 0 deletions x/vaults/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import (

"github.com/onomyprotocol/reserve/app/apptesting"
"github.com/onomyprotocol/reserve/x/vaults/keeper"
"github.com/onomyprotocol/reserve/x/vaults/keeper/mock"
"github.com/onomyprotocol/reserve/x/vaults/types"
"cosmossdk.io/math"
)

type KeeperTestSuite struct {
Expand All @@ -21,6 +23,9 @@ type KeeperTestSuite struct {
func (s *KeeperTestSuite) SetupTest() {
s.Setup()

mockOK := mock.NewMockOracleKeeper()
mockOK.SetPrice("atom", math.LegacyMustNewDecFromStr("8.0"))
s.App.VaultsKeeper.OracleKeeper = mockOK

Check failure on line 28 in x/vaults/keeper/keeper_test.go

View workflow job for this annotation

GitHub Actions / lint

cannot use mockOK (variable of type *"github.com/onomyprotocol/reserve/x/vaults/keeper/mock".MockOracleKeeper) as "github.com/onomyprotocol/reserve/x/vaults/types".OracleKeeper value in assignment: *"github.com/onomyprotocol/reserve/x/vaults/keeper/mock".MockOracleKeeper does not implement "github.com/onomyprotocol/reserve/x/vaults/types".OracleKeeper (wrong type for method GetPrice)

Check failure on line 28 in x/vaults/keeper/keeper_test.go

View workflow job for this annotation

GitHub Actions / tests (01)

cannot use mockOK (variable of type *"github.com/onomyprotocol/reserve/x/vaults/keeper/mock".MockOracleKeeper) as "github.com/onomyprotocol/reserve/x/vaults/types".OracleKeeper value in assignment: *"github.com/onomyprotocol/reserve/x/vaults/keeper/mock".MockOracleKeeper does not implement "github.com/onomyprotocol/reserve/x/vaults/types".OracleKeeper (wrong type for method GetPrice)
s.k = s.App.VaultsKeeper
s.msgServer = keeper.NewMsgServerImpl(s.k)
// s.queryServer = keeper.NewQueryServerImpl(s.k)
Expand Down
25 changes: 25 additions & 0 deletions x/vaults/keeper/mock/oracle_keeper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package mock

import (
"context"

"cosmossdk.io/math"
)

type MockOracleKeeper struct {
prices map[string]math.LegacyDec
}

func NewMockOracleKeeper() *MockOracleKeeper {
return &MockOracleKeeper{
prices: make(map[string]math.LegacyDec),
}
}

func (s *MockOracleKeeper) GetPrice(ctx context.Context, denom string) math.LegacyDec {
return s.prices[denom]
}

func (s *MockOracleKeeper) SetPrice(denom string, price math.LegacyDec) {
s.prices[denom] = price
}
16 changes: 16 additions & 0 deletions x/vaults/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"context"
"fmt"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -81,3 +82,18 @@ func (k msgServer) Repay(ctx context.Context, msg *types.MsgRepay) (*types.MsgRe
}
return &types.MsgRepayResponse{}, nil
}

func (k msgServer) Close(ctx context.Context, msg *types.MsgClose) (*types.MsgCloseResponse, error) {
vault, err := k.GetVault(ctx, msg.VaultId)
if err != nil {
return nil, fmt.Errorf("vault %d was not found", msg.VaultId)
}
if msg.Sender != vault.Owner {
return nil, fmt.Errorf("%s is not vault owner, expected: %s", msg.Sender, vault.Owner)
}
err = k.CloseVault(ctx, vault)
if err != nil {
return nil, err
}
return &types.MsgCloseResponse{}, nil
}
79 changes: 67 additions & 12 deletions x/vaults/keeper/vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ func (k *Keeper) CreateNewVault(
return fmt.Errorf("initial mint should be greater than min. Got %v, expected %v", mint, params.MinInitialDebt)
}

if vm.MintAvailable.LT(mint.Amount) {
return fmt.Errorf("exeed max debt")
}

// Calculate collateral ratio
price := k.oracleKeeper.GetPrice(ctx, denom, "USD")
price := k.OracleKeeper.GetPrice(ctx, denom, "USD")
// TODO: recalculate with denom decimal?
collateralValue := math.LegacyNewDecFromInt(collateral.Amount).Mul(*price)
ratio := collateralValue.QuoInt(mint.Amount)
Expand Down Expand Up @@ -77,6 +81,7 @@ func (k *Keeper) CreateNewVault(
Debt: mintedCoins[0],
CollateralLocked: collateral,
Status: types.ACTIVE,
Address: vaultAddress.String(),
}
err = k.SetVault(ctx, vault)
if err != nil {
Expand All @@ -87,6 +92,28 @@ func (k *Keeper) CreateNewVault(
return k.VaultsManager.Set(ctx, denom, vm)
}

func (k *Keeper) CloseVault(
ctx context.Context,
vault types.Vault,
) error {
// Can not close vault if still debt remain
if vault.Debt.Amount.GT(math.ZeroInt()) {
return fmt.Errorf("debt remain: %v", vault.Debt)
}

// transfer all collateral locked to owner
lockedCoins := sdk.NewCoins(vault.CollateralLocked)
err := k.bankKeeper.SendCoins(ctx, sdk.MustAccAddressFromBech32(vault.Address), sdk.MustAccAddressFromBech32(vault.Owner), lockedCoins)
if err != nil {
return err
}

// Update vault
vault.CollateralLocked.Amount = math.ZeroInt()
vault.Status = types.CLOSED
return k.SetVault(ctx, vault)
}

func (k *Keeper) MintCoin(
ctx context.Context,
vaultId uint64,
Expand All @@ -97,15 +124,22 @@ func (k *Keeper) MintCoin(
if err != nil {
return err
}
if vault.Status != types.ACTIVE {
return fmt.Errorf("Vault is not actived")
}
vm, err := k.GetVaultManager(ctx, vault.CollateralLocked.Denom)
if err != nil {
return fmt.Errorf("%s was not actived", vault.CollateralLocked.Denom)
}

if vm.MintAvailable.LT(mint.Amount) {
return fmt.Errorf("exeed max debt")
}

params := k.GetParams(ctx)

lockedCoin := vault.CollateralLocked
price := k.oracleKeeper.GetPrice(ctx, lockedCoin.Denom, "USD")
price := k.OracleKeeper.GetPrice(ctx, lockedCoin.Denom, "USD")
lockedValue := math.LegacyNewDecFromInt(lockedCoin.Amount).Mul(*price)

feeAmount := math.LegacyNewDecFromInt(mint.Amount).Mul(params.MintingFee).TruncateInt()
Expand Down Expand Up @@ -158,6 +192,9 @@ func (k *Keeper) RepayDebt(
if err != nil {
return err
}
if vault.Status != types.ACTIVE {
return fmt.Errorf("Vault is not actived")
}
vm, err := k.GetVaultManager(ctx, vault.CollateralLocked.Denom)
if err != nil {
return fmt.Errorf("%s was not actived", vault.CollateralLocked.Denom)
Expand Down Expand Up @@ -199,6 +236,9 @@ func (k *Keeper) DepositToVault(
if err != nil {
return err
}
if vault.Status != types.ACTIVE {
return fmt.Errorf("Vault is not actived")
}

// Lock collateral asset
err = k.bankKeeper.SendCoins(ctx, sender, sdk.MustAccAddressFromBech32(vault.Address), sdk.NewCoins(collateral))
Expand All @@ -221,6 +261,9 @@ func (k *Keeper) WithdrawFromVault(
if err != nil {
return err
}
if vault.Status != types.ACTIVE {
return fmt.Errorf("Vault is not actived")
}

if vault.CollateralLocked.Amount.LT(collateral.Amount) {
return fmt.Errorf("%d exeed locked amount: %d", collateral.Amount, vault.CollateralLocked.Amount)
Expand All @@ -232,7 +275,7 @@ func (k *Keeper) WithdrawFromVault(
}

newLock := vault.CollateralLocked.Sub(collateral)
price := k.oracleKeeper.GetPrice(ctx, collateral.Denom, "USD")
price := k.OracleKeeper.GetPrice(ctx, collateral.Denom, "USD")
newLockValue := math.LegacyNewDecFromInt(newLock.Amount).Mul(*price)
ratio := newLockValue.Quo(math.LegacyNewDecFromInt(vault.Debt.Amount))

Expand All @@ -258,7 +301,7 @@ func (k *Keeper) UpdateVaultsDebt(

return k.Vaults.Walk(ctx, nil, func(id uint64, vault types.Vault) (bool, error) {
var err error
if vault.Status == 0 {
if vault.Status == types.ACTIVE {
debtAmount := vault.Debt.Amount
newDebtAmount := math.LegacyNewDecFromInt(debtAmount).Add(math.LegacyNewDecFromInt(debtAmount).Mul(fee)).TruncateInt()
vault.Debt.Amount = newDebtAmount
Expand All @@ -275,8 +318,8 @@ func (k *Keeper) ShouldLiquidate(
price math.LegacyDec,
liquidationRatio math.LegacyDec,
) (bool, error) {
// Only liquidate OPEN vault
if vault.Status != 0 {
// Only liquidate ACTIVE vault
if vault.Status != types.ACTIVE {
return false, nil
}

Expand All @@ -298,7 +341,7 @@ func (k *Keeper) GetLiquidations(
liquidations := make(map[string]*types.Liquidation)

err := k.VaultsManager.Walk(ctx, nil, func(key string, vm types.VaultMamager) (bool, error) {
price := k.oracleKeeper.GetPrice(ctx, vm.Denom, "USD")
price := k.OracleKeeper.GetPrice(ctx, vm.Denom, "USD")
prices[vm.Denom] = *price
liquidationRatios[vm.Denom] = vm.Params.LiquidationRatio
liquidations[vm.Denom] = types.NewEmptyLiquidation(vm.Denom)
Expand Down Expand Up @@ -341,22 +384,22 @@ func (k *Keeper) GetLiquidations(
}

// TODO: Separate this func
// TODO: Update vault manager MintAvailable
func (k *Keeper) Liquidate(
ctx context.Context,
liquidation types.Liquidation,
) (error, bool, sdk.Coin) {
params := k.GetParams(ctx)

// Get total sold amount & collateral asset remain
// var (
// totalDebt, sold, totalCollateralRemain sdk.Coin
// )
vm, err := k.GetVaultManager(ctx, liquidation.Denom)
if err != nil {
return err, false, sdk.Coin{}
}

totalDebt := sdk.NewCoin(params.MintDenom, math.ZeroInt())
sold := sdk.NewCoin(params.MintDenom, math.ZeroInt())
totalCollateralRemain := sdk.NewCoin(liquidation.Denom, math.ZeroInt())


for _, vault := range liquidation.LiquidatingVaults {
totalDebt = totalDebt.Add(vault.Debt)
// transfer all remain collateral locked in vault to vaults module for distributing.
Expand All @@ -381,6 +424,12 @@ func (k *Keeper) Liquidate(
if err != nil {
return err, false, sdk.Coin{}
}
// Increase mint available
vm.MintAvailable = vm.MintAvailable.Add(totalDebt.Amount)
err = k.VaultsManager.Set(ctx, liquidation.Denom, vm)
if err != nil {
return err, false, sdk.Coin{}
}

// If remain sold, send to reserve
remain := sold.Sub(totalDebt)
Expand Down Expand Up @@ -427,6 +476,12 @@ func (k *Keeper) Liquidate(
if err != nil {
return err, false, sdk.Coin{}
}
// Increase mint available
vm.MintAvailable = vm.MintAvailable.Add(sold.Amount)
err = k.VaultsManager.Set(ctx, liquidation.Denom, vm)
if err != nil {
return err, false, sdk.Coin{}
}

// No collateral remain
if totalCollateralRemain.Amount.Equal(math.ZeroInt()) {
Expand Down
Loading

0 comments on commit d0599dc

Please sign in to comment.