-
Notifications
You must be signed in to change notification settings - Fork 7
/
EthSigner.go
177 lines (161 loc) · 5.26 KB
/
EthSigner.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
package zksync
import (
"crypto/ecdsa"
"encoding/hex"
"fmt"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/miguelmota/go-ethereum-hdwallet"
"github.com/pkg/errors"
"math/big"
"strings"
)
type EthSigner interface {
GetAddress() common.Address
SignMessage([]byte) ([]byte, error)
SignHash(msg []byte) ([]byte, error)
SignAuth(txData *ChangePubKey) (*ChangePubKeyECDSA, error)
SignTransaction(tx ZksTransaction, nonce uint32, token *Token, fee *big.Int) (*EthSignature, error)
SignBatch(txs []ZksTransaction, nonce uint32, token *Token, fee *big.Int) (*EthSignature, error)
SignOrder(order *Order, sell, buy *Token) (*EthSignature, error)
}
type DefaultEthSigner struct {
pk *ecdsa.PrivateKey
address common.Address
}
func NewEthSignerFromMnemonic(mnemonic string) (*DefaultEthSigner, error) {
return NewEthSignerFromMnemonicAndAccountId(mnemonic, 0)
}
func NewEthSignerFromMnemonicAndAccountId(mnemonic string, accountId uint32) (*DefaultEthSigner, error) {
wallet, err := hdwallet.NewFromMnemonic(mnemonic)
if err != nil {
return nil, errors.Wrap(err, "failed to create HD wallet from mnemonic")
}
path, err := accounts.ParseDerivationPath(fmt.Sprintf("m/44'/60'/0'/0/%d", accountId))
if err != nil {
return nil, errors.Wrap(err, "failed to parse derivation path")
}
account, err := wallet.Derive(path, true)
if err != nil {
return nil, errors.Wrap(err, "failed to derive account from HD wallet")
}
pk, err := wallet.PrivateKey(account)
if err != nil {
return nil, errors.Wrap(err, "failed to get account's private key from HD wallet")
}
pub := pk.Public().(*ecdsa.PublicKey)
return &DefaultEthSigner{
pk: pk,
address: crypto.PubkeyToAddress(*pub),
}, nil
}
func NewEthSignerFromRawPrivateKey(rawPk []byte) (*DefaultEthSigner, error) {
pk, err := crypto.ToECDSA(rawPk)
if err != nil {
return nil, errors.Wrap(err, "invalid raw private key")
}
pub := pk.Public().(*ecdsa.PublicKey)
return &DefaultEthSigner{
pk: pk,
address: crypto.PubkeyToAddress(*pub),
}, nil
}
func (s *DefaultEthSigner) GetAddress() common.Address {
return s.address
}
func (s *DefaultEthSigner) SignMessage(msg []byte) ([]byte, error) {
sig, err := s.SignHash(accounts.TextHash(msg)) // prefixed
if err != nil {
return nil, errors.Wrap(err, "failed to sign message")
}
// set recovery byte to 27/28
if len(sig) == 65 {
sig[64] += 27
}
return sig, nil
}
func (s *DefaultEthSigner) SignHash(msg []byte) ([]byte, error) {
sig, err := crypto.Sign(msg, s.pk)
if err != nil {
return nil, errors.Wrap(err, "failed to sign hash")
}
return sig, nil
}
func (s *DefaultEthSigner) SignAuth(txData *ChangePubKey) (*ChangePubKeyECDSA, error) {
auth := &ChangePubKeyECDSA{
Type: ChangePubKeyAuthTypeECDSA,
EthSignature: "",
BatchHash: "0x" + hex.EncodeToString(make([]byte, 32)),
}
txData.EthAuthData = auth
msg, err := GetChangePubKeyData(txData)
if err != nil {
return nil, errors.Wrap(err, "failed to get ChangePubKey data for sign")
}
sig, err := s.SignMessage(msg)
if err != nil {
return nil, errors.Wrap(err, "failed to sign ChangePubKeyECDSA msg")
}
auth.EthSignature = "0x" + hex.EncodeToString(sig)
return auth, nil
}
func (s *DefaultEthSigner) SignTransaction(tx ZksTransaction, nonce uint32, token *Token, fee *big.Int) (*EthSignature, error) {
msg, err := GetSignMessage(tx, token, fee)
if err != nil {
return nil, errors.Wrap(err, "failed to get sign message for tx")
}
msg += "\n" + GetNonceMessagePart(nonce)
sig, err := s.SignMessage([]byte(msg))
if err != nil {
return nil, errors.Wrap(err, "failed to sign tx")
}
return &EthSignature{
Type: EthSignatureTypeEth,
Signature: "0x" + hex.EncodeToString(sig),
}, nil
}
func (s *DefaultEthSigner) SignBatch(txs []ZksTransaction, nonce uint32, token *Token, fee *big.Int) (*EthSignature, error) {
batchMsgs := make([]string, 0, len(txs))
for _, tx := range txs {
msg, err := GetSignMessage(tx, token, fee)
if err != nil {
return nil, errors.Wrap(err, "failed to get sign message for one of txs")
}
batchMsgs = append(batchMsgs, msg)
}
batchMsg := strings.Join(batchMsgs, "\n")
batchMsg += "\n" + GetNonceMessagePart(nonce)
sig, err := s.SignMessage([]byte(batchMsg))
if err != nil {
return nil, errors.Wrap(err, "failed to sign batch of txs")
}
return &EthSignature{
Type: EthSignatureTypeEth,
Signature: "0x" + hex.EncodeToString(sig),
}, nil
}
func (s *DefaultEthSigner) SignOrder(order *Order, sell, buy *Token) (*EthSignature, error) {
msg, err := GetOrderMessagePart(order.RecipientAddress.String(), order.Amount, sell, buy, order.Ratio)
if err != nil {
return nil, errors.Wrap(err, "failed to get Order message part")
}
msg += "\n" + GetNonceMessagePart(order.Nonce)
sig, err := s.SignMessage([]byte(msg))
if err != nil {
return nil, errors.Wrap(err, "failed to sign Order")
}
return &EthSignature{
Type: EthSignatureTypeEth,
Signature: "0x" + hex.EncodeToString(sig),
}, nil
}
type EthSignatureType string
const (
EthSignatureTypeEth EthSignatureType = "EthereumSignature"
EthSignatureTypeEIP1271 EthSignatureType = "EIP1271Signature"
)
type EthSignature struct {
Type EthSignatureType `json:"type"`
Signature string `json:"signature"`
}