Scrypto v0.4 release notes

This page contains all of the major changes between the v0.3.0 and v0.4.0 versions of Scrypto. V0.4.0 introduces a new system-level authorization layer as well as a wide array of changes to allow this layer to work and integrate with the existing systems. The introduction of this new auth system unified component and resource authorization under a single system whose interfaces are very syntactically similar.

The addition of this layer prompted the need to slightly change the component instantiation process, the addition of new transaction manifest instructions, and making minor changes to some of the methods on buckets and vaults.

Release Summary

The following is a quick summary as to what is included in this release of Scrypto:

  • Added a way to interact with your dApps from a front-end through the public-test-environment (PTE).

  • Added a new system-level authorization system to Scrypto.

  • Slightly changed the component instantiation process to accommodate for the new authorization system.

  • Changed the account blueprint to accommodate for the changes in the authorization system.

  • Removed the old #[auth(…​)] macro.

  • Removed resource flags in favor of the resource behavior being specified through a set of methods on the resource builder. More information can be found here.

  • Renamed a number of types to make them more closely aligned with their purpose.

  • Added a number of new transaction manifest instructions.

  • Made minor changes to the resim cli.

  • Added support for proper transaction signing using the accounts' private key.

General Changes

This section of the document lists the general changes which have been made in v0.4.0.

Renaming

v0.3.0

v0.4.0

Note

Address

{ResourceAddress, ComponentAddress and PackageAddress}

We decided to split the Address type into more specific types for the three addressable objects. We are giving more information on this bellow.

ResourceDef

ResourceManager

BucketRef

Proof

We decided to rename this while changing to the new authentication system. Now, Proofs are used everywhere you need authentication (method calls, resource authorization, etc…​)

NonFungibleKey

NonFungibleId

Context

Runtime

Mid

LazyMapId

Vid

VaultId

Rid

ProofId

Bid

BucketId

Proofs (from BucketRefs)

In v0.3, When you wanted your users to show that they owned a certain amount of resource to one of your methods without giving ownership of the assets, they used to create and present a BucketRef. With the new authentication system, this idea now also applies to Vaults, where you can now prove that a certain vault, in your account for example, contains an amount of a specific resource. Now, you don’t have to get a bucket out of the vault first to prove ownership of the assets. That’s why we decided to change the naming of BucketRefs.

A nice problem that this solves, that was not working in v0.3, is that you are now able to provide a Proof of a restricted transfer resource to methods without having the authority to transfer the asset itself. That way, your component can create a badge that only it can transfer and still have its users present that badge as a Proof.

Addresses

We decided to remove the generic Address type and add more specific types for each addressable things - ResourceAddress, ComponentAddress and PackageAddress. This now allows you to accept a specific type of address in a method or function’s parameter and the system will make sure that the user provides the right type of address when calling your component.

We also decided to change the way you are converting the address to its actual object. Here is an example on how to do this.

pub fn random(component_address: ComponentAddress, resource_address: ResourceAddress, package_address: PackageAddress) {
    let component: &Component = borrow_component!(component_address);
    let package: &Package = borrow_package!(package_address);
    let resource: &ResourceManager = borrow_resource_manager!(resource_address);
}

Decimal Changes

The Decimal type has had a few changes made to it in this version of Scrypto. Most notably:

  • Added overflow checks to the type. You now get a runtime error when a Decimal overflows.

  • Added rounding methods such as: decimal.floor(), decimal.ceiling(), and a more generic decimal.round().

  • The BigDecimal type has been removed. Consider using the Decimal type instead.

Miscellaneous Changes

  • The NonFungibleId type no longer has a from_u128 function. If you need to create a NonFungibleId from a u128, then use NonFungibleId::from_bytes(number.to_be_bytes().to_vec()).

  • Creating a random NonFungibleId is so common that we decided to add a random() function on NonFungibleId to allow you to easily do that.

  • Added a NonFungibleAddress type. This acts as a more global address that allows someone to refer to a specific ID of a certain non fungible resource with a single address.

Account Component Changes

Changed methods for withdrawing

  • Changed the withdraw method to not take a quantity anymore and return all resources of the specified address instead.

  • Added a withdraw_by_amount(amount, resource_address) method to be able to withdraw a specific resource by amount (just like withdraw in previous versions)

  • Renamed the method withdraw_non_fungibles to withdraw_by_ids

Added methods for creating proofs

You are now able to create Proof (called BucketRefs in previous versions) directly by calling methods on the account component.

  • Added the method create_proof(resource_address) to create a Proof of the complete amount of a specific resource held inside the account. This method locks the vault containing the resource so that you cannot remove resources from it.

  • Added the method create_proof_by_amount(amount, resource_address) to create a Proof of a specified quantity and resource. This method locks only the requested amount from the Vault.

  • Added the method create_proof_by_ids(ids: BTreeSet<NonFungibleId>, resource_address) to create a Proof of non fungible resources. This method locks all the provided ids so that you cannot remove them from the Vault after.

Added a method for fetching the balance of a particular resource

We added the method balance(resource_address) on the account component so that you are able to fetch the balance of a particular resource that an account has. Be warned, someone could fake their balance by getting a flashloan!

Component Changes

The changes made to components are mainly related to how they are instantiated and how you provide its method access authentication rules, more specifically:

  • Instantiating a component now returns a ComponentAddress instead of a Component.

  • Components now require a call to .globalize() after .instantiate() to get an address assigned to them so that they can be used by people.

  • Optionally, you may call .add_access_check() after .instantiate() and before .globalize() to add method access rules to components.

The example code below highlights how this may be done:

  • Scrypto v0.4.0

  • Scrypto v0.3.0

use scrypto::prelude::*;

blueprint! {
    struct Sample {}

    impl Sample {
        pub fn new() -> ComponentAddress { (1)
            return Self{}
                .instantiate()
                .globalize(); (2)
        }
    }
}
1 Instantiation functions now return a ComponentAddress and not a Component.
2 A call to .globalize is now required before the component can be used.
use scrypto::prelude::*;

blueprint! {
    struct Sample {}

    impl Sample {
        pub fn new() -> Component {
            return Self{}
                .instantiate();
        }
    }
}

Resources

Resource Creation

The creation of new resources is almost identical to v0.3.0 with a few exceptions to how the resource behavior and authorizations is now specified. More specifically, we:

  • Removed resource flags in favor of a new system of defining the resource behavior which relies on the new rule-based authorization system.

  • Changed the way in which resource divisibility is specified. It is now specified on the resource builder through a call to .divisibility.

  • Unified the way of specifying the initial supply of fungible and non-fungible resources through the .initial_supply() method on the resource builder for both fungible and non-fungible resources.

The following comparison between v0.3.0 and v0.4.0 helps illustrate the differences between the two versions:

  • Scrypto v0.4.0

  • Scrypto v0.3.0

let my_tokens: Bucket = ResourceBuilder::new_fungible()
    .metadata("name", "New Token")
    .metadata("symbol", "NT")
    .divisibility(7) (1)
    .mintable(rule!(require(admin_badge.resource_address())), LOCKED) (2)
    .burnable(rule!(require(admin_badge.resource_address())), LOCKED) (2)
    .initial_supply(10); (3)
1 Divisibility is now specified in its own chained method call instead of as an argument to one of the resource builder functions.
2 Resource behavior is no longer specified through flags or mutable flags and is instead specified through the appropriate methods on the resource builder.
3 The initial supply of both fungible and non-fungible resources is now specified through a call to .initial_supply().
let my_tokens: Bucket = ResourceBuilder::new_fungible(7) (1)
    .metadata("name", "New Token")
    .metadata("symbol", "NT")
    .flags(MINTABLE | BURNABLE) (2)
    .badge(admin_badge.resource_def(), MAY_MINT | MAY_BURN) (2)
    .initial_supply_fungible(10); (3)
1 Divisibility used to be passed as an argument to the new_fungible function on the resource builder.
2 The token behavior used to be defined through a set of flags which we can enable or disable on the resource.
3 The initial supply of fungible resources used to be specified through a method call to .initial_supply_fungible().

Resource Management

The ResourceManager is meant to replace the ResourceDef, meaning that all operations which had been possible to do through the ResourceDef in the past are now possible through the ResourceManager. This means operations such as minting additional tokens, burning tokens, updating metadata, and so on is now done through the ResourceManager of a resource. In summary, the following are the changes which have been made in this area:

  • Resource management is no longer done through the ResourceDef, instead it is now done through a resource’s ResourceManager.

  • A resource’s ResourceManager can be obtained by borrow_resource_manager!(resource_address).

Resource Containers

Buckets and Vaults have had quite a number of methods added, removed, and renamed to fit within the major renaming of v0.4.0 and with the new rule-based authorization system. The following is the list of method changes on these two types:

Bucket

The following table contains all of the renamed methods on the Bucket type:

v0.3.0

v0.4.0

Note

bucket.burn_with_auth()

bucket.burn()

There is no longer a burn_with_auth method on buckets. Instead, you may use the bucket.burn() method with the appropriate proofs in the Auth-Zone.

bucket.get_non_fungible_keys()

bucket.non_fungible_ids()

The return type on this method has also been changed. In v0.3.0 this method returned a Vec<NonFungibleKey>. However, it now return a set of BTreeSet<NonFungibleId>.

bucket.get_non_fungibles()

bucket.non_fungibles()

bucket.present()

bucket.create_proof()

The following functions have been added to the Bucket type in v0.4.0:

  • bucket.non_fungible()

The following functions have been removed from the Bucket type in v0.4.0. The table below highlights the names of the removed methods as well as how similar functionality can be performed:

v0.3.0 Method

v0.4.0 Equivalent

bucket.resource_def

borrow_resource_manager!(bucket.resource_address())

bucket.get_non_fungible_key()

bucket.non_fungible().id()

bucket.get_non_fungible_data()

bucket.non_fungible().data::<YourType>()

bucket.update_non_fungible_data()

borrow_resource_manager!(bucket.resource_address()).update_non_fungible_data()

Vault

The following table contains all of the renamed methods on the Vault type:

v0.3.0

v0.4.0

Note

vault.take_with_auth()

vault.take()

There is no longer a take_with_auth method on buckets. Instead, you may use the vault.take() method with the appropriate proofs in the Auth-Zone.

vault.take_all_with_auth()

vault.take_all()

There is no longer a take_all_with_auth method on buckets. Instead, you may use the vault.take_all() method with the appropriate proofs in the Auth-Zone.

vault.take_non_fungible_with_auth()

vault.take_non_fungible()

There is no longer a take_non_fungible_with_auth method on buckets. Instead, you may use the vault.take_non_fungible() method with the appropriate proofs in the Auth-Zone.

vault.get_non_fungible_keys()

vault.non_fungible_ids()

The return type on this method has also been changed. In v0.3.0 this method returned a Vec<NonFungibleKey>. However, they now return a set of BTreeSet<NonFungibleId>.

vault.get_non_fungibles()

vault.non_fungibles()

The following functions have been added to the Vault type in v0.4.0:

  • vault.take_non_fungibles()

  • vault.create_proof()

  • vault.create_proof_by_amount()

  • vault.create_proof_by_ids()

  • vault.non_fungible()

The following functions have been removed from the Vault type in v0.4.0. The table below highlights the names of the removed methods as well as how similar functionality can be performed:

v0.3.0 Method

v0.4.0 Equivalent

vault.resource_def

borrow_resource_manager!(vault.resource_address())

vault.get_non_fungible_key()

vault.non_fungible().id()

vault.get_non_fungible_data()

vault.non_fungible().data::<YourType>()

vault.update_non_fungible_data()

borrow_resource_manager!(vault.resource_address()).update_non_fungible_data()

Resim Changes

To accommodate for the new authorization system introduced with this version, resim had some minor changes done to it.

  • Creating a new resim account now shows an additional field for the private key.

$ resim new-account
A new account has been created!
Account component address: 020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a
Public key: 044083a64afb4b630ce7683674a6cdcebc7007aef7cb08f10b2cd491b6ce24ca1204f88bd2a2068e27591f1c5cfbd4fddf9a51f7b2360d784ee1e8fbec8f7476a6
Private key: 7c9fa136d4413fa6173637e883b6998d32e1d675f88cddff9dcbcf331820f4b8
No configuration found on system. will use the above account as default.
  • Setting the default account in resim now requires that the private key is provided. Resim expects that the subcommand is called with the format: resim set-default-account <COMPONENT_ADDRESS> <PRIVATE_KEY>.

  • A resim generate-key-pair subcommand has been added to resim which allows for the generation of a public and private key-pair without the creation of a new account.

  • Multi-signature transactions can be done by specifying the private keys of the signers with the --signing-keys option on the resim run command. Multiple private keys may be provided separated by commas.

  • Resim now allows for package publishing to be exported to a manifest file which includes the WASM byte code and can perform the publishing of the package with resim publish [directory] --manifest output.rtm.

  • Resim now allows for account creation to be exported to a manifest file which includes all of the arguments required for the account to be created already setup and ready to use with resim new-account --manifest output.rtm.

  • The ABI format generated by resim and used in Scrypto has changed between v0.3.0 and v0.4.0. If you rely on the ABI of a blueprint, then you will need to re-export it.

Transaction Manifest Changes

The introduction of the new rule-based authorization system and the renames made to a number of types required that changes be made and additional instructions be added to the transaction manifest in this release.

Before diving into the changes made to the transaction manifest, one thing should be made clear in order for the change log to make sense: before any instructions in the transaction begin execution, the virtual badge of the signers is put into the auth-zone of the transaction. This means that operations which in the past required the cloning and passing of the signers' BucketRef (now called Proof) is no longer required.

General Transaction Manifest Changes

  • Added a new section in the transaction worktop called the Auth-Zone which is designed to be a stack of Proofs.

  • Added new instructions for auth-zone manipulation.

  • Account withdrawals no longer requires a BucketRef (now called Proof) to the Bucket containing the virtual badge. The authorization for that is automatically done through the auth zone.

  • In line with the renames made scrypto-wide, the types used in transaction manifests have also been renamed.

  • Changed the Enum type such that it accepts the string name of the enum instead of the enum values.

Transaction Manifest Renames

The renames made to the transaction manifest syntax are as follows:

v0.3.0 Name

v0.4.0 Name

BucketRef

Proof

NonFungibleKey

NonFungibleId

TAKE_FROM_WORKTOP

TAKE_FROM_WORKTOP_BY_AMOUNT

TAKE_ALL_FROM_WORKTOP

TAKE_FROM_WORKTOP

TAKE_NON_FUNGIBLES_FROM_WORKTOP

TAKE_FROM_WORKTOP_BY_IDS

ASSERT_WORKTOP_CONTAINS

ASSERT_WORKTOP_CONTAINS_BY_AMOUNT

The Address type has also been split into three main types: PackageAddress, ComponentAddress, and ResourceAddress which (as the name suggests) are used to address packages, components, and resources respectively. This means that as of v0.4.0, Address is no longer an accepted type.

New Transaction Manifest Types

The new types introduced to the transaction manifest are as follows:

Name

Description

NonFungibleAddress

Used as a global address for a specific non-fungible token and a specific resource address.

Bytes

Used to represent a hexadecimal string of bytes which is understood by the lexer to be a vector of bytes Vec<u8>.

New Transaction Manifest Instructions

The new instructions introduced to the transaction manifest are as follows:

Name

Description

PUBLISH_PACKAGE

Given some WASM byte-code, this instruction publishes a package with this byte-code.

TAKE_FROM_WORKTOP_BY_AMOUNT

Takes a certain amount of a resource from the transaction worktop and puts it in a Bucket.

TAKE_FROM_WORKTOP_BY_IDS

Takes specific NonFungibleIds of a resource from the transaction worktop and puts it in a Bucket.

ASSERT_WORKTOP_CONTAINS_BY_AMOUNT

Asserts that the transaction worktop contains at least a specific amount of a specific resource.

ASSERT_WORKTOP_CONTAINS_BY_IDS

Asserts that the transaction worktop contains specific NonFungibleIds of a specific resource.

POP_FROM_AUTH_ZONE

The Auth-Zone is a stack of Proofs. This instruction pops the last added Proof off of the Auth-Zone stack.

PUSH_TO_AUTH_ZONE

The Auth-Zone is a stack of Proofs. This instruction pushes a Proof onto the Auth-Zone stack.

CLEAR_AUTH_ZONE

Drops all of the Proofs that are currently in the Auth-Zone.

CREATE_PROOF_FROM_BUCKET

Creates a Proof from a Bucket.

CREATE_PROOF_FROM_AUTH_ZONE

Creates a Proof out of the total amount of a specific resource in the Auth-Zone.

CREATE_PROOF_FROM_AUTH_ZONE_BY_AMOUNT

Creates a Proof out of a specific amount of a specific resource in the Auth-Zone.

CREATE_PROOF_FROM_AUTH_ZONE_BY_IDS

Creates a Proof out of specific NonFungibleIds of a specific resource in the Auth-Zone.

CLONE_PROOF

Clones a Proof.

DROP_PROOF

Drops a Proof such that it’s underlying resource container is no longer locked.

Testing

Changed the way you create accounts

Previously, in your tests, you had to first create a public key and then generate an account address from it. With v0.4, creating a new account in your tests is easier. All you have to do is call the new_account() method on the TransactionExecutor. This method will return a tuple in the form (public_key, signing_key, account_address).

Changed the include_code! macro

When publishing your package, you should now use the compile_package!() macro. You can optionally provide this macro with a parameter for the directory of the package. If you don’t provide one, it will default to the package that the test file is part of. Here is an example:

let package = executor.publish_package(compile_package!()).unwrap();
let other_package = executor.publish_package(compile_package!("../../other_package")).unwrap();

Transaction Building Changes

  • Changed the signature of the TransactionBuilder::new() function. You don’t have to provide the executor as argument anymore.

  • Changed the signature of the TransactionBuilder::build() method to require a nonce. You can get the nonce with the TransactionExecutor and the public key of the signers: executor.get_nonce([public_key])

  • Added an extra step after calling the build(nonce: u64) method. You now have to call the sign([&signing_key]) method to prepare your transaction for execution.

  • Renamed TransactionExecutor::run(transaction) to TransactionExecutor::validate_and_execute(&transaction)

  • Changed the way you provide arguments to your method and function calls. Instead of wrapping the arguments in a vec![] macro, you should use args![] instead. vec! may still be used but you would need to encode the arguments using scrypto_encode()

  • To make it easier to withdraw from an account, you can now simply call the TransactionBuilder’s withdraw_from_account_by_amount(amount, resource_address, account_address) and withdraw_from_account(resource_address, account_address) methods.

This is a lot to take in, so let’s look at an example:

let transaction = TransactionBuilder::new()
    .withdraw_from_account_by_amount(Decimal::one(), RADIX_TOKEN, account1)
    .take_from_worktop(resource_address, |builder, bucket_id| {
        builder.call_method(gumball_machine_address, "buy_gumball", args![
            scrypto::resource::Bucket(bucket_id)
        ])
    })
    .call_method_with_all_resources(account2, "deposit_batch")
    .build(executor.get_nonce([pk]))
    .sign([&sk]);

Changes to the transaction Receipt type

  • Renamed the transaction field to validated_transaction

  • Added field commit_receipt that contains the up and down substates involved in the transaction

  • Added fields new_package_addresses, new_component_addresses and new_resource_addresses