package types import ( "encoding/json" "fmt" "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/exported" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ethcmn "github.com/ethereum/go-ethereum/common" ethcrypto "github.com/ethereum/go-ethereum/crypto" ) var _ exported.Account = (*EthAccount)(nil) var _ exported.GenesisAccount = (*EthAccount)(nil) func init() { authtypes.RegisterAccountTypeCodec(&EthAccount{}, EthAccountName) } // ---------------------------------------------------------------------------- // Main Ethermint account // ---------------------------------------------------------------------------- // EthAccount implements the auth.Account interface and embeds an // auth.BaseAccount type. It is compatible with the auth.AccountKeeper. type EthAccount struct { *authtypes.BaseAccount `json:"base_account" yaml:"base_account"` CodeHash []byte `json:"code_hash" yaml:"code_hash"` } // ProtoAccount defines the prototype function for BaseAccount used for an // AccountKeeper. func ProtoAccount() exported.Account { return &EthAccount{ BaseAccount: &auth.BaseAccount{}, CodeHash: ethcrypto.Keccak256(nil), } } // EthAddress returns the account address ethereum format. func (acc EthAccount) EthAddress() ethcmn.Address { return ethcmn.BytesToAddress(acc.Address.Bytes()) } // TODO: remove on SDK v0.40 // Balance returns the balance of an account. func (acc EthAccount) Balance() sdk.Int { return acc.GetCoins().AmountOf(DenomDefault) } // SetBalance sets an account's balance of aphotons func (acc *EthAccount) SetBalance(amt sdk.Int) { coins := acc.GetCoins() diff := amt.Sub(coins.AmountOf(DenomDefault)) switch { case diff.IsPositive(): // Increase coins to amount coins = coins.Add(sdk.NewCoin(DenomDefault, diff)) case diff.IsNegative(): // Decrease coins to amount coins = coins.Sub(sdk.NewCoins(sdk.NewCoin(DenomDefault, diff.Neg()))) default: return } if err := acc.SetCoins(coins); err != nil { panic(fmt.Errorf("could not set coins for address %s: %w", acc.EthAddress().String(), err)) } } type ethermintAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` EthAddress string `json:"eth_address" yaml:"eth_address"` Coins sdk.Coins `json:"coins" yaml:"coins"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` CodeHash string `json:"code_hash" yaml:"code_hash"` } // MarshalYAML returns the YAML representation of an account. func (acc EthAccount) MarshalYAML() (interface{}, error) { alias := ethermintAccountPretty{ Address: acc.Address, EthAddress: acc.EthAddress().String(), Coins: acc.Coins, AccountNumber: acc.AccountNumber, Sequence: acc.Sequence, CodeHash: ethcmn.Bytes2Hex(acc.CodeHash), } var err error if acc.PubKey != nil { alias.PubKey, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.PubKey) if err != nil { return nil, err } } bz, err := yaml.Marshal(alias) if err != nil { return nil, err } return string(bz), err } // MarshalJSON returns the JSON representation of an EthAccount. func (acc EthAccount) MarshalJSON() ([]byte, error) { alias := ethermintAccountPretty{ Address: acc.Address, EthAddress: acc.EthAddress().String(), Coins: acc.Coins, AccountNumber: acc.AccountNumber, Sequence: acc.Sequence, CodeHash: ethcmn.Bytes2Hex(acc.CodeHash), } var err error if acc.PubKey != nil { alias.PubKey, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.PubKey) if err != nil { return nil, err } } return json.Marshal(alias) } // UnmarshalJSON unmarshals raw JSON bytes into an EthAccount. func (acc *EthAccount) UnmarshalJSON(bz []byte) error { var ( alias ethermintAccountPretty err error ) if err := json.Unmarshal(bz, &alias); err != nil { return err } acc.BaseAccount = &authtypes.BaseAccount{ Coins: alias.Coins, Address: alias.Address, AccountNumber: alias.AccountNumber, Sequence: alias.Sequence, } acc.CodeHash = ethcmn.Hex2Bytes(alias.CodeHash) if alias.PubKey != "" { acc.BaseAccount.PubKey, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) if err != nil { return err } } return nil } // String implements the fmt.Stringer interface func (acc EthAccount) String() string { out, _ := yaml.Marshal(acc) return string(out) }