diff --git a/app/app.go b/app/app.go index d83c40cf..3c05641d 100644 --- a/app/app.go +++ b/app/app.go @@ -76,7 +76,7 @@ type LaconicApp struct { ConsensusParamsKeeper consensuskeeper.Keeper // laconic keepers - AuctionKeeper auctionkeeper.Keeper + AuctionKeeper *auctionkeeper.Keeper // (Use * as per ProvideModule implementation) BondKeeper bondkeeper.Keeper RegistryKeeper registrykeeper.Keeper // RegistryRecordKeeper registrykeeper.RecordKeeper diff --git a/x/auction/expected_keepers.go b/x/auction/expected_keepers.go new file mode 100644 index 00000000..2a7332d7 --- /dev/null +++ b/x/auction/expected_keepers.go @@ -0,0 +1,23 @@ +package auction + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// AuctionUsageKeeper keep track of auction usage in other modules. +// Used to, for example, prevent deletion of a auction that's in use. +type AuctionUsageKeeper interface { + ModuleName() string + UsesAuction(ctx sdk.Context, auctionID string) bool + + OnAuction(ctx sdk.Context, auctionID string) + OnAuctionBid(ctx sdk.Context, auctionID string, bidderAddress string) + OnAuctionWinnerSelected(ctx sdk.Context, auctionID string) +} + +// AuctionHooksWrapper is a wrapper for modules to inject AuctionUsageKeeper using depinject. +// Reference: https://github.com/cosmos/cosmos-sdk/tree/v0.50.3/core/appmodule#resolving-circular-dependencies +type AuctionHooksWrapper struct{ AuctionUsageKeeper } + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (AuctionHooksWrapper) IsOnePerModuleType() {} diff --git a/x/auction/keeper/keeper.go b/x/auction/keeper/keeper.go index e9ae55fd..aadf7d52 100644 --- a/x/auction/keeper/keeper.go +++ b/x/auction/keeper/keeper.go @@ -73,7 +73,7 @@ type Keeper struct { bankKeeper bank.Keeper // Track auction usage in other cosmos-sdk modules (more like a usage tracker). - // usageKeepers []types.AuctionUsageKeeper + usageKeepers []auctiontypes.AuctionUsageKeeper // state management Schema collections.Schema @@ -88,7 +88,7 @@ func NewKeeper( storeService storetypes.KVStoreService, accountKeeper auth.AccountKeeper, bankKeeper bank.Keeper, -) Keeper { +) *Keeper { sb := collections.NewSchemaBuilder(storeService) k := Keeper{ cdc: cdc, @@ -97,7 +97,7 @@ func NewKeeper( Params: collections.NewItem(sb, auctiontypes.ParamsPrefix, "params", codec.CollValue[auctiontypes.Params](cdc)), Auctions: collections.NewIndexedMap(sb, auctiontypes.AuctionsPrefix, "auctions", collections.StringKey, codec.CollValue[auctiontypes.Auction](cdc), newAuctionIndexes(sb)), Bids: collections.NewIndexedMap(sb, auctiontypes.BidsPrefix, "bids", collections.PairKeyCodec(collections.StringKey, collections.StringKey), codec.CollValue[auctiontypes.Bid](cdc), newBidsIndexes(sb)), - // usageKeepers: usageKeepers, + usageKeepers: nil, } schema, err := sb.Build() @@ -107,12 +107,16 @@ func NewKeeper( k.Schema = schema - return k + return &k } -// func (k *Keeper) SetUsageKeepers(usageKeepers []types.AuctionUsageKeeper) { -// k.usageKeepers = usageKeepers -// } +func (k *Keeper) SetUsageKeepers(usageKeepers []auctiontypes.AuctionUsageKeeper) { + if k.usageKeepers != nil { + panic("cannot set auction hooks twice") + } + + k.usageKeepers = usageKeepers +} // SaveAuction - saves a auction to the store. func (k Keeper) SaveAuction(ctx sdk.Context, auction *auctiontypes.Auction) error { diff --git a/x/auction/keeper/msg_server.go b/x/auction/keeper/msg_server.go index 1339c206..45530f30 100644 --- a/x/auction/keeper/msg_server.go +++ b/x/auction/keeper/msg_server.go @@ -10,11 +10,11 @@ import ( var _ auctiontypes.MsgServer = msgServer{} type msgServer struct { - k Keeper + k *Keeper } // NewMsgServerImpl returns an implementation of the module MsgServer interface. -func NewMsgServerImpl(keeper Keeper) auctiontypes.MsgServer { +func NewMsgServerImpl(keeper *Keeper) auctiontypes.MsgServer { return &msgServer{k: keeper} } diff --git a/x/auction/keeper/query_server.go b/x/auction/keeper/query_server.go index 4bcfc824..6b1b3ed3 100644 --- a/x/auction/keeper/query_server.go +++ b/x/auction/keeper/query_server.go @@ -13,11 +13,11 @@ import ( var _ auctiontypes.QueryServer = queryServer{} type queryServer struct { - k Keeper + k *Keeper } // NewQueryServerImpl returns an implementation of the module QueryServer. -func NewQueryServerImpl(k Keeper) auctiontypes.QueryServer { +func NewQueryServerImpl(k *Keeper) auctiontypes.QueryServer { return queryServer{k} } diff --git a/x/auction/module/abci.go b/x/auction/module/abci.go index 63701487..f95b7669 100644 --- a/x/auction/module/abci.go +++ b/x/auction/module/abci.go @@ -9,7 +9,7 @@ import ( ) // EndBlocker is called every block -func EndBlocker(ctx context.Context, k keeper.Keeper) error { +func EndBlocker(ctx context.Context, k *keeper.Keeper) error { sdkCtx := sdk.UnwrapSDKContext(ctx) return k.EndBlockerProcessAuctions(sdkCtx) diff --git a/x/auction/module/depinject.go b/x/auction/module/depinject.go index 8679d8af..764f04ab 100644 --- a/x/auction/module/depinject.go +++ b/x/auction/module/depinject.go @@ -4,12 +4,14 @@ import ( "cosmossdk.io/core/appmodule" "cosmossdk.io/core/store" "cosmossdk.io/depinject" + "golang.org/x/exp/maps" "github.com/cosmos/cosmos-sdk/codec" auth "github.com/cosmos/cosmos-sdk/x/auth/keeper" bank "github.com/cosmos/cosmos-sdk/x/bank/keeper" modulev1 "git.vdb.to/cerc-io/laconic2d/api/cerc/auction/module/v1" + "git.vdb.to/cerc-io/laconic2d/x/auction" "git.vdb.to/cerc-io/laconic2d/x/auction/keeper" ) @@ -25,6 +27,7 @@ func init() { appmodule.Register( &modulev1.Module{}, appmodule.Provide(ProvideModule), + appmodule.Invoke(InvokeSetAuctionHooks), ) } @@ -41,7 +44,11 @@ type ModuleInputs struct { type ModuleOutputs struct { depinject.Out - Keeper keeper.Keeper + // Use * as required by InvokeSetAuctionHooks + // https://github.com/cosmos/cosmos-sdk/tree/v0.50.3/core/appmodule#invoker-invocation-details + // https://github.com/cosmos/cosmos-sdk/tree/v0.50.3/core/appmodule#regular-golang-types + Keeper *keeper.Keeper + Module appmodule.AppModule } @@ -51,3 +58,25 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { return ModuleOutputs{Module: m, Keeper: k} } + +func InvokeSetAuctionHooks( + config *modulev1.Module, + keeper *keeper.Keeper, + auctionHooks map[string]auction.AuctionHooksWrapper, +) error { + // all arguments to invokers are optional + if keeper == nil || config == nil { + return nil + } + + var usageKeepers []auction.AuctionUsageKeeper + + for _, modName := range maps.Keys(auctionHooks) { + hook := auctionHooks[modName] + usageKeepers = append(usageKeepers, hook) + } + + keeper.SetUsageKeepers(usageKeepers) + + return nil +} diff --git a/x/auction/module/module.go b/x/auction/module/module.go index 8105f88f..aaae2474 100644 --- a/x/auction/module/module.go +++ b/x/auction/module/module.go @@ -36,11 +36,11 @@ const ConsensusVersion = 1 type AppModule struct { cdc codec.Codec - keeper keeper.Keeper + keeper *keeper.Keeper } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper *keeper.Keeper) AppModule { return AppModule{ cdc: cdc, keeper: keeper, diff --git a/x/registry/keeper/keeper.go b/x/registry/keeper/keeper.go index b542fb2f..30037c1a 100644 --- a/x/registry/keeper/keeper.go +++ b/x/registry/keeper/keeper.go @@ -89,7 +89,7 @@ type Keeper struct { bankKeeper bank.Keeper recordKeeper RecordKeeper bondKeeper bondkeeper.Keeper - auctionKeeper auctionkeeper.Keeper + auctionKeeper *auctionkeeper.Keeper // state management Schema collections.Schema @@ -109,7 +109,7 @@ func NewKeeper( bankKeeper bank.Keeper, recordKeeper RecordKeeper, bondKeeper bondkeeper.Keeper, - auctionKeeper auctionkeeper.Keeper, + auctionKeeper *auctionkeeper.Keeper, ) Keeper { sb := collections.NewSchemaBuilder(storeService) k := Keeper{ diff --git a/x/registry/keeper/record_keeper.go b/x/registry/keeper/record_keeper.go index c71f54b6..a36e878c 100644 --- a/x/registry/keeper/record_keeper.go +++ b/x/registry/keeper/record_keeper.go @@ -8,19 +8,55 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + auctiontypes "git.vdb.to/cerc-io/laconic2d/x/auction" auctionkeeper "git.vdb.to/cerc-io/laconic2d/x/auction/keeper" registrytypes "git.vdb.to/cerc-io/laconic2d/x/registry" ) // TODO: Add methods +// Record keeper implements the bond usage keeper interface. +var ( + _ auctiontypes.AuctionUsageKeeper = RecordKeeper{} + // _ bondtypes.BondUsageKeeper = (*RecordKeeper)(nil) +) + // RecordKeeper exposes the bare minimal read-only API for other modules. type RecordKeeper struct { cdc codec.BinaryCodec // The wire codec for binary encoding/decoding. - auctionKeeper auctionkeeper.Keeper + auctionKeeper *auctionkeeper.Keeper // storeKey storetypes.StoreKey // Unexposed key to access store from sdk.Context } +// NewRecordKeeper creates new instances of the registry RecordKeeper +func NewRecordKeeper(cdc codec.BinaryCodec, auctionKeeper *auctionkeeper.Keeper) RecordKeeper { + return RecordKeeper{ + auctionKeeper: auctionKeeper, + cdc: cdc, + } +} + +// ModuleName returns the module name. +func (k RecordKeeper) ModuleName() string { + return registrytypes.ModuleName +} + +func (k RecordKeeper) UsesAuction(ctx sdk.Context, auctionID string) bool { + panic("unimplemented") +} + +func (k RecordKeeper) OnAuction(ctx sdk.Context, auctionID string) { + panic("unimplemented") +} + +func (k RecordKeeper) OnAuctionBid(ctx sdk.Context, auctionID string, bidderAddress string) { + panic("unimplemented") +} + +func (k RecordKeeper) OnAuctionWinnerSelected(ctx sdk.Context, auctionID string) { + panic("unimplemented") +} + // RenewRecord renews a record. func (k Keeper) RenewRecord(ctx sdk.Context, msg registrytypes.MsgRenewRecord) error { if has, err := k.HasRecord(ctx, msg.RecordId); !has { diff --git a/x/registry/module/depinject.go b/x/registry/module/depinject.go index 200d02c1..3978fd17 100644 --- a/x/registry/module/depinject.go +++ b/x/registry/module/depinject.go @@ -10,6 +10,7 @@ import ( bank "github.com/cosmos/cosmos-sdk/x/bank/keeper" modulev1 "git.vdb.to/cerc-io/laconic2d/api/cerc/registry/module/v1" + auction "git.vdb.to/cerc-io/laconic2d/x/auction" auctionkeeper "git.vdb.to/cerc-io/laconic2d/x/auction/keeper" bondkeeper "git.vdb.to/cerc-io/laconic2d/x/bond/keeper" "git.vdb.to/cerc-io/laconic2d/x/registry/keeper" @@ -40,7 +41,7 @@ type ModuleInputs struct { BankKeeper bank.Keeper BondKeeper bondkeeper.Keeper - AuctionKeeper auctionkeeper.Keeper + AuctionKeeper *auctionkeeper.Keeper } type ModuleOutputs struct { @@ -48,19 +49,23 @@ type ModuleOutputs struct { Keeper keeper.Keeper Module appmodule.AppModule + + AuctionHooks auction.AuctionHooksWrapper } func ProvideModule(in ModuleInputs) ModuleOutputs { + recordKeeper := keeper.NewRecordKeeper(in.Cdc, in.AuctionKeeper) + k := keeper.NewKeeper( in.Cdc, in.StoreService, in.AccountKeeper, in.BankKeeper, - keeper.RecordKeeper{}, + recordKeeper, in.BondKeeper, in.AuctionKeeper, ) m := NewAppModule(in.Cdc, k) - return ModuleOutputs{Module: m, Keeper: k} + return ModuleOutputs{Module: m, Keeper: k, AuctionHooks: auction.AuctionHooksWrapper{AuctionUsageKeeper: recordKeeper}} }