forked from umbracle/ethgo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
signer.go
138 lines (113 loc) · 2.77 KB
/
signer.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
package wallet
import (
"github.com/deep-nl/ethgo/core"
"math/big"
"github.com/umbracle/fastrlp"
)
type Signer interface {
// RecoverSender returns the sender to the transaction
RecoverSender(tx *core.Transaction) (core.Address, error)
// SignTx signs a transaction
SignTx(tx *core.Transaction, key core.Key) (*core.Transaction, error)
}
type EIP1155Signer struct {
chainID uint64
}
func NewEIP155Signer(chainID uint64) *EIP1155Signer {
return &EIP1155Signer{chainID: chainID}
}
func (e *EIP1155Signer) RecoverSender(tx *core.Transaction) (core.Address, error) {
v := new(big.Int).SetBytes(tx.V).Uint64()
v -= e.chainID * 2
v -= 8
v -= 27
sig, err := encodeSignature(tx.R, tx.S, byte(v))
if err != nil {
return core.Address{}, err
}
addr, err := Ecrecover(signHash(tx, e.chainID), sig)
if err != nil {
return core.Address{}, err
}
return addr, nil
}
func trimBytesZeros(b []byte) []byte {
var i int
for i = 0; i < len(b); i++ {
if b[i] != 0x0 {
break
}
}
return b[i:]
}
func (e *EIP1155Signer) SignTx(tx *core.Transaction, key core.Key) (*core.Transaction, error) {
hash := signHash(tx, e.chainID)
sig, err := key.Sign(hash)
if err != nil {
return nil, err
}
vv := uint64(sig[64])
if tx.Type == 0 {
vv = vv + 35 + e.chainID*2
}
tx.R = trimBytesZeros(sig[:32])
tx.S = trimBytesZeros(sig[32:64])
tx.V = new(big.Int).SetUint64(vv).Bytes()
return tx, nil
}
func signHash(tx *core.Transaction, chainID uint64) []byte {
a := fastrlp.DefaultArenaPool.Get()
v := a.NewArray()
if tx.Type != 0 {
// either dynamic and access type
v.Set(a.NewBigInt(tx.ChainID))
}
v.Set(a.NewUint(tx.Nonce))
if tx.Type == core.TransactionDynamicFee {
// dynamic fee uses
v.Set(a.NewBigInt(tx.MaxPriorityFeePerGas))
v.Set(a.NewBigInt(tx.MaxFeePerGas))
} else {
// legacy and access type use gas price
v.Set(a.NewUint(tx.GasPrice))
}
v.Set(a.NewUint(tx.Gas))
if tx.To == nil {
v.Set(a.NewNull())
} else {
v.Set(a.NewCopyBytes((*tx.To)[:]))
}
v.Set(a.NewBigInt(tx.Value))
v.Set(a.NewCopyBytes(tx.Input))
if tx.Type != 0 {
// either dynamic and access type
accessList, err := tx.AccessList.MarshalRLPWith(a)
if err != nil {
panic(err)
}
v.Set(accessList)
}
// EIP155
if chainID != 0 && tx.Type == 0 {
v.Set(a.NewUint(chainID))
v.Set(a.NewUint(0))
v.Set(a.NewUint(0))
}
dst := v.MarshalTo(nil)
// append the tx type byte
if tx.Type == core.TransactionAccessList {
dst = append([]byte{0x1}, dst...)
} else if tx.Type == core.TransactionDynamicFee {
dst = append([]byte{0x2}, dst...)
}
hash := core.Keccak256(dst)
fastrlp.DefaultArenaPool.Put(a)
return hash
}
func encodeSignature(R, S []byte, V byte) ([]byte, error) {
sig := make([]byte, 65)
copy(sig[32-len(R):32], R)
copy(sig[64-len(S):64], S)
sig[64] = V
return sig, nil
}