fix: replace Supabase Auth with on-chain sender verification in verify-deposit

Removed JWT auth requirement from edge function. Now uses wallet address
from request body and verifies it matches the on-chain transaction sender.
This works with wallet-based auth instead of Supabase Auth.
This commit is contained in:
2026-02-23 08:49:18 +03:00
parent 35a911ae5f
commit ac18e1b98d
2 changed files with 31 additions and 35 deletions
+2 -1
View File
@@ -173,7 +173,8 @@ export function DepositModal({ isOpen, onClose, onSuccess }: DepositModalProps)
body: { body: {
txHash, txHash,
token, token,
expectedAmount: depositAmount expectedAmount: depositAmount,
walletAddress: selectedAccount?.address
} }
}); });
+29 -34
View File
@@ -38,6 +38,7 @@ interface DepositRequest {
txHash: string txHash: string
token: 'HEZ' | 'PEZ' token: 'HEZ' | 'PEZ'
expectedAmount: number expectedAmount: number
walletAddress: string
} }
// Cache API connection // Cache API connection
@@ -232,45 +233,19 @@ serve(async (req) => {
} }
try { try {
// Get authorization header // Create Supabase service client
const authHeader = req.headers.get('Authorization')
if (!authHeader) {
return new Response(
JSON.stringify({ success: false, error: 'Missing authorization header' }),
{ status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
)
}
// Create Supabase clients
const supabaseUrl = Deno.env.get('SUPABASE_URL')! const supabaseUrl = Deno.env.get('SUPABASE_URL')!
const supabaseAnonKey = Deno.env.get('SUPABASE_ANON_KEY')!
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')! const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
// User client (to get user ID)
const userClient = createClient(supabaseUrl, supabaseAnonKey, {
global: { headers: { Authorization: authHeader } }
})
// Service role client (to process deposit)
const serviceClient = createClient(supabaseUrl, supabaseServiceKey) const serviceClient = createClient(supabaseUrl, supabaseServiceKey)
// Get current user
const { data: { user }, error: userError } = await userClient.auth.getUser()
if (userError || !user) {
return new Response(
JSON.stringify({ success: false, error: 'Unauthorized' }),
{ status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
)
}
// Parse request body // Parse request body
const body: DepositRequest = await req.json() const body: DepositRequest = await req.json()
const { txHash, token, expectedAmount } = body const { txHash, token, expectedAmount, walletAddress } = body
// Validate input // Validate input
if (!txHash || !token || !expectedAmount) { if (!txHash || !token || !expectedAmount || !walletAddress) {
return new Response( return new Response(
JSON.stringify({ success: false, error: 'Missing required fields: txHash, token, expectedAmount' }), JSON.stringify({ success: false, error: 'Missing required fields: txHash, token, expectedAmount, walletAddress' }),
{ status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } } { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
) )
} }
@@ -313,11 +288,11 @@ serve(async (req) => {
const { data: depositRequest, error: requestError } = await serviceClient const { data: depositRequest, error: requestError } = await serviceClient
.from('p2p_deposit_withdraw_requests') .from('p2p_deposit_withdraw_requests')
.upsert({ .upsert({
user_id: user.id, user_id: walletAddress,
request_type: 'deposit', request_type: 'deposit',
token, token,
amount: expectedAmount, amount: expectedAmount,
wallet_address: PLATFORM_WALLET, wallet_address: walletAddress,
blockchain_tx_hash: txHash, blockchain_tx_hash: txHash,
status: 'processing' status: 'processing'
}, { }, {
@@ -358,10 +333,30 @@ serve(async (req) => {
) )
} }
// Verify on-chain sender matches claimed wallet address
if (verification.from !== walletAddress) {
await serviceClient
.from('p2p_deposit_withdraw_requests')
.update({
status: 'failed',
error_message: `Sender mismatch: on-chain sender ${verification.from} does not match claimed wallet ${walletAddress}`,
processed_at: new Date().toISOString()
})
.eq('id', depositRequest.id)
return new Response(
JSON.stringify({
success: false,
error: 'Wallet address does not match the transaction sender'
}),
{ status: 403, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
)
}
// Transaction verified! Process deposit using service role // Transaction verified! Process deposit using service role
const { data: processResult, error: processError } = await serviceClient const { data: processResult, error: processError } = await serviceClient
.rpc('process_deposit', { .rpc('process_deposit', {
p_user_id: user.id, p_user_id: walletAddress,
p_token: token, p_token: token,
p_amount: verification.actualAmount || expectedAmount, p_amount: verification.actualAmount || expectedAmount,
p_tx_hash: txHash, p_tx_hash: txHash,
@@ -397,7 +392,7 @@ serve(async (req) => {
} }
// Success! // Success!
console.log(`Deposit successful: User=${user.id}, Amount=${verification.actualAmount || expectedAmount} ${token}`) console.log(`Deposit successful: Wallet=${walletAddress}, Amount=${verification.actualAmount || expectedAmount} ${token}`)
return new Response( return new Response(
JSON.stringify({ JSON.stringify({