import { ethErrors } from 'eth-rpc-errors' ; import { keyringService , notificationService , permissionService , } from 'background/service' ; import { PromiseFlow , underline2Camelcase } from 'background/utils' ; import { EVENTS } from 'consts' ; import providerController from './controller' ; import eventBus from '@/eventBus' ; const isSignApproval = ( type ) => { const SIGN_APPROVALS = [ 'SignText' , 'SignTypedData' , 'SignTx' ] ; return SIGN_APPROVALS . includes ( type ) ; } ; const flow = new PromiseFlow ( ) ; const flowContext = flow . use ( async ( ctx , next ) => { const { data : { method } , } = ctx . request ; ctx . mapMethod = underline2Camelcase ( method ) ; if ( ! providerController [ ctx . mapMethod ] ) { if ( method . startsWith ( 'eth_' ) || method === 'net_version' ) { return providerController . ethRpc ( ctx . request ) ; } throw ethErrors . rpc . methodNotFound ( { message : `method [${ method }] doesn't has corresponding handler` , data : ctx . request . data , } ) ; } return next ( ) ; } ) . use ( async ( ctx , next ) => { const { mapMethod } = ctx ; if ( ! Reflect . getMetadata ( 'SAFE' , providerController , mapMethod ) ) { const isUnlock = keyringService . memStore . getState ( ) . isUnlocked ; if ( ! isUnlock ) { ctx . request . requestedApproval = true ; await notificationService . requestApproval ( { lock : true } ) ; } } return next ( ) ; } ) . use ( async ( ctx , next ) => { const { request : { session : { origin , name , icon } , } , mapMethod , } = ctx ; if ( ! Reflect . getMetadata ( 'SAFE' , providerController , mapMethod ) ) { if ( ! permissionService . hasPerssmion ( origin ) ) { ctx . request . requestedApproval = true ; const { defaultChain } = await notificationService . requestApproval ( { params : { origin , name , icon } , approvalComponent : 'Connect' , } , { height : 390 } ) ; permissionService . addConnectedSite ( origin , name , icon , defaultChain ) ; } } return next ( ) ; } ) . use ( async ( ctx , next ) => { const { request : { data : { params , method } , session : { origin , name , icon } , } , mapMethod , } = ctx ; const [ approvalType , condition , { height = 770 } = { } ] = Reflect . getMetadata ( 'APPROVAL' , providerController , mapMethod ) || [ ] ; if ( approvalType && ( ! condition || ! condition ( ctx . request ) ) ) { ctx . request . requestedApproval = true ; ctx . approvalRes = await notificationService . requestApproval ( { approvalComponent : approvalType , params : { method , data : params , session : { origin , name , icon } , } , origin , } , { height } ) ; if ( isSignApproval ( approvalType ) ) { permissionService . updateConnectSite ( origin , { isSigned : true } , true ) ; } else { permissionService . touchConnectedSite ( origin ) ; } } return next ( ) ; } ) . use ( async ( ctx ) => { const { approvalRes , mapMethod , request } = ctx ; const [ approvalType ] = Reflect . getMetadata ( 'APPROVAL' , providerController , mapMethod ) || [ ] ; const { uiRequestComponent , ... rest } = approvalRes || { } ; const { session : { origin } , } = request ; const requestDefer = Promise . resolve ( providerController [ mapMethod ] ( { ... request , approvalRes , } ) ) ; requestDefer . then ( ( result ) => { if ( isSignApproval ( approvalType ) ) { eventBus . emit ( EVENTS . broadcastToUI , { method : EVENTS . SIGN_FINISHED , params : { success : true , data : result , } , } ) ; } return result ; } ) . catch ( ( e ) => { if ( isSignApproval ( approvalType ) ) { eventBus . emit ( EVENTS . broadcastToUI , { method : EVENTS . SIGN_FINISHED , params : { success : false , errorMsg : JSON . stringify ( e ) , } , } ) ; } } ) ; async function requestApprovalLoop ( { uiRequestComponent , ... rest } ) { ctx . request . requestedApproval = true ; const res = await notificationService . requestApproval ( { approvalComponent : uiRequestComponent , params : rest , origin , approvalType , } ) ; if ( res . uiRequestComponent ) { return await requestApprovalLoop ( res ) ; } else { return res ; } } if ( uiRequestComponent ) { ctx . request . requestedApproval = true ; return await requestApprovalLoop ( { uiRequestComponent , ... rest } ) ; } return requestDefer ; } ) . callback ( ) ; export default ( request ) => { const ctx = { request : { ... request , requestedApproval : false } } ; return flowContext ( ctx ) . finally ( ( ) => { if ( ctx . request . requestedApproval ) { flow . requestedApproval = false ; notificationService . unLock ( ) ; } } ) ; } ;