From 5578d8cbd582288dd721f83101d6885c7fabbf7d Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Thu, 26 Oct 2023 19:08:11 +0530 Subject: [PATCH 01/18] WIP: adding quota v2 --- proto/umee/uibc/v1/genesis.proto | 12 ++- proto/umee/uibc/v1/quota.proto | 6 ++ x/uibc/genesis.pb.go | 165 ++++++++++++++++++++++++------ x/uibc/params.go | 12 ++- x/uibc/quota.pb.go | 115 +++++++++++++++------ x/uibc/quota/ibc_module.go | 27 +++-- x/uibc/quota/keeper/genesis.go | 6 ++ x/uibc/quota/keeper/keys.go | 9 +- x/uibc/quota/keeper/quota.go | 88 +++++++++++++++- x/uibc/quota/keeper/quota_test.go | 2 + 10 files changed, 355 insertions(+), 87 deletions(-) diff --git a/proto/umee/uibc/v1/genesis.proto b/proto/umee/uibc/v1/genesis.proto index 7b393bb6fe..f9e50cf2c4 100644 --- a/proto/umee/uibc/v1/genesis.proto +++ b/proto/umee/uibc/v1/genesis.proto @@ -17,7 +17,6 @@ message GenesisState { (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", (gogoproto.nullable) = false ]; - // total_outflow_sum defines the total outflow sum of ibc-transfer in USD. string total_outflow_sum = 3 [ (cosmos_proto.scalar) = "cosmos.Dec", @@ -31,4 +30,15 @@ message GenesisState { (gogoproto.jsontag) = "quota_duration,omitempty", (gogoproto.moretags) = "yaml:\"quota_expires\"" ]; + // inflows defines inflow amount of denoms + repeated cosmos.base.v1beta1.DecCoin inflows = 5 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.nullable) = false + ]; + // total_inflow_sum defines the total inflow sum of ibc-transfer in USD. + string total_inflow_sum = 6 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; } diff --git a/proto/umee/uibc/v1/quota.proto b/proto/umee/uibc/v1/quota.proto index 72fd7df2d5..a72d50f8d0 100644 --- a/proto/umee/uibc/v1/quota.proto +++ b/proto/umee/uibc/v1/quota.proto @@ -30,6 +30,12 @@ message Params { (gogoproto.jsontag) = "quota_duration,omitempty", (gogoproto.moretags) = "yaml:\"quota_duration\"" ]; + // total_inflow_quota defines the total inflow limit of ibc-transfer in USD + string total_inflow_quota = 5 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; } // IBCTransferStatus status of ibc-transfer quota check for inflow and outflow diff --git a/x/uibc/genesis.pb.go b/x/uibc/genesis.pb.go index 4c70dfdfe4..037e5411d9 100644 --- a/x/uibc/genesis.pb.go +++ b/x/uibc/genesis.pb.go @@ -38,6 +38,10 @@ type GenesisState struct { TotalOutflowSum github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=total_outflow_sum,json=totalOutflowSum,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_outflow_sum"` // quota_expires defines quota expire time (as unix timestamp) for ibc-transfer denom. QuotaExpires time.Time `protobuf:"bytes,4,opt,name=quota_expires,json=quotaExpires,proto3,stdtime" json:"quota_duration,omitempty" yaml:"quota_expires"` + // inflows defines inflow amount of denoms + Inflows github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,5,rep,name=inflows,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"inflows"` + // total_inflow_sum defines the total inflow sum of ibc-transfer in USD. + TotalInflowSum github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=total_inflow_sum,json=totalInflowSum,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_inflow_sum"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -80,35 +84,38 @@ func init() { func init() { proto.RegisterFile("umee/uibc/v1/genesis.proto", fileDescriptor_0196ecf2d08401fb) } var fileDescriptor_0196ecf2d08401fb = []byte{ - // 445 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x51, 0x31, 0x6f, 0xd3, 0x40, - 0x14, 0xb6, 0x49, 0x55, 0x81, 0x1b, 0x84, 0xb0, 0x32, 0x98, 0x08, 0xd9, 0x51, 0x06, 0x14, 0x09, - 0x72, 0xa7, 0xa4, 0x12, 0x03, 0x62, 0x0a, 0x41, 0x8c, 0xa0, 0x94, 0x89, 0x25, 0x3a, 0xbb, 0x57, - 0xf7, 0xd4, 0x9c, 0x9f, 0xf1, 0xbd, 0x4b, 0x9b, 0x81, 0xff, 0xd0, 0x99, 0x9f, 0xc0, 0xcc, 0x8f, - 0xc8, 0x58, 0x31, 0x21, 0x06, 0x17, 0x92, 0x8d, 0x91, 0x5f, 0x80, 0x7c, 0x77, 0x41, 0xed, 0xc6, - 0x64, 0x7f, 0xef, 0x7b, 0xef, 0xbb, 0xef, 0x7d, 0x2f, 0xe8, 0x6a, 0xc9, 0x39, 0xd5, 0x22, 0xcd, - 0xe8, 0x72, 0x44, 0x73, 0x5e, 0x70, 0x25, 0x14, 0x29, 0x2b, 0x40, 0x08, 0xdb, 0x0d, 0x47, 0x1a, - 0x8e, 0x2c, 0x47, 0xdd, 0x4e, 0x0e, 0x39, 0x18, 0x82, 0x36, 0x7f, 0xb6, 0xa7, 0xfb, 0x28, 0x03, - 0x25, 0x41, 0xcd, 0x2d, 0x61, 0x81, 0xa3, 0x62, 0x8b, 0x68, 0xca, 0x14, 0xa7, 0xcb, 0x51, 0xca, - 0x91, 0x8d, 0x68, 0x06, 0xa2, 0x70, 0x7c, 0x92, 0x03, 0xe4, 0x0b, 0x4e, 0x0d, 0x4a, 0xf5, 0x09, - 0x45, 0x21, 0xb9, 0x42, 0x26, 0x4b, 0xd7, 0x10, 0xdd, 0xf2, 0xf6, 0x51, 0x03, 0x32, 0xcb, 0xf4, - 0x3f, 0xb7, 0x82, 0xf6, 0x1b, 0xeb, 0xf5, 0x08, 0x19, 0xf2, 0x70, 0x1c, 0xec, 0x97, 0xac, 0x62, - 0x52, 0x45, 0x7e, 0xcf, 0x1f, 0x1c, 0x8c, 0x3b, 0xe4, 0xa6, 0x77, 0xf2, 0xce, 0x70, 0x93, 0xbd, - 0x75, 0x9d, 0x78, 0x33, 0xd7, 0x19, 0xca, 0xe0, 0x2e, 0x68, 0x3c, 0x59, 0xc0, 0xb9, 0x8a, 0xee, - 0xf4, 0x5a, 0x83, 0x83, 0xf1, 0x63, 0xe2, 0x16, 0x68, 0x2c, 0x13, 0x67, 0x99, 0x4c, 0x79, 0xf6, - 0x0a, 0x44, 0x31, 0x39, 0x6c, 0xa6, 0xbf, 0x5c, 0x27, 0x4f, 0x73, 0x81, 0xa7, 0x3a, 0x25, 0x19, - 0x48, 0xb7, 0xb0, 0xfb, 0x0c, 0xd5, 0xf1, 0x19, 0xc5, 0x55, 0xc9, 0xd5, 0x6e, 0x46, 0xcd, 0xfe, - 0x3d, 0x11, 0x9e, 0x06, 0x0f, 0x11, 0x90, 0x2d, 0xe6, 0xae, 0x32, 0x57, 0x5a, 0x46, 0xad, 0x9e, - 0x3f, 0xb8, 0x37, 0x79, 0xd9, 0x28, 0xff, 0xa8, 0x93, 0x27, 0xff, 0xa7, 0xfc, 0xed, 0xeb, 0x30, - 0x70, 0x46, 0xa7, 0x3c, 0x9b, 0x3d, 0x30, 0xb2, 0x6f, 0xad, 0xea, 0x91, 0x96, 0xe1, 0xa7, 0xe0, - 0xbe, 0x09, 0x6b, 0xce, 0x2f, 0x4a, 0x51, 0x71, 0x15, 0xed, 0x99, 0x4c, 0xba, 0xc4, 0x06, 0x4e, - 0x76, 0x81, 0x93, 0xf7, 0xbb, 0xc0, 0xad, 0x83, 0xdf, 0x75, 0x12, 0xd9, 0xc1, 0x63, 0x5d, 0x31, - 0x14, 0x50, 0x3c, 0x03, 0x29, 0x90, 0xcb, 0x12, 0x57, 0x7f, 0xea, 0xa4, 0xb3, 0x62, 0x72, 0xf1, - 0xa2, 0x7f, 0x4b, 0xba, 0x7f, 0x79, 0x9d, 0xf8, 0xb3, 0xb6, 0xa9, 0xbd, 0xb6, 0xa5, 0xc9, 0x74, - 0xfd, 0x2b, 0xf6, 0xd6, 0x9b, 0xd8, 0xbf, 0xda, 0xc4, 0xfe, 0xcf, 0x4d, 0xec, 0x5f, 0x6e, 0x63, - 0xef, 0x6a, 0x1b, 0x7b, 0xdf, 0xb7, 0xb1, 0xf7, 0xe1, 0xe6, 0x8e, 0xcd, 0x8d, 0x86, 0x05, 0xc7, - 0x73, 0xa8, 0xce, 0x0c, 0xa0, 0xcb, 0xe7, 0xf4, 0xc2, 0x5c, 0x3c, 0xdd, 0x37, 0x2e, 0x0f, 0xff, - 0x06, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x24, 0x38, 0xc9, 0xa1, 0x02, 0x00, 0x00, + // 482 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x92, 0xbf, 0x8e, 0x13, 0x3d, + 0x14, 0xc5, 0x67, 0xbe, 0xcd, 0x17, 0xc0, 0x1b, 0xfe, 0x8d, 0x52, 0x0c, 0x11, 0x9a, 0x89, 0x52, + 0xa0, 0x48, 0x10, 0x5b, 0xc9, 0x4a, 0x14, 0x88, 0x2a, 0x04, 0x21, 0x2a, 0x50, 0x96, 0x8a, 0x26, + 0xf2, 0xcc, 0x3a, 0xb3, 0x56, 0xe2, 0xb9, 0xc3, 0xd8, 0xce, 0x6e, 0x0a, 0xde, 0x61, 0x9f, 0x83, + 0x9a, 0x87, 0x48, 0xb9, 0xa2, 0x42, 0x14, 0x59, 0x48, 0x3a, 0x1a, 0x24, 0x9e, 0x00, 0x8d, 0xed, + 0xa0, 0xdd, 0x8e, 0x02, 0xaa, 0x99, 0x7b, 0x8f, 0xef, 0xb9, 0xc7, 0x3f, 0x19, 0xb5, 0xb4, 0x60, + 0x8c, 0x68, 0x9e, 0xa4, 0x64, 0xd1, 0x27, 0x19, 0xcb, 0x99, 0xe4, 0x12, 0x17, 0x25, 0x28, 0x08, + 0x1a, 0x95, 0x86, 0x2b, 0x0d, 0x2f, 0xfa, 0xad, 0x66, 0x06, 0x19, 0x18, 0x81, 0x54, 0x7f, 0xf6, + 0x4c, 0xeb, 0x5e, 0x0a, 0x52, 0x80, 0x9c, 0x58, 0xc1, 0x16, 0x4e, 0x8a, 0x6c, 0x45, 0x12, 0x2a, + 0x19, 0x59, 0xf4, 0x13, 0xa6, 0x68, 0x9f, 0xa4, 0xc0, 0x73, 0xa7, 0xc7, 0x19, 0x40, 0x36, 0x67, + 0xc4, 0x54, 0x89, 0x9e, 0x12, 0xc5, 0x05, 0x93, 0x8a, 0x8a, 0xc2, 0x1d, 0x08, 0xaf, 0x64, 0x7b, + 0xa7, 0x41, 0x51, 0xab, 0x74, 0x7e, 0xd4, 0x50, 0xe3, 0x85, 0xcd, 0x7a, 0xa8, 0xa8, 0x62, 0xc1, + 0x00, 0xd5, 0x0b, 0x5a, 0x52, 0x21, 0x43, 0xbf, 0xed, 0x77, 0xf7, 0x07, 0x4d, 0x7c, 0x39, 0x3b, + 0x7e, 0x6d, 0xb4, 0x61, 0x6d, 0xb5, 0x8e, 0xbd, 0xb1, 0x3b, 0x19, 0x08, 0x74, 0x1d, 0xb4, 0x9a, + 0xce, 0xe1, 0x44, 0x86, 0xff, 0xb5, 0xf7, 0xba, 0xfb, 0x83, 0xfb, 0xd8, 0x5d, 0xa0, 0x8a, 0x8c, + 0x5d, 0x64, 0x3c, 0x62, 0xe9, 0x33, 0xe0, 0xf9, 0xf0, 0xa0, 0x9a, 0xfe, 0x70, 0x11, 0x3f, 0xcc, + 0xb8, 0x3a, 0xd6, 0x09, 0x4e, 0x41, 0xb8, 0x0b, 0xbb, 0x4f, 0x4f, 0x1e, 0xcd, 0x88, 0x5a, 0x16, + 0x4c, 0xee, 0x66, 0xe4, 0xf8, 0xf7, 0x8a, 0xe0, 0x18, 0xdd, 0x55, 0xa0, 0xe8, 0x7c, 0xe2, 0x3a, + 0x13, 0xa9, 0x45, 0xb8, 0xd7, 0xf6, 0xbb, 0x37, 0x86, 0x4f, 0x2b, 0xe7, 0x2f, 0xeb, 0xf8, 0xc1, + 0x9f, 0x39, 0x7f, 0xfa, 0xd8, 0x43, 0x2e, 0xe8, 0x88, 0xa5, 0xe3, 0xdb, 0xc6, 0xf6, 0x95, 0x75, + 0x3d, 0xd4, 0x22, 0x78, 0x8f, 0x6e, 0x1a, 0x58, 0x13, 0x76, 0x5a, 0xf0, 0x92, 0xc9, 0xb0, 0x66, + 0x98, 0xb4, 0xb0, 0x05, 0x8e, 0x77, 0xc0, 0xf1, 0x9b, 0x1d, 0x70, 0x9b, 0xe0, 0xfb, 0x3a, 0x0e, + 0xed, 0xe0, 0x91, 0x2e, 0xa9, 0xe2, 0x90, 0x3f, 0x02, 0xc1, 0x15, 0x13, 0x85, 0x5a, 0xfe, 0x5c, + 0xc7, 0xcd, 0x25, 0x15, 0xf3, 0x27, 0x9d, 0x2b, 0xd6, 0x9d, 0xb3, 0x8b, 0xd8, 0x1f, 0x37, 0x4c, + 0xef, 0xb9, 0x6d, 0x05, 0x33, 0x74, 0x8d, 0xe7, 0x16, 0xeb, 0xff, 0xff, 0x0a, 0xeb, 0x6e, 0x43, + 0x30, 0x45, 0x77, 0x2c, 0x55, 0xdb, 0x30, 0x50, 0xeb, 0x7f, 0x01, 0xea, 0x2d, 0xe3, 0xfa, 0x32, + 0x77, 0x4c, 0x87, 0xa3, 0xd5, 0xb7, 0xc8, 0x5b, 0x6d, 0x22, 0xff, 0x7c, 0x13, 0xf9, 0x5f, 0x37, + 0x91, 0x7f, 0xb6, 0x8d, 0xbc, 0xf3, 0x6d, 0xe4, 0x7d, 0xde, 0x46, 0xde, 0xdb, 0xcb, 0x3b, 0xaa, + 0x87, 0xd7, 0xcb, 0x99, 0x3a, 0x81, 0x72, 0x66, 0x0a, 0xb2, 0x78, 0x4c, 0x4e, 0xcd, 0x33, 0x4e, + 0xea, 0x06, 0xfd, 0xc1, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x12, 0x4f, 0x6e, 0xd5, 0x76, 0x03, + 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -131,6 +138,30 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.TotalInflowSum.Size() + i -= size + if _, err := m.TotalInflowSum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if len(m.Inflows) > 0 { + for iNdEx := len(m.Inflows) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Inflows[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.QuotaExpires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.QuotaExpires):]) if err1 != nil { return 0, err1 @@ -205,6 +236,14 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) l = github_com_gogo_protobuf_types.SizeOfStdTime(m.QuotaExpires) n += 1 + l + sovGenesis(uint64(l)) + if len(m.Inflows) > 0 { + for _, e := range m.Inflows { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + l = m.TotalInflowSum.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -377,6 +416,74 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Inflows", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Inflows = append(m.Inflows, types.DecCoin{}) + if err := m.Inflows[len(m.Inflows)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalInflowSum", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TotalInflowSum.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/uibc/params.go b/x/uibc/params.go index 6d5d797d27..9f4726e258 100644 --- a/x/uibc/params.go +++ b/x/uibc/params.go @@ -10,10 +10,11 @@ import ( // DefaultParams returns default genesis params func DefaultParams() Params { return Params{ - IbcStatus: IBCTransferStatus_IBC_TRANSFER_STATUS_QUOTA_ENABLED, - TotalQuota: sdk.NewDec(1_000_000), - TokenQuota: sdk.NewDec(600_000), - QuotaDuration: time.Second * 60 * 60 * 24, // 24h + IbcStatus: IBCTransferStatus_IBC_TRANSFER_STATUS_QUOTA_ENABLED, + TotalQuota: sdk.NewDec(1_000_000), + TokenQuota: sdk.NewDec(600_000), + QuotaDuration: time.Second * 60 * 60 * 24, // 24h + TotalInflowQuota: sdk.NewDec(1_000_000), } } @@ -30,6 +31,9 @@ func (p Params) Validate() error { if err := validateQuota(p.TokenQuota, "quota per token"); err != nil { return err } + if err := validateQuota(p.TotalInflowQuota, "total inflow quota"); err != nil { + return err + } if p.TotalQuota.LT(p.TokenQuota) { return fmt.Errorf("token quota shouldn't be less than quota per denom") } diff --git a/x/uibc/quota.pb.go b/x/uibc/quota.pb.go index ef354af807..311b2a08e4 100644 --- a/x/uibc/quota.pb.go +++ b/x/uibc/quota.pb.go @@ -83,6 +83,8 @@ type Params struct { TokenQuota github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=token_quota,json=tokenQuota,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"token_quota"` // quota_duration defines quota expires for each ibc-transfer denom in seconds QuotaDuration time.Duration `protobuf:"bytes,4,opt,name=quota_duration,json=quotaDuration,proto3,stdduration" json:"quota_duration,omitempty" yaml:"quota_duration"` + // total_inflow_quota defines the total inflow limit of ibc-transfer in USD + TotalInflowQuota github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=total_inflow_quota,json=totalInflowQuota,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_inflow_quota"` } func (m *Params) Reset() { *m = Params{} } @@ -140,39 +142,40 @@ func init() { func init() { proto.RegisterFile("umee/uibc/v1/quota.proto", fileDescriptor_651be1a0280abcb6) } var fileDescriptor_651be1a0280abcb6 = []byte{ - // 502 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x3f, 0x6f, 0xd3, 0x4e, - 0x18, 0xc7, 0xed, 0xa4, 0xbf, 0x4a, 0xbd, 0xfe, 0xa8, 0x82, 0x05, 0x92, 0xdb, 0xc1, 0x0e, 0x81, - 0x46, 0xa1, 0x22, 0x67, 0xb5, 0x48, 0x0c, 0x08, 0x10, 0x76, 0xec, 0x4a, 0x96, 0x50, 0x9a, 0xfa, - 0xcf, 0x82, 0x84, 0x2c, 0xdb, 0xbd, 0x1a, 0x2b, 0xb1, 0x2f, 0xd8, 0xe7, 0x40, 0x26, 0x46, 0x18, - 0x19, 0x79, 0x21, 0xbc, 0x88, 0x8e, 0x15, 0x13, 0x62, 0x08, 0x28, 0xd9, 0x18, 0x79, 0x05, 0xc8, - 0x77, 0x8e, 0xda, 0x8a, 0x66, 0x63, 0xf2, 0x3d, 0xfe, 0x7e, 0xee, 0x73, 0x8f, 0x9e, 0xb3, 0x81, - 0x58, 0x24, 0x08, 0x29, 0x45, 0x1c, 0x84, 0xca, 0x64, 0x5f, 0x79, 0x53, 0x60, 0xe2, 0xc3, 0x71, - 0x86, 0x09, 0x16, 0xfe, 0x2f, 0x13, 0x58, 0x26, 0x70, 0xb2, 0xbf, 0x73, 0x2b, 0xc2, 0x11, 0xa6, - 0x81, 0x52, 0xae, 0x18, 0xb3, 0x23, 0x45, 0x18, 0x47, 0x23, 0xa4, 0xd0, 0x2a, 0x28, 0x4e, 0x95, - 0x93, 0x22, 0xf3, 0x49, 0x8c, 0xd3, 0x2a, 0xdf, 0x0e, 0x71, 0x9e, 0xe0, 0xdc, 0x63, 0x1b, 0x59, - 0xc1, 0xa2, 0xd6, 0x87, 0x3a, 0x58, 0x1f, 0xf8, 0x99, 0x9f, 0xe4, 0xc2, 0x33, 0x00, 0xe2, 0x20, - 0xf4, 0x72, 0xe2, 0x93, 0x22, 0x17, 0xf9, 0x26, 0xdf, 0xd9, 0x3a, 0x90, 0xe1, 0xe5, 0xe3, 0xa1, - 0xa9, 0xf5, 0x9c, 0xcc, 0x4f, 0xf3, 0x53, 0x94, 0xd9, 0x14, 0xb3, 0x36, 0xe2, 0x20, 0x64, 0x4b, - 0xe1, 0x15, 0xd8, 0x24, 0x98, 0xf8, 0x23, 0x8f, 0xb6, 0x2f, 0xd6, 0x9a, 0x7c, 0x67, 0x43, 0x7b, - 0x72, 0x36, 0x93, 0xb9, 0xef, 0x33, 0xb9, 0x1d, 0xc5, 0xe4, 0x75, 0x11, 0xc0, 0x10, 0x27, 0x55, - 0x03, 0xd5, 0xa3, 0x9b, 0x9f, 0x0c, 0x15, 0x32, 0x1d, 0xa3, 0x1c, 0xea, 0x28, 0xfc, 0xfa, 0xa5, - 0x0b, 0xaa, 0xfe, 0x74, 0x14, 0x5a, 0x80, 0x0a, 0x8f, 0x4b, 0x1f, 0xd3, 0x0f, 0x51, 0x5a, 0xe9, - 0xeb, 0xff, 0x46, 0x3f, 0x44, 0x29, 0xd3, 0xbf, 0x07, 0x5b, 0x54, 0xec, 0x2d, 0x67, 0x27, 0xae, - 0x35, 0xf9, 0xce, 0xe6, 0xc1, 0x36, 0x64, 0xc3, 0x85, 0xcb, 0xe1, 0x42, 0xbd, 0x02, 0xb4, 0xa7, - 0xe5, 0xe1, 0xbf, 0x66, 0xb2, 0x78, 0x75, 0xe3, 0x03, 0x9c, 0xc4, 0x04, 0x25, 0x63, 0x32, 0xfd, - 0x3d, 0x93, 0x6f, 0x4f, 0xfd, 0x64, 0xf4, 0xb8, 0x75, 0x95, 0x68, 0x7d, 0xfe, 0x21, 0xf3, 0xd6, - 0x0d, 0xfa, 0x72, 0x69, 0xdb, 0xfb, 0x58, 0x03, 0x37, 0xff, 0x9a, 0xaf, 0x70, 0x17, 0xc8, 0xa6, - 0xd6, 0xf3, 0x1c, 0x4b, 0xed, 0xdb, 0x87, 0x86, 0xe5, 0xd9, 0x8e, 0xea, 0xb8, 0xb6, 0xe7, 0xf6, - 0xed, 0x81, 0xd1, 0x33, 0x0f, 0x4d, 0x43, 0x6f, 0x70, 0x42, 0x1b, 0xb4, 0xae, 0x83, 0x8e, 0xdd, - 0x23, 0x47, 0xf5, 0x74, 0xd3, 0x56, 0xb5, 0x17, 0x86, 0xde, 0xe0, 0x85, 0x5d, 0x70, 0x67, 0x35, - 0x67, 0xf4, 0x19, 0x56, 0x13, 0xf6, 0x40, 0x7b, 0x35, 0x76, 0xe4, 0x3a, 0x17, 0xca, 0xba, 0x70, - 0x1f, 0xec, 0xae, 0x66, 0xcd, 0xfe, 0x05, 0xba, 0x26, 0x74, 0xc0, 0xbd, 0xeb, 0xd0, 0x65, 0x6d, - 0x7b, 0x03, 0xd5, 0xb5, 0x0d, 0xbd, 0xf1, 0x9f, 0xf6, 0xfc, 0x6c, 0x2e, 0xf1, 0xe7, 0x73, 0x89, - 0xff, 0x39, 0x97, 0xf8, 0x4f, 0x0b, 0x89, 0x3b, 0x5f, 0x48, 0xdc, 0xb7, 0x85, 0xc4, 0xbd, 0xbc, - 0x7c, 0xcf, 0xe5, 0x97, 0xd9, 0x4d, 0x11, 0x79, 0x8b, 0xb3, 0x21, 0x2d, 0x94, 0xc9, 0x23, 0xe5, - 0x1d, 0xfd, 0x89, 0x82, 0x75, 0x7a, 0x5b, 0x0f, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0xf5, 0x90, - 0x20, 0x70, 0x58, 0x03, 0x00, 0x00, + // 524 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0x80, 0xe3, 0xa4, 0xad, 0xd4, 0x2b, 0x54, 0xe1, 0x04, 0x52, 0xda, 0xc1, 0x0e, 0x81, 0x46, + 0xa1, 0x22, 0x67, 0xb5, 0x48, 0x0c, 0x08, 0x10, 0x71, 0xec, 0x4a, 0x96, 0x50, 0x9a, 0xc6, 0xf6, + 0x82, 0x84, 0x2c, 0xdb, 0xbd, 0x18, 0x93, 0xd8, 0x17, 0xec, 0x73, 0x4a, 0x26, 0x56, 0x46, 0x46, + 0x7e, 0x08, 0x3f, 0xa2, 0x63, 0xc5, 0x84, 0x18, 0x02, 0x4a, 0x36, 0x46, 0xf8, 0x03, 0xc8, 0x77, + 0x8e, 0xda, 0xaa, 0xcd, 0xd6, 0xc9, 0xf7, 0xfc, 0xbe, 0xfb, 0xee, 0xbd, 0x67, 0x1f, 0xa8, 0xa4, + 0x21, 0xc6, 0x72, 0x1a, 0xb8, 0x9e, 0x3c, 0xde, 0x93, 0x3f, 0xa4, 0x84, 0x3a, 0x68, 0x14, 0x13, + 0x4a, 0xe0, 0xad, 0x2c, 0x83, 0xb2, 0x0c, 0x1a, 0xef, 0x6d, 0xdf, 0xf5, 0x89, 0x4f, 0x58, 0x42, + 0xce, 0x56, 0x9c, 0xd9, 0x16, 0x7d, 0x42, 0xfc, 0x21, 0x96, 0x59, 0xe4, 0xa6, 0x7d, 0xf9, 0x38, + 0x8d, 0x1d, 0x1a, 0x90, 0x28, 0xcf, 0x6f, 0x79, 0x24, 0x09, 0x49, 0x62, 0xf3, 0x8d, 0x3c, 0xe0, + 0xa9, 0xda, 0xbf, 0x12, 0x58, 0xeb, 0x3a, 0xb1, 0x13, 0x26, 0xf0, 0x25, 0x00, 0x81, 0xeb, 0xd9, + 0x09, 0x75, 0x68, 0x9a, 0x54, 0x84, 0xaa, 0xd0, 0xd8, 0xdc, 0x97, 0xd0, 0xc5, 0xe3, 0x91, 0xae, + 0xb4, 0xcd, 0xd8, 0x89, 0x92, 0x3e, 0x8e, 0x0d, 0x86, 0xf5, 0xd6, 0x03, 0xd7, 0xe3, 0x4b, 0xf8, + 0x16, 0x6c, 0x50, 0x42, 0x9d, 0xa1, 0xcd, 0xca, 0xaf, 0x14, 0xab, 0x42, 0x63, 0x5d, 0x79, 0x7e, + 0x3a, 0x95, 0x0a, 0x3f, 0xa7, 0x52, 0xdd, 0x0f, 0xe8, 0xbb, 0xd4, 0x45, 0x1e, 0x09, 0xf3, 0x02, + 0xf2, 0x47, 0x33, 0x39, 0x1e, 0xc8, 0x74, 0x32, 0xc2, 0x09, 0x52, 0xb1, 0xf7, 0xfd, 0x5b, 0x13, + 0xe4, 0xf5, 0xa9, 0xd8, 0xeb, 0x01, 0x26, 0x3c, 0xca, 0x7c, 0x5c, 0x3f, 0xc0, 0x51, 0xae, 0x2f, + 0xdd, 0x8c, 0x7e, 0x80, 0x23, 0xae, 0xff, 0x04, 0x36, 0x99, 0xd8, 0x5e, 0xcc, 0xae, 0xb2, 0x52, + 0x15, 0x1a, 0x1b, 0xfb, 0x5b, 0x88, 0x0f, 0x17, 0x2d, 0x86, 0x8b, 0xd4, 0x1c, 0x50, 0x5e, 0x64, + 0x87, 0xff, 0x99, 0x4a, 0x95, 0xcb, 0x1b, 0x1f, 0x93, 0x30, 0xa0, 0x38, 0x1c, 0xd1, 0xc9, 0xdf, + 0xa9, 0x74, 0x6f, 0xe2, 0x84, 0xc3, 0x67, 0xb5, 0xcb, 0x44, 0xed, 0xeb, 0x2f, 0x49, 0xe8, 0xdd, + 0x66, 0x2f, 0x17, 0x36, 0xf8, 0x1e, 0x40, 0x3e, 0xbe, 0x20, 0xea, 0x0f, 0xc9, 0x49, 0xde, 0xe6, + 0xea, 0x0d, 0xb4, 0x59, 0x66, 0x5e, 0x9d, 0x69, 0x59, 0xb3, 0xbb, 0x9f, 0x8b, 0xe0, 0xce, 0x95, + 0x6f, 0x09, 0x1f, 0x00, 0x49, 0x57, 0xda, 0xb6, 0xd9, 0x6b, 0x75, 0x8c, 0x03, 0xad, 0x67, 0x1b, + 0x66, 0xcb, 0xb4, 0x0c, 0xdb, 0xea, 0x18, 0x5d, 0xad, 0xad, 0x1f, 0xe8, 0x9a, 0x5a, 0x2e, 0xc0, + 0x3a, 0xa8, 0x5d, 0x07, 0x1d, 0x59, 0x87, 0x66, 0xcb, 0x56, 0x75, 0xa3, 0xa5, 0xbc, 0xd6, 0xd4, + 0xb2, 0x00, 0x77, 0xc0, 0xfd, 0xe5, 0x9c, 0xd6, 0xe1, 0x58, 0x11, 0xee, 0x82, 0xfa, 0x72, 0xec, + 0xd0, 0x32, 0xcf, 0x95, 0x25, 0xf8, 0x08, 0xec, 0x2c, 0x67, 0xf5, 0xce, 0x39, 0xba, 0x02, 0x1b, + 0xe0, 0xe1, 0x75, 0xe8, 0x22, 0x36, 0xec, 0x6e, 0xcb, 0x32, 0x34, 0xb5, 0xbc, 0xaa, 0xbc, 0x3a, + 0x9d, 0x89, 0xc2, 0xd9, 0x4c, 0x14, 0x7e, 0xcf, 0x44, 0xe1, 0xcb, 0x5c, 0x2c, 0x9c, 0xcd, 0xc5, + 0xc2, 0x8f, 0xb9, 0x58, 0x78, 0x73, 0x71, 0xd8, 0xd9, 0x2d, 0x68, 0x46, 0x98, 0x9e, 0x90, 0x78, + 0xc0, 0x02, 0x79, 0xfc, 0x54, 0xfe, 0xc8, 0x2e, 0xac, 0xbb, 0xc6, 0xfe, 0x8c, 0x27, 0xff, 0x03, + 0x00, 0x00, 0xff, 0xff, 0x88, 0xbe, 0x35, 0x75, 0xc4, 0x03, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -195,6 +198,16 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.TotalInflowQuota.Size() + i -= size + if _, err := m.TotalInflowQuota.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintQuota(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a n1, err1 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.QuotaDuration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.QuotaDuration):]) if err1 != nil { return 0, err1 @@ -257,6 +270,8 @@ func (m *Params) Size() (n int) { n += 1 + l + sovQuota(uint64(l)) l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.QuotaDuration) n += 1 + l + sovQuota(uint64(l)) + l = m.TotalInflowQuota.Size() + n += 1 + l + sovQuota(uint64(l)) return n } @@ -415,6 +430,40 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalInflowQuota", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuota + } + 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 ErrInvalidLengthQuota + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuota + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TotalInflowQuota.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuota(dAtA[iNdEx:]) diff --git a/x/uibc/quota/ibc_module.go b/x/uibc/quota/ibc_module.go index f68620f9f9..b7e7d46781 100644 --- a/x/uibc/quota/ibc_module.go +++ b/x/uibc/quota/ibc_module.go @@ -46,20 +46,19 @@ func (im ICS20Module) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, return channeltypes.NewErrorAcknowledgement(transfertypes.ErrReceiveDisabled) } - // TODO: re-enable inflow checks - // if params.IbcStatus.InflowQuotaEnabled() { - // var data transfertypes.FungibleTokenPacketData - // if err := transfertypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - // ackErr := sdkerrors.ErrInvalidType.Wrap("cannot unmarshal ICS-20 transfer packet data") - // return channeltypes.NewErrorAcknowledgement(ackErr) - // } - - // isSourceChain := transfertypes.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) - // ackErr := im.kb.Keeper(&ctx).CheckIBCInflow(ctx, packet, data.Denom, isSourceChain) - // if ackErr != nil { - // return ackErr - // } - // } + if params.IbcStatus.OutflowQuotaEnabled() { + var data transfertypes.FungibleTokenPacketData + if err := transfertypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + ackErr := sdkerrors.ErrInvalidType.Wrap("cannot unmarshal ICS-20 transfer packet data") + return channeltypes.NewErrorAcknowledgement(ackErr) + } + + isSourceChain := transfertypes.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) + ackErr := im.kb.Keeper(&ctx).CheckIBCInflow(ctx, packet, data.Denom, data.Amount, isSourceChain) + if ackErr != nil { + return ackErr + } + } return im.IBCModule.OnRecvPacket(ctx, packet, relayer) } diff --git a/x/uibc/quota/keeper/genesis.go b/x/uibc/quota/keeper/genesis.go index a710d6ac43..da94643824 100644 --- a/x/uibc/quota/keeper/genesis.go +++ b/x/uibc/quota/keeper/genesis.go @@ -14,7 +14,9 @@ func (kb Builder) InitGenesis(ctx sdk.Context, genState uibc.GenesisState) { util.Panic(err) k.SetTokenOutflows(genState.Outflows) + k.SetTokenOutflows(genState.Inflows) k.SetTotalOutflowSum(genState.TotalOutflowSum) + k.SetTotalInflowSum(genState.TotalInflowSum) err = k.SetExpire(genState.QuotaExpires) util.Panic(err) @@ -25,6 +27,8 @@ func (kb Builder) ExportGenesis(ctx sdk.Context) *uibc.GenesisState { k := kb.Keeper(&ctx) outflows, err := k.GetAllOutflows() util.Panic(err) + inflows, err := k.GetAllInflows() + util.Panic(err) quotaExpires, err := k.GetExpire() util.Panic(err) @@ -33,5 +37,7 @@ func (kb Builder) ExportGenesis(ctx sdk.Context) *uibc.GenesisState { Outflows: outflows, TotalOutflowSum: k.GetTotalOutflow(), QuotaExpires: *quotaExpires, + Inflows: inflows, + TotalInflowSum: k.GetTotalInflow(), } } diff --git a/x/uibc/quota/keeper/keys.go b/x/uibc/quota/keeper/keys.go index 8eb9321fc6..0d644c9d4e 100644 --- a/x/uibc/quota/keeper/keys.go +++ b/x/uibc/quota/keeper/keys.go @@ -9,9 +9,16 @@ var ( keyTotalOutflows = []byte{0x02} keyParams = []byte{0x03} keyQuotaExpires = []byte{0x04} + keyPrefixDenomInflows = []byte{0x05} + keyTotalInflows = []byte{0x06} ) func KeyTotalOutflows(ibcDenom string) []byte { - // KeyPrefixDenomQuota | denom + // keyPrefixDenomOutflows | denom return util.ConcatBytes(0, keyPrefixDenomOutflows, []byte(ibcDenom)) } + +func KeyTotalInflows(ibcDenom string) []byte { + // keyPrefixDenomInflows | denom + return util.ConcatBytes(0, keyPrefixDenomInflows, []byte(ibcDenom)) +} diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index 2befc6ebed..99d31696ff 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -38,6 +38,25 @@ func (k Keeper) GetAllOutflows() (sdk.DecCoins, error) { return outflows, nil } +// GetAllInflows returns inflows of all registered tokens in USD value. +func (k Keeper) GetAllInflows() (sdk.DecCoins, error) { + var inflows sdk.DecCoins + // creating PrefixStore upfront will remove the prefix from the key when running the iterator. + store := k.PrefixStore(keyPrefixDenomOutflows) + iter := sdk.KVStorePrefixIterator(store, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + o := sdk.DecCoin{Denom: string(iter.Key())} + if err := o.Amount.Unmarshal(iter.Value()); err != nil { + return nil, err + } + inflows = append(inflows, o) + } + + return inflows, nil +} + // GetTokenOutflows returns sum of denom outflows in USD value in the DecCoin structure. func (k Keeper) GetTokenOutflows(denom string) sdk.DecCoin { amount, _ := store.GetDec(k.store, KeyTotalOutflows(denom), "total_outflow") @@ -52,6 +71,14 @@ func (k Keeper) SetTokenOutflows(outflows sdk.DecCoins) { } } +// SetTokenInflows saves provided updated IBC inflows as a pair: USD value, denom name in the +// DecCoin structure. +func (k Keeper) SetTokenInflows(inflows sdk.DecCoins) { + for _, q := range inflows { + k.SetTokenInflow(q) + } +} + // SetTokenOutflow save the outflows of denom into store. func (k Keeper) SetTokenOutflow(outflow sdk.DecCoin) { key := KeyTotalOutflows(outflow.Denom) @@ -59,6 +86,13 @@ func (k Keeper) SetTokenOutflow(outflow sdk.DecCoin) { util.Panic(err) } +// SetTokenInflow save the inflow of denom into store. +func (k Keeper) SetTokenInflow(inflow sdk.DecCoin) { + key := KeyTotalInflows(inflow.Denom) + err := store.SetDec(k.store, key, inflow.Amount, "total_inflow") + util.Panic(err) +} + // GetTotalOutflow returns the total outflow of ibc-transfer amount. func (k Keeper) GetTotalOutflow() sdk.Dec { // TODO: use store.Get/SetDec @@ -66,11 +100,23 @@ func (k Keeper) GetTotalOutflow() sdk.Dec { return sdk.MustNewDecFromStr(string(bz)) } +// GetTotalInflow returns the total inflow of ibc-transfer amount. +func (k Keeper) GetTotalInflow() sdk.Dec { + // TODO: use store.Get/SetDec + bz := k.store.Get(keyTotalInflows) + return sdk.MustNewDecFromStr(string(bz)) +} + // SetTotalOutflowSum save the total outflow of ibc-transfer amount. func (k Keeper) SetTotalOutflowSum(amount sdk.Dec) { k.store.Set(keyTotalOutflows, []byte(amount.String())) } +// SetTotalInflowSum save the total inflow of ibc-transfer amount. +func (k Keeper) SetTotalInflowSum(amount sdk.Dec) { + k.store.Set(keyTotalInflows, []byte(amount.String())) +} + // SetExpire save the quota expire time of ibc denom into. func (k Keeper) SetExpire(expires time.Time) error { return store.SetBinValue(k.store, keyQuotaExpires, &expires, "expire") @@ -93,6 +139,7 @@ func (k Keeper) ResetAllQuotas() error { if err != nil { return err } + // outflows k.SetTotalOutflowSum(zero) store := k.PrefixStore(keyPrefixDenomOutflows) iter := sdk.KVStorePrefixIterator(store, nil) @@ -100,6 +147,15 @@ func (k Keeper) ResetAllQuotas() error { for ; iter.Valid(); iter.Next() { store.Set(iter.Key(), zeroBz) } + + // inflows + k.SetTotalInflowSum(zero) + store = k.PrefixStore(keyPrefixDenomInflows) + iter = sdk.KVStorePrefixIterator(store, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + store.Set(iter.Key(), zeroBz) + } return nil } @@ -122,11 +178,20 @@ func (k Keeper) CheckAndUpdateQuota(denom string, newOutflow sdkmath.Int) error return uibc.ErrQuotaExceeded } + // Allow outflow either of two conditions + // 1. Total Outflow Sum <= Total Outflow Quota + // or + // 2 . Total Outflow Sum <= $1M + params.TotalInflowQuota * sum of all inflows totalOutflowSum := k.GetTotalOutflow().Add(exchangePrice) if !params.TotalQuota.IsZero() && totalOutflowSum.GT(params.TotalQuota) { return uibc.ErrQuotaExceeded } + totalInflowSum := k.GetTotalInflow() + if totalOutflowSum.GT(sdk.NewDec(10_000_000).Mul(totalInflowSum).Add(params.TotalInflowQuota)) { + return uibc.ErrQuotaExceeded + } + k.SetTokenOutflow(o) k.SetTotalOutflowSum(totalOutflowSum) return nil @@ -190,7 +255,7 @@ func (k Keeper) UndoUpdateQuota(denom string, amount sdkmath.Int) error { // CheckIBCInflow validates if inflow token is registered in x/leverage func (k Keeper) CheckIBCInflow(ctx sdk.Context, - packet channeltypes.Packet, dataDenom string, isSourceChain bool, + packet channeltypes.Packet, dataDenom, dataAmount string, isSourceChain bool, ) exported.Acknowledgement { // if chain is recevier and sender chain is source then we need create ibc_denom (ibc/hash(channel,denom)) to // check ibc_denom is exists in leverage token registry @@ -201,14 +266,27 @@ func (k Keeper) CheckIBCInflow(ctx sdk.Context, prefixedDenom := sourcePrefix + dataDenom // construct the denomination trace from the full raw denomination and get the ibc_denom ibcDenom := transfertypes.ParseDenomTrace(prefixedDenom).IBCDenom() - _, err := k.leverage.GetTokenSettings(ctx, ibcDenom) + ts, err := k.leverage.GetTokenSettings(ctx, ibcDenom) if err != nil { + // skip if token is not a registered token on leverage if ltypes.ErrNotRegisteredToken.Is(err) { - return channeltypes.NewErrorAcknowledgement(err) + return nil } - // other leverage keeper error -> log the error and allow the inflow transfer. - ctx.Logger().Error("IBC inflows: can't load token registry", "err", err) } + + // get the exchange price (eg: UMEE) in USD from oracle using SYMBOL Denom eg: `UMEE` (uumee) + exchangeRate, err := k.oracle.Price(*k.ctx, strings.ToUpper(ts.SymbolDenom)) + if err != nil { + return channeltypes.NewErrorAcknowledgement(err) + } + // calculate total exchange rate + powerReduction := ten.Power(uint64(ts.Exponent)) + inflowinUSD := sdk.MustNewDecFromStr(dataAmount).Quo(powerReduction).Mul(exchangeRate) + + tokenInflow := sdk.NewDecCoinFromDec(ibcDenom, inflowinUSD) + k.SetTokenInflow(tokenInflow) + totalInflowSum := k.GetTotalInflow() + k.SetTotalInflowSum(totalInflowSum.Add(inflowinUSD)) } return nil diff --git a/x/uibc/quota/keeper/quota_test.go b/x/uibc/quota/keeper/quota_test.go index c1a6c87d5d..6d3a88f352 100644 --- a/x/uibc/quota/keeper/quota_test.go +++ b/x/uibc/quota/keeper/quota_test.go @@ -43,7 +43,9 @@ func TestUnitCheckAndUpdateQuota(t *testing.T) { // k.setQuotaParams(10, 100) k.SetTokenOutflow(sdk.NewInt64DecCoin(umee, 6)) + k.SetTokenInflow(sdk.NewInt64DecCoin(umee, 6)) k.SetTotalOutflowSum(sdk.NewDec(50)) + k.SetTotalInflowSum(sdk.NewDec(50)) err := k.CheckAndUpdateQuota(umee, sdk.NewInt(1)) require.NoError(t, err) From 8663c38b01cab620fffbf3615c6c21c0de5f50b8 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Fri, 27 Oct 2023 17:04:58 +0530 Subject: [PATCH 02/18] adding inflow quota check --- .golangci.yml | 2 +- x/oracle/simulations/operations.go | 2 +- x/uibc/genesis.go | 15 +++++++++++++++ x/uibc/quota/keeper/params_test.go | 3 ++- x/uibc/quota/keeper/quota.go | 14 +++++--------- x/uibc/quota/keeper/quota_test.go | 19 +++++++++++++------ 6 files changed, 37 insertions(+), 18 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 1f542c6c9a..67b182e295 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -25,7 +25,7 @@ linters: - dogsled - errcheck - exportloopref - - goconst + # - goconst - gocritic - gofmt - goimports diff --git a/x/oracle/simulations/operations.go b/x/oracle/simulations/operations.go index b259cc0230..ddb89506bf 100644 --- a/x/oracle/simulations/operations.go +++ b/x/oracle/simulations/operations.go @@ -26,7 +26,7 @@ const ( OpWeightMsgAggregateExchangeRateVote = "op_weight_msg_exchange_rate_aggregate_vote" //nolint: gosec OpWeightMsgDelegateFeedConsent = "op_weight_msg_exchange_feed_consent" //nolint: gosec - salt = "89b8164ca0b4b8703ae9ab25962f3dd6d1de5d656f5442971a93b2ca7893f654" //nolint: gosec + salt = "89b8164ca0b4b8703ae9ab25962f3dd6d1de5d656f5442971a93b2ca7893f654" ) var ( diff --git a/x/uibc/genesis.go b/x/uibc/genesis.go index 6c5467d81f..473377eecb 100644 --- a/x/uibc/genesis.go +++ b/x/uibc/genesis.go @@ -18,8 +18,10 @@ func NewGenesisState(params Params, outflows sdk.DecCoins, outflowSum sdk.Dec) * func DefaultGenesisState() *GenesisState { return &GenesisState{ Params: DefaultParams(), + Inflows: nil, Outflows: nil, TotalOutflowSum: sdk.NewDec(0), + TotalInflowSum: sdk.NewDec(0), } } @@ -38,9 +40,22 @@ func (gs GenesisState) Validate() error { } } + for _, o := range gs.Inflows { + if o.Amount.IsNil() { + return sdkerrors.ErrInvalidRequest.Wrap("ibc denom inflow must be defined") + } + if err := o.Validate(); err != nil { + return err + } + } + if gs.TotalOutflowSum.IsNegative() { return fmt.Errorf("total outflow sum cannot be negative : %s ", gs.TotalOutflowSum.String()) } + if gs.TotalInflowSum.IsNegative() { + return fmt.Errorf("total inflow sum cannot be negative : %s ", gs.TotalInflowSum.String()) + } + return nil } diff --git a/x/uibc/quota/keeper/params_test.go b/x/uibc/quota/keeper/params_test.go index 8e7e7a302f..092bb900fb 100644 --- a/x/uibc/quota/keeper/params_test.go +++ b/x/uibc/quota/keeper/params_test.go @@ -22,6 +22,7 @@ func TestUnitParams(t *testing.T) { params.IbcStatus = uibc.IBCTransferStatus_IBC_TRANSFER_STATUS_QUOTA_DISABLED params.TokenQuota = sdk.MustNewDecFromStr("12.23") params.TotalQuota = sdk.MustNewDecFromStr("3.4321") + params.TotalInflowQuota = sdk.MustNewDecFromStr("3.4321") err := k.SetParams(params) require.NoError(err) // check the updated params @@ -48,7 +49,7 @@ func TestValidateEmergencyQuotaParamsUpdate(t *testing.T) { {"valid total quota update", mkParams(99, 10, 50), ""}, {"valid update", mkParams(0, 0, 50), ""}, - {"invalid update", mkParams(201, 11, 50), "can't increase"}, + {"invalid update", mkParams(201, 11, 50), "can't increase"}, {"invalid total quota update", mkParams(101, 10, 50), "can't increase"}, {"invalid token quota update", mkParams(10, 12, 50), "can't increase"}, {"invalid quota duration update1", mkParams(100, 10, 51), "can't change QuotaDuration"}, diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index 99d31696ff..3429b9fdf4 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -42,7 +42,7 @@ func (k Keeper) GetAllOutflows() (sdk.DecCoins, error) { func (k Keeper) GetAllInflows() (sdk.DecCoins, error) { var inflows sdk.DecCoins // creating PrefixStore upfront will remove the prefix from the key when running the iterator. - store := k.PrefixStore(keyPrefixDenomOutflows) + store := k.PrefixStore(keyPrefixDenomInflows) iter := sdk.KVStorePrefixIterator(store, nil) defer iter.Close() @@ -177,23 +177,19 @@ func (k Keeper) CheckAndUpdateQuota(denom string, newOutflow sdkmath.Int) error if !params.TokenQuota.IsZero() && o.Amount.GT(params.TokenQuota) { return uibc.ErrQuotaExceeded } - // Allow outflow either of two conditions // 1. Total Outflow Sum <= Total Outflow Quota // or // 2 . Total Outflow Sum <= $1M + params.TotalInflowQuota * sum of all inflows totalOutflowSum := k.GetTotalOutflow().Add(exchangePrice) - if !params.TotalQuota.IsZero() && totalOutflowSum.GT(params.TotalQuota) { + ttlInSum := k.GetTotalInflow() + if !(!params.TotalQuota.IsZero() && totalOutflowSum.LTE(params.TotalQuota) || + !ttlInSum.IsZero() && totalOutflowSum.LTE(sdk.NewDec(10_000_000).Mul(ttlInSum).Add(params.TotalInflowQuota))) { return uibc.ErrQuotaExceeded } - - totalInflowSum := k.GetTotalInflow() - if totalOutflowSum.GT(sdk.NewDec(10_000_000).Mul(totalInflowSum).Add(params.TotalInflowQuota)) { - return uibc.ErrQuotaExceeded - } - k.SetTokenOutflow(o) k.SetTotalOutflowSum(totalOutflowSum) + return nil } diff --git a/x/uibc/quota/keeper/quota_test.go b/x/uibc/quota/keeper/quota_test.go index 6d3a88f352..e80d78d4cd 100644 --- a/x/uibc/quota/keeper/quota_test.go +++ b/x/uibc/quota/keeper/quota_test.go @@ -70,24 +70,31 @@ func TestUnitCheckAndUpdateQuota(t *testing.T) { require.NoError(t, err) k.checkOutflows(umee, 50, 94) - // transferring additional 5 umee => 10USD, will fail total quota check + // transferring additional 5 umee => 10USD, will fail total quota check but it will pass inflow quota check + // sum of outflows <= $1M + params.InflowOutflowQuota * sum of all inflows = (10_000_000) * 50 + (0) = 500000000 + // 104 <= 500000000 err = k.CheckAndUpdateQuota(umee, sdk.NewInt(5)) + require.NoError(t, err) + k.checkOutflows(umee, 60, 104) + + // it will fail total quota check and inflow quota check also + err = k.CheckAndUpdateQuota(umee, sdk.NewInt(5000000000)) require.ErrorContains(t, err, "quota") - k.checkOutflows(umee, 50, 94) + k.checkOutflows(umee, 60, 104) // 3. Setting TotalQuota param to 0 should unlimit the total quota check // k.setQuotaParams(0, 0) err = k.CheckAndUpdateQuota(umee, sdk.NewInt(5)) require.NoError(t, err) - k.checkOutflows(umee, 60, 104) + k.checkOutflows(umee, 70, 114) - // 4. Setting TokenQuota to 65 + // 4. Setting TokenQuota to 75 // - k.setQuotaParams(65, 0) + k.setQuotaParams(75, 0) err = k.CheckAndUpdateQuota(umee, sdk.NewInt(1)) require.NoError(t, err) - k.checkOutflows(umee, 62, 106) + k.checkOutflows(umee, 72, 116) err = k.CheckAndUpdateQuota(umee, sdk.NewInt(2)) // exceeds token quota require.ErrorContains(t, err, "quota") From fa816a8e7751695e013c522f85f00714f8607a93 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Fri, 27 Oct 2023 18:17:58 +0530 Subject: [PATCH 03/18] trying to fix ibc tests --- tests/e2e/e2e_ibc_test.go | 8 +++++--- x/uibc/quota/keeper/quota.go | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/e2e/e2e_ibc_test.go b/tests/e2e/e2e_ibc_test.go index 4133bfbd9c..c2a5b1dd18 100644 --- a/tests/e2e/e2e_ibc_test.go +++ b/tests/e2e/e2e_ibc_test.go @@ -156,15 +156,17 @@ func (s *E2ETest) TestIBCTokenTransfer() { atom40 := mulCoin(atomQuota, "0.4") s.SendIBC(s.Chain.ID, setup.GaiaChainID, "", atom40, true, "below token quota but not total quota") // supply will be not be decreased because sending more than total quota from umee to gaia - s.checkSupply(umeeAPIEndpoint, uatomIBCHash, atomFromGaia.Amount) + s.checkSupply(umeeAPIEndpoint, uatomIBCHash, atomFromGaia.Amount.Sub(atom40.Amount)) + s.checkOutflows(umeeAPIEndpoint, uatomIBCHash, true, sdk.NewDecFromInt(atom40.Amount), atomSymbol) // ✅ << BELOW TOKEN QUTOA 5$ but ATOM_QUOTA (5$)+ UMEE_QUOTA(90$) <= TOTAL QUOTA (120$) >> // send $15 ATOM from umee to gaia sendAtom := mulCoin(atomQuota, "0.05") s.SendIBC(s.Chain.ID, setup.GaiaChainID, "", sendAtom, false, "below both quotas") // remaing supply decreased uatom on umee - s.checkSupply(umeeAPIEndpoint, uatomIBCHash, atomFromGaia.Amount.Sub(sendAtom.Amount)) - s.checkOutflows(umeeAPIEndpoint, uatomIBCHash, true, sdk.NewDecFromInt(sendAtom.Amount), atomSymbol) + s.checkSupply(umeeAPIEndpoint, uatomIBCHash, atomFromGaia.Amount.Sub(sendAtom.Amount).Sub(atom40.Amount)) + s.checkOutflows(umeeAPIEndpoint, uatomIBCHash, true, + sdk.NewDecFromInt(sendAtom.Amount).Add(sdk.NewDecFromInt(atom40.Amount)), atomSymbol) // send $45 UMEE from gaia to umee returnUmee := mulCoin(sendUmee, "0.5") diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index 3429b9fdf4..8a6bcddc72 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -184,7 +184,7 @@ func (k Keeper) CheckAndUpdateQuota(denom string, newOutflow sdkmath.Int) error totalOutflowSum := k.GetTotalOutflow().Add(exchangePrice) ttlInSum := k.GetTotalInflow() if !(!params.TotalQuota.IsZero() && totalOutflowSum.LTE(params.TotalQuota) || - !ttlInSum.IsZero() && totalOutflowSum.LTE(sdk.NewDec(10_000_000).Mul(ttlInSum).Add(params.TotalInflowQuota))) { + !ttlInSum.IsZero() && totalOutflowSum.LTE(sdk.NewDec(10_00_000).Mul(ttlInSum).Add(params.TotalInflowQuota))) { return uibc.ErrQuotaExceeded } k.SetTokenOutflow(o) From f2f4660640aa1b4598d2c92eb0e0b1c5bed945b6 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Tue, 31 Oct 2023 12:17:23 +0530 Subject: [PATCH 04/18] update the protos --- x/uibc/genesis.pb.go | 100 +++++++++++++++++++++++++++++++++++++++++++ x/uibc/quota.pb.go | 46 ++++++++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/x/uibc/genesis.pb.go b/x/uibc/genesis.pb.go index 550de825b3..5965541ded 100644 --- a/x/uibc/genesis.pb.go +++ b/x/uibc/genesis.pb.go @@ -138,6 +138,30 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.TotalInflowSum.Size() + i -= size + if _, err := m.TotalInflowSum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if len(m.Inflows) > 0 { + for iNdEx := len(m.Inflows) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Inflows[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } n1, err1 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.QuotaExpires, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.QuotaExpires):]) if err1 != nil { return 0, err1 @@ -212,6 +236,14 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.QuotaExpires) n += 1 + l + sovGenesis(uint64(l)) + if len(m.Inflows) > 0 { + for _, e := range m.Inflows { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + l = m.TotalInflowSum.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -384,6 +416,74 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Inflows", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Inflows = append(m.Inflows, types.DecCoin{}) + if err := m.Inflows[len(m.Inflows)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalInflowSum", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TotalInflowSum.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/uibc/quota.pb.go b/x/uibc/quota.pb.go index 9943a691d9..767037249d 100644 --- a/x/uibc/quota.pb.go +++ b/x/uibc/quota.pb.go @@ -198,6 +198,16 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.TotalInflowQuota.Size() + i -= size + if _, err := m.TotalInflowQuota.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintQuota(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a n1, err1 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.QuotaDuration, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.QuotaDuration):]) if err1 != nil { return 0, err1 @@ -260,6 +270,8 @@ func (m *Params) Size() (n int) { n += 1 + l + sovQuota(uint64(l)) l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.QuotaDuration) n += 1 + l + sovQuota(uint64(l)) + l = m.TotalInflowQuota.Size() + n += 1 + l + sovQuota(uint64(l)) return n } @@ -418,6 +430,40 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalInflowQuota", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuota + } + 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 ErrInvalidLengthQuota + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuota + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TotalInflowQuota.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuota(dAtA[iNdEx:]) From 49112a79a493c4498e27e9f1ad17e3d82ad51a9f Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Tue, 31 Oct 2023 12:18:38 +0530 Subject: [PATCH 05/18] enable goconst in golang-lint --- .golangci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 67b182e295..1f542c6c9a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -25,7 +25,7 @@ linters: - dogsled - errcheck - exportloopref - # - goconst + - goconst - gocritic - gofmt - goimports From b1382bf95b3389c63ff7f10f147fc3822f7b4770 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Tue, 31 Oct 2023 17:13:30 +0530 Subject: [PATCH 06/18] address the review comments --- proto/umee/uibc/v1/genesis.proto | 2 +- proto/umee/uibc/v1/quota.proto | 10 +- x/uibc/genesis.pb.go | 2 +- x/uibc/params.go | 16 +-- x/uibc/quota.pb.go | 132 ++++++++++++++++------- x/uibc/quota/ibc_module.go | 2 +- x/uibc/quota/keeper/genesis.go | 4 +- x/uibc/quota/keeper/intest/quota_test.go | 6 ++ x/uibc/quota/keeper/keys.go | 2 +- x/uibc/quota/keeper/params_test.go | 4 +- x/uibc/quota/keeper/quota.go | 104 +++++++++--------- x/uibc/quota/keeper/quota_test.go | 24 ++++- 12 files changed, 201 insertions(+), 107 deletions(-) diff --git a/proto/umee/uibc/v1/genesis.proto b/proto/umee/uibc/v1/genesis.proto index f9e50cf2c4..942c48b5a0 100644 --- a/proto/umee/uibc/v1/genesis.proto +++ b/proto/umee/uibc/v1/genesis.proto @@ -30,7 +30,7 @@ message GenesisState { (gogoproto.jsontag) = "quota_duration,omitempty", (gogoproto.moretags) = "yaml:\"quota_expires\"" ]; - // inflows defines inflow amount of denoms + // inflows defines inflow amount per denom denoms repeated cosmos.base.v1beta1.DecCoin inflows = 5 [ (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", (gogoproto.nullable) = false diff --git a/proto/umee/uibc/v1/quota.proto b/proto/umee/uibc/v1/quota.proto index a72d50f8d0..bef592e45e 100644 --- a/proto/umee/uibc/v1/quota.proto +++ b/proto/umee/uibc/v1/quota.proto @@ -30,8 +30,14 @@ message Params { (gogoproto.jsontag) = "quota_duration,omitempty", (gogoproto.moretags) = "yaml:\"quota_duration\"" ]; - // total_inflow_quota defines the total inflow limit of ibc-transfer in USD - string total_inflow_quota = 5 [ + // inflow_outflow_quota_base defines the inflow outflow quota base of ibc-transfer in USD + string inflow_outflow_quota_base = 5 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // inflow_outflow_quota_rate defines the rate of total inflows + string inflow_outflow_quota_rate = 6 [ (cosmos_proto.scalar) = "cosmos.Dec", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false diff --git a/x/uibc/genesis.pb.go b/x/uibc/genesis.pb.go index 5965541ded..acf0468b89 100644 --- a/x/uibc/genesis.pb.go +++ b/x/uibc/genesis.pb.go @@ -38,7 +38,7 @@ type GenesisState struct { TotalOutflowSum github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=total_outflow_sum,json=totalOutflowSum,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_outflow_sum"` // quota_expires defines quota expire time (as unix timestamp) for ibc-transfer denom. QuotaExpires time.Time `protobuf:"bytes,4,opt,name=quota_expires,json=quotaExpires,proto3,stdtime" json:"quota_duration,omitempty" yaml:"quota_expires"` - // inflows defines inflow amount of denoms + // inflows defines inflow amount per denom denoms Inflows github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,5,rep,name=inflows,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"inflows"` // total_inflow_sum defines the total inflow sum of ibc-transfer in USD. TotalInflowSum github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=total_inflow_sum,json=totalInflowSum,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_inflow_sum"` diff --git a/x/uibc/params.go b/x/uibc/params.go index 9f4726e258..8bd3499341 100644 --- a/x/uibc/params.go +++ b/x/uibc/params.go @@ -10,11 +10,12 @@ import ( // DefaultParams returns default genesis params func DefaultParams() Params { return Params{ - IbcStatus: IBCTransferStatus_IBC_TRANSFER_STATUS_QUOTA_ENABLED, - TotalQuota: sdk.NewDec(1_000_000), - TokenQuota: sdk.NewDec(600_000), - QuotaDuration: time.Second * 60 * 60 * 24, // 24h - TotalInflowQuota: sdk.NewDec(1_000_000), + IbcStatus: IBCTransferStatus_IBC_TRANSFER_STATUS_QUOTA_ENABLED, + TotalQuota: sdk.NewDec(1_600_000), // $1.6M + TokenQuota: sdk.NewDec(900_000), // $900K + QuotaDuration: time.Second * 60 * 60 * 24, // 24h + InflowOutflowQuotaBase: sdk.NewDec(1_000_000), // 1M + InflowOutflowQuotaRate: sdk.MustNewDecFromStr("0.1"), } } @@ -31,7 +32,10 @@ func (p Params) Validate() error { if err := validateQuota(p.TokenQuota, "quota per token"); err != nil { return err } - if err := validateQuota(p.TotalInflowQuota, "total inflow quota"); err != nil { + if err := validateQuota(p.InflowOutflowQuotaBase, "total inflow outflow quota base"); err != nil { + return err + } + if err := validateQuota(p.InflowOutflowQuotaRate, "total inflow outflow quota rate"); err != nil { return err } if p.TotalQuota.LT(p.TokenQuota) { diff --git a/x/uibc/quota.pb.go b/x/uibc/quota.pb.go index 767037249d..0d73164d21 100644 --- a/x/uibc/quota.pb.go +++ b/x/uibc/quota.pb.go @@ -83,8 +83,10 @@ type Params struct { TokenQuota github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=token_quota,json=tokenQuota,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"token_quota"` // quota_duration defines quota expires for each ibc-transfer denom in seconds QuotaDuration time.Duration `protobuf:"bytes,4,opt,name=quota_duration,json=quotaDuration,proto3,stdduration" json:"quota_duration,omitempty" yaml:"quota_duration"` - // total_inflow_quota defines the total inflow limit of ibc-transfer in USD - TotalInflowQuota github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=total_inflow_quota,json=totalInflowQuota,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_inflow_quota"` + // inflow_outflow_quota_base defines the inflow outflow quota base of ibc-transfer in USD + InflowOutflowQuotaBase github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=inflow_outflow_quota_base,json=inflowOutflowQuotaBase,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflow_outflow_quota_base"` + // inflow_outflow_quota_rate defines the rate of total inflows + InflowOutflowQuotaRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=inflow_outflow_quota_rate,json=inflowOutflowQuotaRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflow_outflow_quota_rate"` } func (m *Params) Reset() { *m = Params{} } @@ -142,40 +144,42 @@ func init() { func init() { proto.RegisterFile("umee/uibc/v1/quota.proto", fileDescriptor_651be1a0280abcb6) } var fileDescriptor_651be1a0280abcb6 = []byte{ - // 524 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x31, 0x6f, 0xd3, 0x40, - 0x14, 0x80, 0xe3, 0xa4, 0xad, 0xd4, 0x2b, 0x54, 0xe1, 0x04, 0x52, 0xda, 0xc1, 0x0e, 0x81, 0x46, - 0xa1, 0x22, 0x67, 0xb5, 0x48, 0x0c, 0x08, 0x10, 0x71, 0xec, 0x4a, 0x96, 0x50, 0x9a, 0xc6, 0xf6, - 0x82, 0x84, 0x2c, 0xdb, 0xbd, 0x18, 0x93, 0xd8, 0x17, 0xec, 0x73, 0x4a, 0x26, 0x56, 0x46, 0x46, - 0x7e, 0x08, 0x3f, 0xa2, 0x63, 0xc5, 0x84, 0x18, 0x02, 0x4a, 0x36, 0x46, 0xf8, 0x03, 0xc8, 0x77, - 0x8e, 0xda, 0xaa, 0xcd, 0xd6, 0xc9, 0xf7, 0xfc, 0xbe, 0xfb, 0xee, 0xbd, 0x67, 0x1f, 0xa8, 0xa4, - 0x21, 0xc6, 0x72, 0x1a, 0xb8, 0x9e, 0x3c, 0xde, 0x93, 0x3f, 0xa4, 0x84, 0x3a, 0x68, 0x14, 0x13, - 0x4a, 0xe0, 0xad, 0x2c, 0x83, 0xb2, 0x0c, 0x1a, 0xef, 0x6d, 0xdf, 0xf5, 0x89, 0x4f, 0x58, 0x42, - 0xce, 0x56, 0x9c, 0xd9, 0x16, 0x7d, 0x42, 0xfc, 0x21, 0x96, 0x59, 0xe4, 0xa6, 0x7d, 0xf9, 0x38, - 0x8d, 0x1d, 0x1a, 0x90, 0x28, 0xcf, 0x6f, 0x79, 0x24, 0x09, 0x49, 0x62, 0xf3, 0x8d, 0x3c, 0xe0, - 0xa9, 0xda, 0xbf, 0x12, 0x58, 0xeb, 0x3a, 0xb1, 0x13, 0x26, 0xf0, 0x25, 0x00, 0x81, 0xeb, 0xd9, - 0x09, 0x75, 0x68, 0x9a, 0x54, 0x84, 0xaa, 0xd0, 0xd8, 0xdc, 0x97, 0xd0, 0xc5, 0xe3, 0x91, 0xae, - 0xb4, 0xcd, 0xd8, 0x89, 0x92, 0x3e, 0x8e, 0x0d, 0x86, 0xf5, 0xd6, 0x03, 0xd7, 0xe3, 0x4b, 0xf8, - 0x16, 0x6c, 0x50, 0x42, 0x9d, 0xa1, 0xcd, 0xca, 0xaf, 0x14, 0xab, 0x42, 0x63, 0x5d, 0x79, 0x7e, - 0x3a, 0x95, 0x0a, 0x3f, 0xa7, 0x52, 0xdd, 0x0f, 0xe8, 0xbb, 0xd4, 0x45, 0x1e, 0x09, 0xf3, 0x02, - 0xf2, 0x47, 0x33, 0x39, 0x1e, 0xc8, 0x74, 0x32, 0xc2, 0x09, 0x52, 0xb1, 0xf7, 0xfd, 0x5b, 0x13, - 0xe4, 0xf5, 0xa9, 0xd8, 0xeb, 0x01, 0x26, 0x3c, 0xca, 0x7c, 0x5c, 0x3f, 0xc0, 0x51, 0xae, 0x2f, - 0xdd, 0x8c, 0x7e, 0x80, 0x23, 0xae, 0xff, 0x04, 0x36, 0x99, 0xd8, 0x5e, 0xcc, 0xae, 0xb2, 0x52, - 0x15, 0x1a, 0x1b, 0xfb, 0x5b, 0x88, 0x0f, 0x17, 0x2d, 0x86, 0x8b, 0xd4, 0x1c, 0x50, 0x5e, 0x64, - 0x87, 0xff, 0x99, 0x4a, 0x95, 0xcb, 0x1b, 0x1f, 0x93, 0x30, 0xa0, 0x38, 0x1c, 0xd1, 0xc9, 0xdf, - 0xa9, 0x74, 0x6f, 0xe2, 0x84, 0xc3, 0x67, 0xb5, 0xcb, 0x44, 0xed, 0xeb, 0x2f, 0x49, 0xe8, 0xdd, - 0x66, 0x2f, 0x17, 0x36, 0xf8, 0x1e, 0x40, 0x3e, 0xbe, 0x20, 0xea, 0x0f, 0xc9, 0x49, 0xde, 0xe6, - 0xea, 0x0d, 0xb4, 0x59, 0x66, 0x5e, 0x9d, 0x69, 0x59, 0xb3, 0xbb, 0x9f, 0x8b, 0xe0, 0xce, 0x95, - 0x6f, 0x09, 0x1f, 0x00, 0x49, 0x57, 0xda, 0xb6, 0xd9, 0x6b, 0x75, 0x8c, 0x03, 0xad, 0x67, 0x1b, - 0x66, 0xcb, 0xb4, 0x0c, 0xdb, 0xea, 0x18, 0x5d, 0xad, 0xad, 0x1f, 0xe8, 0x9a, 0x5a, 0x2e, 0xc0, - 0x3a, 0xa8, 0x5d, 0x07, 0x1d, 0x59, 0x87, 0x66, 0xcb, 0x56, 0x75, 0xa3, 0xa5, 0xbc, 0xd6, 0xd4, - 0xb2, 0x00, 0x77, 0xc0, 0xfd, 0xe5, 0x9c, 0xd6, 0xe1, 0x58, 0x11, 0xee, 0x82, 0xfa, 0x72, 0xec, - 0xd0, 0x32, 0xcf, 0x95, 0x25, 0xf8, 0x08, 0xec, 0x2c, 0x67, 0xf5, 0xce, 0x39, 0xba, 0x02, 0x1b, - 0xe0, 0xe1, 0x75, 0xe8, 0x22, 0x36, 0xec, 0x6e, 0xcb, 0x32, 0x34, 0xb5, 0xbc, 0xaa, 0xbc, 0x3a, - 0x9d, 0x89, 0xc2, 0xd9, 0x4c, 0x14, 0x7e, 0xcf, 0x44, 0xe1, 0xcb, 0x5c, 0x2c, 0x9c, 0xcd, 0xc5, - 0xc2, 0x8f, 0xb9, 0x58, 0x78, 0x73, 0x71, 0xd8, 0xd9, 0x2d, 0x68, 0x46, 0x98, 0x9e, 0x90, 0x78, - 0xc0, 0x02, 0x79, 0xfc, 0x54, 0xfe, 0xc8, 0x2e, 0xac, 0xbb, 0xc6, 0xfe, 0x8c, 0x27, 0xff, 0x03, - 0x00, 0x00, 0xff, 0xff, 0x88, 0xbe, 0x35, 0x75, 0xc4, 0x03, 0x00, 0x00, + // 546 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0x80, 0xe3, 0x34, 0x8d, 0xd4, 0x2b, 0x54, 0xc1, 0x02, 0xe4, 0x74, 0xb0, 0x43, 0xa0, 0x51, + 0xa8, 0x88, 0xad, 0x16, 0x89, 0x01, 0x01, 0x22, 0x8e, 0x5d, 0xc9, 0x12, 0x4a, 0x52, 0xdb, 0x59, + 0x90, 0x90, 0x75, 0x76, 0x2f, 0xc1, 0x4a, 0xec, 0x0b, 0xf6, 0x39, 0x21, 0x13, 0x2b, 0x23, 0x23, + 0x3f, 0x84, 0x1f, 0xd1, 0xb1, 0x62, 0x42, 0x0c, 0x01, 0x25, 0x1b, 0x23, 0x1b, 0x1b, 0xf2, 0x9d, + 0xa3, 0xb6, 0xa2, 0xd9, 0xca, 0x74, 0xf7, 0xf2, 0xbe, 0xfb, 0xde, 0xbb, 0xa7, 0x8b, 0x81, 0x90, + 0x04, 0x08, 0x29, 0x89, 0xef, 0x7a, 0xca, 0xe4, 0x40, 0x79, 0x97, 0x60, 0x02, 0xe5, 0x71, 0x84, + 0x09, 0xe6, 0x6f, 0xa4, 0x19, 0x39, 0xcd, 0xc8, 0x93, 0x83, 0xdd, 0xdb, 0x03, 0x3c, 0xc0, 0x34, + 0xa1, 0xa4, 0x3b, 0xc6, 0xec, 0x8a, 0x03, 0x8c, 0x07, 0x23, 0xa4, 0xd0, 0xc8, 0x4d, 0xfa, 0xca, + 0x49, 0x12, 0x41, 0xe2, 0xe3, 0x30, 0xcb, 0x97, 0x3d, 0x1c, 0x07, 0x38, 0x76, 0xd8, 0x41, 0x16, + 0xb0, 0x54, 0xf5, 0x4f, 0x01, 0x14, 0xbb, 0x30, 0x82, 0x41, 0xcc, 0xbf, 0x00, 0xc0, 0x77, 0x3d, + 0x27, 0x26, 0x90, 0x24, 0xb1, 0xc0, 0x55, 0xb8, 0xfa, 0xce, 0xa1, 0x24, 0x5f, 0x2c, 0x2f, 0x1b, + 0x6a, 0xcb, 0x8e, 0x60, 0x18, 0xf7, 0x51, 0x64, 0x51, 0xcc, 0xdc, 0xf2, 0x5d, 0x8f, 0x6d, 0xf9, + 0x37, 0x60, 0x9b, 0x60, 0x02, 0x47, 0x0e, 0x6d, 0x5f, 0xc8, 0x57, 0xb8, 0xfa, 0x96, 0xfa, 0xec, + 0x74, 0x2e, 0xe5, 0xbe, 0xcf, 0xa5, 0xda, 0xc0, 0x27, 0x6f, 0x13, 0x57, 0xf6, 0x70, 0x90, 0x35, + 0x90, 0x2d, 0x8d, 0xf8, 0x64, 0xa8, 0x90, 0xd9, 0x18, 0xc5, 0xb2, 0x86, 0xbc, 0xaf, 0x5f, 0x1a, + 0x20, 0xeb, 0x4f, 0x43, 0x9e, 0x09, 0xa8, 0xf0, 0x38, 0xf5, 0x31, 0xfd, 0x10, 0x85, 0x99, 0x7e, + 0xe3, 0x7a, 0xf4, 0x43, 0x14, 0x32, 0xfd, 0x07, 0xb0, 0x43, 0xc5, 0xce, 0x6a, 0x76, 0x42, 0xa1, + 0xc2, 0xd5, 0xb7, 0x0f, 0xcb, 0x32, 0x1b, 0xae, 0xbc, 0x1a, 0xae, 0xac, 0x65, 0x80, 0xfa, 0x3c, + 0x2d, 0xfe, 0x6b, 0x2e, 0x09, 0x97, 0x0f, 0x3e, 0xc2, 0x81, 0x4f, 0x50, 0x30, 0x26, 0xb3, 0xdf, + 0x73, 0xe9, 0xce, 0x0c, 0x06, 0xa3, 0xa7, 0xd5, 0xcb, 0x44, 0xf5, 0xf3, 0x0f, 0x89, 0x33, 0x6f, + 0xd2, 0x1f, 0x57, 0x36, 0x7e, 0x0a, 0xca, 0x7e, 0xd8, 0x1f, 0xe1, 0xa9, 0x83, 0x13, 0x42, 0x57, + 0x76, 0xc8, 0x85, 0x31, 0x12, 0x36, 0xaf, 0xe1, 0xb6, 0x77, 0x99, 0xbe, 0xc3, 0xec, 0xf4, 0xd6, + 0x2a, 0x8c, 0xd1, 0xda, 0xc2, 0x11, 0x24, 0x48, 0x28, 0xfe, 0x9f, 0xc2, 0x26, 0x24, 0x68, 0xff, + 0x63, 0x1e, 0xdc, 0xfa, 0xe7, 0x45, 0xf1, 0xf7, 0x81, 0x64, 0xa8, 0x2d, 0xc7, 0x36, 0x9b, 0x6d, + 0xeb, 0x48, 0x37, 0x1d, 0xcb, 0x6e, 0xda, 0x3d, 0xcb, 0xe9, 0xb5, 0xad, 0xae, 0xde, 0x32, 0x8e, + 0x0c, 0x5d, 0x2b, 0xe5, 0xf8, 0x1a, 0xa8, 0x5e, 0x05, 0x1d, 0xf7, 0x3a, 0x76, 0xd3, 0xd1, 0x0c, + 0xab, 0xa9, 0xbe, 0xd2, 0xb5, 0x12, 0xc7, 0xef, 0x81, 0x7b, 0xeb, 0x39, 0xbd, 0xcd, 0xb0, 0x3c, + 0xbf, 0x0f, 0x6a, 0xeb, 0xb1, 0x4e, 0xcf, 0x3e, 0x57, 0x6e, 0xf0, 0x0f, 0xc1, 0xde, 0x7a, 0xd6, + 0x68, 0x9f, 0xa3, 0x05, 0xbe, 0x0e, 0x1e, 0x5c, 0x85, 0xae, 0x62, 0xcb, 0xe9, 0x36, 0x7b, 0x96, + 0xae, 0x95, 0x36, 0xd5, 0x97, 0xa7, 0x0b, 0x91, 0x3b, 0x5b, 0x88, 0xdc, 0xcf, 0x85, 0xc8, 0x7d, + 0x5a, 0x8a, 0xb9, 0xb3, 0xa5, 0x98, 0xfb, 0xb6, 0x14, 0x73, 0xaf, 0x2f, 0x8e, 0x3c, 0xfd, 0x2f, + 0x36, 0x42, 0x44, 0xa6, 0x38, 0x1a, 0xd2, 0x40, 0x99, 0x3c, 0x51, 0xde, 0xd3, 0xcf, 0x86, 0x5b, + 0xa4, 0xef, 0xf3, 0xf1, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x73, 0x20, 0x82, 0x4a, 0x04, + 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -199,9 +203,19 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size := m.TotalInflowQuota.Size() + size := m.InflowOutflowQuotaRate.Size() i -= size - if _, err := m.TotalInflowQuota.MarshalTo(dAtA[i:]); err != nil { + if _, err := m.InflowOutflowQuotaRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintQuota(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + { + size := m.InflowOutflowQuotaBase.Size() + i -= size + if _, err := m.InflowOutflowQuotaBase.MarshalTo(dAtA[i:]); err != nil { return 0, err } i = encodeVarintQuota(dAtA, i, uint64(size)) @@ -270,7 +284,9 @@ func (m *Params) Size() (n int) { n += 1 + l + sovQuota(uint64(l)) l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.QuotaDuration) n += 1 + l + sovQuota(uint64(l)) - l = m.TotalInflowQuota.Size() + l = m.InflowOutflowQuotaBase.Size() + n += 1 + l + sovQuota(uint64(l)) + l = m.InflowOutflowQuotaRate.Size() n += 1 + l + sovQuota(uint64(l)) return n } @@ -432,7 +448,41 @@ func (m *Params) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalInflowQuota", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field InflowOutflowQuotaBase", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuota + } + 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 ErrInvalidLengthQuota + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuota + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InflowOutflowQuotaBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InflowOutflowQuotaRate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -460,7 +510,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.TotalInflowQuota.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.InflowOutflowQuotaRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/uibc/quota/ibc_module.go b/x/uibc/quota/ibc_module.go index ff2c1af290..bf87008e6a 100644 --- a/x/uibc/quota/ibc_module.go +++ b/x/uibc/quota/ibc_module.go @@ -55,7 +55,7 @@ func (im ICS20Module) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, } isSourceChain := transfertypes.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) - ackErr := im.kb.Keeper(&ctx).CheckIBCInflow(ctx, packet, data.Denom, data.Amount, isSourceChain) + ackErr := im.kb.Keeper(&ctx).RecordIBCInflow(ctx, packet, data.Denom, data.Amount, isSourceChain) if ackErr != nil { return ackErr } diff --git a/x/uibc/quota/keeper/genesis.go b/x/uibc/quota/keeper/genesis.go index da94643824..2fd86cb0d4 100644 --- a/x/uibc/quota/keeper/genesis.go +++ b/x/uibc/quota/keeper/genesis.go @@ -14,9 +14,9 @@ func (kb Builder) InitGenesis(ctx sdk.Context, genState uibc.GenesisState) { util.Panic(err) k.SetTokenOutflows(genState.Outflows) - k.SetTokenOutflows(genState.Inflows) + k.SetTokenInflows(genState.Inflows) k.SetTotalOutflowSum(genState.TotalOutflowSum) - k.SetTotalInflowSum(genState.TotalInflowSum) + k.SetTotalInflow(genState.TotalInflowSum) err = k.SetExpire(genState.QuotaExpires) util.Panic(err) diff --git a/x/uibc/quota/keeper/intest/quota_test.go b/x/uibc/quota/keeper/intest/quota_test.go index ec8beca1eb..63789caab2 100644 --- a/x/uibc/quota/keeper/intest/quota_test.go +++ b/x/uibc/quota/keeper/intest/quota_test.go @@ -25,12 +25,18 @@ func TestResetQuota(t *testing.T) { q := k.GetTokenOutflows(umeeQuota.Denom) assert.DeepEqual(t, q, umeeQuota) + k.SetTokenInflow(umeeQuota) + i := k.GetTokenInflow(umeeQuota.Denom) + assert.DeepEqual(t, i, umeeQuota) + // reset the quota k.ResetAllQuotas() // check the quota after reset q = k.GetTokenOutflows(umeeQuota.Denom) assert.DeepEqual(t, q.Amount, sdk.NewDec(0)) + i = k.GetTokenInflow(umeeQuota.Denom) + assert.DeepEqual(t, i.Amount, sdk.NewDec(0)) } func TestKeeper_CheckAndUpdateQuota(t *testing.T) { diff --git a/x/uibc/quota/keeper/keys.go b/x/uibc/quota/keeper/keys.go index 0d644c9d4e..82f5ed4cf6 100644 --- a/x/uibc/quota/keeper/keys.go +++ b/x/uibc/quota/keeper/keys.go @@ -18,7 +18,7 @@ func KeyTotalOutflows(ibcDenom string) []byte { return util.ConcatBytes(0, keyPrefixDenomOutflows, []byte(ibcDenom)) } -func KeyTotalInflows(ibcDenom string) []byte { +func KeyTokenInflow(ibcDenom string) []byte { // keyPrefixDenomInflows | denom return util.ConcatBytes(0, keyPrefixDenomInflows, []byte(ibcDenom)) } diff --git a/x/uibc/quota/keeper/params_test.go b/x/uibc/quota/keeper/params_test.go index 092bb900fb..6eb7734ccb 100644 --- a/x/uibc/quota/keeper/params_test.go +++ b/x/uibc/quota/keeper/params_test.go @@ -22,7 +22,9 @@ func TestUnitParams(t *testing.T) { params.IbcStatus = uibc.IBCTransferStatus_IBC_TRANSFER_STATUS_QUOTA_DISABLED params.TokenQuota = sdk.MustNewDecFromStr("12.23") params.TotalQuota = sdk.MustNewDecFromStr("3.4321") - params.TotalInflowQuota = sdk.MustNewDecFromStr("3.4321") + params.InflowOutflowQuotaBase = sdk.MustNewDecFromStr("3.4321") + params.InflowOutflowQuotaRate = sdk.MustNewDecFromStr("0.2") + err := k.SetParams(params) require.NoError(err) // check the updated params diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index b02cdf0512..3c2061abf0 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -38,6 +38,39 @@ func (k Keeper) GetAllOutflows() (sdk.DecCoins, error) { return outflows, nil } +// GetTokenOutflows returns sum of denom outflows in USD value in the DecCoin structure. +func (k Keeper) GetTokenOutflows(denom string) sdk.DecCoin { + amount, _ := store.GetDec(k.store, KeyTotalOutflows(denom), "total_outflow") + return sdk.NewDecCoinFromDec(denom, amount) +} + +// SetTokenOutflows saves provided updated IBC outflows as a pair: USD value, denom name in the +// DecCoin structure. +func (k Keeper) SetTokenOutflows(outflows sdk.DecCoins) { + for _, q := range outflows { + k.SetTokenOutflow(q) + } +} + +// SetTotalOutflowSum save the total outflow of ibc-transfer amount. +func (k Keeper) SetTotalOutflowSum(amount sdk.Dec) { + err := store.SetDec(k.store, keyTotalOutflows, amount, "total_outflow_sum") + util.Panic(err) +} + +// GetTotalOutflow returns the total outflow of ibc-transfer amount. +func (k Keeper) GetTotalOutflow() sdk.Dec { + amount, _ := store.GetDec(k.store, keyTotalOutflows, "total_outflow") + return amount +} + +// SetTokenOutflow save the outflows of denom into store. +func (k Keeper) SetTokenOutflow(outflow sdk.DecCoin) { + key := KeyTotalOutflows(outflow.Denom) + err := store.SetDec(k.store, key, outflow.Amount, "total_outflow") + util.Panic(err) +} + // GetAllInflows returns inflows of all registered tokens in USD value. func (k Keeper) GetAllInflows() (sdk.DecCoins, error) { var inflows sdk.DecCoins @@ -57,20 +90,6 @@ func (k Keeper) GetAllInflows() (sdk.DecCoins, error) { return inflows, nil } -// GetTokenOutflows returns sum of denom outflows in USD value in the DecCoin structure. -func (k Keeper) GetTokenOutflows(denom string) sdk.DecCoin { - amount, _ := store.GetDec(k.store, KeyTotalOutflows(denom), "total_outflow") - return sdk.NewDecCoinFromDec(denom, amount) -} - -// SetTokenOutflows saves provided updated IBC outflows as a pair: USD value, denom name in the -// DecCoin structure. -func (k Keeper) SetTokenOutflows(outflows sdk.DecCoins) { - for _, q := range outflows { - k.SetTokenOutflow(q) - } -} - // SetTokenInflows saves provided updated IBC inflows as a pair: USD value, denom name in the // DecCoin structure. func (k Keeper) SetTokenInflows(inflows sdk.DecCoins) { @@ -79,42 +98,30 @@ func (k Keeper) SetTokenInflows(inflows sdk.DecCoins) { } } -// SetTokenOutflow save the outflows of denom into store. -func (k Keeper) SetTokenOutflow(outflow sdk.DecCoin) { - key := KeyTotalOutflows(outflow.Denom) - err := store.SetDec(k.store, key, outflow.Amount, "total_outflow") - util.Panic(err) -} - // SetTokenInflow save the inflow of denom into store. func (k Keeper) SetTokenInflow(inflow sdk.DecCoin) { - key := KeyTotalInflows(inflow.Denom) - err := store.SetDec(k.store, key, inflow.Amount, "total_inflow") + key := KeyTokenInflow(inflow.Denom) + err := store.SetDec(k.store, key, inflow.Amount, "token_inflow") util.Panic(err) } -// GetTotalOutflow returns the total outflow of ibc-transfer amount. -func (k Keeper) GetTotalOutflow() sdk.Dec { - // TODO: use store.Get/SetDec - bz := k.store.Get(keyTotalOutflows) - return sdk.MustNewDecFromStr(string(bz)) +// GetTokenInflow returns the inflow of denom from store. +func (k Keeper) GetTokenInflow(denom string) sdk.DecCoin { + key := KeyTokenInflow(denom) + amount, _ := store.GetDec(k.store, key, "token_inflow") + return sdk.NewDecCoinFromDec(denom, amount) } // GetTotalInflow returns the total inflow of ibc-transfer amount. func (k Keeper) GetTotalInflow() sdk.Dec { - // TODO: use store.Get/SetDec - bz := k.store.Get(keyTotalInflows) - return sdk.MustNewDecFromStr(string(bz)) + amount, _ := store.GetDec(k.store, keyTotalInflows, "total_inflows") + return amount } -// SetTotalOutflowSum save the total outflow of ibc-transfer amount. -func (k Keeper) SetTotalOutflowSum(amount sdk.Dec) { - k.store.Set(keyTotalOutflows, []byte(amount.String())) -} - -// SetTotalInflowSum save the total inflow of ibc-transfer amount. -func (k Keeper) SetTotalInflowSum(amount sdk.Dec) { - k.store.Set(keyTotalInflows, []byte(amount.String())) +// SetTotalInflow save the total inflow of ibc-transfer amount. +func (k Keeper) SetTotalInflow(amount sdk.Dec) { + err := store.SetDec(k.store, keyTotalInflows, amount, "total_inflows") + util.Panic(err) } // SetExpire save the quota expire time of ibc denom into. @@ -135,26 +142,22 @@ func (k Keeper) ResetAllQuotas() error { return err } zero := sdk.NewDec(0) - zeroBz, err := zero.Marshal() - if err != nil { - return err - } // outflows k.SetTotalOutflowSum(zero) store := k.PrefixStore(keyPrefixDenomOutflows) iter := sdk.KVStorePrefixIterator(store, nil) defer iter.Close() for ; iter.Valid(); iter.Next() { - store.Set(iter.Key(), zeroBz) + store.Delete(iter.Key()) } // inflows - k.SetTotalInflowSum(zero) + k.SetTotalInflow(zero) store = k.PrefixStore(keyPrefixDenomInflows) iter = sdk.KVStorePrefixIterator(store, nil) defer iter.Close() for ; iter.Valid(); iter.Next() { - store.Set(iter.Key(), zeroBz) + store.Delete(iter.Key()) } return nil } @@ -184,7 +187,8 @@ func (k Keeper) CheckAndUpdateQuota(denom string, newOutflow sdkmath.Int) error totalOutflowSum := k.GetTotalOutflow().Add(exchangePrice) ttlInSum := k.GetTotalInflow() if !(!params.TotalQuota.IsZero() && totalOutflowSum.LTE(params.TotalQuota) || - !ttlInSum.IsZero() && totalOutflowSum.LTE(sdk.NewDec(10_00_000).Mul(ttlInSum).Add(params.TotalInflowQuota))) { + !ttlInSum.IsZero() && + totalOutflowSum.LTE(params.InflowOutflowQuotaBase.Add(ttlInSum.Mul(params.InflowOutflowQuotaRate)))) { return uibc.ErrQuotaExceeded } k.SetTokenOutflow(o) @@ -249,8 +253,8 @@ func (k Keeper) UndoUpdateQuota(denom string, amount sdkmath.Int) error { return nil } -// CheckIBCInflow validates if inflow token is registered in x/leverage -func (k Keeper) CheckIBCInflow(ctx sdk.Context, +// RecordIBCInflow validates if inflow token is registered in x/leverage +func (k Keeper) RecordIBCInflow(ctx sdk.Context, packet channeltypes.Packet, dataDenom, dataAmount string, isSourceChain bool, ) exported.Acknowledgement { // if chain is recevier and sender chain is source then we need create ibc_denom (ibc/hash(channel,denom)) to @@ -282,7 +286,7 @@ func (k Keeper) CheckIBCInflow(ctx sdk.Context, tokenInflow := sdk.NewDecCoinFromDec(ibcDenom, inflowinUSD) k.SetTokenInflow(tokenInflow) totalInflowSum := k.GetTotalInflow() - k.SetTotalInflowSum(totalInflowSum.Add(inflowinUSD)) + k.SetTotalInflow(totalInflowSum.Add(inflowinUSD)) } return nil diff --git a/x/uibc/quota/keeper/quota_test.go b/x/uibc/quota/keeper/quota_test.go index e80d78d4cd..18115608d6 100644 --- a/x/uibc/quota/keeper/quota_test.go +++ b/x/uibc/quota/keeper/quota_test.go @@ -3,8 +3,10 @@ package keeper import ( "testing" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + "gotest.tools/v3/assert" ibcutil "github.com/umee-network/umee/v6/util/ibc" ) @@ -45,7 +47,7 @@ func TestUnitCheckAndUpdateQuota(t *testing.T) { k.SetTokenOutflow(sdk.NewInt64DecCoin(umee, 6)) k.SetTokenInflow(sdk.NewInt64DecCoin(umee, 6)) k.SetTotalOutflowSum(sdk.NewDec(50)) - k.SetTotalInflowSum(sdk.NewDec(50)) + k.SetTotalInflow(sdk.NewDec(50)) err := k.CheckAndUpdateQuota(umee, sdk.NewInt(1)) require.NoError(t, err) @@ -113,3 +115,23 @@ func TestUnitGetExchangePrice(t *testing.T) { _, err = k.getExchangePrice("notexisting", sdk.NewInt(10)) require.ErrorContains(t, err, "not found") } + +func TestSetAndGetIBCInflows(t *testing.T) { + k := initKeeperSimpleMock(t) + inflowSum := sdk.MustNewDecFromStr("123123") + k.SetTotalInflow(inflowSum) + + rv := k.GetTotalInflow() + assert.DeepEqual(t, inflowSum, rv) + + // inflow of token + inflowOfToken := sdk.NewDecCoin("abcd", math.NewInt(1000000)) + k.SetTokenInflow(inflowOfToken) + + val := k.GetTokenInflow(inflowOfToken.Denom) + assert.DeepEqual(t, val, inflowOfToken) + + inflows, err := k.GetAllInflows() + assert.NilError(t, err) + assert.DeepEqual(t, inflows[0], inflowOfToken) +} From 5ad6cb2fe8401d00887657e93252cae6a809ec94 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Tue, 31 Oct 2023 18:52:35 +0530 Subject: [PATCH 07/18] add new params values to upgrade handler --- app/upgrades.go | 16 ++++++++++++++++ x/uibc/quota/keeper/quota.go | 2 +- x/uibc/quota/keeper/quota_test.go | 4 ++-- x/uibc/quota/keeper/unit_test.go | 6 +++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app/upgrades.go b/app/upgrades.go index d6a49f0513..57f657f627 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -126,6 +126,22 @@ func (app *UmeeApp) registerUpgrade6_2(upgradeInfo upgradetypes.Plan) { govParams := app.GovKeeper.GetParams(ctx) govParams.MinInitialDepositRatio = sdk.NewDecWithPrec(1, 2).String() err = app.GovKeeper.SetParams(ctx, govParams) + if err != nil { + return fromVM, err + } + + // uibc params + uibcParams := app.UIbcQuotaKeeperB.Keeper(&ctx).GetParams() + uibcParams.TotalQuota = sdk.NewDec(1_600_000) + uibcParams.TokenQuota = sdk.NewDec(900_000) + uibcParams.InflowOutflowQuotaBase = sdk.NewDec(1_000_000) + // TODO: needs to finalize quota rate + uibcParams.InflowOutflowQuotaRate = sdk.MustNewDecFromStr("0.1") + + err = app.UIbcQuotaKeeperB.Keeper(&ctx).SetParams(uibcParams) + if err != nil { + return fromVM, err + } return fromVM, err }, ) diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index 3c2061abf0..66a1d32106 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -253,7 +253,7 @@ func (k Keeper) UndoUpdateQuota(denom string, amount sdkmath.Int) error { return nil } -// RecordIBCInflow validates if inflow token is registered in x/leverage +// RecordIBCInflow will save the inflow amount if token is registered otherwise it will skip func (k Keeper) RecordIBCInflow(ctx sdk.Context, packet channeltypes.Packet, dataDenom, dataAmount string, isSourceChain bool, ) exported.Acknowledgement { diff --git a/x/uibc/quota/keeper/quota_test.go b/x/uibc/quota/keeper/quota_test.go index 18115608d6..2a48f22456 100644 --- a/x/uibc/quota/keeper/quota_test.go +++ b/x/uibc/quota/keeper/quota_test.go @@ -73,8 +73,8 @@ func TestUnitCheckAndUpdateQuota(t *testing.T) { k.checkOutflows(umee, 50, 94) // transferring additional 5 umee => 10USD, will fail total quota check but it will pass inflow quota check - // sum of outflows <= $1M + params.InflowOutflowQuota * sum of all inflows = (10_000_000) * 50 + (0) = 500000000 - // 104 <= 500000000 + // sum of outflows <= $1M + params.InflowOutflowQuotaRate * sum of all inflows = (10_000_000)+ (50*0) = 10_000_000 + // 104 <= 10_000_000 err = k.CheckAndUpdateQuota(umee, sdk.NewInt(5)) require.NoError(t, err) k.checkOutflows(umee, 60, 104) diff --git a/x/uibc/quota/keeper/unit_test.go b/x/uibc/quota/keeper/unit_test.go index ede6259918..7cb820892d 100644 --- a/x/uibc/quota/keeper/unit_test.go +++ b/x/uibc/quota/keeper/unit_test.go @@ -54,6 +54,10 @@ func (k TestKeeper) checkOutflows(denom string, perToken, total int64) { } func (k TestKeeper) setQuotaParams(perToken, total int64) { - err := k.SetParams(uibc.Params{TokenQuota: sdk.NewDec(perToken), TotalQuota: sdk.NewDec(total)}) + err := k.SetParams(uibc.Params{ + TokenQuota: sdk.NewDec(perToken), + TotalQuota: sdk.NewDec(total), + InflowOutflowQuotaBase: sdk.NewDec(1_000_000), + }) require.NoError(k.t, err) } From 0676c7fe97e887bb43a85e920d1098df099c667f Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Fri, 3 Nov 2023 19:59:43 +0530 Subject: [PATCH 08/18] address the second review comments --- app/upgrades.go | 15 ++++---- x/uibc/README.md | 10 ++++-- x/uibc/params.go | 2 +- x/uibc/quota/keeper/keys.go | 6 ++++ x/uibc/quota/keeper/mocks_test.go | 2 +- x/uibc/quota/keeper/quota.go | 57 ++++++++++++++++--------------- x/uibc/quota/keeper/quota_test.go | 54 ++++++++++++++--------------- x/uibc/quota/keeper/unit_test.go | 1 - 8 files changed, 79 insertions(+), 68 deletions(-) diff --git a/app/upgrades.go b/app/upgrades.go index 71f69887ca..a4b37d79fc 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -129,18 +129,19 @@ func (app *UmeeApp) registerUpgrade6_2(upgradeInfo upgradetypes.Plan) { return fromVM, err } + // uibc migrations + uIBCKeeper := app.UIbcQuotaKeeperB.Keeper(&ctx) + // migrating outflow + oldTotalOutflow := uIBCKeeper.GetOldTotalOutflow() + uIBCKeeper.SetTotalOutflowSum(oldTotalOutflow) // uibc params - uibcParams := app.UIbcQuotaKeeperB.Keeper(&ctx).GetParams() + uibcParams := uIBCKeeper.GetParams() uibcParams.TotalQuota = sdk.NewDec(1_600_000) uibcParams.TokenQuota = sdk.NewDec(900_000) uibcParams.InflowOutflowQuotaBase = sdk.NewDec(1_000_000) - // TODO: needs to finalize quota rate - uibcParams.InflowOutflowQuotaRate = sdk.MustNewDecFromStr("0.1") + uibcParams.InflowOutflowQuotaRate = sdk.MustNewDecFromStr("0.25") - err = app.UIbcQuotaKeeperB.Keeper(&ctx).SetParams(uibcParams) - if err != nil { - return fromVM, err - } + err = uIBCKeeper.SetParams(uibcParams) return fromVM, err }, ) diff --git a/x/uibc/README.md b/x/uibc/README.md index 8162bdd814..78f59ae9e3 100644 --- a/x/uibc/README.md +++ b/x/uibc/README.md @@ -43,9 +43,9 @@ All outflows are measured in token average USD value using our x/oracle `AvgKeep We define 2 Quotas for ICS-20 transfers. Each quota only tracks tokens x/leverage Token Registry. -- `Params.TokenQuota`: upper limit of a sum of all outflows per token. Initially it's set to 0.6m USD per token. It limits the outflows value for each token. +- `Params.TokenQuota`: upper limit of a sum of all outflows per token. Initially it's set to 0.9M USD per token. It limits the outflows value for each token. NOTE: we measure per token as defined in the x/leverage, not the IBC Denom Path (there can be multiple paths). Since creating a channel is permission less, we want to use same quota token. -- `Params.TotalQuota`: upper limit of a sum of all token outflows combined. Initially it's set to 1m USD. Example of IBC outflows reaching the total quota: 300k USD worth of ATOM, 200k USD worth of STATOM, 250k USD worth of UMEE and 250k USD worth JUNO. +- `Params.TotalQuota`: upper limit of a sum of all token outflows combined. Initially it's set to 1.6M USD. Example of IBC outflows reaching the total quota: 600k USD worth of ATOM, 500k USD worth of STATOM, 250k USD worth of UMEE and 250k USD worth JUNO. If a quota parameter is set to zero then we consider it as unlimited. @@ -57,7 +57,11 @@ Transfer of tokens, which are not registered in the x/leverage Token Registry ar #### Inflows -We only allow inflows of tokens registered in x/leverage Token Registry. Other inflow transfers will be rejected. +All inflows are measured in token average USD value using our x/oracle `AvgKeeper`. The `AvgKeeper` aggregates TVWAP prices over 16h window. +We are only tracking inflows for tokens which are registered in x/leverage Token Registry. + +- `Genesis.TotalInflowSum` : Sum of all inflows per token which are registered in x/leverage Token Registry +- `Genesis.Inflows`: Inflows of registered tokens. #### ICS-20 Quota control diff --git a/x/uibc/params.go b/x/uibc/params.go index 8bd3499341..4848c93db8 100644 --- a/x/uibc/params.go +++ b/x/uibc/params.go @@ -15,7 +15,7 @@ func DefaultParams() Params { TokenQuota: sdk.NewDec(900_000), // $900K QuotaDuration: time.Second * 60 * 60 * 24, // 24h InflowOutflowQuotaBase: sdk.NewDec(1_000_000), // 1M - InflowOutflowQuotaRate: sdk.MustNewDecFromStr("0.1"), + InflowOutflowQuotaRate: sdk.MustNewDecFromStr("0.25"), } } diff --git a/x/uibc/quota/keeper/keys.go b/x/uibc/quota/keeper/keys.go index 82f5ed4cf6..af61e3be25 100644 --- a/x/uibc/quota/keeper/keys.go +++ b/x/uibc/quota/keeper/keys.go @@ -22,3 +22,9 @@ func KeyTokenInflow(ibcDenom string) []byte { // keyPrefixDenomInflows | denom return util.ConcatBytes(0, keyPrefixDenomInflows, []byte(ibcDenom)) } + +// DenomFromKey extracts denom from a key with the form +// prefix | denom +func DenomFromKey(key, prefix []byte) string { + return string(key[len(prefix):]) +} diff --git a/x/uibc/quota/keeper/mocks_test.go b/x/uibc/quota/keeper/mocks_test.go index 47deef2cbe..f301bcabc6 100644 --- a/x/uibc/quota/keeper/mocks_test.go +++ b/x/uibc/quota/keeper/mocks_test.go @@ -48,7 +48,7 @@ type Oracle struct { func (o Oracle) Price(_ sdk.Context, denom string) (sdk.Dec, error) { p, ok := o.prices[denom] if !ok { - return p, ltypes.ErrNotRegisteredToken.Wrap(denom) + return sdk.ZeroDec(), nil } return p, nil } diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index 66a1d32106..52e0abcac1 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -22,20 +22,17 @@ var ten = sdk.MustNewDecFromStr("10") // GetAllOutflows returns sum of outflows of all tokens in USD value. func (k Keeper) GetAllOutflows() (sdk.DecCoins, error) { var outflows sdk.DecCoins - // creating PrefixStore upfront will remove the prefix from the key when running the iterator. - store := k.PrefixStore(keyPrefixDenomOutflows) - iter := sdk.KVStorePrefixIterator(store, nil) - defer iter.Close() - - for ; iter.Valid(); iter.Next() { - o := sdk.DecCoin{Denom: string(iter.Key())} - if err := o.Amount.Unmarshal(iter.Value()); err != nil { - return nil, err + iter := func(key, val []byte) error { + o := sdk.DecCoin{Denom: DenomFromKey(key, keyPrefixDenomOutflows)} + if err := o.Amount.Unmarshal(val); err != nil { + return err } outflows = append(outflows, o) + return nil } - return outflows, nil + err := store.Iterate(k.store, keyPrefixDenomOutflows, iter) + return outflows, err } // GetTokenOutflows returns sum of denom outflows in USD value in the DecCoin structure. @@ -74,20 +71,16 @@ func (k Keeper) SetTokenOutflow(outflow sdk.DecCoin) { // GetAllInflows returns inflows of all registered tokens in USD value. func (k Keeper) GetAllInflows() (sdk.DecCoins, error) { var inflows sdk.DecCoins - // creating PrefixStore upfront will remove the prefix from the key when running the iterator. - store := k.PrefixStore(keyPrefixDenomInflows) - iter := sdk.KVStorePrefixIterator(store, nil) - defer iter.Close() - - for ; iter.Valid(); iter.Next() { - o := sdk.DecCoin{Denom: string(iter.Key())} - if err := o.Amount.Unmarshal(iter.Value()); err != nil { - return nil, err + iter := func(key, val []byte) error { + o := sdk.DecCoin{Denom: DenomFromKey(key, keyPrefixDenomInflows)} + if err := o.Amount.Unmarshal(val); err != nil { + return err } inflows = append(inflows, o) + return nil } - - return inflows, nil + err := store.Iterate(k.store, keyPrefixDenomInflows, iter) + return inflows, err } // SetTokenInflows saves provided updated IBC inflows as a pair: USD value, denom name in the @@ -186,10 +179,11 @@ func (k Keeper) CheckAndUpdateQuota(denom string, newOutflow sdkmath.Int) error // 2 . Total Outflow Sum <= $1M + params.TotalInflowQuota * sum of all inflows totalOutflowSum := k.GetTotalOutflow().Add(exchangePrice) ttlInSum := k.GetTotalInflow() - if !(!params.TotalQuota.IsZero() && totalOutflowSum.LTE(params.TotalQuota) || - !ttlInSum.IsZero() && - totalOutflowSum.LTE(params.InflowOutflowQuotaBase.Add(ttlInSum.Mul(params.InflowOutflowQuotaRate)))) { - return uibc.ErrQuotaExceeded + if !params.TotalQuota.IsZero() { + if totalOutflowSum.GT(params.TotalQuota) || + totalOutflowSum.GT(params.InflowOutflowQuotaBase.Add(ttlInSum.Mul(params.InflowOutflowQuotaRate))) { + return uibc.ErrQuotaExceeded + } } k.SetTokenOutflow(o) k.SetTotalOutflowSum(totalOutflowSum) @@ -281,13 +275,20 @@ func (k Keeper) RecordIBCInflow(ctx sdk.Context, } // calculate total exchange rate powerReduction := ten.Power(uint64(ts.Exponent)) - inflowinUSD := sdk.MustNewDecFromStr(dataAmount).Quo(powerReduction).Mul(exchangeRate) + inflowInUSD := sdk.MustNewDecFromStr(dataAmount).Quo(powerReduction).Mul(exchangeRate) - tokenInflow := sdk.NewDecCoinFromDec(ibcDenom, inflowinUSD) + tokenInflow := sdk.NewDecCoinFromDec(ibcDenom, inflowInUSD) k.SetTokenInflow(tokenInflow) totalInflowSum := k.GetTotalInflow() - k.SetTotalInflow(totalInflowSum.Add(inflowinUSD)) + k.SetTotalInflow(totalInflowSum.Add(inflowInUSD)) } return nil } + +// GetOldTotalOutflow returns the total outflow of ibc-transfer amount. +// Note: only using for migration +func (k Keeper) GetOldTotalOutflow() sdk.Dec { + bz := k.store.Get(keyTotalOutflows) + return sdk.MustNewDecFromStr(string(bz)) +} diff --git a/x/uibc/quota/keeper/quota_test.go b/x/uibc/quota/keeper/quota_test.go index 2a48f22456..366f4ab0f7 100644 --- a/x/uibc/quota/keeper/quota_test.go +++ b/x/uibc/quota/keeper/quota_test.go @@ -5,7 +5,6 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" "gotest.tools/v3/assert" ibcutil "github.com/umee-network/umee/v6/util/ibc" @@ -15,24 +14,24 @@ func TestUnitGetQuotas(t *testing.T) { k := initKeeperSimpleMock(t) quotas, err := k.GetAllOutflows() - require.NoError(t, err) - require.Equal(t, len(quotas), 0) + assert.NilError(t, err) + assert.Equal(t, len(quotas), 0) setQuotas := sdk.DecCoins{sdk.NewInt64DecCoin("test_uumee", 10000)} k.SetTokenOutflows(setQuotas) quotas, err = k.GetAllOutflows() - require.NoError(t, err) - require.Equal(t, setQuotas, quotas) + assert.NilError(t, err) + assert.DeepEqual(t, setQuotas, quotas) // get the quota of denom quota := k.GetTokenOutflows(setQuotas[0].Denom) - require.Equal(t, quota.Denom, setQuotas[0].Denom) + assert.Equal(t, quota.Denom, setQuotas[0].Denom) } func TestUnitGetLocalDenom(t *testing.T) { out := ibcutil.GetLocalDenom("umee") - require.Equal(t, "umee", out) + assert.Equal(t, "umee", out) } func TestUnitCheckAndUpdateQuota(t *testing.T) { @@ -50,17 +49,17 @@ func TestUnitCheckAndUpdateQuota(t *testing.T) { k.SetTotalInflow(sdk.NewDec(50)) err := k.CheckAndUpdateQuota(umee, sdk.NewInt(1)) - require.NoError(t, err) + assert.NilError(t, err) k.checkOutflows(umee, 8, 52) // transferring 2 umee => 4USD, will exceed the quota (8+4 > 10) err = k.CheckAndUpdateQuota(umee, sdk.NewInt(2)) - require.ErrorContains(t, err, "quota") + assert.ErrorContains(t, err, "quota") k.checkOutflows(umee, 8, 52) // transferring 1 umee => 2USD, will will be still OK (8+2 <= 10) err = k.CheckAndUpdateQuota(umee, sdk.NewInt(1)) - require.NoError(t, err) + assert.NilError(t, err) k.checkOutflows(umee, 10, 54) // 2. Setting TokenQuota param to 0 should unlimit the token quota check @@ -69,51 +68,52 @@ func TestUnitCheckAndUpdateQuota(t *testing.T) { // transferring 20 umee => 40USD, will skip the token quota check, but will update outflows err = k.CheckAndUpdateQuota(umee, sdk.NewInt(20)) - require.NoError(t, err) + assert.NilError(t, err) k.checkOutflows(umee, 50, 94) // transferring additional 5 umee => 10USD, will fail total quota check but it will pass inflow quota check // sum of outflows <= $1M + params.InflowOutflowQuotaRate * sum of all inflows = (10_000_000)+ (50*0) = 10_000_000 // 104 <= 10_000_000 err = k.CheckAndUpdateQuota(umee, sdk.NewInt(5)) - require.NoError(t, err) - k.checkOutflows(umee, 60, 104) + assert.ErrorContains(t, err, "quota") + k.checkOutflows(umee, 50, 94) // it will fail total quota check and inflow quota check also err = k.CheckAndUpdateQuota(umee, sdk.NewInt(5000000000)) - require.ErrorContains(t, err, "quota") - k.checkOutflows(umee, 60, 104) + assert.ErrorContains(t, err, "quota") + k.checkOutflows(umee, 50, 94) // 3. Setting TotalQuota param to 0 should unlimit the total quota check // k.setQuotaParams(0, 0) err = k.CheckAndUpdateQuota(umee, sdk.NewInt(5)) - require.NoError(t, err) - k.checkOutflows(umee, 70, 114) + assert.NilError(t, err) + k.checkOutflows(umee, 60, 104) - // 4. Setting TokenQuota to 75 + // 4. Setting TokenQuota to 65 // - k.setQuotaParams(75, 0) + k.setQuotaParams(65, 0) err = k.CheckAndUpdateQuota(umee, sdk.NewInt(1)) - require.NoError(t, err) - k.checkOutflows(umee, 72, 116) + assert.NilError(t, err) + k.checkOutflows(umee, 62, 106) err = k.CheckAndUpdateQuota(umee, sdk.NewInt(2)) // exceeds token quota - require.ErrorContains(t, err, "quota") + assert.ErrorContains(t, err, "quota") } func TestUnitGetExchangePrice(t *testing.T) { k := initKeeperSimpleMock(t) p, err := k.getExchangePrice(umee, sdk.NewInt(12)) - require.NoError(t, err) - require.Equal(t, sdk.NewDec(24), p) + assert.NilError(t, err) + assert.DeepEqual(t, sdk.NewDec(24), p) + // ATOM is leverage registered token but price is not avaiable p, err = k.getExchangePrice(atom, sdk.NewInt(3)) - require.NoError(t, err) - require.Equal(t, sdk.NewDec(30), p) + assert.NilError(t, err) + assert.DeepEqual(t, sdk.ZeroDec(), p) _, err = k.getExchangePrice("notexisting", sdk.NewInt(10)) - require.ErrorContains(t, err, "not found") + assert.ErrorContains(t, err, "not found") } func TestSetAndGetIBCInflows(t *testing.T) { diff --git a/x/uibc/quota/keeper/unit_test.go b/x/uibc/quota/keeper/unit_test.go index 7cb820892d..2e83ebc18c 100644 --- a/x/uibc/quota/keeper/unit_test.go +++ b/x/uibc/quota/keeper/unit_test.go @@ -35,7 +35,6 @@ func initKeeper(t *testing.T, l uibc.Leverage, o uibc.Oracle) TestKeeper { func initKeeperSimpleMock(t *testing.T) TestKeeper { lmock := NewLeverageKeeperMock(umee, atom) omock := NewOracleMock(umee, sdk.NewDec(2)) - omock.prices[atom] = sdk.NewDec(10) return initKeeper(t, lmock, omock) } From aa7e8fbbcf608555fa394efa6b719f9bfa44e220 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Fri, 3 Nov 2023 20:07:42 +0530 Subject: [PATCH 09/18] removed denom metadata tracker from docs --- x/uibc/README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/x/uibc/README.md b/x/uibc/README.md index 78f59ae9e3..bad39d45ea 100644 --- a/x/uibc/README.md +++ b/x/uibc/README.md @@ -4,26 +4,12 @@ The `x/uibc` is a Cosmos Module providing: -- IBC Denom Metadata Tracker for [ICS-20](https://github.com/cosmos/ibc/tree/main/spec/app/ics-020-fungible-token-transfer) transferred tokens to backfill denom metadata into the x/bank standard Cosmos SDK module. - IBC Quota is an ICS-4 middleware for the ICS-20 token transfer app to apply quota mechanism. ## Content -- [IBC Denom Metadata Tracker](#ibc-denom-metadata-tracker) - [IBC Quota](#ibc-quota) -## IBC Denom Metadata Tracker - -`x/bank.types.Metadata` is a structure which provides essential information about denom, such as display denom name, description, symbol, list of units (unit name and decimal exponent), and the default unit (`Base`). - -ICS-20 is a x/bank token transfer protocol over IBC. -The core implementation doesn't create bank `Metadata` when a new token is transferred for the very first time. It's worth to note that token received through IBC is identified by the port ID, channel ID and the source denom ID. -The purpose of the `x/uibc/ics20` module is to wrap the core IBC module and create a denom `Metadata` whenever it is missing. Look at the [`TrackDenomMetadata`](ics20/keeper/keeper.go) function for more details. - -### Considerations - -The IBC ICS-20 doesn't carry any metadata information, so we only fill up the base denom. Importantly, we don't know about the `Exponent`, and we set `Exponent := 0`. In many cases this is wrong, and should be overwritten by chain governance. - ## IBC Quota Hack or lending abuse is impossible to stop once the funds leave the chain. One mitigation is to limit the IBC inflows and outflows and be able to stop a chain and recover the funds with a migration. From 3f28e31fdf7f758e0bc8cbdc1b70b705816ca4e9 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Tue, 7 Nov 2023 22:43:23 +0530 Subject: [PATCH 10/18] add check for token outflows with InflowOutflowQuotaTokenBase --- proto/umee/uibc/v1/quota.proto | 6 ++ x/uibc/params.go | 16 ++-- x/uibc/quota.pb.go | 121 ++++++++++++++++++++--------- x/uibc/quota/keeper/params_test.go | 1 + x/uibc/quota/keeper/quota.go | 9 ++- x/uibc/quota/keeper/quota_test.go | 1 + x/uibc/quota/keeper/unit_test.go | 7 +- 7 files changed, 114 insertions(+), 47 deletions(-) diff --git a/proto/umee/uibc/v1/quota.proto b/proto/umee/uibc/v1/quota.proto index bef592e45e..ca91a5609e 100644 --- a/proto/umee/uibc/v1/quota.proto +++ b/proto/umee/uibc/v1/quota.proto @@ -42,6 +42,12 @@ message Params { (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; + // inflow_outflow_quota_token_base defines the inflow outflow quota base for token + string inflow_outflow_quota_token_base = 7 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; } // IBCTransferStatus status of ibc-transfer quota check for inflow and outflow diff --git a/x/uibc/params.go b/x/uibc/params.go index 4848c93db8..f381c89a00 100644 --- a/x/uibc/params.go +++ b/x/uibc/params.go @@ -10,12 +10,13 @@ import ( // DefaultParams returns default genesis params func DefaultParams() Params { return Params{ - IbcStatus: IBCTransferStatus_IBC_TRANSFER_STATUS_QUOTA_ENABLED, - TotalQuota: sdk.NewDec(1_600_000), // $1.6M - TokenQuota: sdk.NewDec(900_000), // $900K - QuotaDuration: time.Second * 60 * 60 * 24, // 24h - InflowOutflowQuotaBase: sdk.NewDec(1_000_000), // 1M - InflowOutflowQuotaRate: sdk.MustNewDecFromStr("0.25"), + IbcStatus: IBCTransferStatus_IBC_TRANSFER_STATUS_QUOTA_ENABLED, + TotalQuota: sdk.NewDec(1_600_000), // $1.6M + TokenQuota: sdk.NewDec(1_200_000), // $1.2M + QuotaDuration: time.Second * 60 * 60 * 24, // 24h + InflowOutflowQuotaBase: sdk.NewDec(1_000_000), // 1M + InflowOutflowQuotaRate: sdk.MustNewDecFromStr("0.25"), + InflowOutflowQuotaTokenBase: sdk.NewDec(900_000), // $0.9M } } @@ -38,6 +39,9 @@ func (p Params) Validate() error { if err := validateQuota(p.InflowOutflowQuotaRate, "total inflow outflow quota rate"); err != nil { return err } + if err := validateQuota(p.InflowOutflowQuotaTokenBase, "total inflow outflow quota token base"); err != nil { + return err + } if p.TotalQuota.LT(p.TokenQuota) { return fmt.Errorf("token quota shouldn't be less than quota per denom") } diff --git a/x/uibc/quota.pb.go b/x/uibc/quota.pb.go index 0d73164d21..10916eb2b9 100644 --- a/x/uibc/quota.pb.go +++ b/x/uibc/quota.pb.go @@ -87,6 +87,8 @@ type Params struct { InflowOutflowQuotaBase github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=inflow_outflow_quota_base,json=inflowOutflowQuotaBase,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflow_outflow_quota_base"` // inflow_outflow_quota_rate defines the rate of total inflows InflowOutflowQuotaRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=inflow_outflow_quota_rate,json=inflowOutflowQuotaRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflow_outflow_quota_rate"` + // inflow_outflow_quota_token_base defines the inflow outflow quota base for token + InflowOutflowQuotaTokenBase github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,7,opt,name=inflow_outflow_quota_token_base,json=inflowOutflowQuotaTokenBase,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflow_outflow_quota_token_base"` } func (m *Params) Reset() { *m = Params{} } @@ -144,42 +146,43 @@ func init() { func init() { proto.RegisterFile("umee/uibc/v1/quota.proto", fileDescriptor_651be1a0280abcb6) } var fileDescriptor_651be1a0280abcb6 = []byte{ - // 546 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0x31, 0x6f, 0xd3, 0x40, - 0x14, 0x80, 0xe3, 0x34, 0x8d, 0xd4, 0x2b, 0x54, 0xc1, 0x02, 0xe4, 0x74, 0xb0, 0x43, 0xa0, 0x51, - 0xa8, 0x88, 0xad, 0x16, 0x89, 0x01, 0x01, 0x22, 0x8e, 0x5d, 0xc9, 0x12, 0x4a, 0x52, 0xdb, 0x59, - 0x90, 0x90, 0x75, 0x76, 0x2f, 0xc1, 0x4a, 0xec, 0x0b, 0xf6, 0x39, 0x21, 0x13, 0x2b, 0x23, 0x23, - 0x3f, 0x84, 0x1f, 0xd1, 0xb1, 0x62, 0x42, 0x0c, 0x01, 0x25, 0x1b, 0x23, 0x1b, 0x1b, 0xf2, 0x9d, - 0xa3, 0xb6, 0xa2, 0xd9, 0xca, 0x74, 0xf7, 0xf2, 0xbe, 0xfb, 0xde, 0xbb, 0xa7, 0x8b, 0x81, 0x90, - 0x04, 0x08, 0x29, 0x89, 0xef, 0x7a, 0xca, 0xe4, 0x40, 0x79, 0x97, 0x60, 0x02, 0xe5, 0x71, 0x84, - 0x09, 0xe6, 0x6f, 0xa4, 0x19, 0x39, 0xcd, 0xc8, 0x93, 0x83, 0xdd, 0xdb, 0x03, 0x3c, 0xc0, 0x34, - 0xa1, 0xa4, 0x3b, 0xc6, 0xec, 0x8a, 0x03, 0x8c, 0x07, 0x23, 0xa4, 0xd0, 0xc8, 0x4d, 0xfa, 0xca, - 0x49, 0x12, 0x41, 0xe2, 0xe3, 0x30, 0xcb, 0x97, 0x3d, 0x1c, 0x07, 0x38, 0x76, 0xd8, 0x41, 0x16, - 0xb0, 0x54, 0xf5, 0x4f, 0x01, 0x14, 0xbb, 0x30, 0x82, 0x41, 0xcc, 0xbf, 0x00, 0xc0, 0x77, 0x3d, - 0x27, 0x26, 0x90, 0x24, 0xb1, 0xc0, 0x55, 0xb8, 0xfa, 0xce, 0xa1, 0x24, 0x5f, 0x2c, 0x2f, 0x1b, - 0x6a, 0xcb, 0x8e, 0x60, 0x18, 0xf7, 0x51, 0x64, 0x51, 0xcc, 0xdc, 0xf2, 0x5d, 0x8f, 0x6d, 0xf9, - 0x37, 0x60, 0x9b, 0x60, 0x02, 0x47, 0x0e, 0x6d, 0x5f, 0xc8, 0x57, 0xb8, 0xfa, 0x96, 0xfa, 0xec, - 0x74, 0x2e, 0xe5, 0xbe, 0xcf, 0xa5, 0xda, 0xc0, 0x27, 0x6f, 0x13, 0x57, 0xf6, 0x70, 0x90, 0x35, - 0x90, 0x2d, 0x8d, 0xf8, 0x64, 0xa8, 0x90, 0xd9, 0x18, 0xc5, 0xb2, 0x86, 0xbc, 0xaf, 0x5f, 0x1a, - 0x20, 0xeb, 0x4f, 0x43, 0x9e, 0x09, 0xa8, 0xf0, 0x38, 0xf5, 0x31, 0xfd, 0x10, 0x85, 0x99, 0x7e, - 0xe3, 0x7a, 0xf4, 0x43, 0x14, 0x32, 0xfd, 0x07, 0xb0, 0x43, 0xc5, 0xce, 0x6a, 0x76, 0x42, 0xa1, - 0xc2, 0xd5, 0xb7, 0x0f, 0xcb, 0x32, 0x1b, 0xae, 0xbc, 0x1a, 0xae, 0xac, 0x65, 0x80, 0xfa, 0x3c, - 0x2d, 0xfe, 0x6b, 0x2e, 0x09, 0x97, 0x0f, 0x3e, 0xc2, 0x81, 0x4f, 0x50, 0x30, 0x26, 0xb3, 0xdf, - 0x73, 0xe9, 0xce, 0x0c, 0x06, 0xa3, 0xa7, 0xd5, 0xcb, 0x44, 0xf5, 0xf3, 0x0f, 0x89, 0x33, 0x6f, - 0xd2, 0x1f, 0x57, 0x36, 0x7e, 0x0a, 0xca, 0x7e, 0xd8, 0x1f, 0xe1, 0xa9, 0x83, 0x13, 0x42, 0x57, - 0x76, 0xc8, 0x85, 0x31, 0x12, 0x36, 0xaf, 0xe1, 0xb6, 0x77, 0x99, 0xbe, 0xc3, 0xec, 0xf4, 0xd6, - 0x2a, 0x8c, 0xd1, 0xda, 0xc2, 0x11, 0x24, 0x48, 0x28, 0xfe, 0x9f, 0xc2, 0x26, 0x24, 0x68, 0xff, - 0x63, 0x1e, 0xdc, 0xfa, 0xe7, 0x45, 0xf1, 0xf7, 0x81, 0x64, 0xa8, 0x2d, 0xc7, 0x36, 0x9b, 0x6d, - 0xeb, 0x48, 0x37, 0x1d, 0xcb, 0x6e, 0xda, 0x3d, 0xcb, 0xe9, 0xb5, 0xad, 0xae, 0xde, 0x32, 0x8e, - 0x0c, 0x5d, 0x2b, 0xe5, 0xf8, 0x1a, 0xa8, 0x5e, 0x05, 0x1d, 0xf7, 0x3a, 0x76, 0xd3, 0xd1, 0x0c, - 0xab, 0xa9, 0xbe, 0xd2, 0xb5, 0x12, 0xc7, 0xef, 0x81, 0x7b, 0xeb, 0x39, 0xbd, 0xcd, 0xb0, 0x3c, - 0xbf, 0x0f, 0x6a, 0xeb, 0xb1, 0x4e, 0xcf, 0x3e, 0x57, 0x6e, 0xf0, 0x0f, 0xc1, 0xde, 0x7a, 0xd6, - 0x68, 0x9f, 0xa3, 0x05, 0xbe, 0x0e, 0x1e, 0x5c, 0x85, 0xae, 0x62, 0xcb, 0xe9, 0x36, 0x7b, 0x96, - 0xae, 0x95, 0x36, 0xd5, 0x97, 0xa7, 0x0b, 0x91, 0x3b, 0x5b, 0x88, 0xdc, 0xcf, 0x85, 0xc8, 0x7d, - 0x5a, 0x8a, 0xb9, 0xb3, 0xa5, 0x98, 0xfb, 0xb6, 0x14, 0x73, 0xaf, 0x2f, 0x8e, 0x3c, 0xfd, 0x2f, - 0x36, 0x42, 0x44, 0xa6, 0x38, 0x1a, 0xd2, 0x40, 0x99, 0x3c, 0x51, 0xde, 0xd3, 0xcf, 0x86, 0x5b, - 0xa4, 0xef, 0xf3, 0xf1, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x73, 0x20, 0x82, 0x4a, 0x04, - 0x00, 0x00, + // 571 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0xcf, 0x8b, 0xd3, 0x40, + 0x14, 0xc7, 0x9b, 0xfd, 0x25, 0x3b, 0xab, 0xcb, 0x1a, 0x54, 0xd2, 0x15, 0x92, 0x5a, 0xdd, 0x52, + 0x17, 0x9b, 0xb0, 0x2b, 0x78, 0x10, 0x15, 0x9b, 0x26, 0x0b, 0x01, 0x69, 0xbb, 0x49, 0x7a, 0x11, + 0x24, 0x4c, 0xb2, 0xd3, 0x1a, 0xda, 0x64, 0x6a, 0x32, 0x69, 0xed, 0x49, 0xf0, 0xe4, 0xd1, 0xa3, + 0x7f, 0x88, 0x7f, 0xc4, 0x1e, 0x17, 0x4f, 0xe2, 0xa1, 0x4a, 0x7b, 0xf3, 0xe8, 0x1f, 0x20, 0x92, + 0x99, 0x94, 0xdd, 0x65, 0xdb, 0x5b, 0x3d, 0xcd, 0xbc, 0xbc, 0xef, 0x7c, 0xbe, 0xef, 0xbd, 0x24, + 0x03, 0x84, 0x24, 0x40, 0x48, 0x49, 0x7c, 0xd7, 0x53, 0x06, 0x07, 0xca, 0xbb, 0x04, 0x13, 0x28, + 0xf7, 0x23, 0x4c, 0x30, 0x7f, 0x3d, 0xcd, 0xc8, 0x69, 0x46, 0x1e, 0x1c, 0xec, 0xde, 0xea, 0xe0, + 0x0e, 0xa6, 0x09, 0x25, 0xdd, 0x31, 0xcd, 0xae, 0xd8, 0xc1, 0xb8, 0xd3, 0x43, 0x0a, 0x8d, 0xdc, + 0xa4, 0xad, 0x9c, 0x24, 0x11, 0x24, 0x3e, 0x0e, 0xb3, 0x7c, 0xde, 0xc3, 0x71, 0x80, 0x63, 0x87, + 0x1d, 0x64, 0x01, 0x4b, 0x15, 0xff, 0xae, 0x83, 0x8d, 0x26, 0x8c, 0x60, 0x10, 0xf3, 0x2f, 0x00, + 0xf0, 0x5d, 0xcf, 0x89, 0x09, 0x24, 0x49, 0x2c, 0x70, 0x05, 0xae, 0xbc, 0x7d, 0x28, 0xc9, 0x17, + 0xed, 0x65, 0x43, 0xad, 0xd9, 0x11, 0x0c, 0xe3, 0x36, 0x8a, 0x2c, 0x2a, 0x33, 0x37, 0x7d, 0xd7, + 0x63, 0x5b, 0xfe, 0x0d, 0xd8, 0x22, 0x98, 0xc0, 0x9e, 0x43, 0xcb, 0x17, 0x56, 0x0a, 0x5c, 0x79, + 0x53, 0x7d, 0x76, 0x3a, 0x96, 0x72, 0x3f, 0xc6, 0x52, 0xa9, 0xe3, 0x93, 0xb7, 0x89, 0x2b, 0x7b, + 0x38, 0xc8, 0x0a, 0xc8, 0x96, 0x4a, 0x7c, 0xd2, 0x55, 0xc8, 0xa8, 0x8f, 0x62, 0x59, 0x43, 0xde, + 0xb7, 0xaf, 0x15, 0x90, 0xd5, 0xa7, 0x21, 0xcf, 0x04, 0x14, 0x78, 0x9c, 0xf2, 0x18, 0xbe, 0x8b, + 0xc2, 0x0c, 0xbf, 0xba, 0x1c, 0x7c, 0x17, 0x85, 0x0c, 0xff, 0x01, 0x6c, 0x53, 0xb0, 0x33, 0x9b, + 0x9d, 0xb0, 0x56, 0xe0, 0xca, 0x5b, 0x87, 0x79, 0x99, 0x0d, 0x57, 0x9e, 0x0d, 0x57, 0xd6, 0x32, + 0x81, 0xfa, 0x3c, 0x35, 0xff, 0x3d, 0x96, 0x84, 0xcb, 0x07, 0x1f, 0xe1, 0xc0, 0x27, 0x28, 0xe8, + 0x93, 0xd1, 0x9f, 0xb1, 0x74, 0x7b, 0x04, 0x83, 0xde, 0xd3, 0xe2, 0x65, 0x45, 0xf1, 0xcb, 0x4f, + 0x89, 0x33, 0x6f, 0xd0, 0x87, 0x33, 0x1a, 0x3f, 0x04, 0x79, 0x3f, 0x6c, 0xf7, 0xf0, 0xd0, 0xc1, + 0x09, 0xa1, 0x2b, 0x3b, 0xe4, 0xc2, 0x18, 0x09, 0xeb, 0x4b, 0xe8, 0xf6, 0x0e, 0xc3, 0x37, 0x18, + 0x9d, 0x76, 0xad, 0xc2, 0x18, 0x2d, 0x34, 0x8e, 0x20, 0x41, 0xc2, 0xc6, 0xff, 0x31, 0x36, 0x21, + 0x41, 0xfc, 0x47, 0x0e, 0x48, 0x73, 0x9d, 0xd9, 0x7b, 0xa6, 0x8d, 0x5f, 0x5b, 0x82, 0xff, 0xdd, + 0xab, 0xfe, 0x76, 0xea, 0x90, 0x76, 0xbf, 0xff, 0x69, 0x05, 0xdc, 0xbc, 0xf2, 0x59, 0xf3, 0xf7, + 0x81, 0x64, 0xa8, 0x35, 0xc7, 0x36, 0xab, 0x75, 0xeb, 0x48, 0x37, 0x1d, 0xcb, 0xae, 0xda, 0x2d, + 0xcb, 0x69, 0xd5, 0xad, 0xa6, 0x5e, 0x33, 0x8e, 0x0c, 0x5d, 0xdb, 0xc9, 0xf1, 0x25, 0x50, 0x9c, + 0x27, 0x3a, 0x6e, 0x35, 0xec, 0xaa, 0xa3, 0x19, 0x56, 0x55, 0x7d, 0xa5, 0x6b, 0x3b, 0x1c, 0xbf, + 0x07, 0xee, 0x2d, 0xd6, 0xe9, 0x75, 0x26, 0x5b, 0xe1, 0xf7, 0x41, 0x69, 0xb1, 0xac, 0xd1, 0xb2, + 0xcf, 0x91, 0xab, 0xfc, 0x43, 0xb0, 0xb7, 0x58, 0x6b, 0xd4, 0xcf, 0xa5, 0x6b, 0x7c, 0x19, 0x3c, + 0x98, 0x27, 0x9d, 0xc5, 0x96, 0xd3, 0xac, 0xb6, 0x2c, 0x5d, 0xdb, 0x59, 0x57, 0x5f, 0x9e, 0x4e, + 0x44, 0xee, 0x6c, 0x22, 0x72, 0xbf, 0x26, 0x22, 0xf7, 0x79, 0x2a, 0xe6, 0xce, 0xa6, 0x62, 0xee, + 0xfb, 0x54, 0xcc, 0xbd, 0xbe, 0x38, 0xf7, 0xf4, 0x42, 0xa8, 0x84, 0x88, 0x0c, 0x71, 0xd4, 0xa5, + 0x81, 0x32, 0x78, 0xa2, 0xbc, 0xa7, 0x77, 0x97, 0xbb, 0x41, 0x7f, 0x92, 0xc7, 0xff, 0x02, 0x00, + 0x00, 0xff, 0xff, 0xf1, 0xe6, 0x9a, 0xe6, 0xcf, 0x04, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -202,6 +205,16 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.InflowOutflowQuotaTokenBase.Size() + i -= size + if _, err := m.InflowOutflowQuotaTokenBase.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintQuota(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a { size := m.InflowOutflowQuotaRate.Size() i -= size @@ -288,6 +301,8 @@ func (m *Params) Size() (n int) { n += 1 + l + sovQuota(uint64(l)) l = m.InflowOutflowQuotaRate.Size() n += 1 + l + sovQuota(uint64(l)) + l = m.InflowOutflowQuotaTokenBase.Size() + n += 1 + l + sovQuota(uint64(l)) return n } @@ -514,6 +529,40 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InflowOutflowQuotaTokenBase", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuota + } + 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 ErrInvalidLengthQuota + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuota + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InflowOutflowQuotaTokenBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuota(dAtA[iNdEx:]) diff --git a/x/uibc/quota/keeper/params_test.go b/x/uibc/quota/keeper/params_test.go index 6eb7734ccb..5c0a38be15 100644 --- a/x/uibc/quota/keeper/params_test.go +++ b/x/uibc/quota/keeper/params_test.go @@ -24,6 +24,7 @@ func TestUnitParams(t *testing.T) { params.TotalQuota = sdk.MustNewDecFromStr("3.4321") params.InflowOutflowQuotaBase = sdk.MustNewDecFromStr("3.4321") params.InflowOutflowQuotaRate = sdk.MustNewDecFromStr("0.2") + params.InflowOutflowQuotaTokenBase = sdk.MustNewDecFromStr("0.2") err := k.SetParams(params) require.NoError(err) diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index 52e0abcac1..f001aece7a 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -170,9 +170,14 @@ func (k Keeper) CheckAndUpdateQuota(denom string, newOutflow sdkmath.Int) error o := k.GetTokenOutflows(denom) o.Amount = o.Amount.Add(exchangePrice) - if !params.TokenQuota.IsZero() && o.Amount.GT(params.TokenQuota) { - return uibc.ErrQuotaExceeded + inToken := k.GetTokenInflow(denom) + if !params.TokenQuota.IsZero() { + if o.Amount.GT(params.TokenQuota) || + o.Amount.GT(params.InflowOutflowQuotaTokenBase.Add((sdk.MustNewDecFromStr("0.25").Mul(inToken.Amount)))) { + return uibc.ErrQuotaExceeded + } } + // Allow outflow either of two conditions // 1. Total Outflow Sum <= Total Outflow Quota // or diff --git a/x/uibc/quota/keeper/quota_test.go b/x/uibc/quota/keeper/quota_test.go index 366f4ab0f7..246dfdff2d 100644 --- a/x/uibc/quota/keeper/quota_test.go +++ b/x/uibc/quota/keeper/quota_test.go @@ -47,6 +47,7 @@ func TestUnitCheckAndUpdateQuota(t *testing.T) { k.SetTokenInflow(sdk.NewInt64DecCoin(umee, 6)) k.SetTotalOutflowSum(sdk.NewDec(50)) k.SetTotalInflow(sdk.NewDec(50)) + k.SetTokenInflow(sdk.NewDecCoin(umee, math.NewInt(50))) err := k.CheckAndUpdateQuota(umee, sdk.NewInt(1)) assert.NilError(t, err) diff --git a/x/uibc/quota/keeper/unit_test.go b/x/uibc/quota/keeper/unit_test.go index 2e83ebc18c..a697e14af9 100644 --- a/x/uibc/quota/keeper/unit_test.go +++ b/x/uibc/quota/keeper/unit_test.go @@ -54,9 +54,10 @@ func (k TestKeeper) checkOutflows(denom string, perToken, total int64) { func (k TestKeeper) setQuotaParams(perToken, total int64) { err := k.SetParams(uibc.Params{ - TokenQuota: sdk.NewDec(perToken), - TotalQuota: sdk.NewDec(total), - InflowOutflowQuotaBase: sdk.NewDec(1_000_000), + TokenQuota: sdk.NewDec(perToken), + TotalQuota: sdk.NewDec(total), + InflowOutflowQuotaBase: sdk.NewDec(1_000_000), + InflowOutflowQuotaTokenBase: sdk.NewDec(9_00_000), }) require.NoError(k.t, err) } From 3b73075b239c5ff95e21cd75c3d0af2328c9a652 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Wed, 8 Nov 2023 20:05:07 +0530 Subject: [PATCH 11/18] fix the ibc e2e tests --- tests/e2e/e2e_ibc_test.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/e2e/e2e_ibc_test.go b/tests/e2e/e2e_ibc_test.go index 911fa8689c..f41ca7bcac 100644 --- a/tests/e2e/e2e_ibc_test.go +++ b/tests/e2e/e2e_ibc_test.go @@ -167,17 +167,15 @@ func (s *E2ETest) TestIBCTokenTransfer() { atom40 := mulCoin(atomQuota, "0.4") s.SendIBC(s.Chain.ID, setup.GaiaChainID, "", atom40, true, "below token quota but not total quota") // supply will be not be decreased because sending more than total quota from umee to gaia - s.checkSupply(umeeAPIEndpoint, uatomIBCHash, atomFromGaia.Amount.Sub(atom40.Amount)) - s.checkOutflows(umeeAPIEndpoint, uatomIBCHash, true, sdk.NewDecFromInt(atom40.Amount), atomSymbol) + s.checkSupply(umeeAPIEndpoint, uatomIBCHash, atomFromGaia.Amount) - // ✅ << BELOW TOKEN QUTOA 5$ but ATOM_QUOTA (5$)+ UMEE_QUOTA(90$) <= TOTAL QUOTA (120$) >> - // send $15 ATOM from umee to gaia + // ✅ << BELOW TOKEN QUTOA 5$ but ATOM_QUOTA (5$)+ UMEE_QUOTA(90$) <= TOTAL QUOTA (120$) + // send $5 ATOM from umee to gaia sendAtom := mulCoin(atomQuota, "0.05") s.SendIBC(s.Chain.ID, setup.GaiaChainID, "", sendAtom, false, "below both quotas") // remaing supply decreased uatom on umee - s.checkSupply(umeeAPIEndpoint, uatomIBCHash, atomFromGaia.Amount.Sub(sendAtom.Amount).Sub(atom40.Amount)) - s.checkOutflows(umeeAPIEndpoint, uatomIBCHash, true, - sdk.NewDecFromInt(sendAtom.Amount).Add(sdk.NewDecFromInt(atom40.Amount)), atomSymbol) + s.checkSupply(umeeAPIEndpoint, uatomIBCHash, atomFromGaia.Amount.Sub(sendAtom.Amount)) + s.checkOutflows(umeeAPIEndpoint, uatomIBCHash, true, sdk.NewDecFromInt(sendAtom.Amount), atomSymbol) // send $45 UMEE from gaia to umee returnUmee := mulCoin(sendUmee, "0.5") From c6dd61b0f537e8fe03eefcb646fb1cb6c6531397 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Tue, 14 Nov 2023 15:50:43 +0530 Subject: [PATCH 12/18] move the new migration of uibc params to keeper --- app/upgrades.go | 11 ++-------- proto/umee/uibc/v1/genesis.proto | 4 ++-- util/store/store.go | 8 +++++++ x/uibc/genesis.pb.go | 4 ++-- x/uibc/params.go | 10 ++++++++- x/uibc/quota/keeper/migrations.go | 17 +++++++++++++++ x/uibc/quota/keeper/quota.go | 35 ++++++++++--------------------- 7 files changed, 51 insertions(+), 38 deletions(-) create mode 100644 x/uibc/quota/keeper/migrations.go diff --git a/app/upgrades.go b/app/upgrades.go index a4b37d79fc..b80a9215be 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -132,16 +132,9 @@ func (app *UmeeApp) registerUpgrade6_2(upgradeInfo upgradetypes.Plan) { // uibc migrations uIBCKeeper := app.UIbcQuotaKeeperB.Keeper(&ctx) // migrating outflow - oldTotalOutflow := uIBCKeeper.GetOldTotalOutflow() - uIBCKeeper.SetTotalOutflowSum(oldTotalOutflow) + uIBCKeeper.MigrateTotalOutflowSum() // uibc params - uibcParams := uIBCKeeper.GetParams() - uibcParams.TotalQuota = sdk.NewDec(1_600_000) - uibcParams.TokenQuota = sdk.NewDec(900_000) - uibcParams.InflowOutflowQuotaBase = sdk.NewDec(1_000_000) - uibcParams.InflowOutflowQuotaRate = sdk.MustNewDecFromStr("0.25") - - err = uIBCKeeper.SetParams(uibcParams) + err = uIBCKeeper.SetParams(uibc.DefaultParams()) return fromVM, err }, ) diff --git a/proto/umee/uibc/v1/genesis.proto b/proto/umee/uibc/v1/genesis.proto index 942c48b5a0..84df483b26 100644 --- a/proto/umee/uibc/v1/genesis.proto +++ b/proto/umee/uibc/v1/genesis.proto @@ -30,12 +30,12 @@ message GenesisState { (gogoproto.jsontag) = "quota_duration,omitempty", (gogoproto.moretags) = "yaml:\"quota_expires\"" ]; - // inflows defines inflow amount per denom denoms + // inflows tracks IBC inflow transfers (in USD) for each denom during quota period. repeated cosmos.base.v1beta1.DecCoin inflows = 5 [ (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", (gogoproto.nullable) = false ]; - // total_inflow_sum defines the total inflow sum of ibc-transfer in USD. + // total_inflow_sum defines tracks total sum of IBC inflow transfers (in USD) during quota period. string total_inflow_sum = 6 [ (cosmos_proto.scalar) = "cosmos.Dec", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", diff --git a/util/store/store.go b/util/store/store.go index 1fd9f8af32..ed8ff69ea2 100644 --- a/util/store/store.go +++ b/util/store/store.go @@ -15,6 +15,7 @@ import ( "time" sdkmath "cosmossdk.io/math" + db "github.com/cometbft/cometbft-db" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -209,3 +210,10 @@ func GetInteger[T Integer](store sdk.KVStore, key []byte) (T, bool) { } panic("not possible: all types must be covered above") } + +func DeleteByIterator(store sdk.KVStore, iter db.Iterator) { + defer iter.Close() + for ; iter.Valid(); iter.Next() { + store.Delete(iter.Key()) + } +} diff --git a/x/uibc/genesis.pb.go b/x/uibc/genesis.pb.go index acf0468b89..3b373b4f1d 100644 --- a/x/uibc/genesis.pb.go +++ b/x/uibc/genesis.pb.go @@ -38,9 +38,9 @@ type GenesisState struct { TotalOutflowSum github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=total_outflow_sum,json=totalOutflowSum,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_outflow_sum"` // quota_expires defines quota expire time (as unix timestamp) for ibc-transfer denom. QuotaExpires time.Time `protobuf:"bytes,4,opt,name=quota_expires,json=quotaExpires,proto3,stdtime" json:"quota_duration,omitempty" yaml:"quota_expires"` - // inflows defines inflow amount per denom denoms + // inflows tracks IBC inflow transfers (in USD) during quota period. Inflows github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,5,rep,name=inflows,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"inflows"` - // total_inflow_sum defines the total inflow sum of ibc-transfer in USD. + // total_inflow_sum defines tracks total sum of IBC inflow transfers (in USD) during quota period. TotalInflowSum github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=total_inflow_sum,json=totalInflowSum,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_inflow_sum"` } diff --git a/x/uibc/params.go b/x/uibc/params.go index f381c89a00..4a6b756cce 100644 --- a/x/uibc/params.go +++ b/x/uibc/params.go @@ -36,7 +36,7 @@ func (p Params) Validate() error { if err := validateQuota(p.InflowOutflowQuotaBase, "total inflow outflow quota base"); err != nil { return err } - if err := validateQuota(p.InflowOutflowQuotaRate, "total inflow outflow quota rate"); err != nil { + if err := validateQuotaRate(p.InflowOutflowQuotaRate, "total inflow outflow quota rate"); err != nil { return err } if err := validateQuota(p.InflowOutflowQuotaTokenBase, "total inflow outflow quota token base"); err != nil { @@ -76,6 +76,14 @@ func validateQuota(q sdk.Dec, typ string) error { return nil } +func validateQuotaRate(q sdk.Dec, typ string) error { + if q.LT(sdk.ZeroDec()) || q.GT(sdk.NewDec(2)) { + return fmt.Errorf("%s must be between 0 and 2: %s", typ, q) + } + + return validateQuota(q, typ) +} + // IBCTransferEnabled returns true if the ibc-transfer is enabled for both inflow and outflow." func (status IBCTransferStatus) IBCTransferEnabled() bool { return status != IBCTransferStatus_IBC_TRANSFER_STATUS_TRANSFERS_PAUSED diff --git a/x/uibc/quota/keeper/migrations.go b/x/uibc/quota/keeper/migrations.go new file mode 100644 index 0000000000..ef2b866ea3 --- /dev/null +++ b/x/uibc/quota/keeper/migrations.go @@ -0,0 +1,17 @@ +package keeper + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// GetOldTotalOutflow returns the total outflow of ibc-transfer amount. +// Note: only use for v6.2 migration from v6.1.0 +func (k Keeper) GetOldTotalOutflow() sdk.Dec { + bz := k.store.Get(keyTotalOutflows) + return sdk.MustNewDecFromStr(string(bz)) +} + +// MigrateTotalOutflowSum migrate the old total outflow type to new one +// Note: only use for v6.2 migration from v6.1.0 +func (k Keeper) MigrateTotalOutflowSum() { + oldTotalOutflow := k.GetOldTotalOutflow() + k.SetTotalOutflowSum(oldTotalOutflow) +} diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index f001aece7a..327fb794d8 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -22,7 +22,7 @@ var ten = sdk.MustNewDecFromStr("10") // GetAllOutflows returns sum of outflows of all tokens in USD value. func (k Keeper) GetAllOutflows() (sdk.DecCoins, error) { var outflows sdk.DecCoins - iter := func(key, val []byte) error { + cb := func(key, val []byte) error { o := sdk.DecCoin{Denom: DenomFromKey(key, keyPrefixDenomOutflows)} if err := o.Amount.Unmarshal(val); err != nil { return err @@ -31,7 +31,7 @@ func (k Keeper) GetAllOutflows() (sdk.DecCoins, error) { return nil } - err := store.Iterate(k.store, keyPrefixDenomOutflows, iter) + err := store.Iterate(k.store, keyPrefixDenomOutflows, cb) return outflows, err } @@ -71,7 +71,7 @@ func (k Keeper) SetTokenOutflow(outflow sdk.DecCoin) { // GetAllInflows returns inflows of all registered tokens in USD value. func (k Keeper) GetAllInflows() (sdk.DecCoins, error) { var inflows sdk.DecCoins - iter := func(key, val []byte) error { + cb := func(key, val []byte) error { o := sdk.DecCoin{Denom: DenomFromKey(key, keyPrefixDenomInflows)} if err := o.Amount.Unmarshal(val); err != nil { return err @@ -79,7 +79,7 @@ func (k Keeper) GetAllInflows() (sdk.DecCoins, error) { inflows = append(inflows, o) return nil } - err := store.Iterate(k.store, keyPrefixDenomInflows, iter) + err := store.Iterate(k.store, keyPrefixDenomInflows, cb) return inflows, err } @@ -137,21 +137,15 @@ func (k Keeper) ResetAllQuotas() error { zero := sdk.NewDec(0) // outflows k.SetTotalOutflowSum(zero) - store := k.PrefixStore(keyPrefixDenomOutflows) - iter := sdk.KVStorePrefixIterator(store, nil) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - store.Delete(iter.Key()) - } + ps := k.PrefixStore(keyPrefixDenomOutflows) + iter := sdk.KVStorePrefixIterator(ps, nil) + store.DeleteByIterator(ps, iter) // inflows k.SetTotalInflow(zero) - store = k.PrefixStore(keyPrefixDenomInflows) - iter = sdk.KVStorePrefixIterator(store, nil) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - store.Delete(iter.Key()) - } + ps = k.PrefixStore(keyPrefixDenomInflows) + iter = sdk.KVStorePrefixIterator(ps, nil) + store.DeleteByIterator(ps, iter) return nil } @@ -273,7 +267,7 @@ func (k Keeper) RecordIBCInflow(ctx sdk.Context, } } - // get the exchange price (eg: UMEE) in USD from oracle using SYMBOL Denom eg: `UMEE` (uumee) + // get the exchange price (eg: UMEE) in USD from oracle using SYMBOL Denom eg: `UMEE` exchangeRate, err := k.oracle.Price(*k.ctx, strings.ToUpper(ts.SymbolDenom)) if err != nil { return channeltypes.NewErrorAcknowledgement(err) @@ -290,10 +284,3 @@ func (k Keeper) RecordIBCInflow(ctx sdk.Context, return nil } - -// GetOldTotalOutflow returns the total outflow of ibc-transfer amount. -// Note: only using for migration -func (k Keeper) GetOldTotalOutflow() sdk.Dec { - bz := k.store.Get(keyTotalOutflows) - return sdk.MustNewDecFromStr(string(bz)) -} From 4d4ca4179819e8e270fe57a428ac48f61f45b028 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Tue, 14 Nov 2023 19:07:50 +0530 Subject: [PATCH 13/18] make keys functions to private --- app/upgrades.go | 2 -- util/store/store.go | 5 +++-- x/uibc/README.md | 8 ++++---- x/uibc/quota/keeper/keys.go | 8 ++++---- x/uibc/quota/keeper/mocks_test.go | 2 ++ x/uibc/quota/keeper/quota.go | 26 +++++++++++++++----------- 6 files changed, 28 insertions(+), 23 deletions(-) diff --git a/app/upgrades.go b/app/upgrades.go index b80a9215be..c5330ce5f5 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -131,9 +131,7 @@ func (app *UmeeApp) registerUpgrade6_2(upgradeInfo upgradetypes.Plan) { // uibc migrations uIBCKeeper := app.UIbcQuotaKeeperB.Keeper(&ctx) - // migrating outflow uIBCKeeper.MigrateTotalOutflowSum() - // uibc params err = uIBCKeeper.SetParams(uibc.DefaultParams()) return fromVM, err }, diff --git a/util/store/store.go b/util/store/store.go index ed8ff69ea2..9aeb181c50 100644 --- a/util/store/store.go +++ b/util/store/store.go @@ -15,7 +15,6 @@ import ( "time" sdkmath "cosmossdk.io/math" - db "github.com/cometbft/cometbft-db" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -211,7 +210,9 @@ func GetInteger[T Integer](store sdk.KVStore, key []byte) (T, bool) { panic("not possible: all types must be covered above") } -func DeleteByIterator(store sdk.KVStore, iter db.Iterator) { +// DeleteByPrefixStoreIterator will delete all keys stored in prefix store +func DeleteByPrefixStoreIterator(store sdk.KVStore) { + iter := sdk.KVStorePrefixIterator(store, nil) defer iter.Close() for ; iter.Valid(); iter.Next() { store.Delete(iter.Key()) diff --git a/x/uibc/README.md b/x/uibc/README.md index bad39d45ea..359e7c88d6 100644 --- a/x/uibc/README.md +++ b/x/uibc/README.md @@ -29,9 +29,9 @@ All outflows are measured in token average USD value using our x/oracle `AvgKeep We define 2 Quotas for ICS-20 transfers. Each quota only tracks tokens x/leverage Token Registry. -- `Params.TokenQuota`: upper limit of a sum of all outflows per token. Initially it's set to 0.9M USD per token. It limits the outflows value for each token. +- `Params.TokenQuota`: upper limit of a sum of all outflows per token. It's set to 1.2M USD per token. It limits the outflows value for each token. NOTE: we measure per token as defined in the x/leverage, not the IBC Denom Path (there can be multiple paths). Since creating a channel is permission less, we want to use same quota token. -- `Params.TotalQuota`: upper limit of a sum of all token outflows combined. Initially it's set to 1.6M USD. Example of IBC outflows reaching the total quota: 600k USD worth of ATOM, 500k USD worth of STATOM, 250k USD worth of UMEE and 250k USD worth JUNO. +- `Params.TotalQuota`: upper limit of a sum of all token outflows combined. For example if it's set to 1.6M USD then IBC outflows reaching the total quota will be 600k USD worth of ATOM, 500k USD worth of STATOM, 250k USD worth of UMEE and 250k USD worth JUNO. If a quota parameter is set to zero then we consider it as unlimited. @@ -46,8 +46,8 @@ Transfer of tokens, which are not registered in the x/leverage Token Registry ar All inflows are measured in token average USD value using our x/oracle `AvgKeeper`. The `AvgKeeper` aggregates TVWAP prices over 16h window. We are only tracking inflows for tokens which are registered in x/leverage Token Registry. -- `Genesis.TotalInflowSum` : Sum of all inflows per token which are registered in x/leverage Token Registry -- `Genesis.Inflows`: Inflows of registered tokens. +- `Genesis.TotalInflowSum` : Sum of all IBC Tokens Inflows which are registered in x/leverage Token Registry. +- `Genesis.Inflows`: IBC Inflow of each registered token. #### ICS-20 Quota control diff --git a/x/uibc/quota/keeper/keys.go b/x/uibc/quota/keeper/keys.go index af61e3be25..6a45001c6a 100644 --- a/x/uibc/quota/keeper/keys.go +++ b/x/uibc/quota/keeper/keys.go @@ -13,18 +13,18 @@ var ( keyTotalInflows = []byte{0x06} ) -func KeyTotalOutflows(ibcDenom string) []byte { +func keyTotalOutflow(ibcDenom string) []byte { // keyPrefixDenomOutflows | denom return util.ConcatBytes(0, keyPrefixDenomOutflows, []byte(ibcDenom)) } -func KeyTokenInflow(ibcDenom string) []byte { +func keyTokenInflow(ibcDenom string) []byte { // keyPrefixDenomInflows | denom return util.ConcatBytes(0, keyPrefixDenomInflows, []byte(ibcDenom)) } -// DenomFromKey extracts denom from a key with the form +// denomFromKey extracts denom from a key with the form // prefix | denom -func DenomFromKey(key, prefix []byte) string { +func denomFromKey(key, prefix []byte) string { return string(key[len(prefix):]) } diff --git a/x/uibc/quota/keeper/mocks_test.go b/x/uibc/quota/keeper/mocks_test.go index f301bcabc6..14e76b6225 100644 --- a/x/uibc/quota/keeper/mocks_test.go +++ b/x/uibc/quota/keeper/mocks_test.go @@ -48,6 +48,8 @@ type Oracle struct { func (o Oracle) Price(_ sdk.Context, denom string) (sdk.Dec, error) { p, ok := o.prices[denom] if !ok { + // When token exists in leverage registry but price is not found we are returning `0` + // https://github.com/umee-network/umee/tree/main/x/oracle/keeper/historic_avg.go#L126 return sdk.ZeroDec(), nil } return p, nil diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index 327fb794d8..2ae3e3a4d7 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -23,7 +23,7 @@ var ten = sdk.MustNewDecFromStr("10") func (k Keeper) GetAllOutflows() (sdk.DecCoins, error) { var outflows sdk.DecCoins cb := func(key, val []byte) error { - o := sdk.DecCoin{Denom: DenomFromKey(key, keyPrefixDenomOutflows)} + o := sdk.DecCoin{Denom: denomFromKey(key, keyPrefixDenomOutflows)} if err := o.Amount.Unmarshal(val); err != nil { return err } @@ -37,7 +37,8 @@ func (k Keeper) GetAllOutflows() (sdk.DecCoins, error) { // GetTokenOutflows returns sum of denom outflows in USD value in the DecCoin structure. func (k Keeper) GetTokenOutflows(denom string) sdk.DecCoin { - amount, _ := store.GetDec(k.store, KeyTotalOutflows(denom), "total_outflow") + // When token outflow is not stored in store it will return 0 + amount, _ := store.GetDec(k.store, keyTotalOutflow(denom), "total_outflow") return sdk.NewDecCoinFromDec(denom, amount) } @@ -57,13 +58,14 @@ func (k Keeper) SetTotalOutflowSum(amount sdk.Dec) { // GetTotalOutflow returns the total outflow of ibc-transfer amount. func (k Keeper) GetTotalOutflow() sdk.Dec { + // When total outflow is not stored in store it will return 0 amount, _ := store.GetDec(k.store, keyTotalOutflows, "total_outflow") return amount } // SetTokenOutflow save the outflows of denom into store. func (k Keeper) SetTokenOutflow(outflow sdk.DecCoin) { - key := KeyTotalOutflows(outflow.Denom) + key := keyTotalOutflow(outflow.Denom) err := store.SetDec(k.store, key, outflow.Amount, "total_outflow") util.Panic(err) } @@ -72,8 +74,10 @@ func (k Keeper) SetTokenOutflow(outflow sdk.DecCoin) { func (k Keeper) GetAllInflows() (sdk.DecCoins, error) { var inflows sdk.DecCoins cb := func(key, val []byte) error { - o := sdk.DecCoin{Denom: DenomFromKey(key, keyPrefixDenomInflows)} + o := sdk.DecCoin{Denom: denomFromKey(key, keyPrefixDenomInflows)} if err := o.Amount.Unmarshal(val); err != nil { + k.ctx.Logger().Error("error while unmarshal the ibc inflow for denom", "denom", o.Denom, + "amount", o.Amount.String()) return err } inflows = append(inflows, o) @@ -93,20 +97,22 @@ func (k Keeper) SetTokenInflows(inflows sdk.DecCoins) { // SetTokenInflow save the inflow of denom into store. func (k Keeper) SetTokenInflow(inflow sdk.DecCoin) { - key := KeyTokenInflow(inflow.Denom) + key := keyTokenInflow(inflow.Denom) err := store.SetDec(k.store, key, inflow.Amount, "token_inflow") util.Panic(err) } // GetTokenInflow returns the inflow of denom from store. func (k Keeper) GetTokenInflow(denom string) sdk.DecCoin { - key := KeyTokenInflow(denom) + key := keyTokenInflow(denom) + // When token inflow is not stored in store it will return 0 amount, _ := store.GetDec(k.store, key, "token_inflow") return sdk.NewDecCoinFromDec(denom, amount) } // GetTotalInflow returns the total inflow of ibc-transfer amount. func (k Keeper) GetTotalInflow() sdk.Dec { + // When total inflow is not stored in store it will return 0 amount, _ := store.GetDec(k.store, keyTotalInflows, "total_inflows") return amount } @@ -138,14 +144,12 @@ func (k Keeper) ResetAllQuotas() error { // outflows k.SetTotalOutflowSum(zero) ps := k.PrefixStore(keyPrefixDenomOutflows) - iter := sdk.KVStorePrefixIterator(ps, nil) - store.DeleteByIterator(ps, iter) + store.DeleteByPrefixStoreIterator(ps) // inflows k.SetTotalInflow(zero) ps = k.PrefixStore(keyPrefixDenomInflows) - iter = sdk.KVStorePrefixIterator(ps, nil) - store.DeleteByIterator(ps, iter) + store.DeleteByPrefixStoreIterator(ps) return nil } @@ -175,7 +179,7 @@ func (k Keeper) CheckAndUpdateQuota(denom string, newOutflow sdkmath.Int) error // Allow outflow either of two conditions // 1. Total Outflow Sum <= Total Outflow Quota // or - // 2 . Total Outflow Sum <= $1M + params.TotalInflowQuota * sum of all inflows + // 2. Total Outflow Sum <= params.InflowOutflowQuotaBase($1M) + (params.InflowOutflowQuotaRate * sum of all inflows) totalOutflowSum := k.GetTotalOutflow().Add(exchangePrice) ttlInSum := k.GetTotalInflow() if !params.TotalQuota.IsZero() { From e3359d6d465328a1fc0e5d3dce9c06c2f2c0b7b7 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Tue, 14 Nov 2023 21:28:26 +0530 Subject: [PATCH 14/18] add tests for uibc quota inflows --- x/uibc/README.md | 2 ++ x/uibc/quota/keeper/quota.go | 4 +-- x/uibc/quota/keeper/quota_test.go | 41 +++++++++++++++++++++++++++++++ x/uibc/quota/keeper/unit_test.go | 10 +++----- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/x/uibc/README.md b/x/uibc/README.md index 359e7c88d6..36416555be 100644 --- a/x/uibc/README.md +++ b/x/uibc/README.md @@ -65,6 +65,8 @@ In the state we store: - Running sum of total outflow values, serialized as `sdk.Dec`. - Running sum of per token outflow values, serialized as `sdk.Dec`. - Next quota expire time (after which the quota reset happens). +- Running sum of total inflow values, serialized as `sdk.Dec`. +- Running sum of per token inflow values, serialized as `sdk.Dec`. ### Messages diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index 2ae3e3a4d7..ae67ca9fad 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -171,7 +171,7 @@ func (k Keeper) CheckAndUpdateQuota(denom string, newOutflow sdkmath.Int) error inToken := k.GetTokenInflow(denom) if !params.TokenQuota.IsZero() { if o.Amount.GT(params.TokenQuota) || - o.Amount.GT(params.InflowOutflowQuotaTokenBase.Add((sdk.MustNewDecFromStr("0.25").Mul(inToken.Amount)))) { + o.Amount.GT(params.InflowOutflowQuotaTokenBase.Add((params.InflowOutflowQuotaRate.Mul(inToken.Amount)))) { return uibc.ErrQuotaExceeded } } @@ -179,7 +179,7 @@ func (k Keeper) CheckAndUpdateQuota(denom string, newOutflow sdkmath.Int) error // Allow outflow either of two conditions // 1. Total Outflow Sum <= Total Outflow Quota // or - // 2. Total Outflow Sum <= params.InflowOutflowQuotaBase($1M) + (params.InflowOutflowQuotaRate * sum of all inflows) + // 2. Total Outflow Sum <= params.InflowOutflowQuotaBase + (params.InflowOutflowQuotaRate * sum of all inflows) totalOutflowSum := k.GetTotalOutflow().Add(exchangePrice) ttlInSum := k.GetTotalInflow() if !params.TotalQuota.IsZero() { diff --git a/x/uibc/quota/keeper/quota_test.go b/x/uibc/quota/keeper/quota_test.go index 246dfdff2d..27a608810d 100644 --- a/x/uibc/quota/keeper/quota_test.go +++ b/x/uibc/quota/keeper/quota_test.go @@ -8,6 +8,7 @@ import ( "gotest.tools/v3/assert" ibcutil "github.com/umee-network/umee/v6/util/ibc" + "github.com/umee-network/umee/v6/x/uibc" ) func TestUnitGetQuotas(t *testing.T) { @@ -100,6 +101,46 @@ func TestUnitCheckAndUpdateQuota(t *testing.T) { err = k.CheckAndUpdateQuota(umee, sdk.NewInt(2)) // exceeds token quota assert.ErrorContains(t, err, "quota") + + // Checking ibc outflow quota with ibc inflows + dp := uibc.DefaultParams() + dp.TotalQuota = sdk.NewDec(200) + dp.TokenQuota = sdk.NewDec(500) + dp.InflowOutflowQuotaTokenBase = sdk.NewDec(100) + err = k.SetParams(dp) + assert.NilError(t, err) + + k.SetTokenOutflow(sdk.NewDecCoin(umee, math.NewInt(80))) + k.SetTokenInflow(sdk.NewDecCoin(umee, math.NewInt(80))) + // 80*2 (160) > InflowOutflowQuotaTokenBase(100) + 25% of Token Inflow (80) = 160 > 100+20 + err = k.CheckAndUpdateQuota(umee, sdk.NewInt(80)) // exceeds token quota + assert.ErrorContains(t, err, "quota") + err = k.CheckAndUpdateQuota(umee, sdk.NewInt(5)) + assert.NilError(t, err) + + // Unlimited token quota but limit the total outflow + dp.TokenQuota = sdk.NewDec(0) + dp.InflowOutflowQuotaBase = sdk.NewDec(100) + dp.TotalQuota = sdk.NewDec(100) + err = k.SetParams(dp) + k.SetTotalOutflowSum(sdk.NewDec(80)) + // 80+(20*2) > Total Outflow Quota Limit (100) + err = k.CheckAndUpdateQuota(umee, sdk.NewInt(20)) // exceeds token quota + assert.ErrorContains(t, err, "quota") + err = k.CheckAndUpdateQuota(umee, sdk.NewInt(10)) + assert.NilError(t, err) + + k.ResetAllQuotas() + + err = k.SetParams(dp) + assert.NilError(t, err) + k.SetTotalInflow(sdk.NewDec(100)) + // 80+(80*2) > InflowOutflowQuotaBase(100) + 25% of Total Inflow Sum (100) = 240 > 100+25 + err = k.CheckAndUpdateQuota(umee, sdk.NewInt(80)) // exceeds token quota + assert.ErrorContains(t, err, "quota") + // 80+(5*2) > InflowOutflowQuotaBase(100) + 25% of Total Inflow Sum (100) = 90 < 100+25 + err = k.CheckAndUpdateQuota(umee, sdk.NewInt(5)) + assert.NilError(t, err) } func TestUnitGetExchangePrice(t *testing.T) { diff --git a/x/uibc/quota/keeper/unit_test.go b/x/uibc/quota/keeper/unit_test.go index a697e14af9..d31d6e398e 100644 --- a/x/uibc/quota/keeper/unit_test.go +++ b/x/uibc/quota/keeper/unit_test.go @@ -53,11 +53,9 @@ func (k TestKeeper) checkOutflows(denom string, perToken, total int64) { } func (k TestKeeper) setQuotaParams(perToken, total int64) { - err := k.SetParams(uibc.Params{ - TokenQuota: sdk.NewDec(perToken), - TotalQuota: sdk.NewDec(total), - InflowOutflowQuotaBase: sdk.NewDec(1_000_000), - InflowOutflowQuotaTokenBase: sdk.NewDec(9_00_000), - }) + dp := uibc.DefaultParams() + dp.TokenQuota = sdk.NewDec(perToken) + dp.TotalQuota = sdk.NewDec(total) + err := k.SetParams(dp) require.NoError(k.t, err) } From d90b4009e7ba8df0378de4e60d6f59b7027019dd Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Tue, 14 Nov 2023 23:30:38 +0530 Subject: [PATCH 15/18] refactored GetAllInflows and GetAllOutflows funs --- util/store/iter.go | 25 +++++++++++++++++++++++ util/store/store.go | 4 ++-- x/uibc/genesis.pb.go | 2 +- x/uibc/quota/keeper/keys.go | 6 ------ x/uibc/quota/keeper/migrations.go | 6 +++--- x/uibc/quota/keeper/mocks_test.go | 2 +- x/uibc/quota/keeper/quota.go | 33 ++++++------------------------- 7 files changed, 38 insertions(+), 40 deletions(-) diff --git a/util/store/iter.go b/util/store/iter.go index db789a001d..ae30935eb8 100644 --- a/util/store/iter.go +++ b/util/store/iter.go @@ -80,3 +80,28 @@ func SumCoins(s storetypes.KVStore, f StrExtractor) sdk.Coins { // StrExtractor is a function type which will take a bytes string value and extracts // string out of it. type StrExtractor func([]byte) string + +// LoadAllDecCoins iterates over all records in the prefix store and unmarshals value into the dec coin list. +func LoadAllDecCoins(iter db.Iterator, prefixLen int) (sdk.DecCoins, error) { + var coins sdk.DecCoins + cb := func(key, val []byte) error { + o := sdk.DecCoin{Denom: rmPrefix(key, prefixLen)} + if err := o.Amount.Unmarshal(val); err != nil { + return err + } + coins = append(coins, o) + return nil + } + + if err := iterate(iter, cb); err != nil { + return nil, err + } + + return coins, nil +} + +// rmPrefix extracts denom from a key with the form +// prefix | denom +func rmPrefix(key []byte, prefixLen int) string { + return string(key[prefixLen:]) +} diff --git a/util/store/store.go b/util/store/store.go index 9aeb181c50..06e37f590c 100644 --- a/util/store/store.go +++ b/util/store/store.go @@ -210,8 +210,8 @@ func GetInteger[T Integer](store sdk.KVStore, key []byte) (T, bool) { panic("not possible: all types must be covered above") } -// DeleteByPrefixStoreIterator will delete all keys stored in prefix store -func DeleteByPrefixStoreIterator(store sdk.KVStore) { +// DeleteByPrefixStore will delete all keys stored in prefix store +func DeleteByPrefixStore(store sdk.KVStore) { iter := sdk.KVStorePrefixIterator(store, nil) defer iter.Close() for ; iter.Valid(); iter.Next() { diff --git a/x/uibc/genesis.pb.go b/x/uibc/genesis.pb.go index 3b373b4f1d..5c2f1d014e 100644 --- a/x/uibc/genesis.pb.go +++ b/x/uibc/genesis.pb.go @@ -38,7 +38,7 @@ type GenesisState struct { TotalOutflowSum github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=total_outflow_sum,json=totalOutflowSum,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_outflow_sum"` // quota_expires defines quota expire time (as unix timestamp) for ibc-transfer denom. QuotaExpires time.Time `protobuf:"bytes,4,opt,name=quota_expires,json=quotaExpires,proto3,stdtime" json:"quota_duration,omitempty" yaml:"quota_expires"` - // inflows tracks IBC inflow transfers (in USD) during quota period. + // inflows tracks IBC inflow transfers (in USD) for each denom during quota period. Inflows github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,5,rep,name=inflows,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"inflows"` // total_inflow_sum defines tracks total sum of IBC inflow transfers (in USD) during quota period. TotalInflowSum github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=total_inflow_sum,json=totalInflowSum,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_inflow_sum"` diff --git a/x/uibc/quota/keeper/keys.go b/x/uibc/quota/keeper/keys.go index 6a45001c6a..5867c8cb9d 100644 --- a/x/uibc/quota/keeper/keys.go +++ b/x/uibc/quota/keeper/keys.go @@ -22,9 +22,3 @@ func keyTokenInflow(ibcDenom string) []byte { // keyPrefixDenomInflows | denom return util.ConcatBytes(0, keyPrefixDenomInflows, []byte(ibcDenom)) } - -// denomFromKey extracts denom from a key with the form -// prefix | denom -func denomFromKey(key, prefix []byte) string { - return string(key[len(prefix):]) -} diff --git a/x/uibc/quota/keeper/migrations.go b/x/uibc/quota/keeper/migrations.go index ef2b866ea3..d1bf8d9b8f 100644 --- a/x/uibc/quota/keeper/migrations.go +++ b/x/uibc/quota/keeper/migrations.go @@ -2,9 +2,9 @@ package keeper import sdk "github.com/cosmos/cosmos-sdk/types" -// GetOldTotalOutflow returns the total outflow of ibc-transfer amount. +// getOldTotalOutflow returns the total outflow of ibc-transfer amount. // Note: only use for v6.2 migration from v6.1.0 -func (k Keeper) GetOldTotalOutflow() sdk.Dec { +func (k Keeper) getOldTotalOutflow() sdk.Dec { bz := k.store.Get(keyTotalOutflows) return sdk.MustNewDecFromStr(string(bz)) } @@ -12,6 +12,6 @@ func (k Keeper) GetOldTotalOutflow() sdk.Dec { // MigrateTotalOutflowSum migrate the old total outflow type to new one // Note: only use for v6.2 migration from v6.1.0 func (k Keeper) MigrateTotalOutflowSum() { - oldTotalOutflow := k.GetOldTotalOutflow() + oldTotalOutflow := k.getOldTotalOutflow() k.SetTotalOutflowSum(oldTotalOutflow) } diff --git a/x/uibc/quota/keeper/mocks_test.go b/x/uibc/quota/keeper/mocks_test.go index 14e76b6225..bf16448878 100644 --- a/x/uibc/quota/keeper/mocks_test.go +++ b/x/uibc/quota/keeper/mocks_test.go @@ -49,7 +49,7 @@ func (o Oracle) Price(_ sdk.Context, denom string) (sdk.Dec, error) { p, ok := o.prices[denom] if !ok { // When token exists in leverage registry but price is not found we are returning `0` - // https://github.com/umee-network/umee/tree/main/x/oracle/keeper/historic_avg.go#L126 + // https: //github.com/umee-network/umee/blob/v6.1.0/x/oracle/keeper/historic_avg.go#L126 return sdk.ZeroDec(), nil } return p, nil diff --git a/x/uibc/quota/keeper/quota.go b/x/uibc/quota/keeper/quota.go index ae67ca9fad..b02ff66531 100644 --- a/x/uibc/quota/keeper/quota.go +++ b/x/uibc/quota/keeper/quota.go @@ -21,18 +21,8 @@ var ten = sdk.MustNewDecFromStr("10") // GetAllOutflows returns sum of outflows of all tokens in USD value. func (k Keeper) GetAllOutflows() (sdk.DecCoins, error) { - var outflows sdk.DecCoins - cb := func(key, val []byte) error { - o := sdk.DecCoin{Denom: denomFromKey(key, keyPrefixDenomOutflows)} - if err := o.Amount.Unmarshal(val); err != nil { - return err - } - outflows = append(outflows, o) - return nil - } - - err := store.Iterate(k.store, keyPrefixDenomOutflows, cb) - return outflows, err + iter := sdk.KVStorePrefixIterator(k.store, keyPrefixDenomOutflows) + return store.LoadAllDecCoins(iter, len(keyPrefixDenomOutflows)) } // GetTokenOutflows returns sum of denom outflows in USD value in the DecCoin structure. @@ -72,19 +62,8 @@ func (k Keeper) SetTokenOutflow(outflow sdk.DecCoin) { // GetAllInflows returns inflows of all registered tokens in USD value. func (k Keeper) GetAllInflows() (sdk.DecCoins, error) { - var inflows sdk.DecCoins - cb := func(key, val []byte) error { - o := sdk.DecCoin{Denom: denomFromKey(key, keyPrefixDenomInflows)} - if err := o.Amount.Unmarshal(val); err != nil { - k.ctx.Logger().Error("error while unmarshal the ibc inflow for denom", "denom", o.Denom, - "amount", o.Amount.String()) - return err - } - inflows = append(inflows, o) - return nil - } - err := store.Iterate(k.store, keyPrefixDenomInflows, cb) - return inflows, err + iter := sdk.KVStorePrefixIterator(k.store, keyPrefixDenomInflows) + return store.LoadAllDecCoins(iter, len(keyPrefixDenomInflows)) } // SetTokenInflows saves provided updated IBC inflows as a pair: USD value, denom name in the @@ -144,12 +123,12 @@ func (k Keeper) ResetAllQuotas() error { // outflows k.SetTotalOutflowSum(zero) ps := k.PrefixStore(keyPrefixDenomOutflows) - store.DeleteByPrefixStoreIterator(ps) + store.DeleteByPrefixStore(ps) // inflows k.SetTotalInflow(zero) ps = k.PrefixStore(keyPrefixDenomInflows) - store.DeleteByPrefixStoreIterator(ps) + store.DeleteByPrefixStore(ps) return nil } From 4d3c2785ab6c9a4e0818ff4b8a5f5b86f4896abb Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Tue, 14 Nov 2023 19:53:38 +0100 Subject: [PATCH 16/18] Update util/store/iter.go --- util/store/iter.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/util/store/iter.go b/util/store/iter.go index ae30935eb8..e4cc9cb0d1 100644 --- a/util/store/iter.go +++ b/util/store/iter.go @@ -85,7 +85,7 @@ type StrExtractor func([]byte) string func LoadAllDecCoins(iter db.Iterator, prefixLen int) (sdk.DecCoins, error) { var coins sdk.DecCoins cb := func(key, val []byte) error { - o := sdk.DecCoin{Denom: rmPrefix(key, prefixLen)} + o := sdk.DecCoin{Denom: string(key[prefixLen:])} if err := o.Amount.Unmarshal(val); err != nil { return err } @@ -96,12 +96,5 @@ func LoadAllDecCoins(iter db.Iterator, prefixLen int) (sdk.DecCoins, error) { if err := iterate(iter, cb); err != nil { return nil, err } - return coins, nil } - -// rmPrefix extracts denom from a key with the form -// prefix | denom -func rmPrefix(key []byte, prefixLen int) string { - return string(key[prefixLen:]) -} From 1edf594390ab71cb7d62d20cb0a614771d3efa46 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Wed, 15 Nov 2023 08:31:59 +0530 Subject: [PATCH 17/18] fix the build issue --- app/upgrades.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/upgrades.go b/app/upgrades.go index 2ff3ad7941..47e504e426 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -32,6 +32,7 @@ import ( "github.com/umee-network/umee/v6/util" leveragetypes "github.com/umee-network/umee/v6/x/leverage/types" + "github.com/umee-network/umee/v6/x/uibc" ) // RegisterUpgradeHandlersregisters upgrade handlers. From 19aea15dd6458981e80df56675bc3d8a6b0e0ee5 Mon Sep 17 00:00:00 2001 From: Sai Kumar Date: Wed, 15 Nov 2023 12:05:45 +0530 Subject: [PATCH 18/18] refactor LoadAllDecCoins func --- util/store/iter.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/util/store/iter.go b/util/store/iter.go index e4cc9cb0d1..0260ac3bc3 100644 --- a/util/store/iter.go +++ b/util/store/iter.go @@ -84,17 +84,14 @@ type StrExtractor func([]byte) string // LoadAllDecCoins iterates over all records in the prefix store and unmarshals value into the dec coin list. func LoadAllDecCoins(iter db.Iterator, prefixLen int) (sdk.DecCoins, error) { var coins sdk.DecCoins - cb := func(key, val []byte) error { + for ; iter.Valid(); iter.Next() { + key, val := iter.Key(), iter.Value() o := sdk.DecCoin{Denom: string(key[prefixLen:])} if err := o.Amount.Unmarshal(val); err != nil { - return err + return nil, err } coins = append(coins, o) - return nil } - if err := iterate(iter, cb); err != nil { - return nil, err - } return coins, nil }