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 if (owner != from || owner != caller) && !self.is_approved_for_all(from, caller) {
349 if let Some(approved) = self.approved_for(token_id) {
350 if approved != caller {
351 self.env().revert(Error::NotAnOwnerOrApproved);
352 }
353 } else {
354 self.env().revert(Error::NotAnOwnerOrApproved);
355 }
356 }
357
358 self.raw_transfer_from(from, to, token_id);
359 }
360
361 fn approve(&mut self, spender: Address, token_id: U256) {
362 let caller = self.env().caller();
363 self.set_approve(token_id, Some(spender));
364 self.env().emit_event(Approval {
365 owner: caller,
366 spender,
367 token_id
368 });
369 }
370
371 fn revoke_approval(&mut self, token_id: U256) {
372 let spender = self
373 .approved_for(token_id)
374 .unwrap_or_revert_with(self, Error::ValueNotSet);
375 self.set_approve(token_id, None);
376 self.env().emit_event(RevokeApproval {
377 owner: self.env().caller(),
378 spender,
379 token_id
380 });
381 }
382
383 fn approved_for(&self, token_id: U256) -> Option<Address> {
384 self.assert_exists(&token_id);
385 self.approvals.get(&token_id).flatten()
386 }
387
388 fn approve_for_all(&mut self, operator: Address) {
389 let caller = self.env().caller();
390 self.set_approval_for_all(caller, operator, true);
391 self.env().emit_event(ApprovalForAll {
392 owner: caller,
393 operator
394 });
395 }
396
397 fn revoke_approval_for_all(&mut self, operator: Address) {
398 let caller = self.env().caller();
399 self.set_approval_for_all(caller, operator, false);
400 self.env().emit_event(RevokeApprovalForAll {
401 owner: caller,
402 operator
403 });
404 }
405
406 fn is_approved_for_all(&self, owner: Address, operator: Address) -> bool {
407 self.operators.get_or_default(&owner, &operator)
408 }
409
410 fn token_metadata(&self, token_id: U256) -> Vec<(String, String)> {
411 self.assert_exists(&token_id);
412 self.metadata
413 .get(&token_id)
414 .unwrap_or_default()
415 .into_iter()
416 .collect()
417 }
418}
419
420impl Cep95 {
421 pub fn init(&mut self, name: String, symbol: String) {
423 self.name.set(name);
425 self.symbol.set(symbol);
426
427 self.balances.init();
429 self.owners.init();
430 self.approvals.init();
431 self.operators.init();
432 self.metadata.init();
433 }
434
435 #[inline]
436 pub fn assert_exists(&self, token_id: &U256) {
439 if !self.exists(token_id) {
440 self.env().revert(Error::InvalidTokenId);
441 }
442 }
443
444 #[inline]
446 pub fn exists(&self, token_id: &U256) -> bool {
447 self.owners.get(token_id).flatten().is_some()
448 }
449
450 #[inline]
452 pub fn clear_approval(&mut self, token_id: &U256) {
453 if self.approvals.get(token_id).is_some() {
454 self.approvals.set(token_id, None);
455 }
456 }
457
458 pub fn mint(&mut self, to: Address, token_id: U256, metadata: Vec<(String, String)>) {
460 if self.exists(&token_id) {
461 self.env().revert(Error::TokenAlreadyExists);
462 }
463
464 self.balances.set(&to, self.balance_of(to) + 1);
465 self.owners.set(&token_id, Some(to));
466 self.metadata.set(&token_id, BTreeMap::from_iter(metadata));
467
468 self.env().emit_event(Mint { to, token_id });
469 }
470
471 pub fn burn(&mut self, token_id: U256) {
473 self.assert_exists(&token_id);
474 let owner = self
475 .owner_of(token_id)
476 .unwrap_or_revert_with(self, Error::ValueNotSet);
477
478 self.clear_approval(&token_id);
479 self.balances.set(&owner, self.balance_of(owner) - 1);
480 self.owners.set(&token_id, None);
481 self.metadata.set(&token_id, Default::default());
482
483 self.env().emit_event(Burn {
484 from: owner,
485 token_id
486 });
487 }
488
489 pub fn set_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
492 self.raw_update_metadata(token_id, metadata, BTreeMap::new());
493 }
494
495 pub fn update_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
500 let current_metadata = self.metadata.get(&token_id).unwrap_or_default();
501 self.raw_update_metadata(token_id, metadata, current_metadata);
502 }
503
504 pub fn raw_transfer_from(&mut self, from: Address, to: Address, token_id: U256) {
506 self.clear_approval(&token_id);
507 self.balances.set(&from, self.balance_of(from) - 1);
508 self.balances.set(&to, self.balance_of(to) + 1);
509 self.owners.set(&token_id, Some(to));
510
511 self.env().emit_event(Transfer { from, to, token_id });
512 }
513
514 fn raw_update_metadata(
515 &mut self,
516 token_id: U256,
517 new_metadata: Vec<(String, String)>,
518 mut current_metadata: BTreeMap<String, String>
519 ) {
520 self.assert_exists(&token_id);
521 for (k, v) in new_metadata {
522 current_metadata.insert(k, v);
523 }
524 self.metadata.set(&token_id, current_metadata);
525 self.env().emit_event(MetadataUpdate { token_id });
526 }
527
528 #[inline]
529 fn set_approve(&mut self, token_id: U256, spender: Option<Address>) {
530 let owner = self
531 .owner_of(token_id)
532 .unwrap_or_revert_with(self, Error::ValueNotSet);
533 let caller = self.env().caller();
534
535 if Some(owner) == spender {
536 self.env().revert(Error::ApprovalToCurrentOwner);
537 }
538
539 if caller != owner && !self.is_approved_for_all(owner, caller) {
540 self.env().revert(Error::NotAnOwnerOrApproved);
541 }
542
543 self.approvals.set(&token_id, spender);
544 }
545
546 #[inline]
547 fn set_approval_for_all(&mut self, caller: Address, operator: Address, approved: bool) {
548 if caller == operator {
549 self.env().revert(Error::ApproveToCaller)
550 }
551
552 self.operators.set(&caller, &operator, approved);
553 }
554}
555
556mod utils {
557 #![allow(dead_code)]
558 use super::*;
559
560 #[odra::module]
561 pub(crate) struct BasicCep95 {
562 token: SubModule<Cep95>
563 }
564
565 #[odra::module]
566 impl BasicCep95 {
567 pub fn init(&mut self, name: String, symbol: String) {
569 self.token.init(name, symbol);
570 }
571
572 delegate! {
573 to self.token {
574 fn name(&self) -> String;
575 fn symbol(&self) -> String;
576 fn balance_of(&self, owner: Address) -> U256;
577 fn owner_of(&self, token_id: U256) -> Option<Address>;
578 fn safe_transfer_from(&mut self, from: Address, to: Address, token_id: U256, data: Option<Bytes>);
579 fn transfer_from(&mut self, from: Address, to: Address, token_id: U256);
580 fn approve(&mut self, spender: Address, token_id: U256);
581 fn revoke_approval(&mut self, token_id: U256);
582 fn approved_for(&self, token_id: U256) -> Option<Address>;
583 fn approve_for_all(&mut self, operator: Address);
584 fn revoke_approval_for_all(&mut self, operator: Address);
585 fn is_approved_for_all(&self, owner: Address, operator: Address) -> bool;
586 fn token_metadata(&self, token_id: U256) -> Vec<(String, String)>;
587 }
588 }
589
590 pub fn mint(&mut self, to: Address, token_id: U256, metadata: Vec<(String, String)>) {
591 self.token.mint(to, token_id, metadata);
592 }
593
594 pub fn burn(&mut self, token_id: U256) {
595 self.token.burn(token_id);
596 }
597
598 pub fn set_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
599 self.token.set_metadata(token_id, metadata);
600 }
601
602 pub fn update_metadata(&mut self, token_id: U256, metadata: Vec<(String, String)>) {
603 self.token.update_metadata(token_id, metadata);
604 }
605 }
606
607 #[odra::module]
608 pub(crate) struct NFTReceiver {
609 #[allow(clippy::type_complexity)]
610 last_call_data: Var<((Address, Address), (U256, Option<Bytes>))>
611 }
612
613 #[odra::module]
614 impl NFTReceiver {
615 #[allow(dead_code)]
616 pub fn on_cep95_received(
617 &mut self,
618 operator: Address,
619 from: Address,
620 token_id: U256,
621 data: Option<Bytes>
622 ) -> bool {
623 self.last_call_data
624 .set(((operator, from), (token_id, data.clone())));
625 true
626 }
627
628 #[allow(dead_code)]
629 pub fn last_call_result(&self) -> ((Address, Address), (U256, Option<Bytes>)) {
630 self.last_call_data.get().unwrap_or_revert(self)
631 }
632 }
633
634 #[odra::module]
635 pub(crate) struct RejectingNFTReceiver;
636
637 #[odra::module]
638 impl RejectingNFTReceiver {
639 #[allow(dead_code)]
640 pub fn on_cep95_received(
641 &mut self,
642 operator: Address,
643 from: Address,
644 token_id: U256,
645 data: Option<Bytes>
646 ) -> bool {
647 false
648 }
649 }
650
651 #[odra::module]
652 pub(crate) struct BasicContract;
653
654 #[odra::module]
655 impl BasicContract {}
656}
657
658#[cfg(test)]
659mod tests {
660 use super::*;
661 use crate::cep95::utils::*;
662 use odra::{
663 host::{Deployer, HostEnv, NoArgs},
664 prelude::Addressable,
665 VmError
666 };
667 use odra_test;
668
669 fn setup() -> (HostEnv, BasicCep95HostRef) {
670 let env = odra_test::env();
671 let cep95 = BasicCep95::try_deploy(
672 &env,
673 BasicCep95InitArgs {
674 name: "TestToken".to_string(),
675 symbol: "TT".to_string()
676 }
677 )
678 .unwrap();
679 (env, cep95)
680 }
681
682 #[test]
683 fn test_deploy() {
684 let env = odra_test::env();
685 let cep95 = BasicCep95::try_deploy(
686 &env,
687 BasicCep95InitArgs {
688 name: "TestToken".to_string(),
689 symbol: "TT".to_string()
690 }
691 );
692 assert!(cep95.is_ok());
693 }
694
695 #[test]
696 fn test_name() {
697 let (env, cep95) = setup();
698 let name = cep95.name();
699 assert_eq!(name, "TestToken");
700 }
701
702 #[test]
703 fn test_symbol() {
704 let (env, cep95) = setup();
705 let symbol = cep95.symbol();
706 assert_eq!(symbol, "TT");
707 }
708
709 #[test]
710 fn test_mint() {
711 let (env, mut cep95) = setup();
712 let owner = env.caller();
713
714 let token_id = U256::from(1);
715 let metadata = vec![("key".to_string(), "value".to_string())];
716 cep95.mint(owner, token_id, metadata);
717
718 assert_eq!(cep95.balance_of(owner), U256::from(1));
719 assert_eq!(cep95.owner_of(token_id), Some(owner));
720 assert_eq!(
721 cep95.token_metadata(token_id),
722 vec![("key".to_string(), "value".to_string())]
723 );
724 assert!(env.emitted(&cep95, "Mint"));
725 }
726
727 #[test]
728 fn test_minting_existing_token() {
729 let (env, mut cep95) = setup();
730 let owner = env.caller();
731
732 let token_id = U256::from(1);
733 let metadata = vec![("key".to_string(), "value".to_string())];
734 cep95.mint(owner, token_id, metadata.clone());
735
736 let result = cep95.try_mint(owner, token_id, metadata);
737 assert_eq!(result, Err(Error::TokenAlreadyExists.into()));
738 }
739
740 #[test]
741 fn test_mint_many_tokens() {
742 let (env, mut cep95) = setup();
743 let owner = env.caller();
744
745 let token_id1 = U256::from(1);
746 let metadata1 = vec![("key1".to_string(), "value1".to_string())];
747 cep95.mint(owner, token_id1, metadata1);
748
749 let token_id2 = U256::from(2);
750 let metadata2 = vec![("key2".to_string(), "value2".to_string())];
751 cep95.mint(owner, token_id2, metadata2);
752
753 assert_eq!(cep95.balance_of(owner), U256::from(2));
754 assert_eq!(cep95.owner_of(token_id1), Some(owner));
755 assert_eq!(cep95.owner_of(token_id2), Some(owner));
756 }
757
758 #[test]
759 fn test_burn() {
760 let (env, mut cep95) = setup();
761 let owner = env.caller();
762
763 let token_id = U256::from(1);
764 let metadata = vec![("key".to_string(), "value".to_string())];
765 cep95.mint(owner, token_id, metadata);
766 cep95.burn(token_id);
767
768 assert_eq!(cep95.balance_of(owner), U256::from(0));
769 assert_eq!(cep95.owner_of(token_id), None);
770 assert_eq!(
771 cep95.try_token_metadata(token_id),
772 Err(Error::InvalidTokenId.into())
773 );
774 assert!(env.emitted(&cep95, "Burn"));
775 }
776
777 #[test]
778 fn test_burn_non_existing_token() {
779 let (env, mut cep95) = setup();
780 let owner = env.caller();
781
782 let token_id = U256::from(1);
783 let result = cep95.try_burn(token_id);
784 assert_eq!(result, Err(Error::InvalidTokenId.into()));
785 }
786
787 #[test]
788 fn test_safe_transfer_to_receiver() {
789 let (env, mut cep95) = setup();
790 let nft_receiver = NFTReceiver::deploy(&env, NoArgs);
791 let recipient = nft_receiver.address();
792 let owner = env.caller();
793
794 let token_id = U256::from(1);
795 let metadata = vec![("key".to_string(), "value".to_string())];
796 cep95.mint(owner, token_id, metadata);
797
798 cep95.safe_transfer_from(owner, recipient, token_id, None);
799
800 assert_eq!(cep95.balance_of(owner), U256::from(0));
801 assert_eq!(cep95.balance_of(recipient), U256::from(1));
802 assert_eq!(
803 nft_receiver.last_call_result(),
804 ((owner, owner), (token_id, None))
805 );
806 }
807
808 #[test]
809 fn test_safe_transfer_to_non_receiver() {
810 let (env, mut cep95) = setup();
811 let contract = BasicContract::deploy(&env, NoArgs);
812 let recipient = contract.address();
813 let owner = env.caller();
814
815 let token_id = U256::from(1);
816 let metadata = vec![("key".to_string(), "value".to_string())];
817 cep95.mint(owner, token_id, metadata);
818
819 let result = cep95.try_safe_transfer_from(owner, recipient, token_id, None);
820 assert_eq!(
821 result,
822 Err(OdraError::VmError(VmError::NoSuchMethod(
823 "on_cep95_received".to_string()
824 )))
825 );
826
827 assert_eq!(cep95.balance_of(owner), U256::from(1));
828 assert_eq!(cep95.balance_of(recipient), U256::from(0));
829 }
830
831 #[test]
832 fn test_safe_transfer_to_rejecting_receiver() {
833 let (env, mut cep95) = setup();
834
835 let owner = env.get_account(0);
836 let contract = RejectingNFTReceiver::deploy(&env, NoArgs);
837 let recipient = contract.address();
838
839 let token_id = U256::from(1);
840 let metadata = vec![("key".to_string(), "value".to_string())];
841 cep95.mint(owner, token_id, metadata);
842
843 let result = cep95.try_safe_transfer_from(owner, recipient, token_id, None);
844 assert_eq!(result, Err(Error::TransferFailed.into()));
845
846 assert_eq!(cep95.balance_of(owner), U256::from(1));
847 assert_eq!(cep95.balance_of(recipient), U256::from(0));
848 }
849
850 #[test]
851 fn test_transfer() {
852 let (env, mut cep95) = setup();
853
854 let owner = env.get_account(0);
855 let recipient = env.get_account(10);
856
857 let token_id = U256::from(1);
858 let metadata = vec![("key".to_string(), "value".to_string())];
859 cep95.mint(owner, token_id, metadata);
860 cep95.transfer_from(owner, recipient, token_id);
861
862 assert_eq!(cep95.balance_of(owner), U256::from(0));
863 assert_eq!(cep95.balance_of(recipient), U256::from(1));
864 assert!(env.emitted(&cep95, "Transfer"));
865 }
866
867 #[test]
868 fn test_transfer_non_existing_token() {
869 let (env, mut cep95) = setup();
870
871 let owner = env.get_account(0);
872 let recipient = env.get_account(10);
873
874 let token_id = U256::from(1);
875 let metadata = vec![("key".to_string(), "value".to_string())];
876 cep95.mint(owner, token_id, metadata);
877
878 let result = cep95.try_transfer_from(owner, recipient, U256::from(2));
879 assert_eq!(result, Err(Error::InvalidTokenId.into()));
880 }
881
882 #[test]
883 fn test_transfer_from_non_owner() {
884 let (env, mut cep95) = setup();
885
886 let recipient = env.get_account(10);
887 let non_owner = env.get_account(11);
888 let owner = env.get_account(0);
889
890 let token_id = U256::from(1);
891 let metadata = vec![("key".to_string(), "value".to_string())];
892 cep95.mint(owner, token_id, metadata);
893
894 let result = cep95.try_transfer_from(non_owner, recipient, token_id);
895 assert_eq!(result, Err(Error::NotAnOwnerOrApproved.into()));
896 assert_eq!(cep95.balance_of(owner), U256::from(1));
897 assert_eq!(cep95.balance_of(recipient), U256::from(0));
898 }
899
900 #[test]
901 fn test_approve() {
902 let (env, mut cep95) = setup();
903 let owner = env.caller();
904
905 let token_id = U256::from(1);
906 let metadata = vec![("key".to_string(), "value".to_string())];
907 cep95.mint(owner, token_id, metadata);
908
909 let spender = env.get_account(10);
910 cep95.approve(spender, token_id);
911
912 assert_eq!(cep95.approved_for(token_id), Some(spender));
913 assert!(env.emitted_event(
914 &cep95,
915 Approval {
916 owner,
917 spender,
918 token_id
919 }
920 ));
921 }
922
923 #[test]
924 fn test_approve_by_non_owner() {
925 let (env, mut cep95) = setup();
926 let owner = env.get_account(0);
927 let non_owner = env.get_account(11);
928
929 let token_id = U256::from(1);
930 let metadata = vec![("key".to_string(), "value".to_string())];
931 cep95.mint(owner, token_id, metadata);
932
933 let spender = env.get_account(10);
934 env.set_caller(non_owner);
935 let result = cep95.try_approve(spender, token_id);
936 assert_eq!(result, Err(Error::NotAnOwnerOrApproved.into()));
937 }
938
939 #[test]
940 fn test_transfer_by_approved() {
941 let (env, mut cep95) = setup();
942 let owner = env.get_account(0);
943 let recipient = env.get_account(10);
944
945 let token_id = U256::from(1);
946 let metadata = vec![("key".to_string(), "value".to_string())];
947 cep95.mint(owner, token_id, metadata);
948
949 let spender = env.get_account(11);
950 cep95.approve(spender, token_id);
951 env.set_caller(spender);
952 cep95.transfer_from(owner, recipient, token_id);
953
954 assert_eq!(cep95.balance_of(owner), U256::from(0));
955 assert_eq!(cep95.balance_of(recipient), U256::from(1));
956 assert!(env.emitted_event(
957 &cep95,
958 Transfer {
959 from: owner,
960 to: recipient,
961 token_id
962 }
963 ));
964 }
965
966 #[test]
967 fn test_approve_for_all() {
968 let (env, mut cep95) = setup();
969 let owner = env.caller();
970 let operator = env.get_account(10);
971
972 cep95.approve_for_all(operator);
973
974 assert!(cep95.is_approved_for_all(owner, operator));
975 assert!(env.emitted(&cep95, "ApprovalForAll"));
976 }
977
978 #[test]
979 fn test_revoke_approval_for_all() {
980 let (env, mut cep95) = setup();
981 let owner = env.caller();
982 let operator = env.get_account(10);
983
984 cep95.approve_for_all(operator);
985 cep95.revoke_approval_for_all(operator);
986
987 assert!(!cep95.is_approved_for_all(owner, operator));
988 assert!(env.emitted(&cep95, "RevokeApprovalForAll"));
989 }
990
991 #[test]
992 fn test_approve_for_all_self() {
993 let (env, mut cep95) = setup();
994 let owner = env.caller();
995
996 let result = cep95.try_approve_for_all(owner);
997 assert_eq!(result, Err(Error::ApproveToCaller.into()));
998 }
999
1000 #[test]
1001 fn test_revoke_approval() {
1002 let (env, mut cep95) = setup();
1003 let owner = env.caller();
1004
1005 let token_id = U256::from(1);
1006 let metadata = vec![("key".to_string(), "value".to_string())];
1007 cep95.mint(owner, token_id, metadata);
1008
1009 let spender = env.get_account(10);
1010 cep95.approve(spender, token_id);
1011 cep95.revoke_approval(token_id);
1012
1013 assert_eq!(cep95.approved_for(token_id), None);
1014 assert!(env.emitted(&cep95, "RevokeApproval"));
1015 }
1016
1017 #[test]
1018 fn revoke_non_existing_approval() {
1019 let (env, mut cep95) = setup();
1020 let owner = env.caller();
1021
1022 let token_id = U256::from(1);
1023 let metadata = vec![("key".to_string(), "value".to_string())];
1024 cep95.mint(owner, token_id, metadata);
1025
1026 let result = cep95.try_revoke_approval(token_id);
1027 assert_eq!(result, Err(Error::ValueNotSet.into()));
1028 }
1029
1030 #[test]
1031 fn test_revoke_approval_by_non_owner() {
1032 let (env, mut cep95) = setup();
1033 let owner = env.get_account(0);
1034 let non_owner = env.get_account(11);
1035
1036 let token_id = U256::from(1);
1037 let metadata = vec![("key".to_string(), "value".to_string())];
1038 cep95.mint(owner, token_id, metadata);
1039
1040 let spender = env.get_account(10);
1041 cep95.approve(spender, token_id);
1042 env.set_caller(non_owner);
1043 let result = cep95.try_revoke_approval(token_id);
1044 assert_eq!(result, Err(Error::NotAnOwnerOrApproved.into()));
1045 }
1046
1047 #[test]
1048 fn test_metadata() {
1049 let (env, mut cep95) = setup();
1050 let owner = env.caller();
1051
1052 let token_id = U256::from(1);
1053 let metadata = vec![("key".to_string(), "value".to_string())];
1054 cep95.mint(owner, token_id, metadata);
1055
1056 assert_eq!(
1057 cep95.token_metadata(token_id),
1058 vec![("key".to_string(), "value".to_string())]
1059 );
1060 }
1061
1062 #[test]
1063 fn test_transfer_by_operator() {
1064 let (env, mut cep95) = setup();
1065 let owner = env.caller();
1066 let recipient = env.get_account(10);
1067 let operator = env.get_account(11);
1068
1069 let token_id1 = U256::from(1);
1070 let metadata = vec![("key".to_string(), "value".to_string())];
1071 cep95.mint(owner, token_id1, metadata.clone());
1072
1073 cep95.approve_for_all(operator);
1074 let token_id2 = U256::from(2);
1075 cep95.mint(owner, token_id2, metadata);
1076
1077 env.set_caller(operator);
1078 cep95.transfer_from(owner, recipient, token_id1);
1079 cep95.transfer_from(owner, recipient, token_id2);
1080
1081 assert_eq!(cep95.balance_of(owner), U256::from(0));
1082 assert_eq!(cep95.balance_of(recipient), U256::from(2));
1083 }
1084
1085 #[test]
1086 fn test_update_metadata() {
1087 let (env, mut cep95) = setup();
1088 let owner = env.caller();
1089
1090 let token_id = U256::from(1);
1091 let metadata = vec![
1092 ("age".to_string(), "30".to_string()),
1093 ("name".to_string(), "Alice".to_string()),
1094 ];
1095 cep95.mint(owner, token_id, metadata);
1096
1097 let new_metadata = vec![("name".to_string(), "Bob".to_string())];
1098 cep95.update_metadata(token_id, new_metadata);
1099
1100 assert_eq!(
1101 cep95.token_metadata(token_id),
1102 vec![
1103 ("age".to_string(), "30".to_string()),
1104 ("name".to_string(), "Bob".to_string()),
1105 ]
1106 );
1107 assert!(env.emitted(&cep95, "MetadataUpdate"));
1108 }
1109
1110 #[test]
1111 fn test_set_metadata() {
1112 let (env, mut cep95) = setup();
1113 let owner = env.caller();
1114
1115 let token_id = U256::from(1);
1116 let metadata = vec![
1117 ("age".to_string(), "30".to_string()),
1118 ("name".to_string(), "Alice".to_string()),
1119 ];
1120 cep95.mint(owner, token_id, metadata);
1121
1122 let new_metadata = vec![("name".to_string(), "Bob".to_string())];
1123 cep95.set_metadata(token_id, new_metadata);
1124
1125 assert_eq!(
1126 cep95.token_metadata(token_id),
1127 vec![("name".to_string(), "Bob".to_string())]
1128 );
1129 assert!(env.emitted(&cep95, "MetadataUpdate"));
1130 }
1131}