Git Product home page Git Product logo

radixdlt / radixdlt-scrypto Goto Github PK

View Code? Open in Web Editor NEW
401.0 28.0 118.0 268.98 MB

Scrypto is the asset-oriented smart contract programming language of the Radix network. It allows you to quickly build secure and composable dApps.

Home Page: https://developers.radixdlt.com/

License: Other

Rust 97.05% Shell 0.27% WebAssembly 2.47% Meson 0.01% C 0.03% Python 0.16% Dockerfile 0.02%
builders defi scrypto smartcontracts

radixdlt-scrypto's Introduction

Scrypto

CI

Language for building DeFi apps on Radix.

Documentation: https://docs.radixdlt.com/docs/scrypto-1

Installation

  1. Install Rust - this requires Rust 1.70+ (if rust is already installed, upgrade with rustup update)
    • Windows:
      git config --system core.longpaths true
    • macOS:
      • Make sure you have the xcode command line tools: xcode-select --install.

      • Install cmake: brew install cmake llvm
        Add LLVM to the system path by adding below line to the:

        • ~/.profile if bash is the default shell
        • ~/.zshrc if zsh is the default shell
        • respective config file in case of other shell
        PATH="$(brew --prefix llvm)/bin:$PATH"
        

        You can check, which shell is the default one by inspecting $SHELL variable:

        echo $SHELL
      • Install the Rust compiler:

      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    • Linux:
      • Make sure a C++ compiler, LLVM, cmake and clang is installed:
      sudo apt install build-essential llvm cmake clang
      • Install the Rust compiler:
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  2. Enable cargo in the current shell:
    • Windows:
      • Start a new PowerShell
    • Linux and macOS:
      source $HOME/.cargo/env
  3. Add WebAssembly target
    rustup target add wasm32-unknown-unknown
  4. Install Radix CLIs
    cargo install radix-clis

Getting Started

If you want a quick walkthrough of how to deploy and run some code, please see the Run Your First Project tutorial. If you prefer to soldier through on your own, keep reading below.

Writing Scrypto Code

  1. Start by creating a new package:
scrypto new-package <package_name>
cd <package_name>
  1. Check out the files under your current directory:
  • Source code is within src/lib.rs;
  • Test code is within tests/lib.rs.
  1. Build your package:
scrypto build
  1. Run tests:
scrypto test

Playing with Radix Engine

Action Command
Create an account resim new-account
Change the default account resim set-default-account <account_address> <account_public_key>
Create a token with fixed supply resim new-token-fixed <amount>
Create a token with mutable supply resim new-token-mutable <minter_resource_address>
Create a badge with fixed supply resim new-badge-fixed <amount>
Create a badge with mutable supply resim new-badge-mutable <minter_resource_address>
Mint resource resim mint <amount> <resource_address> <minter_resource_address>
Transfer resource resim transfer <amount> <resource_address> <recipient_component_address>
Publish a package resim publish <path_to_package_dir>
Call a function resim call-function <package_address> <blueprint_name> <function> <args>
Call a method resim call-method <component_address> <method> <args>
Export the definition of a package resim export-package-definition <package_address> <output>
Show info about an entity resim show <id>
Show info about default account resim show
List all entities resim show-ledger
Reset ledger state resim reset

Note: The commands use the default account as transaction sender.

Compile blueprints with dockerized radix-clis

Follow this guide to build reproducible WASM and RDP files for your Scrypto blueprints.

Using local docker image

The Dockerfile in the root of the repo should be work to build a docker image which will contain all the dependencies needed to be able build a blueprint using scrypto.

Build the docker image like. From the repo root

docker build -t radixdlt/radix-clis .

Then build your package by just running

docker run -v <path-to-your-scrypto-crate>:/src radixdlt/radix-clis

Using published docker image

If you would like to avoid building the docker image, you can skip the build step and do the second step directly, docker will automatically download the docker image we publish

Build your blueprints directly with

docker run -v <path-to-your-scrypto-crate>:/src radixdlt/radix-clis

Project Layout

  • radix-blueprint-schema-init: Blueprint schema initialization structures, used by Radix Package Definition (RPD).
  • radix-clis: Various CLI tools, like resim, scrypto, rtmc and rtmd.
  • radix-common-derive: Macros for defining Decimal and PreciseDecimal.
  • radix-common: Common libraries used by Radix Engine and Scrypto.
  • radix-engine: The Radix Engine implementation.
  • radix-native-sdk: Library to assist native blueprint development.
  • radix-sbor-derives: Macros for encoding and decoding Scrypto SBOR and Manifest SBOR data.
  • radix-substate-store-impls: Various substate store implementations.
  • radix-substate-store-interface: The interface of any substate store.
  • radix-substate-store-queries: Interprets data in substate data by injecting high-level knowledge.
  • radix-transaction-scenarios: Defines various transaction scenarios, for testing.
  • radix-transactions: Radix transaction manifest compiler, transaction models, signing and validating logic.
  • sbor-derive: Macros for encoding and decoding SBOR data.
  • sbor: A generic binary data format, upon which Scrypto SBOR and Manifest SBOR are built.
  • scrypto-derive: Macros for defining blueprints.
  • scrypto-test: Library for testing Scrypto blueprints.
  • scrypto: Scrypto language abstraction.

LFS

Assets under assets-lfs are stored in Git LFS.

To fetch files from LFS, install git-lfs first:

  • MacOS
    brew install git-lfs
    
  • Ubuntu
    curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
    sudo apt-get install git-lfs
    

and then:

git lfs install
git lfs pull

Contribute

To learn more about how to contribute to this project, read the Contributing Guide.

License

The executable components of the Scrypto Code including libraries, CLIs and docker images, are licensed under the Radix Software EULA.

The code in this repository is released under the Radix License 1.0 (modified Apache 2.0):

Copyright 2023 Radix Publishing Ltd incorporated in Jersey, Channel Islands.

Licensed under the Radix License, Version 1.0 (the "License"); you may not use
this file except in compliance with the License.

You may obtain a copy of the License at:
https://www.radixfoundation.org/licenses/license-v1

The Licensor hereby grants permission for the Canonical version of the Work to
be published, distributed and used under or by reference to the Licensor’s
trademark Radix® and use of any unregistered trade names, logos or get-up.

The Licensor provides the Work (and each Contributor provides its Contributions)
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR
PURPOSE.

Whilst the Work is capable of being deployed, used and adopted (instantiated) to
create a distributed ledger it is your responsibility to test and validate the
code, together with all logic and performance of that code under all foreseeable
scenarios.

The Licensor does not make or purport to make and hereby excludes liability for
all and any representation, warranty or undertaking in any form whatsoever,
whether express or implied, to any entity or person, including any
representation, warranty or undertaking, as to the functionality security use,
value or other characteristics of any distributed ledger nor in respect the
functioning or value of any tokens which may be created stored or transferred
using the Work.

The Licensor does not warrant that the Work or any use of the Work complies with
any law or regulation in any territory where it may be implemented or used or
that it will be appropriate for any specific purpose.

Neither the licensor nor any current or former employees, officers, directors,
partners, trustees, representatives, agents, advisors, contractors, or
volunteers of the Licensor shall be liable for any direct or indirect, special,
incidental, consequential or other losses of any kind, in tort, contract or
otherwise (including but not limited to loss of revenue, income or profits, or
loss of use or data, or loss of reputation, or loss of any economic or other
opportunity of whatsoever nature or howsoever arising), arising out of or in
connection with (without limitation of any use, misuse, of any ledger system or
use made or its functionality or any performance or operation of any code or
protocol caused by bugs or programming or logic errors or otherwise);

A. any offer, purchase, holding, use, sale, exchange or transmission of any
cryptographic keys, tokens or assets created, exchanged, stored or arising from
any interaction with the Work;

B. any failure in a transmission or loss of any token or assets keys or other
digital artifacts due to errors in transmission;

C. bugs, hacks, logic errors or faults in the Work or any communication;

D. system software or apparatus including but not limited to losses caused by
errors in holding or transmitting tokens by any third-party;

E. breaches or failure of security including hacker attacks, loss or disclosure
of password, loss of private key, unauthorised use or misuse of such passwords
or keys;

F. any losses including loss of anticipated savings or other benefits resulting
from use of the Work or any changes to the Work (however implemented).

You are solely responsible for; testing, validating and evaluation of all
operation logic, functionality, security and appropriateness of using the Work
for any commercial or non-commercial purpose and for any reproduction or
redistribution by You of the Work. You assume all risks associated with Your use
of the Work and the exercise of permissions under this Licence.

The code includes modified third party work which is reproduced here pursuant to the Apache 2.0 licensing regime. Where third party software has been used this is identified together with the appropriate open-source licence.

radixdlt-scrypto's People

Contributors

0xomara avatar a137x avatar arthurvinci avatar azizi-a avatar balda-rdx avatar bbarwik avatar beemdvp avatar cseidman avatar devmannic avatar dhedey avatar diegomrsantos avatar gianlucardx avatar iamyulong avatar jakerdxworks avatar jakrawcz-rdx avatar klembee avatar kofrdx avatar lrubasze avatar lukasgasior1 avatar malexandru-rdx avatar marek-karwacki-rdx avatar mstrug-rdx avatar muzuke avatar omahs avatar r001 avatar sajjon avatar shambupujar avatar siy avatar talekhinezh avatar unghuuduc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

radixdlt-scrypto's Issues

Better docs for SmartValue

It is unclear from the docs that you have to us scrypto_decode::<T>(&smart_value.encoded) to use a SmartValue.

Check all custom types

All other types besidesBID and RID should be checked. This ensures all data stored are valid per system specification.

fn visit_custom(
&mut self,
ty: u8,
data: Vec<u8>,
bf: fn(&mut Self, BID) -> Result<BID, RuntimeError>,
rf: fn(&mut Self, RID) -> Result<RID, RuntimeError>,
) -> Result<Value, RuntimeError> {
match ty {
SCRYPTO_TYPE_BID => {
let bid = bf(
self,
BID::try_from(data.as_slice()).map_err(|_| {
RuntimeError::InvalidData(DecodeError::InvalidCustomData(ty))
})?,
)?;
Ok(Value::Custom(ty, bid.to_vec()))
}
SCRYPTO_TYPE_RID => {
let rid = rf(
self,
RID::try_from(data.as_slice()).map_err(|_| {
RuntimeError::InvalidData(DecodeError::InvalidCustomData(ty))
})?,
)?;
Ok(Value::Custom(ty, rid.to_vec()))
}
_ => Ok(Value::Custom(ty, data)),
}
}

Invoke a blueprint or component as an account

As agreed by the team, an account is a component which manages all the resources owned through buckets. A transaction orchestrates the flow of data and resource between accounts.

Need to update all authorisation to reflect this change.

Add testing support

Developers should be able to test their Scrypto code without publishing to local simulator.

Unable to change the library name to anything other than `out`

It seems we don't have the flexibility to change the lib name inside the Cargo.toml file. Changing it to anything other than out causes issues with testing and compiling. Also when docs are generated, they are labelled as out too.

Would it be possible to update the following code to allow the lib name to default to maybe CARGO_BIN_NAME to we can at least define a name we would like.

I believe this is the location of the file that needs to be updated:
https://github.com/radixdlt/radixdlt-scrypto/blob/ce6b70929bf487a2cc6779133ddbbc1981893624/scrypto/src/lib.rs

I think we can do something like the following:

#[macro_export]
macro_rules! include_code {
    () => {
        include_bytes!(concat!(
            env!("CARGO_MANIFEST_DIR"),
            format!("/target/wasm32-unknown-unknown/release/{}.wasm", env!("CARGO_BIN_NAME") )
        ))
    };
    ($package_dir: expr) => {
        include_bytes!(concat!(
            $package_dir,
            format!("/target/wasm32-unknown-unknown/release/{}.wasm", env!("CARGO_BIN_NAME"))
        ))
    };
}

Return keyword caused BucketRef not dropping

From @MrAir on Discord:


Hey all, so I'm now in the process of going through the two hour scrypto video and I have a weird error that does not make sense to me.

I'm now at the point in the video where the team is talking about badges and how they can be made. For the withdraw method, I have written the following:

#[auth(admin_badge)]
pub fn withdraw(&mut self) -> Bucket {
  return self.xrd_vault.take_all();
}

For some reason, calling this method fails with the following error:

Transaction Status: FAILURE
Execution Time: 11 ms
Instructions:
├─ DeclareTempBucketRef
├─ CallMethod { component: 02526629b90e1142492e934fbe807b446935407064db3ea2fcf856, method: "withdraw", args: [1, 03c71ddd6b7967d6fd7d0e4a437c45f4ceac132d74d948a07af561] }
├─ BorrowFromContext { amount: 1, resource_def: 03c71ddd6b7967d6fd7d0e4a437c45f4ceac132d74d948a07af561, to: Rid(0) }
├─ CallMethod { component: 029849b6426bf644066da5b7dd8b0c119cf75ce225523046cb23d5, method: "withdraw", args: [Rid(0)] }
├─ DropAllBucketRefs
├─ DepositAllBuckets { account: 02526629b90e1142492e934fbe807b446935407064db3ea2fcf856 }
└─ End { signers: [04005feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9] }
Results:
├─ Ok(None)
├─ Ok(Some(Bid(1)))
├─ Ok(None)
└─ Err(ResourceCheckFailure)
Logs: 0
New Entities: 0
Error: TransactionFailed

However, if I change this method to be the following:

#[auth(admin_badge)]
pub fn withdraw(&mut self) -> Bucket {
  self.xrd_vault.take_all()
}

then I now longer get an error when calling the withdraw method with the badge.

Why is it that removing the explicit return statement fix this issue? Isn't self.xrd_vault.take_all() and return self.xrd_vault.take_all(); equivalent?

Make assert message visible

Asserts are compiled into panic on failure condition. Need to consider if we can make the assert messages visible for debugging purpose.

Support LinkedList

Linked lists are widely used by queue-based application, but not supported by Scrypto. Within Radix Engine, we would like to use LinkedList for storing NFTs.

Check Badges and BadgesRef at runtime

We should check the amount behind a Badges or BadgesRef to make sure the amount is greater than 1. This is as a result of kernel not treating badges and tokens differently.

To `mut` or not to `mut`

Hello!

Nice work on Scrypto.

I noticed in the radixswap example that the reference to self in the add_liquidity, remove_liquidity and swap methods is not mutable, is this a bug or am I missing something?

Encryption on ledger

It would be useful to be able to encrypt sensitive data that is serialized on the ledger, implemented in a way that only the owner of a badge or NFT can decrypt this information. Is this something that is on the roadmap?

A few top of the head examples of information that could use encryption:

Personal data

Looking at the crowdsourcing example provided in PR to the community repository. Collection of addresses to send rewards to for instance is sensitive data that shouldn't be readable on ledger.

Escrow

With an escrow contract, there is a possibility that subject of agreement is sensitive and need to be stored encrypted.

Conditionally use types based on `std` feature flag

We need to conditionally use std or core + alloc types, based on the existence of feature flag std.

This is to ensure all the SBOR/serde annotations are applied to the types being used by the client package.

Use variables that represent fractions

Maybe some day Scrypto could use variables that represent fractions (rational numbers) with numerator and denominator, like num-rational

In this way we could use the simple syntax (easier to understand) without concerning about rounding issues

I don't know if there is any smart contract platform that supports this, and as Radix is focused on DeFi it would be a good fit

In this case the radiswap code could be kept mostly as it is, as long as the returned type in math operations would be the rational/fraction class, example:

let share = lp_tokens.amount() / self.lp_resource_def.supply();

In this case share would be of faction/rational class, and when used in multiplications or divisions, it would avoid losses

For the above to work the amount() and supply() should return fraction instead of Decimal, and then the division operator will be dealt by the class

The downside is the overhead, the library is not small and the computation is higher, probably making the cost higher too

Let's see what other devs think about this

Originally posted by @kroggen in #50 (comment)

new-package template missing drop_all_bucket_refs and deposit_all_buckets

I think the template should default to including these instructions for the new() function call, as it already does for the example from_token method call.

Usage of the TransactionBuilder functions drop_all_bucket_refs() and deposit_all_buckets(...) is inconsistent throughout the core code as well as all of the example code. This is understandable I think but leads to confusing errors when developing new blueprints based off of the template.

In terms of the user experience if this is not fixed we have this example. Create a new package, and modify the new() function to return (Component, Bucket) (and the other correct changes) but then the tests will fail with Err(ResourceCheckFailure) due to the returned Bucket still left "dangling" even though the blueprint is correct. In effect, the test code is wrong because Instruction::DepositAllBuckets is missing.

If you make the same new() call using resim it works properly because it does both:

...
├─ DropAllBucketRefs
├─ DepositAllBuckets { account: ... }
...

Fix goes just before this line:

And looks like this:

// Test the `new` function.
let transaction1 = TransactionBuilder::new(&executor)
    .call_function(package, "Hello", "new", vec![], None)
+   .drop_all_bucket_refs()
+   .deposit_all_buckets(account)
    .build(vec![key])
    .unwrap();
let receipt1 = executor.run(transaction1, false).unwrap();
println!("{:?}\n", receipt1);
assert!(receipt1.success);

I'm happy to submit a small PR for this if you'd like.

Return immutable ledger from TransactionExecutor

When you want to use a ledger for reading you need to drop and reconstruct the executor each time which is really a pain.

Could you add a method to TransactionExecutor that returns the Ledger?

Make burn and mint methods accept references of the BucketRef ?

I see that it is not possible to burn two different tokens with the same badge in a authorize block.
Maybe making mint and burn methods accept a reference to a BucketRef would solve the issue ?

pub fn change_supply(&mut self, badge_to_burn: Bucket) {
    self.minter_badge.authorize(|badge| {
        badge_to_burn.burn(badge);
        // todo: error here: use of moved resource: badge
        self.token_vault.take(100).burn(badge);
    });
}

Avoid the borrow() function when possible

Original code:

  let tokens = token_def.mint(amount, minter_badge.borrow());

The above code uses the borrow() function that has another meaning in finance, so here are some suggestions on how to handle the presentation of badges when necessary

Option 1:

  let tokens = token_def.mint(amount, minter_badge);

Just pass the badge directly as the parameter, and let the functions that receive them to handle them properly

Option 2:

  let tokens = token_def.mint(amount, minter_badge.present());

Create another function that calls borrow() inside, something like present()

Option 3:

  let tokens = minter_badge.authorize(|badge| {
    token_def.mint(amount, badge)
  });

Use the authorize block for functions that require a badge

Idea: add a way to truncate Decimal

I am trying to remove the floating part of a Decimal but can't find an easy way to do it (other than transforming to String and removing the floating part from there).

Enable/decode Scrypto high-level constructs the same as its wrapped value

High-level constructs are encoded differently from its wrapped "pointer"/"handle". This produces redundant code in the final wasm output.

One optimisation would be to encode these high-level constructs the same as the corresponding raw types.

We can start with customising the Decode/Encode trait implementations, and then consider making sbor derive support auto code generation.

Confusion when using Decimal::one() in user code

I came upon a possible point of confusion while trying to withdraw a single token from a vault. Please consider the two below methods:

pub fn withdraw_one(&self) ->Bucket {
    let amount :Decimal = 1.into();
    self.vault.take(amount)
}

pub fn withdraw_one_and_be_surprised(&self) -> Bucket {
    let amount :Decimal = Decimal::one();
    self.vault.take(amount)
}

At first glimpse both methods seem to be doing the same thing, which is to withdraw one full token (1.000000000000000000) from the vault. I would argue, however, that withdraw_one behaves as one would expected, while withdraw_one_and_be_surprised does not. The later method only returns 0.000000000000000001 tokens.

This is of course not necessarily a bug in itself but it may very well lead to bugs in user code. It sure did get me by surprise and (being new to Rust) - took me longer to figure out than I am proud to admit. It might be useful to rename the constant, so the difference to 1.into() becomes immediately apparent to users.

Deterministic WASM build

With deterministic WASM build, one can verify if the published WASM binary is produced from a specific Scrypto source code and compiler toolchain.

Parity team has been using Docker image to produce deterministic outputs. According to their blog post,

Wasm is overall a great invention providing a thin multi-plattform abstraction over the machine language target. Thus the wasm output from a compiler can easily be translated into the actual machine code needed for execution. However, WebAssemblz is not human readable, which makes it hard to audit for the people who should vote upon the chain upgrade. Upgrading a blockchain state transition function can't be taken back, so voting on an opaque block is not particularly instilling confidence in its users.

The way we approach this problem is through "deterministic builds". The rust compiler itself does not, as of now, guarantee that builds are deterministic – meaning that compiling the same code twice will yield the same resulting binary. However, Parity has managed to solve this problem for our code. So at least within the same environment (OS, Compiler, libs installed) it is reasonably deterministic for a set of targets to be consistent and wasm32-unknown-unknown is among them. This allows us to produce a docker-image (and its build description) confirming that the Rust source files indeed result in the binary blob proposed as the next chain runtime. Using the Docker image, auditors can look at the source code directly and do not have to wade through the wasm32 bytecode.

We need to check if similar approach can be applied to Scrypto.

Publish Scrypto to crates.io

Scrypto libraries need to be published to a public repo, so developers can import them directly in Cargo.toml.

Add ability for badges to hold data

Badges are a great concept but many of the possible use cases are not yet possible.
E.g., the "voting power" of a user can not be determined by the badge alone as of now.

Therefore, it would be great of badges could hold values.

SBOR TODOs

  • Fix [()] security flaw for no_metadata mode
  • Optimize [u8] and Vec<u8> decoding
  • Add unused bytes check
  • Add support for BTreeMap and Box
  • Decode any SBOR data
  • Encode fixed array length in type
  • Do not store STRING type for name metadata
  • Open question: how to deal with path and namespace?
  • HashMap and HashSet
  • Duplicate entries in HashMap and HashSet
  • Large byte array
  • Skip and rename fields

[bug] assert! results in empty error message when using format

Given this code

assert!(
    1 > 2,
    "{} should be greater than 2",
    1
);

one would expect the following output

└─ Err(InvokeError(Trap(Trap { kind: Unreachable })))
Logs: 1
└─ [ERROR] Panicked at '1 should be greater than 2', src\lib.rs:61:13
New Entities: 0
Error: TransactionFailed

when the actual result is the following (an empty error message)

└─ Err(InvokeError(Trap(Trap { kind: Unreachable })))
Logs: 1
└─ [ERROR] Panicked at '', src\lib.rs:61:13
New Entities: 0
Error: TransactionFailed

auth macro fails on &mut self methods

My closure implementation in #79 to fix #76 is incorrect. PR to fix on the way

Error:

cannot borrow as mutable
help: consider changing this to mutable: `mut func`

Thanks for raising this @cbisaillon

SBOR generics

Currently, generics are not supported in SBOR. Need to evaluate how important this is and research possible solutions.

Issue when dividing negative Decimal

I get weird results when dividing a negative Decimal:

code:

let a: Decimal = (-42).into();
info!("a: {}", a);
info!("a / 2: {}", a / 2);

result:
image

Enable static linkage of intra-package blueprints

I'd like to suggest a minor change to the blueprint! macro which enables a blueprint to reference another blueprint in the same package without the secondary blueprint being instantiated as a separate component at a separate address.

In effect this allows direct use of functionality "vendoring" dependencies. At least, it's another way to do code reuse with different tradeoffs.

The changes are:

  1. make the blueprint module's visibility pub(crate) so other modules in the create can access it.
    • Purposefully not pub because all the the generated code should not be accessible from outside of wasm for this use case. -- An optimization might be to add a new macro for this use case that doesn't generate as much unnecessary code. This proposal is more pragmatic while much of the code is still in flux I don't think refactoring or duplicating much of the macro code is wise.
  2. Make sure sbor::Describe is implemented so the secondary blueprint storage can be directly used in fields of the main blueprint storage

The change looks like this:

diff --git a/scrypto-derive/src/blueprint.rs b/scrypto-derive/src/blueprint.rs
index 3ff9aa6..2932adb 100644
--- a/scrypto-derive/src/blueprint.rs
+++ b/scrypto-derive/src/blueprint.rs
@@ -43,7 +43,7 @@ pub fn handle_blueprint(input: TokenStream) -> Result<TokenStream> {
     }
 
     let output_mod = quote! {
-        mod blueprint {
+        pub(crate) mod blueprint {
             use super::*;
 
             #[derive(::sbor::TypeId, ::sbor::Encode, ::sbor::Decode)]
@@ -452,7 +452,7 @@ fn generate_stubs(bp_ident: &Ident, items: &[ImplItem]) -> Result<TokenStream> {
     }
 
     let output = quote! {
-        #[derive(::sbor::TypeId, ::sbor::Encode, ::sbor::Decode)]
+        #[derive(::sbor::TypeId, ::sbor::Encode, ::sbor::Decode, ::sbor::Describe)]
         pub struct #bp_ident {
             address: ::scrypto::types::Address,
         }

And then one blueprint can create the storage struct from another blueprint and everything "just works". For example:

mod lib2;
use scrypto::prelude::*;
blueprint! {
    struct Hello {
        // Define what resources and data will be managed by Hello components
        sample_vault: Vault,
        hello2: lib2::blueprint::Hello2,  // using the internal type here
    }
/* ... */
            let c1 = Self {
                sample_vault: Vault::with_bucket(my_bucket),
                hello2: lib2::blueprint::Hello2::new()  // call the internal function here which should return a Hello2, not a Component
            }
/* ... */
            let b2 = self.hello2.free_token2();  // call the function in the exact same way as if it was a Component of type lib2::Hello2
/* ... */

The full example is here: https://github.com/devmannic/scrypto-playground/tree/main/hello-crosscall-static

I full PR would include the above changes and some example to test the feature. The example could be an added rewrite of cross-blueprint-call maybe or just a simple example.

Thanks

Add a LICENSE, CODE_OF_CONDUCT.md, CONTRIBUTING.md

The repository has no license information. It really should have a declared license ASAP. The rest are nice to have too.

  • add LICENSE (one or more)
  • add CODE_OF_CONDUCT.md
  • add CONTRIBUTING.md

I know that building a developer community is a high priority for RDX Works (formerly RadixDLT). IMHO missing these guidelines/declarations runs counter to that goal. You may also want to check on the other radixdlt organization repositories for similarly missing files.

An obvious choice is the Radix License (radixfoundation.org/licenses/license-v1), Please consider an equally or more permissive license which is more commonly used for software to be applied at least to the example code if not the entire repository. I'd suggest one or both of MIT and Apache-2.

Without a license, the Github Terms of Service makes some grants . However, this does not cover publishing derivative works to any non-GitHub service.

For example, I am working on a library which includes modified versions of these examples and some derived functionality. I would like to publish the package on crates.io, but without license information here, I really should only include it on GitHub. It's not a showstopper, but it doesn't feel good.

For reference: excerpt from Github ToS implies the following:

License Grant to Other Users

Any User-Generated Content you post publicly, including issues, comments, and contributions to other Users' repositories, may be > viewed by others. By setting your repositories to be viewed publicly, you agree to allow others to view and "fork" your repositories
(this means that others may make their own copies of Content from your repositories in repositories they control).

If you set your pages and repositories to be viewed publicly, you grant each User of GitHub a nonexclusive, worldwide license to
use, display, and perform Your Content through the GitHub Service and to reproduce Your Content solely on GitHub as permitted
through GitHub's functionality (for example, through forking). You may grant further rights if you adopt a license. If you are
uploading Content you did not create or own, you are responsible for ensuring that the Content you upload is licensed under terms
that grant these permissions to other GitHub Users.

Prevent dangling vaults?

Currently, we are allowed to create vaults freely, with or without attaching it to a component. This may cause resource locked in a vault that nobody effectively owns, by careless developers. Should we do something about this?

Namespacing struct and enum for SBOR

Struct and enum names (with path stripped) are encoded in the binary. This may cause name conflicts when importing ABI.

We need a more elegant way of handling namespace, presumably by introducing canonical path.

Test: new_token_fixed should not be a valid badge

I saw that in the video the radiswap example worked even using the new_token_fixed() instead of new_badge_fixed()

Could this lead to some undesired behaviors, like a breach for attacks?

It could have a test that should fail if new_token_fixed() is used to create a badge

(correct me if I am wrong)

Disallow component re-entrance

When a method is called, the component state is loaded into memory. All state changes are cached and flushed at the end of the invocation.

This may cause unexpected behaviour when there is a re-entrance. The state changes by child process are overwritten by parent process.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.