diff --git a/config_samples/base_mainnet_config_L1.json b/config_samples/base/base_mainnet_config_L1.json similarity index 100% rename from config_samples/base_mainnet_config_L1.json rename to config_samples/base/base_mainnet_config_L1.json diff --git a/config_samples/base_mainnet_config_L2.json b/config_samples/base/base_mainnet_config_L2.json similarity index 100% rename from config_samples/base_mainnet_config_L2.json rename to config_samples/base/base_mainnet_config_L2.json diff --git a/config_samples/linea/mainnet/linea_mainnet_config_L1.json b/config_samples/linea/mainnet/linea_mainnet_config_L1.json new file mode 100644 index 0000000..96ff81d --- /dev/null +++ b/config_samples/linea/mainnet/linea_mainnet_config_L1.json @@ -0,0 +1,27 @@ +{ + "contracts": { + "0x051F1D88f0aF5763fB888eC4378b4D8B29ea3319": "TransparentUpgradeableProxy", + "0x5b0bb17755fba06028530682e2fd5bc373931768": "ProxyAdmin" + }, + "explorer_hostname": "api.etherscan.io", + "explorer_token_env_var": "ETHERSCAN_EXPLORER_TOKEN", + "github_repo": { + "url": "https://github.com/Consensys/linea-contracts-fix", + "commit": "0949c4096664e613f73ed3ce51c32f97fc56cdef", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "0a25c1940ca220686588c4af3ec526f725fe2582", + "relative_root": "contracts", + "//": "oz version 4.8.3" + }, + "@openzeppelin/contracts-upgradeable": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable", + "commit": "58fa0f81c4036f1a3b616fdffad2fd27e5d5ce21", + "relative_root": "contracts", + "//": "oz version 4.8.3" + } + } +} diff --git a/config_samples/linea/mainnet/linea_mainnet_config_L1_tokenbridge.json b/config_samples/linea/mainnet/linea_mainnet_config_L1_tokenbridge.json new file mode 100644 index 0000000..0235fca --- /dev/null +++ b/config_samples/linea/mainnet/linea_mainnet_config_L1_tokenbridge.json @@ -0,0 +1,26 @@ +{ + "contracts": { + "0x6ccfd65b0b14f67259c77ca6267104e058ddb292": "TokenBridge" + }, + "explorer_hostname": "api.etherscan.io", + "explorer_token_env_var": "ETHERSCAN_EXPLORER_TOKEN", + "github_repo": { + "url": "https://github.com/Consensys/linea-contracts-fix", + "commit": "0949c4096664e613f73ed3ce51c32f97fc56cdef", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "e50c24f5839db17f46991478384bfda14acfb830", + "relative_root": "contracts", + "//": "oz version 4.9.2" + }, + "@openzeppelin/contracts-upgradeable": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable", + "commit": "bc95521e34dcd49792065e264a7ad2b5a86f0091", + "relative_root": "contracts", + "//": "oz version 4.9.2" + } + } +} diff --git a/config_samples/linea/mainnet/linea_mainnet_config_L2.json b/config_samples/linea/mainnet/linea_mainnet_config_L2.json new file mode 100644 index 0000000..b2eeda8 --- /dev/null +++ b/config_samples/linea/mainnet/linea_mainnet_config_L2.json @@ -0,0 +1,29 @@ +{ + "contracts": { + "0xa11ba93afbd6d18e26fefdb2c6311da6c9b370d6": "ProxyAdmin", + "0x2bfdf4a0d54c93a4baf74f8dcea8a275d8ee97a9": "TokenBridge", + "0xc0583e2F5930EDE5Fab9D57bAC4169878730B010": "CustomBridgedToken", + "0xF951d7592e03eDB0Bab3D533935e678Ce64Eb927": "ProxyAdmin" + }, + "explorer_hostname": "api.lineascan.build", + "explorer_token_env_var": "LINEA_EXPLORER_TOKEN", + "github_repo": { + "url": "https://github.com/Consensys/linea-contracts-fix", + "commit": "0949c4096664e613f73ed3ce51c32f97fc56cdef", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "e50c24f5839db17f46991478384bfda14acfb830", + "relative_root": "contracts", + "//": "oz version 4.9.2" + }, + "@openzeppelin/contracts-upgradeable": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable", + "commit": "bc95521e34dcd49792065e264a7ad2b5a86f0091", + "relative_root": "contracts", + "//": "oz version 4.9.2" + } + } +} diff --git a/config_samples/linea/mainnet/linea_mainnet_config_L2_gov.json b/config_samples/linea/mainnet/linea_mainnet_config_L2_gov.json new file mode 100644 index 0000000..08045c1 --- /dev/null +++ b/config_samples/linea/mainnet/linea_mainnet_config_L2_gov.json @@ -0,0 +1,13 @@ +{ + "contracts": { + "0x74Be82F00CC867614803ffd7f36A2a4aF0405670": "LineaBridgeExecutor" + }, + "explorer_hostname": "api.lineascan.build", + "explorer_token_env_var": "LINEA_EXPLORER_TOKEN", + "github_repo": { + "url": "https://github.com/Consensys/governance-crosschain-bridges", + "commit": "315308a2640c696937185732159b130417f29997", + "relative_root": "" + }, + "dependencies": {} +} diff --git a/config_samples/linea/mainnet/linea_mainnet_config_L2_proxy.json b/config_samples/linea/mainnet/linea_mainnet_config_L2_proxy.json new file mode 100644 index 0000000..bbe6b19 --- /dev/null +++ b/config_samples/linea/mainnet/linea_mainnet_config_L2_proxy.json @@ -0,0 +1,21 @@ +{ + "contracts": { + "0x353012dc4a9A6cF55c941bADC267f82004A8ceB9": "TransparentUpgradeableProxy", + "0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F": "TransparentUpgradeableProxy" + }, + "explorer_hostname": "api.lineascan.build", + "explorer_token_env_var": "LINEA_EXPLORER_TOKEN", + "github_repo": { + "url": "https://github.com/Consensys/linea-contracts-fix", + "commit": "0949c4096664e613f73ed3ce51c32f97fc56cdef", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "0a25c1940ca220686588c4af3ec526f725fe2582", + "relative_root": "contracts", + "//": "oz version 4.8.3" + } + } +} diff --git a/config_samples/linea/testnet/linea_testnet_config_L1_proxy.json b/config_samples/linea/testnet/linea_testnet_config_L1_proxy.json new file mode 100644 index 0000000..796f1be --- /dev/null +++ b/config_samples/linea/testnet/linea_testnet_config_L1_proxy.json @@ -0,0 +1,19 @@ +{ + "contracts": { + "0x5506A3805fB8A58Fa58248CC52d2b06D92cA94e6": "TransparentUpgradeableProxy" + }, + "explorer_hostname": "api-goerli.etherscan.io", + "github_repo": { + "url": "https://github.com/Consensys/linea-contracts", + "commit": "3cf85529fd4539eb06ba998030c37e47f98c528a", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "0a25c1940ca220686588c4af3ec526f725fe2582", + "relative_root": "contracts", + "//": "oz version 4.8.3" + } + } +} diff --git a/config_samples/linea/testnet/linea_testnet_config_L1_proxyadmin.json b/config_samples/linea/testnet/linea_testnet_config_L1_proxyadmin.json new file mode 100644 index 0000000..32f9165 --- /dev/null +++ b/config_samples/linea/testnet/linea_testnet_config_L1_proxyadmin.json @@ -0,0 +1,19 @@ +{ + "contracts": { + "0xE80528ac405ffd62cE439593cE74C20726048F62": "ProxyAdmin" + }, + "explorer_hostname": "api-goerli.etherscan.io", + "github_repo": { + "url": "https://github.com/Consensys/linea-contracts", + "commit": "3cf85529fd4539eb06ba998030c37e47f98c528a", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "23869e5b2a7c6b9c3e27dee4289615b8cf50e36b", + "relative_root": "contracts", + "//": "oz version 4.1.0" + } + } +} diff --git a/config_samples/linea/testnet/linea_testnet_config_L1_tokenbridge.json b/config_samples/linea/testnet/linea_testnet_config_L1_tokenbridge.json new file mode 100644 index 0000000..1bb9504 --- /dev/null +++ b/config_samples/linea/testnet/linea_testnet_config_L1_tokenbridge.json @@ -0,0 +1,25 @@ +{ + "contracts": { + "0x292A9478A52F0B8b12429c58F79367448aBe0214": "TokenBridge" + }, + "explorer_hostname": "api-goerli.etherscan.io", + "github_repo": { + "url": "https://github.com/Consensys/linea-contracts", + "commit": "3cf85529fd4539eb06ba998030c37e47f98c528a", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "e50c24f5839db17f46991478384bfda14acfb830", + "relative_root": "contracts", + "//": "oz version 4.9.2" + }, + "@openzeppelin/contracts-upgradeable": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable", + "commit": "bc95521e34dcd49792065e264a7ad2b5a86f0091", + "relative_root": "contracts", + "//": "oz version 4.9.2" + } + } +} diff --git a/config_samples/linea/testnet/linea_testnet_config_L2.json b/config_samples/linea/testnet/linea_testnet_config_L2.json new file mode 100644 index 0000000..9947726 --- /dev/null +++ b/config_samples/linea/testnet/linea_testnet_config_L2.json @@ -0,0 +1,25 @@ +{ + "contracts": { + "0x2bb4036e0cdd52c2134a95b6249eb89e5f6bc7f1": "CustomBridgedToken" + }, + "explorer_hostname": "api-testnet.lineascan.build", + "github_repo": { + "url": "https://github.com/Consensys/linea-contracts", + "commit": "3cf85529fd4539eb06ba998030c37e47f98c528a", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "e50c24f5839db17f46991478384bfda14acfb830", + "relative_root": "contracts", + "//": "oz version 4.9.2" + }, + "@openzeppelin/contracts-upgradeable": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable", + "commit": "bc95521e34dcd49792065e264a7ad2b5a86f0091", + "relative_root": "contracts", + "//": "oz version 4.9.2" + } + } +} diff --git a/config_samples/linea/testnet/linea_testnet_config_L2_gov.json b/config_samples/linea/testnet/linea_testnet_config_L2_gov.json new file mode 100644 index 0000000..ba9decc --- /dev/null +++ b/config_samples/linea/testnet/linea_testnet_config_L2_gov.json @@ -0,0 +1,12 @@ +{ + "contracts": { + "0x4b38D24E70079f2dd1D79B86E2B52f4b13872a3B": "LineaBridgeExecutor" + }, + "explorer_hostname": "api-testnet.lineascan.build", + "github_repo": { + "url": "https://github.com/Consensys/governance-crosschain-bridges", + "commit": "7d4fd35e92688d7aa56ae2f94872f851bacae50c", + "relative_root": "contracts/bridges" + }, + "dependencies": {} +} diff --git a/config_samples/linea/testnet/linea_testnet_config_L2_proxy.json b/config_samples/linea/testnet/linea_testnet_config_L2_proxy.json new file mode 100644 index 0000000..90839e6 --- /dev/null +++ b/config_samples/linea/testnet/linea_testnet_config_L2_proxy.json @@ -0,0 +1,20 @@ +{ + "contracts": { + "0x9ceed01e39279a529f44deB9d35E09a04B1E67c8": "TransparentUpgradeableProxy", + "0x71062fBC3da2d792285C3d5dabba12A42339e85c": "ProxyAdmin" + }, + "explorer_hostname": "api-testnet.lineascan.build", + "github_repo": { + "url": "https://github.com/Consensys/linea-contracts", + "commit": "3cf85529fd4539eb06ba998030c37e47f98c528a", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "0a25c1940ca220686588c4af3ec526f725fe2582", + "relative_root": "contracts", + "//": "oz version 4.8.3" + } + } +} diff --git a/config_samples/linea/testnet/linea_testnet_config_L2_proxyadmin.json b/config_samples/linea/testnet/linea_testnet_config_L2_proxyadmin.json new file mode 100644 index 0000000..6902895 --- /dev/null +++ b/config_samples/linea/testnet/linea_testnet_config_L2_proxyadmin.json @@ -0,0 +1,19 @@ +{ + "contracts": { + "0x1637A76e2981bf3fea05B756d79a8f3F874822af": "ProxyAdmin" + }, + "explorer_hostname": "api-testnet.lineascan.build", + "github_repo": { + "url": "https://github.com/Consensys/linea-contracts", + "commit": "3cf85529fd4539eb06ba998030c37e47f98c528a", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "23869e5b2a7c6b9c3e27dee4289615b8cf50e36b", + "relative_root": "contracts", + "//": "oz version 4.1.0" + } + } +} diff --git a/config_samples/mantle_mainnet_config_L1.json b/config_samples/mantle/mainnet/mantle_mainnet_config_L1.json similarity index 100% rename from config_samples/mantle_mainnet_config_L1.json rename to config_samples/mantle/mainnet/mantle_mainnet_config_L1.json diff --git a/config_samples/mantle_mainnet_config_L2.json b/config_samples/mantle/mainnet/mantle_mainnet_config_L2.json similarity index 100% rename from config_samples/mantle_mainnet_config_L2.json rename to config_samples/mantle/mainnet/mantle_mainnet_config_L2.json diff --git a/config_samples/mantle_mainnet_config_L2_gov.json b/config_samples/mantle/mainnet/mantle_mainnet_config_L2_gov.json similarity index 100% rename from config_samples/mantle_mainnet_config_L2_gov.json rename to config_samples/mantle/mainnet/mantle_mainnet_config_L2_gov.json diff --git a/config_samples/mantle_testnet_config_L1.json b/config_samples/mantle/testnet/mantle_testnet_config_L1.json similarity index 100% rename from config_samples/mantle_testnet_config_L1.json rename to config_samples/mantle/testnet/mantle_testnet_config_L1.json diff --git a/config_samples/mantle_testnet_config_L2.json b/config_samples/mantle/testnet/mantle_testnet_config_L2.json similarity index 100% rename from config_samples/mantle_testnet_config_L2.json rename to config_samples/mantle/testnet/mantle_testnet_config_L2.json diff --git a/config_samples/optimism_mainnet_config_L1.json b/config_samples/optimism/optimism_mainnet_config_L1.json similarity index 100% rename from config_samples/optimism_mainnet_config_L1.json rename to config_samples/optimism/optimism_mainnet_config_L1.json diff --git a/config_samples/optimism_mainnet_config_L2.json b/config_samples/optimism/optimism_mainnet_config_L2.json similarity index 100% rename from config_samples/optimism_mainnet_config_L2.json rename to config_samples/optimism/optimism_mainnet_config_L2.json diff --git a/config_samples/zksync_mainnet_config_L1.json b/config_samples/zksync/mainnet/zksync_mainnet_config_L1.json similarity index 100% rename from config_samples/zksync_mainnet_config_L1.json rename to config_samples/zksync/mainnet/zksync_mainnet_config_L1.json diff --git a/config_samples/zksync_mainnet_config_L2.json b/config_samples/zksync/mainnet/zksync_mainnet_config_L2.json similarity index 100% rename from config_samples/zksync_mainnet_config_L2.json rename to config_samples/zksync/mainnet/zksync_mainnet_config_L2.json diff --git a/config_samples/zksync_testnet_config_L1.json b/config_samples/zksync/testnet/zksync_testnet_config_L1.json similarity index 100% rename from config_samples/zksync_testnet_config_L1.json rename to config_samples/zksync/testnet/zksync_testnet_config_L1.json diff --git a/config_samples/zksync_testnet_config_L2.json b/config_samples/zksync/testnet/zksync_testnet_config_L2.json similarity index 100% rename from config_samples/zksync_testnet_config_L2.json rename to config_samples/zksync/testnet/zksync_testnet_config_L2.json diff --git a/main.py b/main.py index 392ddf6..95debc1 100644 --- a/main.py +++ b/main.py @@ -1,15 +1,22 @@ import difflib import sys import time +import argparse +import os from utils.common import load_config, load_env -from utils.constants import DIFFS_DIR, START_TIME +from utils.constants import DIFFS_DIR, START_TIME, DEFAULT_CONFIG_PATH from utils.explorer import get_contract_from_explorer from utils.github import get_file_from_github, resolve_dep from utils.helpers import create_dirs from utils.logger import logger +GITHUB_API_TOKEN = load_env("GITHUB_API_TOKEN", masked=True) + +g_skip_user_input: bool = False + + def run_diff(config, name, address, explorer_api_token, github_api_token): logger.divider() logger.okay("Contract", address) @@ -20,7 +27,9 @@ def run_diff(config, name, address, explorer_api_token, github_api_token): logger.divider() - logger.info(f"Fetching source code from blockchain explorer {config['explorer_hostname']} ...") + logger.info( + f"Fetching source code from blockchain explorer {config['explorer_hostname']} ..." + ) contract_name, source_files = get_contract_from_explorer( token=explorer_api_token, explorer_hostname=config["explorer_hostname"], @@ -38,8 +47,10 @@ def run_diff(config, name, address, explorer_api_token, github_api_token): logger.okay("Contract", contract_name) logger.okay("Files", files_count) - input("Press Enter to proceed...") - logger.divider() + if not g_skip_user_input: + input("Press Enter to proceed...") + logger.divider() + logger.info("Diffing...") report = [] @@ -66,7 +77,14 @@ def run_diff(config, name, address, explorer_api_token, github_api_token): logger.error("File not found", path_to_file) sys.exit() - github_file = get_file_from_github(github_api_token, repo, path_to_file, dep_name) + file_found = bool(repo) + + github_file = get_file_from_github( + github_api_token, repo, path_to_file, dep_name + ) + if not github_file: + github_file = "" + file_found = False github_lines = github_file.splitlines() explorer_lines = source_code["content"].splitlines() @@ -81,8 +99,6 @@ def run_diff(config, name, address, explorer_api_token, github_api_token): diffs = difflib.unified_diff(github_lines, explorer_lines) diffs_count = len(list(diffs)) - file_found = bool(repo) - report_data = [ file_number, filename, @@ -105,45 +121,44 @@ def run_diff(config, name, address, explorer_api_token, github_api_token): logger.report_table(report) -def main(): - logger.info("Welcome to Diffyscan!") - logger.divider() +def process_config(path: str): + logger.info(f"Loading config {path}...") + config = load_config(path) + explorer_token = None + if "explorer_token_env_var" in config: + explorer_token = load_env(config["explorer_token_env_var"], masked=True, required=False) - logger.info("Loading API tokens...") - explorer_api_token = load_env("ETHERSCAN_TOKEN", masked=True) - github_api_token = load_env("GITHUB_API_TOKEN", masked=True) + contracts = config["contracts"] + logger.info(f"Running diff for contracts from config {contracts}...") + for address, name in config["contracts"].items(): + run_diff(config, name, address, explorer_token, GITHUB_API_TOKEN) - contract_address = load_env("CONTRACT_ADDRESS", required=False) - contract_name = load_env("CONTRACT_NAME", required=False) - logger.divider() +def parse_arguments(): + parser = argparse.ArgumentParser() + parser.add_argument("path", nargs="?", default=None, help="Path to config or directory with configs") + parser.add_argument("--yes", "-y", help="If set don't ask for input before validating each contract", action="store_true") + return parser.parse_args() - logger.info("Loading config...") - config = load_config() - if contract_address is not None: - if contract_name is None: - logger.error( - "Please set the 'CONTRACT_NAME' env var for address", - f"{contract_address}", - ) - sys.exit(1) +def main(): + global g_skip_user_input - logger.info( - f"Running diff for a single contract {contract_name} deployed at {contract_address}..." - ) - run_diff( - config, - contract_name, - contract_address, - explorer_api_token, - github_api_token, - ) - else: - contracts = config["contracts"] - logger.info(f"Running diff for contracts from config {contracts}...") - for address, name in config["contracts"].items(): - run_diff(config, name, address, explorer_api_token, github_api_token) + args = parse_arguments() + g_skip_user_input = args.yes + + logger.info("Welcome to Diffyscan!") + logger.divider() + + if args.path is None: + process_config(DEFAULT_CONFIG_PATH) + elif os.path.isfile(args.path): + process_config(args.path) + elif os.path.isdir(args.path): + for filename in os.listdir(args.path): + config_path = os.path.join(args.path, filename) + if os.path.isfile(config_path): + process_config(config_path) execution_time = time.time() - START_TIME diff --git a/utils/common.py b/utils/common.py index 925d1b4..5da67e1 100644 --- a/utils/common.py +++ b/utils/common.py @@ -5,19 +5,18 @@ import requests -from utils.constants import CONFIG_PATH from utils.logger import logger from utils.types import Config def load_env(variable_name, required=True, masked=False): - value = os.getenv(variable_name) + value = os.getenv(variable_name, default=None) if required and not value: logger.error("Env not found", variable_name) sys.exit(1) - printable_value = mask_text(value) if masked else value + printable_value = mask_text(value) if masked and value is not None else str(value) if printable_value: logger.okay(f"{variable_name}", printable_value) @@ -27,17 +26,11 @@ def load_env(variable_name, required=True, masked=False): return value -def load_config() -> Config: - config_path = get_config_path() - - with open(config_path, mode="r") as config_file: +def load_config(path: str) -> Config: + with open(path, mode="r") as config_file: return json.load(config_file) -def get_config_path() -> str: - return CONFIG_PATH - - def fetch(url, headers={}): logger.log(f"fetch: {url}") response = requests.get(url, headers=headers) @@ -46,7 +39,6 @@ def fetch(url, headers={}): logger.error("Request failed", url) logger.error("Status", response.status_code) logger.error("Response", response.text) - sys.exit() return response.json() diff --git a/utils/constants.py b/utils/constants.py index d31b85e..757e5a2 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -5,4 +5,4 @@ START_TIME_INT = int(START_TIME) DIFFS_DIR = f"{DIGEST_DIR}/{START_TIME_INT}/diffs" LOGS_PATH = f"{DIGEST_DIR}/{START_TIME_INT}/logs.txt" -CONFIG_PATH = "config.json" +DEFAULT_CONFIG_PATH = "config.json" diff --git a/utils/explorer.py b/utils/explorer.py index 2323d44..8a942c6 100644 --- a/utils/explorer.py +++ b/utils/explorer.py @@ -11,7 +11,9 @@ def _errorNoSourceCodeAndExit(address): def _get_contract_from_etherscan(token, etherscan_hostname, contract): - etherscan_link = f"https://{etherscan_hostname}/api?module=contract&action=getsourcecode&address={contract}&apikey={token}" + etherscan_link = f"https://{etherscan_hostname}/api?module=contract&action=getsourcecode&address={contract}" + if token is not None: + etherscan_link = f"{etherscan_link}&apikey={token}" response = fetch(etherscan_link) @@ -26,12 +28,18 @@ def _get_contract_from_etherscan(token, etherscan_hostname, contract): _errorNoSourceCodeAndExit(contract) contract_name = data["ContractName"] - source_files = json.loads(data["SourceCode"][1:-1])["sources"].items() + + json_escaped = data["SourceCode"].startswith("{{") + source_files = ( + json.loads(data["SourceCode"][1:-1])["sources"].items() + if json_escaped + else json.loads(data["SourceCode"]).items() + ) return (contract_name, source_files) -def _get_contract_from_zksync(token, zksync_explorer_hostname, contract): +def _get_contract_from_zksync(zksync_explorer_hostname, contract): zksync_explorer_link = ( f"https://{zksync_explorer_hostname}/contract_verification/info/{contract}" ) @@ -53,7 +61,7 @@ def _get_contract_from_zksync(token, zksync_explorer_hostname, contract): return (contract_name, source_files) -def _get_contract_from_mantle(token, mantle_explorer_hostname, contract): +def _get_contract_from_mantle(mantle_explorer_hostname, contract): etherscan_link = f"https://{mantle_explorer_hostname}/api?module=contract&action=getsourcecode&address={contract}" response = fetch(etherscan_link) @@ -71,7 +79,9 @@ def _get_contract_from_mantle(token, mantle_explorer_hostname, contract): def get_contract_from_explorer(token, explorer_hostname, contract): if explorer_hostname.startswith("zksync"): - return _get_contract_from_zksync(token, explorer_hostname, contract) + return _get_contract_from_zksync(explorer_hostname, contract) if explorer_hostname.endswith("mantle.xyz"): - return _get_contract_from_mantle(token, explorer_hostname, contract) + return _get_contract_from_mantle(explorer_hostname, contract) + if explorer_hostname.endswith("lineascan.build"): + return _get_contract_from_etherscan(None, explorer_hostname, contract) return _get_contract_from_etherscan(token, explorer_hostname, contract) diff --git a/utils/github.py b/utils/github.py index 5a32010..bf21877 100644 --- a/utils/github.py +++ b/utils/github.py @@ -2,16 +2,15 @@ from utils.common import fetch, parse_repo_link from utils.logger import logger + def get_file_from_github(github_api_token, dependency_repo, path_to_file, dep_name): path_to_file = path_to_file_without_dependency(path_to_file, dep_name) - user_slash_repo = parse_repo_link(dependency_repo['url']) + user_slash_repo = parse_repo_link(dependency_repo["url"]) - github_api_url = ( - f"https://api.github.com/repos/{user_slash_repo}/contents/{dependency_repo['relative_root']}/{path_to_file}" - ) + github_api_url = f"https://api.github.com/repos/{user_slash_repo}/contents/{dependency_repo['relative_root']}/{path_to_file}" - github_api_url += "?ref=" + dependency_repo['commit'] + github_api_url += "?ref=" + dependency_repo["commit"] github_data = fetch( github_api_url, headers={"Authorization": f"token {github_api_token}"} @@ -21,9 +20,11 @@ def get_file_from_github(github_api_token, dependency_repo, path_to_file, dep_na if not file_content: logger.error("No file content") + return None return base64.b64decode(file_content).decode() + def path_to_file_without_dependency(path_to_file, dep_name): # exclude dependency prefix from path to file # "@aragon/something/lib/my.sol" => "lib/my.sol" diff --git a/utils/logger.py b/utils/logger.py index 3ad069d..7895207 100644 --- a/utils/logger.py +++ b/utils/logger.py @@ -110,7 +110,7 @@ def color_row(self, row): diffs_found = row[3] != None and row[3] > 0 if not file_found: - hlcolor = YELLOW + hlcolor = RED elif diffs_found: hlcolor = RED