Known Issues and Design Decisions
Version: 1.0 Date: December 2025 Status: Pre-Audit
This document tracks known limitations, design trade-offs, and intentional decisions in the Zenpower smart contract system. These are not bugs, but acknowledged constraints that auditors and users should be aware of.
Document Purpose
This document serves to:
- Transparency: Clearly communicate known limitations
- Audit Efficiency: Help auditors focus on unknown issues
- Risk Management: Document accepted risks and rationale
- Future Planning: Track items for future improvement
Important: Items listed here are either:
- Intentional design decisions with known trade-offs
- Acknowledged limitations with mitigation plans
- Low-priority issues deferred to future versions
1. Intentional Design Decisions
1.1 Non-Upgradeable Contracts
Decision: All contracts are deployed without proxy/upgrade patterns
Rationale:
- Trust: Immutability provides stronger security guarantees
- Simplicity: No storage collision or initialization bugs
- Transparency: Code cannot change after deployment
- Philosophy: Commitment to "code is law" principle
Trade-offs:
- ❌ Cannot fix bugs post-deployment
- ❌ Cannot add features without new deployment
- ❌ Migration required for major updates
Mitigation:
- Thorough testing before deployment
- External security audit
- Migration strategy documented
- New contract versions can be deployed
Status: ACCEPTED - Core to trust model
Future Consideration: For v2, may consider minimal upgradeability for configuration only (not core logic)
1.2 Centralized Backend Signer
Decision: TheForge uses single backend signer for attestations
Rationale:
- Simplicity: Easier to implement for v1
- Speed: Single signature verification faster
- Iteration: Allows rapid updates to off-chain verification logic
Trade-offs:
- ❌ Single point of failure
- ❌ Trust in backend operator
- ❌ No redundancy if signer compromised
Mitigation:
- Signer key stored in HSM (planned)
- Monitoring of all signatures
- Emergency pause capability
- Migration to multi-sig planned for v1.1
Status: TEMPORARY - Will be upgraded to multi-sig
Roadmap:
- v1.0: Single signer with HSM
- v1.1: 3-of-5 multi-sig backend
- v2.0: Fully decentralized attestation network
1.3 Off-Chain ZEN$ Currency
Decision: ZEN$ is managed off-chain (database), not on-chain token
Rationale:
- Flexibility: Can adjust economics without gas costs
- Privacy: User balances not public
- Cost: No gas fees for ZEN$ transactions
- UX: Faster transactions, better user experience
Trade-offs:
- ❌ Requires trust in backend database
- ❌ No on-chain proof of ZEN$ balance
- ❌ Centralization risk
Mitigation:
- Backend signature required to burn ZEN$
- Regular balance audits
- Merkle proof system planned
- Migration path to on-chain token exists
Status: ACCEPTED - Intentional hybrid design
Future Consideration: Add Merkle tree of ZEN$ balances published on-chain for verification
1.4 Fixed Forge Path Economics
Decision: Forge paths have fixed ZEN$ costs and ZENCOIN rewards
Rationale:
- Predictability: Users know exact returns
- Fairness: No advantage to timing or market conditions
- Simplicity: Easy to understand and communicate
Trade-offs:
- ❌ No dynamic adjustment for demand
- ❌ May become unbalanced over time
- ❌ Governance required to update
Mitigation:
- Paths can be updated via governance
- Multiple paths provide diversity
- Economic modeling before launch
- Monitoring for gaming/exploitation
Status: ACCEPTED - Can be changed via governance
Future Consideration: Dynamic pricing based on ZENCOIN supply or demand
1.5 Low Governance Quorum (4%)
Decision: Quorum set to 4% of total ZENCOIN supply
Rationale:
- Early Stage: Expected low participation initially
- Activation: Ensures DAO can actually pass proposals
- Progressive: Can be increased as participation grows
Trade-offs:
- ❌ Small minority could control governance
- ❌ Lower security against takeover
- ❌ May not reflect broad consensus
Mitigation:
- 10,000 ZENCOIN proposal threshold
- 7-day voting period for participation
- 48-hour timelock for community reaction
- Quorum can be raised via governance
Status: ACCEPTED - Appropriate for launch phase
Monitoring Plan:
- Track participation rates
- Raise quorum when participation > 10% consistently
- Target 10-15% quorum long-term
1.6 No Vote Locking/Staking Requirement
Decision: ZENCOIN holders can vote without locking tokens
Rationale:
- Accessibility: Lower barrier to participation
- Liquidity: Holders maintain token liquidity
- Flexibility: Can change vote delegation freely
Trade-offs:
- ❌ Vulnerable to flash loan governance attacks (mitigated by delay)
- ❌ No commitment requirement
- ❌ Lower skin-in-the-game
Mitigation:
- 1-day voting delay (snapshot protection)
- Delegation checkpoints prevent same-block attacks
- Timelock provides exit window
- Future staking contract can add incentives
Status: ACCEPTED - Standard OpenZeppelin Governor behavior
Future Consideration: Optional staking contract for enhanced voting power
2. Known Limitations
2.1 Unbounded Array Growth
Issue: userForges[] array grows without limit
Affected Functions:
getForgesForUser()- Returns full array_countActiveForges()- Loops through all forges
Impact:
- May run out of gas with many forges (>100)
- DoS on user's future forge operations
- View functions may fail
Likelihood: LOW - Users limited to 3 concurrent forges
Mitigation (Current):
maxConcurrentForges = 3limits active forges- Economic cost discourages spam
- Off-chain indexing available
Mitigation (Planned):
- Add pagination to view functions
- Implement forge expiration (auto-cleanup)
- Consider mapping-based active count
Status: ACKNOWLEDGED - Low priority, has workarounds
Timeline: Fix in v1.1 if becomes issue
2.2 No Signature Expiration
Issue: Backend signatures have no expiration timestamp
Affected Functions:
startForge()- Accepts signatures indefinitelyclaimForge()- Accepts completion signatures indefinitely
Impact:
- Old signatures could be used much later
- Potential for stale data attack
- No time-bound on signature validity
Likelihood: LOW - forgeId includes timestamp
Mitigation (Current):
- forgeId includes block.timestamp (uniqueness)
- Backend can track used signatures
- Replay protection via forgeId
Mitigation (Planned):
- Add explicit expiration field to signature
- Verify expiration on-chain
- Recommended: 1-hour expiration window
Status: ACKNOWLEDGED - Should be fixed before mainnet
Priority: HIGH
2.3 No Parameter Validation in Path Configuration
Issue: setPathConfig() accepts arbitrary values
Affected Functions:
setPathConfig()- No bounds checking
Impact:
- CONFIG_ROLE could set zenCost = 0
- Could set zencoinReward = MAX_UINT256
- Could set duration = 0
- Breaks economic model
Likelihood: LOW - Requires malicious CONFIG_ROLE
Mitigation (Current):
- CONFIG_ROLE assigned to trusted multisig
- All changes emit events (monitored)
- Community can react via governance
Mitigation (Planned):
function setPathConfig(ForgePath path, PathConfig calldata config) external {
require(config.zenCost >= MIN_ZEN_COST, "Cost too low");
require(config.zenCost <= MAX_ZEN_COST, "Cost too high");
require(config.zencoinReward >= MIN_REWARD, "Reward too low");
require(config.zencoinReward <= MAX_REWARD, "Reward too high");
require(config.duration >= MIN_DURATION, "Duration too short");
require(config.duration <= MAX_DURATION, "Duration too long");
// ... rest of function
}
Status: ACKNOWLEDGED - Should be fixed before mainnet
Priority: CRITICAL
2.4 Pause Has No Time Limit
Issue: Contracts can be paused indefinitely
Affected Contracts:
- ZENCOIN
- TheForge
Impact:
- Complete DoS if pauser malicious or unresponsive
- No automatic unpause mechanism
- DAO voting frozen during ZENCOIN pause
Likelihood: LOW - PAUSER_ROLE is trusted multisig
Mitigation (Current):
- PAUSER_ROLE assigned to Ethics Board multisig
- Multiple signers required
- Community can pressure unpause
Mitigation (Planned):
uint256 public constant MAX_PAUSE_DURATION = 7 days;
uint256 public pausedAt;
function pause() external {
pausedAt = block.timestamp;
_pause();
}
function _requireNotPaused() internal view override {
super._requireNotPaused();
if (paused() && block.timestamp > pausedAt + MAX_PAUSE_DURATION) {
// Auto-unpause after max duration
_unpause();
}
}
Status: ACKNOWLEDGED - Should be added before mainnet
Priority: HIGH
2.5 Single Forge ID Generation Method
Issue: ForgeId uses keccak256(forger, path, timestamp)
Potential Issues:
- Theoretically vulnerable to collision if same user, same path, same block
- Front-running could predict forgeId
- No explicit nonce
Likelihood: VERY LOW - Block timestamps are unique per block
Mitigation (Current):
block.timestampgranularity (seconds) makes collisions unlikely- User can only start one forge per transaction
- Frontend prevents concurrent submissions
Mitigation (Planned):
- Add nonce parameter to forgeId generation
- Use
keccak256(forger, path, timestamp, nonce) - Track nonce per user
Status: ACKNOWLEDGED - Low risk but should be improved
Priority: MEDIUM
2.6 No Minting Rate Limit
Issue: No rate limit on ZENCOIN minting
Affected Functions:
ZENCOIN.forge()- Can be called unlimited times per block
Impact:
- If backend signer compromised, unlimited minting
- No circuit breaker for abnormal minting
- Potential rapid supply drain
Likelihood: LOW - Requires backend compromise
Mitigation (Current):
- Backend implements rate limiting
- Monitoring alerts on abnormal minting
- Pause capability exists
Mitigation (Planned):
uint256 public constant MAX_MINT_PER_HOUR = 10_000 * 10**18;
mapping(uint256 => uint256) public mintedPerHour; // hour => amount
function forge(address to, uint256 amount, bytes32 forgeId) external {
uint256 currentHour = block.timestamp / 1 hours;
require(
mintedPerHour[currentHour] + amount <= MAX_MINT_PER_HOUR,
"Hourly mint limit exceeded"
);
mintedPerHour[currentHour] += amount;
// ... rest of function
}
Status: ACKNOWLEDGED - Defense in depth
Priority: MEDIUM
2.7 No Emergency Admin for Governor
Issue: If governance is broken, no emergency override
Scenario:
- Critical bug found
- Governance vote takes 7 days + 48 hours = 9+ days
- May be too slow for emergency
Likelihood: LOW - Emergency pause exists
Mitigation (Current):
- Pause capability stops damage
- Ethics Board can cancel malicious proposals
- Community can react during timelock
Mitigation (Considered but Rejected):
- Emergency admin role (rejected - too centralized)
- Shorter timelock for emergencies (rejected - security risk)
- Guardian role (may consider for v2)
Status: ACCEPTED - Trade-off for decentralization
Philosophy: Prefer slow but secure over fast but risky
3. Deferred Features
3.1 Signature Malleability Protection
Issue: Raw ecrecover vulnerable to s-value manipulation
Description:
- ECDSA signatures have two valid s-values
- Attacker can flip s-value to create valid alternate signature
- Could bypass signature tracking if implemented naively
Current Status:
- Not exploitable in current design (forgeId prevents replay)
- But non-ideal cryptographic practice
Recommendation:
// Use OpenZeppelin ECDSA library instead
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
function _verifySignature(bytes32 hash, bytes memory sig) internal view {
address recovered = ECDSA.recover(hash, sig);
require(recovered == signer, "Invalid signature");
}
Status: DEFERRED - Not critical but should fix
Priority: HIGH
Timeline: Include in pre-mainnet fixes
3.2 EIP-712 Structured Data Signing
Issue: Using EIP-191 instead of EIP-712 for signatures
Trade-offs:
- EIP-191: Simpler, but less readable
- EIP-712: Better UX (wallet shows readable data), but more complex
Current Status:
- Using EIP-191 with prefix
- Functionally secure but UX could be better
Recommendation:
bytes32 private constant FORGE_TYPEHASH = keccak256(
"Forge(address forger,uint8 path,uint256 zenCommitted,bytes32 forgeId)"
);
function _hashTypedData(bytes32 structHash) internal view returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
Status: DEFERRED - UX improvement for v2
Priority: LOW
Timeline: Consider for v2.0
3.3 Merkle Proof for ZEN$ Balance
Issue: No on-chain proof of ZEN$ balance
Description:
- Users must trust backend's claim of ZEN$ balance
- No way to verify balance independently
- Centralization risk
Proposed Solution:
- Backend publishes Merkle root of all balances weekly
- Users can verify their balance against Merkle root
- On-chain verification during forge start
Status: DEFERRED - Nice to have, not critical
Priority: MEDIUM
Timeline: v1.5 or v2.0
3.4 Batch Operations
Issue: No batch operations for efficiency
Examples:
- Batch claim multiple completed forges
- Batch cancel multiple forges
- Batch delegation
Trade-offs:
- Would save gas for users
- But adds complexity and attack surface
- May enable new DoS vectors
Status: DEFERRED - Optimization for later
Priority: LOW
Timeline: Post-mainnet if user demand
3.5 Forge Transfer/Trading
Issue: Cannot transfer active forge to another address
Scenario:
- User wants to sell incomplete forge
- No mechanism to transfer ownership
- Forge tied to original address
Design Decision:
- Forges are non-transferable by design
- Prevents forge market/speculation
- Maintains "earned, not bought" philosophy
Status: INTENTIONALLY NOT IMPLEMENTED
Future Consideration: Could add transferable forges as separate contract
4. Testnet-Only Issues
4.1 Timestamp Manipulation on Testnets
Issue: Testnet validators can manipulate timestamps
Impact:
- Could claim forges early
- Could game voting delays
- Not representative of mainnet
Mitigation:
- Only affects testing
- Mainnet timestamp manipulation limited (±15 seconds tolerance)
- Forge durations (7-60 days) make ±15 seconds irrelevant
Status: TESTNET ONLY - Not applicable to mainnet
4.2 Low Proposal Threshold for Testing
Issue: Testing with 10,000 ZENCOIN threshold is impractical
Solution:
- Testnet deployment may use lower threshold (e.g., 100 ZENCOIN)
- Documented clearly in deployment scripts
- Mainnet deployment uses documented values
Status: EXPECTED - Different config for testnet
5. Documentation Gaps
5.1 Migration Strategy Not Documented
Issue: No documented process for v1 → v2 migration
Impact:
- Unclear how to upgrade if non-upgradeable
- Users don't know migration process
- Risk of confusion or loss
Planned Documentation:
- Token migration process (snapshot + claim)
- Forge completion process before migration
- Treasury transfer process
- Governance coordination
Status: ACKNOWLEDGED - Documentation needed
Priority: MEDIUM
Timeline: Before mainnet launch
5.2 Emergency Procedures Not Documented
Issue: No runbook for emergency scenarios
Needed Documentation:
- When to pause contracts
- How to coordinate pause across contracts
- Emergency communication templates
- Incident response procedures
- Recovery processes
Status: ACKNOWLEDGED - Critical for operations
Priority: HIGH
Timeline: Before mainnet launch
5.3 Economic Model Not Fully Analyzed
Issue: No formal game theory analysis of forge paths
Questions:
- Are paths balanced?
- Can users game the system?
- What's optimal strategy?
- How does it scale?
Planned Analysis:
- Monte Carlo simulation of user strategies
- Nash equilibrium analysis
- Scaling projections
- Sensitivity analysis
Status: ACKNOWLEDGED - Should complete before launch
Priority: HIGH
Timeline: During audit period
6. External Dependencies
6.1 OpenZeppelin Contract Updates
Issue: Using OpenZeppelin Contracts v5.x
Considerations:
- New vulnerabilities may be discovered
- Updates may be released
- We cannot upgrade (non-upgradeable design)
Mitigation:
- Using stable release (not beta)
- OpenZeppelin contracts are battle-tested
- External audit will review OZ usage
- Monitor OpenZeppelin security advisories
Status: ACCEPTED - Standard dependency risk
Monitoring: Subscribe to OpenZeppelin security announcements
6.2 Solidity Compiler Version
Issue: Using Solidity ^0.8.20
Considerations:
- Newer versions may have bug fixes
- Older versions may have known issues
- Specific version should be pinned for deployment
Mitigation:
- 0.8.20 is stable release
- No known critical bugs in 0.8.20+
- Will pin exact version for mainnet deployment
Status: ACCEPTED - Will pin to 0.8.24 for mainnet
Action: Update pragma solidity 0.8.24; (exact version) before deployment
6.3 EVM Chain Assumptions
Issue: Assumes Ethereum mainnet behavior
Considerations:
- Other chains (L2s, sidechains) may behave differently
- Block time variations
- Gas cost differences
- Opcode availability
Current Support:
- Designed for Ethereum mainnet
- Should work on most EVM chains
- May need adjustments for non-EVM or special chains
Status: ACCEPTED - Ethereum mainnet primary target
Future: Test on target L2s before any multi-chain deployment
7. Trade-off Summary
| Decision | Benefit | Cost | Status |
|---|---|---|---|
| Non-upgradeable | Immutability, trust | Cannot fix bugs | ACCEPTED |
| Single signer | Simplicity, speed | Centralization | TEMPORARY |
| Off-chain ZEN$ | Privacy, flexibility | Trust required | ACCEPTED |
| Fixed economics | Predictability | No dynamic adjustment | ACCEPTED |
| Low quorum (4%) | Early activation | Lower security | TEMPORARY |
| No vote locking | Accessibility | Flash loan risk (low) | ACCEPTED |
| Unbounded arrays | Simplicity | Potential DoS | ACKNOWLEDGED |
| No param validation | Trust in admin | Potential misconfiguration | TO FIX |
| No pause limit | Flexibility | Potential abuse | TO FIX |
8. Pre-Mainnet Checklist
Must be resolved before mainnet:
- Add parameter validation to
setPathConfig() - Implement signature nonce-based replay protection
- Migrate to OpenZeppelin ECDSA library
- Add maximum pause duration
- Document migration strategy
- Create emergency runbook
- Complete economic analysis
- Implement multi-sig backend (or document single-signer HSM setup)
- Add signature expiration checking
- Pin exact Solidity version (0.8.24)
Should be resolved before mainnet:
- Add pagination for unbounded arrays
- Implement forge expiration
- Add minting rate limits
- Improve forgeId generation with nonce
- Comprehensive test coverage (95%+)
- Attack scenario testing
- Testnet deployment and testing
- External audit completion
9. Disclosure Policy
This document is:
- Public: Will be published with audit
- Living: Updated as new issues discovered
- Transparent: Honest about limitations
Updates:
- Major updates: Version increment (1.0 → 2.0)
- Minor updates: Revision date
- All changes tracked in git
Responsibility:
- Security team maintains document
- Community can submit issues/PRs
- Auditors review for completeness
10. Conclusion
Summary
This document tracks 27 items across categories:
| Category | Count | Critical | High | Medium | Low |
|---|---|---|---|---|---|
| Design Decisions | 7 | 0 | 0 | 0 | 7 |
| Known Limitations | 7 | 1 | 3 | 2 | 1 |
| Deferred Features | 5 | 0 | 1 | 2 | 2 |
| Documentation Gaps | 3 | 0 | 2 | 1 | 0 |
| Dependencies | 3 | 0 | 0 | 3 | 0 |
Critical/High Items Requiring Action: 7 Medium Priority Items: 8 Low Priority / Accepted Trade-offs: 12
Transparency Commitment
We believe in radical transparency about security:
- We document what we know we don't know
- We acknowledge trade-offs honestly
- We communicate limitations clearly
- We commit to continuous improvement
This document demonstrates:
- Security-first mindset
- Honest assessment of risks
- Clear prioritization
- Actionable roadmap
Auditor Notes
Dear Auditors,
This document is provided to help you focus your efforts on unknown issues. We have:
- Identified known limitations and design decisions
- Analyzed trade-offs and rationale
- Prioritized items for remediation
- Committed to pre-mainnet fixes
Please:
- Verify our assessment of known issues
- Identify issues we missed
- Evaluate our prioritization
- Recommend additional mitigations
We want your independent assessment, not validation of our assumptions.
Document Version: 1.0 Last Updated: December 2025 Next Review: After external audit Maintained By: Zenpower Security Team
"The first step in fixing a problem is acknowledging it exists."