From c14746a9e4dbde10d6204697a68e6f2de6e83dd1 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 31 Oct 2024 11:49:49 -0700 Subject: [PATCH] PKG -- [FCL-WC] Deeplink on authz if pre-authz is not a WC/RPC service (#1999) --- .changeset/shaggy-snakes-vanish.md | 6 +++++ .../src/current-user/exec-service/index.js | 5 +++- packages/fcl-core/src/current-user/index.js | 18 ++++++++----- packages/fcl-wc/src/constants.ts | 3 +++ packages/fcl-wc/src/fcl-wc.ts | 4 +-- packages/fcl-wc/src/index.ts | 3 +-- packages/fcl-wc/src/service.ts | 22 ++++++++-------- packages/fcl-wc/src/utils.ts | 25 ++++++++++++++++++- 8 files changed, 63 insertions(+), 23 deletions(-) create mode 100644 .changeset/shaggy-snakes-vanish.md diff --git a/.changeset/shaggy-snakes-vanish.md b/.changeset/shaggy-snakes-vanish.md new file mode 100644 index 000000000..1be124673 --- /dev/null +++ b/.changeset/shaggy-snakes-vanish.md @@ -0,0 +1,6 @@ +--- +"@onflow/fcl-core": patch +"@onflow/fcl-wc": patch +--- + +Improve deeplinking for WC/RPC wallets using non-WC/RPC pre-authz services diff --git a/packages/fcl-core/src/current-user/exec-service/index.js b/packages/fcl-core/src/current-user/exec-service/index.js index 276deb49f..d8b0c3d54 100644 --- a/packages/fcl-core/src/current-user/exec-service/index.js +++ b/packages/fcl-core/src/current-user/exec-service/index.js @@ -16,9 +16,10 @@ export const execStrategy = async ({ abortSignal, customRpc, opts, + user, }) => { const strategy = getServiceRegistry().getStrategy(service.method) - return strategy({service, body, config, abortSignal, customRpc, opts}) + return strategy({service, body, config, abortSignal, customRpc, opts, user}) } export async function execService({ @@ -29,6 +30,7 @@ export async function execService({ platform, abortSignal = new AbortController().signal, execStrategy: _execStrategy, + user, }) { // Notify the developer if WalletConnect is not enabled checkWalletConnectEnabled() @@ -53,6 +55,7 @@ export async function execService({ body: msg, config: execConfig, opts, + user, abortSignal, }) diff --git a/packages/fcl-core/src/current-user/index.js b/packages/fcl-core/src/current-user/index.js index 4f8ee796b..b1a87c33b 100644 --- a/packages/fcl-core/src/current-user/index.js +++ b/packages/fcl-core/src/current-user/index.js @@ -12,7 +12,6 @@ import {execService} from "./exec-service" import {normalizeCompositeSignature} from "../normalizers/service/composite-signature" import {getDiscoveryService, makeDiscoveryServices} from "../discovery" import {getServiceRegistry} from "./exec-service/plugins" -import {isMobile} from "../utils" /** * @typedef {import("@onflow/typedefs").CurrentUser} CurrentUser @@ -160,6 +159,7 @@ const getAuthenticate = * @description - Authenticate a user * @param {object} [opts] - Options * @param {object} [opts.service] - Optional service to use for authentication + * @param {object} [opts.user] - Optional user object * @param {boolean} [opts.redir] - Optional redirect flag * @returns */ @@ -189,6 +189,7 @@ const getAuthenticate = msg: accountProofData, opts, platform, + user, }) send(NAME, SET_CURRENT_USER, await buildUser(response)) } catch (error) { @@ -224,6 +225,7 @@ const getAuthenticate = opts, platform, execStrategy: discovery?.execStrategy, + user, }) send(NAME, SET_CURRENT_USER, await buildUser(response)) @@ -258,7 +260,7 @@ const normalizePreAuthzResponse = authz => ({ const getResolvePreAuthz = ({platform}) => - authz => { + (authz, {user}) => { const resp = normalizePreAuthzResponse(authz) const axs = [] @@ -275,9 +277,7 @@ const getResolvePreAuthz = service: az, msg: signable, platform, - opts: { - initiatedByPreAuthz: true, - }, + user, }) }, role: { @@ -319,7 +319,11 @@ const getAuthorization = service: preAuthz, msg: preSignable, platform, - }) + user, + }), + { + user, + } ) if (authz) { return { @@ -339,6 +343,7 @@ const getAuthorization = includeOlderJsonRpcCall: true, }, platform, + user, }) ) }, @@ -446,6 +451,7 @@ const getSignUserMessage = service: signingService, msg: makeSignable(msg), platform, + user, }) if (Array.isArray(response)) { return response.map(compSigs => normalizeCompositeSignature(compSigs)) diff --git a/packages/fcl-wc/src/constants.ts b/packages/fcl-wc/src/constants.ts index d1083e45e..0e5d09c47 100644 --- a/packages/fcl-wc/src/constants.ts +++ b/packages/fcl-wc/src/constants.ts @@ -9,3 +9,6 @@ export enum REQUEST_TYPES { SESSION_REQUEST = "session_proposal", SIGNING_REQUEST = "signing_request", } + +export const SERVICE_PLUGIN_NAME = "fcl-plugin-service-walletconnect" +export const WC_SERVICE_METHOD = "WC/RPC" diff --git a/packages/fcl-wc/src/fcl-wc.ts b/packages/fcl-wc/src/fcl-wc.ts index 556f17e73..503749322 100644 --- a/packages/fcl-wc/src/fcl-wc.ts +++ b/packages/fcl-wc/src/fcl-wc.ts @@ -3,7 +3,7 @@ import SignClient from "@walletconnect/sign-client" import {invariant} from "@onflow/util-invariant" import {LEVELS, log} from "@onflow/util-logger" export {getSdkError} from "@walletconnect/utils" -import {SERVICE_PLUGIN_NAME, makeServicePlugin} from "./service" +import {makeServicePlugin} from "./service" import {CoreTypes} from "@walletconnect/types" export interface FclWalletConnectConfig { @@ -131,4 +131,4 @@ export async function getSignClient() { }) } -export {SERVICE_PLUGIN_NAME} +export {SERVICE_PLUGIN_NAME} from "./constants" diff --git a/packages/fcl-wc/src/index.ts b/packages/fcl-wc/src/index.ts index 31207647d..5bf8e4d34 100644 --- a/packages/fcl-wc/src/index.ts +++ b/packages/fcl-wc/src/index.ts @@ -1,4 +1,3 @@ -export {SERVICE_PLUGIN_NAME, WC_SERVICE_METHOD} from "./service" export {init, initLazy, getSignClient} from "./fcl-wc" export {createSessionProposal, request} from "./session" -export {FLOW_METHODS} from "./constants" +export {FLOW_METHODS, SERVICE_PLUGIN_NAME, WC_SERVICE_METHOD} from "./constants" diff --git a/packages/fcl-wc/src/service.ts b/packages/fcl-wc/src/service.ts index 53c2646b8..90006b047 100644 --- a/packages/fcl-wc/src/service.ts +++ b/packages/fcl-wc/src/service.ts @@ -1,18 +1,19 @@ import {invariant} from "@onflow/util-invariant" import {log, LEVELS} from "@onflow/util-logger" -import {isMobile, openDeeplink} from "./utils" -import {FLOW_METHODS, REQUEST_TYPES} from "./constants" +import {isMobile, openDeeplink, shouldDeepLink} from "./utils" +import { + REQUEST_TYPES, + SERVICE_PLUGIN_NAME, + WC_SERVICE_METHOD, +} from "./constants" import {SignClient} from "@walletconnect/sign-client/dist/types/client" -import {createSessionProposal, makeSessionData, request} from "./session" +import {createSessionProposal, request} from "./session" import {ModalCtrlState} from "@walletconnect/modal-core/dist/_types/src/types/controllerTypes" type WalletConnectModalType = import("@walletconnect/modal").WalletConnectModal type Constructor = new (...args: any[]) => T -export const SERVICE_PLUGIN_NAME = "fcl-plugin-service-walletconnect" -export const WC_SERVICE_METHOD = "WC/RPC" - export const makeServicePlugin = ( client: Promise, opts: { @@ -53,11 +54,13 @@ const makeExec = ( body, opts, abortSignal, + user, }: { service: any body: any opts: any abortSignal?: AbortSignal + user: any }) => { const client = await clientPromise invariant(!!client, "WalletConnect is not initialized") @@ -107,11 +110,8 @@ const makeExec = ( }) } - if ( - isMobile() && - method !== FLOW_METHODS.FLOW_AUTHN && - !(method === FLOW_METHODS.FLOW_AUTHZ && opts.initiatedByPreAuthz) - ) { + // Deeplink to the wallet app if necessary + if (shouldDeepLink({service, user})) { openDeeplink(appLink) } diff --git a/packages/fcl-wc/src/utils.ts b/packages/fcl-wc/src/utils.ts index de0247166..b99492225 100644 --- a/packages/fcl-wc/src/utils.ts +++ b/packages/fcl-wc/src/utils.ts @@ -1,6 +1,9 @@ import {log, LEVELS} from "@onflow/util-logger" -import {invariant} from "@onflow/util-invariant" import * as fclCore from "@onflow/fcl-core" +import {FLOW_METHODS, WC_SERVICE_METHOD} from "./constants" +import {Service} from "@onflow/typedefs" + +const PRE_AUTHZ_SERVICE_TYPE = "pre-authz" const makeFlowServicesFromWallets = (wallets: any[]) => { return Object.values(wallets) @@ -94,3 +97,23 @@ export function openDeeplink(url: string) { window.open(url, "_blank") } } + +export function shouldDeepLink({service, user}: {service: Service; user: any}) { + // Only deeplink on mobile + if (!isMobile()) return false + + // If this is an authn request, the user has already been deeplinked by connectWc + if (service.endpoint === FLOW_METHODS.FLOW_AUTHN) return false + + // If there was a pre-authz WC request, the user has already been deeplinked + if ( + service.endpoint === FLOW_METHODS.FLOW_AUTHZ && + user?.services?.find( + (s: Service) => + s.method === WC_SERVICE_METHOD && s.type === PRE_AUTHZ_SERVICE_TYPE + ) + ) + return false + + return true +}