diff --git a/protocol/x/affiliates/keeper/grpc_query_test.go b/protocol/x/affiliates/keeper/grpc_query_test.go index adeedd9269..a19d76c3a9 100644 --- a/protocol/x/affiliates/keeper/grpc_query_test.go +++ b/protocol/x/affiliates/keeper/grpc_query_test.go @@ -194,6 +194,8 @@ func TestReferredBy(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { + err := k.UpdateAffiliateTiers(ctx, types.DefaultAffiliateTiers) + require.NoError(t, err) tc.setup(ctx, k) res, err := k.ReferredBy(ctx, tc.req) diff --git a/protocol/x/affiliates/keeper/keeper.go b/protocol/x/affiliates/keeper/keeper.go index 53cc82f772..e35f18a5e9 100644 --- a/protocol/x/affiliates/keeper/keeper.go +++ b/protocol/x/affiliates/keeper/keeper.go @@ -71,6 +71,14 @@ func (k Keeper) RegisterAffiliate( return errorsmod.Wrapf(types.ErrAffiliateAlreadyExistsForReferee, "referee: %s, affiliate: %s", referee, affiliateAddr) } + affiliateTiers, err := k.GetAllAffiliateTiers(ctx) + if err != nil { + return err + } + // Return error if no tiers are set. + if len(affiliateTiers.GetTiers()) == 0 { + return types.ErrAffiliateTiersNotSet + } prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.ReferredByKeyPrefix)).Set([]byte(referee), []byte(affiliateAddr)) k.GetIndexerEventManager().AddTxnEvent( ctx, @@ -204,6 +212,10 @@ func (k Keeper) GetTierForAffiliate( return 0, 0, err } tiers := affiliateTiers.GetTiers() + // Return 0 tier if no tiers are set. + if len(tiers) == 0 { + return 0, 0, nil + } numTiers := uint32(len(tiers)) maxTierLevel := numTiers - 1 currentTier := uint32(0) diff --git a/protocol/x/affiliates/keeper/keeper_test.go b/protocol/x/affiliates/keeper/keeper_test.go index c2d5805ec6..96b25b83e5 100644 --- a/protocol/x/affiliates/keeper/keeper_test.go +++ b/protocol/x/affiliates/keeper/keeper_test.go @@ -43,7 +43,8 @@ func TestRegisterAffiliate_GetReferredBy(t *testing.T) { affiliate: constants.BobAccAddress.String(), expectError: nil, setup: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper) { - // No setup needed for this test case + err := k.UpdateAffiliateTiers(ctx, types.DefaultAffiliateTiers) + require.NoError(t, err) }, }, { @@ -52,7 +53,9 @@ func TestRegisterAffiliate_GetReferredBy(t *testing.T) { affiliate: constants.CarlAccAddress.String(), expectError: types.ErrAffiliateAlreadyExistsForReferee, setup: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper) { - err := k.RegisterAffiliate(ctx, constants.AliceAccAddress.String(), constants.BobAccAddress.String()) + err := k.UpdateAffiliateTiers(ctx, types.DefaultAffiliateTiers) + require.NoError(t, err) + err = k.RegisterAffiliate(ctx, constants.AliceAccAddress.String(), constants.BobAccAddress.String()) require.NoError(t, err) }, }, @@ -62,7 +65,8 @@ func TestRegisterAffiliate_GetReferredBy(t *testing.T) { affiliate: constants.BobAccAddress.String(), expectError: types.ErrInvalidAddress, setup: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper) { - // No setup needed for this test case + err := k.UpdateAffiliateTiers(ctx, types.DefaultAffiliateTiers) + require.NoError(t, err) }, }, { @@ -70,6 +74,16 @@ func TestRegisterAffiliate_GetReferredBy(t *testing.T) { referee: constants.AliceAccAddress.String(), affiliate: "invalid_address", expectError: types.ErrInvalidAddress, + setup: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper) { + err := k.UpdateAffiliateTiers(ctx, types.DefaultAffiliateTiers) + require.NoError(t, err) + }, + }, + { + name: "No tiers set", + referee: constants.AliceAccAddress.String(), + affiliate: constants.BobAccAddress.String(), + expectError: types.ErrAffiliateTiersNotSet, setup: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper) { // No setup needed for this test case }, @@ -391,8 +405,10 @@ func TestRegisterAffiliateEmitEvent(t *testing.T) { affiliate := constants.AliceAccAddress.String() referee := constants.BobAccAddress.String() + err := k.UpdateAffiliateTiers(ctx, types.DefaultAffiliateTiers) + require.NoError(t, err) - err := k.RegisterAffiliate(ctx, referee, affiliate) + err = k.RegisterAffiliate(ctx, referee, affiliate) require.NoError(t, err) expectedEvent := &indexerevents.RegisterAffiliateEventV1{ Referee: referee, @@ -744,9 +760,12 @@ func TestAggregateAffiliateReferredVolumeForFills(t *testing.T) { k := tApp.App.AffiliatesKeeper statsKeeper := tApp.App.StatsKeeper + err := k.UpdateAffiliateTiers(ctx, types.DefaultAffiliateTiers) + require.NoError(t, err) + tc.setup(t, ctx, &k, &statsKeeper) - err := k.AggregateAffiliateReferredVolumeForFills(ctx) + err = k.AggregateAffiliateReferredVolumeForFills(ctx) require.NoError(t, err) referredVolume, err := k.GetReferredVolume(ctx, affiliate) @@ -755,3 +774,14 @@ func TestAggregateAffiliateReferredVolumeForFills(t *testing.T) { }) } } + +func TestGetTierForAffiliateEmptyTiers(t *testing.T) { + tApp := testapp.NewTestAppBuilder(t).Build() + ctx := tApp.InitChain() + k := tApp.App.AffiliatesKeeper + + tierLevel, feeSharePpm, err := k.GetTierForAffiliate(ctx, constants.AliceAccAddress.String()) + require.NoError(t, err) + require.Equal(t, uint32(0), tierLevel) + require.Equal(t, uint32(0), feeSharePpm) +} diff --git a/protocol/x/affiliates/keeper/msg_server_test.go b/protocol/x/affiliates/keeper/msg_server_test.go index 3d7db09e0c..84d94af333 100644 --- a/protocol/x/affiliates/keeper/msg_server_test.go +++ b/protocol/x/affiliates/keeper/msg_server_test.go @@ -77,10 +77,12 @@ func TestMsgServer_RegisterAffiliate(t *testing.T) { t.Run(tc.name, func(t *testing.T) { k, ms, ctx := setupMsgServer(t) sdkCtx := sdk.UnwrapSDKContext(ctx) + err := k.UpdateAffiliateTiers(sdkCtx, types.DefaultAffiliateTiers) + require.NoError(t, err) if tc.setup != nil { tc.setup(sdkCtx, k) } - _, err := ms.RegisterAffiliate(ctx, tc.msg) + _, err = ms.RegisterAffiliate(ctx, tc.msg) if tc.expectErr != nil { require.ErrorIs(t, err, tc.expectErr) } else { diff --git a/protocol/x/affiliates/types/errors.go b/protocol/x/affiliates/types/errors.go index 0beb21aa6a..ed8a2062d3 100644 --- a/protocol/x/affiliates/types/errors.go +++ b/protocol/x/affiliates/types/errors.go @@ -14,4 +14,6 @@ var ( ModuleName, 7, "Rev share safety violation") ErrDuplicateAffiliateAddressForWhitelist = errorsmod.Register( ModuleName, 8, "Duplicate affiliate address for whitelist") + ErrAffiliateTiersNotSet = errorsmod.Register(ModuleName, 9, + "Affiliate tiers not set (affiliate program is not active)") ) diff --git a/protocol/x/feetiers/keeper/keeper_test.go b/protocol/x/feetiers/keeper/keeper_test.go index 1d4c8d9bd0..3716c2d835 100644 --- a/protocol/x/feetiers/keeper/keeper_test.go +++ b/protocol/x/feetiers/keeper/keeper_test.go @@ -7,6 +7,7 @@ import ( testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" affiliateskeeper "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/keeper" + affiliatetypes "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types" "github.com/dydxprotocol/v4-chain/protocol/x/feetiers/types" statskeeper "github.com/dydxprotocol/v4-chain/protocol/x/stats/keeper" stattypes "github.com/dydxprotocol/v4-chain/protocol/x/stats/types" @@ -247,6 +248,11 @@ func TestGetPerpetualFeePpm_Referral(t *testing.T) { statsKeeper := tApp.App.StatsKeeper affiliatesKeeper := tApp.App.AffiliatesKeeper + + // common setup + err = affiliatesKeeper.UpdateAffiliateTiers(ctx, affiliatetypes.DefaultAffiliateTiers) + require.NoError(t, err) + if tc.setup != nil { tc.setup(ctx, &affiliatesKeeper, &statsKeeper) } diff --git a/protocol/x/subaccounts/keeper/transfer_test.go b/protocol/x/subaccounts/keeper/transfer_test.go index 5bb53a217e..6fc7e33117 100644 --- a/protocol/x/subaccounts/keeper/transfer_test.go +++ b/protocol/x/subaccounts/keeper/transfer_test.go @@ -1625,6 +1625,8 @@ func TestDistributeFees(t *testing.T) { }, ) } + err = affiliatesKeeper.UpdateAffiliateTiers(ctx, affiliatetypes.DefaultAffiliateTiers) + require.NoError(t, err) if tc.affiliateRevShareAcctAddr != "" { err := affiliatesKeeper.RegisterAffiliate(ctx, refereeAccAddr, tc.affiliateRevShareAcctAddr) require.NoError(t, err)