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