feat:re-verify (#243)
* feat: implements verify context badge * feat: implements verify cases in example dapp - valid/invalid/unknown * fix: styled props --------- Co-authored-by: Gancho Radkov <ganchoradkov@gmail.com>
This commit is contained in:
parent
65a3a7bef1
commit
2143840806
@ -0,0 +1,56 @@
|
||||
import * as React from "react";
|
||||
import { ORIGIN_OPTIONS } from "../constants/default";
|
||||
import styled from "styled-components";
|
||||
|
||||
interface OriginSimulationProps {
|
||||
origin: string;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
const SelectContainer = styled.select`
|
||||
width: 150px;
|
||||
background: transparent;
|
||||
color: black;
|
||||
height: 30px;
|
||||
border-radius: 4px;
|
||||
padding: 2px;
|
||||
font-size: "1.25em";
|
||||
bottom: 40px;
|
||||
left: 50px;
|
||||
direction: ltr;
|
||||
unicode-bidi: embed;
|
||||
margin: 5px;
|
||||
`;
|
||||
|
||||
const SelectOption = styled.option`
|
||||
font-size: "1.25em";
|
||||
`;
|
||||
|
||||
const OriginSimulationDropdown = (props: OriginSimulationProps) => {
|
||||
const { origin, show } = props;
|
||||
const setOrigin = React.useCallback((origin: string) => {
|
||||
localStorage.setItem("wallet_connect_dapp_origin", origin);
|
||||
location.reload();
|
||||
}, []);
|
||||
return (
|
||||
<div>
|
||||
{show && (
|
||||
<SelectContainer
|
||||
value={origin}
|
||||
onChange={(e) => setOrigin(e?.target?.value)}
|
||||
>
|
||||
<option disabled>Origin Url:</option>
|
||||
{ORIGIN_OPTIONS.map((e, i) => {
|
||||
return (
|
||||
<SelectOption key={i} value={e.value}>
|
||||
{e.label}
|
||||
</SelectOption>
|
||||
);
|
||||
})}
|
||||
</SelectContainer>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OriginSimulationDropdown;
|
@ -4,9 +4,10 @@ import styled from "styled-components";
|
||||
import Icon from "./Icon";
|
||||
import { useState } from "react";
|
||||
|
||||
interface DropdownProps {
|
||||
interface RelayRegionDropdownProps {
|
||||
relayerRegion: string;
|
||||
setRelayerRegion?: (relayer: string) => void;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
const SelectContainer = styled.select`
|
||||
@ -17,47 +18,27 @@ const SelectContainer = styled.select`
|
||||
border-radius: 4px;
|
||||
padding: 2px;
|
||||
font-size: "1.25em";
|
||||
position: absolute;
|
||||
bottom: 40px;
|
||||
left: 50px;
|
||||
direction: ltr;
|
||||
unicode-bidi: embed;
|
||||
margin: 5px;
|
||||
`;
|
||||
|
||||
const SelectOption = styled.option`
|
||||
font-size: "1.25em";
|
||||
`;
|
||||
|
||||
const Dropdown = (props: DropdownProps) => {
|
||||
const { relayerRegion, setRelayerRegion } = props;
|
||||
const [openSelect, setOpenSelect] = useState(false);
|
||||
const selectRef = React.createRef();
|
||||
|
||||
const openDropdown = () => {
|
||||
setOpenSelect(!openSelect);
|
||||
};
|
||||
|
||||
const RelayRegionDropdown = (props: RelayRegionDropdownProps) => {
|
||||
const { relayerRegion, setRelayerRegion, show } = props;
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
paddingTop: 72,
|
||||
width: 250,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "flex-end",
|
||||
}}
|
||||
>
|
||||
<button onClick={openDropdown} style={{ background: "transparent" }}>
|
||||
<Icon size={30} src={"/assets/settings.svg"} />
|
||||
</button>
|
||||
{openSelect && (
|
||||
<div>
|
||||
{show && (
|
||||
<SelectContainer
|
||||
value={relayerRegion}
|
||||
onChange={(e) => setRelayerRegion?.(e?.target?.value)}
|
||||
>
|
||||
<option selected disabled>
|
||||
Relayer Region:
|
||||
</option>
|
||||
<option disabled>Relayer Region:</option>
|
||||
{REGIONALIZED_RELAYER_ENDPOINTS.map((e, i) => {
|
||||
return (
|
||||
<SelectOption key={i} value={e.value}>
|
||||
@ -71,4 +52,4 @@ const Dropdown = (props: DropdownProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default Dropdown;
|
||||
export default RelayRegionDropdown;
|
@ -53,6 +53,13 @@ export const SToggleContainer = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
export const SDropDownContainer = styled.div`
|
||||
padding-top: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
`;
|
||||
|
||||
export const SFullWidthContainer = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { getAppMetadata } from "@walletconnect/utils";
|
||||
|
||||
if (!process.env.NEXT_PUBLIC_PROJECT_ID)
|
||||
throw new Error("`NEXT_PUBLIC_PROJECT_ID` env variable is missing.");
|
||||
|
||||
@ -48,6 +50,7 @@ export const DEFAULT_APP_METADATA = {
|
||||
description: "React App for WalletConnect",
|
||||
url: "https://walletconnect.com/",
|
||||
icons: ["https://avatars.githubusercontent.com/u/37784886"],
|
||||
verifyUrl: "https://verify.walletconnect.com",
|
||||
};
|
||||
|
||||
/**
|
||||
@ -185,3 +188,18 @@ export const REGIONALIZED_RELAYER_ENDPOINTS: RelayerType[] = [
|
||||
label: "Asia Pacific",
|
||||
},
|
||||
];
|
||||
|
||||
export const ORIGIN_OPTIONS = [
|
||||
{
|
||||
value: getAppMetadata().url,
|
||||
label: "VALID",
|
||||
},
|
||||
{
|
||||
value: "https://invalid.origin",
|
||||
label: "INVALID",
|
||||
},
|
||||
{
|
||||
value: "unknown",
|
||||
label: "UNKNOWN",
|
||||
},
|
||||
];
|
||||
|
@ -46,6 +46,7 @@ interface IContext {
|
||||
isFetchingBalances: boolean;
|
||||
setChains: any;
|
||||
setRelayerRegion: any;
|
||||
origin: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,7 +87,7 @@ export function ClientContextProvider({
|
||||
const [relayerRegion, setRelayerRegion] = useState<string>(
|
||||
DEFAULT_RELAY_URL!
|
||||
);
|
||||
|
||||
const [origin, setOrigin] = useState<string>(getAppMetadata().url);
|
||||
const reset = () => {
|
||||
setSession(undefined);
|
||||
setBalances({});
|
||||
@ -284,15 +285,24 @@ export function ClientContextProvider({
|
||||
const createClient = useCallback(async () => {
|
||||
try {
|
||||
setIsInitializing(true);
|
||||
|
||||
const claimedOrigin =
|
||||
localStorage.getItem("wallet_connect_dapp_origin") || origin;
|
||||
const _client = await Client.init({
|
||||
logger: DEFAULT_LOGGER,
|
||||
relayUrl: relayerRegion,
|
||||
projectId: DEFAULT_PROJECT_ID,
|
||||
metadata: getAppMetadata() || DEFAULT_APP_METADATA,
|
||||
metadata: {
|
||||
...(getAppMetadata() || DEFAULT_APP_METADATA),
|
||||
url: claimedOrigin,
|
||||
verifyUrl:
|
||||
claimedOrigin === "unknown"
|
||||
? "http://non-existent-url"
|
||||
: DEFAULT_APP_METADATA.verifyUrl, // simulates `UNKNOWN` verify context
|
||||
},
|
||||
});
|
||||
|
||||
setClient(_client);
|
||||
setOrigin(_client.metadata.url);
|
||||
prevRelayerValue.current = relayerRegion;
|
||||
await _subscribeToEvents(_client);
|
||||
await _checkPersistedState(_client);
|
||||
@ -302,7 +312,13 @@ export function ClientContextProvider({
|
||||
} finally {
|
||||
setIsInitializing(false);
|
||||
}
|
||||
}, [_checkPersistedState, _subscribeToEvents, _logClientId, relayerRegion]);
|
||||
}, [
|
||||
_checkPersistedState,
|
||||
_subscribeToEvents,
|
||||
_logClientId,
|
||||
relayerRegion,
|
||||
origin,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!client) {
|
||||
@ -329,6 +345,7 @@ export function ClientContextProvider({
|
||||
disconnect,
|
||||
setChains,
|
||||
setRelayerRegion,
|
||||
origin,
|
||||
}),
|
||||
[
|
||||
pairings,
|
||||
@ -345,6 +362,7 @@ export function ClientContextProvider({
|
||||
disconnect,
|
||||
setChains,
|
||||
setRelayerRegion,
|
||||
origin,
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -4,7 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
|
||||
import Banner from "../components/Banner";
|
||||
import Blockchain from "../components/Blockchain";
|
||||
import Column from "../components/Column";
|
||||
import Dropdown from "../components/Dropdown";
|
||||
import RelayRegionDropdown from "../components/RelayRegionDropdown";
|
||||
import Header from "../components/Header";
|
||||
import Modal from "../components/Modal";
|
||||
import {
|
||||
@ -32,6 +32,7 @@ import {
|
||||
SButtonContainer,
|
||||
SConnectButton,
|
||||
SContent,
|
||||
SDropDownContainer,
|
||||
SLanding,
|
||||
SLayout,
|
||||
SToggleContainer,
|
||||
@ -39,6 +40,8 @@ import {
|
||||
import { useWalletConnectClient } from "../contexts/ClientContext";
|
||||
import { useJsonRpc } from "../contexts/JsonRpcContext";
|
||||
import { useChainData } from "../contexts/ChainDataContext";
|
||||
import Icon from "../components/Icon";
|
||||
import OriginSimulationDropdown from "../components/OriginSimulationDropdown";
|
||||
|
||||
// Normal import does not work here
|
||||
const { version } = require("@walletconnect/sign-client/package.json");
|
||||
@ -66,6 +69,7 @@ const Home: NextPage = () => {
|
||||
isInitializing,
|
||||
setChains,
|
||||
setRelayerRegion,
|
||||
origin,
|
||||
} = useWalletConnectClient();
|
||||
|
||||
// Use `JsonRpcContext` to provide us with relevant RPC methods and states.
|
||||
@ -444,6 +448,12 @@ const Home: NextPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const [openSelect, setOpenSelect] = useState(false);
|
||||
|
||||
const openDropdown = () => {
|
||||
setOpenSelect(!openSelect);
|
||||
};
|
||||
|
||||
const renderContent = () => {
|
||||
const chainOptions = isTestnet ? DEFAULT_TEST_CHAINS : DEFAULT_MAIN_CHAINS;
|
||||
|
||||
@ -469,10 +479,17 @@ const Home: NextPage = () => {
|
||||
<SConnectButton left onClick={onConnect} disabled={!chains.length}>
|
||||
Connect
|
||||
</SConnectButton>
|
||||
<Dropdown
|
||||
relayerRegion={relayerRegion}
|
||||
setRelayerRegion={setRelayerRegion}
|
||||
/>
|
||||
<SDropDownContainer>
|
||||
<RelayRegionDropdown
|
||||
relayerRegion={relayerRegion}
|
||||
setRelayerRegion={setRelayerRegion}
|
||||
show={openSelect}
|
||||
/>
|
||||
<OriginSimulationDropdown origin={origin} show={openSelect} />
|
||||
</SDropDownContainer>
|
||||
<button onClick={openDropdown} style={{ background: "transparent" }}>
|
||||
<Icon size={30} src={"/assets/settings.svg"} />
|
||||
</button>
|
||||
</SButtonContainer>
|
||||
</SLanding>
|
||||
) : (
|
||||
|
@ -1,3 +1,8 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
import SettingsStore from '@/store/SettingsStore'
|
||||
import { getVerifyStatus } from '@/utils/HelperUtil'
|
||||
import { Avatar, Col, Link, Row, Text } from '@nextui-org/react'
|
||||
import { SignClientTypes } from '@walletconnect/types'
|
||||
|
||||
@ -12,17 +17,26 @@ interface IProps {
|
||||
* Components
|
||||
*/
|
||||
export default function ProjectInfoCard({ metadata }: IProps) {
|
||||
const { currentRequestVerifyContext } = useSnapshot(SettingsStore.state)
|
||||
const { icons, name, url } = metadata
|
||||
|
||||
const validation = useMemo(
|
||||
() => getVerifyStatus(currentRequestVerifyContext),
|
||||
[currentRequestVerifyContext]
|
||||
)
|
||||
return (
|
||||
<Row align="center">
|
||||
<Col span={3}>
|
||||
<Avatar src={icons[0]} />
|
||||
</Col>
|
||||
<Col span={14}>
|
||||
<Text h5>{name}</Text>
|
||||
<Link href={url}>{url}</Link>
|
||||
</Col>
|
||||
</Row>
|
||||
<>
|
||||
<Row align="center">
|
||||
<Col span={3}>
|
||||
<Avatar src={icons[0]} />
|
||||
</Col>
|
||||
<Col span={15}>
|
||||
<Text h5>{name}</Text>
|
||||
<Row>
|
||||
<Link href={url}>{url}</Link>
|
||||
<Text style={{ marginLeft: '5px' }}>{validation}</Text>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import { POLKADOT_SIGNING_METHODS } from '@/data/PolkadotData'
|
||||
import { MULTIVERSX_SIGNING_METHODS } from '@/data/MultiversxData'
|
||||
import { TRON_SIGNING_METHODS } from '@/data/TronData'
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import SettingsStore from '@/store/SettingsStore'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { SignClientTypes } from '@walletconnect/types'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
@ -19,6 +21,8 @@ export default function useWalletConnectEventsManager(initialized: boolean) {
|
||||
*****************************************************************************/
|
||||
const onSessionProposal = useCallback(
|
||||
(proposal: SignClientTypes.EventArguments['session_proposal']) => {
|
||||
// set the verify context so it can be displayed in the projectInfoCard
|
||||
SettingsStore.setCurrentRequestVerifyContext(proposal.verifyContext)
|
||||
ModalStore.open('SessionProposalModal', { proposal })
|
||||
},
|
||||
[]
|
||||
@ -30,9 +34,11 @@ export default function useWalletConnectEventsManager(initialized: boolean) {
|
||||
const onSessionRequest = useCallback(
|
||||
async (requestEvent: SignClientTypes.EventArguments['session_request']) => {
|
||||
console.log('session_request', requestEvent)
|
||||
const { topic, params } = requestEvent
|
||||
const { topic, params, verifyContext } = requestEvent
|
||||
const { request } = params
|
||||
const requestSession = signClient.session.get(topic)
|
||||
// set the verify context so it can be displayed in the projectInfoCard
|
||||
SettingsStore.setCurrentRequestVerifyContext(verifyContext)
|
||||
|
||||
switch (request.method) {
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN:
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Verify } from '@walletconnect/types'
|
||||
import { proxy } from 'valtio'
|
||||
|
||||
/**
|
||||
@ -17,6 +18,7 @@ interface State {
|
||||
kadenaAddress: string
|
||||
relayerRegionURL: string
|
||||
activeChainId: string
|
||||
currentRequestVerifyContext?: Verify.Context
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,6 +91,10 @@ const SettingsStore = {
|
||||
state.activeChainId = value
|
||||
},
|
||||
|
||||
setCurrentRequestVerifyContext(context: Verify.Context) {
|
||||
state.currentRequestVerifyContext = context
|
||||
},
|
||||
|
||||
toggleTestNets() {
|
||||
state.testNets = !state.testNets
|
||||
if (state.testNets) {
|
||||
|
@ -9,6 +9,7 @@ import { TRON_CHAINS, TTronChain } from '@/data/TronData'
|
||||
import { KADENA_CHAINS, TKadenaChain } from '@/data/KadenaData'
|
||||
|
||||
import { utils } from 'ethers'
|
||||
import { Verify } from '@walletconnect/types'
|
||||
|
||||
/**
|
||||
* Truncates string (in the middle) via given lenght value
|
||||
@ -160,3 +161,15 @@ export function formatChainName(chainId: string) {
|
||||
chainId
|
||||
)
|
||||
}
|
||||
|
||||
export function getVerifyStatus(context?: Verify.Context) {
|
||||
if (!context) return ''
|
||||
switch (context.verified.validation) {
|
||||
case 'VALID':
|
||||
return '✅ Verified'
|
||||
case 'INVALID':
|
||||
return '❌ Origin does not match'
|
||||
case 'UNKNOWN':
|
||||
return '❓ Unknown'
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user