From fe984e9eb05f46cde4b8790a0ab240720abf779a Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Wed, 22 Jul 2026 11:43:55 +0200 Subject: [PATCH 1/2] fix: register legacy IBC gov proposal content types in atomone gov fork The v4 mainnet upgrade failed during the gov proposal migration with: failed to migrate gov proposals: failed to get proposal value: no concrete type registered for type URL /ibc.core.client.v1.ClientUpdateProposal against interface *v1beta1.Content The AtomOne gov module fork defines its own Content interface (atomone.gov.v1beta1.Content), and MsgExecLegacyContent unpacks its content Any against it. ibc-go registers ClientUpdateProposal and UpgradeProposal against the SDK's gov Content interface, but not against ours, so a historical mainnet proposal (#20) wrapping a ClientUpdateProposal failed to unpack during migration. Register both legacy IBC 02-client proposal content types against the AtomOne Content interface, matching the existing manual registration of the params and upgrade proposal content types. An audit of all 20 atomone-1 mainnet proposals confirms ClientUpdateProposal is the only missing registration; UpgradeProposal is registered defensively as it travels with it in ibc-go. --- app/upgrades/v4/upgrades_test.go | 43 ++++++++++++++++++++++++++++++++ x/gov/types/v1beta1/codec.go | 12 +++++++++ 2 files changed, 55 insertions(+) diff --git a/app/upgrades/v4/upgrades_test.go b/app/upgrades/v4/upgrades_test.go index 5228db5f0..50179f66b 100644 --- a/app/upgrades/v4/upgrades_test.go +++ b/app/upgrades/v4/upgrades_test.go @@ -7,12 +7,16 @@ import ( cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + ibcclienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + "cosmossdk.io/math" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/atomone-hub/atomone/app/helpers" v4 "github.com/atomone-hub/atomone/app/upgrades/v4" + govv1 "github.com/atomone-hub/atomone/x/gov/types/v1" ) func TestMigrateStakingParams(t *testing.T) { @@ -30,3 +34,42 @@ func TestMigrateStakingParams(t *testing.T) { require.Equal(t, fivePercent, got.MinCommissionRate) require.Equal(t, fivePercent, got.MaxCommissionRate) } + +// TestUnpackLegacyIBCProposalContent guards against a regression of the v4 +// mainnet upgrade failure where migrating gov proposals errored with: +// +// no concrete type registered for type URL +// /ibc.core.client.v1.ClientUpdateProposal against interface *v1beta1.Content +// +// Historical mainnet proposals stored a legacy IBC ClientUpdateProposal wrapped +// in a MsgExecLegacyContent. ibc-go registers that content type against the +// SDK's gov Content interface, but the AtomOne gov fork uses its own Content +// interface, so the type must be registered against it manually (see +// x/gov/types/v1beta1/codec.go). This test reproduces the exact unpack chain +// exercised by migrateProposals. +func TestUnpackLegacyIBCProposalContent(t *testing.T) { + app := helpers.Setup(t) + cdc := app.AppCodec() + + content := &ibcclienttypes.ClientUpdateProposal{ //nolint:staticcheck + Title: "update client", + Description: "recover an expired IBC client", + SubjectClientId: "07-tendermint-0", + SubstituteClientId: "07-tendermint-1", + } + contentAny, err := codectypes.NewAnyWithValue(content) + require.NoError(t, err) + + msgAny, err := codectypes.NewAnyWithValue(govv1.NewMsgExecLegacyContent(contentAny, "authority")) + require.NoError(t, err) + + prop := govv1.Proposal{Id: 1, Messages: []*codectypes.Any{msgAny}} + bz, err := cdc.Marshal(&prop) + require.NoError(t, err) + + // Unmarshalling triggers UnpackInterfaces, which resolves the legacy IBC + // content Any against the AtomOne gov v1beta1.Content interface. This is the + // exact step that failed during the v4 mainnet upgrade. + var got govv1.Proposal + require.NoError(t, cdc.Unmarshal(bz, &got)) +} diff --git a/x/gov/types/v1beta1/codec.go b/x/gov/types/v1beta1/codec.go index 86a4b3046..b8527d62b 100644 --- a/x/gov/types/v1beta1/codec.go +++ b/x/gov/types/v1beta1/codec.go @@ -1,6 +1,8 @@ package v1beta1 import ( + ibcclienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + upgradetypes "cosmossdk.io/x/upgrade/types" "github.com/cosmos/cosmos-sdk/codec" @@ -50,6 +52,16 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { (*Content)(nil), &upgradetypes.CancelSoftwareUpgradeProposal{}, //nolint:staticcheck ) + // Legacy IBC 02-client proposal content types. These are registered by + // ibc-go against the SDK's gov Content interface, but not against ours, so + // we must register them manually. Historical mainnet proposals wrapping a + // ClientUpdateProposal or UpgradeProposal in a MsgExecLegacyContent would + // otherwise fail to unpack. + registry.RegisterImplementations( + (*Content)(nil), + &ibcclienttypes.ClientUpdateProposal{}, //nolint:staticcheck + &ibcclienttypes.UpgradeProposal{}, //nolint:staticcheck + ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } From a8eca0e8608f6150c8193f035f277ec22febc3e3 Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Wed, 22 Jul 2026 16:18:37 +0200 Subject: [PATCH 2/2] chore: add v4.0.1 checksums --- RELEASES.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 73461a285..85d5b63d9 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,12 @@ +# v4.0.1 + +5f0819601a9ac5c54c527565df64a51d3604951171b43a0b1f3d1d0de29bdaf9 atomoned-v4.0.1-darwin-amd64 +372371921018e656ac03f5c74c6545792e5c9ff3c360009e25d0ea435688231a atomoned-v4.0.1-darwin-arm64 +8012bf8f6edfc3526071f841efeb1545463de9b267af685549bdc0669f2df9ee atomoned-v4.0.1-linux-amd64 +6f67b3b74b1ddf0f81dcf7cac415a425ff4b9b30256d91ecfe58d37e6a73fd04 atomoned-v4.0.1-linux-arm64 +6d9ad1ff40831fb36482d99e8718aeb9f66cf2756a8c297ee702b8ed07734f2c atomoned-v4.0.1-windows-amd64.exe +dff3bf16a451c8c0685f79400e49d4e721ad547616e8567949eb64ad6088db67 atomoned-v4.0.1-windows-arm64.exe + # v4.0.0 0b67adf734cb88ea794c1e9d486aaca0af66a83d7b85188cf1b5cabfccced5fc atomoned-v4.0.0-darwin-amd64