Skip to main content

2.3 Using third-party canisters

Intermediate
Tutorial

Overview

Third-party canisters are canisters that provide a public service at a static canister ID. Some examples are the DFINITY NNS and Internet Identity canisters, but third-party canisters can also be made by community developers. Using third-party canisters can be a good way to add additional functionalities to your dapp. For example, by integrating the Internet Identity canister into your dapp, you can enable identity and authentication for the users of your application.

dfx enables a dependency workflow, where a canister can be configured to pull third-party canisters that it depends on into the local environment. This can be useful for developers who are looking to test the accuracy of their integration with the third-party canister and perform tests without paying cycles or using production environments. It also drastically simplifies the local deployment of canisters like the II canister, since you don't need to obtain the Wasm and Candid files for the canisters yourself - dfx takes care of it in the background for you.

In this tutorial, you'll be focusing on pulling third-party canisters. If you're interested in developing third-party canisters that can be pulled by other developers, check out the documentation on dfx deps.

Pulling third-party canister dependencies

Let's take a look at a basic example of pulling a third-party canister as a dependency. To do this, you'll use the dfx deps command, which is the dfx subcommand responsible for pulling canisters that are listed as dependencies of another canister in the project's dfx.json file.

Prerequisites

Before you start, verify that you have set up your developer environment according to the instructions in 0.3 Developer environment setup.

Creating a new project

To get started, create a new project in your working directory. Open a terminal window, navigate into your working directory (developer_journey), then use the following commands to start dfx and create a new project:

Use dfx new <project_name> to create a new project:

dfx start --clean --background
dfx new dependencies

You will be prompted to select the language that your backend canister will use. Select 'Motoko':

? Select a backend language: ›
❯ Motoko
Rust
TypeScript (Azle)
Python (Kybra)

dfx versions v0.17.0 and newer support this dfx new interactive prompt. Learn more about dfx v0.17.0.

Then, select a frontend framework for your frontend canister. Select 'No frontend canister':

  ? Select a frontend framework: ›
SvelteKit
React
Vue
Vanilla JS
No JS template
❯ No frontend canister

Lastly, you can include extra features to be added to your project:

  ? Add extra features (space to select, enter to confirm) ›
⬚ Internet Identity
⬚ Bitcoin (Regtest)
⬚ Frontend tests

Then, navigate into the new project directory:

cd dependencies

You'll use the default 'Hello world' project in this example, then you'll pull the Internet Identity canister as a dependency of our dependencies_backend canister.

First, open the dfx.json file in your project's directory. You need to configure your dependencies_backend canister to have the dependencies of internet_identity, with canister ID rdmx6-jaaaa-aaaaa-aaadq-cai on the mainnet. This is the canister ID of the DFINITY canister used to interact with ICP's identity and authentication product called Internet Identity. The developer ladder will dive deeper into II in a later tutorial; for now, you'll just use it to demonstrate how third-party canisters can be used. You can do so by editing our dfx.json file to reflect the following configuration:

dfx.json
{
"canisters": {
"dependencies_backend": {
"type": "motoko",
"main": "src/dependencies_backend/main.mo",
"dependencies": [
"internet_identity"
]
},
"internet_identity": {
"type": "pull",
"id": "rdmx6-jaaaa-aaaaa-aaadq-cai"
}
},
"defaults": {
"build": {
"args": "",
"packtool": ""
}
},
"output_env_file": ".env",
"version": 1
}

Next, run the dfx deps pull command:

dfx deps pull

By running this command, the following steps are executed:

  • First, the dependency canister is fetched and the Wasm for it is downloaded.

  • Then, the hash of the downloaded Wasm is verified against the hash of the deployed canister on the mainnet.

  • Next, a series of information is extracted from the downloaded Wasm file, such as the dfx metadata and Candid information.

The deps/ folder is also created in your project's root folder. The deps/pulled.json file will contain all major information regarding the project's dependencies. In this example, the deps/pulled.json file should resemble the following:

deps/pulled.json
{
"canisters": {
"rdmx6-jaaaa-aaaaa-aaadq-cai": {
"name": "internet_identity",
"wasm_hash": "07869792e0841765e24014a2cb23e4a53d3147be6051bfc4966565017cd5fb2c",
"init_guide": "Use '(null)' for sensible defaults. See the candid interface for more details.",
"candid_args": "(opt InternetIdentityInit)",
"gzip": true
}
}
}%

Using dfx deps

Next, you'll set the init arguments for the dependency canisters using the dfx deps init command. An init argument is an argument that will be passed to the canister when it is deployed. This command will iterate over all listed dependencies in the pulled.json file and set an empty argument for any that do not require an init argument. For those that require an init argument, they will be returned so that they can be set manually. Run the command:

dfx deps init

This will show that our II canister requires an init argument:

WARN: The following canister(s) require an init argument. Please run `dfx deps init <NAME/PRINCIPAL>` to set them individually:
rdmx6-jaaaa-aaaaa-aaadq-cai (internet_identity)

This output shows you that the Internet Identity canister requires an init argument, but it doesn't give you any additional information. For more information, run the command dfx deps init rdmx6-jaaaa-aaaaa-aaadq-cai, which will provide an error message that shows you more details:

Error: Canister rdmx6-jaaaa-aaaaa-aaadq-cai (internet_identity) requires an init argument. The following info might be helpful:
init => Use '(null)' for sensible defaults. See the candid interface for more details.
candid:args => (opt InternetIdentityInit)

In this error, you can see that to use the canister's defaults, you can use a null value as the init argument. To pass this value as an init argument, run the command:

dfx deps init rdmx6-jaaaa-aaaaa-aaadq-cai --argument null

Now it's time to deploy our pulled dependency canister. Run the command:

dfx deps deploy

Lastly, let's deploy our project all together with the dfx deploy command:

dfx deploy

The output will include a local Candid UI URL for both the dependencies_backend canister, which has the default 'Hello world' code, and the local Candid UI URL for the Internet Identity canister.

Installing code for canister dependencies_backend, with canister ID bkyz2-fmaaa-aaaaa-qaaaq-cai
Deployed canisters.
URLs:
Backend canister via Candid interface:
dependencies_backend: http://127.0.0.1:4943/?canisterId=bd3sg-teaaa-aaaaa-qaaba-cai&id=bkyz2-fmaaa-aaaaa-qaaaq-cai
internet_identity: http://127.0.0.1:4943/?canisterId=bd3sg-teaaa-aaaaa-qaaba-cai&id=rdmx6-jaaaa-aaaaa-aaadq-cai

Now, you can interact with the II canister locally using the CLI or the Candid UI. In a future tutorial you'll integrate your backend canister with the II canister. For now, that'll wrap up this module.

Need help?

Did you get stuck somewhere in this tutorial, or feel like you need additional help understanding some of the concepts? The ICP community has several resources available for developers, like working groups and bootcamps, along with our Discord community, forum, and events such as hackathons. Here are a few to check out:

Next steps

Next, let's take a deeper dive into an introduction of Candid and the role that it plays in development on ICP.