# 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.
