Skip to content

Commit

Permalink
Get network economics service (#6174)
Browse files Browse the repository at this point in the history
# Motivation

Currently, the voting power parameters are hardcoded as half a year and
one month. However, they may change in the future. Therefore, we want to
retrieve them from the API. In this PR, we add the service and store to
use them in the following PRs.

# Changes

- New `networkEconomicsStore` store.
- New `loadNetworkEconomicsParameters` service (intentionally no error
toasts, because this doesn't block more important activities).

# Tests

- Added.

# Todos

- [ ] Add entry to changelog (if necessary).
Not necessary.
  • Loading branch information
mstrasinskis authored Jan 16, 2025
1 parent e8f6469 commit 5fba586
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 0 deletions.
4 changes: 4 additions & 0 deletions frontend/src/lib/derived/debug.derived.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
importedTokensStore,
} from "$lib/stores/imported-tokens.store";
import { knownNeuronsStore } from "$lib/stores/known-neurons.store";
import { networkEconomicsStore } from "$lib/stores/network-economics.store";
import { neuronsStore } from "$lib/stores/neurons.store";
import {
proposalPayloadsStore,
Expand Down Expand Up @@ -123,6 +124,7 @@ export const initDebugStore = () =>
defaultIcrcCanistersStore,
importedTokensStore,
failedImportedTokenLedgerIdsStore,
networkEconomicsStore,
],
([
$busyStore,
Expand Down Expand Up @@ -153,6 +155,7 @@ export const initDebugStore = () =>
$defaultIcrcCanistersStore,
$importedTokensStore,
$failedImportedTokenLedgerIdsStore,
$networkEconomicsParametersStore,
]) => ({
busy: $busyStore,
accounts: $accountsStore,
Expand Down Expand Up @@ -182,5 +185,6 @@ export const initDebugStore = () =>
defaultIcrcCanistersStore: $defaultIcrcCanistersStore,
importedTokensStore: $importedTokensStore,
failedImportedTokenLedgerIdsStore: $failedImportedTokenLedgerIdsStore,
networkEconomicsParametersStore: $networkEconomicsParametersStore,
})
);
23 changes: 23 additions & 0 deletions frontend/src/lib/services/network-economics.services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { governanceApiService } from "$lib/api-services/governance.api-service";
import { getAuthenticatedIdentity } from "$lib/services/auth.services";
import { networkEconomicsStore } from "$lib/stores/network-economics.store";

export const loadNetworkEconomicsParameters = async (): Promise<void> => {
try {
const identity = await getAuthenticatedIdentity();
const certified = true;
const parameters = await governanceApiService.getNetworkEconomicsParameters(
{
identity,
certified,
}
);

networkEconomicsStore.setParameters({
parameters,
certified,
});
} catch (error) {
console.error(error);
}
};
38 changes: 38 additions & 0 deletions frontend/src/lib/stores/network-economics.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { NetworkEconomics } from "@dfinity/nns";
import { writable, type Readable } from "svelte/store";

export interface NetworkEconomicsStoreData {
parameters: NetworkEconomics | undefined;
certified: boolean | undefined;
}

export interface NetworkEconomicsStore
extends Readable<NetworkEconomicsStoreData> {
setParameters: (data: NetworkEconomicsStoreData) => void;
}

/**
* A store that contains the [network economics parameters](https://github.com/dfinity/ic/blob/d90e934eb440c730d44d9d9b1ece2cc3f9505d05/rs/nns/governance/proto/ic_nns_governance/pb/v1/governance.proto#L1847).
*/
const initNetworkEconomicsParametersStore = () => {
const initialStoreData: NetworkEconomicsStoreData = {
parameters: undefined,
certified: undefined,
};
const { subscribe, set } =
writable<NetworkEconomicsStoreData>(initialStoreData);

return {
subscribe,

setParameters(parameters: NetworkEconomicsStoreData) {
set(parameters);
},

reset() {
set(initialStoreData);
},
};
};

export const networkEconomicsStore = initNetworkEconomicsParametersStore();
56 changes: 56 additions & 0 deletions frontend/src/tests/lib/services/network-economics.services.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as api from "$lib/api/governance.api";
import { loadNetworkEconomicsParameters } from "$lib/services/network-economics.services";
import { networkEconomicsStore } from "$lib/stores/network-economics.store";
import { mockIdentity, resetIdentity } from "$tests/mocks/auth.store.mock";
import { mockNetworkEconomics } from "$tests/mocks/network-economics.mock";
import { get } from "svelte/store";

describe("network-economics-services", () => {
let spyGetNetworkEconomicsParameters;

beforeEach(() => {
resetIdentity();
spyGetNetworkEconomicsParameters = vi
.spyOn(api, "getNetworkEconomicsParameters")
.mockResolvedValue(mockNetworkEconomics);
});

describe("loadNetworkEconomicsParameters", () => {
it("should load network economics", async () => {
await loadNetworkEconomicsParameters();

expect(spyGetNetworkEconomicsParameters).toHaveBeenCalledTimes(1);
expect(spyGetNetworkEconomicsParameters).toHaveBeenCalledWith({
identity: mockIdentity,
certified: true,
});
});

it("should update networkEconomicsStore store", async () => {
expect(get(networkEconomicsStore)).toEqual({
parameters: undefined,
certified: undefined,
});

await loadNetworkEconomicsParameters();

expect(get(networkEconomicsStore)).toEqual({
parameters: mockNetworkEconomics,
certified: true,
});
});

it("should console log on error", async () => {
vi.spyOn(console, "error").mockReturnValue();
const error = new Error("test error");
spyGetNetworkEconomicsParameters = vi
.spyOn(api, "getNetworkEconomicsParameters")
.mockRejectedValue(error);

await loadNetworkEconomicsParameters();

expect(console.error).toBeCalledWith(error);
expect(console.error).toBeCalledTimes(1);
});
});
});
22 changes: 22 additions & 0 deletions frontend/src/tests/lib/stores/network-economics.store.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { networkEconomicsStore } from "$lib/stores/network-economics.store";
import { mockNetworkEconomics } from "$tests/mocks/network-economics.mock";
import { get } from "svelte/store";

describe("network-economics-store", () => {
it("should set parameters", () => {
expect(get(networkEconomicsStore)).toEqual({
parameters: undefined,
certified: undefined,
});

networkEconomicsStore.setParameters({
parameters: mockNetworkEconomics,
certified: true,
});

expect(get(networkEconomicsStore)).toEqual({
parameters: mockNetworkEconomics,
certified: true,
});
});
});
42 changes: 42 additions & 0 deletions frontend/src/tests/mocks/network-economics.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {
SECONDS_IN_HALF_YEAR,
SECONDS_IN_MONTH,
} from "$lib/constants/constants";
import type { NetworkEconomics } from "@dfinity/nns";

export const mockNetworkEconomics: NetworkEconomics = {
neuronMinimumStake: 100_000_000n,
maxProposalsToKeepPerTopic: 1_000,
neuronManagementFeePerProposal: 10_000n,
rejectCost: 10_000_000n,
transactionFee: 1_000n,
neuronSpawnDissolveDelaySeconds: 3600n * 24n * 7n,
minimumIcpXdrRate: 1n,
maximumNodeProviderRewards: 10_000_000_000n,
neuronsFundEconomics: {
minimumIcpXdrRate: {
basisPoints: 123n,
},
maxTheoreticalNeuronsFundParticipationAmountXdr: {
humanReadable: "456",
},
neuronsFundMatchedFundingCurveCoefficients: {
contributionThresholdXdr: {
humanReadable: "789",
},
oneThirdParticipationMilestoneXdr: {
humanReadable: "123",
},
fullParticipationMilestoneXdr: {
humanReadable: "456",
},
},
maximumIcpXdrRate: {
basisPoints: 456n,
},
},
votingPowerEconomics: {
startReducingVotingPowerAfterSeconds: BigInt(SECONDS_IN_HALF_YEAR),
clearFollowingAfterSeconds: BigInt(SECONDS_IN_MONTH),
},
};

0 comments on commit 5fba586

Please sign in to comment.