mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-22 21:47:56 +00:00
4a3694c831
- Replaced shadowColor/shadowOffset/shadowOpacity/shadowRadius with boxShadow - Fixed 28 files (21 screens + 7 components) - Preserved elevation for Android compatibility - All React Native Web deprecation warnings resolved Files fixed: - All screen components - All reusable components - Navigation components - Modal components
311 lines
9.4 KiB
PL/PgSQL
311 lines
9.4 KiB
PL/PgSQL
-- =====================================================
|
|
-- P2P FIAT SYSTEM - RPC FUNCTIONS
|
|
-- Production-grade stored procedures
|
|
-- =====================================================
|
|
|
|
-- =====================================================
|
|
-- INCREMENT ESCROW BALANCE
|
|
-- =====================================================
|
|
CREATE OR REPLACE FUNCTION public.increment_escrow_balance(
|
|
p_token TEXT,
|
|
p_amount NUMERIC
|
|
) RETURNS void AS $$
|
|
BEGIN
|
|
UPDATE public.platform_escrow_balance
|
|
SET
|
|
total_locked = total_locked + p_amount,
|
|
updated_at = NOW()
|
|
WHERE token = p_token;
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Token % not found in escrow balance', p_token;
|
|
END IF;
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
-- =====================================================
|
|
-- DECREMENT ESCROW BALANCE
|
|
-- =====================================================
|
|
CREATE OR REPLACE FUNCTION public.decrement_escrow_balance(
|
|
p_token TEXT,
|
|
p_amount NUMERIC
|
|
) RETURNS void AS $$
|
|
BEGIN
|
|
UPDATE public.platform_escrow_balance
|
|
SET
|
|
total_locked = total_locked - p_amount,
|
|
updated_at = NOW()
|
|
WHERE token = p_token;
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Token % not found in escrow balance', p_token;
|
|
END IF;
|
|
|
|
-- Check for negative balance (should never happen)
|
|
IF (SELECT total_locked FROM public.platform_escrow_balance WHERE token = p_token) < 0 THEN
|
|
RAISE EXCEPTION 'Escrow balance would go negative for token %', p_token;
|
|
END IF;
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
-- =====================================================
|
|
-- UPDATE P2P REPUTATION AFTER TRADE
|
|
-- =====================================================
|
|
CREATE OR REPLACE FUNCTION public.update_p2p_reputation(
|
|
p_seller_id UUID,
|
|
p_buyer_id UUID,
|
|
p_trade_id UUID
|
|
) RETURNS void AS $$
|
|
DECLARE
|
|
v_trade RECORD;
|
|
v_payment_time_minutes INT;
|
|
v_confirmation_time_minutes INT;
|
|
BEGIN
|
|
-- Get trade details
|
|
SELECT * INTO v_trade
|
|
FROM public.p2p_fiat_trades
|
|
WHERE id = p_trade_id;
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Trade % not found', p_trade_id;
|
|
END IF;
|
|
|
|
-- Calculate timing metrics
|
|
IF v_trade.buyer_marked_paid_at IS NOT NULL THEN
|
|
v_payment_time_minutes := EXTRACT(EPOCH FROM (v_trade.buyer_marked_paid_at - v_trade.created_at)) / 60;
|
|
END IF;
|
|
|
|
IF v_trade.seller_confirmed_at IS NOT NULL AND v_trade.buyer_marked_paid_at IS NOT NULL THEN
|
|
v_confirmation_time_minutes := EXTRACT(EPOCH FROM (v_trade.seller_confirmed_at - v_trade.buyer_marked_paid_at)) / 60;
|
|
END IF;
|
|
|
|
-- Update seller reputation
|
|
INSERT INTO public.p2p_reputation (
|
|
user_id,
|
|
total_trades,
|
|
completed_trades,
|
|
total_as_seller,
|
|
reputation_score,
|
|
avg_confirmation_time_minutes,
|
|
last_trade_at,
|
|
first_trade_at
|
|
) VALUES (
|
|
p_seller_id,
|
|
1,
|
|
1,
|
|
1,
|
|
105, -- +5 bonus for first trade
|
|
v_confirmation_time_minutes,
|
|
NOW(),
|
|
NOW()
|
|
)
|
|
ON CONFLICT (user_id) DO UPDATE SET
|
|
total_trades = p2p_reputation.total_trades + 1,
|
|
completed_trades = p2p_reputation.completed_trades + 1,
|
|
total_as_seller = p2p_reputation.total_as_seller + 1,
|
|
reputation_score = LEAST(p2p_reputation.reputation_score + 5, 1000),
|
|
avg_confirmation_time_minutes = CASE
|
|
WHEN p2p_reputation.avg_confirmation_time_minutes IS NULL THEN v_confirmation_time_minutes
|
|
ELSE (p2p_reputation.avg_confirmation_time_minutes + COALESCE(v_confirmation_time_minutes, 0)) / 2
|
|
END,
|
|
last_trade_at = NOW(),
|
|
updated_at = NOW();
|
|
|
|
-- Update buyer reputation
|
|
INSERT INTO public.p2p_reputation (
|
|
user_id,
|
|
total_trades,
|
|
completed_trades,
|
|
total_as_buyer,
|
|
reputation_score,
|
|
avg_payment_time_minutes,
|
|
last_trade_at,
|
|
first_trade_at
|
|
) VALUES (
|
|
p_buyer_id,
|
|
1,
|
|
1,
|
|
1,
|
|
105,
|
|
v_payment_time_minutes,
|
|
NOW(),
|
|
NOW()
|
|
)
|
|
ON CONFLICT (user_id) DO UPDATE SET
|
|
total_trades = p2p_reputation.total_trades + 1,
|
|
completed_trades = p2p_reputation.completed_trades + 1,
|
|
total_as_buyer = p2p_reputation.total_as_buyer + 1,
|
|
reputation_score = LEAST(p2p_reputation.reputation_score + 5, 1000),
|
|
avg_payment_time_minutes = CASE
|
|
WHEN p2p_reputation.avg_payment_time_minutes IS NULL THEN v_payment_time_minutes
|
|
ELSE (p2p_reputation.avg_payment_time_minutes + COALESCE(v_payment_time_minutes, 0)) / 2
|
|
END,
|
|
last_trade_at = NOW(),
|
|
updated_at = NOW();
|
|
|
|
-- Update trust levels based on reputation score
|
|
UPDATE public.p2p_reputation
|
|
SET trust_level = CASE
|
|
WHEN reputation_score >= 900 THEN 'verified'
|
|
WHEN reputation_score >= 700 THEN 'advanced'
|
|
WHEN reputation_score >= 400 THEN 'intermediate'
|
|
WHEN reputation_score >= 100 THEN 'basic'
|
|
ELSE 'new'
|
|
END,
|
|
fast_trader = CASE
|
|
WHEN avg_payment_time_minutes < 15 AND avg_confirmation_time_minutes < 30 THEN true
|
|
ELSE false
|
|
END
|
|
WHERE user_id IN (p_seller_id, p_buyer_id);
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
-- =====================================================
|
|
-- CANCEL EXPIRED TRADES (Cron job function)
|
|
-- =====================================================
|
|
CREATE OR REPLACE FUNCTION public.cancel_expired_trades()
|
|
RETURNS void AS $$
|
|
DECLARE
|
|
v_trade RECORD;
|
|
BEGIN
|
|
-- Cancel trades where buyer didn't pay in time
|
|
FOR v_trade IN
|
|
SELECT * FROM public.p2p_fiat_trades
|
|
WHERE status = 'pending'
|
|
AND payment_deadline < NOW()
|
|
LOOP
|
|
-- Update trade status
|
|
UPDATE public.p2p_fiat_trades
|
|
SET
|
|
status = 'cancelled',
|
|
cancelled_by = seller_id,
|
|
cancellation_reason = 'Payment deadline expired',
|
|
updated_at = NOW()
|
|
WHERE id = v_trade.id;
|
|
|
|
-- Restore offer remaining amount
|
|
UPDATE public.p2p_fiat_offers
|
|
SET
|
|
remaining_amount = remaining_amount + v_trade.crypto_amount,
|
|
status = CASE
|
|
WHEN status = 'locked' THEN 'open'
|
|
ELSE status
|
|
END,
|
|
updated_at = NOW()
|
|
WHERE id = v_trade.offer_id;
|
|
|
|
-- Update reputation (penalty for buyer)
|
|
UPDATE public.p2p_reputation
|
|
SET
|
|
cancelled_trades = cancelled_trades + 1,
|
|
reputation_score = GREATEST(reputation_score - 10, 0),
|
|
updated_at = NOW()
|
|
WHERE user_id = v_trade.buyer_id;
|
|
END LOOP;
|
|
|
|
-- Auto-release trades where seller didn't confirm in time
|
|
FOR v_trade IN
|
|
SELECT * FROM public.p2p_fiat_trades
|
|
WHERE status = 'payment_sent'
|
|
AND confirmation_deadline < NOW()
|
|
LOOP
|
|
-- Mark as completed (auto-release)
|
|
UPDATE public.p2p_fiat_trades
|
|
SET
|
|
seller_confirmed_at = NOW(),
|
|
status = 'completed',
|
|
completed_at = NOW(),
|
|
updated_at = NOW()
|
|
WHERE id = v_trade.id;
|
|
|
|
-- Note: Actual blockchain release must be done by backend service
|
|
-- This just marks the trade as ready for release
|
|
|
|
-- Update reputations
|
|
PERFORM public.update_p2p_reputation(v_trade.seller_id, v_trade.buyer_id, v_trade.id);
|
|
END LOOP;
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
-- =====================================================
|
|
-- CANCEL EXPIRED OFFERS
|
|
-- =====================================================
|
|
CREATE OR REPLACE FUNCTION public.cancel_expired_offers()
|
|
RETURNS void AS $$
|
|
BEGIN
|
|
UPDATE public.p2p_fiat_offers
|
|
SET
|
|
status = 'cancelled',
|
|
updated_at = NOW()
|
|
WHERE status = 'open'
|
|
AND expires_at < NOW();
|
|
|
|
-- Note: Escrow refunds must be processed by backend service
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
-- =====================================================
|
|
-- GET PAYMENT METHOD DETAILS
|
|
-- =====================================================
|
|
CREATE OR REPLACE FUNCTION public.get_payment_method_details(
|
|
p_offer_id UUID,
|
|
p_requesting_user_id UUID
|
|
) RETURNS TABLE(
|
|
method_name TEXT,
|
|
payment_details JSONB
|
|
) AS $$
|
|
DECLARE
|
|
v_offer RECORD;
|
|
v_trade RECORD;
|
|
BEGIN
|
|
-- Get offer
|
|
SELECT * INTO v_offer
|
|
FROM public.p2p_fiat_offers
|
|
WHERE id = p_offer_id;
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Offer not found';
|
|
END IF;
|
|
|
|
-- Check if user is involved in an active trade for this offer
|
|
SELECT * INTO v_trade
|
|
FROM public.p2p_fiat_trades
|
|
WHERE offer_id = p_offer_id
|
|
AND buyer_id = p_requesting_user_id
|
|
AND status IN ('pending', 'payment_sent')
|
|
LIMIT 1;
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Unauthorized: You must have an active trade to view payment details';
|
|
END IF;
|
|
|
|
-- Return decrypted payment details
|
|
RETURN QUERY
|
|
SELECT
|
|
pm.method_name,
|
|
CASE
|
|
WHEN v_offer.payment_details_encrypted IS NOT NULL THEN
|
|
pgsodium.crypto_aead_aes256gcm_decrypt(
|
|
pgsodium.url_decode((v_offer.payment_details_encrypted->>'ciphertext')::TEXT),
|
|
NULL, -- No associated data used in this context
|
|
pgsodium.url_decode((v_offer.payment_details_encrypted->>'nonce')::TEXT),
|
|
pg_catalog.get_secret_variable('app.app_encryption_key')::BYTEA
|
|
)::TEXT::JSONB
|
|
ELSE
|
|
NULL
|
|
END AS payment_details
|
|
FROM public.payment_methods pm
|
|
WHERE pm.id = v_offer.payment_method_id;
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
-- =====================================================
|
|
-- GRANT EXECUTE PERMISSIONS
|
|
-- =====================================================
|
|
GRANT EXECUTE ON FUNCTION public.increment_escrow_balance TO authenticated;
|
|
GRANT EXECUTE ON FUNCTION public.decrement_escrow_balance TO authenticated;
|
|
GRANT EXECUTE ON FUNCTION public.update_p2p_reputation TO authenticated;
|
|
GRANT EXECUTE ON FUNCTION public.cancel_expired_trades TO authenticated;
|
|
GRANT EXECUTE ON FUNCTION public.cancel_expired_offers TO authenticated;
|
|
GRANT EXECUTE ON FUNCTION public.get_payment_method_details TO authenticated;
|