defuse/contract/tokens/nep245/
deposit.rs

1use defuse_core::{DefuseError, token_id::nep245::Nep245TokenId, tokens::MAX_TOKEN_ID_LEN};
2use defuse_near_utils::{PanicError, UnwrapOrPanic, UnwrapOrPanicError};
3use defuse_nep245::receiver::MultiTokenReceiver;
4use near_plugins::{Pausable, pause};
5use near_sdk::{AccountId, PromiseOrValue, env, json_types::U128, near, require};
6
7use crate::{
8    contract::{Contract, ContractExt},
9    intents::{Intents, ext_intents},
10    tokens::{DepositAction, DepositMessage},
11};
12
13#[near]
14impl MultiTokenReceiver for Contract {
15    /// Deposit multi-tokens.
16    ///
17    /// `msg` contains [`AccountId`] of the internal recipient.
18    /// Empty `msg` means deposit to `sender_id`
19    #[pause]
20    fn mt_on_transfer(
21        &mut self,
22        sender_id: AccountId,
23        previous_owner_ids: Vec<AccountId>,
24        token_ids: Vec<defuse_nep245::TokenId>,
25        amounts: Vec<U128>,
26        msg: String,
27    ) -> PromiseOrValue<Vec<U128>> {
28        let token = env::predecessor_account_id();
29
30        require!(!amounts.is_empty(), "invalid args");
31
32        require!(
33            token_ids.len() == amounts.len(),
34            "NEP-245: Contract MUST panic if `token_ids` length does not equals `amounts` length"
35        );
36
37        require!(
38            previous_owner_ids.len() == token_ids.len(),
39            "NEP-245: Contract MUST panic if `previous_owner_ids` length does not equals `token_ids` length"
40        );
41
42        require!(
43            token != env::current_account_id(),
44            "self-wrapping is not allowed"
45        );
46
47        let core_token_ids = token_ids
48            .iter()
49            .inspect(|token_id| {
50                if token_id.len() > MAX_TOKEN_ID_LEN {
51                    DefuseError::TokenIdTooLarge(token_id.len()).panic_display();
52                }
53            })
54            .cloned()
55            .map(|token_id| Nep245TokenId::new(token.clone(), token_id))
56            .map(Into::into);
57
58        let DepositMessage {
59            receiver_id,
60            action,
61        } = if msg.is_empty() {
62            DepositMessage::new(sender_id.clone())
63        } else {
64            msg.parse().unwrap_or_panic_display()
65        };
66
67        self.deposit(
68            receiver_id.clone(),
69            core_token_ids
70                .clone()
71                .zip(amounts.iter().map(|amount| amount.0)),
72            Some("deposit"),
73        )
74        .unwrap_or_panic();
75
76        let Some(action) = action else {
77            return PromiseOrValue::Value(vec![U128(0); token_ids.len()]);
78        };
79
80        match action {
81            DepositAction::Notify(notify) => Self::notify_on_transfer(
82                sender_id,
83                previous_owner_ids,
84                receiver_id.clone(),
85                core_token_ids.map(|t| t.to_string()).collect(),
86                amounts.clone(),
87                notify,
88            )
89            .then(
90                Self::ext(env::current_account_id())
91                    .with_static_gas(Self::mt_resolve_deposit_gas(amounts.len()))
92                    .with_unused_gas_weight(0)
93                    .mt_resolve_deposit(receiver_id, token.clone(), token_ids, amounts),
94            )
95            .into(),
96            DepositAction::Execute(execute) => {
97                if !execute.execute_intents.is_empty() {
98                    if execute.refund_if_fails {
99                        self.execute_intents(execute.execute_intents);
100                    } else {
101                        ext_intents::ext(env::current_account_id())
102                            .execute_intents(execute.execute_intents)
103                            .detach();
104                    }
105                }
106                PromiseOrValue::Value(vec![U128(0); token_ids.len()])
107            }
108        }
109    }
110}
111
112#[near]
113impl Contract {
114    #[private]
115    #[allow(clippy::needless_pass_by_value)]
116    pub fn mt_resolve_deposit(
117        &mut self,
118        receiver_id: AccountId,
119        contract_id: AccountId,
120        tokens: Vec<defuse_nep245::TokenId>,
121        #[allow(unused_mut)] mut amounts: Vec<U128>,
122    ) -> PromiseOrValue<Vec<U128>> {
123        self.resolve_deposit_internal(
124            &receiver_id,
125            tokens
126                .into_iter()
127                .map(|token_id| Nep245TokenId::new(contract_id.clone(), token_id))
128                .map(Into::into)
129                .zip(amounts.iter_mut().map(|amount| &mut amount.0)),
130        );
131
132        PromiseOrValue::Value(amounts)
133    }
134}