Introduction
Scrypto separates the concept of "smart contract" into two distinct things: blueprints (reusable templates) and components (live instances on the ledger). This separation enables a modular architecture where small, well-tested blueprints are composed into larger systems — much like how object-oriented programming uses classes and composition. The official Scrypto Design Patterns documentation recommends this approach as the default for non-trivial dApps.
Separation of Concerns
Instead of building a monolithic blueprint, decompose your dApp into small blueprints with a single responsibility:
- TokenSale — handles pricing and token distribution
- Treasury — manages collected funds, fee withdrawal
- AccessControl — issues and manages badges
- PriceFeed — wraps an oracle and exposes prices to other components
Each blueprint is easier to test in isolation, reason about for security, and audit independently. Smaller blueprints are also more reusable — a Treasury blueprint can serve a DEX, a lending protocol, or a DAO with no changes.
Inter-Component Calls
Components call each other's methods using their on-ledger address. A component can store another component's address in its state and invoke methods on it:
struct MyDapp {
treasury: Global<Treasury>,
price_feed: Global<PriceFeed>,
}
impl MyDapp {
pub fn buy(&mut self, payment: Bucket) -> Bucket {
let price = self.price_feed.get_price("XRD/USD");
// ... calculate tokens owed ...
self.treasury.deposit(payment);
// ... return tokens ...
}
}Blueprint Reuse & the Catalog
Radix encourages sharing blueprints as published packages that anyone can instantiate. The Blueprint Catalog concept allows developers to find, audit, and reuse existing blueprints rather than reimplementing common patterns.
Importing External Blueprints
To use a blueprint from another package, import it by its package address and instantiate or call it. The Scrypto extern_blueprint! macro generates type-safe bindings:
extern_blueprint! {
"package_rdx...", // on-ledger package address
PriceFeed { // blueprint name
fn get_price(&self, pair: String) -> Decimal;
}
}This generates a type you can use in your component's state and method signatures, with full compile-time type checking.
Factory Pattern
A common pattern for dApps that create multiple similar components (e.g. a DEX creating liquidity pools): write a factory blueprint whose instantiation function creates and configures child components, returning their addresses and any admin badges.
