Skip to content

Commit

Permalink
Support iframe autoconnect (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
codingki authored May 9, 2024
2 parents c735945 + 3449a4b commit 772b95a
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 21 deletions.
4 changes: 3 additions & 1 deletion docs/docs/guides/connect-using-iframe.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ Cosmiframe enforces security by requiring you to specify allowed origins in the
<GrazProvider
grazOptions={{
chains,
allowedIframeParentOrigins: ["https://daodao.zone", "https://dao.daodao.zone"],
iframeOptions: {
allowedIframeParentOrigins: ["https://daodao.zone", "https://dao.daodao.zone"],
},
}}
>
<Component {...pageProps} />
Expand Down
6 changes: 5 additions & 1 deletion docs/docs/provider/grazProvider.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ export default function CustomApp({ Component, pageProps }: AppProps) {
onReconnectFailed?: () => void;
walletConnect?: WalletConnectStore | null;
multiChainFetchConcurrency?: number // when using multi chain hooks it fetch 3 function simultaneously. defaults to 3.
allowedIframeParentOrigins?: string[] // for integrating using WalletType.COSMIFRAME
iframeOptions?: {
// for integrating using WalletType.COSMIFRAME
allowedIframeParentOrigins: string[]
autoConnect?: boolean
}
}
```

Expand Down
4 changes: 3 additions & 1 deletion example/next/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ const CustomApp: NextPage<AppProps> = ({ Component, pageProps }) => {
apiKey: process.env.NEXT_PUBLIC_CAPSULE_API_KEY,
env: process.env.NEXT_PUBLIC_CAPSULE_ENV,
},
allowedIframeParentOrigins: ["https://daodao.zone", "https://dao.daodao.zone"],
iframeOptions: {
allowedIframeParentOrigins: ["https://daodao.zone", "https://dao.daodao.zone", "http://localhost:3000"],
},
}}
>
<Component {...pageProps} />
Expand Down
4 changes: 3 additions & 1 deletion example/starter/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ const MyApp = ({ Component, pageProps }: AppProps) => {
preferNoSetFee: true,
},
},
allowedIframeParentOrigins: ["https://daodao.zone", "https://dao.daodao.zone"],
iframeOptions: {
allowedIframeParentOrigins: ["https://daodao.zone", "https://dao.daodao.zone"],
},
}}
>
<ChakraProvider resetCSS theme={theme}>
Expand Down
11 changes: 4 additions & 7 deletions packages/graz/src/actions/configure.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ChainInfo } from "@keplr-wallet/types";

import type { CapsuleConfig, ChainConfig, GrazInternalStore } from "../store";
import type { CapsuleConfig, ChainConfig, GrazInternalStore, IframeOptions } from "../store";
import { useGrazInternalStore } from "../store";
import type { WalletType } from "../types/wallet";

Expand All @@ -23,17 +23,14 @@ export interface ConfigureGrazArgs {
*/
multiChainFetchConcurrency?: number;
/**
* Origins to allow wrapping this app in an iframe and connecting to this
* Graz instance.
*
* Defaults to none, which disables the iframe wallet.
* Options to enable iframe wallet connection.
*/
allowedIframeParentOrigins?: string[];
iframeOptions?: IframeOptions;
}

export const configureGraz = (args: ConfigureGrazArgs): ConfigureGrazArgs => {
useGrazInternalStore.setState((prev) => ({
allowedIframeParentOrigins: args.allowedIframeParentOrigins || prev.allowedIframeParentOrigins,
iframeOptions: args.iframeOptions || prev.iframeOptions,
walletConnect: args.walletConnect || prev.walletConnect,
walletType: args.defaultWallet || prev.walletType,
capsuleConfig: args.capsuleConfig || prev.capsuleConfig,
Expand Down
9 changes: 7 additions & 2 deletions packages/graz/src/actions/wallet/cosmiframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,22 @@ import type { Wallet } from "../../types/wallet";
export const getCosmiframe = (): Wallet => {
const state = useGrazInternalStore.getState();

if (!state.iframeOptions) {
state._notFoundFn();
throw new Error("no iframe options set");
}

if (!isInIframe()) {
state._notFoundFn();
throw new Error("not in iframe");
}

if (!state.allowedIframeParentOrigins?.length) {
if (!state.iframeOptions.allowedIframeParentOrigins.length) {
state._notFoundFn();
throw new Error("no iframe allowed origins");
}

const keplr = new Cosmiframe(state.allowedIframeParentOrigins).getKeplrClient();
const keplr = new Cosmiframe(state.iframeOptions.allowedIframeParentOrigins).getKeplrClient();

return {
enable: keplr.enable.bind(keplr),
Expand Down
29 changes: 27 additions & 2 deletions packages/graz/src/provider/events.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Cosmiframe } from "@dao-dao/cosmiframe";
import type { FC } from "react";
import { useEffect } from "react";

import { reconnect } from "../actions/account";
import { connect, reconnect } from "../actions/account";
import { checkWallet } from "../actions/wallet";
import { getCosmiframe } from "../actions/wallet/cosmiframe";
import { getCosmostation } from "../actions/wallet/cosmostation";
Expand All @@ -23,10 +24,34 @@ import { WalletType } from "../types/wallet";
export const useGrazEvents = () => {
const isSessionActive =
typeof window !== "undefined" && window.sessionStorage.getItem(RECONNECT_SESSION_KEY) === "Active";
const { _reconnect, _onReconnectFailed, _reconnectConnector } = useGrazInternalStore();
const { _reconnect, _onReconnectFailed, _reconnectConnector, iframeOptions, chains } = useGrazInternalStore();
const { activeChainIds: activeChains, wcSignClients } = useGrazSessionStore();
const isReconnectConnectorReady = checkWallet(_reconnectConnector || undefined);

// Auto connect to iframe if possible.
useEffect(() => {
if (
!iframeOptions ||
iframeOptions.autoConnect === false ||
!iframeOptions.allowedIframeParentOrigins.length ||
!chains
) {
return;
}

const cosmiframe = new Cosmiframe(iframeOptions.allowedIframeParentOrigins);
void cosmiframe.isReady().then((ready) => {
if (ready) {
return connect({
chainId: chains.map((c) => c.chainId),
walletType: WalletType.COSMIFRAME,
});
}
});

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [iframeOptions]);

useEffect(() => {
// will reconnect on refresh
if (_reconnectConnector) {
Expand Down
22 changes: 16 additions & 6 deletions packages/graz/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,29 @@ export interface CapsuleState {
showModal: boolean;
chainId?: string[];
}
export interface GrazInternalStore {

export interface IframeOptions {
/**
* Origins to allow wrapping this app in an iframe and connecting to this Graz
* instance.
*/
allowedIframeParentOrigins: string[];
/**
* Origins to allow wrapping this app in an iframe and connecting to this
* Graz instance.
* Whether or not to auto connect when in an iframe running Cosmiframe. This
* will attempt to connect to all chains provided to GrazProvider.
*
* Defaults to none, which disables the iframe wallet.
* Defaults to true.
*/
allowedIframeParentOrigins: string[] | null;
autoConnect?: boolean;
}

export interface GrazInternalStore {
recentChainIds: string[] | null;
capsuleConfig: CapsuleConfig | null;
capsuleState: CapsuleState | null;
chains: ChainInfo[] | null;
chainsConfig: Record<string, ChainConfig> | null;
iframeOptions: IframeOptions | null;
/**
* Graz will use this number to determine how many concurrent requests to make when using `multiChain` args in hooks.
* Defaults to 3.
Expand Down Expand Up @@ -75,7 +85,7 @@ export type GrazInternalPersistedStore = Pick<
>;

export const grazInternalDefaultValues: GrazInternalStore = {
allowedIframeParentOrigins: null,
iframeOptions: null,
recentChainIds: null,
chains: null,
chainsConfig: null,
Expand Down

0 comments on commit 772b95a

Please sign in to comment.