forked from synapsecns/sanguine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchain.go
143 lines (120 loc) · 4.62 KB
/
chain.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
package simulated
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/lmittmann/w3/w3types"
"github.com/synapsecns/sanguine/ethergo/backends/simulated/multibackend"
"github.com/synapsecns/sanguine/ethergo/chain/client"
"golang.org/x/sync/errgroup"
"math/big"
)
// Client is a simulated client for a simulated backend.
type Client struct {
*multibackend.SimulatedBackend
}
// Web3Version is not implemented on this backend.
func (s Client) Web3Version(_ context.Context) (version string, err error) {
// TODO implement me
panic("cannot implement on this backend")
}
// FeeHistory is not implemented on this backend.
func (s Client) FeeHistory(_ context.Context, _ uint64, _ *big.Int, _ []float64) (*ethereum.FeeHistory, error) {
// TODO implement me
panic("cannot implement on this backend")
}
// PendingBalanceAt calls balance at since simulated backends are monotonic.
func (s Client) PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) {
//nolint: wrapcheck
return s.SimulatedBackend.BalanceAt(ctx, account, nil)
}
// PendingStorageAt gets the storage at since simulated backends cannot have non-final storage.
func (s Client) PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) {
//nolint: wrapcheck
return s.SimulatedBackend.StorageAt(ctx, account, key, nil)
}
// PendingTransactionCount always returns 0 since simulated backends cannot have pending transactions.
func (s Client) PendingTransactionCount(ctx context.Context) (uint, error) {
return 0, nil
}
// SyncProgress panics since this state is not accessible on the simulated backend.
func (s Client) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error) {
panic("not implemented")
}
// NetworkID wraps network id on underlying backend.
func (s Client) NetworkID(ctx context.Context) (*big.Int, error) {
//nolint: errwrap
return s.ChainID(ctx)
}
// ChainConfig gets the chain config for the backend.
func (s Client) ChainConfig() *params.ChainConfig {
return s.Blockchain().Config()
}
// ChainID returns the chain id.
func (s Client) ChainID(_ context.Context) (*big.Int, error) {
return s.ChainConfig().ChainID, nil
}
// Close closes the connection with the chain.
func (s Client) Close() {
// do nothing
}
// CallContext panics here to bypass interface requirements for testing.
func (s Client) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {
panic("CallContext is not supported on the simulated backend")
}
// BatchCallContext panics here to bypass interface requirements for testing.
func (s Client) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error {
panic("BatchCallContext is not supported on the simulated backend")
}
// BatchContext panics here to bypass interface requirements for testing.
func (s Client) BatchContext(ctx context.Context, calls ...w3types.Caller) error {
panic("BatchCallContext is not supported on the simulated backend")
}
// BlockNumber gets the latest block number.
func (s Client) BlockNumber(ctx context.Context) (uint64, error) {
latestBlock, err := s.BlockByNumber(ctx, nil)
if err != nil {
return 0, fmt.Errorf("could not get block: %w", err)
}
return latestBlock.NumberU64(), nil
}
// SuggestGasPrice follows the rpc behavior for SuggestGasPrice. Because we rely
// on the legacy behavior of eth_sendTransaction and don't utilize the base fee (we need to figure
// out a way to do this cross-chain), we emulate the rpc eth_sugestGasPrice behavior here.
// TODO: find out if not emulating the rpc here is intended behavior on geth's end, patch via pr if not.
func (s Client) SuggestGasPrice(ctx context.Context) (gasPrice *big.Int, err error) {
g, ctx := errgroup.WithContext(ctx)
var (
// baseFee is the base fee to add to the gas price estimation
baseFee *big.Int
// estimatedPrice is the gas price estimate
estimatedPrice *big.Int
)
g.Go(func() error {
latestBlock, err := s.BlockByNumber(ctx, nil)
if err != nil {
return fmt.Errorf("could not get latest block to add to base fee: %w", err)
}
baseFee = latestBlock.BaseFee()
return nil
})
g.Go(func() error {
estimatedPrice, err = s.SimulatedBackend.SuggestGasPrice(ctx)
if err != nil {
return fmt.Errorf("could not get suggested gas price")
}
return nil
})
err = g.Wait()
if err != nil {
return nil, fmt.Errorf("could not get gas price: %w", err)
}
if baseFee == nil {
return estimatedPrice, nil
}
return big.NewInt(0).Add(estimatedPrice, baseFee), nil
}
var _ client.EVMClient = &Client{}