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