@@ -249,8 +249,11 @@ export function BridgeUINew() {
249249
250250 // Calculate fee based on current source amount
251251 const feeInfo = useMemo ( ( ) => {
252- const amount = parseFloat ( sourceAmount ) || 0 ;
253- return getFeeInfo ( amount ) ;
252+ const receiveAmount = parseFloat ( sourceAmount ) ;
253+ const usdcValue = activeSourceToken . symbol !== 'USDC' && sourcePriceInUsdc
254+ ? receiveAmount * sourcePriceInUsdc
255+ : receiveAmount ;
256+ return getFeeInfo ( usdcValue ) ;
254257 } , [ sourceAmount ] ) ;
255258
256259 // Validate form and compute validation error message
@@ -630,185 +633,185 @@ export function BridgeUINew() {
630633 const sourceChainName = 'solana' ;
631634 const destChainName = 'base' ;
632635
633- // Calculate fee based on amount ($0.69 flat or 0.20%)
634- const fee = calculateBridgeFee ( parseFloat ( sourceAmount ) ) . toFixed ( 6 ) ;
635-
636- // Step 1: Create transaction in DB
637- console . info ( '💾 Creating transaction record...' ) ;
638- // Convert amount and fee from display units to base units (6 decimals for USDC)
639- const amountInBaseUnits = ( parseFloat ( sourceAmount ) * 1_000_000 ) . toString ( ) ;
640- const feeInBaseUnits = ( parseFloat ( fee ) * 1_000_000 ) . toString ( ) ;
641-
642- const createResult = await api . createBridgeTransaction ( {
643- sourceChain : sourceChainName ,
644- destinationChain : destChainName ,
645- sourceWallet : sourceWallet . address ,
646- destinationWallet : destAddress ,
647- amount : amountInBaseUnits ,
648- fee : feeInBaseUnits ,
649- selectedDestinationToken : destToken . symbol ,
650- userDestinationWallet : destAddress ,
651- } ) ;
636+ // Calculate fee based on amount ($0.69 flat or 0.20%)
637+ const fee = calculateBridgeFee ( parseFloat ( sourceAmount ) ) . toFixed ( 6 ) ;
652638
653- transactionId = createResult . id ;
654- console . info ( '✅ Transaction created:' , transactionId ) ;
639+ // Step 1: Create transaction in DB
640+ console . info ( '💾 Creating transaction record...' ) ;
641+ // Convert amount and fee from display units to base units (6 decimals for USDC)
642+ const amountInBaseUnits = ( parseFloat ( sourceAmount ) * 1_000_000 ) . toString ( ) ;
643+ const feeInBaseUnits = ( parseFloat ( fee ) * 1_000_000 ) . toString ( ) ;
655644
656- // Step 2: Check if we need to swap source token to USDC first
657- const needsSwap = activeSourceToken . symbol !== 'USDC' ;
658- let burnAmount = sourceAmount ; // Default to source amount (for USDC)
645+ const createResult = await api . createBridgeTransaction ( {
646+ sourceChain : sourceChainName ,
647+ destinationChain : destChainName ,
648+ sourceWallet : sourceWallet . address ,
649+ destinationWallet : destAddress ,
650+ amount : amountInBaseUnits ,
651+ fee : feeInBaseUnits ,
652+ selectedDestinationToken : destToken . symbol ,
653+ userDestinationWallet : destAddress ,
654+ } ) ;
659655
660- if ( needsSwap ) {
661- console . info ( `🔄 Swapping ${ activeSourceToken . symbol } to USDC before burn...` ) ;
662- setCurrentStatus ( `Swapping ${ activeSourceToken . symbol } to USDC` ) ;
663- setProgressStep ( 0 ) ;
656+ transactionId = createResult . id ;
657+ console . info ( '✅ Transaction created:' , transactionId ) ;
664658
665- // Calculate how much extra SOL we need to cover the bridge fee
666- // Bridge fee is in USDC, convert to source token
667- const bridgeFeeInSourceToken = sourcePriceInUsdc ? feeInfo . fee / sourcePriceInUsdc : 0 ;
659+ // Step 2: Check if we need to swap source token to USDC first
660+ const needsSwap = activeSourceToken . symbol !== ' USDC' ;
661+ let burnAmount = sourceAmount ; // Default to source amount (for USDC)
668662
669- // Swap amount = user input + enough to cover bridge fee
670- const swapAmount = parseFloat ( sourceAmount ) + bridgeFeeInSourceToken ;
663+ if ( needsSwap ) {
664+ console . info ( `🔄 Swapping ${ activeSourceToken . symbol } to USDC before burn...` ) ;
665+ setCurrentStatus ( `Swapping ${ activeSourceToken . symbol } to USDC` ) ;
666+ setProgressStep ( 0 ) ;
671667
672- console . info ( `💰 Swapping ${ swapAmount . toFixed ( 6 ) } ${ activeSourceToken . symbol } (includes ${ bridgeFeeInSourceToken . toFixed ( 6 ) } ${ activeSourceToken . symbol } for bridge fee)` ) ;
668+ // Calculate how much extra SOL we need to cover the bridge fee
669+ // Bridge fee is in USDC, convert to source token
670+ const bridgeFeeInSourceToken = sourcePriceInUsdc ? feeInfo . fee / sourcePriceInUsdc : 0 ;
673671
674- // Convert swap amount to lamports (SOL has 9 decimals)
675- const sourceAmountLamports = Math . floor ( swapAmount * 1_000_000_000 ) . toString ( ) ;
672+ // Swap amount = user input + enough to cover bridge fee
673+ const swapAmount = parseFloat ( sourceAmount ) + bridgeFeeInSourceToken ;
676674
677- // Build swap transaction
678- console . info ( '🏗️ Building swap transaction on backend...' ) ;
679- const swapBuildResult = await api . buildSwapTransaction ( {
680- transactionId,
681- sourceWallet : sourceWallet . address ,
682- sourceToken : activeSourceToken . symbol ,
683- amount : sourceAmountLamports ,
684- originalAmount : sourceAmount , // Pass the original user input (e.g., "0.015" for display)
685- } ) ;
675+ console . info ( `💰 Swapping ${ swapAmount . toFixed ( 6 ) } ${ activeSourceToken . symbol } (includes ${ bridgeFeeInSourceToken . toFixed ( 6 ) } ${ activeSourceToken . symbol } for bridge fee)` ) ;
686676
687- console . info ( '✅ Swap transaction built:' , {
688- inputAmount : swapBuildResult . inputAmount ,
689- outputAmount : swapBuildResult . outputAmount ,
690- priceImpact : swapBuildResult . priceImpactPct ,
691- } ) ;
677+ // Convert swap amount to lamports (SOL has 9 decimals)
678+ const sourceAmountLamports = Math . floor ( swapAmount * 1_000_000_000 ) . toString ( ) ;
692679
693- // Calculate burn amount: swap output MINUS the bridge fee
694- // Jupiter returns outputAmount in raw USDC units (6 decimals)
695- const swapOutputUsdc = parseFloat ( swapBuildResult . outputAmount ) / 1_000_000 ;
696- burnAmount = ( swapOutputUsdc - feeInfo . fee ) . toFixed ( 6 ) ;
697- console . info ( `💰 Swap output: ${ swapOutputUsdc . toFixed ( 6 ) } USDC` ) ;
698- console . info ( `💰 Bridge fee: ${ feeInfo . fee . toFixed ( 6 ) } USDC` ) ;
699- console . info ( `💰 Burn amount (output - fee): ${ burnAmount } USDC` ) ;
700-
701- // Deserialize and sign swap transaction (versioned transaction from Jupiter)
702- const { VersionedTransaction } = await import ( '@solana/web3.js' ) ;
703- const swapTx = VersionedTransaction . deserialize (
704- Buffer . from ( swapBuildResult . transaction , 'base64' )
705- ) ;
680+ // Build swap transaction
681+ console . info ( '🏗️ Building swap transaction on backend...' ) ;
682+ const swapBuildResult = await api . buildSwapTransaction ( {
683+ transactionId,
684+ sourceWallet : sourceWallet . address ,
685+ sourceToken : activeSourceToken . symbol ,
686+ amount : sourceAmountLamports ,
687+ originalAmount : sourceAmount , // Pass the original user input (e.g., "0.015" for display)
688+ } ) ;
706689
707- console . info ( '🔐 Requesting wallet signature for swap transaction...' ) ;
708- if ( ! signTransaction ) {
709- throw new Error ( 'Wallet does not support transaction signing' ) ;
710- }
690+ console . info ( '✅ Swap transaction built:' , {
691+ inputAmount : swapBuildResult . inputAmount ,
692+ outputAmount : swapBuildResult . outputAmount ,
693+ priceImpact : swapBuildResult . priceImpactPct ,
694+ } ) ;
711695
712- const signedSwapTx = await signTransaction ( swapTx ) ;
713- console . info ( '✅ Swap transaction signed by wallet' ) ;
696+ // Calculate burn amount: swap output MINUS the bridge fee
697+ // Jupiter returns outputAmount in raw USDC units (6 decimals)
698+ const swapOutputUsdc = parseFloat ( swapBuildResult . outputAmount ) / 1_000_000 ;
699+ burnAmount = ( swapOutputUsdc - feeInfo . fee ) . toFixed ( 6 ) ;
700+ console . info ( `💰 Swap output: ${ swapOutputUsdc . toFixed ( 6 ) } USDC` ) ;
701+ console . info ( `💰 Bridge fee: ${ feeInfo . fee . toFixed ( 6 ) } USDC` ) ;
702+ console . info ( `💰 Burn amount (output - fee): ${ burnAmount } USDC` ) ;
703+
704+ // Deserialize and sign swap transaction (versioned transaction from Jupiter)
705+ const { VersionedTransaction } = await import ( '@solana/web3.js' ) ;
706+ const swapTx = VersionedTransaction . deserialize (
707+ Buffer . from ( swapBuildResult . transaction , 'base64' )
708+ ) ;
709+
710+ console . info ( '🔐 Requesting wallet signature for swap transaction...' ) ;
711+ if ( ! signTransaction ) {
712+ throw new Error ( 'Wallet does not support transaction signing' ) ;
713+ }
714714
715- // Submit swap transaction
716- console . info ( '📤 Submitting signed swap transaction to backend...' ) ;
717- await api . submitSwapTransaction ( {
718- transactionId,
719- signedSwapTransaction : Buffer . from ( signedSwapTx . serialize ( ) ) . toString ( 'base64' ) ,
720- } ) ;
715+ const signedSwapTx = await signTransaction ( swapTx ) ;
716+ console . info ( '✅ Swap transaction signed by wallet' ) ;
721717
722- console . info ( '✅ Swap transaction submitted to backend queue' ) ;
718+ // Submit swap transaction
719+ console . info ( '📤 Submitting signed swap transaction to backend...' ) ;
720+ await api . submitSwapTransaction ( {
721+ transactionId,
722+ signedSwapTransaction : Buffer . from ( signedSwapTx . serialize ( ) ) . toString ( 'base64' ) ,
723+ } ) ;
723724
724- // Poll for swap completion
725- console . info ( '🔄 Polling for swap completion...' ) ;
726- const maxSwapAttempts = 60 ; // 60 attempts × 2 seconds = 2 minutes
727- let swapAttempts = 0 ;
725+ console . info ( '✅ Swap transaction submitted to backend queue' ) ;
728726
729- while ( swapAttempts < maxSwapAttempts ) {
730- await new Promise ( resolve => setTimeout ( resolve , 2000 ) ) ; // Wait 2 seconds
731- swapAttempts ++ ;
727+ // Poll for swap completion
728+ console . info ( '🔄 Polling for swap completion...' ) ;
729+ const maxSwapAttempts = 60 ; // 60 attempts × 2 seconds = 2 minutes
730+ let swapAttempts = 0 ;
732731
733- try {
734- const txStatus = await api . getBridgeTransaction ( transactionId ) ;
735- console . info ( `[SWAP POLL ${ swapAttempts } / ${ maxSwapAttempts } ] Swap Status: ${ txStatus . swapStatus } ` ) ;
732+ while ( swapAttempts < maxSwapAttempts ) {
733+ await new Promise ( resolve => setTimeout ( resolve , 2000 ) ) ; // Wait 2 seconds
734+ swapAttempts ++ ;
736735
737- if ( txStatus . swapStatus === 'completed' ) {
738- console . info ( '✅ Swap completed, proceeding to burn...' ) ;
739- setCurrentStatus ( 'Waiting departure confirmation...' ) ;
740- break ;
741- }
736+ try {
737+ const txStatus = await api . getBridgeTransaction ( transactionId ) ;
738+ console . info ( `[SWAP POLL ${ swapAttempts } /${ maxSwapAttempts } ] Swap Status: ${ txStatus . swapStatus } ` ) ;
739+
740+ if ( txStatus . swapStatus === 'completed' ) {
741+ console . info ( '✅ Swap completed, proceeding to burn...' ) ;
742+ setCurrentStatus ( 'Waiting departure confirmation...' ) ;
743+ break ;
744+ }
742745
743- if ( txStatus . swapStatus === 'failed' ) {
744- throw new Error ( 'Swap transaction failed on-chain' ) ;
746+ if ( txStatus . swapStatus === 'failed' ) {
747+ throw new Error ( 'Swap transaction failed on-chain' ) ;
748+ }
749+ } catch ( pollError ) {
750+ console . error ( 'Error polling swap status:' , pollError ) ;
751+ // Continue polling even if one request fails
745752 }
746- } catch ( pollError ) {
747- console . error ( 'Error polling swap status:' , pollError ) ;
748- // Continue polling even if one request fails
749753 }
750- }
751754
752- if ( swapAttempts >= maxSwapAttempts ) {
753- throw new Error ( 'Swap transaction timeout (2 minutes)' ) ;
755+ if ( swapAttempts >= maxSwapAttempts ) {
756+ throw new Error ( 'Swap transaction timeout (2 minutes)' ) ;
757+ }
754758 }
755- }
756759
757- // Step 3: Generate message account keypair on frontend
758- console . info ( '🔑 Generating message account keypair...' ) ;
759- const { Keypair } = await import ( '@solana/web3.js' ) ;
760- const messageAccount = Keypair . generate ( ) ;
761- console . info ( '✅ Message account generated:' , messageAccount . publicKey . toBase58 ( ) ) ;
762-
763- // Step 3: Build burn transaction on backend (send message account keys for storage)
764- console . info ( '🏗️ Building burn transaction on backend...' ) ;
765- const buildResult = await api . buildBurnTransaction ( {
766- transactionId,
767- sourceWallet : sourceWallet . address ,
768- destinationWallet : destAddress ,
769- amount : burnAmount , // Use burnAmount (either original USDC or swapped USDC amount)
770- messageAccountPublicKey : messageAccount . publicKey . toBase58 ( ) ,
771- messageAccountSecretKey : Array . from ( messageAccount . secretKey ) ,
772- } ) ;
760+ // Step 3: Generate message account keypair on frontend
761+ console . info ( '🔑 Generating message account keypair...' ) ;
762+ const { Keypair } = await import ( '@solana/web3.js' ) ;
763+ const messageAccount = Keypair . generate ( ) ;
764+ console . info ( '✅ Message account generated:' , messageAccount . publicKey . toBase58 ( ) ) ;
765+
766+ // Step 3: Build burn transaction on backend (send message account keys for storage)
767+ console . info ( '🏗️ Building burn transaction on backend...' ) ;
768+ const buildResult = await api . buildBurnTransaction ( {
769+ transactionId,
770+ sourceWallet : sourceWallet . address ,
771+ destinationWallet : destAddress ,
772+ amount : burnAmount , // Use burnAmount (either original USDC or swapped USDC amount)
773+ messageAccountPublicKey : messageAccount . publicKey . toBase58 ( ) ,
774+ messageAccountSecretKey : Array . from ( messageAccount . secretKey ) ,
775+ } ) ;
773776
774- console . info ( '✅ Backend built unsigned transaction' ) ;
777+ console . info ( '✅ Backend built unsigned transaction' ) ;
775778
776- // Step 4: Deserialize and sign with Solana wallet
777- const { Transaction } = await import ( '@solana/web3.js' ) ;
778- const unsignedTx = Transaction . from (
779- Buffer . from ( buildResult . unsignedTransaction , 'base64' )
780- ) ;
779+ // Step 4: Deserialize and sign with Solana wallet
780+ const { Transaction } = await import ( '@solana/web3.js' ) ;
781+ const unsignedTx = Transaction . from (
782+ Buffer . from ( buildResult . unsignedTransaction , 'base64' )
783+ ) ;
781784
782- console . info ( '🔐 Requesting Phantom wallet signature (must sign first)...' ) ;
783- if ( ! signTransaction ) {
784- throw new Error ( 'Wallet does not support transaction signing' ) ;
785- }
785+ console . info ( '🔐 Requesting Phantom wallet signature (must sign first)...' ) ;
786+ if ( ! signTransaction ) {
787+ throw new Error ( 'Wallet does not support transaction signing' ) ;
788+ }
786789
787- // Phantom wallet signs FIRST (per Phantom Lighthouse security requirements)
788- const signedTx = await signTransaction ( unsignedTx ) ;
789- console . info ( '✅ Transaction signed by Phantom wallet' ) ;
790-
791- // Now add message account signature AFTER Phantom signed
792- console . info ( '🔐 Adding message account signature...' ) ;
793- signedTx . partialSign ( messageAccount ) ;
794- console . info ( '✅ Message account signature added (Phantom signed first ✓)' ) ;
795-
796- // Step 4: Serialize fully signed transaction
797- const signedBase64 = Buffer . from (
798- signedTx . serialize ( {
799- requireAllSignatures : false ,
800- verifySignatures : false
801- } )
802- ) . toString ( 'base64' ) ;
803-
804- // Step 5: Submit to backend queue
805- console . info ( '📤 Submitting signed transaction to backend...' ) ;
806- await api . submitBurnTransaction ( {
807- transactionId,
808- signedTransaction : signedBase64 ,
809- } ) ;
790+ // Phantom wallet signs FIRST (per Phantom Lighthouse security requirements)
791+ const signedTx = await signTransaction ( unsignedTx ) ;
792+ console . info ( '✅ Transaction signed by Phantom wallet' ) ;
793+
794+ // Now add message account signature AFTER Phantom signed
795+ console . info ( '🔐 Adding message account signature...' ) ;
796+ signedTx . partialSign ( messageAccount ) ;
797+ console . info ( '✅ Message account signature added (Phantom signed first ✓)' ) ;
798+
799+ // Step 4: Serialize fully signed transaction
800+ const signedBase64 = Buffer . from (
801+ signedTx . serialize ( {
802+ requireAllSignatures : false ,
803+ verifySignatures : false
804+ } )
805+ ) . toString ( 'base64' ) ;
806+
807+ // Step 5: Submit to backend queue
808+ console . info ( '📤 Submitting signed transaction to backend...' ) ;
809+ await api . submitBurnTransaction ( {
810+ transactionId,
811+ signedTransaction : signedBase64 ,
812+ } ) ;
810813
811- console . info ( '✅ Transaction submitted to backend queue' ) ;
814+ console . info ( '✅ Transaction submitted to backend queue' ) ;
812815 } // End of Solana source chain flow
813816
814817 // =========================================================================
0 commit comments