@@ -46,6 +46,7 @@ import type {
4646 SignInFutureSSOParams ,
4747 SignInFutureTicketParams ,
4848 SignInFutureTOTPVerifyParams ,
49+ SignInFutureWeb3Params ,
4950 SignInIdentifier ,
5051 SignInJSON ,
5152 SignInJSONSnapshot ,
@@ -871,6 +872,77 @@ class SignInFuture implements SignInFutureResource {
871872 } ) ;
872873 }
873874
875+ async web3 ( params : SignInFutureWeb3Params ) : Promise < { error : unknown } > {
876+ const { strategy } = params ;
877+ const provider = strategy . replace ( 'web3_' , '' ) . replace ( '_signature' , '' ) as Web3Provider ;
878+
879+ return runAsyncResourceTask ( this . resource , async ( ) => {
880+ let identifier ;
881+ let generateSignature ;
882+ switch ( provider ) {
883+ case 'metamask' :
884+ identifier = await getMetamaskIdentifier ( ) ;
885+ generateSignature = generateSignatureWithMetamask ;
886+ break ;
887+ case 'coinbase_wallet' :
888+ identifier = await getCoinbaseWalletIdentifier ( ) ;
889+ generateSignature = generateSignatureWithCoinbaseWallet ;
890+ break ;
891+ case 'base' :
892+ identifier = await getBaseIdentifier ( ) ;
893+ generateSignature = generateSignatureWithBase ;
894+ break ;
895+ case 'okx_wallet' :
896+ identifier = await getOKXWalletIdentifier ( ) ;
897+ generateSignature = generateSignatureWithOKXWallet ;
898+ break ;
899+ default :
900+ throw new Error ( `Unsupported Web3 provider: ${ provider } ` ) ;
901+ }
902+
903+ await this . create ( { identifier } ) ;
904+
905+ const web3FirstFactor = this . resource . supportedFirstFactors ?. find (
906+ f => f . strategy === strategy ,
907+ ) as Web3SignatureFactor ;
908+ if ( ! web3FirstFactor ) {
909+ throw new Error ( 'Web3 first factor not found' ) ;
910+ }
911+
912+ await this . resource . __internal_basePost ( {
913+ body : { web3WalletId : web3FirstFactor . web3WalletId , strategy } ,
914+ action : 'prepare_first_factor' ,
915+ } ) ;
916+
917+ const { message } = this . firstFactorVerification ;
918+ if ( ! message ) {
919+ throw new Error ( 'Web3 nonce not found' ) ;
920+ }
921+
922+ let signature : string ;
923+ try {
924+ signature = await generateSignature ( { identifier, nonce : message } ) ;
925+ } catch ( err ) {
926+ // There is a chance that as a user when you try to setup and use the Coinbase Wallet with an existing
927+ // Passkey in order to authenticate, the initial generate signature request to be rejected. For this
928+ // reason we retry the request once more in order for the flow to be able to be completed successfully.
929+ //
930+ // error code 4001 means the user rejected the request
931+ // Reference: https://docs.cdp.coinbase.com/wallet-sdk/docs/errors
932+ if ( provider === 'coinbase_wallet' && err . code === 4001 ) {
933+ signature = await generateSignature ( { identifier, nonce : message } ) ;
934+ } else {
935+ throw err ;
936+ }
937+ }
938+
939+ await this . resource . __internal_basePost ( {
940+ body : { signature, strategy } ,
941+ action : 'attempt_first_factor' ,
942+ } ) ;
943+ } ) ;
944+ }
945+
874946 async sendMFAPhoneCode ( ) : Promise < { error : unknown } > {
875947 return runAsyncResourceTask ( this . resource , async ( ) => {
876948 const phoneCodeFactor = this . resource . supportedSecondFactors ?. find ( f => f . strategy === 'phone_code' ) ;
0 commit comments