feat(x/precisebank): Add FractionalBalance types (#1907)

- Add necessary types to track account fractional balances.
- Add FractionalBalance type to genesis
This commit is contained in:
drklee3 2024-05-13 14:16:05 -07:00 committed by GitHub
parent 3c53e72220
commit 94914d4ca1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 737 additions and 26 deletions

View File

@ -477,6 +477,7 @@
- [Msg](#kava.liquid.v1beta1.Msg) - [Msg](#kava.liquid.v1beta1.Msg)
- [kava/precisebank/v1/genesis.proto](#kava/precisebank/v1/genesis.proto) - [kava/precisebank/v1/genesis.proto](#kava/precisebank/v1/genesis.proto)
- [FractionalBalance](#kava.precisebank.v1.FractionalBalance)
- [GenesisState](#kava.precisebank.v1.GenesisState) - [GenesisState](#kava.precisebank.v1.GenesisState)
- [kava/pricefeed/v1beta1/store.proto](#kava/pricefeed/v1beta1/store.proto) - [kava/pricefeed/v1beta1/store.proto](#kava/pricefeed/v1beta1/store.proto)
@ -6634,12 +6635,33 @@ Msg defines the liquid Msg service.
<a name="kava.precisebank.v1.FractionalBalance"></a>
### FractionalBalance
FractionalBalance defines the fractional portion of an account balance
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `address` | [string](#string) | | address is the address of the balance holder. |
| `amount` | [string](#string) | | amount indicates amount of only the fractional balance owned by the address. FractionalBalance currently only supports tracking 1 single asset, e.g. fractional balances of ukava. |
<a name="kava.precisebank.v1.GenesisState"></a> <a name="kava.precisebank.v1.GenesisState"></a>
### GenesisState ### GenesisState
GenesisState defines the precisebank module's genesis state. GenesisState defines the precisebank module's genesis state.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `balances` | [FractionalBalance](#kava.precisebank.v1.FractionalBalance) | repeated | balances is a list of all the balances in the precisebank module. |

View File

@ -1,7 +1,34 @@
syntax = "proto3"; syntax = "proto3";
package kava.precisebank.v1; package kava.precisebank.v1;
import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";
option go_package = "github.com/kava-labs/kava/x/precisebank/types"; option go_package = "github.com/kava-labs/kava/x/precisebank/types";
// GenesisState defines the precisebank module's genesis state. // GenesisState defines the precisebank module's genesis state.
message GenesisState {} message GenesisState {
// balances is a list of all the balances in the precisebank module.
repeated FractionalBalance balances = 1 [
(gogoproto.castrepeated) = "FractionalBalances",
(gogoproto.nullable) = false
];
}
// FractionalBalance defines the fractional portion of an account balance
message FractionalBalance {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// address is the address of the balance holder.
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// amount indicates amount of only the fractional balance owned by the
// address. FractionalBalance currently only supports tracking 1 single asset,
// e.g. fractional balances of ukava.
string amount = 2 [
(cosmos_proto.scalar) = "cosmos.Int",
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = false
];
}

View File

@ -33,5 +33,5 @@ func InitGenesis(
// ExportGenesis returns a GenesisState for a given context and keeper. // ExportGenesis returns a GenesisState for a given context and keeper.
func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState { func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState {
return types.NewGenesisState() return types.NewGenesisState(nil)
} }

View File

@ -0,0 +1,57 @@
package types
import (
fmt "fmt"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// maxFractionalAmount is the largest valid value in a FractionalBalance amount.
// This is for direct internal use so that there are no extra allocations.
var maxFractionalAmount = sdkmath.NewInt(1_000_000_000_000).SubRaw(1)
// MaxFractionalAmount returns the largest valid value in a FractionalBalance
// amount.
// FractionalBalance contains **only** the fractional balance of an address.
// We want to extend the current KAVA decimal digits from 6 to 18, or in other
// words add 12 fractional digits to ukava.
// With 12 digits, the valid amount is 1 - 999_999_999_999.
func MaxFractionalAmount() sdkmath.Int {
// BigInt() returns a copy of the internal big.Int, so it's safe to directly
// use it for a new Int instead of creating another big.Int internally.
// We need to copy it because the internal value can be accessed and
// modified via Int.BigIntMut()
return sdkmath.NewIntFromBigIntMut(maxFractionalAmount.BigInt())
}
// FractionalBalance returns a new FractionalBalance with the given address and
// amount.
func NewFractionalBalance(address string, amount sdkmath.Int) FractionalBalance {
return FractionalBalance{
Address: address,
Amount: amount,
}
}
// Validate returns an error if the FractionalBalance has an invalid address or
// negative amount.
func (fb FractionalBalance) Validate() error {
if _, err := sdk.AccAddressFromBech32(fb.Address); err != nil {
return err
}
if fb.Amount.IsNil() {
return fmt.Errorf("nil amount")
}
if !fb.Amount.IsPositive() {
return fmt.Errorf("non-positive amount %v", fb.Amount)
}
if fb.Amount.GT(maxFractionalAmount) {
return fmt.Errorf("amount %v exceeds max of %v", fb.Amount, maxFractionalAmount)
}
return nil
}

View File

@ -0,0 +1,164 @@
package types_test
import (
"math/big"
"testing"
sdkmath "cosmossdk.io/math"
"github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/precisebank/types"
"github.com/stretchr/testify/require"
)
func TestMaxFractionalAmount_Immutable(t *testing.T) {
max1 := types.MaxFractionalAmount()
origInt64 := max1.Int64()
// Get the internal pointer to the big.Int without copying
internalBigInt := max1.BigIntMut()
// Mutate the big.Int -- .Add() mutates in place
internalBigInt.Add(internalBigInt, big.NewInt(5))
// Ensure bigInt was actually mutated
require.Equal(t, origInt64+5, internalBigInt.Int64())
// Fetch the max amount again
max2 := types.MaxFractionalAmount()
require.Equal(
t,
origInt64,
max2.Int64(),
"max amount should be immutable",
)
}
func TestMaxFractionalAmount_Copied(t *testing.T) {
max1 := types.MaxFractionalAmount().BigIntMut()
max2 := types.MaxFractionalAmount().BigIntMut()
// Checks that the returned two pointers do not reference the same object
require.NotSame(t, max1, max2, "max fractional amount should be copied")
}
func TestNewFractionalBalance(t *testing.T) {
tests := []struct {
name string
giveAddress string
giveAmount sdkmath.Int
}{
{
"correctly sets fields",
"cosmos1qperwt9wrnkg5k9e5gzfgjppzpqur82k6c5a0n",
sdkmath.NewInt(100),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fb := types.NewFractionalBalance(tt.giveAddress, tt.giveAmount)
require.Equal(t, tt.giveAddress, fb.Address)
require.Equal(t, tt.giveAmount, fb.Amount)
})
}
}
func TestFractionalBalance_Validate(t *testing.T) {
app.SetSDKConfig()
tests := []struct {
name string
giveAddress string
giveAmount sdkmath.Int
wantErr string
}{
{
"valid",
"kava1gpxd677pp8zr97xvy3pmgk70a9vcpagsakv0tx",
sdkmath.NewInt(100),
"",
},
{
"valid - uppercase address",
"KAVA1GPXD677PP8ZR97XVY3PMGK70A9VCPAGSAKV0TX",
sdkmath.NewInt(100),
"",
},
{
"valid - min balance",
"kava1gpxd677pp8zr97xvy3pmgk70a9vcpagsakv0tx",
sdkmath.NewInt(1),
"",
},
{
"valid - max balance",
"kava1gpxd677pp8zr97xvy3pmgk70a9vcpagsakv0tx",
types.MaxFractionalAmount(),
"",
},
{
"invalid - 0 balance",
"kava1gpxd677pp8zr97xvy3pmgk70a9vcpagsakv0tx",
sdkmath.NewInt(0),
"non-positive amount 0",
},
{
"invalid - empty",
"kava1gpxd677pp8zr97xvy3pmgk70a9vcpagsakv0tx",
sdkmath.Int{},
"nil amount",
},
{
"invalid - mixed case address",
"kava1gpxd677pP8zr97xvy3pmgk70a9vcpagsakv0tx",
sdkmath.NewInt(100),
"decoding bech32 failed: string not all lowercase or all uppercase",
},
{
"invalid - non-bech32 address",
"invalid",
sdkmath.NewInt(100),
"decoding bech32 failed: invalid bech32 string length 7",
},
{
"invalid - wrong bech32 prefix",
"cosmos1qperwt9wrnkg5k9e5gzfgjppzpqur82k7gqd8n",
sdkmath.NewInt(100),
"invalid Bech32 prefix; expected kava, got cosmos",
},
{
"invalid - negative amount",
"kava1gpxd677pp8zr97xvy3pmgk70a9vcpagsakv0tx",
sdkmath.NewInt(-100),
"non-positive amount -100",
},
{
"invalid - max amount + 1",
"kava1gpxd677pp8zr97xvy3pmgk70a9vcpagsakv0tx",
types.MaxFractionalAmount().AddRaw(1),
"amount 1000000000000 exceeds max of 999999999999",
},
{
"invalid - much more than max amount",
"kava1gpxd677pp8zr97xvy3pmgk70a9vcpagsakv0tx",
sdkmath.NewInt(100000000000_000),
"amount 100000000000000 exceeds max of 999999999999",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fb := types.NewFractionalBalance(tt.giveAddress, tt.giveAmount)
err := fb.Validate()
if tt.wantErr == "" {
require.NoError(t, err)
return
}
require.Error(t, err)
require.EqualError(t, err, tt.wantErr)
})
}
}

View File

@ -0,0 +1,35 @@
package types
import (
fmt "fmt"
"strings"
)
// FractionalBalances is a slice of FractionalBalance
type FractionalBalances []FractionalBalance
// Validate returns an error if any FractionalBalance in the slice is invalid.
func (fbs FractionalBalances) Validate() error {
seenAddresses := make(map[string]struct{})
for _, fb := range fbs {
// Individual FractionalBalance validation
if err := fb.Validate(); err != nil {
return fmt.Errorf("invalid fractional balance for %s: %w", fb.Address, err)
}
// Make addresses all lowercase for unique check, as ALL UPPER is also
// a valid address.
lowerAddr := strings.ToLower(fb.Address)
// If this is a duplicate address, return an error
if _, found := seenAddresses[lowerAddr]; found {
return fmt.Errorf("duplicate address %v", lowerAddr)
}
// Mark it as seen
seenAddresses[lowerAddr] = struct{}{}
}
return nil
}

View File

@ -0,0 +1,86 @@
package types_test
import (
"strings"
"testing"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/precisebank/types"
"github.com/stretchr/testify/require"
)
func TestFractionalBalances_Validate(t *testing.T) {
app.SetSDKConfig()
tests := []struct {
name string
fbs types.FractionalBalances
wantErr string
}{
{
"valid - empty",
types.FractionalBalances{},
"",
},
{
"valid - nil",
nil,
"",
},
{
"valid - multiple balances",
types.FractionalBalances{
types.NewFractionalBalance(sdk.AccAddress{1}.String(), sdkmath.NewInt(100)),
types.NewFractionalBalance(sdk.AccAddress{2}.String(), sdkmath.NewInt(100)),
types.NewFractionalBalance(sdk.AccAddress{3}.String(), sdkmath.NewInt(100)),
},
"",
},
{
"invalid - single invalid balance",
types.FractionalBalances{
types.NewFractionalBalance(sdk.AccAddress{1}.String(), sdkmath.NewInt(100)),
types.NewFractionalBalance(sdk.AccAddress{2}.String(), sdkmath.NewInt(-1)),
types.NewFractionalBalance(sdk.AccAddress{3}.String(), sdkmath.NewInt(100)),
},
"invalid fractional balance for kava1qg7c45n6: non-positive amount -1",
},
{
"invalid - duplicate address",
types.FractionalBalances{
types.NewFractionalBalance(sdk.AccAddress{1}.String(), sdkmath.NewInt(100)),
types.NewFractionalBalance(sdk.AccAddress{1}.String(), sdkmath.NewInt(100)),
},
"duplicate address kava1qy0xn7za",
},
{
"invalid - duplicate address upper/lower case",
types.FractionalBalances{
types.NewFractionalBalance(
strings.ToLower(sdk.AccAddress{1}.String()),
sdkmath.NewInt(100),
),
types.NewFractionalBalance(
strings.ToUpper(sdk.AccAddress{1}.String()),
sdkmath.NewInt(100),
),
},
"duplicate address kava1qy0xn7za",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.fbs.Validate()
if tt.wantErr == "" {
require.NoError(t, err)
return
}
require.Error(t, err)
require.EqualError(t, err, tt.wantErr)
})
}
}

View File

@ -1,17 +1,30 @@
package types package types
// Validate performs basic validation of supply genesis data returning an import "fmt"
// error for any failed validation criteria.
// Validate performs basic validation of genesis data returning an error for
// any failed validation criteria.
func (gs *GenesisState) Validate() error { func (gs *GenesisState) Validate() error {
if err := gs.Balances.Validate(); err != nil {
return fmt.Errorf("invalid balances: %w", err)
}
// TODO:
// - Validate remainder amount
// - Validate sum(fractionalBalances) + remainder = whole integer value
// - Cannot validate here: reserve account exists & balance match
return nil return nil
} }
// NewGenesisState creates a new genesis state. // NewGenesisState creates a new genesis state.
func NewGenesisState() *GenesisState { func NewGenesisState(balances FractionalBalances) *GenesisState {
return &GenesisState{} return &GenesisState{
Balances: balances,
}
} }
// DefaultGenesisState returns a default genesis state. // DefaultGenesisState returns a default genesis state.
func DefaultGenesisState() *GenesisState { func DefaultGenesisState() *GenesisState {
return NewGenesisState() return NewGenesisState(FractionalBalances{})
} }

View File

@ -4,7 +4,10 @@
package types package types
import ( import (
cosmossdk_io_math "cosmossdk.io/math"
fmt "fmt" fmt "fmt"
_ "github.com/cosmos/cosmos-proto"
_ "github.com/cosmos/gogoproto/gogoproto"
proto "github.com/cosmos/gogoproto/proto" proto "github.com/cosmos/gogoproto/proto"
io "io" io "io"
math "math" math "math"
@ -24,6 +27,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// GenesisState defines the precisebank module's genesis state. // GenesisState defines the precisebank module's genesis state.
type GenesisState struct { type GenesisState struct {
// balances is a list of all the balances in the precisebank module.
Balances FractionalBalances `protobuf:"bytes,1,rep,name=balances,proto3,castrepeated=FractionalBalances" json:"balances"`
} }
func (m *GenesisState) Reset() { *m = GenesisState{} } func (m *GenesisState) Reset() { *m = GenesisState{} }
@ -59,24 +64,86 @@ func (m *GenesisState) XXX_DiscardUnknown() {
var xxx_messageInfo_GenesisState proto.InternalMessageInfo var xxx_messageInfo_GenesisState proto.InternalMessageInfo
func (m *GenesisState) GetBalances() FractionalBalances {
if m != nil {
return m.Balances
}
return nil
}
// FractionalBalance defines the fractional portion of an account balance
type FractionalBalance struct {
// address is the address of the balance holder.
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
// amount indicates amount of only the fractional balance owned by the
// address. FractionalBalance currently only supports tracking 1 single asset,
// e.g. fractional balances of ukava.
Amount cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=amount,proto3,customtype=cosmossdk.io/math.Int" json:"amount"`
}
func (m *FractionalBalance) Reset() { *m = FractionalBalance{} }
func (m *FractionalBalance) String() string { return proto.CompactTextString(m) }
func (*FractionalBalance) ProtoMessage() {}
func (*FractionalBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_7f1c47a86fb0d2e0, []int{1}
}
func (m *FractionalBalance) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *FractionalBalance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_FractionalBalance.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *FractionalBalance) XXX_Merge(src proto.Message) {
xxx_messageInfo_FractionalBalance.Merge(m, src)
}
func (m *FractionalBalance) XXX_Size() int {
return m.Size()
}
func (m *FractionalBalance) XXX_DiscardUnknown() {
xxx_messageInfo_FractionalBalance.DiscardUnknown(m)
}
var xxx_messageInfo_FractionalBalance proto.InternalMessageInfo
func init() { func init() {
proto.RegisterType((*GenesisState)(nil), "kava.precisebank.v1.GenesisState") proto.RegisterType((*GenesisState)(nil), "kava.precisebank.v1.GenesisState")
proto.RegisterType((*FractionalBalance)(nil), "kava.precisebank.v1.FractionalBalance")
} }
func init() { proto.RegisterFile("kava/precisebank/v1/genesis.proto", fileDescriptor_7f1c47a86fb0d2e0) } func init() { proto.RegisterFile("kava/precisebank/v1/genesis.proto", fileDescriptor_7f1c47a86fb0d2e0) }
var fileDescriptor_7f1c47a86fb0d2e0 = []byte{ var fileDescriptor_7f1c47a86fb0d2e0 = []byte{
// 145 bytes of a gzipped FileDescriptorProto // 331 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xcc, 0x4e, 0x2c, 0x4b, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xcc, 0x4e, 0x2c, 0x4b,
0xd4, 0x2f, 0x28, 0x4a, 0x4d, 0xce, 0x2c, 0x4e, 0x4d, 0x4a, 0xcc, 0xcb, 0xd6, 0x2f, 0x33, 0xd4, 0xd4, 0x2f, 0x28, 0x4a, 0x4d, 0xce, 0x2c, 0x4e, 0x4d, 0x4a, 0xcc, 0xcb, 0xd6, 0x2f, 0x33, 0xd4,
0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x06, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x06,
0x29, 0xd1, 0x43, 0x52, 0xa2, 0x57, 0x66, 0xa8, 0xc4, 0xc7, 0xc5, 0xe3, 0x0e, 0x51, 0x15, 0x5c, 0x29, 0xd1, 0x43, 0x52, 0xa2, 0x57, 0x66, 0x28, 0x25, 0x99, 0x9c, 0x5f, 0x9c, 0x9b, 0x5f, 0x1c,
0x92, 0x58, 0x92, 0xea, 0xe4, 0x7e, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0x0f, 0x56, 0xa2, 0x0f, 0xe1, 0x40, 0xd4, 0x4b, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x43, 0xc4, 0x41,
0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x2c, 0x88, 0xa8, 0x52, 0x1e, 0x17, 0x8f, 0x3b, 0xc4, 0xd8, 0xe0, 0x92, 0xc4, 0x92, 0x54, 0xa1,
0xba, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x20, 0x93, 0x74, 0x73, 0x38, 0x2e, 0x8e, 0xa4, 0xc4, 0x9c, 0xc4, 0xbc, 0xe4, 0xd4, 0x62, 0x09, 0x46, 0x05, 0x66, 0x0d,
0x12, 0x93, 0x8a, 0xc1, 0x2c, 0xfd, 0x0a, 0x14, 0x8b, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0x6e, 0x23, 0x35, 0x3d, 0x2c, 0x16, 0xe9, 0xb9, 0x15, 0x25, 0x26, 0x97, 0x64, 0xe6, 0xe7, 0x25,
0xc0, 0x96, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x51, 0x07, 0x09, 0x29, 0x99, 0x00, 0x00, 0xe6, 0x38, 0x41, 0x94, 0x3b, 0x49, 0x9d, 0xb8, 0x27, 0xcf, 0xb0, 0xea, 0xbe, 0xbc, 0x10, 0x86,
0x00, 0x54, 0x71, 0x10, 0xdc, 0x4c, 0xa5, 0x69, 0x8c, 0x5c, 0x82, 0x18, 0x0a, 0x84, 0x8c, 0xb8, 0xd8,
0x13, 0x53, 0x52, 0x8a, 0x52, 0x8b, 0x41, 0x96, 0x32, 0x6a, 0x70, 0x3a, 0x49, 0x5c, 0xda, 0xa2,
0x2b, 0x02, 0x75, 0xbe, 0x23, 0x44, 0x26, 0xb8, 0xa4, 0x28, 0x33, 0x2f, 0x3d, 0x08, 0xa6, 0x50,
0xc8, 0x99, 0x8b, 0x2d, 0x31, 0x37, 0xbf, 0x34, 0xaf, 0x44, 0x82, 0x09, 0xac, 0x45, 0x1b, 0x64,
0xff, 0xad, 0x7b, 0xf2, 0xa2, 0x10, 0x6d, 0xc5, 0x29, 0xd9, 0x7a, 0x99, 0xf9, 0xfa, 0xb9, 0x89,
0x25, 0x19, 0x7a, 0x9e, 0x79, 0x25, 0x97, 0xb6, 0xe8, 0x72, 0x41, 0xcd, 0xf3, 0xcc, 0x2b, 0x09,
0x82, 0x6a, 0xb5, 0xe2, 0xe8, 0x58, 0x20, 0xcf, 0xf0, 0x62, 0x81, 0x3c, 0x83, 0x93, 0xfb, 0x89,
0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3,
0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0xe9, 0xa6, 0x67, 0x96, 0x64, 0x94, 0x26,
0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x83, 0x82, 0x42, 0x37, 0x27, 0x31, 0xa9, 0x18, 0xcc, 0xd2, 0xaf,
0x40, 0x89, 0xa2, 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, 0x70, 0xc0, 0x1a, 0x03, 0x02, 0x00,
0x00, 0xff, 0xff, 0xf4, 0x2e, 0xbf, 0x96, 0xc3, 0x01, 0x00, 0x00,
} }
func (m *GenesisState) Marshal() (dAtA []byte, err error) { func (m *GenesisState) Marshal() (dAtA []byte, err error) {
@ -99,6 +166,60 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i _ = i
var l int var l int
_ = l _ = l
if len(m.Balances) > 0 {
for iNdEx := len(m.Balances) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.Balances[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func (m *FractionalBalance) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *FractionalBalance) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *FractionalBalance) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
{
size := m.Amount.Size()
i -= size
if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
if len(m.Address) > 0 {
i -= len(m.Address)
copy(dAtA[i:], m.Address)
i = encodeVarintGenesis(dAtA, i, uint64(len(m.Address)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil return len(dAtA) - i, nil
} }
@ -119,6 +240,27 @@ func (m *GenesisState) Size() (n int) {
} }
var l int var l int
_ = l _ = l
if len(m.Balances) > 0 {
for _, e := range m.Balances {
l = e.Size()
n += 1 + l + sovGenesis(uint64(l))
}
}
return n
}
func (m *FractionalBalance) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Address)
if l > 0 {
n += 1 + l + sovGenesis(uint64(l))
}
l = m.Amount.Size()
n += 1 + l + sovGenesis(uint64(l))
return n return n
} }
@ -157,6 +299,156 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error {
return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire)
} }
switch fieldNum { switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Balances", 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.Balances = append(m.Balances, FractionalBalance{})
if err := m.Balances[len(m.Balances)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *FractionalBalance) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: FractionalBalance: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: FractionalBalance: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Address", 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
}
m.Address = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Amount", 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.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:]) skippy, err := skipGenesis(dAtA[iNdEx:])

View File

@ -3,6 +3,8 @@ package types_test
import ( import (
"testing" "testing"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/precisebank/types" "github.com/kava-labs/kava/x/precisebank/types"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -10,26 +12,39 @@ import (
func TestGenesisStateValidate(t *testing.T) { func TestGenesisStateValidate(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
genesisState types.GenesisState genesisState *types.GenesisState
expErr bool expErr bool
}{ }{
{ {
"empty genesisState", "empty genesisState",
types.GenesisState{}, &types.GenesisState{},
false, false,
}, },
{ {
"valid genesisState", "valid genesisState - nil",
// TODO: Fill out fields types.NewGenesisState(nil),
types.GenesisState{},
false, false,
}, },
// TODO: Sum of balances does not equal an integer amount {
// { "invalid - calls (single) FractionalBalance.Validate()",
// "invalid balances", types.NewGenesisState(
// types.GenesisState{}, types.FractionalBalances{
// true, types.NewFractionalBalance(sdk.AccAddress{1}.String(), sdkmath.NewInt(1)),
// }, types.NewFractionalBalance(sdk.AccAddress{2}.String(), sdkmath.NewInt(-1)),
},
),
true,
},
{
"invalid - calls (multi) FractionalBalances.Validate()",
types.NewGenesisState(
types.FractionalBalances{
types.NewFractionalBalance(sdk.AccAddress{1}.String(), sdkmath.NewInt(1)),
types.NewFractionalBalance(sdk.AccAddress{1}.String(), sdkmath.NewInt(1)),
},
),
true,
},
} }
for _, tc := range testCases { for _, tc := range testCases {