Skip to content

Commit

Permalink
Merge pull request #161 from shazow/test-loaders
Browse files Browse the repository at this point in the history
tests: Improve loader tests, add no-result checks
  • Loading branch information
shazow authored Dec 2, 2024
2 parents cfef7ed + 7e0f983 commit 742daea
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 53 deletions.
2 changes: 2 additions & 0 deletions src/__tests__/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type TestWithContext = (
timeout?: number
) => void;

// TODO: Switch to using test.extend? https://vitest.dev/api/#test-extend

function testerWithContext(tester: ItConcurrent, context: any): TestWithContext {
return (name, fn, timeout) => tester(name, () => fn(context), timeout);
}
Expand Down
129 changes: 77 additions & 52 deletions src/__tests__/loaders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@ import { expect, describe } from 'vitest';
import {
defaultABILoader,
defaultSignatureLookup,

SourcifyABILoader,
EtherscanABILoader,
BlockscoutABILoader,
MultiABILoader,

OpenChainSignatureLookup,
SamczunSignatureLookup,
FourByteSignatureLookup,
MultiABILoader,
BlockscoutABILoader,
} from "../loaders";
import type {
ABILoader
} from "../loaders";

import { selectorsFromABI } from "../index";

import { online_test, test } from "./env";
import { describe_cached, online_test, test } from "./env";

const SLOW_ETHERSCAN_TIMEOUT = 30000;

describe('loaders module', () => {
describe('loaders: ABILoader', () => {
online_test('defaultABILoader', async () => {
const addr = "0x7a250d5630b4cf539739df2c5dacb4c659f2488d";
const abi = await defaultABILoader.loadABI(addr);
Expand All @@ -29,16 +35,6 @@ describe('loaders module', () => {
expect(selectors["0x7ff36ab5"]).toStrictEqual("swapExactETHForTokens(uint256,address[],address,uint256)");
});

online_test('defaultSignatureLookup', async () => {
const sig = "swapExactETHForTokens(uint256,address[],address,uint256)";
const selector = "0x7ff36ab5"
const selectors = selectorsFromABI([sig]);
expect(Object.keys(selectors)).toContain(selector);

const r = await defaultSignatureLookup.loadFunctions(selector);
expect(r).toContain(sig);
});

online_test('SourcifyABILoader', async () => {
const loader = new SourcifyABILoader();
const abi = await loader.loadABI("0x7a250d5630b4cf539739df2c5dacb4c659f2488d"); // Unchecksummed address
Expand All @@ -47,30 +43,30 @@ describe('loaders module', () => {
expect(selectors).toContain(sig);
})

online_test('EtherscanABILoader', async () => {
const loader = new EtherscanABILoader({ apiKey: process.env["ETHERSCAN_API_KEY"] });
online_test('EtherscanABILoader', async ({ env }) => {
const loader = new EtherscanABILoader({ apiKey: env["ETHERSCAN_API_KEY"] });
const abi = await loader.loadABI("0x7a250d5630b4cf539739df2c5dacb4c659f2488d");
const selectors = Object.values(selectorsFromABI(abi));
const sig = "swapExactETHForTokens(uint256,address[],address,uint256)";
expect(selectors).toContain(sig);
}, SLOW_ETHERSCAN_TIMEOUT)

online_test('BlockscoutABILoader', async () => {
online_test('BlockscoutABILoader', async ({ env }) => {
const loader = new BlockscoutABILoader({
apiKey: process.env["BLOCKSCOUT_API_KEY"],
apiKey: env["BLOCKSCOUT_API_KEY"],
});
const abi = await loader.loadABI("0x7a250d5630b4cf539739df2c5dacb4c659f2488d");
const selectors = Object.values(selectorsFromABI(abi));
const sig = "swapExactETHForTokens(uint256,address[],address,uint256)";
expect(selectors).toContain(sig);
})

online_test('MultiABILoader', async () => {
online_test('MultiABILoader', async ({ env }) => {
// A contract that is verified on etherscan but not sourcify
const address = "0xa9a57f7d2A54C1E172a7dC546fEE6e03afdD28E2";
const loader = new MultiABILoader([
new SourcifyABILoader(),
new EtherscanABILoader({ apiKey: process.env["ETHERSCAN_API_KEY"] }),
new EtherscanABILoader({ apiKey: env["ETHERSCAN_API_KEY"] }),
]);
const abi = await loader.loadABI(address);
const sig = "getMagistrate()";
Expand All @@ -90,12 +86,6 @@ describe('loaders module', () => {
expect(result.loaderResult?.output?.devdoc).toBeDefined();
})

online_test('SourcifyABILoader_getContract_missing', async () => {
const loader = new SourcifyABILoader();
const r = await loader.getContract("0x0000000000000000000000000000000000000000");
expect(r.ok).toBeFalsy();
})

online_test('SourcifyABILoader_getContract_UniswapV3Factory', async () => {
const loader = new SourcifyABILoader();
const { abi, name } = await loader.getContract("0x1F98431c8aD98523631AE4a59f267346ea31F984");
Expand All @@ -105,8 +95,8 @@ describe('loaders module', () => {
expect(name).toEqual("Canonical Uniswap V3 factory");
})

online_test('EtherscanABILoader_getContract', async () => {
const loader = new EtherscanABILoader({ apiKey: process.env["ETHERSCAN_API_KEY"] });
online_test('EtherscanABILoader_getContract', async ({ env }) => {
const loader = new EtherscanABILoader({ apiKey: env["ETHERSCAN_API_KEY"] });
const result = await loader.getContract("0x7a250d5630b4cf539739df2c5dacb4c659f2488d");
const selectors = Object.values(selectorsFromABI(result.abi));
const sig = "swapExactETHForTokens(uint256,address[],address,uint256)";
Expand All @@ -117,26 +107,26 @@ describe('loaders module', () => {

}, SLOW_ETHERSCAN_TIMEOUT)

online_test('EtherscanABILoader_getContract_UniswapV3Factory', async () => {
const loader = new EtherscanABILoader({ apiKey: process.env["ETHERSCAN_API_KEY"] });
online_test('EtherscanABILoader_getContract_UniswapV3Factory', async ({ env }) => {
const loader = new EtherscanABILoader({ apiKey: env["ETHERSCAN_API_KEY"] });
const { abi, name } = await loader.getContract("0x1F98431c8aD98523631AE4a59f267346ea31F984");
const selectors = Object.values(selectorsFromABI(abi));
const sig = "owner()";
expect(selectors).toContain(sig);
expect(name).toEqual("UniswapV3Factory");
}, SLOW_ETHERSCAN_TIMEOUT)

online_test('EtherscanABILoader_getContract_CompoundUSDCProxy', async () => {
const loader = new EtherscanABILoader({ apiKey: process.env["ETHERSCAN_API_KEY"] });
online_test('EtherscanABILoader_getContract_CompoundUSDCProxy', async ({ env }) => {
const loader = new EtherscanABILoader({ apiKey: env["ETHERSCAN_API_KEY"] });
const result = await loader.getContract("0xc3d688b66703497daa19211eedff47f25384cdc3");
expect(result.name).toEqual("TransparentUpgradeableProxy");
expect(result.loaderResult?.Proxy).toBeTruthy();
expect(result.loaderResult?.Implementation).toMatch(/^0x[0-9a-f]{40}$/);
}, SLOW_ETHERSCAN_TIMEOUT)

online_test('BlockscoutABILoader_getContract', async () => {
online_test('BlockscoutABILoader_getContract', async ({ env }) => {
const loader = new BlockscoutABILoader({
apiKey: process.env["BLOCKSCOUT_API_KEY"],
apiKey: env["BLOCKSCOUT_API_KEY"],
});
const result = await loader.getContract("0x7a250d5630b4cf539739df2c5dacb4c659f2488d");
const selectors = Object.values(selectorsFromABI(result.abi));
Expand All @@ -151,17 +141,9 @@ describe('loaders module', () => {
expect(sources && sources[0].content).toContain("pragma solidity");
})

online_test('BlockscoutABILoader_getContract_missing', async () => {
const loader = new BlockscoutABILoader({
apiKey: process.env["BLOCKSCOUT_API_KEY"],
});
const r = await loader.getContract("0x0000000000000000000000000000000000000000");
expect(r.ok).toBeFalsy();
})

online_test('BlockscoutABILoader_getContract_UniswapV3Factory', async () => {
online_test('BlockscoutABILoader_getContract_UniswapV3Factory', async ({ env }) => {
const loader = new BlockscoutABILoader({
apiKey: process.env["BLOCKSCOUT_API_KEY"],
apiKey: env["BLOCKSCOUT_API_KEY"],
});
const { abi, name } = await loader.getContract("0x1F98431c8aD98523631AE4a59f267346ea31F984");
const selectors = Object.values(selectorsFromABI(abi));
Expand All @@ -170,12 +152,12 @@ describe('loaders module', () => {
expect(name).toEqual("UniswapV3Factory");
})

online_test('MultiABILoader_getContract', async () => {
online_test('MultiABILoader_getContract', async ({ env }) => {
// A contract that is verified on etherscan but not sourcify
const address = "0xa9a57f7d2A54C1E172a7dC546fEE6e03afdD28E2";
const loader = new MultiABILoader([
new SourcifyABILoader(),
new EtherscanABILoader({ apiKey: process.env["ETHERSCAN_API_KEY"] }),
new EtherscanABILoader({ apiKey: env["ETHERSCAN_API_KEY"] }),
]);
const result = await loader.getContract(address);
const sig = "getMagistrate()";
Expand All @@ -185,11 +167,11 @@ describe('loaders module', () => {
expect(result.loader?.name).toStrictEqual(EtherscanABILoader.name);
}, SLOW_ETHERSCAN_TIMEOUT);

online_test('MultiABILoader_getContract_UniswapV3Factory', async () => {
online_test('MultiABILoader_getContract_UniswapV3Factory', async ({ env }) => {
const address = "0x1F98431c8aD98523631AE4a59f267346ea31F984";
const loader = new MultiABILoader([
new SourcifyABILoader(),
new EtherscanABILoader({ apiKey: process.env["ETHERSCAN_API_KEY"] }),
new EtherscanABILoader({ apiKey: env["ETHERSCAN_API_KEY"] }),
]);
const { abi, name } = await loader.getContract(address);
const sig = "owner()";
Expand All @@ -213,10 +195,10 @@ describe('loaders module', () => {
expect(result.loaderResult?.output?.devdoc).toBeDefined();
}, SLOW_ETHERSCAN_TIMEOUT);

online_test('MultiABILoader_EtherscanOnly_getContract_UniswapV3Factory', async () => {
online_test('MultiABILoader_EtherscanOnly_getContract_UniswapV3Factory', async ({ env }) => {
const address = "0x1F98431c8aD98523631AE4a59f267346ea31F984";
const loader = new MultiABILoader([
new EtherscanABILoader({ apiKey: process.env["ETHERSCAN_API_KEY"] }),
new EtherscanABILoader({ apiKey: env["ETHERSCAN_API_KEY"] }),
]);
const res = await loader.getContract(address);
const sig = "owner()";
Expand All @@ -229,6 +211,48 @@ describe('loaders module', () => {
sources?.find(s => s.path?.endsWith("contracts/libraries/UnsafeMath.sol"))?.content
).contains("pragma solidity");
}, SLOW_ETHERSCAN_TIMEOUT);
});

describe_cached("loaders: ABILoader suite", async ({ env }) => {
// Addess we know won't have a verified ABI
const knownUnverified = "0x0000000000000000000000000000000000000001";

function makeTest(loader: ABILoader, knownVerified: string) {
online_test(`${loader.name} unverified getContract`, async () => {
const r = await loader.getContract(knownUnverified);
expect(r.ok).toBeFalsy();
expect(r.abi).toStrictEqual([]);
});

online_test(`${loader.name} unverified loadABI`, async () => {
const r = await loader.loadABI(knownUnverified);
expect(r).toStrictEqual([]);
});

online_test(`${loader.name} verified getContract`, async () => {
const r = await loader.getContract(knownVerified);
expect(r.ok).toBeTruthy();
expect(r.abi).not.toStrictEqual([]);
});
}

const uniswapV2Router = "0x7a250d5630b4cf539739df2c5dacb4c659f2488d";
makeTest(new SourcifyABILoader(), uniswapV2Router);
makeTest(new EtherscanABILoader({ apiKey: env["ETHERSCAN_API_KEY"] }), uniswapV2Router);
makeTest(new BlockscoutABILoader({ apiKey: env["BLOCKSCOUT_API_KEY"] }), uniswapV2Router);
});


describe('loaders: SignatureLookup', () => {
online_test('defaultSignatureLookup', async () => {
const sig = "swapExactETHForTokens(uint256,address[],address,uint256)";
const selector = "0x7ff36ab5"
const selectors = selectorsFromABI([sig]);
expect(Object.keys(selectors)).toContain(selector);

const r = await defaultSignatureLookup.loadFunctions(selector);
expect(r).toContain(sig);
});

online_test('SamczunSignatureLookup', async () => {
const lookup = new SamczunSignatureLookup();
Expand All @@ -250,9 +274,10 @@ describe('loaders module', () => {
const sig = "swapExactETHForTokens(uint256,address[],address,uint256)";
expect(selectors).toContain(sig);
})
})
});


describe('loaders helpers', () => {
describe('loaders: helpers', () => {
test('SourcifyABILoader.stripPathPrefix', () => {
expect(
SourcifyABILoader.stripPathPrefix("/contracts/full_match/1/0x1F98431c8aD98523631AE4a59f267346ea31F984/sources/contracts/interfaces/IERC20Minimal.sol")
Expand Down
2 changes: 1 addition & 1 deletion src/loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ export class BlockscoutABILoader implements ABILoader {
const r = await fetch(url);
const result = (await r.json()) as BlockscoutContractResult;
if (!result.abi) {
throw new Error("ABI is not found");
return [];
}
return result.abi;
} catch (err: any) {
Expand Down

0 comments on commit 742daea

Please sign in to comment.