github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/types/ibc_adapter.go (about) 1 package types 2 3 import ( 4 "fmt" 5 "math/big" 6 "strings" 7 ) 8 9 // String provides a human-readable representation of a coin 10 func (coin CoinAdapter) String() string { 11 return fmt.Sprintf("%v%v", coin.Amount, coin.Denom) 12 } 13 14 // Validate returns an error if the Coin has a negative amount or if 15 // the denom is invalid. 16 func (coin CoinAdapter) Validate() error { 17 if err := ValidateDenom(coin.Denom); err != nil { 18 return err 19 } 20 21 if coin.Amount.IsNegative() { 22 return fmt.Errorf("negative coin amount: %v", coin.Amount) 23 } 24 25 return nil 26 } 27 28 // IsValid returns true if the Coin has a non-negative amount and the denom is valid. 29 func (coin CoinAdapter) IsValid() bool { 30 return coin.Validate() == nil 31 } 32 33 // IsZero returns if this represents no money 34 func (coin CoinAdapter) IsZero() bool { 35 return coin.Amount.IsZero() 36 } 37 38 // IsGTE returns true if they are the same type and the receiver is 39 // an equal or greater value 40 func (coin CoinAdapter) IsGTE(other CoinAdapter) bool { 41 if coin.Denom != other.Denom { 42 panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom)) 43 } 44 45 return !coin.Amount.LT(other.Amount) 46 } 47 48 // IsLT returns true if they are the same type and the receiver is 49 // a smaller value 50 func (coin CoinAdapter) IsLT(other CoinAdapter) bool { 51 if coin.Denom != other.Denom { 52 panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom)) 53 } 54 55 return coin.Amount.LT(other.Amount) 56 } 57 58 // IsEqual returns true if the two sets of Coins have the same value 59 func (coin CoinAdapter) IsEqual(other CoinAdapter) bool { 60 if coin.Denom != other.Denom { 61 panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom)) 62 } 63 64 return coin.Amount.Equal(other.Amount) 65 } 66 67 // Add adds amounts of two coins with same denom. If the coins differ in denom then 68 // it panics. 69 func (coin CoinAdapter) Add(coinB CoinAdapter) CoinAdapter { 70 if coin.Denom != coinB.Denom { 71 panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, coinB.Denom)) 72 } 73 74 return CoinAdapter{coin.Denom, coin.Amount.Add(coinB.Amount)} 75 } 76 77 // Sub subtracts amounts of two coins with same denom. If the coins differ in denom 78 // then it panics. 79 func (coin CoinAdapter) Sub(coinB CoinAdapter) CoinAdapter { 80 if coin.Denom != coinB.Denom { 81 panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, coinB.Denom)) 82 } 83 84 res := CoinAdapter{coin.Denom, coin.Amount.Sub(coinB.Amount)} 85 if res.IsNegative() { 86 panic("negative coin amount") 87 } 88 89 return res 90 } 91 92 // IsPositive returns true if coin amount is positive. 93 // 94 // TODO: Remove once unsigned integers are used. 95 func (coin CoinAdapter) IsPositive() bool { 96 return coin.Amount.Sign() == 1 97 } 98 99 // IsNegative returns true if the coin amount is negative and false otherwise. 100 // 101 // TODO: Remove once unsigned integers are used. 102 func (coin CoinAdapter) IsNegative() bool { 103 return coin.Amount.Sign() == -1 104 } 105 106 // Unmarshal implements the gogo proto custom type interface. 107 func (i *Int) Unmarshal(data []byte) error { 108 if len(data) == 0 { 109 i = nil 110 return nil 111 } 112 113 if i.i == nil { 114 i.i = new(big.Int) 115 } 116 117 if err := i.i.UnmarshalText(data); err != nil { 118 return err 119 } 120 121 if i.i.BitLen() > maxBitLen { 122 return fmt.Errorf("integer out of range; got: %d, max: %d", i.i.BitLen(), maxBitLen) 123 } 124 125 return nil 126 } 127 128 // Size implements the gogo proto custom type interface. 129 func (i *Int) Size() int { 130 bz, _ := i.Marshal() 131 return len(bz) 132 } 133 134 // Marshal implements the gogo proto custom type interface. 135 func (i Int) Marshal() ([]byte, error) { 136 if i.i == nil { 137 i.i = new(big.Int) 138 } 139 return i.i.MarshalText() 140 } 141 142 // MarshalTo implements the gogo proto custom type interface. 143 func (i *Int) MarshalTo(data []byte) (n int, err error) { 144 if i.i == nil { 145 i.i = new(big.Int) 146 } 147 if len(i.i.Bytes()) == 0 { 148 copy(data, []byte{0x30}) 149 return 1, nil 150 } 151 152 bz, err := i.Marshal() 153 if err != nil { 154 return 0, err 155 } 156 157 copy(data, bz) 158 return len(bz), nil 159 } 160 161 func NewIBCCoin(denom string, amount interface{}) DecCoin { 162 switch amount := amount.(type) { 163 case Int: 164 return NewIBCDecCoin(denom, amount) 165 case Dec: 166 return NewDecCoinFromDec(denom, amount) 167 default: 168 panic("Invalid amount") 169 } 170 } 171 172 func NewIBCDecCoin(denom string, amount Int) DecCoin { 173 if err := validateIBCCotin(denom, amount); err != nil { 174 panic(err) 175 } 176 177 return DecCoin{ 178 Denom: denom, 179 Amount: amount.ToDec(), 180 } 181 } 182 183 func validateIBCCotin(denom string, amount Int) error { 184 if !validIBCCoinDenom(denom) { 185 return fmt.Errorf("invalid denom: %s", denom) 186 } 187 188 if amount.IsNegative() { 189 return fmt.Errorf("negative coin amount: %v", amount) 190 } 191 192 return nil 193 } 194 195 func validIBCCoinDenom(denom string) bool { 196 return ibcReDnm.MatchString(denom) 197 } 198 199 // NewCoins constructs a new coin set. 200 func NewIBCCoins(coins ...Coin) Coins { 201 // remove zeroes 202 newCoins := removeZeroCoins(Coins(coins)) 203 if len(newCoins) == 0 { 204 return Coins{} 205 } 206 207 newCoins.Sort() 208 209 // detect duplicate Denoms 210 if dupIndex := findDup(newCoins); dupIndex != -1 { 211 panic(fmt.Errorf("find duplicate denom: %s", newCoins[dupIndex])) 212 } 213 newCoins.IsValid() 214 if !ValidCoins(newCoins) { 215 panic(fmt.Errorf("invalid coin set: %s", newCoins)) 216 } 217 218 return newCoins 219 } 220 func ValidCoins(coins Coins) bool { 221 switch len(coins) { 222 case 0: 223 return true 224 225 case 1: 226 if !validIBCCoinDenom(coins[0].Denom) { 227 return false 228 } 229 return coins[0].IsPositive() 230 231 default: 232 // check single coin case 233 if !ValidCoins(DecCoins{coins[0]}) { 234 return false 235 } 236 237 lowDenom := coins[0].Denom 238 for _, coin := range coins[1:] { 239 if strings.ToLower(coin.Denom) != coin.Denom { 240 return false 241 } 242 if coin.Denom <= lowDenom { 243 return false 244 } 245 if !coin.IsPositive() { 246 return false 247 } 248 249 // we compare each coin against the last denom 250 lowDenom = coin.Denom 251 } 252 253 return true 254 } 255 } 256 257 func (coin DecCoinAdapter) String() string { 258 return fmt.Sprintf("%v%v", coin.Amount, coin.Denom) 259 } 260 261 func (ip IntProtoAdapter) String() string { 262 return ip.Int.String() 263 } 264 265 func (dp DecProtoAdapter) String() string { 266 return dp.Dec.String() 267 }