From 4cc5df0f1fbeb5e1a43ed421e0399aa4d1ada154 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Mon, 27 Apr 2026 19:24:33 +0200 Subject: [PATCH 1/2] docs(digital-assets): restructure digital assets reference and add chain-key token pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename token-ledgers.mdx → ledgers.mdx; rewrite with ledger suite concept, ICRC-3 transaction history section, CLI + language tab separation convention - Rewrite chain-key-tokens.mdx: add ckDOGE and ckSOL deposit/withdrawal flows, slim canister IDs section to pointer, remove duplicate CLI balance checks - Add reference/chain-key-canister-ids.md: canonical canister IDs for all chain-key tokens (ckBTC, ckETH, ckERC20, ckDOGE, ckSOL) with mainnet and testnet - Add reference/icrc-standards.md: index of all adopted ICRC standards with external spec links for both digital asset and wallet signer standards - Rename token-standards.md → digital-asset-standards.md; update description - Rewrite protocol-canisters.md: minter APIs and protocol reference only; add ckDOGE, ckSOL, ckERC20 sections; remove duplicate canister ID tables and deposit/withdrawal flows (now in chain-key-tokens.mdx) - Reorder sidebar: Digital Assets before Chain Fusion; fix reference section order to match index.md grouping (canisters → token standards → costs → errors → specs) - Record CLI/language tab separation convention in decisions.md --- .docs-plan/decisions.md | 18 + docs/concepts/chain-fusion.md | 2 +- docs/getting-started/choose-your-path.md | 2 +- .../digital-assets/chain-key-tokens.mdx | 342 +++++++----------- .../{token-ledgers.mdx => ledgers.mdx} | 85 ++--- docs/guides/digital-assets/rosetta.md | 4 +- .../digital-assets/wallet-integration.md | 16 +- docs/guides/index.md | 22 +- docs/reference/application-canisters.md | 2 +- docs/reference/candid-spec.md | 2 +- docs/reference/chain-key-canister-ids.md | 125 +++++++ docs/reference/cycles-costs.md | 2 +- ...tandards.md => digital-asset-standards.md} | 38 +- docs/reference/execution-errors.md | 2 +- docs/reference/glossary.md | 2 +- docs/reference/http-gateway-spec.md | 2 +- docs/reference/ic-interface-spec.md | 2 +- docs/reference/icrc-standards.md | 45 +++ docs/reference/index.md | 4 +- docs/reference/internet-identity-spec.md | 2 +- docs/reference/protocol-canisters.md | 156 ++++---- docs/reference/subnet-types.md | 2 +- docs/reference/system-canisters.md | 2 +- sidebar.mjs | 8 +- 24 files changed, 483 insertions(+), 404 deletions(-) rename docs/guides/digital-assets/{token-ledgers.mdx => ledgers.mdx} (76%) create mode 100644 docs/reference/chain-key-canister-ids.md rename docs/reference/{token-standards.md => digital-asset-standards.md} (84%) create mode 100644 docs/reference/icrc-standards.md diff --git a/.docs-plan/decisions.md b/.docs-plan/decisions.md index 3dcef315..da5256c7 100644 --- a/.docs-plan/decisions.md +++ b/.docs-plan/decisions.md @@ -4,6 +4,24 @@ Record decisions that constrain future work — things an agent needs to know th --- +## 2026-04-27: CLI and language tabs are always separate + +**Context:** Some pages were mixing CLI commands into the same `` group as Motoko and Rust code. Other pages (e.g. `cycles-management.mdx`, `lifecycle.mdx`) kept CLI as standalone blocks with language tabs appearing separately. The mixed approach creates an awkward tab for users who just want a quick CLI command. +**Decision:** CLI commands always appear as standalone code blocks, never inside a `` group. When a section has both a CLI command and language-specific code, the CLI block comes first (quick-check path), followed by the `` group (integration path). Tab order within language tabs remains Motoko → Rust → others per CLAUDE.md. +**Rationale:** CLI and code serve different audiences and mental models. CLI is for quick ad-hoc use; language code is for building integrations. Mixing them forces one audience to click past irrelevant tabs. Placing CLI first gives the faster answer to the more common case. +**When to revisit:** If a section has no meaningful CLI equivalent, omit it — don't add a CLI block just for consistency. + +--- + +## 2026-04-27: ICRC standards reference restructured into index + detail pages + +**Context:** `reference/token-standards.md` mixed two unrelated standard families (digital asset standards ICRC-1/2/3/7/37 and wallet signer standards ICRC-21/25/27/29/49) under a title that didn't fit either category cleanly. The page also used "token" as a primary descriptor, conflicting with the brand voice push toward "digital assets." +**Decision:** Split into two pages. `reference/icrc-standards.md` is a lightweight index of all ICRC standards grouped by category (extensible for future standards). `reference/digital-asset-standards.md` (renamed from `token-standards.md`) is the deep reference for ICRC-1/2/3/7/37 only. Wallet signer standard detail stays in the wallet integration guide; the index page links to it. `guides/digital-assets/token-ledgers.mdx` renamed to `guides/digital-assets/ledgers.mdx`. +**Rationale:** "Token Standards" as a page title was inaccurate (covered signers too) and jargon-heavy. "ICRC Standards" as a single page title would be too broad (implies ALL ICRC work). Separating the index from the detail page gives a clean extensible home for future ICRC standards without forcing unrelated content together. +**When to revisit:** If wallet signer content grows enough to warrant its own `reference/signer-standards.md`, add it to the index and link from there. + +--- + ## 2026-04-24: Developer Tools is a top-level sidebar item, not a section **Context:** The tools overview page (`reference/developer-tools.md`) is a toolchain catalog — not a how-to guide, concept explanation, or specification. It doesn't fit cleanly in any Diataxis quadrant. It was previously under `guides/tools/` and then considered for Reference. diff --git a/docs/concepts/chain-fusion.md b/docs/concepts/chain-fusion.md index 10bd833c..a746c8f5 100644 --- a/docs/concepts/chain-fusion.md +++ b/docs/concepts/chain-fusion.md @@ -70,7 +70,7 @@ Direct integration provides the strongest trust guarantees. The only assumption Chain-key tokens are digital twins of native assets from other blockchains (for example, ckBTC for Bitcoin and ckETH for Ethereum). Each token is backed 1:1 by the native asset, which is held in a canister-controlled address on the source chain. Minting and burning happen entirely onchain. No bridge, no custodian. -These tokens implement the [ICRC-2](../guides/digital-assets/token-ledgers.md) token standard, so they can be transferred and traded within the ICP ecosystem with the same speed and cost as any other ICP token. When a user wants to redeem the underlying asset, the minter canister signs and submits a withdrawal transaction on the source chain. +These tokens implement the [ICRC-2](../guides/digital-assets/ledgers.md) token standard, so they can be transferred and traded within the ICP ecosystem with the same speed and cost as any other ICP token. When a user wants to redeem the underlying asset, the minter canister signs and submits a withdrawal transaction on the source chain. For details on integrating with chain-key tokens, see the [Chain-key tokens guide](../guides/digital-assets/chain-key-tokens.md). diff --git a/docs/getting-started/choose-your-path.md b/docs/getting-started/choose-your-path.md index 92f22200..b7c5af0c 100644 --- a/docs/getting-started/choose-your-path.md +++ b/docs/getting-started/choose-your-path.md @@ -95,7 +95,7 @@ Chain fusion lets your canister hold native assets, sign transactions, and inter ICP has a standard token framework (ICRC) and chain-key tokens that represent assets from other chains. These guides cover the ledger APIs and token patterns for building payment flows, issuing digital assets, and integrating with exchanges. -**Start with:** [Token ledgers](../guides/digital-assets/token-ledgers.md): understand ICRC token standards and interact with ledger canisters. +**Start with:** [Ledgers](../guides/digital-assets/ledgers.md): understand ICRC token standards and interact with ledger canisters. **Then explore:** diff --git a/docs/guides/digital-assets/chain-key-tokens.mdx b/docs/guides/digital-assets/chain-key-tokens.mdx index 02ae5191..7715cdd7 100644 --- a/docs/guides/digital-assets/chain-key-tokens.mdx +++ b/docs/guides/digital-assets/chain-key-tokens.mdx @@ -1,63 +1,38 @@ --- title: "Chain-Key Tokens" -description: "Work with ckBTC and ckETH: ICP-native representations of Bitcoin and Ether with 1-2 second finality and no custodians" +description: "Deposit, withdraw, and transfer ckBTC, ckETH, ckERC20, ckDOGE, and ckSOL: ICP-native representations of external assets backed 1:1 with no bridges or custodians" sidebar: order: 2 --- import { Tabs, TabItem } from '@astrojs/starlight/components'; -Chain-key tokens are ICP-native tokens that represent assets from other blockchains. Each one is backed 1:1 by the original asset and is controlled entirely by ICP canisters. No bridges, no wrapped tokens, no third-party custodians. +Chain-key tokens are ICP-native representations of assets from other blockchains. Each one is backed 1:1 by the original asset and controlled entirely by ICP canisters. No bridges, no wrapped tokens, no third-party custodians. -**ckBTC** (chain-key Bitcoin) is backed by real BTC held by the ckBTC minter canister. **ckETH** (chain-key Ether) is backed by real ETH held by the ckETH minter canister. Both are ICRC-1 tokens, so any code that works with the ICP ledger also works with ckBTC and ckETH: you only swap the canister ID. +All chain-key tokens implement the [ICRC-1 standard](../../reference/digital-asset-standards.md#icrc-1-fungible-tokens). The deposit and withdrawal flows use [ICRC-2](../../reference/digital-asset-standards.md#icrc-2-approve-and-transfer-from) `icrc2_approve` to authorize the minter to burn tokens on your behalf. -This guide covers: the minting and redemption flows, how to call the minter and ledger from a canister, subaccount derivation for per-user deposit addresses, and the trust model that keeps the peg. +This guide covers deposit and withdrawal flows for each asset, plus the pattern for issuing per-user deposit addresses from a backend canister. -For plain ICRC-1/ICRC-2 transfers without the minting/withdrawal flows, see [Token ledgers](token-ledgers.md). +For plain ICRC-1/ICRC-2 transfers without the minting/withdrawal flows, see [Ledgers](ledgers.md). -## How chain-key tokens maintain their peg - -The ckBTC and ckETH minter canisters hold real BTC and ETH in addresses they control through [chain-key cryptography](../../concepts/chain-key-cryptography.md). The minters use threshold signatures to sign Bitcoin and Ethereum transactions. No private key exists anywhere; signing requires cooperation from the subnet's nodes. - -When a user deposits BTC, the minter mints exactly the same amount of ckBTC. When a user withdraws ckBTC, the minter burns the tokens and sends BTC to the Bitcoin network. The peg holds by design: every ckBTC in circulation corresponds to exactly one satoshi of BTC held by the minter. The ckBTC checker canister publishes a public audit of reserves. - -This means ckBTC and ckETH are not wrapped tokens in the traditional sense. They are ICP tokens whose supply is cryptographically enforced by the minter canister. +## Available chain-key assets -## Canister IDs +The current chain-key assets are: **ckBTC** (Bitcoin), **ckETH** (Ether), **ckERC20** (ERC-20 tokens including ckUSDC, ckUSDT, ckLINK, and others), **ckDOGE** (Dogecoin), and **ckSOL** (Solana). Transfer code is identical across all of them: only the canister ID and fee denomination differ. See [Canister IDs](#canister-ids) for the full list. -### ckBTC +If you need direct Bitcoin UTXO access or custom Bitcoin transaction signing, see [Bitcoin integration](../chain-fusion/bitcoin.md). If you need to call Ethereum contracts or interact with Ethereum infrastructure directly, see [Ethereum integration](../chain-fusion/ethereum.md). For fast ICP-native transfers, chain-key tokens are the simpler choice. -| Canister | Mainnet ID | -|----------|-----------| -| ckBTC Ledger | `mxzaz-hqaaa-aaaar-qaada-cai` | -| ckBTC Minter | `mqygn-kiaaa-aaaar-qaadq-cai` | -| ckBTC Index | `n5wcd-faaaa-aaaar-qaaea-cai` | -| ckBTC Checker | `oltsj-fqaaa-aaaar-qal5q-cai` | - -**Bitcoin Testnet4** (for testing): - -| Canister | Testnet4 ID | -|----------|------------| -| ckBTC Ledger | `mc6ru-gyaaa-aaaar-qaaaq-cai` | -| ckBTC Minter | `ml52i-qqaaa-aaaar-qaaba-cai` | -| ckBTC Index | `mm444-5iaaa-aaaar-qaabq-cai` | - -### ckETH +## How chain-key tokens maintain their peg -| Canister | Mainnet ID | -|----------|-----------| -| ckETH Ledger | `ss2fx-dyaaa-aaaar-qacoq-cai` | -| ckETH Minter | `sv3dd-oaaaa-aaaar-qacoa-cai` | -| ckETH Index | `s3zol-vqaaa-aaaar-qacpa-cai` | +ckBTC and ckETH are not wrapped assets in the traditional sense. The minter canisters hold the underlying BTC and ETH in addresses they control through [chain-key cryptography](../../concepts/chain-key-cryptography.md), using threshold signatures to sign transactions. No private key exists anywhere. Every ckBTC in circulation corresponds to exactly one satoshi of BTC held by the minter. -> Always query `icrc1_fee` at runtime rather than hardcoding. ckBTC uses satoshi units (1 BTC = 100,000,000 satoshis, fee = 10 satoshis). ckETH uses wei units (1 ETH = 10¹⁸ wei). +## ckBTC -## Deposit flow: getting ckBTC from BTC +### Deposit: BTC → ckBTC The deposit flow has two steps: -1. **Get a deposit address**: call `get_btc_address` on the ckBTC minter with the user's principal and an optional subaccount. The minter returns a unique Bitcoin address. -2. **Mint ckBTC**: after the user sends BTC to that address, call `update_balance` on the minter. The minter checks for new UTXOs and mints ckBTC to the corresponding ICRC-1 account. +1. **Get a deposit address**: call `get_btc_address` on the ckBTC minter with the owner principal and an optional subaccount. The minter returns a unique Bitcoin address. +2. **Mint ckBTC**: after BTC is sent to that address, call `update_balance` on the minter. The minter checks for new UTXOs and mints ckBTC to the corresponding ICRC-1 account. The minter requires a minimum number of Bitcoin confirmations before minting (currently 6 on mainnet). `update_balance` returns `NoNewUtxos` if confirmations have not yet been reached: your app should poll or prompt the user to wait. @@ -66,14 +41,9 @@ The minter requires a minimum number of Bitcoin confirmations before minting (cu ```motoko import Principal "mo:core/Principal"; -import Blob "mo:core/Blob"; -import Nat8 "mo:core/Nat8"; -import Array "mo:core/Array"; -import Runtime "mo:core/Runtime"; persistent actor Self { - // Types for the ckBTC minter interface type UpdateBalanceResult = { #Ok : [UtxoStatus]; #Err : UpdateBalanceError; @@ -109,35 +79,19 @@ persistent actor Self { update_balance : shared ({ owner : ?Principal; subaccount : ?Blob }) -> async UpdateBalanceResult; } = actor "mqygn-kiaaa-aaaar-qaadq-cai"; - // Derive a 32-byte subaccount from a principal for per-user deposit addresses - func principalToSubaccount(p : Principal) : Blob { - let bytes = Blob.toArray(Principal.toBlob(p)); - let size = bytes.size(); - let sub = Array.tabulate(32, func(i : Nat) : Nat8 { - if (i == 0) { Nat8.fromNat(size) } - else if (i <= size) { bytes[i - 1] } - else { 0 } - }); - Blob.fromArray(sub) - }; - - // Get the user's unique BTC deposit address - public shared ({ caller }) func getDepositAddress() : async Text { - if (Principal.isAnonymous(caller)) { Runtime.trap("Authentication required") }; - let subaccount = principalToSubaccount(caller); + // Get the BTC deposit address for this canister's default account + public shared func getDepositAddress() : async Text { await ckbtcMinter.get_btc_address({ owner = ?Principal.fromActor(Self); - subaccount = ?subaccount; + subaccount = null; }) }; // Check for new BTC deposits and mint ckBTC - public shared ({ caller }) func checkForDeposit() : async UpdateBalanceResult { - if (Principal.isAnonymous(caller)) { Runtime.trap("Authentication required") }; - let subaccount = principalToSubaccount(caller); + public shared func checkForDeposit() : async UpdateBalanceResult { await ckbtcMinter.update_balance({ owner = ?Principal.fromActor(Self); - subaccount = ?subaccount; + subaccount = null; }) }; } @@ -159,35 +113,16 @@ struct GetBtcAddressArgs { subaccount: Option>, } -#[derive(CandidType, Deserialize, Debug)] -struct UpdateBalanceArgs { - owner: Option, - subaccount: Option>, -} - -// Derive a 32-byte subaccount from a principal for per-user deposit addresses -fn principal_to_subaccount(principal: &Principal) -> [u8; 32] { - let mut subaccount = [0u8; 32]; - let principal_bytes = principal.as_slice(); - subaccount[0] = principal_bytes.len() as u8; - subaccount[1..1 + principal_bytes.len()].copy_from_slice(principal_bytes); - subaccount -} - fn minter_id() -> Principal { Principal::from_text(CKBTC_MINTER).unwrap() } -// Get the user's unique BTC deposit address +// Get the BTC deposit address for this canister's default account #[update] async fn get_deposit_address() -> String { - let caller = ic_cdk::api::msg_caller(); - assert_ne!(caller, Principal::anonymous(), "Authentication required"); - - let subaccount = principal_to_subaccount(&caller); let args = GetBtcAddressArgs { owner: Some(ic_cdk::api::canister_self()), - subaccount: Some(subaccount.to_vec()), + subaccount: None, }; let (address,): (String,) = Call::unbounded_wait(minter_id(), "get_btc_address") @@ -204,11 +139,13 @@ async fn get_deposit_address() -> String { -## Withdrawal flow: converting ckBTC back to BTC +For per-user deposit addresses where each user gets a unique BTC address, see [Per-user deposit addresses](#per-user-deposit-addresses). + +### Withdrawal: ckBTC → BTC To convert ckBTC back to BTC, your canister must: -1. **Approve the minter**: call `icrc2_approve` on the ckBTC ledger, granting the minter canister an allowance to burn ckBTC from the user's account. The amount must include the transfer fee. +1. **Approve the minter**: call `icrc2_approve` on the ckBTC ledger, granting the minter canister an allowance to burn ckBTC from the account. The amount must include the transfer fee. 2. **Request withdrawal**: call `retrieve_btc_with_approval` on the minter with the destination Bitcoin address and the amount in satoshis. The minimum withdrawal amount is 50,000 satoshis (0.0005 BTC). The minter burns the ckBTC and submits a Bitcoin transaction. BTC arrives at the destination address after Bitcoin confirmations (typically 1-2 hours on mainnet). @@ -432,56 +369,101 @@ async fn withdraw_to_btc(btc_address: String, amount: u64) -> RetrieveBtcResult -## ckETH: deposit and withdrawal +## ckETH and ckERC20 -The ckETH minter works similarly to ckBTC but targets Ethereum. Deposits are detected via HTTPS outcalls to Ethereum RPC nodes. The minter monitors a helper contract for ETH transfers and mints ckETH when it detects them. +The ckETH minter handles both ETH and ERC-20 deposits using a shared Ethereum helper smart contract. It monitors the contract for deposit events via HTTPS outcalls and mints the corresponding ckETH or ckERC20 to the target ICRC-1 account. -### Depositing ETH to get ckETH +> Always verify the helper contract address before any important transfer: call `get_minter_info` on the ckETH minter and check `deposit_with_subaccount_helper_contract_address`. -1. Call the `deposit` function on the shared ckETH helper smart contract on Ethereum (mainnet address: `0x6abDA0438307733FC299e9C229FD3cc074bD8cC0`), passing some ETH and your ICP principal as the call data. The helper contract emits a `ReceivedEth` event with the sender, value, and receiver (your principal) as payload. -2. The ckETH minter monitors `ReceivedEth` events by periodically fetching logs from Ethereum RPC providers. When it detects the event, it mints the corresponding amount of ckETH to your ICRC-1 account. +### Deposit: ETH → ckETH -> The ckETH deposit flow requires interacting with an Ethereum wallet or library. For sending Ethereum transactions from an ICP canister, see [Ethereum integration](../chain-fusion/ethereum.md). +1. Call `depositEth` on the ckETH helper contract on Ethereum (mainnet: `0x18901044688D3756C35Ed2b36D93e6a5B8e00E68`), passing: + - The amount of ETH. + - Your ICP principal encoded as `bytes32`. + - A 32-byte subaccount (`0x` for the default account, or a derived subaccount for per-user deposits — see [Per-user deposit addresses](#per-user-deposit-addresses)). +2. The minter detects the `ReceivedEthOrErc20` event and mints ckETH to `(principal, subaccount)` after roughly 20 minutes. -### Withdrawing ckETH to ETH +> The ckETH deposit flow requires an Ethereum wallet or library. For sending Ethereum transactions from an ICP canister, see [Ethereum integration](../chain-fusion/ethereum.md). -The ckETH withdrawal flow is the same approve-then-request pattern as ckBTC: +### Deposit: ERC-20 → ckERC20 -1. Call `icrc2_approve` on the ckETH ledger, granting the ckETH minter an allowance. -2. Call `withdraw_eth` on the ckETH minter with a destination Ethereum address and the amount in wei. +The ERC-20 deposit flow uses the same helper contract and minter: -```bash -# Check ckETH balance (amount in wei) -icp canister call ss2fx-dyaaa-aaaar-qacoq-cai icrc1_balance_of \ - '(record { owner = principal "YOUR-PRINCIPAL"; subaccount = null })' \ - -e ic +1. Call `approve(helper_address, amount)` on the ERC-20 token contract to allow the helper contract to spend your tokens. +2. Call `depositErc20` on the helper contract, passing: + - The ERC-20 token contract address. + - The amount. + - Your ICP principal as `bytes32`. + - A 32-byte subaccount (`0x` for the default account). +3. The minter detects the `ReceivedEthOrErc20` event and mints the corresponding ckERC20 to `(principal, subaccount)`. -# Transfer ckETH (amount in wei) -icp canister call ss2fx-dyaaa-aaaar-qacoq-cai icrc1_transfer \ - '(record { - to = record { owner = principal "RECIPIENT-PRINCIPAL"; subaccount = null }; - amount = 1_000_000_000_000_000 : nat; - fee = opt (2_000_000_000_000 : nat); - memo = null; - from_subaccount = null; - created_at_time = null; - })' -e ic -``` +Supported ERC-20 tokens on mainnet: USDC, USDT, EURC, WBTC, wstETH, LINK, UNI, SHIB, PEPE, XAUT, and OCT. For canister IDs, see [Chain-Key Token Canister IDs](../../reference/chain-key-canister-ids.md#ckerc20). For the authoritative current list including any newly added tokens, call `get_minter_info` on the ckETH minter and check `supported_ckerc20_tokens`. + +### Withdrawal: ckETH or ckERC20 → ETH / ERC-20 + +The withdrawal flow follows the same approve-then-request pattern as ckBTC: + +1. Call `icrc2_approve` on the respective ledger, granting the ckETH minter an allowance. +2. Call `withdraw_eth` on the minter with a destination Ethereum address and the amount in wei. The same minter handles withdrawals for all ckERC20 tokens. + +The minter burns the token and submits an Ethereum transaction. Funds arrive after Ethereum finalization, roughly 20 minutes on mainnet. + +> Query `icrc1_fee` on the ledger before withdrawing. The ckETH fee is denominated in wei and can change. + +## ckDOGE + +ckDOGE follows the same UTXO-based pattern as ckBTC. The minter issues a unique Dogecoin address per `(owner, subaccount)` account. + +> ckDOGE is in beta. The API is stable but the integration warrants careful observation during this period. -> Query `icrc1_fee` on the ckETH ledger before transferring. The fee is denominated in wei and can change. +### Deposit: DOGE → ckDOGE + +1. Call `get_deposit_address` on the ckDOGE minter (`eqltq-xqaaa-aaaar-qb3vq-cai`) with the owner principal and an optional subaccount. The minter returns a unique Dogecoin address. +2. Send DOGE to that address from any Dogecoin wallet. +3. Call `update_balance` on the minter to trigger minting. The minter checks for confirmed UTXOs and mints ckDOGE to the corresponding ICRC-1 account. + +`update_balance` returns `NoNewUtxos` if the required confirmations have not yet been reached. + +### Withdrawal: ckDOGE → DOGE + +1. Call `icrc2_approve` on the ckDOGE ledger (`efmc5-wyaaa-aaaar-qb3wa-cai`), granting the minter an allowance. +2. Call `retrieve_doge_with_approval` on the minter with the destination Dogecoin address and the amount in koinus (1 DOGE = 100,000,000 koinus). + +The minter burns ckDOGE and submits a signed Dogecoin transaction using threshold ECDSA. + +For implementation details and the Candid interface, see the [ckDOGE source](https://github.com/dfinity/ic/tree/master/rs/dogecoin/ckdoge). + +## ckSOL + +ckSOL follows a similar pattern to ckBTC: the minter issues a unique Solana deposit address per `(owner, subaccount)` account. + +### Deposit: SOL → ckSOL + +1. Call `get_deposit_address` on the ckSOL minter with your ICP principal and optional subaccount. The minter returns a unique Solana address. +2. Send SOL to that address from any Solana wallet. +3. Call `process_deposit` on the minter with the Solana transaction signature, owner principal, and subaccount (attach cycles to cover the RPC verification cost). The minter verifies the transaction via the SOL RPC canister and mints ckSOL to your account. + +### Withdrawal: ckSOL → SOL + +1. Call `icrc2_approve` on the ckSOL ledger, granting the minter an allowance. +2. Call `withdraw` on the minter with a destination Solana address and amount in lamports. The minter burns ckSOL and signs a Solana transaction using threshold Ed25519. + +Track withdrawal progress with `withdrawal_status` using the burn block index returned from `withdraw`. + +For canister IDs and further details, see the [ckSOL repository](https://github.com/dfinity/cksol). ## Transferring chain-key tokens -ckBTC and ckETH are ICRC-1 tokens. Transfers work the same as any ICRC-1 transfer: call `icrc1_transfer` on the respective ledger. The only difference is the canister ID and the fee. +All chain-key tokens are ICRC-1 tokens. Transfers work the same as any ICRC-1 transfer: call `icrc1_transfer` on the respective ledger. The only difference is the canister ID and the fee denomination. ```bash # Check ckBTC balance (amount in satoshis) icp canister call mxzaz-hqaaa-aaaar-qaada-cai icrc1_balance_of \ '(record { owner = principal "YOUR-PRINCIPAL"; subaccount = null })' \ - -e ic + -n ic # Check ckBTC transfer fee (in satoshis) -icp canister call mxzaz-hqaaa-aaaar-qaada-cai icrc1_fee '()' -e ic +icp canister call mxzaz-hqaaa-aaaar-qaada-cai icrc1_fee '()' -n ic # Transfer ckBTC (amounts in satoshis; 1 BTC = 100,000,000 satoshis) icp canister call mxzaz-hqaaa-aaaar-qaada-cai icrc1_transfer \ @@ -492,80 +474,23 @@ icp canister call mxzaz-hqaaa-aaaar-qaada-cai icrc1_transfer \ memo = null; from_subaccount = null; created_at_time = null; - })' -e ic + })' -n ic ``` -For Motoko and Rust transfer examples, see [Token ledgers](token-ledgers.md): the code is identical to ICRC-1 transfers, just with the ckBTC or ckETH ledger canister ID and the correct fee. +For Motoko and Rust transfer examples, see [Ledgers](ledgers.md): the code is identical to ICRC-1 transfers, just with the respective ledger canister ID and fee. -## Subaccount derivation for deposit flows +## Per-user deposit addresses -In a typical deposit flow, each user gets a unique deposit subaccount derived from their principal. This lets a single canister manage many users' deposit addresses without deploying separate canisters. +A backend canister serving multiple users needs each user to have a unique deposit address so that deposits can be credited to the correct account. The standard pattern: derive a 32-byte subaccount from the user's principal and pass it to the deposit call. -The standard derivation encodes the principal's length in the first byte, then copies the principal bytes, zero-padding to 32 bytes: +For the derivation code (Motoko and Rust), see [Working with subaccounts](ledgers.md#working-with-subaccounts) in the Ledgers guide. The subaccount derivation is identical across all ICRC-1 assets. - - - -```motoko -import Principal "mo:core/Principal"; -import Blob "mo:core/Blob"; -import Nat8 "mo:core/Nat8"; -import Array "mo:core/Array"; +Pass the derived subaccount to the deposit call for each asset: -type Account = { owner : Principal; subaccount : ?Blob }; - -// Encode a principal as a 32-byte subaccount (length-prefixed, zero-padded) -func principalToSubaccount(p : Principal) : Blob { - let bytes = Blob.toArray(Principal.toBlob(p)); - let size = bytes.size(); - let sub = Array.tabulate(32, func(i : Nat) : Nat8 { - if (i == 0) { Nat8.fromNat(size) } - else if (i <= size) { bytes[i - 1] } - else { 0 } - }); - Blob.fromArray(sub) -}; - -// Account for a user's deposit slot within this canister -func userDepositAccount(canister : Principal, user : Principal) : Account { - { owner = canister; subaccount = ?principalToSubaccount(user) } -}; -``` - - - - -```rust -use candid::Principal; -use icrc_ledger_types::icrc1::account::Account; - -/// Encode a principal as a 32-byte subaccount (length-prefixed, zero-padded) -fn principal_to_subaccount(principal: &Principal) -> [u8; 32] { - let mut subaccount = [0u8; 32]; - let principal_bytes = principal.as_slice(); - subaccount[0] = principal_bytes.len() as u8; - subaccount[1..1 + principal_bytes.len()].copy_from_slice(principal_bytes); - subaccount -} - -/// Account for a user's deposit slot within this canister -fn user_deposit_account(canister: Principal, user: &Principal) -> Account { - Account { - owner: canister, - subaccount: Some(principal_to_subaccount(user)), - } -} -``` - - - - -When calling `get_btc_address`, pass: - -- `owner`: your canister's principal (`Principal.fromActor(Self)` in Motoko, `ic_cdk::api::canister_self()` in Rust) -- `subaccount`: the derived subaccount for the user - -The minter uses `(owner, subaccount)` to determine the Bitcoin address. When a deposit arrives at that address and you call `update_balance` with the same `(owner, subaccount)`, the minter mints ckBTC to the corresponding ICRC-1 account. +- **ckBTC**: pass as the `subaccount` field in `get_btc_address`. Use the same `(owner, subaccount)` pair in `update_balance` to credit the correct account. +- **ckETH / ckERC20**: encode as a `0x`-prefixed hex string and pass to `depositEth` or `depositErc20` on the Ethereum helper contract. +- **ckDOGE**: pass as the `subaccount` field in `get_deposit_address`. Use the same pair in `update_balance` to credit the correct account. +- **ckSOL**: pass as the `subaccount` field in `get_deposit_address`. Use the same pair in `process_deposit`. ## Common pitfalls @@ -577,53 +502,32 @@ The minter uses `(owner, subaccount)` to determine the Bitcoin address. When a d **Omitting the owner in `get_btc_address`.** If you omit `owner`, the minter uses the caller's principal (your canister principal), not the end user's principal. The resulting deposit address will credit your canister's default account rather than the user's subaccount. -**Transfer fee pitfall.** The fee is deducted from the sender's account on top of the amount. If a user has exactly 1,000 satoshis and you transfer 1,000, the transfer fails with `InsufficientFunds`. Transfer `balance - fee` to send the full balance. +**Transfer fee pitfall.** The fee is deducted from the sender's account on top of the amount. If a user has exactly 1,000 satoshis and you transfer 1,000, the transfer fails with `InsufficientFunds`. Transfer `balance - fee` to send the full balance. Always query `icrc1_fee` at runtime rather than hardcoding. Each ledger uses its native unit: ckBTC uses satoshis (1 BTC = 100,000,000 satoshis), ckETH uses wei (1 ETH = 10¹⁸ wei), ckDOGE uses koinu (1 DOGE = 100,000,000 koinu). **Subaccount must be exactly 32 bytes.** Passing a shorter or longer subaccount causes a trap in the minter. Always pad to 32 bytes. +**Depositing an unsupported ERC-20 token.** The ckETH helper contract does not enforce a token whitelist: funds sent for an unsupported token are lost. Always verify support via `get_minter_info` before any transfer. + +**Using an outdated ckETH helper contract address.** The helper contract address can change when the minter is upgraded. Always verify the current address via `get_minter_info` on the ckETH minter, checking `deposit_with_subaccount_helper_contract_address`. + ## Checking balances via CLI +`icrc1_balance_of` works on any chain-key token ledger. Use the ckBTC ledger as an example: + ```bash -# ckBTC balance icp canister call mxzaz-hqaaa-aaaar-qaada-cai icrc1_balance_of \ '(record { owner = principal "YOUR-PRINCIPAL"; subaccount = null })' \ - -e ic - -# ckETH balance -icp canister call ss2fx-dyaaa-aaaar-qacoq-cai icrc1_balance_of \ - '(record { owner = principal "YOUR-PRINCIPAL"; subaccount = null })' \ - -e ic - -# ckBTC deposit address (calls the minter) -icp canister call mqygn-kiaaa-aaaar-qaadq-cai get_btc_address \ - '(record { owner = opt principal "YOUR-PRINCIPAL"; subaccount = null })' \ - -e ic - -# Check for new BTC deposits (calls the minter) -icp canister call mqygn-kiaaa-aaaar-qaadq-cai update_balance \ - '(record { owner = opt principal "YOUR-PRINCIPAL"; subaccount = null })' \ - -e ic + -n ic ``` -## ckBTC vs native Bitcoin integration - -Chain-key tokens and native chain integration serve different use cases: - -| | ckBTC | Native Bitcoin | -|-|-------|----------------| -| Settlement | 1–2 seconds | Minutes (Bitcoin confirmations) | -| Use case | Token transfers, DeFi, payments | Direct UTXO access, custom signing | -| Custody | Minter canister | Your canister directly | -| Fee | 10 satoshis per ckBTC transfer | Bitcoin network fees | - -If you need direct control over Bitcoin UTXOs or want to construct custom Bitcoin transactions, see [Bitcoin integration](../chain-fusion/bitcoin.md). If you need fast, low-fee token transfers within ICP apps, ckBTC is the simpler choice. +For canister IDs for all other chain-key tokens, see [Chain-Key Token Canister IDs](../../reference/chain-key-canister-ids.md). ## Next steps -- [Token ledgers](token-ledgers.md): ICRC-1/ICRC-2 transfer patterns for all tokens, including ckBTC and ckETH +- [Ledgers](ledgers.md): transfer and manage digital assets, including all chain-key tokens - [Bitcoin integration](../chain-fusion/bitcoin.md): native BTC UTXO access and threshold signing - [Ethereum integration](../chain-fusion/ethereum.md): calling Ethereum contracts from ICP canisters -- [Wallet integration](wallet-integration.md): connecting wallets for token flows -- [Token standards](../../reference/token-standards.md): ICRC-1 and ICRC-2 formal specifications +- [Wallet integration](wallet-integration.md): add wallet signing to your app +- [Digital Asset Standards](../../reference/digital-asset-standards.md): formal ICRC standard specifications for fungible assets, NFTs, and their extensions -{/* Upstream: informed by dfinity/icskills skills/ckbtc/SKILL.md; dfinity/icskills skills/icrc-ledger/SKILL.md; dfinity/portal docs/defi/chain-key-tokens/cketh/overview.mdx */} +{/* Upstream: informed by dfinity/icskills skills/ckbtc/SKILL.md; dfinity/icskills skills/icrc-ledger/SKILL.md; dfinity/portal docs/defi/chain-key-tokens/cketh/overview.mdx; dfinity/ic rs/ethereum/cketh/docs/cketh.adoc; dfinity/ic rs/ethereum/cketh/docs/ckerc20.adoc; dfinity/ic rs/bitcoin/ckbtc (ckBTC minter API); dfinity/ic rs/dogecoin/ckdoge (ckDOGE minter API and canister IDs); dfinity/cksol (ckSOL minter API and canister IDs) */} diff --git a/docs/guides/digital-assets/token-ledgers.mdx b/docs/guides/digital-assets/ledgers.mdx similarity index 76% rename from docs/guides/digital-assets/token-ledgers.mdx rename to docs/guides/digital-assets/ledgers.mdx index 323eccf9..5358bf41 100644 --- a/docs/guides/digital-assets/token-ledgers.mdx +++ b/docs/guides/digital-assets/ledgers.mdx @@ -1,39 +1,29 @@ --- -title: "Token Ledgers" -description: "Transfer ICP and ICRC-1/ICRC-2 tokens from canisters and frontends" +title: "Ledgers" +description: "Transfer ICP and ICRC-1/ICRC-2 assets from canisters and frontends" sidebar: order: 1 --- import { Tabs, TabItem } from '@astrojs/starlight/components'; -Every token on ICP (ICP, ckBTC, ckETH, and custom tokens) is managed by a **ledger canister** that implements the ICRC token standards. Because all ledgers share the same interface, code that works with the ICP ledger also works with ckBTC, ckETH, or any ICRC-1 compliant token. You only need to swap the canister ID and fee. +Digital assets on ICP are managed by **ledger canisters** that implement the [ICRC digital asset standards](../../reference/digital-asset-standards.md). The ICP ledger is fully ICRC-1 and ICRC-2 compliant: code that works with the ICP ledger works identically with ckBTC, ckETH, or any ICRC-1 compatible asset. You only need to swap the canister ID and fee. The ICRC specifications use the term "token" throughout their text. -This guide covers the most common token operations: transfers, approvals, subaccounts, and local test ledger setup. For the formal standard specifications, see [Token standards](../../reference/token-standards.md). +Each ledger is paired with an **index canister** that continuously syncs the ledger's blocks and provides efficient per-account transaction history queries. Together they form the **ledger suite**. -## Well-known token ledgers +This guide covers the most common operations: transfers, approvals, subaccounts, transaction history, and local test ledger setup. -The table below lists a few well-known ledgers used throughout this guide. Many more tokens exist on ICP: see the [ICP Dashboard token list](https://dashboard.internetcomputer.org/tokens) for a broader overview. Anyone can deploy an ICRC-1 compliant ledger. +## Well-known ledgers -| Token | Ledger canister ID | -|-------|-------------------| -| ICP | `ryjl3-tyaaa-aaaaa-aaaba-cai` | -| ckBTC | `mxzaz-hqaaa-aaaar-qaada-cai` | -| ckETH | `ss2fx-dyaaa-aaaar-qacoq-cai` | +| Asset | Ledger canister ID | Index canister ID | +|-------|-------------------|------------------| +| ICP | `ryjl3-tyaaa-aaaaa-aaaba-cai` | `qhbym-qaaaa-aaaaa-aaafq-cai` | > Query `icrc1_fee` and `icrc1_decimals` at runtime rather than hardcoding values. -Index canisters (for transaction history): +For chain-key token canister IDs (ckBTC, ckETH, ckDOGE, ckSOL, and ckERC20), see [Chain-Key Token Canister IDs](../../reference/chain-key-canister-ids.md). For chain-key token specifics (minting, deposits, withdrawals), see [Chain-key tokens](chain-key-tokens.md). -| Token | Index canister ID | -|-------|------------------| -| ICP | `qhbym-qaaaa-aaaaa-aaafq-cai` | -| ckBTC | `n5wcd-faaaa-aaaar-qaaea-cai` | -| ckETH | `s3zol-vqaaa-aaaar-qacpa-cai` | - -All of these ledgers are ICRC-1 and ICRC-2 compatible. For chain-key token specifics (minting, deposits, withdrawals), see [Chain-key tokens](chain-key-tokens.md). - -## Transferring tokens (ICRC-1) +## Transferring assets (ICRC-1) The `icrc1_transfer` function sends tokens from the calling canister's account to a destination account. Every ICRC-1 ledger uses the same `Account` type: @@ -179,15 +169,23 @@ For frontend token operations, use the `@icp-sdk/canisters` package. See the [JS Always set the `fee` field explicitly. If you pass a fee that does not match the ledger's current fee, the call returns a `BadFee` error with the `expected_fee` value. You can query the current fee at runtime: ```bash -icp canister call ryjl3-tyaaa-aaaaa-aaaba-cai icrc1_fee '()' -e ic +icp canister call ryjl3-tyaaa-aaaaa-aaaba-cai icrc1_fee '()' -n ic ``` Always set `created_at_time` to enable deduplication. Without it, two identical transfers submitted within 24 hours both execute. -### Checking balances +## Checking balances Query an account's balance with `icrc1_balance_of`. This is a query call: fast and free. +```bash +icp canister call ryjl3-tyaaa-aaaaa-aaaba-cai icrc1_balance_of \ + '(record { owner = principal "YOUR-PRINCIPAL"; subaccount = null })' \ + -n ic +``` + +Replace `ryjl3-tyaaa-aaaaa-aaaba-cai` with the ledger canister ID for any ICRC-1 compatible asset. + @@ -234,9 +232,9 @@ async fn get_balance(ledger: Principal, owner: Principal) -> Result ## Approve and transfer-from (ICRC-2) -ICRC-2 adds an approve/transferFrom pattern, similar to ERC-20 on Ethereum. The token owner first approves a spender for a certain amount, then the spender calls `icrc2_transfer_from` to move tokens. This is a two-step flow: calling `transfer_from` without a prior approval fails with `InsufficientAllowance`. +ICRC-2 adds an approve/transferFrom pattern. The asset owner first approves a spender for a certain amount, then the spender calls `icrc2_transfer_from` to move assets. This is a two-step flow: calling `transfer_from` without a prior approval fails with `InsufficientAllowance`. -**When to use:** DEX swaps, payment processors, subscription services, or any case where a canister needs to pull tokens from a user's account. +**When to use:** Exchange logic, payment processing, subscription services, or any case where a canister needs to pull assets from a user's account. @@ -471,26 +469,27 @@ fn deposit_account(canister: Principal, user: Principal) -> Account { A typical deposit flow: 1. Generate a unique deposit subaccount for each user (derived from their principal). -2. The user transfers tokens to your canister's subaccount address. +2. The user transfers assets to your canister's subaccount address. 3. Your canister checks the subaccount balance and credits the user internally. -4. Your canister sweeps tokens from the subaccount to its default account. +4. Your canister sweeps assets from the subaccount to its default account. + +## Transaction history -## NFTs (ICRC-7 and ICRC-37) +Each ledger is paired with an index canister that syncs blocks continuously from the ledger and builds a per-account index. This is the standard way for canisters to query transaction history without scanning the full block log. -ICRC-7 is the non-fungible token standard on ICP. It follows the same account model as ICRC-1 and defines operations for NFT collections: querying ownership, metadata, and transferring individual tokens by ID. +Query an account's transaction history using `get_account_transactions` on the index canister: -ICRC-37 extends ICRC-7 with an approval workflow (similar to how ICRC-2 extends ICRC-1). It adds `approve`, `revoke_approval`, and `transfer_from` for NFTs. +```bash +icp canister call qhbym-qaaaa-aaaaa-aaafq-cai get_account_transactions \ + '(record { account = record { owner = principal "YOUR-PRINCIPAL" }; max_results = 10 : nat })' \ + -n ic +``` -Key operations: +The response includes a `transactions` list and the account's current `balance` at the tip. Paginate backwards using the `start` field (the oldest block index from the previous response). -- **`icrc7_transfer`**: transfer one or more NFTs by token ID -- **`icrc7_balance_of`**: count how many NFTs an account owns -- **`icrc7_owner_of`**: look up the owner of specific token IDs -- **`icrc7_tokens_of`**: list token IDs owned by an account -- **`icrc37_approve_tokens`**: approve a spender for specific NFTs (ICRC-37) -- **`icrc37_transfer_from`**: transfer NFTs using a prior approval (ICRC-37) +**ICRC-3** is the standard that defines how ledgers expose their block structure: the block schema, archive model, and `icrc3_get_blocks` method. It is why index canisters, Rosetta nodes, and custom indexers can all read the same block data in a consistent, verifiable format. All system ledgers on ICP implement ICRC-3. See [ICRC-3: Transaction log](../../reference/digital-asset-standards.md#icrc-3-transaction-log) for the block schema and method signatures. -For a complete working example with minting, transferring, and a frontend, see the [nft-creator example](https://github.com/dfinity/examples/tree/master/motoko/nft-creator). For the full standard specifications, see [ICRC-7](https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-7/ICRC-7.md) and [ICRC-37](https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-37/ICRC-37.md). +For client-side indexing across multiple ICRC-1 ledgers (exchange integrations, custody platforms, analytics), use the [Rosetta API](rosetta.md). The ICRC Rosetta implementation supports querying balances and transaction history across any number of ICRC-1 compatible ledgers simultaneously. ## Local test ledger @@ -562,9 +561,11 @@ icp canister call icrc1_ledger icrc1_transfer \ ## Next steps -- [Token standards](../../reference/token-standards.md): formal ICRC-1, ICRC-2, ICRC-7, and ICRC-37 specifications -- [Chain-key tokens](chain-key-tokens.md): working with ckBTC and ckETH (minting, deposits, withdrawals) +- [Digital Asset Standards](../../reference/digital-asset-standards.md): ICRC-1, ICRC-2, ICRC-3, ICRC-7, and ICRC-37 specifications including NFT standards +- [Chain-Key Token Canister IDs](../../reference/chain-key-canister-ids.md): mainnet and testnet canister IDs for all chain-key tokens +- [Chain-key tokens](chain-key-tokens.md): minting, depositing, and withdrawing ckBTC, ckETH, ckDOGE, and ckSOL +- [Rosetta API](rosetta.md): client-side indexing and transaction construction for exchanges and custody platforms - [Wallet integration](wallet-integration.md): connecting wallets to your app -- [Inter-canister calls](../canister-calls/inter-canister-calls.md): how inter-canister calls work (ledger calls are inter-canister calls) +- [Inter-canister calls](../canister-calls/inter-canister-calls.md): how canister-to-canister calls work, for example when the index canister reads blocks from the ledger -{/* Upstream: informed by dfinity/portal docs/defi/token-standards/, docs/defi/token-integrations/: icrc-1.mdx, icrc-2.mdx, icrc-7.mdx, icrc-37.mdx; dfinity/icskills skills/icrc-ledger/SKILL.md; dfinity/examples motoko/nft-creator */} +{/* Upstream: informed by dfinity/portal docs/defi/token-standards/, docs/defi/token-integrations/: icrc-1.mdx, icrc-2.mdx, icrc-7.mdx, icrc-37.mdx; dfinity/portal docs/defi/token-indexes/index.mdx (index canister / get_account_transactions); dfinity/portal docs/defi/rosetta/icrc_rosetta/index.mdx (ICRC Rosetta); dfinity/icskills skills/icrc-ledger/SKILL.md */} diff --git a/docs/guides/digital-assets/rosetta.md b/docs/guides/digital-assets/rosetta.md index 0b881dba..93aa4afc 100644 --- a/docs/guides/digital-assets/rosetta.md +++ b/docs/guides/digital-assets/rosetta.md @@ -509,7 +509,7 @@ Each directory includes a `requirements.txt` and a `run_tests.sh` script for iso ## Next steps -- [Token ledgers](token-ledgers.mdx): interact directly with ICP and ICRC-1 ledgers from canister code -- [Token standards](../../reference/token-standards.md): ICRC-1 and ICRC-2 specifications +- [Ledgers](ledgers.md): transfer and manage assets directly from canister code +- [Digital Asset Standards](../../reference/digital-asset-standards.md): formal ICRC standard specifications for fungible assets, NFTs, and their extensions diff --git a/docs/guides/digital-assets/wallet-integration.md b/docs/guides/digital-assets/wallet-integration.md index ebf589ff..54d9dec1 100644 --- a/docs/guides/digital-assets/wallet-integration.md +++ b/docs/guides/digital-assets/wallet-integration.md @@ -24,17 +24,7 @@ Use Internet Identity for login. Use a wallet signer when your app needs users t ## ICRC signer standards -The signer model is defined by a set of ICRC standards: - -| Standard | What it covers | -|---|---| -| ICRC-21 | Canister call consent messages: human-readable summaries | -| ICRC-25 | Signer interaction standard: permission lifecycle | -| ICRC-27 | Accounts: requesting the user's principal | -| ICRC-29 | Window PostMessage transport: popup communication | -| ICRC-49 | Call canister: routing calls through the signer | - -A compliant wallet (such as [OISY](https://oisy.com)) implements all five standards. +The signer model is defined by five ICRC standards (ICRC-21, 25, 27, 29, and 49) covering consent messages, permissions, account discovery, and canister call routing. For details on each, see [Wallet signer standards](../../reference/icrc-standards.md#wallet-signer-standards). A compliant wallet such as [OISY](https://oisy.com) implements all five. ## How it works @@ -251,7 +241,7 @@ Both libraries are expected to move to the `@icp-sdk` namespace on npm and will ## Next steps - [Internet Identity integration](../authentication/internet-identity.md): add authentication alongside wallet signing -- [Token ledgers](token-ledgers.md): work with ICRC-1 and ICRC-2 token standards -- [Token standards reference](../../reference/token-standards.md): ICRC-1, ICRC-2, and related standards +- [Ledgers](ledgers.md): transfer and manage assets with ledgers that implement digital asset standards +- [Digital Asset Standards](../../reference/digital-asset-standards.md): formal ICRC specifications for fungible assets, NFTs, and their extensions diff --git a/docs/guides/index.md b/docs/guides/index.md index c75f3518..ff1a2f49 100644 --- a/docs/guides/index.md +++ b/docs/guides/index.md @@ -7,23 +7,23 @@ sidebar: Practical how-to guides organized by development stage. Each guide solves a specific task with working code. -- **[AI Coding Agents](ai-coding-agents.md)**: Use ICP skills to give AI coding agents accurate canister IDs, tested code patterns, and ICP-specific context. +- **[AI Coding Agents](ai-coding-agents.md)**: Use ICP skills to give AI coding agents accurate canister IDs and tested code patterns. ## Build -- **[Backends](backends/data-persistence.md)**: Data persistence, HTTPS outcalls, timers, randomness, and other backend patterns. -- **[Canister Calls](canister-calls/candid.md)**: Candid interfaces, binding generation, onchain and offchain calling patterns. -- **[Frontends](frontends/asset-canister.md)**: Asset canisters, frontend frameworks, custom domains, and response certification. -- **[Authentication](authentication/internet-identity.md)**: Internet Identity, verifiable credentials, and wallet integration. +- **[Backends](backends/data-persistence.md)**: Persist data, make HTTPS outcalls, schedule timers, and generate randomness. +- **[Canister Calls](canister-calls/candid.md)**: Define Candid interfaces, generate type-safe bindings, and call canisters from backends and frontends. +- **[Frontends](frontends/asset-canister.md)**: Serve assets, integrate frontend frameworks, configure custom domains, and certify responses. +- **[Authentication](authentication/internet-identity.md)**: Add passwordless login and verifiable user identity to your app. ## Quality and shipping -- **[Testing](testing/strategies.md)**: Unit testing, integration testing with PocketIC, and end-to-end strategies. -- **[Canister Management](canister-management/lifecycle.md)**: Create, upgrade, configure, optimize, fund, deploy, and back up canisters. -- **[Security](security/access-management.md)**: Access control, encryption, data integrity, DoS prevention, and safe upgrades. +- **[Testing](testing/strategies.md)**: Write unit tests, run integration tests with PocketIC, and set up end-to-end testing. +- **[Canister Management](canister-management/lifecycle.md)**: Deploy, upgrade, fund, optimize, and back up canisters. +- **[Security](security/access-management.md)**: Implement access control, encryption, DoS prevention, and safe upgrade patterns. ## Advanced features -- **[Chain Fusion](chain-fusion/bitcoin.md)**: Native Bitcoin, Ethereum, Solana, and Dogecoin integration. -- **[Digital Assets](digital-assets/token-ledgers.md)**: Token ledgers, chain-key tokens, and the Rosetta API. -- **[Governance](governance/launching.md)**: Launch and manage an SNS DAO for your app. +- **[Digital Assets](digital-assets/ledgers.md)**: Create and integrate with ledgers and wallets using digital asset standards. +- **[Chain Fusion](chain-fusion/bitcoin.md)**: Connect canisters to Bitcoin, Ethereum, and Solana and sign cross-chain transactions. +- **[Governance](governance/launching.md)**: Transfer control of your app to your community and govern it through proposals. diff --git a/docs/reference/application-canisters.md b/docs/reference/application-canisters.md index 5bc65fee..86401afe 100644 --- a/docs/reference/application-canisters.md +++ b/docs/reference/application-canisters.md @@ -196,7 +196,7 @@ The SNS ledger implements ICRC-1, ICRC-2, and ICRC-3. The key methods are the sa | `icrc2_transfer_from` | Transfer on behalf of an approver | | `icrc3_get_blocks` | Query transaction history (ICRC-3 transaction log) | -For token standard details, see [Token Standards](token-standards.md). +For ICRC interface details, see [Digital Asset Standards](digital-asset-standards.md). ### Querying SNS canister IDs at runtime diff --git a/docs/reference/candid-spec.md b/docs/reference/candid-spec.md index 1d59428f..a37c8aa7 100644 --- a/docs/reference/candid-spec.md +++ b/docs/reference/candid-spec.md @@ -2,7 +2,7 @@ title: "Candid Type Reference" description: "Complete reference for all Candid types: syntax, subtyping rules, and Motoko, Rust and JavaScript mappings" sidebar: - order: 11 + order: 13 --- This document provides detailed reference information about Candid-supported types and links to the Candid specification and documentation for the Candid Rust crate. diff --git a/docs/reference/chain-key-canister-ids.md b/docs/reference/chain-key-canister-ids.md new file mode 100644 index 00000000..f30a3215 --- /dev/null +++ b/docs/reference/chain-key-canister-ids.md @@ -0,0 +1,125 @@ +--- +title: "Chain-Key Token Canister IDs" +description: "Mainnet and testnet canister IDs for all chain-key tokens: ckBTC, ckETH, ckERC20, ckDOGE, and ckSOL" +sidebar: + order: 7 +--- + +Canister IDs for all chain-key tokens. For deposit and withdrawal flows, see [Chain-key tokens](../guides/digital-assets/chain-key-tokens.md). + +- [Mainnet chain-key tokens](https://dashboard.internetcomputer.org/tokens?token_type=chain_key) — live overview including market data +- [Testnet chain-key tokens](https://dashboard.internetcomputer.org/tokens?token_type=chain_key&network=testnet) — testnet tokens deployed on ICP mainnet + +> Always query `icrc1_fee` and `icrc1_decimals` at runtime. Fees and decimal precision are set per ledger and can change. + +## ckBTC + +### Mainnet + +| Canister | ID | +|----------|----| +| Ledger | `mxzaz-hqaaa-aaaar-qaada-cai` | +| Minter | `mqygn-kiaaa-aaaar-qaadq-cai` | +| Index | `n5wcd-faaaa-aaaar-qaaea-cai` | +| Checker | `oltsj-fqaaa-aaaar-qal5q-cai` | + +The checker canister monitors KYT (know your transaction) compliance and is called internally by the minter on deposit. + +### Testnet (Bitcoin Testnet4) + +| Canister | ID | +|----------|----| +| Ledger | `mc6ru-gyaaa-aaaar-qaaaq-cai` | +| Minter | `ml52i-qqaaa-aaaar-qaaba-cai` | +| Index | `mm444-5iaaa-aaaar-qaabq-cai` | + +Use the Testnet4 canisters for integration testing. The ckBTC minter connects to the Bitcoin testnet4 network, so you need real testnet4 BTC (available from faucets). + +## ckETH + +### Mainnet + +| Canister | ID | +|----------|----| +| Ledger | `ss2fx-dyaaa-aaaar-qacoq-cai` | +| Minter | `sv3dd-oaaaa-aaaar-qacoa-cai` | +| Index | `s3zol-vqaaa-aaaar-qacpa-cai` | + +The ckETH minter also handles all ckERC20 tokens. To get the current Ethereum helper contract address, call `get_minter_info` on the minter and read `deposit_with_subaccount_helper_contract_address`. Always verify this before constructing an Ethereum deposit transaction. + +### Testnet (Ethereum Sepolia) + +| Canister | ID | +|----------|----| +| Ledger (ckTestETH) | `apia6-jaaaa-aaaar-qabma-cai` | +| Minter | `jzenf-aiaaa-aaaar-qaa7q-cai` | + +The Sepolia testnet minter connects to Ethereum Sepolia. Use ckTestETH for integration testing without spending real ETH. + +## ckERC20 + +ckERC20 tokens share the ckETH minter. Each token has its own ledger canister. For the authoritative current list, query the minter at runtime — new tokens are added via NNS governance and the table below may lag. + +### Mainnet + +Query the mainnet minter: + +```bash +icp canister call sv3dd-oaaaa-aaaar-qacoa-cai get_minter_info '()' -n ic +``` + +ckERC20 ledger canister IDs on mainnet: + +| Asset | Ledger | ERC-20 contract | +|-------|--------|-----------------| +| ckUSDC | `xevnm-gaaaa-aaaar-qafnq-cai` | `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` | +| ckUSDT | `cngnf-vqaaa-aaaar-qag4q-cai` | `0xdAC17F958D2ee523a2206206994597C13D831ec7` | +| ckEURC | `pe5t5-diaaa-aaaar-qahwa-cai` | `0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c` | +| ckWBTC | `bptq2-faaaa-aaaar-qagxq-cai` | `0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599` | +| ckWSTETH | `j2tuh-yqaaa-aaaar-qahcq-cai` | `0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0` | +| ckLINK | `g4tto-rqaaa-aaaar-qageq-cai` | `0x514910771AF9Ca656af840dff83E8264EcF986CA` | +| ckUNI | `ilzky-ayaaa-aaaar-qahha-cai` | `0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984` | +| ckSHIB | `fxffn-xiaaa-aaaar-qagoa-cai` | `0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE` | +| ckPEPE | `etik7-oiaaa-aaaar-qagia-cai` | `0x6982508145454Ce325dDbE47a25d4ec3d2311933` | +| ckXAUT | `nza5v-qaaaa-aaaar-qahzq-cai` | `0x68749665FF8D2d112Fa859AA293F07A622782F38` | +| ckOCT | `ebo5g-cyaaa-aaaar-qagla-cai` | `0xF5cFBC74057C610c8EF151A439252680AC68c6DC` | + +### Testnet (Ethereum Sepolia) + +Query the Sepolia minter: + +```bash +icp canister call jzenf-aiaaa-aaaar-qaa7q-cai get_minter_info '()' -n ic +``` + +| Asset | Ledger | Sepolia ERC-20 contract | +|-------|--------|------------------------| +| ckSepoliaUSDC | `yfumr-cyaaa-aaaar-qaela-cai` | `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238` | +| ckSepoliaLINK | `r52mc-qaaaa-aaaar-qafzq-cai` | `0x779877A7B0D9E8603169DdbD7836e478b4624789` | +| ckSepoliaPEPE | `hw4ru-taaaa-aaaar-qagdq-cai` | `0x560eF9F39E4B08f9693987cad307f6FBfd97B2F6` | + +## ckDOGE + +### Mainnet + +| Canister | ID | +|----------|----| +| Minter | `eqltq-xqaaa-aaaar-qb3vq-cai` | +| Ledger | `efmc5-wyaaa-aaaar-qb3wa-cai` | +| Index | `ecnej-3aaaa-aaaar-qb3wq-cai` | + +The ckDOGE minter follows the same UTXO-based pattern as ckBTC. Source: [dfinity/ic rs/dogecoin/ckdoge](https://github.com/dfinity/ic/tree/master/rs/dogecoin/ckdoge). + +## ckSOL + +### Mainnet + +| Canister | ID | +|----------|----| +| Minter | `lh22c-kyaaa-aaaar-qb5nq-cai` | +| Ledger | `ls5lp-lqaaa-aaaar-qb5oa-cai` | +| Index | `2ezyf-hqaaa-aaaar-qb6ga-cai` | + +Source: [dfinity/cksol](https://github.com/dfinity/cksol). + + diff --git a/docs/reference/cycles-costs.md b/docs/reference/cycles-costs.md index 20026752..24aa7d93 100644 --- a/docs/reference/cycles-costs.md +++ b/docs/reference/cycles-costs.md @@ -2,7 +2,7 @@ title: "Cycles Costs" description: "Exact cycle costs for compute, storage, HTTPS outcalls, signing, and canister operations" sidebar: - order: 5 + order: 8 --- Canisters pay for the resources they consume and operations they perform using [**cycles**](../concepts/cycles.md). The price of cycles is pegged to [XDR](glossary.md) (Special Drawing Rights): **1 trillion cycles = 1 XDR**. As of May 22, 2025, 1 XDR ≈ $1.35 USD: this rate fluctuates; see the [IMF's XDR exchange data](https://www.imf.org/external/np/fin/data/rms_sdrv.aspx) for the current rate. diff --git a/docs/reference/token-standards.md b/docs/reference/digital-asset-standards.md similarity index 84% rename from docs/reference/token-standards.md rename to docs/reference/digital-asset-standards.md index e3792b07..39673902 100644 --- a/docs/reference/token-standards.md +++ b/docs/reference/digital-asset-standards.md @@ -1,13 +1,11 @@ --- -title: "Token Standards" -description: "ICRC-1 fungible tokens, ICRC-2 approval, ICRC-3 transaction log, and ICRC-7 NFTs" +title: "Digital Asset Standards" +description: "ICP's ICRC standards for fungible assets, NFTs, and their extension protocols" sidebar: - order: 7 + order: 6 --- -ICP uses the ICRC standard family for tokens and token-related operations. This page covers the token standards (ICRC-1 through ICRC-37) and wallet signer standards (ICRC-21 through ICRC-49) that developers need to build financial applications, wallets, and token integrations. - -ICRC stands for Internet Computer Request for Comments. Standards are proposed by the [ICRC working group](https://github.com/dfinity/ICRC), refined through community consensus, and adopted or rejected through NNS governance proposals. +ICP implements digital assets using the ICRC standard family. The specifications use the term "token" throughout: a fungible digital asset is a "fungible token" in ICRC-1, and an NFT is a "non-fungible token" in ICRC-7. This page covers the digital asset standards (ICRC-1 through ICRC-37). For the full list of ICRC standards including wallet signer protocols, see [ICRC Standards](icrc-standards.md). ## Standards overview @@ -18,11 +16,6 @@ ICRC stands for Internet Computer Request for Comments. Standards are proposed b | [ICRC-3](#icrc-3-transaction-log) | Transaction log and block archive | ICRC-1 | Adopted | | [ICRC-7](#icrc-7-non-fungible-tokens) | Non-fungible token (NFT) base standard | none | Adopted | | [ICRC-37](#icrc-37-nft-approvals) | Approve and transfer-from for NFTs | ICRC-7 | Adopted | -| [ICRC-21](#wallet-signer-standards) | Canister call consent messages | none | Adopted | -| [ICRC-25](#wallet-signer-standards) | Signer interaction (permissions) | none | Adopted | -| [ICRC-27](#wallet-signer-standards) | Account discovery | none | Adopted | -| [ICRC-29](#wallet-signer-standards) | Window PostMessage transport | none | Adopted | -| [ICRC-49](#wallet-signer-standards) | Call canister via signer | none | Adopted | ## ICRC-1: Fungible tokens @@ -100,7 +93,7 @@ type TransferError = variant { | `icrc1:decimals` | `Nat` | `8` | | `icrc1:fee` | `Nat` | `10000` | -For a few well-known ledger canister IDs and index canisters, see [Token ledgers](../guides/digital-assets/token-ledgers.md#well-known-token-ledgers). For a broader overview of tokens on ICP, see the [ICP Dashboard token list](https://dashboard.internetcomputer.org/tokens). +For a few well-known ledger canister IDs and index canisters, see [Ledgers](../guides/digital-assets/ledgers.md#well-known-token-ledgers). For a broader overview of tokens on ICP, see the [ICP Dashboard token list](https://dashboard.internetcomputer.org/tokens). [Read the full ICRC-1 standard](https://github.com/dfinity/ICRC-1/tree/main/standards/ICRC-1) @@ -324,27 +317,12 @@ A ledger that implements ICRC-37 must also implement all ICRC-7 methods. Support [Read the full ICRC-37 standard](https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-37/ICRC-37.md) -## Wallet signer standards - -The ICRC signer standards define how wallets interact with apps on ICP. They use a popup-based model where every action requires explicit user approval, communicated via JSON-RPC 2.0 over `window.postMessage`. - -| Standard | Purpose | -|----------|---------| -| **ICRC-21** | Canister call consent messages: enables canisters to provide human-readable descriptions of what a call will do, displayed to the user before signing | -| **ICRC-25** | Signer interaction standard: defines the permission lifecycle (`granted`, `denied`, `ask_on_use`) for signer methods | -| **ICRC-27** | Account discovery: allows apps to request the list of accounts available in the wallet | -| **ICRC-29** | Window PostMessage transport: defines the communication channel between app and signer using `window.postMessage` | -| **ICRC-49** | Call canister: allows apps to request the signer to execute a canister call on behalf of the user | - -These standards are distinct from delegation-based authentication (such as Internet Identity). The signer model requires per-action user approval and does not create sessions or delegated identities. - -For implementation details and code examples, see the [wallet integration guide](../guides/digital-assets/wallet-integration.md). - ## Next steps -- [Token ledgers guide](../guides/digital-assets/token-ledgers.md): deploy and interact with ICRC-1/ICRC-2 ledgers +- [ICRC Standards](icrc-standards.md): full index of all ICRC standards including wallet signer protocols +- [Ledgers guide](../guides/digital-assets/ledgers.md): deploy and interact with ICRC-1/ICRC-2 ledger canisters - [Chain-key tokens guide](../guides/digital-assets/chain-key-tokens.md): work with ckBTC, ckETH, and other chain-key tokens -- [Wallet integration guide](../guides/digital-assets/wallet-integration.md): integrate wallet signer standards into your app +- [Wallet integration guide](../guides/digital-assets/wallet-integration.md): implement wallet signer standards (ICRC-21/25/27/29/49) in your app - [ICRC-1 standard specification](https://github.com/dfinity/ICRC-1/tree/main/standards/ICRC-1): full specification on GitHub - [ICRC-7 standard specification](https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-7/ICRC-7.md): full NFT specification on GitHub diff --git a/docs/reference/execution-errors.md b/docs/reference/execution-errors.md index 0a41d291..60f5360b 100644 --- a/docs/reference/execution-errors.md +++ b/docs/reference/execution-errors.md @@ -2,7 +2,7 @@ title: "Execution Errors" description: "Reference for canister execution errors on ICP: causes, example messages, and how to fix each error." sidebar: - order: 8 + order: 10 --- A reference for errors returned when executing canisters on ICP. Each entry includes the error message, what causes it, and how to fix it. diff --git a/docs/reference/glossary.md b/docs/reference/glossary.md index d10b4de7..5ee2a459 100644 --- a/docs/reference/glossary.md +++ b/docs/reference/glossary.md @@ -2,7 +2,7 @@ title: "Glossary" description: "Definitions of ICP-specific terms: canister, cycle, principal, subnet, and more" sidebar: - order: 13 + order: 15 --- # Glossary diff --git a/docs/reference/http-gateway-spec.md b/docs/reference/http-gateway-spec.md index 57016051..5ef9047d 100644 --- a/docs/reference/http-gateway-spec.md +++ b/docs/reference/http-gateway-spec.md @@ -2,7 +2,7 @@ title: "HTTP Gateway Protocol Specification" description: "The HTTP Gateway Protocol specification: how HTTP clients interact with the Internet Computer through canister-served HTTP responses" sidebar: - order: 10 + order: 12 --- ## Introduction diff --git a/docs/reference/ic-interface-spec.md b/docs/reference/ic-interface-spec.md index c79fb1c8..4180c8b7 100644 --- a/docs/reference/ic-interface-spec.md +++ b/docs/reference/ic-interface-spec.md @@ -2,7 +2,7 @@ title: "IC Interface Specification" description: "The authoritative formal specification of the Internet Computer's external interfaces: System API, HTTPS interface, certified data, management canister, and abstract behavior" sidebar: - order: 9 + order: 11 --- diff --git a/docs/reference/icrc-standards.md b/docs/reference/icrc-standards.md new file mode 100644 index 00000000..d03dc5c7 --- /dev/null +++ b/docs/reference/icrc-standards.md @@ -0,0 +1,45 @@ +--- +title: "ICRC Standards" +description: "Index of all adopted ICRC standards on ICP, grouped by category" +sidebar: + order: 5 +--- + +ICRC stands for Internet Computer Request for Comments. Standards are proposed by the [ICRC working group](https://github.com/dfinity/ICRC), refined through community consensus, and adopted or rejected through NNS governance proposals. + +## Digital asset standards + +Standards for fungible assets, NFTs, and their extension protocols. + +| Standard | Purpose | Extends | Status | +|----------|---------|---------|--------| +| [ICRC-1](digital-asset-standards.md#icrc-1-fungible-tokens) | Fungible token base standard | none | Adopted | +| [ICRC-2](digital-asset-standards.md#icrc-2-approve-and-transfer-from) | Approve and transfer-from | ICRC-1 | Adopted | +| [ICRC-3](digital-asset-standards.md#icrc-3-transaction-log) | Transaction log and block archive | ICRC-1 | Adopted | +| [ICRC-7](digital-asset-standards.md#icrc-7-non-fungible-tokens) | Non-fungible token (NFT) base standard | none | Adopted | +| [ICRC-37](digital-asset-standards.md#icrc-37-nft-approvals) | Approve and transfer-from for NFTs | ICRC-7 | Adopted | + +For full method signatures, Candid types, and implementation details, see [Digital Asset Standards](digital-asset-standards.md). + +## Wallet signer standards + +Standards for wallet and signer interactions between apps and user accounts. + +| Standard | Purpose | Status | +|----------|---------|--------| +| [ICRC-21](https://github.com/dfinity/wg-identity-authentication/blob/main/topics/ICRC-21/icrc_21_consent_msg.md) | Canister call consent messages | Adopted | +| [ICRC-25](https://github.com/dfinity/wg-identity-authentication/blob/main/topics/icrc_25_signer_interaction_standard.md) | Signer interaction (permissions) | Adopted | +| [ICRC-27](https://github.com/dfinity/wg-identity-authentication/blob/main/topics/icrc_27_accounts.md) | Account discovery | Adopted | +| [ICRC-29](https://github.com/dfinity/wg-identity-authentication/blob/main/topics/icrc_29_window_post_message_transport.md) | Window PostMessage transport | Adopted | +| [ICRC-49](https://github.com/dfinity/wg-identity-authentication/blob/main/topics/icrc_49_call_canister.md) | Call canister via signer | Adopted | + +For implementation details and code examples, see the [wallet integration guide](../guides/digital-assets/wallet-integration.md). + +## Next steps + +- [Digital Asset Standards](digital-asset-standards.md): complete method signatures, Candid types, and error definitions for each standard +- [Ledgers](../guides/digital-assets/ledgers.md): transfer assets and set up local test ledgers +- [Wallet integration](../guides/digital-assets/wallet-integration.md): add wallet signing to your app +- [ICRC working group](https://github.com/dfinity/ICRC): browse proposed and in-progress standards + + diff --git a/docs/reference/index.md b/docs/reference/index.md index a05ac4a4..9043f34f 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -20,7 +20,9 @@ Technical reference material for ICP development. These pages cover exact specif ## Tokens and costs -- **[Token Standards](token-standards.md)**: ICRC-1 fungible tokens, ICRC-2 approval, ICRC-3 transaction log, and ICRC-7 NFTs. +- **[ICRC Standards](icrc-standards.md)**: Index of all adopted ICRC standards grouped by category. +- **[Digital Asset Standards](digital-asset-standards.md)**: ICRC-1, ICRC-2, ICRC-3, ICRC-7, and ICRC-37 in full detail. +- **[Chain-Key Token Canister IDs](chain-key-canister-ids.md)**: Mainnet and testnet canister IDs for ckBTC, ckETH, ckERC20, ckDOGE, and ckSOL. - **[Cycles Costs](cycles-costs.md)**: Exact cycle costs for compute, storage, HTTPS outcalls, signing, and canister operations. - **[Subnet Types](subnet-types.md)**: All subnet types with node counts, replication factors, and cycle cost multipliers. diff --git a/docs/reference/internet-identity-spec.md b/docs/reference/internet-identity-spec.md index 7d76e599..590985ea 100644 --- a/docs/reference/internet-identity-spec.md +++ b/docs/reference/internet-identity-spec.md @@ -2,7 +2,7 @@ title: "Internet Identity Specification" description: "The Internet Identity specification: identity design, client authentication protocol, delegation chain, and backend Candid interface" sidebar: - order: 12 + order: 14 --- ## Introduction diff --git a/docs/reference/protocol-canisters.md b/docs/reference/protocol-canisters.md index 1ff4de18..165ed532 100644 --- a/docs/reference/protocol-canisters.md +++ b/docs/reference/protocol-canisters.md @@ -1,12 +1,14 @@ --- title: "Protocol Canisters" -description: "Bitcoin canister, ckBTC minter, ckETH minter, EVM RPC canister, exchange rate canister, and other protocol-level canisters with their canister IDs and interfaces" +description: "Bitcoin canister, ckBTC minter, ckETH minter, EVM RPC canister, exchange rate canister, and other protocol-level canisters with their APIs and Candid interfaces" sidebar: order: 3 --- Protocol canisters implement platform-level features on the Internet Computer. Unlike [system canisters](system-canisters.md), which govern the network itself, protocol canisters provide infrastructure that applications build on: Bitcoin integration, Ethereum integration, chain-key tokens, and exchange rates. They are controlled by the NNS and run on dedicated system subnets. +For all chain-key token canister IDs (ledger, minter, index), see [Chain-Key Token Canister IDs](chain-key-canister-ids.md). For deposit, withdrawal, and transfer flows, see [Chain-key tokens](../guides/digital-assets/chain-key-tokens.md). + ## Bitcoin canisters The Bitcoin integration canisters connect ICP to the Bitcoin network. They track the Bitcoin UTXO set and expose an API that other canisters use to read Bitcoin state and submit transactions. @@ -31,8 +33,6 @@ The Bitcoin integration canisters connect ICP to the Bitcoin network. They track ### Key endpoints -The Bitcoin canisters expose endpoints for reading UTXOs, balances, and block headers, and for submitting transactions. These mirror the management canister Bitcoin API: - - `bitcoin_get_utxos`: returns UTXOs for a Bitcoin address - `bitcoin_get_balance`: returns the balance of a Bitcoin address in satoshi - `bitcoin_send_transaction`: submits a signed Bitcoin transaction @@ -41,92 +41,105 @@ The Bitcoin canisters expose endpoints for reading UTXOs, balances, and block he For integration patterns, see the [Bitcoin guide](../guides/chain-fusion/bitcoin.md). -## ckBTC canisters +## ckBTC minter -Chain-key Bitcoin (ckBTC) is a 1:1 BTC-backed ICRC-2 token native to ICP. The ckBTC minter holds real BTC and mints or burns ckBTC tokens. Transfers settle in seconds with a 10 satoshi fee. +The ckBTC minter holds real BTC in a threshold ECDSA-controlled wallet and mints or burns ckBTC tokens. It issues a unique Bitcoin deposit address per `(owner, subaccount)` account and handles withdrawal requests by submitting signed Bitcoin transactions. -### Mainnet canister IDs +For canister IDs, see [Chain-Key Token Canister IDs — ckBTC](chain-key-canister-ids.md#ckbtc). -| Canister | ID | -|---|---| -| ckBTC Ledger | [`mxzaz-hqaaa-aaaar-qaada-cai`](https://dashboard.internetcomputer.org/canister/mxzaz-hqaaa-aaaar-qaada-cai) | -| ckBTC Minter | [`mqygn-kiaaa-aaaar-qaadq-cai`](https://dashboard.internetcomputer.org/canister/mqygn-kiaaa-aaaar-qaadq-cai) | -| ckBTC Index | [`n5wcd-faaaa-aaaar-qaaea-cai`](https://dashboard.internetcomputer.org/canister/n5wcd-faaaa-aaaar-qaaea-cai) | - -### Bitcoin Testnet4 canister IDs - -| Canister | ID | -|---|---| -| ckBTC Ledger (testnet4) | [`mc6ru-gyaaa-aaaar-qaaaq-cai`](https://dashboard.internetcomputer.org/canister/mc6ru-gyaaa-aaaar-qaaaq-cai) | -| ckBTC Minter (testnet4) | [`ml52i-qqaaa-aaaar-qaaba-cai`](https://dashboard.internetcomputer.org/canister/ml52i-qqaaa-aaaar-qaaba-cai) | -| ckBTC Index (testnet4) | [`mm444-5iaaa-aaaar-qaabq-cai`](https://dashboard.internetcomputer.org/canister/mm444-5iaaa-aaaar-qaabq-cai) | - -### ckBTC minter configuration - -The ckBTC minter has the following key parameters: +### Minter parameters | Parameter | Value | Description | |---|---|---| -| `retrieve_btc_min_amount` | 50,000 satoshi (0.0005 BTC) | Minimum amount for BTC withdrawal | -| `max_time_in_queue_nanos` | 10 minutes | Maximum time a retrieval request can wait in the queue | -| `min_confirmations` | 6 | Bitcoin confirmations required before minting ckBTC | -| `kyt_fee` | 100 satoshi | Fee for know-your-token (KYT) checks | +| `retrieve_btc_min_amount` | 50,000 satoshi | Minimum amount for BTC withdrawal | +| `max_time_in_queue_nanos` | 10 minutes | Maximum time a retrieval request waits | +| `min_confirmations` | 6 | Bitcoin confirmations required before minting | +| `kyt_fee` | 100 satoshi | Fee for know-your-transaction (KYT) check | -### ckBTC minter endpoints +### Minter endpoints - `get_btc_address(owner, subaccount)`: returns a unique Bitcoin deposit address for the given principal and subaccount -- `get_known_utxos(owner, subaccount)`: returns UTXOs already processed by the minter for the given account -- `update_balance(owner, subaccount)`: checks for new UTXOs and mints ckBTC for any newly confirmed deposits +- `update_balance(owner, subaccount)`: checks for newly confirmed UTXOs and mints ckBTC +- `get_known_utxos(owner, subaccount)`: returns UTXOs already processed for the given account - `estimate_withdrawal_fee(amount)`: estimates the fee for retrieving a given BTC amount -- `get_deposit_fee`: returns the current fee charged when minting ckBTC (currently the KYT fee) -- `retrieve_btc_with_approval(address, amount, from_subaccount)`: burns ckBTC (using an ICRC-2 approval) and sends the equivalent BTC to the given Bitcoin address -- `retrieve_btc(address, amount)`: alternative withdrawal flow that requires transferring ckBTC to the minter's withdrawal account first; prefer `retrieve_btc_with_approval` for new integrations -- `get_withdrawal_account`: returns the caller's withdrawal account for use with `retrieve_btc` +- `get_deposit_fee`: returns the current fee charged when minting ckBTC (the KYT fee) +- `retrieve_btc_with_approval(address, amount, from_subaccount)`: burns ckBTC via ICRC-2 approval and sends BTC to the given Bitcoin address - `retrieve_btc_status_v2(block_index)`: returns the status of a previous withdrawal request - `retrieve_btc_status_v2_by_account(account)`: returns statuses for all recent withdrawal requests from the given account - `get_minter_info`: returns current minter parameters -- `get_events(start, length)`: returns the minter's internal event log (for debugging) +- `get_events(start, length)`: returns the minter's internal event log -### Deposit and withdrawal flows +### KYT checker -**Deposit (BTC to ckBTC):** -1. Call `get_btc_address` with the user's principal and subaccount to get a unique Bitcoin deposit address. -2. The user sends BTC to that address. -3. After 6 confirmations, call `update_balance` to trigger minting. The minter credits the ICRC-1 account corresponding to the provided principal and subaccount. +The ckBTC checker canister (`oltsj-fqaaa-aaaar-qal5q-cai`) performs know-your-transaction compliance checks on incoming Bitcoin UTXOs. It is called internally by the minter on deposit and is not part of the developer-facing API. -**Withdrawal (ckBTC to BTC):** -1. Call `icrc2_approve` on the ckBTC ledger to grant the minter allowance. -2. Call `retrieve_btc_with_approval` with the destination Bitcoin address and amount. -3. The minter burns the ckBTC and submits a Bitcoin transaction. BTC arrives after Bitcoin confirmations. +## ckETH minter -For integration examples, see the [Bitcoin guide](../guides/chain-fusion/bitcoin.md). +The ckETH minter bridges ETH and all ERC-20 tokens between Ethereum and ICP. It monitors the ckETH helper contract on Ethereum via HTTPS outcalls to detect deposits, and submits signed Ethereum transactions for withdrawals using threshold ECDSA. -## ckETH canisters +For canister IDs, see [Chain-Key Token Canister IDs — ckETH](chain-key-canister-ids.md#cketh). -Chain-key Ethereum (ckETH) is an ICRC-2 token backed 1:1 by ETH. The ckETH minter bridges between ETH on Ethereum mainnet and ckETH on ICP using HTTPS outcalls and threshold ECDSA. +### Helper contract -### Mainnet canister IDs +The minter uses a helper smart contract on Ethereum to receive deposits for both ETH and ERC-20 tokens. Always verify the current address before constructing a deposit transaction: -| Canister | ID | -|---|---| -| ckETH Ledger | [`ss2fx-dyaaa-aaaar-qacoq-cai`](https://dashboard.internetcomputer.org/canister/ss2fx-dyaaa-aaaar-qacoq-cai) | -| ckETH Minter | [`sv3dd-oaaaa-aaaar-qacoa-cai`](https://dashboard.internetcomputer.org/canister/sv3dd-oaaaa-aaaar-qacoa-cai) | -| ckETH Index | [`s3zol-vqaaa-aaaar-qacpa-cai`](https://dashboard.internetcomputer.org/canister/s3zol-vqaaa-aaaar-qacpa-cai) | +```bash +icp canister call sv3dd-oaaaa-aaaar-qacoa-cai get_minter_info '()' -n ic +``` -### How it works +Check `deposit_with_subaccount_helper_contract_address` in the response. -**Deposit (ETH to ckETH):** -1. The user calls the `deposit` function on the ckETH helper contract on Ethereum, with ETH attached and the destination ICP principal as an argument. -2. The ckETH minter periodically fetches logs from the helper contract via multiple Ethereum JSON-RPC providers. For each `ReceivedEth` event, it mints the corresponding ckETH to the receiver's account on the ckETH ledger. +### Minter endpoints -**Withdrawal (ckETH to ETH):** -1. The user calls `icrc2_approve` on the ckETH ledger to grant the minter allowance. -2. The user calls `withdraw_eth` on the ckETH minter with a destination Ethereum address. -3. The minter burns the ckETH, creates an Ethereum transaction, and submits it to the Ethereum network. +- `get_minter_info`: returns current minter info including the helper contract address and `supported_ckerc20_tokens` +- `withdraw_eth(address, amount)`: burns ckETH or ckERC20 and submits an Ethereum withdrawal transaction; used for both ETH and all ERC-20 withdrawals +- `get_canister_status`: returns the minter's current status -The ckETH ledger follows the ICRC-1/ICRC-2 standard. Interact with it using the same patterns as any ICRC-1 ledger. +## ckERC20 ledgers -For integration examples, see the [Ethereum guide](../guides/chain-fusion/ethereum.md). +ckERC20 tokens share the ckETH minter. Each ERC-20 token has its own ICRC-1 ledger canister. New tokens are added via NNS governance proposals. + +To get the authoritative current list of supported tokens and their ledger canister IDs at runtime: + +```bash +icp canister call sv3dd-oaaaa-aaaar-qacoa-cai get_minter_info '()' -n ic +``` + +Check `supported_ckerc20_tokens` in the response. For a static reference table, see [Chain-Key Token Canister IDs — ckERC20](chain-key-canister-ids.md#ckerc20). + +## ckDOGE minter + +The ckDOGE minter follows the same UTXO-based model as ckBTC. It holds real DOGE in a threshold ECDSA-controlled wallet and issues a unique Dogecoin deposit address per `(owner, subaccount)` account. + +For canister IDs, see [Chain-Key Token Canister IDs — ckDOGE](chain-key-canister-ids.md#ckdoge). + +### Minter endpoints + +- `get_deposit_address(owner, subaccount)`: returns a unique Dogecoin deposit address for the given principal and subaccount +- `update_balance(owner, subaccount)`: checks for newly confirmed UTXOs and mints ckDOGE +- `retrieve_doge_with_approval(address, amount, from_subaccount)`: burns ckDOGE via ICRC-2 approval and sends DOGE to the given Dogecoin address +- `get_minter_info`: returns current minter parameters + +Amounts are denominated in koinu (1 DOGE = 100,000,000 koinu). + +Source: [dfinity/ic — rs/dogecoin/ckdoge](https://github.com/dfinity/ic/tree/master/rs/dogecoin/ckdoge) + +## ckSOL minter + +The ckSOL minter bridges SOL between Solana and ICP. It issues a unique Solana deposit address per `(owner, subaccount)` account and verifies deposits via the SOL RPC canister using threshold signatures (Ed25519). + +For canister IDs, see [Chain-Key Token Canister IDs — ckSOL](chain-key-canister-ids.md#cksol). + +### Minter endpoints + +- `get_deposit_address(owner, subaccount)`: returns a unique Solana deposit address for the given principal and subaccount +- `process_deposit(tx_signature, owner, subaccount)`: verifies a Solana deposit transaction and mints ckSOL; requires cycles to cover RPC verification +- `withdraw(address, amount)`: burns ckSOL via ICRC-2 approval and signs a Solana transaction using threshold Ed25519 +- `withdrawal_status(burn_block_index)`: returns the status of a pending withdrawal + +Amounts are denominated in lamports (1 SOL = 1,000,000,000 lamports). + +Source: [dfinity/cksol](https://github.com/dfinity/cksol) ## EVM RPC canister @@ -252,7 +265,7 @@ icp canister call uf6dk-hyaaa-aaaaq-qaaaq-cai get_exchange_rate \ base_asset = record { symbol = "BTC"; class = variant { Cryptocurrency } }; quote_asset = record { symbol = "USD"; class = variant { FiatCurrency } }; })' \ - -e ic + -n ic ``` ## SNS-W canister @@ -274,21 +287,24 @@ For governance context, see the [SNS documentation](https://learn.internetcomput |---|---|---| | Bitcoin mainnet | `ghsi2-tqaaa-aaaan-aaaca-cai` | Bitcoin mainnet UTXO tracking | | Bitcoin testnet (v4) | `g4xu7-jiaaa-aaaan-aaaaq-cai` | Bitcoin testnet UTXO tracking | -| ckBTC Ledger | `mxzaz-hqaaa-aaaar-qaada-cai` | ckBTC ICRC-1/ICRC-2 token ledger | | ckBTC Minter | `mqygn-kiaaa-aaaar-qaadq-cai` | BTC ↔ ckBTC minting and burning | -| ckBTC Index | `n5wcd-faaaa-aaaar-qaaea-cai` | ckBTC transaction index | -| ckETH Ledger | `ss2fx-dyaaa-aaaar-qacoq-cai` | ckETH ICRC-1/ICRC-2 token ledger | -| ckETH Minter | `sv3dd-oaaaa-aaaar-qacoa-cai` | ETH ↔ ckETH minting and burning | -| ckETH Index | `s3zol-vqaaa-aaaar-qacpa-cai` | ckETH transaction index | +| ckBTC KYT Checker | `oltsj-fqaaa-aaaar-qal5q-cai` | Know-your-transaction compliance | +| ckETH Minter | `sv3dd-oaaaa-aaaar-qacoa-cai` | ETH and ERC-20 ↔ ckETH/ckERC20 minting and burning | +| ckDOGE Minter | `eqltq-xqaaa-aaaar-qb3vq-cai` | DOGE ↔ ckDOGE minting and burning | +| ckSOL Minter | `lh22c-kyaaa-aaaar-qb5nq-cai` | SOL ↔ ckSOL minting and burning | | EVM RPC | `7hfb6-caaaa-aaaar-qadga-cai` | Ethereum JSON-RPC proxy | | Exchange Rate (XRC) | `uf6dk-hyaaa-aaaaq-qaaaq-cai` | Crypto and forex exchange rates | | SNS-W | `qaa6y-5yaaa-aaaaa-aaafa-cai` | SNS deployment and upgrades | +For ledger, index, and testnet canister IDs for all chain-key tokens, see [Chain-Key Token Canister IDs](chain-key-canister-ids.md). + ## Next steps +- [Chain-Key Token Canister IDs](chain-key-canister-ids.md): ledger, minter, and index IDs for all chain-key tokens +- [Chain-key tokens](../guides/digital-assets/chain-key-tokens.md): deposit, withdrawal, and transfer flows for all chain-key tokens - [Bitcoin guide](../guides/chain-fusion/bitcoin.md): integrating Bitcoin in canisters using the Bitcoin canister and ckBTC - [Ethereum guide](../guides/chain-fusion/ethereum.md): integrating Ethereum in canisters using the EVM RPC canister and ckETH - [System canisters](system-canisters.md): NNS canisters, Internet Identity, ICP ledger, and other network-level canisters - [Management canister](management-canister.md): the virtual canister for canister lifecycle, signing, and platform APIs - + diff --git a/docs/reference/subnet-types.md b/docs/reference/subnet-types.md index de8d3880..19bd867a 100644 --- a/docs/reference/subnet-types.md +++ b/docs/reference/subnet-types.md @@ -2,7 +2,7 @@ title: "Subnet Types Reference" description: "All subnet types with node counts, replication factors, and cost multipliers" sidebar: - order: 6 + order: 9 --- The Internet Computer is composed of independent [**subnets**](../concepts/network-overview.md#subnets): each an autonomous blockchain that hosts a set of canisters. Subnets differ in node count, replication factor, costs, geographic distribution, and what canisters they accept. This page lists all subnet types and their properties. diff --git a/docs/reference/system-canisters.md b/docs/reference/system-canisters.md index be1a1ba9..e6000847 100644 --- a/docs/reference/system-canisters.md +++ b/docs/reference/system-canisters.md @@ -133,7 +133,7 @@ Key methods: The ICP ledger archives historical transactions across multiple archive canisters to keep its own state manageable. See [ICP ledger archives](#icp-ledger-archives) below. -For token standards and ICRC interface details, see [Token Standards](token-standards.md). +For ICRC interface details, see [Digital Asset Standards](digital-asset-standards.md). ## ICP ledger archives diff --git a/sidebar.mjs b/sidebar.mjs index 1b9f90db..dfb92661 100644 --- a/sidebar.mjs +++ b/sidebar.mjs @@ -57,14 +57,14 @@ export const sidebar = [ }, // Advanced features { - label: "Chain Fusion", + label: "Digital Assets", collapsed: true, - autogenerate: { directory: "guides/chain-fusion" }, + autogenerate: { directory: "guides/digital-assets" }, }, { - label: "Digital Assets", + label: "Chain Fusion", collapsed: true, - autogenerate: { directory: "guides/digital-assets" }, + autogenerate: { directory: "guides/chain-fusion" }, }, { label: "Governance", From b6f4a4af8d21d993c44e7ba959991e1eef327398 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Mon, 27 Apr 2026 19:29:27 +0200 Subject: [PATCH 2/2] fix(validation): replace em-dashes in chain-key-canister-ids and protocol-canisters --- docs/reference/chain-key-canister-ids.md | 6 +++--- docs/reference/protocol-canisters.md | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/reference/chain-key-canister-ids.md b/docs/reference/chain-key-canister-ids.md index f30a3215..7cdf4747 100644 --- a/docs/reference/chain-key-canister-ids.md +++ b/docs/reference/chain-key-canister-ids.md @@ -7,8 +7,8 @@ sidebar: Canister IDs for all chain-key tokens. For deposit and withdrawal flows, see [Chain-key tokens](../guides/digital-assets/chain-key-tokens.md). -- [Mainnet chain-key tokens](https://dashboard.internetcomputer.org/tokens?token_type=chain_key) — live overview including market data -- [Testnet chain-key tokens](https://dashboard.internetcomputer.org/tokens?token_type=chain_key&network=testnet) — testnet tokens deployed on ICP mainnet +- [Mainnet chain-key tokens](https://dashboard.internetcomputer.org/tokens?token_type=chain_key): live overview including market data +- [Testnet chain-key tokens](https://dashboard.internetcomputer.org/tokens?token_type=chain_key&network=testnet): testnet tokens deployed on ICP mainnet > Always query `icrc1_fee` and `icrc1_decimals` at runtime. Fees and decimal precision are set per ledger and can change. @@ -58,7 +58,7 @@ The Sepolia testnet minter connects to Ethereum Sepolia. Use ckTestETH for integ ## ckERC20 -ckERC20 tokens share the ckETH minter. Each token has its own ledger canister. For the authoritative current list, query the minter at runtime — new tokens are added via NNS governance and the table below may lag. +ckERC20 tokens share the ckETH minter. Each token has its own ledger canister. For the authoritative current list, query the minter at runtime; new tokens are added via NNS governance and the table below may lag. ### Mainnet diff --git a/docs/reference/protocol-canisters.md b/docs/reference/protocol-canisters.md index 165ed532..d786752c 100644 --- a/docs/reference/protocol-canisters.md +++ b/docs/reference/protocol-canisters.md @@ -45,7 +45,7 @@ For integration patterns, see the [Bitcoin guide](../guides/chain-fusion/bitcoin The ckBTC minter holds real BTC in a threshold ECDSA-controlled wallet and mints or burns ckBTC tokens. It issues a unique Bitcoin deposit address per `(owner, subaccount)` account and handles withdrawal requests by submitting signed Bitcoin transactions. -For canister IDs, see [Chain-Key Token Canister IDs — ckBTC](chain-key-canister-ids.md#ckbtc). +For canister IDs, see [Chain-Key Token Canister IDs: ckBTC](chain-key-canister-ids.md#ckbtc). ### Minter parameters @@ -77,7 +77,7 @@ The ckBTC checker canister (`oltsj-fqaaa-aaaar-qal5q-cai`) performs know-your-tr The ckETH minter bridges ETH and all ERC-20 tokens between Ethereum and ICP. It monitors the ckETH helper contract on Ethereum via HTTPS outcalls to detect deposits, and submits signed Ethereum transactions for withdrawals using threshold ECDSA. -For canister IDs, see [Chain-Key Token Canister IDs — ckETH](chain-key-canister-ids.md#cketh). +For canister IDs, see [Chain-Key Token Canister IDs: ckETH](chain-key-canister-ids.md#cketh). ### Helper contract @@ -105,13 +105,13 @@ To get the authoritative current list of supported tokens and their ledger canis icp canister call sv3dd-oaaaa-aaaar-qacoa-cai get_minter_info '()' -n ic ``` -Check `supported_ckerc20_tokens` in the response. For a static reference table, see [Chain-Key Token Canister IDs — ckERC20](chain-key-canister-ids.md#ckerc20). +Check `supported_ckerc20_tokens` in the response. For a static reference table, see [Chain-Key Token Canister IDs: ckERC20](chain-key-canister-ids.md#ckerc20). ## ckDOGE minter The ckDOGE minter follows the same UTXO-based model as ckBTC. It holds real DOGE in a threshold ECDSA-controlled wallet and issues a unique Dogecoin deposit address per `(owner, subaccount)` account. -For canister IDs, see [Chain-Key Token Canister IDs — ckDOGE](chain-key-canister-ids.md#ckdoge). +For canister IDs, see [Chain-Key Token Canister IDs: ckDOGE](chain-key-canister-ids.md#ckdoge). ### Minter endpoints @@ -122,13 +122,13 @@ For canister IDs, see [Chain-Key Token Canister IDs — ckDOGE](chain-key-canist Amounts are denominated in koinu (1 DOGE = 100,000,000 koinu). -Source: [dfinity/ic — rs/dogecoin/ckdoge](https://github.com/dfinity/ic/tree/master/rs/dogecoin/ckdoge) +Source: [dfinity/ic rs/dogecoin/ckdoge](https://github.com/dfinity/ic/tree/master/rs/dogecoin/ckdoge) ## ckSOL minter The ckSOL minter bridges SOL between Solana and ICP. It issues a unique Solana deposit address per `(owner, subaccount)` account and verifies deposits via the SOL RPC canister using threshold signatures (Ed25519). -For canister IDs, see [Chain-Key Token Canister IDs — ckSOL](chain-key-canister-ids.md#cksol). +For canister IDs, see [Chain-Key Token Canister IDs: ckSOL](chain-key-canister-ids.md#cksol). ### Minter endpoints @@ -307,4 +307,4 @@ For ledger, index, and testnet canister IDs for all chain-key tokens, see [Chain - [System canisters](system-canisters.md): NNS canisters, Internet Identity, ICP ledger, and other network-level canisters - [Management canister](management-canister.md): the virtual canister for canister lifecycle, signing, and platform APIs - +