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.
The Scrypto development team mostly uses VS Code, which has a free Rust extension (rust-lang) that works well. |
Open up src/lib.rs
to see the source that we’ll be compiling and deploying to the simulator.
code tutorial/src/lib.rs
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:
Account component address: 020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a
Public key: 044083a64afb4b630ce7683674a6cdcebc7007aef7cb08f10b2cd491b6ce24ca1204f88bd2a2068e27591f1c5cfbd4fddf9a51f7b2360d784ee1e8fbec8f7476a6
Private key: 7c9fa136d4413fa6173637e883b6998d32e1d675f88cddff9dcbcf331820f4b8
No configuration found on system. will use the above xref:system/accounts.adoc[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
resim set-default-account <ACCOUNT_COMPONENT_ADDRESS> \
<PRIVATE_KEY>
command.
Save the address of your new account Component to an environment variable to make your life easier later. For example:
export account=020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a
export pubkey=044083a64afb4b630ce7683674a6cdcebc7007aef7cb08f10b2cd491b6ce24ca1204f88bd2a2068e27591f1c5cfbd4fddf9a51f7b2360d784ee1e8fbec8f7476a6
export privkey=7c9fa136d4413fa6173637e883b6998d32e1d675f88cddff9dcbcf331820f4b8
On Windows, do
# Using the PowerShell
$account="020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a"
$pubkey="044083a64afb4b630ce7683674a6cdcebc7007aef7cb08f10b2cd491b6ce24ca1204f88bd2a2068e27591f1c5cfbd4fddf9a51f7b2360d784ee1e8fbec8f7476a6"
$privkey="7c9fa136d4413fa6173637e883b6998d32e1d675f88cddff9dcbcf331820f4b8"
Displaying the Account
resim show $account
You will get something like this:
Component: 020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a
Blueprint: { package_address: 010000000000000000000000000000000000000000000000000003, blueprint_name: "xref:system/accounts.adoc[Account]" }
Authorization
├─ "deposit_batch" => AllowAll
└─ "deposit" => AllowAll
State: Struct(LazyMap("bc417218214859fbbf019072394c50cc53d5419f4acd7a660dc7c880f0cce31a02040000"))
Lazy Map: 020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a(bc417218214859fbbf019072394c50cc53d5419f4acd7a660dc7c880f0cce31a, 1026)
└─ ResourceAddress("030000000000000000000000000000000000000000000000000004") => Vault("bc417218214859fbbf019072394c50cc53d5419f4acd7a660dc7c880f0cce31a03040000")
Resources:
└─ { amount: 1000000, resource address: 030000000000000000000000000000000000000000000000000004, name: "Radix", symbol: "XRD" }
This reads as:
Caption | Description |
---|---|
All RadixDLT accounts are Component and as such they have a |
|
|
|
|
|
|
Component 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. Account Component' state is stored in a single LazyMap where keys are ResourceAddresses (token addresses), and values are the Vaults that can store those Resources on the Account's behalf. |
Component Instantiation
Now that our package is deployed "on ledger" in the simulator, we will investigate the Hello
Component.
// 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: xref:scrypto-lang/vaults-and-buckets.adoc[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 method that creates a new Component and returns its address. In detail:
-
It creates a new
Bucket
with a Fungible Token of an initial supply of 1000. -
It creates a new
Vault
and puts theBucket
into it. -
It calles the
instantiate
method on theComponent
that will create the Component without an Address, -
It calls the
globalize
method on theComponent
to make it globally accessible adding an Address to it.
Now we will instantiate a Hello
Component by calling the new
function on the Hello
blueprint.
resim call-function $package Hello instantiate_hello
The output should look something like this:
Transaction Status: SUCCESS
Execution Time: 25 ms
Instructions:
├─ CallFunction { package_address: 01a1e4ab9ff224f540ac0cc15ca74cc0ee89c79992afbc60c6716b, blueprint_name: "Hello", function: "instantiate_hello", args: [] }
└─ CallMethodWithAllResources { component_address: 020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a, method: "deposit_batch" }
Instruction Outputs:
├─ ComponentAddress("027dfeaa7617bcab867273dab69be7dfa26cd3694ccef26c75dfb8")
└─ ()
Logs: 0
New Entities: 2
└─ xref:scrypto-lang/blueprints-and-components.adoc[Component]: 027dfeaa7617bcab867273dab69be7dfa26cd3694ccef26c75dfb8
└─ Resource: 03315d52f961068c65758c554b76f08d48713a723b1636c5a5363e
This reads as:
Caption |
Description |
Transaction Status |
Transaction was successful. |
Execution Time |
The transaction took 25 milliseconds to execute. |
Instructions |
The transaction executed contained one |
Instruction Outputs |
The |
Logs: There were no xref |
scrypto-lang/logging.adoc[logs]. |
New Entities |
-
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 resources' definition contain the parameters for the supply of resource 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) -> xref:scrypto-lang/vaults-and-buckets.adoc[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:
-
It logs an info message with the current balance of the
HelloToken
. -
It takes a
Bucket
with one of theHelloToken
from theVault
and returns it to the caller. -
The
Vault
now has one lessHelloToken
in it.
All Buckets must be returned to a |
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
Execution Time: 18 ms
Instructions:
├─ CallMethod { component_address: 027dfeaa7617bcab867273dab69be7dfa26cd3694ccef26c75dfb8, method: "free_token", args: [] }
└─ CallMethodWithAllResources { component_address: 020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a, method: "deposit_batch" }
Instruction Outputs:
├─ xref:scrypto-lang/vaults-and-buckets.adoc[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. |
Execution Time |
The transaction took 18 milliseconds to execute. |
Instructions |
The transaction executed contained one |
Instruction outputs |
The |
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 . --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.
If you ever pull the latest from the Scrypto GitHub repo and see that the core Scrypto implementation has changed (i.e. stuff above the
in order to pick up the changes. And sometimes you will also need to run
to clear the simulator state. |
That concludes this most basic tutorial on using resim
. More content to come!