From 450af73136948b7b50d5b051d3b8378fcc084378 Mon Sep 17 00:00:00 2001 From: vutuanlinh2k2 <69841784+vutuanlinh2k2@users.noreply.github.com> Date: Wed, 21 Feb 2024 22:25:15 +0700 Subject: [PATCH] Signing Rules on Service Details page on Tangle Dapp (#2046) --- .../tangle-dapp/app/claim/EligibleSection.tsx | 2 - apps/tangle-dapp/app/layout.tsx | 1 + .../restake/JobsCard/ActiveJobsTable.tsx | 6 +- .../restake/JobsCard/JobsTableClient.tsx | 9 +- .../restake/JobsCard/PastJobsTable.tsx | 6 +- .../{services => }/restake/JobsCard/index.tsx | 2 +- .../{services => }/restake/JobsCard/types.ts | 0 .../restake/OverviewCard/ActionButton.tsx | 0 .../restake/OverviewCard/index.tsx | 6 +- .../RoleDistributionCard/IndependentChart.tsx | 4 +- .../restake/RoleDistributionCard/index.tsx | 2 +- .../RolesEarningsCard/EarningsChart.tsx | 4 +- .../restake/RolesEarningsCard/index.tsx | 2 +- .../app/{services => }/restake/page.tsx | 0 .../app/services/[serviceId]/DetailTabs.tsx | 2 +- .../app/services/[serviceId]/SigningRules.tsx | 69 +++++++++++++- .../app/services/[serviceId]/page.tsx | 2 +- .../components/Breadcrumbs/Breadcrumbs.tsx | 2 + .../components/sideBar/sideBarProps.ts | 4 +- .../DelegationsPayoutsContainer.tsx | 9 +- .../data/ServiceDetails/getSigningRules.ts | 91 +++++++++++++++++++ apps/tangle-dapp/data/ServiceDetails/index.ts | 1 + apps/tangle-dapp/hooks/useQueryParamKey.ts | 23 ++--- apps/tangle-dapp/styles/globals.css | 14 +++ apps/tangle-dapp/types/index.ts | 41 ++++++--- .../Circuits/client/index.tsx | 14 ++- .../src/components/CodeFile}/CodeFile.tsx | 67 ++++++++------ .../src/components/CodeFile/index.ts | 3 + .../src/components/CodeFile/types.ts | 21 +++++ .../src/components/index.ts | 1 + .../stories/molecules/CodeFile.stories.tsx | 32 +++++++ 31 files changed, 339 insertions(+), 101 deletions(-) rename apps/tangle-dapp/app/{services => }/restake/JobsCard/ActiveJobsTable.tsx (76%) rename apps/tangle-dapp/app/{services => }/restake/JobsCard/JobsTableClient.tsx (93%) rename apps/tangle-dapp/app/{services => }/restake/JobsCard/PastJobsTable.tsx (76%) rename apps/tangle-dapp/app/{services => }/restake/JobsCard/index.tsx (92%) rename apps/tangle-dapp/app/{services => }/restake/JobsCard/types.ts (100%) rename apps/tangle-dapp/app/{services => }/restake/OverviewCard/ActionButton.tsx (100%) rename apps/tangle-dapp/app/{services => }/restake/OverviewCard/index.tsx (91%) rename apps/tangle-dapp/app/{services => }/restake/RoleDistributionCard/IndependentChart.tsx (89%) rename apps/tangle-dapp/app/{services => }/restake/RoleDistributionCard/index.tsx (88%) rename apps/tangle-dapp/app/{services => }/restake/RolesEarningsCard/EarningsChart.tsx (96%) rename apps/tangle-dapp/app/{services => }/restake/RolesEarningsCard/index.tsx (88%) rename apps/tangle-dapp/app/{services => }/restake/page.tsx (100%) create mode 100644 apps/tangle-dapp/data/ServiceDetails/getSigningRules.ts create mode 100644 apps/tangle-dapp/styles/globals.css rename {apps/zk-explorer/containers/ProjectDetailTabs/Circuits/client => libs/webb-ui-components/src/components/CodeFile}/CodeFile.tsx (64%) create mode 100644 libs/webb-ui-components/src/components/CodeFile/index.ts create mode 100644 libs/webb-ui-components/src/components/CodeFile/types.ts create mode 100644 libs/webb-ui-components/src/stories/molecules/CodeFile.stories.tsx diff --git a/apps/tangle-dapp/app/claim/EligibleSection.tsx b/apps/tangle-dapp/app/claim/EligibleSection.tsx index 19c66a276a..64f0e03fbc 100644 --- a/apps/tangle-dapp/app/claim/EligibleSection.tsx +++ b/apps/tangle-dapp/app/claim/EligibleSection.tsx @@ -1,7 +1,5 @@ 'use client'; -import '@webb-tools/tangle-substrate-types'; - import type { SubmittableExtrinsic } from '@polkadot/api/types'; import type { ISubmittableResult } from '@polkadot/types/types'; import { hexToU8a, stringToU8a, u8aToString } from '@polkadot/util'; diff --git a/apps/tangle-dapp/app/layout.tsx b/apps/tangle-dapp/app/layout.tsx index 17c026a6d0..b9467a70ac 100644 --- a/apps/tangle-dapp/app/layout.tsx +++ b/apps/tangle-dapp/app/layout.tsx @@ -1,4 +1,5 @@ import '@webb-tools/webb-ui-components/tailwind.css'; +import '../styles/globals.css'; import Suspense from '@webb-tools/webb-ui-components/components/Suspense'; import { TANGLE_DAPP_URL } from '@webb-tools/webb-ui-components/constants'; diff --git a/apps/tangle-dapp/app/services/restake/JobsCard/ActiveJobsTable.tsx b/apps/tangle-dapp/app/restake/JobsCard/ActiveJobsTable.tsx similarity index 76% rename from apps/tangle-dapp/app/services/restake/JobsCard/ActiveJobsTable.tsx rename to apps/tangle-dapp/app/restake/JobsCard/ActiveJobsTable.tsx index 1e5e29025a..57184d2690 100644 --- a/apps/tangle-dapp/app/services/restake/JobsCard/ActiveJobsTable.tsx +++ b/apps/tangle-dapp/app/restake/JobsCard/ActiveJobsTable.tsx @@ -3,9 +3,9 @@ import { FC } from 'react'; import useSWR from 'swr'; -import ContainerSkeleton from '../../../../components/skeleton/ContainerSkeleton'; -import TableStatus from '../../../../components/TableStatus/TableStatus'; -import getActiveJobs from '../../../../data/JobTables/getActiveJobs'; +import ContainerSkeleton from '../../../components/skeleton/ContainerSkeleton'; +import TableStatus from '../../../components/TableStatus/TableStatus'; +import getActiveJobs from '../../../data/JobTables/getActiveJobs'; import JobsTableClient from './JobsTableClient'; import { JobsTableProps } from './types'; diff --git a/apps/tangle-dapp/app/services/restake/JobsCard/JobsTableClient.tsx b/apps/tangle-dapp/app/restake/JobsCard/JobsTableClient.tsx similarity index 93% rename from apps/tangle-dapp/app/services/restake/JobsCard/JobsTableClient.tsx rename to apps/tangle-dapp/app/restake/JobsCard/JobsTableClient.tsx index c9075e4c48..b1d65ff718 100644 --- a/apps/tangle-dapp/app/services/restake/JobsCard/JobsTableClient.tsx +++ b/apps/tangle-dapp/app/restake/JobsCard/JobsTableClient.tsx @@ -16,12 +16,9 @@ import { } from '@webb-tools/webb-ui-components'; import { FC } from 'react'; -import { HeaderCell, StringCell } from '../../../../components/tableCells'; -import { - serviceTypeToChipColor, - TANGLE_TOKEN_UNIT, -} from '../../../../constants'; -import { JobType } from '../../../../types'; +import { HeaderCell, StringCell } from '../../../components/tableCells'; +import { serviceTypeToChipColor, TANGLE_TOKEN_UNIT } from '../../../constants'; +import { JobType } from '../../../types'; const columnHelper = createColumnHelper(); diff --git a/apps/tangle-dapp/app/services/restake/JobsCard/PastJobsTable.tsx b/apps/tangle-dapp/app/restake/JobsCard/PastJobsTable.tsx similarity index 76% rename from apps/tangle-dapp/app/services/restake/JobsCard/PastJobsTable.tsx rename to apps/tangle-dapp/app/restake/JobsCard/PastJobsTable.tsx index 333baf2f1a..653f1c4ced 100644 --- a/apps/tangle-dapp/app/services/restake/JobsCard/PastJobsTable.tsx +++ b/apps/tangle-dapp/app/restake/JobsCard/PastJobsTable.tsx @@ -1,9 +1,9 @@ import { FC } from 'react'; import useSWR from 'swr'; -import ContainerSkeleton from '../../../../components/skeleton/ContainerSkeleton'; -import TableStatus from '../../../../components/TableStatus/TableStatus'; -import getPastJobs from '../../../../data/JobTables/getPastJobs'; +import ContainerSkeleton from '../../../components/skeleton/ContainerSkeleton'; +import TableStatus from '../../../components/TableStatus/TableStatus'; +import getPastJobs from '../../../data/JobTables/getPastJobs'; import JobsTableClient from './JobsTableClient'; import { JobsTableProps } from './types'; diff --git a/apps/tangle-dapp/app/services/restake/JobsCard/index.tsx b/apps/tangle-dapp/app/restake/JobsCard/index.tsx similarity index 92% rename from apps/tangle-dapp/app/services/restake/JobsCard/index.tsx rename to apps/tangle-dapp/app/restake/JobsCard/index.tsx index 461c22b7e8..2cc887f55c 100644 --- a/apps/tangle-dapp/app/services/restake/JobsCard/index.tsx +++ b/apps/tangle-dapp/app/restake/JobsCard/index.tsx @@ -3,7 +3,7 @@ import { TableAndChartTabs } from '@webb-tools/webb-ui-components/components/TableAndChartTabs'; import { TabContent } from '@webb-tools/webb-ui-components/components/Tabs/TabContent'; -import GlassCard from '../../../../components/GlassCard/GlassCard'; +import GlassCard from '../../../components/GlassCard/GlassCard'; import ActiveJobsTable from './ActiveJobsTable'; import PastJobsTable from './PastJobsTable'; diff --git a/apps/tangle-dapp/app/services/restake/JobsCard/types.ts b/apps/tangle-dapp/app/restake/JobsCard/types.ts similarity index 100% rename from apps/tangle-dapp/app/services/restake/JobsCard/types.ts rename to apps/tangle-dapp/app/restake/JobsCard/types.ts diff --git a/apps/tangle-dapp/app/services/restake/OverviewCard/ActionButton.tsx b/apps/tangle-dapp/app/restake/OverviewCard/ActionButton.tsx similarity index 100% rename from apps/tangle-dapp/app/services/restake/OverviewCard/ActionButton.tsx rename to apps/tangle-dapp/app/restake/OverviewCard/ActionButton.tsx diff --git a/apps/tangle-dapp/app/services/restake/OverviewCard/index.tsx b/apps/tangle-dapp/app/restake/OverviewCard/index.tsx similarity index 91% rename from apps/tangle-dapp/app/services/restake/OverviewCard/index.tsx rename to apps/tangle-dapp/app/restake/OverviewCard/index.tsx index bccc5f43ac..4f4b422158 100644 --- a/apps/tangle-dapp/app/services/restake/OverviewCard/index.tsx +++ b/apps/tangle-dapp/app/restake/OverviewCard/index.tsx @@ -1,9 +1,9 @@ import { Typography } from '@webb-tools/webb-ui-components/typography/Typography'; import { type ComponentProps, type ElementRef, FC, forwardRef } from 'react'; -import { InfoIconWithTooltip } from '../../../../components/InfoIconWithTooltip'; -import TangleCard from '../../../../components/TangleCard'; -import { TANGLE_TOKEN_UNIT } from '../../../../constants'; +import { InfoIconWithTooltip } from '../../../components/InfoIconWithTooltip'; +import TangleCard from '../../../components/TangleCard'; +import { TANGLE_TOKEN_UNIT } from '../../../constants'; import ActionButton from './ActionButton'; const OverviewCard = forwardRef, ComponentProps<'div'>>( diff --git a/apps/tangle-dapp/app/services/restake/RoleDistributionCard/IndependentChart.tsx b/apps/tangle-dapp/app/restake/RoleDistributionCard/IndependentChart.tsx similarity index 89% rename from apps/tangle-dapp/app/services/restake/RoleDistributionCard/IndependentChart.tsx rename to apps/tangle-dapp/app/restake/RoleDistributionCard/IndependentChart.tsx index 01685be583..d9cf568b9e 100644 --- a/apps/tangle-dapp/app/services/restake/RoleDistributionCard/IndependentChart.tsx +++ b/apps/tangle-dapp/app/restake/RoleDistributionCard/IndependentChart.tsx @@ -2,8 +2,8 @@ import { Cell, Pie, PieChart, Tooltip } from 'recharts'; -import ChartTooltip from '../../../../components/ChartTooltip'; -import { ServiceType } from '../../../../types'; +import ChartTooltip from '../../../components/ChartTooltip'; +import { ServiceType } from '../../../types'; const data = [ { name: [ServiceType.ZK_SAAS_GROTH16], value: 400 }, diff --git a/apps/tangle-dapp/app/services/restake/RoleDistributionCard/index.tsx b/apps/tangle-dapp/app/restake/RoleDistributionCard/index.tsx similarity index 88% rename from apps/tangle-dapp/app/services/restake/RoleDistributionCard/index.tsx rename to apps/tangle-dapp/app/restake/RoleDistributionCard/index.tsx index 0328b6cb85..74df48c623 100644 --- a/apps/tangle-dapp/app/services/restake/RoleDistributionCard/index.tsx +++ b/apps/tangle-dapp/app/restake/RoleDistributionCard/index.tsx @@ -2,7 +2,7 @@ import { Typography } from '@webb-tools/webb-ui-components/typography/Typography import dynamic from 'next/dynamic'; import type { FC } from 'react'; -import GlassCard from '../../../../components/GlassCard/GlassCard'; +import GlassCard from '../../../components/GlassCard/GlassCard'; const IndependentChart = dynamic(() => import('./IndependentChart'), { ssr: false, diff --git a/apps/tangle-dapp/app/services/restake/RolesEarningsCard/EarningsChart.tsx b/apps/tangle-dapp/app/restake/RolesEarningsCard/EarningsChart.tsx similarity index 96% rename from apps/tangle-dapp/app/services/restake/RolesEarningsCard/EarningsChart.tsx rename to apps/tangle-dapp/app/restake/RolesEarningsCard/EarningsChart.tsx index bb5a2c161c..9bcd9b52d7 100644 --- a/apps/tangle-dapp/app/services/restake/RolesEarningsCard/EarningsChart.tsx +++ b/apps/tangle-dapp/app/restake/RolesEarningsCard/EarningsChart.tsx @@ -12,8 +12,8 @@ import { YAxis, } from 'recharts'; -import ChartTooltip from '../../../../components/ChartTooltip'; -import { ServiceType } from '../../../../types'; +import ChartTooltip from '../../../components/ChartTooltip'; +import { ServiceType } from '../../../types'; const randNum = () => randNumber({ min: 1000, max: 4000, precision: 100 }); diff --git a/apps/tangle-dapp/app/services/restake/RolesEarningsCard/index.tsx b/apps/tangle-dapp/app/restake/RolesEarningsCard/index.tsx similarity index 88% rename from apps/tangle-dapp/app/services/restake/RolesEarningsCard/index.tsx rename to apps/tangle-dapp/app/restake/RolesEarningsCard/index.tsx index 9e660a100f..ffe0316467 100644 --- a/apps/tangle-dapp/app/services/restake/RolesEarningsCard/index.tsx +++ b/apps/tangle-dapp/app/restake/RolesEarningsCard/index.tsx @@ -2,7 +2,7 @@ import { Typography } from '@webb-tools/webb-ui-components/typography/Typography import dynamic from 'next/dynamic'; import { FC } from 'react'; -import GlassCard from '../../../../components/GlassCard/GlassCard'; +import GlassCard from '../../../components/GlassCard/GlassCard'; const EarningsChart = dynamic(() => import('./EarningsChart'), { ssr: false }); diff --git a/apps/tangle-dapp/app/services/restake/page.tsx b/apps/tangle-dapp/app/restake/page.tsx similarity index 100% rename from apps/tangle-dapp/app/services/restake/page.tsx rename to apps/tangle-dapp/app/restake/page.tsx diff --git a/apps/tangle-dapp/app/services/[serviceId]/DetailTabs.tsx b/apps/tangle-dapp/app/services/[serviceId]/DetailTabs.tsx index 9e0738c108..0c9e808dbe 100644 --- a/apps/tangle-dapp/app/services/[serviceId]/DetailTabs.tsx +++ b/apps/tangle-dapp/app/services/[serviceId]/DetailTabs.tsx @@ -26,7 +26,7 @@ const DetailTabs: FC = ({ serviceId, className }) => { - + ); diff --git a/apps/tangle-dapp/app/services/[serviceId]/SigningRules.tsx b/apps/tangle-dapp/app/services/[serviceId]/SigningRules.tsx index 4b0c515067..04309780c8 100644 --- a/apps/tangle-dapp/app/services/[serviceId]/SigningRules.tsx +++ b/apps/tangle-dapp/app/services/[serviceId]/SigningRules.tsx @@ -1,7 +1,70 @@ -import { FC } from 'react'; +'use client'; -const SigningRules: FC = () => { - return
SigningRules
; +import { CodeFile, Typography } from '@webb-tools/webb-ui-components'; +import { FC, useEffect, useState } from 'react'; +import { twMerge } from 'tailwind-merge'; + +import { getSigningRules } from '../../../data/ServiceDetails'; + +interface SigningRulesProps { + serviceId: string; + className?: string; +} + +const SigningRules: FC = ({ className }) => { + const [signingRulesContractAddr, setSigningRulesContractAddr] = useState< + string | null + >(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + // TODO: get permitted caller + // TODO: check if permitted caller is a contract or not + setSigningRulesContractAddr(''); + setIsLoading(false); + setError(null); + }, []); + + if (isLoading) { + return
Loading...
; + } + + if (error !== null) { + return ( + + Error + + ); + } + + if (signingRulesContractAddr === null) { + return ( + + No Signing Rules associated with this service + + ); + } + + return ( +
+ getSigningRules(signingRulesContractAddr)} + isInNextProject + className="bg-mono-20 dark:bg-mono-200 overflow-auto max-h-[740px]" + // smart contract language: Solidity + language="sol" + /> +
+ ); }; export default SigningRules; diff --git a/apps/tangle-dapp/app/services/[serviceId]/page.tsx b/apps/tangle-dapp/app/services/[serviceId]/page.tsx index 5eb1d272e3..b745ffe471 100644 --- a/apps/tangle-dapp/app/services/[serviceId]/page.tsx +++ b/apps/tangle-dapp/app/services/[serviceId]/page.tsx @@ -15,7 +15,7 @@ export default function ServiceDetails({ {/* Tabs */} {/* Participants Table */} diff --git a/apps/tangle-dapp/components/Breadcrumbs/Breadcrumbs.tsx b/apps/tangle-dapp/components/Breadcrumbs/Breadcrumbs.tsx index 9ee4c8a081..da91a0d621 100644 --- a/apps/tangle-dapp/components/Breadcrumbs/Breadcrumbs.tsx +++ b/apps/tangle-dapp/components/Breadcrumbs/Breadcrumbs.tsx @@ -40,6 +40,7 @@ const getBreadcrumbLabel = ( index: number, pathNames: string[] ) => { + // Service Details page if (pathNames.length === 2 && index === 1 && pathNames[0] === 'services') { return `Details: ${pathName}`; } @@ -53,6 +54,7 @@ const getBreadcrumbIcon = ( index: number, pathNames: string[] ) => { + // Service Details page if (pathNames.length === 2 && index === 1 && pathNames[0] === 'services') { return ; } diff --git a/apps/tangle-dapp/components/sideBar/sideBarProps.ts b/apps/tangle-dapp/components/sideBar/sideBarProps.ts index 9a2ac39e77..96560d483a 100644 --- a/apps/tangle-dapp/components/sideBar/sideBarProps.ts +++ b/apps/tangle-dapp/components/sideBar/sideBarProps.ts @@ -40,13 +40,13 @@ const sideBarItems: SideBarItemProps[] = [ subItems: [ { name: 'Overview', - href: '/services/overview', + href: '/services', isInternal: true, isNext: true, }, { name: 'Restake', - href: '/services/restake', + href: '/restake', isInternal: true, isNext: true, }, diff --git a/apps/tangle-dapp/containers/DelegationsPayoutsContainer/DelegationsPayoutsContainer.tsx b/apps/tangle-dapp/containers/DelegationsPayoutsContainer/DelegationsPayoutsContainer.tsx index 43d8e12592..a9dc18d3a0 100644 --- a/apps/tangle-dapp/containers/DelegationsPayoutsContainer/DelegationsPayoutsContainer.tsx +++ b/apps/tangle-dapp/containers/DelegationsPayoutsContainer/DelegationsPayoutsContainer.tsx @@ -18,8 +18,8 @@ import { ContainerSkeleton, TableStatus } from '../../components'; import useDelegations from '../../data/DelegationsPayouts/useDelegations'; import usePayouts from '../../data/DelegationsPayouts/usePayouts'; import useIsFirstTimeNominatorSubscription from '../../hooks/useIsFirstTimeNominatorSubscription'; -import useQueryParamKey, { QueryParamKey } from '../../hooks/useQueryParamKey'; -import { Payout } from '../../types'; +import useQueryParamKey from '../../hooks/useQueryParamKey'; +import { DelegationsAndPayoutsTab, Payout, QueryParamKey } from '../../types'; import { convertToSubstrateAddress } from '../../utils'; import { DelegateTxContainer } from '../DelegateTxContainer'; import { PayoutAllTxContainer } from '../PayoutAllTxContainer'; @@ -31,11 +31,6 @@ import PayoutTableContainer from './PayoutTableContainer'; const PAGE_SIZE = 10; -export enum DelegationsAndPayoutsTab { - Nominations = 'Nominations', - Payouts = 'Payouts', -} - function assertTab(tab: string): DelegationsAndPayoutsTab { if ( !Object.values(DelegationsAndPayoutsTab).includes( diff --git a/apps/tangle-dapp/data/ServiceDetails/getSigningRules.ts b/apps/tangle-dapp/data/ServiceDetails/getSigningRules.ts new file mode 100644 index 0000000000..4d4e64ccc9 --- /dev/null +++ b/apps/tangle-dapp/data/ServiceDetails/getSigningRules.ts @@ -0,0 +1,91 @@ +const MOCK_FILE = `pragma circom 2.0.0; + +include "../../node_modules/circomlib/circuits/poseidon.circom"; +include "../../node_modules/circomlib/circuits/bitify.circom"; +include "./merkleTreeUpdater.circom"; +include "./treeUpdateArgsHasher.circom"; +include "./merkleTree.circom"; + +// Computes hashes of the next tree layer +template TreeLayer(height) { + var nItems = 1 << height; + signal input ins[nItems * 2]; + signal output outs[nItems]; + + component hash[nItems]; + for(var i = 0; i < nItems; i++) { + hash[i] = HashLeftRight(); + hash[i].left <== ins[i * 2]; + hash[i].right <== ins[i * 2 + 1]; + hash[i].hash ==> outs[i]; + } +} + +// Inserts a leaf batch into a tree +// Checks that tree previously contained zero leaves in the same position +// Hashes leaves with Poseidon hash +// \`batchLevels\` should be less than \`levels\` +template BatchTreeUpdate(levels, batchLevels, zeroBatchLeaf) { + var height = levels - batchLevels; + var nLeaves = 1 << batchLevels; + signal input argsHash; + signal input oldRoot; + signal input newRoot; + signal input pathIndices; + signal input pathElements[height]; + signal input leaves[nLeaves]; + /* signal input blocks[nLeaves]; */ + // Check that hash of arguments is correct + // We compress arguments into a single hash to considerably reduce gas usage on chain + component argsHasher = TreeUpdateArgsHasher(nLeaves); + argsHasher.oldRoot <== oldRoot; + argsHasher.newRoot <== newRoot; + argsHasher.pathIndices <== pathIndices; + for(var i = 0; i < nLeaves; i++) { + argsHasher.leaves[i] <== leaves[i]; + } + argsHash === argsHasher.out; + // Compute batch subtree merkle root + component layers[batchLevels]; + for(var level = batchLevels - 1; level >= 0; level--) { + layers[level] = TreeLayer(level); + for(var i = 0; i < (1 << (level + 1)); i++) { + layers[level].ins[i] <== level == batchLevels - 1 ? leaves[i] : layers[level + 1].outs[i]; + } + } + // Verify that batch subtree was inserted correctly + component treeUpdater = MerkleTreeUpdater(height, zeroBatchLeaf); + treeUpdater.oldRoot <== oldRoot; + treeUpdater.newRoot <== newRoot; + treeUpdater.leaf <== layers[0].outs[0]; + treeUpdater.pathIndices <== pathIndices; + for(var i = 0; i < height; i++) { + treeUpdater.pathElements[i] <== pathElements[i]; + } +} + +// zeroLeaf = keccak256("tornado") % FIELD_SIZE +// zeroBatchLeaf is poseidon(zeroLeaf, zeroLeaf) (batchLevels - 1) times +function nthZero(n) { + assert(n <= 15); + if (n == 0) return 21663839004416932945382355908790599225266501822907911457504978515578255421292; + if (n == 1) return 8995896153219992062710898675021891003404871425075198597897889079729967997688; + if (n == 2) return 15126246733515326086631621937388047923581111613947275249184377560170833782629; + if (n == 3) return 6404200169958188928270149728908101781856690902670925316782889389790091378414; + if (n == 4) return 17903822129909817717122288064678017104411031693253675943446999432073303897479; + if (n == 5) return 11423673436710698439362231088473903829893023095386581732682931796661338615804; + if (n == 6) return 10494842461667482273766668782207799332467432901404302674544629280016211342367; + if (n == 7) return 17400501067905286947724900644309270241576392716005448085614420258732805558809; + if (n == 8) return 7924095784194248701091699324325620647610183513781643345297447650838438175245; + if (n == 9) return 3170907381568164996048434627595073437765146540390351066869729445199396390350; + if (n == 10) return 21224698076141654110749227566074000819685780865045032659353546489395159395031; + if (n == 11) return 18113275293366123216771546175954550524914431153457717566389477633419482708807; + if (n == 12) return 1952712013602708178570747052202251655221844679392349715649271315658568301659; + if (n == 13) return 18071586466641072671725723167170872238457150900980957071031663421538421560166; + if (n == 14) return 9993139859464142980356243228522899168680191731482953959604385644693217291503; + if (n == 15) return 14825089209834329031146290681677780462512538924857394026404638992248153156554; +}`; + +export default async function getSigningRules(_: string) { + return MOCK_FILE; +} diff --git a/apps/tangle-dapp/data/ServiceDetails/index.ts b/apps/tangle-dapp/data/ServiceDetails/index.ts index 791ad21c27..29554df9e8 100644 --- a/apps/tangle-dapp/data/ServiceDetails/index.ts +++ b/apps/tangle-dapp/data/ServiceDetails/index.ts @@ -1,2 +1,3 @@ +export { default as getSigningRules } from './getSigningRules'; export { default as useServiceJobs } from './useServiceJobs'; export { default as useServiceParticipants } from './useServiceParticipants'; diff --git a/apps/tangle-dapp/hooks/useQueryParamKey.ts b/apps/tangle-dapp/hooks/useQueryParamKey.ts index 8f1354f318..c166f84966 100644 --- a/apps/tangle-dapp/hooks/useQueryParamKey.ts +++ b/apps/tangle-dapp/hooks/useQueryParamKey.ts @@ -1,22 +1,13 @@ import { useSearchParams } from 'next/navigation'; import { z } from 'zod'; -import { DelegationsAndPayoutsTab } from '../containers/DelegationsPayoutsContainer/DelegationsPayoutsContainer'; -import { PagePath } from '../types'; - -export enum QueryParamKey { - DelegationsAndPayoutsTab = 'tab', -} - -export type QueryParamKeyOf = - Page extends PagePath.Nomination - ? QueryParamKey.DelegationsAndPayoutsTab - : never; - -export type QueryParamValueOf = - Key extends QueryParamKey.DelegationsAndPayoutsTab - ? DelegationsAndPayoutsTab - : never; +import { + DelegationsAndPayoutsTab, + PagePath, + QueryParamKey, + QueryParamKeyOf, + QueryParamValueOf, +} from '../types'; type UseQueryParamsReturn = { value: QueryParamValueOf> | null; diff --git a/apps/tangle-dapp/styles/globals.css b/apps/tangle-dapp/styles/globals.css new file mode 100644 index 0000000000..372e56dd81 --- /dev/null +++ b/apps/tangle-dapp/styles/globals.css @@ -0,0 +1,14 @@ +::-webkit-scrollbar-corner { + background: rgba(0, 0, 0, 0); +} + +::-webkit-scrollbar-thumb { + all: unset; +} + +/* Override react-syntax-highlighter styling */ +code span { + background: inherit; + font-family: 'Cousine' !important; + font-weight: 400 !important; +} diff --git a/apps/tangle-dapp/types/index.ts b/apps/tangle-dapp/types/index.ts index 7915817387..cf508f0353 100644 --- a/apps/tangle-dapp/types/index.ts +++ b/apps/tangle-dapp/types/index.ts @@ -1,14 +1,35 @@ // Note that this import is necessary to fix a strange type error // in Polkadot API's `api.tx.staking.bond` method, which complains // about requiring three arguments instead of two. + import '@webb-tools/tangle-substrate-types'; -import { DelegationsAndPayoutsTab } from '../containers/DelegationsPayoutsContainer/DelegationsPayoutsContainer'; -import { - QueryParamKey, - QueryParamKeyOf, - QueryParamValueOf, -} from '../hooks/useQueryParamKey'; +export enum PagePath { + Nomination = '/', + ClaimAirdrop = '/claim', + Account = '/account', + ServicesOverview = '/services', + ServicesRestake = '/restake', +} + +export enum QueryParamKey { + DelegationsAndPayoutsTab = 'tab', +} + +export type QueryParamKeyOf = + Page extends PagePath.Nomination + ? QueryParamKey.DelegationsAndPayoutsTab + : never; + +export type QueryParamValueOf = + Key extends QueryParamKey.DelegationsAndPayoutsTab + ? DelegationsAndPayoutsTab + : never; + +export enum DelegationsAndPayoutsTab { + Nominations = 'Nominations', + Payouts = 'Payouts', +} export type Validator = { address: string; @@ -62,14 +83,6 @@ export type Payout = { status: 'claimed' | 'unclaimed'; }; -export enum PagePath { - Nomination = '/', - ClaimAirdrop = '/claim', - Account = '/account', - ServicesOverview = '/services/overview', - ServicesRestake = '/services/restake', -} - /** * Utility type to remove trailing slash from a string. * diff --git a/apps/zk-explorer/containers/ProjectDetailTabs/Circuits/client/index.tsx b/apps/zk-explorer/containers/ProjectDetailTabs/Circuits/client/index.tsx index 5fca086859..6d914a8284 100644 --- a/apps/zk-explorer/containers/ProjectDetailTabs/Circuits/client/index.tsx +++ b/apps/zk-explorer/containers/ProjectDetailTabs/Circuits/client/index.tsx @@ -1,11 +1,10 @@ 'use client'; -import { SkeletonLoader } from '@webb-tools/webb-ui-components'; +import { CodeFile, SkeletonLoader } from '@webb-tools/webb-ui-components'; import cx from 'classnames'; import { useCallback, useEffect, useMemo, useState, type FC } from 'react'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { FileTree } from '../../../../server/projectDetails'; -import CodeFile from './CodeFile'; import Header from './Header'; import NavSideBar from './NavSideBar'; @@ -77,8 +76,17 @@ const CircuitsClient: FC = ({ fileTree }) => { { + if (!activeFileData?.fetchUrl) throw new Error('No fetchUrl'); + const res = await fetch(activeFileData.fetchUrl); + if (res.ok) { + const code = await res.text(); + return code; + } + throw new Error('Cannot load file'); + }} language={activeFileData?.language} + isInNextProject /> diff --git a/apps/zk-explorer/containers/ProjectDetailTabs/Circuits/client/CodeFile.tsx b/libs/webb-ui-components/src/components/CodeFile/CodeFile.tsx similarity index 64% rename from apps/zk-explorer/containers/ProjectDetailTabs/Circuits/client/CodeFile.tsx rename to libs/webb-ui-components/src/components/CodeFile/CodeFile.tsx index 2c554bd0c6..370993ab6b 100644 --- a/apps/zk-explorer/containers/ProjectDetailTabs/Circuits/client/CodeFile.tsx +++ b/libs/webb-ui-components/src/components/CodeFile/CodeFile.tsx @@ -1,41 +1,46 @@ -import { type FC, useEffect, useState, useCallback } from 'react'; -import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; -import { - Button, - notificationApi, - Typography, - SkeletonLoader, - useNextDarkMode as useDarkMode, -} from '@webb-tools/webb-ui-components'; +'use client'; + import { Alert } from '@webb-tools/icons'; +import { type FC, useEffect, useState, useCallback, useMemo } from 'react'; +import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneDark, oneLight, } from 'react-syntax-highlighter/dist/esm/styles/prism'; +import { twMerge } from 'tailwind-merge'; + +import { Button, notificationApi, SkeletonLoader } from '..'; +import { + useDarkMode as useNormalDarkMode, + useNextDarkMode, +} from '../../hooks/useDarkMode'; +import { Typography } from '../../typography'; +import type { CodeFileProps } from './types'; -interface CodeFileProps { - fetchUrl?: string; - language?: string; -} +const CodeFile: FC = ({ + getCodeFileFnc, + language, + isInNextProject, + className, +}) => { + const [code, setCode] = useState(null); + const [isLoadingCode, setIsLoadingCode] = useState(false); + const [error, setError] = useState(null); -const CodeFile: FC = ({ fetchUrl, language }) => { + const useDarkMode = useMemo( + () => (isInNextProject ? useNextDarkMode : useNormalDarkMode), + [isInNextProject] + ); const [isDarkMode] = useDarkMode(); - const [code, setCode] = useState(); - const [isLoadingCode, setIsLoadingCode] = useState(false); - const [error, setError] = useState(); const fetchCodeFile = useCallback(async () => { - if (!fetchUrl) return; setIsLoadingCode(true); try { - const res = await fetch(fetchUrl); - if (res.ok) { - const code = await res.text(); - setCode(code); - } + const code = await getCodeFileFnc(); + setCode(code); } catch (e) { if (e instanceof Error) { - setError(e.message); + setError(e); notificationApi({ variant: 'error', message: 'Cannot load file', @@ -44,7 +49,7 @@ const CodeFile: FC = ({ fetchUrl, language }) => { } finally { setIsLoadingCode(false); } - }, [fetchUrl]); + }, [getCodeFileFnc]); useEffect(() => { fetchCodeFile(); @@ -52,14 +57,14 @@ const CodeFile: FC = ({ fetchUrl, language }) => { if (isLoadingCode) { return ( -
+
); } - if (error) { + if (!isLoadingCode && error) { return (
@@ -85,7 +90,7 @@ const CodeFile: FC = ({ fetchUrl, language }) => { } return ( -
+
{!isLoadingCode && !error && code && ( = ({ fetchUrl, language }) => { showLineNumbers customStyle={{ height: '100%', - backgroundColor: 'inherit', + background: 'inherit', padding: 0, margin: 0, textShadow: 'none', + display: 'flex', + flexDirection: 'column', }} codeTagProps={{ style: { - backgroundColor: 'inherit', + background: 'inherit', textShadow: 'none', }, }} diff --git a/libs/webb-ui-components/src/components/CodeFile/index.ts b/libs/webb-ui-components/src/components/CodeFile/index.ts new file mode 100644 index 0000000000..63473bff2e --- /dev/null +++ b/libs/webb-ui-components/src/components/CodeFile/index.ts @@ -0,0 +1,3 @@ +import CodeFile from './CodeFile'; + +export default CodeFile; diff --git a/libs/webb-ui-components/src/components/CodeFile/types.ts b/libs/webb-ui-components/src/components/CodeFile/types.ts new file mode 100644 index 0000000000..aeff3442d4 --- /dev/null +++ b/libs/webb-ui-components/src/components/CodeFile/types.ts @@ -0,0 +1,21 @@ +export interface CodeFileProps { + /** + * The function to fetch the code file + */ + getCodeFileFnc: () => Promise; + /** + * The programming language of the code file (optional) + */ + language?: string; + + /** + * Track if the components is in a Next.js project or not + * @default true + */ + isInNextProject: boolean; + + /** + * The tailwindcss className to override the style + */ + className?: string; +} diff --git a/libs/webb-ui-components/src/components/index.ts b/libs/webb-ui-components/src/components/index.ts index b6a00590a0..3256391ab0 100644 --- a/libs/webb-ui-components/src/components/index.ts +++ b/libs/webb-ui-components/src/components/index.ts @@ -19,6 +19,7 @@ export * from './ChartContainer'; export * from './CheckBox'; export * from './CheckBoxMenu'; export * from './Chip'; +export { default as CodeFile } from './CodeFile'; export * from './Collapsible'; export * from './ConnectWalletMobileButton'; export * from './CopyWithTooltip'; diff --git a/libs/webb-ui-components/src/stories/molecules/CodeFile.stories.tsx b/libs/webb-ui-components/src/stories/molecules/CodeFile.stories.tsx new file mode 100644 index 0000000000..e8ef445353 --- /dev/null +++ b/libs/webb-ui-components/src/stories/molecules/CodeFile.stories.tsx @@ -0,0 +1,32 @@ +import { CodeFile } from '@webb-tools/webb-ui-components/components'; +import type { Meta, StoryObj } from '@storybook/react'; + +const meta: Meta = { + title: 'Design System/V2 (WIP)/Molecules/CodeFile', +}; + +// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export +export default meta; + +type Story = StoryObj; + +const MOCK_FETCH_URL = + 'https://raw.githubusercontent.com/webb-tools/webb-dapp/develop/apps/zk-explorer/app/page.tsx'; + +// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args +export const Default: Story = { + render: () => ( +
+ { + const res = await fetch(MOCK_FETCH_URL); + const code = await res.text(); + return code; + }} + language="tsx" + isInNextProject={false} + /> + , +
+ ), +};