-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathwallet.go
More file actions
139 lines (121 loc) · 3.6 KB
/
Copy pathwallet.go
File metadata and controls
139 lines (121 loc) · 3.6 KB
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
package api
import (
"context"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rpc"
evmEmulator "github.com/onflow/flow-go/fvm/evm/emulator"
"github.com/onflow/flow-evm-gateway/config"
ethTypes "github.com/onflow/flow-evm-gateway/eth/types"
)
type WalletAPI struct {
net *BlockChainAPI
config config.Config
}
func NewWalletAPI(config config.Config, net *BlockChainAPI) *WalletAPI {
return &WalletAPI{
net: net,
config: config,
}
}
// Accounts returns the collection of accounts this node manages.
func (w *WalletAPI) Accounts() ([]common.Address, error) {
return []common.Address{
crypto.PubkeyToAddress(w.config.WalletKey.PublicKey),
}, nil
}
// Sign calculates an ECDSA signature for:
// keccak256("\x19Ethereum Signed Message:\n" + len(message) + message).
//
// Note, the produced signature conforms to the secp256k1 curve R, S and V values,
// where the V value will be 27 or 28 for legacy reasons.
//
// The account associated with addr must be unlocked.
//
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
func (w *WalletAPI) Sign(
addr common.Address,
data hexutil.Bytes,
) (hexutil.Bytes, error) {
// Transform the given message to the following format:
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message})
hash := accounts.TextHash(data)
// Sign the hash using plain ECDSA operations
signature, err := crypto.Sign(hash, w.config.WalletKey)
if err == nil {
// Transform V from 0/1 to 27/28 according to the yellow paper
signature[64] += 27
}
return signature, err
}
// SignTransaction will sign the given transaction with the from account.
// The node needs to have the private key of the account corresponding with
// the given from address and it needs to be unlocked.
func (w *WalletAPI) SignTransaction(
ctx context.Context,
args ethTypes.TransactionArgs,
) (*ethTypes.SignTransactionResult, error) {
if args.Gas == nil {
return nil, errors.New("gas not specified")
}
if args.GasPrice == nil && (args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil) {
return nil, errors.New("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas")
}
accounts, err := w.Accounts()
if err != nil {
return nil, err
}
from := accounts[0]
nonce := uint64(0)
if args.Nonce != nil {
nonce = uint64(*args.Nonce)
} else {
num := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
n, err := w.net.GetTransactionCount(ctx, from, num)
if err != nil {
return nil, err
}
nonce = uint64(*n)
}
var data []byte
if args.Data != nil {
data = *args.Data
}
tx := types.NewTx(&types.LegacyTx{
Nonce: nonce,
To: args.To,
Value: args.Value.ToInt(),
Gas: uint64(*args.Gas),
GasPrice: args.GasPrice.ToInt(),
Data: data,
})
signed, err := types.SignTx(tx, evmEmulator.GetDefaultSigner(), w.config.WalletKey)
if err != nil {
return nil, fmt.Errorf("error signing EVM transaction: %w", err)
}
raw, err := signed.MarshalBinary()
if err != nil {
return nil, err
}
return ðTypes.SignTransactionResult{
Raw: raw,
Tx: tx,
}, nil
}
// SendTransaction creates a transaction for the given argument, sign it
// and submit it to the transaction pool.
func (w *WalletAPI) SendTransaction(
ctx context.Context,
args ethTypes.TransactionArgs,
) (common.Hash, error) {
signed, err := w.SignTransaction(ctx, args)
if err != nil {
return common.Hash{}, err
}
return w.net.SendRawTransaction(ctx, signed.Raw)
}