Custody Providers
This document is aimed at product owners and architects at custody providers and analytics/reporting firms (“Integrators”) who’d like to get an overview of the integration architecture required for supporting the ICP token and ICP network tokens following the ICRC standards (“ICRC tokens”).
Introduction to Internet Computer (ICP) Integrations
First, the canonical Introduction to ICP. BTW, we use “ICP” interchangeably for the protocol, the network and the token!
The TL;DR from ICP’s 3rd generation approach are:
- You don’t run a node to validate transactions block by block. Instead, you get the block(s) in question using https APIs and verify them using ICP’s 48 byte BLS master public key.
- BLS is only needed for chain validation, i.e. in online systems. Transaction signing requires ECDSA or Ed25519, at least one of which is available in every crypto HSM and MPC library.
- You don’t need an off-chain RPC node: ICP and ICRC token ledgers are ICP canisters (ICP’s name for smart contracts) and have https APIs as primary interface to read balance and transaction data and submit new transactions for broadcasting.
Additionally, Dfinity offers an open source implementation of Coinbase’s Rosetta API as a Docker container. It provides a simple interface to query ICP and ICRC token balances & transactions, as well as prepare and broadcast custody & staking transactions.
Cryptography
Transaction signing: ECDSA or Ed25519
Integrators that send requests to the Internet Computer authenticate the request via a digital signature on a 32-byte digest of the request. Currently supported signatures are vanilla Ed25519 and ECDSA (over secp256r1 and secp256k1) digital signature schemes. Either one can be used. In addition, authentication can also use WebAuth signatures (either ECDSA on secp256r1 or RSA PKCS#1v1.5, both using SHA-256).
Transaction verification: BLS
Integrators also need to support verification of BLS signatures to authenticate on-chain information such as balances, transactions. They are verifiable with the global master public key (chain key cryptography).
Rosetta takes care of this internally, i.e. integration with Rosetta does not require any BLS support.
Creating and Broadcasting Transactions
Valid transaction requests need to be signed and sent to the corresponding token ledger using the token ledger’s https API. There are libraries for Rust, C, Go, TypeScript, etc.
Rosetta API takes care of both transaction request creation and broadcasting.
Querying Balances and Transactions
Token ledgers on ICP create a new block for every transaction, the current practical limit of transactions per second per ledger is 400-600 tps.
Good to know for analytics & reporting use cases: ICP & ICRC Rosetta containers include a sqlite instance that stores all the relevant information for direct querying. Though, to be clear, that’s not a formally supported interface under the Rosetta standard.
Integration with Rosetta
DFINTY provides a Rosetta API docker image for integrators building on ICP. Rosetta is an open standard designed by Coinbase to simplify blockchain deployment and interaction; this allows integrators to spend less time on integration and more time on novel blockchain advancements.
Rosetta supports all the following use cases:
- Querying verified balances & transactions for ICP and ICRC tokens
- Creating transaction requests for ICP and ICRC token transfers
- Creating transaction requests for all steps of the ICP staking / voting workflow
- Broadcasting signed requests
Each token ledger requires its own Rosetta container for local data storage, i.e. integrators will deploy the ICP Rosetta container for ICP token support, and deploy the ICRC Rosetta container multiple times for supporting multiple ICRC tokens.
Compute, memory and storage requirements are minimal, as the heavy lifting computing happens on ICP, and Rosetta acts more like a light node. As of Q2 2024, the biggest container size is the ICP Rosetta container with about 10 GiB space required for the complete 3+ year history.
Native Integration
If using the Rosetta API is not feasible for whatever reason, then integrators interact with ICP or ICRC ledgers directly using their https API.
This requires familiarity with:
- Candid, the language used to specify the interfaces of smart contracts running on ICP
- API and execution model of ICP
- requests are submitted, and replies need to be polled
- different types of requests yield different levels of trust in the response
- API of the ICP ledger (in particular how to fetch and verify the transaction chain)
- API of the Governance smart contract (for implementing staking and staking related operations)
- The ICRC-1 and ICRC-3 standards to support ICRC tokens
There are libraries available from Dfinity for JavaScript/TypeScript (agent-js) and Rust (agent-rs) as well as third-party libraries for other languages incl. Java, C, C++ and Go.
Staking
ICP staking is similar to delegated PoS, but with some key differences:
- ICP staking rewards active voting instead of the typical block creation & validation activity. The factors influencing voting rewards are: staked amount, dissolve delay, age bonus, voting activity (the bigger the better)
- It doesn’t require a validator infrastructure because the voting process runs as a smart contract on ICP.
- Staking sends assets from a custody address to an address type called “neuron”, managed by the Network Nervous System dapp, NNS. The neuron continuous to be controlled by the same private key as the sending custody address (similar to ETH staking)
- Instead of actively voting on all proposals, a staker can delegate their vote to someone else’s neuron, this is called “following a neuron”
- The unlocking period (called “dissolve delay”) can be up to 8 years for maximum rewards. Note that during the last 6 months of the unlocking period, no more rewards will be paid out, meaning that the minimum viable dissolve delay is 6 months..
See the chart below for an overview of the main custody-related workflows
ICRC Token Standards
The ICRC-1 and ICRC-3 token standards were created to facilitate handling of tokens on ICP through a common interface, similar to ERC-20 on Ethereum. It is expected that, going forward, all tokens will support them.
ICP and ICRC tokens have close but not 100% API compatibility, which needs to be considered when using native integration. Another gotcha to consider when going from ICP to ICRC is that the ICP ledger uses a hashed representation of the principal, subaccount pair, while interactions with ICRC ledgers require and use the principal, subaccount pair in plaintext. (Although, to confuse things further, Dfinity’s dashboard block explorer uses the hashed representation also for ICRC token addresses).
Support and more detailed documentation
More detailed documentation is available throughout this Wiki. And the Rosetta API documentation is really a great resource for custody related ICP integrations. Even when not using the Rosetta API, its source code can be used as an example of how to go on about a native integration.
The Developer Forum is the place to get support at any time, and is also frequently visited by the Dfinity team members who supported Coinbase, Sygnum, Copper, Taurus and other custody related ICP-integrations in the past.