harb/VERSION_VALIDATION.md
openhands de3c8eef94 docs: consolidate and update all documentation for launch readiness
- 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>
2026-02-13 19:22:34 +00:00

271 lines
8.4 KiB
Markdown

# 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`
```solidity
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`
```typescript
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.ts` for all consumers
### 3. Ponder Validation (FAIL HARD)
**File:** `services/ponder/src/helpers/version.ts`
```typescript
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 `VERSION` from 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`
```typescript
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_VERSION` is 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:
1. Builds kraiken-lib (including `sync-tax-rates.mjs`)
2. Runs an inline Node.js script that:
- Extracts `VERSION` from `Kraiken.sol`
- Extracts `KRAIKEN_LIB_VERSION` and `COMPATIBLE_CONTRACT_VERSIONS` from `kraiken-lib/src/version.ts`
- Fails if contract VERSION differs from lib VERSION
- Fails if contract VERSION is not in COMPATIBLE_CONTRACT_VERSIONS
**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:
```bash
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:
```typescript
// 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:**
1. Check if contract was upgraded
2. Update `COMPATIBLE_CONTRACT_VERSIONS` in `kraiken-lib/src/version.ts`
3. Run `./scripts/build-kraiken-lib.sh`
4. Run `rm -rf services/ponder/.ponder/`
5. Restart Ponder
#### CI/CD check fails
```
❌ Contract VERSION (2) not in COMPATIBLE_CONTRACT_VERSIONS
```
**Fix:**
- Update `kraiken-lib/src/version.ts` to 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
1. **Store version in Ponder stats table**
- Add `contractVersion` column to `stats`
- Frontend can query via GraphQL
- Enables full 3-way validation (contract → Ponder → frontend)
2. **Multi-contract versioning**
- Add `VERSION` to `Stake.sol`, `LiquidityManager.sol`
- Track all contract versions in kraiken-lib
- Validate full deployment is compatible
3. **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_RATES` array
- ✅ 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:
```solidity
/**
* 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.