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  }