Skip to content

Commit

Permalink
feat(sponsorship): added types package
Browse files Browse the repository at this point in the history
  • Loading branch information
keruch committed Jul 17, 2024
1 parent c428b5f commit 8867d60
Show file tree
Hide file tree
Showing 16 changed files with 612 additions and 57 deletions.
43 changes: 25 additions & 18 deletions x/sponsorship/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,24 @@ func GetTxCmd() *cobra.Command {

func CmdVote() *cobra.Command {
cmd := &cobra.Command{
Use: "vote [gauges] --from <voter>",
Use: "vote [gauge-weights] --from <voter>",
Short: "Submit a vote for gauges",
Example: "dymd tx sponsorship vote gauge1=30,gauge2=40,abstain=30",
Args: cobra.ExactArgs(2),
Example: "dymd tx sponsorship vote gauge1=30,gauge2=40,abstain=30 --from my_validator",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

weights, err := ParseGaugeWeights(args[0])
if err != nil {
return fmt.Errorf("invalid gauge weights: %w", err)
}

msg := types.MsgVote{
Voter: clientCtx.GetFromAddress().String(),
Weights: nil,
Weights: weights,
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
Expand All @@ -55,43 +61,44 @@ func CmdVote() *cobra.Command {
return cmd
}

func ParseGaugeWeights(weights string) ([]types.GaugeWeight, error) {
var result []types.GaugeWeight
pairs := strings.Split(weights, ",")
func ParseGaugeWeights(inputWeights string) ([]types.GaugeWeight, error) {
if inputWeights == "" {
return nil, fmt.Errorf("input weights must not be empty")
}

var totalWeight int
var weights []types.GaugeWeight
pairs := strings.Split(inputWeights, ",")

for _, pair := range pairs {
idValue := strings.Split(pair, ":")
if len(idValue) != 2 {
return nil, fmt.Errorf("invalid input")
return nil, fmt.Errorf("invalid gauge weight format: %s", pair)
}

gaugeID, err := strconv.ParseUint(idValue[0], 10, 64)
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid gauge ID '%s': %w", idValue[0], err)
}

weight, err := strconv.Atoi(idValue[1])
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid gauge weight '%s': %w", idValue[1], err)
}

if weight < 0 || weight > 100 {
return nil, fmt.Errorf("weight must be between 0 and 100")
return nil, fmt.Errorf("weight must be between 0 and 100, got %d", weight)
}

totalWeight += weight

result = append(result, types.GaugeWeight{
weights = append(weights, types.GaugeWeight{
GaugeId: gaugeID,
Weight: math.NewInt(int64(weight)),
})
}

if totalWeight != 100 {
return nil, fmt.Errorf("sum of all weights must be 100, got %d", totalWeight)
err := types.ValidateGaugeWeights(weights)
if err != nil {
return nil, fmt.Errorf("invalid gauge weights: %w", err)
}

return result, nil
return weights, nil
}
79 changes: 55 additions & 24 deletions x/sponsorship/client/cli/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,82 @@ import (
"github.com/dymensionxyz/dymension/v3/x/sponsorship/types"
)

func TestParse(t *testing.T) {
func TestParseGaugeWeights(t *testing.T) {
tests := []struct {
name string
input string
expected []types.GaugeWeight
expectedErr error
name string
input string
expected []types.GaugeWeight
expectError bool
errorContains string
}{
{
name: "Valid input",
input: "15:60,10:70,12:10",
input: "15:60,10:30,12:10",
expected: []types.GaugeWeight{
{GaugeId: 15, Weight: math.NewInt(60)},
{GaugeId: 10, Weight: math.NewInt(30)},
{GaugeId: 12, Weight: math.NewInt(10)},
},
expectedErr: false,
expectError: false,
errorContains: "",
},
{
name: "Invalid input",
input: "15,10:70,12:10",
expected: nil,
expectedErr: true,
name: "Invalid input format",
input: "15,10:70,12:10",
expected: nil,
expectError: true,
errorContains: "invalid gauge weight format",
},
{
name: "Value out of range",
input: "15:101,10:70,12:10",
expected: nil,
expectedErr: true,
name: "Weight > 100",
input: "15:101,10:70,12:10",
expected: nil,
expectError: true,
errorContains: "weight must be between 0 and 100",
},
{
name: "Empty input",
input: "",
expected: nil,
expectedErr: true,
name: "Weight < 0",
input: "15:-10,10:70,12:10",
expected: nil,
expectError: true,
errorContains: "weight must be between 0 and 100",
},
{
name: "Sum of weighs > 100",
input: "15:30,10:30,12:41",
expected: nil,
expectError: true,
errorContains: "invalid gauge weights",
},
{
name: "Sum of weighs < 100",
input: "15:30,10:30,12:39",
expected: nil,
expectError: true,
errorContains: "invalid gauge weights",
},
{
name: "Empty input",
input: "",
expected: nil,
expectError: true,
errorContains: "input weights must not be empty",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := cli.ParseGaugeWeights(tt.input)
if (err != nil) != tt.expectedErr {
t.Errorf("parse() error = %v, expectedErr %v", err, tt.expectedErr)
return
actual, err := cli.ParseGaugeWeights(tt.input)

switch tt.expectError {
case true:
require.Error(t, err)
require.Nil(t, actual)
require.Contains(t, err.Error(), tt.errorContains)
case false:
require.NoError(t, err)
require.Equal(t, tt.expected, actual)
}
require.Equal(t, tt.expected, got)
})
}
}
2 changes: 1 addition & 1 deletion x/sponsorship/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var (
// AppModuleBasic
// ----------------------------------------------------------------------------

// Implements the AppModuleBasic interface for the module.
// AppModuleBasic Implements the module.AppModuleBasic interface for the module.
type AppModuleBasic struct{}

// NewAppModuleBasic creates a new AppModuleBasic struct.
Expand Down
17 changes: 17 additions & 0 deletions x/sponsorship/types/codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package types

import (
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"
)

// RegisterInterfaces registers interfaces types with the interface registry.
func RegisterInterfaces(reg types.InterfaceRegistry) {
reg.RegisterImplementations(
(*sdk.Msg)(nil),
&MsgUpdateParams{},
&MsgVote{},
)
msgservice.RegisterMsgServiceDesc(reg, &_Msg_serviceDesc)
}
12 changes: 12 additions & 0 deletions x/sponsorship/types/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package types

import (
"cosmossdk.io/math"
)

var (
hundred = math.NewInt(100)

DefaultMinAllocationWeight = math.NewInt(10) // 10%
DefaultMinVotingPower = math.NewInt(1)
)
10 changes: 10 additions & 0 deletions x/sponsorship/types/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package types

import errorsmod "cosmossdk.io/errors"

var (
ErrInvalidGaugeWeight = errorsmod.Register(ModuleName, 1, "invalid gauge weight")
ErrInvalidDistribution = errorsmod.Register(ModuleName, 2, "invalid gauge weight distribution")
ErrInvalidParams = errorsmod.Register(ModuleName, 3, "invalid params")
ErrInvalidGenesis = errorsmod.Register(ModuleName, 4, "invalid genesis")
)
1 change: 1 addition & 0 deletions x/sponsorship/types/expected_keepers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package types
15 changes: 15 additions & 0 deletions x/sponsorship/types/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package types

func DefaultGenesis() *GenesisState {
return &GenesisState{
Params: DefaultParams(),
}
}

func (g GenesisState) Validate() error {
err := g.Params.Validate()
if err != nil {
return ErrInvalidGenesis.Wrapf(err.Error())
}
return nil
}
64 changes: 64 additions & 0 deletions x/sponsorship/types/genesis_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package types_test

import (
"testing"

"cosmossdk.io/math"
"github.com/stretchr/testify/require"

"github.com/dymensionxyz/dymension/v3/x/sponsorship/types"
)

func TestGenesis(t *testing.T) {
tests := []struct {
name string
input *types.GenesisState
errorIs error
errorContains string
}{
{
name: "Valid input",
input: &types.GenesisState{
Params: types.Params{
MinAllocationWeight: math.NewInt(20),
MinVotingPower: math.NewInt(20),
},
},
errorIs: nil,
errorContains: "",
},
{
name: "Default is valid",
input: types.DefaultGenesis(),
errorIs: nil,
errorContains: "",
},
{
name: "Invalid params, MinAllocationWeight < 0",
input: &types.GenesisState{
Params: types.Params{
MinAllocationWeight: math.NewInt(-20),
MinVotingPower: math.NewInt(20),
},
},
errorIs: types.ErrInvalidGenesis,
errorContains: "MinAllocationWeight must be >= 0",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.input.Validate()

expectError := tt.errorIs != nil
switch expectError {
case true:
require.Error(t, err)
require.ErrorIs(t, err, tt.errorIs)
require.Contains(t, err.Error(), tt.errorContains)
case false:
require.NoError(t, err)
}
})
}
}
51 changes: 44 additions & 7 deletions x/sponsorship/types/msgs.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,50 @@
package types

import sdk "github.com/cosmos/cosmos-sdk/types"
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

func (m *MsgVote) ValidateBasic() error {
//TODO implement me
panic("implement me")
func (m MsgVote) ValidateBasic() error {
_, err := sdk.AccAddressFromBech32(m.Voter)
if err != nil {
return sdkerrors.ErrInvalidAddress.Wrapf(
"voter '%s' must be a valid bech32 address: %s",
m.Voter, err.Error(),
)
}

err = ValidateGaugeWeights(m.Weights)
if err != nil {
return ErrInvalidDistribution.Wrap(err.Error())
}

return nil
}

func (m MsgVote) GetSigners() []sdk.AccAddress {
signer, _ := sdk.AccAddressFromBech32(m.Voter)
return []sdk.AccAddress{signer}
}

func (m MsgUpdateParams) ValidateBasic() error {
_, err := sdk.AccAddressFromBech32(m.Authority)
if err != nil {
return sdkerrors.ErrInvalidAddress.Wrapf(
"authority '%s' must be a valid bech32 address: %s",
m.Authority, err.Error(),
)
}

err = m.NewParams.Validate()
if err != nil {
return ErrInvalidParams.Wrap(err.Error())
}

return nil
}

func (m *MsgVote) GetSigners() []sdk.AccAddress {
//TODO implement me
panic("implement me")
func (m MsgUpdateParams) GetSigners() []sdk.AccAddress {
signer, _ := sdk.AccAddressFromBech32(m.Authority)
return []sdk.AccAddress{signer}
}
Loading

0 comments on commit 8867d60

Please sign in to comment.