mirror of
https://github.com/logos-messaging/waku-rlnv1-contract.git
synced 2026-01-23 08:33:11 +00:00
158 lines
5.4 KiB
TypeScript
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;
|
|
});
|