Skip to main content

rootchain_std/
rrc721.rs

1use crate::traits::RRC721;
2use alloc::format;
3use alloc::string::String;
4use rootchain_core::types::Address;
5
6pub struct BaseRRC721 {
7    name: String,
8    symbol: String,
9}
10
11impl BaseRRC721 {
12    pub fn new(name: &str, symbol: &str) -> Self {
13        Self {
14            name: String::from(name),
15            symbol: String::from(symbol),
16        }
17    }
18
19    fn get_owner(&self, token_id: u64) -> Option<Address> {
20        let key = format!("tokens/{}", token_id);
21        let mut addr = [0u8; 32];
22        unsafe {
23            if crate::state_get(key.as_ptr(), key.len(), addr.as_mut_ptr(), 32) == 0 {
24                Some(Address(addr))
25            } else {
26                None
27            }
28        }
29    }
30
31    fn set_owner(&mut self, token_id: u64, owner: Address) {
32        let key = format!("tokens/{}", token_id);
33        unsafe {
34            crate::state_set(key.as_ptr(), key.len(), owner.0.as_ptr(), 32);
35        }
36    }
37
38    fn get_balance(&self, owner: Address) -> u64 {
39        let key = format!("balances/{}", hex::encode(owner.0));
40        let mut buf = [0u8; 8];
41        unsafe {
42            if crate::state_get(key.as_ptr(), key.len(), buf.as_mut_ptr(), 8) == 0 {
43                u64::from_le_bytes(buf)
44            } else {
45                0
46            }
47        }
48    }
49
50    fn set_balance(&mut self, owner: Address, balance: u64) {
51        let key = format!("balances/{}", hex::encode(owner.0));
52        let buf = balance.to_le_bytes();
53        unsafe {
54            crate::state_set(key.as_ptr(), key.len(), buf.as_ptr(), 8);
55        }
56    }
57
58    fn is_approved_or_owner(&self, spender: Address, token_id: u64) -> bool {
59        let owner = self.get_owner(token_id);
60        if owner.is_none() {
61            return false;
62        }
63        let owner = owner.unwrap();
64        if owner == spender {
65            return true;
66        }
67        self.get_approved(token_id) == spender
68    }
69}
70
71impl RRC721 for BaseRRC721 {
72    fn name(&self) -> &str {
73        &self.name
74    }
75
76    fn symbol(&self) -> &str {
77        &self.symbol
78    }
79
80    fn balance_of(&self, owner: Address) -> u64 {
81        self.get_balance(owner)
82    }
83
84    fn owner_of(&self, token_id: u64) -> Address {
85        self.get_owner(token_id).unwrap_or(Address([0; 32]))
86    }
87
88    fn safe_transfer_from(
89        &mut self,
90        from: Address,
91        to: Address,
92        token_id: u64,
93    ) -> Result<(), crate::error::Error> {
94        if self.get_owner(token_id) != Some(from) {
95            return Err(crate::error::Error::Internal(100)); // Not owner
96        }
97
98        if !self.is_approved_or_owner(from, token_id) {
99            return Err(crate::error::Error::Internal(101)); // Not authorized
100        }
101
102        // Update balances
103        let from_balance = self.get_balance(from);
104        self.set_balance(from, from_balance.saturating_sub(1));
105
106        let to_balance = self.get_balance(to);
107        self.set_balance(to, to_balance.saturating_add(1));
108
109        // Update owner
110        self.set_owner(token_id, to);
111
112        // Clear approval
113        let approve_key = format!("approvals/{}", token_id);
114        unsafe {
115            crate::state_set(
116                approve_key.as_ptr(),
117                approve_key.len(),
118                [0u8; 32].as_ptr(),
119                32,
120            );
121        }
122
123        Ok(())
124    }
125
126    fn approve(&mut self, to: Address, token_id: u64) -> Result<(), crate::error::Error> {
127        let owner = self.get_owner(token_id);
128        let mut caller = [0u8; 32];
129        unsafe { crate::get_caller(caller.as_mut_ptr()) };
130        if owner != Some(Address(caller)) {
131            return Err(crate::error::Error::Internal(100)); // Not owner
132        }
133
134        let key = format!("approvals/{}", token_id);
135        unsafe {
136            crate::state_set(key.as_ptr(), key.len(), to.0.as_ptr(), 32);
137        }
138        Ok(())
139    }
140
141    fn get_approved(&self, token_id: u64) -> Address {
142        let key = format!("approvals/{}", token_id);
143        let mut addr = [0u8; 32];
144        unsafe {
145            if crate::state_get(key.as_ptr(), key.len(), addr.as_mut_ptr(), 32) == 0 {
146                Address(addr)
147            } else {
148                Address([0; 32])
149            }
150        }
151    }
152
153    fn token_uri(&self, token_id: u64) -> String {
154        let key = format!("uri/{}", token_id);
155        let mut buf = [0u8; 256];
156        unsafe {
157            let len = crate::state_get(key.as_ptr(), key.len(), buf.as_mut_ptr(), 256);
158            if len >= 0 {
159                String::from_utf8_lossy(&buf[..len as usize]).into()
160            } else {
161                String::new()
162            }
163        }
164    }
165
166    fn get_attribute(&self, token_id: u64, key: &str) -> String {
167        let storage_key = format!("attr/{}/{}", token_id, key);
168        let mut buf = [0u8; 128];
169        unsafe {
170            let len = crate::state_get(
171                storage_key.as_ptr(),
172                storage_key.len(),
173                buf.as_mut_ptr(),
174                128,
175            );
176            if len >= 0 {
177                String::from_utf8_lossy(&buf[..len as usize]).into()
178            } else {
179                String::new()
180            }
181        }
182    }
183}
184
185impl BaseRRC721 {
186    pub fn set_token_uri(&mut self, token_id: u64, uri: &str) {
187        let key = format!("uri/{}", token_id);
188        unsafe {
189            crate::state_set(key.as_ptr(), key.len(), uri.as_ptr(), uri.len());
190        }
191    }
192
193    pub fn set_attribute(&mut self, token_id: u64, key: &str, value: &str) {
194        let storage_key = format!("attr/{}/{}", token_id, key);
195        unsafe {
196            crate::state_set(
197                storage_key.as_ptr(),
198                storage_key.len(),
199                value.as_ptr(),
200                value.len(),
201            );
202        }
203    }
204
205    pub fn mint(&mut self, to: Address, token_id: u64) -> Result<(), crate::error::Error> {
206        if self.get_owner(token_id).is_some() {
207            return Err(crate::error::Error::Internal(102)); // Already minted
208        }
209
210        self.set_owner(token_id, to);
211        let balance = self.get_balance(to);
212        self.set_balance(to, balance.saturating_add(1));
213        Ok(())
214    }
215}