Introduction
The Locker is a native blueprint for permissioned resource distribution: a sender deposits resources into the locker addressed to specific recipients, who can then claim them on their own schedule. Lockers were introduced to support airdrops, vesting, and refund flows without forcing recipients to pre-authorize deposits β the engine's native-asset model means tokens cannot be pushed to an account that has not opted in.
The problem it solves
Radix Smart Accounts can refuse deposits. An account owner may set their deposit rules to accept only a chosen list of resources, or only deposits from an authorized depositor, which means a sender cannot assume a transfer will land β an asset-oriented engine will not silently credit a balance the recipient never agreed to hold. A naive airdrop over a few thousand accounts therefore fails for every account whose rules reject it, and the sender is left holding the remainder with no record of who is still owed what.
Before the Locker, applications worked around this by tracking outstanding balances themselves, in their own component state, and exposing a bespoke claim method. The Locker makes that pattern native: a sender deposits resources addressed to specific claimants, the claimants collect on their own schedule, and neither side needs a badge or a custom contract for it. Radix documentation gives bridges as the motivating case β attempt the direct deposit, fall back to a locker when it bounces.
Blueprint interface
The blueprint is named AccountLocker and is defined in the engine's locker invocation definitions. It exposes two instantiation functions and eight methods, split by the role each requires:
| Kind | Name | Notes |
|---|---|---|
| Function | instantiate | Takes an owner role plus the four access rules (storer_role, storer_updater_role, recoverer_role, recoverer_updater_role) and an optional address reservation |
| Function | instantiate_simple | Takes a single allow_recover flag and returns the locker together with a badge bucket |
| Storer | store | Deposits one bucket for one claimant |
| Storer | airdrop | Distributes one bucket across a map of claimants; returns the remainder as Option<Bucket> |
| Recoverer | recover / recover_non_fungibles | Pulls stored resources back out to the operator |
| Public | claim / claim_non_fungibles | Called by anyone; the engine checks the caller is the claimant |
| Getter | get_amount / get_non_fungible_local_ids | Read what a given claimant is owed; the non-fungible getter takes a limit |
Fungible and non-fungible paths are separate methods rather than one overloaded call, and the airdrop map carries a ResourceSpecifier per claimant β either a Fungible(Decimal) amount or a NonFungible set of local IDs.
Direct send, then fall back
Both store and airdrop take a try_direct_send boolean. When it is set, the locker first calls try_deposit_or_refund on the claimant's account, presenting the locker's own global-caller badge as the authorized depositor. If the account accepts, the resources land directly and nothing is stored; if it refunds, the returned bucket is written into a per-claimant vault inside the locker instead. The vault is created on first use.
That single flag is what makes the Locker a drop-in for an existing distribution: the happy path stays a direct transfer, and only the accounts that would have failed end up with something to claim. The choice is the sender's, not the recipient's β passing false stores unconditionally.
Roles and events
Access is split so that filling a locker and emptying it are different privileges. The storer role may call store and airdrop; the recoverer role may pull resources back out with recover; each has a matching updater role that can change who holds it, following the standard role assignment pattern and enforced by access rules. instantiate_simple collapses the choice to one question β whether recovery is allowed at all β and hands back the badge that authorizes it.
The blueprint emits three events: StoreEvent when resources are locked for a claimant, RecoverEvent when the operator takes them back, and ClaimEvent when a claimant collects. Each carries the claimant, the resource address, and the amount or ID set, so an indexer reading the Gateway API can reconstruct the full state of an airdrop without reading substates.
