wip: remove metamask app (#4049)

* wip: disable metamask app

* fix: remove dont comment

* fix: remove dont comment

* Update packages/app-store/index.ts

Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* Update packages/app-store/index.ts

Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* fix: bookingpage

* fix: remove web3Details zod

* removed unused web3

* Build fixes

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
This commit is contained in:
Agusti Fernandez Pardo 2022-09-03 01:55:12 +02:00 committed by GitHub
parent 015ed6d4f9
commit 1948455be0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 22 additions and 862 deletions

View File

@ -15,7 +15,6 @@ import {
useIsBackgroundTransparent,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
import { useContracts } from "@calcom/features/ee/web3/contexts/contractsContext";
import CustomBranding from "@calcom/lib/CustomBranding";
import classNames from "@calcom/lib/classNames";
import { WEBSITE_URL } from "@calcom/lib/constants";
@ -292,7 +291,6 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
const { rescheduleUid } = query;
useTheme(profile.theme);
const { t } = useLocale();
const { contracts } = useContracts();
const availabilityDatePickerEmbedStyles = useEmbedStyles("availabilityDatePicker");
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
@ -313,15 +311,6 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
// TODO: Improve this;
useExposePlanGlobally(eventType.users.length === 1 ? eventType.users[0].plan : "PRO");
// TODO: this needs to be extracted elsewhere
useEffect(() => {
if (eventType.metadata.smartContractAddress) {
const eventOwner = eventType.users[0];
if (!contracts[(eventType.metadata.smartContractAddress || null) as number])
router.replace(`/${eventOwner.username}`);
}
}, [contracts, eventType.metadata.smartContractAddress, eventType.users, router]);
const [recurringEventCount, setRecurringEventCount] = useState(eventType.recurringEvent?.count);
const telemetry = useTelemetry();

View File

@ -27,7 +27,6 @@ import {
useIsBackgroundTransparent,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
import { useContracts } from "@calcom/features/ee/web3/contexts/contractsContext";
import CustomBranding from "@calcom/lib/CustomBranding";
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@ -96,7 +95,6 @@ const BookingPage = ({
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
const router = useRouter();
const { contracts } = useContracts();
const { data: session } = useSession();
const isBackgroundTransparent = useIsBackgroundTransparent();
const telemetry = useTelemetry();
@ -112,15 +110,6 @@ const BookingPage = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (eventType.metadata.smartContractAddress) {
const eventOwner = eventType.users[0];
if (!contracts[(eventType.metadata.smartContractAddress || null) as number])
router.replace(`/${eventOwner.username}`);
}
}, [contracts, eventType.metadata.smartContractAddress, eventType.users, router]);
const mutation = useMutation(createBooking, {
onSuccess: async (responseData) => {
const { id, attendees, paymentUid } = responseData;
@ -192,9 +181,6 @@ const BookingPage = ({
const date = asStringOrNull(router.query.date);
const [guestToggle, setGuestToggle] = useState(booking && booking.attendees.length > 1);
const eventTypeDetail = { isWeb3Active: false, ...eventType };
// it would be nice if Prisma at some point in the future allowed for Json<Location>; as of now this is not the case.
const locations: LocationObject[] = useMemo(
() => (eventType.locations as LocationObject[]) || [],
@ -344,20 +330,11 @@ const BookingPage = ({
{}
);
let web3Details: Record<"userWallet" | "userSignature", string> | undefined;
if (eventTypeDetail.metadata.smartContractAddress) {
web3Details = {
userWallet: window.web3.currentProvider.selectedAddress,
userSignature: contracts[(eventTypeDetail.metadata.smartContractAddress || null) as number],
};
}
if (recurringDates.length) {
// Identify set of bookings to one intance of recurring event to support batch changes
const recurringEventId = uuidv4();
const recurringBookings = recurringDates.map((recurringDate) => ({
...booking,
web3Details,
start: dayjs(recurringDate).format(),
end: dayjs(recurringDate).add(eventType.length, "minute").format(),
eventTypeId: eventType.id,
@ -387,7 +364,6 @@ const BookingPage = ({
} else {
mutation.mutate({
...booking,
web3Details,
start: dayjs(date).format(),
end: dayjs(date).add(eventType.length, "minute").format(),
eventTypeId: eventType.id,
@ -549,11 +525,6 @@ const BookingPage = ({
)}
</div>
</div>
{eventTypeDetail.isWeb3Active && eventType.metadata.smartContractAddress && (
<p className="text-bookinglight mb-1 -ml-2 px-2">
{t("requires_ownership_of_a_token") + " " + eventType.metadata.smartContractAddress}
</p>
)}
{booking?.startTime && rescheduleUid && (
<div>
<p className="mt-8 mb-2 text-sm " data-testid="former_time_p">

View File

@ -9,7 +9,6 @@ import { ComponentProps, ReactNode } from "react";
import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/providerDynamic";
import DynamicIntercomProvider from "@calcom/features/ee/support/lib/intercom/providerDynamic";
import { ContractsProvider } from "@calcom/features/ee/web3/contexts/contractsContext";
import { trpc } from "@calcom/trpc/react";
import { MetaProvider } from "@calcom/ui/v2/core/Meta";
@ -71,22 +70,20 @@ const AppProviders = (props: AppPropsWithChildren) => {
const RemainingProviders = (
<EventCollectionProvider options={{ apiPath: "/api/collect-events" }}>
<ContractsProvider>
<SessionProvider session={session || undefined}>
<CustomI18nextProvider {...props}>
<TooltipProvider>
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
<ThemeProvider
enableColorScheme={false}
storageKey={storageKey}
forcedTheme={forcedTheme}
attribute="class">
<MetaProvider>{props.children}</MetaProvider>
</ThemeProvider>
</TooltipProvider>
</CustomI18nextProvider>
</SessionProvider>
</ContractsProvider>
<SessionProvider session={session || undefined}>
<CustomI18nextProvider {...props}>
<TooltipProvider>
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
<ThemeProvider
enableColorScheme={false}
storageKey={storageKey}
forcedTheme={forcedTheme}
attribute="class">
<MetaProvider>{props.children}</MetaProvider>
</ThemeProvider>
</TooltipProvider>
</CustomI18nextProvider>
</SessionProvider>
</EventCollectionProvider>
);

View File

@ -43,7 +43,6 @@
"@heroicons/react": "^1.0.6",
"@hookform/error-message": "^2.0.0",
"@hookform/resolvers": "^2.9.7",
"@metamask/providers": "^8.1.1",
"@next-auth/prisma-adapter": "^1.0.4",
"@next/bundle-analyzer": "12.1.6",
"@radix-ui/react-avatar": "^0.1.4",

View File

@ -14,7 +14,6 @@ import {
useEmbedStyles,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
import type { CryptoSectionProps } from "@calcom/features/ee/web3/components/CryptoSection";
import CustomBranding from "@calcom/lib/CustomBranding";
import defaultEvents, {
getDynamicEventDescription,
@ -39,14 +38,6 @@ import { ssrInit } from "@server/lib/ssr";
const EventTypeDescription = dynamic(() => import("@calcom/ui/v2/modules/event-types/EventTypeDescription"));
const HeadSeo = dynamic(() => import("@components/seo/head-seo"));
const CryptoSection = dynamic<CryptoSectionProps>(
() => import("@calcom/features/ee/web3/components/CryptoSection")
);
interface EvtsToVerify {
[evtId: string]: boolean;
}
export default function User(props: inferSSRProps<typeof getServerSideProps>) {
const { users, profile, eventTypes, isDynamicGroup, dynamicNames, dynamicUsernames, isSingleUser } = props;
const [user] = users; //To be used when we only have a single user, not dynamic group
@ -103,7 +94,6 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
delete query.user; // So it doesn't display in the Link (and make tests fail)
useExposePlanGlobally("PRO");
const nameOrUsername = user.name || user.username || "";
const [evtsToVerify, setEvtsToVerify] = useState<EvtsToVerify>({});
const telemetry = useTelemetry();
useEffect(() => {
@ -181,20 +171,10 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
query,
}}>
<a
onClick={async (e) => {
// If a token is required for this event type, add a click listener that checks whether the user verified their wallet or not
if (type.metadata.smartContractAddress && !evtsToVerify[type.id]) {
const showToast = (await import("@calcom/lib/notification")).default;
e.preventDefault();
showToast(
"You must verify a wallet with a token belonging to the specified smart contract first",
"error"
);
} else {
sdkActionManager?.fire("eventTypeSelected", {
eventType: type,
});
}
onClick={async () => {
sdkActionManager?.fire("eventTypeSelected", {
eventType: type,
});
}}
className="block w-full p-5"
data-testid="event-type-link">
@ -207,16 +187,6 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
<EventTypeDescription eventType={type} />
</a>
</Link>
{type.isWeb3Active && type.metadata.smartContractAddress && (
<CryptoSection
id={type.id}
pathname={`/${user.username}/${type.slug}`}
smartContractAddress={type.metadata.smartContractAddress as string}
verified={evtsToVerify[type.id]}
setEvtsToVerify={setEvtsToVerify}
oneStep
/>
)}
</div>
))
)}
@ -340,21 +310,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
brandColor: user.brandColor,
darkBrandColor: user.darkBrandColor,
};
const usersIds = users.map((user) => user.id);
const credentials = await prisma.credential.findMany({
where: {
userId: {
in: usersIds,
},
},
select: {
id: true,
type: true,
key: true,
},
});
const web3Credentials = credentials.find((credential) => credential.type.includes("_web3"));
const eventTypesWithHidden = isDynamicGroup ? [] : await getEventTypesWithHiddenFromDB(user.id, user.plan);
const dataFetchEnd = Date.now();
@ -366,10 +321,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
const eventTypes = eventTypesRaw.map((eventType) => ({
...eventType,
metadata: (eventType.metadata || {}) as JSONObject,
isWeb3Active:
web3Credentials && web3Credentials.key
? (((web3Credentials.key as JSONObject).isWeb3Active || false) as boolean)
: false,
}));
const isSingleUser = users.length === 1;

View File

@ -111,29 +111,10 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
if (!eventTypeRaw) return { notFound: true };
const credentials = await prisma.credential.findMany({
where: {
userId: {
in: users.map((user) => user.id),
},
},
select: {
id: true,
type: true,
key: true,
},
});
const web3Credentials = credentials.find((credential) => credential.type.includes("_web3"));
const eventType = {
...eventTypeRaw,
metadata: (eventTypeRaw.metadata || {}) as JSONObject,
recurringEvent: parseRecurringEvent(eventTypeRaw.recurringEvent),
isWeb3Active:
web3Credentials && web3Credentials.key
? (((web3Credentials.key as JSONObject).isWeb3Active || false) as boolean)
: false,
};
const eventTypeObject = [eventType].map((e) => {

View File

@ -19,7 +19,6 @@ import {
sendScheduledEmails,
sendScheduledSeatsEmails,
} from "@calcom/emails";
import verifyAccount from "@calcom/features/ee/web3/utils/verifyAccount";
import { scheduleWorkflowReminders } from "@calcom/features/ee/workflows/lib/reminders/reminderScheduler";
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
import { getDefaultEvent, getGroupName, getUsernameList } from "@calcom/lib/defaultEvents";
@ -556,12 +555,6 @@ async function handler(req: NextApiRequest) {
}
async function createBooking() {
// @TODO: check as metadata
if (reqBody.web3Details) {
const { web3Details } = reqBody;
await verifyAccount(web3Details.userSignature, web3Details.userWallet);
}
if (originalRescheduledBooking) {
evt.title = originalRescheduledBooking?.title || evt.title;
evt.description = originalRescheduledBooking?.description || evt.additionalNotes;

View File

@ -1,23 +1,18 @@
import Image from "next/image";
import React from "react";
import { InstallAppButton } from "@calcom/app-store/components";
import { WEBSITE_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { trpc } from "@calcom/trpc/react";
import type { App } from "@calcom/types/App";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import EmptyScreen from "@calcom/ui/EmptyScreen";
import { Icon } from "@calcom/ui/Icon";
import { List, ListItem, ListItemText, ListItemTitle } from "@calcom/ui/List";
import { List } from "@calcom/ui/List";
import Shell, { ShellSubHeading } from "@calcom/ui/Shell";
import SkeletonLoader from "@calcom/ui/apps/SkeletonLoader";
import { QueryCell } from "@lib/QueryCell";
import classNames from "@lib/classNames";
import { HttpError } from "@lib/core/http/error";
import AppsShell from "@components/AppsShell";
import { CalendarListContainer } from "@components/integrations/CalendarListContainer";
@ -144,81 +139,6 @@ const IntegrationsContainer = ({ variant, className = "" }: IntegrationsContaine
);
};
function Web3Container() {
const { t } = useLocale();
const result = trpc.useQuery(["viewer.web3Integration"]);
const isWeb3Active = !!result.data?.isWeb3Active;
return (
<>
{isWeb3Active && (
<>
<ShellSubHeading title="Web3" subtitle={t("meet_people_with_the_same_tokens")} className="mt-10" />
<div className="lg:col-span-9 lg:pb-8">
<List>
<ListItem className={classNames("flex-col")}>
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-3")}>
<Image width={40} height={40} src="/api/app-store/metamask/icon.svg" alt="Embed" />
<div className="flex-grow truncate pl-2">
<ListItemTitle component="h3">
MetaMask (
<a
className="text-blue-500"
target="_blank"
href={`${WEBSITE_URL}/web3`}
rel="noreferrer">
Read more
</a>
)
</ListItemTitle>
<ListItemText component="p">{t("only_book_people_and_allow")}</ListItemText>
</div>
<Web3ConnectBtn />
</div>
</ListItem>
</List>
</div>
</>
)}
</>
);
}
function Web3ConnectBtn() {
const { t } = useLocale();
const utils = trpc.useContext();
const result = trpc.useQuery(["viewer.web3Integration"]);
const mutation = trpc.useMutation("viewer.enableOrDisableWeb3", {
onSuccess: async (result) => {
const { key } = result;
if ((key as { isWeb3Active: boolean }).isWeb3Active) {
showToast(t("web3_metamask_added"), "success");
} else {
showToast(t("web3_metamask_disconnected"), "success");
}
utils.invalidateQueries("viewer.web3Integration");
},
onError: (err) => {
if (err instanceof HttpError) {
const message = `${err.statusCode}: ${err.message}`;
showToast(message, "error");
}
},
});
return (
<Button
loading={mutation.isLoading}
color={result.data?.isWeb3Active ? "warn" : "secondary"}
disabled={result.isLoading || mutation.isLoading}
onClick={() => {
mutation.mutateAsync({});
}}
data-testid="metamask">
{result.data?.isWeb3Active ? t("remove") : t("add")}
</Button>
);
}
export default function IntegrationsPage() {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.integrations", { onlyInstalled: true }]);
@ -238,7 +158,6 @@ export default function IntegrationsPage() {
<CalendarListContainer />
<IntegrationsContainer variant="payment" className="mt-8" />
<IntegrationsContainer variant="other" className="mt-8" />
<Web3Container />
</>
) : (
<EmptyScreen

View File

@ -68,30 +68,10 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
const eventTypeRaw = hashedLink?.eventType;
if (!eventTypeRaw) return { notFound: true };
const credentials = await prisma.credential.findMany({
where: {
userId: {
in: users.map((user) => user.id),
},
},
select: {
id: true,
type: true,
key: true,
},
});
const web3Credentials = credentials.find((credential) => credential.type.includes("_web3"));
const eventType = {
...eventTypeRaw,
metadata: (eventTypeRaw.metadata || {}) as JSONObject,
recurringEvent: parseRecurringEvent(eventTypeRaw.recurringEvent),
isWeb3Active:
web3Credentials && web3Credentials.key
? (((web3Credentials.key as JSONObject).isWeb3Active || false) as boolean)
: false,
};
const eventTypeObject = [eventType].map((e) => {

View File

@ -76,7 +76,6 @@ type OptionTypeBase = {
export type FormValues = {
title: string;
eventTitle: string;
smartContractAddress: string;
eventName: string;
slug: string;
length: number;
@ -559,7 +558,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
const {
periodDates,
periodCountCalendarDays,
smartContractAddress,
giphyThankYouPage,
beforeBufferTime,
afterBufferTime,
@ -581,7 +579,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
afterEventBuffer: afterBufferTime,
seatsPerTimeSlot: Number.isNaN(seatsPerTimeSlot) ? null : seatsPerTimeSlot,
metadata: {
...(smartContractAddress ? { smartContractAddress } : {}),
...(giphyThankYouPage ? { giphyThankYouPage } : {}),
},
});
@ -853,28 +850,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
</div>
</div>
{eventType.isWeb3Active && (
<div className="block items-center sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<label
htmlFor="smartContractAddress"
className="flex text-sm font-medium text-neutral-700">
{t("Smart Contract Address")}
</label>
</div>
<div className="w-full">
<div className="relative mt-1 rounded-sm">
<input
type="text"
className="block w-full rounded-sm border-gray-300 text-sm "
placeholder={t("Example: 0x71c7656ec7ab88b098defb751b7401b5f6d8976f")}
defaultValue={(eventType.metadata.smartContractAddress || "") as string}
{...formMethods.register("smartContractAddress")}
/>
</div>
</div>
</div>
)}
<div className="block items-center sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<label
@ -1900,17 +1875,12 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
},
});
const web3Credentials = credentials.find((credential) => credential.type.includes("_web3"));
const { locations, metadata, ...restEventType } = rawEventType;
const eventType = {
...restEventType,
recurringEvent: parseRecurringEvent(restEventType.recurringEvent),
locations: locations as unknown as LocationObject[],
metadata: (metadata || {}) as JSONObject,
isWeb3Active:
web3Credentials && web3Credentials.key
? (((web3Credentials.key as JSONObject).isWeb3Active || false) as boolean)
: false,
};
const hasGiphyIntegration = !!credentials.find((credential) => credential.type === "giphy_other");

View File

@ -38,7 +38,6 @@ import { getTranslation } from "@server/lib/i18n";
export type FormValues = {
title: string;
eventTitle: string;
smartContractAddress: string;
eventName: string;
slug: string;
length: number;
@ -203,7 +202,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
const {
periodDates,
periodCountCalendarDays,
smartContractAddress,
giphyThankYouPage,
beforeBufferTime,
afterBufferTime,
@ -225,7 +223,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
afterEventBuffer: afterBufferTime,
seatsPerTimeSlot,
metadata: {
...(smartContractAddress ? { smartContractAddress } : {}),
...(giphyThankYouPage ? { giphyThankYouPage } : {}),
},
});
@ -408,17 +405,12 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
},
});
const web3Credentials = credentials.find((credential) => credential.type.includes("_web3"));
const { locations, metadata, ...restEventType } = rawEventType;
const eventType = {
...restEventType,
recurringEvent: parseRecurringEvent(restEventType.recurringEvent),
locations: locations as unknown as LocationObject[],
metadata: (metadata || {}) as JSONObject,
isWeb3Active:
web3Credentials && web3Credentials.key
? (((web3Credentials.key as JSONObject).isWeb3Active || false) as boolean)
: false,
};
const hasGiphyIntegration = !!credentials.find((credential) => credential.type === "giphy_other");

View File

@ -20,7 +20,6 @@ import { metadata as hubspotothercalendar_meta } from "./hubspotothercalendar/_m
import { metadata as huddle01video_meta } from "./huddle01video/_metadata";
import { metadata as jitsivideo_meta } from "./jitsivideo/_metadata";
import { metadata as larkcalendar_meta } from "./larkcalendar/_metadata";
import { metadata as metamask_meta } from "./metamask/_metadata";
import { metadata as office365calendar_meta } from "./office365calendar/_metadata";
import { metadata as office365video_meta } from "./office365video/_metadata";
import { metadata as ping_meta } from "./ping/_metadata";
@ -52,7 +51,6 @@ export const appStoreMetadata = {
huddle01video: huddle01video_meta,
jitsivideo: jitsivideo_meta,
larkcalendar: larkcalendar_meta,
metamask: metamask_meta,
office365calendar: office365calendar_meta,
office365video: office365video_meta,
ping: ping_meta,
@ -80,7 +78,6 @@ export const InstallAppButtonMap = {
huddle01video: dynamic(() => import("./huddle01video/components/InstallAppButton")),
jitsivideo: dynamic(() => import("./jitsivideo/components/InstallAppButton")),
larkcalendar: dynamic(() => import("./larkcalendar/components/InstallAppButton")),
metamask: dynamic(() => import("./metamask/components/InstallAppButton")),
office365calendar: dynamic(() => import("./office365calendar/components/InstallAppButton")),
office365video: dynamic(() => import("./office365video/components/InstallAppButton")),
riverside: dynamic(() => import("./riverside/components/InstallAppButton")),

View File

@ -17,7 +17,6 @@ export const apiHandlers = {
huddle01video: import("./huddle01video/api"),
jitsivideo: import("./jitsivideo/api"),
larkcalendar: import("./larkcalendar/api"),
metamask: import("./metamask/api"),
office365calendar: import("./office365calendar/api"),
office365video: import("./office365video/api"),
ping: import("./ping/api"),

View File

@ -12,7 +12,6 @@ import * as hubspotothercalendar from "./hubspotothercalendar";
import * as huddle01video from "./huddle01video";
import * as jitsivideo from "./jitsivideo";
import * as larkcalendar from "./larkcalendar";
import * as metamask from "./metamask";
import * as office365calendar from "./office365calendar";
import * as office365video from "./office365video";
import * as slackmessaging from "./slackmessaging";
@ -43,7 +42,6 @@ const appStore = {
vital,
zoomvideo,
wipemycalother,
metamask,
giphy,
zapier,
exchange2013calendar,

View File

@ -1,17 +0,0 @@
---
items:
- /api/app-store/metamask/example1.png
- /api/app-store/metamask/example2.png
---
<Slider items={items} />
Only book and allow bookings from people who share the same tokens, DAOs, or NFTs.
Send a group scheduling link that only members of a DAO or token-based community can join.
Share your booking link and be sure to only receive bookings from owners of your chosen tokens or coins.
Provide office hours for other DAO members or outsiders who want to learn more from you.
[Click here to learn more](https://cal.com/web3)

View File

@ -1,26 +0,0 @@
import type { AppMeta } from "@calcom/types/App";
import _package from "./package.json";
export const metadata = {
name: "MetaMask",
description: _package.description,
installed: true,
category: "web3",
// If using static next public folder, can then be referenced from the base URL (/).
imageSrc: "/api/app-store/metamask/icon.svg",
logo: "/api/app-store/metamask/icon.svg",
publisher: "Cal.com",
rating: 5,
reviews: 69,
slug: "metamask",
title: "MetaMask",
trending: true,
type: "metamask_web3",
url: "https://cal.com/",
variant: "other",
verified: true,
email: "help@cal.com",
} as AppMeta;
export default metadata;

View File

@ -1,39 +0,0 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!req.session?.user?.id) {
return res.status(401).json({ message: "You must be logged in to do this" });
}
const appType = "metamask_web3";
try {
const alreadyInstalled = await prisma.credential.findFirst({
where: {
type: appType,
userId: req.session.user.id,
},
});
if (alreadyInstalled) {
throw new Error("Already installed");
}
const installation = await prisma.credential.create({
data: {
type: appType,
key: { isWeb3Active: true },
userId: req.session.user.id,
appId: "metamask",
},
});
if (!installation) {
throw new Error("Unable to create user credential for metamask");
}
} catch (error: unknown) {
if (error instanceof Error) {
return res.status(500).json({ message: error.message });
}
return res.status(500);
}
return res.status(200).json({ url: "/apps/installed" });
}

View File

@ -1 +0,0 @@
export { default as add } from "./add";

View File

@ -1,19 +0,0 @@
import useAddAppMutation from "../../_utils/useAddAppMutation";
import { InstallAppButtonProps } from "../../types";
export default function InstallAppButton(props: InstallAppButtonProps) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore TODO: deprecate App types in favor of DB slugs
const mutation = useAddAppMutation("metamask");
return (
<>
{props.render({
onClick() {
mutation.mutate("");
},
loading: mutation.isLoading,
})}
</>
);
}

View File

@ -1 +0,0 @@
export { default as InstallAppButton } from "./InstallAppButton";

View File

@ -1,2 +0,0 @@
export * as api from "./api";
export { metadata } from "./_metadata";

View File

@ -1,14 +0,0 @@
{
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"name": "@calcom/metamask",
"version": "0.0.0",
"main": "./index.ts",
"description": "Only book and allow bookings from people who share the same tokens, DAOs, or NFTs.",
"dependencies": {
"@calcom/prisma": "*"
},
"devDependencies": {
"@calcom/types": "*"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 515 KiB

View File

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 318.6 318.6"
style="enable-background:new 0 0 318.6 318.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#E2761B;stroke:#E2761B;stroke-linecap:round;stroke-linejoin:round;}
.st1{fill:#E4761B;stroke:#E4761B;stroke-linecap:round;stroke-linejoin:round;}
.st2{fill:#D7C1B3;stroke:#D7C1B3;stroke-linecap:round;stroke-linejoin:round;}
.st3{fill:#233447;stroke:#233447;stroke-linecap:round;stroke-linejoin:round;}
.st4{fill:#CD6116;stroke:#CD6116;stroke-linecap:round;stroke-linejoin:round;}
.st5{fill:#E4751F;stroke:#E4751F;stroke-linecap:round;stroke-linejoin:round;}
.st6{fill:#F6851B;stroke:#F6851B;stroke-linecap:round;stroke-linejoin:round;}
.st7{fill:#C0AD9E;stroke:#C0AD9E;stroke-linecap:round;stroke-linejoin:round;}
.st8{fill:#161616;stroke:#161616;stroke-linecap:round;stroke-linejoin:round;}
.st9{fill:#763D16;stroke:#763D16;stroke-linecap:round;stroke-linejoin:round;}
</style>
<polygon class="st0" points="274.1,35.5 174.6,109.4 193,65.8 "/>
<g>
<polygon class="st1" points="44.4,35.5 143.1,110.1 125.6,65.8 "/>
<polygon class="st1" points="238.3,206.8 211.8,247.4 268.5,263 284.8,207.7 "/>
<polygon class="st1" points="33.9,207.7 50.1,263 106.8,247.4 80.3,206.8 "/>
<polygon class="st1" points="103.6,138.2 87.8,162.1 144.1,164.6 142.1,104.1 "/>
<polygon class="st1" points="214.9,138.2 175.9,103.4 174.6,164.6 230.8,162.1 "/>
<polygon class="st1" points="106.8,247.4 140.6,230.9 111.4,208.1 "/>
<polygon class="st1" points="177.9,230.9 211.8,247.4 207.1,208.1 "/>
</g>
<g>
<polygon class="st2" points="211.8,247.4 177.9,230.9 180.6,253 180.3,262.3 "/>
<polygon class="st2" points="106.8,247.4 138.3,262.3 138.1,253 140.6,230.9 "/>
</g>
<polygon class="st3" points="138.8,193.5 110.6,185.2 130.5,176.1 "/>
<polygon class="st3" points="179.7,193.5 188,176.1 208,185.2 "/>
<g>
<polygon class="st4" points="106.8,247.4 111.6,206.8 80.3,207.7 "/>
<polygon class="st4" points="207,206.8 211.8,247.4 238.3,207.7 "/>
<polygon class="st4" points="230.8,162.1 174.6,164.6 179.8,193.5 188.1,176.1 208.1,185.2 "/>
<polygon class="st4" points="110.6,185.2 130.6,176.1 138.8,193.5 144.1,164.6 87.8,162.1 "/>
</g>
<g>
<polygon class="st5" points="87.8,162.1 111.4,208.1 110.6,185.2 "/>
<polygon class="st5" points="208.1,185.2 207.1,208.1 230.8,162.1 "/>
<polygon class="st5" points="144.1,164.6 138.8,193.5 145.4,227.6 146.9,182.7 "/>
<polygon class="st5" points="174.6,164.6 171.9,182.6 173.1,227.6 179.8,193.5 "/>
</g>
<polygon class="st6" points="179.8,193.5 173.1,227.6 177.9,230.9 207.1,208.1 208.1,185.2 "/>
<polygon class="st6" points="110.6,185.2 111.4,208.1 140.6,230.9 145.4,227.6 138.8,193.5 "/>
<polygon class="st7" points="180.3,262.3 180.6,253 178.1,250.8 140.4,250.8 138.1,253 138.3,262.3 106.8,247.4 117.8,256.4
140.1,271.9 178.4,271.9 200.8,256.4 211.8,247.4 "/>
<polygon class="st8" points="177.9,230.9 173.1,227.6 145.4,227.6 140.6,230.9 138.1,253 140.4,250.8 178.1,250.8 180.6,253 "/>
<g>
<polygon class="st9" points="278.3,114.2 286.8,73.4 274.1,35.5 177.9,106.9 214.9,138.2 267.2,153.5 278.8,140 273.8,136.4
281.8,129.1 275.6,124.3 283.6,118.2 "/>
<polygon class="st9" points="31.8,73.4 40.3,114.2 34.9,118.2 42.9,124.3 36.8,129.1 44.8,136.4 39.8,140 51.3,153.5 103.6,138.2
140.6,106.9 44.4,35.5 "/>
</g>
<polygon class="st6" points="267.2,153.5 214.9,138.2 230.8,162.1 207.1,208.1 238.3,207.7 284.8,207.7 "/>
<polygon class="st6" points="103.6,138.2 51.3,153.5 33.9,207.7 80.3,207.7 111.4,208.1 87.8,162.1 "/>
<polygon class="st6" points="174.6,164.6 177.9,106.9 193.1,65.8 125.6,65.8 140.6,106.9 144.1,164.6 145.3,182.8 145.4,227.6
173.1,227.6 173.3,182.8 "/>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,9 +0,0 @@
[
{
"inputs": [{ "internalType": "address", "name": "owner", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
}
]

View File

@ -1,143 +0,0 @@
import Router from "next/router";
import React, { useCallback, useMemo, useState } from "react";
import Web3 from "web3";
import type { AbstractProvider } from "web3-core";
import { AbiItem } from "web3-utils";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { Button } from "@calcom/ui/Button";
import { withLicenseRequired } from "../../common/components/LicenseRequired";
import genericAbi from "../abis/abiWithGetBalance.json";
import { useContracts } from "../contexts/contractsContext";
import verifyAccount, { AUTH_MESSAGE } from "../utils/verifyAccount";
interface Window {
ethereum: AbstractProvider & { selectedAddress: string };
web3: Web3;
}
interface EvtsToVerify {
[eventId: string]: boolean;
}
declare const window: Window;
export interface CryptoSectionProps {
id: number | string;
pathname: string;
smartContractAddress: string;
/** When set to true, there will be only 1 button which will both connect Metamask and verify the user's wallet. Otherwise, it will be in 2 steps with 2 buttons. */
oneStep: boolean;
verified: boolean | undefined;
setEvtsToVerify: React.Dispatch<React.SetStateAction<Record<number | string, boolean>>>;
}
const CryptoSection = (props: CryptoSectionProps) => {
// Crypto section which should be shown on booking page if event type requires a smart contract token.
const [ethEnabled, toggleEthEnabled] = useState<boolean>(false);
const { addContract } = useContracts();
const { t } = useLocale();
const connectMetamask = useCallback(async () => {
if (window.ethereum && typeof window.ethereum.request === "function") {
await window.ethereum.request({ method: "eth_requestAccounts" });
window.web3 = new Web3(window.ethereum);
toggleEthEnabled(true);
} else {
toggleEthEnabled(false);
}
}, []);
const verifyWallet = useCallback(async () => {
try {
if (!window.web3) throw new Error("MetaMask browser extension is not installed");
const contract = new window.web3.eth.Contract(genericAbi as AbiItem[], props.smartContractAddress);
const balance = await contract.methods.balanceOf(window.ethereum.selectedAddress).call();
const hasToken = balance > 0;
if (!hasToken)
throw new Error("Specified wallet does not own any tokens belonging to this smart contract");
const [account] = await window.web3.eth.getAccounts();
const signature = await window.web3.eth.personal.sign(AUTH_MESSAGE, account, "");
addContract({ address: props.smartContractAddress, signature });
await verifyAccount(signature, account);
props.setEvtsToVerify((prevState: EvtsToVerify) => ({ ...prevState, [props.id]: hasToken }));
} catch (err) {
const message = err instanceof Error ? err.message : "An error has occurred";
showToast(message, "error");
}
}, [props, addContract]);
// @TODO: Show error on either of buttons if fails. Yup schema already contains the error message.
const successButton = useMemo(() => {
if (props.verified) {
Router.push(props.pathname);
}
return <div />;
}, [props.pathname, props.verified]);
const verifyButton = useMemo(() => {
return (
<Button color="secondary" onClick={verifyWallet} type="button" id="hasToken">
<img className="mr-1 h-5" src="/api/app-store/metamask/icon.svg" alt="MetaMask" />
{t("verify_wallet")}
</Button>
);
}, [verifyWallet, t]);
const connectButton = useMemo(() => {
return (
<Button color="secondary" onClick={connectMetamask} type="button">
{
// eslint-disable-next-line @next/next/no-img-element
<img className="mr-1 h-5" src="/api/app-store/metamask/icon.svg" alt="MetaMask" />
}
{t("connect_metamask")}
</Button>
);
}, [connectMetamask, t]);
const oneStepButton = useMemo(() => {
return (
<Button
color="secondary"
type="button"
onClick={async () => {
await connectMetamask();
await verifyWallet();
}}>
{
// eslint-disable-next-line @next/next/no-img-element
<img className="mr-1 h-5" src="/api/app-store/metamask/icon.svg" alt="MetaMask" />
}
{t("verify_wallet")}
</Button>
);
}, [connectMetamask, verifyWallet, t]);
const determineButton = useCallback(() => {
// Did it in an extra function for some added readability, but this can be done in a ternary depending on preference
if (props.oneStep) {
return props.verified ? successButton : oneStepButton;
} else {
if (ethEnabled) {
return props.verified ? successButton : verifyButton;
} else {
return connectButton;
}
}
}, [props.verified, successButton, oneStepButton, connectButton, ethEnabled, props.oneStep, verifyButton]);
return (
<div
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform opacity-0 transition-opacity group-hover:opacity-100 dark:bg-gray-900"
id={`crypto-${props.id}`}>
{determineButton()}
</div>
);
};
export default withLicenseRequired(CryptoSection);

View File

@ -1,48 +0,0 @@
import noop from "lodash/noop";
import { createContext, ReactNode, useContext } from "react";
import { localStorage } from "@calcom/lib/webstorage";
type contractsContextType = {
contracts: Record<string, string>;
addContract: (payload: addContractsPayload) => void;
};
const contractsContextDefaultValue: contractsContextType = {
contracts: {},
addContract: noop,
};
const ContractsContext = createContext<contractsContextType>(contractsContextDefaultValue);
export function useContracts() {
return useContext(ContractsContext);
}
type Props = {
children: ReactNode;
};
interface addContractsPayload {
address: string;
signature: string;
}
export function ContractsProvider({ children }: Props) {
const addContract = (payload: addContractsPayload) => {
localStorage.setItem(
"contracts",
JSON.stringify({
...JSON.parse(localStorage.getItem("contracts") || "{}"),
[payload.address]: payload.signature,
})
);
};
const value = {
contracts: typeof window !== "undefined" ? JSON.parse(localStorage.getItem("contracts") || "{}") : {},
addContract,
};
return <ContractsContext.Provider value={value}>{children}</ContractsContext.Provider>;
}

View File

@ -1,12 +0,0 @@
import Web3 from "web3";
export const AUTH_MESSAGE =
"I authorize the use of my Ethereum address for the purposes of this application.";
const verifyAccount = async (signature: string, address: string) => {
const web3 = new Web3();
const signingAddress = await web3.eth.accounts.recover(AUTH_MESSAGE, signature);
if (!(address.toLowerCase() === signingAddress.toLowerCase())) throw new Error("Failed to verify address");
};
export default verifyAccount;

View File

@ -75,10 +75,6 @@ const commons = {
schedulingType: SchedulingType.COLLECTIVE,
seatsPerTimeSlot: null,
id: 0,
metadata: {
smartContractAddress: "",
},
isWeb3Active: false,
hideCalendarNotes: false,
recurringEvent: null,
destinationCalendar: null,
@ -88,6 +84,7 @@ const commons = {
userId: 0,
workflows: [],
users: [user],
metadata: {},
};
const min15Event = {

View File

@ -266,7 +266,6 @@ export default async function main() {
// Web3 apps
await createApp("huddle01", "huddle01video", ["web3", "video"], "huddle01_video");
await createApp("metamask", "metamask", ["web3"], "metamask_web3");
// Messaging apps
if (process.env.SLACK_CLIENT_ID && process.env.SLACK_CLIENT_SECRET && process.env.SLACK_SIGNING_SECRET) {
await createApp("slack", "slackmessaging", ["messaging"], "slack_messaging", {

View File

@ -62,12 +62,6 @@ export const stringToDayjs = z.string().transform((val) => dayjs(val));
export const bookingCreateBodySchema = z.object({
email: z.string(),
end: z.string(),
web3Details: z
.object({
userWallet: z.string(),
userSignature: z.string(),
})
.optional(),
eventTypeId: z.number(),
eventTypeSlug: z.string().optional(),
guests: z.array(z.string()).optional(),

View File

@ -638,46 +638,6 @@ const loggedInViewerRouter = createProtectedRouter()
});
},
})
.mutation("enableOrDisableWeb3", {
input: z.object({}),
async resolve({ ctx }) {
const { user } = ctx;
const where = { userId: user.id, type: "metamask_web3" };
const web3Credential = await ctx.prisma.credential.findFirst({
where,
select: {
id: true,
key: true,
},
});
if (web3Credential) {
const deleted = await ctx.prisma.credential.delete({
where: {
id: web3Credential.id,
},
});
return {
...deleted,
key: {
...(deleted.key as JSONObject),
isWeb3Active: false,
},
};
} else {
return ctx.prisma.credential.create({
data: {
type: "metamask_web3",
key: {
isWeb3Active: true,
} as unknown as Prisma.InputJsonObject,
userId: user.id,
},
});
}
},
})
.query("integrations", {
input: z.object({
variant: z.string().optional(),
@ -726,24 +686,6 @@ const loggedInViewerRouter = createProtectedRouter()
return app;
},
})
.query("web3Integration", {
async resolve({ ctx }) {
const { user } = ctx;
const where = { userId: user.id, type: "metamask_web3" };
const web3Credential = await ctx.prisma.credential.findFirst({
where,
select: {
key: true,
},
});
return {
isWeb3Active: web3Credential ? (web3Credential.key as JSONObject).isWeb3Active : false,
};
},
})
.mutation("updateProfile", {
input: z.object({
username: z.string().optional(),

120
yarn.lock
View File

@ -3188,38 +3188,6 @@
resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b"
integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==
"@metamask/object-multiplex@^1.1.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@metamask/object-multiplex/-/object-multiplex-1.2.0.tgz#38fc15c142f61939391e1b9a8eed679696c7e4f4"
integrity sha512-hksV602d3NWE2Q30Mf2Np1WfVKaGqfJRy9vpHAmelbaD0OkDt06/0KQkRR6UVYdMbTbkuEu8xN5JDUU80inGwQ==
dependencies:
end-of-stream "^1.4.4"
once "^1.4.0"
readable-stream "^2.3.3"
"@metamask/providers@^8.1.1":
version "8.1.1"
resolved "https://registry.yarnpkg.com/@metamask/providers/-/providers-8.1.1.tgz#7b0dbb54700c949aafba24c9b98e6f4e9d81f325"
integrity sha512-CG1sAuD6Mp4MZ5U90anf1FT0moDbStGXT+80TQFYXJbBeTQjhp321WgC/F2IgIJ3mFqOiByC3MQHLuunEVMQOA==
dependencies:
"@metamask/object-multiplex" "^1.1.0"
"@metamask/safe-event-emitter" "^2.0.0"
"@types/chrome" "^0.0.136"
detect-browser "^5.2.0"
eth-rpc-errors "^4.0.2"
extension-port-stream "^2.0.1"
fast-deep-equal "^2.0.1"
is-stream "^2.0.0"
json-rpc-engine "^6.1.0"
json-rpc-middleware-stream "^3.0.0"
pump "^3.0.0"
webextension-polyfill-ts "^0.25.0"
"@metamask/safe-event-emitter@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz#af577b477c683fad17c619a78208cede06f9605c"
integrity sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==
"@microsoft/microsoft-graph-types-beta@0.15.0-preview":
version "0.15.0-preview"
resolved "https://registry.yarnpkg.com/@microsoft/microsoft-graph-types-beta/-/microsoft-graph-types-beta-0.15.0-preview.tgz#fed0a99be4e1151d566cf063f024913fb48640cd"
@ -5949,14 +5917,6 @@
"@types/node" "*"
"@types/responselike" "*"
"@types/chrome@^0.0.136":
version "0.0.136"
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.136.tgz#7c011b9f997b0156f25a140188a0c5689d3f368f"
integrity sha512-XDEiRhLkMd+SB7Iw3ZUIj/fov3wLd4HyTdLltVszkgl1dBfc3Rb7oPMVZ2Mz2TLqnF7Ow+StbR8E7r9lqpb4DA==
dependencies:
"@types/filesystem" "*"
"@types/har-format" "*"
"@types/connect@*":
version "3.4.35"
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
@ -6065,18 +6025,6 @@
"@types/qs" "*"
"@types/serve-static" "*"
"@types/filesystem@*":
version "0.0.32"
resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.32.tgz#307df7cc084a2293c3c1a31151b178063e0a8edf"
integrity sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ==
dependencies:
"@types/filewriter" "*"
"@types/filewriter@*":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.29.tgz#a48795ecadf957f6c0d10e0c34af86c098fa5bee"
integrity sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ==
"@types/glidejs__glide@^3.4.2":
version "3.4.2"
resolved "https://registry.yarnpkg.com/@types/glidejs__glide/-/glidejs__glide-3.4.2.tgz#fb486e376aab88788e09bbdeb81f89dcf363be1c"
@ -6102,11 +6050,6 @@
resolved "https://registry.yarnpkg.com/@types/gtag.js/-/gtag.js-0.0.10.tgz#ac90d9b79c00daac447725a4b78ec1c398796760"
integrity sha512-98Hy7woUb3jMAMXkZQwfIOYNyfxmI0+U4m0PpCGdnd/FHk0tDpQFCqgXdNkdEoXsKkcGya/2Gew1cAJjKJspVw==
"@types/har-format@*":
version "1.2.8"
resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.8.tgz#e6908b76d4c88be3db642846bb8b455f0bfb1c4e"
integrity sha512-OP6L9VuZNdskgNN3zFQQ54ceYD8OLq5IbqO4VK91ORLfOm7WdT/CiT/pHEBSQEqCInJ2y3O6iCm/zGtPElpgJQ==
"@types/hast@^2.0.0":
version "2.3.4"
resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc"
@ -10183,11 +10126,6 @@ detab@2.0.4:
dependencies:
repeat-string "^1.5.4"
detect-browser@^5.2.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca"
integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==
detect-element-overflow@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/detect-element-overflow/-/detect-element-overflow-1.2.0.tgz#86e504292ffedc3aef813395fbdf0261aaf6afa9"
@ -10590,7 +10528,7 @@ encoding@0.1.12:
dependencies:
iconv-lite "~0.4.13"
end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.4:
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
@ -11461,13 +11399,6 @@ eth-lib@^0.1.26:
ws "^3.0.0"
xhr-request-promise "^0.1.2"
eth-rpc-errors@^4.0.2:
version "4.0.3"
resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz#6ddb6190a4bf360afda82790bb7d9d5e724f423a"
integrity sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==
dependencies:
fast-safe-stringify "^2.0.6"
ethereum-bloom-filters@^1.0.6:
version "1.0.10"
resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a"
@ -11811,13 +11742,6 @@ extend@^3.0.0, extend@^3.0.2, extend@~3.0.2:
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
extension-port-stream@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extension-port-stream/-/extension-port-stream-2.0.1.tgz#d374820c581418c2275d3c4439ade0b82c4cfac6"
integrity sha512-ltrv4Dh/979I04+D4Te6TFygfRSOc5EBzzlHRldWMS8v73V80qWluxH88hqF0qyUsBXTb8NmzlmSipcre6a+rg==
dependencies:
webextension-polyfill-ts "^0.22.0"
external-editor@^3.0.3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
@ -11851,11 +11775,6 @@ extsprintf@^1.2.0:
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07"
integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@ -11919,7 +11838,7 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
fast-safe-stringify@^2.0.6, fast-safe-stringify@^2.0.7:
fast-safe-stringify@^2.0.7:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
@ -15196,22 +15115,6 @@ json-pointer@0.6.2:
dependencies:
foreach "^2.0.4"
json-rpc-engine@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393"
integrity sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==
dependencies:
"@metamask/safe-event-emitter" "^2.0.0"
eth-rpc-errors "^4.0.2"
json-rpc-middleware-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-rpc-middleware-stream/-/json-rpc-middleware-stream-3.0.0.tgz#8540331d884f36b9e0ad31054cc68ac6b5a89b52"
integrity sha512-JmZmlehE0xF3swwORpLHny/GvW3MZxCsb2uFNBrn8TOqMqivzCfz232NSDLLOtIQlrPlgyEjiYpyzyOPFOzClw==
dependencies:
"@metamask/safe-event-emitter" "^2.0.0"
readable-stream "^2.3.3"
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@ -23930,25 +23833,6 @@ webcrypto-core@^1.4.0:
pvtsutils "^1.2.2"
tslib "^2.3.1"
webextension-polyfill-ts@^0.22.0:
version "0.22.0"
resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.22.0.tgz#86cfd7bab4d9d779d98c8340983f4b691b2343f3"
integrity sha512-3P33ClMwZ/qiAT7UH1ROrkRC1KM78umlnPpRhdC/292UyoTTW9NcjJEqDsv83HbibcTB6qCtpVeuB2q2/oniHQ==
dependencies:
webextension-polyfill "^0.7.0"
webextension-polyfill-ts@^0.25.0:
version "0.25.0"
resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.25.0.tgz#fff041626365dbd0e29c40b197e989a55ec221ca"
integrity sha512-ikQhwwHYkpBu00pFaUzIKY26I6L87DeRI+Q6jBT1daZUNuu8dSrg5U9l/ZbqdaQ1M/TTSPKeAa3kolP5liuedw==
dependencies:
webextension-polyfill "^0.7.0"
webextension-polyfill@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.7.0.tgz#0df1120ff0266056319ce1a622b09ad8d4a56505"
integrity sha512-su48BkMLxqzTTvPSE1eWxKToPS2Tv5DLGxKexLEVpwFd6Po6N8hhSLIvG6acPAg7qERoEaDL+Y5HQJeJeml5Aw==
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"