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