eth-protocols-py 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eth_protocols_py-0.1.4/PKG-INFO +22 -0
- eth_protocols_py-0.1.4/pyproject.toml +38 -0
- eth_protocols_py-0.1.4/setup.cfg +4 -0
- eth_protocols_py-0.1.4/setup.py +13 -0
- eth_protocols_py-0.1.4/src/eth_protocols/__init__.py +13 -0
- eth_protocols_py-0.1.4/src/eth_protocols/camelot_v3/__init__.py +5 -0
- eth_protocols_py-0.1.4/src/eth_protocols/camelot_v3/pool.py +163 -0
- eth_protocols_py-0.1.4/src/eth_protocols/helpers/__init__.py +9 -0
- eth_protocols_py-0.1.4/src/eth_protocols/helpers/dex_pairs.py +254 -0
- eth_protocols_py-0.1.4/src/eth_protocols/helpers/multicall.py +35 -0
- eth_protocols_py-0.1.4/src/eth_protocols/helpers/price_tracker.py +170 -0
- eth_protocols_py-0.1.4/src/eth_protocols/logger.py +3 -0
- eth_protocols_py-0.1.4/src/eth_protocols/tokens/__init__.py +5 -0
- eth_protocols_py-0.1.4/src/eth_protocols/tokens/erc20/__init__.py +198 -0
- eth_protocols_py-0.1.4/src/eth_protocols/tokens/erc20/events.py +37 -0
- eth_protocols_py-0.1.4/src/eth_protocols/types/__init__.py +5 -0
- eth_protocols_py-0.1.4/src/eth_protocols/types/dex_pair.py +123 -0
- eth_protocols_py-0.1.4/src/eth_protocols/uniswap_v2/__init__.py +8 -0
- eth_protocols_py-0.1.4/src/eth_protocols/uniswap_v2/factory.py +46 -0
- eth_protocols_py-0.1.4/src/eth_protocols/uniswap_v2/pair.py +146 -0
- eth_protocols_py-0.1.4/src/eth_protocols/uniswap_v2/price.py +104 -0
- eth_protocols_py-0.1.4/src/eth_protocols/uniswap_v3/__init__.py +5 -0
- eth_protocols_py-0.1.4/src/eth_protocols/uniswap_v3/liquidity.py +3 -0
- eth_protocols_py-0.1.4/src/eth_protocols/uniswap_v3/pool.py +168 -0
- eth_protocols_py-0.1.4/src/eth_protocols/utils/lookup_dict.py +29 -0
- eth_protocols_py-0.1.4/src/eth_protocols_py.egg-info/PKG-INFO +22 -0
- eth_protocols_py-0.1.4/src/eth_protocols_py.egg-info/SOURCES.txt +29 -0
- eth_protocols_py-0.1.4/src/eth_protocols_py.egg-info/dependency_links.txt +1 -0
- eth_protocols_py-0.1.4/src/eth_protocols_py.egg-info/requires.txt +22 -0
- eth_protocols_py-0.1.4/src/eth_protocols_py.egg-info/top_level.txt +1 -0
- eth_protocols_py-0.1.4/tests/test_create2_address.py +12 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: eth-protocols-py
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Requires-Python: >=3.10
|
|
5
|
+
Requires-Dist: eth_rpc_py
|
|
6
|
+
Requires-Dist: eth_typeshed_py
|
|
7
|
+
Requires-Dist: sortedcontainers
|
|
8
|
+
Requires-Dist: eth_hash
|
|
9
|
+
Provides-Extra: lint
|
|
10
|
+
Requires-Dist: mypy; extra == "lint"
|
|
11
|
+
Requires-Dist: ruff; extra == "lint"
|
|
12
|
+
Provides-Extra: test
|
|
13
|
+
Requires-Dist: pytest==7.4.1; extra == "test"
|
|
14
|
+
Requires-Dist: pytest-cov==4.1.0; extra == "test"
|
|
15
|
+
Requires-Dist: coverage[toml]==7.3.1; extra == "test"
|
|
16
|
+
Provides-Extra: build
|
|
17
|
+
Requires-Dist: build[virtualenv]==1.0.3; extra == "build"
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: tox; extra == "dev"
|
|
20
|
+
Requires-Dist: eth-protocols-py[lint]; extra == "dev"
|
|
21
|
+
Requires-Dist: eth-protocols-py[test]; extra == "dev"
|
|
22
|
+
Requires-Dist: eth-protocols-py[build]; extra == "dev"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "setuptools_scm[toml]>=8"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "eth-protocols-py"
|
|
7
|
+
requires-python = ">=3.10"
|
|
8
|
+
dynamic = ["version"]
|
|
9
|
+
dependencies = [
|
|
10
|
+
"eth_rpc_py",
|
|
11
|
+
"eth_typeshed_py",
|
|
12
|
+
"sortedcontainers",
|
|
13
|
+
"eth_hash"
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
# Enables the usage of setuptools_scm
|
|
17
|
+
[tool.setuptools_scm]
|
|
18
|
+
root = "../../"
|
|
19
|
+
|
|
20
|
+
[project.optional-dependencies]
|
|
21
|
+
lint = [
|
|
22
|
+
"mypy",
|
|
23
|
+
"ruff",
|
|
24
|
+
]
|
|
25
|
+
test = [
|
|
26
|
+
"pytest==7.4.1",
|
|
27
|
+
"pytest-cov==4.1.0",
|
|
28
|
+
"coverage[toml]==7.3.1",
|
|
29
|
+
]
|
|
30
|
+
build = [
|
|
31
|
+
"build[virtualenv]==1.0.3",
|
|
32
|
+
]
|
|
33
|
+
dev = [
|
|
34
|
+
"tox",
|
|
35
|
+
"eth-protocols-py[lint]",
|
|
36
|
+
"eth-protocols-py[test]",
|
|
37
|
+
"eth-protocols-py[build]",
|
|
38
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .helpers import DexPairHelper, PriceTracker
|
|
2
|
+
from .tokens import ERC20
|
|
3
|
+
from .uniswap_v2 import V2Factory, V2Pair
|
|
4
|
+
from .uniswap_v3 import V3Pool
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"DexPairHelper",
|
|
8
|
+
"PriceTracker",
|
|
9
|
+
"ERC20",
|
|
10
|
+
"V2Factory",
|
|
11
|
+
"V2Pair",
|
|
12
|
+
"V3Pool",
|
|
13
|
+
]
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
from typing import cast
|
|
3
|
+
|
|
4
|
+
from eth_protocols.tokens import ERC20
|
|
5
|
+
from eth_protocols.types import DexPair
|
|
6
|
+
from eth_rpc.types import BLOCK_STRINGS, MaybeAwaitable
|
|
7
|
+
from eth_typeshed.camelot_v3 import CamelotV3Pool, GlobalState
|
|
8
|
+
from eth_typeshed.erc20 import OwnerRequest
|
|
9
|
+
from eth_typeshed.multicall import multicall
|
|
10
|
+
from eth_typing import HexAddress
|
|
11
|
+
from eth_utils import to_checksum_address
|
|
12
|
+
from pydantic import PrivateAttr
|
|
13
|
+
|
|
14
|
+
Q192 = Decimal(2**192)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CamelotV3Pool(DexPair):
|
|
18
|
+
_contract: CamelotV3Pool = PrivateAttr()
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def load_static(
|
|
22
|
+
cls,
|
|
23
|
+
pair_address: HexAddress,
|
|
24
|
+
tokena: HexAddress,
|
|
25
|
+
tokenb: HexAddress,
|
|
26
|
+
):
|
|
27
|
+
token0, token1 = (
|
|
28
|
+
(tokena, tokenb) if tokena.lower() < tokenb.lower() else (tokenb, tokena)
|
|
29
|
+
)
|
|
30
|
+
return cls(
|
|
31
|
+
token0=ERC20(address=token0), # type: ignore
|
|
32
|
+
token1=ERC20(address=token1), # type: ignore
|
|
33
|
+
pair_address=pair_address,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
async def load_pair(
|
|
38
|
+
cls,
|
|
39
|
+
pair_address: HexAddress,
|
|
40
|
+
):
|
|
41
|
+
# TODO: type hints don't work with pydantic validators
|
|
42
|
+
_contract = CamelotV3Pool(address=pair_address)
|
|
43
|
+
token0, token1, fee = await multicall.execute(
|
|
44
|
+
_contract.token0(),
|
|
45
|
+
_contract.token1(),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
return cls(
|
|
49
|
+
token0=ERC20(address=token0), # type: ignore
|
|
50
|
+
token1=ERC20(address=token1), # type: ignore
|
|
51
|
+
pair_address=pair_address, # type: ignore
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def set_global_state(self, global_stage: GlobalState):
|
|
55
|
+
self._global_state = global_stage
|
|
56
|
+
|
|
57
|
+
def set_reserve0(self, reserve: int):
|
|
58
|
+
self._reserve0 = reserve
|
|
59
|
+
|
|
60
|
+
def set_reserve1(self, reserve: int):
|
|
61
|
+
self._reserve1 = reserve
|
|
62
|
+
|
|
63
|
+
def get_price(
|
|
64
|
+
self,
|
|
65
|
+
token: HexAddress,
|
|
66
|
+
block_number: int | BLOCK_STRINGS = "latest",
|
|
67
|
+
) -> Decimal:
|
|
68
|
+
token = to_checksum_address(token)
|
|
69
|
+
assert token == self.token0.address or token == self.token1.address
|
|
70
|
+
|
|
71
|
+
if block_number:
|
|
72
|
+
global_state = self._contract.global_state().get(block_number=block_number)
|
|
73
|
+
else:
|
|
74
|
+
global_state = self._global_state
|
|
75
|
+
|
|
76
|
+
sqrt_price = global_state.price
|
|
77
|
+
|
|
78
|
+
return self.sqrt_price_x96_to_token_prices(
|
|
79
|
+
sqrt_price,
|
|
80
|
+
self.token0.sync.decimals(),
|
|
81
|
+
self.token1.sync.decimals(),
|
|
82
|
+
token == self.token0.address,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def get_other_token(self, token: HexAddress) -> HexAddress:
|
|
86
|
+
token = to_checksum_address(token)
|
|
87
|
+
if token == self.token0.address:
|
|
88
|
+
return self.token1.address
|
|
89
|
+
elif token == self.token1.address:
|
|
90
|
+
return self.token0.address
|
|
91
|
+
else:
|
|
92
|
+
raise ValueError(
|
|
93
|
+
f"{token=} cannot be found {self.token0.address=} {self.token1.address=}"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def get_reserves(
|
|
97
|
+
self, block_number: int | BLOCK_STRINGS = "latest", sync: bool = False
|
|
98
|
+
) -> MaybeAwaitable[tuple[int, int]]:
|
|
99
|
+
if sync:
|
|
100
|
+
token0_reserves, token1_reserves = multicall.execute(
|
|
101
|
+
*self._construct_pair_balance_request(), sync=True
|
|
102
|
+
)
|
|
103
|
+
self.set_reserves(token0_reserves, token1_reserves)
|
|
104
|
+
return token0_reserves, token1_reserves
|
|
105
|
+
|
|
106
|
+
async def get_reserves() -> tuple[int, int]:
|
|
107
|
+
token0_reserves = await self.token0.balance_of(
|
|
108
|
+
self.pair_address, block_number=block_number
|
|
109
|
+
)
|
|
110
|
+
token1_reserves = await self.token1.balance_of(
|
|
111
|
+
self.pair_address, block_number=block_number
|
|
112
|
+
)
|
|
113
|
+
self.set_reserves(token0_reserves, token1_reserves)
|
|
114
|
+
return token0_reserves, token1_reserves
|
|
115
|
+
|
|
116
|
+
return get_reserves
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def sqrt_price_x96_to_token_prices(
|
|
120
|
+
sqrt_price_x96: int,
|
|
121
|
+
token0_decimals: int,
|
|
122
|
+
token1_decimals: int,
|
|
123
|
+
token0: bool = True,
|
|
124
|
+
) -> Decimal:
|
|
125
|
+
num = Decimal(sqrt_price_x96 * sqrt_price_x96)
|
|
126
|
+
price1: Decimal = (
|
|
127
|
+
(num / Q192)
|
|
128
|
+
* (Decimal(10) ** token0_decimals)
|
|
129
|
+
/ (Decimal(10) ** token1_decimals)
|
|
130
|
+
)
|
|
131
|
+
if token0:
|
|
132
|
+
return Decimal(price1)
|
|
133
|
+
return Decimal(1) / price1
|
|
134
|
+
|
|
135
|
+
def _construct_pair_balance_request(self):
|
|
136
|
+
return [
|
|
137
|
+
self.token0.raw.balance_of(
|
|
138
|
+
OwnerRequest(
|
|
139
|
+
self.pair_address,
|
|
140
|
+
)
|
|
141
|
+
),
|
|
142
|
+
self.token1.raw.balance_of(
|
|
143
|
+
OwnerRequest(
|
|
144
|
+
self.pair_address,
|
|
145
|
+
)
|
|
146
|
+
),
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
@classmethod
|
|
150
|
+
async def get_all_reserves(
|
|
151
|
+
self, pools: list["V3Pool"], block_number: int | BLOCK_STRINGS = "latest"
|
|
152
|
+
) -> list[tuple[int, int]]:
|
|
153
|
+
pool_calls = []
|
|
154
|
+
for pool in pools:
|
|
155
|
+
pool_calls.extend(pool._construct_pair_balance_request())
|
|
156
|
+
reserves = cast(
|
|
157
|
+
list[int],
|
|
158
|
+
await multicall.execute(
|
|
159
|
+
*pool_calls,
|
|
160
|
+
block_number=block_number,
|
|
161
|
+
),
|
|
162
|
+
)
|
|
163
|
+
return [(reserves[i], reserves[i + 1]) for i in range(0, len(reserves), 2)]
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
from itertools import combinations
|
|
2
|
+
|
|
3
|
+
from eth_protocols.camelot_v3 import CamelotV3Pool
|
|
4
|
+
from eth_protocols.uniswap_v2 import V2Pair
|
|
5
|
+
from eth_protocols.uniswap_v3 import V3Pool
|
|
6
|
+
from eth_rpc.types.primitives import uint24
|
|
7
|
+
from eth_typeshed.camelot_v3 import CamelotV3Factory
|
|
8
|
+
from eth_typeshed.camelot_v3 import GetPoolRequest as CamelotGetPoolRequest
|
|
9
|
+
from eth_typeshed.constants import Factories, Tokens
|
|
10
|
+
from eth_typeshed.erc20 import OwnerRequest
|
|
11
|
+
from eth_typeshed.uniswap_v2 import GetPairRequest, UniswapV2Factory, UniswapV2Pair
|
|
12
|
+
from eth_typeshed.uniswap_v3 import GetPoolRequest, UniswapV3Factory, UniswapV3Pool
|
|
13
|
+
from eth_typeshed.utils import try_execute_with_setters
|
|
14
|
+
from eth_typing import HexAddress
|
|
15
|
+
from eth_utils import to_checksum_address
|
|
16
|
+
from pydantic import BaseModel
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DexPairHelper(BaseModel):
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
def find_pair(
|
|
23
|
+
data: dict[HexAddress, list[V2Pair | V3Pool]],
|
|
24
|
+
addr: HexAddress,
|
|
25
|
+
paired_with: HexAddress,
|
|
26
|
+
fee_tiers: list[int],
|
|
27
|
+
uniswap_v2_factory_address: HexAddress,
|
|
28
|
+
uniswap_v3_factory_address: HexAddress,
|
|
29
|
+
):
|
|
30
|
+
addr = to_checksum_address(addr)
|
|
31
|
+
paired_with = to_checksum_address(paired_with)
|
|
32
|
+
calls_list = [
|
|
33
|
+
(
|
|
34
|
+
UniswapV2Factory(address=uniswap_v2_factory_address).get_pair(
|
|
35
|
+
GetPairRequest(token_a=addr, token_b=paired_with)
|
|
36
|
+
),
|
|
37
|
+
lambda result, addr=addr, paired_with=paired_with: (
|
|
38
|
+
data.setdefault(addr, []).append(
|
|
39
|
+
V2Pair.load_static(
|
|
40
|
+
pair_address=result,
|
|
41
|
+
tokena=addr,
|
|
42
|
+
tokenb=paired_with,
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
),
|
|
46
|
+
),
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
for fee in fee_tiers:
|
|
50
|
+
calls_list.extend(
|
|
51
|
+
[
|
|
52
|
+
(
|
|
53
|
+
UniswapV3Factory(address=uniswap_v3_factory_address).get_pool(
|
|
54
|
+
GetPoolRequest(
|
|
55
|
+
token_a=addr,
|
|
56
|
+
token_b=paired_with,
|
|
57
|
+
fee=uint24(fee),
|
|
58
|
+
)
|
|
59
|
+
),
|
|
60
|
+
lambda result, addr=addr, paired_with=paired_with, fee=fee: ( # type: ignore
|
|
61
|
+
data.setdefault(addr, []).append(
|
|
62
|
+
V3Pool.load_static(
|
|
63
|
+
tokena=addr,
|
|
64
|
+
tokenb=paired_with,
|
|
65
|
+
pair_address=result,
|
|
66
|
+
fee=fee,
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
),
|
|
70
|
+
),
|
|
71
|
+
]
|
|
72
|
+
)
|
|
73
|
+
if uniswap_v3_factory_address == Factories.Arbitrum.Camelot_V3:
|
|
74
|
+
calls_list.extend(
|
|
75
|
+
[
|
|
76
|
+
(
|
|
77
|
+
CamelotV3Factory(
|
|
78
|
+
address=uniswap_v3_factory_address
|
|
79
|
+
).pool_by_pair(
|
|
80
|
+
CamelotGetPoolRequest(token_a=addr, token_b=paired_with)
|
|
81
|
+
),
|
|
82
|
+
lambda result, addr=addr, paired_with=paired_with: ( # type: ignore
|
|
83
|
+
data.setdefault(addr, []).append(
|
|
84
|
+
CamelotV3Pool.load_static(
|
|
85
|
+
tokena=addr, tokenb=paired_with, pair_address=result
|
|
86
|
+
)
|
|
87
|
+
)
|
|
88
|
+
),
|
|
89
|
+
),
|
|
90
|
+
]
|
|
91
|
+
)
|
|
92
|
+
return calls_list
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
async def find_all_pairs(
|
|
96
|
+
addresses: list[HexAddress],
|
|
97
|
+
find_pairs: list[HexAddress] = Tokens.for_network().main,
|
|
98
|
+
uniswap_v2_factory_address: HexAddress = Factories.for_network().UniswapV2,
|
|
99
|
+
uniswap_v3_factory_address: HexAddress = Factories.for_network().UniswapV3,
|
|
100
|
+
fee_tiers: list[int] = [500, 3000, 10000],
|
|
101
|
+
block_number: int | None = None,
|
|
102
|
+
) -> dict[HexAddress, list[V2Pair | V3Pool]]:
|
|
103
|
+
data: dict[HexAddress, list[V2Pair | V3Pool]] = {}
|
|
104
|
+
calls_with_setters = []
|
|
105
|
+
for addr in addresses:
|
|
106
|
+
if addr not in data:
|
|
107
|
+
data[addr] = []
|
|
108
|
+
for paired_with in find_pairs:
|
|
109
|
+
calls_with_setters.extend(
|
|
110
|
+
DexPairHelper.find_pair(
|
|
111
|
+
data,
|
|
112
|
+
addr,
|
|
113
|
+
paired_with,
|
|
114
|
+
fee_tiers,
|
|
115
|
+
uniswap_v2_factory_address,
|
|
116
|
+
uniswap_v3_factory_address,
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
await try_execute_with_setters(
|
|
120
|
+
calls_with_setters, block_number=block_number or "latest"
|
|
121
|
+
)
|
|
122
|
+
await DexPairHelper.add_reserves_to_pairs(data, block_number=block_number)
|
|
123
|
+
return data
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
async def find_all_stables_pairs(
|
|
127
|
+
find_pairs: list[HexAddress] = Tokens.for_network().main,
|
|
128
|
+
uniswap_v2_factory_address: HexAddress = Factories.for_network().UniswapV2,
|
|
129
|
+
uniswap_v3_factory_address: HexAddress = Factories.for_network().UniswapV3,
|
|
130
|
+
fee_tiers: list[int] = [500, 3000, 10000],
|
|
131
|
+
block_number: int | None = None,
|
|
132
|
+
) -> dict[HexAddress, list[V2Pair | V3Pool]]:
|
|
133
|
+
data: dict[HexAddress, list[V2Pair | V3Pool]] = {}
|
|
134
|
+
calls_with_setters = []
|
|
135
|
+
|
|
136
|
+
unique_tuples = list(combinations(find_pairs, 2))
|
|
137
|
+
|
|
138
|
+
for t in unique_tuples:
|
|
139
|
+
calls_with_setters.extend(
|
|
140
|
+
DexPairHelper.find_pair(
|
|
141
|
+
data,
|
|
142
|
+
t[0],
|
|
143
|
+
t[1],
|
|
144
|
+
fee_tiers,
|
|
145
|
+
uniswap_v2_factory_address,
|
|
146
|
+
uniswap_v3_factory_address,
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
await try_execute_with_setters(
|
|
150
|
+
calls_with_setters, block_number=block_number or "latest"
|
|
151
|
+
)
|
|
152
|
+
await DexPairHelper.add_reserves_to_pairs(data, block_number=block_number)
|
|
153
|
+
return data
|
|
154
|
+
|
|
155
|
+
@staticmethod
|
|
156
|
+
async def add_reserves_to_pairs(
|
|
157
|
+
data: dict[HexAddress, list[V2Pair | V3Pool]],
|
|
158
|
+
block_number: int | None = None,
|
|
159
|
+
):
|
|
160
|
+
calls_with_setters = []
|
|
161
|
+
|
|
162
|
+
for pairs in data.values():
|
|
163
|
+
for pair in pairs:
|
|
164
|
+
if isinstance(pair, V2Pair):
|
|
165
|
+
calls_with_setters.append(
|
|
166
|
+
(
|
|
167
|
+
UniswapV2Pair(address=pair.pair_address).get_reserves(),
|
|
168
|
+
lambda result, pair=pair: (
|
|
169
|
+
pair.set_reserves(result[0], result[1])
|
|
170
|
+
),
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
calls_with_setters.append(
|
|
174
|
+
(
|
|
175
|
+
pair.token0.raw.decimals(),
|
|
176
|
+
lambda result, pair=pair: (
|
|
177
|
+
pair.token0.set_decimals(result)
|
|
178
|
+
),
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
calls_with_setters.append(
|
|
182
|
+
(
|
|
183
|
+
pair.token0.raw.symbol(),
|
|
184
|
+
lambda result, pair=pair: (pair.token0.set_symbol(result)),
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
calls_with_setters.append(
|
|
188
|
+
(
|
|
189
|
+
pair.token1.raw.decimals(),
|
|
190
|
+
lambda result, pair=pair: (
|
|
191
|
+
pair.token1.set_decimals(result)
|
|
192
|
+
),
|
|
193
|
+
)
|
|
194
|
+
)
|
|
195
|
+
calls_with_setters.append(
|
|
196
|
+
(
|
|
197
|
+
pair.token1.raw.symbol(),
|
|
198
|
+
lambda result, pair=pair: (pair.token1.set_symbol(result)),
|
|
199
|
+
)
|
|
200
|
+
)
|
|
201
|
+
elif isinstance(pair, V3Pool):
|
|
202
|
+
calls_with_setters.append(
|
|
203
|
+
(
|
|
204
|
+
UniswapV3Pool(address=pair.pair_address).slot0(),
|
|
205
|
+
lambda result, pair=pair: (pair.set_slot0(result)),
|
|
206
|
+
)
|
|
207
|
+
)
|
|
208
|
+
calls_with_setters.append(
|
|
209
|
+
(
|
|
210
|
+
pair.token0.raw.balance_of(
|
|
211
|
+
OwnerRequest(owner=pair.pair_address)
|
|
212
|
+
),
|
|
213
|
+
lambda result, pair=pair: (pair.set_reserve0(result)),
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
calls_with_setters.append(
|
|
217
|
+
(
|
|
218
|
+
pair.token1.raw.balance_of(
|
|
219
|
+
OwnerRequest(owner=pair.pair_address)
|
|
220
|
+
),
|
|
221
|
+
lambda result, pair=pair: (pair.set_reserve1(result)),
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
calls_with_setters.append(
|
|
225
|
+
(
|
|
226
|
+
pair.token0.raw.decimals(),
|
|
227
|
+
lambda result, pair=pair: (
|
|
228
|
+
pair.token0.set_decimals(result)
|
|
229
|
+
),
|
|
230
|
+
)
|
|
231
|
+
)
|
|
232
|
+
calls_with_setters.append(
|
|
233
|
+
(
|
|
234
|
+
pair.token0.raw.symbol(),
|
|
235
|
+
lambda result, pair=pair: (pair.token0.set_symbol(result)),
|
|
236
|
+
)
|
|
237
|
+
)
|
|
238
|
+
calls_with_setters.append(
|
|
239
|
+
(
|
|
240
|
+
pair.token1.raw.decimals(),
|
|
241
|
+
lambda result, pair=pair: (
|
|
242
|
+
pair.token1.set_decimals(result)
|
|
243
|
+
),
|
|
244
|
+
)
|
|
245
|
+
)
|
|
246
|
+
calls_with_setters.append(
|
|
247
|
+
(
|
|
248
|
+
pair.token1.raw.symbol(),
|
|
249
|
+
lambda result, pair=pair: (pair.token1.set_symbol(result)),
|
|
250
|
+
)
|
|
251
|
+
)
|
|
252
|
+
await try_execute_with_setters(
|
|
253
|
+
calls_with_setters, block_number=block_number or "latest"
|
|
254
|
+
)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from eth_rpc.types import BLOCK_STRINGS
|
|
2
|
+
from eth_typeshed.utils import try_execute_with_setters
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class MultiCallRequestHelper:
|
|
6
|
+
calls_with_setters: list
|
|
7
|
+
data: dict
|
|
8
|
+
|
|
9
|
+
def __init__(self):
|
|
10
|
+
self.calls_with_setters = []
|
|
11
|
+
self.data = {}
|
|
12
|
+
|
|
13
|
+
def prepare(self, address, protocol_call_func, result_handler_func):
|
|
14
|
+
self.prepare_raw(
|
|
15
|
+
address,
|
|
16
|
+
protocol_call_func,
|
|
17
|
+
lambda result: result_handler_func(self.data[address], result),
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
def prepare_data(self, address, init_key, init_value):
|
|
21
|
+
if address not in self.data:
|
|
22
|
+
self.data[address] = {}
|
|
23
|
+
if init_key not in self.data[address]:
|
|
24
|
+
self.data[address][init_key] = init_value
|
|
25
|
+
|
|
26
|
+
def prepare_raw(self, address, protocol_call_func, lambda_handler_func):
|
|
27
|
+
if address not in self.data:
|
|
28
|
+
self.data[address] = {}
|
|
29
|
+
self.calls_with_setters.append((protocol_call_func, lambda_handler_func))
|
|
30
|
+
|
|
31
|
+
async def call(self, block_number: int | BLOCK_STRINGS = "latest"):
|
|
32
|
+
await try_execute_with_setters(
|
|
33
|
+
self.calls_with_setters, block_number=block_number
|
|
34
|
+
)
|
|
35
|
+
return self.data
|