ERC-8004 & ZK Proofs
This layer ensures every Zyfai Agent action is independently verifiable.
By anchoring Zero-Knowledge Proofs (ZKPs) of correct execution to an on-chain identity via the ERC-8004 standard, Zyfai provides cryptographic, non-repudiable proof of honest operation, establishing the trust layer for the agentic economy.
Why This Model?
Trust must be proven, not promised. ZK Proofs allow anyone to verify the correctness of a computation without revealing sensitive strategy details, preventing front-running. ERC-8004 provides the standard ledger to record these proofs, building a public, auditable reputation for each Agent that enables future Agent-to-Agent communication.
How It Works
- Deterministic Execution: A Zyfai Agent's logic is a deterministic set of rules, guaranteeing the same input always produces the same, verifiable output.
- Proof Generation: For each rebalance, the system generates a ZK proof. This proof cryptographically attests that the Agent's action was the exclusive correct output of its rules.
- Simple, Standalone Verification: A dedicated verifier contract checks this proof, returning a definitive "yes" or "no" on the transaction's integrity.
- Onchain Anchoring via ERC-8004: The ZK proof is permanently linked to the Agent's unique onchain identity in the ERC-8004 Validation Registry. This creates a tamper-proof history of verified actions, building a reputation over time.
For Institutions
This elevates audit and compliance. Institutions can cryptographically verify that an Agent has complied with its mandate. It shifts the basis of delegation to mathematically verified onchain evidence, significantly reducing counterparty risk and enabling trust at scale.
Technical Implementation
ERC-8004 ZK Validation Quick Reference
Contract Addresses
Base Sepolia (Chain ID: 84532)
IdentityRegistry: 0x8004A818BFB912233c491871b3d84c89A494BD9e
ReputationRegistry: 0x8004B663056A597Dffe9eCcC1965A193B7388713
RebalancerVerifier: 0x07A1Dc74Ec0C2F3F9e605Ad464A048099793be09
Ethereum Sepolia (Chain ID: 11155111)
IdentityRegistry: 0x8004A818BFB912233c491871b3d84c89A494BD9e
ReputationRegistry: 0x8004B663056A597Dffe9eCcC1965A193B7388713
RebalancerVerifier: 0x752AC7b1b6707399b989a6c5c68EADfcE041eE7C
Circuit Constraints
| # | Constraint | Formula | Purpose |
|---|---|---|---|
| 1 | Liquidity | liquidity * 85 > zyfiTvl * 100 | Sufficient liquidity |
| 2 | TVL | poolTvl * 1e6 > amount * 400 | Max 25% allocation |
| 3 | APY | newApy > oldApy + 10 OR edge cases | 0.1%+ improvement |
| 4 | APY Stability | apyStable7Days == 1 | 7-day stability |
| 5 | TVL Stability | tvlStable == 1 | Pool stability |
Input Scaling
| Field | Scaling | Example |
|---|---|---|
| Liquidity, TVL | ×100 | $100,000.00 → 10000000 |
| APY | ×10000 | 8.0952% → 80952 |
| Amount | Token units | 2.00519 USDC → 2005190 |
| Booleans | 0 or 1 | Stable → 1 |
Public Signals Order (15 signals)
[
liquidity,// 1. Available liquidity (×100)
zyfiTvl,// 2. Zyfai TVL (×100)
amount,// 3. Rebalancer amount (token units)
poolTvl,// 4. Pool TVL (×100)
newApy,// 5. New APY (×10000)
apyStable7Days,// 6. APY stable? (0/1)
tvlStable,// 7. TVL stable? (0/1)
oldApy,// 8. Old APY (×10000)
oldLiquidity,// 9. Old liquidity (×100)
oldZyfiTvl,// 10. Old Zyfai TVL (×100)
oldTvlStable,// 11. Old TVL stable? (0/1)
oldUtilizationStable,// 12. Old utilization stable? (0/1)
oldCollateralHealth,// 13. Old collateral healthy? (0/1)
oldZyfiTVLCheck,// 14. Old Zyfai TVL check? (0/1)
supportsCurrentPool,// 15. Current pool supported? (0/1)
];
Workflow Diagram
Example Proof
IPFS: View Full Proof
Data:
{
"publicSignals":[
"125570357",// $1,255,703.57 liquidity
"10226",// $102.26 Zyfai TVL
"2005190",// 2.00519 USDC
"1016077651",// $10,160,776.51 pool TVL
"80952",// 8.0952% APY
"1",
"1",// APY & TVL stable
"0",
"0",
"0",// No old opportunity
"1",
"1",
"1",
"1",
"1"// All checks pass
],
"verifierAddress":"0x07A1Dc74Ec0C2F3F9e605Ad464A048099793be09",
"chainId":84532
}
- GitHub Repository: Zyfai ERC-8004 Implementation
- ERC-8004 Standard: EIP-8004
- Circuit Source: rebalancer-validation.circom
- Example Proof: IPFS Gateway
- Read the circuit specification for detailed implementation information
- Explore the example proof
- Check the GitHub repository
Zero-Knowledge Circuit Deep Dive
Circuit Overview
The Zyfai Rebalancer Validation Circuit (rebalancer-validation.circom) is a Circom 2.x circuit that validates DeFi rebalancing opportunities against backend constraints using zero-knowledge proofs. The circuit implements the core validation logic from Zyfai's backend, ensuring opportunities meet all safety and performance criteria.
Circuit Properties
- Language: Circom 2.0.0+
- Proof System: Groth16 (efficient on-chain verification)
- Curve: bn128 (bn254)
- Constraints: ~100-200 (includes comparison circuits from circomlib)
- Public Signals: 15 (all inputs are public)
- Private Signals: None (transparency-focused implementation)
Public Inputs
The circuit has 15 public input signals organized into three categories:
New Opportunity Data (7 signals)
These signals describe the rebalancing opportunity being evaluated:
| Signal | Description | Scaling | Example |
|---|---|---|---|
liquidity | Available liquidity in the pool | ×100 (2 decimals) | 10000000 = $100,000.00 |
zyfiTvl | Current Zyfai TVL in the pool | ×100 (2 decimals) | 500000 = $5,000.00 |
amount | Rebalancer deposit amount | Token smallest unit | 1000000 = 1 USDC (6 decimals) |
poolTvl | Total pool TVL | ×100 (2 decimals) | 10000000 = $100,000.00 |
newApy | New opportunity APY | ×10000 (4 decimals) | 54352 = 5.4352% |
apyStable7Days | APY stable over 7 days | Boolean (0 or 1) | 1 = stable |
tvlStable | TVL is stable | Boolean (0 or 1) | 1 = stable |
Old Opportunity Data (7 signals)
These signals describe the previous opportunity (if any) for comparison and edge case handling:
| Signal | Description | Scaling | Default |
|---|---|---|---|
oldApy | Previous opportunity APY | ×10000 (4 decimals) | 0 = no old opportunity |
oldLiquidity | Old opportunity liquidity | ×100 (2 decimals) | 0 = no old opportunity |
oldZyfiTvl | Old opportunity Zyfai TVL | ×100 (2 decimals) | 0 = no old opportunity |
oldTvlStable | Old opportunity TVL stable | Boolean (0 or 1) | 1 = defaults to stable |
oldUtilizationStable | Old opportunity utilization stable | Boolean (0 or 1) | 1 = defaults to stable |
oldCollateralHealth | Old opportunity collateral healthy | Boolean (0 or 1) | 1 = defaults to healthy |
oldZyfiTVLCheck | Old opportunity passes Zyfai TVL check | Boolean (0 or 1) | 1 = defaults to pass |
User Preferences (1 signal)
| Signal | Description | Scaling | Example |
|---|---|---|---|
supportsCurrentPool | Current pool is in user's preferences | Boolean (0 or 1) | 1 = supported |
Validation Constraints
The circuit enforces 5 core validation rules that all must pass for a valid proof:
1. Available Liquidity Check
Rule: liquidity * 0.85 > zyfiTvl
Purpose: Ensures sufficient liquidity to cover the rebalancing amount.
Implementation:
// Avoid floating point: liquidity * 85 > zyfiTvl * 100
signal liquidityLeft <== liquidity * 85;
signal liquidityRight <== zyfiTvl * 100;
component liquidityCheck = GreaterThan(252);
liquidityCheck.in[0] <== liquidityLeft;
liquidityCheck.in[1] <== liquidityRight;
Example:
liquidity = 10,000,000 (scaled: $100,000.00)
zyfiTvl = 500,000 (scaled: $5,000.00)
Check: 10,000,000 × 85 = 850,000,000 > 500,000 × 100 = 50,000,000 ✓
2. TVL Constraint
Rule: poolTvl * 1e6 > amount * 400
Purpose: Prevents excessive allocation. Ensures rebalancer is at most 25% of pool TVL.
Math: amount * (100 / 25) = amount * 4, scaled by 100: poolTvl * 1e6 > amount * 400
Implementation:
signal tvlLeft <== poolTvl * 1000000;
signal tvlRight <== amount * 400;
component tvlCheck = GreaterThan(252);
tvlCheck.in[0] <== tvlLeft;
tvlCheck.in[1] <== tvlRight;
3. APY Performance Check (with Edge Cases)
Rule: newApy > oldApy + 10 OR edge cases
Purpose: Requires meaningful yield improvement (0.1%+) unless bypassed by edge cases.
Edge Cases (APY check bypassed if ANY are true):
- No Old Opportunity:
oldApy == 0(first deposit or no previous opportunity) - Rebalancing from Problematic Pool:
shouldRebalanceFromOld == 1(computed internally) - Pool No Longer Supported:
supportsCurrentPool == 0(user preferences changed)
shouldRebalanceFromOld Computation:
shouldRebalanceFromOld = enoughLiquidity && (
!oldZyfiTVLCheck ||
!oldTvlStable ||
oldLiquidityIsLow ||
!oldUtilizationStable ||
!oldCollateralHealth
)
Where:
- enoughLiquidity = oldLiquidity * 1e6 >= amount
- oldLiquidityIsLow = oldLiquidity * 0.85 < oldZyfiTvl
Implementation:
// Base APY check: newApy > oldApy + 10 (0.1% improvement)
signal apyThreshold <== oldApy + 10;
component apyCheck = GreaterThan(252);
apyCheck.in[0] <== newApy;
apyCheck.in[1] <== apyThreshold;
// Edge case 1: No old opportunity
component oldApyIsZero = IsEqual();
oldApyIsZero.in[0] <== oldApy;
oldApyIsZero.in[1] <== 0;
// Edge case 2: shouldRebalanceFromOld (computed internally)
// ... (see circuit code for full implementation)
// Edge case 3: Pool no longer supported
signal notSupportsCurrentPool <== 1 - supportsCurrentPool;
// APY check passes if ANY are true (OR logic)
signal apyCheckOrSkip <== apyCheckValue + oldApyIsZeroValue +
shouldRebalanceFromOldValue + notSupportsCurrentPool;
component apyCheckFinal = GreaterThan(252);
apyCheckFinal.in[0] <== apyCheckOrSkip;
apyCheckFinal.in[1] <== 0;
Example:
newApy = 120,000 (12.0000%)
oldApy = 100,000 (10.0000%)
supportsCurrentPool = 1
Check: 120,000 > 100,000 + 10 = 100,010 ✓
Result: 2% improvement exceeds 0.1% threshold
4. APY Stability Check
Rule: apyStable7Days == 1
Purpose: Ensures APY has been stable over the past 7 days (prevents volatile pools).
Implementation:
component apyStabilityCheck = IsEqual();
apyStabilityCheck.in[0] <== apyStable7Days;
apyStabilityCheck.in[1] <== 1;
Example:
apyStable7Days = 1
Check: 1 == 1 ✓
Result: APY is stable
5. TVL Stability Check
Rule: tvlStable == 1
Purpose: Verifies pool TVL is stable (prevents pools with unstable liquidity).
Implementation:
component tvlStabilityCheck = IsEqual();
tvlStabilityCheck.in[0] <== tvlStable;
tvlStabilityCheck.in[1] <== 1;
Example:
tvlStable = 1
Check: 1 == 1 ✓
Result: TVL is stable
Constraint Composition
All 5 checks are combined using AND logic (all must pass):
signal check12 <== liquidityCheckValue * tvlCheckValue;
signal check34 <== apyCheckFinalValue * apyStabilityCheckValue;
signal check5 <== tvlStabilityCheckValue;
signal check1234 <== check12 * check34;
signal finalCheck <== check1234 * check5;
// Enforce all checks must pass
finalCheck === 1;
If any constraint fails, witness generation fails and no proof can be generated.
Example Input
{
"liquidity":100000000,
"zyfiTvl":500000,
"amount":1000000,
"poolTvl":100000000,
"newApy":120000,
"apyStable7Days":1,
"tvlStable":1,
"oldApy":100000,
"oldLiquidity":8000000,
"oldZyfiTvl":400000,
"oldTvlStable":1,
"oldUtilizationStable":1,
"oldCollateralHealth":1,
"oldZyfiTVLCheck":1,
"supportsCurrentPool":1
}
Example Output
{
"isValid":1 (or0)
}
Off-chain Checks
More checks are in done off-chain which are not a part of the zk circuit but the above covers all the basic checks that're being proven on-chain.
Security Considerations
Current Implementation
- ✅ All inputs are public signals (transparency-focused)
- ✅ Boolean validation prevents malformed inputs
- ✅ Circom 2.x syntax with explicit public input declaration
- ✅ Comparison circuits from audited circomlib
- ✅ Edge case handling for APY checks
Performance Metrics
| Operation | Time | Gas Cost |
|---|---|---|
| Circuit Compilation | ~30s | - |
| Witness Generation | ~100ms | - |
| Proof Generation | ~500ms | - |
| Off-Chain Verification | ~50ms | - |
| On-Chain Verification | ~50ms | - |