From 23d6a9cba3db345cf2ecef3eeaeaff9b7c97afa6 Mon Sep 17 00:00:00 2001 From: Etienne Donneger Date: Wed, 2 Oct 2024 14:48:05 -0400 Subject: [PATCH] Replace Etherscan ABI lookups with Sourcify Etherscan requires an API key for ABI lookup and other operations. Sourcify (https://sourcify.dev) is an open-source decentralized alternative. --- packages/cli/src/command-helpers/abi.ts | 30 +++++++++++++++++++++++-- packages/cli/src/commands/init.ts | 4 +++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/command-helpers/abi.ts b/packages/cli/src/command-helpers/abi.ts index 2b808f525..2709929f0 100644 --- a/packages/cli/src/command-helpers/abi.ts +++ b/packages/cli/src/command-helpers/abi.ts @@ -11,6 +11,30 @@ export const loadAbiFromSourcify = async ( ABICtor: typeof ABI, network: string, address: string, +): Promise => + await withSpinner( + `Fetching ABI from Sourcify`, + `Failed to fetch ABI from Sourcify`, + `Warnings while fetching ABI from Sourcify`, + async () => { + const chainId = await getSourcifyChainId(network); + const result = await fetch(`https://repo.sourcify.dev/contracts/full_match/${chainId}/${address}/metadata.json`); + const json = await result.json(); + + // Etherscan returns a JSON object that has a `status`, a `message` and + // a `result` field. The `status` is '0' in case of errors and '1' in + // case of success + if (result.ok) { + return new ABICtor('Contract', undefined, immutable.fromJS(json.output.abi)); + } + throw new Error('ABI not found, try loading it from a local file'); + }, + ); + +export const loadAbiFromEtherscan = async ( + ABICtor: typeof ABI, + network: string, + address: string, ): Promise => await withSpinner( `Fetching ABI from Sourcify`, @@ -202,8 +226,10 @@ const getSourcifyChainId = async (network: string) => { // Can fail if network name doesn't follow https://chainlist.org name convention const match = json.find((e: any) => e.name.toLowerCase().includes(network.replace('-', ' '))); - if (match) return match.chainId; - throw new Error(`Could not find chain id for "${network}"`); + if (match) + return match.chainId; + else + throw new Error(`Could not find chain id for "${network}"`); }; const getEtherscanLikeAPIUrl = (network: string) => { diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 2f68ee723..17c960d20 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -707,7 +707,9 @@ async function processInitForm( // Try loading the ABI from Sourcify, if none was provided if (protocolInstance.hasABIs() && !initAbi) { - abiFromSourcify = await retryWithPrompt(() => loadAbiFromSourcify(ABI, network, value)); + abiFromSourcify = await retryWithPrompt(() => + loadAbiFromSourcify(ABI, network, value), + ); } // If startBlock is not set, try to load it. if (!initStartBlock) {