defuse/contract/tokens/nep245/
deposit.rs1use 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 #[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}