mirror of
https://github.com/logos-messaging/js-rln.git
synced 2026-01-06 23:53:07 +00:00
implement rln contract abstraction, add basic tests, add usefull constants
This commit is contained in:
parent
fa70837558
commit
6fe833b83d
@ -3,14 +3,15 @@
|
||||
"$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/master/cspell.schema.json",
|
||||
"language": "en",
|
||||
"words": [
|
||||
"Waku",
|
||||
"arrayify",
|
||||
"circom",
|
||||
"keypair",
|
||||
"merkle",
|
||||
"nwaku",
|
||||
"vkey",
|
||||
"zkey",
|
||||
"circom",
|
||||
"Waku",
|
||||
"zerokit",
|
||||
"nwaku"
|
||||
"zkey"
|
||||
],
|
||||
"flagWords": [],
|
||||
"ignorePaths": [
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<p>Open the developer tools to see the generated proof and its validation</p>
|
||||
<script src="https://cdn.ethers.io/lib/ethers-5.6.umd.min.js" type="text/javascript">
|
||||
</script>
|
||||
<script src="./index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -38,4 +38,25 @@ rln.create().then(async rlnInstance => {
|
||||
} catch (err) {
|
||||
console.log("Invalid proof")
|
||||
}
|
||||
});
|
||||
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
window.ethereum,
|
||||
"any"
|
||||
);
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const signature = await signer.signMessage(rln.DEFAULT_SIGNATURE_MESSAGE);
|
||||
console.log(`Got signature: ${signature}`);
|
||||
|
||||
const contract = new rln.RLNContract(rln.DEV_CONTRACT.address, signer);
|
||||
|
||||
console.log("Fetching members from Contract");
|
||||
await contract.fetchMembers(rlnInstance, 8261478);
|
||||
console.log(`Fetched members are ${contract.getMembers()}`);
|
||||
|
||||
contract.subscribeToMembers(rlnInstance);
|
||||
console.log("Subscribed to the contract for new members");
|
||||
|
||||
const event = await contract.registerMember(rlnInstance, signature);
|
||||
console.log(`Registered as member with ${event}`);
|
||||
});
|
||||
|
||||
19732
example/package-lock.json
generated
19732
example/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
1294
package-lock.json
generated
1294
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,7 @@
|
||||
"test:tsc": "tsc -p tsconfig.dev.json",
|
||||
"test:browser": "karma start karma.conf.cjs",
|
||||
"watch:build": "tsc -p tsconfig.json -w",
|
||||
"watch:test": "mocha --watch",
|
||||
"watch:test": "mocha -g \"RLN Contract abstraction\"",
|
||||
"prepublish": "npm run build",
|
||||
"reset-hard": "git clean -dfx && git reset --hard && npm i && npm run build"
|
||||
},
|
||||
@ -59,6 +59,7 @@
|
||||
"@size-limit/preset-big-lib": "^8.0.0",
|
||||
"@types/app-root-path": "^1.2.4",
|
||||
"@types/chai": "^4.2.15",
|
||||
"@types/chai-spies": "^1.0.3",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/mocha": "^9.1.0",
|
||||
"@types/node": "^17.0.6",
|
||||
@ -69,6 +70,7 @@
|
||||
"@web/rollup-plugin-import-meta-assets": "^1.0.7",
|
||||
"app-root-path": "^3.0.0",
|
||||
"chai": "^4.3.4",
|
||||
"chai-spies": "^1.0.0",
|
||||
"cspell": "^5.14.0",
|
||||
"eslint": "^8.6.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
@ -125,6 +127,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@waku/zerokit-rln-wasm": "^0.0.5"
|
||||
"@waku/zerokit-rln-wasm": "^0.0.5",
|
||||
"ethers": "^5.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
17
src/const.ts
Normal file
17
src/const.ts
Normal file
@ -0,0 +1,17 @@
|
||||
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)",
|
||||
];
|
||||
|
||||
export const DEV_CONTRACT = {
|
||||
chainId: 5,
|
||||
startBlock: 7109391,
|
||||
address: "0x4252105670fe33d2947e8ead304969849e64f2a6",
|
||||
abi: RLN_ABI,
|
||||
};
|
||||
|
||||
export const DEFAULT_SIGNATURE_MESSAGE =
|
||||
"The signature of this message will be used to generate your RLN credentials. Anyone accessing it may send messages on your behalf, please only share with the RLN dApp";
|
||||
16
src/index.ts
16
src/index.ts
@ -1,6 +1,8 @@
|
||||
import { RLNDecoder, RLNEncoder } from "./codec.js";
|
||||
import type { Proof, RLNInstance } from "./rln.js";
|
||||
import { DEFAULT_SIGNATURE_MESSAGE, DEV_CONTRACT, RLN_ABI } from "./const.js";
|
||||
import { Proof, RLNInstance } from "./rln.js";
|
||||
import { MembershipKey } from "./rln.js";
|
||||
import { RLNContract } from "./rln_contract.js";
|
||||
|
||||
// reexport the create function, dynamically imported from rln.ts
|
||||
export async function create(): Promise<RLNInstance> {
|
||||
@ -11,4 +13,14 @@ export async function create(): Promise<RLNInstance> {
|
||||
return await rlnModule.create();
|
||||
}
|
||||
|
||||
export { RLNInstance, MembershipKey, Proof, RLNEncoder, RLNDecoder };
|
||||
export {
|
||||
RLNInstance,
|
||||
MembershipKey,
|
||||
Proof,
|
||||
RLNEncoder,
|
||||
RLNDecoder,
|
||||
RLNContract,
|
||||
RLN_ABI,
|
||||
DEV_CONTRACT,
|
||||
DEFAULT_SIGNATURE_MESSAGE,
|
||||
};
|
||||
|
||||
60
src/rln_contract.spec.ts
Normal file
60
src/rln_contract.spec.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import chai from "chai";
|
||||
import spies from "chai-spies";
|
||||
import ethers from "ethers";
|
||||
|
||||
import * as rln from "./index.js";
|
||||
|
||||
chai.use(spies);
|
||||
|
||||
describe("RLN Contract abstraction", () => {
|
||||
it("should be able to fetch members from events and store to rln instance", async () => {
|
||||
const rlnInstance = await rln.create();
|
||||
|
||||
chai.spy.on(rlnInstance, "insertMember");
|
||||
|
||||
const voidSigner = new ethers.VoidSigner(rln.DEV_CONTRACT.address);
|
||||
const rlnContract = new rln.RLNContract(
|
||||
rln.DEV_CONTRACT.address,
|
||||
voidSigner
|
||||
);
|
||||
|
||||
chai.spy.on(rlnContract, "contract.queryFilter", () =>
|
||||
Promise.resolve([mockEvent()])
|
||||
);
|
||||
|
||||
await rlnContract.fetchMembers(rlnInstance);
|
||||
|
||||
chai.expect(rlnInstance.insertMember).to.have.been.called();
|
||||
});
|
||||
|
||||
it("should register a member by signature", async () => {
|
||||
const mockSignature =
|
||||
"0xdeb8a6b00a8e404deb1f52d3aa72ed7f60a2ff4484c737eedaef18a0aacb2dfb4d5d74ac39bb71fa358cf2eb390565a35b026cc6272f2010d4351e17670311c21c";
|
||||
|
||||
const rlnInstance = await rln.create();
|
||||
const voidSigner = new ethers.VoidSigner(rln.DEV_CONTRACT.address);
|
||||
const rlnContract = new rln.RLNContract(
|
||||
rln.DEV_CONTRACT.address,
|
||||
voidSigner
|
||||
);
|
||||
|
||||
chai.spy.on(rlnContract, "contract.MEMBERSHIP_DEPOSIT", () =>
|
||||
Promise.resolve(1)
|
||||
);
|
||||
const contractSpy = chai.spy.on(rlnContract, "contract.register");
|
||||
|
||||
await rlnContract.registerMember(rlnInstance, mockSignature);
|
||||
|
||||
chai.expect(contractSpy).to.have.been.called();
|
||||
});
|
||||
});
|
||||
|
||||
function mockEvent(): ethers.Event {
|
||||
return {
|
||||
args: {
|
||||
pubkey:
|
||||
"C4qAaeoqKlLv4Df910gnyuCfKLk7uhIhLZgcQfOMncYJpfZqW+Pdlv3ie6hm4WkGLaS5UIO2QPbyhN4EGx73c8vkTqjv5gK49w/pGIDi+ILMjYqYKexSwJPmPOMn0XM0FDbQ5wwXmZ4SIauYiQM8faZLDk8ltkAsIX/TKA6Dgw0=",
|
||||
index: 1,
|
||||
},
|
||||
} as any as ethers.Event;
|
||||
}
|
||||
91
src/rln_contract.ts
Normal file
91
src/rln_contract.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { ethers } from "ethers";
|
||||
|
||||
import { RLN_ABI } from "./const.js";
|
||||
import { RLNInstance } from "./rln.js";
|
||||
|
||||
type Member = {
|
||||
pubkey: string;
|
||||
index: number;
|
||||
};
|
||||
|
||||
export class RLNContract {
|
||||
private contract: ethers.Contract;
|
||||
private membersFilter: ethers.EventFilter;
|
||||
|
||||
private members: Member[] = [];
|
||||
|
||||
constructor(
|
||||
address: string,
|
||||
provider: ethers.Signer | ethers.providers.Provider
|
||||
) {
|
||||
this.contract = new ethers.Contract(address, RLN_ABI, provider);
|
||||
this.membersFilter = this.contract.filters.MemberRegistered();
|
||||
}
|
||||
|
||||
public getContract(): ethers.Contract {
|
||||
return this.contract;
|
||||
}
|
||||
|
||||
public getMembers(): Member[] {
|
||||
return this.members;
|
||||
}
|
||||
|
||||
public async fetchMembers(
|
||||
rlnInstance: RLNInstance,
|
||||
fromBlock?: number
|
||||
): Promise<void> {
|
||||
const registeredMemberEvents = await this.contract.queryFilter(
|
||||
this.membersFilter,
|
||||
fromBlock
|
||||
);
|
||||
|
||||
for (const event of registeredMemberEvents) {
|
||||
this.addMemberFromEvent(rlnInstance, event);
|
||||
}
|
||||
}
|
||||
|
||||
public subscribeToMembers(rlnInstance: RLNInstance): void {
|
||||
this.contract.on(this.membersFilter, (_pubkey, _index, event) =>
|
||||
this.addMemberFromEvent(rlnInstance, event)
|
||||
);
|
||||
}
|
||||
|
||||
private addMemberFromEvent(
|
||||
rlnInstance: RLNInstance,
|
||||
event: ethers.Event
|
||||
): void {
|
||||
if (!event.args) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pubkey: string = event.args.pubkey;
|
||||
const index: number = event.args.index;
|
||||
|
||||
this.members.push({ index, pubkey });
|
||||
|
||||
const idCommitment = ethers.utils.zeroPad(
|
||||
ethers.utils.arrayify(pubkey),
|
||||
32
|
||||
);
|
||||
rlnInstance.insertMember(idCommitment);
|
||||
}
|
||||
|
||||
public async registerMember(
|
||||
rlnInstance: RLNInstance,
|
||||
signature: string
|
||||
): Promise<ethers.Event | undefined> {
|
||||
const membershipKey = await rlnInstance.generateSeededMembershipKey(
|
||||
signature
|
||||
);
|
||||
const pubkey = ethers.BigNumber.from(membershipKey.IDCommitment);
|
||||
const depositValue = await this.contract.MEMBERSHIP_DEPOSIT();
|
||||
|
||||
const txRegisterResponse: ethers.ContractTransaction =
|
||||
await this.contract.register(pubkey, {
|
||||
value: depositValue,
|
||||
});
|
||||
const txRegisterReceipt = await txRegisterResponse.wait();
|
||||
|
||||
return txRegisterReceipt?.events?.[0];
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user