Implement the quadratic funding allocator (Exchange Driver #15) based on Buterin/Hitzig/Weyl's "Liberal Radicalism" (2018). Replace the heuristic "venture funder picks top-N gaps" with an open contribution mechanism where any agent can fund a gap they care about. The central matching pool uses the quadratic formula match = (Σ √cᵢ)² - Σ cᵢ to reward broad consensus over single-whale capture.
gap_funding_contributions table exists with fields: id, timestamp, agent_id, gap_id, amount, tier (direct/match), matching_amount, total_allocationgap_funding_rounds table exists to track matching rounds (round_number, matching_pool_tokens, gaps_funded, status)QuadraticFundingAllocator class implements:contribute_to_gap(agent_id, gap_id, amount) - Record direct contributionscompute_matching_round(pool_size) - Run quadratic matching every 6hget_gap_funding_stats(gap_id) - Get per-gap funding breakdownget_all_gaps_funding() - Get system-wide funding stats
POST /api/gaps/{gap_id}/fund - Contribute tokens to a gapGET /api/gaps/{gap_id}/funding - Get gap funding statsGET /api/gaps/funding/stats - Get all gaps fundingPOST /api/gaps/funding/match - Run matching round (admin only)
gap:{gap_id} escrow--qf-match, --qf-stats, --qf-contributegap_funding_contributions and gap_funding_rounds tablesQuadraticFundingAllocator class in funding_allocators.py:ensure_schema() - Create tables if not existscontribute_to_gap() - Handle direct contributions with token transfer_get_gap_totals() - Compute quadratic formula: (Σ √cᵢ)² - Σ cᵢcompute_matching_round() - Distribute matching pool pro-rata across gapsget_gap_funding_stats() - Per-gap breakdownget_all_gaps_funding() - System-wide stats
api.py:POST /api/gaps/{gap_id}/fund - Authenticated contributionGET /api/gaps/{gap_id}/funding - Public statsGET /api/gaps/funding/stats - Public system statsPOST /api/gaps/funding/match - Admin-only matching trigger
funding_allocators.py for testingtoken_ledger.py - Token transfers and account managementcapital_pools.py - Pool management for matching poolAGENTS.md, /home/ubuntu/Orchestra/AGENTS.md, CLAUDE.md, alignment/gap/artifact planning docs, this task spec, and the economics v2 spec.PYTHONPATH=. python3 -m economics_drivers.quadratic_funding --dry-run --limit 5 reported round 28 with 5 agents funding 1 gap, 100.0 direct + 500.0 matched tokens.economics_drivers/quadratic_funding.py: _get_agent_gaps() used SELECT DISTINCT gap_id, ac_id, which can return the same gap more than once for an agent if they have multiple recent contributions to the same gap. That can debit an agent for duplicate targets while only retaining one per-gap QF contribution in the {gap_id: {agent_id: amount}} accumulator.DEFAULT CURRENT_TIMESTAMP for fallback schema creation.PYTHONPATH=. pytest tests/test_quadratic_funding.py -q passed; python3 -m py_compile economics_drivers/quadratic_funding.py tests/test_quadratic_funding.py passed; live PostgreSQL dry-run passed.PYTHONPATH=. python3 -m economics_drivers.quadratic_funding --limit 20 completed round 28: 20 agents funded 1 gap, 282.5 direct + 500.0 matched tokens, top gap gap-debate-20260417-033236-0fe26d91.fetch, rebase, and git add, so this commit was prepared in a temporary clone under /tmp and pushed to the task branch.For a gap receiving direct contributions [c₁, c₂, ... cₙ] from n contributors:
direct_total = Σ cᵢ
quadratic_total = (Σ √cᵢ)²
match_amount = quadratic_total - direct_totalThis rewards broad consensus: