1- // Update the import - use the correct way to access freighter
2- declare global {
3- interface Window {
4- freighter ?: any ;
5- }
6- }
1+ /**
2+ * @file freighter.ts
3+ * @description Centralized Freighter wallet service leveraging the official `@stellar/freighter-api` package.
4+ */
5+
6+ import {
7+ isConnected as freighterIsConnected ,
8+ getAddress as freighterGetAddress ,
9+ signTransaction as freighterSignTransaction ,
10+ requestAccess as freighterRequestAccess ,
11+ getNetwork as freighterGetNetwork
12+ } from '@stellar/freighter-api' ;
713
814export interface FreighterWallet {
915 isConnected : ( ) => Promise < boolean > ;
@@ -17,75 +23,115 @@ export class FreighterService {
1723
1824 private constructor ( ) { }
1925
26+ /**
27+ * Retrieves the singleton instance of the FreighterService.
28+ * @returns {FreighterService } The singleton service instance.
29+ */
2030 public static getInstance ( ) : FreighterService {
2131 if ( ! FreighterService . instance ) {
2232 FreighterService . instance = new FreighterService ( ) ;
2333 }
2434 return FreighterService . instance ;
2535 }
2636
27- private async getFreighter ( ) : Promise < any > {
28- // Check if freighter is available
29- if ( typeof window === 'undefined' ) {
30- throw new Error ( 'Window is not defined' ) ;
31- }
32-
33- // Freighter injects itself into the window object
34- if ( ! window . freighter ) {
35- throw new Error ( 'Freighter wallet is not installed' ) ;
36- }
37-
38- return window . freighter ;
39- }
40-
37+ /**
38+ * Checks if the Freighter wallet extension is installed and accessible.
39+ * @returns {Promise<boolean> } True if connected/available.
40+ */
4141 async isInstalled ( ) : Promise < boolean > {
4242 try {
4343 if ( typeof window === 'undefined' ) return false ;
44- return ! ! window . freighter ;
44+ const response = await freighterIsConnected ( ) ;
45+
46+ if ( typeof response === 'object' && response !== null && 'isConnected' in response ) {
47+ return Boolean ( ( response as any ) . isConnected ) ;
48+ }
49+ return Boolean ( response ) ;
4550 } catch ( error ) {
4651 return false ;
4752 }
4853 }
4954
55+ /**
56+ * Requests access to the Freighter wallet and retrieves the user's public address.
57+ * @returns {Promise<string> } The public key address.
58+ */
5059 async connect ( ) : Promise < string > {
5160 try {
52- const freighter = await this . getFreighter ( ) ;
53-
54- // Enable freighter
55- await freighter . enable ( ) ;
61+ const connected = await this . isInstalled ( ) ;
62+ if ( ! connected ) {
63+ await freighterRequestAccess ( ) ;
64+ }
5665
57- // Get public key
58- const publicKey = await freighter . getPublicKey ( ) ;
66+ const response = await freighterGetAddress ( ) ;
67+ let publicKey = '' ;
68+
69+ if ( typeof response === 'object' && response !== null && 'address' in response ) {
70+ publicKey = String ( ( response as any ) . address || '' ) ;
71+ } else {
72+ publicKey = String ( response || '' ) ;
73+ }
74+
75+ if ( ! publicKey ) {
76+ throw new Error ( 'No public key returned from Freighter wallet.' ) ;
77+ }
5978
6079 return publicKey ;
6180 } catch ( error : any ) {
62- throw new Error ( `Failed to connect to Freighter: ${ error . message } ` ) ;
81+ throw new Error ( `Failed to connect to Freighter: ${ error . message || error } ` ) ;
6382 }
6483 }
6584
85+ /**
86+ * Retrieves the current Stellar network from Freighter.
87+ * @returns {Promise<string> } The lowercase network identifier.
88+ */
6689 async getNetwork ( ) : Promise < string > {
6790 try {
68- const freighter = await this . getFreighter ( ) ;
69- const network = await freighter . getNetwork ( ) ;
70- return network . toLowerCase ( ) ; // Convert to lowercase for consistency
91+ const response = await freighterGetNetwork ( ) ;
92+ let networkStr = '' ;
93+
94+ if ( typeof response === 'object' && response !== null ) {
95+ networkStr = String ( ( response as any ) . network || ( response as any ) . id || '' ) ;
96+ } else {
97+ networkStr = String ( response || '' ) ;
98+ }
99+
100+ return ( networkStr || 'testnet' ) . toLowerCase ( ) ;
71101 } catch ( error ) {
72102 throw new Error ( 'Failed to get network from Freighter' ) ;
73103 }
74104 }
75105
106+ /**
107+ * Signs a transaction XDR string using Freighter.
108+ * @param {string } xdr - The transaction XDR payload.
109+ * @returns {Promise<string> } Signed transaction XDR.
110+ */
76111 async signTransaction ( xdr : string ) : Promise < string > {
77112 try {
78- const freighter = await this . getFreighter ( ) ;
79113 const network = await this . getNetwork ( ) ;
80-
81- const signedXdr = await freighter . signTransaction ( xdr , {
82- network,
83- accountToSign : await freighter . getPublicKey ( ) ,
84- } ) ;
85-
86- return signedXdr ;
114+ const addressResp = await freighterGetAddress ( ) ;
115+ let publicKey = '' ;
116+
117+ if ( typeof addressResp === 'object' && addressResp !== null && 'address' in addressResp ) {
118+ publicKey = String ( ( addressResp as any ) . address || '' ) ;
119+ } else {
120+ publicKey = String ( addressResp || '' ) ;
121+ }
122+
123+ // Cast options parameter as any to prevent strict package signature mismatches
124+ const signedResponse = await freighterSignTransaction ( xdr , {
125+ network : network . toUpperCase ( ) . includes ( 'PUBLIC' ) ? 'PUBLIC' : 'TESTNET' ,
126+ accountToSign : publicKey ,
127+ } as any ) ;
128+
129+ if ( typeof signedResponse === 'object' && signedResponse !== null && 'signedTxXdr' in signedResponse ) {
130+ return String ( ( signedResponse as any ) . signedTxXdr ) ;
131+ }
132+ return String ( signedResponse ) ;
87133 } catch ( error : any ) {
88- throw new Error ( `Failed to sign transaction: ${ error . message } ` ) ;
134+ throw new Error ( `Failed to sign transaction: ${ error . message || error } ` ) ;
89135 }
90136 }
91137}
0 commit comments