- Rewrite root README.md with proper project overview, tech stack, and repo structure - Remove duplicate CLAUDE.md files (root, onchain, ponder) — AGENTS.md is the standard - Update HARBERG.md to reflect Stage 1 completion and Stage 2 evolution - Delete stale onchain/testing_todos.md (all high-priority items completed) - Update VERSION_VALIDATION.md for VERSION=2 - Trim root AGENTS.md: replace Docker duplication with docs/docker.md reference - Trim onchain/AGENTS.md (129→71 lines): reference TECHNICAL_APPENDIX for formulas - Trim web-app/AGENTS.md (278→55 lines): remove internal API docs, keep architecture - Rewrite onchain/README.md: add contract table, deployment addresses, analysis links - Trim services/ponder/README.md: remove stale subgraph comparison - Add otterscan to docs/docker.md service topology - Update TECHNICAL_APPENDIX.md references Net: -388 lines across documentation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.4 KiB
Version Validation System
Overview
The Kraiken protocol now includes a version validation system that ensures all stack components (contract, indexer, frontend) are synchronized and compatible. This prevents subtle data corruption bugs that arise from version mismatches.
Architecture
┌─────────────────────────────────────┐
│ Kraiken.sol │
│ uint256 public constant VERSION=2 │ ← Source of Truth
└──────────────┬──────────────────────┘
│ read at startup
▼
┌─────────────────────────────────────┐
│ Ponder Indexer │
│ • Reads contract.VERSION() │
│ • Validates against │
│ COMPATIBLE_CONTRACT_VERSIONS │
│ • FAILS HARD if mismatch │
└──────────────┬──────────────────────┘
│ GraphQL
▼
┌─────────────────────────────────────┐
│ Frontend (web-app) │
│ • Checks KRAIKEN_LIB_VERSION │
│ • Shows warning if issues │
│ • Continues operation │
└─────────────────────────────────────┘
Components
1. Contract Version Constant
File: onchain/src/Kraiken.sol
contract Kraiken is ERC20, ERC20Permit {
/**
* @notice Protocol version for data structure compatibility.
* Increment when making breaking changes to TAX_RATES, events, or core data structures.
*/
uint256 public constant VERSION = 2;
// ...
}
Key properties:
public constant= free to read, immutable- Forces contract redeployment on breaking changes
- Single source of truth for the entire stack
2. kraiken-lib Version Tracking
File: kraiken-lib/src/version.ts
export const KRAIKEN_LIB_VERSION = 2;
export const COMPATIBLE_CONTRACT_VERSIONS = [1, 2];
export function isCompatibleVersion(contractVersion: number): boolean {
return COMPATIBLE_CONTRACT_VERSIONS.includes(contractVersion);
}
Key features:
- Manually maintained list (not parsed from contract)
- Allows backward compatibility (lib can support multiple contract versions)
- Exported by
kraiken-lib/src/index.tsfor all consumers
3. Ponder Validation (FAIL HARD)
File: services/ponder/src/helpers/version.ts
export async function validateContractVersion(context: Context): Promise<void> {
const contractVersion = await context.client.readContract({
address: context.contracts.Kraiken.address,
abi: context.contracts.Kraiken.abi,
functionName: 'VERSION',
});
if (!isCompatibleVersion(Number(contractVersion))) {
console.error(getVersionMismatchError(contractVersion, 'ponder'));
process.exit(1); // FAIL HARD
}
}
Called in: services/ponder/src/kraiken.ts (first Transfer event)
Behavior:
- Reads
VERSIONfrom deployed Kraiken contract - Compares against
COMPATIBLE_CONTRACT_VERSIONS - Exits with error if incompatible (prevents indexing wrong data)
- Logs success if compatible
4. Frontend Validation (WARN)
File: web-app/src/composables/useVersionCheck.ts
export function useVersionCheck() {
async function checkVersions(graphqlUrl: string) {
// Currently placeholder - validates lib loaded correctly
// Future: Query Ponder for stored contract version
versionStatus.value = {
isValid: true,
libVersion: KRAIKEN_LIB_VERSION,
};
}
// ...
}
Behavior:
- Validates
KRAIKEN_LIB_VERSIONis loaded - Future enhancement: Query Ponder GraphQL for contract version
- Shows warning banner if mismatch (doesn't break app)
5. CI/CD Validation
File: .woodpecker/release.yml (version-check step)
The Woodpecker release pipeline validates version consistency on tagged releases. The version-check step:
- Builds kraiken-lib (including
sync-tax-rates.mjs) - Runs an inline Node.js script that:
- Extracts
VERSIONfromKraiken.sol - Extracts
KRAIKEN_LIB_VERSIONandCOMPATIBLE_CONTRACT_VERSIONSfromkraiken-lib/src/version.ts - Fails if contract VERSION differs from lib VERSION
- Fails if contract VERSION is not in COMPATIBLE_CONTRACT_VERSIONS
- Extracts
Triggered on: tag events (releases)
Prevents:
- Releasing with incompatible versions
- Deploying with stale kraiken-lib
Workflows
Version Bump (Breaking Change)
When modifying TAX_RATES or other critical data structures:
1. Edit onchain/src/Kraiken.sol
uint256 public constant VERSION = 2; // Increment
2. Edit kraiken-lib/src/version.ts
export const KRAIKEN_LIB_VERSION = 2;
export const COMPATIBLE_CONTRACT_VERSIONS = [2]; // Or [1, 2] for backward compat
3. Rebuild kraiken-lib
./scripts/build-kraiken-lib.sh
4. Clear Ponder state
rm -rf services/ponder/.ponder/
5. Redeploy contracts (if needed)
cd onchain && forge script ...
6. Restart stack
./scripts/dev.sh restart --full
Adding Backward Compatibility
If lib can work with old AND new contract versions:
// kraiken-lib/src/version.ts
export const KRAIKEN_LIB_VERSION = 2;
export const COMPATIBLE_CONTRACT_VERSIONS = [1, 2]; // Supports both
Ponder will accept either v1 or v2 contracts.
Troubleshooting
Ponder fails with "VERSION MISMATCH"
╔════════════════════════════════════════════════════════════╗
║ ❌ CRITICAL: VERSION MISMATCH (ponder)
╠════════════════════════════════════════════════════════════╣
║ Contract VERSION: 2
║ Library VERSION: 1
║ Compatible versions: 1
Fix:
- Check if contract was upgraded
- Update
COMPATIBLE_CONTRACT_VERSIONSinkraiken-lib/src/version.ts - Run
./scripts/build-kraiken-lib.sh - Run
rm -rf services/ponder/.ponder/ - Restart Ponder
CI/CD check fails
❌ Contract VERSION (2) not in COMPATIBLE_CONTRACT_VERSIONS
Fix:
- Update
kraiken-lib/src/version.tsto include new version - Or revert contract changes if unintentional
Benefits
✅ Prevents data corruption - Ponder won't index with wrong schema
✅ Early detection - Fails at startup, not after hours of indexing
✅ Clear errors - Tells you exactly what to do
✅ Backward compat - Can support multiple versions if needed
✅ CI enforcement - Prevents merging incompatible changes
✅ Future-proof - Easy to extend to other contracts (Stake, LiquidityManager)
Future Enhancements
-
Store version in Ponder stats table
- Add
contractVersioncolumn tostats - Frontend can query via GraphQL
- Enables full 3-way validation (contract → Ponder → frontend)
- Add
-
Multi-contract versioning
- Add
VERSIONtoStake.sol,LiquidityManager.sol - Track all contract versions in kraiken-lib
- Validate full deployment is compatible
- Add
-
Version migration helpers
- Scripts to handle data migrations
- Backward-compatible event handling
- Gradual rollout support
Maintenance
When to increment VERSION
Increment when changes affect indexed data or frontend interpretation:
- ✅ Modifying
TAX_RATESarray - ✅ Adding/removing event parameters
- ✅ Changing event names
- ✅ Modifying struct definitions that frontends consume
- ✅ Breaking changes to staking logic
Don't increment for:
- ❌ Gas optimizations (no data changes)
- ❌ Internal logic changes (if events unchanged)
- ❌ Comment updates
- ❌ Pure view function changes
Documentation
Update VERSION comment in contract with each change:
/**
* Version History:
* - v1: Initial deployment (30-tier TAX_RATES)
* - v2: Added new tax tier at 150% (31 tiers total)
* - v3: Modified PositionCreated event (added taxRateIndex field)
*/
uint256 public constant VERSION = 3;
This creates an audit trail for version changes.