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)); }
97
98 if !self.is_approved_or_owner(from, token_id) {
99 return Err(crate::error::Error::Internal(101)); }
101
102 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 self.set_owner(token_id, to);
111
112 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)); }
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)); }
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}