Run Your First Project

All done with installing the Scrypto toolchain? Great, let’s walk through the steps of running and interacting with some Scrypto code in your simulator environment, starting with a new project.

The basic process involves creating a blueprint package with some blueprint Scrypto code, deploying it to your local simulator (as if deploying it to the Radix network’s blueprint catalog), instantiating a Component from the blueprint, and interacting with the component via a simulated transaction.

Creating a New Blueprint Package

First, we’ll create a new blueprint package.

scrypto new-package tutorial

This will scaffold a simple package which contains a single Hello blueprint. Open the new package directory in an IDE with Rust support. Find the instructions on how to setup the VSCode IDE here.

Open up src/lib.rs to see the source that we’ll be compiling and deploying to the simulator.

code tutorial/src/lib.rs

Hello provides a function which instantiates a new component with a new supply of tokens, and a method which allows the caller to get one of those tokens from the instantiated component.

Creating an Account

Before we can deploy, we first need to create an account on the simulator. On Radix, accounts are themselves components, but resim provides commands to make it convenient to create and use accounts in the simulator environment.

Most of commands offered by the resim tool act within the context of an account.

resim new-account

You should get a success message, and at the bottom of the output you should see the created address and private key:

A new account has been created!
Account component address: account_sim1q0r85g5hyuudv57jeyqrts2u5py6mkr8tzccc8vm0hsq6pkemt
Public key: 0217161655220fa4f68fb78584b87cc8fda2c2332a5eb25ce65b21cbc2fc6b529a
Private key: f7d6ff476d2da934343b24def7ef64e7b70c61c9199c9d43ced7bd486703d748
No configuration found on system. will use the above account as default.

Please do not use these credentials on the main network, as your private key will be stored in plain text.

If you do not see the line about setting your default account, then you already created an account previously. Either reset your entire simulator with the resim reset command and try again, or set this new account as your default account with the following command:

resim set-default-account <ACCOUNT_COMPONENT_ADDRESS> <PRIVATE_KEY>

Save the address of your new account component to an environment variable to make your life easier later. For example:

export account=account_sim1q0r85g5hyuudv57jeyqrts2u5py6mkr8tzccc8vm0hsq6pkemt
export pubkey=0217161655220fa4f68fb78584b87cc8fda2c2332a5eb25ce65b21cbc2fc6b529a
export privkey=f7d6ff476d2da934343b24def7ef64e7b70c61c9199c9d43ced7bd486703d748

On Windows, do

# Using the PowerShell
$account="account_sim1q0r85g5hyuudv57jeyqrts2u5py6mkr8tzccc8vm0hsq6pkemt"
$pubkey="0217161655220fa4f68fb78584b87cc8fda2c2332a5eb25ce65b21cbc2fc6b529a"
$privkey="f7d6ff476d2da934343b24def7ef64e7b70c61c9199c9d43ced7bd486703d748"

Displaying the Account

You can look at the resources on your new account by running:

resim show $account

You will get something like this:

Component: account_sim1q0r85g5hyuudv57jeyqrts2u5py6mkr8tzccc8vm0hsq6pkemt
Blueprint: { package_address: package_sim1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpsuluv44, blueprint_name: "Account" }
Authorization
├─ "deposit_batch" => AllowAll
├─ "balance" => AllowAll
└─ "deposit" => AllowAll
State: Struct(KeyValueStore("f3e28b91854e6b07f805eff77b3a59e18f2ad2aa9da4b6915d7b25f0985854a302040000"))
Key Value Store: account_sim1q0r85g5hyuudv57jeyqrts2u5py6mkr8tzccc8vm0hsq6pkemt(f3e28b91854e6b07f805eff77b3a59e18f2ad2aa9da4b6915d7b25f0985854a3, 1026)
└─ ResourceAddress("resource_sim1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzqu57yag") => Vault("f3e28b91854e6b07f805eff77b3a59e18f2ad2aa9da4b6915d7b25f0985854a304040000")
Resources:
└─ { amount: 1000000, resource address: resource_sim1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzqu57yag, name: "Radix", symbol: "XRD" }

This reads as:

Caption Description

component

All RadixDLT accounts are component and as such they have a ComponentAddress.

Blueprint

A set of component belong to a blueprint. A set of Blueprints belong to a package. Packages have addresses, just like component.

Authorization

All components have a set of authorization rules. Here everyone has access to the deposit and the deposit_batch methods on the users account. This means that everyone can send you any token.

State

Components have a struct that contain all the data they can work on. This complete set of data stored by the component is called the state. The state of the account component consists in a single KeyValueStore where keys are ResourceAddresses (token addresses), and values are the Vaults that can store those resources on the account’s behalf.

Resources

Here is the list of all the resources (tokens) the account owns. There are Fungible and Non-Fungible resources on the Radix DLT.

Deploying the Package

Next, we’ll publish our package:

cd tutorial
resim publish .

You should see the published package’s address in the output. Save that address in the $package environment variable.

export package=<package_address_returned_by_resim_publish>

Component Instantiation

Now that our package is deployed "on ledger" in the simulator, we will want to instantiate a component from its blueprint. Let’s investigate the Hello blueprint to see how we can do that.

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

instantiate_hello() is a function that creates a new component from this blueprint and returns its address. In detail:

  1. It creates a new Bucket with a Fungible Token of an initial supply of 1000.

  2. It creates a new Vault and puts the bucket into it.

  3. It calls the instantiate method on the component that will create the component without an Address,

  4. It calls the globalize method on the component to make it globally accessible adding an Address to it.

Now we will instantiate a Hello component by calling the instantiate_hello function on the Hello blueprint.

resim call-function $package Hello instantiate_hello

The output should look something like this:

Transaction Status: SUCCESS
Transaction Fee: 1.004125 XRD burned, 0.05020625 XRD tipped to validators
Cost Units: 10000000 limit, 1004125 consumed, 0.000001 XRD per cost unit
Execution Time: 67 ms
Instructions:
├─ CallMethod { component_address: component_sim1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqgyhcl2, method_name: "lock_fee", call_data: Struct(Decimal("10")) }
├─ CallFunction { package_address: package_sim1qxsh3hmhus47jwnva2wzndc706j3pygdv06cd2rqydeq0grjgh, blueprint_name: "Hello", method_name: "instantiate_hello", arg: Struct() }
└─ CallMethodWithAllResources { component_address: account_sim1q0r85g5hyuudv57jeyqrts2u5py6mkr8tzccc8vm0hsq6pkemt, method: "deposit_batch" }
Instruction Outputs:
├─ ()
├─ ComponentAddress("component_sim1qf2f2xe2rl3zy4cvl9pt90aj94ca8tz84w3sqfkzrsks9thtea")
└─ ()
Logs: 0
New Entities: 2
└─ Component: component_sim1qf2f2xe2rl3zy4cvl9pt90aj94ca8tz84w3sqfkzrsks9thtea
└─ Resource: resource_sim1qqc3ux4mxuh8y8a5whfsqfmfcpxmun63msrdgvkhpqdqkqv76m

This reads as:

Caption

Description

Transaction Status

Transaction was successful.

Transaction Fee and Cost Units

This sections describes the fees you had to pay to execute this transaction. Read more about fees here.

Execution Time

The transaction took 67 milliseconds to execute.

Instructions

The transaction first executed a call to lock the fees. Then it executed one CallFunction instruction, that called instantiate_hello function which in turn issued a CallMethodWithAllResources instruction.

Instruction Outputs

The CallFunction instruction returned the ComponentAddress of the new component and the CallMethodWithAllResources and fee locking instruction returned empty tuples.

Logs

There were no logs.

New Entities

There were two new entities created the Hello component and the HelloToken resource.

This will create two new entities with two different addresses:
  • a new HelloToken with a ResourceAddress,

  • and your fresh Hello component having a ComponentAddress

Save this to the $component environment variable:

export component=<component_address_returned_by_resim_call_function>

On Radix, tokens and other assets are created as system-level resources, not blueprints, and the definition of the resources contains the parameters for the supply you have requested from the system.

You can investigate these new addresses, if you wish:

resim show <address>

Component Call

First let’s investigate the free_token method:

// 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 following is done in the free_token method:

  1. It logs an info message with the current balance of the HelloToken.

  2. It takes a bucket with one of the HelloToken from the Vault and returns it to the caller.

  3. The Vault now has one less HelloToken in it.

All buckets must be returned to a Vault (or burned) by the end of the transaction, otherwise the system will return an error.

Next, we’ll call the free_token method on our new component.

resim call-method $component free_token

This requires a different resim command than the one we just used since we are now calling a method on an instantiated component instead of the function of a blueprint.

The output should look something like this:

Transaction Status: SUCCESS
Transaction Fee: 1.364579 XRD burned, 0.06822895 XRD tipped to validators
Cost Units: 10000000 limit, 1364579 consumed, 0.000001 XRD per cost unit
Execution Time: 73 ms
Instructions:
├─ CallMethod { component_address: component_sim1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqgyhcl2, method_name: "lock_fee", call_data: Struct(Decimal("10")) }
├─ CallMethod { component_address: component_sim1qf2f2xe2rl3zy4cvl9pt90aj94ca8tz84w3sqfkzrsks9thtea, method_name: "free_token", call_data: Struct() }
└─ CallMethodWithAllResources { component_address: account_sim1q0r85g5hyuudv57jeyqrts2u5py6mkr8tzccc8vm0hsq6pkemt, method: "deposit_batch" }
Instruction Outputs:
├─ ()
├─ Bucket(1024u32)
└─ ()
Logs: 1
└─ [INFO ] My balance is: 1000 HelloToken. Now giving away a token!
New Entities: 0

This reads as:

Caption Description

Transaction status

Transaction was successful.

Transaction Fee and Cost Units

This sections describes the fees you had to pay to execute this transaction. Read more about fees here.

Execution Time

The transaction took 73 milliseconds to execute.

Instructions

The transaction first locked the fees. Then it executed one CallMethod instruction, that called free_token method which in turn issued a CallMethodWithAllResources instruction to store the HelloToken in your account.

Instruction outputs

The CallMethod instruction returned a bucket containing one HelloToken and the CallMethodWithAllResources and fee locking instruction returned empty tuples.

Logs

There was one log message. The message was: [INFO ] My balance is: 1000 HelloToken. Now giving away a token!

And now you have a shiny new HelloToken in your account, and your Hello component has one less. You can verify this with some investigation using resim show on each component.

You can create more accounts, and change which one you’re acting as, by running:

resim set-default-account <ACCOUNT_COMPONENT_ADDRESS> <PRIVATE_KEY>

Final Notes

If you make changes to the structs within your code, then unfortunately you will have to run through the entire publish-instantiate-call flow from scratch, saving the new addresses as they appear. If you only make implementation changes then it is possible to update your package with:

resim publish . --package-address $package

At any point you can instantly get a clean slate in the simulator by running:

resim reset

You almost certainly need to do this if you switch to working on a different project.

That concludes this most basic tutorial on using resim. We suggest to continue your learning journey by reading the "language description" section here.