import { AddressAnalyzer, EthereumAddress } from '@l2beat/common' import { providers, utils } from 'ethers' const IMPLEMENTATION_SLOT = slot('eip1967.proxy.implementation') const ADMIN_SLOT = slot('eip1967.proxy.admin') export async function analyzeEip1967Proxy( provider: providers.Provider, addressAnalyzer: AddressAnalyzer, proxyAddress: string ) { const [implementationSlot, adminSlot] = await Promise.all([ provider.getStorageAt(proxyAddress, IMPLEMENTATION_SLOT), provider.getStorageAt(proxyAddress, ADMIN_SLOT), ]) if (implementationSlot === '0x' + '0'.repeat(64)) { return undefined } const implementation = wordToAddress(implementationSlot) const admin = wordToAddress(adminSlot) const { name } = await addressAnalyzer.analyze( EthereumAddress(implementation) ) return { name, eip1967Implementation: implementation, eip1967Admin: admin, } } function wordToAddress(word: string) { return utils.getAddress('0x' + word.substr(26, 40)) } function slot(name: string) { const hash = utils.solidityKeccak256(['string'], [name]) return '0x' + (BigInt(hash) - 1n).toString(16).padStart(64, '0') }