Skip to content

Commit

Permalink
chore: add v1 to v2 migrator
Browse files Browse the repository at this point in the history
  • Loading branch information
rymnc committed Jan 29, 2024
1 parent 6c7e59d commit 886891b
Show file tree
Hide file tree
Showing 8 changed files with 336 additions and 82 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ yarn deploy:sepolia
yarn verify:sepolia # Ensure you have set ETHERSCAN_API_KEY in your env
```

## Migrating v1 to v2

Refer to the [script](./scripts/migrate/v1-v2.ts) for more information.

### Locally

- To migrate on a local node, first start the local node and then run the migrate script

```shell
yarn node
yarn migrate:v1-v2:localhost
```

### Sepolia

- To migrate to an target network (like Sepolia), use the name as mentioned in the Hardhat config file.

```shell
yarn migrate:v1-v2:sepolia
```

## References

For more information, see https://hardhat.org/hardhat-runner/docs/guides/project-setup
Expand Down
17 changes: 3 additions & 14 deletions deployments/allDeployments.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"chainId": "11155111",
"contracts": {
"WakuRlnRegistry_Implementation": {
"address": "0x451dE04f6C219EFDE9432a3B34D8eaac54C43589",
"address": "0xC58900Eeb0bE8C7f54DdCD40488B30cDeEBCcbD8",
"abi": [
{
"inputs": [],
Expand All @@ -22,17 +22,6 @@
"name": "NoStorageContractAvailable",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "storageAddress",
"type": "address"
}
],
"name": "StorageAlreadyExists",
"type": "error"
},
{
"anonymous": false,
"inputs": [
Expand Down Expand Up @@ -358,7 +347,7 @@
]
},
"WakuRlnRegistry_Proxy": {
"address": "0xE784b13B443b4a60557C8D5AF5942b16E434047B",
"address": "0xABd93f37833107eDbAb58633ad5463aDEa1F95F4",
"abi": [
{
"inputs": [
Expand Down Expand Up @@ -432,7 +421,7 @@
]
},
"WakuRlnStorage_0": {
"address": "0xd0AB35EdF257B2790274d84D485b4B91D90D6144",
"address": "0xbd250d26E9dc468592f51bc892488450BfCb22b7",
"abi": [
{
"inputs": [
Expand Down
53 changes: 21 additions & 32 deletions deployments/sepolia/WakuRlnRegistry_Implementation.json

Large diffs are not rendered by default.

60 changes: 30 additions & 30 deletions deployments/sepolia/WakuRlnRegistry_Proxy.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions deployments/sepolia/WakuRlnStorage_0.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
"deploy:sepolia": "yarn deploy sepolia",
"deploy:localhost": "yarn deploy localhost",
"verify:sepolia": "hardhat --network sepolia etherscan-verify",
"migrate:v1-v2:sepolia": "hardhat --network sepolia run scripts/migrate/v1-v2.ts",
"migrate:v1-v2:localhost": "hardhat --network localhost run scripts/migrate/v1-v2.ts",
"coverage": "forge coverage --report lcov",
"fmt": "prettier --write \"**/*.{js,ts}\"",
"lint": "prettier --check \"**/*.{js,ts}\"",
Expand Down
157 changes: 157 additions & 0 deletions scripts/migrate/v1-v2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
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;
});

0 comments on commit 886891b

Please sign in to comment.