github.com/Finschia/finschia-sdk@v0.48.1/types/coin_test.go (about)

     1  package types_test
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/suite"
     9  
    10  	"github.com/Finschia/finschia-sdk/codec"
    11  	sdk "github.com/Finschia/finschia-sdk/types"
    12  )
    13  
    14  var (
    15  	testDenom1 = "atom"
    16  	testDenom2 = "muon"
    17  )
    18  
    19  type coinTestSuite struct {
    20  	suite.Suite
    21  	ca0, ca1, ca2, cm0, cm1, cm2 sdk.Coin
    22  }
    23  
    24  func TestCoinTestSuite(t *testing.T) {
    25  	suite.Run(t, new(coinTestSuite))
    26  }
    27  
    28  func (s *coinTestSuite) SetupSuite() {
    29  	s.T().Parallel()
    30  	zero := sdk.NewInt(0)
    31  	one := sdk.OneInt()
    32  	two := sdk.NewInt(2)
    33  	s.ca0, s.ca1, s.ca2 = sdk.Coin{testDenom1, zero}, sdk.Coin{testDenom1, one}, sdk.Coin{testDenom1, two}
    34  	s.cm0, s.cm1, s.cm2 = sdk.Coin{testDenom2, zero}, sdk.Coin{testDenom2, one}, sdk.Coin{testDenom2, two}
    35  }
    36  
    37  // ----------------------------------------------------------------------------
    38  // Coin tests
    39  
    40  func (s *coinTestSuite) TestCoin() {
    41  	s.Require().Panics(func() { sdk.NewInt64Coin(testDenom1, -1) })
    42  	s.Require().Panics(func() { sdk.NewCoin(testDenom1, sdk.NewInt(-1)) })
    43  	s.Require().Equal(sdk.NewInt(10), sdk.NewInt64Coin(strings.ToUpper(testDenom1), 10).Amount)
    44  	s.Require().Equal(sdk.NewInt(10), sdk.NewCoin(strings.ToUpper(testDenom1), sdk.NewInt(10)).Amount)
    45  	s.Require().Equal(sdk.NewInt(5), sdk.NewInt64Coin(testDenom1, 5).Amount)
    46  	s.Require().Equal(sdk.NewInt(5), sdk.NewCoin(testDenom1, sdk.NewInt(5)).Amount)
    47  }
    48  
    49  func (s *coinTestSuite) TestCoin_String() {
    50  	coin := sdk.NewCoin(testDenom1, sdk.NewInt(10))
    51  	s.Require().Equal(fmt.Sprintf("10%s", testDenom1), coin.String())
    52  }
    53  
    54  func (s *coinTestSuite) TestIsEqualCoin() {
    55  	cases := []struct {
    56  		inputOne sdk.Coin
    57  		inputTwo sdk.Coin
    58  		expected bool
    59  		panics   bool
    60  	}{
    61  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), true, false},
    62  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), false, true},
    63  		{sdk.NewInt64Coin("stake", 1), sdk.NewInt64Coin("stake", 10), false, false},
    64  	}
    65  
    66  	for tcIndex, tc := range cases {
    67  		tc := tc
    68  		if tc.panics {
    69  			s.Require().Panics(func() { tc.inputOne.IsEqual(tc.inputTwo) })
    70  		} else {
    71  			res := tc.inputOne.IsEqual(tc.inputTwo)
    72  			s.Require().Equal(tc.expected, res, "coin equality relation is incorrect, tc #%d", tcIndex)
    73  		}
    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, sdk.NewInt(-1)}, false},
    91  		{sdk.Coin{testDenom1, sdk.NewInt(0)}, true},
    92  		{sdk.Coin{testDenom1, sdk.OneInt()}, true},
    93  		{sdk.Coin{"Atom", sdk.OneInt()}, true},
    94  		{sdk.Coin{"ATOM", sdk.OneInt()}, true},
    95  		{sdk.Coin{"a", sdk.OneInt()}, false},
    96  		{sdk.Coin{loremIpsum, sdk.OneInt()}, false},
    97  		{sdk.Coin{"ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.OneInt()}, true},
    98  		{sdk.Coin{"atOm", sdk.OneInt()}, true},
    99  		{sdk.Coin{"     ", sdk.OneInt()}, false},
   100  	}
   101  
   102  	for i, tc := range cases {
   103  		s.Require().Equal(tc.expectPass, tc.coin.IsValid(), "unexpected result for IsValid, tc #%d", i)
   104  	}
   105  }
   106  
   107  func (s *coinTestSuite) TestCustomValidation() {
   108  	newDnmRegex := `[\x{1F600}-\x{1F6FF}]`
   109  	sdk.SetCoinDenomRegex(func() string {
   110  		return newDnmRegex
   111  	})
   112  
   113  	cases := []struct {
   114  		coin       sdk.Coin
   115  		expectPass bool
   116  	}{
   117  		{sdk.Coin{"🙂", sdk.NewInt(1)}, true},
   118  		{sdk.Coin{"🙁", sdk.NewInt(1)}, true},
   119  		{sdk.Coin{"🌶", sdk.NewInt(1)}, false}, // outside the unicode range listed above
   120  		{sdk.Coin{"asdf", sdk.NewInt(1)}, false},
   121  		{sdk.Coin{"", sdk.NewInt(1)}, false},
   122  	}
   123  
   124  	for i, tc := range cases {
   125  		s.Require().Equal(tc.expectPass, tc.coin.IsValid(), "unexpected result for IsValid, tc #%d", i)
   126  	}
   127  	sdk.SetCoinDenomRegex(sdk.DefaultCoinDenomRegex)
   128  }
   129  
   130  func (s *coinTestSuite) TestAddCoin() {
   131  	cases := []struct {
   132  		inputOne    sdk.Coin
   133  		inputTwo    sdk.Coin
   134  		expected    sdk.Coin
   135  		shouldPanic bool
   136  	}{
   137  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 2), false},
   138  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom1, 1), false},
   139  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), sdk.NewInt64Coin(testDenom1, 1), true},
   140  	}
   141  
   142  	for tcIndex, tc := range cases {
   143  		tc := tc
   144  		if tc.shouldPanic {
   145  			s.Require().Panics(func() { tc.inputOne.Add(tc.inputTwo) })
   146  		} else {
   147  			res := tc.inputOne.Add(tc.inputTwo)
   148  			s.Require().Equal(tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
   149  		}
   150  	}
   151  }
   152  
   153  func (s *coinTestSuite) TestAddCoinAmount() {
   154  	cases := []struct {
   155  		coin     sdk.Coin
   156  		amount   sdk.Int
   157  		expected sdk.Coin
   158  	}{
   159  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt(1), sdk.NewInt64Coin(testDenom1, 2)},
   160  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt(0), sdk.NewInt64Coin(testDenom1, 1)},
   161  	}
   162  	for i, tc := range cases {
   163  		res := tc.coin.AddAmount(tc.amount)
   164  		s.Require().Equal(tc.expected, res, "result of addition is incorrect, tc #%d", i)
   165  	}
   166  }
   167  
   168  func (s *coinTestSuite) TestSubCoin() {
   169  	cases := []struct {
   170  		inputOne    sdk.Coin
   171  		inputTwo    sdk.Coin
   172  		expected    sdk.Coin
   173  		shouldPanic bool
   174  	}{
   175  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), sdk.NewInt64Coin(testDenom1, 1), true},
   176  		{sdk.NewInt64Coin(testDenom1, 10), sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 9), false},
   177  		{sdk.NewInt64Coin(testDenom1, 5), sdk.NewInt64Coin(testDenom1, 3), sdk.NewInt64Coin(testDenom1, 2), false},
   178  		{sdk.NewInt64Coin(testDenom1, 5), sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom1, 5), false},
   179  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 5), sdk.Coin{}, true},
   180  	}
   181  
   182  	for tcIndex, tc := range cases {
   183  		tc := tc
   184  		if tc.shouldPanic {
   185  			s.Require().Panics(func() { tc.inputOne.Sub(tc.inputTwo) })
   186  		} else {
   187  			res := tc.inputOne.Sub(tc.inputTwo)
   188  			s.Require().Equal(tc.expected, res, "difference of coins is incorrect, tc #%d", tcIndex)
   189  		}
   190  	}
   191  
   192  	tc := struct {
   193  		inputOne sdk.Coin
   194  		inputTwo sdk.Coin
   195  		expected int64
   196  	}{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), 0}
   197  	res := tc.inputOne.Sub(tc.inputTwo)
   198  	s.Require().Equal(tc.expected, res.Amount.Int64())
   199  }
   200  
   201  func (s *coinTestSuite) TestSubCoinAmount() {
   202  	cases := []struct {
   203  		coin        sdk.Coin
   204  		amount      sdk.Int
   205  		expected    sdk.Coin
   206  		shouldPanic bool
   207  	}{
   208  		{sdk.NewInt64Coin(testDenom1, 2), sdk.NewInt(1), sdk.NewInt64Coin(testDenom1, 1), false},
   209  		{sdk.NewInt64Coin(testDenom1, 10), sdk.NewInt(1), sdk.NewInt64Coin(testDenom1, 9), false},
   210  		{sdk.NewInt64Coin(testDenom1, 5), sdk.NewInt(3), sdk.NewInt64Coin(testDenom1, 2), false},
   211  		{sdk.NewInt64Coin(testDenom1, 5), sdk.NewInt(0), sdk.NewInt64Coin(testDenom1, 5), false},
   212  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt(5), sdk.Coin{}, true},
   213  	}
   214  
   215  	for i, tc := range cases {
   216  		if tc.shouldPanic {
   217  			s.Require().Panics(func() { tc.coin.SubAmount(tc.amount) })
   218  		} else {
   219  			res := tc.coin.SubAmount(tc.amount)
   220  			s.Require().Equal(tc.expected, res, "result of subtraction is incorrect, tc #%d", i)
   221  		}
   222  	}
   223  }
   224  
   225  func (s *coinTestSuite) TestIsGTECoin() {
   226  	cases := []struct {
   227  		inputOne sdk.Coin
   228  		inputTwo sdk.Coin
   229  		expected bool
   230  		panics   bool
   231  	}{
   232  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), true, false},
   233  		{sdk.NewInt64Coin(testDenom1, 2), sdk.NewInt64Coin(testDenom1, 1), true, false},
   234  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), false, true},
   235  	}
   236  
   237  	for tcIndex, tc := range cases {
   238  		tc := tc
   239  		if tc.panics {
   240  			s.Require().Panics(func() { tc.inputOne.IsGTE(tc.inputTwo) })
   241  		} else {
   242  			res := tc.inputOne.IsGTE(tc.inputTwo)
   243  			s.Require().Equal(tc.expected, res, "coin GTE relation is incorrect, tc #%d", tcIndex)
   244  		}
   245  	}
   246  }
   247  
   248  func (s *coinTestSuite) TestIsLTCoin() {
   249  	cases := []struct {
   250  		inputOne sdk.Coin
   251  		inputTwo sdk.Coin
   252  		expected bool
   253  		panics   bool
   254  	}{
   255  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), false, false},
   256  		{sdk.NewInt64Coin(testDenom1, 2), sdk.NewInt64Coin(testDenom1, 1), false, false},
   257  		{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1), false, true},
   258  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom2, 1), false, true},
   259  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 1), false, false},
   260  		{sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt64Coin(testDenom1, 2), true, false},
   261  	}
   262  
   263  	for tcIndex, tc := range cases {
   264  		tc := tc
   265  		if tc.panics {
   266  			s.Require().Panics(func() { tc.inputOne.IsLT(tc.inputTwo) })
   267  		} else {
   268  			res := tc.inputOne.IsLT(tc.inputTwo)
   269  			s.Require().Equal(tc.expected, res, "coin LT relation is incorrect, tc #%d", tcIndex)
   270  		}
   271  	}
   272  }
   273  
   274  func (s *coinTestSuite) TestCoinIsZero() {
   275  	coin := sdk.NewInt64Coin(testDenom1, 0)
   276  	res := coin.IsZero()
   277  	s.Require().True(res)
   278  
   279  	coin = sdk.NewInt64Coin(testDenom1, 1)
   280  	res = coin.IsZero()
   281  	s.Require().False(res)
   282  }
   283  
   284  func (s *coinTestSuite) TestCoinIsNil() {
   285  	coin := sdk.Coin{}
   286  	res := coin.IsNil()
   287  	s.Require().True(res)
   288  
   289  	coin = sdk.Coin{Denom: "uatom"}
   290  	res = coin.IsNil()
   291  	s.Require().True(res)
   292  
   293  	coin = sdk.NewInt64Coin(testDenom1, 1)
   294  	res = coin.IsNil()
   295  	s.Require().False(res)
   296  }
   297  
   298  func (s *coinTestSuite) TestFilteredZeroCoins() {
   299  	cases := []struct {
   300  		name     string
   301  		input    sdk.Coins
   302  		original string
   303  		expected string
   304  	}{
   305  		{
   306  			name: "all greater than zero",
   307  			input: sdk.Coins{
   308  				{"testa", sdk.OneInt()},
   309  				{"testb", sdk.NewInt(2)},
   310  				{"testc", sdk.NewInt(3)},
   311  				{"testd", sdk.NewInt(4)},
   312  				{"teste", sdk.NewInt(5)},
   313  			},
   314  			original: "1testa,2testb,3testc,4testd,5teste",
   315  			expected: "1testa,2testb,3testc,4testd,5teste",
   316  		},
   317  		{
   318  			name: "zero coin in middle",
   319  			input: sdk.Coins{
   320  				{"testa", sdk.OneInt()},
   321  				{"testb", sdk.NewInt(2)},
   322  				{"testc", sdk.NewInt(0)},
   323  				{"testd", sdk.NewInt(4)},
   324  				{"teste", sdk.NewInt(5)},
   325  			},
   326  			original: "1testa,2testb,0testc,4testd,5teste",
   327  			expected: "1testa,2testb,4testd,5teste",
   328  		},
   329  		{
   330  			name: "zero coin end (unordered)",
   331  			input: sdk.Coins{
   332  				{"teste", sdk.NewInt(5)},
   333  				{"testc", sdk.NewInt(3)},
   334  				{"testa", sdk.OneInt()},
   335  				{"testd", sdk.NewInt(4)},
   336  				{"testb", sdk.NewInt(0)},
   337  			},
   338  			original: "5teste,3testc,1testa,4testd,0testb",
   339  			expected: "1testa,3testc,4testd,5teste",
   340  		},
   341  	}
   342  
   343  	for _, tt := range cases {
   344  		undertest := sdk.NewCoins(tt.input...)
   345  		s.Require().Equal(tt.expected, undertest.String(), "NewCoins must return expected results")
   346  		s.Require().Equal(tt.original, tt.input.String(), "input must be unmodified and match original")
   347  	}
   348  }
   349  
   350  // ----------------------------------------------------------------------------
   351  // Coins tests
   352  
   353  func (s *coinTestSuite) TestCoins_String() {
   354  	cases := []struct {
   355  		name     string
   356  		input    sdk.Coins
   357  		expected string
   358  	}{
   359  		{
   360  			"empty coins",
   361  			sdk.Coins{},
   362  			"",
   363  		},
   364  		{
   365  			"single coin",
   366  			sdk.Coins{{"tree", sdk.OneInt()}},
   367  			"1tree",
   368  		},
   369  		{
   370  			"multiple coins",
   371  			sdk.Coins{
   372  				{"tree", sdk.OneInt()},
   373  				{"gas", sdk.OneInt()},
   374  				{"mineral", sdk.OneInt()},
   375  			},
   376  			"1tree,1gas,1mineral",
   377  		},
   378  	}
   379  
   380  	for _, tt := range cases {
   381  		s.Require().Equal(tt.expected, tt.input.String())
   382  	}
   383  }
   384  
   385  func (s *coinTestSuite) TestIsZeroCoins() {
   386  	cases := []struct {
   387  		inputOne sdk.Coins
   388  		expected bool
   389  	}{
   390  		{sdk.Coins{}, true},
   391  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, true},
   392  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 0)}, true},
   393  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 1)}, false},
   394  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, false},
   395  	}
   396  
   397  	for _, tc := range cases {
   398  		res := tc.inputOne.IsZero()
   399  		s.Require().Equal(tc.expected, res)
   400  	}
   401  }
   402  
   403  func (s *coinTestSuite) TestEqualCoins() {
   404  	cases := []struct {
   405  		inputOne sdk.Coins
   406  		inputTwo sdk.Coins
   407  		expected bool
   408  		panics   bool
   409  	}{
   410  		{sdk.Coins{}, sdk.Coins{}, true, false},
   411  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, true, false},
   412  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, true, false},
   413  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, sdk.Coins{sdk.NewInt64Coin(testDenom2, 0)}, false, true},
   414  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, sdk.Coins{sdk.NewInt64Coin(testDenom1, 1)}, false, false},
   415  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0)}, sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, false, false},
   416  		{sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, sdk.Coins{sdk.NewInt64Coin(testDenom1, 0), sdk.NewInt64Coin(testDenom2, 1)}, true, false},
   417  	}
   418  
   419  	for tcnum, tc := range cases {
   420  		tc := tc
   421  		if tc.panics {
   422  			s.Require().Panics(func() { tc.inputOne.IsEqual(tc.inputTwo) })
   423  		} else {
   424  			res := tc.inputOne.IsEqual(tc.inputTwo)
   425  			s.Require().Equal(tc.expected, res, "Equality is differed from exported. tc #%d, expected %b, actual %b.", tcnum, tc.expected, res)
   426  		}
   427  	}
   428  }
   429  
   430  func (s *coinTestSuite) TestAddCoins() {
   431  	cases := []struct {
   432  		inputOne sdk.Coins
   433  		inputTwo sdk.Coins
   434  		expected sdk.Coins
   435  	}{
   436  		{sdk.Coins{s.ca1, s.cm1}, sdk.Coins{s.ca1, s.cm1}, sdk.Coins{s.ca2, s.cm2}},
   437  		{sdk.Coins{s.ca0, s.cm1}, sdk.Coins{s.ca0, s.cm0}, sdk.Coins{s.cm1}},
   438  		{sdk.Coins{s.ca2}, sdk.Coins{s.cm0}, sdk.Coins{s.ca2}},
   439  		{sdk.Coins{s.ca1}, sdk.Coins{s.ca1, s.cm2}, sdk.Coins{s.ca2, s.cm2}},
   440  		{sdk.Coins{s.ca0, s.cm0}, sdk.Coins{s.ca0, s.cm0}, sdk.Coins(nil)},
   441  	}
   442  
   443  	for tcIndex, tc := range cases {
   444  		res := tc.inputOne.Add(tc.inputTwo...)
   445  		s.Require().True(res.IsValid())
   446  		s.Require().Equal(tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
   447  	}
   448  }
   449  
   450  func (s *coinTestSuite) TestSubCoins() {
   451  	testCases := []struct {
   452  		inputOne    sdk.Coins
   453  		inputTwo    sdk.Coins
   454  		expected    sdk.Coins
   455  		shouldPanic bool
   456  	}{
   457  		// denoms are not sorted - should panic
   458  		{sdk.Coins{s.ca2}, sdk.Coins{s.cm2, s.ca1}, sdk.Coins{}, true},
   459  		{sdk.Coins{s.cm2, s.ca2}, sdk.Coins{s.ca1}, sdk.Coins{}, true},
   460  		// test cases for sorted denoms
   461  		{sdk.Coins{s.ca2}, sdk.Coins{s.ca1, s.cm2}, sdk.Coins{s.ca1, s.cm2}, true},
   462  		{sdk.Coins{s.ca2}, sdk.Coins{s.cm0}, sdk.Coins{s.ca2}, false},
   463  		{sdk.Coins{s.ca1}, sdk.Coins{s.cm0}, sdk.Coins{s.ca1}, false},
   464  		{sdk.Coins{s.ca1, s.cm1}, sdk.Coins{s.ca1}, sdk.Coins{s.cm1}, false},
   465  		{sdk.Coins{s.ca1, s.cm1}, sdk.Coins{s.ca2}, sdk.Coins{}, true},
   466  	}
   467  
   468  	assert := s.Assert()
   469  	for i, tc := range testCases {
   470  		tc := tc
   471  		if tc.shouldPanic {
   472  			assert.Panics(func() { tc.inputOne.Sub(tc.inputTwo) })
   473  		} else {
   474  			res := tc.inputOne.Sub(tc.inputTwo)
   475  			assert.True(res.IsValid())
   476  			assert.Equal(tc.expected, res, "sum of coins is incorrect, tc #%d", i)
   477  		}
   478  	}
   479  }
   480  
   481  func (s *coinTestSuite) TestCoins_Validate() {
   482  	testCases := []struct {
   483  		name    string
   484  		coins   sdk.Coins
   485  		expPass bool
   486  	}{
   487  		{
   488  			"valid lowercase coins",
   489  			sdk.Coins{
   490  				{"gas", sdk.OneInt()},
   491  				{"mineral", sdk.OneInt()},
   492  				{"tree", sdk.OneInt()},
   493  			},
   494  			true,
   495  		},
   496  		{
   497  			"valid uppercase coins",
   498  			sdk.Coins{
   499  				{"GAS", sdk.OneInt()},
   500  				{"MINERAL", sdk.OneInt()},
   501  				{"TREE", sdk.OneInt()},
   502  			},
   503  			true,
   504  		},
   505  		{
   506  			"valid uppercase coin",
   507  			sdk.Coins{
   508  				{"ATOM", sdk.OneInt()},
   509  			},
   510  			true,
   511  		},
   512  		{
   513  			"valid lower and uppercase coins (1)",
   514  			sdk.Coins{
   515  				{"GAS", sdk.OneInt()},
   516  				{"gAs", sdk.OneInt()},
   517  			},
   518  			true,
   519  		},
   520  		{
   521  			"valid lower and uppercase coins (2)",
   522  			sdk.Coins{
   523  				{"ATOM", sdk.OneInt()},
   524  				{"Atom", sdk.OneInt()},
   525  				{"atom", sdk.OneInt()},
   526  			},
   527  			true,
   528  		},
   529  		{
   530  			"mixed case (1)",
   531  			sdk.Coins{
   532  				{"MineraL", sdk.OneInt()},
   533  				{"TREE", sdk.OneInt()},
   534  				{"gAs", sdk.OneInt()},
   535  			},
   536  			true,
   537  		},
   538  		{
   539  			"mixed case (2)",
   540  			sdk.Coins{
   541  				{"gAs", sdk.OneInt()},
   542  				{"mineral", sdk.OneInt()},
   543  			},
   544  			true,
   545  		},
   546  		{
   547  			"mixed case (3)",
   548  			sdk.Coins{
   549  				{"gAs", sdk.OneInt()},
   550  			},
   551  			true,
   552  		},
   553  		{
   554  			"unicode letters and numbers",
   555  			sdk.Coins{
   556  				{"𐀀𐀆𐀉Ⅲ", sdk.OneInt()},
   557  			},
   558  			false,
   559  		},
   560  		{
   561  			"emojis",
   562  			sdk.Coins{
   563  				{"🤑😋🤔", sdk.OneInt()},
   564  			},
   565  			false,
   566  		},
   567  		{
   568  			"IBC denominations (ADR 001)",
   569  			sdk.Coins{
   570  				{"ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.OneInt()},
   571  				{"ibc/876563AAAACF739EB061C67CDB5EDF2B7C9FD4AA9D876450CC21210807C2820A", sdk.NewInt(2)},
   572  			},
   573  			true,
   574  		},
   575  		{
   576  			"empty (1)",
   577  			sdk.NewCoins(),
   578  			true,
   579  		},
   580  		{
   581  			"empty (2)",
   582  			sdk.Coins{},
   583  			true,
   584  		},
   585  		{
   586  			"invalid denomination (1)",
   587  			sdk.Coins{
   588  				{"MineraL", sdk.OneInt()},
   589  				{"0TREE", sdk.OneInt()},
   590  				{"gAs", sdk.OneInt()},
   591  			},
   592  			false,
   593  		},
   594  		{
   595  			"invalid denomination (2)",
   596  			sdk.Coins{
   597  				{"-GAS", sdk.OneInt()},
   598  				{"gAs", sdk.OneInt()},
   599  			},
   600  			false,
   601  		},
   602  		{
   603  			"bad sort (1)",
   604  			sdk.Coins{
   605  				{"tree", sdk.OneInt()},
   606  				{"gas", sdk.OneInt()},
   607  				{"mineral", sdk.OneInt()},
   608  			},
   609  			false,
   610  		},
   611  		{
   612  			"bad sort (2)",
   613  			sdk.Coins{
   614  				{"gas", sdk.OneInt()},
   615  				{"tree", sdk.OneInt()},
   616  				{"mineral", sdk.OneInt()},
   617  			},
   618  			false,
   619  		},
   620  		{
   621  			"non-positive amount (1)",
   622  			sdk.Coins{
   623  				{"gas", sdk.OneInt()},
   624  				{"tree", sdk.NewInt(0)},
   625  				{"mineral", sdk.OneInt()},
   626  			},
   627  			false,
   628  		},
   629  		{
   630  			"non-positive amount (2)",
   631  			sdk.Coins{
   632  				{"gas", sdk.NewInt(-1)},
   633  				{"tree", sdk.OneInt()},
   634  				{"mineral", sdk.OneInt()},
   635  			},
   636  			false,
   637  		},
   638  		{
   639  			"duplicate denomination",
   640  			sdk.Coins{
   641  				{"gas", sdk.OneInt()},
   642  				{"gas", sdk.OneInt()},
   643  				{"mineral", sdk.OneInt()},
   644  			},
   645  			false,
   646  		},
   647  	}
   648  
   649  	for _, tc := range testCases {
   650  		err := tc.coins.Validate()
   651  		if tc.expPass {
   652  			s.Require().NoError(err, tc.name)
   653  		} else {
   654  			s.Require().Error(err, tc.name)
   655  		}
   656  	}
   657  }
   658  
   659  func (s *coinTestSuite) TestMinMax() {
   660  	one := sdk.OneInt()
   661  	two := sdk.NewInt(2)
   662  
   663  	cases := []struct {
   664  		name   string
   665  		input1 sdk.Coins
   666  		input2 sdk.Coins
   667  		min    sdk.Coins
   668  		max    sdk.Coins
   669  	}{
   670  		{"zero-zero", sdk.Coins{}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{}},
   671  		{"zero-one", sdk.Coins{}, sdk.Coins{{testDenom1, one}}, sdk.Coins{}, sdk.Coins{{testDenom1, one}}},
   672  		{"two-zero", sdk.Coins{{testDenom2, two}}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{{testDenom2, two}}},
   673  		{"disjoint", sdk.Coins{{testDenom1, one}}, sdk.Coins{{testDenom2, two}}, sdk.Coins{}, sdk.Coins{{testDenom1, one}, {testDenom2, two}}},
   674  		{"disjoint2", sdk.Coins{{testDenom2, one}}, sdk.Coins{{testDenom1, two}}, sdk.Coins{}, sdk.Coins{{testDenom1, two}, {testDenom2, one}}},
   675  		{
   676  			"overlap",
   677  			sdk.Coins{{testDenom1, one}, {testDenom2, two}},
   678  			sdk.Coins{{testDenom1, two}, {testDenom2, one}},
   679  			sdk.Coins{{testDenom1, one}, {testDenom2, one}},
   680  			sdk.Coins{{testDenom1, two}, {testDenom2, two}},
   681  		},
   682  	}
   683  
   684  	for _, tc := range cases {
   685  		min := tc.input1.Min(tc.input2)
   686  		max := tc.input1.Max(tc.input2)
   687  		s.Require().True(min.IsEqual(tc.min), tc.name)
   688  		s.Require().True(max.IsEqual(tc.max), tc.name)
   689  	}
   690  }
   691  
   692  func (s *coinTestSuite) TestCoinsGT() {
   693  	one := sdk.OneInt()
   694  	two := sdk.NewInt(2)
   695  
   696  	s.Require().False(sdk.Coins{}.IsAllGT(sdk.Coins{}))
   697  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{}))
   698  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom1, one}}))
   699  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom2, one}}))
   700  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(sdk.Coins{{testDenom2, one}}))
   701  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(sdk.Coins{{testDenom2, two}}))
   702  }
   703  
   704  func (s *coinTestSuite) TestCoinsLT() {
   705  	one := sdk.OneInt()
   706  	two := sdk.NewInt(2)
   707  
   708  	s.Require().False(sdk.Coins{}.IsAllLT(sdk.Coins{}))
   709  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllLT(sdk.Coins{}))
   710  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllLT(sdk.Coins{{testDenom1, one}}))
   711  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllLT(sdk.Coins{{testDenom2, one}}))
   712  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(sdk.Coins{{testDenom2, one}}))
   713  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(sdk.Coins{{testDenom2, two}}))
   714  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(sdk.Coins{{testDenom1, one}, {testDenom2, one}}))
   715  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(sdk.Coins{{testDenom1, two}, {testDenom2, two}}))
   716  	s.Require().True(sdk.Coins{}.IsAllLT(sdk.Coins{{testDenom1, one}}))
   717  }
   718  
   719  func (s *coinTestSuite) TestCoinsLTE() {
   720  	one := sdk.OneInt()
   721  	two := sdk.NewInt(2)
   722  
   723  	s.Require().True(sdk.Coins{}.IsAllLTE(sdk.Coins{}))
   724  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllLTE(sdk.Coins{}))
   725  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAllLTE(sdk.Coins{{testDenom1, one}}))
   726  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllLTE(sdk.Coins{{testDenom2, one}}))
   727  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(sdk.Coins{{testDenom2, one}}))
   728  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(sdk.Coins{{testDenom2, two}}))
   729  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(sdk.Coins{{testDenom1, one}, {testDenom2, one}}))
   730  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   731  	s.Require().True(sdk.Coins{}.IsAllLTE(sdk.Coins{{testDenom1, one}}))
   732  }
   733  
   734  func (s *coinTestSuite) TestParseCoins() {
   735  	one := sdk.OneInt()
   736  
   737  	cases := []struct {
   738  		input    string
   739  		valid    bool      // if false, we expect an error on parse
   740  		expected sdk.Coins // if valid is true, make sure this is returned
   741  	}{
   742  		{"", true, nil},
   743  		{"0stake", true, sdk.Coins{}}, // remove zero coins
   744  		{"0stake,1foo,99bar", true, sdk.Coins{{"bar", sdk.NewInt(99)}, {"foo", one}}}, // remove zero coins
   745  		{"1foo", true, sdk.Coins{{"foo", one}}},
   746  		{"10btc,1atom,20btc", false, nil},
   747  		{"10bar", true, sdk.Coins{{"bar", sdk.NewInt(10)}}},
   748  		{"99bar,1foo", true, sdk.Coins{{"bar", sdk.NewInt(99)}, {"foo", one}}},
   749  		{"98 bar , 1 foo  ", true, sdk.Coins{{"bar", sdk.NewInt(98)}, {"foo", one}}},
   750  		{"  55\t \t bling\n", true, sdk.Coins{{"bling", sdk.NewInt(55)}}},
   751  		{"2foo, 97 bar", true, sdk.Coins{{"bar", sdk.NewInt(97)}, {"foo", sdk.NewInt(2)}}},
   752  		{"5 mycoin,", false, nil},                           // no empty coins in a list
   753  		{"2 3foo, 97 bar", false, nil},                      // 3foo is invalid coin name
   754  		{"11me coin, 12you coin", false, nil},               // no spaces in coin names
   755  		{"1.2btc", true, sdk.Coins{{"btc", sdk.NewInt(1)}}}, // amount can be decimal, will get truncated
   756  		{"5foo:bar", false, nil},                            // invalid separator
   757  		{"10atom10", true, sdk.Coins{{"atom10", sdk.NewInt(10)}}},
   758  		{"200transfer/channelToA/uatom", true, sdk.Coins{{"transfer/channelToA/uatom", sdk.NewInt(200)}}},
   759  		{"50ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", true, sdk.Coins{{"ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.NewInt(50)}}},
   760  		{"120000000000000000000000000000000000000000000000000000000000000000000000000000btc", false, nil},
   761  	}
   762  
   763  	for tcIndex, tc := range cases {
   764  		res, err := sdk.ParseCoinsNormalized(tc.input)
   765  		if !tc.valid {
   766  			s.Require().Error(err, "%s: %#v. tc #%d", tc.input, res, tcIndex)
   767  		} else if s.Assert().Nil(err, "%s: %+v", tc.input, err) {
   768  			s.Require().Equal(tc.expected, res, "coin parsing was incorrect, tc #%d", tcIndex)
   769  		}
   770  	}
   771  }
   772  
   773  func (s *coinTestSuite) TestSortCoins() {
   774  	good := sdk.Coins{
   775  		sdk.NewInt64Coin("gas", 1),
   776  		sdk.NewInt64Coin("mineral", 1),
   777  		sdk.NewInt64Coin("tree", 1),
   778  	}
   779  	empty := sdk.Coins{
   780  		sdk.NewInt64Coin("gold", 0),
   781  	}
   782  	badSort1 := sdk.Coins{
   783  		sdk.NewInt64Coin("tree", 1),
   784  		sdk.NewInt64Coin("gas", 1),
   785  		sdk.NewInt64Coin("mineral", 1),
   786  	}
   787  	badSort2 := sdk.Coins{ // both are after the first one, but the second and third are in the wrong order
   788  		sdk.NewInt64Coin("gas", 1),
   789  		sdk.NewInt64Coin("tree", 1),
   790  		sdk.NewInt64Coin("mineral", 1),
   791  	}
   792  	badAmt := sdk.Coins{
   793  		sdk.NewInt64Coin("gas", 1),
   794  		sdk.NewInt64Coin("tree", 0),
   795  		sdk.NewInt64Coin("mineral", 1),
   796  	}
   797  	dup := sdk.Coins{
   798  		sdk.NewInt64Coin("gas", 1),
   799  		sdk.NewInt64Coin("gas", 1),
   800  		sdk.NewInt64Coin("mineral", 1),
   801  	}
   802  
   803  	cases := []struct {
   804  		name  string
   805  		coins sdk.Coins
   806  		validBefore,
   807  		validAfter bool
   808  	}{
   809  		{"valid coins", good, true, true},
   810  		{"empty coins", empty, false, false},
   811  		{"bad sort (1)", badSort1, false, true},
   812  		{"bad sort (2)", badSort2, false, true},
   813  		{"zero value coin", badAmt, false, false},
   814  		{"duplicate coins", dup, false, false},
   815  	}
   816  
   817  	for _, tc := range cases {
   818  		err := tc.coins.Validate()
   819  		if tc.validBefore {
   820  			s.Require().NoError(err, tc.name)
   821  		} else {
   822  			s.Require().Error(err, tc.name)
   823  		}
   824  
   825  		tc.coins.Sort()
   826  
   827  		err = tc.coins.Validate()
   828  		if tc.validAfter {
   829  			s.Require().NoError(err, tc.name)
   830  		} else {
   831  			s.Require().Error(err, tc.name)
   832  		}
   833  	}
   834  }
   835  
   836  func (s *coinTestSuite) TestAmountOf() {
   837  	case0 := sdk.Coins{}
   838  	case1 := sdk.Coins{
   839  		sdk.NewInt64Coin("gold", 0),
   840  	}
   841  	case2 := sdk.Coins{
   842  		sdk.NewInt64Coin("gas", 1),
   843  		sdk.NewInt64Coin("mineral", 1),
   844  		sdk.NewInt64Coin("tree", 1),
   845  	}
   846  	case3 := sdk.Coins{
   847  		sdk.NewInt64Coin("mineral", 1),
   848  		sdk.NewInt64Coin("tree", 1),
   849  	}
   850  	case4 := sdk.Coins{
   851  		sdk.NewInt64Coin("gas", 8),
   852  	}
   853  
   854  	cases := []struct {
   855  		coins           sdk.Coins
   856  		amountOf        int64
   857  		amountOfSpace   int64
   858  		amountOfGAS     int64
   859  		amountOfMINERAL int64
   860  		amountOfTREE    int64
   861  	}{
   862  		{case0, 0, 0, 0, 0, 0},
   863  		{case1, 0, 0, 0, 0, 0},
   864  		{case2, 0, 0, 1, 1, 1},
   865  		{case3, 0, 0, 0, 1, 1},
   866  		{case4, 0, 0, 8, 0, 0},
   867  	}
   868  
   869  	for _, tc := range cases {
   870  		s.Require().Equal(sdk.NewInt(tc.amountOfGAS), tc.coins.AmountOf("gas"))
   871  		s.Require().Equal(sdk.NewInt(tc.amountOfMINERAL), tc.coins.AmountOf("mineral"))
   872  		s.Require().Equal(sdk.NewInt(tc.amountOfTREE), tc.coins.AmountOf("tree"))
   873  	}
   874  
   875  	s.Require().Panics(func() { cases[0].coins.AmountOf("10Invalid") })
   876  }
   877  
   878  func (s *coinTestSuite) TestCoinsIsAnyGTE() {
   879  	one := sdk.OneInt()
   880  	two := sdk.NewInt(2)
   881  
   882  	s.Require().False(sdk.Coins{}.IsAnyGTE(sdk.Coins{}))
   883  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAnyGTE(sdk.Coins{}))
   884  	s.Require().False(sdk.Coins{}.IsAnyGTE(sdk.Coins{{testDenom1, one}}))
   885  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAnyGTE(sdk.Coins{{testDenom1, two}}))
   886  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAnyGTE(sdk.Coins{{testDenom2, one}}))
   887  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAnyGTE(sdk.Coins{{testDenom1, two}, {testDenom2, one}}))
   888  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAnyGTE(sdk.Coins{{testDenom1, one}}))
   889  	s.Require().True(sdk.Coins{{testDenom1, two}}.IsAnyGTE(sdk.Coins{{testDenom1, one}}))
   890  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAnyGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   891  	s.Require().True(sdk.Coins{{testDenom2, two}}.IsAnyGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   892  	s.Require().False(sdk.Coins{{testDenom2, one}}.IsAnyGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   893  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAnyGTE(sdk.Coins{{testDenom1, one}, {testDenom2, one}}))
   894  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAnyGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   895  	s.Require().True(sdk.Coins{{"xxx", one}, {"yyy", one}}.IsAnyGTE(sdk.Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}}))
   896  }
   897  
   898  func (s *coinTestSuite) TestCoinsIsAllGT() {
   899  	one := sdk.OneInt()
   900  	two := sdk.NewInt(2)
   901  
   902  	s.Require().False(sdk.Coins{}.IsAllGT(sdk.Coins{}))
   903  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{}))
   904  	s.Require().False(sdk.Coins{}.IsAllGT(sdk.Coins{{testDenom1, one}}))
   905  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom1, two}}))
   906  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom2, one}}))
   907  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(sdk.Coins{{testDenom1, two}, {testDenom2, one}}))
   908  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom1, one}}))
   909  	s.Require().True(sdk.Coins{{testDenom1, two}}.IsAllGT(sdk.Coins{{testDenom1, one}}))
   910  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGT(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   911  	s.Require().False(sdk.Coins{{testDenom2, two}}.IsAllGT(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   912  	s.Require().False(sdk.Coins{{testDenom2, one}}.IsAllGT(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   913  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(sdk.Coins{{testDenom1, one}, {testDenom2, one}}))
   914  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   915  	s.Require().False(sdk.Coins{{"xxx", one}, {"yyy", one}}.IsAllGT(sdk.Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}}))
   916  }
   917  
   918  func (s *coinTestSuite) TestCoinsIsAllGTE() {
   919  	one := sdk.OneInt()
   920  	two := sdk.NewInt(2)
   921  
   922  	s.Require().True(sdk.Coins{}.IsAllGTE(sdk.Coins{}))
   923  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAllGTE(sdk.Coins{}))
   924  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(sdk.Coins{{testDenom2, one}}))
   925  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(sdk.Coins{{testDenom2, two}}))
   926  	s.Require().False(sdk.Coins{}.IsAllGTE(sdk.Coins{{testDenom1, one}}))
   927  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGTE(sdk.Coins{{testDenom1, two}}))
   928  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGTE(sdk.Coins{{testDenom2, one}}))
   929  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGTE(sdk.Coins{{testDenom1, two}, {testDenom2, one}}))
   930  	s.Require().True(sdk.Coins{{testDenom1, one}}.IsAllGTE(sdk.Coins{{testDenom1, one}}))
   931  	s.Require().True(sdk.Coins{{testDenom1, two}}.IsAllGTE(sdk.Coins{{testDenom1, one}}))
   932  	s.Require().False(sdk.Coins{{testDenom1, one}}.IsAllGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   933  	s.Require().False(sdk.Coins{{testDenom2, two}}.IsAllGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   934  	s.Require().False(sdk.Coins{{testDenom2, one}}.IsAllGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   935  	s.Require().True(sdk.Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGTE(sdk.Coins{{testDenom1, one}, {testDenom2, one}}))
   936  	s.Require().False(sdk.Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(sdk.Coins{{testDenom1, one}, {testDenom2, two}}))
   937  	s.Require().False(sdk.Coins{{"xxx", one}, {"yyy", one}}.IsAllGTE(sdk.Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}}))
   938  }
   939  
   940  func (s *coinTestSuite) TestNewCoins() {
   941  	tenatom := sdk.NewInt64Coin("atom", 10)
   942  	tenbtc := sdk.NewInt64Coin("btc", 10)
   943  	zeroeth := sdk.NewInt64Coin("eth", 0)
   944  	invalidCoin := sdk.Coin{"0ETH", sdk.OneInt()}
   945  	tests := []struct {
   946  		name      string
   947  		coins     sdk.Coins
   948  		want      sdk.Coins
   949  		wantPanic bool
   950  	}{
   951  		{"empty args", []sdk.Coin{}, sdk.Coins{}, false},
   952  		{"one coin", []sdk.Coin{tenatom}, sdk.Coins{tenatom}, false},
   953  		{"sort after create", []sdk.Coin{tenbtc, tenatom}, sdk.Coins{tenatom, tenbtc}, false},
   954  		{"sort and remove zeroes", []sdk.Coin{zeroeth, tenbtc, tenatom}, sdk.Coins{tenatom, tenbtc}, false},
   955  		{"panic on dups", []sdk.Coin{tenatom, tenatom}, sdk.Coins{}, true},
   956  		{"panic on invalid coin", []sdk.Coin{invalidCoin, tenatom}, sdk.Coins{}, true},
   957  	}
   958  	for _, tt := range tests {
   959  		if tt.wantPanic {
   960  			s.Require().Panics(func() { sdk.NewCoins(tt.coins...) })
   961  			continue
   962  		}
   963  		got := sdk.NewCoins(tt.coins...)
   964  		s.Require().True(got.IsEqual(tt.want))
   965  	}
   966  }
   967  
   968  func (s *coinTestSuite) TestCoinsIsAnyGT() {
   969  	twoAtom := sdk.NewInt64Coin("atom", 2)
   970  	fiveAtom := sdk.NewInt64Coin("atom", 5)
   971  	threeEth := sdk.NewInt64Coin("eth", 3)
   972  	sixEth := sdk.NewInt64Coin("eth", 6)
   973  	twoBtc := sdk.NewInt64Coin("btc", 2)
   974  
   975  	tests := []struct {
   976  		name    string
   977  		coinsA  sdk.Coins
   978  		coinsB  sdk.Coins
   979  		expPass bool
   980  	}{
   981  		{"{} ≤ {}", sdk.Coins{}, sdk.Coins{}, false},
   982  		{"{} ≤ 5atom", sdk.Coins{}, sdk.Coins{fiveAtom}, false},
   983  		{"5atom > 2atom", sdk.Coins{fiveAtom}, sdk.Coins{twoAtom}, true},
   984  		{"2atom ≤ 5atom", sdk.Coins{twoAtom}, sdk.Coins{fiveAtom}, false},
   985  		{"2atom,6eth > 2btc,5atom,3eth", sdk.Coins{twoAtom, sixEth}, sdk.Coins{twoBtc, fiveAtom, threeEth}, true},
   986  		{"2btc,2atom,3eth ≤ 5atom,6eth", sdk.Coins{twoBtc, twoAtom, threeEth}, sdk.Coins{fiveAtom, sixEth}, false},
   987  		{"2atom,6eth ≤ 2btc,5atom", sdk.Coins{twoAtom, sixEth}, sdk.Coins{twoBtc, fiveAtom}, false},
   988  	}
   989  
   990  	for _, tc := range tests {
   991  		s.Require().True(tc.expPass == tc.coinsA.IsAnyGT(tc.coinsB), tc.name)
   992  	}
   993  }
   994  
   995  func (s *coinTestSuite) TestCoinsIsAnyNil() {
   996  	twoAtom := sdk.NewInt64Coin("atom", 2)
   997  	fiveAtom := sdk.NewInt64Coin("atom", 5)
   998  	threeEth := sdk.NewInt64Coin("eth", 3)
   999  	nilAtom := sdk.Coin{Denom: "atom"}
  1000  
  1001  	s.Require().True(sdk.Coins{twoAtom, fiveAtom, threeEth, nilAtom}.IsAnyNil())
  1002  	s.Require().True(sdk.Coins{twoAtom, nilAtom, fiveAtom, threeEth}.IsAnyNil())
  1003  	s.Require().True(sdk.Coins{nilAtom, twoAtom, fiveAtom, threeEth}.IsAnyNil())
  1004  	s.Require().False(sdk.Coins{twoAtom, fiveAtom, threeEth}.IsAnyNil())
  1005  }
  1006  
  1007  func (s *coinTestSuite) TestMarshalJSONCoins() {
  1008  	cdc := codec.NewLegacyAmino()
  1009  	sdk.RegisterLegacyAminoCodec(cdc)
  1010  
  1011  	testCases := []struct {
  1012  		name      string
  1013  		input     sdk.Coins
  1014  		strOutput string
  1015  	}{
  1016  		{"nil coins", nil, `[]`},
  1017  		{"empty coins", sdk.Coins{}, `[]`},
  1018  		{"non-empty coins", sdk.NewCoins(sdk.NewInt64Coin("foo", 50)), `[{"denom":"foo","amount":"50"}]`},
  1019  	}
  1020  
  1021  	for _, tc := range testCases {
  1022  		bz, err := cdc.MarshalJSON(tc.input)
  1023  		s.Require().NoError(err)
  1024  		s.Require().Equal(tc.strOutput, string(bz))
  1025  
  1026  		var newCoins sdk.Coins
  1027  		s.Require().NoError(cdc.UnmarshalJSON(bz, &newCoins))
  1028  
  1029  		if tc.input.Empty() {
  1030  			s.Require().Nil(newCoins)
  1031  		} else {
  1032  			s.Require().Equal(tc.input, newCoins)
  1033  		}
  1034  	}
  1035  }
  1036  
  1037  func (s *coinTestSuite) TestCoinAminoEncoding() {
  1038  	cdc := codec.NewLegacyAmino()
  1039  	c := sdk.NewInt64Coin(testDenom1, 5)
  1040  
  1041  	bz1, err := cdc.Marshal(c)
  1042  	s.Require().NoError(err)
  1043  
  1044  	bz2, err := cdc.MarshalLengthPrefixed(c)
  1045  	s.Require().NoError(err)
  1046  
  1047  	bz3, err := c.Marshal()
  1048  	s.Require().NoError(err)
  1049  	s.Require().Equal(bz1, bz3)
  1050  	s.Require().Equal(bz2[1:], bz3)
  1051  }