forked from zksync-sdk/zksync2-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
EthProvider.go
122 lines (111 loc) · 3.92 KB
/
EthProvider.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 (
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
"github.com/zksync-sdk/zksync2-go/contracts/ERC20"
"github.com/zksync-sdk/zksync2-go/contracts/IL1Bridge"
"math/big"
)
var (
MaxApproveAmount = big.NewInt(0).Sub(big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1))
DefaultThreshold = big.NewInt(0).Exp(big.NewInt(2), big.NewInt(255), nil)
)
type EthProvider interface {
ApproveDeposit(token *Token, limit *big.Int, options *GasOptions) (*types.Transaction, error)
IsDepositApproved(token *Token, to common.Address, threshold *big.Int) (bool, error)
Deposit(token *Token, amount *big.Int, address common.Address, options *GasOptions) (*types.Transaction, error)
}
func NewDefaultEthProvider(rpcClient *rpc.Client, auth *bind.TransactOpts,
l1EthBridgeAddress, l1ERC20BridgeAddress common.Address) (*DefaultEthProvider, error) {
ec := ethclient.NewClient(rpcClient)
l1EthBridge, err := IL1Bridge.NewIL1Bridge(l1EthBridgeAddress, ec)
if err != nil {
return nil, fmt.Errorf("failed to load L1EthBridge: %w", err)
}
l1ERC20Bridge, err := IL1Bridge.NewIL1Bridge(l1ERC20BridgeAddress, ec)
if err != nil {
return nil, fmt.Errorf("failed to load L1ERC20Bridge: %w", err)
}
return &DefaultEthProvider{
rc: rpcClient,
ec: ec,
auth: auth,
l1EthBridgeAddress: l1EthBridgeAddress,
l1ERC20BridgeAddress: l1ERC20BridgeAddress,
l1EthBridge: l1EthBridge,
l1ERC20Bridge: l1ERC20Bridge,
}, nil
}
type DefaultEthProvider struct {
rc *rpc.Client
ec *ethclient.Client
auth *bind.TransactOpts
l1EthBridgeAddress common.Address
l1ERC20BridgeAddress common.Address
l1EthBridge *IL1Bridge.IL1Bridge
l1ERC20Bridge *IL1Bridge.IL1Bridge
}
type GasOptions struct {
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
}
func (p *DefaultEthProvider) ApproveDeposit(token *Token, limit *big.Int, options *GasOptions) (*types.Transaction, error) {
if token == nil {
token = CreateETH()
}
auth := p.getAuth(options)
erc20, err := ERC20.NewERC20(token.L1Address, p.ec)
if err != nil {
return nil, fmt.Errorf("failed to load ERC20: %w", err)
}
if limit == nil || len(limit.Bits()) == 0 {
limit = MaxApproveAmount
}
return erc20.Approve(auth, p.l1ERC20BridgeAddress, limit)
}
func (p *DefaultEthProvider) IsDepositApproved(token *Token, to common.Address, threshold *big.Int) (bool, error) {
if token == nil {
token = CreateETH()
}
erc20, err := ERC20.NewERC20(token.L1Address, p.ec)
if err != nil {
return false, fmt.Errorf("failed to load ERC20: %w", err)
}
if threshold == nil || len(threshold.Bits()) == 0 {
threshold = DefaultThreshold
}
res, err := erc20.Allowance(&bind.CallOpts{}, to, p.l1ERC20BridgeAddress)
if err != nil {
return false, fmt.Errorf("failed to query Allowance: %w", err)
}
return res.Cmp(threshold) >= 0, nil
}
func (p *DefaultEthProvider) Deposit(token *Token, amount *big.Int, address common.Address, options *GasOptions) (*types.Transaction, error) {
if token == nil {
token = CreateETH()
}
auth := p.getAuth(options)
if token.IsETH() {
auth.Value = amount
return p.l1EthBridge.Deposit(auth, address, EthAddress, amount)
} else {
auth.Value = nil
return p.l1ERC20Bridge.Deposit(auth, address, token.L1Address, amount)
}
}
// getAuth make a new copy of origin TransactOpts to be used safely for each call
func (p *DefaultEthProvider) getAuth(options *GasOptions) *bind.TransactOpts {
newAuth := &bind.TransactOpts{
From: p.auth.From,
Signer: p.auth.Signer,
}
if options != nil {
newAuth.GasPrice = options.GasPrice
newAuth.GasLimit = options.GasLimit
}
return newAuth
}