diff --git a/docs/guides/chain-fusion/bitcoin.mdx b/docs/guides/chain-fusion/bitcoin.mdx index 0697a375..16eac75f 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). @@ -1020,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: diff --git a/docs/guides/chain-fusion/dogecoin.md b/docs/guides/chain-fusion/dogecoin.md index 16913cc2..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 (upcoming) | +| Chain-key token | ckBTC | ckDOGE | | 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. 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)}`; }