diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b1a9c20bcf4..dac8e9486a10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. +### Improvements + +* (types) [\#5581](https://github.com/cosmos/cosmos-sdk/pull/5581) Add convenience functions {,Must}Bech32ifyAddressBytes. + ## [v0.38.0] - 2020-01-23 ### State Machine Breaking diff --git a/types/address.go b/types/address.go index dce02ec9c07a..839af224d01f 100644 --- a/types/address.go +++ b/types/address.go @@ -557,6 +557,30 @@ func (ca ConsAddress) String() string { return bech32Addr } +// Bech32ifyAddressBytes returns a bech32 representation of address bytes. +// Returns an empty sting if the byte slice is 0-length. Returns an error if the bech32 conversion +// fails or the prefix is empty. +func Bech32ifyAddressBytes(prefix string, bs []byte) (string, error) { + if len(bs) == 0 { + return "", nil + } + if len(prefix) == 0 { + return "", errors.New("prefix cannot be empty") + } + return bech32.ConvertAndEncode(prefix, bs) +} + +// MustBech32ifyAddressBytes returns a bech32 representation of address bytes. +// Returns an empty sting if the byte slice is 0-length. It panics if the bech32 conversion +// fails or the prefix is empty. +func MustBech32ifyAddressBytes(prefix string, bs []byte) string { + s, err := Bech32ifyAddressBytes(prefix, bs) + if err != nil { + panic(err) + } + return s +} + // Format implements the fmt.Formatter interface. // nolint: errcheck func (ca ConsAddress) Format(s fmt.State, verb rune) { diff --git a/types/address_test.go b/types/address_test.go index 7326ab784293..09e5bf93c463 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -345,3 +345,68 @@ func TestCustomAddressVerifier(t *testing.T) { _, err = types.ConsAddressFromBech32(consBech) require.Nil(t, err) } + +func TestBech32ifyAddressBytes(t *testing.T) { + addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} + type args struct { + prefix string + bs []byte + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + {"empty address", args{"prefixA", []byte{}}, "", false}, + {"empty prefix", args{"", addr20byte}, "", true}, + {"10-byte address", args{"prefixA", addr10byte}, "prefixA1qqqsyqcyq5rqwzqfwvmuzx", false}, + {"10-byte address", args{"prefixB", addr10byte}, "prefixB1qqqsyqcyq5rqwzqf4xftmx", false}, + {"20-byte address", args{"prefixA", addr20byte}, "prefixA1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn6j4npq", false}, + {"20-byte address", args{"prefixB", addr20byte}, "prefixB1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn8e9wka", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt := tt + got, err := types.Bech32ifyAddressBytes(tt.args.prefix, tt.args.bs) + if (err != nil) != tt.wantErr { + t.Errorf("Bech32ifyBytes() error = %v, wantErr %v", err, tt.wantErr) + return + } + require.Equal(t, tt.want, got) + }) + } +} + +func TestMustBech32ifyAddressBytes(t *testing.T) { + addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} + type args struct { + prefix string + bs []byte + } + tests := []struct { + name string + args args + want string + wantPanic bool + }{ + {"empty address", args{"prefixA", []byte{}}, "", false}, + {"empty prefix", args{"", addr20byte}, "", true}, + {"10-byte address", args{"prefixA", addr10byte}, "prefixA1qqqsyqcyq5rqwzqfwvmuzx", false}, + {"10-byte address", args{"prefixB", addr10byte}, "prefixB1qqqsyqcyq5rqwzqf4xftmx", false}, + {"20-byte address", args{"prefixA", addr20byte}, "prefixA1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn6j4npq", false}, + {"20-byte address", args{"prefixB", addr20byte}, "prefixB1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn8e9wka", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt := tt + if tt.wantPanic { + require.Panics(t, func() { types.MustBech32ifyAddressBytes(tt.args.prefix, tt.args.bs) }) + return + } + require.Equal(t, tt.want, types.MustBech32ifyAddressBytes(tt.args.prefix, tt.args.bs)) + }) + } +}