Web3Scout 0.0.7__py3-none-any.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.
- web3scout/__init__.py +37 -0
- web3scout/abi/__init__.py +1 -0
- web3scout/abi/abi_load.py +501 -0
- web3scout/configs/ERC20MockDecimals.json +1 -0
- web3scout/configs/agnostic/UniswapV2Pair.json +667 -0
- web3scout/configs/agnostic/UniswapV3Pool.json +997 -0
- web3scout/configs/erc/ERC20.json +302 -0
- web3scout/configs/erc/ERC20MockDecimals.json +1 -0
- web3scout/configs/sushi/UniswapV2Factory.json +224 -0
- web3scout/configs/sushi/UniswapV2Pair.json +667 -0
- web3scout/configs/sushi/UniswapV2Router02.json +982 -0
- web3scout/configs/uniswap_v3/UniswapV3Factory.json +245 -0
- web3scout/configs/uniswap_v3/UniswapV3Pool.json +997 -0
- web3scout/contract/__utils__.py +2 -0
- web3scout/contract/deploy.py +160 -0
- web3scout/contract/view.py +79 -0
- web3scout/data/__init__.py +2 -0
- web3scout/data/chain_reorganization_resolution.py +48 -0
- web3scout/data/filter.py +55 -0
- web3scout/data/pair.py +172 -0
- web3scout/data/reorganization_monitor.py +427 -0
- web3scout/data/token_details.py +122 -0
- web3scout/enums/__init__.py +2 -0
- web3scout/enums/contracts_enum.py +30 -0
- web3scout/enums/event_type_enum.py +26 -0
- web3scout/enums/init_event_enum.py +44 -0
- web3scout/enums/nets_enum.py +24 -0
- web3scout/enums/platforms_enum.py +23 -0
- web3scout/enums/rpcs_enum.py +40 -0
- web3scout/event/__init__.py +7 -0
- web3scout/event/burn_event.py +110 -0
- web3scout/event/create_event.py +83 -0
- web3scout/event/event.py +26 -0
- web3scout/event/mint_event.py +111 -0
- web3scout/event/process/__init__.py +2 -0
- web3scout/event/process/read_events.py +404 -0
- web3scout/event/process/retrieve_events.py +79 -0
- web3scout/event/swap_event.py +109 -0
- web3scout/event/sync_event.py +92 -0
- web3scout/event/tools/__init__.py +5 -0
- web3scout/event/tools/chain_reorganization_detection.py +18 -0
- web3scout/event/tools/conversion.py +134 -0
- web3scout/event/tools/log_context.py +14 -0
- web3scout/event/tools/log_result.py +100 -0
- web3scout/event/tools/rpc_reorganization_monitor.py +69 -0
- web3scout/event/transfer_event.py +81 -0
- web3scout/token/__init__.py +1 -0
- web3scout/token/fetch/__init__.py +1 -0
- web3scout/token/fetch/fetch_token.py +96 -0
- web3scout/token/token.py +222 -0
- web3scout/uniswap_v2/__init__.py +0 -0
- web3scout/uniswap_v2/fetch_pair_details.py +66 -0
- web3scout/utils/__init__.py +3 -0
- web3scout/utils/base_utils.py +214 -0
- web3scout/utils/connect.py +31 -0
- web3scout/utils/progress_update.py +52 -0
- web3scout-0.0.7.dist-info/METADATA +207 -0
- web3scout-0.0.7.dist-info/RECORD +62 -0
- web3scout-0.0.7.dist-info/WHEEL +5 -0
- web3scout-0.0.7.dist-info/licenses/LICENSE +179 -0
- web3scout-0.0.7.dist-info/licenses/NOTICE +17 -0
- web3scout-0.0.7.dist-info/top_level.txt +1 -0
web3scout/__init__.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# SPDX-Anchored-Identifier: ICMOORE-2025-DEFIPY
|
|
2
|
+
# This file participates in a symbolic cognition substrate.
|
|
3
|
+
|
|
4
|
+
from .abi.abi_load import ABILoad
|
|
5
|
+
from .event.tools.chain_reorganization_detection import ChainReorganizationDetected
|
|
6
|
+
from .event.tools.rpc_reorganization_monitor import JSONRPCReorganizationMonitor
|
|
7
|
+
from .event.tools.conversion import Conversion
|
|
8
|
+
from .event.tools.log_context import LogContext
|
|
9
|
+
from .event.tools.log_result import LogResult
|
|
10
|
+
from .event.process.read_events import ReadEvents
|
|
11
|
+
from .event.process.retrieve_events import RetrieveEvents
|
|
12
|
+
from .event.mint_event import MintEvent
|
|
13
|
+
from .event.swap_event import SwapEvent
|
|
14
|
+
from .event.sync_event import SyncEvent
|
|
15
|
+
from .event.transfer_event import TransferEvent
|
|
16
|
+
from .event.create_event import CreateEvent
|
|
17
|
+
from .event.burn_event import BurnEvent
|
|
18
|
+
from .data.filter import Filter
|
|
19
|
+
from .data.reorganization_monitor import ReorganizationMonitor
|
|
20
|
+
from .data.chain_reorganization_resolution import ChainReorganizationResolution
|
|
21
|
+
from .data.pair import PairDetails
|
|
22
|
+
from .utils.progress_update import ProgressUpdate
|
|
23
|
+
from .utils.base_utils import BaseUtils
|
|
24
|
+
from .contract.deploy import Deploy
|
|
25
|
+
from .contract.view import ViewContract
|
|
26
|
+
from .uniswap_v2.fetch_pair_details import FetchPairDetails
|
|
27
|
+
from .token.token import Token
|
|
28
|
+
from .token.fetch.fetch_token import FetchToken
|
|
29
|
+
from .utils.connect import ConnectW3
|
|
30
|
+
from .enums.event_type_enum import EventTypeEnum as EventType
|
|
31
|
+
from .enums.init_event_enum import InitEventEnum as InitEvent
|
|
32
|
+
from .enums.nets_enum import NetsEnum as Net
|
|
33
|
+
from .enums.rpcs_enum import RPCEnum as RPC
|
|
34
|
+
from .enums.platforms_enum import PlatformsEnum as Platform
|
|
35
|
+
from .enums.contracts_enum import JSONContractsEnum as JSONContract
|
|
36
|
+
|
|
37
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .abi_load import ABILoad
|
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
# This file contains code adapted from web3-ethereum-defi (https://github.com/Kartograf/web3-ethereum-defi)
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
# Original copyright (c) 2023 Kartograf contributors.
|
|
4
|
+
|
|
5
|
+
# Additional modifications by Ian Moore, 2023–2025
|
|
6
|
+
# Licensed under the Apache License, Version 2.0
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import re
|
|
10
|
+
from functools import lru_cache
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional, Sequence, Type, Union
|
|
13
|
+
|
|
14
|
+
import eth_abi
|
|
15
|
+
from eth_abi import decode
|
|
16
|
+
from eth_typing import HexAddress
|
|
17
|
+
from eth_utils import encode_hex, function_abi_to_4byte_selector
|
|
18
|
+
from eth_utils.abi import _abi_to_signature, function_signature_to_4byte_selector
|
|
19
|
+
from hexbytes import HexBytes
|
|
20
|
+
from web3 import Web3
|
|
21
|
+
from web3._utils.abi import get_abi_input_names, get_abi_input_types
|
|
22
|
+
from web3._utils.contracts import encode_abi, get_function_info
|
|
23
|
+
from web3.contract.contract import Contract, ContractFunction
|
|
24
|
+
|
|
25
|
+
# Cache loaded ABI files in-process memory for speedup
|
|
26
|
+
from web3.datastructures import AttributeDict
|
|
27
|
+
|
|
28
|
+
from ..utils.base_utils import ZERO_ADDRESS_STR
|
|
29
|
+
|
|
30
|
+
from ..enums.platforms_enum import PlatformsEnum
|
|
31
|
+
from ..enums.contracts_enum import JSONContractsEnum
|
|
32
|
+
|
|
33
|
+
DEFAULT_CONTRACT = JSONContractsEnum.IUniswapV2Pair
|
|
34
|
+
DEFAULT_PLATFORM = PlatformsEnum.SUSHI
|
|
35
|
+
|
|
36
|
+
# How big are our ABI and contract caches
|
|
37
|
+
_CACHE_SIZE = 512
|
|
38
|
+
|
|
39
|
+
class ABILoad:
|
|
40
|
+
|
|
41
|
+
def __init__(self, platform = None, contract = None):
|
|
42
|
+
self.__platform_name = DEFAULT_PLATFORM if platform == None else platform
|
|
43
|
+
self.__contract_name = DEFAULT_CONTRACT if contract == None else contract
|
|
44
|
+
self.__abi_path = self.__platform_name + '/' + self.__contract_name + '.json'
|
|
45
|
+
|
|
46
|
+
def apply(self, web3: Web3, address: Optional[str] = None):
|
|
47
|
+
return self.get_contract(web3, self.__abi_path, address)
|
|
48
|
+
|
|
49
|
+
def get_contract_name(self):
|
|
50
|
+
return self.__contract_name
|
|
51
|
+
|
|
52
|
+
def get_platform_name(self):
|
|
53
|
+
return self.__platform_name
|
|
54
|
+
|
|
55
|
+
def get_abi_path(self):
|
|
56
|
+
return self.__abi_path
|
|
57
|
+
|
|
58
|
+
@lru_cache(maxsize=_CACHE_SIZE)
|
|
59
|
+
def get_abi_by_filename(self, fname: str) -> dict:
|
|
60
|
+
"""Reads a embedded ABI file and returns it.
|
|
61
|
+
|
|
62
|
+
Example::
|
|
63
|
+
|
|
64
|
+
abi = get_abi_by_filename("ERC20Mock.json")
|
|
65
|
+
|
|
66
|
+
You are most likely interested in the keys `abi` and `bytecode` of the JSON file.
|
|
67
|
+
|
|
68
|
+
Loaded ABI files are cache in in-process memory to speed up future loading.
|
|
69
|
+
|
|
70
|
+
Any results are cached.
|
|
71
|
+
|
|
72
|
+
:param web3: Web3 instance
|
|
73
|
+
:param fname: `JSON filename from supported contract lists <https://github.com/tradingstrategy-ai/web3-ethereum-defi/tree/master/eth_defi/abi>`_.
|
|
74
|
+
:return: Full contract interface, including `bytecode`.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
here = Path(__file__).resolve().parent
|
|
78
|
+
abi_path = here / Path(fname)
|
|
79
|
+
abi_path = str(abi_path).replace("abi/","configs/")
|
|
80
|
+
with open(abi_path, "rt", encoding="utf-8") as f:
|
|
81
|
+
abi = json.load(f)
|
|
82
|
+
return abi
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@lru_cache(maxsize=_CACHE_SIZE)
|
|
86
|
+
def get_contract(
|
|
87
|
+
self,
|
|
88
|
+
web3: Web3,
|
|
89
|
+
fname: str | Path,
|
|
90
|
+
address: Optional[str] = None,
|
|
91
|
+
bytecode: Optional[str] = None,
|
|
92
|
+
) -> Type[Contract]:
|
|
93
|
+
"""Create a Contract proxy class from our bundled contracts or filesystem..
|
|
94
|
+
|
|
95
|
+
`See Web3.py documentation on Contract instances <https://web3py.readthedocs.io/en/stable/contracts.html#contract-deployment-example>`_.
|
|
96
|
+
|
|
97
|
+
Any results are cached. Web3 connection is part of the cache key.
|
|
98
|
+
|
|
99
|
+
.. note ::
|
|
100
|
+
|
|
101
|
+
This function cannot do linking. See :py:func:`get_linked_contract`
|
|
102
|
+
if the bytecode contains link markers.
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
:param web3:
|
|
109
|
+
Web3 instance
|
|
110
|
+
|
|
111
|
+
:param bytecode:
|
|
112
|
+
Override bytecode payload for the contract
|
|
113
|
+
|
|
114
|
+
:param fname:
|
|
115
|
+
Solidity compiler artifact.
|
|
116
|
+
|
|
117
|
+
Use slash prefixed path for absolute lookups.
|
|
118
|
+
|
|
119
|
+
`JSON filename from supported contract lists <https://github.com/tradingstrategy-ai/web3-ethereum-defi/tree/master/eth_defi/abi>`_.
|
|
120
|
+
|
|
121
|
+
:return:
|
|
122
|
+
Contract proxy class
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
contract_interface = self.get_abi_by_filename(fname)
|
|
126
|
+
abi = contract_interface["abi"]
|
|
127
|
+
|
|
128
|
+
if address is None and bytecode is None:
|
|
129
|
+
bytecode = contract_interface["bytecode"]
|
|
130
|
+
|
|
131
|
+
if type(bytecode) == dict:
|
|
132
|
+
# Sol 0.8 / Forge?
|
|
133
|
+
# Contains keys object, sourceMap, linkReferences
|
|
134
|
+
bytecode = bytecode["object"]
|
|
135
|
+
else:
|
|
136
|
+
# Sol 0.6 / legacy
|
|
137
|
+
# Bytecode hex is directly in the key.
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
contract = web3.eth.contract(abi=abi, bytecode=bytecode)
|
|
141
|
+
|
|
142
|
+
elif address is not None and bytecode is None:
|
|
143
|
+
contract = web3.eth.contract(address=address, abi=abi)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
return contract
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def get_linked_contract(
|
|
151
|
+
self,
|
|
152
|
+
web3: Web3,
|
|
153
|
+
fname: str | Path,
|
|
154
|
+
hardhat_export_data: Optional[dict] = None,
|
|
155
|
+
) -> Type[Contract]:
|
|
156
|
+
"""Create a Contract proxy class from our bundled contracts or filesystem and links it Solidity bytecode.
|
|
157
|
+
|
|
158
|
+
Needed when contracts contain references to libraries. The contract bytecode
|
|
159
|
+
must be processed and placeholders must be replaced by the on-chain addresses
|
|
160
|
+
of the deployed library contracts.
|
|
161
|
+
|
|
162
|
+
Example:
|
|
163
|
+
|
|
164
|
+
.. code-block:: python
|
|
165
|
+
|
|
166
|
+
path = self.path.joinpath("artifacts/@aave/core-v3/contracts/mocks/tokens/MintableERC20.sol/MintableERC20.json")
|
|
167
|
+
return get_linked_contract(web3, path, get_aave_hardhard_export())
|
|
168
|
+
|
|
169
|
+
.. note ::
|
|
170
|
+
|
|
171
|
+
If you do not need linking use :py:func:`get_contract` which is faster.
|
|
172
|
+
|
|
173
|
+
:param web3:
|
|
174
|
+
Web3 instance
|
|
175
|
+
|
|
176
|
+
:param fname:
|
|
177
|
+
Solidity compiler artifact.
|
|
178
|
+
|
|
179
|
+
Use slash prefixed path for absolute lookups.
|
|
180
|
+
|
|
181
|
+
`JSON filename from supported contract lists <https://github.com/tradingstrategy-ai/web3-ethereum-defi/tree/master/eth_defi/abi>`_.
|
|
182
|
+
|
|
183
|
+
:param hardhat_export_data:
|
|
184
|
+
Hardhat deployment export data to link bytecode.
|
|
185
|
+
|
|
186
|
+
A JSON file generated by `hardhat deploy --export` command.
|
|
187
|
+
|
|
188
|
+
:return:
|
|
189
|
+
Contract proxy class
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
contract_interface = self.get_abi_by_filename(fname)
|
|
193
|
+
abi = contract_interface["abi"]
|
|
194
|
+
bytecode = contract_interface["deployedBytecode"]
|
|
195
|
+
|
|
196
|
+
link_references = contract_interface["linkReferences"]
|
|
197
|
+
bytecode = self.link_libraries_hardhat(bytecode, link_references, hardhat_export_data)
|
|
198
|
+
|
|
199
|
+
Contract = web3.eth.contract(abi=abi, bytecode=bytecode)
|
|
200
|
+
return Contract
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def get_deployed_contract(
|
|
204
|
+
self,
|
|
205
|
+
web3: Web3,
|
|
206
|
+
fname: str | Path,
|
|
207
|
+
address: Union[HexAddress, str],
|
|
208
|
+
register_for_tracing: bool = True,
|
|
209
|
+
) -> Contract:
|
|
210
|
+
"""Get a Contract proxy objec for a contract deployed at a specific address.
|
|
211
|
+
|
|
212
|
+
`See Web3.py documentation on Contract instances <https://web3py.readthedocs.io/en/stable/contracts.html#contract-deployment-example>`_.
|
|
213
|
+
|
|
214
|
+
:param web3:
|
|
215
|
+
Web3 instance
|
|
216
|
+
|
|
217
|
+
:param fname:
|
|
218
|
+
`JSON filename from supported contract lists <https://github.com/tradingstrategy-ai/web3-ethereum-defi/tree/master/eth_defi/abi>`_.
|
|
219
|
+
|
|
220
|
+
:param address:
|
|
221
|
+
Ethereum address of the deployed contract
|
|
222
|
+
|
|
223
|
+
:param register_for_tracing:
|
|
224
|
+
Add the contract to the deployment registry if not already there.
|
|
225
|
+
|
|
226
|
+
:return:
|
|
227
|
+
`web3.contract.Contract` proxy
|
|
228
|
+
"""
|
|
229
|
+
assert address
|
|
230
|
+
|
|
231
|
+
address = Web3.to_checksum_address(address)
|
|
232
|
+
|
|
233
|
+
Contract = self.get_contract(web3, fname)
|
|
234
|
+
contract = Contract(address)
|
|
235
|
+
|
|
236
|
+
if register_for_tracing:
|
|
237
|
+
# TODO: Currently hack around circular imports, move functoins
|
|
238
|
+
from pachira.contract.deploy import Deploy
|
|
239
|
+
|
|
240
|
+
registered_contract = Deploy().get_registered_contract(web3, address)
|
|
241
|
+
if registered_contract is None:
|
|
242
|
+
Deploy().register_contract(web3, address, contract)
|
|
243
|
+
|
|
244
|
+
return contract
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def get_transaction_data_field(self, tx: AttributeDict) -> str:
|
|
248
|
+
"""Get the "Data" payload of a transaction.
|
|
249
|
+
|
|
250
|
+
Ethereum Tester has this in tx.data while Ganache has this in tx.input.
|
|
251
|
+
Yes, it is madness.
|
|
252
|
+
|
|
253
|
+
Example:
|
|
254
|
+
|
|
255
|
+
.. code-block::
|
|
256
|
+
|
|
257
|
+
tx = web3.eth.get_transaction(tx_hash)
|
|
258
|
+
function, input_args = router.decode_function_input(get_transaction_data_field(tx))
|
|
259
|
+
print("Transaction {tx_hash} called function {function}")
|
|
260
|
+
|
|
261
|
+
"""
|
|
262
|
+
if "data" in tx:
|
|
263
|
+
return tx["data"]
|
|
264
|
+
else:
|
|
265
|
+
return tx["input"]
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def encode_with_signature(self, function_signature: str, args: Sequence) -> bytes:
|
|
269
|
+
"""Mimic Solidity's abi.encodeWithSignature() in Python.
|
|
270
|
+
|
|
271
|
+
This is a Python equivalent for `abi.encodeWithSignature()`.
|
|
272
|
+
|
|
273
|
+
Example:
|
|
274
|
+
|
|
275
|
+
.. code-block:: python
|
|
276
|
+
|
|
277
|
+
payload = encode_with_signature("init(address)", [my_address])
|
|
278
|
+
assert type(payload) == bytes
|
|
279
|
+
|
|
280
|
+
:param function_signature:
|
|
281
|
+
Solidity function signature that can be hashed to a selector.
|
|
282
|
+
|
|
283
|
+
ABI fill be extractd from this signature.
|
|
284
|
+
|
|
285
|
+
:param args:
|
|
286
|
+
Argument values to be encoded.
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
assert type(args) in (tuple, list)
|
|
290
|
+
|
|
291
|
+
function_selector = Web3.keccak(text=function_signature)
|
|
292
|
+
selector_text = self.function_signature[function_signature.find("(") + 1 : function_signature.rfind(")")]
|
|
293
|
+
arg_types = selector_text.split(",")
|
|
294
|
+
encoded_args = eth_abi.encode(arg_types, args)
|
|
295
|
+
return function_selector + encoded_args
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def encode_function_args(self, func: ContractFunction, args: Sequence) -> bytes:
|
|
299
|
+
"""Mimic Solidity's abi.encodeWithSignature() in Python.
|
|
300
|
+
|
|
301
|
+
Uses `web3.Contract.functions` prepared function as the ABI source.
|
|
302
|
+
|
|
303
|
+
:param func:
|
|
304
|
+
Function which arguments we are going to encode.
|
|
305
|
+
|
|
306
|
+
:param args:
|
|
307
|
+
Argument values to be encoded.
|
|
308
|
+
"""
|
|
309
|
+
assert isinstance(func, ContractFunction)
|
|
310
|
+
|
|
311
|
+
web3 = func.w3
|
|
312
|
+
|
|
313
|
+
fn_abi, fn_selector, aligned_fn_arguments = get_function_info(
|
|
314
|
+
func.fn_name,
|
|
315
|
+
web3.codec,
|
|
316
|
+
func.contract_abi,
|
|
317
|
+
args=args,
|
|
318
|
+
)
|
|
319
|
+
arg_types = [t["type"] for t in fn_abi["inputs"]]
|
|
320
|
+
encoded_args = eth_abi.encode(arg_types, args)
|
|
321
|
+
return encoded_args
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def encode_function_call(
|
|
325
|
+
self,
|
|
326
|
+
func: ContractFunction,
|
|
327
|
+
args: Sequence,
|
|
328
|
+
) -> HexBytes:
|
|
329
|
+
"""Encode function selector + its arguments as data payload.
|
|
330
|
+
|
|
331
|
+
Uses `web3.Contract.functions` prepared function as the ABI source.
|
|
332
|
+
|
|
333
|
+
See also :py:func:`encode_function_args`.
|
|
334
|
+
|
|
335
|
+
:param func:
|
|
336
|
+
Function which arguments we are going to encode.
|
|
337
|
+
|
|
338
|
+
:param args:
|
|
339
|
+
Argument values to be encoded.
|
|
340
|
+
|
|
341
|
+
:return:
|
|
342
|
+
Solidity's function selector + argument payload.
|
|
343
|
+
|
|
344
|
+
"""
|
|
345
|
+
w3 = func.w3
|
|
346
|
+
contract_abi = func.contract_abi
|
|
347
|
+
fn_abi = func.abi
|
|
348
|
+
fn_identifier = func.function_identifier
|
|
349
|
+
fn_abi, fn_selector, fn_arguments = get_function_info(
|
|
350
|
+
# type ignored b/c fn_id here is always str b/c FallbackFn is handled above
|
|
351
|
+
fn_identifier, # type: ignore
|
|
352
|
+
w3.codec,
|
|
353
|
+
contract_abi,
|
|
354
|
+
fn_abi,
|
|
355
|
+
args,
|
|
356
|
+
)
|
|
357
|
+
encoded = encode_abi(w3, fn_abi, fn_arguments, fn_selector)
|
|
358
|
+
return HexBytes(encoded)
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def decode_function_args(
|
|
362
|
+
self,
|
|
363
|
+
func: ContractFunction,
|
|
364
|
+
data: bytes | HexBytes,
|
|
365
|
+
) -> dict:
|
|
366
|
+
"""Decode binary CALL or CALLDATA to a Solidity function,
|
|
367
|
+
|
|
368
|
+
Uses `web3.Contract.functions` prepared function as the ABI source.
|
|
369
|
+
|
|
370
|
+
:param func:
|
|
371
|
+
Function which arguments we are going to encode.
|
|
372
|
+
|
|
373
|
+
:param data:
|
|
374
|
+
Extracted from a transaction data field or EVM memoryo trace.
|
|
375
|
+
|
|
376
|
+
:return:
|
|
377
|
+
Ordered dict of the decoded arguments
|
|
378
|
+
"""
|
|
379
|
+
assert isinstance(func, ContractFunction)
|
|
380
|
+
fn_abi = func.abi
|
|
381
|
+
|
|
382
|
+
arg_names = get_abi_input_names(fn_abi)
|
|
383
|
+
arg_types = get_abi_input_types(fn_abi)
|
|
384
|
+
arg_tuple = decode(arg_types, data)
|
|
385
|
+
|
|
386
|
+
return dict(zip(arg_names, arg_tuple))
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def humanise_decoded_arg_data(self, args: dict) -> dict:
|
|
390
|
+
"""Make decoded arguments more human readable.
|
|
391
|
+
|
|
392
|
+
- All arguments are converted to good text types
|
|
393
|
+
|
|
394
|
+
See :py:func:`decode_function_args`
|
|
395
|
+
|
|
396
|
+
:return:
|
|
397
|
+
Ordered dict of decoded arguments, easier to read
|
|
398
|
+
"""
|
|
399
|
+
|
|
400
|
+
def _humanize(v):
|
|
401
|
+
if type(v) == bytes:
|
|
402
|
+
return v.hex()
|
|
403
|
+
return v
|
|
404
|
+
|
|
405
|
+
return {k: _humanize(v) for k, v in args.items()}
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def link_libraries_hardhat(self, bytecode: str, link_references: dict, hardhat_export: dict):
|
|
409
|
+
"""Link Solidity libraries based on Hardhat deployment.
|
|
410
|
+
|
|
411
|
+
.. warning ::
|
|
412
|
+
|
|
413
|
+
Preliminary implementation
|
|
414
|
+
|
|
415
|
+
See :py:func:`get_linked_contract` for details.
|
|
416
|
+
|
|
417
|
+
:param bytecode:
|
|
418
|
+
Raw bytecode of a Solidity contract.
|
|
419
|
+
|
|
420
|
+
Get from ABI file.
|
|
421
|
+
|
|
422
|
+
Bytecode must be a in string format, because placeholders are not parseable hex.
|
|
423
|
+
|
|
424
|
+
:param link_references:
|
|
425
|
+
List of binary sequences we need to replaced by a contract filename.
|
|
426
|
+
|
|
427
|
+
Get from ABI file.
|
|
428
|
+
|
|
429
|
+
:param hardhat_export:
|
|
430
|
+
Hardhat's export format.
|
|
431
|
+
|
|
432
|
+
You get with `hardhat deploy --export`.
|
|
433
|
+
|
|
434
|
+
:return:
|
|
435
|
+
Linked bytecode
|
|
436
|
+
"""
|
|
437
|
+
|
|
438
|
+
assert type(bytecode) == str, f"Got {type(bytecode)}"
|
|
439
|
+
|
|
440
|
+
assert bytecode.startswith("0x")
|
|
441
|
+
|
|
442
|
+
hex_blob = bytecode[2:]
|
|
443
|
+
|
|
444
|
+
# Remove placeholders and replace them with zeroes,
|
|
445
|
+
# so that we can convert the bytecode to binary
|
|
446
|
+
# https://stackoverflow.com/a/16160048/315168
|
|
447
|
+
zeroes = str(ZERO_ADDRESS_STR)[2:]
|
|
448
|
+
fixed_hex_blob = re.sub(r"__\$(.*?)\$__", zeroes, hex_blob, flags=re.DOTALL)
|
|
449
|
+
|
|
450
|
+
data = bytearray.fromhex(fixed_hex_blob)
|
|
451
|
+
|
|
452
|
+
def _get_contract_address(name: str):
|
|
453
|
+
contracts = hardhat_export["contracts"]
|
|
454
|
+
contract = contracts.get(name)
|
|
455
|
+
assert contract, f"Hardhat export does not contain a contract entry for {name}"
|
|
456
|
+
return contract["address"]
|
|
457
|
+
|
|
458
|
+
for ref_file, ref_data in link_references.items():
|
|
459
|
+
# 'contracts/protocol/libraries/logic/BorrowLogic.sol': {'BorrowLogic': [{'length': 20, 'start': 4405}, {'length': 20, 'start': 5081}, {'length': 20, 'start': 7441}, {'length': 20, 'start': 7604}, {'length': 20, 'start': 10111}, {'length': 20, 'start': 12083}]},
|
|
460
|
+
for contract_name, ref_array in ref_data.items():
|
|
461
|
+
address = _get_contract_address(contract_name)
|
|
462
|
+
byte_address = bytes.fromhex(address[2:])
|
|
463
|
+
for ref in ref_array:
|
|
464
|
+
start = ref["start"]
|
|
465
|
+
length = ref["length"]
|
|
466
|
+
data[start : start + length] = byte_address
|
|
467
|
+
# print(f"Linking {contract_name} {start} {address}")
|
|
468
|
+
|
|
469
|
+
return data
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def get_function_selector(self, func: ContractFunction) -> bytes:
|
|
473
|
+
"""Get Solidity function selector.
|
|
474
|
+
|
|
475
|
+
Does not support multiple Solidity functions with the same name, but
|
|
476
|
+
different arguments. On multiple functions
|
|
477
|
+
use one first declared in ABI.
|
|
478
|
+
|
|
479
|
+
Example:
|
|
480
|
+
|
|
481
|
+
.. code-block:: python
|
|
482
|
+
|
|
483
|
+
selector = get_function_selector(uniswap_v2.router.functions.swapExactTokensForTokens)
|
|
484
|
+
assert selector.hex() == 38ed1739
|
|
485
|
+
|
|
486
|
+
:param func:
|
|
487
|
+
Unbound or bound contract function proxy
|
|
488
|
+
|
|
489
|
+
:return:
|
|
490
|
+
Solidity function selector.
|
|
491
|
+
|
|
492
|
+
First 32-bit (4 bytes) keccak hash.
|
|
493
|
+
"""
|
|
494
|
+
|
|
495
|
+
contract_abi = func.contract_abi
|
|
496
|
+
# https://stackoverflow.com/a/8534381/315168
|
|
497
|
+
fn_abi = next((a for a in contract_abi if a.get("name") == func.fn_name), None)
|
|
498
|
+
assert fn_abi, f"Could not find function {func.fn_name} in Contract ABI"
|
|
499
|
+
function_signature = _abi_to_signature(fn_abi)
|
|
500
|
+
fn_selector = function_signature_to_4byte_selector(function_signature) # type: ignore
|
|
501
|
+
return fn_selector
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"abi":[{"type":"constructor","inputs":[{"name":"name","type":"string","internalType":"string"},{"name":"symbol","type":"string","internalType":"string"},{"name":"supply","type":"uint256","internalType":"uint256"},{"name":"__decimals","type":"uint8","internalType":"uint8"}],"stateMutability":"nonpayable"},{"type":"function","name":"allowance","inputs":[{"name":"owner","type":"address","internalType":"address"},{"name":"spender","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"approve","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"balanceOf","inputs":[{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"decimals","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"decreaseAllowance","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"subtractedValue","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"increaseAllowance","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"addedValue","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"name","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"symbol","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"transfer","inputs":[{"name":"recipient","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"transferFrom","inputs":[{"name":"sender","type":"address","internalType":"address"},{"name":"recipient","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"event","name":"Approval","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"spender","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"name":"from","type":"address","indexed":true,"internalType":"address"},{"name":"to","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false}],"bytecode":{"object":"0x60806040523480156200001157600080fd5b5060405162000e3438038062000e34833981810160405260808110156200003757600080fd5b81019080805160405193929190846401000000008211156200005857600080fd5b9083019060208201858111156200006e57600080fd5b82516401000000008111828201881017156200008957600080fd5b82525081516020918201929091019080838360005b83811015620000b85781810151838201526020016200009e565b50505050905090810190601f168015620000e65780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200010a57600080fd5b9083019060208201858111156200012057600080fd5b82516401000000008111828201881017156200013b57600080fd5b82525081516020918201929091019080838360005b838110156200016a57818101518382015260200162000150565b50505050905090810190601f168015620001985780820380516001836020036101000a031916815260200191505b50604090815260208281015192909101518651929450925085918591620001c59160039185019062000391565b508051620001db90600490602084019062000391565b50506005805460ff1916601217905550620001f733836200021b565b6005805460ff9092166101000261ff0019909216919091179055506200042d915050565b6001600160a01b03821662000277576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b62000285600083836200032a565b620002a1816002546200032f60201b620005781790919060201c565b6002556001600160a01b03821660009081526020818152604090912054620002d4918390620005786200032f821b17901c565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b505050565b6000828201838110156200038a576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620003d457805160ff191683800117855562000404565b8280016001018555821562000404579182015b8281111562000404578251825591602001919060010190620003e7565b506200041292915062000416565b5090565b5b8082111562000412576000815560010162000417565b6109f7806200043d6000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063395093511161007157806339509351146101d957806370a082311461020557806395d89b411461022b578063a457c2d714610233578063a9059cbb1461025f578063dd62ed3e1461028b576100a9565b806306fdde03146100ae578063095ea7b31461012b57806318160ddd1461016b57806323b872dd14610185578063313ce567146101bb575b600080fd5b6100b66102b9565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100f05781810151838201526020016100d8565b50505050905090810190601f16801561011d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101576004803603604081101561014157600080fd5b506001600160a01b03813516906020013561034f565b604080519115158252519081900360200190f35b61017361036c565b60408051918252519081900360200190f35b6101576004803603606081101561019b57600080fd5b506001600160a01b03813581169160208101359091169060400135610372565b6101c36103f9565b6040805160ff9092168252519081900360200190f35b610157600480360360408110156101ef57600080fd5b506001600160a01b038135169060200135610407565b6101736004803603602081101561021b57600080fd5b50356001600160a01b0316610455565b6100b6610470565b6101576004803603604081101561024957600080fd5b506001600160a01b0381351690602001356104d1565b6101576004803603604081101561027557600080fd5b506001600160a01b038135169060200135610539565b610173600480360360408110156102a157600080fd5b506001600160a01b038135811691602001351661054d565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156103455780601f1061031a57610100808354040283529160200191610345565b820191906000526020600020905b81548152906001019060200180831161032857829003601f168201915b5050505050905090565b600061036361035c6105d9565b84846105dd565b50600192915050565b60025490565b600061037f8484846106c9565b6103ef8461038b6105d9565b6103ea8560405180606001604052806028815260200161092c602891396001600160a01b038a166000908152600160205260408120906103c96105d9565b6001600160a01b031681526020810191909152604001600020549190610824565b6105dd565b5060019392505050565b600554610100900460ff1690565b60006103636104146105d9565b846103ea85600160006104256105d9565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490610578565b6001600160a01b031660009081526020819052604090205490565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156103455780601f1061031a57610100808354040283529160200191610345565b60006103636104de6105d9565b846103ea8560405180606001604052806025815260200161099d60259139600160006105086105d9565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190610824565b60006103636105466105d9565b84846106c9565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6000828201838110156105d2576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b3390565b6001600160a01b0383166106225760405162461bcd60e51b81526004018080602001828103825260248152602001806109796024913960400191505060405180910390fd5b6001600160a01b0382166106675760405162461bcd60e51b81526004018080602001828103825260228152602001806108e46022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b03831661070e5760405162461bcd60e51b81526004018080602001828103825260258152602001806109546025913960400191505060405180910390fd5b6001600160a01b0382166107535760405162461bcd60e51b81526004018080602001828103825260238152602001806108c16023913960400191505060405180910390fd5b61075e8383836108bb565b61079b81604051806060016040528060268152602001610906602691396001600160a01b0386166000908152602081905260409020549190610824565b6001600160a01b0380851660009081526020819052604080822093909355908416815220546107ca9082610578565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156108b35760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610878578181015183820152602001610860565b50505050905090810190601f1680156108a55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b50505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220ea86aff1c37b689e88e147ee9c1ac6007c344bd820c1317a087853cae935e90764736f6c634300060c0033","sourceMap":"181:406:0:-:0;;;254:227;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;254:227:0;;;;;;;;;;-1:-1:-1;254:227:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;254:227:0;;;;;;;;;;-1:-1:-1;254:227:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;254:227:0;;;;;;;;;;;;;;12998:13:1;;254:227:0;;-1:-1:-1;254:227:0;-1:-1:-1;393:4:0;;399:6;;12998:13:1;;:5;;:13;;;;:::i;:::-;-1:-1:-1;13021:17:1;;;;:7;;:17;;;;;:::i;:::-;-1:-1:-1;;13048:9:1;:14;;-1:-1:-1;;13048:14:1;13060:2;13048:14;;;-1:-1:-1;417:25:0::1;423:10;435:6:::0;417:5:::1;:25::i;:::-;452:9;:22:::0;;::::1;::::0;;::::1;;;-1:-1:-1::0;;452:22:0;;::::1;::::0;;;::::1;::::0;;-1:-1:-1;181:406:0;;-1:-1:-1;;181:406:0;18798:370:1;-1:-1:-1;;;;;18881:21:1;;18873:65;;;;;-1:-1:-1;;;18873:65:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;18949:49;18978:1;18982:7;18991:6;18949:20;:49::i;:::-;19024:24;19041:6;19024:12;;:16;;;;;;:24;;;;:::i;:::-;19009:12;:39;-1:-1:-1;;;;;19079:18:1;;:9;:18;;;;;;;;;;;;:30;;19102:6;;19079:22;;;;;:30;;:::i;:::-;-1:-1:-1;;;;;19058:18:1;;:9;:18;;;;;;;;;;;:51;;;;19124:37;;;;;;;19058:18;;:9;;19124:37;;;;;;;;;;18798:370;;:::o;21667:92::-;;;;:::o;3750:175::-;3808:7;3839:5;;;3862:6;;;;3854:46;;;;;-1:-1:-1;;;3854:46:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;3917:1;3750:175;-1:-1:-1;;;3750:175:1:o;181:406:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;181:406:0;;;-1:-1:-1;181:406:0;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b50600436106100a95760003560e01c8063395093511161007157806339509351146101d957806370a082311461020557806395d89b411461022b578063a457c2d714610233578063a9059cbb1461025f578063dd62ed3e1461028b576100a9565b806306fdde03146100ae578063095ea7b31461012b57806318160ddd1461016b57806323b872dd14610185578063313ce567146101bb575b600080fd5b6100b66102b9565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100f05781810151838201526020016100d8565b50505050905090810190601f16801561011d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101576004803603604081101561014157600080fd5b506001600160a01b03813516906020013561034f565b604080519115158252519081900360200190f35b61017361036c565b60408051918252519081900360200190f35b6101576004803603606081101561019b57600080fd5b506001600160a01b03813581169160208101359091169060400135610372565b6101c36103f9565b6040805160ff9092168252519081900360200190f35b610157600480360360408110156101ef57600080fd5b506001600160a01b038135169060200135610407565b6101736004803603602081101561021b57600080fd5b50356001600160a01b0316610455565b6100b6610470565b6101576004803603604081101561024957600080fd5b506001600160a01b0381351690602001356104d1565b6101576004803603604081101561027557600080fd5b506001600160a01b038135169060200135610539565b610173600480360360408110156102a157600080fd5b506001600160a01b038135811691602001351661054d565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156103455780601f1061031a57610100808354040283529160200191610345565b820191906000526020600020905b81548152906001019060200180831161032857829003601f168201915b5050505050905090565b600061036361035c6105d9565b84846105dd565b50600192915050565b60025490565b600061037f8484846106c9565b6103ef8461038b6105d9565b6103ea8560405180606001604052806028815260200161092c602891396001600160a01b038a166000908152600160205260408120906103c96105d9565b6001600160a01b031681526020810191909152604001600020549190610824565b6105dd565b5060019392505050565b600554610100900460ff1690565b60006103636104146105d9565b846103ea85600160006104256105d9565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490610578565b6001600160a01b031660009081526020819052604090205490565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156103455780601f1061031a57610100808354040283529160200191610345565b60006103636104de6105d9565b846103ea8560405180606001604052806025815260200161099d60259139600160006105086105d9565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190610824565b60006103636105466105d9565b84846106c9565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6000828201838110156105d2576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b3390565b6001600160a01b0383166106225760405162461bcd60e51b81526004018080602001828103825260248152602001806109796024913960400191505060405180910390fd5b6001600160a01b0382166106675760405162461bcd60e51b81526004018080602001828103825260228152602001806108e46022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b03831661070e5760405162461bcd60e51b81526004018080602001828103825260258152602001806109546025913960400191505060405180910390fd5b6001600160a01b0382166107535760405162461bcd60e51b81526004018080602001828103825260238152602001806108c16023913960400191505060405180910390fd5b61075e8383836108bb565b61079b81604051806060016040528060268152602001610906602691396001600160a01b0386166000908152602081905260409020549190610824565b6001600160a01b0380851660009081526020819052604080822093909355908416815220546107ca9082610578565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156108b35760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610878578181015183820152602001610860565b50505050905090810190601f1680156108a55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b50505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220ea86aff1c37b689e88e147ee9c1ac6007c344bd820c1317a087853cae935e90764736f6c634300060c0033","sourceMap":"181:406:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13134:89:1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15210:166;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;15210:166:1;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;14201:106;;;:::i;:::-;;;;;;;;;;;;;;;;15843:317;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;15843:317:1;;;;;;;;;;;;;;;;;:::i;487:98:0:-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;16555:215:1;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;16555:215:1;;;;;;;;:::i;14365:125::-;;;;;;;;;;;;;;;;-1:-1:-1;14365:125:1;-1:-1:-1;;;;;14365:125:1;;:::i;13336:93::-;;;:::i;17257:266::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;17257:266:1;;;;;;;;:::i;14693:172::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;14693:172:1;;;;;;;;:::i;14923:149::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;14923:149:1;;;;;;;;;;:::i;13134:89::-;13211:5;13204:12;;;;;;;;-1:-1:-1;;13204:12:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13179:13;;13204:12;;13211:5;;13204:12;;13211:5;13204:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13134:89;:::o;15210:166::-;15293:4;15309:39;15318:12;:10;:12::i;:::-;15332:7;15341:6;15309:8;:39::i;:::-;-1:-1:-1;15365:4:1;15210:166;;;;:::o;14201:106::-;14288:12;;14201:106;:::o;15843:317::-;15949:4;15965:36;15975:6;15983:9;15994:6;15965:9;:36::i;:::-;16011:121;16020:6;16028:12;:10;:12::i;:::-;16042:89;16080:6;16042:89;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;16042:19:1;;;;;;:11;:19;;;;;;16062:12;:10;:12::i;:::-;-1:-1:-1;;;;;16042:33:1;;;;;;;;;;;;-1:-1:-1;16042:33:1;;;:89;:37;:89::i;:::-;16011:8;:121::i;:::-;-1:-1:-1;16149:4:1;15843:317;;;;;:::o;487:98:0:-;569:9;;;;;;;;487:98::o;16555:215:1:-;16643:4;16659:83;16668:12;:10;:12::i;:::-;16682:7;16691:50;16730:10;16691:11;:25;16703:12;:10;:12::i;:::-;-1:-1:-1;;;;;16691:25:1;;;;;;;;;;;;;;;;;-1:-1:-1;16691:25:1;;;:34;;;;;;;;;;;:38;:50::i;14365:125::-;-1:-1:-1;;;;;14465:18:1;14439:7;14465:18;;;;;;;;;;;;14365:125::o;13336:93::-;13415:7;13408:14;;;;;;;;-1:-1:-1;;13408:14:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13383:13;;13408:14;;13415:7;;13408:14;;13415:7;13408:14;;;;;;;;;;;;;;;;;;;;;;;;17257:266;17350:4;17366:129;17375:12;:10;:12::i;:::-;17389:7;17398:96;17437:15;17398:96;;;;;;;;;;;;;;;;;:11;:25;17410:12;:10;:12::i;:::-;-1:-1:-1;;;;;17398:25:1;;;;;;;;;;;;;;;;;-1:-1:-1;17398:25:1;;;:34;;;;;;;;;;;:96;:38;:96::i;14693:172::-;14779:4;14795:42;14805:12;:10;:12::i;:::-;14819:9;14830:6;14795:9;:42::i;14923:149::-;-1:-1:-1;;;;;15038:18:1;;;15012:7;15038:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;14923:149::o;3750:175::-;3808:7;3839:5;;;3862:6;;;;3854:46;;;;;-1:-1:-1;;;3854:46:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;3917:1;3750:175;-1:-1:-1;;;3750:175:1:o;688:104::-;775:10;688:104;:::o;20321:340::-;-1:-1:-1;;;;;20422:19:1;;20414:68;;;;-1:-1:-1;;;20414:68:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;20500:21:1;;20492:68;;;;-1:-1:-1;;;20492:68:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;20571:18:1;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;20622:32;;;;;;;;;;;;;;;;;20321:340;;;:::o;17997:530::-;-1:-1:-1;;;;;18102:20:1;;18094:70;;;;-1:-1:-1;;;18094:70:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;18182:23:1;;18174:71;;;;-1:-1:-1;;;18174:71:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18256:47;18277:6;18285:9;18296:6;18256:20;:47::i;:::-;18334:71;18356:6;18334:71;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;18334:17:1;;:9;:17;;;;;;;;;;;;:71;:21;:71::i;:::-;-1:-1:-1;;;;;18314:17:1;;;:9;:17;;;;;;;;;;;:91;;;;18438:20;;;;;;;:32;;18463:6;18438:24;:32::i;:::-;-1:-1:-1;;;;;18415:20:1;;;:9;:20;;;;;;;;;;;;:55;;;;18485:35;;;;;;;18415:20;;18485:35;;;;;;;;;;;;;17997:530;;;:::o;6492:163::-;6578:7;6613:12;6605:6;;;;6597:29;;;;-1:-1:-1;;;6597:29:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;6643:5:1;;;6492:163::o;21667:92::-;;;;:::o","linkReferences":{}},"methodIdentifiers":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","decimals()":"313ce567","decreaseAllowance(address,uint256)":"a457c2d7","increaseAllowance(address,uint256)":"39509351","name()":"06fdde03","symbol()":"95d89b41","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"},"rawMetadata":"{\"compiler\":{\"version\":\"0.6.12+commit.27d51765\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"supply\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"__decimals\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"See {IERC20-allowance}.\"},\"approve(address,uint256)\":{\"details\":\"See {IERC20-approve}. Requirements: - `spender` cannot be the zero address.\"},\"balanceOf(address)\":{\"details\":\"See {IERC20-balanceOf}.\"},\"decimals()\":{\"details\":\"Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5,05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is called. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}.\"},\"decreaseAllowance(address,uint256)\":{\"details\":\"Atomically decreases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`.\"},\"increaseAllowance(address,uint256)\":{\"details\":\"Atomically increases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address.\"},\"name()\":{\"details\":\"Returns the name of the token.\"},\"symbol()\":{\"details\":\"Returns the symbol of the token, usually a shorter version of the name.\"},\"totalSupply()\":{\"details\":\"See {IERC20-totalSupply}.\"},\"transfer(address,uint256)\":{\"details\":\"See {IERC20-transfer}. Requirements: - `recipient` cannot be the zero address. - the caller must have a balance of at least `amount`.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. Requirements: - `sender` and `recipient` cannot be the zero address. - `sender` must have a balance of at least `amount`. - the caller must have allowance for ``sender``'s tokens of at least `amount`.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"None of the libraries provide a contract that allows mock us decimals of ERC-20 token, needed for USDC mocks\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/ERC20MockDecimals.sol\":\"ERC20MockDecimals\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@enzyme/=../enzyme/contracts/\",\":@openzeppelin/=../enzyme/node_modules/@openzeppelin/\",\":ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\"]},\"sources\":{\"src/ERC20MockDecimals.sol\":{\"keccak256\":\"0xefce098d3f07f624ae9a3a9eedb56e5f014218715922445183a69481df5087f8\",\"urls\":[\"bzz-raw://6d703e3d9dbee099e084932c313bdfc7bddb6cab64ed2b778555768de79608eb\",\"dweb:/ipfs/QmTueQnWtp6vhgjr77b2pFnrpKxYAyAJpVxfJkdaoXnep4\"]},\"src/ERC20_flat.sol\":{\"keccak256\":\"0x952bffd614c842fd04693d6654a642b1af4805e82d9bb56f2099d2f0a3e55963\",\"urls\":[\"bzz-raw://150ea1b439fa8f42f5fc475de8da03f25029dc900b0b26e5a9b38dccf25a9bfc\",\"dweb:/ipfs/QmU4XX579ZDCZoD2YqEvVrJTavjj6o5vAmjvsEZZqtiN4n\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.6.12+commit.27d51765"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint8","name":"__decimals","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address","indexed":true},{"internalType":"address","name":"spender","type":"address","indexed":true},{"internalType":"uint256","name":"value","type":"uint256","indexed":false}],"type":"event","name":"Approval","anonymous":false},{"inputs":[{"internalType":"address","name":"from","type":"address","indexed":true},{"internalType":"address","name":"to","type":"address","indexed":true},{"internalType":"uint256","name":"value","type":"uint256","indexed":false}],"type":"event","name":"Transfer","anonymous":false},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"stateMutability":"view","type":"function","name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function","name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}]},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"name","outputs":[{"internalType":"string","name":"","type":"string"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"allowance(address,address)":{"details":"See {IERC20-allowance}."},"approve(address,uint256)":{"details":"See {IERC20-approve}. Requirements: - `spender` cannot be the zero address."},"balanceOf(address)":{"details":"See {IERC20-balanceOf}."},"decimals()":{"details":"Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5,05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is called. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}."},"decreaseAllowance(address,uint256)":{"details":"Atomically decreases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`."},"increaseAllowance(address,uint256)":{"details":"Atomically increases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address."},"name()":{"details":"Returns the name of the token."},"symbol()":{"details":"Returns the symbol of the token, usually a shorter version of the name."},"totalSupply()":{"details":"See {IERC20-totalSupply}."},"transfer(address,uint256)":{"details":"See {IERC20-transfer}. Requirements: - `recipient` cannot be the zero address. - the caller must have a balance of at least `amount`."},"transferFrom(address,address,uint256)":{"details":"See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. Requirements: - `sender` and `recipient` cannot be the zero address. - `sender` must have a balance of at least `amount`. - the caller must have allowance for ``sender``'s tokens of at least `amount`."}},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@enzyme/=../enzyme/contracts/","@openzeppelin/=../enzyme/node_modules/@openzeppelin/","ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/ERC20MockDecimals.sol":"ERC20MockDecimals"},"evmVersion":"istanbul","libraries":{}},"sources":{"src/ERC20MockDecimals.sol":{"keccak256":"0xefce098d3f07f624ae9a3a9eedb56e5f014218715922445183a69481df5087f8","urls":["bzz-raw://6d703e3d9dbee099e084932c313bdfc7bddb6cab64ed2b778555768de79608eb","dweb:/ipfs/QmTueQnWtp6vhgjr77b2pFnrpKxYAyAJpVxfJkdaoXnep4"],"license":null},"src/ERC20_flat.sol":{"keccak256":"0x952bffd614c842fd04693d6654a642b1af4805e82d9bb56f2099d2f0a3e55963","urls":["bzz-raw://150ea1b439fa8f42f5fc475de8da03f25029dc900b0b26e5a9b38dccf25a9bfc","dweb:/ipfs/QmU4XX579ZDCZoD2YqEvVrJTavjj6o5vAmjvsEZZqtiN4n"],"license":null}},"version":1},"id":0}
|