Skip to content

Commit 9144e78

Browse files
author
Alex Johnson
authored
feat: usdt protection in antehandler (#2315)
1 parent 53cca79 commit 9144e78

File tree

4 files changed

+126
-21
lines changed

4 files changed

+126
-21
lines changed

protocol/app/ante.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
103103
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "prices keeper is required for ante builder")
104104
}
105105

106+
if options.MarketMapKeeper == nil {
107+
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "market map keeper is required for ante builder")
108+
}
109+
106110
h := &lockingAnteHandler{
107111
authStoreKey: options.AuthStoreKey,
108112
setupContextDecorator: ante.NewSetUpContextDecorator(),

protocol/app/ante/market_update.go

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package ante
33
import (
44
"errors"
55
"fmt"
6+
slinkytypes "github.com/skip-mev/slinky/pkg/types"
67

78
errorsmod "cosmossdk.io/errors"
89
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -14,13 +15,20 @@ import (
1415
pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types"
1516
)
1617

17-
var ErrNoCrossMarketUpdates = errors.New("cannot call MsgUpdateMarkets or MsgUpsertMarkets " +
18-
"on a market listed as cross margin")
18+
var ErrRestrictedMarketUpdates = errors.New("cannot call MsgUpdateMarkets or MsgUpsertMarkets " +
19+
"on a restricted market")
1920

2021
type MarketMapKeeper interface {
2122
GetAllMarkets(ctx sdk.Context) (map[string]mmtypes.Market, error)
2223
}
2324

25+
var (
26+
cpUSDTUSD = slinkytypes.CurrencyPair{
27+
Base: "USDT",
28+
Quote: "USD",
29+
}
30+
)
31+
2432
type ValidateMarketUpdateDecorator struct {
2533
perpKeeper perpetualstypes.PerpetualsKeeper
2634
priceKeeper pricestypes.PricesKeeper
@@ -80,8 +88,8 @@ func (d ValidateMarketUpdateDecorator) AnteHandle(
8088
return ctx, fmt.Errorf("unrecognized message type: %T", msg)
8189
}
8290

83-
if contains := d.doMarketsContainCrossMarket(ctx, markets); contains {
84-
return ctx, ErrNoCrossMarketUpdates
91+
if contains, ticker := d.doMarketsContainRestrictedMarket(ctx, markets); contains {
92+
return ctx, fmt.Errorf("%w: %s", ErrRestrictedMarketUpdates, ticker)
8593
}
8694

8795
// check if the market updates are safe
@@ -92,10 +100,16 @@ func (d ValidateMarketUpdateDecorator) AnteHandle(
92100
return next(ctx, tx, simulate)
93101
}
94102

95-
func (d ValidateMarketUpdateDecorator) doMarketsContainCrossMarket(ctx sdk.Context, markets []mmtypes.Market) bool {
103+
// doMarketsContainRestrictedMarket checks if any of the given markets are restricted:
104+
// 1. markets listed as CROSS perpetuals are restricted
105+
// 2. the USDT/USD market is always restricted
106+
func (d ValidateMarketUpdateDecorator) doMarketsContainRestrictedMarket(
107+
ctx sdk.Context,
108+
markets []mmtypes.Market,
109+
) (bool, string) {
96110
// Grab all the perpetuals markets
97111
perps := d.perpKeeper.GetAllPerpetuals(ctx)
98-
perpsMap := make(map[string]perpetualstypes.PerpetualMarketType)
112+
restrictedMap := make(map[string]bool, len(perps))
99113

100114
// Attempt to fetch the corresponding Prices market and map it to a currency pair
101115
for _, perp := range perps {
@@ -107,20 +121,24 @@ func (d ValidateMarketUpdateDecorator) doMarketsContainCrossMarket(ctx sdk.Conte
107121
if err != nil {
108122
continue
109123
}
110-
perpsMap[cp.String()] = perp.Params.MarketType
124+
restrictedMap[cp.String()] = perp.Params.MarketType == perpetualstypes.
125+
PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS
111126
}
112127

128+
// add usdt/usd market to be restricted
129+
restrictedMap[cpUSDTUSD.String()] = true
130+
113131
// Look in the mapped currency pairs to see if we have invalid updates
114132
for _, market := range markets {
115133
ticker := market.Ticker.CurrencyPair.String()
116134

117-
marketType, found := perpsMap[ticker]
118-
if found && marketType == perpetualstypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS {
119-
return true
135+
restricted, found := restrictedMap[ticker]
136+
if found && restricted {
137+
return true, ticker
120138
}
121139
}
122140

123-
return false
141+
return false, ""
124142
}
125143

126144
// doMarketsUpdateEnabledValues checks if the given markets updates are safe, specifically:

protocol/app/ante/market_update_test.go

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
11
package ante_test
22

33
import (
4-
storetypes "cosmossdk.io/store/types"
54
"math/rand"
65
"testing"
76

87
sdkmath "cosmossdk.io/math"
9-
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
10-
"github.com/dydxprotocol/v4-chain/protocol/dtypes"
11-
"github.com/dydxprotocol/v4-chain/protocol/testutil/constants"
12-
assets "github.com/dydxprotocol/v4-chain/protocol/x/assets/types"
13-
perpetualtypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
14-
prices_types "github.com/dydxprotocol/v4-chain/protocol/x/prices/types"
15-
"github.com/skip-mev/slinky/pkg/types"
16-
mmtypes "github.com/skip-mev/slinky/x/marketmap/types"
17-
8+
storetypes "cosmossdk.io/store/types"
189
"github.com/cosmos/cosmos-sdk/client"
1910
"github.com/cosmos/cosmos-sdk/client/tx"
2011
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
2112
sdk "github.com/cosmos/cosmos-sdk/types"
2213
"github.com/cosmos/cosmos-sdk/types/tx/signing"
2314
xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
15+
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
16+
"github.com/skip-mev/slinky/pkg/types"
17+
mmtypes "github.com/skip-mev/slinky/x/marketmap/types"
2418
"github.com/stretchr/testify/require"
2519

2620
"github.com/dydxprotocol/v4-chain/protocol/app/ante"
21+
"github.com/dydxprotocol/v4-chain/protocol/dtypes"
2722
slinkylib "github.com/dydxprotocol/v4-chain/protocol/lib/slinky"
2823
testante "github.com/dydxprotocol/v4-chain/protocol/testutil/ante"
2924
testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app"
25+
"github.com/dydxprotocol/v4-chain/protocol/testutil/constants"
26+
assets "github.com/dydxprotocol/v4-chain/protocol/x/assets/types"
27+
perpetualtypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
28+
prices_types "github.com/dydxprotocol/v4-chain/protocol/x/prices/types"
3029
)
3130

3231
func TestIsMarketUpdateTx(t *testing.T) {
@@ -212,6 +211,25 @@ var (
212211
},
213212
}
214213

214+
testUSDTUSDMarket = mmtypes.Market{
215+
Ticker: mmtypes.Ticker{
216+
CurrencyPair: types.CurrencyPair{
217+
Base: "USDT",
218+
Quote: "USD",
219+
},
220+
Decimals: 1,
221+
MinProviderCount: 1,
222+
Enabled: true,
223+
Metadata_JSON: "",
224+
},
225+
ProviderConfigs: []mmtypes.ProviderConfig{
226+
{
227+
Name: "test_provider",
228+
OffChainTicker: "USDT/USD",
229+
},
230+
},
231+
}
232+
215233
enabledTestMarketWithProviderConfig = mmtypes.Market{
216234
Ticker: mmtypes.Ticker{
217235
CurrencyPair: types.CurrencyPair{
@@ -726,6 +744,66 @@ func TestValidateMarketUpdateDecorator_AnteHandle(t *testing.T) {
726744
},
727745
wantErr: false,
728746
},
747+
{
748+
name: "always reject USDT/USD - simulate - upsert",
749+
args: args{
750+
msgs: []sdk.Msg{
751+
&mmtypes.MsgUpsertMarkets{
752+
Authority: constants.BobAccAddress.String(),
753+
Markets: []mmtypes.Market{
754+
testUSDTUSDMarket,
755+
},
756+
},
757+
},
758+
simulate: true,
759+
},
760+
wantErr: true,
761+
},
762+
{
763+
name: "always reject USDT/USD - upsert",
764+
args: args{
765+
msgs: []sdk.Msg{
766+
&mmtypes.MsgUpsertMarkets{
767+
Authority: constants.BobAccAddress.String(),
768+
Markets: []mmtypes.Market{
769+
testUSDTUSDMarket,
770+
},
771+
},
772+
},
773+
simulate: false,
774+
},
775+
wantErr: true,
776+
},
777+
{
778+
name: "always reject USDT/USD - simulate - update",
779+
args: args{
780+
msgs: []sdk.Msg{
781+
&mmtypes.MsgUpdateMarkets{
782+
Authority: constants.BobAccAddress.String(),
783+
UpdateMarkets: []mmtypes.Market{
784+
testUSDTUSDMarket,
785+
},
786+
},
787+
},
788+
simulate: true,
789+
},
790+
wantErr: true,
791+
},
792+
{
793+
name: "always reject USDT/USD - update",
794+
args: args{
795+
msgs: []sdk.Msg{
796+
&mmtypes.MsgUpdateMarkets{
797+
Authority: constants.BobAccAddress.String(),
798+
UpdateMarkets: []mmtypes.Market{
799+
testUSDTUSDMarket,
800+
},
801+
},
802+
},
803+
simulate: false,
804+
},
805+
wantErr: true,
806+
},
729807
}
730808
for _, tt := range tests {
731809
t.Run(tt.name, func(t *testing.T) {

protocol/app/ante_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func newHandlerOptions() app.HandlerOptions {
2929
AuthStoreKey: dydxApp.CommitMultiStore().(*rootmulti.Store).StoreKeysByName()[authtypes.StoreKey],
3030
PerpetualsKeeper: dydxApp.PerpetualsKeeper,
3131
PricesKeeper: dydxApp.PricesKeeper,
32+
MarketMapKeeper: &dydxApp.MarketMapKeeper,
3233
}
3334
}
3435

@@ -60,6 +61,10 @@ func TestNewAnteHandler_Error(t *testing.T) {
6061
handlerMutation: func(options *app.HandlerOptions) { options.PricesKeeper = nil },
6162
errorMsg: "prices keeper is required for ante builder",
6263
},
64+
"nil MarketMapKeeper": {
65+
handlerMutation: func(options *app.HandlerOptions) { options.MarketMapKeeper = nil },
66+
errorMsg: "market map keeper is required for ante builder",
67+
},
6368
"nil handlerOptions.SignModeHandler": {
6469
handlerMutation: func(options *app.HandlerOptions) { options.SignModeHandler = nil },
6570
errorMsg: "sign mode handler is required for ante builder",

0 commit comments

Comments
 (0)