github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/btcutil/amount.go (about) 1 // Copyright (c) 2013, 2014 The btcsuite developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package btcutil 6 7 import ( 8 "errors" 9 "math" 10 "strconv" 11 ) 12 13 // AmountUnit describes a method of converting an Amount to something 14 // other than the base unit of a bitcoin. The value of the AmountUnit 15 // is the exponent component of the decadic multiple to convert from 16 // an amount in bitcoin to an amount counted in units. 17 type AmountUnit int 18 19 // These constants define various units used when describing a bitcoin 20 // monetary amount. 21 const ( 22 AmountMegaBTC AmountUnit = 6 23 AmountKiloBTC AmountUnit = 3 24 AmountBTC AmountUnit = 0 25 AmountMilliBTC AmountUnit = -3 26 AmountMicroBTC AmountUnit = -6 27 AmountSatoshi AmountUnit = -8 28 ) 29 30 // String returns the unit as a string. For recognized units, the SI 31 // prefix is used, or "Satoshi" for the base unit. For all unrecognized 32 // units, "1eN BTC" is returned, where N is the AmountUnit. 33 func (u AmountUnit) String() string { 34 switch u { 35 case AmountMegaBTC: 36 return "MBTC" 37 case AmountKiloBTC: 38 return "kBTC" 39 case AmountBTC: 40 return "BTC" 41 case AmountMilliBTC: 42 return "mBTC" 43 case AmountMicroBTC: 44 return "μBTC" 45 case AmountSatoshi: 46 return "Satoshi" 47 default: 48 return "1e" + strconv.FormatInt(int64(u), 10) + " BTC" 49 } 50 } 51 52 // Amount represents the base bitcoin monetary unit (colloquially referred 53 // to as a `Satoshi'). A single Amount is equal to 1e-8 of a bitcoin. 54 type Amount int64 55 56 // round converts a floating point number, which may or may not be representable 57 // as an integer, to the Amount integer type by rounding to the nearest integer. 58 // This is performed by adding or subtracting 0.5 depending on the sign, and 59 // relying on integer truncation to round the value to the nearest Amount. 60 func round(f float64) Amount { 61 if f < 0 { 62 return Amount(f - 0.5) 63 } 64 return Amount(f + 0.5) 65 } 66 67 // NewAmount creates an Amount from a floating point value representing 68 // some value in bitcoin. NewAmount errors if f is NaN or +-Infinity, but 69 // does not check that the amount is within the total amount of bitcoin 70 // producible as f may not refer to an amount at a single moment in time. 71 // 72 // NewAmount is for specifically for converting BTC to Satoshi. 73 // For creating a new Amount with an int64 value which denotes a quantity of Satoshi, 74 // do a simple type conversion from type int64 to Amount. 75 // See GoDoc for example: http://godoc.org/github.com/mit-dci/lit/btcutil#example-Amount 76 func NewAmount(f float64) (Amount, error) { 77 // The amount is only considered invalid if it cannot be represented 78 // as an integer type. This may happen if f is NaN or +-Infinity. 79 switch { 80 case math.IsNaN(f): 81 fallthrough 82 case math.IsInf(f, 1): 83 fallthrough 84 case math.IsInf(f, -1): 85 return 0, errors.New("invalid bitcoin amount") 86 } 87 88 return round(f * SatoshiPerBitcoin), nil 89 } 90 91 // ToUnit converts a monetary amount counted in bitcoin base units to a 92 // floating point value representing an amount of bitcoin. 93 func (a Amount) ToUnit(u AmountUnit) float64 { 94 return float64(a) / math.Pow10(int(u+8)) 95 } 96 97 // ToBTC is the equivalent of calling ToUnit with AmountBTC. 98 func (a Amount) ToBTC() float64 { 99 return a.ToUnit(AmountBTC) 100 } 101 102 // Format formats a monetary amount counted in bitcoin base units as a 103 // string for a given unit. The conversion will succeed for any unit, 104 // however, known units will be formated with an appended label describing 105 // the units with SI notation, or "Satoshi" for the base unit. 106 func (a Amount) Format(u AmountUnit) string { 107 units := " " + u.String() 108 return strconv.FormatFloat(a.ToUnit(u), 'f', -int(u+8), 64) + units 109 } 110 111 // String is the equivalent of calling Format with AmountBTC. 112 func (a Amount) String() string { 113 return a.Format(AmountBTC) 114 } 115 116 // MulF64 multiplies an Amount by a floating point value. While this is not 117 // an operation that must typically be done by a full node or wallet, it is 118 // useful for services that build on top of bitcoin (for example, calculating 119 // a fee by multiplying by a percentage). 120 func (a Amount) MulF64(f float64) Amount { 121 return round(float64(a) * f) 122 }