1#![allow(unused_variables, missing_docs)]
2
3use alloc::collections::BTreeMap;
4use odra::{
5 casper_types::{
6 bytesrepr::{Bytes, ToBytes},
7 U256
8 },
9 named_keys::{
10 base64_encoded_key_value_storage, compound_key_value_storage, single_value_storage
11 },
12 prelude::*,
13 ContractRef
14};
15
16pub trait CEP95Interface {
18 fn name(&self) -> String;
20
21 fn symbol(&self) -> String;
23
24 fn balance_of(&self, owner: Address) -> U256;
32
33 fn owner_of(&self, token_id: U256) -> Option<Address>;
41
42 fn safe_transfer_from(
58 &mut self,
59 from: Address,
60 to: Address,
61 token_id: U256,
62 data: Option<Bytes>
63 );
64
65 fn transfer_from(&mut self, from: Address, to: Address, token_id: U256);
72
73 fn approve(&mut self, spender: Address, token_id: U256);
79
80 fn revoke_approval(&mut self, token_id: U256);
85
86 fn approved_for(&self, token_id: U256) -> Option<Address>;
94
95 fn approve_for_all(&mut self, operator: Address);
100
101 fn revoke_approval_for_all(&mut self, operator: Address);
106
107 fn is_approved_for_all(&self, owner: Address, operator: Address) -> bool;
116
117 fn token_metadata(&self, token_id: U256) -> Vec<(String, String)>;
125}
126
127#[odra::module]
128struct CEP95Receiver;
130
131#[odra::module]
132impl CEP95Receiver {
133 #[allow(dead_code)]
147 pub fn on_cep95_received(
148 &mut self,
149 operator: &Address,
150 from: &Address,
151 token_id: &U256,
152 data: &Option<Bytes>
153 ) -> bool {
154 true
159 }
160}
161
162const KEY_BALANCES: &str = "balances";
163const KEY_NAME: &str = "name";
164const KEY_SYMBOL: &str = "symbol";
165const KEY_APPROVED: &str = "approvals";
166const KEY_OPERATORS: &str = "operators";
167const KEY_METADATA: &str = "token_metadata";
168const KEY_OWNERS: &str = "owners";
169
170single_value_storage!(Cep95Name, String, KEY_NAME, Error::ValueNotSet);
171single_value_storage!(Cep95Symbol, String, KEY_SYMBOL, Error::ValueNotSet);
172base64_encoded_key_value_storage!(Cep95Balances, KEY_BALANCES, Address, U256);
173base64_encoded_key_value_storage!(Cep95Approvals, KEY_APPROVED, U256, Option<Address>);
174compound_key_value_storage!(Cep95Operators, KEY_OPERATORS, Address, bool);
175base64_encoded_key_value_storage!(Cep95Owners, KEY_OWNERS, U256, Option<Address>);
176base64_encoded_key_value_storage!(Cep95Metadata, KEY_METADATA, U256, BTreeMap<String, String>);
177
178#[odra::odra_error]
180pub enum Error {
181 ValueNotSet = 40_000,
183 TransferFailed = 40_001,
185 NotAnOwnerOrApproved = 40_002,
187 ApprovalToCurrentOwner = 40_003,
189 ApproveToCaller = 40_004,
191 InvalidTokenId = 40_005,
193 TokenAlreadyExists = 40_006
195}
196
197#[odra::event]
198pub struct Mint {
200 pub to: Address,
202 pub token_id: U256
204}
205
206#[odra::event]
207pub struct Burn {
209 pub from: Address,
211 pub token_id: U256
213}
214
215#[odra::event]
216pub struct Transfer {
218 pub from: Address,
220 pub to: Address,
222 pub token_id: U256
224}
225
226#[odra::event]
227pub struct Approval {
229 pub owner: Address,
231 pub spender: Address,
233 pub token_id: U256
235}
236
237#[odra::event]
238pub struct RevokeApproval {
240 pub owner: Address,
242 pub spender: Address,
244 pub token_id: U256
246}
247
248#[odra::event]
249pub struct ApprovalForAll {
251 pub owner: Address,
253 pub operator: Address
255}
256
257#[odra::event]
258pub struct RevokeApprovalForAll {
260 pub owner: Address,
262 pub operator: Address
264}
265
266#[odra::event]
267pub struct MetadataUpdate {
269 pub token_id: U256
271}
272
273#[odra::module(
274 events = [
275 Transfer,
276 Approval,
277 RevokeApproval,
278 ApprovalForAll,
279 RevokeApprovalForAll,
280 Mint,
281 Burn,
282 MetadataUpdate
283 ],
284 errors = Error
285)]
286pub struct Cep95 {
288 pub name: SubModule<Cep95Name>,
290 pub symbol: SubModule<Cep95Symbol>,
292 pub balances: SubModule<Cep95Balances>,
294 pub owners: SubModule<Cep95Owners>,
296 pub approvals: SubModule<Cep95Approvals>,
298 pub operators: SubModule<Cep95Operators>,
300 pub metadata: SubModule<Cep95Metadata>
302}
303
304#[odra::module]
305impl CEP95Interface for Cep95 {
306 fn name(&self) -> String {
307 self.name.get()
308 }
309
310 fn symbol(&self) -> String {
311 self.symbol.get()
312 }
313
314 fn balance_of(&self, owner: Address) -> U256 {
315 self.balances.get(&owner).unwrap_or_default()
316 }
317
318 fn owner_of(&self, token_id: U256) -> Option<Address> {
319 self.owners.get(&token_id).flatten()
320 }
321
322 fn safe_transfer_from(
323 &mut self,
324 from: Address,
325 to: Address,
326 token_id: U256,
327 data: Option<Bytes>
328 ) {
329 self.transfer_from(from, to, token_id);
330 if to.is_contract() {
331 let mut receiver = CEP95ReceiverContractRef::new(self.env(), to);
332 let caller = self.env().caller();
333 let result = receiver.on_cep95_received(&caller, &from, &token_id, &data);
334 if !result {
335 self.env().revert(Error::TransferFailed);
336 }
337 }
338 }
339
340 fn transfer_from(&mut self, from: Address, to: Address, token_id: U256) {
341 self.assert_exists(&token_id);
342
343 let caller = self.env().caller();
344 let owner = self
345 .owner_of(token_id)
346 .unwrap_or_revert_with(self, Error::ValueNotSet);
347
348 if owner != from {
350 self.env().revert(Error::NotAnOwnerOrApproved);
351 }
352
353 let is_authorized = owner == caller
359 || self.is_approved_for_all(from, caller)
360 || self.is_spender(token_id, caller);
361
362 if !is_authorized {
363 self.env().revert(Error::NotAnOwnerOrApproved);
364 }
365
366 self.raw_transfer_from(from, to, token_id);
367 }
368
369 fn approve(&mut self, spender: Address, token_id: U256) {
370 let caller = self.env().caller();
371 self.set_approve(token_id, Some(spender));
372 self.env().emit_event(Approval {
373 owner: caller,
374 spender,
375 token_id
376 });
377 }
378
379 fn revoke_approval(&mut self, token_id: U256) {
380 let spender = self
381 .approved_for(token_id)
382 .unwrap_or_revert_with(self, Error::ValueNotSet);
383 self.set_approve(token_id, None);
384 self.env().emit_event(RevokeApproval {
385 owner: self.env().caller(),
386 spender,
387 token_id
388 });
389 }
390
391 fn approved_for(&self, token_id: U256) -> Option<Address> {
392 self.assert_exists(&token_id);
393 self.approvals.get(&token_id).flatten()
394 }
395
396 fn approve_for_all(&mut self, operator: Address) {
397 let caller = self.env().caller();
398 self.set_approval_for_all(caller, operator, true);
399 self.env().emit_event(ApprovalForAll {
400 owner: caller,
401 operator
402 });
403 }
404
405 fn revoke_approval_for_all(&mut self, operator: Address) {
406 let caller = self.env().caller();
407 self.set_approval_for_all(caller, operator, false);
408 self.env().emit_event(RevokeApprovalForAll {
409 owner: caller,
410 operator
411 });
412 }
413
414 fn is_approved_for_all(&self, owner: Address, operator: Address) -> bool {
415 self.operators.get_or_default(&owner, &operator)
416 }
417
418 fn token_metadata(&self, token_id: U256) -> Vec<(String, String)> {
419 self.assert_exists(&token_id);
420 self.metadata
421 .get(&token_id)
422 .unwrap_or_default()
423 .into_iter()
424 .collect()
425 }
426}
427
428impl Cep95 {
429 pub fn init(&mut self, name: String, symbol: String) {
431 self.name.set(name);
433 self.symbol.set(symbol);
434
435 self.balances.init();
437 self.owners.init();
438 self.approvals.init();
439 self.operators.init();
440 self.metadata.init();
441 }
442
443 #[inline]
444 pub fn assert_exists(&self, token_id: &U256) {
447 if !self.exists(token_id) {
448 self.env().revert(Error::InvalidTokenId);
449 }
450 }
451
452 #[inline]
454 pub fn exists(&self, token_id: &U256) -> bool {
455 self.owners.get(token_id).flatten().is_some()
456 }
457
458 #[inline]
461 pub fn clear_approval(&mut self, token_id: &U256) {
462 if self.approvals.get(token_id).is_some() {
463 self.approvals.set(token_id, None);
464 }
465 }
466
467 pub fn raw_mint(&mut self, to: Address, token_id: U256, metadata: Vec<(String, String)>) {
470 if self.exists(&token_id) {
471 self.env().revert(Error::TokenAlreadyExists);
472 }
473
474 self.balances.set(&to, self.balance_of(to) + 1);
475 self.owners.set(&token_id, Some(to));
476 self.metadata.set(&token_id, BTreeMap::from_iter(metadata));
477
478 self.env().emit_event(Mint { to, token_id });
479 }
480
481 pub fn raw_burn(&mut self, token_id: U256) {
484 self.assert_exists(&token_id);
485 let owner = self
486 .owner_of(token_id)
487 .unwrap_or_revert_with(self, Error::ValueNotSet);
488
489 self.clear_approval(&token_id);
490 self.balances.set(&owner, self.balance_of(owner) - 1);
491 self.owners.set(&token_id, None);
492 self.metadata.set(&token_id, Default::default());
493
494 self.env().emit_event(Burn {
495 from: owner,
496 token_id
497 });
498 }
499
500 pub fn set_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
504 self.raw_update_metadata(token_id, metadata, BTreeMap::new());
505 }
506
507 pub fn update_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
513 let current_metadata = self.metadata.get(&token_id).unwrap_or_default();
514 self.raw_update_metadata(token_id, metadata, current_metadata);
515 }
516
517 pub fn raw_transfer_from(&mut self, from: Address, to: Address, token_id: U256) {
520 self.clear_approval(&token_id);
521 self.balances.set(&from, self.balance_of(from) - 1);
522 self.balances.set(&to, self.balance_of(to) + 1);
523 self.owners.set(&token_id, Some(to));
524
525 self.env().emit_event(Transfer { from, to, token_id });
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, spender: Option<Address>) {
544 let owner = self
545 .owner_of(token_id)
546 .unwrap_or_revert_with(self, Error::ValueNotSet);
547 let caller = self.env().caller();
548
549 if Some(owner) == spender {
550 self.env().revert(Error::ApprovalToCurrentOwner);
551 }
552
553 if caller != owner && !self.is_approved_for_all(owner, caller) {
554 self.env().revert(Error::NotAnOwnerOrApproved);
555 }
556
557 self.approvals.set(&token_id, spender);
558 }
559
560 #[inline]
561 fn set_approval_for_all(&mut self, caller: Address, operator: Address, approved: bool) {
562 if caller == operator {
563 self.env().revert(Error::ApproveToCaller)
564 }
565
566 self.operators.set(&caller, &operator, approved);
567 }
568
569 #[inline]
570 fn is_spender(&self, token_id: U256, spender: Address) -> bool {
571 self.approved_for(token_id) == Some(spender)
572 }
573}
574
575mod utils {
576 #![allow(dead_code)]
577 use crate::access::Ownable;
578
579 use super::*;
580
581 #[odra::module]
582 pub(crate) struct BasicCep95 {
583 token: SubModule<Cep95>,
584 ownable: SubModule<Ownable>
585 }
586
587 #[odra::module]
588 impl BasicCep95 {
589 pub fn init(&mut self, name: String, symbol: String) {
591 let owner = self.env().caller();
592 self.ownable.init(owner);
593 self.token.init(name, symbol);
594 }
595
596 delegate! {
597 to self.token {
598 fn name(&self) -> String;
599 fn symbol(&self) -> String;
600 fn balance_of(&self, owner: Address) -> U256;
601 fn owner_of(&self, token_id: U256) -> Option<Address>;
602 fn safe_transfer_from(&mut self, from: Address, to: Address, token_id: U256, data: Option<Bytes>);
603 fn transfer_from(&mut self, from: Address, to: Address, token_id: U256);
604 fn approve(&mut self, spender: Address, token_id: U256);
605 fn revoke_approval(&mut self, token_id: U256);
606 fn approved_for(&self, token_id: U256) -> Option<Address>;
607 fn approve_for_all(&mut self, operator: Address);
608 fn revoke_approval_for_all(&mut self, operator: Address);
609 fn is_approved_for_all(&self, owner: Address, operator: Address) -> bool;
610 fn token_metadata(&self, token_id: U256) -> Vec<(String, String)>;
611 }
612 }
613
614 pub fn mint(&mut self, to: Address, token_id: U256, metadata: Vec<(String, String)>) {
615 self.assert_owner();
616 self.token.raw_mint(to, token_id, metadata);
617 }
618
619 pub fn burn(&mut self, token_id: U256) {
620 self.assert_owner();
621 self.token.raw_burn(token_id);
622 }
623
624 pub fn set_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
625 self.assert_owner();
626 self.token.set_metadata(token_id, metadata);
627 }
628
629 pub fn update_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
630 self.assert_owner();
631 self.token.update_metadata(token_id, metadata);
632 }
633
634 pub fn assert_owner(&self) {
635 self.ownable.assert_owner(&self.env().caller());
636 }
637 }
638
639 #[odra::module]
640 pub(crate) struct NFTReceiver {
641 #[allow(clippy::type_complexity)]
642 last_call_data: Var<((Address, Address), (U256, Option<Bytes>))>
643 }
644
645 #[odra::module]
646 impl NFTReceiver {
647 #[allow(dead_code)]
648 pub fn on_cep95_received(
649 &mut self,
650 operator: Address,
651 from: Address,
652 token_id: U256,
653 data: Option<Bytes>
654 ) -> bool {
655 self.last_call_data
656 .set(((operator, from), (token_id, data.clone())));
657 true
658 }
659
660 #[allow(dead_code)]
661 pub fn last_call_result(&self) -> ((Address, Address), (U256, Option<Bytes>)) {
662 self.last_call_data.get().unwrap_or_revert(self)
663 }
664 }
665
666 #[odra::module]
667 pub(crate) struct RejectingNFTReceiver;
668
669 #[odra::module]
670 impl RejectingNFTReceiver {
671 #[allow(dead_code)]
672 pub fn on_cep95_received(
673 &mut self,
674 operator: Address,
675 from: Address,
676 token_id: U256,
677 data: Option<Bytes>
678 ) -> bool {
679 false
680 }
681 }
682
683 #[odra::module]
684 pub(crate) struct BasicContract;
685
686 #[odra::module]
687 impl BasicContract {}
688}
689
690#[cfg(test)]
691mod tests {
692 use super::*;
693 use crate::cep95::utils::*;
694 use odra::{
695 host::{Deployer, HostEnv, NoArgs},
696 prelude::Addressable,
697 VmError
698 };
699 use odra_test;
700
701 fn setup() -> (HostEnv, BasicCep95HostRef) {
702 let env = odra_test::env();
703 let cep95 = BasicCep95::try_deploy(
704 &env,
705 BasicCep95InitArgs {
706 name: "TestToken".to_string(),
707 symbol: "TT".to_string()
708 }
709 )
710 .unwrap();
711 (env, cep95)
712 }
713
714 #[test]
715 fn test_deploy() {
716 let env = odra_test::env();
717 let cep95 = BasicCep95::try_deploy(
718 &env,
719 BasicCep95InitArgs {
720 name: "TestToken".to_string(),
721 symbol: "TT".to_string()
722 }
723 );
724 assert!(cep95.is_ok());
725 }
726
727 #[test]
728 fn test_name() {
729 let (env, cep95) = setup();
730 let name = cep95.name();
731 assert_eq!(name, "TestToken");
732 }
733
734 #[test]
735 fn test_symbol() {
736 let (env, cep95) = setup();
737 let symbol = cep95.symbol();
738 assert_eq!(symbol, "TT");
739 }
740
741 #[test]
742 fn test_mint() {
743 let (env, mut cep95) = setup();
744 let owner = env.caller();
745
746 let token_id = U256::from(1);
747 let metadata = vec![("key".to_string(), "value".to_string())];
748 cep95.mint(owner, token_id, metadata);
749
750 assert_eq!(cep95.balance_of(owner), U256::from(1));
751 assert_eq!(cep95.owner_of(token_id), Some(owner));
752 assert_eq!(
753 cep95.token_metadata(token_id),
754 vec![("key".to_string(), "value".to_string())]
755 );
756 assert!(env.emitted(&cep95, "Mint"));
757 }
758
759 #[test]
760 fn test_minting_existing_token() {
761 let (env, mut cep95) = setup();
762 let owner = env.caller();
763
764 let token_id = U256::from(1);
765 let metadata = vec![("key".to_string(), "value".to_string())];
766 cep95.mint(owner, token_id, metadata.clone());
767
768 let result = cep95.try_mint(owner, token_id, metadata);
769 assert_eq!(result, Err(Error::TokenAlreadyExists.into()));
770 }
771
772 #[test]
773 fn test_mint_many_tokens() {
774 let (env, mut cep95) = setup();
775 let owner = env.caller();
776
777 let token_id1 = U256::from(1);
778 let metadata1 = vec![("key1".to_string(), "value1".to_string())];
779 cep95.mint(owner, token_id1, metadata1);
780
781 let token_id2 = U256::from(2);
782 let metadata2 = vec![("key2".to_string(), "value2".to_string())];
783 cep95.mint(owner, token_id2, metadata2);
784
785 assert_eq!(cep95.balance_of(owner), U256::from(2));
786 assert_eq!(cep95.owner_of(token_id1), Some(owner));
787 assert_eq!(cep95.owner_of(token_id2), Some(owner));
788 }
789
790 #[test]
791 fn test_burn() {
792 let (env, mut cep95) = setup();
793 let owner = env.caller();
794
795 let token_id = U256::from(1);
796 let metadata = vec![("key".to_string(), "value".to_string())];
797 cep95.mint(owner, token_id, metadata);
798 cep95.burn(token_id);
799
800 assert_eq!(cep95.balance_of(owner), U256::from(0));
801 assert_eq!(cep95.owner_of(token_id), None);
802 assert_eq!(
803 cep95.try_token_metadata(token_id),
804 Err(Error::InvalidTokenId.into())
805 );
806 assert!(env.emitted(&cep95, "Burn"));
807 }
808
809 #[test]
810 fn test_burn_non_existing_token() {
811 let (env, mut cep95) = setup();
812 let owner = env.caller();
813
814 let token_id = U256::from(1);
815 let result = cep95.try_burn(token_id);
816 assert_eq!(result, Err(Error::InvalidTokenId.into()));
817 }
818
819 #[test]
820 fn test_safe_transfer_to_receiver() {
821 let (env, mut cep95) = setup();
822 let nft_receiver = NFTReceiver::deploy(&env, NoArgs);
823 let recipient = nft_receiver.address();
824 let owner = env.caller();
825
826 let token_id = U256::from(1);
827 let metadata = vec![("key".to_string(), "value".to_string())];
828 cep95.mint(owner, token_id, metadata);
829
830 cep95.safe_transfer_from(owner, recipient, token_id, None);
831
832 assert_eq!(cep95.balance_of(owner), U256::from(0));
833 assert_eq!(cep95.balance_of(recipient), U256::from(1));
834 assert_eq!(
835 nft_receiver.last_call_result(),
836 ((owner, owner), (token_id, None))
837 );
838 }
839
840 #[test]
841 fn test_safe_transfer_to_non_receiver() {
842 let (env, mut cep95) = setup();
843 let contract = BasicContract::deploy(&env, NoArgs);
844 let recipient = contract.address();
845 let owner = env.caller();
846
847 let token_id = U256::from(1);
848 let metadata = vec![("key".to_string(), "value".to_string())];
849 cep95.mint(owner, token_id, metadata);
850
851 let result = cep95.try_safe_transfer_from(owner, recipient, token_id, None);
852 assert_eq!(
853 result,
854 Err(OdraError::VmError(VmError::NoSuchMethod(
855 "on_cep95_received".to_string()
856 )))
857 );
858
859 assert_eq!(cep95.balance_of(owner), U256::from(1));
860 assert_eq!(cep95.balance_of(recipient), U256::from(0));
861 }
862
863 #[test]
864 fn test_safe_transfer_to_rejecting_receiver() {
865 let (env, mut cep95) = setup();
866
867 let owner = env.get_account(0);
868 let contract = RejectingNFTReceiver::deploy(&env, NoArgs);
869 let recipient = contract.address();
870
871 let token_id = U256::from(1);
872 let metadata = vec![("key".to_string(), "value".to_string())];
873 cep95.mint(owner, token_id, metadata);
874
875 let result = cep95.try_safe_transfer_from(owner, recipient, token_id, None);
876 assert_eq!(result, Err(Error::TransferFailed.into()));
877
878 assert_eq!(cep95.balance_of(owner), U256::from(1));
879 assert_eq!(cep95.balance_of(recipient), U256::from(0));
880 }
881
882 #[test]
883 fn test_transfer() {
884 let (env, mut cep95) = setup();
885
886 let owner = env.get_account(0);
887 let recipient = env.get_account(10);
888
889 let token_id = U256::from(1);
890 let metadata = vec![("key".to_string(), "value".to_string())];
891 cep95.mint(owner, token_id, metadata);
892 cep95.transfer_from(owner, recipient, token_id);
893
894 assert_eq!(cep95.balance_of(owner), U256::from(0));
895 assert_eq!(cep95.balance_of(recipient), U256::from(1));
896 assert!(env.emitted(&cep95, "Transfer"));
897 }
898
899 #[test]
900 fn test_transfer_non_existing_token() {
901 let (env, mut cep95) = setup();
902
903 let owner = env.get_account(0);
904 let recipient = env.get_account(10);
905
906 let token_id = U256::from(1);
907 let metadata = vec![("key".to_string(), "value".to_string())];
908 cep95.mint(owner, token_id, metadata);
909
910 let result = cep95.try_transfer_from(owner, recipient, U256::from(2));
911 assert_eq!(result, Err(Error::InvalidTokenId.into()));
912 }
913
914 #[test]
915 fn test_transfer_from_non_owner() {
916 let (env, mut cep95) = setup();
917
918 let recipient = env.get_account(10);
919 let non_owner = env.get_account(11);
920 let owner = env.get_account(0);
921
922 let token_id = U256::from(1);
923 let metadata = vec![("key".to_string(), "value".to_string())];
924 cep95.mint(owner, token_id, metadata);
925
926 let result = cep95.try_transfer_from(non_owner, recipient, token_id);
927 assert_eq!(result, Err(Error::NotAnOwnerOrApproved.into()));
928 assert_eq!(cep95.balance_of(owner), U256::from(1));
929 assert_eq!(cep95.balance_of(recipient), U256::from(0));
930 }
931
932 #[test]
933 fn test_approve() {
934 let (env, mut cep95) = setup();
935 let owner = env.caller();
936
937 let token_id = U256::from(1);
938 let metadata = vec![("key".to_string(), "value".to_string())];
939 cep95.mint(owner, token_id, metadata);
940
941 let spender = env.get_account(10);
942 cep95.approve(spender, token_id);
943
944 assert_eq!(cep95.approved_for(token_id), Some(spender));
945 assert!(env.emitted_event(
946 &cep95,
947 Approval {
948 owner,
949 spender,
950 token_id
951 }
952 ));
953 }
954
955 #[test]
956 fn test_approve_by_non_owner() {
957 let (env, mut cep95) = setup();
958 let owner = env.get_account(0);
959 let non_owner = env.get_account(11);
960
961 let token_id = U256::from(1);
962 let metadata = vec![("key".to_string(), "value".to_string())];
963 cep95.mint(owner, token_id, metadata);
964
965 let spender = env.get_account(10);
966 env.set_caller(non_owner);
967 let result = cep95.try_approve(spender, token_id);
968 assert_eq!(result, Err(Error::NotAnOwnerOrApproved.into()));
969 }
970
971 #[test]
972 fn test_transfer_by_approved() {
973 let (env, mut cep95) = setup();
974 let owner = env.get_account(0);
975 let recipient = env.get_account(10);
976
977 let token_id = U256::from(1);
978 let metadata = vec![("key".to_string(), "value".to_string())];
979 cep95.mint(owner, token_id, metadata);
980
981 let spender = env.get_account(11);
982 cep95.approve(spender, token_id);
983 env.set_caller(spender);
984 cep95.transfer_from(owner, recipient, token_id);
985
986 assert_eq!(cep95.balance_of(owner), U256::from(0));
987 assert_eq!(cep95.balance_of(recipient), U256::from(1));
988 assert!(env.emitted_event(
989 &cep95,
990 Transfer {
991 from: owner,
992 to: recipient,
993 token_id
994 }
995 ));
996 }
997
998 #[test]
999 fn test_approve_for_all() {
1000 let (env, mut cep95) = setup();
1001 let owner = env.caller();
1002 let operator = env.get_account(10);
1003
1004 cep95.approve_for_all(operator);
1005
1006 assert!(cep95.is_approved_for_all(owner, operator));
1007 assert!(env.emitted(&cep95, "ApprovalForAll"));
1008 }
1009
1010 #[test]
1011 fn test_revoke_approval_for_all() {
1012 let (env, mut cep95) = setup();
1013 let owner = env.caller();
1014 let operator = env.get_account(10);
1015
1016 cep95.approve_for_all(operator);
1017 cep95.revoke_approval_for_all(operator);
1018
1019 assert!(!cep95.is_approved_for_all(owner, operator));
1020 assert!(env.emitted(&cep95, "RevokeApprovalForAll"));
1021 }
1022
1023 #[test]
1024 fn test_approve_for_all_self() {
1025 let (env, mut cep95) = setup();
1026 let owner = env.caller();
1027
1028 let result = cep95.try_approve_for_all(owner);
1029 assert_eq!(result, Err(Error::ApproveToCaller.into()));
1030 }
1031
1032 #[test]
1033 fn test_revoke_approval() {
1034 let (env, mut cep95) = setup();
1035 let owner = env.caller();
1036
1037 let token_id = U256::from(1);
1038 let metadata = vec![("key".to_string(), "value".to_string())];
1039 cep95.mint(owner, token_id, metadata);
1040
1041 let spender = env.get_account(10);
1042 cep95.approve(spender, token_id);
1043 cep95.revoke_approval(token_id);
1044
1045 assert_eq!(cep95.approved_for(token_id), None);
1046 assert!(env.emitted(&cep95, "RevokeApproval"));
1047 }
1048
1049 #[test]
1050 fn revoke_non_existing_approval() {
1051 let (env, mut cep95) = setup();
1052 let owner = env.caller();
1053
1054 let token_id = U256::from(1);
1055 let metadata = vec![("key".to_string(), "value".to_string())];
1056 cep95.mint(owner, token_id, metadata);
1057
1058 let result = cep95.try_revoke_approval(token_id);
1059 assert_eq!(result, Err(Error::ValueNotSet.into()));
1060 }
1061
1062 #[test]
1063 fn test_revoke_approval_by_non_owner() {
1064 let (env, mut cep95) = setup();
1065 let owner = env.get_account(0);
1066 let non_owner = env.get_account(11);
1067
1068 let token_id = U256::from(1);
1069 let metadata = vec![("key".to_string(), "value".to_string())];
1070 cep95.mint(owner, token_id, metadata);
1071
1072 let spender = env.get_account(10);
1073 cep95.approve(spender, token_id);
1074 env.set_caller(non_owner);
1075 let result = cep95.try_revoke_approval(token_id);
1076 assert_eq!(result, Err(Error::NotAnOwnerOrApproved.into()));
1077 }
1078
1079 #[test]
1080 fn test_metadata() {
1081 let (env, mut cep95) = setup();
1082 let owner = env.caller();
1083
1084 let token_id = U256::from(1);
1085 let metadata = vec![("key".to_string(), "value".to_string())];
1086 cep95.mint(owner, token_id, metadata);
1087
1088 assert_eq!(
1089 cep95.token_metadata(token_id),
1090 vec![("key".to_string(), "value".to_string())]
1091 );
1092 }
1093
1094 #[test]
1095 fn test_transfer_by_operator() {
1096 let (env, mut cep95) = setup();
1097 let owner = env.caller();
1098 let recipient = env.get_account(10);
1099 let operator = env.get_account(11);
1100
1101 let token_id1 = U256::from(1);
1102 let metadata = vec![("key".to_string(), "value".to_string())];
1103 cep95.mint(owner, token_id1, metadata.clone());
1104
1105 cep95.approve_for_all(operator);
1106 let token_id2 = U256::from(2);
1107 cep95.mint(owner, token_id2, metadata);
1108
1109 env.set_caller(operator);
1110 cep95.transfer_from(owner, recipient, token_id1);
1111 cep95.transfer_from(owner, recipient, token_id2);
1112
1113 assert_eq!(cep95.balance_of(owner), U256::from(0));
1114 assert_eq!(cep95.balance_of(recipient), U256::from(2));
1115 }
1116
1117 #[test]
1118 fn test_update_metadata() {
1119 let (env, mut cep95) = setup();
1120 let owner = env.caller();
1121
1122 let token_id = U256::from(1);
1123 let metadata = vec![
1124 ("age".to_string(), "30".to_string()),
1125 ("name".to_string(), "Alice".to_string()),
1126 ];
1127 cep95.mint(owner, token_id, metadata);
1128
1129 let new_metadata = vec![("name".to_string(), "Bob".to_string())];
1130 cep95.update_metadata(token_id, new_metadata);
1131
1132 assert_eq!(
1133 cep95.token_metadata(token_id),
1134 vec![
1135 ("age".to_string(), "30".to_string()),
1136 ("name".to_string(), "Bob".to_string()),
1137 ]
1138 );
1139 assert!(env.emitted(&cep95, "MetadataUpdate"));
1140 }
1141
1142 #[test]
1143 fn test_set_metadata() {
1144 let (env, mut cep95) = setup();
1145 let owner = env.caller();
1146
1147 let token_id = U256::from(1);
1148 let metadata = vec![
1149 ("age".to_string(), "30".to_string()),
1150 ("name".to_string(), "Alice".to_string()),
1151 ];
1152 cep95.mint(owner, token_id, metadata);
1153
1154 let new_metadata = vec![("name".to_string(), "Bob".to_string())];
1155 cep95.set_metadata(token_id, new_metadata);
1156
1157 assert_eq!(
1158 cep95.token_metadata(token_id),
1159 vec![("name".to_string(), "Bob".to_string())]
1160 );
1161 assert!(env.emitted(&cep95, "MetadataUpdate"));
1162 }
1163}