← Solana Builder

Intermediate · LESSON 04 OF 06

4. Cross-program calls and token authorities

By the end, you can trace authority across a composed instruction.

In this lesson8 field notes · practice · sources · checkpoint
A transaction signer calls Program A, which checks and forwards narrow privileges through a CPI to the Token Program, then observes the resulting token-account state.
A transaction signer calls Program A, which checks and forwards narrow privileges through a CPI to the Token Program, then observes the resulting token-account state.Open full-size visual ↗
Read a text version of this diagram

The outer transaction signature and account metadata reach Program A. Program A validates the executable Token Program, source and destination accounts, intended mint, supported authority path, and amount before invoking. The CPI forwards only the signer and writable privileges its child instruction requires. `invoke_signed` can add signer privilege only for a PDA derived with Program A's ID and supplied seeds; it cannot create arbitrary write access. The Token Program checks its instruction and updates token-account state when valid. A failed transaction rolls back application-state changes although its network fee may remain charged. The Token Program owns token-account data; the stored token authority is a separate role.

  1. OUTER TRANSACTION
  2. CALLER PROGRAM
  3. CPI BOUNDARY
  4. CALLEE PROGRAM
  5. RESULTING ACCOUNTS
FIELD NOTE 01

Composition has boundaries

A cross-program invocation calls another program from an executing program. The callee receives specified accounts and instruction data. Writable and signer privileges cannot simply be invented by the caller; PDA signing is a specific runtime mechanism with derivation checks.

FIELD NOTE 02

Inspect the destination program

An application that intends to invoke a token program must validate the program identity and account types. Otherwise an attacker may substitute a program or state that violates assumptions. Validate mint, token account authority, destination, and amount before a transfer or issuance operation.

FIELD NOTE 03

A certificate example

A credential instruction should bind the assessed level and learner to the intended issuer and asset. The payer may cover fees without becoming the credential owner. Write a table separating payer, owner, mint authority, update authority, and any revocation authority.

FIELD NOTE 04

A CPI carries privileges into another program

A cross-program invocation calls another program during the same transaction. The callee receives the accounts and signer or writable privileges forwarded by the caller; it cannot invent stronger privileges. The caller must validate the target program, account relationships, and requested action before invoking it. `invoke_signed` can add signer privilege for a PDA derived with the invoking program's ID and supplied seeds. It does not sign for a user, add arbitrary writable access, or prove that the PDA's data has a particular owner. Caller and callee consume the same transaction compute budget. Follow every CPI edge and ask which input selects the target, which data can change, and which authority can approve the effect.

FIELD NOTE 05

Follow privileges through every CPI

Trace a token transfer from an outer program to the Token Program. Anchor's `Program<Token>` validates the classic Token Program; `Interface<TokenInterface>` can support the classic Token Program and Token-2022 when the application intends both. The type does not decide which mints or extensions the application accepts, so validate that policy explicitly. Keep two meanings of “owner” separate. A token account's top-level Solana owner is its Token Program, which owns the account data. Its decoded token state stores an internal token-account owner authority and may also contain an approved delegate and remaining delegated allowance. The account owner or an approved delegate can authorize a base token transfer. If a Token-2022 mint enables `PermanentDelegate`, that mint-level delegate can also authorize transfers (and burns) across token accounts for that mint; a token holder cannot revoke that mint-level power from their individual account. Treat it as an issuer-wide trust decision, not an ordinary account delegate. `TransferChecked` checks that the supplied mint matches the token accounts and that the supplied decimals match the mint. It does not know which mint or recipient your application intended; validate those relationships before the CPI. For a token program that supports either Token program family, test each allowed program separately, including unsupported extension configurations. A failing inner instruction fails the atomic application-state changes, but a submitted failed transaction may still charge its network fee.

FIELD NOTE 06

Build a privilege ledger before the call

For each CPI, write a row for the target program, source, mint, destination, authority, and payer. Record the exact public key or supported type, whether it must be a signer or writable, who supplies that privilege, and the invariant checked before the call. For a transfer, prove the source and destination use the intended mint, the token program is in the allow-list, and the authority is the source owner, a live delegate with enough allowance, or a deliberately accepted Token-2022 permanent delegate. Do not use the fee payer as a shortcut for token authority. Then compare the inner instruction's account metas with the ledger. Remove signer or writable flags that the callee does not require. Test a correct owner transfer, an approved delegate below and above its allowance, a wrong mint, an unexpected destination, the wrong program, and a permanent delegate when that feature is both enabled and disabled. Assert balances and protected application state after each case; a rejected transfer should not be reported as a successful outer action.

FIELD NOTE 07

Keep payer, owner, and authority distinct

Keep the transaction fee payer, asset owner, and update authority in separate fields in your design. In Metaplex Core, the `owner` is the current holder; `updateAuthority` controls metadata updates and may identify a Collection. Paying the transaction fee or account-storage balance does not set either role. Moving a Core Asset into a Collection after creation requires authority over both the Asset and the target Collection; collection membership can also change which collection-level plugins apply. Freeze or transfer restrictions are another permission, controlled by the relevant plugin authority, and are not implied by ownership or update authority. Record which signer or program rule proves every role and what can change later.

FIELD NOTE 08

Review the whole composed action

Atomic transactions can combine a credential action with other instructions, which is convenient but makes review more important. Inspect every top-level instruction and every CPI path that the program can take. Reject an unexpected token transfer, delegate approval, authority change, or program target even when it appears beside a legitimate mint. Simulate against a fixed local environment where possible, then compare the wallet-signed message with the intended instruction set. A successful simulation predicts execution under that state; it does not guarantee that account state or fees remain unchanged by the time the signed transaction is processed.

MAKE THE CONNECTION

A detail worth keeping.

For each CPI, list the target program, source, mint, destination, authority, and payer. Record each signer or writable requirement, who supplies that privilege, and the invariant checked before invoking. Compare the child instruction's account metas with that ledger and remove anything the callee does not need. A safe composed transaction is a sequence of explicit, validated actions, not a promise made by a frontend.

Work through an example

The payer may be the learner and the credential update authority may be the academy. The asset owner is still the learner. Keeping these roles separate lets someone pay their own rent without receiving authority over the academy collection.

Draw the CPI boundary and annotate its exact signer and writable accounts. Then use a source account with owner PDA A and an approved delegate with allowance 80: determine whether delegate transfers of 50 and 100 can pass, what changes if a Token-2022 permanent delegate is enabled, and which caller must use `invoke_signed` for PDA A.

GUIDED PRACTICE · INTERMEDIATE

Do the work, one step at a time.

Use fictional addresses and disposable test data. Do not enter a recovery phrase or private key. Most exercises work on paper or with a local test; only a lesson that clearly says “read-only Devnet” makes a public network request.

  1. Record the exact allowed callee program IDs and supported Token Program family.
  2. Build a privilege ledger for source, mint, destination, authority, and payer, including each signer and writable requirement.
  3. Test the source owner PDA and an approved delegate with transfers below, at, and above its remaining allowance.
  4. If Token-2022 is in scope, document and test the `PermanentDelegate` policy alongside wrong-mint, destination, program, and signer cases.
  5. Remove signer and writable privileges the callee does not need; record shared compute use and the failed-transaction fee boundary.

Before you move on, check your reasoning

  • Draw an outer instruction and its nested token-program CPI.
  • Mark the actual expected program IDs and signer/writable account metas.
  • Add owner, delegate, mint, destination, and Token-2022 permanent-delegate negative cases.

OPEN SELF-CHECK · UNGRADED

Pause and test your reasoning

A caller marks an account writable, but the calling program received it as read-only. Can a CPI upgrade that privilege?

  1. Yes; a CPI can request any writable or signer privilege from its caller.
  2. No; the callee cannot escalate privileges beyond those passed to the caller, though the caller may sign for its own PDA with valid seeds.
  3. Yes, if the account is owned by the System Program.
Reveal one best answer and its explanation

One best answer: No; the callee cannot escalate privileges beyond those passed to the caller, though the caller may sign for its own PDA with valid seeds.

CPI privileges are bounded by the caller’s privileges. `invoke_signed` lets a program provide signer privilege for a PDA derived under that program ID; it does not let a callee invent another program’s signature or escalate writable access.

Sources: Cross Program Invocation · Account Structure

This practice is not scored, saved, or part of a certificate. Account-based lesson checkpoints and level exams remain separate.

Never enter a recovery phrase or private key into a learning site or lesson exercise.

READ THE SOURCE

Go deeper in the official docs

Reviewed on 2026-09-28. Protocol documentation can change; check the linked page’s current version as you use this material.

  1. Cross Program Invocation ↗
  2. Calling the Token Program via CPI ↗
  3. Transfer Tokens ↗
  4. Approve Delegate ↗
  5. Permanent Delegate ↗
  6. Account Structure ↗
  7. Account Constraints ↗
  8. Account Types ↗
  9. Metaplex Core Asset Account ↗
  10. Updating Core Assets and Collection Membership ↗

Report an issue with this lesson

OPEN LEARNING

Keep learning at your own pace.

This lesson, its guided practice, and all six course lessons are open to everyone. Account-based checkpoints, exams, and saved progress will open when free accounts are ready.

Continue to the next lesson ↗