181 lines
4.7 KiB
Go
181 lines
4.7 KiB
Go
package types
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
|
|
yaml "gopkg.in/yaml.v2"
|
|
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
|
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
|
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
|
)
|
|
|
|
var (
|
|
_ authtypes.AccountI = (*EthAccount)(nil)
|
|
_ authtypes.GenesisAccount = (*EthAccount)(nil)
|
|
_ codectypes.UnpackInterfacesMessage = (*EthAccount)(nil)
|
|
)
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Main Ethermint account
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// ProtoAccount defines the prototype function for BaseAccount used for an
|
|
// AccountKeeper.
|
|
func ProtoAccount() authtypes.AccountI {
|
|
return &EthAccount{
|
|
BaseAccount: &authtypes.BaseAccount{},
|
|
CodeHash: ethcrypto.Keccak256(nil),
|
|
}
|
|
}
|
|
|
|
// EthAddress returns the account address ethereum format.
|
|
func (acc EthAccount) EthAddress() ethcmn.Address {
|
|
return ethcmn.BytesToAddress(acc.GetAddress().Bytes())
|
|
}
|
|
|
|
type ethermintAccountPretty struct {
|
|
Address string `json:"address" yaml:"address"`
|
|
EthAddress string `json:"eth_address" yaml:"eth_address"`
|
|
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(),
|
|
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.GetPubKey())
|
|
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) {
|
|
var ethAddress = ""
|
|
|
|
if acc.BaseAccount != nil && acc.Address != "" {
|
|
ethAddress = acc.EthAddress().String()
|
|
}
|
|
|
|
alias := ethermintAccountPretty{
|
|
Address: acc.Address,
|
|
EthAddress: ethAddress,
|
|
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.GetPubKey())
|
|
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
|
|
}
|
|
|
|
switch {
|
|
case alias.Address != "" && alias.EthAddress != "":
|
|
// Both addresses provided. Verify correctness
|
|
ethAddress := ethcmn.HexToAddress(alias.EthAddress)
|
|
|
|
var address sdk.AccAddress
|
|
address, err = sdk.AccAddressFromBech32(alias.Address)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ethAddressFromAccAddress := ethcmn.BytesToAddress(address.Bytes())
|
|
|
|
if !bytes.Equal(ethAddress.Bytes(), address.Bytes()) {
|
|
err = sdkerrors.Wrapf(
|
|
sdkerrors.ErrInvalidAddress,
|
|
"expected %s, got %s",
|
|
ethAddressFromAccAddress.String(), ethAddress.String(),
|
|
)
|
|
}
|
|
|
|
case alias.Address != "" && alias.EthAddress == "":
|
|
// unmarshal sdk.AccAddress only. Do nothing here
|
|
case alias.Address == "" && alias.EthAddress != "":
|
|
// retrieve sdk.AccAddress from ethereum address
|
|
ethAddress := ethcmn.HexToAddress(alias.EthAddress)
|
|
alias.Address = sdk.AccAddress(ethAddress.Bytes()).String()
|
|
case alias.Address == "" && alias.EthAddress == "":
|
|
err = sdkerrors.Wrapf(
|
|
sdkerrors.ErrInvalidAddress,
|
|
"account must contain address in Ethereum Hex or Cosmos Bech32 format",
|
|
)
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
acc.BaseAccount = &authtypes.BaseAccount{
|
|
Address: alias.Address,
|
|
AccountNumber: alias.AccountNumber,
|
|
Sequence: alias.Sequence,
|
|
}
|
|
|
|
if alias.PubKey != "" {
|
|
pubkey, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := acc.SetPubKey(pubkey); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
acc.CodeHash = ethcmn.HexToHash(alias.CodeHash).Bytes()
|
|
|
|
return nil
|
|
}
|
|
|
|
// String implements the fmt.Stringer interface
|
|
func (acc EthAccount) String() string {
|
|
out, _ := yaml.Marshal(acc)
|
|
return string(out)
|
|
}
|