Skip to content

Commit 2faa826

Browse files
authored
Merge pull request #4 from allinbits/atomone_gov_compat
feat: add atomone compat gov
2 parents 54ecc7b + 6f8306d commit 2faa826

File tree

5 files changed

+102
-29
lines changed

5 files changed

+102
-29
lines changed

app/provider/app.go

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ import (
112112
ibcproviderclient "github.com/cosmos/interchain-security/v5/x/ccv/provider/client"
113113
ibcproviderkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper"
114114
providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
115+
ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types"
115116

116117
"github.com/cosmos/cosmos-sdk/testutil/testdata/testpb"
117118
sigtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
@@ -125,6 +126,61 @@ const (
125126

126127
// this line is used by starport scaffolding # stargate/wasm/app/enabledProposals
127128

129+
// AtomOneGovKeeper wraps the standard SDK gov keeper to behave like AtomOne's gov keeper
130+
// This implements the ccv.GovKeeper interface
131+
type AtomOneGovKeeper struct {
132+
keeper *govkeeper.Keeper
133+
}
134+
135+
// GetProposal implements the AtomOne-style GetProposal method
136+
func (a *AtomOneGovKeeper) GetProposal(ctx sdk.Context, proposalID uint64) (ccvtypes.Proposal, bool) {
137+
prop, err := a.keeper.Proposals.Get(ctx, proposalID)
138+
if err != nil {
139+
return ccvtypes.Proposal{}, false
140+
}
141+
// Convert SDK proposal to ICS minimal proposal type
142+
return ccvtypes.Proposal{
143+
Messages: prop.Messages,
144+
}, true
145+
}
146+
147+
// AtomOneGovHooksWrapper wraps ICS provider hooks to work with standard SDK gov module
148+
// This bridges between AtomOne-style hooks (no errors) and SDK hooks (with errors)
149+
type AtomOneGovHooksWrapper struct {
150+
hooks ibcproviderkeeper.Hooks
151+
}
152+
153+
// Implement standard SDK GovHooks interface by wrapping AtomOne-style hooks
154+
func (w AtomOneGovHooksWrapper) AfterProposalSubmission(ctx context.Context, proposalID uint64) error {
155+
sdkCtx := sdk.UnwrapSDKContext(ctx)
156+
w.hooks.AfterProposalSubmission(sdkCtx, proposalID)
157+
return nil
158+
}
159+
160+
func (w AtomOneGovHooksWrapper) AfterProposalVotingPeriodEnded(ctx context.Context, proposalID uint64) error {
161+
sdkCtx := sdk.UnwrapSDKContext(ctx)
162+
w.hooks.AfterProposalVotingPeriodEnded(sdkCtx, proposalID)
163+
return nil
164+
}
165+
166+
func (w AtomOneGovHooksWrapper) AfterProposalDeposit(ctx context.Context, proposalID uint64, depositorAddr sdk.AccAddress) error {
167+
sdkCtx := sdk.UnwrapSDKContext(ctx)
168+
w.hooks.AfterProposalDeposit(sdkCtx, proposalID, depositorAddr)
169+
return nil
170+
}
171+
172+
func (w AtomOneGovHooksWrapper) AfterProposalVote(ctx context.Context, proposalID uint64, voterAddr sdk.AccAddress) error {
173+
sdkCtx := sdk.UnwrapSDKContext(ctx)
174+
w.hooks.AfterProposalVote(sdkCtx, proposalID, voterAddr)
175+
return nil
176+
}
177+
178+
func (w AtomOneGovHooksWrapper) AfterProposalFailedMinDeposit(ctx context.Context, proposalID uint64) error {
179+
sdkCtx := sdk.UnwrapSDKContext(ctx)
180+
w.hooks.AfterProposalFailedMinDeposit(sdkCtx, proposalID)
181+
return nil
182+
}
183+
128184
var (
129185
// DefaultNodeHome default home directories for the application daemon
130186
DefaultNodeHome string
@@ -460,6 +516,9 @@ func New(
460516
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
461517
)
462518

519+
// Create AtomOne-style gov keeper wrapper
520+
atomOneGovKeeper := &AtomOneGovKeeper{keeper: app.GovKeeper}
521+
463522
// IBC v10: scopedKeeper and portKeeper removed from provider keeper initialization
464523
app.ProviderKeeper = ibcproviderkeeper.NewKeeper(
465524
appCodec,
@@ -473,7 +532,7 @@ func New(
473532
app.AccountKeeper,
474533
app.DistrKeeper,
475534
app.BankKeeper,
476-
*app.GovKeeper,
535+
atomOneGovKeeper,
477536
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
478537
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
479538
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
@@ -490,8 +549,9 @@ func New(
490549
// Set legacy router for backwards compatibility with gov v1beta1
491550
app.GovKeeper.SetLegacyRouter(govRouter)
492551

552+
// Use the AtomOne hooks wrapper to bridge between the two interfaces
493553
app.GovKeeper = app.GovKeeper.SetHooks(
494-
govtypes.NewMultiGovHooks(app.ProviderKeeper.Hooks()),
554+
govtypes.NewMultiGovHooks(AtomOneGovHooksWrapper{hooks: app.ProviderKeeper.Hooks()}),
495555
)
496556

497557
providerModule := ibcprovider.NewAppModule(&app.ProviderKeeper, app.GetSubspace(providertypes.ModuleName))

testutil/keeper/unit_test_helpers.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import (
2929
abci "github.com/cometbft/cometbft/abci/types"
3030
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
3131

32-
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
3332
consumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper"
3433
consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types"
3534
providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper"
@@ -80,6 +79,14 @@ func NewInMemKeeperParams(tb testing.TB) InMemKeeperParams {
8079
}
8180
}
8281

82+
// TestGovKeeper is a mock implementation of GovKeeper for testing
83+
type TestGovKeeper struct{}
84+
85+
// GetProposal returns an empty proposal - tests don't use actual proposals
86+
func (k TestGovKeeper) GetProposal(ctx sdk.Context, proposalID uint64) (types.Proposal, bool) {
87+
return types.Proposal{}, false
88+
}
89+
8390
// A struct holding pointers to any mocked external keeper needed for provider/consumer keeper setup.
8491
type MockedKeepers struct {
8592
*MockScopedKeeper
@@ -130,8 +137,7 @@ func NewInMemProviderKeeper(params InMemKeeperParams, mocks MockedKeepers) provi
130137
mocks.MockAccountKeeper,
131138
mocks.MockDistributionKeeper,
132139
mocks.MockBankKeeper,
133-
// mocks.MockGovKeeper,
134-
govkeeper.Keeper{}, // HACK: to make parts of the test work
140+
TestGovKeeper{}, // Test implementation of GovKeeper
135141
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
136142
address.NewBech32Codec("cosmosvaloper"),
137143
address.NewBech32Codec("cosmosvalcons"),

x/ccv/provider/keeper/hooks.go

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import (
66

77
"cosmossdk.io/math"
88
sdk "github.com/cosmos/cosmos-sdk/types"
9-
sdkgov "github.com/cosmos/cosmos-sdk/x/gov/types"
10-
v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
9+
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
1110
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
1211

1312
"github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
@@ -22,7 +21,7 @@ type Hooks struct {
2221

2322
var (
2423
_ stakingtypes.StakingHooks = Hooks{}
25-
_ sdkgov.GovHooks = Hooks{}
24+
// AtomOne GovHooks interface compatibility is ensured by method signatures
2625
)
2726

2827
// Returns new provider hooks
@@ -209,38 +208,29 @@ func (h Hooks) BeforeTokenizeShareRecordRemoved(_ context.Context, _ uint64) err
209208
// AfterProposalSubmission - call hook if registered
210209
// After a consumerAddition proposal submission, a record is created
211210
// that maps the proposal ID to the consumer chain ID.
212-
func (h Hooks) AfterProposalSubmission(goCtx context.Context, proposalID uint64) error {
213-
ctx := sdk.UnwrapSDKContext(goCtx)
214-
211+
func (h Hooks) AfterProposalSubmission(ctx sdk.Context, proposalID uint64) {
215212
if p, ok := h.GetConsumerAdditionLegacyPropFromProp(ctx, proposalID); ok {
216213
h.k.SetProposedConsumerChain(ctx, p.ChainId, proposalID)
217214
}
218-
return nil
219215
}
220216

221217
// AfterProposalVotingPeriodEnded - call hook if registered
222218
// After proposal voting ends, the consumer chainID in store is deleted.
223219
// When a consumerAddition proposal passes, the consumer chainID is available in providerKeeper.GetAllPendingConsumerAdditionProps
224220
// or providerKeeper.GetAllConsumerChains(ctx).
225-
func (h Hooks) AfterProposalVotingPeriodEnded(goCtx context.Context, proposalID uint64) error {
226-
ctx := sdk.UnwrapSDKContext(goCtx)
227-
221+
func (h Hooks) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) {
228222
if _, ok := h.GetConsumerAdditionLegacyPropFromProp(ctx, proposalID); ok {
229223
h.k.DeleteProposedConsumerChainInStore(ctx, proposalID)
230224
}
231-
return nil
232225
}
233226

234-
func (h Hooks) AfterProposalDeposit(ctx context.Context, proposalID uint64, depositorAddr sdk.AccAddress) error {
235-
return nil
227+
func (h Hooks) AfterProposalDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) {
236228
}
237229

238-
func (h Hooks) AfterProposalVote(ctx context.Context, proposalID uint64, voterAddr sdk.AccAddress) error {
239-
return nil
230+
func (h Hooks) AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) {
240231
}
241232

242-
func (h Hooks) AfterProposalFailedMinDeposit(ctx context.Context, proposalID uint64) error {
243-
return nil
233+
func (h Hooks) AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) {
244234
}
245235

246236
// GetConsumerAdditionLegacyPropFromProp extracts a consumer addition legacy proposal from
@@ -249,20 +239,20 @@ func (h Hooks) GetConsumerAdditionLegacyPropFromProp(
249239
ctx sdk.Context,
250240
proposalID uint64,
251241
) (providertypes.ConsumerAdditionProposal, bool) {
252-
p, err := h.k.govKeeper.Proposals.Get(ctx, proposalID)
253-
if err != nil {
242+
p, found := h.k.govKeeper.GetProposal(ctx, proposalID)
243+
if !found {
254244
return providertypes.ConsumerAdditionProposal{}, false
255245
}
256246

257247
// Iterate over the messages in the proposal
258248
// Note that it's assumed that at most ONE message can contain a consumer addition proposal
259249
for _, msg := range p.GetMessages() {
260-
sdkMsg, isLegacyProposal := msg.GetCachedValue().(*v1.MsgExecLegacyContent)
250+
sdkMsg, isLegacyProposal := msg.GetCachedValue().(*govv1.MsgExecLegacyContent)
261251
if !isLegacyProposal {
262252
continue
263253
}
264254

265-
content, err := v1.LegacyContentFromMessage(sdkMsg)
255+
content, err := govv1.LegacyContentFromMessage(sdkMsg)
266256
if err != nil {
267257
panic(fmt.Errorf("failed to get legacy proposal %d from prop message", proposalID))
268258
}

x/ccv/provider/keeper/keeper.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
2424

2525
"cosmossdk.io/log"
26-
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
2726

2827
consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types"
2928
"github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
@@ -48,7 +47,7 @@ type Keeper struct {
4847
slashingKeeper ccv.SlashingKeeper
4948
distributionKeeper ccv.DistributionKeeper
5049
bankKeeper ccv.BankKeeper
51-
govKeeper govkeeper.Keeper
50+
govKeeper ccv.GovKeeper
5251
feeCollectorName string
5352

5453
validatorAddressCodec addresscodec.Codec
@@ -64,7 +63,7 @@ func NewKeeper(
6463
stakingKeeper ccv.StakingKeeper, slashingKeeper ccv.SlashingKeeper,
6564
accountKeeper ccv.AccountKeeper,
6665
distributionKeeper ccv.DistributionKeeper, bankKeeper ccv.BankKeeper,
67-
govKeeper govkeeper.Keeper,
66+
govKeeper ccv.GovKeeper,
6867
authority string,
6968
validatorAddressCodec, consensusAddressCodec addresscodec.Codec,
7069
feeCollectorName string,

x/ccv/types/expected_keepers.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"cosmossdk.io/math"
1414
storetypes "cosmossdk.io/store/types"
15+
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
1516
sdk "github.com/cosmos/cosmos-sdk/types"
1617
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
1718
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
@@ -118,6 +119,23 @@ type ConsumerHooks interface {
118119
AfterValidatorBonded(ctx context.Context, consAddr sdk.ConsAddress, valAddresses sdk.ValAddress) error
119120
}
120121

122+
// Proposal defines the minimal proposal type needed by ICS
123+
// This is a simplified version that only contains the fields ICS actually uses
124+
type Proposal struct {
125+
Messages []*codectypes.Any
126+
}
127+
128+
// GetMessages returns the proposal messages
129+
func (p Proposal) GetMessages() []*codectypes.Any {
130+
return p.Messages
131+
}
132+
133+
// GovKeeper defines the expected interface for the governance keeper
134+
// Compatible with AtomOne's custom governance implementation
135+
type GovKeeper interface {
136+
GetProposal(ctx sdk.Context, proposalID uint64) (Proposal, bool)
137+
}
138+
121139
// BankKeeper defines the expected interface needed to retrieve account balances.
122140
type BankKeeper interface {
123141
GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin

0 commit comments

Comments
 (0)