2024-01-29 14:03:25 +05:30

158 lines
5.4 KiB
TypeScript

import { BigNumber } from "ethers";
import hre from "hardhat";
import { Provider } from "@ethersproject/providers";
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import { Contract } from "ethers";
async function getRlnV1Registry(provider: Provider) {
const rlnV1Abi = [
"function storages(uint16 index) public view returns (address)",
];
const rlnV1Address = process.env.WAKU_RLNV1_REGISTRY_ADDRESS;
if (!rlnV1Address) {
throw new Error("WAKU_RLNV1_REGISTRY_ADDRESS env variable is not set");
}
const rlnV1Registry = new hre.ethers.Contract(
rlnV1Address,
rlnV1Abi,
provider
);
return rlnV1Registry;
}
async function getRlnV1Storage(rlnV1Registry: Contract) {
const storageIndex = process.env.WAKU_RLNV1_STORAGE_INDEX;
if (!storageIndex) {
throw new Error("WAKU_RLNV1_STORAGE_INDEX env variable is not set");
}
const storageAddress = await rlnV1Registry.storages(storageIndex);
const rlnV1StorageAbi = [
"event MemberRegistered(uint256 idCommitment, uint256 index)",
"function deployedBlockNumber() public view returns (uint32)",
];
const rlnV1Storage = new hre.ethers.Contract(
storageAddress,
rlnV1StorageAbi,
rlnV1Registry.provider
);
return rlnV1Storage;
}
async function getRlnV2Registry(signer: SignerWithAddress) {
const rlnV2Abi = [
"function register(uint256[] calldata commitments, uint256[] calldata limits) public",
"function usingStorageIndex() public view returns (uint16)",
"function storages(uint16 index) public view returns (address)",
];
const rlnV2Address = process.env.WAKU_RLNV2_REGISTRY_ADDRESS;
if (!rlnV2Address) {
throw new Error("WAKU_RLNV2_REGISTRY_ADDRESS env variable is not set");
}
const rlnV2Registry = new hre.ethers.Contract(rlnV2Address, rlnV2Abi, signer);
return rlnV2Registry;
}
async function getRlnV2Storage(rlnV2Registry: Contract) {
const storageIndex = await rlnV2Registry.usingStorageIndex();
const storageAddress = await rlnV2Registry.storages(storageIndex);
const rlnV2StorageAbi = [
"event MemberRegistered(uint256 idCommitment, uint256 index)",
"function deployedBlockNumber() public view returns (uint32)",
];
const rlnV2Storage = new hre.ethers.Contract(
storageAddress,
rlnV2StorageAbi,
rlnV2Registry.provider
);
return rlnV2Storage;
}
async function getRlnV1Commitments(rlnV1Storage: Contract) {
// iteratively loop from deployedBlockNumber to current block
// collect commitments from MemberRegistered events
const deployedBlockNumber = await rlnV1Storage.deployedBlockNumber();
const currentBlockNumber = await rlnV1Storage.provider.getBlockNumber();
if (!currentBlockNumber) {
throw new Error("Could not get current block number");
}
console.log(
`Fetching commitments from block ${deployedBlockNumber} to ${currentBlockNumber}`
);
// chunk in batches of 10_000
const batchSize = 10_000;
// fetch commitments by listening to events on rln-v1
const commitments: BigNumber[] = [];
for (let i = deployedBlockNumber; i < currentBlockNumber; i += batchSize) {
const normalizedBatch = Math.min(currentBlockNumber, i + batchSize);
console.log(`Fetching commitments from block ${i} to ${normalizedBatch}`);
const events = await rlnV1Storage.queryFilter(
"MemberRegistered",
i,
normalizedBatch
);
for (const event of events) {
commitments.push(event.args?.idCommitment);
}
}
return commitments;
}
async function registerRlnV2Commitments(
rlnV2Registry: Contract,
commitments: BigNumber[]
) {
// register commitments on rln-v2, with a default limit of 1, in batches of 20
const limit = 1;
const batch = 10;
const total = commitments.length;
for (let i = 0; i < total; i += batch) {
const normalizedBatch = Math.min(total, i + batch);
const commitmentsBatch = commitments.slice(i, normalizedBatch);
const limits = Array(commitmentsBatch.length).fill(limit);
console.log(
`Registering commitments ${i} to ${normalizedBatch} of ${total}`
);
const tx = await rlnV2Registry.register(commitmentsBatch, limits);
await tx.wait();
}
}
// this script is used to migrate from rln-v1 to rln-v2
// rln-v1 commitments are poseidon([identitySecret]),
// rln-v2 commitments are poseidon([rlnV1Commitment, userMessageLimit])
// we set a default userMessageLimit to 1 for all migrating users,
// to preserve the same message rate as in rln-v1
async function main() {
const [deployer] = await hre.ethers.getSigners();
const rlnV1Registry = await getRlnV1Registry(deployer.provider!);
const rlnV2Registry = await getRlnV2Registry(deployer);
const rlnV1Storage = await getRlnV1Storage(rlnV1Registry);
const rlnV2Storage = await getRlnV2Storage(rlnV2Registry);
console.log(
`Migrating from ${rlnV1Registry.address} registry to ${rlnV2Registry.address} registry`
);
console.log(
`Migrating from ${rlnV1Storage.address} storage to ${rlnV2Storage.address} storage`
);
const commitments = await getRlnV1Commitments(rlnV1Storage);
// register commitments on rln-v2, with a default limit of 1, in batches of 20
await registerRlnV2Commitments(rlnV2Registry, commitments);
console.log(`Migrated ${commitments.length} commitments`);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});