From 0bb4cb709b5bc6146a6270ce4847571700cef86f Mon Sep 17 00:00:00 2001 From: Adam Soffer Date: Sun, 12 Dec 2021 14:24:04 -0500 Subject: [PATCH] Distinguish between demand-side dilution (implicit costs) and fees (direct costs) (#70) --- components/Table/index.tsx | 106 ++++++++++++++++++++++++++++++++---- components/Ticker/index.tsx | 10 +++- pages/[slug].tsx | 69 ++++++++++++++++------- pages/api/projects/[id].ts | 75 ++++++++++++++----------- pages/api/projects/index.ts | 27 ++++++++- registry.json | 3 +- types/index.d.ts | 2 + 7 files changed, 227 insertions(+), 65 deletions(-) diff --git a/components/Table/index.tsx b/components/Table/index.tsx index 992fadf..cb32251 100644 --- a/components/Table/index.tsx +++ b/components/Table/index.tsx @@ -16,6 +16,7 @@ import { ChevronDownIcon, ChevronUpIcon, } from "@radix-ui/react-icons"; +import registry from "../../registry.json"; const Table = ({ columns, data, ...props }) => { const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = @@ -202,7 +203,31 @@ const StyledImage = styled("img", { mr: "$3", }); +const poktDisclaimer = ( + <> + + Pocket has a unique payment mechanism. Developers stake POKT upfront to + lock in a guaranteed amount of bandwidth and pay through dilution as the + protocol mints new POKT and rewards node operators based directly on the + amount of usage of the network. + + + The Web3 Index tracks developers' dilutionary payment activity, but + does not count it towards fees to avoid confusing apples with oranges + (implicit costs vs direct costs). The Pocket DAO is planning a shift from + developers paying via dilution, to developers paying via the burning of + their stake in proportion to their usage. Once the DAO makes this change, + burned staked tokens will count towards fees on the index. + + +); + function renderSwitch(cell) { + const paymentType = + registry[cell.row.values.name.toLowerCase()]?.paymentType === "dilution" + ? "dilution" + : "revenue"; + switch (cell.column.id) { case "usage.revenue.oneWeekTotal": { return `$${Math.round( @@ -211,15 +236,75 @@ function renderSwitch(cell) { } case "usage.revenue.thirtyDayTotal": { if (cell.row.values.untracked) return "--"; - return `$${Math.round( - cell.row.values.usage.revenue.thirtyDayTotal - ).toLocaleString()}`; + return paymentType === "dilution" ? ( + + $0.00 + + + + + ($ + {Math.round( + cell.row.values.usage.dilution.thirtyDayTotal + ).toLocaleString()}{" "} + diluted) + {" "} + + + + + + {poktDisclaimer} + + + + ) : ( + + $ + {Math.round( + cell.row.values.usage.revenue.thirtyDayTotal + ).toLocaleString()} + + ); } case "usage.revenue.ninetyDayTotal": { if (cell.row.values.untracked) return "--"; - return `$${Math.round( - cell.row.values.usage.revenue.ninetyDayTotal - ).toLocaleString()}`; + return paymentType === "dilution" ? ( + + $0.00 + + + + + ($ + {Math.round( + cell.row.values.usage.dilution.ninetyDayTotal + ).toLocaleString()}{" "} + diluted) + {" "} + + + + + + {poktDisclaimer} + + + + ) : ( + + $ + {Math.round( + cell.row.values.usage.revenue.ninetyDayTotal + ).toLocaleString()} + + ); } case "totalRevenue": { return `$${Math.round( @@ -229,7 +314,6 @@ function renderSwitch(cell) { case "usage.revenue.oneWeekPercentChange": { return ( - {/* */} 0 + cell.row.values.usage[paymentType].thirtyDayPercentChange > 0 ? defaultTheme.colors.green : defaultTheme.colors.red; @@ -255,7 +339,9 @@ function renderSwitch(cell) { @@ -264,7 +350,7 @@ function renderSwitch(cell) { case "lastThirtyDays": { if (cell.row.values.untracked) return "--"; const color = - cell.row.values.usage.revenue.thirtyDayPercentChange > 0 + cell.row.values.usage[paymentType].thirtyDayPercentChange > 0 ? defaultTheme.colors.green : defaultTheme.colors.red; diff --git a/components/Ticker/index.tsx b/components/Ticker/index.tsx index a48d054..642d96f 100644 --- a/components/Ticker/index.tsx +++ b/components/Ticker/index.tsx @@ -4,10 +4,16 @@ import Marquee from "react-fast-marquee"; import { useTheme } from "next-themes"; import LineGraph from "../LineGraph"; import { defaultTheme } from "../../stitches.config"; +import registry from "../../registry.json"; const Project = ({ project }) => { + const paymentType = + registry[project.name.toLowerCase()]?.paymentType === "dilution" + ? "dilution" + : "revenue"; + const color = - project.usage.revenue.thirtyDayPercentChange > 0 + project.usage[paymentType].thirtyDayPercentChange > 0 ? defaultTheme.colors.green : defaultTheme.colors.red; @@ -42,7 +48,7 @@ const Project = ({ project }) => { diff --git a/pages/[slug].tsx b/pages/[slug].tsx index f65a176..a42a119 100644 --- a/pages/[slug].tsx +++ b/pages/[slug].tsx @@ -122,6 +122,8 @@ const Project = ({ slug, index, projects, project }) => { const ref = useRef(null); const isClient = typeof window === "object"; const [width, setWidth] = useState(ref?.current?.container?.clientWidth); + const paymentType = + registry[slug]?.paymentType === "dilution" ? "dilution" : "revenue"; useEffect(() => { if (!isClient) { @@ -275,7 +277,9 @@ const Project = ({ slug, index, projects, project }) => { @@ -285,7 +289,7 @@ const Project = ({ slug, index, projects, project }) => { $ {Math.round( - project.usage.revenue.thirtyDayTotal + project.usage[paymentType].thirtyDayTotal ).toLocaleString()} @@ -294,15 +298,18 @@ const Project = ({ slug, index, projects, project }) => { - Total demand-side fees accrued by the protocol - over the last 30 days. + {paymentType === "dilution" + ? "Total dilution incurred by the demand-side of the protocol over the last 30 days." + : "Total demand-side fees accrued by the protocol over the last 30 days."} } /> @@ -312,7 +319,7 @@ const Project = ({ slug, index, projects, project }) => { $ {Math.round( - project.usage.revenue.ninetyDayTotal + project.usage[paymentType].ninetyDayTotal ).toLocaleString()} @@ -321,17 +328,22 @@ const Project = ({ slug, index, projects, project }) => { - Total demand-side fees accrued by the protocol - over the last 90 days. + {paymentType === "dilution" + ? "Total dilution incurred by the demand-side of the protocol over the last 30 days." + : "Total demand-side fees accrued by the protocol over the last 30 days."} } /> { percentChange={Intl.NumberFormat("en-US", { maximumFractionDigits: 2, }).format( - project.usage.revenue.thirtyDayPercentChange + project.usage[paymentType] + .thirtyDayPercentChange )} /> @@ -357,12 +370,25 @@ const Project = ({ slug, index, projects, project }) => { - Trend is the increase, or decrease, in the - protocol's demand-side fees between two - periods. It's calculated by subtracting the - previous 30d fees from the current 30d Fees, and - then dividing that number by the previous 30d - fees. + {paymentType === "dilution" ? ( + + Trend is the increase or decrease in the + protocol's dilutionary activity between + two periods. It's calculated by + subtracting the previous 30d dilution from the + current 30d dilution, and then dividing that + number by the previous 30d dilution. + + ) : ( + + Trend is the increase or decrease in the + protocol's demand-side fees between two + periods. It's calculated by subtracting + the previous 30d fees from the current 30d + fees, and then dividing that number by the + previous 30d fees. + + )} @@ -443,13 +469,18 @@ const Project = ({ slug, index, projects, project }) => { ) : ( )} diff --git a/pages/api/projects/[id].ts b/pages/api/projects/[id].ts index f0b3347..06a3466 100644 --- a/pages/api/projects/[id].ts +++ b/pages/api/projects/[id].ts @@ -14,6 +14,17 @@ const utcThirtyDaysBack = utcCurrentTime.subtract(30, "day").unix(); const utcSixtyDaysBack = utcCurrentTime.subtract(60, "day").unix(); const utcNinetyDaysBack = utcCurrentTime.subtract(90, "day").unix(); +const EMPTY = { + now: 0, + oneDayAgo: 0, + twoDaysAgo: 0, + oneWeekAgo: 0, + twoWeeksAgo: 0, + thirtyDaysAgo: 0, + sixtyDaysAgo: 0, + ninetyDaysAgo: 0, +}; + const getUsageFromDB = async (name) => { const project = await prisma.project.findFirst({ where: { @@ -41,29 +52,27 @@ const getUsageFromDB = async (name) => { take: 1000, }); + const revenue = { + now: now.sum.revenue, // total revenue as of now + oneDayAgo: await getRevenueFromDB(project.id, utcOneDayBack, prisma), // total revenue as of 1 day ago + twoDaysAgo: await getRevenueFromDB(project.id, utcTwoDaysBack, prisma), // total revenue as of two days ago + oneWeekAgo: await getRevenueFromDB(project.id, utcOneWeekBack, prisma), // total revenue as of one week ago + twoWeeksAgo: await getRevenueFromDB(project.id, utcTwoWeeksBack, prisma), // total revenue as of two weeks ago + thirtyDaysAgo: await getRevenueFromDB( + project.id, + utcThirtyDaysBack, + prisma + ), // total revenue as of thirty days ago + sixtyDaysAgo: await getRevenueFromDB(project.id, utcSixtyDaysBack, prisma), // total revenue as of sixty days ago + ninetyDaysAgo: await getRevenueFromDB( + project.id, + utcNinetyDaysBack, + prisma + ), // total revenue as of ninety days ago + }; const tmp = { - revenue: { - now: now.sum.revenue, // total revenue as of now - oneDayAgo: await getRevenueFromDB(project.id, utcOneDayBack, prisma), // total revenue as of 1 day ago - twoDaysAgo: await getRevenueFromDB(project.id, utcTwoDaysBack, prisma), // total revenue as of two days ago - oneWeekAgo: await getRevenueFromDB(project.id, utcOneWeekBack, prisma), // total revenue as of one week ago - twoWeeksAgo: await getRevenueFromDB(project.id, utcTwoWeeksBack, prisma), // total revenue as of two weeks ago - thirtyDaysAgo: await getRevenueFromDB( - project.id, - utcThirtyDaysBack, - prisma - ), // total revenue as of thirty days ago - sixtyDaysAgo: await getRevenueFromDB( - project.id, - utcSixtyDaysBack, - prisma - ), // total revenue as of sixty days ago - ninetyDaysAgo: await getRevenueFromDB( - project.id, - utcNinetyDaysBack, - prisma - ), // total revenue as of ninety days ago - }, + revenue: registry[name].paymentType === "dilution" ? EMPTY : revenue, + dilution: registry[name].paymentType === "dilution" ? revenue : EMPTY, days: days, }; @@ -179,17 +188,19 @@ const getUsageFromSubgraph = async (id) => { days = days.sort((a, b) => (parseInt(a.date) > parseInt(b.date) ? 1 : -1)); + const revenue = { + now: +data.protocol.revenueUSD, + oneDayAgo: +oneDayResult.protocol.revenueUSD, + twoDaysAgo: +twoDayResult.protocol.revenueUSD, + oneWeekAgo: +oneWeekResult.protocol.revenueUSD, + twoWeeksAgo: +twoWeekResult.protocol.revenueUSD, + thirtyDaysAgo: +thirtyDayResult.protocol.revenueUSD, + sixtyDaysAgo: +sixtyDayResult.protocol.revenueUSD, + ninetyDaysAgo: +ninetyDayResult.protocol.revenueUSD, + }; return { - revenue: { - now: +data.protocol.revenueUSD, - oneDayAgo: +oneDayResult.protocol.revenueUSD, - twoDaysAgo: +twoDayResult.protocol.revenueUSD, - oneWeekAgo: +oneWeekResult.protocol.revenueUSD, - twoWeeksAgo: +twoWeekResult.protocol.revenueUSD, - thirtyDaysAgo: +thirtyDayResult.protocol.revenueUSD, - sixtyDaysAgo: +sixtyDayResult.protocol.revenueUSD, - ninetyDaysAgo: +ninetyDayResult.protocol.revenueUSD, - }, + revenue, + dilution: registry[id].paymentType === "dilution" ? revenue : EMPTY, days, }; }; diff --git a/pages/api/projects/index.ts b/pages/api/projects/index.ts index 0efd589..22c078c 100644 --- a/pages/api/projects/index.ts +++ b/pages/api/projects/index.ts @@ -36,11 +36,37 @@ export const getProjects = async () => { data.usage.revenue.sixtyDaysAgo ); + const [oneWeekDilutionTotal, oneWeekDilutionPercentChange] = + getTwoPeriodPercentChange( + data.usage.dilution.now, + data.usage.dilution.oneWeekAgo, + data.usage.dilution.twoWeeksAgo + ); + + const [thirtyDayDilutionTotal, thirtyDayDilutionPercentChange] = + getTwoPeriodPercentChange( + data.usage.dilution.now, + data.usage.dilution.thirtyDaysAgo, + data.usage.dilution.sixtyDaysAgo + ); + projects.push({ ...data, slug: project, usage: { ...data.usage, + dilution: { + ...data.usage.dilution, + oneWeekTotal: oneWeekDilutionTotal, + oneWeekPercentChange: oneWeekDilutionPercentChange, + thirtyDayTotal: registry[project].untracked + ? 0 + : thirtyDayDilutionTotal, + thirtyDayPercentChange: thirtyDayDilutionPercentChange, + ninetyDayTotal: registry[project].untracked + ? 0 + : data.usage.dilution.now - data.usage.dilution.ninetyDaysAgo, + }, revenue: { ...data.usage.revenue, oneWeekTotal, @@ -53,7 +79,6 @@ export const getProjects = async () => { }, }, }); - if (!registry[project].untracked) { totalParticipantRevenueNow += data.usage.revenue.now; totalParticipantRevenueOneWeekAgo += data.usage.revenue.oneWeekAgo; diff --git a/registry.json b/registry.json index 9337304..e27e092 100644 --- a/registry.json +++ b/registry.json @@ -92,6 +92,7 @@ "stack": "Middleware", "subcategory": "Bandwidth", "symbol": "POKT", - "genesisDate": "2020-07-28" + "genesisDate": "2020-07-28", + "paymentType": "dilution" } } diff --git a/types/index.d.ts b/types/index.d.ts index a1c8b41..a4025fa 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -36,6 +36,7 @@ export interface Project { } export interface Usage { revenue: Revenue; + dilution: Revenue; days: Days; [k: string]: unknown; } @@ -53,5 +54,6 @@ export interface Revenue { export interface Items { date: Date; revenue: Revenue; + dilution: Revenue; [k: string]: unknown; }