Skip to content

Commit bfd5914

Browse files
committed
Add support for signing EIP-712 typed data for both Ledger and Trezor devices
1 parent b1eb33c commit bfd5914

20 files changed

+8629
-4233
lines changed

accounts/usbwallet/data_type.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright 2017 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package usbwallet
18+
19+
import (
20+
"fmt"
21+
"regexp"
22+
"strconv"
23+
"strings"
24+
25+
"github.com/ethereum/go-ethereum/signer/core/apitypes"
26+
)
27+
28+
type dataType byte
29+
30+
const (
31+
CustomType dataType = iota
32+
IntType
33+
UintType
34+
AddressType
35+
BoolType
36+
StringType
37+
FixedBytesType
38+
BytesType
39+
)
40+
41+
var nameToType = map[string]dataType{
42+
"int": IntType,
43+
"uint": UintType,
44+
"address": AddressType,
45+
"bool": BoolType,
46+
"string": StringType,
47+
"bytes": BytesType,
48+
}
49+
50+
func parseType(data apitypes.TypedData, field apitypes.Type) (dt dataType, name string, byteLength int, arrayLevels []*int, err error) {
51+
name = strings.TrimSpace(field.Type)
52+
arrayLengths := regexp.MustCompile(`\[(\d*)]`).FindAllStringSubmatch(name, -1)
53+
if len(arrayLengths) > 0 {
54+
arrayLevels = make([]*int, len(arrayLengths))
55+
for i, arrayLength := range arrayLengths {
56+
if len(arrayLength[1]) == 0 {
57+
arrayLevels[i] = nil // nil means dynamic length
58+
} else {
59+
length, _ := strconv.Atoi(arrayLength[1]) // guaranteed to be a digit, ignore error
60+
arrayLevels[i] = &length
61+
}
62+
}
63+
name = name[0:strings.Index(name, "[")]
64+
}
65+
if data.Types[name] != nil {
66+
dt = CustomType
67+
return
68+
}
69+
70+
matches := regexp.MustCompile(`^(.+?)(\d*)$`).FindStringSubmatch(name)
71+
name = matches[1]
72+
lengthStr := matches[2]
73+
74+
var ok bool
75+
if dt, ok = nameToType[name]; !ok {
76+
err = fmt.Errorf("unknown type: %s", field.Type)
77+
return
78+
}
79+
80+
byteLength, _ = strconv.Atoi(lengthStr)
81+
if dt == UintType || dt == IntType {
82+
if lengthStr == "" {
83+
byteLength = 32
84+
} else if byteLength%8 != 0 {
85+
err = fmt.Errorf("invalid length for %s: %s", field.Type, lengthStr)
86+
return
87+
} else {
88+
byteLength /= 8
89+
}
90+
} else if lengthStr != "" {
91+
if dt == BytesType {
92+
dt = FixedBytesType
93+
} else {
94+
err = fmt.Errorf("invalid type: %s", field.Type)
95+
return
96+
}
97+
} else if dt == AddressType {
98+
byteLength = 20 // address is always 20 bytes
99+
}
100+
if lengthStr != "" && (byteLength < 1 || byteLength > 32) {
101+
err = fmt.Errorf("invalid length for %s: %s", field.Type, lengthStr)
102+
return
103+
}
104+
105+
return
106+
}

accounts/usbwallet/hub.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
"github.com/ethereum/go-ethereum/accounts"
2727
"github.com/ethereum/go-ethereum/event"
2828
"github.com/ethereum/go-ethereum/log"
29-
"github.com/karalabe/hid"
29+
"github.com/karalabe/usb"
3030
)
3131

3232
// LedgerScheme is the protocol scheme prefixing account and wallet URLs.
@@ -105,7 +105,7 @@ func NewTrezorHubWithWebUSB() (*Hub, error) {
105105

106106
// newHub creates a new hardware wallet manager for generic USB devices.
107107
func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) {
108-
if !hid.Supported() {
108+
if !usb.Supported() {
109109
return nil, errors.New("unsupported platform")
110110
}
111111
hub := &Hub{
@@ -151,7 +151,7 @@ func (hub *Hub) refreshWallets() {
151151
return
152152
}
153153
// Retrieve the current list of USB wallet devices
154-
var devices []hid.DeviceInfo
154+
var devices []usb.DeviceInfo
155155

156156
if runtime.GOOS == "linux" {
157157
// hidapi on Linux opens the device during enumeration to retrieve some infos,
@@ -166,7 +166,7 @@ func (hub *Hub) refreshWallets() {
166166
return
167167
}
168168
}
169-
infos, err := hid.Enumerate(hub.vendorID, 0)
169+
infos, err := usb.Enumerate(hub.vendorID, 0)
170170
if err != nil {
171171
failcount := hub.enumFails.Add(1)
172172
if runtime.GOOS == "linux" {

0 commit comments

Comments
 (0)