From 545db816d69e3188305dee42f6e0714ac2312f31 Mon Sep 17 00:00:00 2001
From: mstrasinskis <98811342+mstrasinskis@users.noreply.github.com>
Date: Fri, 30 Jun 2023 21:24:13 +0200
Subject: [PATCH] 1 proposal support (#369)
# Motivation
Add `CreateServiceNervousSystem` <-> `RawCreateServiceNervousSystem`
transformations.
Required for [nns-dapp
pr](https://github.com/dfinity/nns-dapp/pull/2753).
# Changes
- add all related transform functions
# Tests
- Manually compared that after `RawCreateServiceNervousSystem to
CreateServiceNervousSystem` transformation all fields and values match.
# Screenshot
| Before | After |
|--------|--------|
|
![image](https://github.com/dfinity/ic-js/assets/98811342/86b2c867-82ab-4ae2-925e-1c331311dd97)
![image](https://github.com/dfinity/ic-js/assets/98811342/748b6f6d-fe0a-42fd-b27d-db02a0f5eb0b)
|
![image](https://github.com/dfinity/nns-dapp/assets/98811342/2dad9709-9a37-4408-99ce-de2c5b22d1ec)
---------
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
---
package.json | 2 +-
packages/ic-management/README.md | 81 ++++-
.../governance/request.converters.ts | 304 +++++++++++++++++-
.../governance/response.converters.ts | 282 +++++++++++++++-
.../nns/src/types/governance_converters.ts | 92 +++++-
5 files changed, 745 insertions(+), 16 deletions(-)
diff --git a/package.json b/package.json
index 2ee23980..bfdf66a0 100644
--- a/package.json
+++ b/package.json
@@ -96,7 +96,7 @@
{
"name": "@dfinity/nns",
"path": "./packages/nns/dist/index.js",
- "limit": "30 kB",
+ "limit": "32 kB",
"ignore": [
"@dfinity/agent",
"@dfinity/candid",
diff --git a/packages/ic-management/README.md b/packages/ic-management/README.md
index cb82d5ad..c1e6e047 100644
--- a/packages/ic-management/README.md
+++ b/packages/ic-management/README.md
@@ -57,8 +57,15 @@ const { status, memory_size, ...rest } = await canisterStatus(YOUR_CANISTER_ID);
#### Methods
- [create](#gear-create)
-- [canisterStatus](#gear-canisterstatus)
+- [createCanister](#gear-createcanister)
- [updateSettings](#gear-updatesettings)
+- [installCode](#gear-installcode)
+- [uninstallCode](#gear-uninstallcode)
+- [startCanister](#gear-startcanister)
+- [stopCanister](#gear-stopcanister)
+- [canisterStatus](#gear-canisterstatus)
+- [canisterInfo](#gear-canisterinfo)
+- [deleteCanister](#gear-deletecanister)
##### :gear: create
@@ -66,21 +73,77 @@ const { status, memory_size, ...rest } = await canisterStatus(YOUR_CANISTER_ID);
| -------- | ---------------------------------------------------------------- |
| `create` | `(options: ICManagementCanisterOptions) => ICManagementCanister` |
-##### :gear: canisterStatus
+##### :gear: createCanister
-Returns canister details (memory size, status, etc.)
+Create a new canister
-| Method | Type |
-| ---------------- | ------------------------------------------------------------ |
-| `canisterStatus` | `(canisterId: Principal) => Promise` |
+| Method | Type |
+| ---------------- | ------------------------------------------------------------------------------------ |
+| `createCanister` | `({ settings, senderCanisterVerion, }?: CreateCanisterParams) => Promise` |
##### :gear: updateSettings
Update canister settings
-| Method | Type |
-| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
-| `updateSettings` | `({ canisterId, settings: { controllers, freezingThreshold, memoryAllocation, computeAllocation, }, }: UpdateSettingsParams) => Promise` |
+| Method | Type |
+| ---------------- | ------------------------------------------------------------------------------------------ |
+| `updateSettings` | `({ canisterId, senderCanisterVerion, settings, }: UpdateSettingsParams) => Promise` |
+
+##### :gear: installCode
+
+Install code to a canister
+
+| Method | Type |
+| ------------- | ---------------------------------------------------------------------------------------------------- |
+| `installCode` | `({ mode, canisterId, wasmModule, arg, senderCanisterVerion, }: InstallCodeParams) => Promise` |
+
+##### :gear: uninstallCode
+
+Uninstall code from a canister
+
+| Method | Type |
+| --------------- | ------------------------------------------------------------------------------- |
+| `uninstallCode` | `({ canisterId, senderCanisterVerion, }: UninstallCodeParams) => Promise` |
+
+##### :gear: startCanister
+
+Start a canister
+
+| Method | Type |
+| --------------- | ------------------------------------------ |
+| `startCanister` | `(canisterId: Principal) => Promise` |
+
+##### :gear: stopCanister
+
+Stop a canister
+
+| Method | Type |
+| -------------- | ------------------------------------------ |
+| `stopCanister` | `(canisterId: Principal) => Promise` |
+
+##### :gear: canisterStatus
+
+Get canister details (memory size, status, etc.)
+
+| Method | Type |
+| ---------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
+| `canisterStatus` | `(canisterId: Principal) => Promise<{ status: { stopped: null; } or { stopping: null; } | { running: null; }; memory_size: bigint; cycles: bigint; settings: definite_canister_settings; idle_cycles_burned_per_day: bigint; module_hash: [] | [...]; }>` |
+
+##### :gear: canisterInfo
+
+Get canister info (controllers, module hash, changes, etc.)
+
+| Method | Type |
+| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `canisterInfo` | `({ canisterId, numRequestChanges, }: CanisterInfoParams) => Promise<{ controllers: Principal[]; module_hash: [] or [Uint8Array]; recent_changes: change[]; total_num_changes: bigint; }>` |
+
+##### :gear: deleteCanister
+
+Deletes a canister
+
+| Method | Type |
+| ---------------- | ------------------------------------------ |
+| `deleteCanister` | `(canisterId: Principal) => Promise` |
diff --git a/packages/nns/src/canisters/governance/request.converters.ts b/packages/nns/src/canisters/governance/request.converters.ts
index a93ff631..0e9fbcf1 100644
--- a/packages/nns/src/canisters/governance/request.converters.ts
+++ b/packages/nns/src/canisters/governance/request.converters.ts
@@ -7,15 +7,29 @@ import type {
By as RawBy,
Change as RawChange,
Command as RawCommand,
+ CreateServiceNervousSystem as RawCreateServiceNervousSystem,
+ DeveloperDistribution as RawDeveloperDistribution,
+ Duration as RawDuration,
Followees as RawFollowees,
+ GovernanceParameters as RawGovernanceParameters,
+ Image as RawImage,
+ InitialTokenDistribution as RawInitialTokenDistribution,
+ LedgerParameters as RawLedgerParameters,
ListNeurons as RawListNeurons,
ListProposalInfo,
ManageNeuron as RawManageNeuron,
+ NeuronBasketConstructionParameters as RawNeuronBasketConstructionParameters,
+ NeuronDistribution as RawNeuronDistribution,
NeuronId as RawNeuronId,
NeuronIdOrSubaccount as RawNeuronIdOrSubaccount,
NodeProvider as RawNodeProvider,
Operation as RawOperation,
+ Percentage as RawPercentage,
RewardMode as RawRewardMode,
+ SwapDistribution as RawSwapDistribution,
+ SwapParameters as RawSwapParameters,
+ Tokens as RawTokens,
+ VotingRewardParameters as RawVotingRewardParameters,
} from "../../../candid/governance";
import type { AccountIdentifier as AccountIdentifierClass } from "../../account_identifier";
import type { Vote } from "../../enums/governance.enums";
@@ -27,16 +41,30 @@ import type {
Change,
ClaimOrRefreshNeuronRequest,
Command,
+ CreateServiceNervousSystem,
+ DeveloperDistribution,
DisburseToNeuronRequest,
+ Duration,
FollowRequest,
+ GovernanceParameters,
+ Image,
+ InitialTokenDistribution,
+ LedgerParameters,
ListProposalsRequest,
MakeProposalRequest,
ManageNeuron,
+ NeuronBasketConstructionParameters,
+ NeuronDistribution,
NeuronIdOrSubaccount,
NodeProvider,
Operation,
+ Percentage,
ProposalId,
RewardMode,
+ SwapDistribution,
+ SwapParameters,
+ Tokens,
+ VotingRewardParameters,
} from "../../types/governance_converters";
import { accountIdentifierToBytes } from "../../utils/account_identifier.utils";
@@ -64,6 +92,275 @@ const fromNeuronIdOrSubaccount = (
throw new UnsupportedValueError(neuronIdOrSubaccount);
};
+const fromPercentage = (percentage: Percentage): RawPercentage =>
+ percentage.basisPoints !== undefined
+ ? { basis_points: [percentage.basisPoints] }
+ : { basis_points: [] };
+
+const fromDuration = (duration: Duration): RawDuration =>
+ duration.seconds !== undefined
+ ? { seconds: [duration.seconds] }
+ : { seconds: [] };
+
+const fromTokens = (tokens: Tokens): RawTokens =>
+ tokens.e8s !== undefined ? { e8s: [tokens.e8s] } : { e8s: [] };
+
+const fromImage = (image: Image): RawImage =>
+ image.base64Encoding !== undefined
+ ? { base64_encoding: [image.base64Encoding] }
+ : { base64_encoding: [] };
+
+const fromVotingRewardParameters = (
+ votingRewardParameters: VotingRewardParameters
+): RawVotingRewardParameters => ({
+ reward_rate_transition_duration:
+ votingRewardParameters.rewardRateTransitionDuration !== undefined
+ ? [fromDuration(votingRewardParameters.rewardRateTransitionDuration)]
+ : [],
+ initial_reward_rate:
+ votingRewardParameters.initialRewardRate !== undefined
+ ? [fromPercentage(votingRewardParameters.initialRewardRate)]
+ : [],
+ final_reward_rate:
+ votingRewardParameters.finalRewardRate !== undefined
+ ? [fromPercentage(votingRewardParameters.finalRewardRate)]
+ : [],
+});
+
+const fromLedgerParameters = (
+ ledgerParameters: LedgerParameters
+): RawLedgerParameters => ({
+ transaction_fee:
+ ledgerParameters.transactionFee !== undefined
+ ? [fromTokens(ledgerParameters.transactionFee)]
+ : [],
+ token_symbol:
+ ledgerParameters.tokenSymbol !== undefined
+ ? [ledgerParameters.tokenSymbol]
+ : [],
+ token_logo:
+ ledgerParameters.tokenLogo !== undefined
+ ? [fromImage(ledgerParameters.tokenLogo)]
+ : [],
+ token_name:
+ ledgerParameters.tokenName !== undefined
+ ? [ledgerParameters.tokenName]
+ : [],
+});
+
+const fromSwapParameters = (
+ swapParameters: SwapParameters
+): RawSwapParameters => ({
+ minimum_participants:
+ swapParameters.minimumParticipants !== undefined
+ ? [swapParameters.minimumParticipants]
+ : [],
+ neuron_basket_construction_parameters:
+ swapParameters.neuronBasketConstructionParameters !== undefined
+ ? [
+ fromNeuronBasketConstructionParameters(
+ swapParameters.neuronBasketConstructionParameters
+ ),
+ ]
+ : [],
+ maximum_participant_icp:
+ swapParameters.maximumParticipantIcp !== undefined
+ ? [fromTokens(swapParameters.maximumParticipantIcp)]
+ : [],
+ minimum_icp:
+ swapParameters.minimumIcp !== undefined
+ ? [fromTokens(swapParameters.minimumIcp)]
+ : [],
+ minimum_participant_icp:
+ swapParameters.minimumParticipantIcp !== undefined
+ ? [fromTokens(swapParameters.minimumParticipantIcp)]
+ : [],
+ maximum_icp:
+ swapParameters.maximumIcp !== undefined
+ ? [fromTokens(swapParameters.maximumIcp)]
+ : [],
+});
+
+const fromNeuronBasketConstructionParameters = (
+ neuronBasketConstructionParameters: NeuronBasketConstructionParameters
+): RawNeuronBasketConstructionParameters => ({
+ dissolve_delay_interval:
+ neuronBasketConstructionParameters.dissolveDelayInterval !== undefined
+ ? [fromDuration(neuronBasketConstructionParameters.dissolveDelayInterval)]
+ : [],
+ count:
+ neuronBasketConstructionParameters.count !== undefined
+ ? [neuronBasketConstructionParameters.count]
+ : [],
+});
+
+const fromGovernanceParameters = (
+ governanceParameters: GovernanceParameters
+): RawGovernanceParameters => ({
+ neuron_maximum_dissolve_delay_bonus:
+ governanceParameters.neuronMaximumDissolveDelayBonus !== undefined
+ ? [fromPercentage(governanceParameters.neuronMaximumDissolveDelayBonus)]
+ : [],
+ neuron_maximum_age_for_age_bonus:
+ governanceParameters.neuronMaximumAgeForAgeBonus !== undefined
+ ? [fromDuration(governanceParameters.neuronMaximumAgeForAgeBonus)]
+ : [],
+ neuron_maximum_dissolve_delay:
+ governanceParameters.neuronMaximumDissolveDelay !== undefined
+ ? [fromDuration(governanceParameters.neuronMaximumDissolveDelay)]
+ : [],
+ neuron_minimum_dissolve_delay_to_vote:
+ governanceParameters.neuronMinimumDissolveDelayToVote !== undefined
+ ? [fromDuration(governanceParameters.neuronMinimumDissolveDelayToVote)]
+ : [],
+ neuron_maximum_age_bonus:
+ governanceParameters.neuronMaximumAgeBonus !== undefined
+ ? [fromPercentage(governanceParameters.neuronMaximumAgeBonus)]
+ : [],
+ neuron_minimum_stake:
+ governanceParameters.neuronMinimumStake !== undefined
+ ? [fromTokens(governanceParameters.neuronMinimumStake)]
+ : [],
+ proposal_wait_for_quiet_deadline_increase:
+ governanceParameters.proposalWaitForQuietDeadlineIncrease !== undefined
+ ? [
+ fromDuration(
+ governanceParameters.proposalWaitForQuietDeadlineIncrease
+ ),
+ ]
+ : [],
+ proposal_initial_voting_period:
+ governanceParameters.proposalInitialVotingPeriod !== undefined
+ ? [fromDuration(governanceParameters.proposalInitialVotingPeriod)]
+ : [],
+ proposal_rejection_fee:
+ governanceParameters.proposalRejectionFee !== undefined
+ ? [fromTokens(governanceParameters.proposalRejectionFee)]
+ : [],
+ voting_reward_parameters:
+ governanceParameters.votingRewardParameters !== undefined
+ ? [
+ fromVotingRewardParameters(
+ governanceParameters.votingRewardParameters
+ ),
+ ]
+ : [],
+});
+
+const fromSwapDistribution = (
+ swapDistribution: SwapDistribution
+): RawSwapDistribution => ({
+ total:
+ swapDistribution.total !== undefined
+ ? [fromTokens(swapDistribution.total)]
+ : [],
+});
+
+const fromInitialTokenDistribution = (
+ initialTokenDistribution: InitialTokenDistribution
+): RawInitialTokenDistribution => ({
+ treasury_distribution:
+ initialTokenDistribution.treasuryDistribution !== undefined
+ ? [fromSwapDistribution(initialTokenDistribution.treasuryDistribution)]
+ : [],
+ developer_distribution:
+ initialTokenDistribution.developerDistribution !== undefined
+ ? [
+ fromDeveloperDistribution(
+ initialTokenDistribution.developerDistribution
+ ),
+ ]
+ : [],
+ swap_distribution:
+ initialTokenDistribution.swapDistribution !== undefined
+ ? [fromSwapDistribution(initialTokenDistribution.swapDistribution)]
+ : [],
+});
+
+const fromNeuronDistribution = (
+ neuronDistribution: NeuronDistribution
+): RawNeuronDistribution => ({
+ controller:
+ neuronDistribution.controller !== undefined
+ ? [Principal.fromText(neuronDistribution.controller)]
+ : [],
+ dissolve_delay:
+ neuronDistribution.dissolveDelay !== undefined
+ ? [fromDuration(neuronDistribution.dissolveDelay)]
+ : [],
+ memo: neuronDistribution.memo !== undefined ? [neuronDistribution.memo] : [],
+ vesting_period:
+ neuronDistribution.vestingPeriod !== undefined
+ ? [fromDuration(neuronDistribution.vestingPeriod)]
+ : [],
+ stake:
+ neuronDistribution.stake !== undefined
+ ? [fromTokens(neuronDistribution.stake)]
+ : [],
+});
+
+const fromDeveloperDistribution = (
+ developerDistribution: DeveloperDistribution
+): RawDeveloperDistribution => ({
+ developer_neurons: developerDistribution.developerNeurons.map(
+ fromNeuronDistribution
+ ),
+});
+
+const fromCreateServiceNervousSystem = (
+ createServiceNervousSystem: CreateServiceNervousSystem
+): RawCreateServiceNervousSystem => ({
+ url:
+ createServiceNervousSystem.url !== undefined
+ ? [createServiceNervousSystem.url]
+ : [],
+ governance_parameters:
+ createServiceNervousSystem.governanceParameters !== undefined
+ ? [
+ fromGovernanceParameters(
+ createServiceNervousSystem.governanceParameters
+ ),
+ ]
+ : [],
+ fallback_controller_principal_ids:
+ createServiceNervousSystem.fallbackControllerPrincipalIds.map(
+ Principal.fromText
+ ),
+ logo:
+ createServiceNervousSystem.logo !== undefined
+ ? [fromImage(createServiceNervousSystem.logo)]
+ : [],
+ name:
+ createServiceNervousSystem.name !== undefined
+ ? [createServiceNervousSystem.name]
+ : [],
+ ledger_parameters:
+ createServiceNervousSystem.ledgerParameters !== undefined
+ ? [fromLedgerParameters(createServiceNervousSystem.ledgerParameters)]
+ : [],
+ description:
+ createServiceNervousSystem.description !== undefined
+ ? [createServiceNervousSystem.description]
+ : [],
+ dapp_canisters: createServiceNervousSystem.dappCanisters.map(
+ (principalId) => ({
+ id: [Principal.fromText(principalId)],
+ })
+ ),
+ swap_parameters:
+ createServiceNervousSystem.swapParameters !== undefined
+ ? [fromSwapParameters(createServiceNervousSystem.swapParameters)]
+ : [],
+ initial_token_distribution:
+ createServiceNervousSystem.initialTokenDistribution !== undefined
+ ? [
+ fromInitialTokenDistribution(
+ createServiceNervousSystem.initialTokenDistribution
+ ),
+ ]
+ : [],
+});
+
const fromAction = (action: Action): RawAction => {
if ("ExecuteNnsFunction" in action) {
const executeNnsFunction = action.ExecuteNnsFunction;
@@ -258,8 +555,11 @@ const fromAction = (action: Action): RawAction => {
}
if ("CreateServiceNervousSystem" in action) {
- // TODO: Convert from CreateServiceNervousSystem to RawCreateServiceNervousSystem
- return action;
+ return {
+ CreateServiceNervousSystem: fromCreateServiceNervousSystem(
+ action.CreateServiceNervousSystem
+ ),
+ };
}
// If there's a missing action, this line will cause a compiler error.
diff --git a/packages/nns/src/canisters/governance/response.converters.ts b/packages/nns/src/canisters/governance/response.converters.ts
index e65149b2..f7ae6f1a 100644
--- a/packages/nns/src/canisters/governance/response.converters.ts
+++ b/packages/nns/src/canisters/governance/response.converters.ts
@@ -7,6 +7,7 @@ import type {
} from "@dfinity/nns-proto";
import { Principal } from "@dfinity/principal";
import { fromNullable, uint8ArrayToArrayOfNumber } from "@dfinity/utils";
+import { fromDefinedNullable } from "@dfinity/utils/src";
import type { Map } from "google-protobuf";
import type {
AccountIdentifier as RawAccountIdentifier,
@@ -15,30 +16,45 @@ import type {
Ballot as RawBallot,
BallotInfo as RawBallotInfo,
By as RawBy,
+ Canister as RawCanister,
Change as RawChange,
Command as RawCommand,
+ DeveloperDistribution as RawDeveloperDistribution,
DissolveState as RawDissolveState,
+ Duration as RawDuration,
Followees as RawFollowees,
+ GovernanceParameters as RawGovernanceParameters,
+ Image as RawImage,
+ InitialTokenDistribution as RawInitialTokenDistribution,
KnownNeuron as RawKnownNeuron,
+ LedgerParameters as RawLedgerParameters,
ListNeuronsResponse as RawListNeuronsResponse,
ListProposalInfoResponse as RawListProposalInfoResponse,
Neuron as RawNeuron,
+ NeuronBasketConstructionParameters as RawNeuronBasketConstructionParameters,
+ NeuronDistribution as RawNeuronDistribution,
NeuronId as RawNeuronId,
NeuronIdOrSubaccount as RawNeuronIdOrSubaccount,
NeuronInfo as RawNeuronInfo,
NodeProvider as RawNodeProvider,
Operation as RawOperation,
Params,
+ Percentage as RawPercentage,
Proposal as RawProposal,
ProposalInfo as RawProposalInfo,
RewardMode as RawRewardMode,
+ SwapDistribution as RawSwapDistribution,
+ SwapParameters as RawSwapParameters,
Tally as RawTally,
+ Tokens as RawTokens,
+ VotingRewardParameters as RawVotingRewardParameters,
} from "../../../candid/governance";
import { AccountIdentifier, SubAccount } from "../../account_identifier";
import { NeuronState } from "../../enums/governance.enums";
import { UnsupportedValueError } from "../../errors/governance.errors";
import type {
AccountIdentifier as AccountIdentifierString,
+ CanisterIdString,
E8s,
NeuronId,
} from "../../types/common";
@@ -49,19 +65,32 @@ import type {
By,
Change,
Command,
+ DeveloperDistribution,
DissolveState,
+ Duration,
Followees,
+ GovernanceParameters,
+ Image,
+ InitialTokenDistribution,
KnownNeuron,
+ LedgerParameters,
ListProposalsResponse,
Neuron,
+ NeuronBasketConstructionParameters,
+ NeuronDistribution,
NeuronIdOrSubaccount,
NeuronInfo,
NodeProvider,
Operation,
+ Percentage,
Proposal,
ProposalInfo,
RewardMode,
+ SwapDistribution,
+ SwapParameters,
Tally,
+ Tokens,
+ VotingRewardParameters,
} from "../../types/governance_converters";
import {
accountIdentifierFromBytes,
@@ -393,8 +422,35 @@ const toAction = (action: RawAction): Action => {
}
if ("CreateServiceNervousSystem" in action) {
- // TODO: Convert from RawCreateServiceNervousSystem to CreateServiceNervousSystem (no arrays as optionals)
- return action;
+ const createServiceNervousSystem = action.CreateServiceNervousSystem;
+ return {
+ CreateServiceNervousSystem: {
+ url: fromNullable(createServiceNervousSystem.url),
+ governanceParameters: toGovernanceParameters(
+ fromNullable(createServiceNervousSystem.governance_parameters)
+ ),
+ fallbackControllerPrincipalIds:
+ createServiceNervousSystem.fallback_controller_principal_ids.map(
+ (principalId) => principalId.toString()
+ ),
+ logo: toImage(fromNullable(createServiceNervousSystem.logo)),
+ name: fromNullable(createServiceNervousSystem.name),
+ ledgerParameters: toLedgerParameters(
+ fromNullable(createServiceNervousSystem.ledger_parameters)
+ ),
+ description: fromNullable(createServiceNervousSystem.description),
+ dappCanisters:
+ (createServiceNervousSystem.dapp_canisters.map(
+ toCanisterIdString
+ ) as CanisterIdString[]) ?? [],
+ swapParameters: toSwapParameters(
+ fromNullable(createServiceNervousSystem.swap_parameters)
+ ),
+ initialTokenDistribution: toInitialTokenDistribution(
+ fromNullable(createServiceNervousSystem.initial_token_distribution)
+ ),
+ },
+ };
}
throw new UnsupportedValueError(action);
@@ -914,3 +970,225 @@ export const convertPbNeuronToNeuronInfo =
: convertPbNeuronToFullNeuron({ pbNeuron, pbNeuronInfo, canisterId }),
};
};
+
+const toPercentage = (
+ percentage: RawPercentage | undefined
+): Percentage | undefined => {
+ return percentage === undefined
+ ? undefined
+ : {
+ basisPoints: fromNullable(percentage.basis_points),
+ };
+};
+
+const toDuration = (
+ duration: RawDuration | undefined
+): Duration | undefined => {
+ return duration === undefined
+ ? undefined
+ : {
+ seconds: fromNullable(duration.seconds),
+ };
+};
+
+const toTokens = (tokens: RawTokens | undefined): Tokens | undefined => {
+ return tokens === undefined
+ ? undefined
+ : {
+ e8s: fromNullable(tokens.e8s),
+ };
+};
+
+const toCanisterIdString = (
+ canister: RawCanister | undefined
+): CanisterIdString | undefined => {
+ return canister === undefined
+ ? undefined
+ : canister.id.length === 0
+ ? undefined
+ : fromDefinedNullable(canister.id).toString();
+};
+
+const toImage = (image: RawImage | undefined): Image | undefined => {
+ return image === undefined
+ ? undefined
+ : {
+ base64Encoding: fromNullable(image.base64_encoding),
+ };
+};
+
+const toLedgerParameters = (
+ ledgerParameters: RawLedgerParameters | undefined
+): LedgerParameters | undefined => {
+ return ledgerParameters === undefined
+ ? undefined
+ : {
+ transactionFee: toTokens(
+ fromNullable(ledgerParameters.transaction_fee)
+ ),
+ tokenSymbol: fromNullable(ledgerParameters.token_symbol),
+ tokenLogo: toImage(fromNullable(ledgerParameters.token_logo)),
+ tokenName: fromNullable(ledgerParameters.token_name),
+ };
+};
+
+const toVotingRewardParameters = (
+ votingRewardParameters: RawVotingRewardParameters | undefined
+): VotingRewardParameters | undefined => {
+ return votingRewardParameters === undefined
+ ? undefined
+ : {
+ rewardRateTransitionDuration: toDuration(
+ fromNullable(votingRewardParameters.reward_rate_transition_duration)
+ ),
+ initialRewardRate: toPercentage(
+ fromNullable(votingRewardParameters.initial_reward_rate)
+ ),
+ finalRewardRate: toPercentage(
+ fromNullable(votingRewardParameters.final_reward_rate)
+ ),
+ };
+};
+
+const toGovernanceParameters = (
+ governanceParameters: RawGovernanceParameters | undefined
+): GovernanceParameters | undefined => {
+ return governanceParameters === undefined
+ ? undefined
+ : {
+ neuronMaximumDissolveDelayBonus: toPercentage(
+ fromNullable(governanceParameters.neuron_maximum_dissolve_delay_bonus)
+ ),
+ neuronMaximumAgeForAgeBonus: toDuration(
+ fromNullable(governanceParameters.neuron_maximum_age_for_age_bonus)
+ ),
+ neuronMaximumDissolveDelay: toDuration(
+ fromNullable(governanceParameters.neuron_maximum_dissolve_delay)
+ ),
+ neuronMinimumDissolveDelayToVote: toDuration(
+ fromNullable(
+ governanceParameters.neuron_minimum_dissolve_delay_to_vote
+ )
+ ),
+ neuronMaximumAgeBonus: toPercentage(
+ fromNullable(governanceParameters.neuron_maximum_age_bonus)
+ ),
+ neuronMinimumStake: toTokens(
+ fromNullable(governanceParameters.neuron_minimum_stake)
+ ),
+ proposalWaitForQuietDeadlineIncrease: toDuration(
+ fromNullable(
+ governanceParameters.proposal_wait_for_quiet_deadline_increase
+ )
+ ),
+ proposalInitialVotingPeriod: toDuration(
+ fromNullable(governanceParameters.proposal_initial_voting_period)
+ ),
+ proposalRejectionFee: toTokens(
+ fromNullable(governanceParameters.proposal_rejection_fee)
+ ),
+ votingRewardParameters: toVotingRewardParameters(
+ fromNullable(governanceParameters.voting_reward_parameters)
+ ),
+ };
+};
+
+const toNeuronBasketConstructionParameters = (
+ neuronBasketConstructionParameters:
+ | RawNeuronBasketConstructionParameters
+ | undefined
+): NeuronBasketConstructionParameters | undefined => {
+ return neuronBasketConstructionParameters === undefined
+ ? undefined
+ : {
+ dissolveDelayInterval: toDuration(
+ fromNullable(
+ neuronBasketConstructionParameters.dissolve_delay_interval
+ )
+ ),
+ count: fromNullable(neuronBasketConstructionParameters.count),
+ };
+};
+
+const toSwapParameters = (
+ swapParameters: RawSwapParameters | undefined
+): SwapParameters | undefined => {
+ return swapParameters === undefined
+ ? undefined
+ : {
+ minimumParticipants: fromNullable(swapParameters.minimum_participants),
+ neuronBasketConstructionParameters:
+ toNeuronBasketConstructionParameters(
+ fromNullable(swapParameters.neuron_basket_construction_parameters)
+ ),
+ maximumParticipantIcp: toTokens(
+ fromNullable(swapParameters.maximum_participant_icp)
+ ),
+ minimumIcp: toTokens(fromNullable(swapParameters.minimum_icp)),
+ minimumParticipantIcp: toTokens(
+ fromNullable(swapParameters.minimum_participant_icp)
+ ),
+ maximumIcp: toTokens(fromNullable(swapParameters.maximum_icp)),
+ };
+};
+
+const toSwapDistribution = (
+ swapDistribution: RawSwapDistribution | undefined
+): SwapDistribution | undefined => {
+ return swapDistribution === undefined
+ ? undefined
+ : {
+ total: toTokens(fromNullable(swapDistribution.total)),
+ };
+};
+
+const toNeuronDistribution = (
+ neuronDistribution: RawNeuronDistribution | undefined
+): NeuronDistribution | undefined => {
+ return neuronDistribution === undefined
+ ? undefined
+ : {
+ controller:
+ neuronDistribution.controller.length === 0
+ ? undefined
+ : neuronDistribution.controller[0].toString(),
+ dissolveDelay: toDuration(
+ fromNullable(neuronDistribution.dissolve_delay)
+ ),
+ memo: fromNullable(neuronDistribution.memo),
+ vestingPeriod: toDuration(
+ fromNullable(neuronDistribution.vesting_period)
+ ),
+ stake: toTokens(fromNullable(neuronDistribution.stake)),
+ };
+};
+
+const toDeveloperDistribution = (
+ developerDistribution: RawDeveloperDistribution | undefined
+): DeveloperDistribution | undefined => {
+ return developerDistribution === undefined
+ ? undefined
+ : {
+ developerNeurons: developerDistribution.developer_neurons.map(
+ toNeuronDistribution
+ ) as Array,
+ };
+};
+
+const toInitialTokenDistribution = (
+ initialTokenDistribution: RawInitialTokenDistribution | undefined
+): InitialTokenDistribution | undefined => {
+ return initialTokenDistribution === undefined
+ ? undefined
+ : {
+ treasuryDistribution: toSwapDistribution(
+ fromNullable(initialTokenDistribution.treasury_distribution)
+ ),
+ developerDistribution: toDeveloperDistribution(
+ fromNullable(initialTokenDistribution.developer_distribution)
+ ),
+ swapDistribution: toSwapDistribution(
+ fromNullable(initialTokenDistribution.swap_distribution)
+ ),
+ };
+};
diff --git a/packages/nns/src/types/governance_converters.ts b/packages/nns/src/types/governance_converters.ts
index 19f41d38..8c9b67db 100644
--- a/packages/nns/src/types/governance_converters.ts
+++ b/packages/nns/src/types/governance_converters.ts
@@ -1,6 +1,5 @@
import type { DerEncodedPublicKey } from "@dfinity/agent";
import type { Principal } from "@dfinity/principal";
-import type { CreateServiceNervousSystem } from "../../candid/governance";
import type {
NeuronState,
ProposalRewardStatus,
@@ -22,7 +21,6 @@ export type Action =
| {
ExecuteNnsFunction: ExecuteNnsFunction;
}
- // TODO: Create new CreateServiceNervousSystem type (don't use array for optional fields)
| { CreateServiceNervousSystem: CreateServiceNervousSystem }
| { ManageNeuron: ManageNeuron }
| { ApproveGenesisKyc: ApproveGenesisKyc }
@@ -490,3 +488,93 @@ export interface MakeExecuteNnsFunctionProposalRequest {
export interface ListNodeProvidersResponse {
nodeProviders: NodeProvider[];
}
+
+export interface Percentage {
+ basisPoints?: bigint;
+}
+
+export interface Duration {
+ seconds?: bigint;
+}
+
+export interface Tokens {
+ e8s?: bigint;
+}
+
+export interface Image {
+ base64Encoding?: string;
+}
+
+export interface LedgerParameters {
+ transactionFee?: Tokens;
+ tokenSymbol?: string;
+ tokenLogo?: Image;
+ tokenName?: string;
+}
+
+export interface VotingRewardParameters {
+ rewardRateTransitionDuration?: Duration;
+ initialRewardRate?: Percentage;
+ finalRewardRate?: Percentage;
+}
+
+export interface GovernanceParameters {
+ neuronMaximumDissolveDelayBonus?: Percentage;
+ neuronMaximumAgeForAgeBonus?: Duration;
+ neuronMaximumDissolveDelay?: Duration;
+ neuronMinimumDissolveDelayToVote?: Duration;
+ neuronMaximumAgeBonus?: Percentage;
+ neuronMinimumStake?: Tokens;
+ proposalWaitForQuietDeadlineIncrease?: Duration;
+ proposalInitialVotingPeriod?: Duration;
+ proposalRejectionFee?: Tokens;
+ votingRewardParameters?: VotingRewardParameters;
+}
+
+export interface NeuronBasketConstructionParameters {
+ dissolveDelayInterval?: Duration;
+ count?: bigint;
+}
+export interface SwapParameters {
+ minimumParticipants?: bigint;
+ neuronBasketConstructionParameters?: NeuronBasketConstructionParameters;
+ maximumParticipantIcp?: Tokens;
+ minimumIcp?: Tokens;
+ minimumParticipantIcp?: Tokens;
+ maximumIcp?: Tokens;
+}
+
+export interface SwapDistribution {
+ total?: Tokens;
+}
+
+export interface NeuronDistribution {
+ controller?: PrincipalString;
+ dissolveDelay?: Duration;
+ memo?: bigint;
+ vestingPeriod?: Duration;
+ stake?: Tokens;
+}
+
+export interface DeveloperDistribution {
+ developerNeurons: Array;
+}
+
+export interface InitialTokenDistribution {
+ treasuryDistribution?: SwapDistribution;
+ developerDistribution?: DeveloperDistribution;
+ swapDistribution?: SwapDistribution;
+}
+
+export interface CreateServiceNervousSystem {
+ url?: string;
+ governanceParameters?: GovernanceParameters;
+ fallbackControllerPrincipalIds: Array;
+ logo?: Image;
+ name?: string;
+ ledgerParameters?: LedgerParameters;
+ description?: string;
+ dappCanisters: Array;
+ swapParameters?: SwapParameters;
+ initialTokenDistribution?: InitialTokenDistribution;
+}