Guess an ABI from an Ethereum contract address, even if it's unverified.
WhatsABI does bounded-complexity static analysis to disassemble EVM bytecode and map out the possible call flows, which allows us to discover function selectors and other metadata about the contract.
WhatsABI is perfect for building procedural frontends, embedding in wallets, block explorers, or doing bytecode analysis.
WhatsABI is different from other EVM analysis tools in some important ways:
O(instructions)
with a small constant factor, so that complex contracts don't cause it to time out or use unbounded memory.What can WhatsABI do?
Quick start:
import { ethers } from "ethers";
import { whatsabi } from "@shazow/whatsabi";
const provider = ethers.getDefaultProvider(); // substitute with your fav provider
const address = "0x00000000006c3852cbEf3e08E8dF289169EdE581"; // Or your fav contract address
// Quick-start:
const result = await whatsabi.autoload(address, { provider });
console.log(result.abi);
// -> [ ... ]
Breaking it down:
const code = await provider.getCode(address); // Load the bytecode
// Get just the callable selectors
const selectors = whatsabi.selectorsFromBytecode(code);
console.log(selectors); // -> ["0x06fdde03", "0x46423aa7", "0x55944a42", ...]
// Get an ABI-like list of interfaces
const abi = whatsabi.abiFromBytecode(code);
console.log(abi);
// -> [
// {"type": "event", "hash": "0x721c20121297512b72821b97f5326877ea8ecf4bb9948fea5bfcb6453074d37f"},
// {"type": "function", "payable": true, "selector": "0x06fdde03", ...},
// {"type": "function", "payable": true, "selector": "0x46423aa7", ...},
// ...
// We also have a suite of database loaders for convenience
const signatureLookup = new whatsabi.loaders.OpenChainSignatureLookup();
console.log(await signatureLookup.loadFunctions("0x06fdde03"));
// -> ["name()"]);
console.log(await signatureLookup.loadFunctions("0x46423aa7"));
// -> ["getOrderStatus(bytes32)"]);
// We also have event loaders!
console.log(await signatureLookup.loadEvents("0x721c20121297512b72821b97f5326877ea8ecf4bb9948fea5bfcb6453074d37f"));
// -> ["CounterIncremented(uint256,address)"]
// There are more fancy loaders in whatsabi.loaders.*, take a look!
// Here's a multiloader with an Etherscan API key, it can be used with autoload below.
// Each source will be attempted until a result is found.
const loader = new whatsabi.loaders.MultiABILoader([
new whatsabi.loaders.SourcifyABILoader(),
new whatsabi.loaders.EtherscanABILoader({
apiKey: "...", // Replace the value with your Etherscan API key
}),
]);
const { abi, name, /* ... other metadata */ } = await loader.getContract(address));
All together with our do-all-the-things helper:
...
let result = await whatsabi.autoload(address, {
provider: provider,
// * Optional loaders:
// abiLoader: whatsabi.loaders.defaultABILoader,
// signatureLoader: whatsabi.loaders.defaultSignatureLookup,
// There is a handy helper for adding the default loaders but with your own settings
... whatsabi.loaders.defaultsWithEnv({
SOURCIFY_CHAIN_ID: 42161,
ETHERSCAN_BASE_URL: "https://api.arbiscan.io/api",
ETHERSCAN_API_KEY: "MYSECRETAPIKEY",
}),
// * Optional hooks:
// onProgress: (phase: string) => { ... }
// onError: (phase: string, context: any) => { ... }
onProgress: (phase) => console.log("autoload progress", phase),
onError: (phase, context) => console.log("autoload error", phase, context),
// * Optional settings:
// followProxies: false,
// enableExperimentalMetadata: false,
});
console.log(result.abi);
// Detail will vary depending on whether `address` source code was available,
// or if bytecode-loaded selector signatures were available, or
// if WhatsABI had to guess everything from just bytecode.
// We can even detect and resolve proxies!
if (result.followProxies) {
console.log("Proxies detected:", result.proxies);
result = await result.followProxies();
console.log(result.abi);
}
Or we can auto-follow resolved proxies, and expand parts of the result object:
const { abi, address } = await whatsabi.autoload(
"0x4f8AD938eBA0CD19155a835f617317a6E788c868",
{
provider,
followProxies: true,
},
});
console.log("Resolved to:", address);
// -> "0x964f84048f0d9bb24b82413413299c0a1d61ea9f"
Omg WhatsABI by