setIsOpen(!isOpen);
const { delegatedSubnets } = useDelegateSubnetStore();
- const isSubnetDelegated = delegatedSubnets.some(
- (s) => s.id === subnet.netuid,
- );
+ const isSubnetDelegated = delegatedSubnets.some((s) => s.id === id);
return (
-
-
-
+
+
+
+ {percentage && }
-
+
-
- {isOpen && (
-
-
- {subnetDataList.map((field) => (
-
- ))}
-
-
- )}
-
- );
-}
-
-function InfoItem({ label, value }: { label: string; value: unknown }) {
- return (
-
- {label}:
-
- {value !== null && value !== undefined ? String(value) : "N/A"}
-
);
}
diff --git a/apps/commune-validator/src/app/module/[...slug]/page.tsx b/apps/commune-validator/src/app/module/[...slug]/page.tsx
deleted file mode 100644
index cbf0d5a7..00000000
--- a/apps/commune-validator/src/app/module/[...slug]/page.tsx
+++ /dev/null
@@ -1,138 +0,0 @@
-import Link from "next/link";
-import { notFound } from "next/navigation";
-import { ArrowLeftIcon } from "@heroicons/react/16/solid";
-
-import { MarkdownView } from "@commune-ts/ui/markdown-view";
-import { fetchCustomMetadata, smallAddress } from "@commune-ts/utils";
-
-import { ReportModule } from "~/app/components/report-module";
-import { api } from "~/trpc/server";
-
-interface Params {
- params: {
- slug: string[];
- };
-}
-
-interface CustomMetadata {
- Ok?: {
- title?: string;
- body?: string;
- };
-}
-
-export default async function ModulePage({ params }: Params) {
- const { slug } = params;
-
- if (slug.length !== 1) {
- notFound();
- }
-
- const id = slug[0];
-
- if (!/^\d+$/.test(String(id))) {
- notFound();
- }
-
- const mdl = await api.module.byId({ id: Number(id) });
-
- if (!mdl) {
- notFound();
- }
-
- const metadata = (await fetchCustomMetadata(
- "proposal",
- mdl.id,
- mdl.metadataUri ?? "",
- )) as CustomMetadata;
-
- const title = metadata.Ok?.title ?? "No Metadata";
- // limited to 140 characters
- const description = metadata.Ok?.body ?? "This module has no custom metadata";
-
- return (
-
-
-
-
- Go back to modules list
-
-
- {title}
-
-
-
-
-
-
-
-
-
-
-
-
Publication Date
- {new Date(mdl.createdAt).toLocaleString()}
-
-
-
Address
- {smallAddress(String(mdl.moduleKey))}
-
-
-
Emission
- {mdl.emission ?? 0}
-
-
-
Total Stakers
- {mdl.totalStakers ?? 0}
-
-
-
-
-
Category
-
- {mdl.incentive === mdl.dividend ||
- !mdl.incentive ||
- !mdl.dividend
- ? "Inactive"
- : mdl.incentive > mdl.dividend
- ? "Miner"
- : "Validator"}
-
-
-
-
Reading Time
- {calculateReadingTime(description)}
-
-
-
Incentive
- {mdl.incentive ?? 0}
-
-
-
Total Staked
- {mdl.totalStaked ?? 0}
-
-
-
-
-
-
- );
-}
-
-function calculateReadingTime(text: string): string {
- const wordsPerMinute = 200; // Average reading speed
- const words = text.split(/\s+/).length; // Split text by whitespace and count words
- const minutes = words / wordsPerMinute;
-
- const minutesRounded = Math.ceil(minutes); // Round up to the nearest minute
-
- return `${minutesRounded} min read`;
-}
diff --git a/apps/commune-validator/src/stores/delegateModuleStore.ts b/apps/commune-validator/src/stores/delegateModuleStore.ts
index 1b1bb680..1506cdfd 100644
--- a/apps/commune-validator/src/stores/delegateModuleStore.ts
+++ b/apps/commune-validator/src/stores/delegateModuleStore.ts
@@ -3,9 +3,8 @@ import { persist } from "zustand/middleware";
interface DelegatedModule {
id: number;
- address: string;
- title: string;
name: string;
+ address: string;
percentage: number;
}
diff --git a/apps/commune-validator/src/stores/delegateSubnetStore.ts b/apps/commune-validator/src/stores/delegateSubnetStore.ts
index 26529d9f..6a5bc804 100644
--- a/apps/commune-validator/src/stores/delegateSubnetStore.ts
+++ b/apps/commune-validator/src/stores/delegateSubnetStore.ts
@@ -1,10 +1,11 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";
-import type { Subnet } from "~/utils/types";
-
-interface DelegatedSubnet extends Subnet {
+export interface DelegatedSubnet {
+ id: number;
+ name: string;
percentage: number;
+ founderAddress: string;
}
interface DelegateState {
@@ -44,8 +45,8 @@ export const useDelegateSubnetStore = create
()(
getTotalPercentage: () => {
return get().delegatedSubnets.reduce((sum, m) => sum + m.percentage, 0);
},
- setDelegatedSubnetsFromDB: (Subnets) =>
- set(() => ({ delegatedSubnets: Subnets, originalSubnets: Subnets })),
+ setDelegatedSubnetsFromDB: (subnets) =>
+ set(() => ({ delegatedSubnets: subnets, originalSubnets: subnets })),
updateOriginalSubnets: () =>
set((state) => ({ originalSubnets: [...state.delegatedSubnets] })),
hasUnsavedChanges: () => {
@@ -53,11 +54,11 @@ export const useDelegateSubnetStore = create()(
if (state.delegatedSubnets.length !== state.originalSubnets.length) {
return true;
}
- return state.delegatedSubnets.some((Subnet, index) => {
+ return state.delegatedSubnets.some((subnet, index) => {
const originalSubnet = state.originalSubnets[index];
return (
- Subnet.id !== originalSubnet?.id ||
- Subnet.percentage !== originalSubnet.percentage
+ subnet.id !== originalSubnet?.id ||
+ subnet.percentage !== originalSubnet.percentage
);
});
},
diff --git a/apps/commune-validator/src/utils/types.ts b/apps/commune-validator/src/utils/types.ts
index 2858c224..de5eea2f 100644
--- a/apps/commune-validator/src/utils/types.ts
+++ b/apps/commune-validator/src/utils/types.ts
@@ -6,6 +6,10 @@ export type Subnet = NonNullable<
inferProcedureOutput
>;
+export type Module = NonNullable<
+ inferProcedureOutput
+>;
+
export type ReportReason = NonNullable<
inferProcedureOutput
>["reason"];
diff --git a/apps/commune-worker/src/workers/subnet-fetcher.ts b/apps/commune-worker/src/workers/subnet-fetcher.ts
index d1fdd325..8fd44aa8 100644
--- a/apps/commune-worker/src/workers/subnet-fetcher.ts
+++ b/apps/commune-worker/src/workers/subnet-fetcher.ts
@@ -27,7 +27,7 @@ export async function subnetFetcherWorker(props: WorkerProps) {
SubnetToDatabase(subnet, props.lastBlock.blockNumber),
);
log(
- `Block ${props.lastBlock.blockNumber}: upserting ${subnetData.length} modules`,
+ `Block ${props.lastBlock.blockNumber}: upserting ${subnetData.length} subnets`,
);
await upsertSubnetData(subnetData);
diff --git a/packages/utils/index.ts b/packages/utils/index.ts
index dea2712b..8efeb5db 100644
--- a/packages/utils/index.ts
+++ b/packages/utils/index.ts
@@ -1,30 +1,29 @@
+import { BN } from "@polkadot/util";
import { CID } from "multiformats/cid";
import { match } from "rustie";
import { AssertionError } from "tsafe";
import type {
AnyTuple,
+ Api,
Codec,
CustomDaoMetadata,
CustomDataError,
CustomMetadata,
DaoApplications,
Entry,
- OptionalProperties,
Proposal,
RawEntry,
Result,
SS58Address,
StorageKey,
- SubspaceModule,
ZodSchema,
- Api
} from "@commune-ts/types";
import {
CUSTOM_METADATA_SCHEMA,
DAO_APPLICATIONS_SCHEMA,
PROPOSAL_SCHEMA,
- URL_SCHEMA
+ URL_SCHEMA,
} from "@commune-ts/types";
/**
@@ -113,9 +112,7 @@ export function bigintDivision(a: bigint, b: bigint, precision = 8n): number {
return (Number(a) * Number(base)) / Number(b) / baseNum;
}
-import { BN } from '@polkadot/util';
-
-const NANO_MULTIPLIER = new BN('1000000000');
+const NANO_MULTIPLIER = new BN("1000000000");
/**
* Converts a nano value to its standard unit representation
@@ -123,12 +120,15 @@ const NANO_MULTIPLIER = new BN('1000000000');
* @param decimals - Number of decimal places to round to (default: 6)
* @returns The value in standard units as a string
*/
-export function fromNano(nanoValue: number | string | bigint | BN, decimals = 9): string {
+export function fromNano(
+ nanoValue: number | string | bigint | BN,
+ decimals = 9,
+): string {
const bnValue = new BN(nanoValue.toString());
const integerPart = bnValue.div(NANO_MULTIPLIER);
const fractionalPart = bnValue.mod(NANO_MULTIPLIER);
- const fractionalStr = fractionalPart.toString().padStart(9, '0');
+ const fractionalStr = fractionalPart.toString().padStart(9, "0");
const roundedFractionalStr = fractionalStr.slice(0, decimals);
return `${integerPart.toString()}.${roundedFractionalStr}`;
@@ -140,19 +140,23 @@ export function fromNano(nanoValue: number | string | bigint | BN, decimals = 9)
* @returns The value in nano units as a BN
*/
export function toNano(standardValue: number | string): BN {
- const [integerPart, fractionalPart = ''] = standardValue.toString().split('.');
- const paddedFractionalPart = fractionalPart.padEnd(9, '0');
+ const [integerPart, fractionalPart = ""] = standardValue
+ .toString()
+ .split(".");
+ const paddedFractionalPart = fractionalPart.padEnd(9, "0");
const nanoValue = `${integerPart}${paddedFractionalPart}`;
return new BN(nanoValue);
}
-
export function formatToken(nano: number | bigint, decimalPlaces = 2): string {
const fullPrecisionAmount = fromNano(nano).toString();
- const [integerPart = '0', fractionalPart = ''] = fullPrecisionAmount.split('.');
+ const [integerPart = "0", fractionalPart = ""] =
+ fullPrecisionAmount.split(".");
- const formattedIntegerPart = Number(integerPart).toLocaleString('en-US');
- const roundedFractionalPart = fractionalPart.slice(0, decimalPlaces).padEnd(decimalPlaces, '0');
+ const formattedIntegerPart = Number(integerPart).toLocaleString("en-US");
+ const roundedFractionalPart = fractionalPart
+ .slice(0, decimalPlaces)
+ .padEnd(decimalPlaces, "0");
return `${formattedIntegerPart}.${roundedFractionalPart}`;
}
@@ -263,24 +267,43 @@ export function getExpirationTime(
}
export interface ChainEntry {
-
getMapModules(netuid?: number): Record;
}
-
export type SubspacePalletName =
- | "subspaceModule" | "governanceModule" | "subnetEmissionModule";
-
+ | "subspaceModule"
+ | "governanceModule"
+ | "subnetEmissionModule";
export type SubspaceStorageName =
- | "emission" | "incentive" | "dividends" | "lastUpdate"
- | "metadata" | "registrationBlock" | "name" | "address"
- | "keys" | "subnetNames" | "immunityPeriod" | "minAllowedWeights"
- | "maxAllowedWeights" | "tempo" | "maxAllowedUids" | "founder"
- | "founderShare" | "incentiveRatio" | "trustRatio" | "maxWeightAge"
- | "bondsMovingAverage" | "maximumSetWeightCallsPerEpoch" | "minValidatorStake"
- | "maxAllowedValidators" | "moduleBurnConfig" | "subnetMetadata"
- | "subnetGovernanceConfig" | "subnetEmission";
+ | "emission"
+ | "incentive"
+ | "dividends"
+ | "lastUpdate"
+ | "metadata"
+ | "registrationBlock"
+ | "name"
+ | "address"
+ | "keys"
+ | "subnetNames"
+ | "immunityPeriod"
+ | "minAllowedWeights"
+ | "maxAllowedWeights"
+ | "tempo"
+ | "maxAllowedUids"
+ | "founder"
+ | "founderShare"
+ | "incentiveRatio"
+ | "trustRatio"
+ | "maxWeightAge"
+ | "bondsMovingAverage"
+ | "maximumSetWeightCallsPerEpoch"
+ | "minValidatorStake"
+ | "maxAllowedValidators"
+ | "moduleBurnConfig"
+ | "subnetMetadata"
+ | "subnetGovernanceConfig"
+ | "subnetEmission";
// TODO: add MinimumAllowedStake, stakeFrom
@@ -288,7 +311,10 @@ export function standardizeUidToSS58address(
outerRecord: Record>,
uidToKey: Record,
): Record> {
- const processedRecord: Record> = {} as Record>;
+ const processedRecord: Record<
+ T,
+ Record
+ > = {} as Record>;
const entries = Object.entries(outerRecord) as [T, Record][];
for (const [outerKey, innerRecord] of entries) {
@@ -311,26 +337,45 @@ export function standardizeUidToSS58address(
return processedRecord;
}
-
type StorageTypes = "VecMapping" | "DoubleMap" | "SimpleMap";
export function getSubspaceStorageMappingKind(
- prop: SubspaceStorageName
+ prop: SubspaceStorageName,
): StorageTypes | null {
-
const vecProps: SubspaceStorageName[] = [
- "emission", "incentive", "dividends", "lastUpdate"
+ "emission",
+ "incentive",
+ "dividends",
+ "lastUpdate",
];
const doubleMapProps: SubspaceStorageName[] = [
- "metadata", "registrationBlock", "name", "address", "keys"
+ "metadata",
+ "registrationBlock",
+ "name",
+ "address",
+ "keys",
];
const simpleMapProps: SubspaceStorageName[] = [
- "minAllowedWeights", "maxWeightAge", "maxAllowedWeights", "trustRatio",
- "tempo", "founderShare", "subnetNames", "immunityPeriod", "maxAllowedUids",
- "founder", "incentiveRatio", "bondsMovingAverage",
- "maximumSetWeightCallsPerEpoch", "minValidatorStake", "maxAllowedValidators",
- "moduleBurnConfig", "subnetMetadata", "subnetGovernanceConfig", "subnetEmission"
- ]
+ "minAllowedWeights",
+ "maxWeightAge",
+ "maxAllowedWeights",
+ "trustRatio",
+ "tempo",
+ "founderShare",
+ "subnetNames",
+ "immunityPeriod",
+ "maxAllowedUids",
+ "founder",
+ "incentiveRatio",
+ "bondsMovingAverage",
+ "maximumSetWeightCallsPerEpoch",
+ "minValidatorStake",
+ "maxAllowedValidators",
+ "moduleBurnConfig",
+ "subnetMetadata",
+ "subnetGovernanceConfig",
+ "subnetEmission",
+ ];
const mapping = {
VecMapping: vecProps,
DoubleMap: doubleMapProps,
@@ -347,7 +392,8 @@ export async function getPropsToMap(
api: Api,
netuid?: number,
): Promise> {
- const mapped_prop_entries: Record = {} as Record
+ const mapped_prop_entries: Record =
+ {} as Record;
for (const [palletName, storageNames] of Object.entries(props)) {
const asyncOperations = storageNames.map(async (storageName) => {
@@ -363,7 +409,8 @@ export async function getPropsToMap(
}
mapped_prop_entries[storageName] = new StorageVecMap(entries);
} else if (value === "DoubleMap") {
- const entries = await api.query[palletName]?.[storageName]?.entries(netuid);
+ const entries =
+ await api.query[palletName]?.[storageName]?.entries(netuid);
if (entries === undefined) {
console.log(`No entries for ${palletName}.${storageName}`);
@@ -390,7 +437,7 @@ export async function getPropsToMap(
}
export class StorageVecMap implements ChainEntry {
- constructor(private readonly entry: [StorageKey, Codec][]) { }
+ constructor(private readonly entry: [StorageKey, Codec][]) {}
getMapModules(netuid: number) {
if (netuid === undefined) {
@@ -403,13 +450,12 @@ export class StorageVecMap implements ChainEntry {
values.map((value, index) => [index, value]),
);
return modules_map;
- }
- else return {};
+ } else return {};
}
}
export class SimpleMap implements ChainEntry {
- constructor(private readonly entry: [StorageKey, Codec][]) { }
+ constructor(private readonly entry: [StorageKey, Codec][]) {}
getMapModules() {
const modules_map = Object.fromEntries(
@@ -420,11 +466,11 @@ export class SimpleMap implements ChainEntry {
}
export class DoubleMapEntries implements ChainEntry {
- constructor(private readonly entries: [StorageKey, Codec][]) { }
+ constructor(private readonly entries: [StorageKey, Codec][]) {}
getMapModules() {
const moduleIdToPropValue: Record = {};
- this.entries.forEach(entry => {
+ this.entries.forEach((entry) => {
const moduleCodec = entry[1];
const moduleId = entry[0].args[1]?.toPrimitive() as number;
moduleIdToPropValue[moduleId] = moduleCodec.toPrimitive() as string;
@@ -433,7 +479,6 @@ export class DoubleMapEntries implements ChainEntry {
}
}
-
export function parseAddress(valueRaw: Codec): DaoApplications | null {
const value = valueRaw.toPrimitive();
const validated = DAO_APPLICATIONS_SCHEMA.safeParse(value);
@@ -465,7 +510,7 @@ export const paramNameToDisplayName = (paramName: string): string => {
return (
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
PARAM_FIELD_DISPLAY_NAMES[
- paramName as keyof typeof PARAM_FIELD_DISPLAY_NAMES
+ paramName as keyof typeof PARAM_FIELD_DISPLAY_NAMES
] ?? paramName
);
};
@@ -555,4 +600,4 @@ export function flattenResult(x: Result): T | null {
return null;
},
});
-}
\ No newline at end of file
+}