Hello World!

A good "Hello, World!" example provides the simplest possible piece of code to understand the basics of a new language. However, Scrypto isn’t just a typical language – it is specialized for the management of assets on a decentralized network. So rather than just printing "Hello, World!" to a console, our example will hand out a token! Hopefully you’ll get a taste of how asset-oriented programming with Scrypto for DeFi works.

You can find the code for this example on github here, or by simply creating a new package with scrypto new-package.

File Structure

Our hello-world package has the same layout of files as documented here.

Let’s jump straight into the source file src/lib.rs.

Building a Blueprint

A blueprint is the code that defines a shared data structure and implementation. Multiple blueprints are grouped into a package.

In this example, we have only one blueprint in the package called Hello, which defines:

  • The state structure of all Hello components (a single vault, which is a container for resources);

  • A function new, which instantiates a Hello component;

  • A method free_token, which returns a bucket of HelloToken each time invoked.

For more on components and blueprints, see here.

use scrypto::prelude::*;

blueprint! {
    struct Hello {
        sample_vault: Vault,
    }

    impl Hello {
         pub fn new() -> Component {
            // stripped
         }

         pub fn free_token(&mut self) -> Bucket {
            // stripped
         }
    }
}

Instantiating a Component

The way to instantiate a component is through the instantiate() method on the state structure, after providing the initial values for all the fields.

Self {
    sample_vault: Vault::with_bucket(my_bucket),
}
.instantiate()

ResourceDef, Vault and Bucket

In Scrypto, assets like tokens, NFTs, and more are not implemented as blueprints or components. Instead, they are types of resources that are configured and requested directly from the system.

To define a new resource, we use the ResourceBuilder, specifying the metadata and initial supply. We can use the ResourceBuilder to create a simple fungible-supply token called HelloToken like this:

let my_bucket: Bucket = ResourceBuilder::new_fungible(0)
    .metadata("name", "HelloToken")
    .metadata("symbol", "HT")
    .initial_supply_fungible(1000);

Resources have many more configuration parameters that can be used to define a range of asset behaviors; this is only a very simple example.

Once created, the 1000 resource-based HelloToken tokens are held in transient container my_bucket. To permanently store the created resources, we need to put them into a Vault like this:

let vault: Vault = Vault::with_bucket(my_bucket);

Completing the new function

Now that we know how to define a new resource with the ResourceBuilder, let’s complete the new function. This function will create a new HelloToken definition with an initial supply of 1000, store the 1000 tokens inside a state struct and instantiate a component from that state.

pub fn new() -> Component {
    // 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(0)
        .metadata("name", "HelloToken")
        .metadata("symbol", "HT")
        .initial_supply_fungible(1000);

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

Completing the free_token method

We want the free_token method to take a HelloToken from the sample_vault and return it to the caller. We can achieve this by calling the take method on our vault:

// 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)
}

Now Say Hello

Let’s deploy, instantiate, and send a transaction to our code.

  1. Create a new account, and save the account address:

    resim new-account
  2. Publish the package, and save the package address:

    resim publish .
  3. Call the new function to instantiate a component, and save the component address:

    resim call-function <PACKAGE_ADDRESS> Hello new
  4. Call the free_token method of the component we just instantiated:

    resim call-method <COMPONENT_ADDRESS> free_token
  5. Check out our balance:

    resim show <ACCOUNT_ADDRESS>