Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API-level proxy detection and implementation resolution #1711

Merged
merged 11 commits into from
Nov 27, 2024

Conversation

manuelwedler
Copy link
Contributor

@manuelwedler manuelwedler commented Oct 22, 2024

Closes #1655

This implements an API-level proxy detection as in #1655 by making use of the whatsabi library. A few explanations about this PR:

  • I had to add two methods to the SourcifyChain class for making it compatible to the whatsabi library as a provider, and for being able to resolve the implementation addresses of DiamondProxy contracts.
  • I added a proxyResolutionError to the API response for the case that the proxy resolution fails. This could be due to an unresponsive RPC for example. In such a case, I still want to respond successfully to the user but let them know why the proxy fields are not there.
  • Related to proxies: Multiple instances of the same resolver shazow/whatsabi#142:
    • A FixedProxyResolver was returned in a lot of cases where actually a library was called by a DELEGATECALL. I decided to only support EIP1167 proxies for this resolver. Any other FixedProxy would be a non-standardised proxy (or even a library). So in case a FixedProxyResolver is detected, we check explicitly for the opcodes standardised in EIP1167.
    • I saw a few cases where multiple resolvers were returned, and also some cases where a resolver resolves to 0x0. The latter was for example the case for a factory contract which deploys EIP1967 contracts. Therefore, I iterate over the returned resolvers and return the first implementation address which is not 0x0.
  • This feature is only added to the /check-all-by-addresses endpoint and not the check-by-addresses endpoint, because in the latter the chainIds array does not contain objects.

Remaining issue (non-blocking)

There is still a problem left from shazow/whatsabi#142:
A contract that embeds a proxy (as for example a factory contract) could falsely be detected as a proxy.

A first proposal to solve this is to not consider contracts with CREATE/CREATE2 opcodes as proxies. However, this will not catch all contracts that only embed proxy bytecodes, and also exclude factory contracts that could be at the same time a proxy.

Edit: We decided that this problem is not a blocker for this PR. IMO, it is good to get this out and test it. The proxy data won't be persisted in our database with this change, so before we persist it we might be able to improve the proxy detection.

@manuelwedler manuelwedler changed the title API-level proxy detection and implementation resolution Add API-level proxy detection and implementation resolution Oct 22, 2024
@manuelwedler manuelwedler marked this pull request as ready for review October 24, 2024 12:01
@kuzdogan kuzdogan self-assigned this Oct 28, 2024
@kuzdogan
Copy link
Member

Can you rebase this @manuelwedler I am seeing changes from #1689

Copy link
Member

@kuzdogan kuzdogan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll further review after rebase

chainId,
status: found[0].runtimeMatch,
...proxyStatus,
});
}
} catch (error) {
// ignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not introduced by this PR but not a good idea to ignore silently. We should log here

@manuelwedler
Copy link
Contributor Author

Done. I think this was due to rewriting history. IMO, we should never do this again.

@kuzdogan
Copy link
Member

Done. I think this was due to rewriting history. IMO, we should never do this again.

Right, but not never, IMO it was necessary in this case, unfortunately.

Copy link
Member

@kuzdogan kuzdogan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments and asking for explanations on the proxy resolution. In general looks good, and not a too big PR 👍

@manuelwedler
Copy link
Contributor Author

Added more comments. Hope they are comprehensive enough

@manuelwedler manuelwedler force-pushed the proxy-resolution branch 2 times, most recently from 6f40b57 to 234ecc5 Compare November 25, 2024 06:34
@manuelwedler
Copy link
Contributor Author

I also updated whatsabi to the latest version, and added a check for factory contracts which is enabled by the latest version.

Copy link
Member

@kuzdogan kuzdogan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it! The comments in the proxy-utils.ts make it a lot clearer now.

Just, proxy resolution is added to checkAllByChainAndAddress but not checkByChainAndAddress. I'm ok with not adding it to the latter endpoint but just wanted to bring it up.

Comment on lines +59 to +69
const fixedProxy = proxyResolvers.find(
(proxy) => proxy instanceof whatsabi.proxies.FixedProxyResolver,
);
// Only return EIP1167Proxies because whatsabi can falsely detect non-proxy contracts as FixedProxies (e.g. libraries)
if (fixedProxy && isEIP1167Proxy(bytecode, fixedProxy.resolvedAddress)) {
return {
isProxy: true,
proxyType: "EIP1167Proxy",
implementations: [fixedProxy.resolvedAddress],
};
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between a FixedProxy and EIP1167Proxy?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whatsabi returns a FixedProxy for anything called with a DELEGATECALL. I think the idea is to also catch non-standardized "minimal" proxies, but the problem with this approach is that it can also include libraries as seen in this issue: shazow/whatsabi#142

Therefore, I decided to only support the standard EIP 1167.

@manuelwedler
Copy link
Contributor Author

Just, proxy resolution is added to checkAllByChainAndAddress but not checkByChainAndAddress. I'm ok with not adding it to the latter endpoint but just wanted to bring it up.

Unfortunately, the responds of the checkByChainAndAddress endpoint is structered differently and does not allow to add the proxy detection in a backwards-compatible way. I mentioned this in the PR description.

@manuelwedler manuelwedler merged commit ba3a8c8 into staging Nov 27, 2024
4 of 6 checks passed
@manuelwedler manuelwedler deleted the proxy-resolution branch November 27, 2024 08:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: COMPLETED
Development

Successfully merging this pull request may close these issues.

API-level proxy detection and implementation resolution
2 participants