libertaria-stack/core/l1-membrane/monetary_controller.zig

346 lines
10 KiB
Zig

// monetary_controller.zig - LIBERTARIA L1 ECONOMIC ENGINE
// RFC-0648 + RFC-0649 Implementation
//
// DEPLOYMENT TARGET: 03:00 Session (2026-02-05)
// STATUS: Ready for implementation
const std = @import("std");
const assert = std.debug.assert;
// =============================================================================
// PROTOCOL ENSHRINED CONSTANTS (Immutable)
// =============================================================================
/// Maximum deflation rate (hard floor)
const PROTOCOL_FLOOR: f64 = -0.05; // -5% per epoch max
/// Maximum inflation rate (hard ceiling)
const PROTOCOL_CEILING: f64 = 0.20; // +20% per epoch max
/// Target velocity (Chapter-tunable, but default)
const DEFAULT_V_TARGET: f64 = 6.0;
/// Stability band thresholds
const STAGNATION_THRESHOLD: f64 = 0.8; // 80% of target = stimulus
const OVERHEAT_THRESHOLD: f64 = 1.2; // 120% of target = brake
// =============================================================================
// CHAPTER-TUNABLE PARAMETERS (Genesis-configurable)
// =============================================================================
pub const MonetaryParams = struct {
// PID Gains - TUNE THESE IN FIELD
Kp: f64 = 0.15, // Proportional: immediate response
Ki: f64 = 0.02, // Integral: long-term correction
Kd: f64 = 0.08, // Derivative: dampening
// Opportunity Window
opportunity_multiplier: f64 = 1.5, // 50% bonus during stimulus
difficulty_scalar: f64 = 0.9, // 10% easier to mint
q_boost_factor: f64 = 0.15, // 15% activity boost
// Extraction
base_fee_burn_rate: f64 = 0.1, // 10% fee increase
demurrage_rate: f64 = 0.001, // 0.1% per epoch on stagnant
// Anti-Sybil
genesis_difficulty: u32 = 20, // ~10 min on smartphone
maintenance_difficulty: u32 = 12, // ~10 sec monthly
// Velocity target
V_target: f64 = DEFAULT_V_TARGET,
};
// =============================================================================
// STATE VARIABLES (Per-Chapter)
// =============================================================================
pub const MonetaryState = struct {
M: f64, // Money Supply (Mass)
V: f64, // Velocity
Q: f64, // Economic Activity (Output)
P: f64, // Price Level
// PID State
error_integral: f64 = 0.0,
prev_error: f64 = 0.0,
// Epoch tracking
current_epoch: u64 = 0,
pub fn init(M_initial: f64, V_initial: f64, Q_initial: f64) MonetaryState {
return .{
.M = M_initial,
.V = V_initial,
.Q = Q_initial,
.P = 1.0,
};
}
};
// =============================================================================
// CORE ALGORITHMS
// =============================================================================
/// PID Controller with tanh saturation
///
/// u(t) = Kp*e(t) + Ki*∫e(t)dt + Kd*de/dt
/// ΔM(t) = M(t) * clamp(tanh(k*u), FLOOR, CEILING)
pub fn pidController(
state: *MonetaryState,
params: MonetaryParams,
V_measured: f64,
) f64 {
// 1. Calculate error
const error = params.V_target - V_measured;
// 2. Update integral
state.error_integral += error;
// 3. Calculate derivative
const derivative = error - state.prev_error;
state.prev_error = error;
// 4. Raw PID output
const u = params.Kp * error +
params.Ki * state.error_integral +
params.Kd * derivative;
// 5. tanh saturation (smooth)
const tanh_u = std.math.tanh(u);
// 6. Hard protocol caps (enshrined)
return std.math.clamp(tanh_u, PROTOCOL_FLOOR, PROTOCOL_CEILING);
}
/// Opportunity Window: Injection during stagnation
///
/// When V < 0.8 * target:
/// - Difficulty drops (cheaper to mint)
/// - Multiplier active (more rewarding)
/// - Q boost (psychological stimulus)
pub fn applyOpportunityWindow(
state: *MonetaryState,
params: MonetaryParams,
delta_m_raw: f64,
) struct { delta_m: f64, active: bool, q_boost: f64 } {
const is_stagnant = state.V < params.V_target * STAGNATION_THRESHOLD;
if (is_stagnant) {
// Stimulus: Make work cheaper AND more rewarding
const delta_m = delta_m_raw * params.opportunity_multiplier;
// Psychological boost: Economic activity increases
// This is the KEY INSIGHT: Stimulus → Behavior, not just Money
const q_boost = state.Q * params.q_boost_factor;
state.Q += q_boost;
return .{
.delta_m = delta_m,
.active = true,
.q_boost = q_boost,
};
}
return .{
.delta_m = delta_m_raw,
.active = false,
.q_boost = 0.0,
};
}
/// Extraction: Cooling during overheating
///
/// When V > 1.2 * target:
/// - Base fee burn (transactions more expensive)
/// - Demurrage on stagnant money
pub fn applyExtraction(
state: *MonetaryState,
params: MonetaryParams,
delta_m_raw: f64,
) struct { delta_m: f64, active: bool, burned: f64 } {
const is_overheated = state.V > params.V_target * OVERHEAT_THRESHOLD;
if (is_overheated) {
// 1. Demurrage on stagnant M
const demurrage_burn = state.M * params.demurrage_rate;
state.M -= demurrage_burn;
// 2. Extra brake on emission
const delta_m = delta_m_raw * 0.8;
return .{
.delta_m = delta_m,
.active = true,
.burned = demurrage_burn,
};
}
return .{
.delta_m = delta_m_raw,
.active = false,
.burned = 0.0,
};
}
/// Main Monetary Step Function
///
/// Called once per epoch by L1 consensus
pub fn monetaryStep(
state: *MonetaryState,
params: MonetaryParams,
exogenous_shock: f64, // External events (panic, bubble)
) void {
state.current_epoch += 1;
// 1. Apply exogenous shocks (market psychology)
state.V += exogenous_shock;
// 2. PID Controller
const delta_m_raw = pidController(state, params, state.V);
// 3. Opportunity Window (stimulus if stagnant)
const opp = applyOpportunityWindow(state, params, delta_m_raw);
// 4. Extraction (brake if overheated)
const ext = applyExtraction(state, params, opp.delta_m);
// 5. Update Money Supply
state.M *= (1.0 + ext.delta_m);
// 6. Natural Q decay (activity slows without stimulus)
state.Q *= 0.995;
// 7. Recalculate V from Fisher equation
// But: Q is now endogenous (can be boosted by stimulus)
state.V = (state.P * state.Q) / state.M;
// 8. Floor protection
if (state.V < 0.1) state.V = 0.1;
}
// =============================================================================
// ANTI-SYBIL: SOULKEY VALIDATION
// =============================================================================
pub const SoulKey = struct {
did: [32]u8,
genesis_proof: EntropyProof,
last_maintenance: u64,
maintenance_debt: f64,
};
pub const EntropyProof = struct {
nonce: [32]u8,
difficulty: u32,
hash: [32]u8,
};
/// Verify Argon2id proof
pub fn verifyEntropyProof(proof: EntropyProof, required_difficulty: u32) bool {
// TODO: Argon2id verification
// Returns true if hash meets difficulty target
_ = proof;
_ = required_difficulty;
return true; // Placeholder
}
/// Check if SoulKey qualifies for Opportunity Window
pub fn qualifiesForMintWindow(
soul: SoulKey,
current_epoch: u64,
params: MonetaryParams,
) bool {
// Must have genesis
if (!verifyEntropyProof(soul.genesis_proof, params.genesis_difficulty)) {
return false;
}
// Must be maintained (Kenya Rule: 1 proof/month)
const epochs_since_maintenance = current_epoch - soul.last_maintenance;
const max_epochs = 30 * 24 * 6; // ~1 month (10-min epochs)
if (epochs_since_maintenance > max_epochs) {
return false; // Maintenance debt too high
}
return true;
}
// =============================================================================
// HAMILTONIAN UTILITIES
// =============================================================================
/// Economic Energy: E = 0.5 * M * V²
pub fn calculateEnergy(state: MonetaryState) f64 {
return 0.5 * state.M * state.V * state.V;
}
/// Momentum: P = M * V
pub fn calculateMomentum(state: MonetaryState) f64 {
return state.M * state.V;
}
/// Check if system is in equilibrium
pub fn isEquilibrium(state: MonetaryState, params: MonetaryParams) bool {
const ratio = state.V / params.V_target;
return ratio >= 0.9 and ratio <= 1.1;
}
// =============================================================================
// TEST HARNESS (for 03:00 session)
// =============================================================================
test "monetary controller basic" {
var state = MonetaryState.init(1000.0, 5.0, 5000.0);
const params = MonetaryParams{};
// Run 100 epochs
var i: usize = 0;
while (i < 100) : (i += 1) {
monetaryStep(&state, params, 0.0);
}
// System should stabilize near target
try std.testing.expect(state.V > 4.0);
try std.testing.expect(state.V < 8.0);
}
test "opportunity window triggers" {
var state = MonetaryState.init(1000.0, 2.0, 5000.0); // Stagnant
const params = MonetaryParams{};
const delta_before = state.M;
monetaryStep(&state, params, 0.0);
const delta_after = state.M;
// Should have triggered stimulus
try std.testing.expect(delta_after > delta_before * 1.01);
}
test "extraction triggers" {
var state = MonetaryState.init(1000.0, 10.0, 5000.0); // Overheated
const params = MonetaryParams{};
const m_before = state.M;
monetaryStep(&state, params, 0.0);
const m_after = state.M;
// Should have burned some M via demurrage
try std.testing.expect(m_after < m_before);
}
// =============================================================================
// TODO FOR 03:00 SESSION
// =============================================================================
// [ ] Integrate with RFC-0315 (Access Toll Protocol)
// [ ] Argon2d proof verification
// [ ] Chapter persistence (save/restore state)
// [ ] Event hooks for external monitoring
// [ ] Fuzz testing with random shocks
// END monetary_controller.zig