11import { Router , Response } from "express" ;
2- import { Connection , PublicKey } from "@solana/web3.js" ;
2+ import {
3+ Connection ,
4+ PublicKey ,
5+ ParsedInstruction ,
6+ PartiallyDecodedInstruction ,
7+ } from "@solana/web3.js" ;
38import { AuthenticatedRequest } from "../middleware" ;
49import { treasury_wallet } from "../constants" ;
510import { TierService } from "../services/tier.service" ;
@@ -9,7 +14,7 @@ export const paymentRouter = Router();
914const connection = new Connection ( "https://api.devnet.solana.com" , "confirmed" ) ;
1015
1116// Expected SOL amount for premium upgrade (e.g. 0.1 SOL)
12- const PREMIUM_UPGRADE_LAMPORTS = 0.1 * 1_000_000_000 ;
17+ const PREMIUM_UPGRADE_LAMPORTS = 100_000_000 ;
1318
1419/**
1520 * @swagger
@@ -40,69 +45,100 @@ const PREMIUM_UPGRADE_LAMPORTS = 0.1 * 1_000_000_000;
4045 * 500:
4146 * description: Internal verification error
4247 */
43- paymentRouter . post ( "/verify-upgrade" , async ( req : AuthenticatedRequest , res : Response ) : Promise < any > => {
44- try {
45- const walletAddress = req . walletAddress ;
46- const { signature } = req . body ;
47-
48- if ( ! walletAddress ) {
49- return res . status ( 401 ) . json ( { error : "Unauthorized" } ) ;
50- }
51-
52- if ( ! signature ) {
53- return res . status ( 400 ) . json ( { error : "Transaction signature is required" } ) ;
54- }
55-
56- Logger . info ( `Verifying transaction ${ signature } for wallet ${ walletAddress } ` ) ;
57-
58- // Wait slightly to ensure RPC node has the transaction
59- await new Promise ( resolve => setTimeout ( resolve , 2000 ) ) ;
60-
61- // Fetch transaction details
62- const tx = await connection . getTransaction ( signature , {
63- maxSupportedTransactionVersion : 0 ,
64- commitment : "confirmed" ,
65- } ) ;
66-
67- if ( ! tx || ! tx . meta ) {
68- return res . status ( 400 ) . json ( { error : "Transaction not found or not confirmed" } ) ;
69- }
70-
71- if ( tx . meta . err ) {
72- return res . status ( 400 ) . json ( { error : "Transaction failed on-chain" } ) ;
73- }
74-
75- // Verify it's a transfer to our treasury wallet
76- // Look at postBalances - preBalances to see net change for treasury
77- const accountKeys = tx . transaction . message . getAccountKeys ( ) ;
78-
79- // Find index of treasury wallet
80- const treasuryIndex = accountKeys . staticAccountKeys . findIndex (
81- ( key ) => key . toBase58 ( ) === treasury_wallet
82- ) ;
83-
84- if ( treasuryIndex === - 1 ) {
85- return res . status ( 400 ) . json ( { error : "Treasury wallet not involved in transaction" } ) ;
86- }
87-
88- const preBalance = tx . meta . preBalances [ treasuryIndex ] ;
89- const postBalance = tx . meta . postBalances [ treasuryIndex ] ;
90- const amountReceived = postBalance - preBalance ;
48+ paymentRouter . post (
49+ "/verify-upgrade" ,
50+ async ( req : AuthenticatedRequest , res : Response ) : Promise < any > => {
51+ try {
52+ const walletAddress = req . walletAddress ;
53+ const { signature } = req . body ;
54+
55+ if ( ! walletAddress ) {
56+ return res . status ( 401 ) . json ( { error : "Unauthorized" } ) ;
57+ }
58+
59+ Logger . info ( "Wallet address:" , walletAddress ) ;
60+
61+ if ( ! signature ) {
62+ return res
63+ . status ( 400 )
64+ . json ( { error : "Transaction signature is required" } ) ;
65+ }
66+
67+ Logger . info (
68+ `Verifying transaction ${ signature } for wallet ${ walletAddress } ` ,
69+ ) ;
70+
71+ // Wait slightly to ensure RPC node has the transaction
72+ await new Promise ( ( resolve ) => setTimeout ( resolve , 2000 ) ) ;
73+
74+ // Verify it's a transfer to our treasury wallet
75+ // Look at postBalances - preBalances to see net change for treasury
76+ const parsedTx = await connection . getParsedTransaction ( signature , {
77+ maxSupportedTransactionVersion : 0 ,
78+ commitment : "confirmed" ,
79+ } ) ;
9180
92- if ( amountReceived < PREMIUM_UPGRADE_LAMPORTS ) {
93- return res . status ( 400 ) . json ( {
94- error : "Insufficient payment" ,
95- expected : PREMIUM_UPGRADE_LAMPORTS ,
96- received : amountReceived
81+ if ( ! parsedTx || ! parsedTx . meta ) {
82+ return res . status ( 400 ) . json ( {
83+ error : "Transaction not found or not confirmed" ,
84+ } ) ;
85+ }
86+
87+ if ( parsedTx . meta . err ) {
88+ return res . status ( 400 ) . json ( {
89+ error : "Transaction failed on-chain" ,
90+ } ) ;
91+ }
92+
93+ const instructions = parsedTx . transaction . message . instructions ;
94+
95+ Logger . info ( "Instructions:" , JSON . stringify ( instructions , null , 2 ) ) ;
96+
97+ const transferInstruction = instructions . find (
98+ ( ix ) : ix is ParsedInstruction =>
99+ "parsed" in ix &&
100+ ix . program === "system" &&
101+ ix . parsed ?. type === "transfer" &&
102+ ix . parsed ?. info ?. destination === treasury_wallet ,
103+ ) ;
104+
105+ if ( ! transferInstruction ) {
106+ return res . status ( 400 ) . json ( {
107+ error : "No valid transfer to treasury wallet found" ,
108+ } ) ;
109+ }
110+
111+ const sender = transferInstruction . parsed . info . source ;
112+
113+ if ( sender !== walletAddress ) {
114+ return res . status ( 400 ) . json ( {
115+ error : "Transaction sender mismatch" ,
116+ } ) ;
117+ }
118+
119+ const lamports = Number ( transferInstruction . parsed . info . lamports ) ;
120+
121+ Logger . info ( "Transfer sender:" , sender ) ;
122+ Logger . info ( "Transfer amount:" , lamports ) ;
123+
124+ if ( lamports < PREMIUM_UPGRADE_LAMPORTS ) {
125+ return res . status ( 400 ) . json ( {
126+ error : "Insufficient payment" ,
127+ expected : PREMIUM_UPGRADE_LAMPORTS ,
128+ received : lamports ,
129+ } ) ;
130+ }
131+
132+ // Upgrade the user
133+ await TierService . upgradeUserToPremium ( walletAddress ) ;
134+
135+ return res . json ( {
136+ success : true ,
137+ message : "Upgraded to Premium successfully" ,
97138 } ) ;
139+ } catch ( error ) {
140+ Logger . error ( "Failed to verify transaction:" , error ) ;
141+ return res . status ( 500 ) . json ( { error : "Internal verification error" } ) ;
98142 }
99-
100- // Upgrade the user
101- await TierService . upgradeUserToPremium ( walletAddress ) ;
102-
103- return res . json ( { success : true , message : "Upgraded to Premium successfully" } ) ;
104- } catch ( error ) {
105- Logger . error ( "Failed to verify transaction:" , error ) ;
106- return res . status ( 500 ) . json ( { error : "Internal verification error" } ) ;
107- }
108- } ) ;
143+ } ,
144+ ) ;
0 commit comments