Skip to content

Commit

Permalink
Signing Rules on Service Details page on Tangle Dapp (#2046)
Browse files Browse the repository at this point in the history
  • Loading branch information
vutuanlinh2k2 authored Feb 21, 2024
1 parent 48ba5a1 commit 450af73
Show file tree
Hide file tree
Showing 31 changed files with 339 additions and 101 deletions.
2 changes: 0 additions & 2 deletions apps/tangle-dapp/app/claim/EligibleSection.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
1 change: 1 addition & 0 deletions apps/tangle-dapp/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<JobType>();

Expand Down
Original file line number Diff line number Diff line change
@@ -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';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
Original file line number Diff line number Diff line change
@@ -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<ElementRef<'div'>, ComponentProps<'div'>>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 });

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion apps/tangle-dapp/app/services/[serviceId]/DetailTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const DetailTabs: FC<DetailTabsProps> = ({ serviceId, className }) => {
<JobsListTable serviceId={serviceId} />
</TabContent>
<TabContent value={SIGNING_RULES_TAB} className="flex-1">
<SigningRules />
<SigningRules serviceId={serviceId} />
</TabContent>
</TableAndChartTabs>
);
Expand Down
69 changes: 66 additions & 3 deletions apps/tangle-dapp/app/services/[serviceId]/SigningRules.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,70 @@
import { FC } from 'react';
'use client';

const SigningRules: FC = () => {
return <div>SigningRules</div>;
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<SigningRulesProps> = ({ className }) => {
const [signingRulesContractAddr, setSigningRulesContractAddr] = useState<
string | null
>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);

useEffect(() => {
// TODO: get permitted caller
// TODO: check if permitted caller is a contract or not
setSigningRulesContractAddr('');
setIsLoading(false);
setError(null);
}, []);

if (isLoading) {
return <div>Loading...</div>;
}

if (error !== null) {
return (
<Typography variant="body1" color="error">
Error
</Typography>
);
}

if (signingRulesContractAddr === null) {
return (
<Typography variant="body1">
No Signing Rules associated with this service
</Typography>
);
}

return (
<div
className={twMerge(
'bg-[linear-gradient(180deg,#FFF_0%,rgba(255,255,255,0.50)_100%)]',
'dark:bg-[linear-gradient(180deg,#2B2F40_0%,rgba(43,47,64,0.00)_100%)]',
'h-full p-6 rounded-2xl flex flex-col',
'border border-mono-0 dark:border-mono-160',
className
)}
>
<CodeFile
getCodeFileFnc={() => getSigningRules(signingRulesContractAddr)}
isInNextProject
className="bg-mono-20 dark:bg-mono-200 overflow-auto max-h-[740px]"
// smart contract language: Solidity
language="sol"
/>
</div>
);
};

export default SigningRules;
2 changes: 1 addition & 1 deletion apps/tangle-dapp/app/services/[serviceId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function ServiceDetails({
{/* Tabs */}
<DetailTabs
serviceId={serviceId}
className="lg:min-h-[600px] md:flex-[3]"
className="lg:min-h-[600px] md:flex-[3] min-w-0"
/>

{/* Participants Table */}
Expand Down
2 changes: 2 additions & 0 deletions apps/tangle-dapp/components/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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}`;
}
Expand All @@ -53,6 +54,7 @@ const getBreadcrumbIcon = (
index: number,
pathNames: string[]
) => {
// Service Details page
if (pathNames.length === 2 && index === 1 && pathNames[0] === 'services') {
return <CodeFill className="w-4 h-4 lg:w-6 lg:h-6" />;
}
Expand Down
4 changes: 2 additions & 2 deletions apps/tangle-dapp/components/sideBar/sideBarProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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(
Expand Down
91 changes: 91 additions & 0 deletions apps/tangle-dapp/data/ServiceDetails/getSigningRules.ts
Original file line number Diff line number Diff line change
@@ -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;
}
1 change: 1 addition & 0 deletions apps/tangle-dapp/data/ServiceDetails/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as getSigningRules } from './getSigningRules';
export { default as useServiceJobs } from './useServiceJobs';
export { default as useServiceParticipants } from './useServiceParticipants';
23 changes: 7 additions & 16 deletions apps/tangle-dapp/hooks/useQueryParamKey.ts
Original file line number Diff line number Diff line change
@@ -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> =
Page extends PagePath.Nomination
? QueryParamKey.DelegationsAndPayoutsTab
: never;

export type QueryParamValueOf<Key extends QueryParamKey> =
Key extends QueryParamKey.DelegationsAndPayoutsTab
? DelegationsAndPayoutsTab
: never;
import {
DelegationsAndPayoutsTab,
PagePath,
QueryParamKey,
QueryParamKeyOf,
QueryParamValueOf,
} from '../types';

type UseQueryParamsReturn<Page extends PagePath> = {
value: QueryParamValueOf<QueryParamKeyOf<Page>> | null;
Expand Down
Loading

0 comments on commit 450af73

Please sign in to comment.