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. simulation codes for canto modules #65

Merged
merged 27 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c1422aa
feat: simulation for `coinswap` module
poorphd Jul 4, 2024
683e130
feat: simulation for `csr` module
poorphd Jul 4, 2024
d41595f
feat: simulation for `epochs` module
poorphd Jul 4, 2024
4f222ea
WIP: simulation for `erc20` module
poorphd Jul 4, 2024
c7742e3
WIP: simulation for `govshuttle` module
poorphd Jul 4, 2024
adb6bb4
feat: simulation for `inflation` module
poorphd Jul 4, 2024
25d9a53
feat: proposal simulation for `erc20` module
poorphd Jul 5, 2024
e4cf1a8
feat: proposal simulation for `govshuttle` module
poorphd Jul 5, 2024
c9021b2
WIP: proposal simulation for `erc20` module
poorphd Jul 8, 2024
2d65e23
WIP: proposal simulation for `erc20` module
poorphd Jul 8, 2024
f1af21c
feat: proposal simulation for `erc20` module
poorphd Jul 8, 2024
cce1043
chore: missing methods for mock keepers
poorphd Jul 9, 2024
447a4d7
refactor: Remove RandomizedParams from AppModuleSimulation interface
poorphd Jul 9, 2024
fe7b5b8
fix: NoOpMsg for disabled pair
poorphd Jul 9, 2024
df52384
fix: NoOpMsg types
poorphd Jul 9, 2024
9c8ad99
Merge remote-tracking branch 'refs/remotes/origin/v8/develop' into pa…
poorphd Jul 10, 2024
9e696e8
Merge branch 'v8/develop' into patch/simulation
poorphd Jul 24, 2024
45ac147
fix: msg route registeration
poorphd Jul 24, 2024
66d4aea
fix: key prefix name
poorphd Jul 24, 2024
1e4dd7e
fix: coinswap module's operation simulation
poorphd Jul 25, 2024
542ac82
chore: make MintCoins to use variable amount instead of int value
poorphd Jul 25, 2024
1089c9b
fix: panic on division by zero
poorphd Jul 25, 2024
ed9eef0
fix: commnets
poorphd Jul 26, 2024
6d15af1
feat: implement RegisterStoreDecoder for canto modules
poorphd Jul 26, 2024
096d7d1
chore: interface chack for module.AppModuleSimulation
poorphd Jul 26, 2024
332ff06
fix: add liquidity operation
poorphd Jul 26, 2024
1c5079b
fix: swap operation
poorphd Jul 26, 2024
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
8 changes: 4 additions & 4 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -758,12 +758,12 @@ func NewCanto(
feemarket.NewAppModule(app.FeeMarketKeeper, feeMarketSs),

// Canto app modules
inflation.NewAppModule(app.InflationKeeper, app.AccountKeeper, *app.StakingKeeper),
erc20.NewAppModule(app.Erc20Keeper, app.AccountKeeper, app.AccountKeeper.AddressCodec()),
inflation.NewAppModule(appCodec, app.InflationKeeper, app.AccountKeeper, *app.StakingKeeper),
erc20.NewAppModule(appCodec, app.Erc20Keeper, app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.FeeMarketKeeper, app.AccountKeeper.AddressCodec()),
epochs.NewAppModule(appCodec, app.EpochsKeeper),
onboarding.NewAppModule(*app.OnboardingKeeper),
govshuttle.NewAppModule(app.GovshuttleKeeper, app.AccountKeeper, app.AccountKeeper.AddressCodec()),
csr.NewAppModule(app.CSRKeeper, app.AccountKeeper),
govshuttle.NewAppModule(appCodec, app.GovshuttleKeeper, app.AccountKeeper, app.AccountKeeper.AddressCodec()),
csr.NewAppModule(appCodec, app.CSRKeeper, app.AccountKeeper),
coinswap.NewAppModule(appCodec, app.CoinswapKeeper, app.AccountKeeper, app.BankKeeper),
)

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 = 50
DefaultWeightMsgAddLiquidity int = 10
DefaultWeightMsgRemoveLiquidity int = 10
)
15 changes: 10 additions & 5 deletions x/coinswap/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
"math/rand"

"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -40,6 +39,11 @@ type AppModuleBasic struct {
cdc codec.Codec
}

// NewAppModuleBasic return a new AppModuleBasic
func NewAppModuleBasic(cdc codec.Codec) AppModuleBasic {
return AppModuleBasic{cdc: cdc}
}

// Name returns the coinswap module's name.
func (AppModuleBasic) Name() string { return types.ModuleName }

Expand Down Expand Up @@ -100,7 +104,7 @@ type AppModule struct {
// NewAppModule creates a new AppModule object
func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{cdc: cdc},
AppModuleBasic: NewAppModuleBasic(cdc),
keeper: keeper,
accountKeeper: accountKeeper,
bankKeeper: bankKeeper,
Expand Down Expand Up @@ -157,13 +161,14 @@ func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.We
return nil
}

// RandomizedParams creates randomized coinswap param changes for the simulator.
func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.LegacyParamChange {
return simulation.ParamChanges(r)
// ProposalMsgs returns msgs used for governance proposals for simulations.
func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg {
return simulation.ProposalMsgs()
}

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

// WeightedOperations returns the all the coinswap module operations with their respective weights.
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]))
}
}
}
61 changes: 61 additions & 0 deletions x/coinswap/simulation/decoder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package simulation_test

import (
"fmt"
"testing"

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

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

func TestCoinSwapStore(t *testing.T) {
encodingConfig := moduletestutil.MakeTestEncodingConfig(module.AppModuleBasic{})
cdc := encodingConfig.Codec
dec := simulation.NewDecodeStore(cdc)

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.MustMarshal(&pool)},
{Key: []byte(types.KeyPoolLptDenom), Value: cdc.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)
}
})
}
}
75 changes: 74 additions & 1 deletion x/coinswap/simulation/genesis.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,81 @@
package simulation

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

sdkmath "cosmossdk.io/math"
"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) sdkmath.LegacyDec {
return sdkmath.LegacyNewDecWithPrec(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) sdkmath.LegacyDec {
return sdkmath.LegacyNewDecWithPrec(int64(simtypes.RandIntBetween(r, 0, 10)), 3)
}

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

func generateRandomMaxSwapAmount(r *rand.Rand) sdk.Coins {
return sdk.NewCoins(
sdk.NewCoin(types.UsdcIBCDenom, sdkmath.NewIntWithDecimal(int64(simtypes.RandIntBetween(r, 1, 100)), 6)),
sdk.NewCoin(types.UsdtIBCDenom, sdkmath.NewIntWithDecimal(int64(simtypes.RandIntBetween(r, 1, 100)), 6)),
sdk.NewCoin(types.EthIBCDenom, sdkmath.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(
fee, &genesis.Params.Fee, simState.Rand,
func(r *rand.Rand) { genesis.Params.Fee = generateRandomFee(r) },
)

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

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

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

simState.AppParams.GetOrGenerate(
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)

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

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

"cosmossdk.io/math"
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: math.NewInt(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, math.LegacyNewDecWithPrec(4, 3), genState.Params.Fee)
require.Equal(t, sdk.NewInt64Coin(sdk.DefaultBondDenom, 163511), genState.Params.PoolCreationFee)
require.Equal(t, math.LegacyNewDecWithPrec(6, 3), genState.Params.TaxRate)
require.Equal(t, math.NewIntWithDecimal(3310, 18), genState.Params.MaxStandardCoinPerPool)
require.Equal(t, sdk.NewCoins(
sdk.NewCoin(types.UsdcIBCDenom, math.NewIntWithDecimal(70, 6)),
sdk.NewCoin(types.UsdtIBCDenom, math.NewIntWithDecimal(52, 6)),
sdk.NewCoin(types.EthIBCDenom, math.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