-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ffba985
commit 7f78b30
Showing
11 changed files
with
392 additions
and
152 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
""" | ||
Generates a mermaid class diagram with the contract selectors and | ||
the dependencies between contracts. | ||
Usage: | ||
python scripts/class_diagram.py [glob_pattern] (--internal) (--members) | ||
""" | ||
import sys | ||
from base64 import b64encode | ||
from dataclasses import dataclass | ||
from glob import glob | ||
from pathlib import Path | ||
|
||
import boa | ||
from vyper import ast | ||
|
||
|
||
@dataclass | ||
class ContractDependencies: | ||
""" | ||
Describes the information extracted from each vyper contract in order to generate | ||
the class diagram. | ||
""" | ||
|
||
# the name of the contract (file) | ||
contract: str | ||
# a dict of the interface name to a list of the selectors where it's used | ||
interfaces: dict[str, set[str]] | ||
functions: list[str] | ||
variables: list[str] | ||
|
||
|
||
def get_function_descriptor(node: ast.FunctionDef) -> str: | ||
"""Returns a string describing the function signature.""" | ||
args_descriptor = ", ".join(a.node_source_code for a in node.args.args) | ||
return f"({node.returns} {node.name} {args_descriptor})" | ||
|
||
|
||
def parse_contract(filename: str) -> ContractDependencies: | ||
""" | ||
The interfaces used in a contract and a list of the slots where it's used. | ||
:param filename: The path to the Vyper source code. | ||
:return: a list of the interface names used in the contract | ||
""" | ||
module = boa.load_partial(filename).compiler_data.vyper_module | ||
interfaces = module.get_children(ast.InterfaceDef) | ||
return ContractDependencies( | ||
contract=Path(filename).stem, | ||
interfaces={ | ||
i.name: { | ||
node.get_ancestor(ast.FunctionDef).name | ||
for node in module.get_descendants(ast.Call) | ||
if getattr(node.func, "id", None) == i.name | ||
} | ||
for i in interfaces | ||
}, | ||
functions=sorted( | ||
{ | ||
get_function_descriptor(node) | ||
for node in module.get_children(ast.FunctionDef) | ||
} | ||
), | ||
variables=sorted( | ||
{ | ||
node.node_source_code.replace("(", " ").replace(")", "") | ||
for node in module.get_children(ast.VariableDecl) | ||
} | ||
), | ||
) | ||
|
||
|
||
def main(pattern: str, internal=True, members=True) -> None: | ||
""" | ||
Generates a mermaid graph of the dependencies between contracts. | ||
Prints the graph and a link to the image via the Mermaid Live Editor. | ||
:param pattern: a glob pattern to match the contracts | ||
:param internal: whether to include internal dependencies | ||
:param members: whether to include the members of each contract | ||
""" | ||
contracts = [ | ||
parse_contract(filename) for filename in glob(pattern, recursive=True) | ||
] | ||
names = {c.contract for c in contracts} | ||
|
||
classes = ( | ||
[ | ||
line | ||
for contract in contracts | ||
for line in [f" class {contract.contract} {{"] | ||
+ contract.variables | ||
+ contract.functions | ||
+ [" }"] | ||
] | ||
if members | ||
else [] | ||
) | ||
|
||
connections = [ | ||
f" {contract.contract} --> {interface}: " | ||
f"{', '.join(selectors) if 0 < len(selectors) < 3 else f'{len(selectors)} selectors'}" | ||
for contract in contracts | ||
for interface, selectors in contract.interfaces.items() | ||
if not internal or interface in names | ||
] | ||
|
||
graph = "\n".join(["classDiagram"] + classes + connections) | ||
|
||
print(graph) | ||
print( | ||
f"https://mermaid.ink/img/{b64encode(graph.encode()).decode('ascii')}" | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
args = sys.argv[1:] | ||
main( | ||
pattern=args[0] if args else "contracts/**/*.vy", | ||
internal="--internal" in args, | ||
members="--members" in args, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,83 +1,110 @@ | ||
import click | ||
from ape import project | ||
from ape.cli import NetworkBoundCommand, account_option, network_option | ||
""" | ||
Deploy the contracts to the network. | ||
Usage for fork mode: | ||
scripts/deploy.py | ||
requires the RPC_ETHEREUM environment variable to be set | ||
Usage for prod mode: | ||
scripts/deploy.py --prod | ||
requires the URL and ACCOUNT environment variables to be set | ||
""" | ||
import boa | ||
from eth_abi import encode | ||
from rich import Console as RichConsole | ||
|
||
from scripts.deployment_utils import setup_environment | ||
|
||
ADDRESS_PROVIDER = "0x0000000022D53366457F9d5E68Ec105046FC4383" | ||
STABLE_REGISTRY_ADDRESS = "0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5" | ||
STABLE_FACTORY_ADDRESS = "0xB9fC157394Af804a3578134A6585C0dc9cc990d4" | ||
CRYPTO_REGISTRY_ADDRESS = "" # left blank because a new one gets deployed | ||
CRYPTO_FACTORY_ADDRESS = "0xF18056Bbd320E96A48e3Fbf8bC061322531aac99" | ||
|
||
|
||
@click.group(short_help="Deploy the project") | ||
def cli(): | ||
pass | ||
|
||
def main(): | ||
""" | ||
Deploy the contracts to the network. | ||
It does the following: | ||
1. deploys the base pool registry | ||
2. deploys the crypto registry | ||
3. deploys the stable registry handler | ||
4. deploys the stable factory handler | ||
5. deploys the crypto registry handler | ||
6. deploys the crypto factory handler | ||
7. deploys the metaregistry | ||
""" | ||
console = RichConsole() | ||
setup_environment(console) | ||
|
||
@cli.command(cls=NetworkBoundCommand) | ||
@network_option() | ||
@account_option() | ||
def main(network, account): | ||
# deploy basepool registry: | ||
base_pool_registry = account.deploy(project.BasePoolRegistry) | ||
base_pool_registry = boa.load( | ||
"contracts/mainnet/registries/BasePoolRegistry.vy" | ||
) | ||
|
||
# deploy crypto registry: | ||
print( | ||
console.log( | ||
"Crypto Registry constructor arguments: ", | ||
encode(["address", "address"], [ADDRESS_PROVIDER, base_pool_registry]), | ||
) | ||
crypto_registry = account.deploy( | ||
project.CryptoRegistryV1, | ||
crypto_registry = boa.load( | ||
"contracts/mainnet/registries/CryptoRegistryV1.vy", | ||
ADDRESS_PROVIDER, | ||
base_pool_registry, | ||
) | ||
|
||
# deploy stable registry handler: | ||
print( | ||
console.log( | ||
"Stable Registry Handler constructor arguments: ", | ||
encode(["address"], [STABLE_REGISTRY_ADDRESS]).hex(), | ||
) | ||
account.deploy(project.StableRegistryHandler, STABLE_REGISTRY_ADDRESS) | ||
boa.load( | ||
"contracts/mainnet/registry_handlers/StableRegistryHandler.vy", | ||
STABLE_REGISTRY_ADDRESS, | ||
) | ||
|
||
# deploy stable factory handler: | ||
print( | ||
console.log( | ||
"Stable Factory Handler constructor arguments: ", | ||
encode( | ||
["address", "address"], | ||
[STABLE_FACTORY_ADDRESS, base_pool_registry], | ||
).hex(), | ||
) | ||
account.deploy( | ||
project.StableFactoryHandler, | ||
boa.load( | ||
"contracts/mainnet/registry_handlers/StableFactoryHandler.vy", | ||
STABLE_FACTORY_ADDRESS, | ||
base_pool_registry, | ||
) | ||
|
||
# deploy crypto registry handler: | ||
print( | ||
console.log( | ||
"Crypto Registry Handler constructor arguments: ", | ||
encode(["address"], [crypto_registry]).hex(), | ||
) | ||
account.deploy(project.CryptoRegistryHandler, crypto_registry) | ||
boa.load( | ||
"contracts/mainnet/registry_handlers/CryptoRegistryHandler.vy", | ||
crypto_registry, | ||
) | ||
|
||
# deploy crypto factory handler: | ||
print( | ||
console.log( | ||
"Crypto Factory Handler constructor arguments: ", | ||
encode( | ||
["address", "address"], | ||
[CRYPTO_FACTORY_ADDRESS, base_pool_registry], | ||
).hex(), | ||
) | ||
account.deploy( | ||
project.CryptoFactoryHandler, | ||
boa.load( | ||
"contracts/mainnet/registry_handlers/CryptoFactoryHandler.vy", | ||
CRYPTO_FACTORY_ADDRESS, | ||
base_pool_registry, | ||
) | ||
|
||
# deploy metaregistry: | ||
print( | ||
console.log( | ||
"MetaRegistry constructor arguments: ", | ||
encode(["address"], [ADDRESS_PROVIDER]).hex(), | ||
) | ||
account.deploy(project.MetaRegistry, ADDRESS_PROVIDER) | ||
boa.load("contracts/mainnet/MetaRegistry.vy", ADDRESS_PROVIDER) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Oops, something went wrong.