From 03454e4b2213189712a61b30df1091eaff829343 Mon Sep 17 00:00:00 2001 From: Mohammed Affan Date: Mon, 16 Sep 2024 11:58:47 -0400 Subject: [PATCH] [OTE-780] Add client code for affiliates (#2252) --- .../dydxprotocol/affiliates/genesis.ts | 28 +++++-- proto/dydxprotocol/affiliates/genesis.proto | 7 +- .../app/testdata/default_genesis_state.json | 6 +- .../scripts/genesis/sample_pregenesis.json | 8 +- protocol/x/affiliates/client/cli/query.go | 72 ++++++++++++++++++ .../x/affiliates/client/cli/query_test.go | 74 +++++++++++++++++++ protocol/x/affiliates/client/cli/tx.go | 24 ++++++ protocol/x/affiliates/genesis.go | 13 +++- protocol/x/affiliates/keeper/grpc_query.go | 6 +- .../x/affiliates/keeper/grpc_query_test.go | 4 +- protocol/x/affiliates/types/genesis.go | 6 +- protocol/x/affiliates/types/genesis.pb.go | 74 +++++++++++++++++-- protocol/x/revshare/keeper/revshare_test.go | 3 +- 13 files changed, 298 insertions(+), 27 deletions(-) create mode 100644 protocol/x/affiliates/client/cli/query_test.go diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/affiliates/genesis.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/affiliates/genesis.ts index 75fa8edfa3..17ec53fdf6 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/affiliates/genesis.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/affiliates/genesis.ts @@ -1,18 +1,31 @@ +import { AffiliateTiers, AffiliateTiersSDKType } from "./affiliates"; import * as _m0 from "protobufjs/minimal"; import { DeepPartial } from "../../helpers"; /** GenesisState defines generis state of `x/affiliates` */ -export interface GenesisState {} +export interface GenesisState { + /** The list of affiliate tiers */ + affiliateTiers?: AffiliateTiers; +} /** GenesisState defines generis state of `x/affiliates` */ -export interface GenesisStateSDKType {} +export interface GenesisStateSDKType { + /** The list of affiliate tiers */ + affiliate_tiers?: AffiliateTiersSDKType; +} function createBaseGenesisState(): GenesisState { - return {}; + return { + affiliateTiers: undefined + }; } export const GenesisState = { - encode(_: GenesisState, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + encode(message: GenesisState, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.affiliateTiers !== undefined) { + AffiliateTiers.encode(message.affiliateTiers, writer.uint32(10).fork()).ldelim(); + } + return writer; }, @@ -25,6 +38,10 @@ export const GenesisState = { const tag = reader.uint32(); switch (tag >>> 3) { + case 1: + message.affiliateTiers = AffiliateTiers.decode(reader, reader.uint32()); + break; + default: reader.skipType(tag & 7); break; @@ -34,8 +51,9 @@ export const GenesisState = { return message; }, - fromPartial(_: DeepPartial): GenesisState { + fromPartial(object: DeepPartial): GenesisState { const message = createBaseGenesisState(); + message.affiliateTiers = object.affiliateTiers !== undefined && object.affiliateTiers !== null ? AffiliateTiers.fromPartial(object.affiliateTiers) : undefined; return message; } diff --git a/proto/dydxprotocol/affiliates/genesis.proto b/proto/dydxprotocol/affiliates/genesis.proto index 62315d2c44..4dd0dd2291 100644 --- a/proto/dydxprotocol/affiliates/genesis.proto +++ b/proto/dydxprotocol/affiliates/genesis.proto @@ -1,7 +1,12 @@ syntax = "proto3"; package dydxprotocol.affiliates; +import "gogoproto/gogo.proto"; +import "dydxprotocol/affiliates/affiliates.proto"; option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types"; // GenesisState defines generis state of `x/affiliates` -message GenesisState {} \ No newline at end of file +message GenesisState { + // The list of affiliate tiers + AffiliateTiers affiliate_tiers = 1 [ (gogoproto.nullable) = false ]; +} \ No newline at end of file diff --git a/protocol/app/testdata/default_genesis_state.json b/protocol/app/testdata/default_genesis_state.json index 970ae13312..a73a85e96b 100644 --- a/protocol/app/testdata/default_genesis_state.json +++ b/protocol/app/testdata/default_genesis_state.json @@ -13,7 +13,11 @@ } ] }, - "affiliates": {}, + "affiliates": { + "affiliate_tiers": { + "tiers": [] + } + }, "auth": { "params": { "max_memo_characters": "256", diff --git a/protocol/scripts/genesis/sample_pregenesis.json b/protocol/scripts/genesis/sample_pregenesis.json index 5925ef792a..f242459218 100644 --- a/protocol/scripts/genesis/sample_pregenesis.json +++ b/protocol/scripts/genesis/sample_pregenesis.json @@ -2,7 +2,11 @@ "app_hash": null, "app_name": "dydxprotocold", "app_state": { - "affiliates": {}, + "affiliates": { + "affiliate_tiers": { + "tiers": [] + } + }, "assets": { "assets": [ { @@ -3973,7 +3977,7 @@ ] } }, - "app_version": "5.2.1-19-g04197f43", + "app_version": "5.2.1-103-g5c95dd72", "chain_id": "dydx-sample-1", "consensus": { "params": { diff --git a/protocol/x/affiliates/client/cli/query.go b/protocol/x/affiliates/client/cli/query.go index f5145a6c05..872ba5443b 100644 --- a/protocol/x/affiliates/client/cli/query.go +++ b/protocol/x/affiliates/client/cli/query.go @@ -1,6 +1,7 @@ package cli import ( + "context" "fmt" "github.com/spf13/cobra" @@ -20,5 +21,76 @@ func GetQueryCmd(queryRoute string) *cobra.Command { RunE: client.ValidateCmd, } + cmd.AddCommand( + GetCmdQueryAffiliateTiers(), + GetCmdQueryAffiliateInfo(), + GetCmdQueryReferredBy(), + ) + return cmd +} + +func GetCmdQueryAffiliateTiers() *cobra.Command { + cmd := &cobra.Command{ + Use: "affiliate-tiers", + Short: "Query affiliate tiers", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.AllAffiliateTiers(context.Background(), &types.AllAffiliateTiersRequest{}) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + } + return cmd +} + +func GetCmdQueryAffiliateInfo() *cobra.Command { + cmd := &cobra.Command{ + Use: "affiliate-info [affiliate-address]", + Short: "Query affiliate info", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.AffiliateInfo(context.Background(), &types.AffiliateInfoRequest{ + Address: args[0], + }) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + } + return cmd +} + +func GetCmdQueryReferredBy() *cobra.Command { + cmd := &cobra.Command{ + Use: "referred-by [address]", + Short: "Query the referee that referred the given addresss", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.ReferredBy(context.Background(), &types.ReferredByRequest{ + Address: args[0], + }) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + } return cmd } diff --git a/protocol/x/affiliates/client/cli/query_test.go b/protocol/x/affiliates/client/cli/query_test.go new file mode 100644 index 0000000000..036e64a404 --- /dev/null +++ b/protocol/x/affiliates/client/cli/query_test.go @@ -0,0 +1,74 @@ +package cli_test + +import ( + "strconv" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/stretchr/testify/require" + + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + "github.com/dydxprotocol/v4-chain/protocol/testutil/network" + "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/client/cli" + "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types" +) + +// Prevent strconv unused error +var _ = strconv.IntSize + +func setupNetwork(t *testing.T) (*network.Network, client.Context) { + t.Helper() + cfg := network.DefaultConfig(nil) + + // Init state. + state := types.GenesisState{} + require.NoError(t, cfg.Codec.UnmarshalJSON(cfg.GenesisState[types.ModuleName], &state)) + + // Modify default genesis state + state = *types.DefaultGenesis() + + // Add test affiliate tiers + state.AffiliateTiers = types.DefaultAffiliateTiers + + buf, err := cfg.Codec.MarshalJSON(&state) + require.NoError(t, err) + cfg.GenesisState[types.ModuleName] = buf + net := network.New(t, cfg) + ctx := net.Validators[0].ClientCtx + + return net, ctx +} + +func TestQueryAffiliateTiers(t *testing.T) { + net, ctx := setupNetwork(t) + + out, err := clitestutil.ExecTestCLICmd(ctx, cli.GetCmdQueryAffiliateTiers(), []string{}) + require.NoError(t, err) + + var resp types.AllAffiliateTiersResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + require.Equal(t, types.DefaultAffiliateTiers, resp.Tiers) +} + +func TestQueryAffiliateInfo(t *testing.T) { + net, ctx := setupNetwork(t) + + testAddress := constants.AliceAccAddress.String() + out, err := clitestutil.ExecTestCLICmd(ctx, cli.GetCmdQueryAffiliateInfo(), []string{testAddress}) + require.NoError(t, err) + + var resp types.AffiliateInfoResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) +} + +func TestQueryReferredBy(t *testing.T) { + net, ctx := setupNetwork(t) + + testAddress := constants.AliceAccAddress.String() + out, err := clitestutil.ExecTestCLICmd(ctx, cli.GetCmdQueryReferredBy(), []string{testAddress}) + require.NoError(t, err) + + var resp types.ReferredByResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) +} diff --git a/protocol/x/affiliates/client/cli/tx.go b/protocol/x/affiliates/client/cli/tx.go index fab8d4a046..1deb7a0897 100644 --- a/protocol/x/affiliates/client/cli/tx.go +++ b/protocol/x/affiliates/client/cli/tx.go @@ -6,6 +6,8 @@ import ( "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types" ) @@ -18,5 +20,27 @@ func GetTxCmd() *cobra.Command { SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, } + cmd.AddCommand(CmdRegisterAffiliate()) + return cmd +} + +func CmdRegisterAffiliate() *cobra.Command { + cmd := &cobra.Command{ + Use: "register-affiliate [affiliate] [referee]", + Short: "Register an affiliate", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + msg := types.MsgRegisterAffiliate{ + Affiliate: args[0], + Referee: args[1], + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + } + flags.AddTxFlagsToCmd(cmd) return cmd } diff --git a/protocol/x/affiliates/genesis.go b/protocol/x/affiliates/genesis.go index 4767af4794..fd6c3d4ec7 100644 --- a/protocol/x/affiliates/genesis.go +++ b/protocol/x/affiliates/genesis.go @@ -8,9 +8,20 @@ import ( // InitGenesis initializes the module's state from a provided genesis state. func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { + err := k.UpdateAffiliateTiers(ctx, genState.AffiliateTiers) + if err != nil { + panic(err) + } } // ExportGenesis returns the module's exported genesis. func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { - return &types.GenesisState{} + affiliateTiers, err := k.GetAllAffiliateTiers(ctx) + if err != nil { + panic(err) + } + + return &types.GenesisState{ + AffiliateTiers: affiliateTiers, + } } diff --git a/protocol/x/affiliates/keeper/grpc_query.go b/protocol/x/affiliates/keeper/grpc_query.go index fff1a96295..a4a992b271 100644 --- a/protocol/x/affiliates/keeper/grpc_query.go +++ b/protocol/x/affiliates/keeper/grpc_query.go @@ -49,11 +49,7 @@ func (k Keeper) ReferredBy(ctx context.Context, affiliateAddr, exists := k.GetReferredBy(sdkCtx, req.GetAddress()) if !exists { - return &types.ReferredByResponse{}, errorsmod.Wrapf( - types.ErrAffiliateNotFound, - "affiliate not found for address: %s", - req.GetAddress(), - ) + return &types.ReferredByResponse{}, nil } return &types.ReferredByResponse{ diff --git a/protocol/x/affiliates/keeper/grpc_query_test.go b/protocol/x/affiliates/keeper/grpc_query_test.go index 8c4ea7618b..dce8e7c35e 100644 --- a/protocol/x/affiliates/keeper/grpc_query_test.go +++ b/protocol/x/affiliates/keeper/grpc_query_test.go @@ -142,13 +142,13 @@ func TestReferredBy(t *testing.T) { AffiliateAddress: constants.BobAccAddress.String(), }, }, - "Affiliate not found": { + "Affiliate not registered": { req: &types.ReferredByRequest{ Address: constants.DaveAccAddress.String(), }, setup: func(ctx sdk.Context, k keeper.Keeper) {}, expected: nil, - expectError: types.ErrAffiliateNotFound, + expectError: nil, }, } diff --git a/protocol/x/affiliates/types/genesis.go b/protocol/x/affiliates/types/genesis.go index 09583a5f2e..68668b98df 100644 --- a/protocol/x/affiliates/types/genesis.go +++ b/protocol/x/affiliates/types/genesis.go @@ -2,7 +2,11 @@ package types // DefaultGenesis returns the default stats genesis state. func DefaultGenesis() *GenesisState { - return &GenesisState{} + return &GenesisState{ + AffiliateTiers: AffiliateTiers{ + Tiers: []AffiliateTiers_Tier{}, + }, + } } // Validate performs basic genesis state validation returning an error upon any diff --git a/protocol/x/affiliates/types/genesis.pb.go b/protocol/x/affiliates/types/genesis.pb.go index 98728d902f..890eab489a 100644 --- a/protocol/x/affiliates/types/genesis.pb.go +++ b/protocol/x/affiliates/types/genesis.pb.go @@ -5,6 +5,7 @@ package types import ( fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" math "math" @@ -24,6 +25,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines generis state of `x/affiliates` type GenesisState struct { + // The list of affiliate tiers + AffiliateTiers AffiliateTiers `protobuf:"bytes,1,opt,name=affiliate_tiers,json=affiliateTiers,proto3" json:"affiliate_tiers"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -59,6 +62,13 @@ func (m *GenesisState) XXX_DiscardUnknown() { var xxx_messageInfo_GenesisState proto.InternalMessageInfo +func (m *GenesisState) GetAffiliateTiers() AffiliateTiers { + if m != nil { + return m.AffiliateTiers + } + return AffiliateTiers{} +} + func init() { proto.RegisterType((*GenesisState)(nil), "dydxprotocol.affiliates.GenesisState") } @@ -68,17 +78,20 @@ func init() { } var fileDescriptor_7d3ffc50e877971b = []byte{ - // 146 bytes of a gzipped FileDescriptorProto + // 207 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4d, 0xa9, 0x4c, 0xa9, 0x28, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 0x4f, 0x4c, 0x4b, 0xcb, 0xcc, 0xc9, 0x4c, 0x2c, 0x49, 0x2d, 0xd6, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x03, 0xcb, 0x09, 0x89, - 0x23, 0x2b, 0xd3, 0x43, 0x28, 0x53, 0xe2, 0xe3, 0xe2, 0x71, 0x87, 0xa8, 0x0c, 0x2e, 0x49, 0x2c, - 0x49, 0x75, 0x0a, 0x3b, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, - 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0x9b, 0xf4, - 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0x14, 0x4b, 0xcb, 0x4c, 0x74, 0x93, - 0x33, 0x12, 0x33, 0xf3, 0xf4, 0xe1, 0x22, 0x15, 0xc8, 0x0e, 0x29, 0xa9, 0x2c, 0x48, 0x2d, 0x4e, - 0x62, 0x03, 0x4b, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x52, 0x0f, 0x30, 0xb0, 0x00, - 0x00, 0x00, + 0x23, 0x2b, 0xd3, 0x43, 0x28, 0x93, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x4b, 0xe8, 0x83, 0x58, + 0x10, 0xe5, 0x52, 0x1a, 0xb8, 0x4c, 0x45, 0x30, 0x21, 0x2a, 0x95, 0xd2, 0xb8, 0x78, 0xdc, 0x21, + 0x36, 0x05, 0x97, 0x24, 0x96, 0xa4, 0x0a, 0x85, 0x71, 0xf1, 0xc3, 0xd5, 0xc4, 0x97, 0x64, 0xa6, + 0x16, 0x15, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0xa9, 0xeb, 0xe1, 0x70, 0x82, 0x9e, 0x23, + 0x8c, 0x19, 0x02, 0x52, 0xee, 0xc4, 0x72, 0xe2, 0x9e, 0x3c, 0x43, 0x10, 0x5f, 0x22, 0xaa, 0x68, + 0xd8, 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, 0xd9, 0xa4, 0x67, 0x96, 0x64, + 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xa3, 0x38, 0xbb, 0xcc, 0x44, 0x37, 0x39, 0x23, 0x31, + 0x33, 0x4f, 0x1f, 0x2e, 0x52, 0x81, 0xec, 0x95, 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, 0xb0, + 0xa4, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x3f, 0xb3, 0x6a, 0x5a, 0x48, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -101,6 +114,16 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.AffiliateTiers.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 } @@ -121,6 +144,8 @@ func (m *GenesisState) Size() (n int) { } var l int _ = l + l = m.AffiliateTiers.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -159,6 +184,39 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AffiliateTiers", 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 + } + if err := m.AffiliateTiers.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/protocol/x/revshare/keeper/revshare_test.go b/protocol/x/revshare/keeper/revshare_test.go index fae19e4f07..dcf12fbcf1 100644 --- a/protocol/x/revshare/keeper/revshare_test.go +++ b/protocol/x/revshare/keeper/revshare_test.go @@ -675,7 +675,8 @@ func TestKeeper_GetAllRevShares_Invalid(t *testing.T) { err := affiliatesKeeper.UpdateAffiliateTiers(ctx, affiliatetypes.DefaultAffiliateTiers) require.NoError(t, err) - err = affiliatesKeeper.RegisterAffiliate(ctx, constants.AliceAccAddress.String(), constants.BobAccAddress.String()) + err = affiliatesKeeper.RegisterAffiliate(ctx, constants.AliceAccAddress.String(), + constants.BobAccAddress.String()) require.NoError(t, err) }, },