> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/zkp2p/zkp2p-contracts/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting Guide

> Common issues and solutions for zkp2p-v2-contracts

This guide covers common issues you may encounter when integrating with or developing on zkp2p-v2-contracts, along with their solutions.

## Deployment Issues

### Contract Deployment Fails

**Symptoms**: Deployment script fails with error or timeout

**Common Causes**:

1. **Missing Environment Variables**
   ```bash theme={null}
   # Check .env file has all required keys
   ALCHEMY_API_KEY=your_key_here
   BASE_DEPLOY_PRIVATE_KEY=your_private_key
   BASESCAN_API_KEY=your_basescan_key
   ```

2. **Insufficient Gas**
   * Solution: Increase gas limit in `hardhat.config.ts`
   * Check current network gas prices

3. **Network Connection Issues**
   * Verify RPC endpoint is accessible
   * Try alternative RPC provider (Alchemy, Infura)

4. **Nonce Mismatch**
   ```bash theme={null}
   # Reset nonce by deleting deployment cache
   rm -rf deployments/{network}/.migrations.json
   ```

### Deployment Scripts Skip Unexpectedly

**Symptoms**: Some deployment scripts don't execute

**Solution**: Check the `func.skip` condition in deployment files. Many scripts are frozen in production:

```typescript theme={null}
func.skip = async (hre: HardhatRuntimeEnvironment): Promise<boolean> => {
  const network = hre.network.name;
  if (network === "localhost" || network === "hardhat") {
    return false;
  }
  return true; // Frozen for production networks
};
```

For production deployments, payment methods are now managed by `15_configure_v2_payment_methods.ts`.

### Contract Verification Fails

**Symptoms**: Etherscan/Basescan verification returns error

**Solutions**:

1. **Check API Key**:
   ```bash theme={null}
   # Verify Basescan API key is set
   echo $BASESCAN_API_KEY
   ```

2. **Wait for Block Confirmations**:
   ```bash theme={null}
   # Wait 5-10 blocks before verifying
   yarn etherscan:base
   ```

3. **Manual Verification**:
   * Use Basescan GUI with flattened contract
   * Ensure compiler version matches `hardhat.config.ts`

## Payment Verification Issues

### Payment Proof Verification Fails

**Symptoms**: `fulfillIntent()` reverts with verification error

**Common Errors**:

#### "UPV: Invalid payment method"

**Cause**: Payment method not registered with UnifiedPaymentVerifier

**Solution**:

```typescript theme={null}
// Check if payment method is registered
const isRegistered = await unifiedVerifier.isPaymentMethod(paymentMethodHash);

if (!isRegistered) {
  // Register payment method (owner only)
  await unifiedVerifier.addPaymentMethod(paymentMethodHash);
}
```

See `contracts/unifiedVerifier/UnifiedPaymentVerifier.sol:142`

#### "UPV: Invalid attestation"

**Cause**: EIP-712 signature verification failed

**Solutions**:

1. **Check Witness Signer**:
   ```typescript theme={null}
   // Ensure correct witness signed the attestation
   const expectedWitness = await attestationVerifier.witness();
   ```

2. **Verify Domain Separator**:
   ```typescript theme={null}
   // Domain must match verifier contract
   const domainSeparator = await unifiedVerifier.DOMAIN_SEPARATOR();
   ```

3. **Check Data Hash Integrity**:
   ```typescript theme={null}
   // dataHash must match keccak256(data)
   const computedHash = ethers.utils.keccak256(attestation.data);
   assert(computedHash === attestation.dataHash);
   ```

See `contracts/unifiedVerifier/UnifiedPaymentVerifier.sol:183-214`

#### "UPV: Snapshot hash mismatch"

**Cause**: Intent snapshot doesn't match on-chain intent

**Solution**:
Ensure all intent fields match:

```typescript theme={null}
// Verify intent snapshot
const intent = await orchestrator.getIntent(intentHash);

// All these must match:
assert(snapshot.intentHash === intentHash);
assert(snapshot.payeeDetails === intent.payeeId);
assert(snapshot.amount === intent.amount);
assert(snapshot.paymentMethod === intent.paymentMethod);
assert(snapshot.fiatCurrency === intent.fiatCurrency);
assert(snapshot.conversionRate === intent.conversionRate);
assert(snapshot.signalTimestamp === intent.timestamp);
```

See `contracts/unifiedVerifier/UnifiedPaymentVerifier.sol:220-234`

#### "UPV: Snapshot timestamp buffer exceeds maximum"

**Cause**: Timestamp buffer exceeds 48-hour maximum

**Solution**:

```typescript theme={null}
const MAX_TIMESTAMP_BUFFER_MS = 48 * 60 * 60 * 1000; // 48 hours
assert(snapshot.timestampBuffer <= MAX_TIMESTAMP_BUFFER_MS);
```

See `contracts/unifiedVerifier/UnifiedPaymentVerifier.sol:31`

#### "UPV: Data hash mismatch"

**Cause**: Signed data hash doesn't match actual data

**Solution**:

```typescript theme={null}
// Recompute data hash
const dataHash = ethers.utils.keccak256(attestation.data);

// Update attestation
attestation.dataHash = dataHash;
```

See `contracts/unifiedVerifier/UnifiedPaymentVerifier.sol:202-205`

### Nullifier Already Used

**Symptoms**: Transaction reverts with nullifier error

**Cause**: Payment ID has already been used (double-spend prevention)

**Explanation**:
Nullifiers are created as: `keccak256(abi.encodePacked(paymentMethod, paymentId))`

Each payment can only be used once across the entire protocol.

**Solution**:

* **If legitimate retry**: Use a different payment (new payment ID)
* **If testing**: Deploy fresh contracts or use different payment IDs
* **In production**: This is expected behavior - find the original intent that used this payment

See `contracts/unifiedVerifier/UnifiedPaymentVerifier.sol:242-245`

### Payment Method Not Found in Registry

**Symptoms**: `signalIntent()` reverts with payment method error

**Cause**: Payment method not registered in PaymentVerifierRegistry

**Solution**:

```typescript theme={null}
// Add payment method to registry (owner only)
await paymentVerifierRegistry.addPaymentMethod(
  paymentMethodHash,
  unifiedVerifierAddress,
  [Currency.USD, Currency.EUR] // Supported currencies
);
```

## Intent Lifecycle Issues

### Cannot Signal Intent

**Symptoms**: `signalIntent()` reverts

**Common Causes**:

#### Insufficient Deposit Liquidity

```typescript theme={null}
// Check available deposit amount
const deposit = await escrow.getDeposit(depositId);
const available = deposit.availableAmount;

if (intentAmount > available) {
  // Reduce intent amount or choose different deposit
}
```

#### Amount Below Minimum

```typescript theme={null}
// Check minimum amount for payment method
const minAmount = await escrow.getMinAmount(depositId, paymentMethodHash);

if (intentAmount < minAmount) {
  // Increase intent amount
}
```

#### Deposit Expired

```typescript theme={null}
// Check deposit expiry
const deposit = await escrow.getDeposit(depositId);
const currentTime = Math.floor(Date.now() / 1000);

if (currentTime > deposit.expiryTimestamp) {
  // Deposit has expired, choose another
}
```

#### Invalid Gating Signature

```typescript theme={null}
// If orchestrator requires gating signature
const gatingSignature = await generateGatingServiceSignature(
  gatingServiceWallet,
  intentOwner,
  escrowAddress,
  depositId,
  // ... other params
);

await orchestrator.signalIntent({
  // ... intent params
}, gatingSignature); // Include signature
```

### Cannot Fulfill Intent

**Symptoms**: `fulfillIntent()` reverts

**Common Causes**:

#### Intent Expired

```typescript theme={null}
// Check intent expiry
const intent = await orchestrator.getIntent(intentHash);
const currentTime = Math.floor(Date.now() / 1000);

if (currentTime > intent.expiryTimestamp) {
  // Intent has expired, must cancel instead
  await orchestrator.cancelIntent(intentHash);
}
```

#### Wrong Intent State

```typescript theme={null}
// Intent must be in SIGNALED state
const intent = await orchestrator.getIntent(intentHash);
const IntentState = {
  NONE: 0,
  SIGNALED: 1,
  FULFILLED: 2,
  CANCELLED: 3
};

assert(intent.state === IntentState.SIGNALED);
```

#### Payment Verification Failed

See [Payment Verification Issues](#payment-verification-issues) section above.

### Cannot Cancel Intent

**Symptoms**: `cancelIntent()` reverts

**Cause**: Intent not yet expired or already fulfilled

**Solution**:

```typescript theme={null}
const intent = await orchestrator.getIntent(intentHash);
const currentTime = Math.floor(Date.now() / 1000);

if (currentTime <= intent.expiryTimestamp) {
  // Wait until expiry before canceling
  const waitTime = intent.expiryTimestamp - currentTime;
  console.log(`Wait ${waitTime} seconds before canceling`);
}
```

## Testing Issues

### Tests Fail with Timeout

**Symptoms**: Tests hang or timeout

**Solutions**:

1. **Increase Timeout**:
   ```typescript theme={null}
   // In test file
   this.timeout(120000); // 2 minutes
   ```

2. **Use Fast Tests**:
   ```bash theme={null}
   yarn test:fast  # Skips slow integration tests
   ```

3. **Run Specific Suite**:
   ```bash theme={null}
   yarn test test/unifiedVerifier/unifiedPaymentVerifier.spec.ts
   ```

### Mock Contract Issues

**Symptoms**: Mock contracts behave unexpectedly

**Solution**: Check mock configuration in test setup

```typescript theme={null}
// Example: Configure mock USDC
usdcToken = await deployer.deployUSDCMock(
  ethers.utils.parseUnits("1000000", 6),
  "USDC",
  "USDC"
);

// Transfer to test accounts
await usdcToken.transfer(maker.address, depositAmount);
await usdcToken.connect(maker.wallet).approve(escrow.address, depositAmount);
```

### Foundry Tests Fail

**Symptoms**: `yarn test:forge` fails

**Solutions**:

1. **Update Foundry**:
   ```bash theme={null}
   foundryup
   ```

2. **Clean Cache**:
   ```bash theme={null}
   forge clean
   forge build
   ```

3. **Check Remappings**:
   ```bash theme={null}
   # Verify remappings in foundry.toml
   cat foundry.toml
   ```

## Integration Issues

### TypeScript Type Errors

**Symptoms**: TypeScript compilation errors with contract types

**Solution**: Regenerate Typechain bindings

```bash theme={null}
# Full rebuild
yarn build

# Or just regenerate types
yarn compile
yarn typechain
```

Types are in `typechain/` directory.

### Contract Address Not Found

**Symptoms**: Cannot find deployed contract address

**Solution**: Check deployment artifacts

```typescript theme={null}
import { getDeployedContractAddress } from "./deployments/helpers";

const orchestratorAddress = getDeployedContractAddress(
  network,
  "Orchestrator"
);
```

Deployment artifacts are in `deployments/{network}/`.

### Event Parsing Fails

**Symptoms**: Cannot parse contract events

**Solution**: Use correct event filter and parsing

```typescript theme={null}
// Listen for IntentSignaled event
const filter = orchestrator.filters.IntentSignaled();
const events = await orchestrator.queryFilter(filter, fromBlock, toBlock);

events.forEach(event => {
  const { intentHash, escrow, depositId } = event.args;
  console.log(`Intent ${intentHash} signaled`);
});
```

### Gas Estimation Fails

**Symptoms**: Transaction reverts during gas estimation

**Solutions**:

1. **Simulate Transaction**:
   ```typescript theme={null}
   // Use callStatic to simulate
   try {
     await orchestrator.callStatic.fulfillIntent({
       intentHash,
       paymentProof,
       data
     });
   } catch (error) {
     console.error("Simulation failed:", error);
   }
   ```

2. **Manual Gas Limit**:
   ```typescript theme={null}
   await orchestrator.fulfillIntent(
     { intentHash, paymentProof, data },
     { gasLimit: 500000 }
   );
   ```

## Registry Permission Issues

### "Caller is not owner"

**Symptoms**: Registry modification reverts with ownership error

**Cause**: Only owner can modify registries

**Solution**:

```typescript theme={null}
// Check current owner
const owner = await paymentVerifierRegistry.owner();

// Transfer ownership if needed (current owner only)
await paymentVerifierRegistry.transferOwnership(newOwner);
```

### "Caller does not have write permission"

**Symptoms**: Cannot write to NullifierRegistry

**Cause**: UnifiedPaymentVerifier needs write permission

**Solution**:

```typescript theme={null}
// Grant write permission (owner only)
await nullifierRegistry.addWritePermission(unifiedVerifierAddress);
```

See deployment script `01_deploy_unified_verifier.ts` for setup example.

## Network-Specific Issues

### Base Network Issues

#### High Gas Prices

**Solution**: Wait for lower gas prices or increase gas budget

```typescript theme={null}
// Check current gas price
const gasPrice = await ethers.provider.getGasPrice();
console.log(`Current gas price: ${ethers.utils.formatUnits(gasPrice, "gwei")} gwei`);
```

#### RPC Rate Limiting

**Solution**: Use dedicated RPC provider or implement retry logic

```typescript theme={null}
// Exponential backoff retry
const retry = async (fn, retries = 3) => {
  for (let i = 0; i < retries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
    }
  }
};
```

### Base Sepolia (Testnet) Issues

#### Insufficient Test ETH

**Solution**: Get test ETH from Base Sepolia faucet

* [Base Sepolia Faucet](https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet)
* [Alchemy Faucet](https://sepoliafaucet.com/)

#### Test USDC Not Available

**Solution**: Deploy mock USDC for testing

```typescript theme={null}
const usdcMock = await deployer.deployUSDCMock(
  ethers.utils.parseUnits("1000000", 6),
  "USDC",
  "USDC"
);
```

## Build & Compilation Issues

### Compilation Fails

**Symptoms**: `yarn compile` fails with Solidity errors

**Solutions**:

1. **Clean Build**:
   ```bash theme={null}
   yarn clean
   yarn compile
   ```

2. **Check Solidity Version**:
   * Contracts require Solidity ^0.8.18
   * Verify `hardhat.config.ts` compiler version

3. **Missing Dependencies**:
   ```bash theme={null}
   # Reinstall dependencies
   rm -rf node_modules
   yarn install
   ```

### Module Not Found

**Symptoms**: Import errors in TypeScript files

**Solution**: Check module aliases in `tsconfig.json`

```json theme={null}
{
  "compilerOptions": {
    "paths": {
      "@utils/*": ["./utils/*"],
      "@typechain/*": ["./typechain/*"]
    }
  }
}
```

## Performance Issues

### Slow RPC Responses

**Solutions**:

1. **Use Protocol Viewer**: Batch queries instead of individual calls
   ```typescript theme={null}
   // Instead of multiple calls
   const deposit1 = await escrow.getDeposit(id1);
   const deposit2 = await escrow.getDeposit(id2);

   // Use Protocol Viewer batching
   const deposits = await protocolViewer.getDeposits(
     escrowAddress,
     [id1, id2]
   );
   ```

2. **Cache Results**: Store frequently accessed data locally

3. **Use Multicall**: Batch multiple read operations

### High Transaction Costs

**Solutions**:

1. **Optimize Data**: Minimize data in transactions
2. **Use Relayers**: For gasless transactions (configure RelayerRegistry)
3. **Batch Operations**: Combine multiple actions when possible

## Getting More Help

If you're still experiencing issues:

1. **Check Test Files**: See `test/` for working examples
2. **Review Deployment Scripts**: See `deploy/` for configuration examples
3. **Read Contract Comments**: Contracts have extensive NatSpec documentation
4. **Check GitHub Issues**: [zkp2p-v2-contracts issues](https://github.com/zkp2p/zkp2p-v2-contracts/issues)
5. **Ask the Community**: Visit [zkp2p.xyz](https://zkp2p.xyz) for community links

### Useful References

* [FAQ](/resources/faq)
* [Supported Payment Methods](/resources/supported-payment-methods)
* [Contract Overview](/contracts/interfaces)
* [API Reference](/contracts/interfaces)
* [Development Guide](/quickstart)
