Skip to content

Commit

Permalink
autoload: AutoloadResult{ContractResult} and AutoloadConfig{loadContr…
Browse files Browse the repository at this point in the history
…actResult}

Use ABILoader.getContract instead of loadABI when loadContractResult is
set.
  • Loading branch information
shazow committed Sep 29, 2024
1 parent 1055953 commit 902ab40
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 13 deletions.
20 changes: 18 additions & 2 deletions src/__tests__/auto.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,27 @@ online_test('autoload non-contract', async ({ provider, env }) => {
expect(abi).toStrictEqual([]);
});

online_test('autoload verified etherscan', async ({ provider, env }) => {
online_test('autoload verified multi', async ({ provider, env }) => {
const address = "0x8f8ef111b67c04eb1641f5ff19ee54cda062f163"; // Uniswap v3 pool, verified on Etherscan and Sourcify
const result = await autoload(address, {
provider: provider,
...whatsabi.loaders.defaultsWithEnv(env),
});
expect(result.abiLoadedFrom?.name).toBeTruthy()
expect(result.abiLoadedFrom?.name).toBeTruthy();
});

online_test('autoload loadContractResult verified etherscan', async ({ provider, env }) => {
const address = "0xc3d688b66703497daa19211eedff47f25384cdc3"; // Compound USDC proxy
const result = await autoload(address, {
provider: provider,
loadContractResult: true,
followProxies: false,
abiLoader: new whatsabi.loaders.EtherscanABILoader({ apiKey: env.ETHERSCAN_API_KEY }),
});
expect(result.abiLoadedFrom?.name).toBe("EtherscanABILoader");
expect(result.contractResult?.ok).toBeTruthy();
expect(result.contractResult?.name).toBe("TransparentUpgradeableProxy");
expect(result.contractResult?.compilerVersion).toBe("v0.8.15+commit.e14f2714");
expect(result.contractResult?.loaderResult?.Proxy).toBe("1");
expect(result.contractResult?.loaderResult?.Implementation).toBe("0x8a807d39f1d642dd8c12fe2e249fe97847f01ba0");
});
45 changes: 34 additions & 11 deletions src/auto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Fragment, FunctionFragment } from "ethers";
import type { AnyProvider } from "./providers.js";
import type { ABI, ABIFunction } from "./abi.js";
import { type ProxyResolver, DiamondProxyResolver } from "./proxies.js";
import type { ABILoader, SignatureLookup } from "./loaders.js";
import type { ABILoader, SignatureLookup, ContractResult } from "./loaders.js";
import * as errors from "./errors.js";

import { CompatibleProvider } from "./providers.js";
Expand All @@ -28,6 +28,9 @@ export type AutoloadResult = {
/** Whether the `abi` is loaded from a verified source */
abiLoadedFrom?: ABILoader;

/** Full contract metadata result, only included if {@link AutoloadConfig.loadContractResult} is true. */
contractResult?: ContractResult;

/** List of resolveable proxies detected in the contract */
proxies: ProxyResolver[],

Expand Down Expand Up @@ -82,6 +85,15 @@ export type AutoloadConfig = {
*/
followProxies?: boolean;


/**
* Load full contract metadata result, include it in {@link AutoloadResult.ContractResult} if successful.
*
* This changes the behaviour of autoload to use {@link ABILoader.getContract} instead of {@link ABILoader.loadABI},
* which returns a larger superset result including all of the available verified contract metadata.
*/
loadContractResult?: boolean;

/**
* Enable pulling additional metadata from WhatsABI's static analysis, still unreliable
*
Expand Down Expand Up @@ -213,16 +225,27 @@ export async function autoload(address: string, config: AutoloadConfig): Promise
}

try {
const addresses = Object.keys(facets);
const promises = addresses.map(addr => loader.loadABI(addr));
const results = await Promise.all(promises);
const abis = Object.fromEntries(results.map((abi, i) => {
return [addresses[i], abi];
}));
result.abi = pruneFacets(facets, abis);
if (result.abi.length > 0) {
result.abiLoadedFrom = abiLoadedFrom;
return result;
if (config.loadContractResult) {
const contractResult = await loader.getContract(address);
if (contractResult) {
result.contractResult = contractResult;
result.abi = contractResult.abi;
result.abiLoadedFrom = contractResult.loader;
return result;
}
} else {
// Load ABIs of all available facets and merge
const addresses = Object.keys(facets);
const promises = addresses.map(addr => loader.loadABI(addr));
const results = await Promise.all(promises);
const abis = Object.fromEntries(results.map((abi, i) => {
return [addresses[i], abi];
}));
result.abi = pruneFacets(facets, abis);
if (result.abi.length > 0) {
result.abiLoadedFrom = abiLoadedFrom;
return result;
}
}
} catch (error: any) {
// TODO: Catch useful errors
Expand Down

0 comments on commit 902ab40

Please sign in to comment.