Upgrade/update celo sepolia hub kyc (#1725)

* fix: update celo-sepolia in upgrade script to correct chain ID

* feat: add celo-sepolia deployed contracts to registry.json

* fix: upgrade script now reads version from contract directly

* fix: add library linking for kyc related contracts in upgrade script

* feat: IdentityVerificationHub v2.13.0 deployed on Celo Sepolia

- Implementation: 0x244c93516Abd58E1952452d3D8C4Ce7D454776B8
- Code-only upgrade (no new initializer), adds KYC support
- Tx: 0xf24d1c2cd4fd0055237f406a9850ce6e24f538ed09e57ff09755ed142fcc903c

* chore: yarn prettier

* Feat/new gcp verifier (#1719)

* feat: new gcp jwt verifier

* lint: contracts

---------

Co-authored-by: Nesopie <87437291+Nesopie@users.noreply.github.com>
This commit is contained in:
Evi Nova
2026-02-10 18:44:50 +10:00
committed by GitHub
parent 2a583f72c7
commit fa253fcf2d
3 changed files with 114 additions and 42 deletions

View File

@@ -37,7 +37,7 @@ import {
getLatestVersionInfo,
getVersionInfo,
getGovernanceConfig,
validateReinitializerVersion,
readReinitializerVersion,
} from "./utils";
import { execSync } from "child_process";
import * as readline from "readline";
@@ -65,7 +65,7 @@ async function promptYesNo(question: string): Promise<boolean> {
*/
const CHAIN_CONFIG: Record<SupportedNetwork, { chainId: number; safePrefix: string }> = {
celo: { chainId: 42220, safePrefix: "celo" },
"celo-sepolia": { chainId: 44787, safePrefix: "celo" },
"celo-sepolia": { chainId: 11142220, safePrefix: "celo" },
sepolia: { chainId: 11155111, safePrefix: "sep" },
localhost: { chainId: 31337, safePrefix: "eth" },
};
@@ -314,39 +314,54 @@ task("upgrade", "Deploy new implementation and create Safe proposal for upgrade"
// ========================================================================
log.step("Checking reinitializer version...");
// Check if target version already exists in registry
const targetVersionInfo = getVersionInfo(contractId, newVersion);
const latestVersionInfo = getLatestVersionInfo(contractId);
const latestInitVersion = latestVersionInfo?.info.initializerVersion || 0;
// If target version exists, use its initializerVersion; otherwise increment latest
const expectedInitializerVersion = targetVersionInfo
? targetVersionInfo.initializerVersion
: (latestVersionInfo?.info.initializerVersion || 0) + 1;
let actualReinitVersion: number | null = null;
let noNewInitializer = false;
if (contractFilePath) {
const reinitValidation = validateReinitializerVersion(contractFilePath, expectedInitializerVersion);
actualReinitVersion = readReinitializerVersion(contractFilePath);
if (!reinitValidation.valid) {
log.error(reinitValidation.error!);
if (actualReinitVersion === null) {
log.error("Could not find reinitializer in contract file");
return;
}
// If target version already exists in registry, validate against its expected version
if (targetVersionInfo) {
const expected = targetVersionInfo.initializerVersion;
if (actualReinitVersion !== expected) {
log.error(`Reinitializer mismatch: expected ${expected}, found ${actualReinitVersion}`);
return;
}
}
if (actualReinitVersion === latestInitVersion) {
// No new reinitializer — code-only upgrade
noNewInitializer = true;
log.success(`No new initialization needed (reinitializer stays at ${actualReinitVersion})`);
} else if (actualReinitVersion === latestInitVersion + 1) {
// Standard upgrade with new reinitializer
log.success(`Reinitializer version correct: reinitializer(${actualReinitVersion})`);
} else {
log.error(
`Unexpected reinitializer(${actualReinitVersion}). Expected ${latestInitVersion} (no-init) or ${latestInitVersion + 1} (with init)`,
);
log.box([
"REINITIALIZER VERSION MISMATCH",
"═".repeat(50),
"",
`Expected: reinitializer(${expectedInitializerVersion})`,
reinitValidation.actual !== null ? `Found: reinitializer(${reinitValidation.actual})` : "Found: none",
`Latest registry version has reinitializer: ${latestInitVersion}`,
`Contract file has reinitializer: ${actualReinitVersion}`,
"",
"The initialize function must use the correct reinitializer version.",
"Each upgrade should increment the version by 1.",
"",
"Example pattern:",
` function initialize(...) external reinitializer(${expectedInitializerVersion}) {`,
" // initialization logic",
" }",
"Valid options:",
` ${latestInitVersion} — code-only upgrade (no new initialization)`,
` ${latestInitVersion + 1} — upgrade with new initializer`,
]);
return;
}
log.success(`Reinitializer version correct: reinitializer(${reinitValidation.actual})`);
} else {
log.warning("Could not locate contract file - skipping reinitializer check");
}
@@ -389,14 +404,25 @@ task("upgrade", "Deploy new implementation and create Safe proposal for upgrade"
try {
if (contractName === "IdentityVerificationHubImplV2") {
const CustomVerifier = await hre.ethers.getContractFactory("CustomVerifier");
const customVerifier = await CustomVerifier.deploy();
await customVerifier.waitForDeployment();
const libraryNames = [
"CustomVerifier",
"OutputFormatterLib",
"ProofVerifierLib",
"RegisterProofVerifierLib",
"DscProofVerifierLib",
"RootCheckLib",
"OfacCheckLib",
];
const libraries: Record<string, string> = {};
for (const libName of libraryNames) {
const LibFactory = await hre.ethers.getContractFactory(libName);
const lib = await LibFactory.deploy();
await lib.waitForDeployment();
libraries[libName] = await lib.getAddress();
log.info(`Deployed library: ${libName}${libraries[libName]}`);
}
ContractFactory = await hre.ethers.getContractFactory(contractName, {
libraries: { CustomVerifier: await customVerifier.getAddress() },
});
log.info("Deployed CustomVerifier library for linking");
ContractFactory = await hre.ethers.getContractFactory(contractName, { libraries });
} else if (
contractName === "IdentityRegistryImplV1" ||
contractName === "IdentityRegistryIdCardImplV1" ||
@@ -593,7 +619,7 @@ task("upgrade", "Deploy new implementation and create Safe proposal for upgrade"
log.step("Updating deployment registry...");
const latestVersion = getLatestVersionInfo(contractId);
const newInitializerVersion = (latestVersion?.info.initializerVersion || 0) + 1;
const newInitializerVersion = actualReinitVersion ?? (latestVersion?.info.initializerVersion || 0) + 1;
const deployerAddress = (await hre.ethers.provider.getSigner()).address;
addVersion(
@@ -602,7 +628,7 @@ task("upgrade", "Deploy new implementation and create Safe proposal for upgrade"
newVersion,
{
initializerVersion: newInitializerVersion,
initializerFunction: "initialize", // Always "initialize" - version tracked via reinitializer(N) modifier
initializerFunction: noNewInitializer ? "" : "initialize",
changelog: changelog || `Upgrade to v${newVersion}`,
gitTag: `${contractId.toLowerCase()}-v${newVersion}`,
},
@@ -680,18 +706,22 @@ task("upgrade", "Deploy new implementation and create Safe proposal for upgrade"
// Encode initializer function call
let initData = "0x";
const targetVersionInfoForInit = getVersionInfo(contractId, newVersion);
const initializerName = targetVersionInfoForInit?.initializerFunction || `initializeV${newInitializerVersion}`;
if (!noNewInitializer) {
const targetVersionInfoForInit = getVersionInfo(contractId, newVersion);
const initializerName = targetVersionInfoForInit?.initializerFunction || `initializeV${newInitializerVersion}`;
try {
const iface = proxyContract.interface;
const initFragment = iface.getFunction(initializerName);
if (initFragment && initFragment.inputs.length === 0) {
initData = iface.encodeFunctionData(initializerName, []);
log.detail("Initializer", initializerName);
try {
const iface = proxyContract.interface;
const initFragment = iface.getFunction(initializerName);
if (initFragment && initFragment.inputs.length === 0) {
initData = iface.encodeFunctionData(initializerName, []);
log.detail("Initializer", initializerName);
}
} catch {
log.detail("Initializer", "None");
}
} catch {
log.detail("Initializer", "None");
} else {
log.detail("Initializer", "None (code-only upgrade)");
}
// Build upgrade transaction data