95 lines
2.9 KiB
Go
95 lines
2.9 KiB
Go
|
// 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
|
||
|
|
||
|
// These constants define the various standard units used when describing
|
||
|
// a bitcoin monetary amount.
|
||
|
const (
|
||
|
AmountMegaBitcoin AmountUnit = 6
|
||
|
AmountKiloBitcoin AmountUnit = 3
|
||
|
AmountBitcoin AmountUnit = 0
|
||
|
AmountMilliBitcoin AmountUnit = -3
|
||
|
AmountMicroBitcoin AmountUnit = -6
|
||
|
AmountBaseBitcoin AmountUnit = -8
|
||
|
)
|
||
|
|
||
|
// 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 {
|
||
|
case AmountMegaBitcoin:
|
||
|
return "MBTC"
|
||
|
case AmountKiloBitcoin:
|
||
|
return "kBTC"
|
||
|
case AmountBitcoin:
|
||
|
return "BTC"
|
||
|
case AmountMilliBitcoin:
|
||
|
return "mBTC"
|
||
|
case AmountMicroBitcoin:
|
||
|
return "μBTC"
|
||
|
case AmountBaseBitcoin:
|
||
|
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
|
||
|
|
||
|
// NewAmount creates an Amount from a floating point value representing
|
||
|
// some value in bitcoin.
|
||
|
func NewAmount(f float64) (Amount, error) {
|
||
|
a := f * float64(SatoshiPerBitcoin)
|
||
|
|
||
|
// The amount is only valid if it does not exceed the total amount
|
||
|
// of bitcoin producable, and is not a floating point number that
|
||
|
// would otherwise fail that check such as NaN or +-Inf.
|
||
|
switch abs := math.Abs(a); {
|
||
|
case abs > float64(MaxSatoshi):
|
||
|
fallthrough
|
||
|
case math.IsNaN(abs) || math.IsInf(abs, 1):
|
||
|
return 0, errors.New("invalid bitcoin amount")
|
||
|
}
|
||
|
|
||
|
// Depending on the sign, add or subtract 0.5 and rely on integer
|
||
|
// truncation to correctly round the value up or down.
|
||
|
if a < 0 {
|
||
|
a = a - 0.5
|
||
|
} else {
|
||
|
a = a + 0.5
|
||
|
}
|
||
|
return Amount(a), nil
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
// the units with SI notation.
|
||
|
func (a Amount) Format(u AmountUnit) string {
|
||
|
units := " " + u.String()
|
||
|
return strconv.FormatFloat(a.ToUnit(u), 'f', -int(u+8), 64) + units
|
||
|
}
|