amount.go raw

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