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
instantiate_hello
, which instantiates aHello
component; -
A method
free_token
, which returns a bucket ofHelloToken
each time invoked.
For more on components and blueprints, see here.
use scrypto::prelude::*;
blueprint! {
struct Hello {
sample_vault: Vault,
}
impl Hello {
pub fn instantiate_hello() -> ComponentAddress {
// 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()
.globalize()
ResourceAddress, 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()
.metadata("name", "HelloToken")
.metadata("symbol", "HT")
.initial_supply(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 constructor function
Now that we know how to define a new resource with the ResourceBuilder
, let’s complete the instantiate_hello
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 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()
.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()
}
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.
-
Create a new account, and save the account address:
resim new-account
-
Publish the package, and save the package address:
resim publish .
-
Call the
instantiate_hello
function to instantiate a component, and save the component address:resim call-function <PACKAGE_ADDRESS> Hello instantiate_hello
-
Call the
free_token
method of the component we just instantiated:resim call-method <COMPONENT_ADDRESS> free_token
-
Check out our balance:
resim show <ACCOUNT_ADDRESS>