-
Notifications
You must be signed in to change notification settings - Fork 868
/
generateVerifyBash.js
153 lines (126 loc) · 4.68 KB
/
generateVerifyBash.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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);
});