-
Notifications
You must be signed in to change notification settings - Fork 177
/
Copy pathhelpers.go
224 lines (190 loc) · 5.58 KB
/
helpers.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package eth
import (
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi"
ethcommon "github.com/ethereum/go-ethereum/common"
"math"
"math/big"
"reflect"
"regexp"
"strings"
)
const DefaultMaxDecimals = 18
const percDivisor = 1000000
const percDivisorMinter = 1000000000
var (
BlocksUntilFirstClaimDeadline = big.NewInt(200)
maxUint256 = new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1))
)
func FormatUnits(baseAmount *big.Int, name string) string {
if baseAmount == nil {
return "0 " + name
}
if baseAmount.Cmp(big.NewInt(10000000000000000)) == -1 {
switch name {
case "ETH":
return fmt.Sprintf("%v WEI", baseAmount)
default:
return fmt.Sprintf("%v LPTU", baseAmount)
}
} else {
switch name {
case "ETH":
return fmt.Sprintf("%v ETH", FromBaseAmount(baseAmount, DefaultMaxDecimals))
default:
return fmt.Sprintf("%v LPT", FromBaseAmount(baseAmount, DefaultMaxDecimals))
}
}
}
func FormatPercMinter(value *big.Int) string {
pMultiplier := percDivisorMinter / 100.0
return fmt.Sprintf("%v", float64(value.Int64())/pMultiplier)
}
func FormatPerc(value *big.Int) string {
perc := ToPerc(value)
return fmt.Sprintf("%v", perc)
}
func ToPerc(value *big.Int) float64 {
pMultiplier := percDivisor / 100.0
return float64(value.Int64()) / pMultiplier
}
func FromPerc(perc float64) *big.Int {
return fromPerc(perc, big.NewFloat(percDivisor/100.0))
}
func FromPercOfUint256(perc float64) *big.Int {
multiplier := new(big.Float).SetInt(new(big.Int).Div(maxUint256, big.NewInt(100)))
return fromPerc(perc, multiplier)
}
func IsNullAddress(addr ethcommon.Address) bool {
return addr == ethcommon.Address{}
}
func fromPerc(perc float64, multiplier *big.Float) *big.Int {
floatRes := new(big.Float).Mul(big.NewFloat(perc), multiplier)
intRes, _ := floatRes.Int(nil)
return intRes
}
func ToBaseAmount(v string, maxDecimals int) (*big.Int, error) {
// check that string is a float represented as a string with "." as seperator
ok, err := regexp.MatchString("^[-+]?[0-9]*.?[0-9]+$", v)
if !ok || err != nil {
return nil, fmt.Errorf("submitted value %v is not a valid float", v)
}
splitNum := strings.Split(v, ".")
// If '.' is absent from string, add an empty string to become the decimal part
if len(splitNum) == 1 {
splitNum = append(splitNum, "")
}
intPart := splitNum[0]
decPart := splitNum[1]
// If decimal part is longer than 18 decimals return an error
if len(decPart) > maxDecimals {
return nil, fmt.Errorf("submitted value has more than 18 decimals")
}
// If decimal part is shorter than 18 digits, pad with "0"
for len(decPart) < maxDecimals {
decPart += "0"
}
// Combine intPart and decPart into a big.Int
baseAmount, ok := new(big.Int).SetString(intPart+decPart, 10)
if !ok {
return nil, fmt.Errorf("unable to convert floatString %v into big.Int", intPart+decPart)
}
return baseAmount, nil
}
func FromBaseAmount(v *big.Int, maxDecimals int) string {
baseAmount := v.String()
// if length < 18 leftPad with zeros
for len(baseAmount) < maxDecimals {
baseAmount = "0" + baseAmount
}
// split decPart and intPart
intPart := baseAmount[:len(baseAmount)-maxDecimals]
decPart := baseAmount[len(baseAmount)-maxDecimals:]
// if no int part, add "0"
if len(intPart) == 0 {
intPart = "0"
}
// remove right padded 0's from decPart
decPart = strings.TrimRight(decPart, "0")
// if there are no decimals just return the integer part
if len(decPart) == 0 {
return intPart
}
return intPart + "." + decPart
}
func parseABI(abiString string) (abi.ABI, error) {
return abi.JSON(strings.NewReader(abiString))
}
func decodeTxParams(abi *abi.ABI, v map[string]interface{}, data []byte) error {
m, err := abi.MethodById(data[:4])
if err != nil {
return err
}
if err := m.Inputs.UnpackIntoMap(v, data[4:]); err != nil {
return err
}
for k, val := range v {
v[k] = ethTypeToStringyType(val)
}
return nil
}
func ethTypeToStringyType(v interface{}) interface{} {
val := reflect.Indirect(reflect.ValueOf(v))
switch vTy := val.Interface().(type) {
case []byte:
return "0x" + ethcommon.Bytes2Hex(vTy)
case [32]byte:
return fmt.Sprintf("0x%x", vTy)
case ethcommon.Address:
return vTy.Hex()
case ethcommon.Hash:
return "0x" + vTy.Hex()
case big.Int:
return vTy.String()
default:
return handleComplexEthType(val)
}
}
func handleComplexEthType(val reflect.Value) interface{} {
switch val.Kind() {
// tuple
case reflect.Struct:
vString := "{"
for i := 0; i < val.NumField(); i++ {
vString += fmt.Sprintf(" %v", val.Type().Field(i).Name)
vString += ": "
vString += fmt.Sprintf("%v ", ethTypeToStringyType(val.Field(i).Interface()))
}
vString += "}"
return vString
case reflect.Array:
return handleEthSlice(val)
case reflect.Slice:
return handleEthSlice(val)
default:
return val.Interface()
}
}
func handleEthSlice(val reflect.Value) string {
if val.Kind() != reflect.Array && val.Kind() != reflect.Slice {
return ""
}
vString := "["
for i := 0; i < val.Len(); i++ {
vString += fmt.Sprintf(" %v ", ethTypeToStringyType(val.Index(i).Interface()))
}
vString += "]"
return vString
}
// FromWei converts a wei amount to another denomination
// e.g. FromWei(1e18, params.Ether) = 1
func FromWei(amount *big.Int, to int) string {
maxDecimals := int(math.Log10(float64(to)))
return FromBaseAmount(amount, maxDecimals)
}
// ToWei converts an amount in another denomination to the corresponding amount in wei
// e.g. ToWei("1", params.Ether) = 1e18
func ToWei(amount string, from int) (*big.Int, error) {
maxDecimals := int(math.Log10(float64(from)))
return ToBaseAmount(amount, maxDecimals)
}