diff --git a/.pending/improvements/sdk/4259-Coins-that-are- b/.pending/improvements/sdk/4259-Coins-that-are- new file mode 100644 index 0000000000..8571e213a3 --- /dev/null +++ b/.pending/improvements/sdk/4259-Coins-that-are- @@ -0,0 +1,2 @@ +#4259 `Coins` that are `nil` are now JSON encoded as an empty array `[]`. +Decoding remains unchanged and behavior is left intact. diff --git a/types/coin.go b/types/coin.go index 9de3bda58a..8d0f03c7da 100644 --- a/types/coin.go +++ b/types/coin.go @@ -1,6 +1,7 @@ package types import ( + "encoding/json" "fmt" "regexp" "sort" @@ -151,6 +152,18 @@ func NewCoins(coins ...Coin) Coins { return newCoins } +type coinsJSON Coins + +// MarshalJSON implements a custom JSON marshaller for the Coins type to allow +// nil Coins to be encoded as an empty array. +func (coins Coins) MarshalJSON() ([]byte, error) { + if coins == nil { + return json.Marshal(coinsJSON(Coins{})) + } + + return json.Marshal(coinsJSON(coins)) +} + func (coins Coins) String() string { if len(coins) == 0 { return "" diff --git a/types/coin_test.go b/types/coin_test.go index ee4c2de649..c3a843e62d 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -4,6 +4,7 @@ import ( "strings" "testing" + "github.com/cosmos/cosmos-sdk/codec" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -621,3 +622,35 @@ func TestFindDup(t *testing.T) { }) } } + +func TestMarshalJSONCoins(t *testing.T) { + cdc := codec.New() + RegisterCodec(cdc) + + testCases := []struct { + name string + input Coins + strOutput string + }{ + {"nil coins", nil, `[]`}, + {"empty coins", Coins{}, `[]`}, + {"non-empty coins", NewCoins(NewInt64Coin("foo", 50)), `[{"denom":"foo","amount":"50"}]`}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + bz, err := cdc.MarshalJSON(tc.input) + require.NoError(t, err) + require.Equal(t, tc.strOutput, string(bz)) + + var newCoins Coins + require.NoError(t, cdc.UnmarshalJSON(bz, &newCoins)) + + if tc.input.Empty() { + require.Nil(t, newCoins) + } else { + require.Equal(t, tc.input, newCoins) + } + }) + } +}