Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update contract #72

Merged
merged 10 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"gen",
"proto",
"*.spec.ts",
"src/resources.ts"
"src/resources.ts",
"src/constants.ts"
],
"patterns": [
{
Expand Down
72 changes: 63 additions & 9 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,68 @@
export const RLN_ABI = [
"function MEMBERSHIP_DEPOSIT() public view returns(uint256)",
"function register(uint256 pubkey) external payable",
"function withdraw(uint256 secret, uint256 _pubkeyIndex, address payable receiver) external",
"event MemberRegistered(uint256 pubkey, uint256 index)",
"event MemberWithdrawn(uint256 pubkey, uint256 index)",
// ref https://github.com/waku-org/waku-rln-contract/blob/19fded82bca07e7b535b429dc507cfb83f10dfcf/deployments/sepolia/WakuRlnRegistry_Implementation.json#L3
export const RLN_REGISTRY_ABI = [
"error IncompatibleStorage()",
"error IncompatibleStorageIndex()",
"error NoStorageContractAvailable()",
"error StorageAlreadyExists(address storageAddress)",
"event AdminChanged(address previousAdmin, address newAdmin)",
"event BeaconUpgraded(address indexed beacon)",
"event Initialized(uint8 version)",
"event NewStorageContract(uint16 index, address storageAddress)",
"event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)",
"event Upgraded(address indexed implementation)",
"function forceProgress()",
"function initialize(address _poseidonHasher)",
"function newStorage()",
"function nextStorageIndex() view returns (uint16)",
"function owner() view returns (address)",
"function poseidonHasher() view returns (address)",
"function proxiableUUID() view returns (bytes32)",
"function register(uint16 storageIndex, uint256 commitment)",
"function register(uint256[] commitments)",
"function register(uint16 storageIndex, uint256[] commitments)",
"function registerStorage(address storageAddress)",
"function renounceOwnership()",
"function storages(uint16) view returns (address)",
"function transferOwnership(address newOwner)",
"function upgradeTo(address newImplementation)",
"function upgradeToAndCall(address newImplementation, bytes data) payable",
"function usingStorageIndex() view returns (uint16)",
];

// ref https://github.com/waku-org/waku-rln-contract/blob/19fded82bca07e7b535b429dc507cfb83f10dfcf/deployments/sepolia/WakuRlnStorage_0.json#L3
export const RLN_STORAGE_ABI = [
"constructor(address _poseidonHasher, uint16 _contractIndex)",
"error DuplicateIdCommitment()",
"error FullTree()",
"error InvalidIdCommitment(uint256 idCommitment)",
"error NotImplemented()",
"event MemberRegistered(uint256 idCommitment, uint256 index)",
"event MemberWithdrawn(uint256 idCommitment, uint256 index)",
"event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)",
"function DEPTH() view returns (uint256)",
"function MEMBERSHIP_DEPOSIT() view returns (uint256)",
"function SET_SIZE() view returns (uint256)",
"function contractIndex() view returns (uint16)",
"function deployedBlockNumber() view returns (uint32)",
"function idCommitmentIndex() view returns (uint256)",
"function isValidCommitment(uint256 idCommitment) view returns (bool)",
"function memberExists(uint256) view returns (bool)",
"function members(uint256) view returns (uint256)",
"function owner() view returns (address)",
"function poseidonHasher() view returns (address)",
"function register(uint256[] idCommitments)",
"function register(uint256 idCommitment) payable",
"function renounceOwnership()",
"function slash(uint256 idCommitment, address receiver, uint256[8] proof) pure",
"function stakedAmounts(uint256) view returns (uint256)",
"function transferOwnership(address newOwner)",
"function verifier() view returns (address)",
"function withdraw() pure",
"function withdrawalBalance(address) view returns (uint256)",
];

export const SEPOLIA_CONTRACT = {
chainId: 11155111,
startBlock: 3193048,
address: "0x9C09146844C1326c2dBC41c451766C7138F88155",
abi: RLN_ABI,
address: "0xF1935b338321013f11068abCafC548A7B0db732C",
abi: RLN_REGISTRY_ABI,
};
9 changes: 7 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { RLNDecoder, RLNEncoder } from "./codec.js";
import { RLN_ABI, SEPOLIA_CONTRACT } from "./constants.js";
import {
RLN_REGISTRY_ABI,
RLN_STORAGE_ABI,
SEPOLIA_CONTRACT,
} from "./constants.js";
import { Keystore } from "./keystore/index.js";
import {
IdentityCredential,
Expand Down Expand Up @@ -29,6 +33,7 @@ export {
RLNDecoder,
MerkleRootTracker,
RLNContract,
RLN_ABI,
RLN_STORAGE_ABI,
RLN_REGISTRY_ABI,
SEPOLIA_CONTRACT,
};
67 changes: 54 additions & 13 deletions src/rln_contract.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ethers } from "ethers";

import { RLN_ABI } from "./constants.js";
import { RLN_REGISTRY_ABI, RLN_STORAGE_ABI } from "./constants.js";
import { IdentityCredential, RLNInstance } from "./rln.js";
import { MerkleRootTracker } from "./root_tracker.js";

Expand All @@ -9,9 +9,11 @@ type Member = {
index: number;
};

type Provider = ethers.Signer | ethers.providers.Provider;

type ContractOptions = {
address: string;
provider: ethers.Signer | ethers.providers.Provider;
provider: Provider;
};

type FetchMembersOptions = {
Expand All @@ -21,10 +23,14 @@ type FetchMembersOptions = {
};

export class RLNContract {
private _contract: ethers.Contract;
private membersFilter: ethers.EventFilter;
private registryContract: ethers.Contract;
private merkleRootTracker: MerkleRootTracker;

private deployBlock: undefined | number;
private storageIndex: undefined | number;
private storageContract: undefined | ethers.Contract;
private _membersFilter: undefined | ethers.EventFilter;

private _members: Member[] = [];

public static async init(
Expand All @@ -33,36 +39,64 @@ export class RLNContract {
): Promise<RLNContract> {
const rlnContract = new RLNContract(rlnInstance, options);

await rlnContract.initStorageContract(options.provider);
await rlnContract.fetchMembers(rlnInstance);
rlnContract.subscribeToMembers(rlnInstance);

return rlnContract;
}

constructor(
private constructor(
rlnInstance: RLNInstance,
{ address, provider }: ContractOptions
) {
const initialRoot = rlnInstance.getMerkleRoot();

this._contract = new ethers.Contract(address, RLN_ABI, provider);
this.registryContract = new ethers.Contract(
address,
RLN_REGISTRY_ABI,
provider
);
this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
this.membersFilter = this.contract.filters.MemberRegistered();
}

private async initStorageContract(provider: Provider): Promise<void> {
const index = await this.registryContract.usingStorageIndex();
const address = await this.registryContract.storages(index);

this.storageIndex = index;
this.storageContract = new ethers.Contract(
address,
RLN_STORAGE_ABI,
provider
);
this._membersFilter = this.storageContract.filters.MemberRegistered();

this.deployBlock = await this.storageContract.deployedBlockNumber();
}

public get contract(): ethers.Contract {
return this._contract;
// since init is only way to create RLNContract class
// it is guaranteed that this.storageContract is populated
return this.storageContract as ethers.Contract;
}

public get members(): Member[] {
return this._members;
}

private get membersFilter(): ethers.EventFilter {
// since init is only way to create RLNContract class
// it is guaranteed that this.storageContract is populated
return this._membersFilter as ethers.EventFilter;
}

public async fetchMembers(
rlnInstance: RLNInstance,
options: FetchMembersOptions = {}
): Promise<void> {
const registeredMemberEvents = await queryFilter(this.contract, {
fromBlock: this.deployBlock,
...options,
membersFilter: this.membersFilter,
});
Expand Down Expand Up @@ -164,12 +198,19 @@ export class RLNContract {
public async registerWithKey(
credential: IdentityCredential
): Promise<ethers.Event | undefined> {
const depositValue = await this.contract.MEMBERSHIP_DEPOSIT();

if (!this.storageIndex) {
throw Error(
"Cannot register credential, no storage contract index found."
);
}
const txRegisterResponse: ethers.ContractTransaction =
await this.contract.register(credential.IDCommitmentBigInt, {
value: depositValue,
});
await this.registryContract.register(
this.storageIndex,
credential.IDCommitmentBigInt,
{
gasLimit: 100000,
}
);
const txRegisterReceipt = await txRegisterResponse.wait();

return txRegisterReceipt?.events?.[0];
Expand Down
Loading