feat: implement multi-send transaction command (#11738)
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Anil Kumar Kammari <anil@vitwit.com>
This commit is contained in:
co-authored by
Aleksandr Bezobchuk
Anil Kumar Kammari
parent
0c0b4da114
commit
6a9b8247f6
@@ -410,6 +410,71 @@ func (coins Coins) SafeSub(coinsB ...Coin) (Coins, bool) {
|
||||
return diff, diff.IsAnyNegative()
|
||||
}
|
||||
|
||||
// MulInt performs the scalar multiplication of coins with a `multiplier`
|
||||
// All coins are multipled by x
|
||||
// e.g.
|
||||
// {2A, 3B} * 2 = {4A, 6B}
|
||||
// {2A} * 0 panics
|
||||
// Note, if IsValid was true on Coins, IsValid stays true.
|
||||
func (coins Coins) MulInt(x Int) Coins {
|
||||
coins, ok := coins.SafeMulInt(x)
|
||||
if !ok {
|
||||
panic("multiplying by zero is an invalid operation on coins")
|
||||
}
|
||||
|
||||
return coins
|
||||
}
|
||||
|
||||
// SafeMulInt performs the same arithmetic as MulInt but returns false
|
||||
// if the `multiplier` is zero because it makes IsValid return false.
|
||||
func (coins Coins) SafeMulInt(x Int) (Coins, bool) {
|
||||
if x.IsZero() {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
res := make(Coins, len(coins))
|
||||
for i, coin := range coins {
|
||||
coin := coin
|
||||
res[i] = NewCoin(coin.Denom, coin.Amount.Mul(x))
|
||||
}
|
||||
|
||||
return res, true
|
||||
}
|
||||
|
||||
// QuoInt performs the scalar division of coins with a `divisor`
|
||||
// All coins are divided by x and trucated.
|
||||
// e.g.
|
||||
// {2A, 30B} / 2 = {1A, 15B}
|
||||
// {2A} / 2 = {1A}
|
||||
// {4A} / {8A} = {0A}
|
||||
// {2A} / 0 = panics
|
||||
// Note, if IsValid was true on Coins, IsValid stays true,
|
||||
// unless the `divisor` is greater than the smallest coin amount.
|
||||
func (coins Coins) QuoInt(x Int) Coins {
|
||||
coins, ok := coins.SafeQuoInt(x)
|
||||
if !ok {
|
||||
panic("dividing by zero is an invalid operation on coins")
|
||||
}
|
||||
|
||||
return coins
|
||||
}
|
||||
|
||||
// SafeQuoInt performs the same arithmetic as QuoInt but returns an error
|
||||
// if the division cannot be done.
|
||||
func (coins Coins) SafeQuoInt(x Int) (Coins, bool) {
|
||||
if x.IsZero() {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var res Coins
|
||||
for _, coin := range coins {
|
||||
coin := coin
|
||||
res = append(res, NewCoin(coin.Denom, coin.Amount.Quo(x)))
|
||||
}
|
||||
|
||||
return res, true
|
||||
}
|
||||
|
||||
// Max takes two valid Coins inputs and returns a valid Coins result
|
||||
// where for every denom D, AmountOf(D) of the result is the maximum
|
||||
// of AmountOf(D) of the inputs. Note that the result might be not
|
||||
|
||||
+57
-3
@@ -18,7 +18,7 @@ var (
|
||||
|
||||
type coinTestSuite struct {
|
||||
suite.Suite
|
||||
ca0, ca1, ca2, cm0, cm1, cm2 sdk.Coin
|
||||
ca0, ca1, ca2, ca4, cm0, cm1, cm2, cm4 sdk.Coin
|
||||
}
|
||||
|
||||
func TestCoinTestSuite(t *testing.T) {
|
||||
@@ -30,8 +30,10 @@ func (s *coinTestSuite) SetupSuite() {
|
||||
zero := sdk.NewInt(0)
|
||||
one := sdk.OneInt()
|
||||
two := sdk.NewInt(2)
|
||||
s.ca0, s.ca1, s.ca2 = sdk.Coin{testDenom1, zero}, sdk.Coin{testDenom1, one}, sdk.Coin{testDenom1, two}
|
||||
s.cm0, s.cm1, s.cm2 = sdk.Coin{testDenom2, zero}, sdk.Coin{testDenom2, one}, sdk.Coin{testDenom2, two}
|
||||
four := sdk.NewInt(4)
|
||||
|
||||
s.ca0, s.ca1, s.ca2, s.ca4 = sdk.NewCoin(testDenom1, zero), sdk.NewCoin(testDenom1, one), sdk.NewCoin(testDenom1, two), sdk.NewCoin(testDenom1, four)
|
||||
s.cm0, s.cm1, s.cm2, s.cm4 = sdk.NewCoin(testDenom2, zero), sdk.NewCoin(testDenom2, one), sdk.NewCoin(testDenom2, two), sdk.NewCoin(testDenom2, four)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -224,6 +226,58 @@ func (s *coinTestSuite) TestSubCoinAmount() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *coinTestSuite) TestMulIntCoins() {
|
||||
testCases := []struct {
|
||||
input sdk.Coins
|
||||
multiplier sdk.Int
|
||||
expected sdk.Coins
|
||||
shouldPanic bool
|
||||
}{
|
||||
{sdk.Coins{s.ca2}, sdk.NewInt(0), sdk.Coins{s.ca0}, true},
|
||||
{sdk.Coins{s.ca2}, sdk.NewInt(2), sdk.Coins{s.ca4}, false},
|
||||
{sdk.Coins{s.ca1, s.cm2}, sdk.NewInt(2), sdk.Coins{s.ca2, s.cm4}, false},
|
||||
}
|
||||
|
||||
assert := s.Assert()
|
||||
for i, tc := range testCases {
|
||||
tc := tc
|
||||
if tc.shouldPanic {
|
||||
assert.Panics(func() { tc.input.MulInt(tc.multiplier) })
|
||||
} else {
|
||||
res := tc.input.MulInt(tc.multiplier)
|
||||
assert.True(res.IsValid())
|
||||
assert.Equal(tc.expected, res, "multiplication of coins is incorrect, tc #%d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *coinTestSuite) TestQuoIntCoins() {
|
||||
testCases := []struct {
|
||||
input sdk.Coins
|
||||
divisor sdk.Int
|
||||
expected sdk.Coins
|
||||
isValid bool
|
||||
shouldPanic bool
|
||||
}{
|
||||
{sdk.Coins{s.ca2, s.ca1}, sdk.NewInt(0), sdk.Coins{s.ca0, s.ca0}, true, true},
|
||||
{sdk.Coins{s.ca2}, sdk.NewInt(4), sdk.Coins{s.ca0}, false, false},
|
||||
{sdk.Coins{s.ca2, s.cm4}, sdk.NewInt(2), sdk.Coins{s.ca1, s.cm2}, true, false},
|
||||
{sdk.Coins{s.ca4}, sdk.NewInt(2), sdk.Coins{s.ca2}, true, false},
|
||||
}
|
||||
|
||||
assert := s.Assert()
|
||||
for i, tc := range testCases {
|
||||
tc := tc
|
||||
if tc.shouldPanic {
|
||||
assert.Panics(func() { tc.input.QuoInt(tc.divisor) })
|
||||
} else {
|
||||
res := tc.input.QuoInt(tc.divisor)
|
||||
assert.Equal(tc.isValid, res.IsValid())
|
||||
assert.Equal(tc.expected, res, "quotient of coins is incorrect, tc #%d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *coinTestSuite) TestIsGTECoin() {
|
||||
cases := []struct {
|
||||
inputOne sdk.Coin
|
||||
|
||||
Reference in New Issue
Block a user