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