@@ -26,11 +26,7 @@ import { useStringGetter } from '@/hooks/useStringGetter';
2626import { appQueryClient } from '@/state/appQueryClient' ;
2727import { useAppDispatch , useAppSelector } from '@/state/appTypes' ;
2828import { forceOpenDialog , openDialog } from '@/state/dialogs' ;
29- import {
30- setRequiresAddressUpload ,
31- setTurnkeyEmailOnboardingData ,
32- setWalletInfo ,
33- } from '@/state/wallet' ;
29+ import { setTurnkeyEmailOnboardingData , setWalletInfo } from '@/state/wallet' ;
3430import { getSourceAccount , getTurnkeyEmailOnboardingData } from '@/state/walletSelectors' ;
3531
3632import { identify , track } from '@/lib/analytics/analytics' ;
@@ -74,7 +70,7 @@ const useTurnkeyAuthContext = () => {
7470 const indexerUrl = useAppSelector ( selectIndexerUrl ) ;
7571 const sourceAccount = useAppSelector ( getSourceAccount ) ;
7672 const { indexedDbClient, authIframeClient } = useTurnkey ( ) ;
77- const { dydxAddress, setWalletFromSignature, selectWallet } = useAccounts ( ) ;
73+ const { dydxAddress : connectedDydxAddress , setWalletFromSignature, selectWallet } = useAccounts ( ) ;
7874 const [ searchParams , setSearchParams ] = useSearchParams ( ) ;
7975 const [ emailToken , setEmailToken ] = useState < string > ( ) ;
8076 const [ emailSignInError , setEmailSignInError ] = useState < string > ( ) ;
@@ -91,6 +87,71 @@ const useTurnkeyAuthContext = () => {
9187 getUploadAddressPayload,
9288 } = useTurnkeyWallet ( ) ;
9389
90+ /* ----------------------------- Upload Address ----------------------------- */
91+
92+ const { mutateAsync : sendUploadAddressRequest , isPending : isUploadingAddress } = useMutation ( {
93+ mutationFn : async ( {
94+ payload,
95+ } : {
96+ payload : { dydxAddress : string ; signature : string } ;
97+ } ) : Promise < { success : boolean } > => {
98+ const body = JSON . stringify ( payload ) ;
99+
100+ const response = await fetch ( `${ indexerUrl } /v4/turnkey/uploadAddress` , {
101+ method : 'POST' ,
102+ headers : {
103+ 'Content-Type' : 'application/json' ,
104+ Accept : 'application/json' ,
105+ } ,
106+ body,
107+ } ) . then ( ( res ) => res . json ( ) ) ;
108+
109+ if ( response . errors && Array . isArray ( response . errors ) ) {
110+ const errorMsg = response . errors . map ( ( e : { msg : string } ) => e . msg ) . join ( ', ' ) ;
111+ throw new Error ( `useTurnkeyAuth: Backend Error: ${ errorMsg } ` ) ;
112+ }
113+
114+ // TODO(turnkey): handle policy returned in response
115+ return response ;
116+ } ,
117+ onError : ( error , variables ) => {
118+ track (
119+ AnalyticsEvents . UploadAddressError ( {
120+ dydxAddress : variables . payload . dydxAddress ,
121+ error : error . message ,
122+ } )
123+ ) ;
124+ logBonsaiError ( 'TurnkeyOnboarding' , 'Error posting to upload address' , { error } ) ;
125+ } ,
126+ onSuccess : ( ) => {
127+ appQueryClient . invalidateQueries ( { queryKey : [ 'turnkeyWallets' ] } ) ;
128+ } ,
129+ } ) ;
130+
131+ const uploadAddress = useCallback (
132+ async ( {
133+ tkClient,
134+ dydxAddress,
135+ } : {
136+ tkClient ?: TurnkeyIndexedDbClient ;
137+ dydxAddress : string ;
138+ } ) => {
139+ try {
140+ logBonsaiInfo ( 'TurnkeyOnboarding' , 'Attempting to upload address' ) ;
141+
142+ if ( tkClient == null ) {
143+ throw new Error ( 'No tk client provided' ) ;
144+ }
145+
146+ const payload = await getUploadAddressPayload ( { dydxAddress, tkClient } ) ;
147+ await sendUploadAddressRequest ( { payload } ) ;
148+ } catch ( error ) {
149+ logBonsaiError ( 'TurnkeyOnboarding' , 'Error uploading address' , { error } ) ;
150+ }
151+ } ,
152+ [ getUploadAddressPayload , sendUploadAddressRequest ]
153+ ) ;
154+
94155 /* ----------------------------- Sign In ----------------------------- */
95156
96157 const { mutate : sendSignInRequest , status } = useMutation ( {
@@ -136,7 +197,6 @@ const useTurnkeyAuthContext = () => {
136197 if ( response . dydxAddress === '' ) {
137198 setIsNewTurnkeyUser ( true ) ;
138199 identify ( AnalyticsUserProperties . IsNewUser ( true ) ) ;
139- dispatch ( setRequiresAddressUpload ( true ) ) ;
140200 } else {
141201 identify ( AnalyticsUserProperties . IsNewUser ( false ) ) ;
142202 }
@@ -239,19 +299,37 @@ const useTurnkeyAuthContext = () => {
239299
240300 const handleOauthResponse = useCallback (
241301 async ( { response } : { response : TurnkeyOAuthResponse } ) => {
242- const { session, salt } = response ;
302+ const { session, salt, dydxAddress : uploadedDydxAddress } = response ;
243303 if ( session == null ) {
244304 throw new Error ( 'useTurnkeyAuth: No session found' ) ;
245305 } else if ( salt == null ) {
246306 throw new Error ( 'useTurnkeyAuth: No salt found' ) ;
247307 }
248308
249309 await indexedDbClient ?. loginWithSession ( session ) ;
250- await onboardDydx ( { salt, setWalletFromSignature, tkClient : indexedDbClient } ) ;
310+ const derivedDydxAddress = await onboardDydx ( {
311+ salt,
312+ setWalletFromSignature,
313+ tkClient : indexedDbClient ,
314+ } ) ;
315+
316+ if ( uploadedDydxAddress === '' && derivedDydxAddress ) {
317+ try {
318+ await uploadAddress ( { tkClient : indexedDbClient , dydxAddress : derivedDydxAddress } ) ;
319+ } catch ( uploadAddressError ) {
320+ if (
321+ uploadAddressError instanceof Error &&
322+ ! uploadAddressError . message . includes ( 'Dydx address already uploaded' )
323+ ) {
324+ throw uploadAddressError ;
325+ }
326+ }
327+ }
328+
251329 setEmailSignInStatus ( 'success' ) ;
252330 setEmailSignInError ( undefined ) ;
253331 } ,
254- [ onboardDydx , indexedDbClient , setWalletFromSignature ]
332+ [ onboardDydx , indexedDbClient , setWalletFromSignature , uploadAddress ]
255333 ) ;
256334
257335 /* ----------------------------- Email Sign In ----------------------------- */
@@ -302,7 +380,8 @@ const useTurnkeyAuthContext = () => {
302380 throw new Error ( 'No public key found' ) ;
303381 }
304382
305- const { organizationId } = turnkeyEmailOnboardingData ?? { } ;
383+ const { organizationId, dydxAddress : uploadedDydxAddress } =
384+ turnkeyEmailOnboardingData ?? { } ;
306385
307386 if ( ! organizationId ) {
308387 throw new Error ( 'Organization ID was not found' ) ;
@@ -322,7 +401,24 @@ const useTurnkeyAuthContext = () => {
322401 }
323402
324403 await indexedDbClient . loginWithSession ( session ) ;
325- await onboardDydx ( { setWalletFromSignature, tkClient : indexedDbClient } ) ;
404+ const derivedDydxAddress = await onboardDydx ( {
405+ setWalletFromSignature,
406+ tkClient : indexedDbClient ,
407+ } ) ;
408+
409+ if ( derivedDydxAddress && uploadedDydxAddress === '' ) {
410+ try {
411+ await uploadAddress ( { tkClient : indexedDbClient , dydxAddress : derivedDydxAddress } ) ;
412+ } catch ( uploadAddressError ) {
413+ if (
414+ uploadAddressError instanceof Error &&
415+ ! uploadAddressError . message . includes ( 'Dydx address already uploaded' )
416+ ) {
417+ throw uploadAddressError ;
418+ }
419+ }
420+ }
421+
326422 setEmailSignInStatus ( 'success' ) ;
327423
328424 track (
@@ -386,6 +482,7 @@ const useTurnkeyAuthContext = () => {
386482 setSearchParams ,
387483 stringGetter ,
388484 endTurnkeySession ,
485+ uploadAddress ,
389486 ]
390487 ) ;
391488
@@ -429,76 +526,6 @@ const useTurnkeyAuthContext = () => {
429526 setEmailSignInError ( undefined ) ;
430527 } , [ searchParams , setSearchParams ] ) ;
431528
432- /* ----------------------------- Upload Address ----------------------------- */
433- const { mutateAsync : sendUploadAddressRequest , isPending : isUploadingAddress } = useMutation ( {
434- mutationFn : async ( {
435- payload,
436- } : {
437- payload : { dydxAddress : string ; signature : string } ;
438- } ) : Promise < { success : boolean } > => {
439- const body = JSON . stringify ( payload ) ;
440-
441- const response = await fetch ( `${ indexerUrl } /v4/turnkey/uploadAddress` , {
442- method : 'POST' ,
443- headers : {
444- 'Content-Type' : 'application/json' ,
445- Accept : 'application/json' ,
446- } ,
447- body,
448- } ) . then ( ( res ) => res . json ( ) ) ;
449-
450- if ( response . errors && Array . isArray ( response . errors ) ) {
451- const errorMsg = response . errors . map ( ( e : { msg : string } ) => e . msg ) . join ( ', ' ) ;
452- throw new Error ( `useTurnkeyAuth: Backend Error: ${ errorMsg } ` ) ;
453- }
454-
455- // TODO(turnkey): handle policy returned in response
456- return response ;
457- } ,
458- onError : ( error , variables ) => {
459- track (
460- AnalyticsEvents . UploadAddressError ( {
461- dydxAddress : variables . payload . dydxAddress ,
462- error : error . message ,
463- } )
464- ) ;
465- logBonsaiError ( 'TurnkeyOnboarding' , 'Error posting to upload address' , { error } ) ;
466- } ,
467- onSuccess : ( ) => {
468- appQueryClient . invalidateQueries ( { queryKey : [ 'turnkeyWallets' ] } ) ;
469- } ,
470- } ) ;
471-
472- const uploadAddress = useCallback (
473- async ( { tkClient } : { tkClient ?: TurnkeyIndexedDbClient } ) => {
474- try {
475- logBonsaiInfo ( 'TurnkeyOnboarding' , 'Attempting to upload address' ) ;
476-
477- if ( dydxAddress == null ) {
478- throw new Error ( 'No dydx address provided' ) ;
479- }
480-
481- if ( tkClient == null ) {
482- throw new Error ( 'No tk client provided' ) ;
483- }
484-
485- const payload = await getUploadAddressPayload ( { dydxAddress, tkClient } ) ;
486- const result = await sendUploadAddressRequest ( { payload } ) ;
487-
488- if ( ! result . success ) {
489- dispatch ( setRequiresAddressUpload ( true ) ) ;
490- }
491- } catch ( error ) {
492- if ( ( error . message ?? '' ) . includes ( 'Dydx address already uploaded' ) ) {
493- dispatch ( setRequiresAddressUpload ( false ) ) ;
494- } else {
495- logBonsaiError ( 'TurnkeyOnboarding' , 'Error uploading address' , { error } ) ;
496- }
497- }
498- } ,
499- [ dispatch , dydxAddress , getUploadAddressPayload , sendUploadAddressRequest ]
500- ) ;
501-
502529 /* ----------------------------- Side Effects ----------------------------- */
503530
504531 /**
@@ -509,14 +536,21 @@ const useTurnkeyAuthContext = () => {
509536 const turnkeyOnboardingToken = searchParams . get ( 'token' ) ;
510537 const hasEncryptedSignature = sourceAccount . encryptedSignature != null ;
511538
512- if ( turnkeyOnboardingToken && dydxAddress != null ) {
539+ if ( turnkeyOnboardingToken && connectedDydxAddress != null ) {
513540 searchParams . delete ( 'token' ) ;
514541 setSearchParams ( searchParams ) ;
515542 } else if ( turnkeyOnboardingToken && ! hasEncryptedSignature ) {
516543 setEmailToken ( turnkeyOnboardingToken ) ;
517544 dispatch ( openDialog ( DialogTypes . EmailSignInStatus ( { } ) ) ) ;
518545 }
519- } , [ searchParams , dispatch , sourceAccount , dydxAddress , resetEmailSignInStatus , setSearchParams ] ) ;
546+ } , [
547+ searchParams ,
548+ dispatch ,
549+ sourceAccount ,
550+ connectedDydxAddress ,
551+ resetEmailSignInStatus ,
552+ setSearchParams ,
553+ ] ) ;
520554
521555 /**
522556 * @description Side effect triggered after the email token is saved to state.
@@ -548,19 +582,6 @@ const useTurnkeyAuthContext = () => {
548582 ) ;
549583 } , [ sourceAccount . walletInfo ] ) ;
550584
551- /**
552- * @description Side effect to upload the address if it is required and the user has a dydx address.
553- * This is triggered after the user has signed in with email or OAuth and has derived their dydx address.
554- */
555- useEffect ( ( ) => {
556- if ( indexedDbClient && needsAddressUpload && dydxAddress != null ) {
557- // Set RequiredAddressUpload to false to prevent the upload from being triggered again.
558- // If the uploadAddress mutation fails, the requiredAddressUpload flag will be set back to true.
559- dispatch ( setRequiresAddressUpload ( false ) ) ;
560- uploadAddress ( { tkClient : indexedDbClient } ) ;
561- }
562- } , [ dispatch , dydxAddress , uploadAddress , indexedDbClient , needsAddressUpload ] ) ;
563-
564585 /* ----------------------------- Return Values----------------------------- */
565586
566587 return {
0 commit comments