Skip to main content

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