Skip to content

Commit

Permalink
fix: simulation for ERC20 module
Browse files Browse the repository at this point in the history
  • Loading branch information
poorphd committed Aug 23, 2023
1 parent 17307e9 commit 0b1bd63
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 201 deletions.
6 changes: 2 additions & 4 deletions app/params/weights.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ const (
DefaultWeightToggleTokenConversionProposal int = 5
DefaultWeightLendingMarketProposal int = 5
DefaultWeightTreasuryProposal int = 5
DefaultWeightMsgConvertCoinNativeCoin int = 20
DefaultWeightMsgConvertCoinNativeERC20 int = 20

DefaultWeightMsgConvertErc20NativeCoin int = 20
DefaultWeightMsgConvertErc20NativeToken int = 20
DefaultWeightMsgConvertCoin int = 20
DefaultWeightMsgConvertErc20 int = 20
)
5 changes: 3 additions & 2 deletions x/erc20/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,13 @@ func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes
}

func (am AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
return []simtypes.ParamChange{}
return simulation.ParamChanges(r)
}

func (am AppModule) RegisterStoreDecoder(decoderRegistry sdk.StoreDecoderRegistry) {
decoderRegistry[types.StoreKey] = simulation.NewDecodeStore(am.cdc)
}

func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
return []simtypes.WeightedOperation{}
return simulation.WeightedOperations(simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, am.keeper)
}
205 changes: 14 additions & 191 deletions x/erc20/simulation/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,8 @@ import (

// Simulation operation weights constants.
const (
OpWeightMsgConvertCoinNativeCoin = "op_weight_msg_convert_coin_native_coin"
OpWeightMsgConvertCoinNativeERC20 = "op_weight_msg_convert_coin_native_erc20"

OpWeightMsgConvertErc20NativeCoin = "op_weight_msg_convert_erc20_native_coin"
OpWeightMsgConvertErc20NativeToken = "op_weight_msg_convert_erc20_native_token"
OpWeightMsgConvertCoin = "op_weight_msg_convert_coin"
OpWeightMsgConvertErc20 = "op_weight_msg_convert_erc20"
)

var (
Expand All @@ -47,119 +44,29 @@ func WeightedOperations(
k keeper.Keeper,
) simulation.WeightedOperations {
var weightMsgConvertCoinNativeCoin int
appParams.GetOrGenerate(cdc, OpWeightMsgConvertCoinNativeCoin, &weightMsgConvertCoinNativeCoin, nil, func(_ *rand.Rand) {
weightMsgConvertCoinNativeCoin = params.DefaultWeightMsgConvertCoinNativeCoin
})

var weightMsgConvertCoinNativeERC20 int
appParams.GetOrGenerate(cdc, OpWeightMsgConvertCoinNativeERC20, &weightMsgConvertCoinNativeERC20, nil, func(_ *rand.Rand) {
weightMsgConvertCoinNativeERC20 = params.DefaultWeightMsgConvertCoinNativeERC20
appParams.GetOrGenerate(cdc, OpWeightMsgConvertCoin, &weightMsgConvertCoinNativeCoin, nil, func(_ *rand.Rand) {
weightMsgConvertCoinNativeCoin = params.DefaultWeightMsgConvertCoin
})

var weightMsgConvertErc20NativeCoin int
appParams.GetOrGenerate(cdc, OpWeightMsgConvertErc20NativeCoin, &weightMsgConvertErc20NativeCoin, nil, func(_ *rand.Rand) {
weightMsgConvertErc20NativeCoin = params.DefaultWeightMsgConvertErc20NativeCoin
})

var weightMsgConvertErc20NativeToken int
appParams.GetOrGenerate(cdc, OpWeightMsgConvertErc20NativeToken, &weightMsgConvertErc20NativeToken, nil, func(_ *rand.Rand) {
weightMsgConvertErc20NativeToken = params.DefaultWeightMsgConvertErc20NativeToken
appParams.GetOrGenerate(cdc, OpWeightMsgConvertErc20, &weightMsgConvertErc20NativeCoin, nil, func(_ *rand.Rand) {
weightMsgConvertErc20NativeCoin = params.DefaultWeightMsgConvertErc20
})

return simulation.WeightedOperations{
simulation.NewWeightedOperation(
weightMsgConvertCoinNativeCoin,
SimulateMsgConvertCoinNativeCoin(ak, bk, k),
),
simulation.NewWeightedOperation(
weightMsgConvertCoinNativeERC20,
SimulateMsgConvertCoinNativeERC20(ak, bk, k),
SimulateMsgConvertCoin(ak, bk, k),
),
simulation.NewWeightedOperation(
weightMsgConvertErc20NativeCoin,
SimulateMsgConvertErc20NativeCoin(ak, bk, k),
),
simulation.NewWeightedOperation(
weightMsgConvertErc20NativeToken,
SimulateMsgConvertErc20NativeToken(ak, bk, k),
SimulateMsgConvertErc20(ak, bk, k),
),
}
}

// SimulateMsgConvertCoinNativeCoin generates a MsgConvertCoin with random values for convertCoinNativeCoin
func SimulateMsgConvertCoinNativeCoin(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {

pairs := k.GetTokenPairs(ctx)

if len(pairs) == 0 {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgConvertCoin, "no pairs available"), nil, nil
}

var candidates []types.TokenPair
for _, pair := range pairs {
if pair.IsNativeCoin() {
candidates = append(candidates, pair)
}
}

if len(candidates) == 0 {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgConvertCoin, "no native coin pairs available"), nil, nil
}

// randomly pick one pair
pair := pairs[r.Intn(len(candidates))]
baseDenom := pair.GetDenom()

// select random account that has coins baseDenom
var simAccount simtypes.Account
var spendable sdk.Coins
skip := true

for i := 0; i < len(accs); i++ {
simAccount, _ = simtypes.RandomAcc(r, accs)
spendable = bk.SpendableCoins(ctx, simAccount.Address)
if spendable.AmountOf(baseDenom).IsPositive() {
skip = false
break
}
}

if skip {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgConvertCoin, "no account has coins"), nil, nil
}

priv, _ := ethsecp256k1.GenerateKey()
address := common.BytesToAddress(priv.PubKey().Address().Bytes())

msg := types.NewMsgConvertCoin(
sdk.NewCoin(baseDenom, spendable.AmountOf(baseDenom)),
address,
simAccount.Address,
)

txCtx := simulation.OperationInput{
R: r,
App: app,
TxGen: simapp.MakeTestEncodingConfig().TxConfig,
Cdc: nil,
Msg: msg,
MsgType: msg.Type(),
CoinsSpentInMsg: spendable,
Context: ctx,
SimAccount: simAccount,
AccountKeeper: ak,
Bankkeeper: bk,
ModuleName: types.ModuleName,
}
return types.GenAndDeliverTxWithFees(txCtx, Gas, Fees)
}
}

// SimulateMsgConvertCoinNativeERC20 generates a MsgConvertCoin with random values for convertCoinNativeERC20
func SimulateMsgConvertCoinNativeERC20(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
// SimulateMsgConvertCoin generates a MsgConvertCoin with random values for convertCoinNativeCoin
func SimulateMsgConvertCoin(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
Expand All @@ -170,25 +77,13 @@ func SimulateMsgConvertCoinNativeERC20(ak types.AccountKeeper, bk types.BankKeep
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgConvertCoin, "no pairs available"), nil, nil
}

var candidates []types.TokenPair
for _, pair := range pairs {
if pair.IsNativeERC20() {
candidates = append(candidates, pair)
}
}

if len(candidates) == 0 {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgConvertCoin, "no native ERC20 pairs available"), nil, nil
}

// randomly pick one pair
pair := pairs[r.Intn(len(candidates))]
pair := pairs[r.Intn(len(pairs))]
baseDenom := pair.GetDenom()

// select random account that has coins baseDenom
var simAccount simtypes.Account
var spendable sdk.Coins
erc20ABI := contracts.ERC20MinterBurnerDecimalsContract.ABI
skip := true

for i := 0; i < len(accs); i++ {
Expand All @@ -204,11 +99,6 @@ func SimulateMsgConvertCoinNativeERC20(ak types.AccountKeeper, bk types.BankKeep
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgConvertCoin, "no account has coins"), nil, nil
}

erc20Balance := k.BalanceOf(ctx, erc20ABI, pair.GetERC20Contract(), types.ModuleAddress)
if erc20Balance.Cmp(spendable.AmountOf(baseDenom).BigInt()) < 0 {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgConvertCoin, "ERC20 balance is not enough"), nil, nil
}

priv, _ := ethsecp256k1.GenerateKey()
address := common.BytesToAddress(priv.PubKey().Address().Bytes())

Expand Down Expand Up @@ -236,8 +126,8 @@ func SimulateMsgConvertCoinNativeERC20(ak types.AccountKeeper, bk types.BankKeep
}
}

// SimulateMsgConvertErc20NativeCoin generates a MsgConvertErc20 with random values for convertERC20NativeCoin.
func SimulateMsgConvertErc20NativeCoin(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
// SimulateMsgConvertErc20 generates a MsgConvertErc20 with random values for convertERC20NativeCoin.
func SimulateMsgConvertErc20(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
Expand All @@ -248,75 +138,8 @@ func SimulateMsgConvertErc20NativeCoin(ak types.AccountKeeper, bk types.BankKeep
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgConvertERC20, "no pairs available"), nil, nil
}

var candidates []types.TokenPair
for _, pair := range pairs {
if pair.IsNativeCoin() {
candidates = append(candidates, pair)
}
}

// randomly pick one pair
pair := pairs[r.Intn(len(candidates))]

// select random account that has coins baseDenom
var simAccount simtypes.Account
var erc20Balance *big.Int
erc20ABI := contracts.ERC20MinterBurnerDecimalsContract.ABI
skip := true

for i := 0; i < len(accs); i++ {
simAccount, _ = simtypes.RandomAcc(r, accs)
erc20Balance = k.BalanceOf(ctx, erc20ABI, pair.GetERC20Contract(), common.BytesToAddress(simAccount.Address.Bytes()))
if erc20Balance.Cmp(big.NewInt(0)) > 0 {
skip = false
break
}
}

if skip {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgConvertERC20, "no account has native ERC20"), nil, nil
}

msg := types.NewMsgConvertERC20(sdk.NewIntFromBigInt(erc20Balance), simAccount.Address, pair.GetERC20Contract(), common.BytesToAddress(simAccount.Address.Bytes()))

txCtx := simulation.OperationInput{
R: r,
App: app,
TxGen: simapp.MakeTestEncodingConfig().TxConfig,
Cdc: nil,
Msg: msg,
MsgType: msg.Type(),
CoinsSpentInMsg: sdk.NewCoins(),
Context: ctx,
SimAccount: simAccount,
AccountKeeper: ak,
Bankkeeper: bk,
ModuleName: types.ModuleName,
}
return types.GenAndDeliverTxWithFees(txCtx, Gas, Fees)
}
}

// SimulateMsgConvertErc20NativeToken generates a MsgConvertErc20 with random values for convertERC20NativeToken.
func SimulateMsgConvertErc20NativeToken(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
pairs := k.GetTokenPairs(ctx)

if len(pairs) == 0 {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgConvertERC20, "no pairs available"), nil, nil
}

var candidates []types.TokenPair
for _, pair := range pairs {
if pair.IsNativeERC20() {
candidates = append(candidates, pair)
}
}

// randomly pick one pair
pair := pairs[r.Intn(len(candidates))]
pair := pairs[r.Intn(len(pairs))]

// select random account that has coins baseDenom
var simAccount simtypes.Account
Expand Down
6 changes: 2 additions & 4 deletions x/erc20/simulation/operation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,8 @@ func TestWeightedOperations(t *testing.T) {
opMsgRoute string
opMsgName string
}{
{params.DefaultWeightMsgConvertCoinNativeCoin, types.ModuleName, types.TypeMsgConvertCoin},
{params.DefaultWeightMsgConvertCoinNativeERC20, types.ModuleName, types.TypeMsgConvertCoin},
{params.DefaultWeightMsgConvertErc20NativeCoin, types.ModuleName, types.TypeMsgConvertERC20},
{params.DefaultWeightMsgConvertErc20NativeToken, types.ModuleName, types.TypeMsgConvertERC20},
{params.DefaultWeightMsgConvertCoin, types.ModuleName, types.TypeMsgConvertCoin},
{params.DefaultWeightMsgConvertErc20, types.ModuleName, types.TypeMsgConvertERC20},
}

for i, w := range weightedOps {
Expand Down

0 comments on commit 0b1bd63

Please sign in to comment.