diff --git a/contracts/scripts/deleteDscKeyCommitment.ts b/contracts/scripts/deleteDscKeyCommitment.ts new file mode 100644 index 000000000..fa48ccd67 --- /dev/null +++ b/contracts/scripts/deleteDscKeyCommitment.ts @@ -0,0 +1,124 @@ +/** + * DSC Key Commitment Deletion Script + * + * This script is designed to delete all DSC key commitments from the registry contract. + * + * The process works as follows: + * 1. Reads the serialized DSC tree data from JSON + * 2. Initializes a LeanIMT (Lean Incremental Merkle Tree) instance with the same data + * 3. For each commitment in the tree: + * a. Generates a Merkle proof (sibling nodes) needed for the deletion + * b. Calls the contract's devRemoveDscKeyCommitment method + * c. Updates the local tree to maintain consistency with the contract + * + * The script ensures the local tree stays in sync with the contract by updating + * each leaf to zero after successfully removing it from the contract. + * + * Requirements: + * - A properly configured .env file with RPC_URL and PRIVATE_KEY + * - Access to the serialized DSC tree data in the specified path + * - Owner permissions on the registry contract + */ + +import { LeanIMT } from "@openpassport/zk-kit-lean-imt"; +import * as dotenv from "dotenv"; +import { ethers } from "ethers"; +import * as fs from "fs"; +import * as path from "path"; +import { poseidon2 } from "poseidon-lite"; + +dotenv.config(); + +// Read the serialized DSC tree data +const serializedDscTreePath = path.join(__dirname, "../../registry/outputs/serialized_dsc_tree.json"); +const serialized_dsc_tree_json = fs.readFileSync(serializedDscTreePath, "utf-8"); +const serialized_dsc_tree = JSON.parse(JSON.parse(serialized_dsc_tree_json)); + +// Create DSC key commitment tree from the serialized data +const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); +// Initialize LeanIMT with the hash function +const dscTree = new LeanIMT(hashFunction); + +// Function to initialize the tree with all commitments +function initializeTree() { + console.log("Initializing DSC tree..."); + // The first array in serialized_dsc_tree[0] contains the leaf nodes + for (let i = 0; i < serialized_dsc_tree[0].length; i++) { + dscTree.insert(BigInt(serialized_dsc_tree[0][i])); + } + console.log(`Initialized DSC tree with ${dscTree.size} commitments. Root: ${dscTree.root}`); +} + +async function main() { + try { + // Set up connection to blockchain + const provider = new ethers.JsonRpcProvider(process.env.RPC_URL as string); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY as string, provider); + + // Load the registry contract + const registryAbiFile = fs.readFileSync(path.join(__dirname, "../ignition/deployments/chain-11155111/artifacts/DeployRegistryModule#IdentityRegistryImplV1.json"), "utf-8"); + const registryAbi = JSON.parse(registryAbiFile).abi; + const registryAddress = "0xD961B67B35739cCF16326B087C9aD2c0095cCc4E"; // Update with your contract address + const registry = new ethers.Contract(registryAddress, registryAbi, wallet); + + // Initialize our tree with all the DSC key commitments + initializeTree(); + + // Get all commitments to delete + const commitments = serialized_dsc_tree[0]; + console.log(`Total commitments to delete: ${commitments.length}`); + + // Delete each commitment one by one + for (let i = 0; i < commitments.length; i++) { + try { + const commitment = BigInt(commitments[i]); + console.log(`Processing commitment ${i+1}/${commitments.length}: ${commitment.toString()}`); + + // Find the index of the commitment in the tree + const index = dscTree.indexOf(commitment); + if (index === -1) { + console.warn(`Commitment ${commitment.toString()} not found in the tree, skipping...`); + continue; + } + + // Generate the proof for the current commitment + const { siblings } = dscTree.generateProof(index); + + // Convert siblings to string array for contract call + const siblingNodes = siblings.map(s => s.toString()); + + // Call the contract to remove the commitment + console.log(`Removing commitment from contract...`); + const tx = await registry.devRemoveDscKeyCommitment( + commitment.toString(), + siblingNodes + ); + + console.log(`Transaction sent. Waiting for confirmation...`); + const receipt = await tx.wait(); + console.log(`Transaction confirmed! Hash: ${receipt.hash}`); + + // Update the commitment in our local tree to keep it in sync with the contract + // According to documentation, update takes index and new value + dscTree.update(index, BigInt(0)); // Update to zero, effectively "removing" it + console.log(`Removed commitment ${i+1}. New tree root: ${dscTree.root}`); + + // Small delay to avoid spamming the network + await new Promise(resolve => setTimeout(resolve, 1000)); + } catch (error) { + console.error(`Error processing commitment ${i+1}:`, error); + // Continue with the next commitment + } + } + + console.log("All DSC key commitments have been removed."); + } catch (error) { + console.error("Error in main function:", error); + process.exitCode = 1; + } +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +});