mirror of
https://github.com/selfxyz/self.git
synced 2026-02-19 02:24:25 -05:00
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:
@@ -29,7 +29,7 @@ import {console} from "hardhat/console.sol";
|
||||
* @dev This contract orchestrates multi-step verification processes including document attestation,
|
||||
* zero-knowledge proofs, OFAC compliance, and attribute disclosure control.
|
||||
*
|
||||
* @custom:version 2.12.0
|
||||
* @custom:version 2.13.0
|
||||
*/
|
||||
contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
/// @custom:storage-location erc7201:self.storage.IdentityVerificationHub
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "./registry.schema.json",
|
||||
"lastUpdated": "2025-12-10T06:17:50.863Z",
|
||||
"lastUpdated": "2026-02-02T14:47:21.978Z",
|
||||
"contracts": {
|
||||
"IdentityVerificationHub": {
|
||||
"source": "IdentityVerificationHubImplV2",
|
||||
@@ -73,6 +73,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"celo-sepolia": {
|
||||
"chainId": 11142220,
|
||||
"governance": {
|
||||
"securityMultisig": "0x82D8DaC3a386dec55a0a44DffBd3113e8A7D139B",
|
||||
"operationsMultisig": "0x82D8DaC3a386dec55a0a44DffBd3113e8A7D139B",
|
||||
"securityThreshold": "1/1",
|
||||
"operationsThreshold": "1/1"
|
||||
},
|
||||
"deployments": {
|
||||
"IdentityVerificationHub": {
|
||||
"proxy": "0x16ECBA51e18a4a7e61fdC417f0d47AFEeDfbed74",
|
||||
"currentVersion": "2.13.0",
|
||||
"currentImpl": "0x244c93516Abd58E1952452d3D8C4Ce7D454776B8"
|
||||
}
|
||||
}
|
||||
},
|
||||
"localhost": {
|
||||
"chainId": 31337,
|
||||
"governance": {
|
||||
@@ -97,6 +113,12 @@
|
||||
"deployedAt": "2025-12-10T05:43:58.258Z",
|
||||
"deployedBy": "0xCaEe7aAF115F04D836E2D362A7c07F04db436bd0",
|
||||
"gitCommit": ""
|
||||
},
|
||||
"celo-sepolia": {
|
||||
"impl": "0x92d637c5e6EFa17320B663f97cc4d44176984dAd",
|
||||
"deployedAt": "2026-02-02T13:39:44.500Z",
|
||||
"deployedBy": "0x846F1cF04ec494303e4B90440b130bb01913E703",
|
||||
"gitCommit": "61a41950"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -111,6 +133,26 @@
|
||||
"deployedAt": "",
|
||||
"deployedBy": "",
|
||||
"gitCommit": ""
|
||||
},
|
||||
"celo-sepolia": {
|
||||
"impl": "0x48985ec4f71cBC8f387c5C77143110018560c7eD",
|
||||
"deployedAt": "",
|
||||
"deployedBy": "0x846f1cf04ec494303e4b90440b130bb01913e703",
|
||||
"gitCommit": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"2.13.0": {
|
||||
"initializerVersion": 12,
|
||||
"initializerFunction": "",
|
||||
"changelog": "Upgrade to v2.13.0",
|
||||
"gitTag": "identityverificationhub-v2.13.0",
|
||||
"deployments": {
|
||||
"celo-sepolia": {
|
||||
"impl": "0x244c93516Abd58E1952452d3D8C4Ce7D454776B8",
|
||||
"deployedAt": "2026-02-02T14:47:21.882Z",
|
||||
"deployedBy": "0x82D8DaC3a386dec55a0a44DffBd3113e8A7D139B",
|
||||
"gitCommit": "33bca485"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user