Skip to content

Commit 3c59a0e

Browse files
authored
docs: clarify inter-canister calls (#4919)
This PR updates the docs to better illustrate how to call other canisters in Motoko.
1 parent 957b6a5 commit 3c59a0e

File tree

1 file changed

+65
-31
lines changed

1 file changed

+65
-31
lines changed

doc/md/writing-motoko/intercanister-calls.md

+65-31
Original file line numberDiff line numberDiff line change
@@ -4,76 +4,99 @@ sidebar_position: 12
44

55
# Inter-canister calls
66

7-
8-
97
One of the most important features of ICP for developers is the ability to call functions in one canister from another canister. This capability to make calls between canisters, also sometimes referred to as **inter-canister calls**, enables you to reuse and share functionality in multiple dapps.
108

119
For example, you might want to create a dapp for professional networking, organizing community events, or hosting fundraising activities. Each of these dapps might have a social component that enables users to identify social relationships based on some criteria or shared interest, such as friends and family or current and former colleagues.
1210

1311
To address this social component, you might want to create a single canister for storing user relationships then write your professional networking, community organizing, or fundraising application to import and call functions that are defined in the canister for social connections. You could then build additional applications to use the social connections canister or extend the features provided by the social connections canister to make it useful to an even broader community of other developers.
1412

15-
This example will showcase a simple way to configure inter-canister calls that can be used as the foundation for more elaborate projects and use-cases such as those mentioned above.
13+
## Basic usage
14+
15+
A simple way to set up inter-canister calls is through your project's `dfx.json` file.
16+
17+
For example, let's say that you want to build a canister named `foo` which calls the canister `bar`.
18+
Here is the `dfx.json` file:
19+
20+
```json
21+
{
22+
"canisters": {
23+
"foo": {
24+
"dependencies": ["bar"],
25+
"type": "motoko",
26+
"main": "src/Foo.mo"
27+
},
28+
"bar": {
29+
"type": "motoko",
30+
"main": "src/Bar.mo"
31+
}
32+
}
33+
}
34+
```
1635

17-
## Example
36+
Notice that `foo` includes `bar` as a canister dependency.
1837

19-
Consider the following code for `Canister1`:
38+
Below is an example implementation of `foo` (`src/Foo.mo`) which calls the `bar` canister:
2039

2140
```motoko no-repl
22-
import Canister2 "canister:canister2";
41+
import Bar "canister:bar";
2342
24-
persistent actor Canister1 {
43+
persistent actor Foo {
2544
2645
public func main() : async Nat {
27-
return await Canister2.getValue();
46+
let value = await Bar.getValue(); // Call a method on the `bar` canister
47+
value;
2848
};
2949
3050
};
3151
```
3252

33-
Then, consider the following code for `Canister2`:
53+
Below is an implementation for `bar` (`src/Bar.mo`):
3454

3555
```motoko
3656
import Debug "mo:base/Debug";
3757
38-
persistent actor Canister2 {
58+
persistent actor Bar {
59+
3960
public func getValue() : async Nat {
40-
Debug.print("Hello from canister 2!");
41-
return 10;
61+
Debug.print("Hello from the `bar` canister!");
62+
123;
4263
};
64+
4365
};
4466
```
4567

68+
To run this example, you can use the `dfx canister call` subcommand (after deploying the canisters with `dfx deploy`):
4669

47-
To make an inter-canister call from `canister1` to `canister2`, you can use the `dfx` command:
48-
49-
```
50-
dfx canister call canister1 main
70+
```bash
71+
dfx canister call foo main
5172
```
5273

5374
The output should resemble the following:
5475

55-
```
56-
2023-06-15 15:53:39.567801 UTC: [Canister ajuq4-ruaaa-aaaaa-qaaga-cai] Hello from canister 2!
57-
(10 : nat)
76+
```bash
77+
2025-02-21 15:53:39.567801 UTC: [Canister ajuq4-ruaaa-aaaaa-qaaga-cai] Hello from the `bar` canister!
78+
(123 : nat)
5879
```
5980

60-
Alternatively, you can also use a canister id to access a previously deployed canister by using the following piece of code in `canister1`:
81+
You can also use a canister ID to access a previously deployed canister as shown in this alternate implementation of `foo`:
6182

6283
```motoko
63-
persistent actor {
64-
84+
persistent actor Foo {
6585
public func main(canisterId: Text) : async Nat {
66-
let canister2 = actor(canisterId): actor { getValue: () -> async Nat };
67-
return await canister2.getValue();
86+
let Bar = actor(canisterId): actor {
87+
getValue: () -> async Nat; // Define the expected canister interface
88+
};
89+
let value = await Bar.getValue(); // Call the canister
90+
value;
6891
};
6992
7093
};
7194
```
7295

73-
Then, use the following call, replacing `canisterID` with the principal ID of a previously deployed canister:
96+
Then, use the following call, replacing `canister-id` with the ID of a previously deployed canister:
7497

75-
```
76-
dfx canister call canister1 main "canisterID"
98+
```bash
99+
dfx canister call foo main "canister-id"
77100
```
78101

79102
## Advanced usage
@@ -87,6 +110,7 @@ import IC "mo:base/ExperimentalInternetComputer";
87110
import Debug "mo:base/Debug";
88111
89112
persistent actor AdvancedCanister1 {
113+
90114
public func main(canisterId : Principal) : async Nat {
91115
// Define the method name and input args
92116
let name = "getValue";
@@ -97,10 +121,10 @@ persistent actor AdvancedCanister1 {
97121
let encodedValue = await IC.call(canisterId, name, encodedArgs);
98122
99123
// Decode the return value
100-
let ?value : ?Nat = from_candid encodedValue
101-
else Debug.trap("Unexpected return value");
102-
return value;
103-
}
124+
let ?value : ?Nat = from_candid encodedValue else Debug.trap("Unexpected return value");
125+
value;
126+
};
127+
104128
}
105129
```
106130

@@ -117,4 +141,14 @@ persistent actor AdvancedCanister2 {
117141
};
118142
```
119143

144+
In some situations, it may be useful to reference a canister by ID. This is possible with the following import syntax:
145+
146+
```motoko
147+
import Canister "ic:7hfb6-caaaa-aaaar-qadga-cai";
148+
```
149+
150+
If you do this, double check that the referenced canister is available and has the same canister ID in all intended runtime environments (usually the local replica and ICP mainnet).
151+
152+
In addition, a corresponding `.did` file with name `7hfb6-caaaa-aaaar-qadga-cai.did`, containing the Candid interface of the imported canister, must be available on the `moc` compiler's `actor-idl` path.
153+
120154
<img src="https://github.com/user-attachments/assets/844ca364-4d71-42b3-aaec-4a6c3509ee2e" alt="Logo" width="150" height="150" />

0 commit comments

Comments
 (0)