UNPKG

@hyperlane-xyz/sdk

Version:

The official SDK for the Hyperlane Network

131 lines 6.11 kB
import { ProxyAdmin__factory, TransparentUpgradeableProxy__factory, } from '@hyperlane-xyz/core'; import { assert, eqAddress } from '@hyperlane-xyz/utils'; import { tryGetContractDeploymentTransaction } from '../../block-explorer/etherscan.js'; import { ExplorerFamily } from '../../metadata/chainMetadataTypes.js'; import { proxyAdmin, proxyImplementation } from '../proxy.js'; export function formatFunctionArguments(fragment, args) { const params = Object.fromEntries(fragment.inputs.map((input, index) => [input.name, args[index]])); return JSON.stringify(params, null, 2); } export function getConstructorArguments(contract, bytecode) { const tx = contract.deployTransaction; if (tx === undefined) throw new Error('deploy transaction not found'); return tx.data.replace(bytecode, ''); } export function buildVerificationInput(name, address, constructorArguments, isProxy = name.endsWith('Proxy'), expectedimplementation) { return { name: name.charAt(0).toUpperCase() + name.slice(1), address, constructorArguments, isProxy, expectedimplementation, }; } export function getContractVerificationInput({ name, contract, bytecode, isProxy, expectedimplementation, }) { const args = getConstructorArguments(contract, bytecode); return buildVerificationInput(name, contract.address, args, isProxy, expectedimplementation); } /** * Check if the artifact should be added to the verification inputs. * @param verificationInputs - The verification inputs for the chain. * @param chain - The chain to check. * @param artifact - The artifact to check. * @returns */ export function shouldAddVerificationInput(verificationInputs, chain, artifact) { return !verificationInputs[chain].some((existingArtifact) => existingArtifact.name === artifact.name && eqAddress(existingArtifact.address, artifact.address) && existingArtifact.constructorArguments === artifact.constructorArguments && existingArtifact.isProxy === artifact.isProxy); } /** * Retrieves the constructor args using their respective Explorer and/or RPC (eth_getTransactionByHash) */ export async function getConstructorArgumentsApi({ chainName, contractAddress, bytecode, multiProvider, }) { const { family } = multiProvider.getExplorerApi(chainName); let constructorArgs; switch (family) { case ExplorerFamily.Routescan: case ExplorerFamily.Etherscan: constructorArgs = await getEtherscanConstructorArgs({ chainName, contractAddress, bytecode, multiProvider, }); break; case ExplorerFamily.Blockscout: constructorArgs = await getBlockScoutConstructorArgs({ chainName, contractAddress, multiProvider, }); break; default: throw new Error(`Explorer Family ${family} unsupported`); } return constructorArgs; } export async function getEtherscanConstructorArgs({ bytecode, chainName, contractAddress, multiProvider, }) { const { apiUrl: blockExplorerApiUrl, apiKey: blockExplorerApiKey } = multiProvider.getExplorerApi(chainName); const creationTx = await tryGetContractDeploymentTransaction({ apiUrl: blockExplorerApiUrl, apiKey: blockExplorerApiKey }, { contractAddress }); // Fetch deployment bytecode (includes constructor args) assert(creationTx, 'Contract creation transaction not found!'); const metadata = multiProvider.getChainMetadata(chainName); const rpcUrl = metadata.rpcUrls[0].http; const creationTxResp = await fetch(rpcUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ method: 'eth_getTransactionByHash', params: [creationTx.txHash], id: 1, jsonrpc: '2.0', }), }); // Truncate the deployment bytecode const creationInput = (await creationTxResp.json()).result.input; return creationInput.substring(bytecode.length); } export async function getBlockScoutConstructorArgs({ chainName, contractAddress, multiProvider, }) { const { apiUrl: blockExplorerApiUrl } = multiProvider.getExplorerApi(chainName); const url = new URL(`/api/v2/smart-contracts/${contractAddress}`, blockExplorerApiUrl); const smartContractResp = await fetch(url, { headers: { 'Content-Type': 'application/json', }, }); return (await smartContractResp.json()).constructor_args; } export async function getProxyAndAdminInput({ chainName, multiProvider, proxyAddress, }) { const provider = multiProvider.getProvider(chainName); const proxyAdminAddress = await proxyAdmin(provider, proxyAddress); const proxyAdminConstructorArgs = await getConstructorArgumentsApi({ chainName, multiProvider, bytecode: ProxyAdmin__factory.bytecode, contractAddress: proxyAdminAddress, }); const proxyAdminInput = buildVerificationInput('ProxyAdmin', proxyAdminAddress, proxyAdminConstructorArgs); const proxyConstructorArgs = await getConstructorArgumentsApi({ chainName, multiProvider, contractAddress: proxyAddress, bytecode: TransparentUpgradeableProxy__factory.bytecode, }); const transparentUpgradeableProxyInput = buildVerificationInput('TransparentUpgradeableProxy', proxyAddress, proxyConstructorArgs, true, await proxyImplementation(provider, proxyAddress)); return { proxyAdminInput, transparentUpgradeableProxyInput }; } export async function getImplementationInput({ bytecode, chainName, contractName, implementationAddress, multiProvider, }) { const implementationConstructorArgs = await getConstructorArgumentsApi({ bytecode, chainName, multiProvider, contractAddress: implementationAddress, }); return buildVerificationInput(contractName, implementationAddress, implementationConstructorArgs); } //# sourceMappingURL=utils.js.map