From 5385760d61413a5ac6c5826aa8ece4e8f4ca1650 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Tue, 1 Oct 2024 20:50:34 +0700 Subject: [PATCH 1/6] close vault --- proto/reserve/vaults/tx.proto | 17 ++ x/vaults/keeper/msg_server.go | 16 ++ x/vaults/keeper/vault.go | 23 +- x/vaults/types/tx.pb.go | 462 ++++++++++++++++++++++++++++++---- 4 files changed, 462 insertions(+), 56 deletions(-) diff --git a/proto/reserve/vaults/tx.proto b/proto/reserve/vaults/tx.proto index 50e7597..ec2158d 100644 --- a/proto/reserve/vaults/tx.proto +++ b/proto/reserve/vaults/tx.proto @@ -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 { @@ -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 {} diff --git a/x/vaults/keeper/msg_server.go b/x/vaults/keeper/msg_server.go index 1ac6203..0dc0166 100644 --- a/x/vaults/keeper/msg_server.go +++ b/x/vaults/keeper/msg_server.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "fmt" errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -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 +} diff --git a/x/vaults/keeper/vault.go b/x/vaults/keeper/vault.go index d2c40a4..4eb7497 100644 --- a/x/vaults/keeper/vault.go +++ b/x/vaults/keeper/vault.go @@ -87,6 +87,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, @@ -356,7 +378,6 @@ func (k *Keeper) Liquidate( 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. diff --git a/x/vaults/types/tx.pb.go b/x/vaults/types/tx.pb.go index 42dd7c5..68a346e 100644 --- a/x/vaults/types/tx.pb.go +++ b/x/vaults/types/tx.pb.go @@ -595,6 +595,82 @@ func (m *MsgRepayResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgRepayResponse proto.InternalMessageInfo +// MsgClose defines a SDK message for closing vault. +type MsgClose struct { + VaultId uint64 `protobuf:"varint,1,opt,name=vault_id,json=vaultId,proto3" json:"vault_id,omitempty"` + Sender string `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` +} + +func (m *MsgClose) Reset() { *m = MsgClose{} } +func (m *MsgClose) String() string { return proto.CompactTextString(m) } +func (*MsgClose) ProtoMessage() {} +func (*MsgClose) Descriptor() ([]byte, []int) { + return fileDescriptor_bbce2367024dc47b, []int{14} +} +func (m *MsgClose) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgClose) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgClose.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgClose) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgClose.Merge(m, src) +} +func (m *MsgClose) XXX_Size() int { + return m.Size() +} +func (m *MsgClose) XXX_DiscardUnknown() { + xxx_messageInfo_MsgClose.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgClose proto.InternalMessageInfo + +// MsgRepayResponse defines the Msg/Mint response type. +type MsgCloseResponse struct { +} + +func (m *MsgCloseResponse) Reset() { *m = MsgCloseResponse{} } +func (m *MsgCloseResponse) String() string { return proto.CompactTextString(m) } +func (*MsgCloseResponse) ProtoMessage() {} +func (*MsgCloseResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bbce2367024dc47b, []int{15} +} +func (m *MsgCloseResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCloseResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCloseResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCloseResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCloseResponse.Merge(m, src) +} +func (m *MsgCloseResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgCloseResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCloseResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCloseResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgUpdateParams)(nil), "reserve.vaults.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "reserve.vaults.MsgUpdateParamsResponse") @@ -610,67 +686,71 @@ func init() { proto.RegisterType((*MsgMintResponse)(nil), "reserve.vaults.MsgMintResponse") proto.RegisterType((*MsgRepay)(nil), "reserve.vaults.MsgRepay") proto.RegisterType((*MsgRepayResponse)(nil), "reserve.vaults.MsgRepayResponse") + proto.RegisterType((*MsgClose)(nil), "reserve.vaults.MsgClose") + proto.RegisterType((*MsgCloseResponse)(nil), "reserve.vaults.MsgCloseResponse") } func init() { proto.RegisterFile("reserve/vaults/tx.proto", fileDescriptor_bbce2367024dc47b) } var fileDescriptor_bbce2367024dc47b = []byte{ - // 875 bytes of a gzipped FileDescriptorProto + // 901 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xcf, 0x6f, 0x1b, 0x45, - 0x14, 0xf6, 0x92, 0x38, 0x3f, 0x5e, 0x50, 0x49, 0xa6, 0x6e, 0xe2, 0x6c, 0xc4, 0x3a, 0x72, 0x25, - 0xa8, 0x82, 0xba, 0xdb, 0xa4, 0x52, 0x25, 0x22, 0x0e, 0x34, 0xf1, 0xc5, 0xa2, 0x2b, 0x21, 0xa3, - 0x02, 0xe2, 0x62, 0x8d, 0x77, 0x47, 0xeb, 0x11, 0xde, 0x19, 0xb3, 0x33, 0x76, 0xe3, 0x1b, 0xe2, - 0x84, 0x38, 0x71, 0xe3, 0xda, 0x23, 0x20, 0x90, 0x72, 0xe8, 0x85, 0x33, 0x97, 0x1e, 0xab, 0x9e, - 0x10, 0x87, 0x0a, 0x25, 0x87, 0x70, 0xe2, 0x6f, 0x40, 0x3b, 0x33, 0xbb, 0x5e, 0xbb, 0x76, 0x09, - 0xea, 0x25, 0x97, 0xc4, 0xb3, 0xdf, 0x7b, 0xdf, 0x7b, 0xdf, 0x7b, 0x6f, 0x7e, 0xc0, 0x56, 0x42, - 0x04, 0x49, 0x86, 0xc4, 0x1b, 0xe2, 0x41, 0x4f, 0x0a, 0x4f, 0x9e, 0xb8, 0xfd, 0x84, 0x4b, 0x8e, - 0xae, 0x19, 0xc0, 0xd5, 0x80, 0x5d, 0x89, 0x78, 0xc4, 0x15, 0xe4, 0xa5, 0xbf, 0xb4, 0x95, 0xbd, - 0x33, 0xe5, 0xde, 0xc7, 0x09, 0x8e, 0x85, 0x01, 0x37, 0x70, 0x4c, 0x19, 0xf7, 0xd4, 0x5f, 0xf3, - 0x69, 0x3b, 0xe0, 0x22, 0xe6, 0xa2, 0xad, 0x89, 0xf4, 0xc2, 0x40, 0x5b, 0x7a, 0xe5, 0xc5, 0x22, - 0xf2, 0x86, 0xfb, 0xe9, 0x3f, 0x03, 0x38, 0x06, 0xe8, 0x60, 0x41, 0xbc, 0xe1, 0x7e, 0x87, 0x48, - 0xbc, 0xef, 0x05, 0x9c, 0x32, 0x8d, 0xd7, 0x7f, 0xb3, 0xe0, 0x2d, 0x5f, 0x44, 0x0f, 0xfb, 0x21, - 0x96, 0xe4, 0x63, 0x95, 0x00, 0xba, 0x07, 0xab, 0x78, 0x20, 0xbb, 0x3c, 0xa1, 0x72, 0x54, 0xb5, - 0x76, 0xad, 0x5b, 0xab, 0x47, 0xd5, 0xe7, 0x4f, 0x6e, 0x57, 0x4c, 0xc4, 0xfb, 0x61, 0x98, 0x10, - 0x21, 0x3e, 0x91, 0x09, 0x65, 0x51, 0x6b, 0x6c, 0x8a, 0xde, 0x87, 0x25, 0x2d, 0xa1, 0xfa, 0xc6, - 0xae, 0x75, 0x6b, 0xed, 0x60, 0xd3, 0x9d, 0x2c, 0x83, 0xab, 0xf9, 0x8f, 0x56, 0x9f, 0xbe, 0xa8, - 0x95, 0x7e, 0xbc, 0x38, 0xdd, 0xb3, 0x5a, 0xc6, 0xe1, 0xf0, 0xee, 0x37, 0x17, 0xa7, 0x7b, 0x63, - 0xaa, 0xef, 0x2e, 0x4e, 0xf7, 0x76, 0xb3, 0xea, 0x9c, 0x78, 0x3c, 0xc1, 0x41, 0x8f, 0x78, 0x53, - 0x79, 0xd6, 0xb7, 0x61, 0x6b, 0xea, 0x53, 0x8b, 0x88, 0x3e, 0x67, 0x82, 0xd4, 0x7f, 0x58, 0x80, - 0xeb, 0xbe, 0x88, 0xee, 0x07, 0x92, 0x0e, 0xc9, 0x31, 0xef, 0xf5, 0xb0, 0x24, 0x09, 0xee, 0xa1, - 0x0a, 0x94, 0x43, 0xc2, 0x78, 0xac, 0x65, 0xb5, 0xf4, 0x02, 0x75, 0xa1, 0x12, 0x53, 0xd6, 0x0e, - 0x72, 0xbb, 0x76, 0x82, 0x25, 0xe5, 0x4a, 0xc6, 0xea, 0xd1, 0xbd, 0x34, 0xdd, 0x3f, 0x5f, 0xd4, - 0x76, 0xb4, 0x7e, 0x11, 0x7e, 0xe9, 0x52, 0xee, 0xc5, 0x58, 0x76, 0xdd, 0x07, 0x24, 0xc2, 0xc1, - 0xa8, 0x41, 0x82, 0xe7, 0x4f, 0x6e, 0x83, 0x29, 0x4f, 0x83, 0x04, 0x5a, 0x1b, 0x8a, 0x29, 0x1b, - 0x87, 0x6e, 0xa5, 0x8c, 0x28, 0x80, 0x8d, 0x1e, 0xfd, 0x6a, 0x40, 0xc3, 0x74, 0xc5, 0x4c, 0x98, - 0x85, 0xd7, 0x0a, 0xb3, 0x5e, 0x20, 0xd4, 0x41, 0x3e, 0x82, 0x95, 0x18, 0x9f, 0xb4, 0x43, 0xd2, - 0x91, 0xd5, 0x45, 0xc5, 0x7d, 0xc7, 0x70, 0xdf, 0x78, 0x99, 0xbb, 0xc9, 0x64, 0x81, 0xb5, 0xc9, - 0xa4, 0x66, 0x5d, 0x8e, 0xf1, 0x49, 0x83, 0x74, 0xe4, 0xe4, 0x30, 0x94, 0x2f, 0x3d, 0x0c, 0x87, - 0x9b, 0xdf, 0x3e, 0xae, 0x95, 0xfe, 0x7e, 0x5c, 0x2b, 0x4d, 0x76, 0xb6, 0xfe, 0x36, 0xec, 0xcc, - 0x68, 0x4c, 0xde, 0xb8, 0x7f, 0x2c, 0xb8, 0xe6, 0x8b, 0xe8, 0x38, 0x21, 0x58, 0x92, 0x4f, 0xd3, - 0xb1, 0x99, 0xd3, 0x33, 0x17, 0xca, 0xfc, 0x11, 0x23, 0x89, 0x69, 0xd2, 0xfc, 0x9c, 0xb4, 0x19, - 0x6a, 0x00, 0x8c, 0xfb, 0xab, 0x4a, 0xbe, 0x76, 0xb0, 0xed, 0x1a, 0x8f, 0x74, 0x77, 0xb8, 0x66, - 0x77, 0xb8, 0xc7, 0x9c, 0xb2, 0xe2, 0x8c, 0x16, 0xfc, 0xd0, 0x07, 0xb0, 0x14, 0x53, 0x26, 0x49, - 0xa8, 0x0a, 0x7b, 0x59, 0x06, 0xe3, 0x73, 0x88, 0x8a, 0x35, 0xd1, 0x79, 0xd5, 0xab, 0xb0, 0x39, - 0xa9, 0x37, 0x2f, 0xc5, 0x2f, 0x16, 0x80, 0x2f, 0xa2, 0x06, 0xe9, 0x73, 0x41, 0x25, 0xda, 0x86, - 0x15, 0xb5, 0x8d, 0xda, 0x34, 0x54, 0x95, 0x58, 0x6c, 0x2d, 0xab, 0x75, 0x33, 0x44, 0x77, 0x60, - 0x49, 0x10, 0x16, 0x5e, 0xa2, 0x18, 0xc6, 0x2e, 0xd5, 0x81, 0x63, 0x3e, 0x60, 0xf2, 0x7f, 0x55, - 0xc2, 0xf8, 0x1c, 0x5e, 0x2f, 0xea, 0x30, 0x94, 0xf5, 0x0a, 0xa0, 0x71, 0xb6, 0xb9, 0x88, 0x5f, - 0x2d, 0x58, 0xf3, 0x45, 0xf4, 0x19, 0x95, 0xdd, 0x30, 0xc1, 0x8f, 0xae, 0xbc, 0x8a, 0x1b, 0xea, - 0xdc, 0xc8, 0xd2, 0xcd, 0x65, 0xfc, 0x64, 0xc1, 0xb2, 0x2f, 0x22, 0x9f, 0xb2, 0xab, 0xdf, 0x88, - 0x0d, 0x75, 0xa2, 0xa7, 0xa9, 0xe6, 0xe9, 0xff, 0x6c, 0xc1, 0x8a, 0x2f, 0xa2, 0x16, 0xe9, 0xe3, - 0xd1, 0x95, 0xcf, 0x1f, 0xc1, 0x7a, 0x96, 0x6b, 0x26, 0xe0, 0xe0, 0xf7, 0x45, 0x58, 0xf0, 0x45, - 0x84, 0x3e, 0x87, 0x37, 0x27, 0xae, 0xaa, 0xda, 0xf4, 0x15, 0x33, 0x75, 0x21, 0xd8, 0xef, 0xfe, - 0x87, 0x41, 0x16, 0x01, 0x85, 0xb0, 0xfe, 0xd2, 0x6d, 0x71, 0x73, 0x86, 0xf3, 0xb4, 0x91, 0xfd, - 0xde, 0x25, 0x8c, 0xf2, 0x28, 0x0f, 0x61, 0xad, 0x78, 0xb4, 0x39, 0x33, 0x7c, 0x0b, 0xb8, 0xfd, - 0xce, 0xab, 0xf1, 0x9c, 0xb6, 0x09, 0xcb, 0xd9, 0x31, 0x61, 0xcf, 0x70, 0x31, 0x98, 0x5d, 0x9f, - 0x8f, 0xe5, 0x54, 0x0f, 0x60, 0x25, 0xdf, 0xac, 0x3b, 0x33, 0xec, 0x33, 0xd0, 0xbe, 0xf9, 0x0a, - 0x30, 0x67, 0xfb, 0x10, 0x16, 0xd5, 0x9e, 0xd9, 0x9a, 0x61, 0x9c, 0x02, 0x76, 0x6d, 0x0e, 0x90, - 0x33, 0x1c, 0x43, 0x59, 0x8f, 0x6d, 0x75, 0x86, 0xa5, 0x42, 0xec, 0xdd, 0x79, 0x48, 0x46, 0x62, - 0x97, 0xbf, 0x4e, 0xc7, 0xee, 0xa8, 0xf9, 0xf4, 0xcc, 0xb1, 0x9e, 0x9d, 0x39, 0xd6, 0x5f, 0x67, - 0x8e, 0xf5, 0xfd, 0xb9, 0x53, 0x7a, 0x76, 0xee, 0x94, 0xfe, 0x38, 0x77, 0x4a, 0x5f, 0x78, 0x11, - 0x95, 0xdd, 0x41, 0xc7, 0x0d, 0x78, 0xec, 0x71, 0xc6, 0xe3, 0x91, 0x7a, 0x1d, 0x05, 0xbc, 0xe7, - 0x8d, 0x5f, 0x21, 0xd9, 0x23, 0x6f, 0xd4, 0x27, 0xa2, 0xb3, 0xa4, 0x0c, 0xee, 0xfe, 0x1b, 0x00, - 0x00, 0xff, 0xff, 0x61, 0x5f, 0x73, 0x64, 0x03, 0x0a, 0x00, 0x00, + 0x14, 0xf6, 0x92, 0x38, 0x3f, 0x5e, 0x50, 0x49, 0xb6, 0x6e, 0xe2, 0x6c, 0x84, 0x1d, 0xb9, 0x12, + 0x54, 0x41, 0xdd, 0x6d, 0x52, 0xa9, 0x12, 0x11, 0x07, 0x1a, 0xfb, 0x62, 0xd1, 0x95, 0x90, 0x51, + 0x01, 0x71, 0xb1, 0xc6, 0xbb, 0xa3, 0xf5, 0x88, 0xdd, 0x19, 0xb3, 0x33, 0x76, 0xe3, 0x1b, 0xe2, + 0x54, 0x71, 0xe2, 0xc6, 0xb5, 0x47, 0x40, 0x20, 0xe5, 0xd0, 0x0b, 0xff, 0x41, 0x8f, 0x55, 0x4f, + 0x88, 0x43, 0x85, 0x92, 0x43, 0x38, 0xf1, 0x37, 0xa0, 0x9d, 0x99, 0x5d, 0xaf, 0x9d, 0x75, 0x08, + 0x82, 0x43, 0x2e, 0x89, 0x67, 0xbf, 0xf7, 0xbe, 0xf7, 0xbd, 0xf7, 0xe6, 0xcd, 0x0c, 0x6c, 0xc5, + 0x98, 0xe3, 0x78, 0x84, 0x9d, 0x11, 0x1a, 0x86, 0x82, 0x3b, 0xe2, 0xd8, 0x1e, 0xc4, 0x4c, 0x30, + 0xf3, 0x86, 0x06, 0x6c, 0x05, 0x58, 0x95, 0x80, 0x05, 0x4c, 0x42, 0x4e, 0xf2, 0x4b, 0x59, 0x59, + 0x3b, 0x33, 0xee, 0x03, 0x14, 0xa3, 0x88, 0x6b, 0x70, 0x03, 0x45, 0x84, 0x32, 0x47, 0xfe, 0xd5, + 0x9f, 0xb6, 0x3d, 0xc6, 0x23, 0xc6, 0xbb, 0x8a, 0x48, 0x2d, 0x34, 0xb4, 0xa5, 0x56, 0x4e, 0xc4, + 0x03, 0x67, 0xb4, 0x9f, 0xfc, 0xd3, 0x40, 0x4d, 0x03, 0x3d, 0xc4, 0xb1, 0x33, 0xda, 0xef, 0x61, + 0x81, 0xf6, 0x1d, 0x8f, 0x11, 0xaa, 0xf0, 0xc6, 0xaf, 0x06, 0xbc, 0xe5, 0xf2, 0xe0, 0xf1, 0xc0, + 0x47, 0x02, 0x7f, 0x2c, 0x05, 0x98, 0x0f, 0x60, 0x15, 0x0d, 0x45, 0x9f, 0xc5, 0x44, 0x8c, 0xab, + 0xc6, 0xae, 0x71, 0x67, 0xf5, 0xa8, 0xfa, 0xea, 0xf9, 0xdd, 0x8a, 0x8e, 0xf8, 0xd0, 0xf7, 0x63, + 0xcc, 0xf9, 0x27, 0x22, 0x26, 0x34, 0xe8, 0x4c, 0x4c, 0xcd, 0xf7, 0x61, 0x49, 0xa5, 0x50, 0x7d, + 0x63, 0xd7, 0xb8, 0xb3, 0x76, 0xb0, 0x69, 0x4f, 0x97, 0xc1, 0x56, 0xfc, 0x47, 0xab, 0x2f, 0x5e, + 0xd7, 0x4b, 0x3f, 0x9c, 0x9f, 0xec, 0x19, 0x1d, 0xed, 0x70, 0x78, 0xff, 0x9b, 0xf3, 0x93, 0xbd, + 0x09, 0xd5, 0xb7, 0xe7, 0x27, 0x7b, 0xbb, 0x69, 0x75, 0x8e, 0x1d, 0x16, 0x23, 0x2f, 0xc4, 0xce, + 0x8c, 0xce, 0xc6, 0x36, 0x6c, 0xcd, 0x7c, 0xea, 0x60, 0x3e, 0x60, 0x94, 0xe3, 0xc6, 0xf7, 0x0b, + 0x70, 0xd3, 0xe5, 0xc1, 0x43, 0x4f, 0x90, 0x11, 0x6e, 0xb2, 0x30, 0x44, 0x02, 0xc7, 0x28, 0x34, + 0x2b, 0x50, 0xf6, 0x31, 0x65, 0x91, 0x4a, 0xab, 0xa3, 0x16, 0x66, 0x1f, 0x2a, 0x11, 0xa1, 0x5d, + 0x2f, 0xb3, 0xeb, 0xc6, 0x48, 0x10, 0x26, 0xd3, 0x58, 0x3d, 0x7a, 0x90, 0xc8, 0xfd, 0xfd, 0x75, + 0x7d, 0x47, 0xe5, 0xcf, 0xfd, 0x2f, 0x6d, 0xc2, 0x9c, 0x08, 0x89, 0xbe, 0xfd, 0x08, 0x07, 0xc8, + 0x1b, 0xb7, 0xb0, 0xf7, 0xea, 0xf9, 0x5d, 0xd0, 0xe5, 0x69, 0x61, 0x4f, 0xe5, 0x66, 0x46, 0x84, + 0x4e, 0x42, 0x77, 0x12, 0x46, 0xd3, 0x83, 0x8d, 0x90, 0x7c, 0x35, 0x24, 0x7e, 0xb2, 0xa2, 0x3a, + 0xcc, 0xc2, 0x7f, 0x0a, 0xb3, 0x9e, 0x23, 0x54, 0x41, 0x3e, 0x82, 0x95, 0x08, 0x1d, 0x77, 0x7d, + 0xdc, 0x13, 0xd5, 0x45, 0xc9, 0x7d, 0x4f, 0x73, 0xdf, 0xba, 0xc8, 0xdd, 0xa6, 0x22, 0xc7, 0xda, + 0xa6, 0x42, 0xb1, 0x2e, 0x47, 0xe8, 0xb8, 0x85, 0x7b, 0x62, 0x7a, 0x33, 0x94, 0xaf, 0xbc, 0x19, + 0x0e, 0x37, 0x9f, 0x3e, 0xab, 0x97, 0xfe, 0x7c, 0x56, 0x2f, 0x4d, 0x77, 0xb6, 0xf1, 0x36, 0xec, + 0x14, 0x34, 0x26, 0x6b, 0xdc, 0x5f, 0x06, 0xdc, 0x70, 0x79, 0xd0, 0x8c, 0x31, 0x12, 0xf8, 0xd3, + 0x64, 0xdb, 0xcc, 0xe9, 0x99, 0x0d, 0x65, 0xf6, 0x84, 0xe2, 0x58, 0x37, 0x69, 0xbe, 0x26, 0x65, + 0x66, 0xb6, 0x00, 0x26, 0xfd, 0x95, 0x25, 0x5f, 0x3b, 0xd8, 0xb6, 0xb5, 0x47, 0x32, 0x1d, 0xb6, + 0x9e, 0x0e, 0xbb, 0xc9, 0x08, 0xcd, 0xef, 0xd1, 0x9c, 0x9f, 0xf9, 0x01, 0x2c, 0x45, 0x84, 0x0a, + 0xec, 0xcb, 0xc2, 0x5e, 0x95, 0x41, 0xfb, 0x1c, 0x9a, 0xf9, 0x9a, 0x28, 0x5d, 0x8d, 0x2a, 0x6c, + 0x4e, 0xe7, 0x9b, 0x95, 0xe2, 0x67, 0x03, 0xc0, 0xe5, 0x41, 0x0b, 0x0f, 0x18, 0x27, 0xc2, 0xdc, + 0x86, 0x15, 0x39, 0x46, 0x5d, 0xe2, 0xcb, 0x4a, 0x2c, 0x76, 0x96, 0xe5, 0xba, 0xed, 0x9b, 0xf7, + 0x60, 0x89, 0x63, 0xea, 0x5f, 0xa1, 0x18, 0xda, 0x2e, 0xc9, 0x03, 0x45, 0x6c, 0x48, 0xc5, 0xbf, + 0xaa, 0x84, 0xf6, 0x39, 0xbc, 0x99, 0xcf, 0x43, 0x53, 0x36, 0x2a, 0x60, 0x4e, 0xd4, 0x66, 0x49, + 0xfc, 0x62, 0xc0, 0x9a, 0xcb, 0x83, 0xcf, 0x88, 0xe8, 0xfb, 0x31, 0x7a, 0x72, 0xed, 0xb3, 0xb8, + 0x25, 0xcf, 0x8d, 0x54, 0x6e, 0x96, 0xc6, 0x8f, 0x06, 0x2c, 0xbb, 0x3c, 0x70, 0x09, 0xbd, 0xfe, + 0x8d, 0xd8, 0x90, 0x27, 0x7a, 0x22, 0x35, 0x93, 0xff, 0x93, 0x01, 0x2b, 0x2e, 0x0f, 0x3a, 0x78, + 0x80, 0xc6, 0xd7, 0x5e, 0xbf, 0x09, 0xeb, 0xa9, 0xd6, 0x2c, 0x81, 0x50, 0xea, 0x6f, 0x86, 0x8c, + 0xe3, 0xff, 0x55, 0xff, 0x65, 0x0a, 0x64, 0xb4, 0x54, 0xc1, 0xc1, 0xd3, 0x32, 0x2c, 0xb8, 0x3c, + 0x30, 0x3f, 0x87, 0x37, 0xa7, 0x2e, 0xcb, 0xfa, 0xec, 0x25, 0x37, 0x73, 0x25, 0x59, 0xef, 0xfe, + 0x83, 0x41, 0x1a, 0xc1, 0xf4, 0x61, 0xfd, 0xc2, 0x7d, 0x75, 0xbb, 0xc0, 0x79, 0xd6, 0xc8, 0x7a, + 0xef, 0x0a, 0x46, 0x59, 0x94, 0xc7, 0xb0, 0x96, 0x3f, 0x5c, 0x6b, 0x05, 0xbe, 0x39, 0xdc, 0x7a, + 0xe7, 0x72, 0x3c, 0xa3, 0x6d, 0xc3, 0x72, 0x7a, 0x50, 0x59, 0x05, 0x2e, 0x1a, 0xb3, 0x1a, 0xf3, + 0xb1, 0x8c, 0xea, 0x11, 0xac, 0x64, 0xc7, 0xc5, 0x4e, 0x81, 0x7d, 0x0a, 0x5a, 0xb7, 0x2f, 0x01, + 0x33, 0xb6, 0x0f, 0x61, 0x51, 0x4e, 0xed, 0x56, 0x81, 0x71, 0x02, 0x58, 0xf5, 0x39, 0x40, 0xc6, + 0xd0, 0x84, 0xb2, 0x1a, 0x9c, 0x6a, 0x81, 0xa5, 0x44, 0xac, 0xdd, 0x79, 0x48, 0x9e, 0x44, 0xed, + 0xde, 0x22, 0x12, 0x89, 0x14, 0x92, 0x4c, 0xed, 0x41, 0xab, 0xfc, 0x75, 0x32, 0x3d, 0x47, 0xed, + 0x17, 0xa7, 0x35, 0xe3, 0xe5, 0x69, 0xcd, 0xf8, 0xe3, 0xb4, 0x66, 0x7c, 0x77, 0x56, 0x2b, 0xbd, + 0x3c, 0xab, 0x95, 0x7e, 0x3b, 0xab, 0x95, 0xbe, 0x70, 0x02, 0x22, 0xfa, 0xc3, 0x9e, 0xed, 0xb1, + 0xc8, 0x61, 0x94, 0x45, 0x63, 0xf9, 0xc8, 0xf3, 0x58, 0xe8, 0x4c, 0x1e, 0x53, 0xe9, 0x5b, 0x75, + 0x3c, 0xc0, 0xbc, 0xb7, 0x24, 0x0d, 0xee, 0xff, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xa4, 0xa0, 0x2b, + 0x6d, 0xca, 0x0a, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -701,6 +781,8 @@ type MsgClient interface { Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) // Repay defines a method for reducing debt by burning tokens Repay(ctx context.Context, in *MsgRepay, opts ...grpc.CallOption) (*MsgRepayResponse, error) + // Close defines a method for close vault + Close(ctx context.Context, in *MsgClose, opts ...grpc.CallOption) (*MsgCloseResponse, error) } type msgClient struct { @@ -774,6 +856,15 @@ func (c *msgClient) Repay(ctx context.Context, in *MsgRepay, opts ...grpc.CallOp return out, nil } +func (c *msgClient) Close(ctx context.Context, in *MsgClose, opts ...grpc.CallOption) (*MsgCloseResponse, error) { + out := new(MsgCloseResponse) + err := c.cc.Invoke(ctx, "/reserve.vaults.Msg/Close", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { // UpdateParams defines a (governance) operation for updating the module @@ -792,6 +883,8 @@ type MsgServer interface { Mint(context.Context, *MsgMint) (*MsgMintResponse, error) // Repay defines a method for reducing debt by burning tokens Repay(context.Context, *MsgRepay) (*MsgRepayResponse, error) + // Close defines a method for close vault + Close(context.Context, *MsgClose) (*MsgCloseResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -819,6 +912,9 @@ func (*UnimplementedMsgServer) Mint(ctx context.Context, req *MsgMint) (*MsgMint func (*UnimplementedMsgServer) Repay(ctx context.Context, req *MsgRepay) (*MsgRepayResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Repay not implemented") } +func (*UnimplementedMsgServer) Close(ctx context.Context, req *MsgClose) (*MsgCloseResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Close not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -950,6 +1046,24 @@ func _Msg_Repay_Handler(srv interface{}, ctx context.Context, dec func(interface return interceptor(ctx, in, info, handler) } +func _Msg_Close_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgClose) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Close(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/reserve.vaults.Msg/Close", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Close(ctx, req.(*MsgClose)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "reserve.vaults.Msg", HandlerType: (*MsgServer)(nil), @@ -982,6 +1096,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "Repay", Handler: _Msg_Repay_Handler, }, + { + MethodName: "Close", + Handler: _Msg_Close_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "reserve/vaults/tx.proto", @@ -1492,6 +1610,64 @@ func (m *MsgRepayResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MsgClose) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgClose) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgClose) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0x12 + } + if m.VaultId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.VaultId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgCloseResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgCloseResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCloseResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -1697,6 +1873,31 @@ func (m *MsgRepayResponse) Size() (n int) { return n } +func (m *MsgClose) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.VaultId != 0 { + n += 1 + sovTx(uint64(m.VaultId)) + } + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgCloseResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -3100,6 +3301,157 @@ func (m *MsgRepayResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgClose) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgClose: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgClose: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field VaultId", wireType) + } + m.VaultId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.VaultId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgCloseResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgCloseResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCloseResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From 3bdc3afa771ccd3feef7774ac15ed2934bc313f3 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Tue, 1 Oct 2024 20:53:56 +0700 Subject: [PATCH 2/6] check vault status --- x/vaults/keeper/vault.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/x/vaults/keeper/vault.go b/x/vaults/keeper/vault.go index 4eb7497..01951ab 100644 --- a/x/vaults/keeper/vault.go +++ b/x/vaults/keeper/vault.go @@ -119,6 +119,9 @@ 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) @@ -180,6 +183,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) @@ -221,6 +227,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)) @@ -243,6 +252,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) @@ -280,7 +292,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 @@ -297,8 +309,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 } From 5740455593cc9f11dcdb0df7caab2f4514432f65 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:48:58 +0700 Subject: [PATCH 3/6] vaults: set up test --- x/vaults/keeper/keeper.go | 9 +++++---- x/vaults/keeper/keeper_test.go | 5 +++++ x/vaults/keeper/mock/oracle_keeper.go | 25 +++++++++++++++++++++++++ x/vaults/module/module.go | 2 +- 4 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 x/vaults/keeper/mock/oracle_keeper.go diff --git a/x/vaults/keeper/keeper.go b/x/vaults/keeper/keeper.go index a83e089..d76383e 100644 --- a/x/vaults/keeper/keeper.go +++ b/x/vaults/keeper/keeper.go @@ -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" ) @@ -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. @@ -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) @@ -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)), diff --git a/x/vaults/keeper/keeper_test.go b/x/vaults/keeper/keeper_test.go index 5051fe7..b0f2052 100644 --- a/x/vaults/keeper/keeper_test.go +++ b/x/vaults/keeper/keeper_test.go @@ -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 { @@ -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 s.k = s.App.VaultsKeeper s.msgServer = keeper.NewMsgServerImpl(s.k) // s.queryServer = keeper.NewQueryServerImpl(s.k) diff --git a/x/vaults/keeper/mock/oracle_keeper.go b/x/vaults/keeper/mock/oracle_keeper.go new file mode 100644 index 0000000..b299612 --- /dev/null +++ b/x/vaults/keeper/mock/oracle_keeper.go @@ -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 +} diff --git a/x/vaults/module/module.go b/x/vaults/module/module.go index 3bf005d..afb35d0 100644 --- a/x/vaults/module/module.go +++ b/x/vaults/module/module.go @@ -193,7 +193,7 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { // in.Logger, in.AccountKeeper, in.BankKeeper, - in.OracleKeeper, + &in.OracleKeeper, authority.String(), ) m := NewAppModule( From 6267f2a472646a90277b7ae2d44fba5bb1697f9c Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:49:25 +0700 Subject: [PATCH 4/6] test TestCreateNewVault --- x/vaults/keeper/vaults_test.go | 86 +++++++++++++++++++++++++++------- x/vaults/types/params.go | 2 +- 2 files changed, 69 insertions(+), 19 deletions(-) diff --git a/x/vaults/keeper/vaults_test.go b/x/vaults/keeper/vaults_test.go index f582f28..6533806 100644 --- a/x/vaults/keeper/vaults_test.go +++ b/x/vaults/keeper/vaults_test.go @@ -29,11 +29,13 @@ func (s *KeeperTestSuite) TestVaultsStore() { func (s *KeeperTestSuite) TestCreateNewVault() { s.SetupTest() var ( - denom = "atom" - coin = sdk.NewCoin(denom, math.NewInt(1000)) - coinMintToAcc = sdk.NewCoin(denom, math.NewInt(1000000)) - maxDebt = math.NewInt(10000) + denom = "atom" + mintDenom = types.DefaultMintDenom + collateral = sdk.NewCoin(denom, math.NewInt(10_000_000)) // 10 atom = 80$ + maxDebt = math.NewInt(100_000_000) ) + err := s.k.ActiveCollateralAsset(s.Ctx, denom, math.LegacyMustNewDecFromStr("1.6"), math.LegacyMustNewDecFromStr("1.5"), maxDebt) + s.Require().NoError(err) tests := []struct { name string @@ -42,37 +44,83 @@ func (s *KeeperTestSuite) TestCreateNewVault() { owner sdk.AccAddress collateral sdk.Coin mint sdk.Coin + expErr bool }{ { - name: "success", + name: "mint less than min initial debt", setup: func() { - err := s.k.ActiveCollateralAsset(s.Ctx, denom, math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt) + err = s.App.BankKeeper.MintCoins(s.Ctx, types.ModuleName, sdk.NewCoins(collateral)) s.Require().NoError(err) - - err = s.App.BankKeeper.MintCoins(s.Ctx, types.ModuleName, sdk.NewCoins(coinMintToAcc)) + err = s.App.BankKeeper.SendCoinsFromModuleToAccount(s.Ctx, types.ModuleName, s.TestAccs[0], sdk.NewCoins(collateral)) s.Require().NoError(err) - err = s.App.BankKeeper.SendCoinsFromModuleToAccount(s.Ctx, types.ModuleName, s.TestAccs[0], sdk.NewCoins(coinMintToAcc)) + }, + denom: "atom", + owner: s.TestAccs[0], + collateral: collateral, + mint: sdk.NewCoin(mintDenom, math.NewInt(10_000_000)), + expErr: true, + }, + { + name: "exeed max debt", + setup: func() { + err = s.App.BankKeeper.MintCoins(s.Ctx, types.ModuleName, sdk.NewCoins(collateral)) + s.Require().NoError(err) + err = s.App.BankKeeper.SendCoinsFromModuleToAccount(s.Ctx, types.ModuleName, s.TestAccs[0], sdk.NewCoins(collateral)) s.Require().NoError(err) }, - denom: denom, + denom: "atom", owner: s.TestAccs[0], - collateral: coin, - mint: coin, + collateral: collateral, + mint: sdk.NewCoin(mintDenom, math.NewInt(110_000_000)), + expErr: true, + }, + { + name: "invalid ratio", + setup: func() { + err = s.App.BankKeeper.MintCoins(s.Ctx, types.ModuleName, sdk.NewCoins(collateral)) + s.Require().NoError(err) + err = s.App.BankKeeper.SendCoinsFromModuleToAccount(s.Ctx, types.ModuleName, s.TestAccs[0], sdk.NewCoins(collateral)) + s.Require().NoError(err) + }, + denom: "atom", + owner: s.TestAccs[0], + collateral: collateral, + mint: sdk.NewCoin(mintDenom, math.NewInt(60_000_000)), + expErr: true, + }, + { + name: "success", + setup: func() { + err = s.App.BankKeeper.MintCoins(s.Ctx, types.ModuleName, sdk.NewCoins(collateral)) + s.Require().NoError(err) + err = s.App.BankKeeper.SendCoinsFromModuleToAccount(s.Ctx, types.ModuleName, s.TestAccs[0], sdk.NewCoins(collateral)) + s.Require().NoError(err) + }, + denom: "atom", + owner: s.TestAccs[0], + collateral: collateral, + mint: sdk.NewCoin(mintDenom, math.NewInt(40_000_000)), + expErr: false, }, } for _, t := range tests { s.Run(t.name, func() { t.setup() err := s.k.CreateNewVault(s.Ctx, t.denom, t.owner, t.collateral, t.mint) - s.Require().NoError(err) + if t.expErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) - vm, err := s.k.GetVaultManager(s.Ctx, denom) - s.Require().NoError(err) - s.Require().NotEqual(maxDebt, vm.MintAvailable) + vm, err := s.k.GetVaultManager(s.Ctx, denom) + s.Require().NoError(err) + s.Require().NotEqual(maxDebt, vm.MintAvailable) + } }) } } +// TODO: Update func (s *KeeperTestSuite) TestRepayDebt() { s.SetupTest() var ( @@ -127,6 +175,7 @@ func (s *KeeperTestSuite) TestRepayDebt() { } } +// TODO: Update func (s *KeeperTestSuite) TestDepositToVault() { s.SetupTest() var ( @@ -181,6 +230,7 @@ func (s *KeeperTestSuite) TestDepositToVault() { } } +// TODO: Update func (s *KeeperTestSuite) TestWithdrawFromVault() { s.SetupTest() var ( @@ -235,6 +285,7 @@ func (s *KeeperTestSuite) TestWithdrawFromVault() { } } +// TODO: Update func (s *KeeperTestSuite) TestUpdateVaultsDebt() { s.SetupTest() var ( @@ -321,7 +372,7 @@ func (s *KeeperTestSuite) TestLiquidate() { }, }, }, - expVaultStatus: []types.VaultStatus{types.LIQUIDATED}, + expVaultStatus: []types.VaultStatus{types.LIQUIDATED}, reserveBalances: sdk.NewCoins(sdk.NewCoin(types.DefaultMintDenom, math.NewInt(10_000_000))), }, { @@ -523,7 +574,6 @@ func (s *KeeperTestSuite) TestLiquidate() { s.Require().Equal(updatedVault.Status, t.expVaultStatus[i]) } - }) } } diff --git a/x/vaults/types/params.go b/x/vaults/types/params.go index 46c8c65..4eb04a5 100644 --- a/x/vaults/types/params.go +++ b/x/vaults/types/params.go @@ -11,7 +11,7 @@ var ( DefaultMintingFee = math.LegacyMustNewDecFromStr("0.05") DefaultStabilityFee = math.LegacyMustNewDecFromStr("0.05") DefaultLiquidationPenalty = math.LegacyMustNewDecFromStr("0.05") - DefaultMinInitialDebt = math.NewInt(1) + DefaultMinInitialDebt = math.NewInt(20_000_000) DefaultRecalculateDebtPeriod = uint64(1) DefaultLiquidatePeriod = uint64(1) DefaultMintDenom = "nomusd" From fc0204d6fd339431ae379aee5bcf2414e2245f57 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:49:46 +0700 Subject: [PATCH 5/6] update vaults logic --- x/vaults/keeper/vault.go | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/x/vaults/keeper/vault.go b/x/vaults/keeper/vault.go index 01951ab..c2fb56a 100644 --- a/x/vaults/keeper/vault.go +++ b/x/vaults/keeper/vault.go @@ -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) + price := k.OracleKeeper.GetPrice(ctx, denom) // TODO: recalculate with denom decimal? collateralValue := math.LegacyNewDecFromInt(collateral.Amount).Mul(price) ratio := collateralValue.QuoInt(mint.Amount) @@ -127,10 +131,14 @@ func (k *Keeper) MintCoin( 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) + price := k.OracleKeeper.GetPrice(ctx, lockedCoin.Denom) lockedValue := math.LegacyNewDecFromInt(lockedCoin.Amount).Mul(price) feeAmount := math.LegacyNewDecFromInt(mint.Amount).Mul(params.MintingFee).TruncateInt() @@ -266,7 +274,7 @@ func (k *Keeper) WithdrawFromVault( } newLock := vault.CollateralLocked.Sub(collateral) - price := k.oracleKeeper.GetPrice(ctx, collateral.Denom) + price := k.OracleKeeper.GetPrice(ctx, collateral.Denom) newLockValue := math.LegacyNewDecFromInt(newLock.Amount).Mul(price) ratio := newLockValue.Quo(math.LegacyNewDecFromInt(vault.Debt.Amount)) @@ -332,7 +340,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) + price := k.OracleKeeper.GetPrice(ctx, vm.Denom) prices[vm.Denom] = price liquidationRatios[vm.Denom] = vm.Params.LiquidationRatio liquidations[vm.Denom] = types.NewEmptyLiquidation(vm.Denom) @@ -375,16 +383,17 @@ 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()) @@ -414,6 +423,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) @@ -460,6 +475,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()) { From f64f66831134a3c61c374b5fa2513d20ada0ac4b Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:37:27 +0700 Subject: [PATCH 6/6] add address to vault struct --- x/vaults/keeper/vault.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/vaults/keeper/vault.go b/x/vaults/keeper/vault.go index c2fb56a..0999644 100644 --- a/x/vaults/keeper/vault.go +++ b/x/vaults/keeper/vault.go @@ -81,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 {