mirror of
https://github.com/logos-messaging/logos-messaging-js.git
synced 2026-05-05 20:29:26 +00:00
fix: refactor to use a single viem client object
This commit is contained in:
parent
64aef7b2a2
commit
ad24c6c787
@ -1,7 +1,6 @@
|
||||
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";
|
||||
|
||||
@ -9,17 +8,17 @@ use(chaiAsPromised);
|
||||
|
||||
function createMockRLNBaseContract(
|
||||
mockContract: any,
|
||||
mockPublicClient: PublicClient
|
||||
mockRpcClient: any
|
||||
): RLNBaseContract {
|
||||
const dummy = Object.create(RLNBaseContract.prototype);
|
||||
dummy.contract = mockContract;
|
||||
dummy.publicClient = mockPublicClient;
|
||||
dummy.rpcClient = mockRpcClient;
|
||||
return dummy as RLNBaseContract;
|
||||
}
|
||||
|
||||
describe("RLNBaseContract.getPriceForRateLimit (unit)", function () {
|
||||
let mockContract: any;
|
||||
let mockPublicClient: any;
|
||||
let mockRpcClient: any;
|
||||
let priceCalculatorReadStub: sinon.SinonStub;
|
||||
let readContractStub: sinon.SinonStub;
|
||||
|
||||
@ -33,7 +32,7 @@ describe("RLNBaseContract.getPriceForRateLimit (unit)", function () {
|
||||
}
|
||||
};
|
||||
|
||||
mockPublicClient = {
|
||||
mockRpcClient = {
|
||||
readContract: readContractStub
|
||||
};
|
||||
});
|
||||
@ -50,7 +49,7 @@ describe("RLNBaseContract.getPriceForRateLimit (unit)", function () {
|
||||
priceCalculatorReadStub.resolves(priceCalculatorAddress);
|
||||
readContractStub.resolves([fakeToken, fakePrice]);
|
||||
|
||||
const rlnBase = createMockRLNBaseContract(mockContract, mockPublicClient);
|
||||
const rlnBase = createMockRLNBaseContract(mockContract, mockRpcClient);
|
||||
const result = await rlnBase.getPriceForRateLimit(20);
|
||||
|
||||
expect(result.token).to.equal(fakeToken);
|
||||
@ -72,7 +71,7 @@ describe("RLNBaseContract.getPriceForRateLimit (unit)", function () {
|
||||
priceCalculatorReadStub.resolves(priceCalculatorAddress);
|
||||
readContractStub.rejects(new Error("fail"));
|
||||
|
||||
const rlnBase = createMockRLNBaseContract(mockContract, mockPublicClient);
|
||||
const rlnBase = createMockRLNBaseContract(mockContract, mockRpcClient);
|
||||
await expect(rlnBase.getPriceForRateLimit(20)).to.be.rejectedWith("fail");
|
||||
|
||||
expect(priceCalculatorReadStub.calledOnce).to.be.true;
|
||||
@ -85,7 +84,7 @@ describe("RLNBaseContract.getPriceForRateLimit (unit)", function () {
|
||||
priceCalculatorReadStub.resolves(priceCalculatorAddress);
|
||||
readContractStub.resolves([null, null]);
|
||||
|
||||
const rlnBase = createMockRLNBaseContract(mockContract, mockPublicClient);
|
||||
const rlnBase = createMockRLNBaseContract(mockContract, mockRpcClient);
|
||||
const result = await rlnBase.getPriceForRateLimit(20);
|
||||
|
||||
expect(result.token).to.be.null;
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
GetContractEventsReturnType,
|
||||
GetContractReturnType,
|
||||
type Hash,
|
||||
publicActions,
|
||||
PublicClient,
|
||||
WalletClient
|
||||
} from "viem";
|
||||
@ -38,8 +39,7 @@ export class RLNBaseContract {
|
||||
typeof wakuRlnV2Abi,
|
||||
PublicClient | WalletClient
|
||||
>;
|
||||
public publicClient: PublicClient;
|
||||
public walletClient: WalletClient;
|
||||
public rpcClient: WalletClient & PublicClient;
|
||||
private deployBlock: undefined | number;
|
||||
private rateLimit: number;
|
||||
private minRateLimit?: number;
|
||||
@ -51,21 +51,16 @@ export class RLNBaseContract {
|
||||
* Private constructor for RLNBaseContract. Use static create() instead.
|
||||
*/
|
||||
protected constructor(options: RLNContractOptions) {
|
||||
const {
|
||||
address,
|
||||
publicClient,
|
||||
walletClient,
|
||||
rateLimit = DEFAULT_RATE_LIMIT
|
||||
} = options;
|
||||
const { address, rpcClient, rateLimit = DEFAULT_RATE_LIMIT } = options;
|
||||
|
||||
log.info("Initializing RLNBaseContract", { address, rateLimit });
|
||||
|
||||
this.publicClient = publicClient;
|
||||
this.walletClient = walletClient;
|
||||
this.rpcClient = rpcClient.extend(publicActions) as WalletClient &
|
||||
PublicClient;
|
||||
this.contract = getContract({
|
||||
address,
|
||||
abi: wakuRlnV2Abi,
|
||||
client: { wallet: walletClient, public: publicClient }
|
||||
client: this.rpcClient
|
||||
});
|
||||
this.rateLimit = rateLimit;
|
||||
|
||||
@ -334,7 +329,7 @@ export class RLNBaseContract {
|
||||
idCommitmentBigInt
|
||||
]);
|
||||
|
||||
const currentBlock = await this.publicClient.getBlockNumber();
|
||||
const currentBlock = await this.rpcClient.getBlockNumber();
|
||||
|
||||
const [
|
||||
depositAmount,
|
||||
@ -379,15 +374,15 @@ export class RLNBaseContract {
|
||||
}
|
||||
|
||||
public async extendMembership(idCommitmentBigInt: bigint): Promise<Hash> {
|
||||
if (!this.walletClient.account) {
|
||||
if (!this.rpcClient.account) {
|
||||
throw new Error(
|
||||
"Failed to extendMembership: no account set in wallet client"
|
||||
);
|
||||
}
|
||||
try {
|
||||
await this.contract.simulate.extendMemberships([[idCommitmentBigInt]], {
|
||||
chain: this.walletClient.chain,
|
||||
account: this.walletClient.account!.address
|
||||
chain: this.rpcClient.chain,
|
||||
account: (this.rpcClient as WalletClient).account!.address
|
||||
});
|
||||
} catch (err) {
|
||||
throw new Error("Simulating extending membership failed: " + err);
|
||||
@ -395,12 +390,12 @@ export class RLNBaseContract {
|
||||
const hash = await this.contract.write.extendMemberships(
|
||||
[[idCommitmentBigInt]],
|
||||
{
|
||||
account: this.walletClient.account!,
|
||||
chain: this.walletClient.chain
|
||||
account: this.rpcClient.account!,
|
||||
chain: this.rpcClient.chain
|
||||
}
|
||||
);
|
||||
|
||||
await this.publicClient.waitForTransactionReceipt({ hash });
|
||||
await this.rpcClient.waitForTransactionReceipt({ hash });
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -414,7 +409,7 @@ export class RLNBaseContract {
|
||||
) {
|
||||
throw new Error("Membership is not expired or in grace period");
|
||||
}
|
||||
if (!this.walletClient.account) {
|
||||
if (!this.rpcClient.account) {
|
||||
throw new Error(
|
||||
"Failed to eraseMembership: no account set in wallet client"
|
||||
);
|
||||
@ -424,8 +419,8 @@ export class RLNBaseContract {
|
||||
await this.contract.simulate.eraseMemberships(
|
||||
[[idCommitmentBigInt], eraseFromMembershipSet],
|
||||
{
|
||||
chain: this.walletClient.chain,
|
||||
account: this.walletClient.account!.address
|
||||
chain: this.rpcClient.chain,
|
||||
account: (this.rpcClient as WalletClient).account!.address
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
@ -435,11 +430,11 @@ export class RLNBaseContract {
|
||||
const hash = await this.contract.write.eraseMemberships(
|
||||
[[idCommitmentBigInt], eraseFromMembershipSet],
|
||||
{
|
||||
chain: this.walletClient.chain,
|
||||
account: this.walletClient.account!
|
||||
chain: this.rpcClient.chain,
|
||||
account: this.rpcClient.account!
|
||||
}
|
||||
);
|
||||
await this.publicClient.waitForTransactionReceipt({ hash });
|
||||
await this.rpcClient.waitForTransactionReceipt({ hash });
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -455,7 +450,7 @@ export class RLNBaseContract {
|
||||
`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
|
||||
);
|
||||
}
|
||||
if (!this.walletClient.account) {
|
||||
if (!this.rpcClient.account) {
|
||||
throw new Error(
|
||||
"Failed to registerMembership: no account set in wallet client"
|
||||
);
|
||||
@ -464,8 +459,8 @@ export class RLNBaseContract {
|
||||
await this.contract.simulate.register(
|
||||
[idCommitmentBigInt, rateLimit, []],
|
||||
{
|
||||
chain: this.walletClient.chain,
|
||||
account: this.walletClient.account!.address
|
||||
chain: this.rpcClient.chain,
|
||||
account: (this.rpcClient as WalletClient).account!.address
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
@ -475,11 +470,11 @@ export class RLNBaseContract {
|
||||
const hash = await this.contract.write.register(
|
||||
[idCommitmentBigInt, rateLimit, []],
|
||||
{
|
||||
chain: this.walletClient.chain,
|
||||
account: this.walletClient.account!
|
||||
chain: this.rpcClient.chain,
|
||||
account: this.rpcClient.account!
|
||||
}
|
||||
);
|
||||
await this.publicClient.waitForTransactionReceipt({ hash });
|
||||
await this.rpcClient.waitForTransactionReceipt({ hash });
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -489,25 +484,25 @@ export class RLNBaseContract {
|
||||
* NOTE: Funds are sent to msg.sender (the walletClient's address)
|
||||
*/
|
||||
public async withdraw(token: string): Promise<Hash> {
|
||||
if (!this.walletClient.account) {
|
||||
if (!this.rpcClient.account) {
|
||||
throw new Error("Failed to withdraw: no account set in wallet client");
|
||||
}
|
||||
|
||||
try {
|
||||
await this.contract.simulate.withdraw([token as Address], {
|
||||
chain: this.walletClient.chain,
|
||||
account: this.walletClient.account!.address
|
||||
chain: this.rpcClient.chain,
|
||||
account: (this.rpcClient as WalletClient).account!.address
|
||||
});
|
||||
} catch (err) {
|
||||
throw new Error("Error simulating withdraw: " + err);
|
||||
}
|
||||
|
||||
const hash = await this.contract.write.withdraw([token as Address], {
|
||||
chain: this.walletClient.chain,
|
||||
account: this.walletClient.account!
|
||||
chain: this.rpcClient.chain,
|
||||
account: this.rpcClient.account!
|
||||
});
|
||||
|
||||
await this.publicClient.waitForTransactionReceipt({ hash });
|
||||
await this.rpcClient.waitForTransactionReceipt({ hash });
|
||||
return hash;
|
||||
}
|
||||
public async registerWithIdentity(
|
||||
@ -539,23 +534,22 @@ export class RLNBaseContract {
|
||||
await this.contract.simulate.register(
|
||||
[identity.IDCommitmentBigInt, this.rateLimit, []],
|
||||
{
|
||||
chain: this.walletClient.chain,
|
||||
account: this.walletClient.account!.address
|
||||
chain: this.rpcClient.chain,
|
||||
account: (this.rpcClient as WalletClient).account!.address
|
||||
}
|
||||
);
|
||||
|
||||
const hash: Hash = await this.contract.write.register(
|
||||
[identity.IDCommitmentBigInt, this.rateLimit, []],
|
||||
{
|
||||
chain: this.walletClient.chain,
|
||||
account: this.walletClient.account!
|
||||
chain: this.rpcClient.chain,
|
||||
account: this.rpcClient.account!
|
||||
}
|
||||
);
|
||||
|
||||
const txRegisterReceipt =
|
||||
await this.publicClient.waitForTransactionReceipt({
|
||||
hash
|
||||
});
|
||||
const txRegisterReceipt = await this.rpcClient.waitForTransactionReceipt({
|
||||
hash
|
||||
});
|
||||
|
||||
if (txRegisterReceipt.status === "reverted") {
|
||||
throw new Error("Transaction failed on-chain");
|
||||
@ -709,7 +703,7 @@ export class RLNBaseContract {
|
||||
price: bigint | null;
|
||||
}> {
|
||||
const address = await this.contract.read.priceCalculator();
|
||||
const [token, price] = await this.publicClient.readContract({
|
||||
const [token, price] = await this.rpcClient.readContract({
|
||||
address,
|
||||
abi: iPriceCalculatorAbi,
|
||||
functionName: "calculate",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Address, PublicClient, WalletClient } from "viem";
|
||||
import { Address, WalletClient } from "viem";
|
||||
|
||||
export type Member = {
|
||||
idCommitment: string;
|
||||
@ -6,8 +6,7 @@ export type Member = {
|
||||
};
|
||||
|
||||
export interface RLNContractOptions {
|
||||
publicClient: PublicClient;
|
||||
walletClient: WalletClient;
|
||||
rpcClient: WalletClient;
|
||||
address: Address;
|
||||
rateLimit?: number;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Logger } from "@waku/utils";
|
||||
import { PublicClient, WalletClient } from "viem";
|
||||
import { publicActions, PublicClient, WalletClient } from "viem";
|
||||
|
||||
import { RLN_CONTRACT } from "./contract/constants.js";
|
||||
import { RLNBaseContract } from "./contract/rln_base_contract.js";
|
||||
@ -10,7 +10,7 @@ import type {
|
||||
} from "./keystore/index.js";
|
||||
import { KeystoreEntity, Password } from "./keystore/types.js";
|
||||
import { RegisterMembershipOptions, StartRLNOptions } from "./types.js";
|
||||
import { createViemClientsFromWindow } from "./utils/index.js";
|
||||
import { createViemClientFromWindow } from "./utils/index.js";
|
||||
import { Zerokit } from "./zerokit.js";
|
||||
|
||||
const log = new Logger("rln:credentials");
|
||||
@ -24,8 +24,7 @@ export class RLNCredentialsManager {
|
||||
protected starting = false;
|
||||
|
||||
public contract: undefined | RLNBaseContract;
|
||||
public walletClient: undefined | WalletClient;
|
||||
public publicClient: undefined | PublicClient;
|
||||
public rpcClient: undefined | (WalletClient & PublicClient);
|
||||
|
||||
protected keystore = Keystore.create();
|
||||
public credentials: undefined | DecryptedCredentials;
|
||||
@ -56,7 +55,7 @@ export class RLNCredentialsManager {
|
||||
log.info("Credentials successfully decrypted");
|
||||
}
|
||||
|
||||
const { walletClient, publicClient, address, rateLimit } =
|
||||
const { rpcClient, address, rateLimit } =
|
||||
await this.determineStartOptions(options, credentials);
|
||||
|
||||
log.info(`Using contract address: ${address}`);
|
||||
@ -67,12 +66,10 @@ export class RLNCredentialsManager {
|
||||
}
|
||||
|
||||
this.credentials = credentials;
|
||||
this.walletClient = walletClient!;
|
||||
this.publicClient = publicClient!;
|
||||
this.rpcClient = rpcClient!;
|
||||
this.contract = await RLNBaseContract.create({
|
||||
address: address! as `0x${string}`,
|
||||
publicClient: publicClient!,
|
||||
walletClient: walletClient!,
|
||||
rpcClient: this.rpcClient,
|
||||
rateLimit: rateLimit ?? this.zerokit.rateLimit
|
||||
});
|
||||
|
||||
@ -131,9 +128,7 @@ export class RLNCredentialsManager {
|
||||
protected async determineStartOptions(
|
||||
options: StartRLNOptions,
|
||||
credentials: KeystoreEntity | undefined
|
||||
): Promise<
|
||||
StartRLNOptions & { walletClient: WalletClient; publicClient: PublicClient }
|
||||
> {
|
||||
): Promise<StartRLNOptions & { rpcClient: WalletClient & PublicClient }> {
|
||||
let chainId = credentials?.membership.chainId;
|
||||
const address =
|
||||
credentials?.membership.address ||
|
||||
@ -145,21 +140,16 @@ export class RLNCredentialsManager {
|
||||
log.info(`Using Linea contract with chainId: ${chainId}`);
|
||||
}
|
||||
|
||||
const walletClient = options.walletClient;
|
||||
const publicClient = options.publicClient;
|
||||
|
||||
let clients: { walletClient: WalletClient; publicClient: PublicClient };
|
||||
|
||||
if (!walletClient || !publicClient) {
|
||||
clients = await createViemClientsFromWindow();
|
||||
} else {
|
||||
clients = { walletClient, publicClient };
|
||||
let rpcClient: (WalletClient & PublicClient) | undefined =
|
||||
options.rpcClient?.extend(publicActions) as WalletClient & PublicClient;
|
||||
if (!rpcClient) {
|
||||
rpcClient = await createViemClientFromWindow();
|
||||
}
|
||||
|
||||
const currentChainId = await clients.publicClient.getChainId();
|
||||
const currentChainId = rpcClient.chain?.id;
|
||||
log.info(`Current chain ID: ${currentChainId}`);
|
||||
|
||||
if (chainId && chainId !== currentChainId.toString()) {
|
||||
if (chainId && chainId !== currentChainId?.toString()) {
|
||||
log.error(
|
||||
`Chain ID mismatch: contract=${chainId}, current=${currentChainId}`
|
||||
);
|
||||
@ -169,8 +159,7 @@ export class RLNCredentialsManager {
|
||||
}
|
||||
|
||||
return {
|
||||
walletClient: clients.walletClient,
|
||||
publicClient: clients.publicClient,
|
||||
rpcClient,
|
||||
address
|
||||
};
|
||||
}
|
||||
@ -216,9 +205,9 @@ export class RLNCredentialsManager {
|
||||
protected async verifyCredentialsAgainstContract(
|
||||
credentials: KeystoreEntity
|
||||
): Promise<void> {
|
||||
if (!this.contract || !this.publicClient) {
|
||||
if (!this.contract || !this.rpcClient) {
|
||||
throw Error(
|
||||
"Failed to verify chain coordinates: no contract or publicClient initialized."
|
||||
"Failed to verify chain coordinates: no contract or viem client initialized."
|
||||
);
|
||||
}
|
||||
|
||||
@ -231,7 +220,7 @@ export class RLNCredentialsManager {
|
||||
}
|
||||
|
||||
const chainId = credentials.membership.chainId;
|
||||
const currentChainId = await this.publicClient.getChainId();
|
||||
const currentChainId = await this.rpcClient.getChainId();
|
||||
if (chainId !== currentChainId.toString()) {
|
||||
throw Error(
|
||||
`Failed to verify chain coordinates: credentials chainID=${chainId} is not equal to registryContract chainID=${currentChainId}`
|
||||
|
||||
@ -4,7 +4,7 @@ import { createRLN } from "./create.js";
|
||||
import { IdentityCredential } from "./identity.js";
|
||||
import { Keystore } from "./keystore/index.js";
|
||||
import { RLNInstance } from "./rln.js";
|
||||
import { createViemClientsFromWindow } from "./utils/index.js";
|
||||
import { createViemClientFromWindow } from "./utils/index.js";
|
||||
|
||||
export {
|
||||
RLNBaseContract,
|
||||
@ -13,7 +13,7 @@ export {
|
||||
RLNInstance,
|
||||
IdentityCredential,
|
||||
RLN_CONTRACT,
|
||||
createViemClientsFromWindow as extractMetaMaskSigner
|
||||
createViemClientFromWindow
|
||||
};
|
||||
|
||||
// Export wagmi-generated ABIs
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { PublicClient, WalletClient } from "viem";
|
||||
import { WalletClient } from "viem";
|
||||
|
||||
import { IdentityCredential } from "./identity.js";
|
||||
import {
|
||||
@ -10,8 +10,7 @@ export type StartRLNOptions = {
|
||||
/**
|
||||
* If not set - will attempt to create from injected provider.
|
||||
*/
|
||||
walletClient?: WalletClient;
|
||||
publicClient?: PublicClient;
|
||||
rpcClient?: WalletClient;
|
||||
/**
|
||||
* If not set - will use default SEPOLIA_CONTRACT address.
|
||||
*/
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export { createViemClientsFromWindow } from "./walletClient.js";
|
||||
export { createViemClientFromWindow } from "./walletClient.js";
|
||||
export { BytesUtils } from "./bytes.js";
|
||||
export { sha256, poseidonHash } from "./hash.js";
|
||||
export { dateToEpoch, epochIntToBytes, epochBytesToInt } from "./epoch.js";
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import {
|
||||
createPublicClient,
|
||||
createWalletClient,
|
||||
custom,
|
||||
publicActions,
|
||||
PublicClient,
|
||||
WalletClient
|
||||
} from "viem";
|
||||
import { type Chain, lineaSepolia } from "viem/chains";
|
||||
|
||||
export const createViemClientsFromWindow = async (
|
||||
export const createViemClientFromWindow = async (
|
||||
chain: Chain = lineaSepolia
|
||||
): Promise<{ walletClient: WalletClient; publicClient: PublicClient }> => {
|
||||
): Promise<WalletClient & PublicClient> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const ethereum = (window as any).ethereum;
|
||||
|
||||
@ -21,16 +21,11 @@ export const createViemClientsFromWindow = async (
|
||||
|
||||
const [account] = await ethereum.request({ method: "eth_requestAccounts" });
|
||||
|
||||
const walletClient = createWalletClient({
|
||||
const rpcClient = createWalletClient({
|
||||
account,
|
||||
chain,
|
||||
transport: custom(ethereum)
|
||||
});
|
||||
}).extend(publicActions);
|
||||
|
||||
const publicClient = createPublicClient({
|
||||
chain,
|
||||
transport: custom(ethereum)
|
||||
});
|
||||
|
||||
return { walletClient, publicClient };
|
||||
return rpcClient;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user