Introduction
Radix enforces a strict invariant: every resource must exist inside a container at all times. There are two container types: Vaults (permanent, on-ledger storage) and Buckets (temporary, transaction-scoped carriers). The Radix Engine guarantees that resources cannot be duplicated, accidentally destroyed, or left in limbo – if your transaction ends with an undeposited bucket, it fails. This "physical resource" model eliminates entire categories of bugs common in other smart contract platforms.
Vault Patterns
Single-Vault Component
The simplest pattern: a component holds one vault to store a single resource type. A token sale component, for example, stores tokens in a vault and returns XRD payment to the buyer's account.
struct TokenSale {
token_vault: Vault, // holds tokens for sale
xrd_vault: Vault, // collects XRD payments
price: Decimal,
}Multi-Vault Component (HashMap)
When a component needs to manage arbitrary resource types (e.g. a DEX liquidity pool or a wallet-like component), use a HashMap<ResourceAddress, Vault>. When a new resource type is deposited, create a new vault; when an existing type arrives, deposit into the matching vault. Compiled and called under Scrypto 1.4.0 on 29 September 2026, two deposits of XRD land in one vault.
struct MultiVault {
vaults: HashMap<ResourceAddress, Vault>,
}
impl MultiVault {
pub fn deposit(&mut self, bucket: Bucket) {
let addr = bucket.resource_address();
self.vaults
.entry(addr)
.or_insert_with(|| Vault::new(addr))
.put(bucket);
}
}A HashMap sits inside the component's state, so every method call reads the whole map. For a collection that grows without limit, a KeyValueStore<ResourceAddress, Vault> (source) stores each entry separately and loads only the entries a call touches.
Vault Take & Put
Withdraw resources from a vault with .take(amount) (returns a Bucket) or .take_all(). Deposit with .put(bucket). Withdrawing specific non-fungibles needs a NonFungibleVault: .take_non_fungible(&id) and .take_non_fungibles(&ids), where ids is an IndexSet<NonFungibleLocalId>, are defined on ScryptoNonFungibleVault and not on a plain Vault. A component that stores a generic Vault reaches them through .as_non_fungible():
let nft: NonFungibleBucket = self.vault.as_non_fungible().take_non_fungible(&id);Bucket Patterns
Bucket Passing (Move Semantics)
Buckets use Rust's ownership model – passing a bucket to a function moves it. The caller no longer has access. This prevents double-spending at the language level.
A component cannot withdraw from a user's account, so the caller that creates the bucket is a transaction manifest. This one buys from the TokenSale above, and committed in resim under Scrypto 1.4.0:
CALL_METHOD Address("${account}") "lock_fee" Decimal("10");
CALL_METHOD Address("${account}") "withdraw" Address("${xrd}") Decimal("100");
TAKE_FROM_WORKTOP Address("${xrd}") Decimal("100") Bucket("payment");
CALL_METHOD Address("${token_sale}") "buy" Bucket("payment");
CALL_METHOD Address("${account}") "deposit_batch" Expression("ENTIRE_WORKTOP");Bucket Splitting
Use .take(amount) on a bucket to split it into two buckets – the original retains the remainder. This is how you implement partial fills, fee extraction, or distributing resources across multiple destinations within a single transaction.
The Worktop
In transaction manifests, returned resources land on the worktop – a temporary staging area. Use TAKE_FROM_WORKTOP to create named buckets from worktop resources, then pass them to subsequent method calls. Leftover resources fail a transaction in two different places, both tested in resim on 29 September 2026. A named bucket that no later instruction uses is rejected before execution, with DanglingBucket, and no fee is charged. Resources left on the worktop get through validation and fail when the transaction ends, as a committed failure with DropNonEmptyBucket, and the fee is paid. The last instruction in the manifest above, deposit_batch with ENTIRE_WORKTOP, is there to empty it.
Next Steps
- Multi-Component Architecture – split a growing dApp across components that call each other
External Links
- Vaults and Buckets – Official Docs
- Resources – Official Docs
- Permissioned and Regulated Assets – freeze, recall and withdrawal rules on resources, with worked examples
