-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
address.go
145 lines (121 loc) · 4.05 KB
/
address.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
package ethkey
import (
"database/sql/driver"
"encoding/hex"
"fmt"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/smartcontractkit/chainlink/v2/core/utils"
)
// EIP55Address is a new type for string which persists an ethereum address in
// its original string representation which includes a leading 0x, and EIP55
// checksum which is represented by the case of digits A-F.
type EIP55Address string
// NewEIP55Address creates an EIP55Address from a string, an error is returned if:
//
// 1) There is no leading 0x
// 2) The length is wrong
// 3) There are any non hexadecimal characters
// 4) The checksum fails
func NewEIP55Address(s string) (EIP55Address, error) {
address := common.HexToAddress(s)
if s != address.Hex() {
return EIP55Address(""), fmt.Errorf(`"%s" is not a valid EIP55 formatted address`, s)
}
return EIP55Address(s), nil
}
func MustEIP55Address(s string) EIP55Address {
addr, err := NewEIP55Address(s)
if err != nil {
panic(err)
}
return addr
}
// EIP55AddressFromAddress forces an address into EIP55Address format
// It is safe to panic on error since address.Hex() should ALWAYS generate EIP55Address-compatible hex strings
func EIP55AddressFromAddress(a common.Address) EIP55Address {
addr, err := NewEIP55Address(a.Hex())
if err != nil {
panic(err)
}
return addr
}
// Bytes returns the raw bytes
func (a EIP55Address) Bytes() []byte { return a.Address().Bytes() }
// Big returns a big.Int representation
func (a EIP55Address) Big() *big.Int { return a.Address().Hash().Big() }
// Hash returns the Hash
func (a EIP55Address) Hash() common.Hash { return a.Address().Hash() }
// Address returns EIP55Address as a go-ethereum Address type
func (a EIP55Address) Address() common.Address { return common.HexToAddress(a.String()) }
// String implements the stringer interface and is used also by the logger.
func (a EIP55Address) String() string {
return string(a)
}
// Hex is identical to String but makes the API similar to common.Address
func (a EIP55Address) Hex() string {
return a.String()
}
// Format implements fmt.Formatter
func (a EIP55Address) Format(s fmt.State, c rune) {
_, _ = fmt.Fprint(s, a.String())
}
// UnmarshalText parses a hash from plain text
func (a *EIP55Address) UnmarshalText(input []byte) error {
var err error
*a, err = NewEIP55Address(string(input))
return err
}
// UnmarshalJSON parses a hash from a JSON string
func (a *EIP55Address) UnmarshalJSON(input []byte) error {
input = utils.RemoveQuotes(input)
return a.UnmarshalText(input)
}
// Value returns this instance serialized for database storage.
func (a EIP55Address) Value() (driver.Value, error) {
return a.Bytes(), nil
}
// Scan reads the database value and returns an instance.
func (a *EIP55Address) Scan(value interface{}) error {
switch v := value.(type) {
case string:
*a = EIP55Address(v)
case []byte:
address := common.HexToAddress("0x" + hex.EncodeToString(v))
*a = EIP55Address(address.Hex())
default:
return fmt.Errorf("unable to convert %v of %T to EIP55Address", value, value)
}
return nil
}
// IsZeroAddress determines whether the address is 0x0000... or not
func (a EIP55Address) IsZero() bool {
return a.Address() == common.Address{}
}
// EIP55AddressCollection is an array of EIP55Addresses.
type EIP55AddressCollection []EIP55Address
// Value returns this instance serialized for database storage.
func (c EIP55AddressCollection) Value() (driver.Value, error) {
// Unable to convert copy-free without unsafe:
// https://stackoverflow.com/a/48554123/639773
converted := make([]string, len(c))
for i, e := range c {
converted[i] = string(e)
}
return strings.Join(converted, ","), nil
}
// Scan reads the database value and returns an instance.
func (c *EIP55AddressCollection) Scan(value interface{}) error {
temp, ok := value.(string)
if !ok {
return fmt.Errorf("unable to convert %v of %T to EIP55AddressCollection", value, value)
}
arr := strings.Split(temp, ",")
collection := make(EIP55AddressCollection, len(arr))
for i, r := range arr {
collection[i] = EIP55Address(r)
}
*c = collection
return nil
}