1#![allow(unused_variables, missing_docs)]
2
3use alloc::collections::BTreeMap;
4use odra::{
5 casper_types::{bytesrepr::Bytes, U256},
6 named_keys::{
7 base64_encoded_key_value_storage, compound_key_value_storage, single_value_storage
8 },
9 prelude::*,
10 ContractRef
11};
12
13pub trait CEP95Interface {
15 fn name(&self) -> String;
17
18 fn symbol(&self) -> String;
20
21 fn balance_of(&self, owner: Address) -> U256;
29
30 fn owner_of(&self, token_id: U256) -> Option<Address>;
38
39 fn safe_transfer_from(
55 &mut self,
56 from: Address,
57 to: Address,
58 token_id: U256,
59 data: Option<Bytes>
60 );
61
62 fn transfer_from(&mut self, from: Address, to: Address, token_id: U256);
69
70 fn approve(&mut self, spender: Address, token_id: U256);
76
77 fn revoke_approval(&mut self, token_id: U256);
82
83 fn approved_for(&self, token_id: U256) -> Option<Address>;
91
92 fn approve_for_all(&mut self, operator: Address);
97
98 fn revoke_approval_for_all(&mut self, operator: Address);
103
104 fn is_approved_for_all(&self, owner: Address, operator: Address) -> bool;
113
114 fn token_metadata(&self, token_id: U256) -> Vec<(String, String)>;
122}
123
124#[odra::module]
125struct CEP95Receiver;
127
128#[odra::module]
129impl CEP95Receiver {
130 #[allow(dead_code)]
144 pub fn on_cep95_received(
145 &mut self,
146 operator: &Address,
147 from: &Address,
148 token_id: &U256,
149 data: &Option<Bytes>
150 ) -> bool {
151 true
156 }
157}
158
159const KEY_BALANCES: &str = "balances";
160const KEY_NAME: &str = "name";
161const KEY_SYMBOL: &str = "symbol";
162const KEY_APPROVED: &str = "approvals";
163const KEY_OPERATORS: &str = "operators";
164const KEY_METADATA: &str = "token_metadata";
165const KEY_OWNERS: &str = "owners";
166
167single_value_storage!(Cep95Name, String, KEY_NAME, Error::ValueNotSet);
168single_value_storage!(Cep95Symbol, String, KEY_SYMBOL, Error::ValueNotSet);
169base64_encoded_key_value_storage!(Cep95Balances, KEY_BALANCES, Address, U256);
170base64_encoded_key_value_storage!(Cep95Approvals, KEY_APPROVED, U256, Option<Address>);
171compound_key_value_storage!(Cep95Operators, KEY_OPERATORS, Address, bool);
172base64_encoded_key_value_storage!(Cep95Owners, KEY_OWNERS, U256, Option<Address>);
173base64_encoded_key_value_storage!(Cep95Metadata, KEY_METADATA, U256, BTreeMap<String, String>);
174
175#[odra::odra_error]
177pub enum Error {
178 ValueNotSet = 40_000,
180 TransferFailed = 40_001,
182 NotAnOwnerOrApproved = 40_002,
184 ApprovalToCurrentOwner = 40_003,
186 ApproveToCaller = 40_004,
188 InvalidTokenId = 40_005,
190 TokenAlreadyExists = 40_006
192}
193
194#[odra::event]
195pub struct Mint {
197 pub to: Address,
199 pub token_id: U256
201}
202
203#[odra::event]
204pub struct Burn {
206 pub from: Address,
208 pub token_id: U256
210}
211
212#[odra::event]
213pub struct Transfer {
215 pub from: Address,
217 pub to: Address,
219 pub token_id: U256
221}
222
223#[odra::event]
224pub struct Approval {
226 pub owner: Address,
228 pub spender: Address,
230 pub token_id: U256
232}
233
234#[odra::event]
235pub struct RevokeApproval {
237 pub owner: Address,
239 pub spender: Address,
241 pub token_id: U256
243}
244
245#[odra::event]
246pub struct ApprovalForAll {
248 pub owner: Address,
250 pub operator: Address
252}
253
254#[odra::event]
255pub struct RevokeApprovalForAll {
257 pub owner: Address,
259 pub operator: Address
261}
262
263#[odra::event]
264pub struct MetadataUpdate {
266 pub token_id: U256
268}
269
270#[odra::module(
271 events = [
272 Transfer,
273 Approval,
274 RevokeApproval,
275 ApprovalForAll,
276 RevokeApprovalForAll,
277 Mint,
278 Burn,
279 MetadataUpdate
280 ],
281 errors = Error
282)]
283pub struct Cep95 {
285 pub name: SubModule<Cep95Name>,
287 pub symbol: SubModule<Cep95Symbol>,
289 pub balances: SubModule<Cep95Balances>,
291 pub owners: SubModule<Cep95Owners>,
293 pub approvals: SubModule<Cep95Approvals>,
295 pub operators: SubModule<Cep95Operators>,
297 pub metadata: SubModule<Cep95Metadata>
299}
300
301#[odra::module]
302impl CEP95Interface for Cep95 {
303 fn name(&self) -> String {
304 self.name.get()
305 }
306
307 fn symbol(&self) -> String {
308 self.symbol.get()
309 }
310
311 fn balance_of(&self, owner: Address) -> U256 {
312 self.balances.get(&owner).unwrap_or_default()
313 }
314
315 fn owner_of(&self, token_id: U256) -> Option<Address> {
316 self.owners.get(&token_id).flatten()
317 }
318
319 fn safe_transfer_from(
320 &mut self,
321 from: Address,
322 to: Address,
323 token_id: U256,
324 data: Option<Bytes>
325 ) {
326 self.transfer_from(from, to, token_id);
327 if to.is_contract() {
328 let mut receiver = CEP95ReceiverContractRef::new(self.env(), to);
329 let caller = self.env().caller();
330 let result = receiver.on_cep95_received(&caller, &from, &token_id, &data);
331 if !result {
332 self.env().revert(Error::TransferFailed);
333 }
334 }
335 }
336
337 fn transfer_from(&mut self, from: Address, to: Address, token_id: U256) {
338 self.assert_exists(&token_id);
339
340 let caller = self.env().caller();
341 let owner = self.owner_of(token_id).unwrap_or_revert_with(self, Error::InvalidTokenId);
342
343 if owner != from {
345 self.env().revert(Error::NotAnOwnerOrApproved);
346 }
347
348 let is_authorized = owner == caller
350 || self.is_approved_for_all(from, caller)
351 || self.is_spender(token_id, caller);
352 if !is_authorized {
353 self.env().revert(Error::NotAnOwnerOrApproved);
354 }
355
356 self.raw_transfer(to, token_id); }
358
359 fn approve(&mut self, spender: Address, token_id: U256) {
360 let caller = self.env().caller();
361 let owner = self
362 .owner_of(token_id)
363 .unwrap_or_revert_with(self, Error::InvalidTokenId);
364 self.set_approve(token_id, owner, Some(spender));
365 self.env().emit_event(Approval {
366 owner,
367 spender,
368 token_id
369 });
370 }
371
372 fn revoke_approval(&mut self, token_id: U256) {
373 let spender = self
374 .approved_for(token_id)
375 .unwrap_or_revert_with(self, Error::ValueNotSet);
376 let owner = self
377 .owner_of(token_id)
378 .unwrap_or_revert_with(self, Error::InvalidTokenId);
379 self.set_approve(token_id, owner, None);
380 self.env().emit_event(RevokeApproval {
381 owner,
382 spender,
383 token_id
384 });
385 }
386
387 fn approved_for(&self, token_id: U256) -> Option<Address> {
388 self.assert_exists(&token_id);
389 self.approvals.get(&token_id).flatten()
390 }
391
392 fn approve_for_all(&mut self, operator: Address) {
393 let caller = self.env().caller();
394 self.set_approval_for_all(caller, operator, true);
395 self.env().emit_event(ApprovalForAll {
396 owner: caller,
397 operator
398 });
399 }
400
401 fn revoke_approval_for_all(&mut self, operator: Address) {
402 let caller = self.env().caller();
403 self.set_approval_for_all(caller, operator, false);
404 self.env().emit_event(RevokeApprovalForAll {
405 owner: caller,
406 operator
407 });
408 }
409
410 fn is_approved_for_all(&self, owner: Address, operator: Address) -> bool {
411 self.operators.get_or_default(&owner, &operator)
412 }
413
414 fn token_metadata(&self, token_id: U256) -> Vec<(String, String)> {
415 self.assert_exists(&token_id);
416 self.metadata
417 .get(&token_id)
418 .unwrap_or_default()
419 .into_iter()
420 .collect()
421 }
422}
423
424impl Cep95 {
425 pub fn init(&mut self, name: String, symbol: String) {
427 self.name.set(name);
429 self.symbol.set(symbol);
430
431 self.balances.init();
433 self.owners.init();
434 self.approvals.init();
435 self.operators.init();
436 self.metadata.init();
437 }
438
439 #[inline]
440 pub fn assert_exists(&self, token_id: &U256) {
443 if !self.exists(token_id) {
444 self.env().revert(Error::InvalidTokenId);
445 }
446 }
447
448 #[inline]
450 pub fn exists(&self, token_id: &U256) -> bool {
451 self.owners.get(token_id).flatten().is_some()
452 }
453
454 #[inline]
457 pub fn clear_approval(&mut self, token_id: &U256) {
458 if self.approvals.get(token_id).is_some() {
459 self.approvals.set(token_id, None);
460 }
461 }
462
463 pub fn raw_mint(&mut self, to: Address, token_id: U256, metadata: Vec<(String, String)>) {
466 if self.exists(&token_id) {
467 self.env().revert(Error::TokenAlreadyExists);
468 }
469
470 self.balances.set(&to, self.balance_of(to) + 1);
471 self.owners.set(&token_id, Some(to));
472 self.metadata.set(&token_id, BTreeMap::from_iter(metadata));
473
474 self.env().emit_event(Mint { to, token_id });
475 }
476
477 pub fn raw_burn(&mut self, token_id: U256) {
480 self.assert_exists(&token_id);
481 let owner = self
482 .owner_of(token_id)
483 .unwrap_or_revert_with(self, Error::ValueNotSet);
484
485 self.clear_approval(&token_id);
486 self.balances.set(&owner, self.balance_of(owner) - 1);
487 self.owners.set(&token_id, None);
488 self.metadata.set(&token_id, Default::default());
489
490 self.env().emit_event(Burn {
491 from: owner,
492 token_id
493 });
494 }
495
496 pub fn set_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
500 self.raw_update_metadata(token_id, metadata, BTreeMap::new());
501 }
502
503 pub fn update_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
509 let current_metadata = self.metadata.get(&token_id).unwrap_or_default();
510 self.raw_update_metadata(token_id, metadata, current_metadata);
511 }
512
513 pub fn raw_transfer(&mut self, to: Address, token_id: U256) -> Address {
516 self.clear_approval(&token_id);
517 let from = self
518 .owner_of(token_id)
519 .unwrap_or_revert_with(self, Error::InvalidTokenId);
520 self.balances.set(&from, self.balance_of(from) - 1);
521 self.balances.set(&to, self.balance_of(to) + 1);
522 self.owners.set(&token_id, Some(to));
523
524 self.env().emit_event(Transfer { from, to, token_id });
525 from
526 }
527
528 fn raw_update_metadata(
529 &mut self,
530 token_id: U256,
531 new_metadata: Vec<(String, String)>,
532 mut current_metadata: BTreeMap<String, String>
533 ) {
534 self.assert_exists(&token_id);
535 for (k, v) in new_metadata {
536 current_metadata.insert(k, v);
537 }
538 self.metadata.set(&token_id, current_metadata);
539 self.env().emit_event(MetadataUpdate { token_id });
540 }
541
542 #[inline]
543 fn set_approve(&mut self, token_id: U256, owner: Address, spender: Option<Address>) {
544 if Some(owner) == spender {
545 self.env().revert(Error::ApprovalToCurrentOwner);
546 }
547
548 let caller = self.env().caller();
549 if caller != owner && !self.is_approved_for_all(owner, caller) {
550 self.env().revert(Error::NotAnOwnerOrApproved);
551 }
552
553 self.approvals.set(&token_id, spender);
554 }
555
556 #[inline]
557 fn set_approval_for_all(&mut self, caller: Address, operator: Address, approved: bool) {
558 if caller == operator {
559 self.env().revert(Error::ApproveToCaller)
560 }
561
562 self.operators.set(&caller, &operator, approved);
563 }
564
565 #[inline]
566 fn is_spender(&self, token_id: U256, spender: Address) -> bool {
567 self.approved_for(token_id) == Some(spender)
568 }
569}
570
571mod utils {
572 #![allow(dead_code)]
573 use crate::access::Ownable;
574
575 use super::*;
576
577 #[odra::module]
578 pub(crate) struct BasicCep95 {
579 token: SubModule<Cep95>,
580 ownable: SubModule<Ownable>
581 }
582
583 #[odra::module]
584 impl BasicCep95 {
585 pub fn init(&mut self, name: String, symbol: String) {
587 let owner = self.env().caller();
588 self.ownable.init(owner);
589 self.token.init(name, symbol);
590 }
591
592 delegate! {
593 to self.token {
594 fn name(&self) -> String;
595 fn symbol(&self) -> String;
596 fn balance_of(&self, owner: Address) -> U256;
597 fn owner_of(&self, token_id: U256) -> Option<Address>;
598 fn safe_transfer_from(&mut self, from: Address, to: Address, token_id: U256, data: Option<Bytes>);
599 fn transfer_from(&mut self, from: Address, to: Address, token_id: U256);
600 fn approve(&mut self, spender: Address, token_id: U256);
601 fn revoke_approval(&mut self, token_id: U256);
602 fn approved_for(&self, token_id: U256) -> Option<Address>;
603 fn approve_for_all(&mut self, operator: Address);
604 fn revoke_approval_for_all(&mut self, operator: Address);
605 fn is_approved_for_all(&self, owner: Address, operator: Address) -> bool;
606 fn token_metadata(&self, token_id: U256) -> Vec<(String, String)>;
607 }
608 }
609
610 pub fn mint(&mut self, to: Address, token_id: U256, metadata: Vec<(String, String)>) {
611 self.assert_owner();
612 self.token.raw_mint(to, token_id, metadata);
613 }
614
615 pub fn burn(&mut self, token_id: U256) {
616 self.assert_owner();
617 self.token.raw_burn(token_id);
618 }
619
620 pub fn set_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
621 self.assert_owner();
622 self.token.set_metadata(token_id, metadata);
623 }
624
625 pub fn update_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
626 self.assert_owner();
627 self.token.update_metadata(token_id, metadata);
628 }
629
630 pub fn assert_owner(&self) {
631 self.ownable.assert_owner(&self.env().caller());
632 }
633 }
634
635 #[odra::module]
636 pub(crate) struct NFTReceiver {
637 #[allow(clippy::type_complexity)]
638 last_call_data: Var<((Address, Address), (U256, Option<Bytes>))>
639 }
640
641 #[odra::module]
642 impl NFTReceiver {
643 #[allow(dead_code)]
644 pub fn on_cep95_received(
645 &mut self,
646 operator: Address,
647 from: Address,
648 token_id: U256,
649 data: Option<Bytes>
650 ) -> bool {
651 self.last_call_data
652 .set(((operator, from), (token_id, data.clone())));
653 true
654 }
655
656 #[allow(dead_code)]
657 pub fn last_call_result(&self) -> ((Address, Address), (U256, Option<Bytes>)) {
658 self.last_call_data.get().unwrap_or_revert(self)
659 }
660 }
661
662 #[odra::module]
663 pub(crate) struct RejectingNFTReceiver;
664
665 #[odra::module]
666 impl RejectingNFTReceiver {
667 #[allow(dead_code)]
668 pub fn on_cep95_received(
669 &mut self,
670 operator: Address,
671 from: Address,
672 token_id: U256,
673 data: Option<Bytes>
674 ) -> bool {
675 false
676 }
677 }
678
679 #[odra::module]
680 pub(crate) struct BasicContract;
681
682 #[odra::module]
683 impl BasicContract {}
684}
685
686#[cfg(test)]
687mod tests {
688 use super::*;
689 use crate::cep95::utils::*;
690 use odra::{
691 host::{Deployer, HostEnv, NoArgs},
692 prelude::Addressable,
693 VmError
694 };
695 use odra_test;
696
697 fn setup() -> (HostEnv, BasicCep95HostRef) {
698 let env = odra_test::env();
699 let cep95 = BasicCep95::try_deploy(
700 &env,
701 BasicCep95InitArgs {
702 name: "TestToken".to_string(),
703 symbol: "TT".to_string()
704 }
705 )
706 .unwrap();
707 (env, cep95)
708 }
709
710 #[test]
711 fn test_deploy() {
712 let env = odra_test::env();
713 let cep95 = BasicCep95::try_deploy(
714 &env,
715 BasicCep95InitArgs {
716 name: "TestToken".to_string(),
717 symbol: "TT".to_string()
718 }
719 );
720 assert!(cep95.is_ok());
721 }
722
723 #[test]
724 fn test_name() {
725 let (env, cep95) = setup();
726 let name = cep95.name();
727 assert_eq!(name, "TestToken");
728 }
729
730 #[test]
731 fn test_symbol() {
732 let (env, cep95) = setup();
733 let symbol = cep95.symbol();
734 assert_eq!(symbol, "TT");
735 }
736
737 #[test]
738 fn test_mint() {
739 let (env, mut cep95) = setup();
740 let owner = env.caller();
741
742 let token_id = U256::from(1);
743 let metadata = vec![("key".to_string(), "value".to_string())];
744 cep95.mint(owner, token_id, metadata);
745
746 assert_eq!(cep95.balance_of(owner), U256::from(1));
747 assert_eq!(cep95.owner_of(token_id), Some(owner));
748 assert_eq!(
749 cep95.token_metadata(token_id),
750 vec![("key".to_string(), "value".to_string())]
751 );
752 assert!(env.emitted(&cep95, "Mint"));
753 }
754
755 #[test]
756 fn test_minting_existing_token() {
757 let (env, mut cep95) = setup();
758 let owner = env.caller();
759
760 let token_id = U256::from(1);
761 let metadata = vec![("key".to_string(), "value".to_string())];
762 cep95.mint(owner, token_id, metadata.clone());
763
764 let result = cep95.try_mint(owner, token_id, metadata);
765 assert_eq!(result, Err(Error::TokenAlreadyExists.into()));
766 }
767
768 #[test]
769 fn test_mint_many_tokens() {
770 let (env, mut cep95) = setup();
771 let owner = env.caller();
772
773 let token_id1 = U256::from(1);
774 let metadata1 = vec![("key1".to_string(), "value1".to_string())];
775 cep95.mint(owner, token_id1, metadata1);
776
777 let token_id2 = U256::from(2);
778 let metadata2 = vec![("key2".to_string(), "value2".to_string())];
779 cep95.mint(owner, token_id2, metadata2);
780
781 assert_eq!(cep95.balance_of(owner), U256::from(2));
782 assert_eq!(cep95.owner_of(token_id1), Some(owner));
783 assert_eq!(cep95.owner_of(token_id2), Some(owner));
784 }
785
786 #[test]
787 fn test_burn() {
788 let (env, mut cep95) = setup();
789 let owner = env.caller();
790
791 let token_id = U256::from(1);
792 let metadata = vec![("key".to_string(), "value".to_string())];
793 cep95.mint(owner, token_id, metadata);
794 cep95.burn(token_id);
795
796 assert_eq!(cep95.balance_of(owner), U256::from(0));
797 assert_eq!(cep95.owner_of(token_id), None);
798 assert_eq!(
799 cep95.try_token_metadata(token_id),
800 Err(Error::InvalidTokenId.into())
801 );
802 assert!(env.emitted(&cep95, "Burn"));
803 }
804
805 #[test]
806 fn test_burn_non_existing_token() {
807 let (env, mut cep95) = setup();
808 let owner = env.caller();
809
810 let token_id = U256::from(1);
811 let result = cep95.try_burn(token_id);
812 assert_eq!(result, Err(Error::InvalidTokenId.into()));
813 }
814
815 #[test]
816 fn test_safe_transfer_to_receiver() {
817 let (env, mut cep95) = setup();
818 let nft_receiver = NFTReceiver::deploy(&env, NoArgs);
819 let recipient = nft_receiver.address();
820 let owner = env.caller();
821
822 let token_id = U256::from(1);
823 let metadata = vec![("key".to_string(), "value".to_string())];
824 cep95.mint(owner, token_id, metadata);
825
826 cep95.safe_transfer_from(owner, recipient, token_id, None);
827
828 assert_eq!(cep95.balance_of(owner), U256::from(0));
829 assert_eq!(cep95.balance_of(recipient), U256::from(1));
830 assert_eq!(
831 nft_receiver.last_call_result(),
832 ((owner, owner), (token_id, None))
833 );
834 }
835
836 #[test]
837 fn test_safe_transfer_to_non_receiver() {
838 let (env, mut cep95) = setup();
839 let contract = BasicContract::deploy(&env, NoArgs);
840 let recipient = contract.address();
841 let owner = env.caller();
842
843 let token_id = U256::from(1);
844 let metadata = vec![("key".to_string(), "value".to_string())];
845 cep95.mint(owner, token_id, metadata);
846
847 let result = cep95.try_safe_transfer_from(owner, recipient, token_id, None);
848 assert_eq!(
849 result,
850 Err(OdraError::VmError(VmError::NoSuchMethod(
851 "on_cep95_received".to_string()
852 )))
853 );
854
855 assert_eq!(cep95.balance_of(owner), U256::from(1));
856 assert_eq!(cep95.balance_of(recipient), U256::from(0));
857 }
858
859 #[test]
860 fn test_safe_transfer_to_rejecting_receiver() {
861 let (env, mut cep95) = setup();
862
863 let owner = env.get_account(0);
864 let contract = RejectingNFTReceiver::deploy(&env, NoArgs);
865 let recipient = contract.address();
866
867 let token_id = U256::from(1);
868 let metadata = vec![("key".to_string(), "value".to_string())];
869 cep95.mint(owner, token_id, metadata);
870
871 let result = cep95.try_safe_transfer_from(owner, recipient, token_id, None);
872 assert_eq!(result, Err(Error::TransferFailed.into()));
873
874 assert_eq!(cep95.balance_of(owner), U256::from(1));
875 assert_eq!(cep95.balance_of(recipient), U256::from(0));
876 }
877
878 #[test]
879 fn test_transfer() {
880 let (env, mut cep95) = setup();
881
882 let owner = env.get_account(0);
883 let recipient = env.get_account(10);
884
885 let token_id = U256::from(1);
886 let metadata = vec![("key".to_string(), "value".to_string())];
887 cep95.mint(owner, token_id, metadata);
888 cep95.transfer_from(owner, recipient, token_id);
889
890 assert_eq!(cep95.balance_of(owner), U256::from(0));
891 assert_eq!(cep95.balance_of(recipient), U256::from(1));
892 assert!(env.emitted(&cep95, "Transfer"));
893 }
894
895 #[test]
896 fn test_transfer_non_existing_token() {
897 let (env, mut cep95) = setup();
898
899 let owner = env.get_account(0);
900 let recipient = env.get_account(10);
901
902 let token_id = U256::from(1);
903 let metadata = vec![("key".to_string(), "value".to_string())];
904 cep95.mint(owner, token_id, metadata);
905
906 let result = cep95.try_transfer_from(owner, recipient, U256::from(2));
907 assert_eq!(result, Err(Error::InvalidTokenId.into()));
908 }
909
910 #[test]
911 fn test_transfer_from_non_owner() {
912 let (env, mut cep95) = setup();
913
914 let recipient = env.get_account(10);
915 let non_owner = env.get_account(11);
916 let owner = env.get_account(0);
917
918 let token_id = U256::from(1);
919 let metadata = vec![("key".to_string(), "value".to_string())];
920 cep95.mint(owner, token_id, metadata);
921
922 let result = cep95.try_transfer_from(non_owner, recipient, token_id);
923 assert_eq!(result, Err(Error::NotAnOwnerOrApproved.into()));
924 assert_eq!(cep95.balance_of(owner), U256::from(1));
925 assert_eq!(cep95.balance_of(recipient), U256::from(0));
926 }
927
928 #[test]
929 fn test_approve() {
930 let (env, mut cep95) = setup();
931 let owner = env.caller();
932
933 let token_id = U256::from(1);
934 let metadata = vec![("key".to_string(), "value".to_string())];
935 cep95.mint(owner, token_id, metadata);
936
937 let spender = env.get_account(10);
938 cep95.approve(spender, token_id);
939
940 assert_eq!(cep95.approved_for(token_id), Some(spender));
941 assert!(env.emitted_event(
942 &cep95,
943 Approval {
944 owner,
945 spender,
946 token_id
947 }
948 ));
949 }
950
951 #[test]
952 fn test_approve_by_non_owner() {
953 let (env, mut cep95) = setup();
954 let owner = env.get_account(0);
955 let non_owner = env.get_account(11);
956
957 let token_id = U256::from(1);
958 let metadata = vec![("key".to_string(), "value".to_string())];
959 cep95.mint(owner, token_id, metadata);
960
961 let spender = env.get_account(10);
962 env.set_caller(non_owner);
963 let result = cep95.try_approve(spender, token_id);
964 assert_eq!(result, Err(Error::NotAnOwnerOrApproved.into()));
965 }
966
967 #[test]
968 fn test_approve_by_spender() {
969 let (env, mut cep95) = setup();
970 let owner = env.get_account(0);
971 let spender = env.get_account(10);
972
973 let token_id = U256::from(1);
974 let metadata = vec![("key".to_string(), "value".to_string())];
975 cep95.approve_for_all(spender);
976 cep95.mint(owner, token_id, metadata);
977
978 env.set_caller(spender);
979 let result = cep95.try_approve(spender, token_id);
980 assert!(result.is_ok());
981 assert!(env.emitted_event(
982 &cep95,
983 Approval {
984 owner,
985 spender,
986 token_id
987 }
988 ));
989 }
990
991 #[test]
992 fn test_transfer_by_approved() {
993 let (env, mut cep95) = setup();
994 let owner = env.get_account(0);
995 let recipient = env.get_account(10);
996
997 let token_id = U256::from(1);
998 let metadata = vec![("key".to_string(), "value".to_string())];
999 cep95.mint(owner, token_id, metadata);
1000
1001 let spender = env.get_account(11);
1002 cep95.approve(spender, token_id);
1003 env.set_caller(spender);
1004 cep95.transfer_from(owner, recipient, token_id);
1005
1006 assert_eq!(cep95.balance_of(owner), U256::from(0));
1007 assert_eq!(cep95.balance_of(recipient), U256::from(1));
1008 assert!(env.emitted_event(
1009 &cep95,
1010 Transfer {
1011 from: owner,
1012 to: recipient,
1013 token_id
1014 }
1015 ));
1016 }
1017
1018 #[test]
1019 fn test_approve_for_all() {
1020 let (env, mut cep95) = setup();
1021 let owner = env.caller();
1022 let operator = env.get_account(10);
1023
1024 cep95.approve_for_all(operator);
1025
1026 assert!(cep95.is_approved_for_all(owner, operator));
1027 assert!(env.emitted(&cep95, "ApprovalForAll"));
1028 }
1029
1030 #[test]
1031 fn test_revoke_approval_for_all() {
1032 let (env, mut cep95) = setup();
1033 let owner = env.caller();
1034 let operator = env.get_account(10);
1035
1036 cep95.approve_for_all(operator);
1037 cep95.revoke_approval_for_all(operator);
1038
1039 assert!(!cep95.is_approved_for_all(owner, operator));
1040 assert!(env.emitted(&cep95, "RevokeApprovalForAll"));
1041 }
1042
1043 #[test]
1044 fn test_approve_for_all_self() {
1045 let (env, mut cep95) = setup();
1046 let owner = env.caller();
1047
1048 let result = cep95.try_approve_for_all(owner);
1049 assert_eq!(result, Err(Error::ApproveToCaller.into()));
1050 }
1051
1052 #[test]
1053 fn test_revoke_approval() {
1054 let (env, mut cep95) = setup();
1055 let owner = env.caller();
1056
1057 let token_id = U256::from(1);
1058 let metadata = vec![("key".to_string(), "value".to_string())];
1059 cep95.mint(owner, token_id, metadata);
1060
1061 let spender = env.get_account(10);
1062 cep95.approve(spender, token_id);
1063 cep95.revoke_approval(token_id);
1064
1065 assert_eq!(cep95.approved_for(token_id), None);
1066 assert!(env.emitted(&cep95, "RevokeApproval"));
1067 }
1068
1069 #[test]
1070 fn test_revoke_approval_by_spender() {
1071 let (env, mut cep95) = setup();
1072 let owner = env.caller();
1073 let spender = env.get_account(10);
1074
1075 let token_id = U256::from(1);
1076 let metadata = vec![("key".to_string(), "value".to_string())];
1077 cep95.approve_for_all(spender);
1078 cep95.mint(owner, token_id, metadata);
1079 cep95.approve(spender, token_id);
1080
1081 env.set_caller(spender);
1082 cep95.revoke_approval(token_id);
1083
1084 assert_eq!(cep95.approved_for(token_id), None);
1085 assert!(env.emitted_event(
1086 &cep95,
1087 RevokeApproval {
1088 owner,
1089 spender,
1090 token_id
1091 }
1092 ));
1093 }
1094
1095 #[test]
1096 fn revoke_non_existing_approval() {
1097 let (env, mut cep95) = setup();
1098 let owner = env.caller();
1099
1100 let token_id = U256::from(1);
1101 let metadata = vec![("key".to_string(), "value".to_string())];
1102 cep95.mint(owner, token_id, metadata);
1103
1104 let result = cep95.try_revoke_approval(token_id);
1105 assert_eq!(result, Err(Error::ValueNotSet.into()));
1106 }
1107
1108 #[test]
1109 fn test_revoke_approval_by_non_owner() {
1110 let (env, mut cep95) = setup();
1111 let owner = env.get_account(0);
1112 let non_owner = env.get_account(11);
1113
1114 let token_id = U256::from(1);
1115 let metadata = vec![("key".to_string(), "value".to_string())];
1116 cep95.mint(owner, token_id, metadata);
1117
1118 let spender = env.get_account(10);
1119 cep95.approve(spender, token_id);
1120 env.set_caller(non_owner);
1121 let result = cep95.try_revoke_approval(token_id);
1122 assert_eq!(result, Err(Error::NotAnOwnerOrApproved.into()));
1123 }
1124
1125 #[test]
1126 fn test_approval_cleared_after_transfer() {
1127 let (env, mut cep95) = setup();
1131 let owner = env.get_account(0);
1132 let spender = env.get_account(11);
1133 let recipient = env.get_account(10);
1134 let attacker_dest = env.get_account(12);
1135
1136 let token_id = U256::from(1);
1137 let metadata = vec![("key".to_string(), "value".to_string())];
1138 cep95.mint(owner, token_id, metadata);
1139
1140 cep95.approve(spender, token_id);
1142 cep95.transfer_from(owner, recipient, token_id);
1143
1144 assert_eq!(cep95.approved_for(token_id), None);
1146
1147 env.set_caller(spender);
1149 let result = cep95.try_transfer_from(recipient, attacker_dest, token_id);
1150 assert_eq!(result, Err(Error::NotAnOwnerOrApproved.into()));
1151 assert_eq!(cep95.owner_of(token_id), Some(recipient));
1152 assert_eq!(cep95.balance_of(recipient), U256::from(1));
1153 assert_eq!(cep95.balance_of(attacker_dest), U256::from(0));
1154 }
1155
1156 #[test]
1157 fn test_metadata() {
1158 let (env, mut cep95) = setup();
1159 let owner = env.caller();
1160
1161 let token_id = U256::from(1);
1162 let metadata = vec![("key".to_string(), "value".to_string())];
1163 cep95.mint(owner, token_id, metadata);
1164
1165 assert_eq!(
1166 cep95.token_metadata(token_id),
1167 vec![("key".to_string(), "value".to_string())]
1168 );
1169 }
1170
1171 #[test]
1172 fn test_transfer_by_operator() {
1173 let (env, mut cep95) = setup();
1174 let owner = env.caller();
1175 let recipient = env.get_account(10);
1176 let operator = env.get_account(11);
1177
1178 let token_id1 = U256::from(1);
1179 let metadata = vec![("key".to_string(), "value".to_string())];
1180 cep95.mint(owner, token_id1, metadata.clone());
1181
1182 cep95.approve_for_all(operator);
1183 let token_id2 = U256::from(2);
1184 cep95.mint(owner, token_id2, metadata);
1185
1186 env.set_caller(operator);
1187 cep95.transfer_from(owner, recipient, token_id1);
1188 cep95.transfer_from(owner, recipient, token_id2);
1189
1190 assert_eq!(cep95.balance_of(owner), U256::from(0));
1191 assert_eq!(cep95.balance_of(recipient), U256::from(2));
1192 }
1193
1194 #[test]
1195 fn test_update_metadata() {
1196 let (env, mut cep95) = setup();
1197 let owner = env.caller();
1198
1199 let token_id = U256::from(1);
1200 let metadata = vec![
1201 ("age".to_string(), "30".to_string()),
1202 ("name".to_string(), "Alice".to_string()),
1203 ];
1204 cep95.mint(owner, token_id, metadata);
1205
1206 let new_metadata = vec![("name".to_string(), "Bob".to_string())];
1207 cep95.update_metadata(token_id, new_metadata);
1208
1209 assert_eq!(
1210 cep95.token_metadata(token_id),
1211 vec![
1212 ("age".to_string(), "30".to_string()),
1213 ("name".to_string(), "Bob".to_string()),
1214 ]
1215 );
1216 assert!(env.emitted(&cep95, "MetadataUpdate"));
1217 }
1218
1219 #[test]
1220 fn test_set_metadata() {
1221 let (env, mut cep95) = setup();
1222 let owner = env.caller();
1223
1224 let token_id = U256::from(1);
1225 let metadata = vec![
1226 ("age".to_string(), "30".to_string()),
1227 ("name".to_string(), "Alice".to_string()),
1228 ];
1229 cep95.mint(owner, token_id, metadata);
1230
1231 let new_metadata = vec![("name".to_string(), "Bob".to_string())];
1232 cep95.set_metadata(token_id, new_metadata);
1233
1234 assert_eq!(
1235 cep95.token_metadata(token_id),
1236 vec![("name".to_string(), "Bob".to_string())]
1237 );
1238 assert!(env.emitted(&cep95, "MetadataUpdate"));
1239 }
1240}