2014-04-12 05:03:00 +02:00
|
|
|
// Copyright (c) 2013, 2014 Conformal Systems LLC.
|
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package btcutil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"math"
|
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
|
|
|
// AmountUnit describes a method of converting an Amount to something
|
|
|
|
// other than the base unit of a bitcoin. The value of the AmountUnit
|
|
|
|
// is the exponent component of the decadic multiple to convert from
|
|
|
|
// an amount in bitcoin to an amount counted in units.
|
|
|
|
type AmountUnit int
|
|
|
|
|
2014-04-12 06:23:27 +02:00
|
|
|
// These constants define various units used when describing a bitcoin
|
|
|
|
// monetary amount.
|
2014-04-12 05:03:00 +02:00
|
|
|
const (
|
2014-04-12 06:23:27 +02:00
|
|
|
AmountMegaBTC AmountUnit = 6
|
|
|
|
AmountKiloBTC AmountUnit = 3
|
|
|
|
AmountBTC AmountUnit = 0
|
|
|
|
AmountMilliBTC AmountUnit = -3
|
|
|
|
AmountMicroBTC AmountUnit = -6
|
|
|
|
AmountSatoshi AmountUnit = -8
|
2014-04-12 05:03:00 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// String returns the unit as a string. For recognized units, the SI
|
|
|
|
// prefix is used, or "Satoshi" for the base unit. For all unrecognized
|
|
|
|
// units, "1eN BTC" is returned, where N is the AmountUnit.
|
|
|
|
func (u AmountUnit) String() string {
|
|
|
|
switch u {
|
2014-04-12 06:23:27 +02:00
|
|
|
case AmountMegaBTC:
|
2014-04-12 05:03:00 +02:00
|
|
|
return "MBTC"
|
2014-04-12 06:23:27 +02:00
|
|
|
case AmountKiloBTC:
|
2014-04-12 05:03:00 +02:00
|
|
|
return "kBTC"
|
2014-04-12 06:23:27 +02:00
|
|
|
case AmountBTC:
|
2014-04-12 05:03:00 +02:00
|
|
|
return "BTC"
|
2014-04-12 06:23:27 +02:00
|
|
|
case AmountMilliBTC:
|
2014-04-12 05:03:00 +02:00
|
|
|
return "mBTC"
|
2014-04-12 06:23:27 +02:00
|
|
|
case AmountMicroBTC:
|
2014-04-12 05:03:00 +02:00
|
|
|
return "μBTC"
|
2014-04-12 06:23:27 +02:00
|
|
|
case AmountSatoshi:
|
2014-04-12 05:03:00 +02:00
|
|
|
return "Satoshi"
|
|
|
|
default:
|
|
|
|
return "1e" + strconv.FormatInt(int64(u), 10) + " BTC"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Amount represents the base bitcoin monetary unit (colloquially referred
|
|
|
|
// to as a `Satoshi'). A single Amount is equal to 1e-8 of a bitcoin.
|
|
|
|
type Amount int64
|
|
|
|
|
2014-06-20 22:17:48 +02:00
|
|
|
// round converts a floating point number, which may or may not be representable
|
|
|
|
// as an integer, to the Amount integer type by rounding to the nearest integer.
|
|
|
|
// This is performed by adding or subtracting 0.5 depending on the sign, and
|
|
|
|
// relying on integer truncation to round the value to the nearest Amount.
|
|
|
|
func round(f float64) Amount {
|
|
|
|
if f < 0 {
|
|
|
|
return Amount(f - 0.5)
|
|
|
|
}
|
|
|
|
return Amount(f + 0.5)
|
|
|
|
}
|
|
|
|
|
2014-04-12 05:03:00 +02:00
|
|
|
// NewAmount creates an Amount from a floating point value representing
|
2014-04-12 23:20:11 +02:00
|
|
|
// some value in bitcoin. NewAmount errors if f is NaN or +-Infinity, but
|
|
|
|
// does not check that the amount is within the total amount of bitcoin
|
|
|
|
// producable as f may not refer to an amount at a single moment in time.
|
2014-04-12 05:03:00 +02:00
|
|
|
func NewAmount(f float64) (Amount, error) {
|
2014-04-12 23:20:11 +02:00
|
|
|
// The amount is only considered invalid if it cannot be represented
|
|
|
|
// as an integer type. This may happen if f is NaN or +-Infinity.
|
|
|
|
switch {
|
|
|
|
case math.IsNaN(f):
|
|
|
|
fallthrough
|
|
|
|
case math.IsInf(f, 1):
|
2014-04-12 05:03:00 +02:00
|
|
|
fallthrough
|
2014-04-12 23:20:11 +02:00
|
|
|
case math.IsInf(f, -1):
|
2014-04-12 05:03:00 +02:00
|
|
|
return 0, errors.New("invalid bitcoin amount")
|
|
|
|
}
|
|
|
|
|
2014-07-07 15:55:44 +02:00
|
|
|
return round(f * SatoshiPerBitcoin), nil
|
2014-04-12 05:03:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ToUnit converts a monetary amount counted in bitcoin base units to a
|
|
|
|
// floating point value representing an amount of bitcoin.
|
|
|
|
func (a Amount) ToUnit(u AmountUnit) float64 {
|
|
|
|
return float64(a) / math.Pow10(int(u+8))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Format formats a monetary amount counted in bitcoin base units as a
|
|
|
|
// string for a given unit. The conversion will succeed for any unit,
|
|
|
|
// however, known units will be formated with an appended label describing
|
2014-04-12 06:23:27 +02:00
|
|
|
// the units with SI notation, or "Satoshi" for the base unit.
|
2014-04-12 05:03:00 +02:00
|
|
|
func (a Amount) Format(u AmountUnit) string {
|
|
|
|
units := " " + u.String()
|
|
|
|
return strconv.FormatFloat(a.ToUnit(u), 'f', -int(u+8), 64) + units
|
|
|
|
}
|
2014-04-12 06:16:41 +02:00
|
|
|
|
2014-04-12 06:23:27 +02:00
|
|
|
// String is the equivalent of calling Format with AmountBTC.
|
2014-04-12 06:16:41 +02:00
|
|
|
func (a Amount) String() string {
|
2014-04-12 06:23:27 +02:00
|
|
|
return a.Format(AmountBTC)
|
2014-04-12 06:16:41 +02:00
|
|
|
}
|
2014-06-20 22:17:48 +02:00
|
|
|
|
|
|
|
// MulF64 multiplies an Amount by a floating point value. While this is not
|
|
|
|
// an operation that must typically be done by a full node or wallet, it is
|
|
|
|
// useful for services that build on top of bitcoin (for example, calculating
|
|
|
|
// a fee by multiplying by a percentage).
|
|
|
|
func (a Amount) MulF64(f float64) Amount {
|
|
|
|
return round(float64(a) * f)
|
|
|
|
}
|