Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 5 additions & 14 deletions internal/migrations/032-order-book-actions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ PUBLIC VIEW RETURNS (market_exists BOOLEAN) {
-- =============================================================================

-- =============================================================================
-- MATCHING ENGINE (Issue 6)
-- MATCHING ENGINE
-- =============================================================================
/**
* The matching engine automatically executes trades by matching compatible orders.
Expand Down Expand Up @@ -1064,7 +1064,6 @@ CREATE OR REPLACE ACTION place_buy_order(
-- ==========================================================================

-- Attempt to match this buy order with existing sell orders
-- Note: This is a stub in Issue 2, full implementation in Issue 6
match_orders($query_id, $outcome, $price);

-- Success: Order placed (may be partially or fully matched by future matching engine)
Expand Down Expand Up @@ -1239,7 +1238,6 @@ CREATE OR REPLACE ACTION place_sell_order(
-- ==========================================================================

-- Attempt to match this sell order with existing buy orders
-- Note: This is a stub in Issue 3, full implementation in Issue 6
match_orders($query_id, $outcome, $price);

-- Success: Order placed (may be partially or fully matched by future matching engine)
Expand Down Expand Up @@ -1273,7 +1271,7 @@ CREATE OR REPLACE ACTION place_sell_order(
* - NO price: 100 - $true_price (e.g., 100 - 56 = 44 cents = $0.44)
* - Total: Always $1.00 per share pair
*
* LP Reward Eligibility (Issue 9 - TO BE IMPLEMENTED):
* LP Reward Eligibility:
*
* To qualify for LP rewards, ALL of the following must be true:
* 1. BOTH buy and sell prices must be within max_spread of market midpoint (50):
Expand All @@ -1290,8 +1288,6 @@ CREATE OR REPLACE ACTION place_sell_order(
* - Split @ $0.56/$0.44: Distance = 6¢ → OUTSIDE spread → NOT qualified ❌
* - Split @ $0.52/$0.48: Distance = 2¢ → WITHIN spread → QUALIFIED ✅
*
* Implementation: LP tracking deferred to Issue 9 (LP rewards and fee distribution)
*
* Examples:
* place_split_limit_order(1, 56, 100) -- Mint 100 pairs: hold YES, sell NO @ $0.44
* place_split_limit_order(1, 35, 50) -- Mint 50 pairs: hold YES, sell NO @ $0.65
Expand Down Expand Up @@ -1453,7 +1449,6 @@ CREATE OR REPLACE ACTION place_split_limit_order(
-- ==========================================================================

-- Attempt to match the NO sell order with existing buy orders
-- Note: This is a stub in Issue 4, full implementation in Issue 6
-- Match is attempted on the FALSE (NO) outcome at the false_price
match_orders($query_id, FALSE, $false_price);

Expand Down Expand Up @@ -1870,7 +1865,7 @@ CREATE OR REPLACE ACTION change_bid(
-- SECTION 9: TRIGGER MATCHING ENGINE
-- ==========================================================================

-- Try to match new order immediately (stub in Issue 5B, full implementation in Issue 6)
-- Try to match new order immediately
-- Note: match_orders expects positive price (1-99), so use $new_abs_price not $new_price
match_orders($query_id, $outcome, $new_abs_price);

Expand Down Expand Up @@ -2119,7 +2114,7 @@ CREATE OR REPLACE ACTION change_ask(
-- SECTION 8: TRIGGER MATCHING ENGINE
-- ==========================================================================

-- Try to match new order immediately (stub in Issue 5B, full implementation in Issue 6)
-- Try to match new order immediately
match_orders($query_id, $outcome, $new_price);

-- Success: Sell order price modified atomically
Expand All @@ -2145,7 +2140,7 @@ CREATE OR REPLACE ACTION change_ask(
*
* After settlement:
* - All trading is permanently blocked (buy, sell, split, cancel, change orders)
* - Users must call claim_payout() to redeem winning shares (Issue 8)
* - Users must call claim_payout() to redeem winning shares
* - Market state is frozen and cannot be changed
*
* Parameters:
Expand All @@ -2163,9 +2158,6 @@ CREATE OR REPLACE ACTION change_ask(
*
* Examples:
* settle_market(1) -- Settle market ID 1 using its attestation
*
* Note: This action is part of Issue 7 (Manual Settlement). Automatic settlement
* via extension (Issue 7B) will call this action on a schedule.
*/
CREATE OR REPLACE ACTION settle_market(
$query_id INT
Expand Down Expand Up @@ -2264,7 +2256,6 @@ CREATE OR REPLACE ACTION settle_market(
settled_at = @block_timestamp
WHERE id = $query_id;

-- Issue 8: Automatic atomic settlement processing
-- Process all payouts, refunds, and fee collection atomically
process_settlement($query_id, $winning_outcome);
};
114 changes: 108 additions & 6 deletions internal/migrations/033-order-book-settlement.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* - Pay winners (shares × $1.00 - 2% redemption fee)
* - Refund open buy orders (no fee)
* - Delete all positions atomically
* - Collect fees in vault (Issue 9 will distribute them)
* - Collect fees in vault
*
* Implementation Note:
* Uses CTE + ARRAY_AGG to collect all payout data in a single query, then
Expand Down Expand Up @@ -55,7 +55,7 @@ CREATE OR REPLACE ACTION ob_batch_unlock_collateral(
};

-- ============================================================================
-- Fee Distribution to Liquidity Providers (Issue 9B)
-- Fee Distribution to Liquidity Providers
-- ============================================================================

/**
Expand All @@ -64,7 +64,7 @@ CREATE OR REPLACE ACTION ob_batch_unlock_collateral(
* Distributes settlement fees to liquidity providers based on sampled rewards.
* Called automatically after winner payouts in process_settlement().
*
* DYNAMIC REWARDS MODEL (Issue 9 Refactor):
* DYNAMIC REWARDS MODEL:
* Uses the ob_rewards table populated by periodic sample_lp_rewards() calls.
* Fees are distributed proportionally across all sampled blocks.
*
Expand All @@ -77,18 +77,27 @@ CREATE OR REPLACE ACTION ob_batch_unlock_collateral(
* This approach minimizes truncation (single point vs per-block) and ensures
* zero fee loss by giving the remainder to the first participant.
*
* AUDIT TRAIL:
* Before deleting ob_rewards, creates immutable records in:
* - ob_fee_distributions: Summary (query_id, total_fees, LP count, timestamp)
* - ob_fee_distribution_details: Per-LP rewards (participant_id, amount, percent)
*
* This ensures full traceability for compliance and user verification.
*
* Parameters:
* - $query_id: Settled market ID
* - $total_fees: Total fees collected (2% of redemptions), in wei
*
* Behavior:
* - No samples → fees remain in vault (safe accumulation)
* - No samples → fees remain in vault (safe accumulation), NO audit record
* - Distributes proportionally across sampled blocks with zero loss
* - Creates audit records in ob_fee_distributions tables
* - Deletes processed rewards from ob_rewards table
*
* Dependencies:
* - ob_rewards table (created in migration 034-order-book-rewards.sql)
* - ob_batch_unlock_collateral() helper (defined above in this migration)
* - ob_rewards table (created in migration 034)
* - ob_fee_distributions tables (created in migration 036)
* - ob_batch_unlock_collateral() helper (defined above)
* - ethereum_bridge.unlock() (from Migration 031)
*/
CREATE OR REPLACE ACTION distribute_fees(
Expand Down Expand Up @@ -175,7 +184,100 @@ CREATE OR REPLACE ACTION distribute_fees(
ob_batch_unlock_collateral($wallet_addresses, $amounts);
}

-- Step 5.5: CREATE AUDIT RECORDS
-- Insert distribution summary and per-LP details BEFORE deleting ob_rewards.
-- This ensures full traceability for compliance and user verification.

-- Only create audit if distribution actually occurred
if $wallet_addresses IS NOT NULL AND COALESCE(array_length($wallet_addresses), 0) > 0 {
-- Generate distribution ID (MAX+1 pattern, safe in Kwil sequential execution)
$distribution_id INT;
for $row in SELECT COALESCE(MAX(id), 0) + 1 as next_id FROM ob_fee_distributions {
$distribution_id := $row.next_id;
}

-- Insert distribution summary
INSERT INTO ob_fee_distributions (
id,
query_id,
total_fees_distributed,
total_lp_count,
block_count,
distributed_at
) VALUES (
$distribution_id,
$query_id,
$total_fees,
COALESCE(array_length($wallet_addresses), 0),
$block_count,
@block_timestamp
);

-- Insert per-LP details
-- Match the distributed amounts (from arrays) with participant data from ob_rewards
-- This creates audit records showing exactly who got what
$idx INT := 1;
for $w_row in SELECT wallet FROM UNNEST($wallet_addresses) AS w(wallet) {
$wallet_hex TEXT := $w_row.wallet;

-- Get corresponding amount (arrays are same length, ordered by participant_id)
$reward_amount NUMERIC(78, 0);
for $a_row in
SELECT amount
FROM UNNEST($amounts) AS a(amount)
LIMIT 1 OFFSET ($idx - 1)
{
$reward_amount := $a_row.amount;
}

-- Get participant info by matching wallet address
$pid INT;
$wallet_bytes BYTEA;
$total_reward_pct NUMERIC(10, 2);

for $p_data in
SELECT
p.id,
p.wallet_address
FROM ob_participants p
WHERE '0x' || encode(p.wallet_address, 'hex') = $wallet_hex
{
$pid := $p_data.id;
$wallet_bytes := $p_data.wallet_address;

-- Calculate total_reward_percent in separate query to avoid type inference issues
$total_reward_pct := 0::NUMERIC(10,2);
for $pct_row in
SELECT SUM(reward_percent::NUMERIC(10,2))::NUMERIC(10,2) as sum_pct
FROM ob_rewards
WHERE query_id = $query_id AND participant_id = $pid
{
if $pct_row.sum_pct IS NOT NULL {
$total_reward_pct := $pct_row.sum_pct;
}
}
}

INSERT INTO ob_fee_distribution_details (
distribution_id,
participant_id,
wallet_address,
reward_amount,
total_reward_percent
) VALUES (
$distribution_id,
$pid,
$wallet_bytes,
$reward_amount,
$total_reward_pct
);

$idx := $idx + 1;
}
}

-- Step 6: Cleanup - delete processed rewards to save storage
-- NOW SAFE: Audit records created above preserve distribution history
DELETE FROM ob_rewards WHERE query_id = $query_id;
};

Expand Down
9 changes: 1 addition & 8 deletions internal/migrations/034-order-book-rewards.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* MIGRATION 034: DYNAMIC LP REWARDS SAMPLING (ISSUE 9 REFACTOR)
* MIGRATION 034: DYNAMIC LP REWARDS SAMPLING
*
* Purpose:
* Store periodic snapshots of liquidity provider reward eligibility.
Expand All @@ -14,13 +14,6 @@
*
* References:
* - Polymarket Rewards: https://docs.polymarket.com/developers/rewards/overview
* - TRUF Spec: /PredictionMarketTasks/OrderbookSetupGoal/orderBookLiquidityRewardsProgram/0mainDoc.md
* - Reference SQL: /PredictionMarketTasks/OrderbookSetupGoal/orderBookLiquidityRewardsProgram/2DynamicRewardsCalculation.md
*
* Related Issues:
* - Task 9R1: Schema Migration + Cleanup (THIS MIGRATION)
* - Task 9R2: Rewards Sampling Implementation (sample_lp_rewards logic)
* - Task 9R3: Settlement Fee Distribution (uses this table)
*/

-- ============================================================================
Expand Down
Loading
Loading