Ledger integration options
Developers have several options for integrating with the ICP or ICRC-1 ledgers. They can use either the ICP or ICRC Rosetta implementations, which is commonly recommended, although for some workflows, it might be beneficial to directly integrate with these ledgers instead. This section will describe what a direct integration means, how it can be achieved, and how it differs to using Rosetta.
Token architecture overview
Tokens on ICP are managed by smart contracts. The ICP ledger canister manages the list of balances for ICP tokens and implements methods for transferring tokens. It builds a chain of blocks consisting of all ICP token transactions since genesis. The chain is authenticated by having the ICP sign the tip of the chain. External parties can retrieve this chain and verify it is genuine by:
- Verifying the signature using the public key of ICP.
- Verifying that the blocks are properly chained such that each block contains the hash of the preceding block. Altering the chaining by some malicious party requires breaking the hash function.
Smart contract tokens other than ICP, e.g. ckBTC or CHAT, follow the ICRC suite of standards (ICRC-1, ICRC-2, etc) and can be integrated in a similar manner. For differences in detail, see below.
Transactions that are executed on ICP are reported on the dashboard under the transactions panel. This panel distinguishes between update and query calls. Transactions executed by the ICP ledger appear on the dashboard under the ICP tab.
The left side of the diagram above represents a subnet. The right is a schematic representation of the ICP ledger canister. The canister build maintains a blockchain of all ICP transactions. Each block in the chain holds one ICP transaction and the hash of the previous block.
Unlike the vast majority of other blockchains, completely validating token transactions on ICP does not require a full node. In fact, full nodes are not used for transaction validation. This is because transaction validation is done using ICP’s public key.
Types of integration
There are two ways to integrate with ICP tokens:
Direct integration: Requires an integration layer which interacts with ICP smart contracts via the ICP API.
Rosetta integration: Requires running an instance of a Rosetta node within the trust domain of an integrator.
Direct integration
For a direct integration, one needs to provide an integration layer which interacts with ICP smart contracts via the ICP API. This integration layer needs to call into the ICP ledger canister to issue and retrieve transactions. On ICP, submitting messages does not require running a node as all of the communication uses publicly available URLs and can be validated using the network's public key and chain-key cryptography. This type of integration requires familiarity with the ICP API and the ICP ledger API. There are API libraries for JavaScript/TypeScript, Rust, Java, C, C++, and Go.
Direct integration is supported by libraries for Rust and Typescript, but proficient use of these tools would require familiarity with the following concepts:
- The distinction between update calls and query calls.
- Reading the result of update calls.
- Deduplication guarantees of ICP.
- Ingress message lifecycle.
- How to verify the result of calls to canisters.
- API of the token canister(s) and their semantics.
- Deduplication guarantees by the ledger.
- How to fetch the token ledger and verify it is genuine.
- CBOR (Concise Binary Object Representation).
- Candid (ICP’s interface description language).
To implement a direct integration, you will need to:
Call a method of a canister: Calling canister methods is done by constructing a message that specifies the canister, the method, and its parameters, among other things, then submitting this message to the network.
Make a call to a canister: To interact with a canister on ICP, an ingress message is constructed. This message specifies the target canister, the method to be invoked, and the call's payload. Additional parameters include an ingress expiration time, an optional nonce, and the caller's principal identifier. The API of most canisters, including token ledgers, is defined using a Candid Interface Definition Language (IDL). Calls can be executed either replicated or non-replicated, depending on the endpoint where they are submitted.
Read the result of a replicated call: The outcome of a replicated call's execution is temporarily stored in the public ingress history of the respective subnet. To access the result, a read state request is submitted, including the previously generated request ID. Given the asynchronous nature of this execution, results must be actively polled. Results are maintained in the ingress history for a brief period (5 minutes post-execution). Therefore, canisters may provide alternative methods for result retrieval that access the canister's internal state directly, such as ledger canisters offering transaction history and balance book access.
Support and libraries
The Internet Computer supports interactions with ICP canisters through official JavaScript/TypeScript (agent-js) and Rust (agent-rs) libraries. Additionally, third-party libraries exist for other languages like Java, C, C++, and Go.
Ledger canister API
The API for ledger canisters is generally standardized, following the ICRC-1 standard for basic token transfers across the Internet Computer. All tokens adhering to this standard implement it. The ICRC-3 standard further elaborates on how to fetch and verify the authenticity of the transaction chain maintained by canisters, ensuring integrity and trustworthiness in transactions.
Rosetta node integration
The Rosetta node acts as a bridge between the Rosetta API specification by Coinbase and the Internet Computer Protocol (ICP), translating API calls to ICP requests. It is an abstraction layer that hides the ICP network and ledger canister APIs. Interaction with the Rosetta node follows the Rosetta API standard proposed and maintained by Coinbase.
The Rosetta node fetches and verifies the ICP token transaction chain and makes it available through the Rosetta API. It also permanently syncs with the ICP ledger by downloading and verifying the ICP token transaction ledger. It offers endpoints for searching transactions and blocks in the downloaded chain. This node also fetches and verifies ICP transaction chains, storing data in a SQL database that's accessible both through the Rosetta API and directly with SQL tools.
The Rosetta node can be run in a Docker container offering an HTTP REST API interface. It requires IPv6 connectivity, and minimal compute, RAM and disk requirements (10 GB disk space currently).
DFINITY does not operate Rosetta nodes for the ICP community, and as of now there are no known third party providers. The Rosetta node should run within the trust domain of an integrator.
The ICP Rosetta node consists of three main parts: integration with the ICP ledger, compliance with the Coinbase API, and a governance integration. It operates in two modes:
- Online mode: Interacts with the ICP for real-time operations like checking account balances and submitting transactions.
- Offline mode: Used for transaction signing without an internet connection, suitable for securely signing transactions with private keys from cold storage.