diff --git a/types/coin.go b/types/coin.go index 95b30a890..cf6e4d122 100644 --- a/types/coin.go +++ b/types/coin.go @@ -269,6 +269,23 @@ func (coins Coins) safeAdd(coinsB Coins) Coins { } } +// ContainsDenomsOf returns true if coinsB' denom set +// is subset of the receiver's denoms. +func (coins Coins) ContainsDenomsOf(coinsB Coins) bool { + // more denoms in B than in receiver + if len(coinsB) > len(coins) { + return false + } + + for _, coinB := range coinsB { + if coins.AmountOf(coinB.Denom).IsZero() { + return false + } + } + + return true +} + // Sub subtracts a set of coins from another. // // e.g. @@ -297,12 +314,26 @@ func (coins Coins) SafeSub(coinsB Coins) (Coins, bool) { // IsAllGT returns true if for every denom in coins, the denom is present at a // greater amount in coinsB. func (coins Coins) IsAllGT(coinsB Coins) bool { - diff, _ := coins.SafeSub(coinsB) - if len(diff) == 0 { + if len(coins) == 0 { return false } - return diff.IsAllPositive() + if len(coinsB) == 0 { + return true + } + + if !coins.ContainsDenomsOf(coinsB) { + return false + } + + for _, coinB := range coinsB { + amountA, amountB := coins.AmountOf(coinB.Denom), coinB.Amount + if !amountA.GT(amountB) { + return false + } + } + + return true } // IsAllGTE returns true iff for every denom in coins, the denom is present at diff --git a/types/coin_test.go b/types/coin_test.go index b29b5ece6..f9268b019 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -276,10 +276,7 @@ func TestCoins(t *testing.T) { mixedCase3 := Coins{ {"gAs", NewInt(1)}, } - empty := Coins{ - {"gold", NewInt(0)}, - } - null := Coins{} + empty := NewCoins() badSort1 := Coins{ {"tree", NewInt(1)}, {"gas", NewInt(1)}, @@ -312,7 +309,7 @@ func TestCoins(t *testing.T) { assert.False(t, mixedCase2.IsValid(), "First Coins denoms contain upper case characters") assert.False(t, mixedCase3.IsValid(), "Single denom in Coins contains upper case characters") assert.True(t, good.IsAllPositive(), "Expected coins to be positive: %v", good) - assert.False(t, null.IsAllPositive(), "Expected coins to not be positive: %v", null) + assert.False(t, empty.IsAllPositive(), "Expected coins to not be positive: %v", empty) assert.True(t, good.IsAllGTE(empty), "Expected %v to be >= %v", good, empty) assert.False(t, good.IsAllLT(empty), "Expected %v to be < %v", good, empty) assert.True(t, empty.IsAllLT(good), "Expected %v to be < %v", empty, good) @@ -331,7 +328,7 @@ func TestCoinsGT(t *testing.T) { assert.True(t, Coins{{testDenom1, one}}.IsAllGT(Coins{})) assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom1, one}})) assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom2, one}})) - assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(Coins{{testDenom2, one}})) + assert.True(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(Coins{{testDenom2, one}})) assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(Coins{{testDenom2, two}})) } @@ -358,7 +355,7 @@ func TestCoinsLT(t *testing.T) { assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom2, one}})) assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom2, two}})) assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom1, one}, {testDenom2, one}})) - assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom1, one}, {testDenom2, two}})) + assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom1, two}, {testDenom2, two}})) assert.True(t, Coins{}.IsAllLT(Coins{{testDenom1, one}})) }