Skip to content

Commit cc59dd2

Browse files
affanv14teddyding
andauthored
[OTE-817] update trading rewards with new logic (#2300)
Co-authored-by: Teddy Ding <teddy@dydx.exchange>
1 parent b0034d0 commit cc59dd2

File tree

6 files changed

+122
-48
lines changed

6 files changed

+122
-48
lines changed

protocol/testing/e2e/trading_rewards/trading_rewards_test.go

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package trading_rewards_test
22

33
import (
4-
sdkmath "cosmossdk.io/math"
5-
"github.com/cosmos/gogoproto/proto"
6-
"github.com/dydxprotocol/v4-chain/protocol/app/flags"
74
"math/big"
85
"testing"
96
"time"
107

8+
sdkmath "cosmossdk.io/math"
9+
"github.com/cosmos/gogoproto/proto"
10+
"github.com/dydxprotocol/v4-chain/protocol/app/flags"
11+
1112
"github.com/cometbft/cometbft/types"
1213
sdk "github.com/cosmos/cosmos-sdk/types"
1314
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
@@ -229,20 +230,20 @@ func TestTradingRewards(t *testing.T) {
229230
},
230231
{
231232
AccAddress: RewardsTreasuryAccAddress,
232-
// Total of ~5.06 full coins have vested, which is less than calculated
233-
// rewards (~5.5 full coins). So all reward tokens were distributed.
233+
// Total of ~5.06 full coins have vested, calculated rewards are
234+
// ~1.99 full coins. So remaining rewards are ~3.07 full coins.
234235
Balance: big_testutil.MustFirst(new(big.Int).SetString(
235-
"0",
236+
"3077645653924902967",
236237
10,
237238
)),
238239
},
239240
{
240241
AccAddress: constants.AliceAccAddress,
241-
// starting balance + ~5.06 full coins rewards
242+
// starting balance + ~1.99 full coins rewards
242243
Balance: new(big.Int).Add(
243244
TestAccountStartingTokenBalance,
244245
big_testutil.MustFirst(new(big.Int).SetString(
245-
"5068012730847979890",
246+
"1990367076923076923",
246247
10,
247248
)),
248249
),
@@ -258,7 +259,7 @@ func TestTradingRewards(t *testing.T) {
258259
TradingRewards: []*indexerevents.AddressTradingReward{
259260
{
260261
Owner: constants.AliceAccAddress.String(),
261-
DenomAmount: dtypes.NewIntFromUint64(5068012730847979890),
262+
DenomAmount: dtypes.NewIntFromUint64(1990367076923076923),
262263
},
263264
},
264265
},
@@ -277,10 +278,10 @@ func TestTradingRewards(t *testing.T) {
277278
},
278279
{
279280
AccAddress: RewardsTreasuryAccAddress,
280-
// ~25.34 full coins. Note this is exactly 10x the amount vested per block,
281+
// balance + ~25.34 full coins. Note this is exactly 10x the amount vested per block,
281282
// since 10 blocks has passed since the last check.
282283
Balance: big_testutil.MustFirst(new(big.Int).SetString(
283-
"25340063654239899450",
284+
"28417709308164802417",
284285
10,
285286
)),
286287
},
@@ -300,23 +301,23 @@ func TestTradingRewards(t *testing.T) {
300301
{
301302
AccAddress: constants.BobAccAddress,
302303
// Starting balance: 500000000000000000000000
303-
// Total rewards = (TakerFee - TakerVolume * MaxMakerRebate) * 0.99
304-
// = ($28003 * 0.05% - $28003 * 0.011%) * 0.99
305-
// = ($14.0015 - $3.08033) 0.99 = $10.8119583
306-
// Reward tokens = $10.8119583 / $1.95 = 5.544594 full coins
304+
// Total rewards = (TakerFee - TakerVolume * MaxMakerRebate - (takerFee * MaxPossibleTakerFeeRevShare)) * 0.99
305+
// = ($28003 * 0.05% - $28003 * 0.011% - $28003 * 0.05% * 0.5) * 0.99
306+
// = ($14.0015 - $3.08033 - $7.00075) 0.99 = $3.8812158
307+
// Reward tokens = $3.8812158 / $1.95 = 1.9903670769 full coins
307308
Balance: new(big.Int).Add(
308309
TestAccountStartingTokenBalance,
309310
big_testutil.MustFirst(new(big.Int).SetString(
310-
"5544594000000000000",
311+
"1990367076923076923",
311312
10,
312313
)),
313314
),
314315
},
315316
{
316317
AccAddress: RewardsTreasuryAccAddress,
317-
// 25.34 + 2.534 - 5.544594 ~= 22.329 full coins
318+
// balance + 25.34 + 2.534 - 1.9903670769 ~= 22.329 full coins
318319
Balance: big_testutil.MustFirst(new(big.Int).SetString(
319-
"22329476019663889395",
320+
"28961348596665715439",
320321
10,
321322
)),
322323
},
@@ -326,7 +327,7 @@ func TestTradingRewards(t *testing.T) {
326327
TradingRewards: []*indexerevents.AddressTradingReward{
327328
{
328329
Owner: constants.BobAccAddress.String(),
329-
DenomAmount: dtypes.NewIntFromUint64(5544594000000000000),
330+
DenomAmount: dtypes.NewIntFromUint64(1990367076923076923),
330331
},
331332
},
332333
},
@@ -482,8 +483,8 @@ func TestTradingRewards(t *testing.T) {
482483
// - Carl and Dave: $12.519
483484
// Total rewards tokens distributed: ~25.34 (less than the value of net fees)
484485
// Entitled reward tokens:
485-
// - Alice and Bob: 8.0539
486-
// - Carl and Dave: 4.616
486+
// - Alice and Bob: 3.98073
487+
// - Carl and Dave: 2.28156
487488
ExpectedBalances: []expectedBalance{
488489
{
489490
AccAddress: RewardsVesterAccAddress,
@@ -495,9 +496,9 @@ func TestTradingRewards(t *testing.T) {
495496
},
496497
{
497498
AccAddress: RewardsTreasuryAccAddress,
498-
// All vested rewards were distributed, only rounding dusts left.
499+
// 12.52458 full coins distributed, ~12.815 full coins remaining
499500
Balance: big_testutil.MustFirst(new(big.Int).SetString(
500-
"2",
501+
"12815456885009130222",
501502
10,
502503
)),
503504
},
@@ -506,7 +507,7 @@ func TestTradingRewards(t *testing.T) {
506507
Balance: new(big.Int).Add(
507508
TestAccountStartingTokenBalance,
508509
big_testutil.MustFirst(new(big.Int).SetString(
509-
"8053910091363583686",
510+
"3980734153846153845",
510511
10,
511512
)),
512513
),
@@ -516,7 +517,7 @@ func TestTradingRewards(t *testing.T) {
516517
Balance: new(big.Int).Add(
517518
TestAccountStartingTokenBalance,
518519
big_testutil.MustFirst(new(big.Int).SetString(
519-
"8053910091363583686",
520+
"3980734153846153845",
520521
10,
521522
)),
522523
),
@@ -526,7 +527,7 @@ func TestTradingRewards(t *testing.T) {
526527
Balance: new(big.Int).Add(
527528
TestAccountStartingTokenBalance,
528529
big_testutil.MustFirst(new(big.Int).SetString(
529-
"4616121735756366038",
530+
"2281569230769230769",
530531
10,
531532
)),
532533
),
@@ -536,7 +537,7 @@ func TestTradingRewards(t *testing.T) {
536537
Balance: new(big.Int).Add(
537538
TestAccountStartingTokenBalance,
538539
big_testutil.MustFirst(new(big.Int).SetString(
539-
"4616121735756366038",
540+
"2281569230769230769",
540541
10,
541542
)),
542543
),
@@ -547,19 +548,19 @@ func TestTradingRewards(t *testing.T) {
547548
TradingRewards: []*indexerevents.AddressTradingReward{
548549
{
549550
Owner: constants.BobAccAddress.String(),
550-
DenomAmount: dtypes.NewIntFromUint64(8053910091363583686),
551+
DenomAmount: dtypes.NewIntFromUint64(3980734153846153845),
551552
},
552553
{
553554
Owner: constants.AliceAccAddress.String(),
554-
DenomAmount: dtypes.NewIntFromUint64(8053910091363583686),
555+
DenomAmount: dtypes.NewIntFromUint64(3980734153846153845),
555556
},
556557
{
557558
Owner: constants.CarlAccAddress.String(),
558-
DenomAmount: dtypes.NewIntFromUint64(4616121735756366038),
559+
DenomAmount: dtypes.NewIntFromUint64(2281569230769230769),
559560
},
560561
{
561562
Owner: constants.DaveAccAddress.String(),
562-
DenomAmount: dtypes.NewIntFromUint64(4616121735756366038),
563+
DenomAmount: dtypes.NewIntFromUint64(2281569230769230769),
563564
},
564565
},
565566
},

protocol/x/revshare/keeper/revshare.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ func (k Keeper) getAffiliateRevShares(
227227
) ([]types.RevShare, error) {
228228
takerAddr := fill.TakerAddr
229229
takerFee := fill.TakerFeeQuoteQuantums
230-
if fill.MonthlyRollingTakerVolumeQuantums >= types.Max30dRefereeVolumeQuantums {
230+
if fill.MonthlyRollingTakerVolumeQuantums >= types.MaxReferee30dVolumeForAffiliateShareQuantums {
231231
return nil, nil
232232
}
233233

protocol/x/revshare/keeper/revshare_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ func TestKeeper_GetAllRevShares_Valid(t *testing.T) {
504504
MakerFeeQuoteQuantums: big.NewInt(2_000_000),
505505
FillQuoteQuantums: big.NewInt(100_000_000_000),
506506
ProductId: perpetualId,
507-
MonthlyRollingTakerVolumeQuantums: types.Max30dRefereeVolumeQuantums + 1,
507+
MonthlyRollingTakerVolumeQuantums: types.MaxReferee30dVolumeForAffiliateShareQuantums + 1,
508508
MarketId: marketId,
509509
},
510510
expectedRevSharesForFill: types.RevSharesForFill{
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package types
22

33
const (
4-
// 25 million USDC
5-
Max30dRefereeVolumeQuantums = uint64(25_000_000_000_000)
4+
// 50 million USDC
5+
MaxReferee30dVolumeForAffiliateShareQuantums = uint64(50_000_000_000_000)
66
)

protocol/x/rewards/keeper/keeper.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/dydxprotocol/v4-chain/protocol/lib"
2020
"github.com/dydxprotocol/v4-chain/protocol/lib/log"
2121
"github.com/dydxprotocol/v4-chain/protocol/lib/metrics"
22+
affiliatetypes "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types"
2223
clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types"
2324
revsharetypes "github.com/dydxprotocol/v4-chain/protocol/x/revshare/types"
2425
"github.com/dydxprotocol/v4-chain/protocol/x/rewards/types"
@@ -120,15 +121,20 @@ func (k Keeper) GetRewardShare(
120121
//
121122
// Within each block, total reward share score for an address is defined as:
122123
//
123-
// reward_share_score = total_taker_fees_paid - total_rev_shared_taker_fee
124+
// reward_share_score = total_taker_fees_paid - max_possible_taker_fee_rev_share
124125
// - max_possible_maker_rebate * taker_volume + total_positive_maker_fees - total_rev_shared_maker_fee
125126
//
126127
// Hence, for each fill, increment reward share score as follow:
127128
// - Let F = sum(percentages of general rev-share) (excluding taker only rev share i.e. affiliate)
128129
// - For maker address, positive_maker_fees * (1 - F) are added to reward share score.
129130
// - For taker address, (positive_taker_fees - max_possible_maker_rebate
130-
// * fill_quote_quantum - taker_fee_rev_share) * (1 - F)
131+
// * fill_quote_quantum - max_possible_taker_fee_rev_share) * (1 - F)
131132
// are added to reward share score.
133+
// max_possible_taker_fee_rev_share is 0 when taker trailing volume is > MaxReferee30dVolumeForAffiliateShareQuantums,
134+
// since taker_fee_share is only affiliate at the moment, and they don’t generate affiliate rev share.
135+
// When taker volume ≤ MaxReferee30dVolumeForAffiliateShareQuantums,
136+
// max_possible_taker_fee_rev_share = max_vip_affiliate_share * taker_fee
137+
// regardless of if the taker has an affiliate or not.
132138

133139
func (k Keeper) AddRewardSharesForFill(
134140
ctx sdk.Context,
@@ -143,9 +149,15 @@ func (k Keeper) AddRewardSharesForFill(
143149
if value, ok := revSharesForFill.FeeSourceToRevSharePpm[revsharetypes.REV_SHARE_FEE_SOURCE_NET_FEE]; ok {
144150
totalNetFeeRevSharePpm = value
145151
}
146-
totalTakerFeeRevShareQuantums := big.NewInt(0)
147-
if value, ok := revSharesForFill.FeeSourceToQuoteQuantums[revsharetypes.REV_SHARE_FEE_SOURCE_TAKER_FEE]; ok {
148-
totalTakerFeeRevShareQuantums = value
152+
maxPossibleTakerFeeRevShare := big.NewInt(0)
153+
154+
// taker revshare is always 0 if taker rolling volume is greater than or equal
155+
// to Max30dTakerVolumeQuantums, so no need to reduce score by `max_possible_taker_fee_rev_share`
156+
if fill.MonthlyRollingTakerVolumeQuantums < revsharetypes.MaxReferee30dVolumeForAffiliateShareQuantums {
157+
maxPossibleTakerFeeRevShare = lib.BigMulPpm(fill.TakerFeeQuoteQuantums,
158+
lib.BigU(affiliatetypes.AffiliatesRevSharePpmCap),
159+
false,
160+
)
149161
}
150162

151163
totalFeeSubNetRevSharePpm := lib.OneMillion - totalNetFeeRevSharePpm
@@ -159,7 +171,7 @@ func (k Keeper) AddRewardSharesForFill(
159171
)
160172
netTakerFee = netTakerFee.Sub(
161173
netTakerFee,
162-
totalTakerFeeRevShareQuantums,
174+
maxPossibleTakerFeeRevShare,
163175
)
164176
takerWeight := lib.BigMulPpm(
165177
netTakerFee,

protocol/x/rewards/keeper/keeper_test.go

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ func TestAddRewardSharesForFill(t *testing.T) {
184184
},
185185
expectedTakerShare: types.RewardShare{
186186
Address: takerAddress,
187-
Weight: dtypes.NewInt(1_200_000), // 2 - 0.1% * 800
187+
Weight: dtypes.NewInt(200_000), // 2 - 0.1% * 800 -(2 * 0.5)
188188
},
189189
expectedMakerShare: types.RewardShare{
190190
Address: makerAddress,
@@ -218,7 +218,7 @@ func TestAddRewardSharesForFill(t *testing.T) {
218218
},
219219
expectedTakerShare: types.RewardShare{
220220
Address: takerAddress,
221-
Weight: dtypes.NewInt(1_250_000), // 2 - 0.1% * 750
221+
Weight: dtypes.NewInt(250_000), // 2 - 0.1% * 750 - (2 * 0.5)
222222
},
223223
expectedMakerShare: types.RewardShare{
224224
Address: makerAddress,
@@ -252,7 +252,7 @@ func TestAddRewardSharesForFill(t *testing.T) {
252252
},
253253
expectedTakerShare: types.RewardShare{
254254
Address: takerAddress,
255-
Weight: dtypes.NewInt(1_625_000), // 2 - 0.05% * 750
255+
Weight: dtypes.NewInt(625_000), // 2 - 0.05% * 750 - (2 * 0.5)
256256
},
257257
expectedMakerShare: types.RewardShare{
258258
Address: makerAddress,
@@ -319,7 +319,7 @@ func TestAddRewardSharesForFill(t *testing.T) {
319319
},
320320
expectedTakerShare: types.RewardShare{
321321
Address: takerAddress,
322-
Weight: dtypes.NewInt(700_000),
322+
Weight: dtypes.NewInt(350_000), // 0.7 - (0.7 * 0.5)
323323
},
324324
expectedMakerShare: types.RewardShare{
325325
Address: makerAddress,
@@ -367,7 +367,7 @@ func TestAddRewardSharesForFill(t *testing.T) {
367367
},
368368
expectedTakerShare: types.RewardShare{
369369
Address: takerAddress,
370-
Weight: dtypes.NewInt(1_080_000), // (2 - 0.1% * 800 - 0) * (1 - 0.1)
370+
Weight: dtypes.NewInt(180_000), // (2 - 0.1% * 800 - 0.5*2) * (1 - 0.1)
371371
},
372372
expectedMakerShare: types.RewardShare{
373373
Address: makerAddress,
@@ -422,7 +422,7 @@ func TestAddRewardSharesForFill(t *testing.T) {
422422
},
423423
expectedTakerShare: types.RewardShare{
424424
Address: takerAddress,
425-
Weight: dtypes.NewInt(960_000), // (2 - 0.1% * 800 - 0) * (1 - 0.2)
425+
Weight: dtypes.NewInt(160_000), // (2 - 0.1% * 800 - 0.5*2) * (1 - 0.2)
426426
},
427427
expectedMakerShare: types.RewardShare{
428428
Address: makerAddress,
@@ -483,7 +483,68 @@ func TestAddRewardSharesForFill(t *testing.T) {
483483
},
484484
expectedTakerShare: types.RewardShare{
485485
Address: takerAddress,
486-
Weight: dtypes.NewInt(900_000), // (2 - 0.1% * 800 - 0.2) * (1 - 0.1)
486+
Weight: dtypes.NewInt(180_000), // (2 - 0.1% * 800 - 1) * (1 - 0.1)
487+
},
488+
expectedMakerShare: types.RewardShare{
489+
Address: makerAddress,
490+
Weight: dtypes.NewInt(900_000), // 1 * (1 - 0.1)
491+
},
492+
},
493+
"positive maker + taker fees reduced by maker rebate, taker + net fee revshare,rolling taker volume > 50 mil": {
494+
prevTakerRewardShare: nil,
495+
prevMakerRewardShare: nil,
496+
fill: clobtypes.FillForProcess{
497+
TakerAddr: takerAddress,
498+
TakerFeeQuoteQuantums: big.NewInt(2_000_000),
499+
MakerAddr: makerAddress,
500+
MakerFeeQuoteQuantums: big.NewInt(1_000_000),
501+
FillQuoteQuantums: big.NewInt(800_000_000),
502+
ProductId: uint32(1),
503+
MarketId: uint32(1),
504+
MonthlyRollingTakerVolumeQuantums: 60_000_000_000_000,
505+
},
506+
revSharesForFill: revsharetypes.RevSharesForFill{
507+
AllRevShares: []revsharetypes.RevShare{
508+
{
509+
Recipient: constants.AliceAccAddress.String(),
510+
RevShareFeeSource: revsharetypes.REV_SHARE_FEE_SOURCE_NET_FEE,
511+
RevShareType: revsharetypes.REV_SHARE_TYPE_UNCONDITIONAL,
512+
QuoteQuantums: big.NewInt(200_000),
513+
RevSharePpm: 100_000, // 10%
514+
},
515+
{
516+
Recipient: takerAddress,
517+
RevShareFeeSource: revsharetypes.REV_SHARE_FEE_SOURCE_TAKER_FEE,
518+
RevShareType: revsharetypes.REV_SHARE_TYPE_AFFILIATE,
519+
QuoteQuantums: big.NewInt(200_000),
520+
RevSharePpm: 100_000, // 10%
521+
},
522+
},
523+
FeeSourceToQuoteQuantums: map[revsharetypes.RevShareFeeSource]*big.Int{
524+
revsharetypes.REV_SHARE_FEE_SOURCE_NET_FEE: big.NewInt(200_000),
525+
revsharetypes.REV_SHARE_FEE_SOURCE_TAKER_FEE: big.NewInt(200_000),
526+
},
527+
FeeSourceToRevSharePpm: map[revsharetypes.RevShareFeeSource]uint32{
528+
revsharetypes.REV_SHARE_FEE_SOURCE_NET_FEE: 100_000, // 10%
529+
revsharetypes.REV_SHARE_FEE_SOURCE_TAKER_FEE: 100_000, // 10%
530+
},
531+
AffiliateRevShare: &revsharetypes.RevShare{
532+
Recipient: takerAddress,
533+
RevShareFeeSource: revsharetypes.REV_SHARE_FEE_SOURCE_TAKER_FEE,
534+
RevShareType: revsharetypes.REV_SHARE_TYPE_AFFILIATE,
535+
QuoteQuantums: big.NewInt(200_000),
536+
RevSharePpm: 100_000, // 10%
537+
},
538+
},
539+
feeTiers: []*feetierstypes.PerpetualFeeTier{
540+
{
541+
MakerFeePpm: -1_000, // -0.1%
542+
TakerFeePpm: 2_000, // 0.2%
543+
},
544+
},
545+
expectedTakerShare: types.RewardShare{
546+
Address: takerAddress,
547+
Weight: dtypes.NewInt(1_080_000), // (2 - 0.1% * 800 - 0) * (1 - 0.1)
487548
},
488549
expectedMakerShare: types.RewardShare{
489550
Address: makerAddress,

0 commit comments

Comments
 (0)