tax rate, version and compose (#70)
resolves #67 Co-authored-by: johba <johba@harb.eth> Reviewed-on: https://codeberg.org/johba/harb/pulls/70
This commit is contained in:
parent
d8ca557eb6
commit
6cbb1781ce
40 changed files with 1243 additions and 213 deletions
279
VERSION_VALIDATION.md
Normal file
279
VERSION_VALIDATION.md
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
# 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=1 │ ← 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 = 1;
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**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 = 1;
|
||||
|
||||
export const COMPATIBLE_CONTRACT_VERSIONS = [1];
|
||||
|
||||
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:** `.github/workflows/validate-version.yml`
|
||||
|
||||
```yaml
|
||||
- name: Extract versions and validate
|
||||
run: |
|
||||
CONTRACT_VERSION=$(grep -oP 'VERSION\s*=\s*\K\d+' onchain/src/Kraiken.sol)
|
||||
LIB_VERSION=$(grep -oP 'KRAIKEN_LIB_VERSION\s*=\s*\K\d+' kraiken-lib/src/version.ts)
|
||||
COMPATIBLE=$(grep -oP 'COMPATIBLE_CONTRACT_VERSIONS\s*=\s*\[\K[^\]]+' kraiken-lib/src/version.ts)
|
||||
|
||||
if echo ",$COMPATIBLE," | grep -q ",$CONTRACT_VERSION,"; then
|
||||
echo "✓ Version sync validated"
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
**Triggered on:**
|
||||
- PRs touching `Kraiken.sol` or `version.ts`
|
||||
- Pushes to `master`/`main`
|
||||
|
||||
**Prevents:**
|
||||
- Merging 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue