11import React from "react" ;
2+ import Cookies from "js-cookie" ;
23import { ConnectKitButton , ConnectKitProvider } from "connectkit" ;
34import { SiweMessage } from "siwe" ;
4- import { useAccount , useDisconnect } from "wagmi" ;
5- import Cookies from "js-cookie" ;
5+ import { useAccount , useChainId , useDisconnect , useSignMessage } from "wagmi" ;
6+ import { useCountdown } from "usehooks-ts" ;
7+
68import devfolioLogoFull from "./assets/devfolio-logo-full.svg" ;
79import connectWallet from "./assets/connect-wallet.svg" ;
810import stepCheck from "./assets/step-check.svg" ;
911import loader from "./assets/loader.svg" ;
10- import { useCountdown } from "usehooks-ts" ;
1112
1213type ACTION_TYPE = "signin" | "signup" | "connect" ;
1314type STEP_STAGE = "complete" | "incomplete" ;
@@ -20,6 +21,8 @@ const oidc_nonce = params.get("oidc_nonce") ?? "";
2021const client_id = params . get ( "client_id" ) ?? "" ;
2122const action = ( params . get ( "action" ) as ACTION_TYPE | undefined ) ?? "signin" ;
2223
24+ const COUNTDOWN_IN_SECONDS = 3 ;
25+
2326const TITLE : Record < ACTION_TYPE , string > = {
2427 signin : "Sign in with Ethereum" ,
2528 signup : "Sign up with Ethereum" ,
@@ -106,41 +109,99 @@ const Step = ({
106109} ;
107110
108111function App ( ) {
112+ let siweSessionTimeout : NodeJS . Timeout ;
113+ let redirectTimeout : NodeJS . Timeout ;
114+
109115 const account = useAccount ( ) ;
110116 const { disconnect } = useDisconnect ( ) ;
117+ const chainId = useChainId ( ) ;
111118
112- const [ isVerifyingAddress , setIsVerifyingAddress ] =
113- React . useState < boolean > ( false ) ;
114- const [ activeStepNumber , setActiveStepNumber ] = React . useState < number > ( 1 ) ;
119+ const { signMessage : wagmiSignMessage } = useSignMessage ( {
120+ mutation : {
121+ onSuccess : ( signature ) => onVerifyAddressSuccess ( signature ) ,
122+ } ,
123+ } ) ;
115124
116125 const [ count , { startCountdown } ] = useCountdown ( {
117- countStart : 3 ,
126+ countStart : COUNTDOWN_IN_SECONDS ,
118127 intervalMs : 1000 ,
119128 } ) ;
120129
121- const onWalletConnectSuccess = ( ) => {
122- setActiveStepNumber ( 2 ) ;
123- } ;
130+ const [ localSession , setLocalSession ] = React . useState < {
131+ message : SiweMessage ;
132+ raw : string ;
133+ signature ?: string ;
134+ } | null > ( null ) ;
135+
136+ const [ isVerifyingAddress , setIsVerifyingAddress ] =
137+ React . useState < boolean > ( false ) ;
138+
139+ const [ activeStepNumber , setActiveStepNumber ] = React . useState < number > ( 1 ) ;
140+
141+ const expirationTime = React . useMemo ( ( ) => {
142+ return new Date (
143+ new Date ( ) . getTime ( ) + 2 * 24 * 60 * 60 * 1000 , // 48h
144+ ) ;
145+ } , [ ] ) ;
146+
147+ // Clear all the timeout before closing the tab/app
148+ React . useEffect ( ( ) => {
149+ return ( ) => {
150+ clearTimeout ( siweSessionTimeout ) ;
151+ clearTimeout ( redirectTimeout ) ;
152+ } ;
153+ // eslint-disable-next-line react-hooks/exhaustive-deps
154+ } , [ ] ) ;
155+
156+ const onVerifyAddressSuccess = ( signature ?: string ) => {
157+ if (
158+ ! localSession ?. message ||
159+ ! localSession ?. raw ||
160+ typeof signature !== "string" ||
161+ signature ?. length === 0
162+ )
163+ return ;
124164
125- const onVerifyAddressSuccess = ( ) => {
126165 // Start countdown for redirect
127166 startCountdown ( ) ;
128167 setIsVerifyingAddress ( false ) ;
129168
130169 setActiveStepNumber ( 3 ) ;
170+
171+ siweSessionTimeout = setTimeout (
172+ ( ) => {
173+ Cookies . set (
174+ "siwe" ,
175+ JSON . stringify ( {
176+ ...localSession ,
177+ signature,
178+ } ) ,
179+ {
180+ expires : expirationTime ,
181+ } ,
182+ ) ;
183+ } ,
184+ ( COUNTDOWN_IN_SECONDS - 2 ) * 1000 ,
185+ ) ;
186+
187+ redirectTimeout = setTimeout ( ( ) => {
188+ window . location . replace (
189+ `/sign_in?redirect_uri=${ encodeURI ( redirect ) } &state=${ encodeURI (
190+ state ,
191+ ) } &client_id=${ encodeURI ( client_id ) } ${ encodeURI ( oidc_nonce ) } `,
192+ ) ;
193+ } , COUNTDOWN_IN_SECONDS * 1000 ) ;
194+ } ;
195+
196+ const onWalletConnectSuccess = ( ) => {
197+ setActiveStepNumber ( 2 ) ;
131198 } ;
132199
133200 const handleSignInWithEthereum = async ( e : React . MouseEvent ) => {
134201 e . preventDefault ( ) ;
135202 setIsVerifyingAddress ( true ) ;
136203 const address = account ?. address ;
137204 try {
138- const expirationTime = new Date (
139- new Date ( ) . getTime ( ) + 2 * 24 * 60 * 60 * 1000 , // 48h
140- ) ;
141-
142- const chainId = await account . connector ?. getChainId ( ) ;
143-
144205 const signMessage = new SiweMessage ( {
145206 domain : window . location . host ,
146207 address : address ,
@@ -152,33 +213,18 @@ function App() {
152213 nonce,
153214 resources : [ redirect ] ,
154215 } ) . prepareMessage ( ) ;
155- const walletClient = await account . connector ?. getWalletClient ( ) ;
156216
157- const signature = await walletClient ?. signMessage ( {
217+ wagmiSignMessage ( {
158218 account : account . address ,
159219 message : signMessage ,
160220 } ) ;
161221
162222 const message = new SiweMessage ( signMessage ) ;
163- const session = {
223+
224+ setLocalSession ( {
164225 message,
165226 raw : signMessage ,
166- signature,
167- } ;
168-
169- onVerifyAddressSuccess ( ) ;
170-
171- setTimeout ( ( ) => {
172- Cookies . set ( "siwe" , JSON . stringify ( session ) , {
173- expires : expirationTime ,
174- } ) ;
175-
176- window . location . replace (
177- `/sign_in?redirect_uri=${ encodeURI ( redirect ) } &state=${ encodeURI (
178- state ,
179- ) } &client_id=${ encodeURI ( client_id ) } ${ encodeURI ( oidc_nonce ) } `,
180- ) ;
181- } , 3000 ) ;
227+ } ) ;
182228
183229 return ;
184230 } catch ( e ) {
0 commit comments