1use alloc::{string::String, vec::Vec};
12use alloy_primitives::{Address, U256};
13use alloy_sol_types::{sol, SolError};
14use core::{borrow::BorrowMut, marker::PhantomData};
15use stylus_sdk::{abi::Bytes, evm, msg, prelude::*};
16
17pub trait ERC721Params {
18 const NAME: &'static str;
19
20 const SYMBOL: &'static str;
21
22 fn token_uri(id: U256) -> String;
23}
24
25sol_storage! {
26 pub struct ERC721<T: ERC721Params> {
28 mapping(uint256 => address) owner_of;
29 mapping(address => uint256) balance_of;
30 mapping(uint256 => address) get_approved;
31 mapping(address => mapping(address => bool)) is_approved_for_all;
32 PhantomData<T> phantom;
33 }
34}
35
36sol! {
38 event Transfer(address indexed from, address indexed to, uint256 indexed id);
39 event Approval(address indexed owner, address indexed spender, uint256 indexed id);
40 event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
41
42 error NotMinted();
43 error ZeroAddress();
44 error NotAuthorized();
45 error WrongFrom();
46 error InvalidRecipient();
47 error UnsafeRecipient();
48 error AlreadyMinted();
49}
50
51pub enum ERC721Error {
53 NotMinted(NotMinted),
54 ZeroAddress(ZeroAddress),
55 NotAuthorized(NotAuthorized),
56 WrongFrom(WrongFrom),
57 InvalidRecipient(InvalidRecipient),
58 UnsafeRecipient(UnsafeRecipient),
59 CallFailed(stylus_sdk::call::Error),
60 AlreadyMinted(AlreadyMinted),
61}
62
63impl From<stylus_sdk::call::Error> for ERC721Error {
64 fn from(err: stylus_sdk::call::Error) -> Self {
65 Self::CallFailed(err)
66 }
67}
68
69impl From<ERC721Error> for Vec<u8> {
71 fn from(val: ERC721Error) -> Self {
72 match val {
73 ERC721Error::NotMinted(err) => err.encode(),
74 ERC721Error::ZeroAddress(err) => err.encode(),
75 ERC721Error::NotAuthorized(err) => err.encode(),
76 ERC721Error::WrongFrom(err) => err.encode(),
77 ERC721Error::InvalidRecipient(err) => err.encode(),
78 ERC721Error::UnsafeRecipient(err) => err.encode(),
79 ERC721Error::CallFailed(err) => err.into(),
80 ERC721Error::AlreadyMinted(err) => err.encode(),
81 }
82 }
83}
84
85type Result<T, E = ERC721Error> = core::result::Result<T, E>;
87
88impl<T: ERC721Params> ERC721<T> {
89 fn call_receiver<S: TopLevelStorage>(
90 storage: &mut S,
91 id: U256,
92 from: Address,
93 to: Address,
94 data: Vec<u8>,
95 ) -> Result<()> {
96 if to.has_code() {
97 let receiver = IERC721TokenReceiver::new(to);
98 let received = receiver
99 .on_erc_721_received(&mut *storage, msg::sender(), from, id, data)?
100 .0;
101
102 if u32::from_be_bytes(received) != 0x150b7a02 {
104 return Err(ERC721Error::UnsafeRecipient(UnsafeRecipient {}));
105 }
106 }
107 Ok(())
108 }
109
110 pub fn safe_transfer<S: TopLevelStorage + BorrowMut<Self>>(
111 storage: &mut S,
112 id: U256,
113 from: Address,
114 to: Address,
115 data: Vec<u8>,
116 ) -> Result<()> {
117 storage.borrow_mut().transfer_from(from, to, id)?;
118 Self::call_receiver(storage, id, from, to, data)
119 }
120
121 pub fn mint(&mut self, to: Address, id: U256) -> Result<()> {
122 if to.is_zero() {
123 return Err(ERC721Error::InvalidRecipient(InvalidRecipient {}));
124 }
125
126 if self.owner_of.get(id) != Address::ZERO {
127 return Err(ERC721Error::AlreadyMinted(AlreadyMinted {}));
128 }
129
130 let mut to_balance = self.balance_of.setter(to);
131 let balance = to_balance.get() + U256::from(1);
132 to_balance.set(balance);
133
134 self.owner_of.setter(id).set(to);
135
136 evm::log(Transfer {
137 from: Address::ZERO,
138 to: to,
139 id: id,
140 });
141
142 Ok(())
143 }
144
145 pub fn burn(&mut self, id: U256) -> Result<()> {
146 let owner = self.owner_of.get(id);
147
148 if owner.is_zero() {
149 return Err(ERC721Error::NotMinted(NotMinted {}));
150 }
151
152 let mut owner_balance = self.balance_of.setter(owner);
153 let balance = owner_balance.get() - U256::from(1);
154 owner_balance.set(balance);
155
156 self.owner_of.delete(id);
157
158 self.get_approved.delete(id);
159
160 evm::log(Transfer {
161 from: owner,
162 to: Address::ZERO,
163 id: id,
164 });
165
166 Ok(())
167 }
168
169 pub fn safe_mint<S: TopLevelStorage>(
170 &mut self,
171 storage: &mut S,
172 to: Address,
173 id: U256,
174 ) -> Result<()> {
175 Self::mint(self, to, id)?;
176
177 Self::call_receiver(storage, id, Address::ZERO, to, vec![])?;
178
179 Ok(())
180 }
181
182 pub fn safe_mint_with_data<S: TopLevelStorage>(
183 &mut self,
184 storage: &mut S,
185 to: Address,
186 id: U256,
187 data: Bytes,
188 ) -> Result<()> {
189 Self::mint(self, to, id)?;
190
191 Self::call_receiver(storage, id, Address::ZERO, to, data.0)?;
192
193 Ok(())
194 }
195}
196
197#[external]
198impl<T: ERC721Params> ERC721<T> {
199 pub fn name() -> Result<String> {
200 Ok(T::NAME.into())
201 }
202
203 pub fn symbol() -> Result<String> {
204 Ok(T::SYMBOL.into())
205 }
206
207 pub fn owner_of(&self, id: U256) -> Result<Address> {
208 let owner = self.owner_of.get(id);
209
210 if owner.is_zero() {
211 return Err(ERC721Error::NotMinted(NotMinted {}));
212 }
213
214 Ok(owner)
215 }
216
217 pub fn balance_of(&self, owner: Address) -> Result<U256> {
218 if owner.is_zero() {
219 return Err(ERC721Error::ZeroAddress(ZeroAddress {}));
220 }
221
222 Ok(self.balance_of.get(owner))
223 }
224
225 pub fn get_approved(&self, id: U256) -> Result<Address> {
226 Ok(self.get_approved.get(id))
227 }
228
229 pub fn is_approved_for_all(&self, owner: Address, operator: Address) -> Result<bool> {
230 Ok(self.is_approved_for_all.getter(owner).get(operator))
231 }
232
233 #[selector(name = "tokenURI")]
234 pub fn token_uri(&self, id: U256) -> Result<String> {
235 Ok(T::token_uri(id))
236 }
237
238 pub fn approve(&mut self, spender: Address, id: U256) -> Result<()> {
239 let owner = self.owner_of.get(id);
240
241 if msg::sender() != owner || !self.is_approved_for_all.getter(owner).get(msg::sender()) {
242 return Err(ERC721Error::NotAuthorized(NotAuthorized {}));
243 }
244
245 self.get_approved.setter(id).set(spender);
246
247 evm::log(Approval {
248 owner: owner,
249 spender: spender,
250 id: id,
251 });
252
253 Ok(())
254 }
255
256 pub fn set_approval_for_all(&mut self, operator: Address, approved: bool) -> Result<()> {
257 self.is_approved_for_all
258 .setter(msg::sender())
259 .insert(operator, approved);
260
261 evm::log(ApprovalForAll {
262 owner: msg::sender(),
263 operator: operator,
264 approved: approved,
265 });
266
267 Ok(())
268 }
269
270 pub fn transfer_from(&mut self, from: Address, to: Address, id: U256) -> Result<()> {
271 if from != self.owner_of.get(id) {
272 return Err(ERC721Error::WrongFrom(WrongFrom {}));
273 }
274
275 if to.is_zero() {
276 return Err(ERC721Error::InvalidRecipient(InvalidRecipient {}));
277 }
278
279 if msg::sender() != from
280 && !self.is_approved_for_all.getter(from).get(msg::sender())
281 && msg::sender() != self.get_approved.get(id)
282 {
283 return Err(ERC721Error::NotAuthorized(NotAuthorized {}));
284 }
285
286 let mut from_balance = self.balance_of.setter(from);
287 let balance = from_balance.get() - U256::from(1);
288 from_balance.set(balance);
289
290 let mut to_balance = self.balance_of.setter(to);
291 let balance = to_balance.get() + U256::from(1);
292 to_balance.set(balance);
293
294 self.owner_of.setter(id).set(to);
295
296 self.get_approved.delete(id);
297
298 evm::log(Transfer {
299 from: from,
300 to: to,
301 id: id,
302 });
303
304 Ok(())
305 }
306
307 pub fn safe_transfer_from<S: TopLevelStorage + BorrowMut<Self>>(
308 storage: &mut S,
309 from: Address,
310 to: Address,
311 id: U256,
312 ) -> Result<()> {
313 Self::safe_transfer_from_with_data(storage, from, to, id, Bytes(vec![]))
314 }
315
316 #[selector(name = "safeTransferFrom")]
317 pub fn safe_transfer_from_with_data<S: TopLevelStorage + BorrowMut<Self>>(
318 storage: &mut S,
319 from: Address,
320 to: Address,
321 id: U256,
322 data: Bytes,
323 ) -> Result<()> {
324 Self::safe_transfer(storage, id, from, to, data.0)
325 }
326
327 pub fn supports_interface(interface: [u8; 4]) -> Result<bool> {
328 let supported = interface == 0x01ffc9a7u32.to_be_bytes() || interface == 0x80ac58cdu32.to_be_bytes() || interface == 0x780e9d63u32.to_be_bytes(); Ok(supported)
332 }
333}
334
335sol_interface! {
336 interface IERC721TokenReceiver {
337 function onERC721Received(address operator, address from, uint256 id, bytes data) external returns(bytes4);
338 }
339}