From a2a96f39eba2955079edc55fed8d8b697481781b Mon Sep 17 00:00:00 2001 From: Rick Porter Date: Fri, 10 Sep 2021 19:59:17 -0700 Subject: [PATCH 1/6] adding more query types --- package.json | 2 +- src/ic_loot_assets/App.vue | 8 +-- src/ic_loot_assets/main.js | 6 ++ src/ic_loot_rs/address.rs | 2 +- src/ic_loot_rs/ic_loot.did | 36 ++++++++++ src/ic_loot_rs/lib.rs | 135 +++++++++++++++++++++++++++++++++++-- src/ic_loot_rs/loot2.rs | 122 +++++++++++++++++++++++++++++++++ 7 files changed, 299 insertions(+), 12 deletions(-) create mode 100644 src/ic_loot_rs/loot2.rs diff --git a/package.json b/package.json index be5613d..00ede20 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "vite build", "dev": "vite", - "dfx:install": "dfx canister --network=ic ic_loot_rs --all --mode reinstall", + "dfx:install": "dfx canister install ic_loot_rs --all --mode upgrade", "dfx:rebuild": "dfx build && npm run dfx:install", "dfx:setup": "dfx canister create --all && dfx build && npm run dfx:install" }, diff --git a/src/ic_loot_assets/App.vue b/src/ic_loot_assets/App.vue index e896d05..14de6d9 100644 --- a/src/ic_loot_assets/App.vue +++ b/src/ic_loot_assets/App.vue @@ -12,15 +12,15 @@
@@ -29,7 +29,7 @@ Internet Computer - project based on the + project inspired by Loot Project diff --git a/src/ic_loot_assets/main.js b/src/ic_loot_assets/main.js index c046927..9a5584c 100644 --- a/src/ic_loot_assets/main.js +++ b/src/ic_loot_assets/main.js @@ -1,6 +1,7 @@ import { createApp } from "vue"; import App from "./App.vue"; import "virtual:windi.css"; +import VueGtag from "vue-gtag-next"; /** * @dfinity/agent requires this. Can be removed once it's fixed @@ -9,5 +10,10 @@ window.global = window; const app = createApp(App); +app.use(VueGtag, { + property: { + id: "G-KE88EVJHWW", + }, +}); app.mount("#app"); diff --git a/src/ic_loot_rs/address.rs b/src/ic_loot_rs/address.rs index d72853a..40a7a9a 100644 --- a/src/ic_loot_rs/address.rs +++ b/src/ic_loot_rs/address.rs @@ -84,7 +84,7 @@ impl AddressBook { pub fn claim(&mut self, user_id: Principal) -> Result { - if self.claim_index > self.total_supply { + if self.claim_index >= self.total_supply { return Err("No more claims left".to_string()); } diff --git a/src/ic_loot_rs/ic_loot.did b/src/ic_loot_rs/ic_loot.did index ad124f7..037c8f3 100644 --- a/src/ic_loot_rs/ic_loot.did +++ b/src/ic_loot_rs/ic_loot.did @@ -1,3 +1,17 @@ +// http://icdrip.io + +// ██▓ ▄████▄ ▓█████▄ ██▀███ ██▓ ██▓███ +// ▓██▒▒██▀ ▀█ ▒██▀ ██▌▓██ ▒ ██▒▓██▒▓██░ ██▒ +// ▒██▒▒▓█ ▄ ░██ █▌▓██ ░▄█ ▒▒██▒▓██░ ██▓▒ +// ░██░▒▓▓▄ ▄██▒ ░▓█▄ ▌▒██▀▀█▄ ░██░▒██▄█▓▒ ▒ +// ░██░▒ ▓███▀ ░ ░▒████▓ ░██▓ ▒██▒░██░▒██▒ ░ ░ +// ░▓ ░ ░▒ ▒ ░ ▒▒▓ ▒ ░ ▒▓ ░▒▓░░▓ ▒▓▒░ ░ ░ +// ▒ ░ ░ ▒ ░ ▒ ▒ ░▒ ░ ▒░ ▒ ░░▒ ░ +// ▒ ░░ ░ ░ ░ ░░ ░ ▒ ░░░ +// ░ ░ ░ ░ ░ ░ +// ░ ░ + + type HeaderField = record { text; text; }; type HttpRequest = record { @@ -26,12 +40,34 @@ type ClaimResult = variant { Err: text; }; +type LootData = record { + slot: text; + name: text; + + prefix: text; + name_prefix: text; + name_suffix: text; + special: bool; +}; + +type DataOfQuery = variant { + Range: record {nat64; nat64}; + List: vec nat64; +}; + + + service : { http_request: (request: HttpRequest) -> (HttpResponse) query; get_address_book: () -> (AddressBook) query; get_token_properties: (nat64) -> (vec record { text; text}) query; + get_token_properties_range: (nat64, nat64) -> (vec vec record { text; text}) query; + + data_of: (nat64) -> (vec LootData) query; + data_of_many: (DataOfQuery) -> (vec record {nat64; vec LootData;}) query; + get_cycles: () -> (int64); get_airdrops: () -> (vec record { nat64; bool }) query; add_airdrops: (vec principal) -> (bool); name: () -> (text) query; diff --git a/src/ic_loot_rs/lib.rs b/src/ic_loot_rs/lib.rs index d2e664f..0236458 100644 --- a/src/ic_loot_rs/lib.rs +++ b/src/ic_loot_rs/lib.rs @@ -7,10 +7,11 @@ use std::collections::BTreeMap; mod loot; mod rand; mod address; +mod loot2; use crate::address::AddressBook; use crate::loot::Loot; - +use crate::loot2::{Loot2, LootData}; #[init] fn init() { @@ -446,6 +447,22 @@ fn init_loot() -> () { "Monogramed", "Haute Couture", ].iter().map(|s| s.to_string()).collect(); + + + let loot2 = storage::get_mut::(); + *loot2 = Loot2 { + weapons: loot.weapons.clone(), + waist: loot.waist.clone(), + chest: loot.chest.clone(), + head: loot.head.clone(), + foot: loot.foot.clone(), + underwear: loot.underwear.clone(), + accessory: loot.accessory.clone(), + pants: loot.pants.clone(), + prefixes: loot.prefixes.clone(), + name_prefixes: loot.name_prefixes.clone(), + name_suffixes: loot.name_suffixes.clone(), + } } #[query] @@ -475,8 +492,8 @@ fn transfer_to(user: Principal, token_id: u64) -> bool { #[update] fn claim() -> Result { - return Err("No claims for this NFT type (IC DRIP)".to_string()); - //return storage::get_mut::().claim(ic_cdk::caller()); + //return Err("No claims for this NFT type (IC DRIP)".to_string()); + return storage::get_mut::().claim(ic_cdk::caller()); } //Allow the original airdrop to always exists for future references @@ -538,6 +555,11 @@ fn get_controllers() -> Vec { return storage::get::().controllers.clone(); } +#[update] +fn get_cycles() -> i64 { + return ic_cdk::api::call::msg_cycles_available(); +} + #[query] fn name() -> String { return "IC_DRIP".to_string(); @@ -607,16 +629,82 @@ async fn http_request(req: HttpRequest) -> HttpResponse { } } +#[query] +fn data_of(token_id: u64) -> Vec { + + let address_book = storage::get::(); + if token_id <= 0 || token_id > address_book.total_supply || !address_book.is_claimed(&token_id) { + return Vec::new(); + } + let seed = address_book.token_seeds.get(&token_id).unwrap(); + let loot = storage::get::(); + return loot.get_properties(token_id + seed); +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub enum DataOfQuery { + Range(u64, u64), + List(Vec) +} + +#[query] +fn data_of_many(query: DataOfQuery) -> BTreeMap> { + let address_book = storage::get::(); + match query { + DataOfQuery::Range(from, to) => { + let mut results = BTreeMap::new(); + for i in from..to+1 { + if !address_book.is_claimed(&i) { + continue; + } + let seed = address_book.token_seeds.get(&i).unwrap(); + let loot = storage::get::(); + results.insert(i, loot.get_properties(i + seed)); + } + return results; + }, + DataOfQuery::List(items) => { + let mut results = BTreeMap::new(); + for id in items { + if !address_book.is_claimed(&id) { + continue; + } + let seed = address_book.token_seeds.get(&id).unwrap(); + let loot = storage::get::(); + results.insert(id, loot.get_properties(id + seed)); + } + return results; + }, + } +} + #[query] fn get_token_properties(token_id: u64) -> Vec<(String, String)> { - let address_book = storage::get_mut::(); + let address_book = storage::get::(); if token_id <= 0 || token_id > address_book.total_supply || !address_book.is_claimed(&token_id) { return Vec::new(); } + let seed = address_book.token_seeds.get(&token_id).unwrap(); + let loot = storage::get::(); + return loot.get_properties(token_id + seed); +} - let loot = storage::get_mut::(); - return loot.get_properties(token_id); +#[query] +fn get_token_properties_range(from: u64, to:u64) -> Vec> { + + let address_book = storage::get::(); + + let mut results = Vec::new(); + for i in from..to+1 { + if !address_book.is_claimed(&i) { + continue; + } + let seed = address_book.token_seeds.get(&i).unwrap(); + let loot = storage::get::(); + results.push(loot.get_properties(i + seed)) + } + return results; } @@ -624,6 +712,20 @@ fn get_token_properties(token_id: u64) -> Vec<(String, String)> { #[query(name = "__get_candid_interface_tmp_hack")] fn export_candid() -> String { return r#" + +// http://icdrip.io + +// ██▓ ▄████▄ ▓█████▄ ██▀███ ██▓ ██▓███ +// ▓██▒▒██▀ ▀█ ▒██▀ ██▌▓██ ▒ ██▒▓██▒▓██░ ██▒ +// ▒██▒▒▓█ ▄ ░██ █▌▓██ ░▄█ ▒▒██▒▓██░ ██▓▒ +// ░██░▒▓▓▄ ▄██▒ ░▓█▄ ▌▒██▀▀█▄ ░██░▒██▄█▓▒ ▒ +// ░██░▒ ▓███▀ ░ ░▒████▓ ░██▓ ▒██▒░██░▒██▒ ░ ░ +// ░▓ ░ ░▒ ▒ ░ ▒▒▓ ▒ ░ ▒▓ ░▒▓░░▓ ▒▓▒░ ░ ░ +// ▒ ░ ░ ▒ ░ ▒ ▒ ░▒ ░ ▒░ ▒ ░░▒ ░ +// ▒ ░░ ░ ░ ░ ░░ ░ ▒ ░░░ +// ░ ░ ░ ░ ░ ░ +// ░ ░ + type HeaderField = record { text; text; }; type HttpRequest = record { @@ -652,12 +754,33 @@ type ClaimResult = variant { Err: text; }; +type LootData = record { + slot: text; + name: text; + + prefix: text; + name_prefix: text; + name_suffix: text; + special: bool; +}; + +type DataOfQuery = variant { + Range: record {nat64; nat64}; + List: vec nat64; +}; + service : { http_request: (request: HttpRequest) -> (HttpResponse) query; get_address_book: () -> (AddressBook) query; + get_token_properties: (nat64) -> (vec record { text; text}) query; + get_token_properties_range: (nat64, nat64) -> (vec vec record { text; text}) query; + + data_of: (nat64) -> (vec LootData) query; + data_of_many: (DataOfQuery) -> (vec record {nat64; vec LootData;}) query; + get_cycles: () -> (int64); get_airdrops: () -> (vec record { nat64; bool }) query; add_airdrops: (vec principal) -> (bool); name: () -> (text) query; diff --git a/src/ic_loot_rs/loot2.rs b/src/ic_loot_rs/loot2.rs new file mode 100644 index 0000000..991111d --- /dev/null +++ b/src/ic_loot_rs/loot2.rs @@ -0,0 +1,122 @@ + +use ic_cdk::export::{candid::{CandidType, Deserialize}}; +use crate::rand::Rand; + +//I created this because I did not want to +//mess with the generator which is being used. + +#[derive(Clone, Debug, Default, CandidType, Deserialize)] +pub struct Loot2 { + pub weapons: Vec, + pub chest: Vec, + pub head: Vec, + pub waist: Vec, + pub foot: Vec, + pub underwear: Vec, + pub accessory: Vec, + pub pants: Vec, + + pub prefixes: Vec, + pub name_prefixes: Vec, + pub name_suffixes: Vec, +} + +#[derive(Clone, Debug, Default, CandidType, Deserialize)] +pub struct LootData { + pub slot: String, + pub name: String, + + pub prefix: String, + pub name_prefix: String, + pub name_suffix: String, + pub special: bool +} + + +impl Loot2 { + + pub fn get_weapon(&self, token_id: u64) -> LootData { + self.compute(&self.weapons, 1, token_id, "weapon".to_string()) + } + + pub fn get_chest(&self, token_id: u64) -> LootData { + self.compute(&self.chest, 222, token_id, "chest".to_string()) + } + + pub fn get_head(&self, token_id: u64) -> LootData { + self.compute(&self.head, 333, token_id, "head".to_string()) + } + + pub fn get_waist(&self, token_id: u64) -> LootData { + self.compute(&self.waist, 4444, token_id, "waist".to_string()) + } + + pub fn get_foot(&self, token_id: u64) -> LootData { + self.compute(&self.foot, 55555, token_id, "foot".to_string()) + } + + pub fn get_underwear(&self, token_id: u64) -> LootData { + self.compute(&self.underwear, 666666, token_id, "underwear".to_string()) + } + + pub fn get_accessory(&self, token_id: u64) -> LootData { + self.compute(&self.accessory, 7777777, token_id, "accessory".to_string()) + } + + pub fn get_pants(&self, token_id: u64) -> LootData { + self.compute(&self.pants, 88888888, token_id, "pants".to_string()) + } + + pub fn get_prefix(&self, rand: u64) -> String { + return self.prefixes[rand as usize % &self.prefixes.len()].clone(); + } + + pub fn get_name_prefix(&self, rand: u64) -> String { + return self.name_prefixes[rand as usize % &self.name_prefixes.len()].clone(); + } + + pub fn get_name_suffix(&self, rand: u64) -> String { + return self.name_suffixes[rand as usize % &self.name_suffixes.len()].clone(); + } + + pub fn compute(&self, items: &Vec, offset: u64, token_id: u64, kind: String) -> LootData { + let rand = Rand::new(token_id + offset).rand(); + let item_index = rand as usize % items.len(); + + let mut data = LootData::default(); + + data.slot = kind.clone(); + data.name = items[item_index].clone(); + + let greatness = rand % 21; + + if greatness > 14 { + data.prefix = self.get_prefix(rand); + } + if greatness > 19 { + if greatness == 19 { + data.name_prefix = self.get_name_prefix(rand); + data.name_suffix = self.get_name_suffix(rand); + data.special = false; + } else { + data.special = true; + data.name_prefix = self.get_name_prefix(rand); + data.name_suffix = self.get_name_suffix(rand); + } + } + return data; + } + + pub fn get_properties(&self, token_id: u64) -> Vec { + return vec![ + self.get_weapon(token_id), + self.get_chest(token_id), + self.get_head(token_id), + self.get_waist(token_id), + self.get_pants(token_id), + self.get_underwear(token_id), + self.get_accessory(token_id), + self.get_foot(token_id), + ] + } +} \ No newline at end of file From edb28b4646923ed6fe2c9d4ba6826942f6e353c9 Mon Sep 17 00:00:00 2001 From: Rick Porter Date: Sat, 11 Sep 2021 12:28:09 -0700 Subject: [PATCH 2/6] transfer_with_notify --- src/ic_loot_rs/ic_loot.did | 8 +- src/ic_loot_rs/lib.rs | 166 +++++++++++++++++++++++++------------ 2 files changed, 122 insertions(+), 52 deletions(-) diff --git a/src/ic_loot_rs/ic_loot.did b/src/ic_loot_rs/ic_loot.did index 037c8f3..f2c1b14 100644 --- a/src/ic_loot_rs/ic_loot.did +++ b/src/ic_loot_rs/ic_loot.did @@ -55,7 +55,12 @@ type DataOfQuery = variant { List: vec nat64; }; - +type TransferNotification = record { + to: principal; + from: principal; + amount: nat64; + memo: opt blob; +}; service : { http_request: (request: HttpRequest) -> (HttpResponse) query; @@ -75,6 +80,7 @@ service : { user_tokens: (principal) -> (vec nat64) query; owner_of: (nat64) -> (opt principal) query; transfer_to: (principal, nat64) -> (bool); + transfer_with_notify: (principal, nat64, TransferNotification) -> (bool); claim: () -> (ClaimResult); remaining: () -> (nat64); supply: () -> (nat64); diff --git a/src/ic_loot_rs/lib.rs b/src/ic_loot_rs/lib.rs index 0236458..f3bb27c 100644 --- a/src/ic_loot_rs/lib.rs +++ b/src/ic_loot_rs/lib.rs @@ -1,18 +1,31 @@ -use ic_cdk::export::{candid::{CandidType, Deserialize}, Principal}; +use ic_cdk::api::call::CallResult; +use ic_cdk::export::{ + candid::{CandidType, Deserialize}, + Principal, +}; use ic_cdk::storage; use ic_cdk_macros::*; -use serde_bytes::{ByteBuf}; +use serde_bytes::ByteBuf; use std::collections::BTreeMap; -mod loot; -mod rand; mod address; +mod loot; mod loot2; +mod rand; use crate::address::AddressBook; use crate::loot::Loot; use crate::loot2::{Loot2, LootData}; +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct TransferNotification { + pub to: Principal, + pub token: u64, + pub from: Principal, + pub amount: u64, + pub memo: Option>, +} + #[init] fn init() { ic_cdk::println!("Init {:?}", ic_cdk::api::time()); @@ -21,16 +34,15 @@ fn init() { address_book.total_supply = 8000; //needs to be a way to pass this into init - let owner_id = Principal::from_text( - "2c22g-lboam-nseoa-i5al6-o7k6f-o2fwz-huoua-be63r-oi3k2-wy7uq-zae" - ).unwrap(); + let owner_id = + Principal::from_text("2c22g-lboam-nseoa-i5al6-o7k6f-o2fwz-huoua-be63r-oi3k2-wy7uq-zae") + .unwrap(); address_book.add_controller(&owner_id); init_loot(); } fn init_loot() -> () { - let loot = storage::get_mut::(); loot.weapons = vec![ @@ -71,7 +83,10 @@ fn init_loot() -> () { "Book", "Pocket Watch", "Wrench", - ].iter().map(|s| s.to_string()).collect(); + ] + .iter() + .map(|s| s.to_string()) + .collect(); loot.chest = vec![ "Robe", @@ -118,7 +133,10 @@ fn init_loot() -> () { "Trench Coat", "Cape", "Kimono", - ].iter().map(|s| s.to_string()).collect(); + ] + .iter() + .map(|s| s.to_string()) + .collect(); loot.head = vec![ "Fedora", @@ -173,7 +191,10 @@ fn init_loot() -> () { "Bonnet", "Fez", "Space Helmet", - ].iter().map(|s| s.to_string()).collect(); + ] + .iter() + .map(|s| s.to_string()) + .collect(); loot.waist = vec![ "Fanny Pack", @@ -189,7 +210,10 @@ fn init_loot() -> () { "Suspenders", "Rope", "Jeweled Belt", - ].iter().map(|s| s.to_string()).collect(); + ] + .iter() + .map(|s| s.to_string()) + .collect(); loot.foot = vec![ "Slippers", @@ -226,7 +250,10 @@ fn init_loot() -> () { "Moccasins", "Espadrilles", "Loafers", - ].iter().map(|s| s.to_string()).collect(); + ] + .iter() + .map(|s| s.to_string()) + .collect(); loot.underwear = vec![ "Thong", @@ -244,7 +271,10 @@ fn init_loot() -> () { "Granny Panties", "Diaper", "Garter", - ].iter().map(|s| s.to_string()).collect(); + ] + .iter() + .map(|s| s.to_string()) + .collect(); loot.accessory = vec![ "Necklace", @@ -308,7 +338,10 @@ fn init_loot() -> () { "Scrunchie", "Bracelet", "Kandi Bracelet", - ].iter().map(|s| s.to_string()).collect(); + ] + .iter() + .map(|s| s.to_string()) + .collect(); loot.pants = vec![ "Shorts", @@ -338,7 +371,10 @@ fn init_loot() -> () { "Hot Pants", "Swim Trunks", "Capri Pants", - ].iter().map(|s| s.to_string()).collect(); + ] + .iter() + .map(|s| s.to_string()) + .collect(); loot.prefixes = vec![ "Second Hand", @@ -363,7 +399,10 @@ fn init_loot() -> () { "Vintage", "Retro", "Victorian", - ].iter().map(|s| s.to_string()).collect(); + ] + .iter() + .map(|s| s.to_string()) + .collect(); loot.name_prefixes = vec![ "Gold", @@ -409,7 +448,10 @@ fn init_loot() -> () { "Boho", "Military", "Velour", - ].iter().map(|s| s.to_string()).collect(); + ] + .iter() + .map(|s| s.to_string()) + .collect(); loot.name_suffixes = vec![ "Dirty", @@ -446,8 +488,10 @@ fn init_loot() -> () { "Formal", "Monogramed", "Haute Couture", - ].iter().map(|s| s.to_string()).collect(); - + ] + .iter() + .map(|s| s.to_string()) + .collect(); let loot2 = storage::get_mut::(); *loot2 = Loot2 { @@ -482,7 +526,7 @@ fn remaining() -> u64 { #[query] fn owner_of(token_id: u64) -> Option { - return storage::get::().owner_of(&token_id); + return storage::get::().owner_of(&token_id); } #[update] @@ -490,6 +534,22 @@ fn transfer_to(user: Principal, token_id: u64) -> bool { return storage::get_mut::().transfer_to(user, token_id); } +#[update] +async fn transfer_with_notify( + user: Principal, + token_id: u64, + notification: TransferNotification, +) -> bool { + let address_book = storage::get_mut::(); + if address_book.transfer_to(user, token_id) { + let _result: CallResult<()> = + ic_cdk::call(notification.to, "transfer_notification", (notification,)).await; + return true; + } else { + return false; + } +} + #[update] fn claim() -> Result { //return Err("No claims for this NFT type (IC DRIP)".to_string()); @@ -507,13 +567,13 @@ fn get_airdrops() -> Vec<(u64, bool)> { let mut results: Vec<(u64, bool)> = Vec::new(); for token in tokens { results.push(( - token.clone(), - address_book.is_owner_of(ic_cdk::caller(), token) + token.clone(), + address_book.is_owner_of(ic_cdk::caller(), token), )); } return results; - }, - None => Vec::new() + } + None => Vec::new(), } } @@ -534,7 +594,7 @@ fn add_airdrops(users: Vec) -> bool { for id in users { match address_book.claim(id) { Ok(token_id) => update_airdroppers(id, token_id), - Err(_) => return false + Err(_) => return false, } } return true; @@ -592,10 +652,8 @@ struct HttpResponse { body: Vec, } - #[query] async fn http_request(req: HttpRequest) -> HttpResponse { - let parts: Vec<&str> = req.url.split('?').collect(); let token_param: Vec<&str> = parts[1].split('=').collect(); @@ -603,12 +661,13 @@ async fn http_request(req: HttpRequest) -> HttpResponse { let address_book = storage::get_mut::(); - if token_id <= 0 || token_id > address_book.total_supply || !address_book.is_claimed(&token_id) { + if token_id <= 0 || token_id > address_book.total_supply || !address_book.is_claimed(&token_id) + { return HttpResponse { status_code: 404, headers: Vec::new(), body: Vec::new(), - } + }; } let loot = storage::get_mut::(); @@ -621,19 +680,22 @@ async fn http_request(req: HttpRequest) -> HttpResponse { let mut headers: Vec = Vec::new(); headers.push(("content-type".to_string(), "image/svg+xml".to_string())); - headers.push(("cache-control".to_string(), "public, max-age=604800, immutable".to_string())); + headers.push(( + "cache-control".to_string(), + "public, max-age=604800, immutable".to_string(), + )); return HttpResponse { status_code: 200, headers, body: results.to_vec(), - } + }; } #[query] fn data_of(token_id: u64) -> Vec { - let address_book = storage::get::(); - if token_id <= 0 || token_id > address_book.total_supply || !address_book.is_claimed(&token_id) { + if token_id <= 0 || token_id > address_book.total_supply || !address_book.is_claimed(&token_id) + { return Vec::new(); } let seed = address_book.token_seeds.get(&token_id).unwrap(); @@ -644,7 +706,7 @@ fn data_of(token_id: u64) -> Vec { #[derive(Clone, Debug, CandidType, Deserialize)] pub enum DataOfQuery { Range(u64, u64), - List(Vec) + List(Vec), } #[query] @@ -653,7 +715,7 @@ fn data_of_many(query: DataOfQuery) -> BTreeMap> { match query { DataOfQuery::Range(from, to) => { let mut results = BTreeMap::new(); - for i in from..to+1 { + for i in from..to + 1 { if !address_book.is_claimed(&i) { continue; } @@ -662,7 +724,7 @@ fn data_of_many(query: DataOfQuery) -> BTreeMap> { results.insert(i, loot.get_properties(i + seed)); } return results; - }, + } DataOfQuery::List(items) => { let mut results = BTreeMap::new(); for id in items { @@ -674,15 +736,15 @@ fn data_of_many(query: DataOfQuery) -> BTreeMap> { results.insert(id, loot.get_properties(id + seed)); } return results; - }, + } } } #[query] fn get_token_properties(token_id: u64) -> Vec<(String, String)> { - let address_book = storage::get::(); - if token_id <= 0 || token_id > address_book.total_supply || !address_book.is_claimed(&token_id) { + if token_id <= 0 || token_id > address_book.total_supply || !address_book.is_claimed(&token_id) + { return Vec::new(); } let seed = address_book.token_seeds.get(&token_id).unwrap(); @@ -691,12 +753,10 @@ fn get_token_properties(token_id: u64) -> Vec<(String, String)> { } #[query] -fn get_token_properties_range(from: u64, to:u64) -> Vec> { - +fn get_token_properties_range(from: u64, to: u64) -> Vec> { let address_book = storage::get::(); - let mut results = Vec::new(); - for i in from..to+1 { + for i in from..to + 1 { if !address_book.is_claimed(&i) { continue; } @@ -707,7 +767,6 @@ fn get_token_properties_range(from: u64, to:u64) -> Vec> { return results; } - //this is not working correctly. #[query(name = "__get_candid_interface_tmp_hack")] fn export_candid() -> String { @@ -754,6 +813,13 @@ type ClaimResult = variant { Err: text; }; +type TransferNotification = record { + to: principal; + from: principal; + amount: nat64; + memo: opt blob; +}; + type LootData = record { slot: text; name: text; @@ -788,6 +854,7 @@ service : { user_tokens: (principal) -> (vec nat64) query; owner_of: (nat64) -> (opt principal) query; transfer_to: (principal, nat64) -> (bool); + transfer_with_notify: (principal, nat64, TransferNotification) -> (bool); claim: () -> (ClaimResult); remaining: () -> (nat64); @@ -796,19 +863,18 @@ service : { remove_controller: (principal) -> (bool); supply: () -> (nat64); } - "#.to_string(); + "# + .to_string(); } #[derive(CandidType, Deserialize)] struct StableStorage { address_book: AddressBook, - airdroppers: BTreeMap> + airdroppers: BTreeMap>, } - #[pre_upgrade] fn pre_upgrade() { - let stable = StableStorage { address_book: storage::get::().clone(), airdroppers: storage::get::>>().clone(), @@ -829,10 +895,8 @@ fn pre_upgrade() { fn post_upgrade() { init(); if let Ok((storage,)) = storage::stable_restore::<(StableStorage,)>() { - let address_book = storage::get_mut::(); *address_book = storage.address_book; - let airdroppers = storage::get_mut::>>(); *airdroppers = storage.airdroppers; } From 119d180069a9958b8759aa6dc4046aeee0a070bb Mon Sep 17 00:00:00 2001 From: Rick Porter Date: Sat, 11 Sep 2021 23:06:07 -0700 Subject: [PATCH 3/6] added transfer_with_notify --- src/ic_loot_rs/address.rs | 21 +++++++++++++++++++++ src/ic_loot_rs/ic_loot.did | 4 ++-- src/ic_loot_rs/lib.rs | 35 +++++++++++++++++++++++------------ 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/ic_loot_rs/address.rs b/src/ic_loot_rs/address.rs index 40a7a9a..d73806a 100644 --- a/src/ic_loot_rs/address.rs +++ b/src/ic_loot_rs/address.rs @@ -64,6 +64,27 @@ impl AddressBook { return false; } + pub fn undo_transfer(&mut self, user_id: Principal, token_id: u64) -> bool { + if let Some(token_owner) = self.tokens.get(&token_id) { + if &user_id == token_owner { + self.tokens.insert(token_id, ic_cdk::caller()); + return true; + } + } + return false; + } + + pub fn undo_transfer2(&mut self, user_id: Principal, token_id: u64) -> bool { + if let Some(token_owner) = self.tokens.get(&token_id) { + if &user_id == token_owner { + ic_cdk::println!("qwe12qw21wq {:?}", token_owner); + self.tokens.insert(token_id, ic_cdk::caller()); + return true; + } + } + return false; + } + pub fn transfer_to(&mut self, user: Principal, token_id: u64) -> bool { if let Some(token_owner) = self.tokens.get(&token_id) { if token_owner == &ic_cdk::caller() { diff --git a/src/ic_loot_rs/ic_loot.did b/src/ic_loot_rs/ic_loot.did index f2c1b14..6e14bbe 100644 --- a/src/ic_loot_rs/ic_loot.did +++ b/src/ic_loot_rs/ic_loot.did @@ -58,8 +58,8 @@ type DataOfQuery = variant { type TransferNotification = record { to: principal; from: principal; + token_id: nat64; amount: nat64; - memo: opt blob; }; service : { @@ -80,7 +80,7 @@ service : { user_tokens: (principal) -> (vec nat64) query; owner_of: (nat64) -> (opt principal) query; transfer_to: (principal, nat64) -> (bool); - transfer_with_notify: (principal, nat64, TransferNotification) -> (bool); + transfer_with_notify: (principal, nat64) -> (bool); claim: () -> (ClaimResult); remaining: () -> (nat64); supply: () -> (nat64); diff --git a/src/ic_loot_rs/lib.rs b/src/ic_loot_rs/lib.rs index f3bb27c..2852b6a 100644 --- a/src/ic_loot_rs/lib.rs +++ b/src/ic_loot_rs/lib.rs @@ -20,10 +20,9 @@ use crate::loot2::{Loot2, LootData}; #[derive(Clone, Debug, CandidType, Deserialize)] pub struct TransferNotification { pub to: Principal, - pub token: u64, + pub token_id: u64, pub from: Principal, pub amount: u64, - pub memo: Option>, } #[init] @@ -536,15 +535,27 @@ fn transfer_to(user: Principal, token_id: u64) -> bool { #[update] async fn transfer_with_notify( - user: Principal, - token_id: u64, - notification: TransferNotification, + user_id: Principal, token_id: u64 ) -> bool { let address_book = storage::get_mut::(); - if address_book.transfer_to(user, token_id) { - let _result: CallResult<()> = - ic_cdk::call(notification.to, "transfer_notification", (notification,)).await; - return true; + if address_book.transfer_to(user_id, token_id) { + match + ic_cdk::call(user_id, "transfer_notification", ( + TransferNotification{ + to: user_id, + from: ic_cdk::caller(), + token_id: token_id, + amount: 1 + },) + ).await as CallResult<()> { + Ok(_) => return true, + Err(_) => { + //gets in rejected state and the next + //line is not executed completely + //address_book.undo_transfer(user_id, token_id); + return false; + } + } } else { return false; } @@ -816,9 +827,9 @@ type ClaimResult = variant { type TransferNotification = record { to: principal; from: principal; + token_id: nat64; amount: nat64; - memo: opt blob; -}; + }; type LootData = record { slot: text; @@ -854,7 +865,7 @@ service : { user_tokens: (principal) -> (vec nat64) query; owner_of: (nat64) -> (opt principal) query; transfer_to: (principal, nat64) -> (bool); - transfer_with_notify: (principal, nat64, TransferNotification) -> (bool); + transfer_with_notify: (principal, nat64) -> (bool); claim: () -> (ClaimResult); remaining: () -> (nat64); From 59f964e4f2f77a57e43b561c4499857dbb7977b2 Mon Sep 17 00:00:00 2001 From: Rick Porter Date: Sat, 11 Sep 2021 23:24:18 -0700 Subject: [PATCH 4/6] removed undo duplicate function --- package-lock.json | 5 ----- src/ic_loot_rs/address.rs | 11 ----------- src/ic_loot_rs/lib.rs | 1 + 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2f669f6..754aa75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1455,11 +1455,6 @@ "@vue/shared": "3.2.9" } }, - "vue-analytics": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/vue-analytics/-/vue-analytics-5.22.1.tgz", - "integrity": "sha512-HPKQMN7gfcUqS5SxoO0VxqLRRSPkG1H1FqglsHccz6BatBatNtm/Vyy8brApktZxNCfnAkrSVDpxg3/FNDeOgQ==" - }, "vue-gtag-next": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/vue-gtag-next/-/vue-gtag-next-1.14.0.tgz", diff --git a/src/ic_loot_rs/address.rs b/src/ic_loot_rs/address.rs index d73806a..03523f6 100644 --- a/src/ic_loot_rs/address.rs +++ b/src/ic_loot_rs/address.rs @@ -74,17 +74,6 @@ impl AddressBook { return false; } - pub fn undo_transfer2(&mut self, user_id: Principal, token_id: u64) -> bool { - if let Some(token_owner) = self.tokens.get(&token_id) { - if &user_id == token_owner { - ic_cdk::println!("qwe12qw21wq {:?}", token_owner); - self.tokens.insert(token_id, ic_cdk::caller()); - return true; - } - } - return false; - } - pub fn transfer_to(&mut self, user: Principal, token_id: u64) -> bool { if let Some(token_owner) = self.tokens.get(&token_id) { if token_owner == &ic_cdk::caller() { diff --git a/src/ic_loot_rs/lib.rs b/src/ic_loot_rs/lib.rs index 2852b6a..bf59c77 100644 --- a/src/ic_loot_rs/lib.rs +++ b/src/ic_loot_rs/lib.rs @@ -784,6 +784,7 @@ fn export_candid() -> String { return r#" // http://icdrip.io +// STAGING ENVIRONMENT // ██▓ ▄████▄ ▓█████▄ ██▀███ ██▓ ██▓███ // ▓██▒▒██▀ ▀█ ▒██▀ ██▌▓██ ▒ ██▒▓██▒▓██░ ██▒ From f1c944e09317625801b92e42b8e5b7f6a6f6b51c Mon Sep 17 00:00:00 2001 From: Rick Porter Date: Sun, 12 Sep 2021 16:27:14 -0700 Subject: [PATCH 5/6] added transfer_with_notify --- package.json | 2 +- src/ic_loot_rs/lib.rs | 39 +++++++++++++++++++------------------ src/ic_loot_rs/loot.rs | 43 ++++++++++++++++++++++++----------------- src/ic_loot_rs/loot2.rs | 27 +++++++++++++------------- 4 files changed, 60 insertions(+), 51 deletions(-) diff --git a/package.json b/package.json index 00ede20..73c25c7 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "vite build", "dev": "vite", - "dfx:install": "dfx canister install ic_loot_rs --all --mode upgrade", + "dfx:install": "dfx canister install ic_loot_rs --all", "dfx:rebuild": "dfx build && npm run dfx:install", "dfx:setup": "dfx canister create --all && dfx build && npm run dfx:install" }, diff --git a/src/ic_loot_rs/lib.rs b/src/ic_loot_rs/lib.rs index bf59c77..020de6d 100644 --- a/src/ic_loot_rs/lib.rs +++ b/src/ic_loot_rs/lib.rs @@ -534,28 +534,29 @@ fn transfer_to(user: Principal, token_id: u64) -> bool { } #[update] -async fn transfer_with_notify( - user_id: Principal, token_id: u64 -) -> bool { +async fn transfer_with_notify(user_id: Principal, token_id: u64) -> bool { let address_book = storage::get_mut::(); if address_book.transfer_to(user_id, token_id) { - match - ic_cdk::call(user_id, "transfer_notification", ( - TransferNotification{ - to: user_id, - from: ic_cdk::caller(), - token_id: token_id, - amount: 1 - },) - ).await as CallResult<()> { - Ok(_) => return true, - Err(_) => { - //gets in rejected state and the next - //line is not executed completely - //address_book.undo_transfer(user_id, token_id); - return false; - } + match ic_cdk::call( + user_id, + "transfer_notification", + (TransferNotification { + to: user_id, + from: ic_cdk::caller(), + token_id: token_id, + amount: 1, + },), + ) + .await as CallResult<()> + { + Ok(_) => return true, + Err(_) => { + //gets in rejected state and the next + //line is not executed completely + //address_book.undo_transfer(user_id, token_id); + return false; } + } } else { return false; } diff --git a/src/ic_loot_rs/loot.rs b/src/ic_loot_rs/loot.rs index 82c2f5f..8ac33ad 100644 --- a/src/ic_loot_rs/loot.rs +++ b/src/ic_loot_rs/loot.rs @@ -1,7 +1,5 @@ - -use ic_cdk::export::{candid::{CandidType, Deserialize}}; use crate::rand::Rand; - +use ic_cdk::export::candid::{CandidType, Deserialize}; #[derive(Clone, Debug, Default, CandidType, Deserialize)] pub struct Loot { @@ -13,7 +11,6 @@ pub struct Loot { pub underwear: Vec, pub accessory: Vec, pub pants: Vec, - pub prefixes: Vec, pub suffixes: Vec, pub name_prefixes: Vec, @@ -21,7 +18,6 @@ pub struct Loot { } impl Loot { - pub fn get_weapon(&self, token_id: u64) -> String { self.compute(&self.weapons, 1, token_id) } @@ -75,15 +71,25 @@ impl Loot { let greatness = rand % 21; if greatness > 14 { - output = format!("{} {}",self.get_prefix(rand), output); - } + output = format!("{} {}", self.get_prefix(rand), output); + } if greatness > 19 { if greatness == 19 { - output = format!("\"{}\" {} ({})", self.get_name_prefix(rand), self.get_name_suffix(rand), output); + output = format!( + "\"{}\" {} ({})", + self.get_name_prefix(rand), + self.get_name_suffix(rand), + output + ); } else { - output = format!("\"{}\" {} ({}) 🔥", self.get_name_prefix(rand), output, self.get_name_suffix(rand)); + output = format!( + "\"{}\" {} ({}) 🔥", + self.get_name_prefix(rand), + output, + self.get_name_suffix(rand) + ); } - } + } return output; } @@ -97,11 +103,12 @@ impl Loot { ("pants".to_string(), self.get_pants(token_id)), ("underwear".to_string(), self.get_underwear(token_id)), ("accessory".to_string(), self.get_accessory(token_id)), - ] + ]; } pub fn generate(&self, token_id: u64) -> String { - return format!(r#" + return format!( + r#" - "#, - self.get_weapon(token_id), - self.get_chest(token_id), - self.get_head(token_id), - self.get_waist(token_id), + "#, + self.get_weapon(token_id), + self.get_chest(token_id), + self.get_head(token_id), + self.get_waist(token_id), self.get_foot(token_id), self.get_underwear(token_id), self.get_accessory(token_id), self.get_pants(token_id), ); } -} \ No newline at end of file +} diff --git a/src/ic_loot_rs/loot2.rs b/src/ic_loot_rs/loot2.rs index 991111d..15da261 100644 --- a/src/ic_loot_rs/loot2.rs +++ b/src/ic_loot_rs/loot2.rs @@ -1,8 +1,7 @@ - -use ic_cdk::export::{candid::{CandidType, Deserialize}}; use crate::rand::Rand; +use ic_cdk::export::candid::{CandidType, Deserialize}; -//I created this because I did not want to +//I created this because I did not want to //mess with the generator which is being used. #[derive(Clone, Debug, Default, CandidType, Deserialize)] @@ -15,7 +14,6 @@ pub struct Loot2 { pub underwear: Vec, pub accessory: Vec, pub pants: Vec, - pub prefixes: Vec, pub name_prefixes: Vec, pub name_suffixes: Vec, @@ -25,16 +23,13 @@ pub struct Loot2 { pub struct LootData { pub slot: String, pub name: String, - pub prefix: String, pub name_prefix: String, pub name_suffix: String, - pub special: bool + pub special: bool, } - impl Loot2 { - pub fn get_weapon(&self, token_id: u64) -> LootData { self.compute(&self.weapons, 1, token_id, "weapon".to_string()) } @@ -79,7 +74,13 @@ impl Loot2 { return self.name_suffixes[rand as usize % &self.name_suffixes.len()].clone(); } - pub fn compute(&self, items: &Vec, offset: u64, token_id: u64, kind: String) -> LootData { + pub fn compute( + &self, + items: &Vec, + offset: u64, + token_id: u64, + kind: String, + ) -> LootData { let rand = Rand::new(token_id + offset).rand(); let item_index = rand as usize % items.len(); @@ -92,7 +93,7 @@ impl Loot2 { if greatness > 14 { data.prefix = self.get_prefix(rand); - } + } if greatness > 19 { if greatness == 19 { data.name_prefix = self.get_name_prefix(rand); @@ -103,7 +104,7 @@ impl Loot2 { data.name_prefix = self.get_name_prefix(rand); data.name_suffix = self.get_name_suffix(rand); } - } + } return data; } @@ -117,6 +118,6 @@ impl Loot2 { self.get_underwear(token_id), self.get_accessory(token_id), self.get_foot(token_id), - ] + ]; } -} \ No newline at end of file +} From 0ae9e43618675346637798573ef14e131b1cc4a3 Mon Sep 17 00:00:00 2001 From: Norton Wang <1502552+FloorLamp@users.noreply.github.com> Date: Tue, 14 Sep 2021 19:42:19 -0400 Subject: [PATCH 6/6] Bump ic-cdk and fix cycle balance --- src/ic_loot_rs/Cargo.toml | 4 ++-- src/ic_loot_rs/lib.rs | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ic_loot_rs/Cargo.toml b/src/ic_loot_rs/Cargo.toml index ca11896..03d6846 100644 --- a/src/ic_loot_rs/Cargo.toml +++ b/src/ic_loot_rs/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["cdylib"] [dependencies] ic-types = "0.2.1" -ic-cdk = "0.2.4" +ic-cdk = "0.3.1" base64 = "0.13.0" ic-cdk-macros = "0.3.0" ic-certified-map = "0.1.0" @@ -21,4 +21,4 @@ num-traits = "0.2.14" serde = "1.0.116" serde_cbor = "0.11" serde_bytes = "0.11" -serde_with = "1.6.2" \ No newline at end of file +serde_with = "1.6.2" diff --git a/src/ic_loot_rs/lib.rs b/src/ic_loot_rs/lib.rs index 020de6d..6009642 100644 --- a/src/ic_loot_rs/lib.rs +++ b/src/ic_loot_rs/lib.rs @@ -628,8 +628,8 @@ fn get_controllers() -> Vec { } #[update] -fn get_cycles() -> i64 { - return ic_cdk::api::call::msg_cycles_available(); +fn get_cycles() -> u64 { + return ic_cdk::api::canister_balance(); } #[query] @@ -787,17 +787,17 @@ fn export_candid() -> String { // http://icdrip.io // STAGING ENVIRONMENT -// ██▓ ▄████▄ ▓█████▄ ██▀███ ██▓ ██▓███ +// ██▓ ▄████▄ ▓█████▄ ██▀███ ██▓ ██▓███ // ▓██▒▒██▀ ▀█ ▒██▀ ██▌▓██ ▒ ██▒▓██▒▓██░ ██▒ // ▒██▒▒▓█ ▄ ░██ █▌▓██ ░▄█ ▒▒██▒▓██░ ██▓▒ // ░██░▒▓▓▄ ▄██▒ ░▓█▄ ▌▒██▀▀█▄ ░██░▒██▄█▓▒ ▒ // ░██░▒ ▓███▀ ░ ░▒████▓ ░██▓ ▒██▒░██░▒██▒ ░ ░ // ░▓ ░ ░▒ ▒ ░ ▒▒▓ ▒ ░ ▒▓ ░▒▓░░▓ ▒▓▒░ ░ ░ -// ▒ ░ ░ ▒ ░ ▒ ▒ ░▒ ░ ▒░ ▒ ░░▒ ░ -// ▒ ░░ ░ ░ ░ ░░ ░ ▒ ░░░ -// ░ ░ ░ ░ ░ ░ -// ░ ░ - +// ▒ ░ ░ ▒ ░ ▒ ▒ ░▒ ░ ▒░ ▒ ░░▒ ░ +// ▒ ░░ ░ ░ ░ ░░ ░ ▒ ░░░ +// ░ ░ ░ ░ ░ ░ +// ░ ░ + type HeaderField = record { text; text; }; type HttpRequest = record { @@ -847,7 +847,7 @@ type DataOfQuery = variant { Range: record {nat64; nat64}; List: vec nat64; }; - + service : { http_request: (request: HttpRequest) -> (HttpResponse) query; @@ -859,7 +859,7 @@ service : { data_of: (nat64) -> (vec LootData) query; data_of_many: (DataOfQuery) -> (vec record {nat64; vec LootData;}) query; - get_cycles: () -> (int64); + get_cycles: () -> (nat64); get_airdrops: () -> (vec record { nat64; bool }) query; add_airdrops: (vec principal) -> (bool); name: () -> (text) query;