From 66ba9f0af042c991c315f4ab44c8e0c478a1b7ae Mon Sep 17 00:00:00 2001 From: Arseniy Klempner Date: Fri, 24 Oct 2025 15:41:14 -0700 Subject: [PATCH] feat: migrate rln from ethers to viem --- package-lock.json | 33 +- packages/rln/package.json | 1 - packages/rln/setup-contract-abi.sh | 30 -- .../rln/src/contract/price_calculator.spec.ts | 29 ++ .../rln/src/contract/rln_base_contract.ts | 336 ++++++++++++++++++ packages/rln/src/contract/types.ts | 9 + packages/rln/src/index.ts | 8 + 7 files changed, 391 insertions(+), 55 deletions(-) delete mode 100755 packages/rln/setup-contract-abi.sh diff --git a/package-lock.json b/package-lock.json index 632b0873b2..564859de98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17917,6 +17917,12 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-sha3": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz", + "integrity": "sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg==", + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -33259,9 +33265,9 @@ } }, "node_modules/viem": { - "version": "2.39.0", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.39.0.tgz", - "integrity": "sha512-rCN+IfnMESlrg/iPyyVL+M9NS/BHzyyNy72470tFmbTuscY3iPaZGMtJDcHKKV8TC6HV9DjWk0zWX6cpu0juyA==", + "version": "2.38.4", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.38.4.tgz", + "integrity": "sha512-qnyPNg6Lz1EEC86si/1dq7GlOyZVFHSgAW+p8Q31R5idnAYCOdTM2q5KLE4/ykMeMXzY0bnp5MWTtR/wjCtWmQ==", "funding": [ { "type": "github", @@ -34778,12 +34784,6 @@ "@esbuild/win32-x64": "0.21.5" } }, - "packages/browser-tests/node_modules/js-sha3": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz", - "integrity": "sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg==", - "license": "MIT" - }, "packages/browser-tests/node_modules/undici-types": { "version": "6.19.8", "dev": true, @@ -34954,10 +34954,6 @@ } } }, - "packages/enr/node_modules/js-sha3": { - "version": "0.9.3", - "license": "MIT" - }, "packages/headless-tests": { "name": "@waku/headless-tests", "version": "0.1.0", @@ -35026,10 +35022,6 @@ "node": ">=22" } }, - "packages/message-encryption/node_modules/js-sha3": { - "version": "0.9.3", - "license": "MIT" - }, "packages/proto": { "name": "@waku/proto", "version": "0.0.15", @@ -35678,13 +35670,6 @@ "node": ">=0.3.1" } }, - "packages/rln/node_modules/js-sha3": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz", - "integrity": "sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg==", - "dev": true, - "license": "MIT" - }, "packages/rln/node_modules/loupe": { "version": "3.1.3", "license": "MIT" diff --git a/packages/rln/package.json b/packages/rln/package.json index 925cd41c2d..9eb5beaecd 100644 --- a/packages/rln/package.json +++ b/packages/rln/package.json @@ -62,7 +62,6 @@ "@waku/build-utils": "^1.0.0", "@waku/interfaces": "0.0.34", "@waku/message-encryption": "^0.0.37", - "@wagmi/cli": "^2.7.0", "deep-equal-in-any-order": "^2.0.6", "fast-check": "^3.23.2", "rollup-plugin-copy": "^3.5.0" diff --git a/packages/rln/setup-contract-abi.sh b/packages/rln/setup-contract-abi.sh deleted file mode 100755 index 73061023cc..0000000000 --- a/packages/rln/setup-contract-abi.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -SUBMODULE_DIR="$SCRIPT_DIR/waku-rlnv2-contract" - -echo "Setting up waku-rlnv2-contract submodule..." - -# Initialize submodule if needed -if [ ! -d "$SUBMODULE_DIR/.git" ]; then - echo "Initializing submodule..." - cd "$SCRIPT_DIR/../.." - git submodule update --init --recursive packages/rln/waku-rlnv2-contract -fi - -# Install dependencies -echo "Installing submodule dependencies..." -cd "$SUBMODULE_DIR" -npm install - -# Build contracts with Foundry -echo "Building contracts with Foundry..." -forge build - -# Generate ABIs -echo "Generating contract ABIs..." -cd "$SCRIPT_DIR" -npx wagmi generate - -echo "✅ Contract ABI setup complete!" diff --git a/packages/rln/src/contract/price_calculator.spec.ts b/packages/rln/src/contract/price_calculator.spec.ts index e2fa53b1ec..b2af2a3c8f 100644 --- a/packages/rln/src/contract/price_calculator.spec.ts +++ b/packages/rln/src/contract/price_calculator.spec.ts @@ -1,6 +1,7 @@ import { expect, use } from "chai"; import chaiAsPromised from "chai-as-promised"; import sinon from "sinon"; +import { PublicClient } from "viem"; import { RLNBaseContract } from "./rln_base_contract.js"; @@ -8,17 +9,29 @@ use(chaiAsPromised); function createMockRLNBaseContract( mockContract: any, +<<<<<<< HEAD mockRpcClient: any ): RLNBaseContract { const dummy = Object.create(RLNBaseContract.prototype); dummy.contract = mockContract; dummy.rpcClient = mockRpcClient; +======= + mockPublicClient: PublicClient +): RLNBaseContract { + const dummy = Object.create(RLNBaseContract.prototype); + dummy.contract = mockContract; + dummy.publicClient = mockPublicClient; +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) return dummy as RLNBaseContract; } describe("RLNBaseContract.getPriceForRateLimit (unit)", function () { let mockContract: any; +<<<<<<< HEAD let mockRpcClient: any; +======= + let mockPublicClient: any; +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) let priceCalculatorReadStub: sinon.SinonStub; let readContractStub: sinon.SinonStub; @@ -32,7 +45,11 @@ describe("RLNBaseContract.getPriceForRateLimit (unit)", function () { } }; +<<<<<<< HEAD mockRpcClient = { +======= + mockPublicClient = { +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) readContract: readContractStub }; }); @@ -49,7 +66,11 @@ describe("RLNBaseContract.getPriceForRateLimit (unit)", function () { priceCalculatorReadStub.resolves(priceCalculatorAddress); readContractStub.resolves([fakeToken, fakePrice]); +<<<<<<< HEAD const rlnBase = createMockRLNBaseContract(mockContract, mockRpcClient); +======= + const rlnBase = createMockRLNBaseContract(mockContract, mockPublicClient); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) const result = await rlnBase.getPriceForRateLimit(20); expect(result.token).to.equal(fakeToken); @@ -71,7 +92,11 @@ describe("RLNBaseContract.getPriceForRateLimit (unit)", function () { priceCalculatorReadStub.resolves(priceCalculatorAddress); readContractStub.rejects(new Error("fail")); +<<<<<<< HEAD const rlnBase = createMockRLNBaseContract(mockContract, mockRpcClient); +======= + const rlnBase = createMockRLNBaseContract(mockContract, mockPublicClient); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) await expect(rlnBase.getPriceForRateLimit(20)).to.be.rejectedWith("fail"); expect(priceCalculatorReadStub.calledOnce).to.be.true; @@ -84,7 +109,11 @@ describe("RLNBaseContract.getPriceForRateLimit (unit)", function () { priceCalculatorReadStub.resolves(priceCalculatorAddress); readContractStub.resolves([null, null]); +<<<<<<< HEAD const rlnBase = createMockRLNBaseContract(mockContract, mockRpcClient); +======= + const rlnBase = createMockRLNBaseContract(mockContract, mockPublicClient); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) const result = await rlnBase.getPriceForRateLimit(20); expect(result.token).to.be.null; diff --git a/packages/rln/src/contract/rln_base_contract.ts b/packages/rln/src/contract/rln_base_contract.ts index 75c4f7a4ef..c603dae247 100644 --- a/packages/rln/src/contract/rln_base_contract.ts +++ b/packages/rln/src/contract/rln_base_contract.ts @@ -3,10 +3,18 @@ import { type Address, decodeEventLog, getContract, +<<<<<<< HEAD type GetContractReturnType, type Hash, type PublicClient, type WalletClient +======= + GetContractEventsReturnType, + GetContractReturnType, + type Hash, + PublicClient, + WalletClient +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) } from "viem"; import { IdentityCredential } from "../identity.js"; @@ -19,6 +27,11 @@ import { RLN_CONTRACT } from "./constants.js"; import { +<<<<<<< HEAD +======= + FetchMembersOptions, + Member, +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) MembershipInfo, MembershipState, RLNContractOptions @@ -27,20 +40,36 @@ import { iPriceCalculatorAbi, wakuRlnV2Abi } from "./wagmi/generated.js"; const log = new Logger("rln:contract:base"); +type MembershipEvents = GetContractEventsReturnType< + typeof wakuRlnV2Abi, + "MembershipRegistered" | "MembershipErased" | "MembershipExpired" +>; export class RLNBaseContract { public contract: GetContractReturnType< typeof wakuRlnV2Abi, PublicClient | WalletClient >; +<<<<<<< HEAD public rpcClient: RpcClient; +======= + public publicClient: PublicClient; + public walletClient: WalletClient; + private deployBlock: undefined | number; +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) private rateLimit: number; private minRateLimit?: number; private maxRateLimit?: number; +<<<<<<< HEAD +======= + protected _members: Map = new Map(); + +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) /** * Private constructor for RLNBaseContract. Use static create() instead. */ protected constructor(options: RLNContractOptions) { +<<<<<<< HEAD const { address, rpcClient, rateLimit = DEFAULT_RATE_LIMIT } = options; log.info("Initializing RLNBaseContract", { address, rateLimit }); @@ -52,6 +81,34 @@ export class RLNBaseContract { client: this.rpcClient }); this.rateLimit = rateLimit; +======= + const { + address, + publicClient, + walletClient, + rateLimit = DEFAULT_RATE_LIMIT + } = options; + + log.info("Initializing RLNBaseContract", { address, rateLimit }); + + this.publicClient = publicClient; + this.walletClient = walletClient; + this.contract = getContract({ + address, + abi: wakuRlnV2Abi, + client: { wallet: walletClient, public: publicClient } + }); + this.rateLimit = rateLimit; + + // Initialize members and subscriptions + this.fetchMembers() + .then(() => { + this.subscribeToMembers(); + }) + .catch((error) => { + log.error("Failed to initialize members", { error }); + }); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) } /** @@ -62,6 +119,11 @@ export class RLNBaseContract { ): Promise { const instance = new RLNBaseContract(options); +<<<<<<< HEAD +======= + instance.deployBlock = await instance.contract.read.deployedBlockNumber(); + +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) const [min, max] = await Promise.all([ instance.contract.read.minMembershipRateLimit(), instance.contract.read.maxMembershipRateLimit() @@ -149,6 +211,18 @@ export class RLNBaseContract { */ public async getMerkleRoot(): Promise { return this.contract.read.root(); +<<<<<<< HEAD + } + + /** + * Gets the Merkle proof for a member at a given index + * @param index The index of the member in the membership set + * @returns Promise Array of 20 Merkle proof elements + * + */ + public async getMerkleProof(index: number): Promise { + return await this.contract.read.getMerkleProof([index]); +======= } /** @@ -161,6 +235,145 @@ export class RLNBaseContract { return await this.contract.read.getMerkleProof([index]); } + public get members(): Member[] { + const sortedMembers = Array.from(this._members.values()).sort( + (left, right) => Number(left.index) - Number(right.index) + ); + return sortedMembers; + } + + public async fetchMembers(options: FetchMembersOptions = {}): Promise { + const fromBlock = options.fromBlock + ? BigInt(options.fromBlock!) + : BigInt(this.deployBlock!); + const registeredMemberEvents = + await this.contract.getEvents.MembershipRegistered({ + fromBlock, + toBlock: fromBlock + BigInt(options.fetchRange!) + }); + const removedMemberEvents = await this.contract.getEvents.MembershipErased({ + fromBlock, + toBlock: fromBlock + BigInt(options.fetchRange!) + }); + const expiredMemberEvents = await this.contract.getEvents.MembershipExpired( + { + fromBlock, + toBlock: fromBlock + BigInt(options.fetchRange!) + } + ); + + const events = [ + ...registeredMemberEvents, + ...removedMemberEvents, + ...expiredMemberEvents + ]; + this.processEvents(events); + } + + public processEvents(events: MembershipEvents): void { + const toRemoveTable = new Map(); + const toInsertTable = new Map(); + + events.forEach((evt) => { + if (!evt.args) { + return; + } + const blockNumber = Number(evt.blockNumber); + if ( + evt.eventName === "MembershipErased" || + evt.eventName === "MembershipExpired" + ) { + const index = evt.args.index; + + if (!index) { + return; + } + + const toRemoveVal = toRemoveTable.get(blockNumber); + if (toRemoveVal != undefined) { + toRemoveVal.push(index); + toRemoveTable.set(blockNumber, toRemoveVal); + } else { + toRemoveTable.set(blockNumber, [index]); + } + } else if (evt.eventName === "MembershipRegistered") { + let eventsPerBlock = toInsertTable.get(blockNumber); + if (eventsPerBlock == undefined) { + eventsPerBlock = []; + } + + eventsPerBlock.push(evt); + toInsertTable.set(blockNumber, eventsPerBlock); + } + }); + } + + public static splitToChunks( + from: number, + to: number, + step: number + ): Array<[number, number]> { + const chunks: Array<[number, number]> = []; + + let left = from; + while (left < to) { + const right = left + step < to ? left + step : to; + + chunks.push([left, right] as [number, number]); + + left = right; + } + + return chunks; + } + + public static *takeN(array: T[], size: number): Iterable { + let start = 0; + + while (start < array.length) { + const portion = array.slice(start, start + size); + + yield portion; + + start += size; + } + } + + public static async ignoreErrors( + promise: Promise, + defaultValue: T + ): Promise { + try { + return await promise; + } catch (err: unknown) { + if (err instanceof Error) { + log.info(`Ignoring an error during query: ${err.message}`); + } else { + log.info(`Ignoring an unknown error during query`); + } + return defaultValue; + } + } + + public subscribeToMembers(): void { + this.contract.watchEvent.MembershipRegistered({ + onLogs: (logs) => { + this.processEvents(logs); + } + }); + this.contract.watchEvent.MembershipExpired({ + onLogs: (logs) => { + this.processEvents(logs); + } + }); + this.contract.watchEvent.MembershipErased({ + onLogs: (logs) => { + this.processEvents(logs); + } + }); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) + } + public async getMembershipInfo( idCommitmentBigInt: bigint ): Promise { @@ -169,7 +382,11 @@ export class RLNBaseContract { idCommitmentBigInt ]); +<<<<<<< HEAD const currentBlock = await this.rpcClient.getBlockNumber(); +======= + const currentBlock = await this.publicClient.getBlockNumber(); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) const [ depositAmount, @@ -214,15 +431,24 @@ export class RLNBaseContract { } public async extendMembership(idCommitmentBigInt: bigint): Promise { +<<<<<<< HEAD if (!this.rpcClient.account) { +======= + if (!this.walletClient.account) { +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) throw new Error( "Failed to extendMembership: no account set in wallet client" ); } try { await this.contract.simulate.extendMemberships([[idCommitmentBigInt]], { +<<<<<<< HEAD chain: this.rpcClient.chain, account: this.rpcClient.account.address +======= + chain: this.walletClient.chain, + account: this.walletClient.account!.address +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) }); } catch (err) { throw new Error("Simulating extending membership failed: " + err); @@ -230,12 +456,21 @@ export class RLNBaseContract { const hash = await this.contract.write.extendMemberships( [[idCommitmentBigInt]], { +<<<<<<< HEAD account: this.rpcClient.account, chain: this.rpcClient.chain } ); await this.rpcClient.waitForTransactionReceipt({ hash }); +======= + account: this.walletClient.account!, + chain: this.walletClient.chain + } + ); + + await this.publicClient.waitForTransactionReceipt({ hash }); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) return hash; } @@ -249,7 +484,11 @@ export class RLNBaseContract { ) { throw new Error("Membership is not expired or in grace period"); } +<<<<<<< HEAD if (!this.rpcClient.account) { +======= + if (!this.walletClient.account) { +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) throw new Error( "Failed to eraseMembership: no account set in wallet client" ); @@ -259,8 +498,13 @@ export class RLNBaseContract { await this.contract.simulate.eraseMemberships( [[idCommitmentBigInt], eraseFromMembershipSet], { +<<<<<<< HEAD chain: this.rpcClient.chain, account: this.rpcClient.account.address +======= + chain: this.walletClient.chain, + account: this.walletClient.account!.address +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) } ); } catch (err) { @@ -270,11 +514,19 @@ export class RLNBaseContract { const hash = await this.contract.write.eraseMemberships( [[idCommitmentBigInt], eraseFromMembershipSet], { +<<<<<<< HEAD chain: this.rpcClient.chain, account: this.rpcClient.account } ); await this.rpcClient.waitForTransactionReceipt({ hash }); +======= + chain: this.walletClient.chain, + account: this.walletClient.account! + } + ); + await this.publicClient.waitForTransactionReceipt({ hash }); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) return hash; } @@ -290,7 +542,11 @@ export class RLNBaseContract { `Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}` ); } +<<<<<<< HEAD if (!this.rpcClient.account) { +======= + if (!this.walletClient.account) { +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) throw new Error( "Failed to registerMembership: no account set in wallet client" ); @@ -299,8 +555,13 @@ export class RLNBaseContract { await this.contract.simulate.register( [idCommitmentBigInt, rateLimit, []], { +<<<<<<< HEAD chain: this.rpcClient.chain, account: this.rpcClient.account.address +======= + chain: this.walletClient.chain, + account: this.walletClient.account!.address +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) } ); } catch (err) { @@ -310,15 +571,24 @@ export class RLNBaseContract { const hash = await this.contract.write.register( [idCommitmentBigInt, rateLimit, []], { +<<<<<<< HEAD chain: this.rpcClient.chain, account: this.rpcClient.account } ); await this.rpcClient.waitForTransactionReceipt({ hash }); +======= + chain: this.walletClient.chain, + account: this.walletClient.account! + } + ); + await this.publicClient.waitForTransactionReceipt({ hash }); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) return hash; } /** +<<<<<<< HEAD * Withdraw deposited tokens after membership is erased. * The smart contract validates that the sender is the holder of the membership, * and will only send tokens to that address. @@ -326,24 +596,45 @@ export class RLNBaseContract { */ public async withdraw(token: string): Promise { if (!this.rpcClient.account) { +======= + * Withdraw deposited tokens after membership is erased + * @param token - Token address to withdraw + * NOTE: Funds are sent to msg.sender (the walletClient's address) + */ + public async withdraw(token: string): Promise { + if (!this.walletClient.account) { +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) throw new Error("Failed to withdraw: no account set in wallet client"); } try { await this.contract.simulate.withdraw([token as Address], { +<<<<<<< HEAD chain: this.rpcClient.chain, account: this.rpcClient.account.address +======= + chain: this.walletClient.chain, + account: this.walletClient.account!.address +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) }); } catch (err) { throw new Error("Error simulating withdraw: " + err); } const hash = await this.contract.write.withdraw([token as Address], { +<<<<<<< HEAD chain: this.rpcClient.chain, account: this.rpcClient.account }); await this.rpcClient.waitForTransactionReceipt({ hash }); +======= + chain: this.walletClient.chain, + account: this.walletClient.account! + }); + + await this.publicClient.waitForTransactionReceipt({ hash }); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) return hash; } public async registerWithIdentity( @@ -381,14 +672,20 @@ export class RLNBaseContract { await this.contract.simulate.register( [identity.IDCommitmentBigInt, this.rateLimit, []], { +<<<<<<< HEAD chain: this.rpcClient.chain, account: this.rpcClient.account.address +======= + chain: this.walletClient.chain, + account: this.walletClient.account!.address +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) } ); const hash: Hash = await this.contract.write.register( [identity.IDCommitmentBigInt, this.rateLimit, []], { +<<<<<<< HEAD chain: this.rpcClient.chain, account: this.rpcClient.account } @@ -397,6 +694,17 @@ export class RLNBaseContract { const txRegisterReceipt = await this.rpcClient.waitForTransactionReceipt({ hash }); +======= + chain: this.walletClient.chain, + account: this.walletClient.account! + } + ); + + const txRegisterReceipt = + await this.publicClient.waitForTransactionReceipt({ + hash + }); +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) if (txRegisterReceipt.status === "reverted") { throw new Error("Transaction failed on-chain"); @@ -427,6 +735,7 @@ export class RLNBaseContract { const decoded = decodeEventLog({ abi: wakuRlnV2Abi, data: memberRegisteredLog.data, +<<<<<<< HEAD topics: memberRegisteredLog.topics, eventName: "MembershipRegistered" }); @@ -434,15 +743,35 @@ export class RLNBaseContract { log.info( `Successfully registered membership with index ${decoded.args.index} ` + `and rate limit ${decoded.args.membershipRateLimit}` +======= + topics: memberRegisteredLog.topics + }); + + const decodedArgs = decoded.args as { + idCommitment: bigint; + membershipRateLimit: number; + index: number; + }; + + log.info( + `Successfully registered membership with index ${decodedArgs.index} ` + + `and rate limit ${decodedArgs.membershipRateLimit}` +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) ); return { identity, membership: { address: this.contract.address, +<<<<<<< HEAD treeIndex: decoded.args.index, chainId: String(RLN_CONTRACT.chainId), rateLimit: Number(decoded.args.membershipRateLimit) +======= + treeIndex: decodedArgs.index, + chainId: String(RLN_CONTRACT.chainId), + rateLimit: decodedArgs.membershipRateLimit +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) } }; } catch (error) { @@ -491,7 +820,10 @@ export class RLNBaseContract { } private async getMemberIndex(idCommitmentBigInt: bigint): Promise { +<<<<<<< HEAD // Current version of the contract has the index at position 5 in the membership struct +======= +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) return (await this.contract.read.memberships([idCommitmentBigInt]))[5]; } @@ -546,7 +878,11 @@ export class RLNBaseContract { price: bigint | null; }> { const address = await this.contract.read.priceCalculator(); +<<<<<<< HEAD const [token, price] = await this.rpcClient.readContract({ +======= + const [token, price] = await this.publicClient.readContract({ +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) address, abi: iPriceCalculatorAbi, functionName: "calculate", diff --git a/packages/rln/src/contract/types.ts b/packages/rln/src/contract/types.ts index 479ed412bb..0436c95cbc 100644 --- a/packages/rln/src/contract/types.ts +++ b/packages/rln/src/contract/types.ts @@ -1,6 +1,10 @@ +<<<<<<< HEAD import { Address } from "viem"; import { RpcClient } from "../utils/index.js"; +======= +import { Address, PublicClient, WalletClient } from "viem"; +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) export type Member = { idCommitment: string; @@ -8,7 +12,12 @@ export type Member = { }; export interface RLNContractOptions { +<<<<<<< HEAD rpcClient: RpcClient; +======= + publicClient: PublicClient; + walletClient: WalletClient; +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) address: Address; rateLimit?: number; } diff --git a/packages/rln/src/index.ts b/packages/rln/src/index.ts index b2bd28e3e3..cd4daf3ed3 100644 --- a/packages/rln/src/index.ts +++ b/packages/rln/src/index.ts @@ -4,7 +4,11 @@ import { createRLN } from "./create.js"; import { IdentityCredential } from "./identity.js"; import { Keystore } from "./keystore/index.js"; import { RLNInstance } from "./rln.js"; +<<<<<<< HEAD import { createViemClientFromWindow } from "./utils/index.js"; +======= +import { createViemClientsFromWindow } from "./utils/index.js"; +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) export { RLNBaseContract, @@ -13,7 +17,11 @@ export { RLNInstance, IdentityCredential, RLN_CONTRACT, +<<<<<<< HEAD createViemClientFromWindow +======= + createViemClientsFromWindow as extractMetaMaskSigner +>>>>>>> a88dd8cdbd (feat: migrate rln from ethers to viem) }; export {