Skip to content

Commit

Permalink
Merge pull request #110 from helium/arman/supply-updates
Browse files Browse the repository at this point in the history
Supply API updates
  • Loading branch information
abhay authored Dec 13, 2023
2 parents cb25968 + ee877ff commit 9cbd13f
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 24 deletions.
72 changes: 54 additions & 18 deletions src/app/api/stats/supply/[token]/route.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
import { NextRequest, NextResponse } from "next/server"
import {
HNT_MAX_SUPPLY,
IOT_MAX_SUPPLY,
MOBILE_MAX_SUPPLY,
} from "@/app/stats/utils/emissions"
import { fetchMint } from "@/app/stats/utils/fetchMint"
import { HNT_MINT, MOBILE_MINT, IOT_MINT, toNumber } from "@helium/spl-utils"
import {
getRemainingEmissions,
getDailyEmisisons,
MAX_DAILY_NET_EMISSIONS,
getDailyEmisisons,
getRemainingEmissions,
} from "@/app/stats/utils/remainingEmissions"
import { db } from "@/knex/db"
import { MaxSupply } from "@/knex/maxSupply"
import { HNT_MINT, IOT_MINT, MOBILE_MINT, toNumber } from "@helium/spl-utils"
import { NextRequest, NextResponse } from "next/server"

enum SupplyToken {
HNT = "hnt",
MOBILE = "mobile",
IOT = "iot",
}

type SupplyToken = "hnt" | "mobile" | "iot"
type SupplyType = "circulating" | "total" | "max"
enum SupplyType {
CIRCULATING = "circulating",
TOTAL = "total",
LIMIT = "limit",
MAX = "max",
}

export async function GET(
request: NextRequest,
Expand All @@ -19,33 +36,41 @@ export async function GET(
const type = searchParams.get("type") as SupplyType

if (
!["hnt", "mobile", "iot"].includes(token) ||
!["circulating", "total", "max"].includes(type)
!Object.values(SupplyToken).includes(token) ||
!Object.values(SupplyType).includes(type)
) {
return new NextResponse(null, { status: 400 })
}

const mintInfo = await fetchMint(
{
hnt: HNT_MINT,
mobile: MOBILE_MINT,
iot: IOT_MINT,
[SupplyToken.HNT]: HNT_MINT,
[SupplyToken.MOBILE]: MOBILE_MINT,
[SupplyToken.IOT]: IOT_MINT,
}[token]
)

if (type === "circulating") {
if (type === SupplyType.CIRCULATING || type === SupplyType.TOTAL) {
const circulatingSupply = mintInfo.info?.info.supply!

return NextResponse.json(
toNumber(circulatingSupply, mintInfo?.info?.info.decimals || 0)
)
} else if (type === "total" || type === "max") {
// Return the same thing for total and max as they are functionally the same for us
let remainingEmissions = Math.ceil(getRemainingEmissions(new Date(), token))
} else if (type === SupplyType.LIMIT) {
let remainingEmissions = 0
let supply = mintInfo.info?.info.supply!

if (token === "hnt") {
if (token === SupplyToken.HNT) {
// Due to Net Emissions, assume the max amount will be re-emitted
remainingEmissions += Math.ceil(MAX_DAILY_NET_EMISSIONS)
remainingEmissions = Math.ceil(MAX_DAILY_NET_EMISSIONS)

// using existing supply limit logic to avoid repeating edge case logic
const maxSupplyDb = new MaxSupply(db)
const supplyLimit = (await maxSupplyDb.getLatest({ withBurn: false }))
?.max_supply!
supply = supplyLimit
} else {
remainingEmissions += Math.ceil(getRemainingEmissions(new Date(), token))
}

// Add the daily emissions for today to be conservative
Expand All @@ -54,12 +79,23 @@ export async function GET(
remainingEmissions += Math.ceil(dailyEmissions)

const totalSupply =
mintInfo.info?.info.supply! +
supply +
BigInt(remainingEmissions) *
BigInt(Math.pow(10, mintInfo?.info?.info.decimals || 0))

return NextResponse.json(
toNumber(totalSupply, mintInfo?.info?.info.decimals || 0)
)
} else if (type === SupplyType.MAX) {
switch (token) {
case SupplyToken.HNT:
return NextResponse.json(HNT_MAX_SUPPLY)
case SupplyToken.MOBILE:
return NextResponse.json(MOBILE_MAX_SUPPLY)
case SupplyToken.IOT:
return NextResponse.json(IOT_MAX_SUPPLY)
default:
return new NextResponse(null, { status: 400 })
}
}
}
15 changes: 13 additions & 2 deletions src/app/stats/components/HntInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
fetchHntBurn,
fetchHntEmissions,
} from "../utils/dune/fetchHntEmissions"
import { HNT_MAX_SUPPLY } from "../utils/emissions"
import { fetchHntGovernanceStats } from "../utils/fetchGovernanceMetrics"
import { fetchMint } from "../utils/fetchMint"
import { getNextHalvening } from "../utils/getNextHalvening"
Expand Down Expand Up @@ -127,7 +128,7 @@ export const HntInfo = async () => {
}}
/>
<StatItem
label="Max Supply"
label="Supply Limit"
value={`~${humanReadableBigint(
maxSupplyRecord.max_supply,
hntMint?.info?.info.decimals || 8,
Expand All @@ -136,10 +137,20 @@ export const HntInfo = async () => {
tooltip={{
description:
"Maximum supply of HNT derived by summing current supply, remaining emissions, and today's burned HNT (which are re-emitted via net emissions). This is an upper limit that will not be reached and does not consider future HNT burn. Accurate within 1643 HNT.",
cadence: `Every 8h (last run ${format(
cadence: `Daily (last run ${format(
maxSupplyRecord.recorded_at,
DATE_FORMAT
)})`,
id: "HNT Supply Limit",
}}
/>
<StatItem
label="Max Supply"
value={HNT_MAX_SUPPLY.toLocaleString()}
tooltip={{
description:
"Maximum supply of HNT that can ever exist as defined in HIPs. This is an upper limit that will not be reached and does not consider past or future HNT burn.",
cadence: "Fixed",
id: "HNT Max Supply",
}}
/>
Expand Down
20 changes: 17 additions & 3 deletions src/app/stats/components/SubDaoInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
toNumber,
} from "@helium/spl-utils"
import { PublicKey } from "@solana/web3.js"
import { IOT_MAX_SUPPLY, MOBILE_MAX_SUPPLY } from "../utils/emissions"
import { fetchSubDaoGovernanceStats } from "../utils/fetchGovernanceMetrics"
import { fetchMint } from "../utils/fetchMint"
import { fetchSubDaoEpochInfo } from "../utils/fetchSubDaoEpochInfo"
Expand All @@ -31,6 +32,7 @@ type SubDaoType = {
subDaoMint: PublicKey
maxDescription: string
activeDetails: string
maxSupply: number
}

const MOBILE_INFO: SubDaoType = {
Expand All @@ -43,6 +45,7 @@ const MOBILE_INFO: SubDaoType = {
maxDescription:
"This is an upper limit that will not be reached and does not consider future MOBILE burn. Reason: Daily emissions are currently only 86% of scheduled emissions, as not all rewardable entities (service providers, and oracles) exist or currently receive rewards.",
activeDetails: " This exclusively includes active gateways (not radios).",
maxSupply: MOBILE_MAX_SUPPLY,
}

const IOT_INFO: SubDaoType = {
Expand All @@ -55,6 +58,7 @@ const IOT_INFO: SubDaoType = {
maxDescription:
"This is an upper limit that will not be reached and does not consider future IOT burn. Reason: Daily emissions are currently only 93% of scheduled emissions, as oracles do not currently receive rewards.",
activeDetails: "",
maxSupply: IOT_MAX_SUPPLY,
}

export const SubDaoInfo = async ({ subDao }: { subDao: SubDao }) => {
Expand All @@ -67,6 +71,7 @@ export const SubDaoInfo = async ({ subDao }: { subDao: SubDao }) => {
icon,
subDaoMint,
maxDescription,
maxSupply,
} = subDao === "mobile" ? MOBILE_INFO : IOT_INFO
const [activeCount, mintInfo, epochInfo, treasuryInfo, governanceMetrics] =
await Promise.all([
Expand All @@ -86,7 +91,7 @@ export const SubDaoInfo = async ({ subDao }: { subDao: SubDao }) => {
const remainingEmissions = Math.round(
getRemainingEmissions(new Date(), subDao)
)
const maxSupply =
const supplyLimit =
mintInfo.info?.info.supply! + BigInt(remainingEmissions) * BigInt(1000000)

const supplyStaked = governanceMetrics.total.hnt
Expand Down Expand Up @@ -173,15 +178,24 @@ export const SubDaoInfo = async ({ subDao }: { subDao: SubDao }) => {
}}
/>
<StatItem
label="Max Supply"
label="Supply Limit"
value={humanReadableBigint(
maxSupply,
supplyLimit,
mintInfo?.info?.info.decimals || 0,
0
)}
tooltip={{
description: `Maximum supply of ${title} derived by current supply plus remaining emissions. ${maxDescription}`,
cadence: "Live",
id: `${title} Supply Limit`,
}}
/>
<StatItem
label="Max Supply"
value={maxSupply.toLocaleString()}
tooltip={{
description: `Maximum supply of ${title} that can ever exist as defined in HIPs. This is an upper limit that will not be reached and does not consider ${title} past or future burn.`,
cadence: "Fixed",
id: `${title} Max Supply`,
}}
/>
Expand Down
3 changes: 3 additions & 0 deletions src/app/stats/utils/emissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const HNT_MAX_SUPPLY = 223_000_000
export const IOT_MAX_SUPPLY = 200_000_000_000
export const MOBILE_MAX_SUPPLY = 200_000_000_000
2 changes: 1 addition & 1 deletion src/knex/maxSupply.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class MaxSupply {
this.knex = knex
}

private async getLatest({
async getLatest({
withBurn,
}: {
withBurn: boolean
Expand Down

0 comments on commit 9cbd13f

Please sign in to comment.