github.com/cosmos/cosmos-sdk@v0.50.10/types/coin_test.go (about)

     1  package types_test
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/require"
     9  	"github.com/stretchr/testify/suite"
    10  
    11  	"cosmossdk.io/math"
    12  
    13  	"github.com/cosmos/cosmos-sdk/codec"
    14  	sdk "github.com/cosmos/cosmos-sdk/types"
    15  )
    16  
    17  var (
    18  	testDenom1 = "atom"
    19  	testDenom2 = "muon"
    20  )
    21  
    22  type coinTestSuite struct {
    23  	suite.Suite
    24  	ca0, ca1, ca2, ca4, cm0, cm1, cm2, cm4 sdk.Coin
    25  	emptyCoins                             sdk.Coins
    26  }
    27  
    28  func TestCoinTestSuite(t *testing.T) {
    29  	suite.Run(t, new(coinTestSuite))
    30  }
    31  
    32  func (s *coinTestSuite) SetupSuite() {
    33  	zero := math.NewInt(0)
    34  	one := math.OneInt()
    35  	two := math.NewInt(2)
    36  	four := math.NewInt(4)
    37  
    38  	s.ca0, s.ca1, s.ca2, s.ca4 = sdk.NewCoin(testDenom1, zero), sdk.NewCoin(testDenom1, one), sdk.NewCoin(testDenom1, two), sdk.NewCoin(testDenom1, four)
    39  	s.cm0, s.cm1, s.cm2, s.cm4 = sdk.NewCoin(testDenom2, zero), sdk.NewCoin(testDenom2, one), sdk.NewCoin(testDenom2, two), sdk.NewCoin(testDenom2, four)
    40  	s.emptyCoins = sdk.Coins{}
    41  }
    42  
    43  // ----------------------------------------------------------------------------
    44  // Coin tests
    45  
    46  func (s *coinTestSuite) TestCoin() {
    47  	s.Require().Panics(func() { sdk.NewInt64Coin(testDenom1, -1) })
    48  	s.Require().Panics(func() { sdk.NewCoin(testDenom1, math.NewInt(-1)) })
    49  	s.Require().Equal(math.NewInt(10), sdk.NewInt64Coin(strings.ToUpper(testDenom1), 10).Amount)
    50  	s.Require().Equal(math.NewInt(10), sdk.NewCoin(strings.ToUpper(testDenom1), math.NewInt(10)).Amount)
    51  	s.Require().Equal(math.NewInt(5), sdk.NewInt64Coin(testDenom1, 5).Amount)
    52  	s.Require().Equal(math.NewInt(5), sdk.NewCoin(testDenom1, math.NewInt(5)).Amount)
    53  }
    54  
    55  func (s *coinTestSuite) TestCoin_String() {
    56  	coin := sdk.NewCoin(testDenom1, math.NewInt(10))
    57  	s.Require().Equal(fmt.Sprintf("10%s", testDenom1), coin.String())
    58  }
    59  
    60  func (s *coinTestSuite) TestIsEqualCoin() {
    61  	cases := []struct {
    62  		inputOne sdk.Coin
    63  		inputTwo sdk.Coin
    64  		expected bool
    65  	}{
    66  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), true},
    67  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), false},
    68  		{sdk.NewInt64Coin("stake", 1), sdk.NewInt64Coin("stake", 10), false},
    69  	}
    70  
    71  	for tcIndex, tc := range cases {
    72  		res := tc.inputOne.IsEqual(tc.inputTwo)
    73  		s.Require().Equal(tc.expected, res, "coin equality relation is incorrect, tc #%d", tcIndex)
    74  	}
    75  }
    76  
    77  func (s *coinTestSuite) TestCoinIsValid() {
    78  	loremIpsum := `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam viverra dui vel nulla aliquet, non dictum elit aliquam. Proin consequat leo in consectetur mattis. Phasellus eget odio luctus, rutrum dolor at, venenatis ante. Praesent metus erat, sodales vitae sagittis eget, commodo non ipsum. Duis eget urna quis erat mattis pulvinar. Vivamus egestas imperdiet sem, porttitor hendrerit lorem pulvinar in. Vivamus laoreet sapien eget libero euismod tristique. Suspendisse tincidunt nulla quis luctus mattis.
    79  	Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed id turpis at erat placerat fermentum id sed sapien. Fusce mattis enim id nulla viverra, eget placerat eros aliquet. Nunc fringilla urna ac condimentum ultricies. Praesent in eros ac neque fringilla sodales. Donec ut venenatis eros. Quisque iaculis lectus neque, a varius sem ullamcorper nec. Cras tincidunt dignissim libero nec volutpat. Donec molestie enim sed metus venenatis, quis elementum sem varius. Curabitur eu venenatis nulla.
    80  	Cras sit amet ligula vel turpis placerat sollicitudin. Nunc massa odio, eleifend id lacus nec, ultricies elementum arcu. Donec imperdiet nulla lacus, a venenatis lacus fermentum nec. Proin vestibulum dolor enim, vitae posuere velit aliquet non. Suspendisse pharetra condimentum nunc tincidunt viverra. Etiam posuere, ligula ut maximus congue, mauris orci consectetur velit, vel finibus eros metus non tellus. Nullam et dictum metus. Aliquam maximus fermentum mauris elementum aliquet. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam dapibus lectus sed tellus rutrum tincidunt. Nulla at dolor sem. Ut non dictum arcu, eget congue sem.`
    81  
    82  	loremIpsum = strings.ReplaceAll(loremIpsum, " ", "")
    83  	loremIpsum = strings.ReplaceAll(loremIpsum, ".", "")
    84  	loremIpsum = strings.ReplaceAll(loremIpsum, ",", "")
    85  
    86  	cases := []struct {
    87  		coin       sdk.Coin
    88  		expectPass bool
    89  	}{
    90  		{sdk.Coin{testDenom1, math.NewInt(-1)}, false},
    91  		{sdk.Coin{testDenom1, math.NewInt(0)}, true},
    92  		{sdk.Coin{testDenom1, math.OneInt()}, true},
    93  		{sdk.Coin{"Atom", math.OneInt()}, true},
    94  		{sdk.Coin{"ATOM", math.OneInt()}, true},
    95  		{sdk.Coin{"a", math.OneInt()}, false},
    96  		{sdk.Coin{loremIpsum, math.OneInt()}, false},
    97  		{sdk.Coin{"ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", math.OneInt()}, true},
    98  		{sdk.Coin{"atOm", math.OneInt()}, true},
    99  		{sdk.Coin{"x:y-z.1_2", math.OneInt()}, true},
   100  		{sdk.Coin{"     ", math.OneInt()}, false},
   101  	}
   102  
   103  	for i, tc := range cases {
   104  		s.Require().Equal(tc.expectPass, tc.coin.IsValid(), "unexpected result for IsValid, tc #%d", i)
   105  	}
   106  }
   107  
   108  func (s *coinTestSuite) TestCustomValidation() {
   109  	newDnmRegex := `[\x{1F600}-\x{1F6FF}]`
   110  	sdk.SetCoinDenomRegex(func() string {
   111  		return newDnmRegex
   112  	})
   113  
   114  	cases := []struct {
   115  		coin       sdk.Coin
   116  		expectPass bool
   117  	}{
   118  		{sdk.Coin{"🙂", math.NewInt(1)}, true},
   119  		{sdk.Coin{"🙁", math.NewInt(1)}, true},
   120  		{sdk.Coin{"🌶", math.NewInt(1)}, false}, // outside the unicode range listed above
   121  		{sdk.Coin{"asdf", math.NewInt(1)}, false},
   122  		{sdk.Coin{"", math.NewInt(1)}, false},
   123  	}
   124  
   125  	for i, tc := range cases {
   126  		s.Require().Equal(tc.expectPass, tc.coin.IsValid(), "unexpected result for IsValid, tc #%d", i)
   127  	}
   128  	sdk.SetCoinDenomRegex(sdk.DefaultCoinDenomRegex)
   129  }
   130  
   131  func (s *coinTestSuite) TestCoinsDenoms() {
   132  	cases := []struct {
   133  		coins      sdk.Coins
   134  		testOutput []string
   135  		expectPass bool
   136  	}{
   137  		{sdk.NewCoins(sdk.Coin{"ATOM", math.NewInt(1)}, sdk.Coin{"JUNO", math.NewInt(1)}, sdk.Coin{"OSMO", math.NewInt(1)}, sdk.Coin{"RAT", math.NewInt(1)}), []string{"ATOM", "JUNO", "OSMO", "RAT"}, true},
   138  		{sdk.NewCoins(sdk.Coin{"ATOM", math.NewInt(1)}, sdk.Coin{"JUNO", math.NewInt(1)}), []string{"ATOM"}, false},
   139  	}
   140  
   141  	for i, tc := range cases {
   142  		expectedOutput := tc.coins.Denoms()
   143  		count := 0
   144  		if len(expectedOutput) == len(tc.testOutput) {
   145  			for k := range tc.testOutput {
   146  				if tc.testOutput[k] != expectedOutput[k] {
   147  					count++
   148  					break
   149  				}
   150  			}
   151  		} else {
   152  			count++
   153  		}
   154  		s.Require().Equal(count == 0, tc.expectPass, "unexpected result for coins.Denoms, tc #%d", i)
   155  	}
   156  }
   157  
   158  func (s *coinTestSuite) TestAddCoin() {
   159  	cases := []struct {
   160  		inputOne    sdk.Coin
   161  		inputTwo    sdk.Coin
   162  		expected    sdk.Coin
   163  		shouldPanic bool
   164  	}{
   165  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 2), false},
   166  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom1, 1), false},
   167  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), sdk.NewInt64Coin(testDenom1, 1), true},
   168  	}
   169  
   170  	for tcIndex, tc := range cases {
   171  		tc := tc
   172  		if tc.shouldPanic {
   173  			s.Require().Panics(func() { tc.inputOne.Add(tc.inputTwo) })
   174  		} else {
   175  			res := tc.inputOne.Add(tc.inputTwo)
   176  			s.Require().Equal(tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
   177  		}
   178  	}
   179  }
   180  
   181  func (s *coinTestSuite) TestAddCoinAmount() {
   182  	cases := []struct {
   183  		coin     sdk.Coin
   184  		amount   math.Int
   185  		expected sdk.Coin
   186  	}{
   187  		{sdk.NewInt64Coin(testDenom1, 1), math.NewInt(1), sdk.NewInt64Coin(testDenom1, 2)},
   188  		{sdk.NewInt64Coin(testDenom1, 1), math.NewInt(0), sdk.NewInt64Coin(testDenom1, 1)},
   189  	}
   190  	for i, tc := range cases {
   191  		res := tc.coin.AddAmount(tc.amount)
   192  		s.Require().Equal(tc.expected, res, "result of addition is incorrect, tc #%d", i)
   193  	}
   194  }
   195  
   196  func (s *coinTestSuite) TestSubCoin() {
   197  	cases := []struct {
   198  		inputOne    sdk.Coin
   199  		inputTwo    sdk.Coin
   200  		expected    sdk.Coin
   201  		shouldPanic bool
   202  	}{
   203  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), sdk.NewInt64Coin(testDenom1, 1), true},
   204  		{sdk.NewInt64Coin(testDenom1, 10), sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 9), false},
   205  		{sdk.NewInt64Coin(testDenom1, 5), sdk.NewInt64Coin(testDenom1, 3), sdk.NewInt64Coin(testDenom1, 2), false},
   206  		{sdk.NewInt64Coin(testDenom1, 5), sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom1, 5), false},
   207  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 5), sdk.Coin{}, true},
   208  	}
   209  
   210  	for tcIndex, tc := range cases {
   211  		tc := tc
   212  		if tc.shouldPanic {
   213  			s.Require().Panics(func() { tc.inputOne.Sub(tc.inputTwo) })
   214  		} else {
   215  			res := tc.inputOne.Sub(tc.inputTwo)
   216  			s.Require().Equal(tc.expected, res, "difference of coins is incorrect, tc #%d", tcIndex)
   217  		}
   218  	}
   219  
   220  	tc := struct {
   221  		inputOne sdk.Coin
   222  		inputTwo sdk.Coin
   223  		expected int64
   224  	}{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), 0}
   225  	res := tc.inputOne.Sub(tc.inputTwo)
   226  	s.Require().Equal(tc.expected, res.Amount.Int64())
   227  }
   228  
   229  func (s *coinTestSuite) TestSubCoinAmount() {
   230  	cases := []struct {
   231  		coin        sdk.Coin
   232  		amount      math.Int
   233  		expected    sdk.Coin
   234  		shouldPanic bool
   235  	}{
   236  		{sdk.NewInt64Coin(testDenom1, 2), math.NewInt(1), sdk.NewInt64Coin(testDenom1, 1), false},
   237  		{sdk.NewInt64Coin(testDenom1, 10), math.NewInt(1), sdk.NewInt64Coin(testDenom1, 9), false},
   238  		{sdk.NewInt64Coin(testDenom1, 5), math.NewInt(3), sdk.NewInt64Coin(testDenom1, 2), false},
   239  		{sdk.NewInt64Coin(testDenom1, 5), math.NewInt(0), sdk.NewInt64Coin(testDenom1, 5), false},
   240  		{sdk.NewInt64Coin(testDenom1, 1), math.NewInt(5), sdk.Coin{}, true},
   241  	}
   242  
   243  	for i, tc := range cases {
   244  		if tc.shouldPanic {
   245  			s.Require().Panics(func() { tc.coin.SubAmount(tc.amount) })
   246  		} else {
   247  			res := tc.coin.SubAmount(tc.amount)
   248  			s.Require().Equal(tc.expected, res, "result of subtraction is incorrect, tc #%d", i)
   249  		}
   250  	}
   251  }
   252  
   253  func (s *coinTestSuite) TestMulIntCoins() {
   254  	testCases := []struct {
   255  		input       sdk.Coins
   256  		multiplier  math.Int
   257  		expected    sdk.Coins
   258  		shouldPanic bool
   259  	}{
   260  		{sdk.Coins{s.ca2}, math.NewInt(0), sdk.Coins{s.ca0}, true},
   261  		{sdk.Coins{s.ca2}, math.NewInt(2), sdk.Coins{s.ca4}, false},
   262  		{sdk.Coins{s.ca1, s.cm2}, math.NewInt(2), sdk.Coins{s.ca2, s.cm4}, false},
   263  	}
   264  
   265  	assert := s.Assert()
   266  	for i, tc := range testCases {
   267  		tc := tc
   268  		if tc.shouldPanic {
   269  			assert.Panics(func() { tc.input.MulInt(tc.multiplier) })
   270  		} else {
   271  			res := tc.input.MulInt(tc.multiplier)
   272  			assert.True(res.IsValid())
   273  			assert.Equal(tc.expected, res, "multiplication of coins is incorrect, tc #%d", i)
   274  		}
   275  	}
   276  }
   277  
   278  func (s *coinTestSuite) TestQuoIntCoins() {
   279  	testCases := []struct {
   280  		input       sdk.Coins
   281  		divisor     math.Int
   282  		expected    sdk.Coins
   283  		isValid     bool
   284  		shouldPanic bool
   285  	}{
   286  		{sdk.Coins{s.ca2, s.ca1}, math.NewInt(0), sdk.Coins{s.ca0, s.ca0}, true, true},
   287  		{sdk.Coins{s.ca2}, math.NewInt(4), sdk.Coins{s.ca0}, false, false},
   288  		{sdk.Coins{s.ca2, s.cm4}, math.NewInt(2), sdk.Coins{s.ca1, s.cm2}, true, false},
   289  		{sdk.Coins{s.ca4}, math.NewInt(2), sdk.Coins{s.ca2}, true, false},
   290  	}
   291  
   292  	assert := s.Assert()
   293  	for i, tc := range testCases {
   294  		tc := tc
   295  		if tc.shouldPanic {
   296  			assert.Panics(func() { tc.input.QuoInt(tc.divisor) })
   297  		} else {
   298  			res := tc.input.QuoInt(tc.divisor)
   299  			assert.Equal(tc.isValid, res.IsValid())
   300  			assert.Equal(tc.expected, res, "quotient of coins is incorrect, tc #%d", i)
   301  		}
   302  	}
   303  }
   304  
   305  func (s *coinTestSuite) TestIsGTECoin() {
   306  	cases := []struct {
   307  		inputOne sdk.Coin
   308  		inputTwo sdk.Coin
   309  		expected bool
   310  		panics   bool
   311  	}{
   312  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), true, false},
   313  		{sdk.NewInt64Coin(testDenom1, 2), sdk.NewInt64Coin(testDenom1, 1), true, false},
   314  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 2), false, false},
   315  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), false, true},
   316  	}
   317  
   318  	for tcIndex, tc := range cases {
   319  		tc := tc
   320  		if tc.panics {
   321  			s.Require().Panics(func() { tc.inputOne.IsGTE(tc.inputTwo) })
   322  		} else {
   323  			res := tc.inputOne.IsGTE(tc.inputTwo)
   324  			s.Require().Equal(tc.expected, res, "coin GTE relation is incorrect, tc #%d", tcIndex)
   325  		}
   326  	}
   327  }
   328  
   329  func (s *coinTestSuite) TestIsLTECoin() {
   330  	cases := []struct {
   331  		inputOne sdk.Coin
   332  		inputTwo sdk.Coin
   333  		expected bool
   334  		panics   bool
   335  	}{
   336  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), true, false},
   337  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 2), true, false},
   338  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), false, true},
   339  		{sdk.NewInt64Coin(testDenom1, 2), sdk.NewInt64Coin(testDenom1, 1), false, false},
   340  	}
   341  
   342  	for tcIndex, tc := range cases {
   343  		tc := tc
   344  		if tc.panics {
   345  			s.Require().Panics(func() { tc.inputOne.IsLTE(tc.inputTwo) })
   346  		} else {
   347  			res := tc.inputOne.IsLTE(tc.inputTwo)
   348  			s.Require().Equal(tc.expected, res, "coin LTE relation is incorrect, tc #%d", tcIndex)
   349  		}
   350  	}
   351  }
   352  
   353  func (s *coinTestSuite) TestIsLTCoin() {
   354  	cases := []struct {
   355  		inputOne sdk.Coin
   356  		inputTwo sdk.Coin
   357  		expected bool
   358  		panics   bool
   359  	}{
   360  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), false, false},
   361  		{sdk.NewInt64Coin(testDenom1, 2), sdk.NewInt64Coin(testDenom1, 1), false, false},
   362  		{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1), false, true},
   363  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), false, true},
   364  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), false, false},
   365  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 2), true, false},
   366  	}
   367  
   368  	for tcIndex, tc := range cases {
   369  		tc := tc
   370  		if tc.panics {
   371  			s.Require().Panics(func() { tc.inputOne.IsLT(tc.inputTwo) })
   372  		} else {
   373  			res := tc.inputOne.IsLT(tc.inputTwo)
   374  			s.Require().Equal(tc.expected, res, "coin LT relation is incorrect, tc #%d", tcIndex)
   375  		}
   376  	}
   377  }
   378  
   379  func (s *coinTestSuite) TestCoinIsZero() {
   380  	coin := sdk.NewInt64Coin(testDenom1, 0)
   381  	res := coin.IsZero()
   382  	s.Require().True(res)
   383  
   384  	coin = sdk.NewInt64Coin(testDenom1, 1)
   385  	res = coin.IsZero()
   386  	s.Require().False(res)
   387  }
   388  
   389  func (s *coinTestSuite) TestCoinIsNil() {
   390  	coin := sdk.Coin{}
   391  	res := coin.IsNil()
   392  	s.Require().True(res)
   393  
   394  	coin = sdk.Coin{Denom: "uatom"}
   395  	res = coin.IsNil()
   396  	s.Require().True(res)
   397  
   398  	coin = sdk.NewInt64Coin(testDenom1, 1)
   399  	res = coin.IsNil()
   400  	s.Require().False(res)
   401  }
   402  
   403  func (s *coinTestSuite) TestFilteredZeroCoins() {
   404  	cases := []struct {
   405  		name     string
   406  		input    sdk.Coins
   407  		original string
   408  		expected string
   409  	}{
   410  		{
   411  			name: "all greater than zero",
   412  			input: sdk.Coins{
   413  				{"testa", math.OneInt()},
   414  				{"testb", math.NewInt(2)},
   415  				{"testc", math.NewInt(3)},
   416  				{"testd", math.NewInt(4)},
   417  				{"teste", math.NewInt(5)},
   418  			},
   419  			original: "1testa,2testb,3testc,4testd,5teste",
   420  			expected: "1testa,2testb,3testc,4testd,5teste",
   421  		},
   422  		{
   423  			name: "zero coin in middle",
   424  			input: sdk.Coins{
   425  				{"testa", math.OneInt()},
   426  				{"testb", math.NewInt(2)},
   427  				{"testc", math.NewInt(0)},
   428  				{"testd", math.NewInt(4)},
   429  				{"teste", math.NewInt(5)},
   430  			},
   431  			original: "1testa,2testb,0testc,4testd,5teste",
   432  			expected: "1testa,2testb,4testd,5teste",
   433  		},
   434  		{
   435  			name: "zero coin end (unordered)",
   436  			input: sdk.Coins{
   437  				{"teste", math.NewInt(5)},
   438  				{"testc", math.NewInt(3)},
   439  				{"testa", math.OneInt()},
   440  				{"testd", math.NewInt(4)},
   441  				{"testb", math.NewInt(0)},
   442  			},
   443  			original: "5teste,3testc,1testa,4testd,0testb",
   444  			expected: "1testa,3testc,4testd,5teste",
   445  		},
   446  	}
   447  
   448  	for _, tt := range cases {
   449  		undertest := sdk.NewCoins(tt.input...)
   450  		s.Require().Equal(tt.expected, undertest.String(), "NewCoins must return expected results")
   451  		s.Require().Equal(tt.original, tt.input.String(), "input must be unmodified and match original")
   452  	}
   453  }
   454  
   455  // ----------------------------------------------------------------------------
   456  // Coins tests
   457  
   458  func (s *coinTestSuite) TestCoins_String() {
   459  	cases := []struct {
   460  		name     string
   461  		input    sdk.Coins
   462  		expected string
   463  	}{
   464  		{
   465  			"empty coins",
   466  			sdk.Coins{},
   467  			"",
   468  		},
   469  		{
   470  			"single coin",
   471  			sdk.Coins{{"tree", math.OneInt()}},
   472  			"1tree",
   473  		},
   474  		{
   475  			"multiple coins",
   476  			sdk.Coins{
   477  				{"tree", math.OneInt()},
   478  				{"gas", math.OneInt()},
   479  				{"mineral", math.OneInt()},
   480  			},
   481  			"1tree,1gas,1mineral",
   482  		},
   483  	}
   484  
   485  	for _, tt := range cases {
   486  		s.Require().Equal(tt.expected, tt.input.String())
   487  	}
   488  }
   489  
   490  func (s *coinTestSuite) TestIsZeroCoins() {
   491  	cases := []struct {
   492  		inputOne sdk.Coins
   493  		expected bool
   494  	}{
   495  		{sdk.Coins{}, true},
   496  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, true},
   497  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 0)}, true},
   498  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 1)}, false},
   499  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, false},
   500  	}
   501  
   502  	for _, tc := range cases {
   503  		res := tc.inputOne.IsZero()
   504  		s.Require().Equal(tc.expected, res)
   505  	}
   506  }
   507  
   508  func (s *coinTestSuite) TestEqualCoins() {
   509  	cases := []struct {
   510  		inputOne sdk.Coins
   511  		inputTwo sdk.Coins
   512  		expected bool
   513  	}{
   514  		{sdk.Coins{}, sdk.Coins{}, true},
   515  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, true},
   516  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, true},
   517  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, sdk.Coins{sdk.NewInt64Coin(testDenom2, 0)}, false},
   518  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, sdk.Coins{sdk.NewInt64Coin(testDenom1, 1)}, false},
   519  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, false},
   520  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, true},
   521  	}
   522  
   523  	for tcnum, tc := range cases {
   524  		res := tc.inputOne.Equal(tc.inputTwo)
   525  		s.Require().Equal(tc.expected, res, "Equality is differed from exported. tc #%d, expected %b, actual %b.", tcnum, tc.expected, res)
   526  	}
   527  }
   528  
   529  func (s *coinTestSuite) TestAddCoins() {
   530  	cA0M0 := sdk.Coins{s.ca0, s.cm0}
   531  	cA0M1 := sdk.Coins{s.ca0, s.cm1}
   532  	cA1M1 := sdk.Coins{s.ca1, s.cm1}
   533  	cases := []struct {
   534  		name     string
   535  		inputOne sdk.Coins
   536  		inputTwo sdk.Coins
   537  		expected sdk.Coins
   538  		msg      string
   539  	}{
   540  		{"adding two empty lists", s.emptyCoins, s.emptyCoins, s.emptyCoins, "empty, non list should be returned"},
   541  		{"empty list + set", s.emptyCoins, cA0M1, sdk.Coins{s.cm1}, "zero coins should be removed"},
   542  		{"empty list + set", s.emptyCoins, cA1M1, cA1M1, "zero + a_non_zero = a_non_zero"},
   543  		{"set + empty list", cA0M1, s.emptyCoins, sdk.Coins{s.cm1}, "zero coins should be removed"},
   544  		{"set + empty list", cA1M1, s.emptyCoins, cA1M1, "a_non_zero + zero  = a_non_zero"},
   545  		{
   546  			"{1atom,1muon}+{1atom,1muon}", cA1M1, cA1M1,
   547  			sdk.Coins{s.ca2, s.cm2},
   548  			"a + a = 2a",
   549  		},
   550  		{
   551  			"{0atom,1muon}+{0atom,0muon}", cA0M1, cA0M0,
   552  			sdk.Coins{s.cm1},
   553  			"zero coins should be removed",
   554  		},
   555  		{
   556  			"{2atom}+{0muon}",
   557  			sdk.Coins{s.ca2},
   558  			sdk.Coins{s.cm0},
   559  			sdk.Coins{s.ca2},
   560  			"zero coins should be removed",
   561  		},
   562  		{
   563  			"{1atom}+{1atom,2muon}",
   564  			sdk.Coins{s.ca1},
   565  			sdk.Coins{s.ca1, s.cm2},
   566  			sdk.Coins{s.ca2, s.cm2},
   567  			"should be correctly added",
   568  		},
   569  		{
   570  			"{0atom,0muon}+{0atom,0muon}", cA0M0, cA0M0, s.emptyCoins,
   571  			"sets with zero coins should return empty set",
   572  		},
   573  	}
   574  
   575  	for _, tc := range cases {
   576  		s.T().Run(tc.name, func(t *testing.T) {
   577  			res := tc.inputOne.Add(tc.inputTwo...)
   578  			require.True(t, res.IsValid(), fmt.Sprintf("%s + %s = %s", tc.inputOne, tc.inputTwo, res))
   579  			require.Equal(t, tc.expected, res, tc.msg)
   580  		})
   581  	}
   582  }
   583  
   584  // Tests that even if coins with repeated denominations are passed into .Add that they
   585  // are correctly coalesced. Please see issue https://github.com/cosmos/cosmos-sdk/issues/13234
   586  func TestCoinsAddCoalescesDuplicateDenominations(t *testing.T) {
   587  	A := sdk.Coins{
   588  		{"den", math.NewInt(2)},
   589  		{"den", math.NewInt(3)},
   590  	}
   591  	B := sdk.Coins{
   592  		{"den", math.NewInt(3)},
   593  		{"den", math.NewInt(2)},
   594  		{"den", math.NewInt(1)},
   595  	}
   596  
   597  	A = A.Sort()
   598  	B = B.Sort()
   599  	got := A.Add(B...)
   600  
   601  	want := sdk.Coins{
   602  		{"den", math.NewInt(11)},
   603  	}
   604  
   605  	if !got.Equal(want) {
   606  		t.Fatalf("Wrong result\n\tGot:   %s\n\tWant: %s", got, want)
   607  	}
   608  }
   609  
   610  func (s *coinTestSuite) TestSubCoins() {
   611  	cA0M0 := sdk.Coins{s.ca0, s.cm0}
   612  	cA0M1 := sdk.Coins{s.ca0, s.cm1}
   613  	testCases := []struct {
   614  		inputOne    sdk.Coins
   615  		inputTwo    sdk.Coins
   616  		expected    sdk.Coins
   617  		shouldPanic bool
   618  	}{
   619  		{s.emptyCoins, s.emptyCoins, s.emptyCoins, false},
   620  		{cA0M0, s.emptyCoins, s.emptyCoins, false},
   621  		{cA0M0, sdk.Coins{s.cm0}, s.emptyCoins, false},
   622  		{sdk.Coins{s.cm0}, cA0M0, s.emptyCoins, false},
   623  		{cA0M1, s.emptyCoins, sdk.Coins{s.cm1}, false},
   624  		// denoms are not sorted - should panic
   625  		{sdk.Coins{s.ca2}, sdk.Coins{s.cm2, s.ca1}, sdk.Coins{}, true},
   626  		{sdk.Coins{s.cm2, s.ca2}, sdk.Coins{s.ca1}, sdk.Coins{}, true},
   627  		// test cases for sorted denoms
   628  		{sdk.Coins{s.ca2}, sdk.Coins{s.ca1, s.cm2}, sdk.Coins{s.ca1, s.cm2}, true},
   629  		{sdk.Coins{s.ca2}, sdk.Coins{s.cm0}, sdk.Coins{s.ca2}, false},
   630  		{sdk.Coins{s.ca1}, sdk.Coins{s.cm0}, sdk.Coins{s.ca1}, false},
   631  		{sdk.Coins{s.ca1, s.cm1}, sdk.Coins{s.ca1}, sdk.Coins{s.cm1}, false},
   632  		{sdk.Coins{s.ca1, s.cm1}, sdk.Coins{s.ca2}, sdk.Coins{}, true},
   633  	}
   634  
   635  	assert := s.Assert()
   636  	for i, tc := range testCases {
   637  		tc := tc
   638  		if tc.shouldPanic {
   639  			assert.Panics(func() { tc.inputOne.Sub(tc.inputTwo...) })
   640  		} else {
   641  			res := tc.inputOne.Sub(tc.inputTwo...)
   642  			assert.True(res.IsValid())
   643  			assert.Equal(tc.expected, res, "sum of coins is incorrect, tc #%d", i)
   644  		}
   645  	}
   646  }
   647  
   648  func (s *coinTestSuite) TestSafeSubCoin() {
   649  	cases := []struct {
   650  		inputOne  sdk.Coin
   651  		inputTwo  sdk.Coin
   652  		expected  sdk.Coin
   653  		expErrMsg string
   654  	}{
   655  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), sdk.NewInt64Coin(testDenom1, 1), "invalid coin denoms"},
   656  		{sdk.NewInt64Coin(testDenom1, 10), sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 9), ""},
   657  		{sdk.NewInt64Coin(testDenom1, 5), sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom1, 5), ""},
   658  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 5), sdk.Coin{}, "negative coin amount"},
   659  	}
   660  
   661  	for _, tc := range cases {
   662  		tc := tc
   663  		res, err := tc.inputOne.SafeSub(tc.inputTwo)
   664  		if err != nil {
   665  			s.Require().Contains(err.Error(), tc.expErrMsg)
   666  			return
   667  		}
   668  		s.Require().Equal(tc.expected, res)
   669  	}
   670  }
   671  
   672  func (s *coinTestSuite) TestCoins_Validate() {
   673  	testCases := []struct {
   674  		name    string
   675  		coins   sdk.Coins
   676  		expPass bool
   677  	}{
   678  		{
   679  			"valid lowercase coins",
   680  			sdk.Coins{
   681  				{"gas", math.OneInt()},
   682  				{"mineral", math.OneInt()},
   683  				{"tree", math.OneInt()},
   684  			},
   685  			true,
   686  		},
   687  		{
   688  			"valid uppercase coins",
   689  			sdk.Coins{
   690  				{"GAS", math.OneInt()},
   691  				{"MINERAL", math.OneInt()},
   692  				{"TREE", math.OneInt()},
   693  			},
   694  			true,
   695  		},
   696  		{
   697  			"valid uppercase coin",
   698  			sdk.Coins{
   699  				{"ATOM", math.OneInt()},
   700  			},
   701  			true,
   702  		},
   703  		{
   704  			"valid lower and uppercase coins (1)",
   705  			sdk.Coins{
   706  				{"GAS", math.OneInt()},
   707  				{"gAs", math.OneInt()},
   708  			},
   709  			true,
   710  		},
   711  		{
   712  			"valid lower and uppercase coins (2)",
   713  			sdk.Coins{
   714  				{"ATOM", math.OneInt()},
   715  				{"Atom", math.OneInt()},
   716  				{"atom", math.OneInt()},
   717  			},
   718  			true,
   719  		},
   720  		{
   721  			"mixed case (1)",
   722  			sdk.Coins{
   723  				{"MineraL", math.OneInt()},
   724  				{"TREE", math.OneInt()},
   725  				{"gAs", math.OneInt()},
   726  			},
   727  			true,
   728  		},
   729  		{
   730  			"mixed case (2)",
   731  			sdk.Coins{
   732  				{"gAs", math.OneInt()},
   733  				{"mineral", math.OneInt()},
   734  			},
   735  			true,
   736  		},
   737  		{
   738  			"mixed case (3)",
   739  			sdk.Coins{
   740  				{"gAs", math.OneInt()},
   741  			},
   742  			true,
   743  		},
   744  		{
   745  			"unicode letters and numbers",
   746  			sdk.Coins{
   747  				{"𐀀𐀆𐀉Ⅲ", math.OneInt()},
   748  			},
   749  			false,
   750  		},
   751  		{
   752  			"emojis",
   753  			sdk.Coins{
   754  				{"🤑😋🤔", math.OneInt()},
   755  			},
   756  			false,
   757  		},
   758  		{
   759  			"IBC denominations (ADR 001)",
   760  			sdk.Coins{
   761  				{"ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", math.OneInt()},
   762  				{"ibc/876563AAAACF739EB061C67CDB5EDF2B7C9FD4AA9D876450CC21210807C2820A", math.NewInt(2)},
   763  			},
   764  			true,
   765  		},
   766  		{
   767  			"empty (1)",
   768  			sdk.NewCoins(),
   769  			true,
   770  		},
   771  		{
   772  			"empty (2)",
   773  			sdk.Coins{},
   774  			true,
   775  		},
   776  		{
   777  			"invalid denomination (1)",
   778  			sdk.Coins{
   779  				{"MineraL", math.OneInt()},
   780  				{"0TREE", math.OneInt()},
   781  				{"gAs", math.OneInt()},
   782  			},
   783  			false,
   784  		},
   785  		{
   786  			"invalid denomination (2)",
   787  			sdk.Coins{
   788  				{"-GAS", math.OneInt()},
   789  				{"gAs", math.OneInt()},
   790  			},
   791  			false,
   792  		},
   793  		{
   794  			"bad sort (1)",
   795  			sdk.Coins{
   796  				{"tree", math.OneInt()},
   797  				{"gas", math.OneInt()},
   798  				{"mineral", math.OneInt()},
   799  			},
   800  			false,
   801  		},
   802  		{
   803  			"bad sort (2)",
   804  			sdk.Coins{
   805  				{"gas", math.OneInt()},
   806  				{"tree", math.OneInt()},
   807  				{"mineral", math.OneInt()},
   808  			},
   809  			false,
   810  		},
   811  		{
   812  			"bad sort (3)",
   813  			sdk.Coins{
   814  				{"gas", math.OneInt()},
   815  				{"tree", math.OneInt()},
   816  				{"gas", math.OneInt()},
   817  			},
   818  			false,
   819  		},
   820  		{
   821  			"non-positive amount (1)",
   822  			sdk.Coins{
   823  				{"gas", math.OneInt()},
   824  				{"tree", math.NewInt(0)},
   825  				{"mineral", math.OneInt()},
   826  			},
   827  			false,
   828  		},
   829  		{
   830  			"non-positive amount (2)",
   831  			sdk.Coins{
   832  				{"gas", math.NewInt(-1)},
   833  				{"tree", math.OneInt()},
   834  				{"mineral", math.OneInt()},
   835  			},
   836  			false,
   837  		},
   838  		{
   839  			"duplicate denomination (1)",
   840  			sdk.Coins{
   841  				{"gas", math.OneInt()},
   842  				{"gas", math.OneInt()},
   843  				{"mineral", math.OneInt()},
   844  			},
   845  			false,
   846  		},
   847  		{
   848  			"duplicate denomination (2)",
   849  			sdk.Coins{
   850  				{"gold", math.OneInt()},
   851  				{"gold", math.OneInt()},
   852  			},
   853  			false,
   854  		},
   855  		{
   856  			"duplicate denomination (3)",
   857  			sdk.Coins{
   858  				{"gas", math.OneInt()},
   859  				{"mineral", math.OneInt()},
   860  				{"silver", math.OneInt()},
   861  				{"silver", math.OneInt()},
   862  			},
   863  			false,
   864  		},
   865  	}
   866  
   867  	for _, tc := range testCases {
   868  		err := tc.coins.Validate()
   869  		if tc.expPass {
   870  			s.Require().NoError(err, tc.name)
   871  		} else {
   872  			s.Require().Error(err, tc.name)
   873  		}
   874  	}
   875  }
   876  
   877  func (s *coinTestSuite) TestMinMax() {
   878  	one := math.OneInt()
   879  	two := math.NewInt(2)
   880  
   881  	cases := []struct {
   882  		name   string
   883  		input1 sdk.Coins
   884  		input2 sdk.Coins
   885  		min    sdk.Coins
   886  		max    sdk.Coins
   887  	}{
   888  		{"zero-zero", sdk.Coins{}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{}},
   889  		{"zero-one", sdk.Coins{}, sdk.Coins{{testDenom1, one}}, sdk.Coins{}, sdk.Coins{{testDenom1, one}}},
   890  		{"two-zero", sdk.Coins{{testDenom2, two}}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{{testDenom2, two}}},
   891  		{"disjoint", sdk.Coins{{testDenom1, one}}, sdk.Coins{{testDenom2, two}}, sdk.Coins{}, sdk.Coins{{testDenom1, one}, {testDenom2, two}}},
   892  		{
   893  			"overlap",
   894  			sdk.Coins{{testDenom1, one}, {testDenom2, two}},
   895  			sdk.Coins{{testDenom1, two}, {testDenom2, one}},
   896  			sdk.Coins{{testDenom1, one}, {testDenom2, one}},
   897  			sdk.Coins{{testDenom1, two}, {testDenom2, two}},
   898  		},
   899  	}
   900  
   901  	for _, tc := range cases {
   902  		min := tc.input1.Min(tc.input2)
   903  		max := tc.input1.Max(tc.input2)
   904  		s.Require().True(min.Equal(tc.min), tc.name)
   905  		s.Require().True(max.Equal(tc.max), tc.name)
   906  	}
   907  }
   908  
   909  func (s *coinTestSuite) TestCoinsGT() {
   910  	one := math.OneInt()
   911  	two := math.NewInt(2)
   912  
   913  	s.Require().False(sdk.Coins{}.IsAllGT(sdk.Coins{}))
   914  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{}))
   915  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom1, one}}))
   916  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom2, one}}))
   917  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(sdk.Coins{{testDenom2, one}}))
   918  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(sdk.Coins{{testDenom2, two}}))
   919  }
   920  
   921  func (s *coinTestSuite) TestCoinsLT() {
   922  	one := math.OneInt()
   923  	two := math.NewInt(2)
   924  
   925  	s.Require().False(sdk.Coins{}.IsAllLT(sdk.Coins{}))
   926  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllLT(sdk.Coins{}))
   927  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllLT(sdk.Coins{{testDenom1, one}}))
   928  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllLT(sdk.Coins{{testDenom2, one}}))
   929  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(sdk.Coins{{testDenom2, one}}))
   930  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(sdk.Coins{{testDenom2, two}}))
   931  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(sdk.Coins{{testDenom1, one}, {testDenom2, one}}))
   932  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(sdk.Coins{{testDenom1, two}, {testDenom2, two}}))
   933  	s.Require().True(sdk.Coins{}.IsAllLT(sdk.Coins{{testDenom1, one}}))
   934  }
   935  
   936  func (s *coinTestSuite) TestCoinsLTE() {
   937  	one := math.OneInt()
   938  	two := math.NewInt(2)
   939  
   940  	s.Require().True(sdk.Coins{}.IsAllLTE(sdk.Coins{}))
   941  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllLTE(sdk.Coins{}))
   942  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAllLTE(sdk.Coins{{testDenom1, one}}))
   943  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllLTE(sdk.Coins{{testDenom2, one}}))
   944  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(sdk.Coins{{testDenom2, one}}))
   945  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(sdk.Coins{{testDenom2, two}}))
   946  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(sdk.Coins{{testDenom1, one}, {testDenom2, one}}))
   947  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   948  	s.Require().True(sdk.Coins{}.IsAllLTE(sdk.Coins{{testDenom1, one}}))
   949  }
   950  
   951  func (s *coinTestSuite) TestParseCoins() {
   952  	one := math.OneInt()
   953  
   954  	cases := []struct {
   955  		input    string
   956  		valid    bool      // if false, we expect an error on parse
   957  		expected sdk.Coins // if valid is true, make sure this is returned
   958  	}{
   959  		{"", true, nil},
   960  		{"0stake", true, sdk.Coins{}}, // remove zero coins
   961  		{"0stake,1foo,99bar", true, sdk.Coins{{"bar", math.NewInt(99)}, {"foo", one}}}, // remove zero coins
   962  		{"1foo", true, sdk.Coins{{"foo", one}}},
   963  		{"10btc,1atom,20btc", false, nil},
   964  		{"10bar", true, sdk.Coins{{"bar", math.NewInt(10)}}},
   965  		{"99bar,1foo", true, sdk.Coins{{"bar", math.NewInt(99)}, {"foo", one}}},
   966  		{"98 bar , 1 foo  ", true, sdk.Coins{{"bar", math.NewInt(98)}, {"foo", one}}},
   967  		{"  55\t \t bling\n", true, sdk.Coins{{"bling", math.NewInt(55)}}},
   968  		{"2foo, 97 bar", true, sdk.Coins{{"bar", math.NewInt(97)}, {"foo", math.NewInt(2)}}},
   969  		{"5 mycoin,", false, nil},                            // no empty coins in a list
   970  		{"2 3foo, 97 bar", false, nil},                       // 3foo is invalid coin name
   971  		{"11me coin, 12you coin", false, nil},                // no spaces in coin names
   972  		{"1.2btc", true, sdk.Coins{{"btc", math.NewInt(1)}}}, // amount can be decimal, will get truncated
   973  		{"5foo:bar", true, sdk.Coins{{"foo:bar", math.NewInt(5)}}},
   974  		{"10atom10", true, sdk.Coins{{"atom10", math.NewInt(10)}}},
   975  		{"200transfer/channelToA/uatom", true, sdk.Coins{{"transfer/channelToA/uatom", math.NewInt(200)}}},
   976  		{"50ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", true, sdk.Coins{{"ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", math.NewInt(50)}}},
   977  		{"120000000000000000000000000000000000000000000000000000000000000000000000000000btc", false, nil},
   978  	}
   979  
   980  	for tcIndex, tc := range cases {
   981  		res, err := sdk.ParseCoinsNormalized(tc.input)
   982  		if !tc.valid {
   983  			s.Require().Error(err, "%s: %#v. tc #%d", tc.input, res, tcIndex)
   984  		} else if s.Assert().Nil(err, "%s: %+v", tc.input, err) {
   985  			s.Require().Equal(tc.expected, res, "coin parsing was incorrect, tc #%d", tcIndex)
   986  		}
   987  	}
   988  }
   989  
   990  func (s *coinTestSuite) TestSortCoins() {
   991  	good := sdk.Coins{
   992  		sdk.NewInt64Coin("gas", 1),
   993  		sdk.NewInt64Coin("mineral", 1),
   994  		sdk.NewInt64Coin("tree", 1),
   995  	}
   996  	empty := sdk.Coins{
   997  		sdk.NewInt64Coin("gold", 0),
   998  	}
   999  	badSort1 := sdk.Coins{
  1000  		sdk.NewInt64Coin("tree", 1),
  1001  		sdk.NewInt64Coin("gas", 1),
  1002  		sdk.NewInt64Coin("mineral", 1),
  1003  	}
  1004  	badSort2 := sdk.Coins{ // both are after the first one, but the second and third are in the wrong order
  1005  		sdk.NewInt64Coin("gas", 1),
  1006  		sdk.NewInt64Coin("tree", 1),
  1007  		sdk.NewInt64Coin("mineral", 1),
  1008  	}
  1009  	badAmt := sdk.Coins{
  1010  		sdk.NewInt64Coin("gas", 1),
  1011  		sdk.NewInt64Coin("tree", 0),
  1012  		sdk.NewInt64Coin("mineral", 1),
  1013  	}
  1014  	dup := sdk.Coins{
  1015  		sdk.NewInt64Coin("gas", 1),
  1016  		sdk.NewInt64Coin("gas", 1),
  1017  		sdk.NewInt64Coin("mineral", 1),
  1018  	}
  1019  
  1020  	cases := []struct {
  1021  		name  string
  1022  		coins sdk.Coins
  1023  		validBefore,
  1024  		validAfter bool
  1025  	}{
  1026  		{"valid coins", good, true, true},
  1027  		{"empty coins", empty, false, false},
  1028  		{"bad sort (1)", badSort1, false, true},
  1029  		{"bad sort (2)", badSort2, false, true},
  1030  		{"zero value coin", badAmt, false, false},
  1031  		{"duplicate coins", dup, false, false},
  1032  	}
  1033  
  1034  	for _, tc := range cases {
  1035  		err := tc.coins.Validate()
  1036  		if tc.validBefore {
  1037  			s.Require().NoError(err, tc.name)
  1038  		} else {
  1039  			s.Require().Error(err, tc.name)
  1040  		}
  1041  
  1042  		tc.coins.Sort()
  1043  
  1044  		err = tc.coins.Validate()
  1045  		if tc.validAfter {
  1046  			s.Require().NoError(err, tc.name)
  1047  		} else {
  1048  			s.Require().Error(err, tc.name)
  1049  		}
  1050  	}
  1051  }
  1052  
  1053  func (s *coinTestSuite) TestSearch() {
  1054  	require := s.Require()
  1055  	case0 := sdk.Coins{}
  1056  	case1 := sdk.Coins{
  1057  		sdk.NewInt64Coin("gold", 0),
  1058  	}
  1059  	case2 := sdk.Coins{
  1060  		sdk.NewInt64Coin("gas", 1),
  1061  		sdk.NewInt64Coin("mineral", 1),
  1062  		sdk.NewInt64Coin("tree", 1),
  1063  	}
  1064  	case3 := sdk.Coins{
  1065  		sdk.NewInt64Coin("mineral", 1),
  1066  		sdk.NewInt64Coin("tree", 1),
  1067  	}
  1068  	case4 := sdk.Coins{
  1069  		sdk.NewInt64Coin("gas", 8),
  1070  	}
  1071  
  1072  	amountOfCases := []struct {
  1073  		coins           sdk.Coins
  1074  		amountOf        int64
  1075  		amountOfSpace   int64
  1076  		amountOfGAS     int64
  1077  		amountOfMINERAL int64
  1078  		amountOfTREE    int64
  1079  	}{
  1080  		{case0, 0, 0, 0, 0, 0},
  1081  		{case1, 0, 0, 0, 0, 0},
  1082  		{case2, 0, 0, 1, 1, 1},
  1083  		{case3, 0, 0, 0, 1, 1},
  1084  		{case4, 0, 0, 8, 0, 0},
  1085  	}
  1086  
  1087  	s.Run("AmountOf", func() {
  1088  		for i, tc := range amountOfCases {
  1089  			require.Equal(math.NewInt(tc.amountOfGAS), tc.coins.AmountOf("gas"), i)
  1090  			require.Equal(math.NewInt(tc.amountOfMINERAL), tc.coins.AmountOf("mineral"), i)
  1091  			require.Equal(math.NewInt(tc.amountOfTREE), tc.coins.AmountOf("tree"), i)
  1092  		}
  1093  		require.Panics(func() { amountOfCases[0].coins.AmountOf("10Invalid") })
  1094  	})
  1095  
  1096  	zeroCoin := sdk.Coin{}
  1097  	findCases := []struct {
  1098  		coins        sdk.Coins
  1099  		denom        string
  1100  		expectedOk   bool
  1101  		expectedCoin sdk.Coin
  1102  	}{
  1103  		{case0, "any", false, zeroCoin},
  1104  		{case1, "other", false, zeroCoin},
  1105  		{case1, "gold", true, case1[0]},
  1106  		{case4, "gas", true, case4[0]},
  1107  		{case2, "gas", true, case2[0]},
  1108  		{case2, "mineral", true, case2[1]},
  1109  		{case2, "tree", true, case2[2]},
  1110  		{case2, "other", false, zeroCoin},
  1111  	}
  1112  	s.Run("Find", func() {
  1113  		for i, tc := range findCases {
  1114  			ok, c := tc.coins.Find(tc.denom)
  1115  			require.Equal(tc.expectedOk, ok, i)
  1116  			require.Equal(tc.expectedCoin, c, i)
  1117  		}
  1118  	})
  1119  }
  1120  
  1121  func (s *coinTestSuite) TestCoinsIsAnyGTE() {
  1122  	one := math.OneInt()
  1123  	two := math.NewInt(2)
  1124  
  1125  	s.Require().False(sdk.Coins{}.IsAnyGTE(sdk.Coins{}))
  1126  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAnyGTE(sdk.Coins{}))
  1127  	s.Require().False(sdk.Coins{}.IsAnyGTE(sdk.Coins{{testDenom1, one}}))
  1128  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAnyGTE(sdk.Coins{{testDenom1, two}}))
  1129  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAnyGTE(sdk.Coins{{testDenom2, one}}))
  1130  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAnyGTE(sdk.Coins{{testDenom1, two}, {testDenom2, one}}))
  1131  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAnyGTE(sdk.Coins{{testDenom1, one}}))
  1132  	s.Require().True(sdk.Coins{{testDenom1, two}}.IsAnyGTE(sdk.Coins{{testDenom1, one}}))
  1133  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAnyGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1134  	s.Require().True(sdk.Coins{{testDenom2, two}}.IsAnyGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1135  	s.Require().False(sdk.Coins{{testDenom2, one}}.IsAnyGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1136  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAnyGTE(sdk.Coins{{testDenom1, one}, {testDenom2, one}}))
  1137  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAnyGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1138  	s.Require().True(sdk.Coins{{"xxx", one}, {"yyy", one}}.IsAnyGTE(sdk.Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}}))
  1139  }
  1140  
  1141  func (s *coinTestSuite) TestCoinsIsAllGT() {
  1142  	one := math.OneInt()
  1143  	two := math.NewInt(2)
  1144  
  1145  	s.Require().False(sdk.Coins{}.IsAllGT(sdk.Coins{}))
  1146  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{}))
  1147  	s.Require().False(sdk.Coins{}.IsAllGT(sdk.Coins{{testDenom1, one}}))
  1148  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom1, two}}))
  1149  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom2, one}}))
  1150  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(sdk.Coins{{testDenom1, two}, {testDenom2, one}}))
  1151  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom1, one}}))
  1152  	s.Require().True(sdk.Coins{{testDenom1, two}}.IsAllGT(sdk.Coins{{testDenom1, one}}))
  1153  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1154  	s.Require().False(sdk.Coins{{testDenom2, two}}.IsAllGT(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1155  	s.Require().False(sdk.Coins{{testDenom2, one}}.IsAllGT(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1156  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(sdk.Coins{{testDenom1, one}, {testDenom2, one}}))
  1157  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1158  	s.Require().False(sdk.Coins{{"xxx", one}, {"yyy", one}}.IsAllGT(sdk.Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}}))
  1159  }
  1160  
  1161  func (s *coinTestSuite) TestCoinsIsAllGTE() {
  1162  	one := math.OneInt()
  1163  	two := math.NewInt(2)
  1164  
  1165  	s.Require().True(sdk.Coins{}.IsAllGTE(sdk.Coins{}))
  1166  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAllGTE(sdk.Coins{}))
  1167  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(sdk.Coins{{testDenom2, one}}))
  1168  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(sdk.Coins{{testDenom2, two}}))
  1169  	s.Require().False(sdk.Coins{}.IsAllGTE(sdk.Coins{{testDenom1, one}}))
  1170  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGTE(sdk.Coins{{testDenom1, two}}))
  1171  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGTE(sdk.Coins{{testDenom2, one}}))
  1172  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGTE(sdk.Coins{{testDenom1, two}, {testDenom2, one}}))
  1173  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAllGTE(sdk.Coins{{testDenom1, one}}))
  1174  	s.Require().True(sdk.Coins{{testDenom1, two}}.IsAllGTE(sdk.Coins{{testDenom1, one}}))
  1175  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1176  	s.Require().False(sdk.Coins{{testDenom2, two}}.IsAllGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1177  	s.Require().False(sdk.Coins{{testDenom2, one}}.IsAllGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1178  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGTE(sdk.Coins{{testDenom1, one}, {testDenom2, one}}))
  1179  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
  1180  	s.Require().False(sdk.Coins{{"xxx", one}, {"yyy", one}}.IsAllGTE(sdk.Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}}))
  1181  }
  1182  
  1183  func (s *coinTestSuite) TestNewCoins() {
  1184  	tenatom := sdk.NewInt64Coin("atom", 10)
  1185  	tenbtc := sdk.NewInt64Coin("btc", 10)
  1186  	zeroeth := sdk.NewInt64Coin("eth", 0)
  1187  	invalidCoin := sdk.Coin{"0ETH", math.OneInt()}
  1188  	tests := []struct {
  1189  		name      string
  1190  		coins     sdk.Coins
  1191  		want      sdk.Coins
  1192  		wantPanic bool
  1193  	}{
  1194  		{"empty args", []sdk.Coin{}, sdk.Coins{}, false},
  1195  		{"one coin", []sdk.Coin{tenatom}, sdk.Coins{tenatom}, false},
  1196  		{"sort after create", []sdk.Coin{tenbtc, tenatom}, sdk.Coins{tenatom, tenbtc}, false},
  1197  		{"sort and remove zeroes", []sdk.Coin{zeroeth, tenbtc, tenatom}, sdk.Coins{tenatom, tenbtc}, false},
  1198  		{"panic on dups", []sdk.Coin{tenatom, tenatom}, sdk.Coins{}, true},
  1199  		{"panic on invalid coin", []sdk.Coin{invalidCoin, tenatom}, sdk.Coins{}, true},
  1200  	}
  1201  	for _, tt := range tests {
  1202  		if tt.wantPanic {
  1203  			s.Require().Panics(func() { sdk.NewCoins(tt.coins...) })
  1204  			continue
  1205  		}
  1206  		got := sdk.NewCoins(tt.coins...)
  1207  		s.Require().True(got.Equal(tt.want))
  1208  	}
  1209  }
  1210  
  1211  func (s *coinTestSuite) TestCoinsIsAnyGT() {
  1212  	twoAtom := sdk.NewInt64Coin("atom", 2)
  1213  	fiveAtom := sdk.NewInt64Coin("atom", 5)
  1214  	threeEth := sdk.NewInt64Coin("eth", 3)
  1215  	sixEth := sdk.NewInt64Coin("eth", 6)
  1216  	twoBtc := sdk.NewInt64Coin("btc", 2)
  1217  
  1218  	tests := []struct {
  1219  		name    string
  1220  		coinsA  sdk.Coins
  1221  		coinsB  sdk.Coins
  1222  		expPass bool
  1223  	}{
  1224  		{"{} ≤ {}", sdk.Coins{}, sdk.Coins{}, false},
  1225  		{"{} ≤ 5atom", sdk.Coins{}, sdk.Coins{fiveAtom}, false},
  1226  		{"5atom > 2atom", sdk.Coins{fiveAtom}, sdk.Coins{twoAtom}, true},
  1227  		{"2atom ≤ 5atom", sdk.Coins{twoAtom}, sdk.Coins{fiveAtom}, false},
  1228  		{"2atom,6eth > 2btc,5atom,3eth", sdk.Coins{twoAtom, sixEth}, sdk.Coins{twoBtc, fiveAtom, threeEth}, true},
  1229  		{"2btc,2atom,3eth ≤ 5atom,6eth", sdk.Coins{twoBtc, twoAtom, threeEth}, sdk.Coins{fiveAtom, sixEth}, false},
  1230  		{"2atom,6eth ≤ 2btc,5atom", sdk.Coins{twoAtom, sixEth}, sdk.Coins{twoBtc, fiveAtom}, false},
  1231  	}
  1232  
  1233  	for _, tc := range tests {
  1234  		s.Require().True(tc.expPass == tc.coinsA.IsAnyGT(tc.coinsB), tc.name)
  1235  	}
  1236  }
  1237  
  1238  func (s *coinTestSuite) TestCoinsIsAnyNil() {
  1239  	twoAtom := sdk.NewInt64Coin("atom", 2)
  1240  	fiveAtom := sdk.NewInt64Coin("atom", 5)
  1241  	threeEth := sdk.NewInt64Coin("eth", 3)
  1242  	nilAtom := sdk.Coin{Denom: "atom"}
  1243  
  1244  	s.Require().True(sdk.Coins{twoAtom, fiveAtom, threeEth, nilAtom}.IsAnyNil())
  1245  	s.Require().True(sdk.Coins{twoAtom, nilAtom, fiveAtom, threeEth}.IsAnyNil())
  1246  	s.Require().True(sdk.Coins{nilAtom, twoAtom, fiveAtom, threeEth}.IsAnyNil())
  1247  	s.Require().False(sdk.Coins{twoAtom, fiveAtom, threeEth}.IsAnyNil())
  1248  }
  1249  
  1250  func (s *coinTestSuite) TestMarshalJSONCoins() {
  1251  	cdc := codec.NewLegacyAmino()
  1252  	sdk.RegisterLegacyAminoCodec(cdc)
  1253  
  1254  	testCases := []struct {
  1255  		name      string
  1256  		input     sdk.Coins
  1257  		strOutput string
  1258  	}{
  1259  		{"nil coins", nil, `[]`},
  1260  		{"empty coins", sdk.Coins{}, `[]`},
  1261  		{"non-empty coins", sdk.NewCoins(sdk.NewInt64Coin("foo", 50)), `[{"denom":"foo","amount":"50"}]`},
  1262  	}
  1263  
  1264  	for _, tc := range testCases {
  1265  		bz, err := cdc.MarshalJSON(tc.input)
  1266  		s.Require().NoError(err)
  1267  		s.Require().Equal(tc.strOutput, string(bz))
  1268  
  1269  		var newCoins sdk.Coins
  1270  		s.Require().NoError(cdc.UnmarshalJSON(bz, &newCoins))
  1271  
  1272  		if tc.input.Empty() {
  1273  			s.Require().Nil(newCoins)
  1274  		} else {
  1275  			s.Require().Equal(tc.input, newCoins)
  1276  		}
  1277  	}
  1278  }
  1279  
  1280  func (s *coinTestSuite) TestCoinValidate() {
  1281  	testCases := []struct {
  1282  		name    string
  1283  		coin    sdk.Coin
  1284  		wantErr string
  1285  	}{
  1286  		{"nil coin: nil Amount", sdk.Coin{}, "invalid denom"},
  1287  		{"non-blank coin, nil Amount", sdk.Coin{Denom: "atom"}, "amount is nil"},
  1288  		{"valid coin", sdk.Coin{Denom: "atom", Amount: math.NewInt(100)}, ""},
  1289  		{"negative coin", sdk.Coin{Denom: "atom", Amount: math.NewInt(-999)}, "negative coin amount"},
  1290  	}
  1291  
  1292  	for _, tc := range testCases {
  1293  		tc := tc
  1294  		t := s.T()
  1295  		t.Run(tc.name, func(t *testing.T) {
  1296  			err := tc.coin.Validate()
  1297  			switch {
  1298  			case tc.wantErr == "":
  1299  				if err != nil {
  1300  					t.Errorf("Unexpected error: %v", err)
  1301  				}
  1302  				return
  1303  			case err == nil:
  1304  				t.Error("Expected an error")
  1305  			case !strings.Contains(err.Error(), tc.wantErr):
  1306  				t.Errorf("Error mismatch\n\tGot:  %q\nWant: %q", err, tc.wantErr)
  1307  			}
  1308  		})
  1309  	}
  1310  }
  1311  
  1312  func (s *coinTestSuite) TestCoinAminoEncoding() {
  1313  	cdc := codec.NewLegacyAmino()
  1314  	c := sdk.NewInt64Coin(testDenom1, 5)
  1315  
  1316  	bz1, err := cdc.Marshal(c)
  1317  	s.Require().NoError(err)
  1318  
  1319  	bz2, err := cdc.MarshalLengthPrefixed(c)
  1320  	s.Require().NoError(err)
  1321  
  1322  	bz3, err := c.Marshal()
  1323  	s.Require().NoError(err)
  1324  	s.Require().Equal(bz1, bz3)
  1325  	s.Require().Equal(bz2[1:], bz3)
  1326  }