Skip to content

Commit

Permalink
Merge pull request #759 from valory-xyz/fix/pricing
Browse files Browse the repository at this point in the history
Improve the EIP1559 strategy
  • Loading branch information
Adamantios authored Sep 24, 2024
2 parents 3a0a6f3 + 39bec05 commit 4cd5f40
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 64 deletions.
27 changes: 9 additions & 18 deletions docs/api/plugins/aea_ledger_ethereum/ethereum.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,17 @@ percentage

gwei

<a id="plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.wei_to_gwei"></a>
<a id="plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.to_eth_unit"></a>

#### wei`_`to`_`gwei
#### to`_`eth`_`unit

```python
def wei_to_gwei(number: Type[int]) -> Union[int, decimal.Decimal]
def to_eth_unit(number: Union[int, float, str, decimal.Decimal],
unit_in: str = DEFAULT_CURRENCY_DENOM,
unit_out: str = GWEI) -> Union[int, Wei, decimal.Decimal]
```

Covert WEI to GWEI

<a id="plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.round_to_whole_gwei"></a>

#### round`_`to`_`whole`_`gwei

```python
def round_to_whole_gwei(number: Type[int]) -> Wei
```

Round WEI to equivalent GWEI
Covert a number to the given unit.

<a id="plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.get_base_fee_multiplier"></a>

Expand Down Expand Up @@ -74,9 +66,8 @@ Estimate priority fee from base fee.
```python
def get_gas_price_strategy_eip1559(
max_gas_fast: int, fee_history_blocks: int, fee_history_percentile: int,
default_priority_fee: Optional[int],
fallback_estimate: Dict[str,
Optional[int]], priority_fee_increase_boundary: int
default_priority_fee: Optional[int], fallback_estimate: Dict[str, Wei],
priority_fee_increase_boundary: int
) -> Callable[[Web3, TxParams], Dict[str, Wei]]
```

Expand All @@ -89,7 +80,7 @@ Get the gas price strategy.
```python
def get_gas_price_strategy_eip1559_polygon(
gas_endpoint: str,
fallback_estimate: Dict[str, Optional[int]],
fallback_estimate: Dict[str, Wei],
speed: Optional[str] = SPEED_FAST
) -> Callable[[Any, Any], Dict[str, Wei]]
```
Expand Down
10 changes: 5 additions & 5 deletions docs/package_list.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
| contract/fetchai/erc1155/0.22.0 | `bafybeiff7a6xncyad53o2r7lekpnhexcspze6ocy55xtpzqeuacnlpunm4` |
| connection/fetchai/gym/0.19.0 | `bafybeicqqvl4tt3qbulnkoffciagmfd6p3hxxi3i2mrrqtnbycv757pn6y` |
| connection/fetchai/stub/0.21.0 | `bafybeibybboiwgklfiqpkkcw6rwj65s5jalzfzf6mh6fstxdlt6habzwvy` |
| connection/valory/ledger/0.19.0 | `bafybeibigvowo52dw3tqwmxkdxtq52qzm6iqw752gpzpi23kgej4k3sum4` |
| connection/valory/ledger/0.19.0 | `bafybeigntoericenpzvwejqfuc3kqzo2pscs76qoygg5dbj6f4zxusru5e` |
| connection/valory/http_server/0.22.0 | `bafybeihpgu56ovmq4npazdbh6y6ru5i7zuv6wvdglpxavsckyih56smu7m` |
| connection/valory/p2p_libp2p/0.1.0 | `bafybeic2u7azbwjny2nhaltqnbohlvysx3x6ectzbege7sxwrbzcz4lcma` |
| connection/valory/p2p_libp2p_client/0.1.0 | `bafybeid3xg5k2ol5adflqloy75ibgljmol6xsvzvezebsg7oudxeeolz7e` |
Expand All @@ -26,12 +26,12 @@
| skill/fetchai/error_test_skill/0.1.0 | `bafybeihsbtlpe7h6fsvoxban5rilkmwviwkokul5cqym6atoolirontiyu` |
| skill/fetchai/gym/0.20.0 | `bafybeie7y2fsxfuhsqxqcaluo5exskmrm5q3a6e2hfcskcuvzvxjjhijh4` |
| skill/fetchai/http_echo/0.20.0 | `bafybeicfiri2juaqh3azeit3z3rf44kgxdo6oj4lgxjgvnowq6m7j47qrm` |
| skill/fetchai/erc1155_client/0.28.0 | `bafybeigeoxvo3dabzbhjphu2n32wn5bomhv7b6ge6ogcte7qa6h42rwn5a` |
| skill/fetchai/erc1155_deploy/0.30.0 | `bafybeialn4tcp4vs7nousugfjpin5r37vhd2qcmphi3fs7ob66kcwb5gu4` |
| skill/fetchai/erc1155_client/0.28.0 | `bafybeih7q6b2lcqcbh7rln3mgcnbtzlw7cpzjl23znnz6jj74cc4noahvq` |
| skill/fetchai/erc1155_deploy/0.30.0 | `bafybeigoarj6k2czdhhfqzry5w5jn2ux7chszem37zxiqy3232jr2mxs64` |
| skill/fetchai/error/0.17.0 | `bafybeicboomvykqhel3otyv4qg5t3hzpo6kmn5bk4ljluithhuieu7flsm` |
| skill/fetchai/fipa_dummy_buyer/0.2.0 | `bafybeidgso7lo5ay44mbxsp3lxilrgeek3ye44e6wus2ayq6kyxfvc3vjm` |
| skill/fetchai/generic_buyer/0.26.0 | `bafybeienntvkd7blbbc4p624dop7tz4iejtpi36somhohbi4tmxd63ksr4` |
| skill/fetchai/generic_seller/0.27.0 | `bafybeid4y4p2xlnkezvtzhgwfdzrowhul34md64shf3jv5nskpggskc3fm` |
| skill/fetchai/generic_buyer/0.26.0 | `bafybeihzzcbki3p5l4nt5spbddx6nzbejv7b6nruhycwaxfrstjwmrfucq` |
| skill/fetchai/generic_seller/0.27.0 | `bafybeig3ffbcefeandebzepxabztob5sdkumydzla52k7pvztmjfegwflq` |
| skill/fetchai/task_test_skill/0.1.0 | `bafybeidv77u2xl52mnxakwvh7fuh46aiwfpteyof4eaptfd4agoi6cdble` |
| agent/fetchai/error_test/0.1.0 | `bafybeiecm675ndzbh35jkejtxn4ughoutztltjhgwzfbp57okabedjmnpq` |
| agent/fetchai/gym_aea/0.25.0 | `bafybeibzn3qomqmkaksgpd3gn6aijffvvw7rojswhoytiovohuc737fvfm` |
Expand Down
86 changes: 50 additions & 36 deletions plugins/aea-ledger-ethereum/aea_ledger_ethereum/ethereum.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from collections import defaultdict
from copy import deepcopy
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union, cast
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast
from uuid import uuid4

import ipfshttpclient # noqa: F401 # pylint: disable=unused-import
Expand Down Expand Up @@ -72,6 +72,7 @@
DEFAULT_ADDRESS = "http://127.0.0.1:8545"
DEFAULT_CHAIN_ID = 1337
DEFAULT_CURRENCY_DENOM = "wei"
GWEI = "gwei"
ETH_GASSTATION_URL = "https://ethgasstation.info/api/ethgasAPI.json"
_ABI = "abi"
_BYTECODE = "bytecode"
Expand All @@ -95,8 +96,8 @@

# In case something goes wrong fall back to this estimate
FALLBACK_ESTIMATE = {
"maxFeePerGas": to_wei(20, "gwei"),
"maxPriorityFeePerGas": to_wei(3, "gwei"),
"maxFeePerGas": to_wei(20, GWEI),
"maxPriorityFeePerGas": to_wei(3, GWEI),
}

PRIORITY_FEE_INCREASE_BOUNDARY = 200 # percentage
Expand Down Expand Up @@ -136,16 +137,19 @@
MATCH_ANY = "match_any"


def wei_to_gwei(number: Type[int]) -> Union[int, decimal.Decimal]:
"""Covert WEI to GWEI"""
return from_wei(cast(int, number), unit="gwei")
def to_eth_unit(
number: Union[int, float, str, decimal.Decimal],
unit_in: str = DEFAULT_CURRENCY_DENOM,
unit_out: str = GWEI,
) -> Union[int, Wei, decimal.Decimal]:
"""Covert a number to the given unit."""
if not (isinstance(number, int) and unit_in == DEFAULT_CURRENCY_DENOM):
number = to_wei(number, unit_in)

if unit_out == DEFAULT_CURRENCY_DENOM:
return number

def round_to_whole_gwei(number: Type[int]) -> Wei:
"""Round WEI to equivalent GWEI"""
gwei = wei_to_gwei(number)
rounded = math.ceil(gwei)
return cast(Wei, to_wei(rounded, "gwei"))
return from_wei(number, unit_out)


def get_base_fee_multiplier(base_fee_gwei: Union[int, decimal.Decimal]) -> float:
Expand Down Expand Up @@ -176,7 +180,9 @@ def estimate_priority_fee(

# This is going to break if more percentiles are introduced in the future,
# i.e., `fee_history_percentile` param becomes a `List[int]`.
rewards = sorted([reward[0] for reward in fee_history["reward"] if reward[0] > 0])
rewards = sorted(
[reward[0] for reward in fee_history.get("reward", []) if reward[0] > 0]
)
if len(rewards) == 0:
return None

Expand Down Expand Up @@ -204,11 +210,18 @@ def get_gas_price_strategy_eip1559(
fee_history_blocks: int,
fee_history_percentile: int,
default_priority_fee: Optional[int],
fallback_estimate: Dict[str, Optional[int]],
fallback_estimate: Dict[str, Wei],
priority_fee_increase_boundary: int,
) -> Callable[[Web3, TxParams], Dict[str, Wei]]:
"""Get the gas price strategy."""

def fallback(
warning: str = "An error occurred while estimating gas price. Falling back.",
) -> Dict[str, Wei]:
"""Return the fallback estimate and log a warning."""
_default_logger.warning(warning)
return fallback_estimate

def eip1559_price_strategy(
web3: Web3, # pylint: disable=redefined-outer-name
transaction_params: TxParams, # pylint: disable=unused-argument
Expand All @@ -227,7 +240,11 @@ def eip1559_price_strategy(
latest_block = web3.eth.get_block("latest")
base_fee = latest_block.get("baseFeePerGas")
block_number = latest_block.get("number")
base_fee_gwei = wei_to_gwei(base_fee)

if base_fee is None or block_number is None:
return fallback()

base_fee_gwei = to_eth_unit(base_fee)

estimated_priority_fee = estimate_priority_fee(
web3,
Expand All @@ -239,43 +256,40 @@ def eip1559_price_strategy(
)

if estimated_priority_fee is None:
_default_logger.warning(
"An error occurred while estimating priority fee, falling back"
)
return fallback_estimate
return fallback()

max_priority_fee_per_gas = max(
estimated_priority_fee,
to_wei(default_priority_fee, "gwei")
if default_priority_fee is not None
else -1,
)
multiplier = get_base_fee_multiplier(base_fee_gwei)

potential_max_fee = base_fee * multiplier
max_fee_per_gas = (
(potential_max_fee + max_priority_fee_per_gas)
if max_priority_fee_per_gas > potential_max_fee
(potential_max_fee + estimated_priority_fee)
if estimated_priority_fee > potential_max_fee
else potential_max_fee
)

if (
wei_to_gwei(max_fee_per_gas) >= max_gas_fast
or wei_to_gwei(max_priority_fee_per_gas) >= max_gas_fast
to_eth_unit(max_fee_per_gas) >= max_gas_fast
or to_eth_unit(estimated_priority_fee) >= max_gas_fast
):
return fallback_estimate
return fallback(
"The estimated gas price is larger than the `max_gas_fast`. Falling back."
)

estimate = {
"maxFeePerGas": max_fee_per_gas,
"maxPriorityFeePerGas": estimated_priority_fee,
}
return {
"maxFeePerGas": round_to_whole_gwei(max_fee_per_gas),
"maxPriorityFeePerGas": round_to_whole_gwei(max_priority_fee_per_gas),
fee: to_eth_unit(amount, unit_out=DEFAULT_CURRENCY_DENOM)
for fee, amount in estimate.items()
}

return eip1559_price_strategy


def get_gas_price_strategy_eip1559_polygon(
gas_endpoint: str,
fallback_estimate: Dict[str, Optional[int]],
fallback_estimate: Dict[str, Wei],
speed: Optional[str] = SPEED_FAST,
) -> Callable[[Any, Any], Dict[str, Wei]]:
"""Get the gas price strategy."""
Expand All @@ -289,8 +303,8 @@ def eip1559_price_strategy(
if response.status_code == 200:
data = response.json()[speed]
return {
"maxFeePerGas": Wei(to_wei(data["maxFee"], "gwei")),
"maxPriorityFeePerGas": Wei(to_wei(data["maxPriorityFee"], "gwei")),
"maxFeePerGas": Wei(to_wei(data["maxFee"], GWEI)),
"maxPriorityFeePerGas": Wei(to_wei(data["maxPriorityFee"], GWEI)),
}
return fallback_estimate
except requests.exceptions.RequestException:
Expand Down Expand Up @@ -351,14 +365,14 @@ def gas_station_gas_price_strategy(
_default_logger.error(
f"Gas station API response: {response.status_code}, {response.text}, using fallback gas price."
)
return {"gasPrice": web3.to_wei(GAS_STATION_FALLBACK_ESTIMATE, "gwei")}
return {"gasPrice": web3.to_wei(GAS_STATION_FALLBACK_ESTIMATE, GWEI)}
response_dict = response.json()
_default_logger.debug("Gas station API response: {}".format(response_dict))
result = response_dict.get(gas_price_strategy, None)
if type(result) not in [int, float]: # pragma: nocover
raise ValueError(f"Invalid return value for `{gas_price_strategy}`!")
gwei_result = result / 10 # adjustment (see api documentation)
wei_result = web3.to_wei(gwei_result, "gwei")
wei_result = web3.to_wei(gwei_result, GWEI)
return {"gasPrice": wei_result}

return gas_station_gas_price_strategy
Expand Down
11 changes: 6 additions & 5 deletions plugins/aea-ledger-ethereum/tests/test_ethereum.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,23 +509,24 @@ def test_gas_price_strategy_eip1559() -> None:

web3 = Web3()
get_block_mock = mock.patch.object(
web3.eth, "get_block", return_value={"baseFeePerGas": 150e9, "number": 1}
web3.eth, "get_block", return_value={"baseFeePerGas": 15e10, "number": 1}
)

mock_hist_data = get_history_data(n_blocks=5)
rewards = [rew[0] for rew in mock_hist_data["reward"]]
fee_history_mock = mock.patch.object(
web3.eth,
"fee_history",
return_value=get_history_data(
n_blocks=5,
),
return_value=mock_hist_data,
)

with get_block_mock:
with fee_history_mock:
gas_stregy = callable_(web3, "tx_params")

assert all([key in gas_stregy for key in ["maxFeePerGas", "maxPriorityFeePerGas"]])
assert all([value > 1e8 for value in gas_stregy.values()])
assert gas_stregy["maxFeePerGas"] == 21e10
assert gas_stregy["maxPriorityFeePerGas"] < max(rewards)


def test_gas_price_strategy_eip1559_estimate_none() -> None:
Expand Down

0 comments on commit 4cd5f40

Please sign in to comment.