Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: simulations for canto modules #47

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,8 @@ func NewCanto(
AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)).
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)).
AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)).
AddRoute(erc20types.RouterKey, erc20.NewErc20ProposalHandler(&app.Erc20Keeper)).
AddRoute(govshuttletypes.RouterKey, govshuttle.NewgovshuttleProposalHandler(&app.GovshuttleKeeper))
AddRoute(erc20types.RouterKey, erc20keeper.NewErc20ProposalHandler(&app.Erc20Keeper)).
AddRoute(govshuttletypes.RouterKey, govshuttlekeeper.NewgovshuttleProposalHandler(&app.GovshuttleKeeper))

govKeeper := govkeeper.NewKeeper(
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName),
Expand Down Expand Up @@ -595,12 +595,12 @@ func NewCanto(
evm.NewAppModule(app.EvmKeeper, app.AccountKeeper),
feemarket.NewAppModule(app.FeeMarketKeeper),
// Canto app modules
inflation.NewAppModule(app.InflationKeeper, app.AccountKeeper, app.StakingKeeper),
erc20.NewAppModule(app.Erc20Keeper, app.AccountKeeper),
inflation.NewAppModule(appCodec, app.InflationKeeper, app.AccountKeeper, app.StakingKeeper),
erc20.NewAppModule(appCodec, app.Erc20Keeper, app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.FeeMarketKeeper),
epochs.NewAppModule(appCodec, app.EpochsKeeper),
onboarding.NewAppModule(*app.OnboardingKeeper),
govshuttle.NewAppModule(app.GovshuttleKeeper, app.AccountKeeper),
csr.NewAppModule(app.CSRKeeper, app.AccountKeeper),
govshuttle.NewAppModule(appCodec, app.GovshuttleKeeper, app.AccountKeeper),
csr.NewAppModule(appCodec, app.CSRKeeper, app.AccountKeeper),
coinswap.NewAppModule(appCodec, app.CoinswapKeeper, app.AccountKeeper, app.BankKeeper),
)

Expand Down Expand Up @@ -745,9 +745,12 @@ func NewCanto(
// canto, ethermint modules
evm.NewAppModule(app.EvmKeeper, app.AccountKeeper),
epochs.NewAppModule(appCodec, app.EpochsKeeper),
inflation.NewAppModule(app.InflationKeeper, app.AccountKeeper, app.StakingKeeper),
inflation.NewAppModule(appCodec, app.InflationKeeper, app.AccountKeeper, app.StakingKeeper),
feemarket.NewAppModule(app.FeeMarketKeeper),
coinswap.NewAppModule(appCodec, app.CoinswapKeeper, app.AccountKeeper, app.BankKeeper),
csr.NewAppModule(appCodec, app.CSRKeeper, app.AccountKeeper),
govshuttle.NewAppModule(appCodec, app.GovshuttleKeeper, app.AccountKeeper),
erc20.NewAppModule(appCodec, app.Erc20Keeper, app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.FeeMarketKeeper),

// TODO: Modules that have not yet been implemented for simulation
// govshuttle, csr, inflation, erc20
Expand Down
16 changes: 16 additions & 0 deletions app/params/weights.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package params

const (
DefaultWeightRegisterCoinProposal int = 5
DefaultWeightRegisterERC20Proposal int = 5
DefaultWeightToggleTokenConversionProposal int = 5
DefaultWeightLendingMarketProposal int = 5
DefaultWeightTreasuryProposal int = 5

DefaultWeightMsgConvertCoin int = 20
DefaultWeightMsgConvertErc20 int = 20

DefaultWeightMsgSwapOrder int = 10
DefaultWeightMsgAddLiquidity int = 20
DefaultWeightMsgRemoveLiquidity int = 10
)
4 changes: 3 additions & 1 deletion app/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ func TestAppImportExport(t *testing.T) {
},
},
{app.keys[distrtypes.StoreKey], newApp.keys[distrtypes.StoreKey], [][]byte{}},
{app.keys[paramstypes.StoreKey], newApp.keys[paramstypes.StoreKey], [][]byte{}},
{app.keys[paramstypes.StoreKey], newApp.keys[paramstypes.StoreKey], [][]byte{
[]byte("evm/EnableExtraEIPs"), []byte("bank/SendEnabled"),
}},
{app.keys[evidencetypes.StoreKey], newApp.keys[evidencetypes.StoreKey], [][]byte{}},
{app.keys[capabilitytypes.StoreKey], newApp.keys[capabilitytypes.StoreKey], [][]byte{}},
{app.keys[feegrant.StoreKey], newApp.keys[feegrant.StoreKey], [][]byte{}},
Expand Down
3 changes: 3 additions & 0 deletions proto/canto/csr/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package canto.csr.v1;

import "gogoproto/gogo.proto";
import "canto/csr/v1/params.proto";
import "canto/csr/v1/csr.proto";

option go_package = "github.com/Canto-Network/Canto/v7/x/csr/types";

// GenesisState defines the csr module's genesis state.
message GenesisState {
// params defines all of the parameters of the module
Params params = 1 [ (gogoproto.nullable) = false ];
repeated CSR csrs = 2 [ (gogoproto.nullable) = false ];
bytes turnstile_address = 3;
}
1 change: 1 addition & 0 deletions proto/canto/govshuttle/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ option go_package = "github.com/Canto-Network/Canto/v7/x/govshuttle/types";
// GenesisState defines the govshuttle module's genesis state.
message GenesisState {
Params params = 1 [ (gogoproto.nullable) = false ];
bytes port_address = 2;
// this line is used by starport scaffolding # genesis/proto/state
}
1 change: 1 addition & 0 deletions x/coinswap/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {

// RegisterStoreDecoder registers a decoder for coinswap module's types
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc)

}

Expand Down
37 changes: 34 additions & 3 deletions x/coinswap/simulation/decoder.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,41 @@
package simulation

import (
"bytes"
"fmt"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/kv"

"github.com/Canto-Network/Canto/v7/x/coinswap/types"
)

// DecodeStore unmarshals the KVPair's Value to the corresponding htlc type
func DecodeStore(kvA, kvB kv.Pair) string {
return ""
// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
// Value to the corresponding farming type.
func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string {
return func(kvA, kvB kv.Pair) string {
switch {
case bytes.Equal(kvA.Key[:], []byte(types.KeyPool)):
var pA, pB types.Pool
cdc.MustUnmarshal(kvA.Value, &pA)
cdc.MustUnmarshal(kvB.Value, &pB)
return fmt.Sprintf("%v\n%v", pA, pB)

case bytes.Equal(kvA.Key[:], []byte(types.KeyNextPoolSequence)):
var seqA, seqB uint64
seqA = sdk.BigEndianToUint64(kvA.Value)
seqB = sdk.BigEndianToUint64(kvB.Value)
return fmt.Sprintf("%v\n%v", seqA, seqB)

case bytes.Equal(kvA.Key[:], []byte(types.KeyPoolLptDenom)):
var pA, pB types.Pool
cdc.MustUnmarshal(kvA.Value, &pA)
cdc.MustUnmarshal(kvB.Value, &pB)
return fmt.Sprintf("%v\n%v", pA, pB)

default:
panic(fmt.Sprintf("invalid coinswap key prefix %X", kvA.Key[:1]))
}
}
}
59 changes: 59 additions & 0 deletions x/coinswap/simulation/decoder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package simulation_test

import (
"fmt"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"

"github.com/Canto-Network/Canto/v7/x/coinswap/simulation"
"github.com/Canto-Network/Canto/v7/x/coinswap/types"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/types/kv"
)

func TestCoinSwapStore(t *testing.T) {
cdc := simapp.MakeTestEncodingConfig()
dec := simulation.NewDecodeStore(cdc.Marshaler)

pool := types.Pool{
Id: types.GetPoolId("denom1"),
StandardDenom: "denom2",
CounterpartyDenom: "denom1",
EscrowAddress: types.GetReservePoolAddr("lptDenom").String(),
LptDenom: "lptDenom",
}

sequence := uint64(1)

kvPairs := kv.Pairs{
Pairs: []kv.Pair{
{Key: []byte(types.KeyPool), Value: cdc.Marshaler.MustMarshal(&pool)},
{Key: []byte(types.KeyPoolLptDenom), Value: cdc.Marshaler.MustMarshal(&pool)},
{Key: []byte(types.KeyNextPoolSequence), Value: sdk.Uint64ToBigEndian(sequence)},
{Key: []byte{0x99}, Value: []byte{0x99}},
},
}

tests := []struct {
name string
expectedLog string
}{
{"Pool", fmt.Sprintf("%v\n%v", pool, pool)},
{"PoolLptDenom", fmt.Sprintf("%v\n%v", pool, pool)},
{"NextPoolSequence", fmt.Sprintf("%v\n%v", sequence, sequence)},
{"other", ""},
}
for i, tt := range tests {
i, tt := i, tt
t.Run(tt.name, func(t *testing.T) {
switch i {
case len(tests) - 1:
require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name)
default:
require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name)
}
})
}
}
74 changes: 73 additions & 1 deletion x/coinswap/simulation/genesis.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,80 @@
package simulation

import (
"encoding/json"
"fmt"
"math/rand"

"github.com/Canto-Network/Canto/v7/x/coinswap/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
)

// simulation parameter constants
const (
fee = "fee"
poolCreationFee = "pool_creation_fee"
taxRate = "tax_rate"
maxStandardCoinPerPool = "max_standard_coin_per_pool"
maxSwapAmount = "max_swap_amount"
)

func generateRandomFee(r *rand.Rand) sdk.Dec {
return sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 0, 10)), 3)
}

func generateRandomPoolCreationFee(r *rand.Rand) sdk.Coin {
return sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simtypes.RandIntBetween(r, 0, 1000000)))
}

func generateRandomTaxRate(r *rand.Rand) sdk.Dec {
return sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 0, 10)), 3)
}

func generateRandomMaxStandardCoinPerPool(r *rand.Rand) sdk.Int {
return sdk.NewIntWithDecimal(int64(simtypes.RandIntBetween(r, 0, 10000)), 18)
}

func generateRandomMaxSwapAmount(r *rand.Rand) sdk.Coins {
return sdk.NewCoins(
sdk.NewCoin(types.UsdcIBCDenom, sdk.NewIntWithDecimal(int64(simtypes.RandIntBetween(r, 1, 100)), 6)),
sdk.NewCoin(types.UsdtIBCDenom, sdk.NewIntWithDecimal(int64(simtypes.RandIntBetween(r, 1, 100)), 6)),
sdk.NewCoin(types.EthIBCDenom, sdk.NewIntWithDecimal(int64(simtypes.RandIntBetween(r, 1, 100)), 16)),
)
}

// RandomizedGenState generates a random GenesisState for coinswap
func RandomizedGenState(simState *module.SimulationState) {}
func RandomizedGenState(simState *module.SimulationState) {
genesis := types.DefaultGenesisState()

simState.AppParams.GetOrGenerate(
simState.Cdc, fee, &genesis.Params.Fee, simState.Rand,
func(r *rand.Rand) { genesis.Params.Fee = generateRandomFee(r) },
)

simState.AppParams.GetOrGenerate(
simState.Cdc, poolCreationFee, &genesis.Params.PoolCreationFee, simState.Rand,
func(r *rand.Rand) { genesis.Params.PoolCreationFee = generateRandomPoolCreationFee(r) },
)

simState.AppParams.GetOrGenerate(
simState.Cdc, taxRate, &genesis.Params.TaxRate, simState.Rand,
func(r *rand.Rand) { genesis.Params.TaxRate = generateRandomTaxRate(r) },
)

simState.AppParams.GetOrGenerate(
simState.Cdc, maxStandardCoinPerPool, &genesis.Params.MaxStandardCoinPerPool, simState.Rand,
func(r *rand.Rand) { genesis.Params.MaxStandardCoinPerPool = generateRandomMaxStandardCoinPerPool(r) },
)

simState.AppParams.GetOrGenerate(
simState.Cdc, maxSwapAmount, &genesis.Params.MaxSwapAmount, simState.Rand,
func(r *rand.Rand) { genesis.Params.MaxSwapAmount = generateRandomMaxSwapAmount(r) },
)

bz, _ := json.MarshalIndent(&genesis, "", " ")
fmt.Printf("Selected randomly generated coinswap parameters:\n%s\n", bz)
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(genesis)

}
80 changes: 80 additions & 0 deletions x/coinswap/simulation/genesis_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package simulation_test

import (
"encoding/json"
"math/rand"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"

"github.com/Canto-Network/Canto/v7/x/coinswap/simulation"
"github.com/Canto-Network/Canto/v7/x/coinswap/types"
)

func TestRandomizedGenState(t *testing.T) {
interfaceRegistry := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(interfaceRegistry)

s := rand.NewSource(2)
r := rand.New(s)

simState := module.SimulationState{
AppParams: make(simtypes.AppParams),
Cdc: cdc,
Rand: r,
NumBonded: 3,
Accounts: simtypes.RandomAccounts(r, 3),
InitialStake: 1000,
GenState: make(map[string]json.RawMessage),
}

simulation.RandomizedGenState(&simState)

var genState types.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &genState)

require.Equal(t, sdk.NewDecWithPrec(4, 3), genState.Params.Fee)
require.Equal(t, sdk.NewInt64Coin(sdk.DefaultBondDenom, 163511), genState.Params.PoolCreationFee)
require.Equal(t, sdk.NewDecWithPrec(6, 3), genState.Params.TaxRate)
require.Equal(t, sdk.NewIntWithDecimal(3310, 18), genState.Params.MaxStandardCoinPerPool)
require.Equal(t, sdk.NewCoins(
sdk.NewCoin(types.UsdcIBCDenom, sdk.NewIntWithDecimal(70, 6)),
sdk.NewCoin(types.UsdtIBCDenom, sdk.NewIntWithDecimal(52, 6)),
sdk.NewCoin(types.EthIBCDenom, sdk.NewIntWithDecimal(65, 16)),
), genState.Params.MaxSwapAmount)

}

// TestInvalidGenesisState tests invalid genesis states.
func TestInvalidGenesisState(t *testing.T) {
interfaceRegistry := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(interfaceRegistry)

s := rand.NewSource(1)
r := rand.New(s)

// all these tests will panic
tests := []struct {
simState module.SimulationState
panicMsg string
}{
{ // panic => reason: incomplete initialization of the simState
module.SimulationState{}, "invalid memory address or nil pointer dereference"},
{ // panic => reason: incomplete initialization of the simState
module.SimulationState{
AppParams: make(simtypes.AppParams),
Cdc: cdc,
Rand: r,
}, "assignment to entry in nil map"},
}

for _, tt := range tests {
require.Panicsf(t, func() { simulation.RandomizedGenState(&tt.simState) }, tt.panicMsg)
}
}
Loading
Loading