Skip to content

Commit

Permalink
Integrate asset FT extensions into the DEX matching fuzz test.
Browse files Browse the repository at this point in the history
  • Loading branch information
dzmitryhil committed Nov 29, 2024
1 parent 8a6828d commit 1f5569a
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 20 deletions.
20 changes: 17 additions & 3 deletions testutil/simapp/simapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import (
"github.com/CoreumFoundation/coreum/v5/pkg/config/constant"
)

const appHash = "sim-app-hash"

// Settings for the simapp initialization.
type Settings struct {
db dbm.DB
Expand Down Expand Up @@ -128,23 +130,35 @@ func New(options ...Option) *App {

// BeginNextBlock begins new SimApp block and returns the ctx of the new block.
func (s *App) BeginNextBlock() (sdk.Context, sdk.BeginBlock, error) {
header := tmproto.Header{Height: s.App.LastBlockHeight() + 1, Time: time.Now()}
header := tmproto.Header{
Height: s.App.LastBlockHeight() + 1,
Time: time.Now(),
AppHash: []byte(appHash),
}
ctx := s.NewContextLegacy(false, header)
beginBlock, err := s.App.BeginBlocker(ctx)
return ctx, beginBlock, err
}

// BeginNextBlockAtTime begins new SimApp block and returns the ctx of the new block with given time.
func (s *App) BeginNextBlockAtTime(blockTime time.Time) (sdk.Context, sdk.BeginBlock, error) {
header := tmproto.Header{Height: s.App.LastBlockHeight() + 1, Time: blockTime}
header := tmproto.Header{
Height: s.App.LastBlockHeight() + 1,
Time: blockTime,
AppHash: []byte(appHash),
}
ctx := s.NewContextLegacy(false, header)
beginBlock, err := s.App.BeginBlocker(ctx)
return ctx, beginBlock, err
}

// BeginNextBlockAtHeight begins new SimApp block and returns the ctx of the new block with given hight.
func (s *App) BeginNextBlockAtHeight(height int64) (sdk.Context, sdk.BeginBlock, error) {
header := tmproto.Header{Height: height, Time: time.Now()}
header := tmproto.Header{
Height: height,
Time: time.Now(),
AppHash: []byte(appHash),
}
ctx := s.NewContextLegacy(false, header)
beginBlock, err := s.App.BeginBlocker(ctx)
return ctx, beginBlock, err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const AMOUNT_IGNORE_BURN_RATE_TRIGGER: Uint128 = Uint128::new(108);
const AMOUNT_IGNORE_SEND_COMMISSION_RATE_TRIGGER: Uint128 = Uint128::new(109);
const AMOUNT_BLOCK_IBC_TRIGGER: Uint128 = Uint128::new(110);
const AMOUNT_BLOCK_SMART_CONTRACT_TRIGGER: Uint128 = Uint128::new(111);
const ID_DEX_ORDER_TRIGGER: &str = "id-blocked";
const ID_DEX_ORDER_SUFFIX_TRIGGER: &str = "blocked";
const AMOUNT_DEX_EXPECT_TO_SPEND_TRIGGER: Uint128 = Uint128::new(103);
const AMOUNT_DEX_EXPECT_TO_RECEIVE_TRIGGER: Uint128 = Uint128::new(104);

Expand Down Expand Up @@ -183,7 +183,7 @@ pub fn sudo_extension_place_order(
expected_to_spend: Coin,
expected_to_receive: Coin,
) -> CoreumResult<ContractError> {
if order.id == ID_DEX_ORDER_TRIGGER
if order.id.ends_with(ID_DEX_ORDER_SUFFIX_TRIGGER)
|| expected_to_spend.amount == AMOUNT_DEX_EXPECT_TO_SPEND_TRIGGER.to_string()
|| expected_to_receive.amount == AMOUNT_DEX_EXPECT_TO_RECEIVE_TRIGGER.to_string()
{
Expand Down
27 changes: 24 additions & 3 deletions x/dex/keeper/keeper_ft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
)

var (
IDDEXOrderSuffixTrigger = "blocked"
AmountDEXExpectToSpendTrigger = sdkmath.NewInt(103)
AmountDEXExpectToReceiveTrigger = sdkmath.NewInt(104)
)
Expand Down Expand Up @@ -83,7 +84,7 @@ func TestKeeper_PlaceOrderWithExtension(t *testing.T) {
wantDEXErr: false,
},
{
name: "sell_dex_error",
name: "sell_dex_error_spend_amount",
order: types.Order{
Creator: func() string {
creator, _ := testApp.GenAccount(sdkCtx)
Expand All @@ -100,6 +101,24 @@ func TestKeeper_PlaceOrderWithExtension(t *testing.T) {
},
wantDEXErr: true,
},
{
name: "sell_dex_error_order_id",
order: types.Order{
Creator: func() string {
creator, _ := testApp.GenAccount(sdkCtx)
return creator.String()
}(),
Type: types.ORDER_TYPE_LIMIT,
ID: uuid.Generate().String()[:10] + IDDEXOrderSuffixTrigger,
BaseDenom: denomWithExtension,
QuoteDenom: denom2,
Price: lo.ToPtr(types.MustNewPriceFromString("1")),
Quantity: sdkmath.NewInt(10),
Side: types.SIDE_SELL,
TimeInForce: types.TIME_IN_FORCE_GTC,
},
wantDEXErr: true,
},
{
name: "buy_positive",
order: types.Order{
Expand All @@ -119,7 +138,7 @@ func TestKeeper_PlaceOrderWithExtension(t *testing.T) {
wantDEXErr: false,
},
{
name: "buy_dex_error",
name: "buy_dex_error_receive_amount",
order: types.Order{
Creator: func() string {
creator, _ := testApp.GenAccount(sdkCtx)
Expand Down Expand Up @@ -147,9 +166,11 @@ func TestKeeper_PlaceOrderWithExtension(t *testing.T) {
if !tt.wantDEXErr {
require.NoError(t, testApp.DEXKeeper.PlaceOrder(sdkCtx, tt.order))
} else {
err := testApp.DEXKeeper.PlaceOrder(sdkCtx, tt.order)
require.ErrorIs(t, err, assetfttypes.ErrExtensionCallFailed)
require.ErrorContains(
t,
testApp.DEXKeeper.PlaceOrder(sdkCtx, tt.order),
err,
"wasm error: DEX order placement is failed",
)
}
Expand Down
61 changes: 49 additions & 12 deletions x/dex/keeper/keeper_matching_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

sdkerrors "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -21,6 +22,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/CoreumFoundation/coreum/v5/testutil/simapp"
testcontracts "github.com/CoreumFoundation/coreum/v5/x/asset/ft/keeper/test-contracts"
assetfttypes "github.com/CoreumFoundation/coreum/v5/x/asset/ft/types"
"github.com/CoreumFoundation/coreum/v5/x/dex/types"
)
Expand All @@ -30,7 +32,7 @@ type FuzzAppConfig struct {
AssetFTDefaultDenomsCount int
AssetFTWhitelistingCount int
AssetFTFreezingDenomsCount int
AssetFTWhitelistedDenomsCount int
AssetFTExtensionDenomsCount int
AssetFTAllFeaturesDenomsCount int
NativeDenomCount int

Expand All @@ -42,11 +44,12 @@ type FuzzAppConfig struct {
CancelOrdersPercent int
CancelOrdersByDenomPercent int

MarketOrdersPercent int
TimeInForceIOCPercent int
TimeInForceFOKPercent int
GoodTilBlockHeightPercent int
GoodTilBlockTimePercent int
MarketOrdersPercent int
TimeInForceIOCPercent int
TimeInForceFOKPercent int
GoodTilBlockHeightPercent int
GoodTilBlockTimePercent int
ProhibitedExtensionOrderPercent int

FundOrderReservePercent int
CreateVestingAccountPercent int
Expand Down Expand Up @@ -95,6 +98,11 @@ func NewFuzzApp(
return denom
})

extensionCodeID, _, err := testApp.WasmPermissionedKeeper.Create(
sdkCtx, issuer, testcontracts.AssetExtensionWasm, &wasmtypes.AllowEverybody,
)
require.NoError(t, err)

ftDenoms := make([]string, 0)
defaultFTSettings := assetfttypes.IssueSettings{
Issuer: issuer,
Expand Down Expand Up @@ -140,6 +148,21 @@ func NewFuzzApp(
require.NoError(t, err)
return denom
})...)
ftDenoms = append(ftDenoms, lo.RepeatBy(cfg.AssetFTExtensionDenomsCount, func(i int) string {
settings := defaultFTSettings
settings.Symbol = fmt.Sprintf("EXT%d", i)
settings.Subunit = fmt.Sprintf("ext%d", i)
settings.Features = append(
settings.Features,
assetfttypes.Feature_extension,
)
settings.ExtensionSettings = &assetfttypes.ExtensionIssueSettings{
CodeId: extensionCodeID,
}
denom, err := testApp.AssetFTKeeper.Issue(sdkCtx, settings)
require.NoError(t, err)
return denom
})...)
ftDenoms = append(ftDenoms, lo.RepeatBy(cfg.AssetFTAllFeaturesDenomsCount, func(i int) string {
settings := defaultFTSettings
settings.Symbol = fmt.Sprintf("ALL%d", i)
Expand All @@ -149,7 +172,11 @@ func NewFuzzApp(
assetfttypes.Feature_whitelisting,
assetfttypes.Feature_freezing,
assetfttypes.Feature_dex_whitelisted_denoms,
assetfttypes.Feature_extension,
)
settings.ExtensionSettings = &assetfttypes.ExtensionIssueSettings{
CodeId: extensionCodeID,
}
denom, err := testApp.AssetFTKeeper.Issue(sdkCtx, settings)
require.NoError(t, err)
return denom
Expand Down Expand Up @@ -293,10 +320,15 @@ func (fa *FuzzApp) GenOrder(
quantity = 1
}

var orderIDSuffix string
if randBoolWithPercent(rnd, fa.cfg.ProhibitedExtensionOrderPercent) {
orderIDSuffix = IDDEXOrderSuffixTrigger
}

return types.Order{
Creator: creator.String(),
Type: orderType,
ID: randString(20, rnd),
ID: randString(20, rnd) + orderIDSuffix,
BaseDenom: baseDenom,
QuoteDenom: quoteDenom,
Price: price,
Expand Down Expand Up @@ -519,6 +551,9 @@ func (fa *FuzzApp) PlaceOrder(t *testing.T, sdkCtx sdk.Context, order types.Orde
receivableAmt.String(), requiredWhitelistedAmt.String(),
)
return
case sdkerrors.IsOf(err, assetfttypes.ErrExtensionCallFailed):
// the error is expected, the failure is cased by extension smart contract
return
case strings.Contains(err.Error(), "the price must be multiple of"), // price tick
strings.Contains(err.Error(), "good til"),
strings.Contains(err.Error(), "it's prohibited to save more than"),
Expand Down Expand Up @@ -604,6 +639,7 @@ func FuzzPlaceCancelOrder(f *testing.F) {
AssetFTDefaultDenomsCount: 2,
AssetFTWhitelistingCount: 2,
AssetFTFreezingDenomsCount: 2,
AssetFTExtensionDenomsCount: 2,
AssetFTAllFeaturesDenomsCount: 2,
NativeDenomCount: 2,

Expand All @@ -614,11 +650,12 @@ func FuzzPlaceCancelOrder(f *testing.F) {
CancelOrdersPercent: 5,
CancelOrdersByDenomPercent: 2,

MarketOrdersPercent: 8,
TimeInForceIOCPercent: 4,
TimeInForceFOKPercent: 4,
GoodTilBlockHeightPercent: 10,
GoodTilBlockTimePercent: 10,
MarketOrdersPercent: 8,
TimeInForceIOCPercent: 4,
TimeInForceFOKPercent: 4,
GoodTilBlockHeightPercent: 10,
GoodTilBlockTimePercent: 10,
ProhibitedExtensionOrderPercent: 10,

FundOrderReservePercent: 80,
CreateVestingAccountPercent: 25, // 25% of accounts will be vesting accounts
Expand Down

0 comments on commit 1f5569a

Please sign in to comment.