shazow / whatsabi

Extract the ABI (and other metadata) from Ethereum bytecode, even without source code.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

disasm: Detect proxies

shazow opened this issue · comments

Would be great if we could detect proxies from EVM bytecode, at least common patterns?

Not sure where to start, need to look at good examples.

https://github.com/jtriley-eth/minimum-viable-proxy might be a fun starting point.

@vincelwt that is useful, thank you! I was hoping to be able to detect some proxies statically, but this is a nice fallback.

Some more useful notes: We should keep track of common EIP-1967 slot addresses in case they're hardcoded in the bytecode, better yet we can detect common interface selectors for these.

Bonus if we can provide helpers for querying on-chain slot state for contracts. https://github.com/apoorvlathey/storage-slots is a cool frontend for doing stuff like that.

Also looking back at my prior notes, the gnosis/evm-proxy-detection module has a similar idea but handles more formats.

Hey, I'd love to see this feature! With proxies there's of course two ABIs, the proxy and the implementation. It would be great if they're returned separately so they can be disambiguated by the caller, as it's easy for the caller to merge together if they want them merged.

I noticed a lot of arbitrum/optimism predeploys are behind proxies and I was looking to fetch them, so I'd love to see this supported. Here's a (non comprehensive, but should cover most cases) list I have of proxy patterns:

  1. Check for an implementation()(address) function. (Optimism predeploys use this).
  2. Check for a getProxyImplementation()(address) function. (Arbitrum predeploys use this)
  3. ERC-1967 logic address slot.
  4. ERC-1967 beacon address slot (requires a call to implementation()(address) on the beacon).
  5. Bytes 11 through 30 of the bytecode are where the implementation address for ERC-1167 proxies are stored.

Per ERC-1967, (3) should be prioritized over (4) if both are present. I'll continue updating this list as I come across more proxy patterns

@mds1 Very nice, thank you for the details. The current plan is to just return whether any known proxy slot addresses were present during the bytecode parsing, then have separate helper methods for resolving them (which will require more specific on-chain providers, probably getStorageAt and maybe call, but would really love to avoid doing calls when possible).

Proxies support is in main now! Anyone want to give it a whirl before I cut a release later this week? <3

ooo yes I will definitely try this! can you give me the tldr on the commands I need for "given an address, get the (1) the proxy ABI, (2) the implementation address, and (3) the implementation ABI, all with resolved selectors"? Is it just this below snippet from the readme? I'm not sure if that abi is the proxy, impl, or both

const { abi, address } = await whatsabi.autoload("0x4f8AD938eBA0CD19155a835f617317a6E788c868", {
    provider,

    followProxies: true,
});

console.log("Resolved to:", address);
// -> "0x964f84048f0d9bb24b82413413299c0a1d61ea9f"

(Also I'm guessing that has to be an ethers provider, but I'm going to be using this in a project that uses viem, so would prefer to just pass the code directly instead of install ethers)

Yea, the README snippet should have the "easy mode" details, whatsabi.autoload(...) now returns an AutoloadResult object which has the effective address and abi and any proxies detected, and a followProxies() helper if proxies were detected. If you pass in followProxies: true then it'll automagically follow and just return the final destination.

Any provider with getStorageAt and call should do the trick for proxies. I'm still depending on ethers.js out of convenience for various helpers, but the plan is to remove that dependency before v1.0.

For autoload, it's still assuming ethers, I'll try to fix that now.

Ok that should make viem workable, but I haven't had a chance to test locally yet, please report back. :)