Skip to main content

Integrate the Alliance module

Alliance can be integrated into both new and existing blockchains. It is an isolated module that doesn’t modify any existing CosmosSDK code. New blockchains can simply import the module and existing chains can perform a software upgrade.

Chains that want to create an Alliance must enable the following modules:

  • x/auth: retrieve information about internal blockchain accounts
  • x/bank: mint, burn or send coins
  • x/staking: bond, unbond, delegate tokens and hooks
  • x/distribution: withdraw rewards
  • x/gov: create Alliances through governance

Since Interchain Security is based on the IBC standard, the Alliance module has an indirect dependency on x/ibc to bridge foreign tokens. Alliance allows any ADR 024 compliant token to be staked as long as it has been whitelisted.

Prerequisites

The Alliance Module requires:

Configuring and Adding Alliance to a CosmosSDK Chain

Implementation example

Refer to the example pull request for an implementation of the following steps.

  1. Add the Alliance package to the go.mod file with the latest released version and install it.
go.mod
Copy

_5
require (
_5
...
_5
github.com/terra-money/alliance v<LATEST-VERSION>
_5
...
_5
)
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5

  1. Add the following modules to app.go
go.mod
app.go
Copy

_4
alliancemodule "github.com/terra-money/alliance/x/alliance"
_4
alliancemoduleclient "github.com/terra-money/alliance/x/alliance/client"
_4
alliancemodulekeeper "github.com/terra-money/alliance/x/alliance/keeper"
_4
alliancemoduletypes "github.com/terra-money/alliance/x/alliance/types"
_4
_4
_4
_4
_4
_4
_4
_4
_4
_4
_4
_4
_4
_4
_4
_4

  1. Register the AllianceKeeper in App struct.
go.mod
app.go
Copy

_5
type App struct {
_5
...
_5
AllianceKeeper alliancemodulekeeper.Keeper
_5
...
_5
}
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5

  1. Add the Alliance module into the BasicManager instantiation.
go.mod
app.go
Copy

_5
ModuleBasics = module.NewBasicManager(
_5
...
_5
alliancemodule.AppModuleBasic{},
_5
...
_5
)
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5

  1. Add the Alliance module to the app. The Alliance module needs to be specified after the stakingKeeper is instantiated.
go.mod
app.go
Copy

_21
...
_21
_21
stakingKeeper := stakingkeeper.NewKeeper(
_21
appCodec,
_21
keys[stakingtypes.StoreKey],
_21
app.AccountKeeper,
_21
app.BankKeeper,
_21
app.GetSubspace(stakingtypes.ModuleName),
_21
)
_21
_21
...
_21
_21
app.AllianceKeeper = alliancemodulekeeper.NewKeeper(
_21
appCodec,
_21
keys[alliancemoduletypes.StoreKey],
_21
app.GetSubspace(alliancemoduletypes.ModuleName),
_21
app.AccountKeeper,
_21
app.BankKeeper,
_21
&app.StakingKeeper,
_21
app.DistrKeeper,

  1. Add the Alliance staking hooks to app.StakingKeeper.
go.mod
app.go
Copy

_5
_5
app.StakingKeeper = *stakingKeeper.SetHooks(
_5
stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(),
_5
app.SlashingKeeper.Hooks(), app.AllianceKeeper.StakingHooks()),
_5
)
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5

  1. Add the requisite Alliance module types to the module account permissions.
go.mod
app.go
Copy

_12
maccPerms = map[string][]string{
_12
authtypes.FeeCollectorName: nil,
_12
distrtypes.ModuleName: nil,
_12
icatypes.ModuleName: nil,
_12
minttypes.ModuleName: {authtypes.Minter},
_12
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking},
_12
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
_12
govtypes.ModuleName: {authtypes.Burner},
_12
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
_12
alliancemoduletypes.ModuleName: {authtypes.Minter, authtypes.Burner},
_12
alliancemoduletypes.RewardsPoolName: nil,
_12
}
_12
_12
_12
_12
_12
_12
_12
_12

  1. Add the alliance storekey to the KVStore.
go.mod
app.go
Copy

_5
keys := sdk.NewKVStoreKeys(
_5
...
_5
alliancemoduletypes.StoreKey,
_5
...
_5
)
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5

  1. Add the Alliance module to the app manager and simulation manager instantiations.
go.mod
app.go
Copy

_13
app.mm = module.NewManager(
_13
...
_13
icaModule,
_13
alliancemodule.NewAppModule(appCodec, app.AllianceKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
_13
...
_13
)
_13
_13
app.sm = module.NewSimulationManager(
_13
...
_13
transferModule,
_13
alliancemodule.NewAppModule(appCodec, app.AllianceKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
_13
...
_13
)
_13
_13
_13
_13
_13
_13
_13

  1. Add the module as the final element to the following:
  • SetOrderBeginBlockers
  • SetOrderEndBlockers
  • SetOrderInitGenesis
go.mod
app.go
Copy

_14
app.mm.SetOrderBeginBlockers(
_14
...
_14
alliancemoduletypes.ModuleName,
_14
)
_14
_14
app.mm.SetOrderEndBlockers(
_14
...
_14
alliancemoduletypes.ModuleName,
_14
)
_14
_14
app.mm.SetOrderInitGenesis(
_14
...
_14
alliancemoduletypes.ModuleName,
_14
)
_14
_14
_14
_14
_14
_14

  1. Add the Alliance proposal handler route to the governance module.
go.mod
app.go
Copy

_9
govRouter.
_9
_9
AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).
_9
_9
...
_9
_9
AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)).
_9
_9
AddRoute(alliancemoduletypes.RouterKey, alliancemodule.NewAllianceProposalHandler(app.AllianceKeeper))
_9
_9
_9
_9
_9
_9
_9
_9
_9
_9
_9

  1. Add the governance proposal handlers.
go.mod
app.go
Copy

_13
govProposalHandlers = append(govProposalHandlers,
_13
_13
...
_13
_13
ibcclientclient.UpgradeProposalHandler,
_13
_13
alliancemoduleclient.CreateAllianceProposalHandler,
_13
_13
alliancemoduleclient.UpdateAllianceProposalHandler,
_13
_13
alliancemoduleclient.DeleteAllianceProposalHandler,
_13
_13
)
_13
_13
_13
_13
_13
_13
_13

  1. Block the module account address.
go.mod
app.go
Copy

_9
func (app *App) BlockedModuleAccountAddrs() map[string]bool {
_9
_9
...
_9
_9
delete(modAccAddrs, authtypes.NewModuleAddress(alliancemoduletypes.ModuleName).String())
_9
_9
return modAccAddrs
_9
_9
}
_9
_9
_9
_9
_9
_9
_9
_9
_9
_9
_9

  1. Add the init params keepers.
go.mod
app.go
Copy

_9
func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper {
_9
_9
...
_9
_9
paramsKeeper.Subspace(alliancemoduletypes.ModuleName)
_9
_9
return paramsKeeper
_9
_9
}
_9
_9
_9
_9
_9
_9
_9
_9
_9
_9
_9

  1. Add the Alliance package to the go.mod file with the latest released version and install it.
  1. Add the following modules to app.go
  1. Register the AllianceKeeper in App struct.
  1. Add the Alliance module into the BasicManager instantiation.
  1. Add the Alliance module to the app. The Alliance module needs to be specified after the stakingKeeper is instantiated.
  1. Add the Alliance staking hooks to app.StakingKeeper.
  1. Add the requisite Alliance module types to the module account permissions.
  1. Add the alliance storekey to the KVStore.
  1. Add the Alliance module to the app manager and simulation manager instantiations.
  1. Add the module as the final element to the following:
  • SetOrderBeginBlockers
  • SetOrderEndBlockers
  • SetOrderInitGenesis
  1. Add the Alliance proposal handler route to the governance module.
  1. Add the governance proposal handlers.
  1. Block the module account address.
  1. Add the init params keepers.
go.mod
CopyExpandClose

_5
require (
_5
...
_5
github.com/terra-money/alliance v<LATEST-VERSION>
_5
...
_5
)
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5
_5

Configuring the Bank Module

Because the Alliance module mints and burns native staking tokens when rebalancing voting power, a chain's Total Supply API needs to be updated to return accurate results. This custom wrapper only affects the following APIs: /cosmos/bank/v1beta1/supply & /cosmos/bank/v1beta1/supply/by_denom. Follow these instructions to update your API for supply accuracy.

  1. Update the imports to use a custom wrapper over the Bank module.
app.go
Copy

_11
import (
_11
...
_11
// Delete or comment the native bank module imports
_11
// "github.com/cosmos/cosmos-sdk/x/bank"
_11
// bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
_11
_11
// Replace the imports from the Alliance module
_11
bank "github.com/terra-money/alliance/custom/bank"
_11
bankkeeper "github.com/terra-money/alliance/custom/bank/keeper"
_11
...
_11
)
_11
_11
_11
_11
_11
_11
_11
_11
_11

  1. Add a line to register the keepers that the custom Bank module needs
app.go
Copy

_12
app.AllianceKeeper = alliancemodulekeeper.NewKeeper(
_12
appCodec,
_12
keys[alliancemoduletypes.StoreKey],
_12
app.GetSubspace(alliancemoduletypes.ModuleName),
_12
app.AccountKeeper,
_12
app.BankKeeper,
_12
&stakingKeeper,
_12
app.DistrKeeper,
_12
)
_12
_12
// Add this after instantiating the `Alliance keeper`
_12
app.BankKeeper.RegisterKeepers(app.AllianceKeeper, &stakingKeeper)
_12
_12
_12
_12
_12
_12
_12
_12

  1. Update the imports to use a custom wrapper over the Bank module.
  1. Add a line to register the keepers that the custom Bank module needs
app.go
CopyExpandClose

_11
import (
_11
...
_11
// Delete or comment the native bank module imports
_11
// "github.com/cosmos/cosmos-sdk/x/bank"
_11
// bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
_11
_11
// Replace the imports from the Alliance module
_11
bank "github.com/terra-money/alliance/custom/bank"
_11
bankkeeper "github.com/terra-money/alliance/custom/bank/keeper"
_11
...
_11
)
_11
_11
_11
_11
_11
_11
_11
_11
_11