> ## Documentation Index
> Fetch the complete documentation index at: https://shield.fi/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Caller and signer

> How immediate callers, top-level signers, record recipients, and confidential addresses differ across direct and routed execution.

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:

```text theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
signer = wallet address
caller = wallet address
blinded_address = public pseudonym derived from wallet and private factor
```

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:

```text theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
signer = top-level user account
caller = intermediary program address
blinded_address = public pseudonym bound to signer
```

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.

| Role                 | Source                                                 | Function                                              |
| -------------------- | ------------------------------------------------------ | ----------------------------------------------------- |
| Signer               | `self.signer`                                          | Top-level account authorizing the transaction         |
| Caller               | `self.caller`                                          | Direct account or program invoking the AMM            |
| Recipient            | `recipient`, `withdrawal`, or a record's `owner` field | Address that receives a `PositionNFT` or token record |
| Confidential address | Public derived address                                 | One-use swap pseudonym stored in public swap fields   |

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.

## Signer is not legal identity

`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.

## Related pages

* [Confidential addresses](./confidential-addresses)
* [Compliance records](./compliance-records)
* [Trust and key boundaries](../security/trust-and-key-boundaries)
