github.com/InjectiveLabs/sdk-go@v1.53.0/chain/peggy/types/ethereum.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"cosmossdk.io/errors"
     9  	"cosmossdk.io/math"
    10  	sdk "github.com/cosmos/cosmos-sdk/types"
    11  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    12  	gethcommon "github.com/ethereum/go-ethereum/common"
    13  )
    14  
    15  const (
    16  	// PeggyDenomPrefix indicates the prefix for all assests minted by this module
    17  	PeggyDenomPrefix = ModuleName
    18  
    19  	// PeggyDenomSeparator is the separator for peggy denoms
    20  	PeggyDenomSeparator = ""
    21  
    22  	// ETHContractAddressLen is the length of contract address bytes
    23  	ETHContractAddressLen = 20
    24  
    25  	// PeggyDenomLen is the length of the denoms generated by the peggy module
    26  	PeggyDenomLen = len(PeggyDenomPrefix) + len(PeggyDenomSeparator) + ETHContractAddressLen
    27  
    28  	// ZeroAddress is an EthAddress containing the zero ethereum address
    29  	ZeroAddressString = "0x0000000000000000000000000000000000000000"
    30  )
    31  
    32  // EthAddrLessThan migrates the Ethereum address less than function
    33  func EthAddrLessThan(e, o string) bool {
    34  	return bytes.Compare([]byte(e), []byte(o)) == -1
    35  }
    36  
    37  // Returns a new EthAddress with 0x0000000000000000000000000000000000000000 as the wrapped address
    38  func ZeroAddress() gethcommon.Address {
    39  	return gethcommon.HexToAddress(ZeroAddressString)
    40  }
    41  
    42  // Creates a new EthAddress from a string, performing validation and returning any validation errors
    43  func NewEthAddress(address string) (*gethcommon.Address, error) {
    44  	if err := ValidateEthAddress(address); err != nil {
    45  		return nil, errors.Wrap(err, "invalid input address")
    46  	}
    47  
    48  	addr := gethcommon.HexToAddress(address)
    49  	return &addr, nil
    50  }
    51  
    52  // ValidateEthAddress validates the ethereum address strings
    53  func ValidateEthAddress(address string) error {
    54  	if address == "" {
    55  		return fmt.Errorf("empty")
    56  	}
    57  	if !gethcommon.IsHexAddress(address) {
    58  		return fmt.Errorf("%s is not a valid ETH address", address)
    59  	}
    60  	return nil
    61  }
    62  
    63  // NewERC20Token returns a new instance of an ERC20
    64  func NewERC20Token(amount uint64, contract gethcommon.Address) *ERC20Token {
    65  	return &ERC20Token{Amount: math.NewIntFromUint64(amount), Contract: contract.Hex()}
    66  }
    67  
    68  func NewSDKIntERC20Token(amount math.Int, contract gethcommon.Address) *ERC20Token {
    69  	return &ERC20Token{Amount: amount, Contract: contract.Hex()}
    70  }
    71  
    72  // PeggyCoin returns the peggy representation of an ERC20 token
    73  func (e *ERC20Token) PeggyCoin() sdk.Coin {
    74  	return sdk.NewCoin(PeggyDenomString(gethcommon.HexToAddress(e.Contract)), e.Amount)
    75  }
    76  
    77  type PeggyDenom []byte
    78  
    79  func (p PeggyDenom) String() string {
    80  	contractAddress, err := p.TokenContract()
    81  	if err != nil {
    82  		// the case of unparseable peggy denom
    83  		return fmt.Sprintf("%x(error: %s)", []byte(p), err.Error())
    84  	}
    85  
    86  	return PeggyDenomString(contractAddress)
    87  }
    88  
    89  func (p PeggyDenom) TokenContract() (gethcommon.Address, error) {
    90  	fullPrefix := []byte(PeggyDenomPrefix + PeggyDenomSeparator)
    91  	if !bytes.HasPrefix(p, fullPrefix) {
    92  		err := fmt.Errorf("denom '%x' byte prefix not equal to expected '%x'", []byte(p), fullPrefix)
    93  		return gethcommon.Address{}, err
    94  	}
    95  
    96  	addressBytes := bytes.TrimPrefix(p, fullPrefix)
    97  	if len(addressBytes) != ETHContractAddressLen {
    98  		err := fmt.Errorf("failed to validate Ethereum address bytes: %x", addressBytes)
    99  		return gethcommon.Address{}, err
   100  	}
   101  
   102  	return gethcommon.BytesToAddress(addressBytes), nil
   103  }
   104  
   105  func NewPeggyDenom(tokenContract gethcommon.Address) PeggyDenom {
   106  	buf := make([]byte, 0, PeggyDenomLen)
   107  	buf = append(buf, PeggyDenomPrefix+PeggyDenomSeparator...)
   108  	buf = append(buf, tokenContract.Bytes()...)
   109  
   110  	return PeggyDenom(buf)
   111  }
   112  
   113  func NewPeggyDenomFromString(denom string) (PeggyDenom, error) {
   114  	fullPrefix := PeggyDenomPrefix + PeggyDenomSeparator
   115  	if !strings.HasPrefix(denom, fullPrefix) {
   116  		err := fmt.Errorf("denom '%s' string prefix not equal to expected '%s'", denom, fullPrefix)
   117  		return nil, err
   118  	}
   119  
   120  	addressHex := strings.TrimPrefix(denom, fullPrefix)
   121  	if err := ValidateEthAddress(addressHex); err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	peggyDenom := NewPeggyDenom(gethcommon.HexToAddress(addressHex))
   126  	return peggyDenom, nil
   127  }
   128  
   129  func PeggyDenomString(tokenContract gethcommon.Address) string {
   130  	return fmt.Sprintf("%s%s%s", PeggyDenomPrefix, PeggyDenomSeparator, tokenContract.Hex())
   131  }
   132  
   133  // ValidateBasic permforms stateless validation
   134  func (e *ERC20Token) ValidateBasic() error {
   135  	if err := ValidateEthAddress(e.Contract); err != nil {
   136  		return errors.Wrap(err, "ethereum address")
   137  	}
   138  
   139  	if !e.PeggyCoin().IsValid() {
   140  		return errors.Wrap(sdkerrors.ErrInvalidCoins, e.PeggyCoin().String())
   141  	}
   142  
   143  	if !e.PeggyCoin().IsPositive() {
   144  		return errors.Wrap(sdkerrors.ErrInvalidCoins, e.PeggyCoin().String())
   145  	}
   146  
   147  	return nil
   148  }
   149  
   150  // Add adds one ERC20 to another
   151  func (e *ERC20Token) Add(o *ERC20Token) (*ERC20Token, error) {
   152  	if e.Contract != o.Contract {
   153  		return nil, fmt.Errorf("invalid contract address")
   154  	}
   155  
   156  	sum := e.Amount.Add(o.Amount)
   157  	if !sum.IsUint64() {
   158  		return nil, fmt.Errorf("invalid amount")
   159  	}
   160  
   161  	return NewERC20Token(sum.Uint64(), gethcommon.HexToAddress(e.Contract)), nil
   162  }