---
title: "Buckets, Proofs & Vaults"
url: "https://radix-wiki.miow.me/contents/tech/core-concepts/buckets-proofs-and-vaults"
updated: 2026-10-03
description: "Radix's asset-oriented programming model uses three core container types:"
---

# Buckets, Proofs & Vaults

|  |  |
| --- | --- |
| **Vault** | Permanent storage container for [resources](/contents/tech/core-concepts/resources) |
| **Bucket** | Temporary container for moving resources between calls |
| **Proof** | Zero-cost ownership evidence (doesn't move the resource) |

# Buckets, Proofs & Vaults

## Overview

Radix's [asset-oriented programming](/contents/tech/core-concepts/asset-oriented-programming) model uses three core container types:

### Vaults

Permanent storage for [resources](/contents/tech/core-concepts/resources). Every account, [component](/contents/tech/core-concepts/components), and dApp stores its assets in vaults. Vaults enforce the conservation law – tokens can only be moved, never duplicated or destroyed (unless explicitly burned).

### [Buckets](https://docs.radixdlt.com/docs/resources)

Temporary containers for moving resources between method calls within a [transaction manifest](/contents/tech/core-protocols/transaction-manifests). [Buckets](https://docs.radixdlt.com/docs/buckets-and-vaults) must be emptied by the end of a transaction – they cannot be stored, preventing tokens from being "stuck" in contract state.

### [Proofs](https://docs.radixdlt.com/docs/auth)

Non-transferable evidence of resource ownership. Proofs are placed in [auth zones](/contents/tech/core-concepts/access-rules-and-auth-zones) to satisfy [access rules](https://docs.radixdlt.com/docs/auth) without moving the underlying asset. This enables [badge](/contents/tech/core-concepts/badges)-gated access patterns.

## A vault answers to the resource, not to its holder

The three containers are usually taught as storage classes, which understates what a vault is. A vault is a node in the engine's own state tree, created and owned by a component, holding exactly one [resource](/contents/tech/core-concepts/asset-oriented-programming) type. Its methods are not free functions on the owning component. They are [blueprint](/contents/tech/core-concepts/blueprints-and-packages) methods, and each one is gated by a role that is defined on the _resource_. In [the fungible vault blueprint](https://github.com/radixdlt/radixdlt-scrypto/blob/v1.3.1/radix-engine/src/blueprints/resource/fungible/fungible_vault.rs#L266-L273) the map is explicit: `take`, `take_advanced` and `lock_fee` require the withdrawer role, `put` the depositor role, `recall` the recaller role, `burn` the burner role, and `freeze` and `unfreeze` the freezer role.

On a freely transferable token most of those roles are set open at creation, because a token nobody may withdraw is not a token. What protects a user's balance is therefore not the vault. It is the [account component](/contents/tech/core-protocols/smart-accounts) that holds the vault, whose own [access rules](/contents/tech/core-concepts/access-rules-and-auth-zones) put the owner badge in front of `withdraw`. A manifest reaches the vault by going through the account, and the account is where the check lives. The vault is the container; the component around it is the lock. Distinguishing the two matters for anyone writing a blueprint that stores other people's assets, because a vault handed out or reachable by another route carries no protection of its own.

Buckets are the other half of the same design. A bucket exists only for the length of a [transaction](/contents/tech/core-protocols/transaction-manifests), cannot be written into component state, and must be empty or returned to a vault before the transaction finalizes. That single rule is what makes the [conservation guarantee](https://docs.radixdlt.com/docs/buckets-and-vaults) checkable by the engine instead of by an auditor: a transaction that would lose, duplicate or strand a token fails at commit rather than succeeding quietly, and there is no path by which tokens become permanently stuck in a contract that forgot to implement a withdrawal. Proofs sit outside this flow entirely. A proof is evidence that some quantity of a resource is held, placed in an [auth zone](/contents/tech/core-concepts/access-rules-and-auth-zones) for the duration of a call and then dropped. It moves nothing, so presenting a badge to a method that demands one costs neither the badge nor a transfer.

## When the boundary failed (August 2026)

The distinction above stopped being academic on 31 August 2026. In the [Hyperlane asset drain and network halt](/contents/history/hyperlane-asset-drain-2026), transactions took resources out of vaults belonging to other people without ever going through the accounts that held them. The engine's reference check accepted a vault named directly in a manifest as a valid direct-access reference on the strength of its blueprint alone, and once the caller held that reference, `take` was gated only by the resource's withdrawer role, which on a freely transferable token is open. The account's access rules were never consulted because the account was never called. The full account of the defect, with the source references, is on the [Radix Engine](/contents/tech/core-protocols/radix-engine) page.

Nothing in the container model itself was broken by this. Conservation held, buckets still balanced, and no token was duplicated or destroyed. What failed was the assumption that a vault is only ever reachable through the component that owns it, which is the assumption everything above rests on.

## External Links

- [Radix Docs: Resources](https://docs.radixdlt.com/docs/resources)
- [Radix Docs: Buckets and Vaults](https://docs.radixdlt.com/docs/buckets-and-vaults)
- [Radix Docs: Auth, proofs and access rules](https://docs.radixdlt.com/docs/auth)
- [radixdlt-scrypto v1.3.1: fungible_vault.rs](https://github.com/radixdlt/radixdlt-scrypto/blob/v1.3.1/radix-engine/src/blueprints/resource/fungible/fungible_vault.rs)
