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.
- eth_portfolio/__init__.py +25 -0
- eth_portfolio/_argspec.cpython-313-darwin.so +0 -0
- eth_portfolio/_argspec.py +42 -0
- eth_portfolio/_cache.py +121 -0
- eth_portfolio/_config.cpython-313-darwin.so +0 -0
- eth_portfolio/_config.py +4 -0
- eth_portfolio/_db/__init__.py +0 -0
- eth_portfolio/_db/decorators.py +147 -0
- eth_portfolio/_db/entities.py +311 -0
- eth_portfolio/_db/utils.py +604 -0
- eth_portfolio/_decimal.py +156 -0
- eth_portfolio/_decorators.py +84 -0
- eth_portfolio/_exceptions.py +67 -0
- eth_portfolio/_ledgers/__init__.py +0 -0
- eth_portfolio/_ledgers/address.py +938 -0
- eth_portfolio/_ledgers/portfolio.py +327 -0
- eth_portfolio/_loaders/__init__.py +33 -0
- eth_portfolio/_loaders/_nonce.cpython-313-darwin.so +0 -0
- eth_portfolio/_loaders/_nonce.py +196 -0
- eth_portfolio/_loaders/balances.cpython-313-darwin.so +0 -0
- eth_portfolio/_loaders/balances.py +94 -0
- eth_portfolio/_loaders/token_transfer.py +217 -0
- eth_portfolio/_loaders/transaction.py +240 -0
- eth_portfolio/_loaders/utils.cpython-313-darwin.so +0 -0
- eth_portfolio/_loaders/utils.py +68 -0
- eth_portfolio/_shitcoins.cpython-313-darwin.so +0 -0
- eth_portfolio/_shitcoins.py +329 -0
- eth_portfolio/_stableish.cpython-313-darwin.so +0 -0
- eth_portfolio/_stableish.py +42 -0
- eth_portfolio/_submodules.py +73 -0
- eth_portfolio/_utils.py +225 -0
- eth_portfolio/_ydb/__init__.py +0 -0
- eth_portfolio/_ydb/token_transfers.py +145 -0
- eth_portfolio/address.py +397 -0
- eth_portfolio/buckets.py +194 -0
- eth_portfolio/constants.cpython-313-darwin.so +0 -0
- eth_portfolio/constants.py +82 -0
- eth_portfolio/portfolio.py +661 -0
- eth_portfolio/protocols/__init__.py +67 -0
- eth_portfolio/protocols/_base.py +108 -0
- eth_portfolio/protocols/convex.py +17 -0
- eth_portfolio/protocols/dsr.py +51 -0
- eth_portfolio/protocols/lending/README.md +6 -0
- eth_portfolio/protocols/lending/__init__.py +50 -0
- eth_portfolio/protocols/lending/_base.py +57 -0
- eth_portfolio/protocols/lending/compound.py +187 -0
- eth_portfolio/protocols/lending/liquity.py +110 -0
- eth_portfolio/protocols/lending/maker.py +104 -0
- eth_portfolio/protocols/lending/unit.py +46 -0
- eth_portfolio/protocols/liquity.py +16 -0
- eth_portfolio/py.typed +0 -0
- eth_portfolio/structs/__init__.py +43 -0
- eth_portfolio/structs/modified.py +69 -0
- eth_portfolio/structs/structs.py +637 -0
- eth_portfolio/typing/__init__.py +1447 -0
- eth_portfolio/typing/balance/single.py +176 -0
- eth_portfolio__mypyc.cpython-313-darwin.so +0 -0
- eth_portfolio_scripts/__init__.py +20 -0
- eth_portfolio_scripts/_args.py +26 -0
- eth_portfolio_scripts/_logging.py +15 -0
- eth_portfolio_scripts/_portfolio.py +194 -0
- eth_portfolio_scripts/_utils.py +106 -0
- eth_portfolio_scripts/balances.cpython-313-darwin.so +0 -0
- eth_portfolio_scripts/balances.py +52 -0
- eth_portfolio_scripts/docker/.grafana/dashboards/Portfolio/Balances.json +1962 -0
- eth_portfolio_scripts/docker/.grafana/dashboards/dashboards.yaml +10 -0
- eth_portfolio_scripts/docker/.grafana/datasources/datasources.yml +11 -0
- eth_portfolio_scripts/docker/__init__.cpython-313-darwin.so +0 -0
- eth_portfolio_scripts/docker/__init__.py +16 -0
- eth_portfolio_scripts/docker/check.cpython-313-darwin.so +0 -0
- eth_portfolio_scripts/docker/check.py +67 -0
- eth_portfolio_scripts/docker/docker-compose.yaml +61 -0
- eth_portfolio_scripts/docker/docker_compose.cpython-313-darwin.so +0 -0
- eth_portfolio_scripts/docker/docker_compose.py +96 -0
- eth_portfolio_scripts/main.py +119 -0
- eth_portfolio_scripts/py.typed +1 -0
- eth_portfolio_scripts/victoria/__init__.py +73 -0
- eth_portfolio_scripts/victoria/types.py +38 -0
- eth_portfolio_temp-0.2.15.dist-info/METADATA +26 -0
- eth_portfolio_temp-0.2.15.dist-info/RECORD +83 -0
- eth_portfolio_temp-0.2.15.dist-info/WHEEL +6 -0
- eth_portfolio_temp-0.2.15.dist-info/entry_points.txt +2 -0
- eth_portfolio_temp-0.2.15.dist-info/top_level.txt +3 -0
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Defines the data classes used to represent the various types of value-transfer actions on the blockchain. These include transactions, internal transfers, and token transfers.
|
|
3
|
+
|
|
4
|
+
The classes are designed to provide a consistent and flexible interface for working with blockchain data. Instance attributes can be fetched with either dot notation or key lookup. Classes are compatible with the standard dictionary interface.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from functools import cached_property
|
|
8
|
+
from typing import (
|
|
9
|
+
Any,
|
|
10
|
+
ClassVar,
|
|
11
|
+
Dict,
|
|
12
|
+
List,
|
|
13
|
+
Literal,
|
|
14
|
+
Optional,
|
|
15
|
+
Tuple,
|
|
16
|
+
TypeVar,
|
|
17
|
+
Union,
|
|
18
|
+
final,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
import evmspec
|
|
22
|
+
from brownie import chain
|
|
23
|
+
from dictstruct import DictStruct
|
|
24
|
+
from evmspec.data import Address, BlockHash, TransactionHash, Wei
|
|
25
|
+
from evmspec.structs.trace import reward
|
|
26
|
+
from evmspec.structs.transaction import AccessListEntry
|
|
27
|
+
from hexbytes import HexBytes
|
|
28
|
+
from msgspec import Struct
|
|
29
|
+
from y import Network
|
|
30
|
+
from y._db.log import Log
|
|
31
|
+
from y._decorators import stuck_coro_debugger
|
|
32
|
+
from y.constants import EEE_ADDRESS
|
|
33
|
+
from y.datatypes import Block
|
|
34
|
+
|
|
35
|
+
from eth_portfolio._decimal import Decimal
|
|
36
|
+
from eth_portfolio._utils import _get_price
|
|
37
|
+
from eth_portfolio.structs.modified import ModifiedTrace, _modified_trace_type_map
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class _LedgerEntryBase(DictStruct, kw_only=True, frozen=True, omit_defaults=True, repr_omit_defaults=True): # type: ignore [call-arg]
|
|
41
|
+
"""
|
|
42
|
+
The :class:`~structs._LedgerEntryBase` class is a base class for ledger entries representing on-chain actions in a blockchain.
|
|
43
|
+
|
|
44
|
+
Provides common attributes for transactions, internal transfers, and token transfers.
|
|
45
|
+
|
|
46
|
+
Extended by specific ledger entry types :class:`~structs.Transaction`, :class:`~structs.InternalTransfer`, and :class:`~structs.TokenTransfer`.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def _evm_object(self) -> Union[evmspec.Transaction, evmspec.FilterTrace, Log]:
|
|
51
|
+
"""
|
|
52
|
+
The EVM object associated with {cls_name}, exactly as it was received from the RPC.
|
|
53
|
+
"""
|
|
54
|
+
return getattr(self, self.entry_type)
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def chainid(self) -> Network:
|
|
58
|
+
"""
|
|
59
|
+
The network ID where the {cls_name} occurred.
|
|
60
|
+
"""
|
|
61
|
+
try:
|
|
62
|
+
return Network(self._evm_object.chainId)
|
|
63
|
+
except AttributeError:
|
|
64
|
+
return Network(chain.id)
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def block_number(self) -> Block:
|
|
68
|
+
"""
|
|
69
|
+
The block number where the {cls_name} was included.
|
|
70
|
+
"""
|
|
71
|
+
return self._evm_object.block
|
|
72
|
+
|
|
73
|
+
price: Optional[Decimal] = None
|
|
74
|
+
"""
|
|
75
|
+
The price of the cryptocurrency at the time of the {cls_name}, if known.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
value_usd: Optional[Decimal] = None
|
|
79
|
+
"""
|
|
80
|
+
The USD value of the cryptocurrency transferred in the {cls_name}, if price is known.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
def __init_subclass__(cls, **kwargs: Any) -> None:
|
|
84
|
+
super().__init_subclass__(**kwargs)
|
|
85
|
+
|
|
86
|
+
# Replace {cls_name} in attribute-level docstrings
|
|
87
|
+
for key, attr in cls.__dict__.items():
|
|
88
|
+
if attr.__doc__ and "{cls_name}" in attr.__doc__:
|
|
89
|
+
attr.__doc__ = attr.__doc__.replace("{cls_name}", cls.__name__)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _get_init_kwargs(original_struct: Struct) -> Dict[str, Any]:
|
|
93
|
+
kwargs = {}
|
|
94
|
+
for key in original_struct.__struct_fields__:
|
|
95
|
+
try:
|
|
96
|
+
kwargs[key] = getattr(original_struct, key)
|
|
97
|
+
except AttributeError:
|
|
98
|
+
continue
|
|
99
|
+
return kwargs
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class _TransactionBase(
|
|
103
|
+
_LedgerEntryBase,
|
|
104
|
+
kw_only=True,
|
|
105
|
+
frozen=True,
|
|
106
|
+
array_like=True,
|
|
107
|
+
forbid_unknown_fields=True,
|
|
108
|
+
omit_defaults=True,
|
|
109
|
+
repr_omit_defaults=True,
|
|
110
|
+
dict=True,
|
|
111
|
+
):
|
|
112
|
+
"""
|
|
113
|
+
The :class:`~structs.Transaction` class represents a complete on-chain blockchain transaction.
|
|
114
|
+
|
|
115
|
+
Contains detailed information about a single executed transaction on the blockchain,
|
|
116
|
+
including gas parameters, signature components, and transaction-specific data.
|
|
117
|
+
|
|
118
|
+
Example:
|
|
119
|
+
>>> tx = Transaction(tx=Transaction1559(...))
|
|
120
|
+
>>> tx.chainid
|
|
121
|
+
Network.Mainnet
|
|
122
|
+
>>> tx.type
|
|
123
|
+
2
|
|
124
|
+
>>> tx.max_fee_per_gas
|
|
125
|
+
30000000000
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
entry_type: ClassVar[Literal["transaction"]] = "transaction"
|
|
129
|
+
"""
|
|
130
|
+
Constant indicating this value transfer is an on-chain transaction entry.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
@classmethod
|
|
134
|
+
def from_rpc_response(
|
|
135
|
+
cls,
|
|
136
|
+
transaction: evmspec.Transaction,
|
|
137
|
+
*,
|
|
138
|
+
price: Optional[Decimal] = None,
|
|
139
|
+
value_usd: Optional[Decimal] = None,
|
|
140
|
+
) -> "Transaction":
|
|
141
|
+
return cls(
|
|
142
|
+
transaction=transaction,
|
|
143
|
+
price=price,
|
|
144
|
+
value_usd=value_usd,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def hash(self) -> TransactionHash:
|
|
149
|
+
"""
|
|
150
|
+
The unique transaction hash.
|
|
151
|
+
"""
|
|
152
|
+
return self.transaction.hash
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def block_hash(self) -> BlockHash:
|
|
156
|
+
"""
|
|
157
|
+
The hash of the block that includes this Transaction.
|
|
158
|
+
"""
|
|
159
|
+
return self.transaction.blockHash
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def transaction_index(self) -> Optional[int]:
|
|
163
|
+
"""
|
|
164
|
+
The index of the transaction within its block, if applicable.
|
|
165
|
+
"""
|
|
166
|
+
return self.transaction.transactionIndex
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def nonce(self) -> int:
|
|
170
|
+
"""
|
|
171
|
+
The sender's transaction count at the time of this Transaction.
|
|
172
|
+
"""
|
|
173
|
+
return self.transaction.nonce
|
|
174
|
+
|
|
175
|
+
@cached_property
|
|
176
|
+
def type(self) -> Optional[int]:
|
|
177
|
+
"""
|
|
178
|
+
The transaction type (e.g., 0 for legacy, 1 for EIP-2930, 2 for EIP-1559).
|
|
179
|
+
None for chains that don't specify transaction types.
|
|
180
|
+
"""
|
|
181
|
+
if typ := self.transaction.type:
|
|
182
|
+
return int(typ.hex(), 16)
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def from_address(self) -> Optional[Address]:
|
|
186
|
+
"""
|
|
187
|
+
The address from which the transaction was sent, if applicable.
|
|
188
|
+
"""
|
|
189
|
+
return self.transaction.sender
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def to_address(self) -> Optional[Address]:
|
|
193
|
+
"""
|
|
194
|
+
The address to which the transaction was sent, if applicable.
|
|
195
|
+
"""
|
|
196
|
+
return self.transaction.to
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def value(self) -> Decimal:
|
|
200
|
+
"""
|
|
201
|
+
The value/amount of cryptocurrency transferred in the transaction, scaled to a human-readable decimal value.
|
|
202
|
+
"""
|
|
203
|
+
return Wei(self.transaction.value).scaled
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def gas(self) -> int:
|
|
207
|
+
"""
|
|
208
|
+
The maximum amount of gas the sender is willing to use for the Transaction.
|
|
209
|
+
"""
|
|
210
|
+
return self.transaction.gas
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def gas_price(self) -> int:
|
|
214
|
+
"""
|
|
215
|
+
The price per unit of gas the sender is willing to pay (for legacy and EIP-2930 transactions).
|
|
216
|
+
"""
|
|
217
|
+
return self.transaction.gasPrice
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def max_fee_per_gas(self) -> Optional[int]:
|
|
221
|
+
"""
|
|
222
|
+
The maximum total fee per gas the sender is willing to pay (for EIP-1559 transactions only).
|
|
223
|
+
"""
|
|
224
|
+
return self.transaction.maxFeePerGas
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def max_priority_fee_per_gas(self) -> Optional[int]:
|
|
228
|
+
"""
|
|
229
|
+
The maximum priority fee per gas the sender is willing to pay (for EIP-1559 transactions only).
|
|
230
|
+
"""
|
|
231
|
+
return self.transaction.maxPriorityFeePerGas
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def input(self) -> HexBytes:
|
|
235
|
+
"""
|
|
236
|
+
The data payload sent with the Transaction, often used for contract interactions.
|
|
237
|
+
"""
|
|
238
|
+
return self.transaction.input
|
|
239
|
+
|
|
240
|
+
@property
|
|
241
|
+
def r(self) -> HexBytes:
|
|
242
|
+
"""
|
|
243
|
+
The R component of the Transaction's ECDSA signature.
|
|
244
|
+
"""
|
|
245
|
+
return self.transaction.r
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def s(self) -> HexBytes:
|
|
249
|
+
"""
|
|
250
|
+
The S component of the Transaction's ECDSA signature.
|
|
251
|
+
"""
|
|
252
|
+
return self.transaction.s
|
|
253
|
+
|
|
254
|
+
@property
|
|
255
|
+
def v(self) -> int:
|
|
256
|
+
"""
|
|
257
|
+
The V component of the Transaction's ECDSA signature, used for replay protection.
|
|
258
|
+
"""
|
|
259
|
+
return self.transaction.v
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def access_list(self) -> Optional[Tuple[AccessListEntry, ...]]:
|
|
263
|
+
"""
|
|
264
|
+
List of addresses and storage keys the transaction plans to access (for EIP-2930 and EIP-1559 transactions).
|
|
265
|
+
"""
|
|
266
|
+
return self.transaction.accessList
|
|
267
|
+
|
|
268
|
+
@property
|
|
269
|
+
def y_parity(self) -> Optional[int]:
|
|
270
|
+
"""
|
|
271
|
+
The Y parity of the transaction signature, used in EIP-2718 typed transactions.
|
|
272
|
+
"""
|
|
273
|
+
return self.transaction.yParity
|
|
274
|
+
|
|
275
|
+
@property
|
|
276
|
+
def __db_primary_key__(self) -> Dict[str, tuple[int, Address] | int]:
|
|
277
|
+
return {"from_address": (chain.id, self.from_address), "nonce": self.nonce}
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
@final
|
|
281
|
+
class Transaction(
|
|
282
|
+
_TransactionBase,
|
|
283
|
+
kw_only=True,
|
|
284
|
+
frozen=True,
|
|
285
|
+
array_like=True,
|
|
286
|
+
forbid_unknown_fields=True,
|
|
287
|
+
omit_defaults=True,
|
|
288
|
+
repr_omit_defaults=True,
|
|
289
|
+
dict=True,
|
|
290
|
+
):
|
|
291
|
+
|
|
292
|
+
transaction: evmspec.Transaction
|
|
293
|
+
"""
|
|
294
|
+
The transaction object received by calling eth_getTransactionByHash.
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@final
|
|
299
|
+
class TransactionRLP(
|
|
300
|
+
_TransactionBase,
|
|
301
|
+
kw_only=True,
|
|
302
|
+
frozen=True,
|
|
303
|
+
array_like=True,
|
|
304
|
+
forbid_unknown_fields=True,
|
|
305
|
+
omit_defaults=True,
|
|
306
|
+
repr_omit_defaults=True,
|
|
307
|
+
dict=True,
|
|
308
|
+
):
|
|
309
|
+
|
|
310
|
+
transaction: evmspec.TransactionRLP
|
|
311
|
+
"""
|
|
312
|
+
The transaction object received by calling eth_getTransactionByHash.
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
@final
|
|
317
|
+
class InternalTransfer(
|
|
318
|
+
_LedgerEntryBase,
|
|
319
|
+
kw_only=True,
|
|
320
|
+
frozen=True,
|
|
321
|
+
array_like=True,
|
|
322
|
+
forbid_unknown_fields=True,
|
|
323
|
+
omit_defaults=True,
|
|
324
|
+
repr_omit_defaults=True,
|
|
325
|
+
):
|
|
326
|
+
"""
|
|
327
|
+
The :class:`~structs.InternalTransfer`class represents an internal transfer or call within a blockchain transaction.
|
|
328
|
+
|
|
329
|
+
Captures operations that occur during transaction execution, such as contract-to-contract calls,
|
|
330
|
+
contract creations, or self-destructs. These are not separate on-chain transactions but part of
|
|
331
|
+
the execution of a single transaction.
|
|
332
|
+
|
|
333
|
+
Example:
|
|
334
|
+
>>> internal_tx = InternalTransfer(trace=evmspec.FilterTrace(...), ...)
|
|
335
|
+
>>> internal_tx.type
|
|
336
|
+
'call'
|
|
337
|
+
>>> internal_tx.trace_address
|
|
338
|
+
'0.1'
|
|
339
|
+
>>> internal_tx.gas_used
|
|
340
|
+
21000
|
|
341
|
+
"""
|
|
342
|
+
|
|
343
|
+
@staticmethod
|
|
344
|
+
@stuck_coro_debugger
|
|
345
|
+
async def from_trace(trace: evmspec.FilterTrace, load_prices: bool) -> "InternalTransfer":
|
|
346
|
+
# sourcery skip: simplify-boolean-comparison
|
|
347
|
+
"""
|
|
348
|
+
Asynchronously processes a raw internal transfer dictionary into an InternalTransfer object.
|
|
349
|
+
|
|
350
|
+
This function is the core of the internal transfer processing pipeline. It handles
|
|
351
|
+
various types of transfers, including special cases like block and uncle rewards.
|
|
352
|
+
It also filters out certain transfers (e.g., to Gnosis Safe Singleton) and verifies
|
|
353
|
+
transaction success for non-reward transfers.
|
|
354
|
+
|
|
355
|
+
The function performs several data transformations:
|
|
356
|
+
- Value and gas conversions
|
|
357
|
+
- Optional USD price loading
|
|
358
|
+
- Field standardization
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
transfer: A dictionary containing the raw internal transfer data. Expected to have keys such as
|
|
362
|
+
'type', 'transactionHash', 'blockNumber', 'from', 'to', 'value', 'gas', 'gasUsed', 'traceAddress'.
|
|
363
|
+
load_prices: Flag to determine whether to load USD prices for the transfer value.
|
|
364
|
+
|
|
365
|
+
Returns:
|
|
366
|
+
A processed InternalTransfer object.
|
|
367
|
+
|
|
368
|
+
Example:
|
|
369
|
+
>>> transfer = {"type": "call", "transactionHash": "0x123...", "blockNumber": 15537393, "from": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "to": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", "value": "0x10", "gas": "0x5208", "gasUsed": "0x5208", "traceAddress": [0]}
|
|
370
|
+
>>> internal_tx = await load_internal_transfer(transfer=transfer, load_prices=True); print(internal_tx)
|
|
371
|
+
|
|
372
|
+
Note:
|
|
373
|
+
- Transfers to the Gnosis Safe Singleton (0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552) are filtered out
|
|
374
|
+
as they typically don't represent actual value transfers.
|
|
375
|
+
- The `traceAddress` is converted to a string for consistent representation across different scenarios.
|
|
376
|
+
- For block and uncle rewards, `gas` is set to 0 as these are not regular transactions.
|
|
377
|
+
- When loading prices, the `EEE_ADDRESS` constant is used, which represents the native currency of the chain.
|
|
378
|
+
|
|
379
|
+
Integration with eth_portfolio ecosystem:
|
|
380
|
+
- Uses the InternalTransfer struct from eth_portfolio.structs for standardized output.
|
|
381
|
+
- Utilizes utility functions from eth_portfolio._loaders.utils and eth_portfolio._utils.
|
|
382
|
+
- Interacts with the global 'chain' object from the brownie library for chain ID.
|
|
383
|
+
"""
|
|
384
|
+
|
|
385
|
+
modified_cls = _modified_trace_type_map[type(trace)]
|
|
386
|
+
modified_trace = modified_cls(**_get_init_kwargs(trace))
|
|
387
|
+
|
|
388
|
+
if load_prices is False:
|
|
389
|
+
return InternalTransfer(trace=modified_trace)
|
|
390
|
+
|
|
391
|
+
price = await _get_price(EEE_ADDRESS, trace.block)
|
|
392
|
+
value_usd = round(trace.action.value.scaled * price, 18)
|
|
393
|
+
return InternalTransfer(trace=modified_trace, price=price, value_usd=value_usd)
|
|
394
|
+
|
|
395
|
+
entry_type: ClassVar[Literal["internal_transfer"]] = "internal_transfer"
|
|
396
|
+
"""
|
|
397
|
+
Constant indicating this value transfer is an internal transfer or call entry.
|
|
398
|
+
"""
|
|
399
|
+
|
|
400
|
+
@property
|
|
401
|
+
def _evm_object(self) -> ModifiedTrace:
|
|
402
|
+
return self.trace
|
|
403
|
+
|
|
404
|
+
trace: ModifiedTrace
|
|
405
|
+
"""
|
|
406
|
+
The raw trace object associated with this internal transfer.
|
|
407
|
+
"""
|
|
408
|
+
|
|
409
|
+
@property
|
|
410
|
+
def block_hash(self) -> HexBytes:
|
|
411
|
+
"""
|
|
412
|
+
The hash of the block containing the transaction that includes this InternalTransfer.
|
|
413
|
+
"""
|
|
414
|
+
return self.trace.blockHash
|
|
415
|
+
|
|
416
|
+
@property
|
|
417
|
+
def transaction_index(self) -> Optional[int]:
|
|
418
|
+
"""
|
|
419
|
+
The index of the transaction within its block, if applicable.
|
|
420
|
+
"""
|
|
421
|
+
return self.trace.transactionPosition
|
|
422
|
+
|
|
423
|
+
@property
|
|
424
|
+
def hash(self) -> Union[HexBytes, str]:
|
|
425
|
+
"""
|
|
426
|
+
The unique hash of the transaction containing this internal transfer.
|
|
427
|
+
"""
|
|
428
|
+
return (
|
|
429
|
+
f"{self.trace.action.rewardType.name} reward"
|
|
430
|
+
if isinstance(self.trace, reward.Trace)
|
|
431
|
+
else self.trace.transactionHash
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
@property
|
|
435
|
+
def from_address(self) -> Address:
|
|
436
|
+
"""
|
|
437
|
+
The address from which the internal transfer was sent, if applicable.
|
|
438
|
+
"""
|
|
439
|
+
return self.trace.action.sender
|
|
440
|
+
|
|
441
|
+
@property
|
|
442
|
+
def to_address(self) -> Optional[Address]:
|
|
443
|
+
"""
|
|
444
|
+
The address to which the internal transfer was sent, if applicable.
|
|
445
|
+
"""
|
|
446
|
+
action = self.trace.action
|
|
447
|
+
# NOTE: for block reward transfers, the recipient is 'author'
|
|
448
|
+
return action.author if isinstance(action, reward.Action) else action.to
|
|
449
|
+
|
|
450
|
+
@property
|
|
451
|
+
def value(self) -> Decimal:
|
|
452
|
+
"""
|
|
453
|
+
The value/amount of cryptocurrency transferred in the internal transfer, scaled to a human-readable decimal value.
|
|
454
|
+
"""
|
|
455
|
+
return self.trace.action.value.scaled
|
|
456
|
+
|
|
457
|
+
@property
|
|
458
|
+
def type(self) -> Literal["call", "create", "reward", "suicide"]:
|
|
459
|
+
return self.trace.type
|
|
460
|
+
|
|
461
|
+
@property
|
|
462
|
+
def trace_address(self) -> List[int]:
|
|
463
|
+
"""
|
|
464
|
+
The path of sub-calls to reach this InternalTransfer within the transaction,
|
|
465
|
+
|
|
466
|
+
Example:
|
|
467
|
+
- The following trace_address
|
|
468
|
+
```python
|
|
469
|
+
[0, 1, 2]
|
|
470
|
+
```
|
|
471
|
+
represents the third sub-call of the second sub-call of the first top-level call.
|
|
472
|
+
"""
|
|
473
|
+
return self.trace.traceAddress
|
|
474
|
+
|
|
475
|
+
@property
|
|
476
|
+
def gas(self) -> int:
|
|
477
|
+
"""
|
|
478
|
+
The amount of gas allocated for this internal operation.
|
|
479
|
+
"""
|
|
480
|
+
return 0 if isinstance(self.trace, reward.Trace) else self.trace.action.gas
|
|
481
|
+
|
|
482
|
+
@property
|
|
483
|
+
def gas_used(self) -> int:
|
|
484
|
+
"""
|
|
485
|
+
The amount of gas actually consumed by this internal operation, if known.
|
|
486
|
+
"""
|
|
487
|
+
return self.trace.result.gasUsed
|
|
488
|
+
|
|
489
|
+
@property
|
|
490
|
+
def subtraces(self) -> int:
|
|
491
|
+
"""
|
|
492
|
+
The number of sub-operations spawned by this InternalTransfer.
|
|
493
|
+
"""
|
|
494
|
+
return self.trace.subtraces
|
|
495
|
+
|
|
496
|
+
@property
|
|
497
|
+
def call_type(self) -> Optional[str]:
|
|
498
|
+
"""
|
|
499
|
+
The type of call made in this InternalTransfer (e.g., "call", "delegatecall", "staticcall").
|
|
500
|
+
"""
|
|
501
|
+
return self.trace.action.callType.name
|
|
502
|
+
|
|
503
|
+
@property
|
|
504
|
+
def reward_type(self) -> Optional[str]:
|
|
505
|
+
"""
|
|
506
|
+
The type of the reward, for reward transactions.
|
|
507
|
+
"""
|
|
508
|
+
return self.trace.action.rewardType.name
|
|
509
|
+
|
|
510
|
+
@property
|
|
511
|
+
def input(self) -> HexBytes:
|
|
512
|
+
"""
|
|
513
|
+
The input data for this internal operation, if any.
|
|
514
|
+
"""
|
|
515
|
+
return self.trace.action.input
|
|
516
|
+
|
|
517
|
+
@property
|
|
518
|
+
def output(self) -> HexBytes:
|
|
519
|
+
"""
|
|
520
|
+
The output data from this internal operation, if any.
|
|
521
|
+
"""
|
|
522
|
+
return self.trace.result.output
|
|
523
|
+
|
|
524
|
+
'''
|
|
525
|
+
init: Optional[HexBytes] = UNSET
|
|
526
|
+
"""
|
|
527
|
+
The initialization code for contract creation, if this is a create operation.
|
|
528
|
+
"""
|
|
529
|
+
|
|
530
|
+
address: Optional[HexBytes] = UNSET
|
|
531
|
+
"""
|
|
532
|
+
The address of the account or contract involved in this InternalTransfer.
|
|
533
|
+
"""
|
|
534
|
+
|
|
535
|
+
code: Optional[HexBytes] = UNSET
|
|
536
|
+
"""
|
|
537
|
+
The code of the contract involved in this InternalTransfer, if applicable.
|
|
538
|
+
"""
|
|
539
|
+
'''
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
@final
|
|
543
|
+
class TokenTransfer(
|
|
544
|
+
_LedgerEntryBase,
|
|
545
|
+
kw_only=True,
|
|
546
|
+
frozen=True,
|
|
547
|
+
array_like=True,
|
|
548
|
+
forbid_unknown_fields=True,
|
|
549
|
+
omit_defaults=True,
|
|
550
|
+
):
|
|
551
|
+
"""
|
|
552
|
+
The :class:`~structs.TokenTransfer` class represents a token transfer event within a blockchain transaction.
|
|
553
|
+
|
|
554
|
+
Captures the movement of ERC20-like tokens between addresses. These are typically
|
|
555
|
+
emitted as events by token contracts and are not separate transactions but part of
|
|
556
|
+
the execution of a transaction interacting with the token contract.
|
|
557
|
+
|
|
558
|
+
Example:
|
|
559
|
+
>>> token_transfer = TokenTransfer(
|
|
560
|
+
... log=Log(...),
|
|
561
|
+
... value=Decimal("1000000"), # 1 USDC (assuming 6 decimals)
|
|
562
|
+
... token="USDC",
|
|
563
|
+
... )
|
|
564
|
+
>>> token_transfer.token
|
|
565
|
+
'USDC'
|
|
566
|
+
>>> token_transfer.value
|
|
567
|
+
Decimal('1000000')
|
|
568
|
+
>>> token_transfer.log_index
|
|
569
|
+
3
|
|
570
|
+
"""
|
|
571
|
+
|
|
572
|
+
entry_type: ClassVar[Literal["token_transfer"]] = "token_transfer"
|
|
573
|
+
"""
|
|
574
|
+
Constant indicating this value transfer is a token transfer entry.
|
|
575
|
+
"""
|
|
576
|
+
|
|
577
|
+
log: Log
|
|
578
|
+
"""
|
|
579
|
+
The log associated with this token transfer.
|
|
580
|
+
"""
|
|
581
|
+
|
|
582
|
+
@property
|
|
583
|
+
def from_address(self) -> Address:
|
|
584
|
+
return self.log.topic1.as_address
|
|
585
|
+
|
|
586
|
+
@property
|
|
587
|
+
def to_address(self) -> Address:
|
|
588
|
+
return self.log.topic2.as_address
|
|
589
|
+
|
|
590
|
+
@property
|
|
591
|
+
def _evm_object(self) -> Log:
|
|
592
|
+
return self.log
|
|
593
|
+
|
|
594
|
+
transaction_index: int
|
|
595
|
+
|
|
596
|
+
@property
|
|
597
|
+
def log_index(self) -> int:
|
|
598
|
+
"""
|
|
599
|
+
The index of this transfer event within the transaction logs.
|
|
600
|
+
Used to uniquely identify the Transfer event associated with this TokenTransfer within the transaction.
|
|
601
|
+
"""
|
|
602
|
+
return self.log.logIndex
|
|
603
|
+
|
|
604
|
+
token: Optional[str]
|
|
605
|
+
"""
|
|
606
|
+
The symbol of the token being transferred, if known.
|
|
607
|
+
"""
|
|
608
|
+
|
|
609
|
+
@property
|
|
610
|
+
def hash(self) -> HexBytes:
|
|
611
|
+
"""
|
|
612
|
+
The unique hash of the transaction containing this token transfer.
|
|
613
|
+
"""
|
|
614
|
+
return self.log.transactionHash
|
|
615
|
+
|
|
616
|
+
@property
|
|
617
|
+
def token_address(self) -> Address:
|
|
618
|
+
"""
|
|
619
|
+
The contract address of the token being transferred.
|
|
620
|
+
"""
|
|
621
|
+
return self.log.address
|
|
622
|
+
|
|
623
|
+
value: Decimal
|
|
624
|
+
"""
|
|
625
|
+
The amount of tokens transferred, scaled to a human-readable decimal value.
|
|
626
|
+
"""
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
LedgerEntry = Union[Transaction, InternalTransfer, TokenTransfer]
|
|
630
|
+
"""
|
|
631
|
+
Type alias representing any type of ledger entry (:class:`~structs.Transaction`, :class:`~structs.InternalTransfer`, or :class:`~structs.TokenTransfer`).
|
|
632
|
+
"""
|
|
633
|
+
|
|
634
|
+
_LE = TypeVar("_LE", Transaction, InternalTransfer, TokenTransfer)
|
|
635
|
+
"""
|
|
636
|
+
Type variable for generic operations on ledger entries. Can be :class:`~structs.Transaction`, :class:`~structs.InternalTransfer`, or :class:`~structs.TokenTransfer`.
|
|
637
|
+
"""
|