Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions contracts/privacy_pool/src/core/withdraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub fn execute(
proof: Proof,
pub_inputs: PublicInputs,
) -> Result<bool, Error> {
let invoker_addr = env.invoker();
// Load and validate pool configuration
let pool_config = config::load_pool_config(&env, &pool_id)?;
validation::require_not_paused(&pool_config)?;
Expand Down Expand Up @@ -55,6 +56,14 @@ pub fn execute(
let recipient = address_decoder::decode_address(&env, &pub_inputs.recipient);
let relayer_opt = address_decoder::decode_optional_relayer(&env, &pub_inputs.relayer);

// ZK-073: If no relayer is specified (zero-relayer semantics),
// enforce that the recipient must be the transaction invoker.
if relayer_opt.is_none() {
if recipient != invoker_addr {
return Err(Error::ZeroRelayerRecipientMismatch);
}
}

// Step 7: Transfer funds
transfer_funds(
&env,
Expand Down
8 changes: 5 additions & 3 deletions contracts/privacy_pool/src/types/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ pub enum Error {
FeeExceedsAmount = 43,
/// Relayer address is non-zero but fee is zero
InvalidRelayerFee = 44,
/// Recipient address must be invoker for zero-relayer withdrawals
ZeroRelayerRecipientMismatch = 45,
/// Recipient address is invalid
InvalidRecipient = 45,
InvalidRecipient = 46,
/// Pool ID in public inputs does not match the pool being withdrawn from
InvalidPoolId = 46,
InvalidPoolId = 47,
/// Denomination in public inputs does not match the pool denomination
InvalidDenomination = 47,
InvalidDenomination = 48,

// ── Verifying Key ──────────────────────────────────
/// Verifying key has not been set
Expand Down
25 changes: 22 additions & 3 deletions sdk/src/test/harness/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,10 @@ export enum ContractErrorCode {
InvalidProof = 42,
FeeExceedsAmount = 43,
InvalidRelayerFee = 44,
InvalidRecipient = 45,
InvalidPoolId = 46,
InvalidDenomination = 47,
ZeroRelayerRecipientMismatch = 45,
InvalidRecipient = 46,
InvalidPoolId = 47,
InvalidDenomination = 48,

// Verifying Key
NoVerifyingKey = 50,
Expand Down Expand Up @@ -419,6 +420,24 @@ function classifyByErrorCode(
};

// Recipient errors
case ContractErrorCode.ZeroRelayerRecipientMismatch:
return {
category: ErrorCategory.RECIPIENT_ERROR,
originalMessage: error.message,
errorCode,
actionableMessage: 'Recipient address must be the transaction invoker for zero-relayer withdrawals.',
recommendations: [
'When not using a relayer, ensure the withdrawal recipient is your own address',
'Verify the recipient address matches the invoker address of the transaction',
`Recipient: ${context?.recipient?.slice(0, 16)}...`,
],
context: {
errorCode,
recipient: context?.recipient,
relayer: context?.relayer,
},
};

case ContractErrorCode.InvalidRecipient:
return {
category: ErrorCategory.RECIPIENT_ERROR,
Expand Down