mirror of
https://github.com/0xbow-io/privacy-pools-core.git
synced 2026-01-09 01:17:58 -05:00
feat(sdk): support AccountCommitment type in proveWithdrawal (#78)
This commit is contained in:
@@ -5,6 +5,7 @@ import { Commitment, CommitmentProof } from "../types/commitment.js";
|
||||
import { WithdrawalProof, WithdrawalProofInput } from "../types/withdrawal.js";
|
||||
import { ContractInteractionsService } from "./contracts.service.js";
|
||||
import { Hex, Address, Chain } from "viem";
|
||||
import { AccountCommitment } from "../types/account.js";
|
||||
|
||||
/**
|
||||
* Main SDK class providing access to all privacy pool functionality.
|
||||
@@ -72,7 +73,7 @@ export class PrivacyPoolSDK {
|
||||
* @param withdrawal - Withdrawal details
|
||||
*/
|
||||
public async proveWithdrawal(
|
||||
commitment: Commitment,
|
||||
commitment: Commitment | AccountCommitment ,
|
||||
input: WithdrawalProofInput,
|
||||
): Promise<WithdrawalProof> {
|
||||
return await this.withdrawalService.proveWithdrawal(commitment, input);
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
CircuitName,
|
||||
CircuitsInterface,
|
||||
} from "../interfaces/circuits.interface.js";
|
||||
import { Commitment } from "../types/commitment.js";
|
||||
import { WithdrawalProof, WithdrawalProofInput } from "../types/withdrawal.js";
|
||||
import { AccountCommitment, Commitment } from "../index.js";
|
||||
|
||||
/**
|
||||
* Service responsible for handling withdrawal-related operations.
|
||||
@@ -23,8 +23,8 @@ export class WithdrawalService {
|
||||
* @throws {ProofError} If proof generation fails
|
||||
*/
|
||||
public async proveWithdrawal(
|
||||
commitment: Commitment,
|
||||
input: WithdrawalProofInput,
|
||||
commitment: Commitment | AccountCommitment,
|
||||
input: WithdrawalProofInput
|
||||
): Promise<WithdrawalProof> {
|
||||
try {
|
||||
const inputSignals = this.prepareInputSignals(commitment, input);
|
||||
@@ -80,9 +80,25 @@ export class WithdrawalService {
|
||||
* Prepares input signals for the withdrawal circuit.
|
||||
*/
|
||||
private prepareInputSignals(
|
||||
commitment: Commitment,
|
||||
input: WithdrawalProofInput,
|
||||
commitment: Commitment | AccountCommitment,
|
||||
input: WithdrawalProofInput
|
||||
): Record<string, bigint | bigint[] | string> {
|
||||
let existingValue: bigint;
|
||||
let existingNullifier: bigint;
|
||||
let existingSecret: bigint;
|
||||
let label: bigint;
|
||||
if ("preimage" in commitment) {
|
||||
existingValue = commitment.preimage.value;
|
||||
existingNullifier = commitment.preimage.precommitment.nullifier;
|
||||
existingSecret = commitment.preimage.precommitment.secret;
|
||||
label = commitment.preimage.label;
|
||||
} else {
|
||||
existingValue = commitment.value;
|
||||
existingNullifier = commitment.nullifier;
|
||||
existingSecret = commitment.secret;
|
||||
label = commitment.label;
|
||||
}
|
||||
|
||||
return {
|
||||
// Public signals
|
||||
withdrawnValue: input.withdrawalAmount,
|
||||
@@ -93,10 +109,10 @@ export class WithdrawalService {
|
||||
context: input.context,
|
||||
|
||||
// Private signals
|
||||
label: commitment.preimage.label,
|
||||
existingValue: commitment.preimage.value,
|
||||
existingNullifier: commitment.preimage.precommitment.nullifier,
|
||||
existingSecret: commitment.preimage.precommitment.secret,
|
||||
label,
|
||||
existingValue,
|
||||
existingNullifier,
|
||||
existingSecret,
|
||||
newNullifier: input.newNullifier,
|
||||
newSecret: input.newSecret,
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as snarkjs from "snarkjs";
|
||||
import { Commitment, Hash, Secret } from "../../src/types/commitment.js";
|
||||
import { LeanIMTMerkleProof } from "@zk-kit/lean-imt";
|
||||
import { ProofError } from "../../src/errors/base.error.js";
|
||||
import { AccountCommitment } from "../../src/types/account.js";
|
||||
|
||||
vi.mock("snarkjs");
|
||||
vi.mock("viem", async (importOriginal) => {
|
||||
@@ -55,7 +56,7 @@ describe("PrivacyPoolSDK", () => {
|
||||
BigInt(1),
|
||||
BigInt(2),
|
||||
BigInt(3) as Secret,
|
||||
BigInt(4) as Secret,
|
||||
BigInt(4) as Secret
|
||||
);
|
||||
expect(result).toStrictEqual({
|
||||
proof: "PROOF",
|
||||
@@ -65,7 +66,7 @@ describe("PrivacyPoolSDK", () => {
|
||||
expect(snarkjs.groth16.fullProve).toHaveBeenCalledWith(
|
||||
inputSignals,
|
||||
binariesMock.commitment.wasm,
|
||||
binariesMock.commitment.zkey,
|
||||
binariesMock.commitment.zkey
|
||||
);
|
||||
});
|
||||
|
||||
@@ -81,7 +82,7 @@ describe("PrivacyPoolSDK", () => {
|
||||
sdk.verifyCommitment({
|
||||
proof: {} as snarkjs.Groth16Proof,
|
||||
publicSignals: [],
|
||||
}),
|
||||
})
|
||||
).rejects.toThrowError(ProofError);
|
||||
});
|
||||
|
||||
@@ -158,6 +159,63 @@ describe("PrivacyPoolSDK", () => {
|
||||
expect(downloadArtifactsSpy).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("can prove withdrawal with account commitment", async () => {
|
||||
const mockAccountCommitment: AccountCommitment = {
|
||||
hash: BigInt(1) as Hash,
|
||||
value: BigInt(1000),
|
||||
label: BigInt(3) as Hash,
|
||||
nullifier: BigInt(2) as Secret,
|
||||
secret: BigInt(4) as Secret,
|
||||
blockNumber: BigInt(5),
|
||||
txHash: "0x1234",
|
||||
};
|
||||
|
||||
snarkjs.groth16.fullProve = vi.fn().mockResolvedValue({
|
||||
proof: "mockProof",
|
||||
publicSignals: "mockPublicSignals",
|
||||
});
|
||||
|
||||
const stateMerkleProof: LeanIMTMerkleProof<bigint> = {
|
||||
root: BigInt(5),
|
||||
leaf: mockCommitment.hash,
|
||||
index: 1,
|
||||
siblings: [BigInt(6), BigInt(7)],
|
||||
};
|
||||
|
||||
const aspMerkleProof: LeanIMTMerkleProof<bigint> = {
|
||||
root: BigInt(8),
|
||||
leaf: BigInt(3),
|
||||
index: 2,
|
||||
siblings: [BigInt(9), BigInt(10)],
|
||||
};
|
||||
|
||||
const withdrawalInput = {
|
||||
withdrawalAmount: BigInt(500),
|
||||
stateMerkleProof,
|
||||
aspMerkleProof,
|
||||
stateRoot: BigInt(5) as Hash,
|
||||
aspRoot: BigInt(8) as Hash,
|
||||
newNullifier: BigInt(12) as Secret,
|
||||
newSecret: BigInt(13) as Secret,
|
||||
context: BigInt(1),
|
||||
stateTreeDepth: BigInt(32),
|
||||
aspTreeDepth: BigInt(32),
|
||||
};
|
||||
|
||||
const downloadArtifactsSpy = vi
|
||||
.spyOn(circuits, "downloadArtifacts")
|
||||
.mockResolvedValue(binariesMock);
|
||||
|
||||
const result = await sdk.proveWithdrawal(
|
||||
mockAccountCommitment,
|
||||
withdrawalInput
|
||||
);
|
||||
|
||||
expect(result).toHaveProperty("proof", "mockProof");
|
||||
expect(result).toHaveProperty("publicSignals", "mockPublicSignals");
|
||||
expect(downloadArtifactsSpy).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("should throw error on proof generation failure", async () => {
|
||||
snarkjs.groth16.fullProve = vi
|
||||
.fn()
|
||||
@@ -191,7 +249,7 @@ describe("PrivacyPoolSDK", () => {
|
||||
};
|
||||
|
||||
await expect(
|
||||
sdk.proveWithdrawal(mockCommitment, withdrawalInput),
|
||||
sdk.proveWithdrawal(mockCommitment, withdrawalInput)
|
||||
).rejects.toThrow(ProofError);
|
||||
});
|
||||
|
||||
@@ -207,7 +265,7 @@ describe("PrivacyPoolSDK", () => {
|
||||
sdk.verifyWithdrawal({
|
||||
proof: {} as snarkjs.Groth16Proof,
|
||||
publicSignals: [],
|
||||
}),
|
||||
})
|
||||
).rejects.toThrow(ProofError);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user