Skip to content

Commit

Permalink
feat: sns wrapper for nns-dapp (#137)
Browse files Browse the repository at this point in the history
# Motivation

For nns-dapp - and for any devs - we want to provide an easy way that loads all the canisters' actors of a particular sns and provide all features.

# Changes

- new `SnsWrapper` that contains all actors and wrap all features for a particular sns
- `initSns` that query a particular root canister about other canister id and load all actor and provide the `SnsWrapper`
- init `GovernanceCanister` and provide `listNeurons`
- build bundle improved by chunking all code and making code also available in `index`
  • Loading branch information
peterpeterparker authored Jul 12, 2022
1 parent b568756 commit 02c2b6f
Show file tree
Hide file tree
Showing 37 changed files with 590 additions and 82 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
# 0.x.y (2022-aa-bb)

- Fix how the neuron account was converted to a string for Proto.
- Use the governance canister id of the class in converters. This allows to also have proper conversion on testnets.
### Breaking Changes

- `nns` library `esm` canisters chunks renamed with suffix `.canister`

### Features

- new library `@dfinity/sns`
- use the governance canister id of the class in converters. This allows to also have proper conversion on testnets.

### Fix

- fix how the neuron account was converted to a `string` for `proto`.

### Build

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The libraries are still in active development, and new features will incremental
## Libraries

- [nns](/packages/nns): interfacing with the **ledger** and **governance** canisters of the IC
- [sns](/packages/sns): interacting with a sns project (_coming soon_)
- [sns](/packages/sns): interacting with a Service Nervous System (SNS) project
- cmc: querying the Cmc canister (_coming soon_)

## Links
Expand Down
2 changes: 1 addition & 1 deletion packages/nns/candid/genesis_token.did
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated from IC repo commit 987e1c810a9f6770fd1b2f1ae4a895d751d5ef41 'rs/nns/gtc/canister/gtc.did' by import-candid
// Generated from IC repo commit a1080f27696c890c19d7068f668bd062f3787564 'rs/nns/gtc/canister/gtc.did' by import-candid
type AccountState = record {
authenticated_principal_id : opt principal;
successfully_transferred_neurons : vec TransferredNeuron;
Expand Down
2 changes: 1 addition & 1 deletion packages/nns/candid/governance.did
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated from IC repo commit 987e1c810a9f6770fd1b2f1ae4a895d751d5ef41 'rs/nns/governance/canister/governance.did' by import-candid
// Generated from IC repo commit a1080f27696c890c19d7068f668bd062f3787564 'rs/nns/governance/canister/governance.did' by import-candid
type AccountIdentifier = record { hash : vec nat8 };
type Action = variant {
RegisterKnownNeuron : KnownNeuron;
Expand Down
2 changes: 1 addition & 1 deletion packages/nns/candid/ledger.did
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated from IC repo commit 987e1c810a9f6770fd1b2f1ae4a895d751d5ef41 'rs/rosetta-api/ledger_canister/ledger.did' by import-candid
// Generated from IC repo commit a1080f27696c890c19d7068f668bd062f3787564 'rs/rosetta-api/ledger_canister/ledger.did' by import-candid
// This is the official Ledger interface that is guaranteed to be backward compatible.

// Amount of tokens, measured in 10^-8 of a token.
Expand Down
27 changes: 21 additions & 6 deletions packages/nns/candid/sns_wasm.certified.idl.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,29 @@ export const idlFactory = ({ IDL }) => {
const AddWasmError = IDL.Record({ 'error' : IDL.Text });
const Result = IDL.Variant({ 'Ok' : AddWasmOk, 'Error' : AddWasmError });
const AddWasmResponse = IDL.Record({ 'result' : IDL.Opt(Result) });
const TokenDistribution = IDL.Record({
'distributions' : IDL.Vec(IDL.Tuple(IDL.Text, IDL.Nat64)),
const TreasuryDistribution = IDL.Record({ 'total_e8s' : IDL.Nat64 });
const NeuronDistribution = IDL.Record({
'controller' : IDL.Opt(IDL.Principal),
'stake_e8s' : IDL.Nat64,
});
const DeveloperDistribution = IDL.Record({
'developer_neurons' : IDL.Vec(NeuronDistribution),
});
const AirdropDistribution = IDL.Record({
'airdrop_neurons' : IDL.Vec(NeuronDistribution),
});
const SwapDistribution = IDL.Record({
'total_e8s' : IDL.Nat64,
'initial_swap_amount_e8s' : IDL.Nat64,
});
const FractionalDeveloperVotingPower = IDL.Record({
'treasury_distribution' : IDL.Opt(TreasuryDistribution),
'developer_distribution' : IDL.Opt(DeveloperDistribution),
'airdrop_distribution' : IDL.Opt(AirdropDistribution),
'swap_distribution' : IDL.Opt(SwapDistribution),
});
const InitialTokenDistribution = IDL.Record({
'swap' : IDL.Nat64,
'developers' : IDL.Opt(TokenDistribution),
'treasury' : IDL.Opt(TokenDistribution),
const InitialTokenDistribution = IDL.Variant({
'FractionalDeveloperVotingPower' : FractionalDeveloperVotingPower,
});
const SnsInitPayload = IDL.Record({
'min_participant_icp_e8s' : IDL.Opt(IDL.Nat64),
Expand Down
31 changes: 24 additions & 7 deletions packages/nns/candid/sns_wasm.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export interface AddWasmRequest {
export interface AddWasmResponse {
result: [] | [Result];
}
export interface AirdropDistribution {
airdrop_neurons: Array<NeuronDistribution>;
}
export interface DeployNewSnsRequest {
sns_init_payload: [] | [SnsInitPayload];
}
Expand All @@ -22,6 +25,15 @@ export interface DeployNewSnsResponse {
export interface DeployedSns {
root_canister_id: [] | [Principal];
}
export interface DeveloperDistribution {
developer_neurons: Array<NeuronDistribution>;
}
export interface FractionalDeveloperVotingPower {
treasury_distribution: [] | [TreasuryDistribution];
developer_distribution: [] | [DeveloperDistribution];
airdrop_distribution: [] | [AirdropDistribution];
swap_distribution: [] | [SwapDistribution];
}
export interface GetNextSnsVersionRequest {
current_version: [] | [SnsVersion];
}
Expand All @@ -34,14 +46,16 @@ export interface GetWasmRequest {
export interface GetWasmResponse {
wasm: [] | [SnsWasm];
}
export interface InitialTokenDistribution {
swap: bigint;
developers: [] | [TokenDistribution];
treasury: [] | [TokenDistribution];
}
export type InitialTokenDistribution = {
FractionalDeveloperVotingPower: FractionalDeveloperVotingPower;
};
export interface ListDeployedSnsesResponse {
instances: Array<DeployedSns>;
}
export interface NeuronDistribution {
controller: [] | [Principal];
stake_e8s: bigint;
}
export type Result = { Ok: AddWasmOk } | { Error: AddWasmError };
export interface SnsCanisterIds {
root: [] | [Principal];
Expand Down Expand Up @@ -75,8 +89,11 @@ export interface SnsWasm {
export interface SnsWasmCanisterInitPayload {
sns_subnet_ids: Array<Principal>;
}
export interface TokenDistribution {
distributions: Array<[string, bigint]>;
export interface SwapDistribution {
total_e8s: bigint;
initial_swap_amount_e8s: bigint;
}
export interface TreasuryDistribution {
total_e8s: bigint;
}
export interface _SERVICE {
Expand Down
27 changes: 20 additions & 7 deletions packages/nns/candid/sns_wasm.did
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
// Generated from IC repo commit 987e1c810a9f6770fd1b2f1ae4a895d751d5ef41 'rs/nns/sns-wasm/canister/sns-wasm.did' by import-candid
// Generated from IC repo commit a1080f27696c890c19d7068f668bd062f3787564 'rs/nns/sns-wasm/canister/sns-wasm.did' by import-candid
type AddWasmError = record { error : text };
type AddWasmOk = record { hash : vec nat8 };
type AddWasmRequest = record { hash : vec nat8; wasm : opt SnsWasm };
type AddWasmResponse = record { result : opt Result };
type AirdropDistribution = record { airdrop_neurons : vec NeuronDistribution };
type DeployNewSnsRequest = record { sns_init_payload : opt SnsInitPayload };
type DeployNewSnsResponse = record {
subnet_id : opt principal;
canisters : opt SnsCanisterIds;
};
type DeployedSns = record { root_canister_id : opt principal };
type DeveloperDistribution = record {
developer_neurons : vec NeuronDistribution;
};
type FractionalDeveloperVotingPower = record {
treasury_distribution : opt TreasuryDistribution;
developer_distribution : opt DeveloperDistribution;
airdrop_distribution : opt AirdropDistribution;
swap_distribution : opt SwapDistribution;
};
type GetNextSnsVersionRequest = record { current_version : opt SnsVersion };
type GetNextSnsVersionResponse = record { next_version : opt SnsVersion };
type GetWasmRequest = record { hash : vec nat8 };
type GetWasmResponse = record { wasm : opt SnsWasm };
type InitialTokenDistribution = record {
swap : nat64;
developers : opt TokenDistribution;
treasury : opt TokenDistribution;
type InitialTokenDistribution = variant {
FractionalDeveloperVotingPower : FractionalDeveloperVotingPower;
};
type ListDeployedSnsesResponse = record { instances : vec DeployedSns };
type NeuronDistribution = record {
controller : opt principal;
stake_e8s : nat64;
};
type Result = variant { Ok : AddWasmOk; Error : AddWasmError };
type SnsCanisterIds = record {
root : opt principal;
Expand Down Expand Up @@ -47,10 +59,11 @@ type SnsVersion = record {
};
type SnsWasm = record { wasm : vec nat8; canister_type : int32 };
type SnsWasmCanisterInitPayload = record { sns_subnet_ids : vec principal };
type TokenDistribution = record {
distributions : vec record { text; nat64 };
type SwapDistribution = record {
total_e8s : nat64;
initial_swap_amount_e8s : nat64;
};
type TreasuryDistribution = record { total_e8s : nat64 };
service : (SnsWasmCanisterInitPayload) -> {
add_wasm : (AddWasmRequest) -> (AddWasmResponse);
deploy_new_sns : (DeployNewSnsRequest) -> (DeployNewSnsResponse);
Expand Down
27 changes: 21 additions & 6 deletions packages/nns/candid/sns_wasm.idl.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,29 @@ export const idlFactory = ({ IDL }) => {
const AddWasmError = IDL.Record({ 'error' : IDL.Text });
const Result = IDL.Variant({ 'Ok' : AddWasmOk, 'Error' : AddWasmError });
const AddWasmResponse = IDL.Record({ 'result' : IDL.Opt(Result) });
const TokenDistribution = IDL.Record({
'distributions' : IDL.Vec(IDL.Tuple(IDL.Text, IDL.Nat64)),
const TreasuryDistribution = IDL.Record({ 'total_e8s' : IDL.Nat64 });
const NeuronDistribution = IDL.Record({
'controller' : IDL.Opt(IDL.Principal),
'stake_e8s' : IDL.Nat64,
});
const DeveloperDistribution = IDL.Record({
'developer_neurons' : IDL.Vec(NeuronDistribution),
});
const AirdropDistribution = IDL.Record({
'airdrop_neurons' : IDL.Vec(NeuronDistribution),
});
const SwapDistribution = IDL.Record({
'total_e8s' : IDL.Nat64,
'initial_swap_amount_e8s' : IDL.Nat64,
});
const FractionalDeveloperVotingPower = IDL.Record({
'treasury_distribution' : IDL.Opt(TreasuryDistribution),
'developer_distribution' : IDL.Opt(DeveloperDistribution),
'airdrop_distribution' : IDL.Opt(AirdropDistribution),
'swap_distribution' : IDL.Opt(SwapDistribution),
});
const InitialTokenDistribution = IDL.Record({
'swap' : IDL.Nat64,
'developers' : IDL.Opt(TokenDistribution),
'treasury' : IDL.Opt(TokenDistribution),
const InitialTokenDistribution = IDL.Variant({
'FractionalDeveloperVotingPower' : FractionalDeveloperVotingPower,
});
const SnsInitPayload = IDL.Record({
'min_participant_icp_e8s' : IDL.Opt(IDL.Nat64),
Expand Down
2 changes: 1 addition & 1 deletion packages/nns/src/constants/canister_ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const MAINNET_GENESIS_TOKEN_CANISTER_ID = Principal.fromText(
"renrk-eyaaa-aaaaa-aaada-cai"
);

// TODO: Sns-wasm canister is not yet deployed on mainnet
// TODO(L2-828): Sns-wasm canister is not yet deployed on mainnet
export const MAINNET_SNS_WASM_CANISTER_ID = Principal.fromText(
"r7inp-6aaaa-aaaaa-aaabq-cai"
);
1 change: 1 addition & 0 deletions packages/nns/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export * from "./types/governance.options";
export * from "./types/governance_converters";
export * from "./types/icp";
export * from "./types/ledger.options";
export type { SnsWasmCanisterOptions } from "./types/sns_wasm.options";
export * from "./utils/accounts.utils";
export * from "./utils/account_identifier.utils";
export * from "./utils/neurons.utils";
6 changes: 3 additions & 3 deletions packages/nns/src/mocks/sns_wasm.mock.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Principal } from "@dfinity/principal";
import type { DeployedSns } from "../../candid/sns_wasm";

export const snsMock: DeployedSns[] = [
export const deployedSnsMock: DeployedSns[] = [
{
root_canister_id: [Principal.fromText("sp3hj-caaaa-aaaaa-aaajq-cai")],
root_canister_id: [Principal.fromText("pin7y-wyaaa-aaaaa-aacpa-cai")],
},
{
root_canister_id: [Principal.fromText("ryjl3-tyaaa-aaaaa-aaaba-cai")],
root_canister_id: [Principal.fromText("zdlco-vyaaa-aaaaa-aabva-cai")],
},
];
6 changes: 3 additions & 3 deletions packages/nns/src/sns_wasm.canister.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { ActorSubclass } from "@dfinity/agent";
import { mock } from "jest-mock-extended";
import type { _SERVICE as SnsWasmService } from "../candid/sns_wasm";
import { snsMock } from "./mocks/sns_wasm.mock";
import { deployedSnsMock } from "./mocks/sns_wasm.mock";
import { SnsWasmCanister } from "./sns_wasm.canister";

describe("Sns-wasm", () => {
it("should return the list of sns", async () => {
const service = mock<ActorSubclass<SnsWasmService>>();
service.list_deployed_snses.mockResolvedValue({
instances: snsMock,
instances: deployedSnsMock,
});

const canister = SnsWasmCanister.create({
certifiedServiceOverride: service,
});
const res = await canister.listSnses({});
expect(res).toEqual(snsMock);
expect(res).toEqual(deployedSnsMock);
});
});
4 changes: 4 additions & 0 deletions packages/nns/src/types/sns_wasm.options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { _SERVICE as SnsWasmService } from "../../candid/sns_wasm";
import type { CanisterOptions } from "./canister.options";

export type SnsWasmCanisterOptions = CanisterOptions<SnsWasmService>;
2 changes: 1 addition & 1 deletion packages/sns/candid/ledger.did
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated from IC repo commit 987e1c810a9f6770fd1b2f1ae4a895d751d5ef41 'rs/rosetta-api/ledger_canister/ledger.did' by import-candid
// Generated from IC repo commit a1080f27696c890c19d7068f668bd062f3787564 'rs/rosetta-api/ledger_canister/ledger.did' by import-candid
// This is the official Ledger interface that is guaranteed to be backward compatible.

// Amount of tokens, measured in 10^-8 of a token.
Expand Down
2 changes: 1 addition & 1 deletion packages/sns/candid/sns_governance.did
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated from IC repo commit 987e1c810a9f6770fd1b2f1ae4a895d751d5ef41 'rs/sns/governance/canister/governance.did' by import-candid
// Generated from IC repo commit a1080f27696c890c19d7068f668bd062f3787564 'rs/sns/governance/canister/governance.did' by import-candid
type AccountIdentifier = record { hash : vec nat8 };
type Action = variant {
ManageNervousSystemParameters : NervousSystemParameters;
Expand Down
2 changes: 1 addition & 1 deletion packages/sns/candid/sns_root.did
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated from IC repo commit 987e1c810a9f6770fd1b2f1ae4a895d751d5ef41 'rs/sns/root/canister/root.did' by import-candid
// Generated from IC repo commit a1080f27696c890c19d7068f668bd062f3787564 'rs/sns/root/canister/root.did' by import-candid
type CanisterStatusResultV2 = record {
controller : principal;
status : CanisterStatusType_1;
Expand Down
2 changes: 1 addition & 1 deletion packages/sns/candid/sns_swap.did
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated from IC repo commit 987e1c810a9f6770fd1b2f1ae4a895d751d5ef41 'rs/sns/swap/canister/swap.did' by import-candid
// Generated from IC repo commit a1080f27696c890c19d7068f668bd062f3787564 'rs/sns/swap/canister/swap.did' by import-candid
type BuyerState = record {
icp_disbursing : bool;
amount_sns_e8s : nat64;
Expand Down
6 changes: 6 additions & 0 deletions packages/sns/src/constants/governance.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* A default length for the queried list of neurons
*
* Source: https://github.com/dfinity/ic/blob/master/rs/sns/governance/src/neuron.rs
*/
export const MAX_LIST_NEURONS_RESULTS = 100;
39 changes: 39 additions & 0 deletions packages/sns/src/governance.canister.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { ActorSubclass } from "@dfinity/agent";
import { mock } from "jest-mock-extended";
import type { _SERVICE as SnsGovernanceCanister } from "../candid/sns_governance";
import { MAX_LIST_NEURONS_RESULTS } from "./constants/governance.constants";
import { GovernanceCanister } from "./governance.canister";
import { neuronsMock } from "./mocks/governance.mock";
import { rootCanisterIdMock } from "./mocks/sns.mock";

describe("Governance canister", () => {
it("should return the list of neurons of the sns", async () => {
const service = mock<ActorSubclass<SnsGovernanceCanister>>();
service.list_neurons.mockResolvedValue({ neurons: neuronsMock });

const canister = GovernanceCanister.create({
canisterId: rootCanisterIdMock,
certifiedServiceOverride: service,
});
const res = await canister.listNeurons({});
expect(res).toEqual(neuronsMock);
});

it("should call list of neurons with default param", async () => {
const service = mock<ActorSubclass<SnsGovernanceCanister>>();
const mockListNeurons = service.list_neurons.mockResolvedValue({
neurons: neuronsMock,
});

const canister = GovernanceCanister.create({
canisterId: rootCanisterIdMock,
certifiedServiceOverride: service,
});
await canister.listNeurons({});
expect(mockListNeurons).toHaveBeenCalledWith({
limit: MAX_LIST_NEURONS_RESULTS,
of_principal: [],
start_page_at: [],
});
});
});
Loading

0 comments on commit 02c2b6f

Please sign in to comment.