Skip to content

Commit

Permalink
Merge pull request #88 from helium/mbthiery/update-mobile-emissions
Browse files Browse the repository at this point in the history
Update mobile emissions for mappers release
  • Loading branch information
mbthiery committed Jul 28, 2023
2 parents 3d1e7ef + 92c9ea1 commit 76837a2
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 108 deletions.
25 changes: 5 additions & 20 deletions src/app/stats/components/SubDaoInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ import {
toNumber,
} from "@helium/spl-utils"
import { PublicKey } from "@solana/web3.js"
import { isBefore } from "date-fns"
import { fetchSubDaoGovernanceStats } from "../utils/fetchGovernanceMetrics"
import { fetchMint } from "../utils/fetchMint"
import { fetchSubDaoEpochInfo } from "../utils/fetchSubDaoEpochInfo"
import { fetchSubDaoTreasuryInfo } from "../utils/fetchSubDaoTreasuryInfo"
import { fetchTokenAccount } from "../utils/fetchTokenAccount"
import {
AUG_1_2023,
getDailyEmisisons,
getLatestSubNetworkEmissions,
getRemainingEmissions,
} from "../utils/remainingEmissions"
import { SubDao } from "../utils/types"
Expand All @@ -31,7 +29,6 @@ type SubDaoType = {
linkText: string
icon: Icon
subDaoMint: PublicKey
dailyEmissions: number
maxDescription: string
}

Expand All @@ -42,9 +39,8 @@ const MOBILE_INFO: SubDaoType = {
linkText: "Learn More About MOBILE",
icon: "mobile",
subDaoMint: MOBILE_MINT,
dailyEmissions: 108493150,
maxDescription:
"This is an upper limit that will not be reached and does not consider future MOBILE burn. Reason: Daily emissions are currently only 66% of scheduled emissions, as not all rewardable entities (mappers, service providers, and oracles) exist or currently receive rewards.",
"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.",
}

const IOT_INFO: SubDaoType = {
Expand All @@ -54,22 +50,13 @@ const IOT_INFO: SubDaoType = {
linkText: "Learn More About IOT",
icon: "iot",
subDaoMint: IOT_MINT,
dailyEmissions: 165616438,
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.",
}

export const SubDaoInfo = async ({ subDao }: { subDao: SubDao }) => {
const {
activeUrl,
link,
linkText,
title,
icon,
subDaoMint,
dailyEmissions,
maxDescription,
} = subDao === "mobile" ? MOBILE_INFO : IOT_INFO
const { activeUrl, link, linkText, title, icon, subDaoMint, maxDescription } =
subDao === "mobile" ? MOBILE_INFO : IOT_INFO
const [activeCount, mintInfo, epochInfo, treasuryInfo, governanceMetrics] =
await Promise.all([
fetcher(activeUrl),
Expand Down Expand Up @@ -178,9 +165,7 @@ export const SubDaoInfo = async ({ subDao }: { subDao: SubDao }) => {
<StatItem
label="Daily Emissions"
value={numberWithCommas(
isBefore(new Date(), AUG_1_2023)
? dailyEmissions
: Math.round(getDailyEmisisons(new Date(), subDao, "current"))
getLatestSubNetworkEmissions(new Date(), subDao)
)}
tooltip={{
description: `Amount of ${title} emitted each day.`,
Expand Down
131 changes: 62 additions & 69 deletions src/app/stats/utils/remainingEmissions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { add, sub } from "date-fns"
import {
AUG_1_2023,
getDailyEmisisons,
getLatestSubNetworkEmissions,
getRemainingEmissions,
} from "./remainingEmissions"
import subNetworkEmissions from "./subNetworkEmissions.json"

describe("getRemaingEmissions", () => {
describe("hnt", () => {
Expand Down Expand Up @@ -193,84 +195,75 @@ describe("getRemaingEmissions", () => {
const after2024 = add(AUG_1_2023, { days: 1, years: 1 }) // non-leap
const after2025 = add(AUG_1_2023, { days: 1, years: 2 })

describe("for max emissions", () => {
it("returns the correct values for HNT", () => {
const yearlyEmissions = 15000000
it("returns the correct values for HNT", () => {
const yearlyEmissions = 15000000

expect(getDailyEmisisons(after2023, "hnt")).toBe(yearlyEmissions / 366)
expect(getDailyEmisisons(after2024, "hnt")).toBe(yearlyEmissions / 365)
expect(getDailyEmisisons(after2025, "hnt")).toBe(
yearlyEmissions / 365 / 2
)
})

it("returns the correct values for IOT", () => {
const yearlyEmissions = 32500000000

expect(getDailyEmisisons(after2023, "iot")).toBe(yearlyEmissions / 366)
expect(getDailyEmisisons(after2024, "iot")).toBe(yearlyEmissions / 365)
expect(getDailyEmisisons(after2025, "iot")).toBe(
yearlyEmissions / 365 / 2
)
})
expect(getDailyEmisisons(after2023, "hnt")).toBe(yearlyEmissions / 366)
expect(getDailyEmisisons(after2024, "hnt")).toBe(yearlyEmissions / 365)
expect(getDailyEmisisons(after2025, "hnt")).toBe(
yearlyEmissions / 365 / 2
)
})

it("returns the correct values for MOBILE", () => {
const yearlyEmissions = 30000000000
it("returns the correct values for IOT", () => {
const yearlyEmissions = 32500000000

expect(getDailyEmisisons(after2023, "mobile")).toBe(
yearlyEmissions / 366
)
expect(getDailyEmisisons(after2024, "mobile")).toBe(
yearlyEmissions / 365
)
expect(getDailyEmisisons(after2025, "mobile")).toBe(
yearlyEmissions / 365 / 2
)
})
expect(getDailyEmisisons(after2023, "iot")).toBe(yearlyEmissions / 366)
expect(getDailyEmisisons(after2024, "iot")).toBe(yearlyEmissions / 365)
expect(getDailyEmisisons(after2025, "iot")).toBe(
yearlyEmissions / 365 / 2
)
})

describe("for current emissions", () => {
it("returns the correct values for HNT", () => {
const yearlyEmissions = 15000000
it("returns the correct values for MOBILE", () => {
const yearlyEmissions = 30000000000

expect(getDailyEmisisons(after2023, "hnt", "current")).toBe(
yearlyEmissions / 366
)
expect(getDailyEmisisons(after2024, "hnt", "current")).toBe(
yearlyEmissions / 365
)
expect(getDailyEmisisons(after2025, "hnt", "current")).toBe(
yearlyEmissions / 365 / 2
)
})

it("returns the correct values for IOT", () => {
const yearlyEmissions = 30225000000
expect(getDailyEmisisons(after2023, "mobile")).toBe(yearlyEmissions / 366)
expect(getDailyEmisisons(after2024, "mobile")).toBe(yearlyEmissions / 365)
expect(getDailyEmisisons(after2025, "mobile")).toBe(
yearlyEmissions / 365 / 2
)
})
})

expect(getDailyEmisisons(after2023, "iot", "current")).toBe(
yearlyEmissions / 366
)
expect(getDailyEmisisons(after2024, "iot", "current")).toBe(
yearlyEmissions / 365
)
expect(getDailyEmisisons(after2025, "iot", "current")).toBe(
yearlyEmissions / 365 / 2
)
})
describe("getLatestSubNetworkEmissions", () => {
it("returns the correct values for IOT", () => {
const before2023 = sub(AUG_1_2023, { days: 1 })
const after2023 = add(AUG_1_2023, { days: 1, hours: 1 }) // leap year
const after2024 = add(AUG_1_2023, { days: 1, years: 1, hours: 1 }) // non-leap
expect(getLatestSubNetworkEmissions(before2023, "iot")).toBe(
subNetworkEmissions.iot[0].emissionsPerEpoch
)
expect(getLatestSubNetworkEmissions(after2023, "iot")).toBe(
subNetworkEmissions.iot[1].emissionsPerEpoch
)
expect(getLatestSubNetworkEmissions(after2024, "iot")).toBe(
subNetworkEmissions.iot[2].emissionsPerEpoch
)
})

it("returns the correct values for MOBILE", () => {
const yearlyEmissions = 19800000000
it("returns the correct values for MOBILE", () => {
const weekBefore2023 = sub(AUG_1_2023, { days: 7 })
const catchupDay = sub(AUG_1_2023, { days: 2, hours: 23 })
const before2023 = sub(AUG_1_2023, { days: 1 })
const after2023 = add(AUG_1_2023, { days: 1, hours: 1 }) // leap year
const after2024 = add(AUG_1_2023, { days: 1, years: 1, hours: 1 }) // non-leap

expect(getDailyEmisisons(after2023, "mobile", "current")).toBe(
yearlyEmissions / 366
)
expect(getDailyEmisisons(after2024, "mobile", "current")).toBe(
yearlyEmissions / 365
)
expect(getDailyEmisisons(after2025, "mobile", "current")).toBe(
yearlyEmissions / 365 / 2
)
})
expect(getLatestSubNetworkEmissions(weekBefore2023, "mobile")).toBe(
subNetworkEmissions.mobile[0].emissionsPerEpoch
)
expect(getLatestSubNetworkEmissions(catchupDay, "mobile")).toBe(
subNetworkEmissions.mobile[1].emissionsPerEpoch
)
expect(getLatestSubNetworkEmissions(before2023, "mobile")).toBe(
subNetworkEmissions.mobile[2].emissionsPerEpoch
)
expect(getLatestSubNetworkEmissions(after2023, "mobile")).toBe(
subNetworkEmissions.mobile[3].emissionsPerEpoch
)
expect(getLatestSubNetworkEmissions(after2024, "mobile")).toBe(
subNetworkEmissions.mobile[4].emissionsPerEpoch
)
})
})
})
51 changes: 32 additions & 19 deletions src/app/stats/utils/remainingEmissions.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { add, differenceInDays, differenceInYears, isBefore } from "date-fns"
import {
add,
differenceInDays,
differenceInYears,
isAfter,
isBefore,
sub,
} from "date-fns"
import subNetworkEmissions from "./subNetworkEmissions.json"
import { SubDao } from "./types"

export const AUG_1_2023 = new Date(1690848000 * 1000)
const YEARLY_EMISSIONS = {
max: {
hnt: 15000000,
iot: 32500000000,
mobile: 30000000000,
},
current: {
hnt: 15000000, // full emissions
iot: 30225000000, // 7% to oracles not allocated
mobile: 19800000000, // 34% to mappers, service providers, and oracles not allocated
},
hnt: 15000000,
iot: 32500000000,
mobile: 30000000000,
}

type Token = "hnt" | "mobile" | "iot"
export const getRemainingEmissions = (date: Date, token: Token) => {
const yearlyEmissions = YEARLY_EMISSIONS.max[token]
const yearlyEmissions = YEARLY_EMISSIONS[token]
const REMAINING_AUG_1_2023 = yearlyEmissions * 4
let daysDelta = Math.abs(differenceInDays(AUG_1_2023, date))
if (isBefore(date, AUG_1_2023)) {
Expand Down Expand Up @@ -46,13 +48,8 @@ export const getRemainingEmissions = (date: Date, token: Token) => {
return remainingEmissions - daysDelta * getDailyEmisisons(date, token)
}

type EmissionType = "max" | "current"
export const getDailyEmisisons = (
date: Date,
token: Token,
type: EmissionType = "max"
) => {
const yearlyEmissions = YEARLY_EMISSIONS[type][token]
export const getDailyEmisisons = (date: Date, token: Token) => {
const yearlyEmissions = YEARLY_EMISSIONS[token]
const yearsDeltaAug23 = differenceInYears(date, AUG_1_2023)
const isLeapYear = yearsDeltaAug23 % 4 === 0
const numDays = isLeapYear ? 366 : 365
Expand All @@ -61,3 +58,19 @@ export const getDailyEmisisons = (

return adjustedYearlyEmissions / numDays
}

// emissions schedule taken from https://github.com/helium/helium-program-library/tree/master/packages/helium-admin-cli/emissions
export const getLatestSubNetworkEmissions = (date: Date, token: SubDao) => {
const adjustedDate = sub(date, { days: 1 })
const emissions = subNetworkEmissions[token]
let currentEmissions = emissions[0].emissionsPerEpoch
let index = 1
while (
index < emissions.length &&
isAfter(adjustedDate, new Date(emissions[index].startTime))
) {
currentEmissions = emissions[index].emissionsPerEpoch
index++
}
return currentEmissions
}
38 changes: 38 additions & 0 deletions src/app/stats/utils/subNetworkEmissions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"mobile": [
{
"startTime": "2023-04-18T00:00:00Z",
"emissionsPerEpoch": 108493151
},
{
"startTime": "2023-07-28T00:00:00Z",
"emissionsPerEpoch": 174246575
},
{
"startTime": "2023-07-29T00:00:01Z",
"emissionsPerEpoch": 141369863
},
{
"startTime": "2023-08-01T00:00:00Z",
"emissionsPerEpoch": 70491803
},
{
"startTime": "2024-08-01T00:00:00Z",
"emissionsPerEpoch": 70684932
}
],
"iot": [
{
"startTime": "2023-04-18T00:00:00Z",
"emissionsPerEpoch": 165616438
},
{
"startTime": "2023-08-01T00:00:00Z",
"emissionsPerEpoch": 82581967
},
{
"startTime": "2024-08-01T00:00:00Z",
"emissionsPerEpoch": 82808219
}
]
}

0 comments on commit 76837a2

Please sign in to comment.