Skip to main content

defuse/contract/tokens/nep245/
deposit.rs

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