New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add a toy example - rock's candy shop #2
Merged
Merged
Changes from 6 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
0d015de
First version of rocks example
RockHoward 92205bd
renamed the example directory
RockHoward c80c6d8
a first example - a POC for a Candy Shop
RockHoward 962f513
a first example of a POC Candy Shop
RockHoward 5149fe9
Fixed a warning about a snake name.
RockHoward 528e6b2
Cargo.toml now uses relative paths.
RockHoward 27a9656
first commit for utility_token_service
RockHoward 1ac7b65
Merge branch 'radixdlt:main' into main
RockHoward File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
[package] | ||
name = "rocks-candy-shop" | ||
version = "0.1.0" | ||
edition = "2018" | ||
|
||
[dependencies] | ||
sbor = { path = "../../../sbor" } | ||
scrypto = { path = "../../../scrypto" } | ||
|
||
[dev-dependencies] | ||
radix-engine = { path = "../../../radix-engine" } | ||
|
||
[profile.release] | ||
opt-level = 's' # Optimize for size. | ||
lto = true # Enable Link Time Optimization. | ||
codegen-units = 1 # Reduce number of codegen units to increase optimizations. | ||
panic = 'abort' # Abort on panic. | ||
|
||
[lib] | ||
crate-type = ["cdylib", "lib"] | ||
name = "out" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
{ | ||
"commands": [ | ||
{ | ||
"cmd": "reset", | ||
"args": [], | ||
"envs": [] | ||
}, | ||
{ | ||
"cmd": "new-account", | ||
"args": [], | ||
"envs": [ | ||
"account", | ||
"pubkey" | ||
] | ||
}, | ||
{ | ||
"cmd": "new-account", | ||
"args": [], | ||
"envs": [ | ||
"account2", | ||
"pubkey2" | ||
] | ||
}, | ||
{ | ||
"cmd": "new-token-fixed", | ||
"args": [ | ||
"10000", | ||
"--name", | ||
"emunie", | ||
"--symbol", | ||
"EMT" | ||
], | ||
"envs": [ | ||
"tokenEMT" | ||
] | ||
}, | ||
{ | ||
"cmd": "new-token-fixed", | ||
"args": [ | ||
"10000", | ||
"--name", | ||
"gmunie", | ||
"--symbol", | ||
"GMT" | ||
], | ||
"envs": [ | ||
"tokenGMT" | ||
] | ||
}, | ||
{ | ||
"cmd": "publish", | ||
"args": [ | ||
"." | ||
], | ||
"envs": [ | ||
"package" | ||
] | ||
}, | ||
{ | ||
"cmd": "call-function", | ||
"args": [ | ||
"$package", | ||
"CandyShop", | ||
"initial_supply", | ||
"500" | ||
], | ||
"envs": [ | ||
"tokenGUM", | ||
"tokenJAWB", | ||
"tokenLPOP", | ||
"tokenCANE", | ||
"tokenJELLY", | ||
"tokenMINT", | ||
"tokenBEAR", | ||
"component" | ||
] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
{ | ||
"commands": [ | ||
{ | ||
"cmd": "reset", | ||
"args": [], | ||
"envs": [] | ||
}, | ||
{ | ||
"cmd": "new-account", | ||
"args": [], | ||
"envs": [ | ||
"account", | ||
"pubkey" | ||
] | ||
}, | ||
{ | ||
"cmd": "new-account", | ||
"args": [], | ||
"envs": [ | ||
"account2", | ||
"pubkey2" | ||
] | ||
}, | ||
{ | ||
"cmd": "new-token-fixed", | ||
"args": [ | ||
"10000", | ||
"--name", | ||
"emunie", | ||
"--symbol", | ||
"EMT" | ||
], | ||
"envs": [ | ||
"tokenEMT" | ||
] | ||
}, | ||
{ | ||
"cmd": "new-token-fixed", | ||
"args": [ | ||
"10000", | ||
"--name", | ||
"gmunie", | ||
"--symbol", | ||
"GMT" | ||
], | ||
"envs": [ | ||
"tokenGMT" | ||
] | ||
}, | ||
{ | ||
"cmd": "publish", | ||
"args": [ | ||
"." | ||
], | ||
"envs": [ | ||
"package" | ||
] | ||
}, | ||
{ | ||
"cmd": "call-function", | ||
"args": [ | ||
"$package", | ||
"CandyShop", | ||
"new" | ||
], | ||
"envs": [ | ||
"component" | ||
] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
use scrypto::prelude::*; | ||
|
||
/* This a non-trivial example that shows off a blueprint that operates with | ||
with an adjustable number of vaults. My main discover was that you can | ||
return Vec<Bucket> and the resim methd call can handle it and update | ||
the account correctly. | ||
|
||
If someone wants to do so there are many possible extensions: | ||
- add purchase method(s) via XRD | ||
- have the purchase method(s) also return change | ||
- add badges to control who can get the collected XRD | ||
- allow for different prices for each type of candy | ||
- allow candy restocking by a badged account (hint: mutable supply) | ||
- tag the candy_vaults with the rri instead of the token symbol | ||
- many more... | ||
*/ | ||
|
||
blueprint! { | ||
struct CandyShop { | ||
// The different kinds of candies are kept here with each in a tuple | ||
// with a unique tag string that doubles as the candies' token symbol. | ||
candy_vaults: Vec<(String,Vault)> | ||
} | ||
|
||
impl CandyShop { | ||
|
||
pub fn new() -> Component { | ||
// This constructor sets up an empty candy shop | ||
let tagged_vaults: Vec<(String,Vault)> = Vec::new(); | ||
Self { | ||
candy_vaults: tagged_vaults | ||
} | ||
.instantiate() | ||
} | ||
|
||
pub fn initial_supply( supply_size: u32 ) -> Component { | ||
// This constructor sets up a variety of candies with the specified amount. | ||
let mut tagged_vaults: Vec<(String,Vault)> = Vec::new(); | ||
// Now define the meta data for each type of candy. | ||
let mut metas = vec![("Gumball", "GUM", "The best gumball in the world.")]; | ||
metas.push(("Jawbreaker", "JAWB", "Jawbreakers teach patience.")); | ||
metas.push(("Lollipop","LPOP","You can't lick Lollipops!")); | ||
metas.push(("Candy Cane", "CANE", "Striped candy rules!")); | ||
metas.push(("Jelly Bean", "JELLY", "Jelly Beans are best!")); | ||
metas.push(("Mint Candy", "MINT", "Mints are wonderful!")); | ||
metas.push(("Gummy Bear", "BEAR", "Gummy Bears rules!")); | ||
// Create a supply | ||
for tup in metas { | ||
let bucket = ResourceBuilder::new() | ||
.metadata("name", tup.0.to_string()) | ||
.metadata("symbol", tup.1.to_string()) | ||
.metadata("description", tup.2.to_string()) | ||
.new_token_fixed(supply_size); | ||
tagged_vaults.push((tup.1.to_string(), Vault::with_bucket(bucket))); | ||
} | ||
Self { | ||
candy_vaults: tagged_vaults | ||
} | ||
.instantiate() | ||
} | ||
|
||
fn take_from_vault(&self, symbol: String, quantity: Decimal) -> Bucket { | ||
// private function returns a bucket with the specified number and type of candy (or an empty bucket) | ||
for c in &self.candy_vaults[..] { | ||
if c.0 == symbol { | ||
let v = &c.1; | ||
if v.amount() >= quantity { | ||
return v.take(quantity) | ||
} else { | ||
break; | ||
} | ||
} | ||
} | ||
let empty_bucket: Bucket = Bucket::new(RADIX_TOKEN); // canonical way to make an empty_bucket | ||
return empty_bucket | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an interesting case where the bucket "type" is dynamic and sometimes the method doesn't even want to return a bucket. I would consider returning an |
||
|
||
pub fn free_gum(&self) -> Bucket { | ||
// Return a gumball if we have at least one available. | ||
// If there is no GUM vault or the GUM vaut is empty, this method will fail. | ||
self.take_from_vault("GUM".to_string(), 1.into()) | ||
} | ||
|
||
pub fn free_samples(&mut self) -> Vec<Bucket> { | ||
let mut buckets = Vec::new(); | ||
for c in &self.candy_vaults[..] { | ||
if c.1.amount() > 0.into() { | ||
buckets.push(c.1.take(1)); | ||
} | ||
} | ||
return buckets | ||
} | ||
|
||
fn contains(&self, symbol: &str) -> bool { | ||
// return True if the symbol is found in the candy_vaults based on the token symbol | ||
let mut found: bool = false; | ||
let symbol_string = symbol.to_string(); | ||
for c in &self.candy_vaults[..] { | ||
if c.0 == symbol_string { | ||
found = true; | ||
break; | ||
} | ||
} | ||
return found | ||
} | ||
|
||
pub fn add_candy(&mut self, name: String, symbol: String, description: String, supply_size: Decimal) { | ||
scrypto_assert!(supply_size >= 1.into(), "Not enough initial candy"); | ||
scrypto_assert!(self.contains(&symbol) == false, "That type of candy is already available."); | ||
// Add a new kind of candy to the CandyShop | ||
let bucket = ResourceBuilder::new() | ||
.metadata("name", name) | ||
.metadata("symbol", symbol.to_string()) | ||
.metadata("description", description) | ||
.new_token_fixed(supply_size); | ||
self.candy_vaults.push((symbol, Vault::with_bucket(bucket))); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
use radix_engine::ledger::*; | ||
use radix_engine::transaction::*; | ||
use scrypto::prelude::*; | ||
|
||
#[test] | ||
fn test_hello() { | ||
// Set up environment. | ||
let mut ledger = InMemoryLedger::with_bootstrap(); | ||
let mut executor = TransactionExecutor::new(&mut ledger, 0, 0); | ||
let key = executor.new_public_key(); | ||
let account = executor.new_account(key); | ||
let package = executor.publish_package(include_code!()); | ||
|
||
// Test the `new` function. | ||
let transaction1 = TransactionBuilder::new(&executor) | ||
.call_function(package, "Hello", "new", vec![], None) | ||
.build(vec![key]) | ||
.unwrap(); | ||
let receipt1 = executor.run(transaction1, false).unwrap(); | ||
println!("{:?}\n", receipt1); | ||
assert!(receipt1.success); | ||
|
||
// Test the `free_token` method. | ||
let component = receipt1.component(0).unwrap(); | ||
let transaction2 = TransactionBuilder::new(&executor) | ||
.call_method(component, "free_token", vec![], Some(account)) | ||
.drop_all_bucket_refs() | ||
.deposit_all_buckets(account) | ||
.build(vec![key]) | ||
.unwrap(); | ||
let receipt2 = executor.run(transaction2, false).unwrap(); | ||
println!("{:?}\n", receipt2); | ||
assert!(receipt2.success); | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would consider using a
HashMap
orLazyMap
to make vault retrieval easier.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a separate example called Vending Machine that uses a HashMap of Vaults and so I think that I will leave this one as is just to show a different way to handle a requirement for dynamic Vaults. I will look into Option and fit that into an example somewhere as well. The empty_bucket approach shown is going to be a common idiom I would think simply because of it's simplicity.