-
Notifications
You must be signed in to change notification settings - Fork 1
/
amount.go
111 lines (98 loc) · 3.77 KB
/
amount.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package amt
import (
"errors"
"math"
"strconv"
)
// Unit 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 Unit int
// These constants define various units used when describing a bitcoin monetary amount.
const (
MegaDUO Unit = 6
KiloDUO Unit = 3
DUO Unit = 0
MilliDUO Unit = -3
MicroDUO Unit = -6
Satoshi Unit = -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 DUO" is returned, where N is the AmountUnit.
func (u Unit) String() string {
switch u {
case MegaDUO:
return "MDUO"
case KiloDUO:
return "kDUO"
case DUO:
return "DUO"
case MilliDUO:
return "mDUO"
case MicroDUO:
return "μDUO"
case Satoshi:
return "Satoshi"
default:
return "1e" + strconv.FormatInt(int64(u), 10) + " DUO"
}
}
// 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
func (a Amount) Int64() int64 {
return int64(a)
}
// 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)
}
// NewAmount creates an Amount from a floating point value representing 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 producible as f may not
// refer to an amount at a single moment in time. NewAmount is for specifically for converting DUO to Satoshi. For
// creating a new Amount with an int64 value which denotes a quantity of Satoshi, do a simple type conversion from type
// int64 to Amount. See GoDoc for example: http://godoc.org/github.com/p9c/monorepo/util#example-Amount
func NewAmount(f float64) (Amount, error) {
// 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):
fallthrough
case math.IsInf(f, -1):
return 0, errors.New("invalid bitcoin amount")
}
return round(f * float64(SatoshiPerBitcoin)), 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 Unit) float64 {
return float64(a) / math.Pow10(int(u+8))
}
// ToDUO is the equivalent of calling ToUnit with AmountDUO.
func (a Amount) ToDUO() float64 {
return a.ToUnit(DUO)
}
// 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, or "Satoshi" for the base unit.
func (a Amount) Format(u Unit) string {
units := " " + u.String()
return strconv.FormatFloat(a.ToUnit(u), 'f', -int(u+8), 64) + units
}
// String is the equivalent of calling Format with AmountDUO.
func (a Amount) String() string {
return a.Format(DUO)
}
// 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 podbuild 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)
}