eth-portfolio-temp 0.2.15__cp313-cp313-macosx_11_0_arm64.whl

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.

Potentially problematic release.


This version of eth-portfolio-temp might be problematic. Click here for more details.

Files changed (83) hide show
  1. eth_portfolio/__init__.py +25 -0
  2. eth_portfolio/_argspec.cpython-313-darwin.so +0 -0
  3. eth_portfolio/_argspec.py +42 -0
  4. eth_portfolio/_cache.py +121 -0
  5. eth_portfolio/_config.cpython-313-darwin.so +0 -0
  6. eth_portfolio/_config.py +4 -0
  7. eth_portfolio/_db/__init__.py +0 -0
  8. eth_portfolio/_db/decorators.py +147 -0
  9. eth_portfolio/_db/entities.py +311 -0
  10. eth_portfolio/_db/utils.py +604 -0
  11. eth_portfolio/_decimal.py +156 -0
  12. eth_portfolio/_decorators.py +84 -0
  13. eth_portfolio/_exceptions.py +67 -0
  14. eth_portfolio/_ledgers/__init__.py +0 -0
  15. eth_portfolio/_ledgers/address.py +938 -0
  16. eth_portfolio/_ledgers/portfolio.py +327 -0
  17. eth_portfolio/_loaders/__init__.py +33 -0
  18. eth_portfolio/_loaders/_nonce.cpython-313-darwin.so +0 -0
  19. eth_portfolio/_loaders/_nonce.py +196 -0
  20. eth_portfolio/_loaders/balances.cpython-313-darwin.so +0 -0
  21. eth_portfolio/_loaders/balances.py +94 -0
  22. eth_portfolio/_loaders/token_transfer.py +217 -0
  23. eth_portfolio/_loaders/transaction.py +240 -0
  24. eth_portfolio/_loaders/utils.cpython-313-darwin.so +0 -0
  25. eth_portfolio/_loaders/utils.py +68 -0
  26. eth_portfolio/_shitcoins.cpython-313-darwin.so +0 -0
  27. eth_portfolio/_shitcoins.py +329 -0
  28. eth_portfolio/_stableish.cpython-313-darwin.so +0 -0
  29. eth_portfolio/_stableish.py +42 -0
  30. eth_portfolio/_submodules.py +73 -0
  31. eth_portfolio/_utils.py +225 -0
  32. eth_portfolio/_ydb/__init__.py +0 -0
  33. eth_portfolio/_ydb/token_transfers.py +145 -0
  34. eth_portfolio/address.py +397 -0
  35. eth_portfolio/buckets.py +194 -0
  36. eth_portfolio/constants.cpython-313-darwin.so +0 -0
  37. eth_portfolio/constants.py +82 -0
  38. eth_portfolio/portfolio.py +661 -0
  39. eth_portfolio/protocols/__init__.py +67 -0
  40. eth_portfolio/protocols/_base.py +108 -0
  41. eth_portfolio/protocols/convex.py +17 -0
  42. eth_portfolio/protocols/dsr.py +51 -0
  43. eth_portfolio/protocols/lending/README.md +6 -0
  44. eth_portfolio/protocols/lending/__init__.py +50 -0
  45. eth_portfolio/protocols/lending/_base.py +57 -0
  46. eth_portfolio/protocols/lending/compound.py +187 -0
  47. eth_portfolio/protocols/lending/liquity.py +110 -0
  48. eth_portfolio/protocols/lending/maker.py +104 -0
  49. eth_portfolio/protocols/lending/unit.py +46 -0
  50. eth_portfolio/protocols/liquity.py +16 -0
  51. eth_portfolio/py.typed +0 -0
  52. eth_portfolio/structs/__init__.py +43 -0
  53. eth_portfolio/structs/modified.py +69 -0
  54. eth_portfolio/structs/structs.py +637 -0
  55. eth_portfolio/typing/__init__.py +1447 -0
  56. eth_portfolio/typing/balance/single.py +176 -0
  57. eth_portfolio__mypyc.cpython-313-darwin.so +0 -0
  58. eth_portfolio_scripts/__init__.py +20 -0
  59. eth_portfolio_scripts/_args.py +26 -0
  60. eth_portfolio_scripts/_logging.py +15 -0
  61. eth_portfolio_scripts/_portfolio.py +194 -0
  62. eth_portfolio_scripts/_utils.py +106 -0
  63. eth_portfolio_scripts/balances.cpython-313-darwin.so +0 -0
  64. eth_portfolio_scripts/balances.py +52 -0
  65. eth_portfolio_scripts/docker/.grafana/dashboards/Portfolio/Balances.json +1962 -0
  66. eth_portfolio_scripts/docker/.grafana/dashboards/dashboards.yaml +10 -0
  67. eth_portfolio_scripts/docker/.grafana/datasources/datasources.yml +11 -0
  68. eth_portfolio_scripts/docker/__init__.cpython-313-darwin.so +0 -0
  69. eth_portfolio_scripts/docker/__init__.py +16 -0
  70. eth_portfolio_scripts/docker/check.cpython-313-darwin.so +0 -0
  71. eth_portfolio_scripts/docker/check.py +67 -0
  72. eth_portfolio_scripts/docker/docker-compose.yaml +61 -0
  73. eth_portfolio_scripts/docker/docker_compose.cpython-313-darwin.so +0 -0
  74. eth_portfolio_scripts/docker/docker_compose.py +96 -0
  75. eth_portfolio_scripts/main.py +119 -0
  76. eth_portfolio_scripts/py.typed +1 -0
  77. eth_portfolio_scripts/victoria/__init__.py +73 -0
  78. eth_portfolio_scripts/victoria/types.py +38 -0
  79. eth_portfolio_temp-0.2.15.dist-info/METADATA +26 -0
  80. eth_portfolio_temp-0.2.15.dist-info/RECORD +83 -0
  81. eth_portfolio_temp-0.2.15.dist-info/WHEEL +6 -0
  82. eth_portfolio_temp-0.2.15.dist-info/entry_points.txt +2 -0
  83. eth_portfolio_temp-0.2.15.dist-info/top_level.txt +3 -0
@@ -0,0 +1,145 @@
1
+ from abc import abstractmethod
2
+ from asyncio import Task, create_task, sleep
3
+ from logging import DEBUG, getLogger
4
+ from typing import Any, AsyncIterator, Final, List
5
+
6
+ import dank_mids
7
+ import evmspec
8
+ import y._db.log
9
+ from a_sync import ASyncIterable, ASyncIterator, as_yielded
10
+ from brownie import chain
11
+ from eth_typing import BlockNumber, ChecksumAddress
12
+ from faster_eth_abi import encode
13
+ from faster_eth_utils import encode_hex
14
+ from y.utils.events import ProcessedEvents
15
+
16
+ from eth_portfolio._loaders import load_token_transfer
17
+ from eth_portfolio._shitcoins import SHITCOINS
18
+ from eth_portfolio.constants import TRANSFER_SIGS
19
+ from eth_portfolio.structs import TokenTransfer
20
+
21
+
22
+ logger: Final = getLogger(__name__)
23
+ _logger_is_enabled_for: Final = logger.isEnabledFor
24
+ _logger_log: Final = logger._log
25
+
26
+
27
+ def encode_address(address: Any) -> bytes:
28
+ return encode_hex(encode(["address"], [str(address)]))
29
+
30
+
31
+ class _TokenTransfers(ProcessedEvents["Task[TokenTransfer]"]):
32
+ """A helper mixin that contains all logic for fetching token transfers for a particular wallet address"""
33
+
34
+ __slots__ = "address", "_load_prices"
35
+
36
+ def __init__(
37
+ self,
38
+ address: ChecksumAddress,
39
+ from_block: BlockNumber,
40
+ load_prices: bool = False,
41
+ ) -> None:
42
+ self.address: Final = address
43
+ self._load_prices: Final = load_prices
44
+ super().__init__(topics=self._topics, from_block=from_block)
45
+
46
+ def __repr__(self) -> str:
47
+ return f"{self.__class__.__name__}(address={self.address})"
48
+
49
+ @property
50
+ @abstractmethod
51
+ def _topics(self) -> List: ...
52
+
53
+ @ASyncIterator.wrap # type: ignore [call-overload]
54
+ async def yield_thru_block(self, block: BlockNumber) -> AsyncIterator["Task[TokenTransfer]"]:
55
+ if not _logger_is_enabled_for(DEBUG):
56
+ async for task in self._objects_thru(block=block):
57
+ yield task
58
+ return
59
+
60
+ _logger_log(DEBUG, "%s yielding all objects thru block %s", (self, block))
61
+ async for task in self._objects_thru(block=block):
62
+ _logger_log(
63
+ DEBUG,
64
+ "yielding %s at block %s [thru: %s, lock: %s]",
65
+ (task, task.block, block, self._lock.value),
66
+ )
67
+ yield task
68
+ _logger_log(DEBUG, "%s yield thru %s complete", (self, block))
69
+
70
+ async def _extend(self, objs: List[evmspec.Log]) -> None:
71
+ shitcoins = SHITCOINS.get(chain.id, set())
72
+ append_loader_task = self._objects.append
73
+ done = 0
74
+ for log in objs:
75
+ if log.address in shitcoins:
76
+ continue
77
+ # save i/o
78
+ array_encodable_log = y._db.log.Log(**log)
79
+ task = create_task(load_token_transfer(array_encodable_log, self._load_prices))
80
+ task.block = log.block # type: ignore [attr-defined]
81
+ append_loader_task(task)
82
+ done += 1
83
+ # Make sure the event loop doesn't get blocked
84
+ if done % 100 == 0:
85
+ await sleep(0)
86
+
87
+ def _get_block_for_obj(self, task: "Task[TokenTransfer]") -> int:
88
+ return task.block # type: ignore [attr-defined]
89
+
90
+ def _process_event(self, task: "Task[TokenTransfer]") -> "Task[TokenTransfer]":
91
+ return task
92
+
93
+ def _done_callback(self, task: Task) -> None:
94
+ if e := task.exception():
95
+ self._exc = e
96
+ logger.exception(e)
97
+ raise e
98
+
99
+
100
+ class InboundTokenTransfers(_TokenTransfers):
101
+ """A container that fetches and iterates over all inbound token transfers for a particular wallet address"""
102
+
103
+ @property
104
+ def _topics(self) -> List:
105
+ return [TRANSFER_SIGS, None, encode_address(self.address)]
106
+
107
+
108
+ class OutboundTokenTransfers(_TokenTransfers):
109
+ """A container that fetches and iterates over all outbound token transfers for a particular wallet address"""
110
+
111
+ @property
112
+ def _topics(self) -> List:
113
+ return [TRANSFER_SIGS, encode_address(self.address)]
114
+
115
+
116
+ class TokenTransfers(ASyncIterable[TokenTransfer]):
117
+ """
118
+ A container that fetches and iterates over all token transfers for a particular wallet address.
119
+ NOTE: These do not come back in chronologcal order.
120
+ """
121
+
122
+ def __init__(
123
+ self,
124
+ address: ChecksumAddress,
125
+ from_block: BlockNumber,
126
+ load_prices: bool = False,
127
+ ) -> None:
128
+ self.transfers_in: Final = InboundTokenTransfers(
129
+ address, from_block, load_prices=load_prices
130
+ )
131
+ self.transfers_out: Final = OutboundTokenTransfers(
132
+ address, from_block, load_prices=load_prices
133
+ )
134
+
135
+ async def __aiter__(self) -> AsyncIterator["Task[TokenTransfer]"]:
136
+ async for transfer in self.__yield_thru_block(await dank_mids.eth.block_number):
137
+ yield transfer
138
+
139
+ def yield_thru_block(self, block: BlockNumber) -> ASyncIterator["Task[TokenTransfer]"]:
140
+ return ASyncIterator(self.__yield_thru_block(block))
141
+
142
+ def __yield_thru_block(self, block: BlockNumber) -> AsyncIterator["Task[TokenTransfer]"]:
143
+ return as_yielded(
144
+ self.transfers_in.yield_thru_block(block), self.transfers_out.yield_thru_block(block)
145
+ )
@@ -0,0 +1,397 @@
1
+ """
2
+ This module defines the :class:`~PortfolioAddress` class, which represents an address managed by the `eth-portfolio` system.
3
+ The :class:`~PortfolioAddress` class is designed to manage different aspects of an Ethereum address within the portfolio,
4
+ such as transactions, transfers, balances, and interactions with both external and lending protocols.
5
+
6
+ Key components and functionalities provided by the :class:`~eth_portfolio.address.PortfolioAddress` class include:
7
+ - Handling Ethereum and token balances
8
+ - Managing debt and collateral from lending protocols
9
+ - Tracking transactions and transfers (both internal and token transfers)
10
+ - Providing comprehensive balance descriptions at specific block heights
11
+
12
+ The class leverages asynchronous operations using the `a_sync` library to efficiently gather and process data.
13
+ It also integrates with various submodules from `eth-portfolio` to load balances, manage ledgers, and interact
14
+ with external protocols.
15
+ """
16
+
17
+ import logging
18
+ from asyncio import Task, create_task, gather
19
+ from typing import Dict, Final, Optional, final
20
+
21
+ import a_sync
22
+ import dank_mids
23
+ import eth_retry
24
+ import y
25
+ from a_sync.exceptions import MappingIsEmptyError
26
+ from eth_typing import BlockNumber
27
+ from y import convert
28
+ from y._decorators import stuck_coro_debugger
29
+ from y.datatypes import Address, Block
30
+
31
+ from eth_portfolio import protocols
32
+ from eth_portfolio._ledgers.address import (
33
+ AddressInternalTransfersLedger,
34
+ AddressLedgerBase,
35
+ AddressTokenTransfersLedger,
36
+ AddressTransactionsLedger,
37
+ PandableLedgerEntryList,
38
+ )
39
+ from eth_portfolio._loaders import balances
40
+ from eth_portfolio._utils import _LedgeredBase, _get_price
41
+ from eth_portfolio.typing import Balance, RemoteTokenBalances, TokenBalances, WalletBalances
42
+
43
+
44
+ logger: Final = logging.getLogger(__name__)
45
+
46
+ checksum: Final = convert.to_address
47
+
48
+
49
+ @final
50
+ class PortfolioAddress(_LedgeredBase[AddressLedgerBase]):
51
+ """
52
+ Represents a portfolio address within the eth-portfolio system.
53
+
54
+ This class is designed to manage different aspects of an Ethereum address within the portfolio,
55
+ such as transactions, transfers, balances, and interactions with both external and lending protocols.
56
+
57
+ Key components and functionalities provided by the :class:`~eth_portfolio.address.PortfolioAddress` class include:
58
+ - Handling Ethereum and token balances
59
+ - Managing debt and collateral from lending protocols
60
+ - Tracking transactions and transfers (both internal and token transfers)
61
+ - Providing comprehensive balance descriptions at specific block heights
62
+
63
+ The class leverages asynchronous operations using the `a_sync` library to efficiently gather and process data.
64
+ It also integrates with various submodules from `eth-portfolio` to load balances, manage ledgers, and interact
65
+ with external protocols.
66
+ """
67
+
68
+ def __init__(
69
+ self,
70
+ address: Address,
71
+ start_block: Block,
72
+ load_prices: bool,
73
+ num_workers_transactions: int = 1000,
74
+ asynchronous: bool = False,
75
+ ) -> None: # type: ignore
76
+ """
77
+ Initializes the :class:`~PortfolioAddress` instance.
78
+
79
+ Args:
80
+ address: The Ethereum address to manage.
81
+ start_block: The block number from which to start tracking.
82
+ load_prices: Flag indicating if price loading is enabled.
83
+ num_workers_transactions (optional): Number of workers for transaction processing. Defaults to 1000.
84
+ asynchronous (optional): Flag for asynchronous operation. Defaults to False.
85
+
86
+ Raises:
87
+ TypeError: If `asynchronous` is not a boolean.
88
+
89
+ Examples:
90
+ >>> address = PortfolioAddress('0x1234...', 0, True)
91
+ >>> print(address)
92
+
93
+ >>> address = PortfolioAddress('0x1234...', 0, False, num_workers_transactions=500, asynchronous=True)
94
+ >>> print(address)
95
+
96
+ See Also:
97
+ - :class:`~eth_portfolio.portfolio.Portfolio`
98
+ - :class:`~eth_portfolio._ledgers.address.AddressTransactionsLedger`
99
+ - :class:`~eth_portfolio._ledgers.address.AddressInternalTransfersLedger`
100
+ - :class:`~eth_portfolio._ledgers.address.AddressTokenTransfersLedger`
101
+ """
102
+ self.address: Final = convert.to_address(address)
103
+ """
104
+ The address being managed.
105
+ """
106
+ if not isinstance(asynchronous, bool):
107
+ raise TypeError(f"`asynchronous` must be a boolean, you passed {type(asynchronous)}")
108
+
109
+ self.asynchronous: Final = asynchronous
110
+ """
111
+ Flag indicating if the operations are asynchronous.
112
+ """
113
+
114
+ self.load_prices: Final = load_prices
115
+ """
116
+ Indicates if price loading is enabled.
117
+ """
118
+
119
+ super().__init__(start_block)
120
+
121
+ self.transactions: Final = AddressTransactionsLedger(self, num_workers_transactions) # type: ignore [misc]
122
+ """
123
+ Ledger for tracking transactions.
124
+ """
125
+
126
+ self.internal_transfers: Final = AddressInternalTransfersLedger(self) # type: ignore [misc]
127
+ """
128
+ Ledger for tracking internal transfers.
129
+ """
130
+
131
+ self.token_transfers: Final = AddressTokenTransfersLedger(self) # type: ignore [misc]
132
+ """
133
+ Ledger for tracking token transfers.
134
+ """
135
+
136
+ def __str__(self) -> str:
137
+ """
138
+ Returns the string representation of the address.
139
+
140
+ Returns:
141
+ The address as a string.
142
+ """
143
+ return self.address
144
+
145
+ def __repr__(self) -> str:
146
+ """
147
+ Returns the string representation of the PortfolioAddress instance.
148
+
149
+ Returns:
150
+ The string representation.
151
+ """
152
+ return f"<{self.__class__.__name__} address={self.address} at {hex(id(self))}>"
153
+
154
+ def __eq__(self, other: object) -> bool:
155
+ """
156
+ Checks equality with another object.
157
+
158
+ Args:
159
+ other: The object to compare with.
160
+
161
+ Returns:
162
+ True if equal, False otherwise.
163
+ """
164
+ if isinstance(other, PortfolioAddress):
165
+ return self.address == other.address
166
+ elif isinstance(other, str):
167
+ return self.address == checksum(other)
168
+ return False
169
+
170
+ def __hash__(self) -> int:
171
+ """
172
+ Returns the hash of the address.
173
+
174
+ Returns:
175
+ The hash value.
176
+ """
177
+ return hash(self.address)
178
+
179
+ # Primary functions
180
+
181
+ @stuck_coro_debugger
182
+ async def describe(self, block: int) -> WalletBalances:
183
+ """
184
+ Describes all of the wallet's balances at a given block.
185
+
186
+ Args:
187
+ block: The block number.
188
+
189
+ Returns:
190
+ :class:`~eth_portfolio.typing.WalletBalances`: The wallet balances.
191
+
192
+ Raises:
193
+ TypeError: If block is not an integer.
194
+
195
+ Examples:
196
+ >>> wallet_balances = await address.describe(12345678)
197
+ """
198
+ if not isinstance(block, int):
199
+ raise TypeError(f"Block must be an integer. You passed {type(block)} {block}")
200
+ coros = {
201
+ "assets": self.assets(block, sync=False),
202
+ "debt": self.debt(block, sync=False),
203
+ "external": self.external_balances(block, sync=False),
204
+ }
205
+ return WalletBalances(await a_sync.gather(coros), block=block) # type: ignore [arg-type]
206
+
207
+ @stuck_coro_debugger
208
+ async def assets(self, block: Optional[Block] = None) -> TokenBalances:
209
+ """
210
+ Retrieves the balances for every asset in the wallet at a given block.
211
+
212
+ Args:
213
+ block (optional): The block number to query. Defaults to None, which uses the latest block.
214
+
215
+ Returns:
216
+ :class:`~eth_portfolio.typing.TokenBalances`: The asset balances at `block`.
217
+
218
+ Examples:
219
+ >>> assets = await address.assets(12345678)
220
+ """
221
+ return await self.balances(block=block, sync=False) # type: ignore [return-value]
222
+
223
+ @stuck_coro_debugger
224
+ async def debt(self, block: Optional[Block] = None) -> RemoteTokenBalances:
225
+ """
226
+ Retrieves all debt balances for the wallet at a given block.
227
+
228
+ Args:
229
+ block (optional): The block number. Defaults to None, which uses the latest block.
230
+
231
+ Returns:
232
+ :class:`~eth_portfolio.typing.RemoteTokenBalances`: The debt balances at `block`.
233
+
234
+ Examples:
235
+ >>> debt = await address.debt(12345678)
236
+ """
237
+ return await protocols.lending.debt(self.address, block=block)
238
+
239
+ @stuck_coro_debugger
240
+ async def external_balances(self, block: Optional[Block] = None) -> RemoteTokenBalances:
241
+ """
242
+ Retrieves the balances owned by the wallet, but not held *in* the wallet, at a given block.
243
+
244
+ Args:
245
+ block (optional): The block number. Defaults to None, which uses the latest block.
246
+
247
+ Returns:
248
+ :class:`~eth_portfolio.typing.RemoteTokenBalances`: The external balances.
249
+
250
+ Examples:
251
+ >>> external_balances = await address.external_balances(12345678)
252
+ """
253
+ staking: "Task[RemoteTokenBalances]"
254
+ collateral: RemoteTokenBalances
255
+
256
+ staking = create_task(self.staking(block, sync=False)) # type: ignore [arg-type]
257
+ try:
258
+ collateral = await self.collateral(block, sync=False) # type: ignore [assignment]
259
+ except:
260
+ staking.cancel()
261
+ raise
262
+ else:
263
+ return collateral + await staking
264
+
265
+ # Assets
266
+
267
+ @stuck_coro_debugger
268
+ async def balances(self, block: Optional[Block]) -> TokenBalances:
269
+ """
270
+ Retrieves balances for all assets in the wallet at a given block.
271
+
272
+ Args:
273
+ block: The block number.
274
+
275
+ Returns:
276
+ :class:`~eth_portfolio.typing.TokenBalances`: The balances.
277
+
278
+ Examples:
279
+ >>> balances = await address.balances(12345678)
280
+ """
281
+ eth_balance, token_balances = await gather(
282
+ self.eth_balance(block, sync=False),
283
+ self.token_balances(block, sync=False),
284
+ )
285
+ token_balances[y.EEE_ADDRESS] = eth_balance # type: ignore [call-overload]
286
+ return token_balances # type: ignore [return-value]
287
+
288
+ @eth_retry.auto_retry
289
+ @stuck_coro_debugger
290
+ async def eth_balance(self, block: Optional[Block]) -> Balance:
291
+ """
292
+ Retrieves the ETH balance for the wallet at a given block.
293
+
294
+ Args:
295
+ block: The block number.
296
+
297
+ Returns:
298
+ :class:`~eth_portfolio.typing.Balance`: The ETH balance at `block`.
299
+
300
+ Examples:
301
+ >>> eth_balance = await address.eth_balance(12345678)
302
+ """
303
+ if balance := await dank_mids.eth.get_balance(
304
+ self.address, block_identifier=block # type: ignore [arg-type]
305
+ ): # TODO: move hex into dank
306
+ price = await _get_price(y.WRAPPED_GAS_COIN, block)
307
+ return Balance(
308
+ balance.scaled,
309
+ round(balance.scaled * price, 18),
310
+ token=y.EEE_ADDRESS,
311
+ block=block,
312
+ )
313
+ return Balance(token=y.EEE_ADDRESS, block=block)
314
+
315
+ @stuck_coro_debugger
316
+ async def token_balances(self, block: BlockNumber) -> TokenBalances:
317
+ """
318
+ Retrieves the balances for all tokens in the wallet at a given block.
319
+
320
+ Args:
321
+ block: The block number.
322
+
323
+ Returns:
324
+ :class:`~eth_portfolio.typing.TokenBalances`: The token balances at `block`.
325
+
326
+ Examples:
327
+ >>> token_balances = await address.token_balances(12345678)
328
+ """
329
+ try:
330
+ data = a_sync.map(
331
+ balances.load_token_balance,
332
+ self.token_transfers._yield_tokens_at_block(block=block),
333
+ address=self.address,
334
+ block=block,
335
+ )
336
+ return TokenBalances(await data, block=block)
337
+ except MappingIsEmptyError:
338
+ return TokenBalances(block=block)
339
+
340
+ @stuck_coro_debugger
341
+ async def collateral(self, block: Optional[Block] = None) -> RemoteTokenBalances:
342
+ """
343
+ Retrieves all balances held by lending protocols on behalf of the wallet at a given block.
344
+
345
+ Args:
346
+ block (optional): The block number. Defaults to None, which uses the latest block.
347
+
348
+ Returns:
349
+ :class:`~eth_portfolio.typing.RemoteTokenBalances`: The collateral balances.
350
+
351
+ Examples:
352
+ >>> collateral = await address.collateral(12345678)
353
+ """
354
+ return await protocols.lending.collateral(self.address, block=block)
355
+
356
+ @stuck_coro_debugger
357
+ async def staking(self, block: Optional[Block] = None) -> RemoteTokenBalances:
358
+ """
359
+ Retrieves all balances staked in protocols supported by eth_portfolio on behalf of the wallet at a given block.
360
+
361
+ Args:
362
+ block (optional): The block number. Defaults to None, which uses the latest block.
363
+
364
+ Returns:
365
+ :class:`~eth_portfolio.typing.RemoteTokenBalances`: The staked balances.
366
+
367
+ Examples:
368
+ >>> staking_balances = await address.staking(12345678)
369
+ """
370
+ return await protocols.balances(self.address, block=block)
371
+
372
+ # Ledger Entries
373
+
374
+ @stuck_coro_debugger
375
+ async def all(self, start_block: Block, end_block: Block) -> Dict[str, PandableLedgerEntryList]:
376
+ """
377
+ Retrieves all ledger entries between two blocks.
378
+
379
+ Args:
380
+ start_block: The starting block number.
381
+ end_block: The ending block number.
382
+
383
+ Returns:
384
+ Dict[str, :class:`~eth_portfolio._ledgers.address.PandableLedgerEntryList`]: The ledger entries.
385
+
386
+ Examples:
387
+ >>> all_entries = await address.all(12000000, 12345678)
388
+ """
389
+ return await a_sync.gather(
390
+ {
391
+ "transactions": self.transactions.get(start_block, end_block, sync=False),
392
+ "internal_transactions": self.internal_transfers.get(
393
+ start_block, end_block, sync=False
394
+ ),
395
+ "token_transfers": self.token_transfers.get(start_block, end_block, sync=False),
396
+ }
397
+ )