defuse/contract/tokens/nep245/
resolver.rs1use std::borrow::Cow;
2
3use defuse_near_utils::{Lock, REFUND_MEMO, UnwrapOrPanic, UnwrapOrPanicError};
4use defuse_nep245::{
5 ClearedApproval, MtEvent, MtTransferEvent, TokenId, resolver::MultiTokenResolver,
6};
7use near_sdk::{AccountId, env, json_types::U128, near, require, serde_json};
8
9use crate::contract::{Contract, ContractExt};
10
11#[near]
12impl MultiTokenResolver for Contract {
13 #[private]
14 fn mt_resolve_transfer(
15 &mut self,
16 previous_owner_ids: Vec<AccountId>,
17 receiver_id: AccountId,
18 token_ids: Vec<TokenId>,
19 #[allow(unused_mut)] mut amounts: Vec<U128>,
20 approvals: Option<Vec<Option<Vec<ClearedApproval>>>>,
21 ) -> Vec<U128> {
22 require!(approvals.is_none(), "approvals are not supported");
23 require!(
24 !token_ids.is_empty()
25 && previous_owner_ids.len() == token_ids.len()
26 && amounts.len() == token_ids.len(),
27 "invalid args"
28 );
29
30 let mut refunds =
31 env::promise_result_checked(0, Self::mt_on_transfer_max_result_len(amounts.len()))
32 .ok()
33 .and_then(|value| serde_json::from_slice::<Vec<U128>>(&value).ok())
34 .filter(|refund| refund.len() == amounts.len())
35 .unwrap_or_else(|| amounts.clone());
36
37 let sender_id = previous_owner_ids.first().cloned().unwrap_or_panic();
38
39 for ((token_id, previous_owner_id), (amount, refund)) in token_ids
40 .iter()
41 .map(|token_id| token_id.parse().unwrap_or_panic_display())
42 .zip(previous_owner_ids)
43 .zip(amounts.iter_mut().zip(&mut refunds))
44 {
45 require!(
46 sender_id == previous_owner_id,
47 "approvals are not supported"
48 );
49
50 refund.0 = refund.0.min(amount.0);
51 let Some(receiver) = self
52 .accounts
53 .get_mut(&receiver_id)
54 .map(Lock::as_inner_unchecked_mut)
67 else {
68 return amounts;
70 };
71 let receiver_balance = receiver.token_balances.amount_for(&token_id);
72 refund.0 = refund.0.min(receiver_balance);
74 if refund.0 == 0 {
75 continue;
77 }
78
79 receiver
81 .token_balances
82 .sub(token_id.clone(), refund.0)
83 .unwrap_or_panic();
84 self.accounts
86 .get_or_create(previous_owner_id)
87 .as_inner_unchecked_mut()
89 .token_balances
90 .add(token_id, refund.0)
91 .unwrap_or_panic();
92
93 amount.0 -= refund.0;
95 }
96
97 let (refunded_token_ids, refunded_amounts): (Vec<_>, Vec<_>) = token_ids
98 .into_iter()
99 .zip(refunds)
100 .filter(|(_token_id, refund)| refund.0 > 0)
101 .unzip();
102
103 if !refunded_amounts.is_empty() {
104 MtEvent::MtTransfer(Cow::Borrowed(
105 [MtTransferEvent {
106 authorized_id: None,
107 old_owner_id: Cow::Borrowed(&receiver_id),
108 new_owner_id: Cow::Borrowed(&sender_id),
109 token_ids: refunded_token_ids.into(),
110 amounts: refunded_amounts.into(),
111 memo: Some(REFUND_MEMO.into()),
112 }]
113 .as_slice(),
114 ))
115 .emit();
118 }
119
120 amounts
121 }
122}