Skip to content

Commit

Permalink
feat: hooking up new hook for namada keychain
Browse files Browse the repository at this point in the history
  • Loading branch information
jurevans committed Nov 25, 2024
1 parent 87d3b3c commit d3ce3b8
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 68 deletions.
1 change: 1 addition & 0 deletions apps/extension/src/background/approvals/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export class ApprovalsService {
interfaceOrigin: string,
chainId?: string
): Promise<void> {
console.log("approveConnection", { interfaceOrigin, chainId });
const alreadyApproved = await this.isConnectionApproved(
interfaceOrigin,
chainId
Expand Down
25 changes: 16 additions & 9 deletions apps/namadillo/src/App/Common/ConnectExtensionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { ActionButton } from "@namada/components";
import { namadaExtensionAttachStatus } from "atoms/settings";
import { useExtensionConnect } from "hooks/useExtensionConnect";
import { useAtomValue } from "jotai";
import {
namadaExtensionAttachStatus,
namadaExtensionConnectionStatus,
} from "atoms/settings";
import { useNamadaKeychain } from "hooks/useNamadaKeychain";
import { useAtom, useAtomValue } from "jotai";

export const ConnectExtensionButton = (): JSX.Element => {
const extensionAttachStatus = useAtomValue(namadaExtensionAttachStatus);
const { connect, isConnected } = useExtensionConnect();
const { connect } = useNamadaKeychain();
const [connectStatus] = useAtom(namadaExtensionConnectionStatus);

// TODO create an action button when the extension is connected
// but the account is missing, like on useConnectText

return (
<>
{extensionAttachStatus === "attached" && !isConnected && (
<ActionButton backgroundColor="yellow" size="sm" onClick={connect}>
Connect Keychain
</ActionButton>
)}
{extensionAttachStatus === "attached" &&
connectStatus !== "connected" && (
<ActionButton backgroundColor="yellow" size="sm" onClick={connect}>
{connectStatus === "connecting" ?
"Connecting..."
: "Connect Keychain"}
</ActionButton>
)}
{extensionAttachStatus === "detached" && (
<ActionButton
href="https://namada.net/extension"
Expand Down
3 changes: 2 additions & 1 deletion apps/namadillo/src/atoms/settings/atoms.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { isUrlValid, sanitizeUrl } from "@namada/utils";
import { indexerRpcUrlAtom } from "atoms/chain";
import { AttachStatus, ConnectStatus } from "integrations/types";
import { Getter, Setter, atom, getDefaultStore } from "jotai";
import { atomWithMutation, atomWithQuery } from "jotai-tanstack-query";
import { atomWithStorage } from "jotai/utils";
Expand All @@ -12,6 +11,8 @@ import {
isRpcAlive,
} from "./services";

export type AttachStatus = "pending" | "attached" | "detached";
export type ConnectStatus = "idle" | "connecting" | "connected" | "error";
export const namadaExtensionAttachStatus = atom<AttachStatus>("pending");
export const namadaExtensionConnectionStatus = atom<ConnectStatus>("idle");

Expand Down
3 changes: 1 addition & 2 deletions apps/namadillo/src/hooks/useExtensionConnect.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useIntegrationConnection } from "@namada/integrations";
import { ExtensionKey } from "@namada/types";
import { namadaExtensionConnectionStatus } from "atoms/settings";
import { ConnectStatus } from "integrations/types";
import { ConnectStatus, namadaExtensionConnectionStatus } from "atoms/settings";
import { useAtom } from "jotai";
import { useEffect } from "react";

Expand Down
7 changes: 4 additions & 3 deletions apps/namadillo/src/hooks/useExtensionEvents.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useEventListenerOnce } from "@namada/hooks";
import { useIntegration } from "@namada/integrations";
import { Events } from "@namada/types";
import { accountBalanceAtom, defaultAccountAtom } from "atoms/accounts";
import { namadaExtensionConnectionStatus } from "atoms/settings";
import { useAtomValue, useSetAtom } from "jotai";
import { useNamadaKeychain } from "./useNamadaKeychain";

export const useExtensionEvents = (): void => {
const defaultAccount = useAtomValue(defaultAccountAtom);
const balances = useAtomValue(accountBalanceAtom);
const integration = useIntegration("namada");
const { namadaKeychain } = useNamadaKeychain();

const setNamadaExtensionConnected = useSetAtom(
namadaExtensionConnectionStatus
Expand All @@ -21,8 +21,9 @@ export const useExtensionEvents = (): void => {
});

useEventListenerOnce(Events.ConnectionRevoked, async () => {
const injectedNamada = await namadaKeychain.get();
setNamadaExtensionConnected(
(await integration.isConnected()) ? "connected" : "idle"
(await injectedNamada?.isConnected()) ? "connected" : "idle"
);
});
};
82 changes: 34 additions & 48 deletions apps/namadillo/src/hooks/useNamadaKeychain.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { WindowWithNamada } from "@namada/types";
import { chainParametersAtom } from "atoms/chain";
import { AttachStatus, ConnectStatus, Wallet } from "integrations/types";
import { useAtomValue } from "jotai";
import { useEffect, useState } from "react";
import {
namadaExtensionAttachStatus,
namadaExtensionConnectionStatus,
} from "atoms/settings";
import { Wallet } from "integrations/types";
import { useAtom, useAtomValue } from "jotai";
import { useCallback, useState } from "react";

export type InjectedNamada = WindowWithNamada["namada"];

export class NamadaKeychain implements Wallet {
static detect(): boolean {
return Boolean((window as WindowWithNamada).namada);
}

// TODO: Should we use this, or keep our existing download buttons?
install(): void {
console.warn(
"Namada is not available. Redirecting to the Namada download page..."
Expand Down Expand Up @@ -49,60 +58,37 @@ export class NamadaKeychain implements Wallet {
}
}

export const useNamadaKeychain = (): [
attachStatus: AttachStatus,
connectStatus: ConnectStatus,
connect: () => Promise<void>,
namada: NamadaKeychain,
error?: string,
] => {
const [attachStatus, setAttachStatus] = useState<AttachStatus>("detached");
const [connectStatus, setConnectStatus] = useState<ConnectStatus>("idle");
const [connectError, setConnectError] = useState<string>();
export const useNamadaKeychain = (): {
connect: () => Promise<void>;
namadaKeychain: NamadaKeychain;
error?: string;
} => {
const [connectStatus, setConnectStatus] = useAtom(
namadaExtensionConnectionStatus
);
const [attachStatus] = useAtom(namadaExtensionAttachStatus);
const [error, setError] = useState<string>();
const { data: chain } = useAtomValue(chainParametersAtom);
const namadaKeychain = new NamadaKeychain();
const chainId = chain?.chainId;

const connect = async (): Promise<void> => {
if (!chain) {
const connect = useCallback(async (): Promise<void> => {
if (
!chainId ||
attachStatus !== "attached" ||
connectStatus === "connected"
) {
return;
}
setConnectStatus("connecting");
namadaKeychain
.connect(chain.chainId)
.then(() => {
console.info(`Connected to keychain with ${chain.chainId}`);
setConnectStatus("connected");
})
.connect(chainId)
.then(() => setConnectStatus("connected"))
.catch((e) => {
console.error(e);
setConnectStatus("error");
setConnectError(e);
setError(e);
});
};

useEffect(() => {
setAttachStatus("pending");
namadaKeychain
.get()
.then(() => setAttachStatus("attached"))
.catch(() => setAttachStatus("detached"));
}, []);

useEffect(() => {
if (attachStatus === "attached") {
if (chain?.chainId) {
namadaKeychain
.get()
.then((namada) =>
namada
.isConnected(chain.chainId)
.then(() =>
console.info(`Connected to keychain with ${chain.chainId}`)
)
);
}
}
}, [chain]);
}, [chainId, attachStatus, connectStatus]);

return [attachStatus, connectStatus, connect, namadaKeychain, connectError];
return { connect, namadaKeychain, error };
};
4 changes: 2 additions & 2 deletions apps/namadillo/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { init as initShared } from "@namada/shared/src/init-inline";
import init from "@namada/sdk/inline-init";
import { QueryProvider } from "App/Common/QueryProvider";
import { SdkProvider } from "hooks/useSdk";
import React from "react";
Expand All @@ -20,7 +20,7 @@ const container = document.getElementById("root");

if (container) {
const root = createRoot(container);
initShared().then(() => {
init().then(() => {
root.render(
<React.StrictMode>
<QueryProvider>
Expand Down
3 changes: 0 additions & 3 deletions apps/namadillo/src/integrations/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { ChainRegistryEntry } from "types";

export type AttachStatus = "pending" | "attached" | "detached";
export type ConnectStatus = "idle" | "connecting" | "connected" | "error";

// Generic wallet functionality
export interface Wallet {
install(): void;
Expand Down

0 comments on commit d3ce3b8

Please sign in to comment.