use defuse_core::token_id::nep245::Nep245TokenId; use defuse_near_utils::{ CURRENT_ACCOUNT_ID, PREDECESSOR_ACCOUNT_ID, UnwrapOrPanic, UnwrapOrPanicError, }; use defuse_nep245::receiver::MultiTokenReceiver; use near_plugins::{Pausable, pause}; use near_sdk::{AccountId, PromiseOrValue, json_types::U128, near, require}; use crate::{ contract::{Contract, ContractExt}, intents::{Intents, ext_intents}, tokens::{DepositAction, DepositMessage}, }; #[near] impl MultiTokenReceiver for Contract { /// Deposit multi-tokens. /// /// `msg` contains [`AccountId`] of the internal recipient. /// Empty `msg` means deposit to `sender_id` #[pause] fn mt_on_transfer( &mut self, sender_id: AccountId, previous_owner_ids: Vec, token_ids: Vec, amounts: Vec, msg: String, ) -> PromiseOrValue> { let token = &*PREDECESSOR_ACCOUNT_ID; require!(!amounts.is_empty(), "invalid args"); require!( token_ids.len() == amounts.len(), "NEP-245: Contract MUST panic if `token_ids` length does not equals `amounts` length" ); require!( previous_owner_ids.len() == token_ids.len(), "NEP-245: Contract MUST panic if `previous_owner_ids` length does not equals `token_ids` length" ); require!( token != &*CURRENT_ACCOUNT_ID, "self-wrapping is not allowed" ); let DepositMessage { receiver_id, action, } = if msg.is_empty() { DepositMessage::new(sender_id.clone()) } else { msg.parse().unwrap_or_panic_display() }; let core_token_ids = token_ids .iter() .cloned() .map(|token_id| Nep245TokenId::new(token.clone(), token_id)) .map(UnwrapOrPanicError::unwrap_or_panic_display) .map(Into::into); self.deposit( receiver_id.clone(), core_token_ids .clone() .zip(amounts.iter().map(|amount| amount.0)), Some("deposit"), ) .unwrap_or_panic(); let Some(action) = action else { return PromiseOrValue::Value(vec![U128(0); token_ids.len()]); }; match action { DepositAction::Notify(notify) => Self::notify_on_transfer( sender_id, previous_owner_ids, receiver_id.clone(), core_token_ids.map(|t| t.to_string()).collect(), amounts.clone(), notify, ) .then( Self::ext(CURRENT_ACCOUNT_ID.clone()) .with_static_gas(Self::mt_resolve_deposit_gas(amounts.len())) .with_unused_gas_weight(0) .mt_resolve_deposit(receiver_id, token.clone(), token_ids, amounts), ) .into(), DepositAction::Execute(execute) => { if !execute.execute_intents.is_empty() { if execute.refund_if_fails { self.execute_intents(execute.execute_intents); } else { let _ = ext_intents::ext(CURRENT_ACCOUNT_ID.clone()) .execute_intents(execute.execute_intents); } } PromiseOrValue::Value(vec![U128(0); token_ids.len()]) } } } } #[near] impl Contract { #[private] #[allow(clippy::needless_pass_by_value)] pub fn mt_resolve_deposit( &mut self, receiver_id: AccountId, contract_id: AccountId, tokens: Vec, #[allow(unused_mut)] mut amounts: Vec, ) -> PromiseOrValue> { self.resolve_deposit_internal( &receiver_id, tokens .into_iter() .map(|token_id| Nep245TokenId::new(contract_id.clone(), token_id)) .map(UnwrapOrPanicError::unwrap_or_panic_display) .map(Into::into) .zip(amounts.iter_mut().map(|amount| &mut amount.0)), ); PromiseOrValue::Value(amounts) } }