From 0c6dd919b1462475fd842853313adbff82a89717 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 29 Apr 2026 23:37:10 +0200 Subject: [PATCH 1/4] docs(chain-fusion): add flow diagrams and ckSOL/ckDOGE sections - bitcoin.mdx: add PlantUML sequence diagrams for ckBTC deposit and withdrawal flows - ethereum.mdx: add PlantUML sequence diagram for EVM RPC canister request flow - dogecoin.md: add ckDOGE section with deposit/withdrawal diagrams; mark ckDOGE as live - solana.mdx: add SOL RPC canister flow diagram; add ckSOL section with deposit/withdrawal diagrams; remove stale "No ckSOL token" limitation Source: dfinity/ic rs/bitcoin/ckbtc, rs/dogecoin/ckdoge, rs/ethereum/cketh; dfinity/cksol --- docs/guides/chain-fusion/bitcoin.mdx | 24 ++++++++++++ docs/guides/chain-fusion/dogecoin.md | 34 ++++++++++++++++- docs/guides/chain-fusion/ethereum.mdx | 18 +++++++++ docs/guides/chain-fusion/solana.mdx | 53 ++++++++++++++++++++++++++- 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/docs/guides/chain-fusion/bitcoin.mdx b/docs/guides/chain-fusion/bitcoin.mdx index 0697a375..a6a4f74e 100644 --- a/docs/guides/chain-fusion/bitcoin.mdx +++ b/docs/guides/chain-fusion/bitcoin.mdx @@ -31,6 +31,18 @@ ckBTC is the recommended path for most developers. The ckBTC minter canister hol ### Deposit flow (BTC to ckBTC) +```plantuml +actor User +participant "ckBTC Minter" as Minter +participant "Bitcoin Network" as BTC + +User -> Minter: get_btc_address(account) +Minter --> User: btc_address +User -> BTC: send BTC to btc_address +User -> Minter: update_balance(account) +Minter --> User: ckBTC minted to ICRC-1 account +``` + 1. Call `get_btc_address` on the minter with the user's principal and subaccount. This returns a unique Bitcoin address controlled by the minter. 2. The user sends BTC to that address using any Bitcoin wallet. 3. Wait for Bitcoin confirmations (the minter requires confirmations before minting). @@ -227,6 +239,18 @@ async fn transfer(to: Principal, amount: Nat) -> Result { ### Withdraw (ckBTC to BTC) +```plantuml +actor User +participant "ckBTC Ledger" as Ledger +participant "ckBTC Minter" as Minter +participant "Bitcoin Network" as BTC + +User -> Ledger: icrc2_approve(spender=minter, amount) +User -> Minter: retrieve_btc_with_approval(btc_address, amount) +Minter -> Ledger: icrc2_transfer_from(user, minter, amount) +Minter -> BTC: send BTC to btc_address +``` + Withdrawal is a two-step process: approve the minter to spend your ckBTC, then call `retrieve_btc_with_approval`. The minimum withdrawal is 50,000 satoshis (0.0005 BTC). diff --git a/docs/guides/chain-fusion/dogecoin.md b/docs/guides/chain-fusion/dogecoin.md index 16913cc2..d4507f30 100644 --- a/docs/guides/chain-fusion/dogecoin.md +++ b/docs/guides/chain-fusion/dogecoin.md @@ -132,7 +132,7 @@ The key differences in implementation: | | Bitcoin | Dogecoin | |---|---|---| | API | Management canister (`bitcoin_*` methods) | Dogecoin canister | -| Chain-key token | ckBTC (live) | ckDOGE (upcoming) | +| Chain-key token | ckBTC (live) | ckDOGE (live) | | Address prefix | `1`, `3`, `bc1` (mainnet) | `D` (mainnet) | | Unit | satoshi | koinu | | Status | Stable | Beta | @@ -143,6 +143,38 @@ Developers familiar with the Bitcoin integration will find the Dogecoin integrat The Dogecoin canister is controlled by the [Network Nervous System](../../concepts/governance.md). Any changes to the canister require an NNS proposal that the community must review and approve before taking effect. This means your canister can call the Dogecoin canister without additional trust assumptions beyond the NNS governance process itself. +## ckDOGE + +ckDOGE is a 1:1 DOGE-backed token on ICP. The ckDOGE minter holds real DOGE and mints or burns ckDOGE using the same ICRC-1/ICRC-2 interface as ckBTC. For canister IDs and CLI-based deposit and withdrawal flows, see [Chain-key tokens](../digital-assets/chain-key-tokens.md). + +### Deposit (DOGE to ckDOGE) + +```plantuml +actor User +participant "ckDOGE Minter" as Minter +participant "Dogecoin Network" as DOGE + +User -> Minter: get_doge_address(account) +Minter --> User: doge_address +User -> DOGE: send DOGE to doge_address +User -> Minter: update_balance(account) +Minter --> User: ckDOGE minted to ICRC-1 account +``` + +### Withdrawal (ckDOGE to DOGE) + +```plantuml +actor User +participant "ckDOGE Ledger" as Ledger +participant "ckDOGE Minter" as Minter +participant "Dogecoin Network" as DOGE + +User -> Ledger: icrc2_approve(spender=minter, amount) +User -> Minter: retrieve_doge_with_approval(doge_address, amount) +Minter -> Ledger: icrc2_transfer_from(user, minter, amount) +Minter -> DOGE: send DOGE to doge_address +``` + ## Next steps - [Chain fusion overview](../../concepts/chain-fusion.md): understand how ICP integrates with external blockchains diff --git a/docs/guides/chain-fusion/ethereum.mdx b/docs/guides/chain-fusion/ethereum.mdx index 8df5e15a..9014bda5 100644 --- a/docs/guides/chain-fusion/ethereum.mdx +++ b/docs/guides/chain-fusion/ethereum.mdx @@ -15,6 +15,24 @@ For a conceptual overview of how ICP connects to other blockchains, see [Chain F The EVM RPC canister (`7hfb6-caaaa-aaaar-qadga-cai`) is a system canister deployed on ICP's 34-node fiduciary subnet. When your canister calls it: +```plantuml +participant "Your Canister" as Canister +participant "EVM RPC Canister" as EVM +participant "Provider 1" as P1 +participant "Provider 2" as P2 +participant "Provider N" as PN + +Canister -> EVM: eth_getBlockByNumber(chain, args) + cycles +EVM -> P1: JSON-RPC (HTTPS outcall) +EVM -> P2: JSON-RPC (HTTPS outcall) +EVM -> PN: JSON-RPC (HTTPS outcall) +P1 --> EVM: response +P2 --> EVM: response +PN --> EVM: response +note right of EVM: consensus check (≥2/3 nodes agree) +EVM --> Canister: Consistent(result) + refund excess cycles +``` + 1. Your canister sends a request to the EVM RPC canister with cycles attached. 2. The EVM RPC canister fans the request out to multiple RPC providers via [HTTPS outcalls](../backends/https-outcalls.md). 3. Each provider's response goes through ICP subnet consensus (at least 2/3 of nodes must agree). diff --git a/docs/guides/chain-fusion/solana.mdx b/docs/guides/chain-fusion/solana.mdx index fa20a4cf..ad64fa5d 100644 --- a/docs/guides/chain-fusion/solana.mdx +++ b/docs/guides/chain-fusion/solana.mdx @@ -22,6 +22,18 @@ Two ICP features enable Solana integration: The SOL RPC canister (`2xib7-jqaaa-aaaar-qai6q-cai`) is deployed on ICP mainnet and handles Solana JSON-RPC calls on your behalf. When your canister calls it: +```plantuml +participant "Your Canister" as Canister +participant "SOL RPC Canister" as SolRpc +participant "Solana Providers" as Providers +participant "Solana" as SOL + +Canister -> SolRpc: request(json_rpc, max_response_bytes) + cycles +SolRpc -> Providers: HTTPS outcalls to multiple providers +Providers --> SolRpc: aggregated responses +SolRpc --> Canister: result + refund excess cycles +``` + 1. Your canister sends a JSON-RPC request with cycles attached. 2. The SOL RPC canister fans the request out to multiple Solana RPC providers via HTTPS outcalls. 3. Responses are aggregated. The canister returns the result once providers agree. @@ -328,6 +340,46 @@ Every SOL RPC call requires cycles to cover HTTPS outcall costs. The `sign_with_ Send 10B cycles per RPC call as a starting budget: unused cycles are refunded. Set `max_response_bytes` to the minimum needed; smaller values reduce costs. +## ckSOL + +ckSOL is a 1:1 SOL-backed token on ICP. The ckSOL minter holds real SOL via chain-key Ed25519 addresses and mints or burns ckSOL using the ICRC-1/ICRC-2 interface. For canister IDs and CLI-based deposit and withdrawal flows, see [Chain-key tokens](../digital-assets/chain-key-tokens.md). + +### Deposit (SOL to ckSOL) + +```plantuml +actor User +participant "ckSOL Minter" as Minter +participant "ckSOL Ledger" as Ledger +participant "SOL RPC Canister" as SolRpc +participant "Solana" as SOL + +User -> Minter: get_deposit_address(owner, subaccount) +Minter --> User: deposit_address +User -> SOL: transfer SOL to deposit_address +User -> Minter: process_deposit(owner, subaccount, tx_signature) +Minter -> SolRpc: fetch & verify transaction +Minter -> Ledger: mint ckSOL (amount - deposit_fee) +Minter --> User: Minted { block_index, minted_amount } +``` + +### Withdrawal (ckSOL to SOL) + +```plantuml +actor User +participant "ckSOL Minter" as Minter +participant "ckSOL Ledger" as Ledger +participant "Solana" as SOL + +User -> Ledger: icrc2_approve(spender=minter, amount) +User -> Minter: withdraw(sol_address, amount) +Minter -> Ledger: burn via icrc2_transfer_from(user, amount) +Minter --> User: burn_block_index +note right of Minter: processed asynchronously +Minter -> SOL: submit SOL transfer (chain-key Ed25519) +User -> Minter: withdrawal_status(burn_block_index) +Minter --> User: TxFinalized +``` + ## Current status and limitations The Solana integration is newer than the Bitcoin and Ethereum integrations: @@ -335,7 +387,6 @@ The Solana integration is newer than the Bitcoin and Ethereum integrations: - **SOL RPC canister is live on mainnet**: deployed and functional, with the API surface still evolving. - **Threshold Ed25519 is available**: both test (`test_key_1`) and production (`key_1`) keys are live on ICP mainnet. - **No SPL token helpers**: SPL token operations (reading token accounts, transferring tokens) require constructing JSON-RPC calls and transaction instructions manually. -- **No ckSOL token**: unlike Bitcoin (ckBTC) and Ethereum (ckETH), there is no chain-key SOL token yet. - **Transaction construction is manual**: there is no official ICP library for building Solana transactions. See the [basic_solana example](https://github.com/dfinity/sol-rpc-canister/tree/main/examples/basic_solana) for a reference implementation. Follow the [SOL RPC canister repository](https://github.com/dfinity/sol-rpc-canister/blob/main/README.md) for the latest updates. From b3f5d4514c312f9e0e4339994208a0f4f34d8d0c Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 29 Apr 2026 23:37:44 +0200 Subject: [PATCH 2/4] fix(dogecoin): remove status qualifiers from comparison table --- docs/guides/chain-fusion/dogecoin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/chain-fusion/dogecoin.md b/docs/guides/chain-fusion/dogecoin.md index d4507f30..125789f6 100644 --- a/docs/guides/chain-fusion/dogecoin.md +++ b/docs/guides/chain-fusion/dogecoin.md @@ -132,7 +132,7 @@ The key differences in implementation: | | Bitcoin | Dogecoin | |---|---|---| | API | Management canister (`bitcoin_*` methods) | Dogecoin canister | -| Chain-key token | ckBTC (live) | ckDOGE (live) | +| Chain-key token | ckBTC | ckDOGE | | Address prefix | `1`, `3`, `bc1` (mainnet) | `D` (mainnet) | | Unit | satoshi | koinu | | Status | Stable | Beta | From ad51c00799805b875400cc9292a4d611b2289575 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 29 Apr 2026 23:46:12 +0200 Subject: [PATCH 3/4] fix(bitcoin): capitalise Quickstart heading --- docs/guides/chain-fusion/bitcoin.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/chain-fusion/bitcoin.mdx b/docs/guides/chain-fusion/bitcoin.mdx index a6a4f74e..16eac75f 100644 --- a/docs/guides/chain-fusion/bitcoin.mdx +++ b/docs/guides/chain-fusion/bitcoin.mdx @@ -1044,7 +1044,7 @@ All Bitcoin API calls require cycles attached to the call. In Rust, the `ic-cdk- ## Development setup -### Quick start with the bitcoin-starter template +### Quickstart with the bitcoin-starter template The fastest way to get started is with the bitcoin-starter template: From 5af9a072d1f271f56a563abefa5aa221c68daeea Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 29 Apr 2026 23:56:03 +0200 Subject: [PATCH 4/4] infra(plantuml): inject ICP brand skin globally into all PlantUML diagrams Transparent background, terracotta arrows, parchment boxes, ink text. Applied centrally in the plugin so no per-page skinparam needed. --- plugins/remark-plantuml.mjs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/plugins/remark-plantuml.mjs b/plugins/remark-plantuml.mjs index 75398b6e..e75013a1 100644 --- a/plugins/remark-plantuml.mjs +++ b/plugins/remark-plantuml.mjs @@ -19,11 +19,30 @@ function encode(data) { return r; } +const SKIN = ` +skinparam backgroundColor transparent +skinparam defaultFontName sans-serif +skinparam defaultFontSize 13 +skinparam defaultFontColor #1a1714 +skinparam sequenceArrowThickness 1.5 +skinparam sequenceArrowColor #cc5a2b +skinparam SequenceLifeLineBorderColor #e5ddcf +skinparam ParticipantBackgroundColor #fdfaf3 +skinparam ParticipantBorderColor #e5ddcf +skinparam ParticipantFontColor #1a1714 +skinparam ActorBackgroundColor #fdfaf3 +skinparam ActorBorderColor #e5ddcf +skinparam ActorFontColor #1a1714 +skinparam NoteBackgroundColor #f2d7c7 +skinparam NoteBorderColor #e5ddcf +skinparam NoteFontColor #1a1714 +`; + function toUrl(source) { - const src = source.trimStart().startsWith("@startuml") + const body = source.trimStart().startsWith("@startuml") ? source - : `@startuml\n${source}\n@enduml`; - const compressed = deflateRawSync(Buffer.from(src, "utf-8"), { level: 9 }); + : `@startuml\n${SKIN}\n${source}\n@enduml`; + const compressed = deflateRawSync(Buffer.from(body, "utf-8"), { level: 9 }); return `${SERVER}/${encode(compressed)}`; }