package types import ( "encoding/json" "errors" "fmt" "strings" yaml "gopkg.in/yaml.v2" "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/supply/exported" ) var ( _ authexported.GenesisAccount = (*ModuleAccount)(nil) _ exported.ModuleAccountI = (*ModuleAccount)(nil) ) // NewModuleAddress creates an AccAddress from the hash of the module's name func NewModuleAddress(name string) sdk.AccAddress { return sdk.AccAddress(crypto.AddressHash([]byte(name))) } // NewEmptyModuleAccount creates a empty ModuleAccount from a string func NewEmptyModuleAccount(name string, permissions ...string) *ModuleAccount { moduleAddress := NewModuleAddress(name) baseAcc := authtypes.NewBaseAccountWithAddress(moduleAddress) if err := validatePermissions(permissions...); err != nil { panic(err) } return &ModuleAccount{ BaseAccount: baseAcc, Name: name, Permissions: permissions, } } // NewModuleAccount creates a new ModuleAccount instance func NewModuleAccount(ba *authtypes.BaseAccount, name string, permissions ...string) *ModuleAccount { if err := validatePermissions(permissions...); err != nil { panic(err) } return &ModuleAccount{ BaseAccount: ba, Name: name, Permissions: permissions, } } // HasPermission returns whether or not the module account has permission. func (ma ModuleAccount) HasPermission(permission string) bool { for _, perm := range ma.Permissions { if perm == permission { return true } } return false } // GetName returns the the name of the holder's module func (ma ModuleAccount) GetName() string { return ma.Name } // GetPermissions returns permissions granted to the module account func (ma ModuleAccount) GetPermissions() []string { return ma.Permissions } // SetPubKey - Implements Account func (ma ModuleAccount) SetPubKey(pubKey crypto.PubKey) error { return fmt.Errorf("not supported for module accounts") } // SetSequence - Implements Account func (ma ModuleAccount) SetSequence(seq uint64) error { return fmt.Errorf("not supported for module accounts") } // Validate checks for errors on the account fields func (ma ModuleAccount) Validate() error { if strings.TrimSpace(ma.Name) == "" { return errors.New("module account name cannot be blank") } if !ma.Address.Equals(sdk.AccAddress(crypto.AddressHash([]byte(ma.Name)))) { return fmt.Errorf("address %s cannot be derived from the module name '%s'", ma.Address, ma.Name) } return ma.BaseAccount.Validate() } type moduleAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` Name string `json:"name" yaml:"name"` Permissions []string `json:"permissions" yaml:"permissions"` } func (ma ModuleAccount) String() string { out, _ := ma.MarshalYAML() return out.(string) } // MarshalYAML returns the YAML representation of a ModuleAccount. func (ma ModuleAccount) MarshalYAML() (interface{}, error) { bs, err := yaml.Marshal(moduleAccountPretty{ Address: ma.Address, PubKey: "", AccountNumber: ma.AccountNumber, Sequence: ma.Sequence, Name: ma.Name, Permissions: ma.Permissions, }) if err != nil { return nil, err } return string(bs), nil } // MarshalJSON returns the JSON representation of a ModuleAccount. func (ma ModuleAccount) MarshalJSON() ([]byte, error) { return json.Marshal(moduleAccountPretty{ Address: ma.Address, PubKey: "", AccountNumber: ma.AccountNumber, Sequence: ma.Sequence, Name: ma.Name, Permissions: ma.Permissions, }) } // UnmarshalJSON unmarshals raw JSON bytes into a ModuleAccount. func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error { var alias moduleAccountPretty if err := json.Unmarshal(bz, &alias); err != nil { return err } ma.BaseAccount = authtypes.NewBaseAccount(alias.Address, nil, alias.AccountNumber, alias.Sequence) ma.Name = alias.Name ma.Permissions = alias.Permissions return nil }