Category: Coding Mistakes
Move coins are case-insensitive in cosmos
Low Severity
Low Impact
Medium Likelihood
Description
When performing operations on Move coins, the metadata address is fetched from the coins denom:
// Extract metadata address from a denom
func MetadataAddressFromDenom(denom string) (vmtypes.AccountAddress, error) {
if strings.HasPrefix(denom, DenomTraceDenomPrefixMove) {
addrBz, err := hex.DecodeString(strings.TrimPrefix(denom, DenomTraceDenomPrefixMove))
if err != nil {
return vmtypes.AccountAddress{}, err
}
return vmtypes.NewAccountAddressFromBytes(addrBz)
}
// non move coins are generated from 0x1.
return NamedObjectAddress(vmtypes.StdAddress, denom), nil
}
The issue is that hex.DecodeString
is case-insensitive, so a denom of move/AAAA
and move/aaaa
will both return the same metadata address. Inside the Move VM, the metadata addresses are always case-insensitive when parsed, but the default cosmos SDK behavior is that they are case-sensitive.
This could cause functions such as Coins.Validate
to incorrectly validate the coins, even when there are duplicates:
// Validate checks that the Coins are sorted, have positive amount, with a valid and unique
// denomination (i.e no duplicates). Otherwise, it returns an error.
func (coins Coins) Validate() error {
Impact
Any function relying on the fact that a validated coins
should contain no duplicates could have this invariant broken.
Recommendations
A check should be added to ensure that the denom
values for Move coins are always lowercase.