From 7476c86c4225a44e5ddc7ce44392f86151e3d057 Mon Sep 17 00:00:00 2001 From: Justin Barnett <61020572+jusbar23@users.noreply.github.com> Date: Fri, 22 Aug 2025 10:31:52 -0400 Subject: [PATCH] Create new instance for fee calculation (#3051) (cherry picked from commit 143470db7378ece5cd1209d8c3cfbe18280cd104) --- protocol/x/revshare/keeper/revshare.go | 9 +- protocol/x/revshare/keeper/revshare_test.go | 218 ++++++++++++++++++++ 2 files changed, 225 insertions(+), 2 deletions(-) diff --git a/protocol/x/revshare/keeper/revshare.go b/protocol/x/revshare/keeper/revshare.go index f1b7c8c4c4..483935a5f4 100644 --- a/protocol/x/revshare/keeper/revshare.go +++ b/protocol/x/revshare/keeper/revshare.go @@ -220,7 +220,7 @@ func (k Keeper) GetAllRevShares( } var orderRouterRevShares []types.RevShare - netFeesSubRevenueShare := netFees + netFeesSubRevenueShare := new(big.Int).Set(netFees) // No affiliate fees shared, so we can generate order router rev shares if affiliateRevShares == nil { orderRouterRevShares, err = k.getOrderRouterRevShares(ctx, fill, takerFees, makerFees) @@ -231,7 +231,7 @@ func (k Keeper) GetAllRevShares( netFeesSubRevenueShare.Sub(netFeesSubRevenueShare, revShare.QuoteQuantums) } } else { - netFeesSubRevenueShare = new(big.Int).Sub(netFees, affiliateFeesShared) + netFeesSubRevenueShare.Sub(netFeesSubRevenueShare, affiliateFeesShared) } if netFeesSubRevenueShare.Sign() <= 0 { @@ -270,8 +270,13 @@ func (k Keeper) GetAllRevShares( // Add the rev share ppm to the total for the fee source feeSourceToRevSharePpm[revShare.RevShareFeeSource] += revShare.RevSharePpm } + // Check total fees shared is less than or equal to net fees if totalFeesShared.Cmp(netFees) > 0 { + k.Logger(ctx).Error( + "Total fees exceed net fees. Total fees: ", totalFeesShared, + "Net fees: ", netFees, + "Revshares generated: ", revShares) return types.RevSharesForFill{}, types.ErrTotalFeesSharedExceedsNetFees } diff --git a/protocol/x/revshare/keeper/revshare_test.go b/protocol/x/revshare/keeper/revshare_test.go index f056b26305..0ee8ff85d3 100644 --- a/protocol/x/revshare/keeper/revshare_test.go +++ b/protocol/x/revshare/keeper/revshare_test.go @@ -652,6 +652,224 @@ func TestKeeper_GetAllRevShares_Valid(t *testing.T) { require.NoError(t, err) }, }, + { + name: "Valid taker order router rev share with unconditional rev share", + expectedRevSharesForFill: types.RevSharesForFill{ + AllRevShares: []types.RevShare{ + { + Recipient: constants.DaveAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_TAKER_FEE, + RevShareType: types.REV_SHARE_TYPE_ORDER_ROUTER, + QuoteQuantums: big.NewInt(175_000), + RevSharePpm: 500_000, // 50% + }, + { + Recipient: constants.BobAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE, + RevShareType: types.REV_SHARE_TYPE_UNCONDITIONAL, + QuoteQuantums: big.NewInt(87_500), + RevSharePpm: 500_000, // 50% + }, + { + Recipient: constants.CarlAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE, + RevShareType: types.REV_SHARE_TYPE_UNCONDITIONAL, + QuoteQuantums: big.NewInt(17_500), + RevSharePpm: 100_000, // 20% + }, + }, + FeeSourceToQuoteQuantums: map[types.RevShareFeeSource]*big.Int{ + types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE: big.NewInt(105_000), + types.REV_SHARE_FEE_SOURCE_TAKER_FEE: big.NewInt(175_000), + types.REV_SHARE_FEE_SOURCE_MAKER_FEE: big.NewInt(0), + }, + FeeSourceToRevSharePpm: map[types.RevShareFeeSource]uint32{ + types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE: 600_000, // 60% + types.REV_SHARE_FEE_SOURCE_TAKER_FEE: 500_000, // 50% + types.REV_SHARE_FEE_SOURCE_MAKER_FEE: 0, + }, + AffiliateRevShare: nil, + }, + fill: clobtypes.FillForProcess{ + TakerAddr: constants.AliceAccAddress.String(), + TakerFeeQuoteQuantums: big.NewInt(450_000), + MakerAddr: constants.BobAccAddress.String(), + MakerFeeQuoteQuantums: big.NewInt(-100_000), + FillQuoteQuantums: big.NewInt(100_000_000), + ProductId: perpetualId, + MarketId: marketId, + MonthlyRollingTakerVolumeQuantums: 1_000_000_000_000, + TakerOrderRouterAddr: constants.DaveAccAddress.String(), + }, + setup: func(tApp *testapp.TestApp, ctx sdk.Context, keeper *keeper.Keeper, + affiliatesKeeper *affiliateskeeper.Keeper) { + keeper.SetUnconditionalRevShareConfigParams(ctx, types.UnconditionalRevShareConfig{ + Configs: []types.UnconditionalRevShareConfig_RecipientConfig{ + { + Address: constants.BobAccAddress.String(), + SharePpm: 500_000, // 20% + }, + { + Address: constants.CarlAccAddress.String(), + SharePpm: 100_000, // 10% + }, + }, + }) + // Set order router rev shares + err := keeper.SetOrderRouterRevShare(ctx, constants.DaveAccAddress.String(), 500_000) // 10% + require.NoError(t, err) + }, + }, + { + name: "Valid taker order router rev share with unconditional rev share and maker fee " + + "rebate and maker order router rev share", + expectedRevSharesForFill: types.RevSharesForFill{ + AllRevShares: []types.RevShare{ + { + Recipient: constants.DaveAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_TAKER_FEE, + RevShareType: types.REV_SHARE_TYPE_ORDER_ROUTER, + QuoteQuantums: big.NewInt(225_000), + RevSharePpm: 500_000, // 50% + }, + { + Recipient: constants.BobAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE, + RevShareType: types.REV_SHARE_TYPE_UNCONDITIONAL, + QuoteQuantums: big.NewInt(162_500), // 50% * ((taker + maker) - taker ORRS) + RevSharePpm: 500_000, // 50% + }, + { + Recipient: constants.CarlAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE, + RevShareType: types.REV_SHARE_TYPE_UNCONDITIONAL, + QuoteQuantums: big.NewInt(32_500), + RevSharePpm: 100_000, // 10% + }, + }, + FeeSourceToQuoteQuantums: map[types.RevShareFeeSource]*big.Int{ + types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE: big.NewInt(195_000), + types.REV_SHARE_FEE_SOURCE_TAKER_FEE: big.NewInt(225_000), + types.REV_SHARE_FEE_SOURCE_MAKER_FEE: big.NewInt(0), + }, + FeeSourceToRevSharePpm: map[types.RevShareFeeSource]uint32{ + types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE: 600_000, // 60% + types.REV_SHARE_FEE_SOURCE_TAKER_FEE: 500_000, // 50% + types.REV_SHARE_FEE_SOURCE_MAKER_FEE: 0, + }, + AffiliateRevShare: nil, + }, + fill: clobtypes.FillForProcess{ + TakerAddr: constants.AliceAccAddress.String(), + TakerFeeQuoteQuantums: big.NewInt(450_000), + MakerAddr: constants.BobAccAddress.String(), + MakerFeeQuoteQuantums: big.NewInt(100_000), + FillQuoteQuantums: big.NewInt(100_000_000), + ProductId: perpetualId, + MarketId: marketId, + MonthlyRollingTakerVolumeQuantums: 1_000_000_000_000, + TakerOrderRouterAddr: constants.DaveAccAddress.String(), + }, + setup: func(tApp *testapp.TestApp, ctx sdk.Context, keeper *keeper.Keeper, + affiliatesKeeper *affiliateskeeper.Keeper) { + keeper.SetUnconditionalRevShareConfigParams(ctx, types.UnconditionalRevShareConfig{ + Configs: []types.UnconditionalRevShareConfig_RecipientConfig{ + { + Address: constants.BobAccAddress.String(), + SharePpm: 500_000, // 50% + }, + { + Address: constants.CarlAccAddress.String(), + SharePpm: 100_000, // 10% + }, + }, + }) + // Set order router rev shares + err := keeper.SetOrderRouterRevShare(ctx, constants.DaveAccAddress.String(), 500_000) // 50% + require.NoError(t, err) + err = keeper.SetOrderRouterRevShare(ctx, constants.AliceAccAddress.String(), 500_000) // 50% + require.NoError(t, err) + }, + }, + { + name: "Valid taker order router rev share with unconditional rev share and maker fee " + + "rebate and maker order router rev share", + expectedRevSharesForFill: types.RevSharesForFill{ + AllRevShares: []types.RevShare{ + { + Recipient: constants.DaveAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_TAKER_FEE, + RevShareType: types.REV_SHARE_TYPE_ORDER_ROUTER, + QuoteQuantums: big.NewInt(225_000), + RevSharePpm: 500_000, // 50% + }, + { + Recipient: constants.AliceAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_MAKER_FEE, + RevShareType: types.REV_SHARE_TYPE_ORDER_ROUTER, + QuoteQuantums: big.NewInt(50_000), + RevSharePpm: 500_000, // 50% + }, + { + Recipient: constants.BobAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE, + RevShareType: types.REV_SHARE_TYPE_UNCONDITIONAL, + QuoteQuantums: big.NewInt(137_500), + RevSharePpm: 500_000, // 50% + }, + { + Recipient: constants.CarlAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE, + RevShareType: types.REV_SHARE_TYPE_UNCONDITIONAL, + QuoteQuantums: big.NewInt(27_500), + RevSharePpm: 100_000, // 20% + }, + }, + FeeSourceToQuoteQuantums: map[types.RevShareFeeSource]*big.Int{ + types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE: big.NewInt(165_000), + types.REV_SHARE_FEE_SOURCE_TAKER_FEE: big.NewInt(225_000), + types.REV_SHARE_FEE_SOURCE_MAKER_FEE: big.NewInt(50_000), + }, + FeeSourceToRevSharePpm: map[types.RevShareFeeSource]uint32{ + types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE: 600_000, // 60% + types.REV_SHARE_FEE_SOURCE_TAKER_FEE: 500_000, // 50% + types.REV_SHARE_FEE_SOURCE_MAKER_FEE: 500_000, // 50% + }, + AffiliateRevShare: nil, + }, + fill: clobtypes.FillForProcess{ + TakerAddr: constants.AliceAccAddress.String(), + TakerFeeQuoteQuantums: big.NewInt(450_000), + MakerAddr: constants.BobAccAddress.String(), + MakerFeeQuoteQuantums: big.NewInt(100_000), + FillQuoteQuantums: big.NewInt(100_000_000), + ProductId: perpetualId, + MarketId: marketId, + MonthlyRollingTakerVolumeQuantums: 1_000_000_000_000, + TakerOrderRouterAddr: constants.DaveAccAddress.String(), + MakerOrderRouterAddr: constants.AliceAccAddress.String(), + }, + setup: func(tApp *testapp.TestApp, ctx sdk.Context, keeper *keeper.Keeper, + affiliatesKeeper *affiliateskeeper.Keeper) { + keeper.SetUnconditionalRevShareConfigParams(ctx, types.UnconditionalRevShareConfig{ + Configs: []types.UnconditionalRevShareConfig_RecipientConfig{ + { + Address: constants.BobAccAddress.String(), + SharePpm: 500_000, // 50% + }, + { + Address: constants.CarlAccAddress.String(), + SharePpm: 100_000, // 10% + }, + }, + }) + // Set order router rev shares + err := keeper.SetOrderRouterRevShare(ctx, constants.DaveAccAddress.String(), 500_000) // 50% + require.NoError(t, err) + err = keeper.SetOrderRouterRevShare(ctx, constants.AliceAccAddress.String(), 500_000) // 50% + require.NoError(t, err) + }, + }, { name: "Valid revenue share with whitelisted affiliate and no unconditional rev shares", expectedRevSharesForFill: types.RevSharesForFill{