github.com/cosmos/cosmos-sdk@v0.50.10/types/coin.go (about) 1 package types 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "regexp" 8 "sort" 9 "strings" 10 11 "cosmossdk.io/math" 12 ) 13 14 //----------------------------------------------------------------------------- 15 // Coin 16 17 // NewCoin returns a new coin with a denomination and amount. It will panic if 18 // the amount is negative or if the denomination is invalid. 19 func NewCoin(denom string, amount math.Int) Coin { 20 coin := Coin{ 21 Denom: denom, 22 Amount: amount, 23 } 24 25 if err := coin.Validate(); err != nil { 26 panic(err) 27 } 28 29 return coin 30 } 31 32 // NewInt64Coin returns a new coin with a denomination and amount. It will panic 33 // if the amount is negative. 34 func NewInt64Coin(denom string, amount int64) Coin { 35 return NewCoin(denom, math.NewInt(amount)) 36 } 37 38 // String provides a human-readable representation of a coin 39 func (coin Coin) String() string { 40 return fmt.Sprintf("%v%s", coin.Amount, coin.Denom) 41 } 42 43 // Validate returns an error if the Coin has a negative amount or if 44 // the denom is invalid. 45 func (coin Coin) Validate() error { 46 if err := ValidateDenom(coin.Denom); err != nil { 47 return err 48 } 49 50 if coin.Amount.IsNil() { 51 return errors.New("amount is nil") 52 } 53 54 if coin.Amount.IsNegative() { 55 return fmt.Errorf("negative coin amount: %v", coin.Amount) 56 } 57 58 return nil 59 } 60 61 // IsValid returns true if the Coin has a non-negative amount and the denom is valid. 62 func (coin Coin) IsValid() bool { 63 return coin.Validate() == nil 64 } 65 66 // IsZero returns if this represents no money 67 func (coin Coin) IsZero() bool { 68 return coin.Amount.IsZero() 69 } 70 71 // IsGTE returns true if they are the same type and the receiver is 72 // an equal or greater value 73 func (coin Coin) IsGTE(other Coin) bool { 74 if coin.Denom != other.Denom { 75 panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom)) 76 } 77 78 return !coin.Amount.LT(other.Amount) 79 } 80 81 // IsLT returns true if they are the same type and the receiver is 82 // a smaller value 83 func (coin Coin) IsLT(other Coin) bool { 84 if coin.Denom != other.Denom { 85 panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom)) 86 } 87 88 return coin.Amount.LT(other.Amount) 89 } 90 91 // IsLTE returns true if they are the same type and the receiver is 92 // an equal or smaller value 93 func (coin Coin) IsLTE(other Coin) bool { 94 if coin.Denom != other.Denom { 95 panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom)) 96 } 97 98 return !coin.Amount.GT(other.Amount) 99 } 100 101 // IsEqual returns true if the two sets of Coins have the same value 102 // Deprecated: Use Coin.Equal instead. 103 func (coin Coin) IsEqual(other Coin) bool { 104 return coin.Equal(other) 105 } 106 107 // Add adds amounts of two coins with same denom. If the coins differ in denom then 108 // it panics. 109 func (coin Coin) Add(coinB Coin) Coin { 110 if coin.Denom != coinB.Denom { 111 panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, coinB.Denom)) 112 } 113 114 return Coin{coin.Denom, coin.Amount.Add(coinB.Amount)} 115 } 116 117 // AddAmount adds an amount to the Coin. 118 func (coin Coin) AddAmount(amount math.Int) Coin { 119 return Coin{coin.Denom, coin.Amount.Add(amount)} 120 } 121 122 // Sub subtracts amounts of two coins with same denom and panics on error. 123 func (coin Coin) Sub(coinB Coin) Coin { 124 res, err := coin.SafeSub(coinB) 125 if err != nil { 126 panic(err) 127 } 128 129 return res 130 } 131 132 // SafeSub safely subtracts the amounts of two coins. It returns an error if the coins differ 133 // in denom or subtraction results in negative coin denom. 134 func (coin Coin) SafeSub(coinB Coin) (Coin, error) { 135 if coin.Denom != coinB.Denom { 136 return Coin{}, fmt.Errorf("invalid coin denoms: %s, %s", coin.Denom, coinB.Denom) 137 } 138 139 res := Coin{coin.Denom, coin.Amount.Sub(coinB.Amount)} 140 if res.IsNegative() { 141 return Coin{}, fmt.Errorf("negative coin amount: %s", res) 142 } 143 144 return res, nil 145 } 146 147 // SubAmount subtracts an amount from the Coin. 148 func (coin Coin) SubAmount(amount math.Int) Coin { 149 res := Coin{coin.Denom, coin.Amount.Sub(amount)} 150 if res.IsNegative() { 151 panic("negative coin amount") 152 } 153 154 return res 155 } 156 157 // IsPositive returns true if coin amount is positive. 158 // 159 // TODO: Remove once unsigned integers are used. 160 func (coin Coin) IsPositive() bool { 161 return coin.Amount.Sign() == 1 162 } 163 164 // IsNegative returns true if the coin amount is negative and false otherwise. 165 // 166 // TODO: Remove once unsigned integers are used. 167 func (coin Coin) IsNegative() bool { 168 return coin.Amount.Sign() == -1 169 } 170 171 // IsNil returns true if the coin amount is nil and false otherwise. 172 func (coin Coin) IsNil() bool { 173 return coin.Amount.BigInt() == nil 174 } 175 176 //----------------------------------------------------------------------------- 177 // Coins 178 179 // Coins is a set of Coin, one per currency 180 type Coins []Coin 181 182 // NewCoins constructs a new coin set. The provided coins will be sanitized by removing 183 // zero coins and sorting the coin set. A panic will occur if the coin set is not valid. 184 func NewCoins(coins ...Coin) Coins { 185 newCoins := sanitizeCoins(coins) 186 if err := newCoins.Validate(); err != nil { 187 panic(fmt.Errorf("invalid coin set %s: %w", newCoins, err)) 188 } 189 190 return newCoins 191 } 192 193 func sanitizeCoins(coins []Coin) Coins { 194 newCoins := removeZeroCoins(coins) 195 if len(newCoins) == 0 { 196 return Coins{} 197 } 198 199 return newCoins.Sort() 200 } 201 202 type coinsJSON Coins 203 204 // MarshalJSON implements a custom JSON marshaller for the Coins type to allow 205 // nil Coins to be encoded as an empty array. 206 func (coins Coins) MarshalJSON() ([]byte, error) { 207 if coins == nil { 208 return json.Marshal(coinsJSON(Coins{})) 209 } 210 211 return json.Marshal(coinsJSON(coins)) 212 } 213 214 func (coins Coins) String() string { 215 if len(coins) == 0 { 216 return "" 217 } else if len(coins) == 1 { 218 return coins[0].String() 219 } 220 221 // Build the string with a string builder 222 var out strings.Builder 223 for _, coin := range coins[:len(coins)-1] { 224 out.WriteString(coin.String()) 225 out.WriteByte(',') 226 } 227 out.WriteString(coins[len(coins)-1].String()) 228 return out.String() 229 } 230 231 // Validate checks that the Coins are sorted, have positive amount, with a valid and unique 232 // denomination (i.e no duplicates). Otherwise, it returns an error. 233 func (coins Coins) Validate() error { 234 switch len(coins) { 235 case 0: 236 return nil 237 238 case 1: 239 if err := ValidateDenom(coins[0].Denom); err != nil { 240 return err 241 } 242 if !coins[0].IsPositive() { 243 return fmt.Errorf("coin %s amount is not positive", coins[0]) 244 } 245 return nil 246 247 default: 248 // check single coin case 249 if err := (Coins{coins[0]}).Validate(); err != nil { 250 return err 251 } 252 253 lowDenom := coins[0].Denom 254 255 for _, coin := range coins[1:] { 256 if err := ValidateDenom(coin.Denom); err != nil { 257 return err 258 } 259 if coin.Denom < lowDenom { 260 return fmt.Errorf("denomination %s is not sorted", coin.Denom) 261 } 262 if coin.Denom == lowDenom { 263 return fmt.Errorf("duplicate denomination %s", coin.Denom) 264 } 265 if !coin.IsPositive() { 266 return fmt.Errorf("coin %s amount is not positive", coin.Denom) 267 } 268 269 // we compare each coin against the last denom 270 lowDenom = coin.Denom 271 } 272 273 return nil 274 } 275 } 276 277 func (coins Coins) isSorted() bool { 278 for i := 1; i < len(coins); i++ { 279 if coins[i-1].Denom > coins[i].Denom { 280 return false 281 } 282 } 283 return true 284 } 285 286 // IsValid calls Validate and returns true when the Coins are sorted, have positive amount, with a 287 // valid and unique denomination (i.e no duplicates). 288 func (coins Coins) IsValid() bool { 289 return coins.Validate() == nil 290 } 291 292 // Denoms returns all denoms associated with a Coins object 293 func (coins Coins) Denoms() []string { 294 res := make([]string, len(coins)) 295 for i, coin := range coins { 296 res[i] = coin.Denom 297 } 298 return res 299 } 300 301 // Add adds two sets of coins. 302 // 303 // e.g. 304 // {2A} + {A, 2B} = {3A, 2B} 305 // {2A} + {0B} = {2A} 306 // 307 // NOTE: Add operates under the invariant that coins are sorted by 308 // denominations. 309 // 310 // CONTRACT: Add will never return Coins where one Coin has a non-positive 311 // amount. In otherwords, IsValid will always return true. 312 // The function panics if `coins` or `coinsB` are not sorted (ascending). 313 func (coins Coins) Add(coinsB ...Coin) Coins { 314 return coins.safeAdd(coinsB) 315 } 316 317 // safeAdd will perform addition of two coins sets. If both coin sets are 318 // empty, then an empty set is returned. If only a single set is empty, the 319 // other set is returned. Otherwise, the coins are compared in order of their 320 // denomination and addition only occurs when the denominations match, otherwise 321 // the coin is simply added to the sum assuming it's not zero. 322 // The function panics if `coins` or `coinsB` are not sorted (ascending). 323 func (coins Coins) safeAdd(coinsB Coins) (coalesced Coins) { 324 // probably the best way will be to make Coins and interface and hide the structure 325 // definition (type alias) 326 if !coins.isSorted() { 327 panic("Coins (self) must be sorted") 328 } 329 if !coinsB.isSorted() { 330 panic("Wrong argument: coins must be sorted") 331 } 332 333 uniqCoins := make(map[string]Coins, len(coins)+len(coinsB)) 334 // Traverse all the coins for each of the coins and coinsB. 335 for _, cL := range []Coins{coins, coinsB} { 336 for _, c := range cL { 337 uniqCoins[c.Denom] = append(uniqCoins[c.Denom], c) 338 } 339 } 340 341 for denom, cL := range uniqCoins { //#nosec 342 comboCoin := Coin{Denom: denom, Amount: math.NewInt(0)} 343 for _, c := range cL { 344 comboCoin = comboCoin.Add(c) 345 } 346 if !comboCoin.IsZero() { 347 coalesced = append(coalesced, comboCoin) 348 } 349 } 350 if coalesced == nil { 351 return Coins{} 352 } 353 return coalesced.Sort() 354 } 355 356 // DenomsSubsetOf returns true if receiver's denom set 357 // is subset of coinsB's denoms. 358 func (coins Coins) DenomsSubsetOf(coinsB Coins) bool { 359 // more denoms in B than in receiver 360 if len(coins) > len(coinsB) { 361 return false 362 } 363 364 for _, coin := range coins { 365 if coinsB.AmountOf(coin.Denom).IsZero() { 366 return false 367 } 368 } 369 370 return true 371 } 372 373 // Sub subtracts a set of coins from another. 374 // 375 // e.g. 376 // {2A, 3B} - {A} = {A, 3B} 377 // {2A} - {0B} = {2A} 378 // {A, B} - {A} = {B} 379 // 380 // CONTRACT: Sub will never return Coins where one Coin has a non-positive 381 // amount. In otherwords, IsValid will always return true. 382 func (coins Coins) Sub(coinsB ...Coin) Coins { 383 diff, hasNeg := coins.SafeSub(coinsB...) 384 if hasNeg { 385 panic("negative coin amount") 386 } 387 388 return diff 389 } 390 391 // SafeSub performs the same arithmetic as Sub but returns a boolean if any 392 // negative coin amount was returned. 393 // The function panics if `coins` or `coinsB` are not sorted (ascending). 394 func (coins Coins) SafeSub(coinsB ...Coin) (Coins, bool) { 395 diff := coins.safeAdd(NewCoins(coinsB...).negative()) 396 return diff, diff.IsAnyNegative() 397 } 398 399 // MulInt performs the scalar multiplication of coins with a `multiplier` 400 // All coins are multiplied by x 401 // e.g. 402 // {2A, 3B} * 2 = {4A, 6B} 403 // {2A} * 0 panics 404 // Note, if IsValid was true on Coins, IsValid stays true. 405 func (coins Coins) MulInt(x math.Int) Coins { 406 coins, ok := coins.SafeMulInt(x) 407 if !ok { 408 panic("multiplying by zero is an invalid operation on coins") 409 } 410 411 return coins 412 } 413 414 // SafeMulInt performs the same arithmetic as MulInt but returns false 415 // if the `multiplier` is zero because it makes IsValid return false. 416 func (coins Coins) SafeMulInt(x math.Int) (Coins, bool) { 417 if x.IsZero() { 418 return nil, false 419 } 420 421 res := make(Coins, len(coins)) 422 for i, coin := range coins { 423 coin := coin 424 res[i] = NewCoin(coin.Denom, coin.Amount.Mul(x)) 425 } 426 427 return res, true 428 } 429 430 // QuoInt performs the scalar division of coins with a `divisor` 431 // All coins are divided by x and truncated. 432 // e.g. 433 // {2A, 30B} / 2 = {1A, 15B} 434 // {2A} / 2 = {1A} 435 // {4A} / {8A} = {0A} 436 // {2A} / 0 = panics 437 // Note, if IsValid was true on Coins, IsValid stays true, 438 // unless the `divisor` is greater than the smallest coin amount. 439 func (coins Coins) QuoInt(x math.Int) Coins { 440 coins, ok := coins.SafeQuoInt(x) 441 if !ok { 442 panic("dividing by zero is an invalid operation on coins") 443 } 444 445 return coins 446 } 447 448 // SafeQuoInt performs the same arithmetic as QuoInt but returns an error 449 // if the division cannot be done. 450 func (coins Coins) SafeQuoInt(x math.Int) (Coins, bool) { 451 if x.IsZero() { 452 return nil, false 453 } 454 455 var res Coins 456 for _, coin := range coins { 457 coin := coin 458 res = append(res, NewCoin(coin.Denom, coin.Amount.Quo(x))) 459 } 460 461 return res, true 462 } 463 464 // Max takes two valid Coins inputs and returns a valid Coins result 465 // where for every denom D, AmountOf(D) of the result is the maximum 466 // of AmountOf(D) of the inputs. Note that the result might be not 467 // be equal to either input. For any valid Coins a, b, and c, the 468 // following are always true: 469 // 470 // a.IsAllLTE(a.Max(b)) 471 // b.IsAllLTE(a.Max(b)) 472 // a.IsAllLTE(c) && b.IsAllLTE(c) == a.Max(b).IsAllLTE(c) 473 // a.Add(b...).Equal(a.Min(b).Add(a.Max(b)...)) 474 // 475 // E.g. 476 // {1A, 3B, 2C}.Max({4A, 2B, 2C} == {4A, 3B, 2C}) 477 // {2A, 3B}.Max({1B, 4C}) == {2A, 3B, 4C} 478 // {1A, 2B}.Max({}) == {1A, 2B} 479 func (coins Coins) Max(coinsB Coins) Coins { 480 max := make([]Coin, 0) 481 indexA, indexB := 0, 0 482 for indexA < len(coins) && indexB < len(coinsB) { 483 coinA, coinB := coins[indexA], coinsB[indexB] 484 switch strings.Compare(coinA.Denom, coinB.Denom) { 485 case -1: // denom missing from coinsB 486 max = append(max, coinA) 487 indexA++ 488 case 0: // same denom in both 489 maxCoin := coinA 490 if coinB.Amount.GT(maxCoin.Amount) { 491 maxCoin = coinB 492 } 493 max = append(max, maxCoin) 494 indexA++ 495 indexB++ 496 case 1: // denom missing from coinsA 497 max = append(max, coinB) 498 indexB++ 499 } 500 } 501 for ; indexA < len(coins); indexA++ { 502 max = append(max, coins[indexA]) 503 } 504 for ; indexB < len(coinsB); indexB++ { 505 max = append(max, coinsB[indexB]) 506 } 507 return NewCoins(max...) 508 } 509 510 // Min takes two valid Coins inputs and returns a valid Coins result 511 // where for every denom D, AmountOf(D) of the result is the minimum 512 // of AmountOf(D) of the inputs. Note that the result might be not 513 // be equal to either input. For any valid Coins a, b, and c, the 514 // following are always true: 515 // 516 // a.Min(b).IsAllLTE(a) 517 // a.Min(b).IsAllLTE(b) 518 // c.IsAllLTE(a) && c.IsAllLTE(b) == c.IsAllLTE(a.Min(b)) 519 // a.Add(b...).Equal(a.Min(b).Add(a.Max(b)...)) 520 // 521 // E.g. 522 // {1A, 3B, 2C}.Min({4A, 2B, 2C} == {1A, 2B, 2C}) 523 // {2A, 3B}.Min({1B, 4C}) == {1B} 524 // {1A, 2B}.Min({3C}) == empty 525 // 526 // See also DecCoins.Intersect(). 527 func (coins Coins) Min(coinsB Coins) Coins { 528 min := make([]Coin, 0) 529 for indexA, indexB := 0, 0; indexA < len(coins) && indexB < len(coinsB); { 530 coinA, coinB := coins[indexA], coinsB[indexB] 531 switch strings.Compare(coinA.Denom, coinB.Denom) { 532 case -1: // denom missing from coinsB 533 indexA++ 534 case 0: // same denom in both 535 minCoin := coinA 536 if coinB.Amount.LT(minCoin.Amount) { 537 minCoin = coinB 538 } 539 if !minCoin.IsZero() { 540 min = append(min, minCoin) 541 } 542 indexA++ 543 indexB++ 544 case 1: // denom missing from coins 545 indexB++ 546 } 547 } 548 return NewCoins(min...) 549 } 550 551 // IsAllGT returns true if for every denom in coinsB, 552 // the denom is present at a greater amount in coins. 553 func (coins Coins) IsAllGT(coinsB Coins) bool { 554 if len(coins) == 0 { 555 return false 556 } 557 558 if len(coinsB) == 0 { 559 return true 560 } 561 562 if !coinsB.DenomsSubsetOf(coins) { 563 return false 564 } 565 566 for _, coinB := range coinsB { 567 amountA, amountB := coins.AmountOf(coinB.Denom), coinB.Amount 568 if !amountA.GT(amountB) { 569 return false 570 } 571 } 572 573 return true 574 } 575 576 // IsAllGTE returns false if for any denom in coinsB, 577 // the denom is present at a smaller amount in coins; 578 // else returns true. 579 func (coins Coins) IsAllGTE(coinsB Coins) bool { 580 if len(coinsB) == 0 { 581 return true 582 } 583 584 if len(coins) == 0 { 585 return false 586 } 587 588 for _, coinB := range coinsB { 589 if coinB.Amount.GT(coins.AmountOf(coinB.Denom)) { 590 return false 591 } 592 } 593 594 return true 595 } 596 597 // IsAllLT returns True iff for every denom in coins, the denom is present at 598 // a smaller amount in coinsB. 599 func (coins Coins) IsAllLT(coinsB Coins) bool { 600 return coinsB.IsAllGT(coins) 601 } 602 603 // IsAllLTE returns true iff for every denom in coins, the denom is present at 604 // a smaller or equal amount in coinsB. 605 func (coins Coins) IsAllLTE(coinsB Coins) bool { 606 return coinsB.IsAllGTE(coins) 607 } 608 609 // IsAnyGT returns true iff for any denom in coins, the denom is present at a 610 // greater amount in coinsB. 611 // 612 // e.g. 613 // {2A, 3B}.IsAnyGT{A} = true 614 // {2A, 3B}.IsAnyGT{5C} = false 615 // {}.IsAnyGT{5C} = false 616 // {2A, 3B}.IsAnyGT{} = false 617 func (coins Coins) IsAnyGT(coinsB Coins) bool { 618 if len(coinsB) == 0 { 619 return false 620 } 621 622 for _, coin := range coins { 623 amt := coinsB.AmountOf(coin.Denom) 624 if coin.Amount.GT(amt) && !amt.IsZero() { 625 return true 626 } 627 } 628 629 return false 630 } 631 632 // IsAnyGTE returns true iff coins contains at least one denom that is present 633 // at a greater or equal amount in coinsB; it returns false otherwise. 634 // 635 // NOTE: IsAnyGTE operates under the invariant that both coin sets are sorted 636 // by denominations and there exists no zero coins. 637 func (coins Coins) IsAnyGTE(coinsB Coins) bool { 638 if len(coinsB) == 0 { 639 return false 640 } 641 642 for _, coin := range coins { 643 amt := coinsB.AmountOf(coin.Denom) 644 if coin.Amount.GTE(amt) && !amt.IsZero() { 645 return true 646 } 647 } 648 649 return false 650 } 651 652 // IsZero returns true if there are no coins or all coins are zero. 653 func (coins Coins) IsZero() bool { 654 for _, coin := range coins { 655 if !coin.IsZero() { 656 return false 657 } 658 } 659 return true 660 } 661 662 // Equal returns true if the two sets of Coins have the same value 663 func (coins Coins) Equal(coinsB Coins) bool { 664 if len(coins) != len(coinsB) { 665 return false 666 } 667 668 coins = coins.Sort() 669 coinsB = coinsB.Sort() 670 671 for i := 0; i < len(coins); i++ { 672 if !coins[i].Equal(coinsB[i]) { 673 return false 674 } 675 } 676 677 return true 678 } 679 680 // Empty returns true if there are no coins and false otherwise. 681 func (coins Coins) Empty() bool { 682 return len(coins) == 0 683 } 684 685 // AmountOf returns the amount of a denom from coins 686 func (coins Coins) AmountOf(denom string) math.Int { 687 mustValidateDenom(denom) 688 return coins.AmountOfNoDenomValidation(denom) 689 } 690 691 // AmountOfNoDenomValidation returns the amount of a denom from coins 692 // without validating the denomination. 693 func (coins Coins) AmountOfNoDenomValidation(denom string) math.Int { 694 if ok, c := coins.Find(denom); ok { 695 return c.Amount 696 } 697 return math.ZeroInt() 698 } 699 700 // Find returns true and coin if the denom exists in coins. Otherwise it returns false 701 // and a zero coin. Uses binary search. 702 // CONTRACT: coins must be valid (sorted). 703 func (coins Coins) Find(denom string) (bool, Coin) { 704 switch len(coins) { 705 case 0: 706 return false, Coin{} 707 708 case 1: 709 coin := coins[0] 710 if coin.Denom == denom { 711 return true, coin 712 } 713 return false, Coin{} 714 715 default: 716 midIdx := len(coins) / 2 // 2:1, 3:1, 4:2 717 coin := coins[midIdx] 718 switch { 719 case denom < coin.Denom: 720 return coins[:midIdx].Find(denom) 721 case denom == coin.Denom: 722 return true, coin 723 default: 724 return coins[midIdx+1:].Find(denom) 725 } 726 } 727 } 728 729 // GetDenomByIndex returns the Denom of the certain coin to make the findDup generic 730 func (coins Coins) GetDenomByIndex(i int) string { 731 return coins[i].Denom 732 } 733 734 // IsAllPositive returns true if there is at least one coin and all currencies 735 // have a positive value. 736 func (coins Coins) IsAllPositive() bool { 737 if len(coins) == 0 { 738 return false 739 } 740 741 for _, coin := range coins { 742 if !coin.IsPositive() { 743 return false 744 } 745 } 746 747 return true 748 } 749 750 // IsAnyNegative returns true if there is at least one coin whose amount 751 // is negative; returns false otherwise. It returns false if the coin set 752 // is empty too. 753 // 754 // TODO: Remove once unsigned integers are used. 755 func (coins Coins) IsAnyNegative() bool { 756 for _, coin := range coins { 757 if coin.IsNegative() { 758 return true 759 } 760 } 761 762 return false 763 } 764 765 // IsAnyNil returns true if there is at least one coin whose amount 766 // is nil; returns false otherwise. It returns false if the coin set 767 // is empty too. 768 func (coins Coins) IsAnyNil() bool { 769 for _, coin := range coins { 770 if coin.IsNil() { 771 return true 772 } 773 } 774 775 return false 776 } 777 778 // negative returns a set of coins with all amount negative. 779 // 780 // TODO: Remove once unsigned integers are used. 781 func (coins Coins) negative() Coins { 782 res := make([]Coin, 0, len(coins)) 783 784 for _, coin := range coins { 785 res = append(res, Coin{ 786 Denom: coin.Denom, 787 Amount: coin.Amount.Neg(), 788 }) 789 } 790 791 return res 792 } 793 794 // removeZeroCoins removes all zero coins from the given coin set in-place. 795 func removeZeroCoins(coins Coins) Coins { 796 nonZeros := make([]Coin, 0, len(coins)) 797 798 for _, coin := range coins { 799 if !coin.IsZero() { 800 nonZeros = append(nonZeros, coin) 801 } 802 } 803 804 return nonZeros 805 } 806 807 //----------------------------------------------------------------------------- 808 // Sort interface 809 810 // Len implements sort.Interface for Coins 811 func (coins Coins) Len() int { return len(coins) } 812 813 // Less implements sort.Interface for Coins 814 func (coins Coins) Less(i, j int) bool { return coins[i].Denom < coins[j].Denom } 815 816 // Swap implements sort.Interface for Coins 817 func (coins Coins) Swap(i, j int) { coins[i], coins[j] = coins[j], coins[i] } 818 819 var _ sort.Interface = Coins{} 820 821 // Sort is a helper function to sort the set of coins in-place 822 func (coins Coins) Sort() Coins { 823 // sort.Sort(coins) does a costly runtime copy as part of `runtime.convTSlice` 824 // So we avoid this heap allocation if len(coins) <= 1. In the future, we should hopefully find 825 // a strategy to always avoid this. 826 if len(coins) > 1 { 827 sort.Sort(coins) 828 } 829 return coins 830 } 831 832 //----------------------------------------------------------------------------- 833 // Parsing 834 835 var ( 836 // Denominations can be 3 ~ 128 characters long and support letters, followed by either 837 // a letter, a number or a separator ('/', ':', '.', '_' or '-'). 838 reDnmString = `[a-zA-Z][a-zA-Z0-9/:._-]{2,127}` 839 reDecAmt = `[[:digit:]]+(?:\.[[:digit:]]+)?|\.[[:digit:]]+` 840 reSpc = `[[:space:]]*` 841 reDnm *regexp.Regexp 842 reDecCoin *regexp.Regexp 843 ) 844 845 func init() { 846 SetCoinDenomRegex(DefaultCoinDenomRegex) 847 } 848 849 // DefaultCoinDenomRegex returns the default regex string 850 func DefaultCoinDenomRegex() string { 851 return reDnmString 852 } 853 854 // coinDenomRegex returns the current regex string and can be overwritten for custom validation 855 var coinDenomRegex = DefaultCoinDenomRegex 856 857 // SetCoinDenomRegex allows for coin's custom validation by overriding the regular 858 // expression string used for denom validation. 859 func SetCoinDenomRegex(reFn func() string) { 860 coinDenomRegex = reFn 861 862 reDnm = regexp.MustCompile(fmt.Sprintf(`^%s$`, coinDenomRegex())) 863 reDecCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reDecAmt, reSpc, coinDenomRegex())) 864 } 865 866 // ValidateDenom is the default validation function for Coin.Denom. 867 func ValidateDenom(denom string) error { 868 if !reDnm.MatchString(denom) { 869 return fmt.Errorf("invalid denom: %s", denom) 870 } 871 return nil 872 } 873 874 func mustValidateDenom(denom string) { 875 if err := ValidateDenom(denom); err != nil { 876 panic(err) 877 } 878 } 879 880 // ParseCoinNormalized parses and normalize a cli input for one coin type, returning errors if invalid or on an empty string 881 // as well. 882 // Expected format: "{amount}{denomination}" 883 func ParseCoinNormalized(coinStr string) (coin Coin, err error) { 884 decCoin, err := ParseDecCoin(coinStr) 885 if err != nil { 886 return Coin{}, err 887 } 888 889 coin, _ = NormalizeDecCoin(decCoin).TruncateDecimal() 890 return coin, nil 891 } 892 893 // ParseCoinsNormalized will parse out a list of coins separated by commas, and normalize them by converting to the smallest 894 // unit. If the parsing is successful, the provided coins will be sanitized by removing zero coins and sorting the coin 895 // set. Lastly a validation of the coin set is executed. If the check passes, ParseCoinsNormalized will return the 896 // sanitized coins. 897 // Otherwise, it will return an error. 898 // If an empty string is provided to ParseCoinsNormalized, it returns nil Coins. 899 // ParseCoinsNormalized supports decimal coins as inputs, and truncate them to int after converted to the smallest unit. 900 // Expected format: "{amount0}{denomination},...,{amountN}{denominationN}" 901 func ParseCoinsNormalized(coinStr string) (Coins, error) { 902 coins, err := ParseDecCoins(coinStr) 903 if err != nil { 904 return Coins{}, err 905 } 906 return NormalizeCoins(coins), nil 907 }