@@ -46,6 +46,16 @@ class Uniswap:
46
46
Wrapper around Uniswap contracts.
47
47
"""
48
48
49
+ address :AddressLike
50
+ version :int
51
+
52
+ w3 :Web3
53
+ netid :int
54
+ netname :str
55
+
56
+ default_slippage :float
57
+ use_estimate_gas :bool
58
+
49
59
def __init__ (
50
60
self ,
51
61
address :Union [AddressLike ,str ,None ],
@@ -54,6 +64,8 @@ def __init__(
54
64
web3 :Web3 = None ,
55
65
version :int = 1 ,
56
66
default_slippage :float = 0.01 ,
67
+ use_estimate_gas :bool = True ,
68
+ # use_eip1559: bool = True,
57
69
factory_contract_addr :str = None ,
58
70
router_contract_addr :str = None ,
59
71
)-> None :
@@ -67,7 +79,7 @@ def __init__(
67
79
:param factory_contract_addr: Can be optionally set to override the address of the factory contract.
68
80
:param router_contract_addr: Can be optionally set to override the address of the router contract (v2 only).
69
81
"""
70
- self .address : AddressLike = _str_to_addr (
82
+ self .address = _str_to_addr (
71
83
address or "0x0000000000000000000000000000000000000000"
72
84
)
73
85
self .private_key = (
@@ -79,22 +91,23 @@ def __init__(
79
91
80
92
# TODO: Write tests for slippage
81
93
self .default_slippage = default_slippage
94
+ self .use_estimate_gas = use_estimate_gas
82
95
83
96
if web3 :
84
97
self .w3 = web3
85
98
else :
86
99
# Initialize web3. Extra provider for testing.
87
- self . provider = provider or os . environ [ "PROVIDER" ]
88
- self . w3 = Web3 (
89
- Web3 .HTTPProvider (self . provider ,request_kwargs = {"timeout" :60 })
90
- )
91
-
92
- netid = int (self .w3 .net .version )
93
- if netid in _netid_to_name :
94
- self .network = _netid_to_name [netid ]
100
+ if not provider :
101
+ provider = os . environ [ "PROVIDER" ]
102
+ self . w3 = Web3 ( Web3 .HTTPProvider (provider ,request_kwargs = {"timeout" :60 }) )
103
+
104
+ # Cache netid to avoid extra RPC calls
105
+ self . netid = int (self .w3 .net .version )
106
+ if self . netid in _netid_to_name :
107
+ self .netname = _netid_to_name [self . netid ]
95
108
else :
96
- raise Exception (f"Unknown netid:{ netid } " )
97
- logger .info (f"Using{ self .w3 } ('{ self .network } ' )" )
109
+ raise Exception (f"Unknown netid:{ self . netid } " )
110
+ logger .info (f"Using{ self .w3 } ('{ self .netname } ', netid: { self . netid } )" )
98
111
99
112
self .last_nonce :Nonce = self .w3 .eth .get_transaction_count (self .address )
100
113
@@ -103,14 +116,14 @@ def __init__(
103
116
# max_approval_check checks that current approval is above a reasonable number
104
117
# The program cannot check for max_approval each time because it decreases
105
118
# with each trade.
106
- self . max_approval_hex = f"0x{ 64 * 'f' } "
107
- self .max_approval_int = int (self . max_approval_hex ,16 )
108
- self . max_approval_check_hex = f"0x{ 15 * '0' } { 49 * 'f' } "
109
- self .max_approval_check_int = int (self . max_approval_check_hex ,16 )
119
+ max_approval_hex = f"0x{ 64 * 'f' } "
120
+ self .max_approval_int = int (max_approval_hex ,16 )
121
+ max_approval_check_hex = f"0x{ 15 * '0' } { 49 * 'f' } "
122
+ self .max_approval_check_int = int (max_approval_check_hex ,16 )
110
123
111
124
if self .version == 1 :
112
125
if factory_contract_addr is None :
113
- factory_contract_addr = _factory_contract_addresses_v1 [self .network ]
126
+ factory_contract_addr = _factory_contract_addresses_v1 [self .netname ]
114
127
115
128
self .factory_contract = _load_contract (
116
129
self .w3 ,
@@ -119,11 +132,11 @@ def __init__(
119
132
)
120
133
elif self .version == 2 :
121
134
if router_contract_addr is None :
122
- router_contract_addr = _router_contract_addresses_v2 [self .network ]
135
+ router_contract_addr = _router_contract_addresses_v2 [self .netname ]
123
136
self .router_address :AddressLike = _str_to_addr (router_contract_addr )
124
137
125
138
if factory_contract_addr is None :
126
- factory_contract_addr = _factory_contract_addresses_v2 [self .network ]
139
+ factory_contract_addr = _factory_contract_addresses_v2 [self .netname ]
127
140
self .factory_contract = _load_contract (
128
141
self .w3 ,
129
142
abi_name = "uniswap-v2/factory" ,
@@ -1092,8 +1105,19 @@ def _build_and_send_tx(
1092
1105
if not tx_params :
1093
1106
tx_params = self ._get_tx_params ()
1094
1107
transaction = function .buildTransaction (tx_params )
1095
- # Uniswap3 uses 20% margin for transactions
1096
- transaction ["gas" ]= Wei (int (self .w3 .eth .estimate_gas (transaction )* 1.2 ))
1108
+
1109
+ if "gas" not in tx_params :
1110
+ # `use_estimate_gas` needs to be True for networks like Arbitrum (can't assume 250000 gas),
1111
+ # but it breaks tests for unknown reasons because estimateGas takes forever on some tx's.
1112
+ # Maybe an issue with ganache? (got GC warnings once...)
1113
+ if self .use_estimate_gas :
1114
+ # The Uniswap V3 UI uses 20% margin for transactions
1115
+ transaction ["gas" ]= Wei (
1116
+ int (self .w3 .eth .estimate_gas (transaction )* 1.2 )
1117
+ )
1118
+ else :
1119
+ transaction ["gas" ]= Wei (250000 )
1120
+
1097
1121
signed_txn = self .w3 .eth .account .sign_transaction (
1098
1122
transaction ,private_key = self .private_key
1099
1123
)
@@ -1105,15 +1129,18 @@ def _build_and_send_tx(
1105
1129
logger .debug (f"nonce:{ tx_params ['nonce' ]} " )
1106
1130
self .last_nonce = Nonce (tx_params ["nonce" ]+ 1 )
1107
1131
1108
- def _get_tx_params (self ,value :Wei = Wei (0 ))-> TxParams :
1132
+ def _get_tx_params (self ,value :Wei = Wei (0 ), gas : Wei = None )-> TxParams :
1109
1133
"""Get generic transaction parameters."""
1110
- return {
1134
+ params : TxParams = {
1111
1135
"from" :_addr_to_str (self .address ),
1112
1136
"value" :value ,
1113
1137
"nonce" :max (
1114
1138
self .last_nonce ,self .w3 .eth .get_transaction_count (self .address )
1115
1139
),
1116
1140
}
1141
+ if gas :
1142
+ params ["gas" ]= gas
1143
+ return params
1117
1144
1118
1145
# ------ Price Calculation Utils ---------------------------------------------------
1119
1146
def _calculate_max_input_token (
@@ -1344,14 +1371,12 @@ def _get_token_addresses(self) -> Dict[str, ChecksumAddress]:
1344
1371
Returns a dict with addresses for tokens for the current net.
1345
1372
Used in testing.
1346
1373
"""
1347
- netid = int (self .w3 .net .version )
1348
- netname = _netid_to_name [netid ]
1349
- if netname == "mainnet" :
1374
+ if self .netname == "mainnet" :
1350
1375
return tokens
1351
- elif netname == "rinkeby" :
1376
+ elif self . netname == "rinkeby" :
1352
1377
return tokens_rinkeby
1353
1378
else :
1354
- raise Exception (f"Unknown net '{ netname } '" )
1379
+ raise Exception (f"Unknown net '{ self . netname } '" )
1355
1380
1356
1381
# ---- Old v1 utils ----
1357
1382