forked from zksync-sdk/zksync2-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEthSigner.go
122 lines (111 loc) · 3.62 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
package zksync2
import (
"crypto/ecdsa"
"fmt"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/miguelmota/go-ethereum-hdwallet"
"github.com/pkg/errors"
)
type EthSigner interface {
GetAddress() common.Address
GetDomain() *Eip712Domain
SignHash(msg []byte) ([]byte, error)
SignTypedData(d *Eip712Domain, data EIP712TypedData) ([]byte, error)
}
type DefaultEthSigner struct {
pk *ecdsa.PrivateKey
address common.Address
domain *Eip712Domain
}
func NewEthSignerFromMnemonic(mnemonic string, chainId int64) (*DefaultEthSigner, error) {
return NewEthSignerFromMnemonicAndAccountId(mnemonic, 0, chainId)
}
func NewEthSignerFromMnemonicAndAccountId(mnemonic string, accountId uint32, chainId int64) (*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),
domain: DefaultEip712Domain(chainId),
}, nil
}
func NewEthSignerFromRawPrivateKey(rawPk []byte, chainId int64) (*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),
domain: DefaultEip712Domain(chainId),
}, nil
}
func (s *DefaultEthSigner) GetAddress() common.Address {
return s.address
}
func (s *DefaultEthSigner) GetDomain() *Eip712Domain {
return s.domain
}
func (s *DefaultEthSigner) SignTypedData(domain *Eip712Domain, data EIP712TypedData) ([]byte, error) {
// compile TypedData structure
typedData := apitypes.TypedData{
Types: apitypes.Types{
data.GetEIP712Type(): data.GetEIP712Types(),
domain.GetEIP712Type(): domain.GetEIP712Types(),
},
PrimaryType: data.GetEIP712Type(),
Domain: domain.GetEIP712Domain(),
Message: data.GetEIP712Message(),
}
hash, err := s.HashTypedData(typedData)
if err != nil {
return nil, fmt.Errorf("failed to get hash of typed data: %w", err)
}
sig, err := crypto.Sign(hash, s.pk)
if err != nil {
return nil, fmt.Errorf("failed to sign hash of typed data: %w", err)
}
if sig[64] < 27 {
sig[64] += 27
}
return sig, nil
}
func (s *DefaultEthSigner) HashTypedData(data apitypes.TypedData) ([]byte, error) {
domain, err := data.HashStruct("EIP712Domain", data.Domain.Map())
if err != nil {
return nil, fmt.Errorf("failed to get hash of typed data domain: %w", err)
}
dataHash, err := data.HashStruct(data.PrimaryType, data.Message)
if err != nil {
return nil, fmt.Errorf("failed to get hash of typed message: %w", err)
}
prefixedData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domain), string(dataHash)))
prefixedDataHash := crypto.Keccak256(prefixedData)
return prefixedDataHash, 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
}