Skip to content

Commit

Permalink
add checksum check
Browse files Browse the repository at this point in the history
  • Loading branch information
lumtis committed Dec 11, 2024
1 parent 376b714 commit 00563a9
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 55 deletions.
12 changes: 0 additions & 12 deletions pkg/crypto/address.go

This file was deleted.

37 changes: 0 additions & 37 deletions pkg/crypto/address_test.go

This file was deleted.

29 changes: 29 additions & 0 deletions pkg/crypto/evm_address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package crypto

import (
"github.com/ethereum/go-ethereum/common"
"strings"

"github.com/zeta-chain/node/pkg/constant"
)

// IsEmptyAddress returns true if the address is empty
func IsEmptyAddress(address common.Address) bool {
return address == (common.Address{}) || address.Hex() == constant.EVMZeroAddress
}

// IsEVMAddress returns true if the string is an EVM address
// independently of the checksum format
func IsEVMAddress(address string) bool {
return len(address) == 42 && strings.HasPrefix(address, "0x") && common.IsHexAddress(address)
}

// IsChecksumAddress returns true if the EVM address string is a valid checksum address
func IsChecksumAddress(address string) bool {
return address == common.HexToAddress(address).Hex()
}

// ToChecksumAddress returns the checksum address of the given EVM address
func ToChecksumAddress(address string) string {
return common.HexToAddress(address).Hex()
}
156 changes: 156 additions & 0 deletions pkg/crypto/evm_address_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package crypto

import (
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/node/pkg/constant"
"testing"
)

func TestIsEmptyAddress(t *testing.T) {
tests := []struct {
name string
address common.Address
want bool
}{
{
name: "empty address",
address: common.Address{},
want: true,
},
{
name: "zero address",
address: common.HexToAddress(constant.EVMZeroAddress),
want: true,
},
{
name: "non empty address",
address: common.HexToAddress("0x1"),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require.EqualValues(t, tt.want, IsEmptyAddress(tt.address))
})
}
}

func TestIsEVMAddress(t *testing.T) {
tests := []struct {
name string
address string
want bool
}{
{
name: "EVM address",
address: "0x5a4f260A7D716c859A2736151cB38b9c58C32c64",
want: true,
},
{
name: "EVM address with invalid checksum",
address: "0x5a4f260a7D716c859A2736151CB38b9c58C32c64",
want: true,
},
{
name: "EVM address all lowercase",
address: "0x5a4f260a7d716c859a2736151cb38b9c58c32c64",
want: true,
},
{
name: "EVM address all uppercase",
address: "0x5A4F260A7D716C859A2736151CB38B9C58C32C64",
want: true,
},
{
name: "invalid EVM address",
address: "5a4f260A7D716c859A2736151cB38b9c58C32c64",
},
{
name: "empty address",
address: "",
},
{
name: "non EVM address",
address: "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require.EqualValues(t, tt.want, IsEVMAddress(tt.address))
})
}
}

func TestIsChecksumAddress(t *testing.T) {
tests := []struct {
name string
address string
want bool
}{
{
name: "checksum address",
address: "0x5a4f260A7D716c859A2736151cB38b9c58C32c64",
want: true,
},
{
name: "invalid checksum address",
address: "0x5a4f260a7D716c859A2736151CB38b9c58C32c64",
},
{
name: "all lowercase",
address: "0x5a4f260a7d716c859a2736151cb38b9c58c32c64",
},
{
name: "all uppercase",
address: "0x5A4F260A7D716C859A2736151CB38B9C58C32C64",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require.EqualValues(t, tt.want, IsChecksumAddress(tt.address))
})
}
}

func TestToChecksumAddress(t *testing.T) {
tests := []struct {
name string
address string
want string
}{
{
name: "checksum address",
address: "0x5a4f260A7D716c859A2736151cB38b9c58C32c64",
want: "0x5a4f260A7D716c859A2736151cB38b9c58C32c64",
},
{
name: "all lowercase",
address: "0x5a4f260a7d716c859a2736151cb38b9c58c32c64",
want: "0x5a4f260A7D716c859A2736151cB38b9c58C32c64",
},
{
name: "all uppercase",
address: "0x5A4F260A7D716C859A2736151CB38B9C58C32C64",
want: "0x5a4f260A7D716c859A2736151cB38b9c58C32c64",
},
{
name: "empty address returns null address",
address: "",
want: "0x0000000000000000000000000000000000000000",
},
{
name: "non evm address returns null address",
address: "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr",
want: "0x0000000000000000000000000000000000000000",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require.EqualValues(t, tt.want, ToChecksumAddress(tt.address))
})
}
}
23 changes: 19 additions & 4 deletions x/crosschain/types/message_whitelist_erc20.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import (
cosmoserrors "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

"github.com/pkg/errors"
"github.com/zeta-chain/node/pkg/crypto"
"github.com/zeta-chain/node/x/fungible/types"
)

Expand Down Expand Up @@ -50,10 +51,10 @@ func (msg *MsgWhitelistERC20) GetSignBytes() []byte {
func (msg *MsgWhitelistERC20) ValidateBasic() error {
_, err := sdk.AccAddressFromBech32(msg.Creator)
if err != nil {
return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err)
return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err.Error())
}
if msg.Erc20Address == "" {
return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "empty asset address")
if err := validateAssetAddress(msg.Erc20Address); err != nil {
return cosmoserrors.Wrapf(types.ErrInvalidAddress, "invalid asset address (%s)", err.Error())
}
if msg.Decimals > 128 {
return cosmoserrors.Wrapf(types.ErrInvalidDecimals, "invalid decimals (%d)", msg.Decimals)
Expand All @@ -63,3 +64,17 @@ func (msg *MsgWhitelistERC20) ValidateBasic() error {
}
return nil
}

func validateAssetAddress(address string) error {
if address == "" {
return errors.New("empty asset address")
}

// if the address is an evm address, check if it is in checksum format
if crypto.IsEVMAddress(address) && !crypto.IsChecksumAddress(address) {
return errors.New("evm address is not in checksum format")
}

// currently no specific check is implemented for other address format
return nil
}
30 changes: 28 additions & 2 deletions x/crosschain/types/message_whitelist_erc20_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,36 @@ func TestMsgWhitelistERC20_ValidateBasic(t *testing.T) {
error: true,
},
{
name: "valid",
name: "evm asset address with invalid checksum format",
msg: types.NewMsgWhitelistERC20(
sample.AccAddress(),
sample.EthAddress().Hex(),
"0x5a4f260a7d716c859a2736151cb38b9c58c32c64",
1,
"name",
"symbol",
6,
10,
),
error: true,
},
{
name: "valid message with evm asset address",
msg: types.NewMsgWhitelistERC20(
sample.AccAddress(),
"0x5a4f260A7D716c859A2736151cB38b9c58C32c64",
1,
"name",
"symbol",
6,
10,
),
error: false,
},
{
name: "valid message with solana asset address",
msg: types.NewMsgWhitelistERC20(
sample.AccAddress(),
"Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr",
1,
"name",
"symbol",
Expand Down

0 comments on commit 00563a9

Please sign in to comment.