Files
core/generateVerifyBash.js
2023-10-28 02:41:47 +02:00

154 lines
4.7 KiB
JavaScript

const fs = require('fs').promises;
const path = require('path');
const { utils } = require('ethers');
// Capture the command line arguments
const [_, __, DeploymentName, ChainId, ChainName] = process.argv;
if (!DeploymentName || !ChainId || !ChainName) {
console.error('Please provide DeploymentName, ChainId and ChainName as command line arguments.');
process.exit(1);
}
async function findDeploymentDirectory(basePath, prefix, chainId) {
const dirs = await fs.readdir(basePath);
const filtered = dirs.filter((dir) => dir.startsWith(prefix));
if (filtered.length !== 1) {
for (const dir of filtered) {
console.error(dir);
}
throw new Error(`Expected to find one directory, but found ${filtered.length} dirs.`);
}
if (chainId) {
return path.join(basePath, filtered[0], ChainId);
} else {
return path.join(basePath, filtered[0]);
}
}
async function findApiDirectory(basePath, prefix) {
const dirs = await fs.readdir(basePath);
const filteredDirs = dirs.filter((dir) => dir.startsWith(prefix) && !dir.includes('.t.'));
const foundDirs = [];
for (const dir of filteredDirs) {
const contents = await fs.readdir(path.join(basePath, dir));
if (contents.includes(`${prefix}.json`)) {
foundDirs.push(dir);
}
}
if (foundDirs.length !== 1) {
for (const dir of foundDirs) {
console.error(dir);
}
throw new Error(
`Expected to find one directory, but found the above ${foundDirs.length} dirs.`
);
}
return path.join(basePath, foundDirs[0]);
}
function transformArgsForEncoding(args, inputs) {
if (typeof args === 'string' && args.startsWith('(') && args.endsWith(')')) {
// Convert the tuple string into an array
args = args
.slice(1, -1)
.split(',')
.map((item) => item.trim());
}
return args.map((arg, index) => {
if (inputs[index].type === 'tuple') {
// If the type is a tuple, recursively transform its arguments
return transformArgsForEncoding(arg, inputs[index].components);
} else {
return arg;
}
});
}
async function encodeConstructorArgs(contractName, args) {
const contractDirectory = await findApiDirectory('out', contractName);
const filePath = path.join(contractDirectory, `${contractName}.json`);
const fileContents = await fs.readFile(filePath, 'utf-8');
const data = JSON.parse(fileContents);
const abi = data.abi;
// Example usage
const constructorAbi = abi.find((item) => item.type === 'constructor');
// console.log('\n\nABI tuple definition:', constructorAbi.inputs);
if (!constructorAbi) {
throw new Error('Constructor ABI not found for the contract.');
}
// Convert tuple string representation to arrays
const transformedArgs = transformArgsForEncoding(args, constructorAbi.inputs);
const encodedArgs = utils.defaultAbiCoder.encode(constructorAbi.inputs, transformedArgs);
return encodedArgs;
}
async function outputLibrariesMessage(data) {
if (data.libraries && data.libraries.length > 0) {
console.log(
'\n\nPlease make sure you have the following libraries added into your foundry.toml file:\n'
);
console.log('libraries = [');
data.libraries.forEach((lib) => {
console.log(`\t"${lib}",`);
});
console.log(']');
} else {
console.log('No libraries found in the broadcast JSON.');
}
}
async function generateBashScript() {
const deploymentPath = await findDeploymentDirectory('broadcast', DeploymentName, ChainId);
const files = await fs.readdir(deploymentPath);
const targetFile = files.find((file) => file.endsWith('-latest.json'));
if (!targetFile) {
throw new Error('No matching JSON file found.');
}
const fileContents = await fs.readFile(path.join(deploymentPath, targetFile), 'utf-8');
const data = JSON.parse(fileContents);
const transactions = data.transactions.filter(
(transaction) => transaction.transactionType === 'CREATE'
);
const bashCommands = await Promise.all(
transactions.map(async (transaction) => {
let baseCmd = `forge verify-contract ${transaction.contractAddress} ${transaction.contractName} --chain ${ChainName} --watch`;
if (transaction.arguments && transaction.arguments.length > 0) {
// Placeholder for abi encoding
const abiEncodedArgs = await encodeConstructorArgs(
transaction.contractName,
transaction.arguments
);
baseCmd += ` --constructor-args ${abiEncodedArgs}`;
}
return baseCmd;
})
);
await fs.writeFile('verify.sh', bashCommands.join('\n'));
console.log('verify.sh has been generated successfully.');
// Call the function
outputLibrariesMessage(data);
}
generateBashScript().catch((error) => {
console.error('An error occurred:', error);
});