# Making type safe inter canister calls in Rust doesn't work using ic\_cdk macro

**URL:** <https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245>\
**Category:** Rust\
**Created:** [September 2, 2022, 7:55am UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245 "2022-09-02T07:55:53Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![saikatdas0790](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/saikatdas0790/32/17147_2.png) [@saikatdas0790](https://forum.dfinity.org/u/saikatdas0790)\
**Post date:** [September 2, 2022, 7:55am UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/1 "2022-09-02T07:55:53Z")

</div>

I tried following [this mechanism](https://internetcomputer.org/docs/current/developer-docs/build/cdks/cdk-rs-dfinity/multiply-dependency) as documented in the official docs.

I created a minimum reproduction [here](https://github.com/saikatdas0790/importing_canisters) for the behaviour that I’m going to explain below.

Basically I’m trying to import one canister from the other using this bit of code

```rust
#[ic_cdk_macros::import(canister = "imported_canister")]
struct ImportedCanister;

```

The imported canister is defined in the `dfx.json` file.

The issue with the current state of the code is that it works if you directly deploy it using `dfx deploy`. But since the `import` macro has a compilation error with the message

> error: Could not find DFX bindings for canister named ‘imported\_canister’. Did you build using DFX?

The other cargo commands will not work. The automatic Candid generation relies on the ability to run `cargo test` and so will other cargo commands. The code also lights up RED with compilation errors wherever the imported canister struct is used.

This is disappointing behaviour considering that Rust provides fantastic compiler guarantees and having to work around the compiler is janky and should be fixed.

Thoughts?

---

<div class="post-metadata">

**Author:** ![lwshang](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/lwshang/32/3394_2.png) [@lwshang](https://forum.dfinity.org/u/lwshang)\
**Post date:** [September 6, 2022, 2:01pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/2 "2022-09-06T14:01:55Z")

</div>

Hi @saikatdas0790, we are implementing a new mechanism to generate Rust bindings from candid for inter-canister calls. The high level idea it to utilize `build.rs` to explicitly generate Rust file during build time. One of the considerations for this design is to make the canister can be built via `cargo build` instead of requiring dfx.

The implementation may takes a few weeks since there are still some problems to be solved. For example, how do we pass the callee canister ID to the caller? Currently, we rely on environment variables set by dfx during compile time.

---

<div class="post-metadata">

**Author:** ![lastmjs](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/lastmjs/32/3406_2.png) [@lastmjs](https://forum.dfinity.org/u/lastmjs)\
**Post date:** [September 8, 2022, 7:20pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/3 "2022-09-08T19:20:49Z")

</div>

The import macro seems to have a lot of problems, are you familiar with how to do cross canister calls from Rust without it?

---

<div class="post-metadata">

**Author:** ![saikatdas0790](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/saikatdas0790/32/17147_2.png) [@saikatdas0790](https://forum.dfinity.org/u/saikatdas0790)\
**Post date:** [September 9, 2022, 3:39am UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/4 "2022-09-09T03:39:38Z")

</div>

There are 2 alternatives that I’m still considering:

- Making a raw call using the ic\_cdk as demonstrated [here](https://docs.rs/ic-cdk/latest/ic_cdk/api/call/fn.call.html)
- Making an intercanister call using ic-kit as demonstated [here](https://docs.rs/ic-kit/0.5.0-alpha.4/ic_kit/ic/struct.CallBuilder.html)

Note that IC kit is very much alpha and the current release(0.5.0-alpha.4) is missing key features like being able to spawn canisters dynamically. Here’s a [link](https://github.com/Psychedelic/ic-kit/issues/23) to a conversation with the brilliant @qti3e regarding the above

Both of the above mechanisms require dynamic calls, meaning you need to pass function names as strings and are not as type aware as the call with the `import` macro that the Dfinity example provides.

Curious about what your thoughts on the above are.

---

<div class="post-metadata">

**Author:** ![lastmjs](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/lastmjs/32/3406_2.png) [@lastmjs](https://forum.dfinity.org/u/lastmjs)\
**Post date:** [September 9, 2022, 12:37pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/5 "2022-09-09T12:37:21Z")

</div>

We use ic\_cdk::api::call::call for almost all cross canister calls in Rust, unless we need call\_raw. It’s statically type safe

---

<div class="post-metadata">

**Author:** ![lastmjs](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/lastmjs/32/3406_2.png) [@lastmjs](https://forum.dfinity.org/u/lastmjs)\
**Post date:** [September 9, 2022, 12:38pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/6 "2022-09-09T12:38:19Z")

</div>

You do pass function names as strings, but it works extremely well and I’d be surprised if most Rust devs aren’t doing it this way

---

<div class="post-metadata">

**Author:** ![saikatdas0790](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/saikatdas0790/32/17147_2.png) [@saikatdas0790](https://forum.dfinity.org/u/saikatdas0790)\
**Post date:** [September 14, 2022, 5:20pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/7 "2022-09-14T17:20:07Z")

</div>

Hi @lastmjs and @lwshang,

I was thinking about what we had discussed here.  
In [this example](https://github.com/saikatdas0790/importing_canisters), how would I find the canister\_id to be passed to `ic_cdk::api::call::call`?

The thing about the `import` macro is, it also figures out the canister\_id to be called depending on whether I’m running locally or on mainnet. How would that work for a direct call using `ic_cdk`?

---

<div class="post-metadata">

**Author:** ![lastmjs](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/lastmjs/32/3406_2.png) [@lastmjs](https://forum.dfinity.org/u/lastmjs)\
**Post date:** [September 14, 2022, 8:58pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/8 "2022-09-14T20:58:51Z")

</div>

You can look in `.dfx/local/canister_ids.json` to find the canister ids, that’s one way. Once you push to production you’ll have a root level `canister_ids.json`. You can also use `dfx` to get the canister id based on the name. In your Rust code you can check if you’re in production and choose which id to use. One way to do this would be to use `ic_cdk::api::id` to get the id of your canister and thus check if you’re in production or not.

---

<div class="post-metadata">

**Author:** ![saikatdas0790](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/saikatdas0790/32/17147_2.png) [@saikatdas0790](https://forum.dfinity.org/u/saikatdas0790)\
**Post date:** [September 15, 2022, 3:53am UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/9 "2022-09-15T03:53:58Z")

</div>

I’ll try to explain again because I believe I wasn’t clear enough in my earlier message.

So the thing is, I have a caller and a callee in a dfx project.

With the import macro, if I specify the canister name, it figures out what canister to call automagically no matter which environment i’m running on and no matter how many times i start fresh on a local replica.

If I am manually looking at the canister\_ids.json file, then I will be hard coding canister IDs in the caller canister code depending on the environment running on. This will simply NOT DO. Apart from clean canister installs on a local replica, if we have 2 different devs working on the project, that’s 3 different canister IDs (prod, dev 1 local, dev 2 local) that need to be updated and kept in sync and forgetting to update once will lead to service outage.

IF you’re suggesting dynamically reading the `canister_ids.json` and injecting those values into code, then that could work. But my Rust skills are still kinda weak, and I think I would probably need to write a macro to do it, but I’m kinda lost. Any guidance there is appreciated. Also, obviously, happy to share findings.

Using `ic_cdk::api::id` would work if I needed to know the canister ID of the callee from inside itself. How would the caller canister get that ID for it to make that call?

Please let me know if I’m making sense or I misinterpreted what you were saying 🙂

---

<div class="post-metadata">

**Author:** ![PeanutNJam](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/peanutnjam/32/6366_2.png) [@PeanutNJam](https://forum.dfinity.org/u/PeanutNJam)\
**Post date:** [February 12, 2023, 12:18pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/10 "2023-02-12T12:18:32Z")

</div>

> [@saikatdas0790](#):
>
> this example

Hi, sorry for this late message on this thread, but i have a similar problem. I wish to call a method main in an adjacent canister from a canister called rustycan. Ive already tried that import derived trait, and now i try using the ic0 call in ic-cdk::api. The ::call method needs three args, and T is what i try to implement below for Called and trait ArgumentDecoder (note theres theres two - with+w/o lifetimes. I am doing something stupid, but hope you could point me in the right direction so i can critique my work. PS: as a follow up, what if the main method takes no args, why do i need to give the T: ArgumentDecoder param regardless? Here is the code:

#[derive(Debug, PartialEq)]  
struct Called {  
s: u64,  
}

impl ArgumentDecoder for Called {  
fn encode(self, ser: &mut IDLBuilder) → Result\<()\>{  
Ok(())  
}

}

impl\<'a\> ArgumentDecoder\<'a\> for Called {  
fn decode(\_de: &mut candid::de ::IDLDeserialize\<'a\>) → candid::Result {  
Ok(Called { s: (10u64) })  
}  
}

#[update]  
#[ic\_cdk::export::candid::candid\_method(update)]  
async fn call\_canister(principal: Principal) → Result\<(), ()\>{  
let called = Called {s: 10u64};  
let s = “main”.to\_string();  
if let Ok(\_x) = ic\_cdk::api::call::call(principal, &s , called).await {  
return Ok(());  
}  
Err(())  
}

---

<div class="post-metadata">

**Author:** ![lastmjs](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/lastmjs/32/3406_2.png) [@lastmjs](https://forum.dfinity.org/u/lastmjs)\
**Post date:** [February 13, 2023, 7:10pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/11 "2023-02-13T19:10:29Z")

</div>

> [@PeanutNJam](#):
>
> ic\_cdk::api::call::call(principal, &s , called).await

Try passing in a tuple for called: `ic_cdk::api::call::call(principal, &s , (called,)).await` Also just derive `CandidType` on your `Called` struct.

---

<div class="post-metadata">

**Author:** ![PeanutNJam](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/peanutnjam/32/6366_2.png) [@PeanutNJam](https://forum.dfinity.org/u/PeanutNJam)\
**Post date:** [February 13, 2023, 8:40pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/12 "2023-02-13T20:40:58Z")

</div>

Thanks for this, i found the pub-sub example and copied it last night. I understand it much better now… but i reckon that motoko version is correct, while the rust is not, ie, the counter is not reset and remains zero for the rust impl.

---

<div class="post-metadata">

**Author:** ![famouscat8](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/famouscat8/32/4732_2.png) [@famouscat8](https://forum.dfinity.org/u/famouscat8)\
**Post date:** [August 10, 2023, 1:42pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/13 "2023-08-10T13:42:26Z")

</div>

Any progress? Any progress?

---

<div class="post-metadata">

**Author:** ![lwshang](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/lwshang/32/3394_2.png) [@lwshang](https://forum.dfinity.org/u/lwshang)\
**Post date:** [August 10, 2023, 4:14pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/14 "2023-08-10T16:14:32Z")

</div>

Yes. In recent published `ic-cdk` v0.10, we have the new `ic-cdk-bindgen` crate which replaces `#[import]` macro.

You may want to read the changelog: [https://github.com/dfinity/cdk-rs/blob/main/src/ic-cdk/CHANGELOG.md#added](https://github.com/dfinity/cdk-rs/blob/main/src/ic-cdk/CHANGELOG.md#added).

The cdk-rs examples are using this new approach. For example. [https://github.com/dfinity/cdk-rs/blob/main/examples/profile/src/profile\_inter\_rs/build.rs](https://github.com/dfinity/cdk-rs/blob/main/examples/profile/src/profile_inter_rs/build.rs)

---

<div class="post-metadata">

**Author:** ![famouscat8](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/famouscat8/32/4732_2.png) [@famouscat8](https://forum.dfinity.org/u/famouscat8)\
**Post date:** [August 10, 2023, 4:36pm UTC](https://forum.dfinity.org/t/making-type-safe-inter-canister-calls-in-rust-doesnt-work-using-ic-cdk-macro/15245/15 "2023-08-10T16:36:35Z")

</div>

thks for reply, great job!
