Skip to content

Commit 68a64aa

Browse files
fetch inherited functions and deployedOnBlock
1 parent 5f20444 commit 68a64aa

File tree

1 file changed

+122
-65
lines changed

1 file changed

+122
-65
lines changed

packages/hardhat/scripts/generateTsAbis.ts

Lines changed: 122 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const generatedContractComment = `
1717
`;
1818

1919
const DEPLOYMENTS_DIR = "./ignition/deployments";
20-
// const ARTIFACTS_DIR = "./artifacts";
20+
const ARTIFACTS_DIR = "./artifacts";
2121

2222
function getDirectories(path: string) {
2323
return fs
@@ -26,83 +26,140 @@ function getDirectories(path: string) {
2626
.map(dirent => dirent.name);
2727
}
2828

29-
function getContractFilenames(path: string) {
30-
return fs
31-
.readdirSync(path, { withFileTypes: true })
32-
.filter(dirent => dirent.isFile() && dirent.name.endsWith(".json"))
33-
.map(dirent => dirent.name.split(".")[0]);
29+
function getActualSourcesForContract(sources: Record<string, any>, contractName: string) {
30+
for (const sourcePath of Object.keys(sources)) {
31+
const sourceName = sourcePath.split("/").pop()?.split(".sol")[0];
32+
if (sourceName === contractName) {
33+
const contractContent = sources[sourcePath].content as string;
34+
const regex = /contract\s+(\w+)\s+is\s+([^{}]+)\{/;
35+
const match = contractContent.match(regex);
36+
37+
if (match) {
38+
const inheritancePart = match[2];
39+
// Split the inherited contracts by commas to get the list of inherited contracts
40+
const inheritedContracts = inheritancePart.split(",").map(contract => `${contract.trim()}.sol`);
41+
42+
return inheritedContracts;
43+
}
44+
return [];
45+
}
46+
}
47+
return [];
48+
}
49+
50+
function getInheritedFunctions(
51+
sources: Record<string, any>,
52+
contractName: string,
53+
compiledContracts: Record<string, any>,
54+
) {
55+
const actualSources = getActualSourcesForContract(sources, contractName);
56+
const inheritedFunctions = {} as Record<string, any>;
57+
58+
for (const sourceContractName of actualSources) {
59+
const sourcePath = Object.keys(sources).find(key => key.includes(`/${sourceContractName}`));
60+
61+
if (sourcePath) {
62+
// Extract the actual contract name without .sol extension
63+
const cleanContractName = sourceContractName.replace(".sol", "");
64+
65+
// Try to find the contract in the compiled output
66+
const compiledContract = compiledContracts[sourcePath]?.[cleanContractName];
67+
68+
if (compiledContract?.abi) {
69+
for (const functionAbi of compiledContract.abi) {
70+
if (functionAbi.type === "function") {
71+
inheritedFunctions[functionAbi.name] = sourcePath;
72+
}
73+
}
74+
}
75+
}
76+
}
77+
78+
return inheritedFunctions;
3479
}
3580

36-
// function getActualSourcesForContract(sources: Record<string, any>, contractName: string) {
37-
// for (const sourcePath of Object.keys(sources)) {
38-
// const sourceName = sourcePath.split("/").pop()?.split(".sol")[0];
39-
// if (sourceName === contractName) {
40-
// const contractContent = sources[sourcePath].content as string;
41-
// const regex = /contract\s+(\w+)\s+is\s+([^{}]+)\{/;
42-
// const match = contractContent.match(regex);
43-
44-
// if (match) {
45-
// const inheritancePart = match[2];
46-
// // Split the inherited contracts by commas to get the list of inherited contracts
47-
// const inheritedContracts = inheritancePart.split(",").map(contract => `${contract.trim()}.sol`);
48-
49-
// return inheritedContracts;
50-
// }
51-
// return [];
52-
// }
53-
// }
54-
// return [];
55-
// }
56-
57-
// function getInheritedFunctions(sources: Record<string, any>, contractName: string) {
58-
// const actualSources = getActualSourcesForContract(sources, contractName);
59-
// const inheritedFunctions = {} as Record<string, any>;
60-
61-
// for (const sourceContractName of actualSources) {
62-
// const sourcePath = Object.keys(sources).find(key => key.includes(`/${sourceContractName}`));
63-
// if (sourcePath) {
64-
// const sourceName = sourcePath?.split("/").pop()?.split(".sol")[0];
65-
// const { abi } = JSON.parse(fs.readFileSync(`${ARTIFACTS_DIR}/${sourcePath}/${sourceName}.json`).toString());
66-
// for (const functionAbi of abi) {
67-
// if (functionAbi.type === "function") {
68-
// inheritedFunctions[functionAbi.name] = sourcePath;
69-
// }
70-
// }
71-
// }
72-
// }
73-
74-
// return inheritedFunctions;
75-
// }
81+
function getDeploymentBlockNumbers(journalPath: string): Record<string, number> {
82+
const blockNumbers: Record<string, number> = {};
83+
84+
if (!fs.existsSync(journalPath)) {
85+
return blockNumbers;
86+
}
87+
88+
const journalContent = fs.readFileSync(journalPath, "utf-8");
89+
const lines = journalContent.split("\n").filter(line => line.trim());
90+
91+
for (const line of lines) {
92+
try {
93+
const entry = JSON.parse(line);
94+
// Look for TRANSACTION_CONFIRM entries which contain deployment receipt info
95+
if (entry.type === "TRANSACTION_CONFIRM" && entry.receipt?.blockNumber && entry.futureId) {
96+
blockNumbers[entry.futureId] = entry.receipt.blockNumber;
97+
}
98+
} catch {
99+
// Skip invalid JSON lines
100+
continue;
101+
}
102+
}
103+
104+
return blockNumbers;
105+
}
76106

77107
function getContractDataFromDeployments() {
78108
if (!fs.existsSync(DEPLOYMENTS_DIR)) {
79109
throw Error("At least one other deployment script should exist to generate an actual contract.");
80110
}
81111
const output = {} as Record<string, any>;
82-
const chainDirectories = getDirectories(DEPLOYMENTS_DIR);
112+
for (const dirName of getDirectories(DEPLOYMENTS_DIR)) {
113+
const chainId = dirName.split("-")[1];
114+
115+
const arfifactsPath = `${DEPLOYMENTS_DIR}/${dirName}/artifacts`;
116+
const journalPath = `${DEPLOYMENTS_DIR}/${dirName}/journal.jsonl`;
117+
118+
// Get block numbers from journal
119+
const blockNumbers = getDeploymentBlockNumbers(journalPath);
83120

84-
for (const chainDirectory of chainDirectories) {
85-
const chainId = chainDirectory.split("-")[1];
121+
const fileNames = new Set<string>();
122+
123+
for (const fileName of fs.readdirSync(arfifactsPath)) {
124+
const actualFile = fileName.split(".")[0];
125+
fileNames.add(actualFile);
126+
}
86127

87128
const contracts = {} as Record<string, any>;
88-
for (const contractFilename of getContractFilenames(`${DEPLOYMENTS_DIR}/${chainDirectory}/artifacts`)) {
89-
const { abi, contractName } = JSON.parse(
90-
fs.readFileSync(`${DEPLOYMENTS_DIR}/${chainDirectory}/artifacts/${contractFilename}.json`).toString(),
91-
);
92-
const deployedAddresses = JSON.parse(
93-
fs.readFileSync(`${DEPLOYMENTS_DIR}/${chainDirectory}/deployed_addresses.json`).toString(),
94-
);
95-
const address = deployedAddresses[contractFilename];
96-
97-
// const inheritedFunctions = metadata ? getInheritedFunctions(JSON.parse(metadata).sources, contractName) : {};
98-
// TODO
99-
const inheritedFunctions = {};
100-
// TODO
101-
const receipt = {
102-
blockNumber: 0,
129+
130+
for (const fileName of fileNames) {
131+
const JsonFilePath = `${arfifactsPath}/${fileName}.json`;
132+
const JsonFileContent = fs.readFileSync(JsonFilePath).toString();
133+
const { abi, contractName, buildInfoId } = JSON.parse(JsonFileContent);
134+
135+
const ignitionBuildInfoPath = `${DEPLOYMENTS_DIR}/${dirName}/build-info/${buildInfoId}.json`;
136+
const ignitionBuildInfo = JSON.parse(fs.readFileSync(ignitionBuildInfoPath).toString());
137+
const { input } = ignitionBuildInfo;
138+
139+
const artifactsBuildInfoPath = `${ARTIFACTS_DIR}/build-info/${buildInfoId}.output.json`;
140+
let compiledContracts = {};
141+
if (fs.existsSync(artifactsBuildInfoPath)) {
142+
const artifactsBuildInfo = JSON.parse(fs.readFileSync(artifactsBuildInfoPath).toString());
143+
compiledContracts = artifactsBuildInfo.output?.contracts || {};
144+
}
145+
146+
const inheritedFunctions = getInheritedFunctions(input.sources, contractName, compiledContracts);
147+
148+
const deployedAddresses = fs.readFileSync(`${DEPLOYMENTS_DIR}/${dirName}/deployed_addresses.json`).toString();
149+
const deployedAddressesJson = JSON.parse(deployedAddresses);
150+
const address = deployedAddressesJson[fileName];
151+
152+
// Get deployment block number from journal (futureId matches fileName)
153+
const deploymentBlock = blockNumbers[fileName];
154+
155+
contracts[contractName] = {
156+
address,
157+
abi,
158+
inheritedFunctions,
159+
...(deploymentBlock !== undefined && { deployedOnBlock: deploymentBlock }),
103160
};
104-
contracts[contractName] = { address, abi, inheritedFunctions, deployedOnBlock: receipt?.blockNumber };
105161
}
162+
106163
output[chainId] = contracts;
107164
}
108165
return output;

0 commit comments

Comments
 (0)