Skip to main content
Leo exposes two execution identities in proof context:
  • self.caller is the account or program that invoked the current entry function.
  • self.signer is the top-level account that signed the transaction.
They often match in a direct wallet call. They differ when another program invokes Shield Swap on the user’s behalf. All three compliance records retain both values so routed execution does not lose top-level account attribution.

Direct invocation

In a direct swap submitted by a wallet:
The public swap mappings store the confidential address, not the signer or caller values captured in the compliance record. In a direct mint, the signer and caller normally match. The private position owner and immutable withdrawal address can each be different because mint accepts both inputs separately.

Routed invocation

When a router or custody program calls Shield Swap:
Storing only caller would identify the integration but not the top-level account. Storing only signer would lose the immediate routing context. The current schema stores both.

Four relevant roles

Direct and routed calls can contain four distinct identities. These roles can differ.

Mint example

An institution signs a transaction through a custody program and assigns the position to a segregated wallet:
  • Signer: institution’s transaction account
  • Caller: custody program
  • Recipient: segregated position wallet
  • Token ID: public position handle
MintComplianceRecord captures signer, caller, owner recipient, immutable withdrawal, nonce, and token ID.

Swap example

A user signs through a router:
  • Signer: user account
  • Caller: router program
  • Confidential address: public one-use pseudonym
  • Claim recipient: signer, because the claim creates token records for self.signer
SwapComplianceRecord captures signer, caller, and the confidential address.

Collect example

An LP consumes a PositionNFT whose immutable withdrawal address differs from its owner:
  • Signer and record owner authorize the collect
  • The NFT withdrawal address receives the token records
  • Public state shows amounts and position update
  • The original mint compliance record contains the withdrawal address
The caller cannot replace that address during collect.

Contract use of caller

Administrative functions generally capture self.caller and pass it to finalization, where assert_admin compares it with the public admin mapping. This means a normal admin account must invoke the function directly. If an admin wants to operate through a governance program, that program address must itself be the configured admin and must complete the two-step transfer process. The imported multisig check governs program upgrades at editions greater than zero. Routine admin authorization uses self.caller and the admin mapping.

Contract use of signer

The core program uses self.signer to:
  • Derive and verify public confidential addresses
  • Direct single-hop claim records
  • Direct all swap-claim output and refund records
  • Populate compliance records with caller and signer attribution
  • Return the pool creator address publicly from create_pool
burn does not return self.signer as a public output. self.signer proves which Aleo account authorized the top-level transaction. It does not establish:
  • The named person controlling the account
  • Beneficial ownership of assets
  • Authority to act for an institution
  • Jurisdiction or location
  • Screening or KYC status
A compliance system must maintain an external binding between the Aleo address and its verified subject. The compliance record can then connect the verified account to a specific public swap or position.

Integration requirements

Routers and custody programs should document:
  • Which program address appears as caller
  • Which account remains signer
  • Whether mint recipient can differ from signer
  • How blinding material is generated and returned to the signer
  • Who initiates claim
  • How compliance records are associated with an off-chain customer or account ID
Compliance parsers must preserve caller and signer as separate fields and must not assume equality.