Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OTE-780] Add client code for affiliates #2252

Merged
merged 9 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion proto/dydxprotocol/affiliates/genesis.proto
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
syntax = "proto3";
package dydxprotocol.affiliates;
import "gogoproto/gogo.proto";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the missing import for "gogoproto/gogo.proto".

The static analysis tool buf reports a missing import for "gogoproto/gogo.proto". This issue needs to be resolved to ensure successful compilation of the code.

Please check the following:

  1. Ensure that the gogoproto library is properly installed and configured in your project's build system.
  2. Verify that the import path is correct and the "gogo.proto" file exists in the specified location.

If you need further assistance, I'd be happy to help you resolve this issue. Let me know if you'd like me to investigate further or provide more specific guidance.

Tools
buf

3-3: import "gogoproto/gogo.proto": file does not exist

(COMPILE)

import "cosmos_proto/cosmos.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 {}
message GenesisState {
// The list of affiliate tiers
AffiliateTiers affiliate_tiers = 1 [ (gogoproto.nullable) = false ];
}
72 changes: 72 additions & 0 deletions protocol/x/affiliates/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"context"
"fmt"

"github.com/spf13/cobra"
Expand All @@ -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
}
74 changes: 74 additions & 0 deletions protocol/x/affiliates/client/cli/query_test.go
Original file line number Diff line number Diff line change
@@ -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))
}
Comment on lines +54 to +63
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add assertions for the returned affiliate info.

The TestQueryAffiliateInfo function correctly sets up the network and executes the GetCmdQueryAffiliateInfo CLI command with a test address. It also unmarshals the response into an AffiliateInfoResponse struct.

However, it does not assert anything about the returned affiliate info. Consider adding assertions to check that the returned affiliate info matches the expected values for the test address.


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))
}
Comment on lines +65 to +74
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add assertions for the returned referred-by info.

The TestQueryReferredBy function correctly sets up the network and executes the GetCmdQueryReferredBy CLI command with a test address. It also unmarshals the response into a ReferredByResponse struct.

However, it does not assert anything about the returned referred-by info. Consider adding assertions to check that the returned referred-by info matches the expected values for the test address.

24 changes: 24 additions & 0 deletions protocol/x/affiliates/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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
}
10 changes: 9 additions & 1 deletion protocol/x/affiliates/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@ import (

// InitGenesis initializes the module's state from a provided genesis state.
func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
k.UpdateAffiliateTiers(ctx, genState.AffiliateTiers)
}

// 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,
}
}
6 changes: 1 addition & 5 deletions protocol/x/affiliates/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

Based on the analysis of the test cases, it appears that the tests for the ReferredBy function have not been updated to reflect the new behavior of returning an empty response instead of an error when no affiliate is found. This inconsistency could lead to potential issues and false negative test results.

To address this, we should recommend updating the test cases to align with the new implementation. Here's the final response:

Update test cases for ReferredBy function to expect empty response

The test cases for the ReferredBy function in protocol/x/affiliates/keeper/grpc_query_test.go need to be updated to reflect the new behavior of returning an empty response instead of an error when no affiliate is found. Specifically, the "Affiliate not found" test case should be modified as follows:

  • Remove the expectError: types.ErrAffiliateNotFound line.
  • Update the expected field to be an empty ReferredByResponse instead of nil.
  • Modify the assertion to check for an empty response rather than an error.

This update will ensure that the tests accurately reflect the new implementation and prevent potential false negative results.

Analysis chain

Verify the impact of returning an empty response on the calling code.

The change simplifies the control flow by removing the error handling when an affiliate is not found and returns an empty ReferredByResponse instead. This may impact how the calling code interprets the absence of an affiliate and may lead to different handling of the response in the broader application context.

Please verify that the calling code and the broader application can handle the empty response correctly. You can use the following script to search for the usage of the ReferredBy function and analyze the impact of the change:


To complete the verification process, we need to check if the test cases for the ReferredBy function have been updated to expect an empty response instead of an error when no affiliate is found. Let's examine the relevant test file.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the impact of returning an empty response on the calling code.

# Test: Search for the function usage. Expect: Analyze how the response is handled.
rg --type go -A 10 $'ReferredBy\('

Length of output: 18042


Script:

#!/bin/bash
# Description: Check if test cases for ReferredBy have been updated

# Test: Examine the test cases for ReferredBy function
cat protocol/x/affiliates/keeper/grpc_query_test.go

Length of output: 5723

}

return &types.ReferredByResponse{
Expand Down
4 changes: 3 additions & 1 deletion protocol/x/affiliates/types/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package types

// DefaultGenesis returns the default stats genesis state.
func DefaultGenesis() *GenesisState {
return &GenesisState{}
return &GenesisState{
AffiliateTiers: AffiliateTiers{},
}
}

// Validate performs basic genesis state validation returning an error upon any
Expand Down
76 changes: 68 additions & 8 deletions protocol/x/affiliates/types/genesis.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading