spawn_wasm_erc721/
erc721.rs1use std::collections::HashMap;
2use wasm_bindgen::prelude::*;
3use web_sys::console;
4
5#[wasm_bindgen]
7pub struct ERC721 {
8 owner: String,
9 token_owner: HashMap<u64, String>, owned_tokens: HashMap<String, Vec<u64>>, approvals: HashMap<u64, String>, }
13
14#[wasm_bindgen]
15impl ERC721 {
16 #[wasm_bindgen(constructor)]
18 pub fn new(owner: String) -> ERC721 {
19 Self::log_event("ERC721 Created", &format!("Owner: {}", owner));
20 ERC721 {
21 owner,
22 token_owner: HashMap::new(),
23 owned_tokens: HashMap::new(),
24 approvals: HashMap::new(),
25 }
26 }
27
28 pub fn owner_of(&self, token_id: u64) -> Option<String> {
30 self.token_owner.get(&token_id).cloned()
31 }
32
33 pub fn mint(&mut self, owner: String, token_id: u64) -> Result<(), String> {
35 if owner != self.owner {
36 Self::log_event("Minting Failed", "Unauthorized attempt");
37 return Err("Only the contract owner can mint new tokens".to_string());
38 }
39
40 if self.token_owner.contains_key(&token_id) {
41 Self::log_event("Minting Failed", &format!("Token ID {} already exists", token_id));
42 return Err("Token ID already exists".to_string());
43 }
44
45 self.token_owner.insert(token_id, owner.clone());
46 self.owned_tokens.entry(owner.clone()).or_insert(Vec::new()).push(token_id);
47 Self::log_event("Token Minted", &format!("Token ID: {}, Owner: {}", token_id, owner));
48 Ok(())
49 }
50
51 pub fn transfer(&mut self, from: String, to: String, token_id: u64) -> Result<(), String> {
53 let owner = self.token_owner.get(&token_id).ok_or("Token does not exist")?;
54
55 if owner != &from && !self.is_approved_or_owner(from.clone(), token_id) {
56 Self::log_event("Transfer Failed", "Unauthorized attempt");
57 return Err("Unauthorized transfer attempt".to_string());
58 }
59
60 self.remove_token_from_owner(from.clone(), token_id);
61 self.token_owner.insert(token_id, to.clone());
62 self.owned_tokens.entry(to.clone()).or_insert(Vec::new()).push(token_id);
63 Self::log_event("Token Transferred", &format!("Token ID: {}, From: {}, To: {}", token_id, from, to));
64 Ok(())
65 }
66
67 pub fn approve(&mut self, owner: String, approved: String, token_id: u64) -> Result<(), String> {
69 let token_owner = self.token_owner.get(&token_id).ok_or("Token does not exist")?;
70
71 if token_owner != &owner {
72 Self::log_event("Approval Failed", "Unauthorized attempt");
73 return Err("Only the owner can approve".to_string());
74 }
75
76 self.approvals.insert(token_id, approved.clone());
77 Self::log_event("Approval Granted", &format!("Token ID: {}, Approved for: {}", token_id, approved));
78 Ok(())
79 }
80
81 pub fn get_approved(&self, token_id: u64) -> Option<String> {
83 self.approvals.get(&token_id).cloned()
84 }
85
86 pub fn is_approved_or_owner(&self, user: String, token_id: u64) -> bool {
88 let owner = self.token_owner.get(&token_id);
89 let approved = self.approvals.get(&token_id);
90
91 owner.map(|o| o == &user).unwrap_or(false) || approved.map(|a| a == &user).unwrap_or(false)
92 }
93
94 pub fn tokens_of_owner(&self, owner: String) -> Vec<u64> {
96 self.owned_tokens.get(&owner).cloned().unwrap_or_else(Vec::new)
97 }
98
99 fn log_event(event: &str, details: &str) {
101 console::log_2(&event.into(), &details.into());
102 }
103
104 fn remove_token_from_owner(&mut self, owner: String, token_id: u64) {
106 if let Some(tokens) = self.owned_tokens.get_mut(&owner) {
107 tokens.retain(|&id| id != token_id);
108 }
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_mint_and_transfer() {
118 let mut erc721 = ERC721::new("owner".to_string());
119
120 assert!(erc721.mint("owner".to_string(), 1).is_ok());
122 assert_eq!(erc721.owner_of(1).unwrap(), "owner".to_string());
123
124 assert!(erc721.transfer("owner".to_string(), "user1".to_string(), 1).is_ok());
126 assert_eq!(erc721.owner_of(1).unwrap(), "user1".to_string());
127
128 assert!(erc721.transfer("owner".to_string(), "user2".to_string(), 1).is_err());
130 }
131
132 #[test]
133 fn test_approval_and_transfer() {
134 let mut erc721 = ERC721::new("owner".to_string());
135
136 erc721.mint("owner".to_string(), 1).unwrap();
138
139 assert!(erc721.approve("owner".to_string(), "user1".to_string(), 1).is_ok());
141 assert_eq!(erc721.get_approved(1).unwrap(), "user1".to_string());
142
143 assert!(erc721.transfer("user1".to_string(), "user2".to_string(), 1).is_ok());
145 assert_eq!(erc721.owner_of(1).unwrap(), "user2".to_string());
146 }
147}