From 42ac595f2adc66a9fde59e7f09677772345bb9ed Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 23 Jan 2026 15:56:37 +0100 Subject: [PATCH 1/7] feat: wire in place testnet command --- cmd/atomoned/cmd/inplace_testnet.go | 240 ++++++++++++++++++++++++++++ cmd/atomoned/cmd/root.go | 1 + 2 files changed, 241 insertions(+) create mode 100644 cmd/atomoned/cmd/inplace_testnet.go diff --git a/cmd/atomoned/cmd/inplace_testnet.go b/cmd/atomoned/cmd/inplace_testnet.go new file mode 100644 index 000000000..43a5ae3f8 --- /dev/null +++ b/cmd/atomoned/cmd/inplace_testnet.go @@ -0,0 +1,240 @@ +package cmd + +import ( + "errors" + "fmt" + "io" + "os" + "strings" + + "cosmossdk.io/log" + "cosmossdk.io/math" + storetypes "cosmossdk.io/store/types" + atomone "github.com/atomone-hub/atomone/app" + "github.com/cometbft/cometbft/crypto" + "github.com/cometbft/cometbft/libs/bytes" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/client/flags" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/server" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/spf13/cast" + "github.com/spf13/cobra" +) + +const valVotingPower int64 = 900000000000000 + +var flagAccountsToFund = "accounts-to-fund" + +type valArgs struct { + newValAddr bytes.HexBytes + newOperatorAddress string + newValPubKey crypto.PubKey + accountsToFund []string + upgradeToTrigger string + homeDir string +} + +func NewInPlaceTestnetCmd() *cobra.Command { + cmd := server.InPlaceTestnetCreator(newTestnetApp) + cmd.Short = "Updates chain's application and consensus state with provided validator info and starts the node" + cmd.Long = `The test command modifies both application and consensus stores within a local mainnet node and starts the node, +with the aim of facilitating testing procedures. This command replaces existing validator data with updated information, +thereby removing the old validator set and introducing a new set suitable for local testing purposes. By altering the state extracted from the mainnet node, +it enables developers to configure their local environments to reflect mainnet conditions more accurately.` + cmd.Example = `atomoned in-place-testnet testing-1 cosmosvaloper1w7f3xx7e75p4l7qdym5msqem9rd4dyc4mq79dm --home $HOME/.atomone/validator1 --validator-privkey=6dq+/KHNvyiw2TToCgOpUpQKIzrLs69Rb8Az39xvmxPHNoPxY1Cil8FY+4DhT9YwD6s0tFABMlLcpaylzKKBOg== --accounts-to-fund="cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq,cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x"` + + cmd.Flags().String(flagAccountsToFund, "", "Comma-separated list of account addresses that will be funded for testing purposes") + return cmd +} + +// newTestnetApp starts by running the normal newApp method. From there, the app interface returned is modified in order +// for a testnet to be created from the provided app. +func newTestnetApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { + // Create an app and type cast to an App + newApp := newApp(logger, db, traceStore, appOpts) + testApp, ok := newApp.(*atomone.AtomOneApp) + if !ok { + panic("app created from newApp is not of type App") + } + + // Get command args + args, err := getCommandArgs(appOpts) + if err != nil { + panic(err) + } + + return initAppForTestnet(testApp, args) +} + +func initAppForTestnet(app *atomone.AtomOneApp, args valArgs) *atomone.AtomOneApp { + // Required Changes: + // + ctx := app.NewUncachedContext(true, cmtproto.Header{}) + + pubkey := &ed25519.PubKey{Key: args.newValPubKey.Bytes()} + pubkeyAny, err := codectypes.NewAnyWithValue(pubkey) + handleErr(err) + + // STAKING + // + + // Create Validator struct for our new validator. + newVal := stakingtypes.Validator{ + OperatorAddress: args.newOperatorAddress, + ConsensusPubkey: pubkeyAny, + Jailed: false, + Status: stakingtypes.Bonded, + Tokens: math.NewInt(valVotingPower), + DelegatorShares: math.LegacyMustNewDecFromStr("10000000"), + Description: stakingtypes.Description{ + Moniker: "Testnet Validator", + }, + Commission: stakingtypes.Commission{ + CommissionRates: stakingtypes.CommissionRates{ + Rate: math.LegacyMustNewDecFromStr("0.05"), + MaxRate: math.LegacyMustNewDecFromStr("0.1"), + MaxChangeRate: math.LegacyMustNewDecFromStr("0.05"), + }, + }, + MinSelfDelegation: math.OneInt(), + } + + validator, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(newVal.GetOperator()) + handleErr(err) + + // Remove all validators from power store + stakingKey := app.GetKey(stakingtypes.ModuleName) + stakingStore := ctx.KVStore(stakingKey) + iterator, err := app.StakingKeeper.ValidatorsPowerStoreIterator(ctx) + handleErr(err) + + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Remove all validators from last validators store + iterator, err = app.StakingKeeper.LastValidatorsIterator(ctx) + handleErr(err) + + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Remove all validators from validators store + iterator = stakingStore.Iterator(stakingtypes.ValidatorsKey, storetypes.PrefixEndBytes(stakingtypes.ValidatorsKey)) + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Remove all validators from unbonding queue + iterator = stakingStore.Iterator(stakingtypes.ValidatorQueueKey, storetypes.PrefixEndBytes(stakingtypes.ValidatorQueueKey)) + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Add our validator to power and last validators store + handleErr(app.StakingKeeper.SetValidator(ctx, newVal)) + handleErr(app.StakingKeeper.SetValidatorByConsAddr(ctx, newVal)) + handleErr(app.StakingKeeper.SetValidatorByPowerIndex(ctx, newVal)) + handleErr(app.StakingKeeper.SetLastValidatorPower(ctx, validator, 0)) + handleErr(app.StakingKeeper.Hooks().AfterValidatorCreated(ctx, validator)) + + // DISTRIBUTION + // + + // Initialize records for this validator across all distribution stores + handleErr(app.DistrKeeper.SetValidatorHistoricalRewards(ctx, validator, 0, distrtypes.NewValidatorHistoricalRewards(sdk.DecCoins{}, 1))) + handleErr(app.DistrKeeper.SetValidatorCurrentRewards(ctx, validator, distrtypes.NewValidatorCurrentRewards(sdk.DecCoins{}, 1))) + handleErr(app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, validator, distrtypes.InitialValidatorAccumulatedCommission())) + handleErr(app.DistrKeeper.SetValidatorOutstandingRewards(ctx, validator, distrtypes.ValidatorOutstandingRewards{Rewards: sdk.DecCoins{}})) + + // SLASHING + // + + // Set validator signing info for our new validator. + newConsAddr := sdk.ConsAddress(args.newValAddr.Bytes()) + newValidatorSigningInfo := slashingtypes.ValidatorSigningInfo{ + Address: newConsAddr.String(), + StartHeight: app.LastBlockHeight() - 1, + Tombstoned: false, + } + _ = app.SlashingKeeper.SetValidatorSigningInfo(ctx, newConsAddr, newValidatorSigningInfo) + + // BANK + // + bondDenom, err := app.StakingKeeper.BondDenom(ctx) + handleErr(err) + + defaultCoins := sdk.NewCoins(sdk.NewInt64Coin(bondDenom, 1000000000)) + + // Fund local accounts + for _, accountStr := range args.accountsToFund { + handleErr(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, defaultCoins)) + + account, err := app.AccountKeeper.AddressCodec().StringToBytes(accountStr) + handleErr(err) + + handleErr(app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, account, defaultCoins)) + } + + return app +} + +// parse the input flags and returns valArgs +func getCommandArgs(appOpts servertypes.AppOptions) (valArgs, error) { + args := valArgs{} + + newValAddr, ok := appOpts.Get(server.KeyNewValAddr).(bytes.HexBytes) + if !ok { + return args, errors.New("newValAddr is not of type bytes.HexBytes") + } + args.newValAddr = newValAddr + newValPubKey, ok := appOpts.Get(server.KeyUserPubKey).(crypto.PubKey) + if !ok { + return args, errors.New("newValPubKey is not of type crypto.PubKey") + } + args.newValPubKey = newValPubKey + newOperatorAddress, ok := appOpts.Get(server.KeyNewOpAddr).(string) + if !ok { + return args, errors.New("newOperatorAddress is not of type string") + } + args.newOperatorAddress = newOperatorAddress + upgradeToTrigger, ok := appOpts.Get(server.KeyTriggerTestnetUpgrade).(string) + if !ok { + return args, errors.New("upgradeToTrigger is not of type string") + } + args.upgradeToTrigger = upgradeToTrigger + + // parsing and set accounts to fund + accountsString := cast.ToString(appOpts.Get(flagAccountsToFund)) + args.accountsToFund = append(args.accountsToFund, strings.Split(accountsString, ",")...) + + // home dir + homeDir := cast.ToString(appOpts.Get(flags.FlagHome)) + if homeDir == "" { + return args, errors.New("invalid home dir") + } + args.homeDir = homeDir + + return args, nil +} + +// handleErr prints the error and exits the program if the error is not nil +func handleErr(err error) { + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } +} diff --git a/cmd/atomoned/cmd/root.go b/cmd/atomoned/cmd/root.go index e80fe4c42..35eccda4e 100644 --- a/cmd/atomoned/cmd/root.go +++ b/cmd/atomoned/cmd/root.go @@ -146,6 +146,7 @@ func initRootCmd( ) { rootCmd.AddCommand( genutilcli.InitCmd(basicManager, atomone.DefaultNodeHome), + NewInPlaceTestnetCmd(), tmcli.NewCompletionCmd(rootCmd, true), NewTestnetCmd(basicManager, banktypes.GenesisBalancesIterator{}), addDebugCommands(debug.Cmd()), From 55302695dd622683dcde58c9f229d1324f5d46ce Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 26 Jan 2026 17:34:30 +0100 Subject: [PATCH 2/7] lint --- cmd/atomoned/cmd/inplace_testnet.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/cmd/atomoned/cmd/inplace_testnet.go b/cmd/atomoned/cmd/inplace_testnet.go index 43a5ae3f8..f886f10bf 100644 --- a/cmd/atomoned/cmd/inplace_testnet.go +++ b/cmd/atomoned/cmd/inplace_testnet.go @@ -7,14 +7,19 @@ import ( "os" "strings" - "cosmossdk.io/log" - "cosmossdk.io/math" - storetypes "cosmossdk.io/store/types" - atomone "github.com/atomone-hub/atomone/app" + "github.com/spf13/cast" + "github.com/spf13/cobra" + "github.com/cometbft/cometbft/crypto" "github.com/cometbft/cometbft/libs/bytes" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + dbm "github.com/cosmos/cosmos-db" + + "cosmossdk.io/log" + "cosmossdk.io/math" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/client/flags" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" @@ -25,8 +30,8 @@ import ( minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/spf13/cast" - "github.com/spf13/cobra" + + atomone "github.com/atomone-hub/atomone/app" ) const valVotingPower int64 = 900000000000000 From b399d83b1755ddab2341b1937084c591a2da5a68 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 26 Jan 2026 17:36:47 +0100 Subject: [PATCH 3/7] simplify wrapper --- cmd/atomoned/cmd/inplace_testnet.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cmd/atomoned/cmd/inplace_testnet.go b/cmd/atomoned/cmd/inplace_testnet.go index f886f10bf..69c85eae2 100644 --- a/cmd/atomoned/cmd/inplace_testnet.go +++ b/cmd/atomoned/cmd/inplace_testnet.go @@ -49,11 +49,6 @@ type valArgs struct { func NewInPlaceTestnetCmd() *cobra.Command { cmd := server.InPlaceTestnetCreator(newTestnetApp) - cmd.Short = "Updates chain's application and consensus state with provided validator info and starts the node" - cmd.Long = `The test command modifies both application and consensus stores within a local mainnet node and starts the node, -with the aim of facilitating testing procedures. This command replaces existing validator data with updated information, -thereby removing the old validator set and introducing a new set suitable for local testing purposes. By altering the state extracted from the mainnet node, -it enables developers to configure their local environments to reflect mainnet conditions more accurately.` cmd.Example = `atomoned in-place-testnet testing-1 cosmosvaloper1w7f3xx7e75p4l7qdym5msqem9rd4dyc4mq79dm --home $HOME/.atomone/validator1 --validator-privkey=6dq+/KHNvyiw2TToCgOpUpQKIzrLs69Rb8Az39xvmxPHNoPxY1Cil8FY+4DhT9YwD6s0tFABMlLcpaylzKKBOg== --accounts-to-fund="cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq,cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x"` cmd.Flags().String(flagAccountsToFund, "", "Comma-separated list of account addresses that will be funded for testing purposes") From 4c6324beae6dbc2f0b650293ca700fcd7731a27c Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Wed, 28 Jan 2026 12:26:13 +0100 Subject: [PATCH 4/7] bump to latest cosmso-sdk with fix --- go.mod | 3 ++- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 883747e2d..d924b6081 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24.5 replace ( cosmossdk.io/x/feegrant => cosmossdk.io/x/feegrant v0.1.1 cosmossdk.io/x/upgrade => github.com/atomone-hub/cosmos-sdk/x/upgrade v0.1.5-atomone.1.0.20251218143825-cbb67818e94a - github.com/cosmos/cosmos-sdk => github.com/atomone-hub/cosmos-sdk v0.50.14-atomone.1.0.20251218143825-cbb67818e94a + github.com/cosmos/cosmos-sdk => github.com/atomone-hub/cosmos-sdk v0.50.14-atomone.1.0.20260128112133-ef9d3c69a0b4 github.com/cosmos/ibc-go/v10 => github.com/cosmos/ibc-go/v10 v10.2.0 ) @@ -242,6 +242,7 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.15.0 // indirect diff --git a/go.sum b/go.sum index 2c0eee1db..2b5316b08 100644 --- a/go.sum +++ b/go.sum @@ -97,8 +97,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/atomone-hub/cosmos-sdk v0.50.14-atomone.1.0.20251218143825-cbb67818e94a h1:Q8/YS/lWw2+EGsDe1qd9ljKJbfBZ+p4w4Z9toqKUDM4= -github.com/atomone-hub/cosmos-sdk v0.50.14-atomone.1.0.20251218143825-cbb67818e94a/go.mod h1:Ga+HHYYVVJ+32dKLM7RZxPTy2PfU8WDeR/4E0g8oL1E= +github.com/atomone-hub/cosmos-sdk v0.50.14-atomone.1.0.20260128112133-ef9d3c69a0b4 h1:ppfdL5dQCWrVJRPi9Vhc0mKR2DNSvQFgfzXqppnvlkk= +github.com/atomone-hub/cosmos-sdk v0.50.14-atomone.1.0.20260128112133-ef9d3c69a0b4/go.mod h1:3lw4iUC57NuskCeAXFYzFNa2ZUGj1mXxOXdxVBdqrhg= github.com/atomone-hub/cosmos-sdk/x/upgrade v0.1.5-atomone.1.0.20251218143825-cbb67818e94a h1:hoLPN0l4Z3ndSDoxyAFz9eRAKYsj49px/dYz4feX0BQ= github.com/atomone-hub/cosmos-sdk/x/upgrade v0.1.5-atomone.1.0.20251218143825-cbb67818e94a/go.mod h1:Fj4o8oq4Ek3aiuzeG5haL4ExKY3MHndz8J/F7q3PguE= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= @@ -922,8 +922,8 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= From bec1539893c7530a38ad0bb4f4eb00bbbea8c5d7 Mon Sep 17 00:00:00 2001 From: julienrbrt Date: Thu, 29 Jan 2026 17:39:19 +0100 Subject: [PATCH 5/7] Update cmd/atomoned/cmd/inplace_testnet.go Co-authored-by: Thomas --- cmd/atomoned/cmd/inplace_testnet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/atomoned/cmd/inplace_testnet.go b/cmd/atomoned/cmd/inplace_testnet.go index 69c85eae2..dd4333763 100644 --- a/cmd/atomoned/cmd/inplace_testnet.go +++ b/cmd/atomoned/cmd/inplace_testnet.go @@ -49,7 +49,7 @@ type valArgs struct { func NewInPlaceTestnetCmd() *cobra.Command { cmd := server.InPlaceTestnetCreator(newTestnetApp) - cmd.Example = `atomoned in-place-testnet testing-1 cosmosvaloper1w7f3xx7e75p4l7qdym5msqem9rd4dyc4mq79dm --home $HOME/.atomone/validator1 --validator-privkey=6dq+/KHNvyiw2TToCgOpUpQKIzrLs69Rb8Az39xvmxPHNoPxY1Cil8FY+4DhT9YwD6s0tFABMlLcpaylzKKBOg== --accounts-to-fund="cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq,cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x"` + cmd.Example = `atomoned in-place-testnet testing-1 atonevaloper1w7f3xx7e75p4l7qdym5msqem9rd4dyc4jfa7ag --home $HOME/.atomone/validator1 --validator-privkey=6dq+/KHNvyiw2TToCgOpUpQKIzrLs69Rb8Az39xvmxPHNoPxY1Cil8FY+4DhT9YwD6s0tFABMlLcpaylzKKBOg== --accounts-to-fund="atone1f7twgcq4ypzg7y24wuywy06xmdet8pc4m7dv9c,atone1qvuhm5m644660nd8377d6l7yz9e9hhm9hv8p87"` cmd.Flags().String(flagAccountsToFund, "", "Comma-separated list of account addresses that will be funded for testing purposes") return cmd From 8c237c5451c7e87ba027c7ee468336858f59512c Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 3 Feb 2026 13:48:17 +0100 Subject: [PATCH 6/7] add bonddenom fallback --- cmd/atomoned/cmd/inplace_testnet.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/atomoned/cmd/inplace_testnet.go b/cmd/atomoned/cmd/inplace_testnet.go index dd4333763..68ae71164 100644 --- a/cmd/atomoned/cmd/inplace_testnet.go +++ b/cmd/atomoned/cmd/inplace_testnet.go @@ -32,6 +32,7 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" atomone "github.com/atomone-hub/atomone/app" + "github.com/atomone-hub/atomone/app/params" ) const valVotingPower int64 = 900000000000000 @@ -176,6 +177,9 @@ func initAppForTestnet(app *atomone.AtomOneApp, args valArgs) *atomone.AtomOneAp // bondDenom, err := app.StakingKeeper.BondDenom(ctx) handleErr(err) + if bondDenom == "" { + bondDenom = params.BondDenom + } defaultCoins := sdk.NewCoins(sdk.NewInt64Coin(bondDenom, 1000000000)) From dc5179235c1db0544e72084edf49c63af1185718 Mon Sep 17 00:00:00 2001 From: julienrbrt Date: Tue, 17 Feb 2026 17:51:11 +0100 Subject: [PATCH 7/7] Apply suggestions from code review Co-authored-by: Thomas --- cmd/atomoned/cmd/inplace_testnet.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/atomoned/cmd/inplace_testnet.go b/cmd/atomoned/cmd/inplace_testnet.go index 68ae71164..a1d1c34be 100644 --- a/cmd/atomoned/cmd/inplace_testnet.go +++ b/cmd/atomoned/cmd/inplace_testnet.go @@ -223,7 +223,9 @@ func getCommandArgs(appOpts servertypes.AppOptions) (valArgs, error) { // parsing and set accounts to fund accountsString := cast.ToString(appOpts.Get(flagAccountsToFund)) - args.accountsToFund = append(args.accountsToFund, strings.Split(accountsString, ",")...) + if len(accountsString) > 0 { + args.accountsToFund = strings.Split(accountsString, ",") + } // home dir homeDir := cast.ToString(appOpts.Get(flags.FlagHome)) @@ -238,7 +240,6 @@ func getCommandArgs(appOpts servertypes.AppOptions) (valArgs, error) { // handleErr prints the error and exits the program if the error is not nil func handleErr(err error) { if err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - os.Exit(1) + panic(err) } }