Skip to content

Commit

Permalink
feat(reference): act-1327 - added support eip-6963 (#1389)
Browse files Browse the repository at this point in the history
* feat(reference): act-1327 - added support eip-6963

* feat(reference): remove selecte wallets
  • Loading branch information
TrofimovAnton85 authored Jul 10, 2024
1 parent f624894 commit c3a9e47
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 12 deletions.
36 changes: 31 additions & 5 deletions src/components/ParserOpenRPC/AuthBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import React from "react";
import Link from "@docusaurus/Link";
import styles from "./styles.module.css";
import global from "../global.module.css";
import { EIP6963ProviderDetail } from "@site/src/hooks/store.ts"

interface AuthBoxProps {
isMetamaskInstalled: boolean;
metamaskProviders: any;
handleConnect: (i) => void;
selectedProvider?: number;
}

const MetamaskInstallMessage = () => (
Expand All @@ -15,10 +18,33 @@ const MetamaskInstallMessage = () => (
</div>
);

export const AuthBox = ({ isMetamaskInstalled }: AuthBoxProps) => {
export const AuthBox = ({ metamaskProviders = [], selectedProvider, handleConnect }: AuthBoxProps) => {
if (metamaskProviders.length === 0) {
return <MetamaskInstallMessage />
}

if (metamaskProviders.length > 0) {
return null
}

return (
<>
{!isMetamaskInstalled ? <MetamaskInstallMessage /> : null}
</>
<div className={styles.msgWrapper}>
<p>Select a MetaMask provider to use interactive features:</p>
<div className={styles.mmBtnRow}>
{metamaskProviders.map((provider: EIP6963ProviderDetail, i) => (
<div key={provider.info.uuid} className={styles.mmBtnCol}>
<button className={styles.mmBtn} onClick={() => handleConnect(i)}>
<img
src={provider.info.icon}
alt={provider.info.name}
width="30"
/>
<div className="padding-left--md">{provider.info.name}</div>
{selectedProvider === i && <span className={styles.mmBtnCheck}>&#10003;</span>}
</button>
</div>
))}
</div>
</div>
);
};
34 changes: 34 additions & 0 deletions src/components/ParserOpenRPC/AuthBox/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,37 @@
font-size: 14px;
line-height: 22px;
}

.mmBtnRow {
display: flex;
flex-wrap: wrap;
}

.mmBtnCol {
width: 100%;
margin-bottom: 10px;
}

.mmBtn {
position: relative;
display: flex;
align-items: center;
padding: 16px 30px 16px 20px;
width: 100%;
background: none;
border-radius: 10px;
outline: none;
font-size: 16px;
font-weight: 500;
line-height: 22px;
border: 1px solid rgba(3, 118, 201, 1);
color: rgba(3, 118, 201, 1);
}

.mmBtnCheck {
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 15px;
font-size: 16px;
}
31 changes: 25 additions & 6 deletions src/components/ParserOpenRPC/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
trackInputChangeForSegment
} from "@site/src/lib/segmentAnalytics";
import { useLocation } from "@docusaurus/router";
import { useSyncProviders } from "@site/src/hooks/useSyncProviders.ts"

interface ParserProps {
network: NETWORK_NAMES;
Expand All @@ -34,7 +35,6 @@ export const ParserOpenRPCContext = createContext<ParserOpenRPCContextProps | nu

export default function ParserOpenRPC({ network, method }: ParserProps) {
if (!method || !network) return null;
const [metamaskInstalled, setMetamaskInstalled] = useState(false);
const [isModalOpen, setModalOpen] = useState(false);
const [reqResult, setReqResult] = useState(null);
const [paramsData, setParamsData] = useState([]);
Expand Down Expand Up @@ -90,16 +90,30 @@ export default function ParserOpenRPC({ network, method }: ParserProps) {

const location = useLocation();

const [selectedWallet, setSelectedWallet] = useState(0);
const providers = useSyncProviders();

const handleConnect = (i:number) => {
setSelectedWallet(i);
}

useEffect(() => {
const installed = !!(window as any)?.ethereum;
setMetamaskInstalled(installed);
trackPageViewForSegment({
name: "Reference page",
path: location.pathname,
userExperience: "new"
})
}, []);

const metamaskProviders = useMemo(() => {
const isMetamasks = providers.filter(pr => pr?.info?.name?.includes("MetaMask"));
if (isMetamasks.length > 1) {
const indexWallet = isMetamasks.findIndex(item => item.info.name === "MetaMask");
setSelectedWallet(indexWallet);
}
return isMetamasks;
}, [providers]);

const onParamsChangeHandle = (data) => {
if (typeof data !== 'object' || data === null || Object.keys(data).length === 0) {
setParamsData([]);
Expand All @@ -112,8 +126,9 @@ export default function ParserOpenRPC({ network, method }: ParserProps) {
}

const onSubmitRequestHandle = async () => {
if (metamaskProviders.length === 0) return
try {
const response = await (window as any).ethereum.request({
const response = await metamaskProviders[selectedWallet].provider.request({
method: method,
params: paramsData
})
Expand Down Expand Up @@ -188,9 +203,13 @@ export default function ParserOpenRPC({ network, method }: ParserProps) {
</div>
<div className={global.colRight}>
<div className={global.stickyCol}>
<AuthBox isMetamaskInstalled={metamaskInstalled} />
<AuthBox
metamaskProviders={metamaskProviders}
selectedProvider={selectedWallet}
handleConnect={handleConnect}
/>
<RequestBox
isMetamaskInstalled={metamaskInstalled}
isMetamaskInstalled={metamaskProviders.length > 0}
method={method}
params={currentMethodData.params}
paramsData={paramsData}
Expand Down
49 changes: 49 additions & 0 deletions src/hooks/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
declare global{
interface WindowEventMap {
"eip6963:announceProvider": CustomEvent
}
}

export interface EIP6963ProviderInfo {
walletId: string;
uuid: string;
name: string;
icon: string;
}

export interface EIP1193Provider {
isStatus?: boolean;
host?: string;
path?: string;
sendAsync?: (request: { method: string, params?: Array<unknown> }, callback: (error: Error | null, response: unknown) => void) => void;
send?: (request: { method: string, params?: Array<unknown> }, callback: (error: Error | null, response: unknown) => void) => void;
request: (request: { method: string, params?: Array<unknown> }) => Promise<unknown>;
}

export interface EIP6963ProviderDetail {
info: EIP6963ProviderInfo;
provider: EIP1193Provider;
}

type EIP6963AnnounceProviderEvent = {
detail: {
info: EIP6963ProviderInfo;
provider: EIP1193Provider;
}
}

let providers: EIP6963ProviderDetail[] = []
export const store = {
value: ()=> providers,
subscribe: (callback: ()=> void) => {
function onAnnouncement(event: EIP6963AnnounceProviderEvent){
if(providers.map(p => p.info.uuid).includes(event.detail.info.uuid)) return
providers = [...providers, event.detail]
callback()
}
window.addEventListener("eip6963:announceProvider", onAnnouncement);
window.dispatchEvent(new Event("eip6963:requestProvider"));

return () => window.removeEventListener("eip6963:announceProvider", onAnnouncement)
}
}
4 changes: 4 additions & 0 deletions src/hooks/useSyncProviders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { useSyncExternalStore } from "react";
import { store } from "./store";

export const useSyncProviders = ()=> useSyncExternalStore(store.subscribe, store.value, store.value)
2 changes: 1 addition & 1 deletion wallet/reference/new-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ sidebar_class_name: "hidden"
import ParserOpenRPC from "@site/src/components/ParserOpenRPC";
import { NETWORK_NAMES } from "@site/src/plugins/plugin-json-rpc";

<ParserOpenRPC network={NETWORK_NAMES.metamask} method="eth_call" />
<ParserOpenRPC network={NETWORK_NAMES.metamask} method="eth_requestAccounts" />

0 comments on commit c3a9e47

Please sign in to comment.