import fetch from 'node-fetch' interface NetworkData { chainId: number names: string[] etherscanApiUrl: string } const networks: { [id: number]: NetworkData } = { 1: { chainId: 1, names: ['mainnet', 'main', 'eth', 'ethereum'], etherscanApiUrl: 'https://api.etherscan.io', }, 3: { chainId: 3, names: ['ropsten'], etherscanApiUrl: 'https://api-ropsten.etherscan.io', }, 4: { chainId: 4, names: ['rinkeby'], etherscanApiUrl: 'https://api-rinkeby.etherscan.io', }, 5: { chainId: 5, names: ['goerli'], etherscanApiUrl: 'https://api-goerli.etherscan.io', }, 10: { chainId: 10, names: ['optimism'], etherscanApiUrl: 'https://api-optimistic.etherscan.io', }, 42: { chainId: 42, names: ['kovan'], etherscanApiUrl: 'https://api-kovan.etherscan.io', }, 69: { chainId: 69, names: ['opkovan', 'kovan-optimism', 'optimistic-kovan'], etherscanApiUrl: 'https://api-kovan-optimistic.etherscan.io', }, } export class Etherscan { net: NetworkData constructor( private readonly apiKey: string, private readonly network: string | number ) { if (typeof network === 'string') { this.net = Object.values(networks).find((net) => { return net.names.includes(network) }) } else { this.net = networks[this.network] } } public async getContractSource(address: string): Promise { const url = new URL(`${this.net.etherscanApiUrl}/api`) url.searchParams.append('module', 'contract') url.searchParams.append('action', 'getsourcecode') url.searchParams.append('address', address) url.searchParams.append('apikey', this.apiKey) const response = await fetch(url) const result = await response.json() return (result as { result: number[] }).result[0] } public async getContractABI(address: string): Promise { const source = await this.getContractSource(address) if (source.Proxy === '1') { const impl = await this.getContractSource(source.Implementation) return impl.ABI } else { return source.ABI } } }