Guides
Executing Canister Calls

Executing canister calls

Your application will likely execute calls to your own canisters (targets) and others (non-targets i.e. ledger canisters).

The following guide teaches you how to set up actors to each depending on how the user authenticated, whether the canister is a target, and if the method being called requires a user to execute.

Steps

1. Connect Wallet

Follow the connect-wallet guide to connect a wallet address.

2. Import idlFactories

You'll need an idlFactory for each canister you want to call.

// import the idlFactory for your canister that implements icrc28_trusted_origins
import { idlFactory as targetIdlFactory } from "/path/to/target/did.js"
 
// import the idlFactory of another canister (i.e. ICRC1 token ledger)
import { idlFactory as nontargetIdlFactory } from "/path/to/nontarget/did.js"

3. Set up agents

IdentityKit comes bundled with an agent that can be used to create actors for calling canisters. You should also import @dfinity/agent for cases when your users connect with an anonymous relying party delegation or when you need to query something for which the user doesn't need to execute themselves.

import { useIdentityKit } from "@nfid/identitykit/react"
import { HttpAgent, Actor } from "@dfinity/agent"
 
const { delegationType, identity, agent } = useIdentityKit()
 
// Create an unauthenticatedAgent when you need to execute calls for which the user doesn't need to execute themselves
const [unauthenticatedAgent, setUnauthenticatedAgent] = useState<HttpAgent | undefined>()
 
useEffect(() => {
  HttpAgent.create({ host: "https://icp-api.io/" }).then(setUnauthenticatedAgent)
}, [])
 
// Create an HttpAgent in case the connected delegation is not for their wallet address
const [authenticatedNonTargetAgent, setAuthenticatedNonTargetAgent] = useState<
  HttpAgent | undefined
>()
 
useEffect(() => {
  if (identity && delegationType === IdentityKitDelegationType.ANONYMOUS) {
    HttpAgent.create({ identity, host: "https://icp-api.io/" }).then(setAuthenticatedNonTargetAgent)
  }
}, [identity, delegationType])
⚠️

Example created for global network interaction, check also

local-development

4. Create actors

Create actors for the canisters you want to call with the idlFactories you imported and their canister IDs.

import { useIdentityKit } from "@nfid/identitykit/react"
 
const { agent, identity, delegationType } = useIdentityKit()
 
// Actor for one of your application's target canisters
const targetActor =
  agent &&
  Actor.createActor(targetIdlFactory, {
    agent,
    canisterId: TARGET_CANISTER_ID_TO_CALL,
  })
 
// Actor for a different canister in the ecosystem (i.e. icrc2_approve)
const nonTargetActor =
  identity && delegationType === IdentityKitDelegationType.ANONYMOUS && authenticatedNonTargetAgent
    ? Actor.createActor(nontargetIdlFactory, {
        agent: authenticatedNonTargetAgent,
        canisterId: NON_TARGET_CANISTER_ID_TO_CALL,
      })
    : undefined
 
// Actor for methods the user doesn't need to be authenticated to call (i.e. icrc2_allowance)
// These will never result in a wallet approval prompt.
const nonTargetUnauthenticatedActor = Actor.createActor(nontargetIdlFactory, {
  agent: unauthenticatedAgent,
  canisterId: NON_TARGET_CANISTER_ID_TO_CALL,
})

5. Call canister

Execute your calls.

if (actor) {
  const result = await actor.{yourmethod}
}

Note on UX

The user may see a wallet approval pop-up depending on how they authenticated:

Auth optionWallet addressWallet approval pop-up for executing calls to your canistersWallet approval pop-up for executing calls to other canisters
AccountGlobalYesYes
Account DelegationGlobalNoYes
Relying Party DelegationUnique to dApp URLNoNo

Use the Delegation Toolkit to remove wallet approval pop-ups for executing calls to your canisters and read more about the differences between accounts and delegations.