Skip to content

Instantly share code, notes, and snippets.

@blmalone
Last active May 16, 2024 16:54
Show Gist options
  • Save blmalone/1aedfec0e35af7690115125d251acf7e to your computer and use it in GitHub Desktop.
Save blmalone/1aedfec0e35af7690115125d251acf7e to your computer and use it in GitHub Desktop.
Define all L1 smart contracts version numbers for all optimism release tags (op-contracts/vX.Y.Z).
import * as https from "https";
/**
* A mapping of smart contract names to their corresponding paths in the Optimism repository.
*/
const CONTRACT_PATHS = {
AddressManager: "legacy/AddressManager",
AnchorStateRegistry: "dispute/AnchorStateRegistry",
DelayedWETH: "dispute/weth/DelayedWETH",
DisputeGameFactory: "dispute/DisputeGameFactory",
L1CrossDomainMessenger: "L1/L1CrossDomainMessenger",
L1ERC721Bridge: "L1/L1ERC721Bridge",
L1StandardBridge: "L1/L1StandardBridge",
L2OutputOracle: "L1/L2OutputOracle",
OptimismMintableERC20Factory: "universal/OptimismMintableERC20Factory",
OptimismPortal: "L1/OptimismPortal",
OptimismPortal2: "L1/OptimismPortal2",
SystemConfig: "L1/SystemConfig",
SuperchainConfig: "L1/SuperchainConfig",
ProtocolVersions: "L1/ProtocolVersions",
LivenessGuard: "Safe/LivenessGuard",
LivenessModule: "Safe/LivenessModule",
DeputyGuardianModule: "Safe/DeputyGuardianModule"
};
/**
* Release tags to query for.
*/
const TAGGED_VERSIONS = [
"v1.0.0",
"v1.1.0",
"v1.2.0",
"v1.3.0",
"v1.4.0-rc.2",
"v1.4.0-rc.3",
"v1.4.0-rc.4",
"v1.5.0-rc.1"
];
/**
* Smart contracts that were updated per op-contracts release tag (op-contracts/vX.Y.Z).
*/
const CONTRACT_DELTAS = {
"v1.5.0-rc.1": {
...CONTRACT_PATHS
},
"v1.4.0-rc.4": {
...CONTRACT_PATHS
},
"v1.4.0-rc.3": {
...CONTRACT_PATHS
},
"v1.4.0-rc.2": {
L2OutputOracle: CONTRACT_PATHS.L2OutputOracle,
OptimismPortal: CONTRACT_PATHS.OptimismPortal,
SystemConfig: CONTRACT_PATHS.SystemConfig,
DisputeGameFactory: CONTRACT_PATHS.DisputeGameFactory,
AnchorStateRegistry: CONTRACT_PATHS.AnchorStateRegistry,
DelayedWETH: CONTRACT_PATHS.DelayedWETH,
OptimismPortal2: CONTRACT_PATHS.OptimismPortal2
},
"v1.3.0": {
OptimismPortal: CONTRACT_PATHS.OptimismPortal,
L1CrossDomainMessenger: CONTRACT_PATHS.L1CrossDomainMessenger,
L1StandardBridge: CONTRACT_PATHS.L1StandardBridge,
L1ERC721Bridge: CONTRACT_PATHS.L1ERC721Bridge,
OptimismMintableERC20Factory: CONTRACT_PATHS.OptimismMintableERC20Factory,
L2OutputOracle: CONTRACT_PATHS.L2OutputOracle,
SystemConfig: CONTRACT_PATHS.SystemConfig
},
"v1.2.0": {
...CONTRACT_PATHS
},
"v1.1.0": {
ProtocolVersions: CONTRACT_PATHS.ProtocolVersions
},
"v1.0.0": {
...CONTRACT_PATHS
}
};
interface RequestOptions<T> {
method: "GET" | "POST";
headers?: { [key: string]: string };
data?: T;
}
function constructUrls(taggedVersion: string, contractPath: string): { rawUrl: string, url: string } {
const rawBaseUri = `https://raw.githubusercontent.com/ethereum-optimism/optimism/op-contracts/${taggedVersion}/packages/contracts-bedrock`;
const suffix = taggedVersion === "v1.0.0" ? "contracts" : "src";
const baseUri = `https://github.com/ethereum-optimism/optimism/blob/op-contracts/${taggedVersion}/packages/contracts-bedrock`;
return { rawUrl: `${rawBaseUri}/${suffix}/${contractPath}.sol`, url: `${baseUri}/${suffix}/${contractPath}.sol` };
}
async function makeRequest<T>(url: string, options: RequestOptions<T>): Promise<string> {
const { method, headers, data } = options;
const requestOptions: https.RequestOptions = { method, headers: headers || {} };
return new Promise<string>((resolve, reject) => {
const req = https.request(url, requestOptions, res => {
let responseData = "";
res.on("data", chunk => responseData += chunk);
res.on("end", () => resolve(responseData));
});
req.on("error", error => reject(error.message));
if (method === "POST" && data) {
req.write(JSON.stringify(data));
}
req.end();
});
}
async function fetchContract(url: string): Promise<string | undefined> {
try {
return makeRequest(url, { method: "GET", headers: {}, data: {} });
} catch (error) {
console.error("Error fetching contract:", error);
return undefined;
}
}
function extractVersion(response: string, rawUrl: string, url: string, contractPath: string): { version: string, rawUrl: string, url: string } | undefined {
const lines = response.split("\n");
const versionMatchRegex = /constant version = "(.*?)"/;
const semverMatchRegex = /\*\s*@custom:semver\s+([0-9]+\.[0-9]+\.[0-9]+)/;
for (let i = 0; i < lines.length; i++) {
const versionMatch = lines[i].match(versionMatchRegex);
if (versionMatch) {
return { version: versionMatch[1], rawUrl, url: `${url}#L${i}` };
}
if (contractPath.includes("AddressManager")) {
return { version: "Latest", rawUrl, url };
}
const semverMatch = lines[i].match(semverMatchRegex);
if (semverMatch) {
return { version: semverMatch[1], rawUrl, url: `${url}#L${++i}` };
}
}
return undefined;
}
function removeBeforeSlash(input: string): string {
const index = input.lastIndexOf("/");
return index !== -1 ? input.substring(index + 1) : input;
}
function makeLink(url: string, version: string): string {
return `\u001B]8;;${url}\u0007${version}\u001B]8;;\u0007`; // Using OSC 8 for hyperlinks in compatible terminals
}
async function main() {
const mapping = {};
const tempMappingEntry = {};
const consoleOutputEntry = {};
for (const taggedVersion of TAGGED_VERSIONS) {
console.log(`\n##########\n${taggedVersion}\n##########`);
const contractsToCheck = CONTRACT_DELTAS[taggedVersion];
for (const contractPath of Object.values(contractsToCheck) as string[]) {
const urls = constructUrls(taggedVersion, contractPath);
const data = await fetchContract(urls.rawUrl);
if (data) {
const versionInfo = extractVersion(data, urls.rawUrl, urls.url, contractPath);
if (versionInfo) { // if undefined, means contract live during this release tag.
consoleOutputEntry[removeBeforeSlash(contractPath)] = makeLink(versionInfo.url, versionInfo.version);
tempMappingEntry[removeBeforeSlash(contractPath)] = versionInfo.version;
}
}
}
Object.entries(consoleOutputEntry).forEach(([chainVersion, version]) =>
console.log(`${chainVersion}: ${version}`)
);
mapping[taggedVersion] = JSON.parse(JSON.stringify(tempMappingEntry));
}
// console.log(JSON.stringify(mapping));
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment