-
Notifications
You must be signed in to change notification settings - Fork 509
A specification for the cycles minting canister. #5574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bogwar
wants to merge
26
commits into
master
Choose a base branch
from
bw/cmcspec
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+552
−0
Open
Changes from 9 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
93332e5
initial cmc spec file
bogwar 5fcf45a
API overview
bogwar 05e0039
notify_create_canister
bogwar 8b357f7
notify_create_canister
bogwar c615079
notify_topup_canister
bogwar 4a3502e
fixed memo for topup
bogwar 37ff838
create_canister
bogwar e95b8c6
added shared logic section for settings and encoding of principal as …
bogwar 61680ad
added legacy memo for notify_mint
bogwar a16f639
Apply Jesse's changes
bogwar cfe15e4
Apply Severin's changes
bogwar 4c033e7
memo fix
bogwar 90ba3e8
Merge branch 'bw/cmcspec' of github.com:dfinity/portal into bw/cmcspec
bogwar cc22a9f
added some clarifications
bogwar fa16af2
removed mnemonics for memo fields, added remaining methods
bogwar 6b841fa
new section + shared behaviour for notify-* methods
bogwar d0289cc
pass
bogwar f6a79cf
added more methods
bogwar 0c5976e
spourious lines
bogwar da41311
pointers to encoding of principals into subaccounts
bogwar 5386421
Update docs/references/cmcspec.mdx
bogwar f666563
Update docs/references/cmcspec.mdx
bogwar 93ac15b
Update docs/references/cmcspec.mdx
bogwar c287dad
Update docs/references/cmcspec.mdx
bogwar 2b22664
Update docs/references/cmcspec.mdx
bogwar fee8fb1
Merge branch 'master' into bw/cmcspec
marc0olo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,241 @@ | ||||||
| import { MarkdownChipRow } from "/src/components/Chip/MarkdownChipRow"; | ||||||
|
|
||||||
| # Cycles Minting Canister (CMC) API | ||||||
|
|
||||||
| <MarkdownChipRow labels={["Reference"]} /> | ||||||
|
|
||||||
| ## Overview | ||||||
|
|
||||||
| The Cycles Minting Canister (CMC) is a system canister on the Internet Computer responsible for converting ICP tokens into **cycles**. It supports: | ||||||
|
|
||||||
| - Topping up existing canisters | ||||||
| - Creating new canisters | ||||||
| - Depositing minted cycles into ledger-managed accounts | ||||||
| - Fetching exchange rates and subnet configuration | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| The CMC is governed entirely by the **NNS (Network Nervous System)** and receives configuration updates through proposals. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| ## Configuration Parameters | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| - **Conversion Rate Source**: The ICP/XDR exchange rate is **pushed** into the CMC by a dedicated *exchange rate canister*. This data reflects live market pricing and determines the ICP→cycles conversion. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| - **Governance Control**: All operations of the CMC — including upgrades, configuration, and authorized callers — are managed through NNS proposals. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
|
|
||||||
| ## API Endpoints | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| The CMC exposes a set of core methods for converting ICP into cycles and interacting with subnet configuration. These include: | ||||||
|
|
||||||
| - `notify_create_canister`: Processes an ICP payment by minting cycles and using them to create a new canister, assigning control to the specified principal and applying optional settings. | ||||||
| - `notify_top_up`: Processes an ICP payment by minting cycles and sending them to an existing canister to increase its available balance. | ||||||
| - `notify_mint_cycles`: Processes an ICP payment by minting cycles and depositing them into a cycles ledger account associated with a subaccount. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - `create_canister`: Creates a canister using cycles directly attached to the call. | ||||||
| - `get_icp_xdr_conversion_rate`: Returns the current ICP/XDR exchange rate with certification. | ||||||
| - `get_subnet_types_to_subnets`: Lists available subnets grouped by their types. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - `get_principals_authorized_to_create_canisters_to_subnets`: Indicates which principals are permitted to create canisters on which subnets. | ||||||
| - `get_default_subnets`: Returns the subnets for general-purpose canister creation. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - `get_build_metadata`: Displays internal version and build information for the CMC. | ||||||
|
|
||||||
|
|
||||||
| ## API Reference | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| ### `notify_create_canister` | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| Creates a new canister after verifying an ICP payment recorded in the ICP Ledger. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| If the `subnet_selection field is omitted, the CMC will automatically choose a suitable subnet at random from the available options. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| The CMC expects the payment to follow a strict structure that encodes both the **intent** and the **recipient**: | ||||||
|
|
||||||
| - The **destination account** of the ICP transfer must be the CMC's account with a subaccount derived from the intended controller's principal. | ||||||
| - The **memo field** must explicitly indicate the intent to create a canister. This can be expressed as: | ||||||
| - A legacy 64-bit unsigned integer memo with value `0x41455243` (ASCII `"CREA"`) | ||||||
| - Or, for ICRC-1-compatible transfers (e.g., `icrc1_transfer`, `icrc2_transfer_from`), a memo blob equal to: | ||||||
| ```candid | ||||||
| "\43\52\45\41\00\00\00\00" | ||||||
| ``` | ||||||
| which represents `"CREA"` padded to 8 bytes. | ||||||
|
|
||||||
| - **Parameters:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| ```candid | ||||||
| record { | ||||||
| block_index: nat64; // The ledger block containing the ICP payment | ||||||
| controller: principal; // The principal who will control the new canister | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| settings: opt CanisterSettings; // Optional settings like controllers, memory limits, etc. | ||||||
| subnet_type: opt text; // Deprecated: legacy subnet selection | ||||||
| subnet_selection: opt SubnetSelection; // Preferred subnet selection method | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| - **Returns:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| ```candid | ||||||
| variant { Ok: principal; Err: NotifyError } | ||||||
| ``` | ||||||
|
|
||||||
| - **Notes:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - The call is idempotent with respect to `block_index`; repeating it returns the same result. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - The controller must match the one encoded in the subaccount used for the payment. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - Only transactions that follow the exact memo format will be processed successfully. | ||||||
|
|
||||||
|
|
||||||
| ### `notify_top_up` | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| Tops up an existing canister by minting cycles based on an ICP payment recorded in the ICP Ledger. | ||||||
|
|
||||||
| The CMC expects the payment to follow a strict structure that encodes both the **intent** and the **target canister**: | ||||||
|
|
||||||
| - The **destination account** of the ICP transfer must be the CMC's account with a subaccount derived from the target canister’s principal. | ||||||
| - The **memo field** must explicitly indicate the intent to top up a canister. This can be expressed as: | ||||||
| - A legacy 64-bit unsigned integer memo with value `0x50555054` (ASCII `"PUPT"`) | ||||||
| - Or, for ICRC-1-compatible transfers (e.g., `icrc1_transfer`, `icrc2_transfer_from`), a memo blob equal to: | ||||||
| ```candid | ||||||
| "\50\55\50\54\00\00\00\00" | ||||||
| ``` | ||||||
| which represents `"PUPT"` padded to 8 bytes. | ||||||
|
|
||||||
| - **Parameters:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| ```candid | ||||||
| record { | ||||||
| block_index: nat64; // Block index of the ICP ledger payment | ||||||
| canister_id: principal; // Canister to be topped up | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| - **Returns:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| ```candid | ||||||
| variant { Ok: nat; Err: NotifyError } // Number of cycles minted and sent | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| ``` | ||||||
|
|
||||||
| - **Notes:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - The subaccount used in the transfer must be derived from the target canister’s principal using the standard 32-byte encoding (see “Shared Logic” section). | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - This method is idempotent by `block_index`: retrying the same request will return the same result if it already succeeded. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, probably worth noting cache expiry time and that it can only be called on recent-enough blocks |
||||||
| - Only transfers matching the expected structure and memo will be accepted. | ||||||
|
|
||||||
| ## `notify_mint_cycles` | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| Mints cycles into a **cycles ledger account** based on an ICP payment recorded in the ICP Ledger. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| This method is used to deposit minted cycles into a specific subaccount in the **cycles ledger**. It supports minting from both legacy and ICRC-1-style transfers. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| The CMC expects the payment to follow a strict structure that encodes the **intent** and **destination**: | ||||||
|
|
||||||
| - The **destination account** must be the CMC’s account with the subaccount matching the `to_subaccount` parameter. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - The **memo field** must explicitly indicate the intent to mint cycles. This can be: | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - For legacy `transfer` calls: a `u64` memo with value: | ||||||
| ```candid | ||||||
| 0x544e494d // ASCII "MINT" | ||||||
| ``` | ||||||
| - For ICRC-1-compatible transfers (e.g., `icrc1_transfer`, `icrc2_transfer_from`): a `blob` memo equal to: | ||||||
| ```candid | ||||||
| "\4d\49\4e\54\00\00\00\00" | ||||||
| ``` | ||||||
| which represents `"MINT"` padded to 8 bytes | ||||||
|
|
||||||
| - **Parameters:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| ```candid | ||||||
| record { | ||||||
| block_index: nat64; // Block index of the ICP ledger payment | ||||||
| to_subaccount: opt blob; // 32-byte subaccount to credit in the cycles ledger | ||||||
| deposit_memo: opt blob; // Optional application-specific memo | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| - **Returns:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| ```candid | ||||||
| variant { | ||||||
| Ok: record { | ||||||
| block_index: nat; // Block index in the cycles ledger | ||||||
| minted: nat; // Amount of cycles minted | ||||||
| balance: nat; // Final balance of the cycles ledger account | ||||||
| }; | ||||||
| Err: NotifyError; | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| - **Notes:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - The caller must be authorized to invoke this method. | ||||||
| - The subaccount in the payment must match `to_subaccount` exactly. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - This method is idempotent by `block_index`. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - Both legacy and ICRC-1 memo formats are accepted if they correctly encode `"MINT"`. | ||||||
|
|
||||||
|
|
||||||
| ### `create_canister` | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| Creates a new canister using cycles attached directly to the call (not from an ICP ledger payment). | ||||||
|
|
||||||
| Unlike `notify_create_canister`, this method does not rely on an external ICP transaction. Instead, the calling canister must attach enough cycles to cover the creation cost. | ||||||
|
|
||||||
| - If `subnet_selection` is omitted, the CMC will select a suitable subnet at random from the available subnets. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - If `settings` is provided, it will override default configuration for the new canister. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - If no `settings` are given, the calling principal becomes the sole controller. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| - **Parameters:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| ```candid | ||||||
| record { | ||||||
| settings: opt CanisterSettings; // Optional settings: controller(s), allocations, limits, etc. | ||||||
| subnet_type: opt text; // (Deprecated) Legacy subnet type selection | ||||||
| subnet_selection: opt SubnetSelection; // Preferred way to select the subnet | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| - **Returns:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| ```candid | ||||||
| variant { Ok: principal; Err: CreateCanisterError } | ||||||
| ``` | ||||||
|
|
||||||
| - **Notes:** | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
| - This method requires cycles to be attached to the call. | ||||||
| - Returns the principal of the newly created canister. | ||||||
| - The result is **not idempotent** — calling it again will consume cycles and create a different canister. | ||||||
|
|
||||||
|
|
||||||
| ## Shared Logic | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| ### Canister Settings | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| The `CanisterSettings` record allows configuration of the canister at the time of creation or through governance. Each field is optional and will default to system-provided values if not specified. | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| ```candid | ||||||
| record { | ||||||
| controllers : opt vec principal; // List of principals allowed to control the canister | ||||||
| compute_allocation : opt nat; // Percentage (0-100) of guaranteed compute capacity | ||||||
| memory_allocation : opt nat; // Memory reserved for the canister, in bytes | ||||||
| freezing_threshold : opt nat; // Number of seconds the canister can go without being topped up before being frozen | ||||||
| reserved_cycles_limit : opt nat; // Reserved minimum cycle balance for execution | ||||||
| log_visibility : opt variant { | ||||||
| controllers; | ||||||
| public; | ||||||
| }; // Visibility of canister logs | ||||||
| wasm_memory_limit : opt nat; // Cap on wasm memory usage, in bytes | ||||||
| wasm_memory_threshold : opt nat; // Threshold to trigger memory alerts or actions | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| Unspecified fields are interpreted as: | ||||||
| - `controllers`: Defaults to the caller of the method | ||||||
| - Other fields: Use system-wide default configuration values | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| --- | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| ### Encoding a Principal into a Subaccount | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| Several CMC methods require an ICP payment to be sent to a subaccount that encodes a principal (e.g., the controller of a new canister or the canister being topped up). | ||||||
|
|
||||||
| To derive this subaccount, the principal is serialized and packed into a 32-byte array using the following logic: | ||||||
|
|
||||||
| ```motoko | ||||||
| public func principalToSubAccount(id: Principal) : [Nat8] { | ||||||
| let p = Blob.toArray(Principal.toBlob(id)); | ||||||
| Array.tabulate(32, func(i : Nat) : Nat8 { | ||||||
| if (i >= p.size() + 1) 0 | ||||||
| else if (i == 0) (Nat8.fromNat(p.size())) | ||||||
| else (p[i - 1]) | ||||||
| }) | ||||||
| }; | ||||||
| ``` | ||||||
|
|
||||||
| This produces a 32-byte subaccount where: | ||||||
| - The first byte contains the length of the principal | ||||||
| - The next bytes contain the principal's raw byte encoding | ||||||
| - The remainder is zero-padded to reach 32 bytes | ||||||
|
bogwar marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| This convention ensures the CMC can determine which principal or canister an incoming payment was intended for. | ||||||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.