Blueprints and Components

Scrypto splits the concept of "smart contract" into two parts: blueprints and components.

Scrypto code starts its lifecycle as a blueprint package. Each package contains one or more blueprints, which are deployed to the ledger and define your dApp’s logic.

Blueprints in Scrypto are similar to classes in object-oriented programming. Each blueprint contains declarations of state structure, functions, and methods. All instances (components) instantiated from the same blueprint will behave consistently.

Blueprints can be considered templates for components. A function on the blueprint is expected to perform the instantiation of the blueprint into an active component, typically including configuration parameters for that instance. As templates, blueprints contain no internal state and can hold no resources.

Components then are individual instances of blueprints that expose methods that may be called via transactions or other component logic. Components may contain internal state and hold resources.

A simple example blueprint:

use scrypto::prelude::*;

blueprint! {
    struct Hello {
        // Define what resources and data will be managed by Hello components
        sample_vault: Vault,
    }

    impl Hello {
        // Implement the functions and methods which will manage those resources and data

        // This is a function, and can be called directly on the blueprint once deployed
        pub fn instantiate_hello() -> ComponentAddress {
            // Create a new token called "HelloToken," with a fixed supply of 1000, and put that supply into a bucket
            let my_bucket: Bucket = ResourceBuilder::new_fungible()
                .divisibility(DIVISIBILITY_MAXIMUM)
                .metadata("name", "HelloToken")
                .metadata("symbol", "HT")
                .initial_supply(1000);

            // Instantiate a Hello component, populating its vault with our supply of 1000 HelloToken
            Self {
                sample_vault: Vault::with_bucket(my_bucket),
            }
            .instantiate()
            .globalize()
        }

        // This is a method, because it needs a reference to self.  Methods can only be called on components
        pub fn free_token(&mut self) -> Bucket {
            info!(
                "My balance is: {} HelloToken. Now giving away a token!",
                self.sample_vault.amount()
            );
            // If the semi-colon is omitted on the last line, the last value seen is automatically returned
            // In this case, a bucket containing 1 HelloToken is returned
            self.sample_vault.take(1)
        }
    }
}

The use Declaration

The very first part of a blueprint is the use declaration to import symbols from the Scrypto standard library and/or other libraries. It creates local name bindings with items defined in an external path.

The example scrypto::prelude::* is the list of things that are commonly used in Scrypto. Importing Scrypto prelude saves you from manually importing everything that you need individually.

The blueprint! Macro

The blueprint! macro allows you to define a blueprint using items defined in Rust grammar. It accepts a pair of struct and impl, and produces a blueprint that conforms to the Scrypto application binary interface (ABI).

Inside the struct, you define all the fields that each component instantiated from it will have. The fields can be of any type supported by SBOR, including but not limited to integers, strings, tuples, vectors and maps.

Inside the impl, you define all the functions and methods. You can learn more from this doc.

Blueprint Visibility

All blueprints are currently public. Inner blueprints are not supported but may be introduced in the future.