defuse/contract/tokens/nep171/
deposit.rs

1use defuse_core::{
2    DefuseError,
3    token_id::{TokenId, nep171::Nep171TokenId},
4    tokens::MAX_TOKEN_ID_LEN,
5};
6use defuse_near_utils::{PanicError, UnwrapOrPanic, UnwrapOrPanicError};
7use near_contract_standards::non_fungible_token::core::NonFungibleTokenReceiver;
8use near_plugins::{Pausable, pause};
9use near_sdk::{AccountId, PromiseOrValue, env, json_types::U128, near};
10
11use crate::{
12    contract::{Contract, ContractExt},
13    intents::{Intents, ext_intents},
14    tokens::{DepositAction, DepositMessage},
15};
16
17#[near]
18impl NonFungibleTokenReceiver for Contract {
19    /// Deposit non-fungible token.
20    ///
21    /// `msg` contains [`AccountId`] of the internal recipient.
22    /// Empty `msg` means deposit to `sender_id`
23    #[pause]
24    fn nft_on_transfer(
25        &mut self,
26        sender_id: AccountId,
27        previous_owner_id: AccountId,
28        token_id: near_contract_standards::non_fungible_token::TokenId,
29        msg: String,
30    ) -> PromiseOrValue<bool> {
31        if token_id.len() > MAX_TOKEN_ID_LEN {
32            DefuseError::TokenIdTooLarge(token_id.len()).panic_display();
33        }
34
35        let DepositMessage {
36            receiver_id,
37            action,
38        } = if msg.is_empty() {
39            DepositMessage::new(sender_id.clone())
40        } else {
41            msg.parse().unwrap_or_panic_display()
42        };
43
44        let core_token_id: TokenId =
45            Nep171TokenId::new(env::predecessor_account_id(), token_id.clone()).into();
46
47        self.deposit(
48            receiver_id.clone(),
49            [(core_token_id.clone(), 1)],
50            Some("deposit"),
51        )
52        .unwrap_or_panic();
53
54        let Some(action) = action else {
55            return PromiseOrValue::Value(false);
56        };
57
58        match action {
59            DepositAction::Notify(notify) => Self::notify_on_transfer(
60                sender_id,
61                vec![previous_owner_id],
62                receiver_id.clone(),
63                vec![core_token_id.to_string()],
64                vec![U128(1)],
65                notify,
66            )
67            .then(
68                Self::ext(env::current_account_id())
69                    .with_static_gas(Self::mt_resolve_deposit_gas(1))
70                    .with_unused_gas_weight(0)
71                    .nft_resolve_deposit(receiver_id, env::predecessor_account_id(), token_id),
72            )
73            .into(),
74            DepositAction::Execute(execute) => {
75                if !execute.execute_intents.is_empty() {
76                    if execute.refund_if_fails {
77                        self.execute_intents(execute.execute_intents);
78                    } else {
79                        ext_intents::ext(env::current_account_id())
80                            .execute_intents(execute.execute_intents)
81                            .detach();
82                    }
83                }
84
85                PromiseOrValue::Value(false)
86            }
87        }
88    }
89}
90
91#[near]
92impl Contract {
93    #[private]
94    #[allow(clippy::needless_pass_by_value)]
95    pub fn nft_resolve_deposit(
96        &mut self,
97        receiver_id: AccountId,
98        contract_id: AccountId,
99        nft_token_id: near_contract_standards::non_fungible_token::TokenId,
100    ) -> PromiseOrValue<bool> {
101        let mut amount = 1u128;
102
103        self.resolve_deposit_internal(
104            &receiver_id,
105            [(
106                Nep171TokenId::new(contract_id, nft_token_id).into(),
107                &mut amount,
108            )],
109        );
110        PromiseOrValue::Value(amount != 0)
111    }
112}