Skip to content

Commit

Permalink
feat: CMC get default subnets (#733)
Browse files Browse the repository at this point in the history
# Motivation

Particularly those days when the subnets are overloaded, it can be
interesting for devs to be able to programmatically get a list of
subnets. Therefore, this PR exposes the function `get_default_subnets`
of the CMC canister.

# Changes

- Implement `get_default_subnets` in `CMCCanister`.

---------

Signed-off-by: David Dal Busco <david.dalbusco@dfinity.org>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
peterpeterparker and github-actions[bot] authored Oct 15, 2024
1 parent c1b9a1d commit ae6c752
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

- For consistency, the `CMCCanister.create` function now requires the `canisterId` option to be provided exclusively as a `Principal`.

## Features

- Add support for `get_default_subnets` to `@dfinity/cmc`.

# 2024.10.09-1140Z

## Overview
Expand Down
18 changes: 18 additions & 0 deletions packages/cmc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const rate = await getIcpToCyclesConversionRate();
- [getIcpToCyclesConversionRate](#gear-geticptocyclesconversionrate)
- [notifyCreateCanister](#gear-notifycreatecanister)
- [notifyTopUp](#gear-notifytopup)
- [getDefaultSubnets](#gear-getdefaultsubnets)

##### :gear: create

Expand Down Expand Up @@ -104,4 +105,21 @@ It returns the new Cycles of the canister.

[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/cmc/src/cmc.canister.ts#L76)

##### :gear: getDefaultSubnets

This function calls the `get_default_subnets` method of the CMC canister, which returns a list of
default subnets as `Principal` objects. It can be called as query or update.

| Method | Type |
| ------------------- | ------------------------------------------------------- |
| `getDefaultSubnets` | `({ certified }?: QueryParams) => Promise<Principal[]>` |

Parameters:

- `params`: - The query parameters for the call.
- `params.certified`: - Determines whether the response should be certified
(default: non-certified if not specified).

[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/cmc/src/cmc.canister.ts#L101)

<!-- TSDOC_END -->
63 changes: 63 additions & 0 deletions packages/cmc/src/cmc.canister.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ActorSubclass, HttpAgent } from "@dfinity/agent";
import { Principal } from "@dfinity/principal";
import { arrayOfNumberToUint8Array } from "@dfinity/utils";
import type { QueryParams } from "@dfinity/utils/src";
import { mock } from "jest-mock-extended";
import type {
_SERVICE as CMCService,
Expand All @@ -16,6 +17,7 @@ import {
RefundedError,
TransactionTooOldError,
} from "./cmc.errors";
import { mockPrincipalText } from "./cmc.mock";

describe("CyclesMintingCanister", () => {
const mockAgent: HttpAgent = mock<HttpAgent>();
Expand Down Expand Up @@ -291,4 +293,65 @@ describe("CyclesMintingCanister", () => {
expect(call).rejects.toThrowError(CMCError);
});
});

describe("CMCCanister.getDefaultSubnets", () => {
const expectedSubnets = [
Principal.fromText(mockPrincipalText),
Principal.fromText("aaaaa-aa"),
];

it("should return a list of default subnets for a query", async () => {
const service = mock<CMCService>();
service.get_default_subnets.mockResolvedValue(expectedSubnets);

const cmc = await createCMC(service);

const callerSpy = jest.spyOn(
cmc as unknown as {
caller: (params: QueryParams) => Promise<CMCService>;
},
"caller",
);

const result = await cmc.getDefaultSubnets({ certified: false });

expect(result).toEqual(expectedSubnets);
expect(service.get_default_subnets).toHaveBeenCalledTimes(1);

expect(callerSpy).toHaveBeenCalledWith({ certified: false });
});

it("should return a list of default subnets for an update", async () => {
const service = mock<CMCService>();
service.get_default_subnets.mockResolvedValue(expectedSubnets);

const cmc = await createCMC(service);

const callerSpy = jest.spyOn(
cmc as unknown as {
caller: (params: QueryParams) => Promise<CMCService>;
},
"caller",
);

const result = await cmc.getDefaultSubnets({ certified: true });

expect(result).toEqual(expectedSubnets);
expect(service.get_default_subnets).toHaveBeenCalledTimes(1);

expect(callerSpy).toHaveBeenCalledWith({ certified: true });
});

it("should throw an error if the canister call ends in error", async () => {
const service = mock<CMCService>();
service.get_default_subnets.mockRejectedValue(new Error("Test"));

const cmc = await createCMC(service);

await expect(cmc.getDefaultSubnets({ certified: true })).rejects.toThrow(
"Test",
);
expect(service.get_default_subnets).toHaveBeenCalledTimes(1);
});
});
});
20 changes: 19 additions & 1 deletion packages/cmc/src/cmc.canister.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Principal } from "@dfinity/principal";
import { Canister, createServices } from "@dfinity/utils";
import { Canister, createServices, type QueryParams } from "@dfinity/utils";
import type {
_SERVICE as CMCCanisterService,
Cycles,
Expand Down Expand Up @@ -86,4 +86,22 @@ export class CMCCanister extends Canister<CMCCanisterService> {
`Unsupported response type in notifyTopUp ${JSON.stringify(response)}`,
);
};

/**
* This function calls the `get_default_subnets` method of the CMC canister, which returns a list of
* default subnets as `Principal` objects. It can be called as query or update.
*
* @param {Object} [params] - The query parameters for the call.
* @param {boolean} [params.certified] - Determines whether the response should be certified
* (default: non-certified if not specified).
*
* @returns {Promise<Principal[]>} - A promise that resolves to an array of `Principal` objects
* representing the default subnets.
*/
public getDefaultSubnets = async ({ certified }: QueryParams = {}): Promise<
Principal[]
> => {
const { get_default_subnets } = this.caller({ certified });
return get_default_subnets();
};
}

0 comments on commit ae6c752

Please sign in to comment.