diff --git a/README.md b/README.md index 4211bff7..7a509b4e 100644 --- a/README.md +++ b/README.md @@ -57,16 +57,31 @@ By default, the list of connectors is: ## Connect with specific connectors ```js -const webwallet = await connect([new WebWalletConnector()]) +const webwallet = await connect({ + connectors: [new WebWalletConnector()] +}) + +const webwallet = await connect({ + connectors: [new WebwalletGoogleAuthConnector({ + clientId: "YOUR_GOOGLE_CLIENT_ID", + authorizedPartyId: "STRING_IDENTIFYING YOUR PROJECT" + })] +}) -const argentMobileWallet = await connect([ - new ArgentMobileConnector() -]) +const google -const wallet = await connect([ - new InjectedConnector({ options: { id: "argentX" } }), - new InjectedConnector({ options: { id: "braavos" } }) -]) +const argentMobileWallet = await connect({ + connectors: [ + new ArgentMobileConnector() + ] +}) + +const wallet = await connect({ + connectors: [ + new InjectedConnector({ options: { id: "argentX" } }), + new InjectedConnector({ options: { id: "braavos" } }) + ] +}) ``` ## Reconnect to a previously connected wallet on load: diff --git a/src/connectors/webwallet/helpers/trpc.ts b/src/connectors/webwallet/helpers/trpc.ts index 9fe64c02..bbd19720 100644 --- a/src/connectors/webwallet/helpers/trpc.ts +++ b/src/connectors/webwallet/helpers/trpc.ts @@ -64,6 +64,8 @@ const appRouter = t.router({ .input( z.object({ theme: z.enum(["light", "dark", "auto"]).optional(), + token: z.string().optional(), + authorizedPartyId: z.string().optional(), }), ) .output( @@ -73,17 +75,6 @@ const appRouter = t.router({ }), ) .mutation(async () => ({})), - connectWebwalletSSO: t.procedure - .input( - z.object({ token: z.string(), authorizedPartyId: z.string().optional() }), - ) - .output( - z.object({ - account: z.string().array().optional(), - chainId: z.string().optional(), - }), - ) - .mutation(async () => ({})), enable: t.procedure.output(z.string()).mutation(async () => ""), execute: t.procedure .input(StarknetMethodArgumentsSchemas.execute) diff --git a/src/connectors/webwallet/index.ts b/src/connectors/webwallet/index.ts index 007c3f7a..a4441423 100644 --- a/src/connectors/webwallet/index.ts +++ b/src/connectors/webwallet/index.ts @@ -1,15 +1,15 @@ import { Permission, + type AccountChangeEventHandler, type RequestFnCall, type RpcMessage, type RpcTypeToMessageMap, - type AccountChangeEventHandler, type StarknetWindowObject, } from "@starknet-io/types-js" import { Account, - AccountInterface, - ProviderInterface, + type AccountInterface, + type ProviderInterface, type ProviderOptions, } from "starknet" import { @@ -28,25 +28,25 @@ import { import { DEFAULT_WEBWALLET_ICON, DEFAULT_WEBWALLET_URL } from "./constants" import { openWebwallet } from "./helpers/openWebwallet" import { setPopupOptions } from "./helpers/trpc" +import type { WebWalletStarknetWindowObject } from "./starknetWindowObject/argentStarknetWindowObject" import type { - Theme, - WebWalletStarknetWindowObject, -} from "./starknetWindowObject/argentStarknetWindowObject" + WebWalletConnectorOptions, + WebwalletGoogleAuthOptions, +} from "./types" let _wallet: StarknetWindowObject | null = null let _address: string | null = null -interface WebWalletConnectorOptions { - url?: string - theme?: Theme - ssoToken?: string - authorizedPartyId?: string -} - export class WebWalletConnector extends Connector { - private _wallet: StarknetWindowObject | null = null - private _options: WebWalletConnectorOptions - + protected _wallet: StarknetWindowObject | null = null + protected _options: WebWalletConnectorOptions + + /** + * @param options.url - Webwallet URL + * @param options.theme - Theme + * @param options.ssoToken - SSO token - response from Google Auth + * @param options.authorizedPartyId - String identifying your project + */ constructor(options: WebWalletConnectorOptions = {}) { super() this._options = options @@ -115,24 +115,15 @@ export class WebWalletConnector extends Connector { } try { - let account, chainId - - if (this._options.ssoToken) { - const ssoReponse = await ( - this._wallet as WebWalletStarknetWindowObject - ).connectWebwalletSSO( - this._options.ssoToken, - this._options.authorizedPartyId, - ) - account = ssoReponse.account - chainId = ssoReponse.chainId - } else { - const connectResponse = await ( - this._wallet as WebWalletStarknetWindowObject - ).connectWebwallet({ theme: this._options.theme }) - account = connectResponse.account - chainId = connectResponse.chainId - } + const connectResponse = await ( + this._wallet as WebWalletStarknetWindowObject + ).connectWebwallet({ + theme: this._options.theme, + token: this._options.ssoToken, + authorizedPartyId: this._options.authorizedPartyId, + }) + const account = connectResponse.account + const chainId = connectResponse.chainId if (!account || !chainId) { return {} @@ -227,7 +218,7 @@ export class WebWalletConnector extends Connector { this._wallet = null } - private async ensureWallet(): Promise { + protected async ensureWallet(): Promise { const origin = this._options.url || DEFAULT_WEBWALLET_URL setPopupOptions({ origin, @@ -241,3 +232,46 @@ export class WebWalletConnector extends Connector { } export type { WebWalletStarknetWindowObject } + +export class WebwalletGoogleAuthConnector extends WebWalletConnector { + private _clientId: string + + /** + * @param options.clientId - Google client ID + * @param options.authorizedPartyId - String identifying your project + */ + constructor( + options: WebwalletGoogleAuthOptions = { + clientId: "", + }, + ) { + if (!options.clientId) { + throw new Error("clientId is required") + } + + super(options) + this._clientId = options.clientId + } + + get id(): string { + this._wallet = _wallet + return this._wallet?.id || "argentWebWalletGoogleAuth" + } + + get title(): string { + return "Google" + } + + get clientId(): string { + return this._clientId + } + + public setSSOToken(response: { credential: string | null }) { + if (response.credential) { + // Send the token to your server for verification + this._options.ssoToken = response.credential + } else { + throw new Error("No credential received") + } + } +} diff --git a/src/connectors/webwallet/starknetWindowObject/argentStarknetWindowObject.ts b/src/connectors/webwallet/starknetWindowObject/argentStarknetWindowObject.ts index fc6f1fa0..aa5749c2 100644 --- a/src/connectors/webwallet/starknetWindowObject/argentStarknetWindowObject.ts +++ b/src/connectors/webwallet/starknetWindowObject/argentStarknetWindowObject.ts @@ -37,6 +37,8 @@ export type Theme = "light" | "dark" type ConnectWebwalletProps = { theme?: Theme + token?: string + authorizedPartyId?: string } export type WebWalletStarknetWindowObject = StarknetWindowObject & { @@ -45,13 +47,6 @@ export type WebWalletStarknetWindowObject = StarknetWindowObject & { account?: string[] chainId?: string }> - connectWebwalletSSO( - token: string, - authorizedPartyId?: string, - ): Promise<{ - account?: string[] - chainId?: string - }> } export const getArgentStarknetWindowObject = ( @@ -64,11 +59,12 @@ export const getArgentStarknetWindowObject = ( return proxyLink.getLoginStatus.mutate() }, connectWebwallet: (props = {}) => { - const { theme } = props - return proxyLink.connectWebwallet.mutate({ theme }) - }, - connectWebwalletSSO: (token, authorizedPartyId) => { - return proxyLink.connectWebwalletSSO.mutate({ token, authorizedPartyId }) + const { theme, token, authorizedPartyId } = props + return proxyLink.connectWebwallet.mutate({ + theme, + token, + authorizedPartyId, + }) }, async request(call) { switch (call.type) { diff --git a/src/connectors/webwallet/types/index.ts b/src/connectors/webwallet/types/index.ts new file mode 100644 index 00000000..336a87d8 --- /dev/null +++ b/src/connectors/webwallet/types/index.ts @@ -0,0 +1,19 @@ +import type { Theme } from "../starknetWindowObject/argentStarknetWindowObject" + +declare global { + interface Window { + google: any + } +} + +export interface WebWalletConnectorOptions { + url?: string + theme?: Theme + ssoToken?: string + authorizedPartyId?: string +} + +export interface WebwalletGoogleAuthOptions extends WebWalletConnectorOptions { + clientId: string + authorizedPartyId?: string +} diff --git a/src/helpers/defaultConnectors.ts b/src/helpers/defaultConnectors.ts index 08f5256e..1571dc3e 100644 --- a/src/helpers/defaultConnectors.ts +++ b/src/helpers/defaultConnectors.ts @@ -5,7 +5,10 @@ import { } from "../connectors/argentMobile" import { BraavosMobileBaseConnector } from "../connectors/braavosMobile" import { InjectedConnector } from "../connectors/injected" -import { WebWalletConnector } from "../connectors/webwallet" +import { + WebWalletConnector, + WebwalletGoogleAuthConnector, +} from "../connectors/webwallet" const isMobileDevice = () => { // Primary method: User Agent + Touch support check @@ -25,9 +28,14 @@ const isMobileDevice = () => { export const defaultConnectors = ({ argentMobileOptions, webWalletUrl, + googleAuthOptions, }: { argentMobileOptions: ArgentMobileConnectorOptions webWalletUrl?: string + googleAuthOptions?: { + clientId: string + authorizedPartyId: string + } }): StarknetkitConnector[] => { const isSafari = typeof window !== "undefined" @@ -51,5 +59,15 @@ export const defaultConnectors = ({ } defaultConnectors.push(new WebWalletConnector({ url: webWalletUrl })) + if (googleAuthOptions) { + defaultConnectors.push( + new WebwalletGoogleAuthConnector({ + url: webWalletUrl, + clientId: googleAuthOptions.clientId, + authorizedPartyId: googleAuthOptions.authorizedPartyId, + }), + ) + } + return defaultConnectors } diff --git a/src/main.ts b/src/main.ts index 61f604f4..547cb59e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -58,6 +58,7 @@ export const connect = async ({ modalTheme, dappName, resultType = "wallet", + googleAuthOptions, ...restOptions }: ConnectOptionsWithConnectors | ConnectOptions): Promise => { const { webWalletUrl = DEFAULT_WEBWALLET_URL, argentMobileOptions } = @@ -72,6 +73,7 @@ export const connect = async ({ ? defaultConnectors({ argentMobileOptions, webWalletUrl, + googleAuthOptions, }) : connectors diff --git a/src/modal/Modal.svelte b/src/modal/Modal.svelte index 7e7ea85f..4d80b6d0 100644 --- a/src/modal/Modal.svelte +++ b/src/modal/Modal.svelte @@ -5,6 +5,7 @@ import { InjectedConnector } from "../connectors/injected" import type { ModalWallet } from "../types/modal" import ConnectorButton from "./ConnectorButton.svelte" + import WebwalletGoogleAuth from "./WebwalletGoogleAuth.svelte" export let dappName: string = window?.document.title ?? "" export let modalWallets: ModalWallet[] @@ -144,7 +145,11 @@
    {#each modalWallets as wallet} - + {#if wallet.connector.id === "argentWebWalletGoogleAuth"} + + {:else} + + {/if} {/each}
diff --git a/src/modal/WebwalletGoogleAuth.svelte b/src/modal/WebwalletGoogleAuth.svelte new file mode 100644 index 00000000..01755431 --- /dev/null +++ b/src/modal/WebwalletGoogleAuth.svelte @@ -0,0 +1,146 @@ + + + +
  • e.key === "Enter" && handleClick()} +> + {#if loadingItem} +
    + + Loading... +
    {/if} + +
    + +
    +

    + {wallet.title ?? wallet.name} +

    +

    + {wallet.subtitle ?? ""} +

    +
    +
  • diff --git a/src/types/modal.ts b/src/types/modal.ts index b57f35db..4285ce7a 100644 --- a/src/types/modal.ts +++ b/src/types/modal.ts @@ -17,6 +17,10 @@ export interface ConnectOptions extends GetWalletOptions { resultType?: "connector" | "wallet" webWalletUrl?: string argentMobileOptions: ArgentMobileConnectorOptions + googleAuthOptions?: { + clientId: string + authorizedPartyId: string + } } export interface ConnectOptionsWithConnectors @@ -32,6 +36,7 @@ export type ModalWallet = { subtitle?: string title?: string connector: StarknetkitConnector + clientId?: string } export type ModalResult = {