|
10 | 10 | from hexbytes import HexBytes |
11 | 11 | from web3 import Web3 |
12 | 12 | from web3.contract import Contract, ContractFunction |
13 | | -from web3.types import TxParams |
| 13 | +from web3.types import TxParams, Wei |
14 | 14 |
|
15 | 15 | from oracle.keeper.typings import Parameters |
16 | 16 | from oracle.oracle.distributor.common.types import DistributorVote |
@@ -183,15 +183,71 @@ def get_transaction_params(web3_client: Web3) -> TxParams: |
183 | 183 | ) |
184 | 184 |
|
185 | 185 |
|
186 | | -def submit_update(web3_client: Web3, function_call: ContractFunction) -> None: |
187 | | - tx_params = get_transaction_params(web3_client) |
188 | | - estimated_gas = function_call.estimateGas(tx_params) |
| 186 | +def get_high_priority_tx_params(web3_client) -> {}: |
| 187 | + """ |
| 188 | + `maxPriorityFeePerGas <= maxFeePerGas` must be fulfilled |
| 189 | + Because of that when increasing `maxPriorityFeePerGas` I have to adjust `maxFeePerGas`. |
| 190 | + See https://eips.ethereum.org/EIPS/eip-1559 for details. |
| 191 | + """ |
| 192 | + tx_params = {} |
| 193 | + |
| 194 | + max_priority_fee_per_gas = _calc_high_priority_fee(web3_client) |
| 195 | + |
| 196 | + # Reference: `_max_fee_per_gas` in web3/_utils/async_transactions.py |
| 197 | + block = web3_client.eth.get_block("latest") |
| 198 | + max_fee_per_gas = Wei(max_priority_fee_per_gas + (2 * block["baseFeePerGas"])) |
| 199 | + |
| 200 | + tx_params["maxPriorityFeePerGas"] = max_priority_fee_per_gas |
| 201 | + tx_params["maxFeePerGas"] = max_fee_per_gas |
| 202 | + logger.debug("tx_params %s", tx_params) |
| 203 | + |
| 204 | + return tx_params |
| 205 | + |
189 | 206 |
|
190 | | - # add 10% margin to the estimated gas |
191 | | - tx_params["gas"] = int(estimated_gas * 0.1) + estimated_gas |
| 207 | +def _calc_high_priority_fee(web3_client) -> Wei: |
| 208 | + """ |
| 209 | + reference: "high" priority value from https://etherscan.io/gastracker |
| 210 | + """ |
| 211 | + num_blocks = 10 |
| 212 | + percentile = 80 |
| 213 | + history = web3_client.eth.fee_history(num_blocks, "pending", [percentile]) |
| 214 | + validator_rewards = [r[0] for r in history["reward"]] |
| 215 | + mean_reward = int(sum(validator_rewards) / len(validator_rewards)) |
| 216 | + |
| 217 | + # prettify `mean_reward` |
| 218 | + # same as `round(value, 1)` if value was in gwei |
| 219 | + if mean_reward > Web3.toWei(1, "gwei"): |
| 220 | + mean_reward = round(mean_reward, -8) |
| 221 | + |
| 222 | + return Wei(mean_reward) |
| 223 | + |
| 224 | + |
| 225 | +def submit_update(web3_client: Web3, function_call: ContractFunction) -> None: |
| 226 | + ATTEMPTS_WITH_DEFAULT_GAS = 5 |
| 227 | + for i in range(ATTEMPTS_WITH_DEFAULT_GAS): |
| 228 | + try: |
| 229 | + tx_params = get_transaction_params(web3_client) |
| 230 | + estimated_gas = function_call.estimateGas(tx_params) |
| 231 | + |
| 232 | + # add 10% margin to the estimated gas |
| 233 | + tx_params["gas"] = int(estimated_gas * 0.1) + estimated_gas |
| 234 | + |
| 235 | + # execute transaction |
| 236 | + tx_hash = function_call.transact(tx_params) |
| 237 | + except ValueError as e: |
| 238 | + # Handle only FeeTooLow error |
| 239 | + code = None |
| 240 | + if e.args and isinstance(e.args[0], dict): |
| 241 | + code = e.args[0].get("code") |
| 242 | + if not code or code != -32010: |
| 243 | + raise e |
| 244 | + logger.exception(e) |
| 245 | + if i < ATTEMPTS_WITH_DEFAULT_GAS - 1: # skip last sleep |
| 246 | + time.sleep(NETWORK_CONFIG.SECONDS_PER_BLOCK) |
| 247 | + else: |
| 248 | + tx_params = get_high_priority_tx_params(web3_client) |
| 249 | + tx_hash = function_call.transact(tx_params) |
192 | 250 |
|
193 | | - # execute transaction |
194 | | - tx_hash = function_call.transact(tx_params) |
195 | 251 | logger.info(f"Submitted transaction: {Web3.toHex(tx_hash)}") |
196 | 252 | wait_for_transaction(web3_client, tx_hash) |
197 | 253 |
|
|
0 commit comments