use crate::nft::base::StorageKey;
use crate::nft::events::NftTransfer;
use crate::nft::{NonFungibleToken, TokenId};
use near_sdk::collections::UnorderedSet;
use near_sdk::{env, require, AccountId};
use std::collections::HashMap;
impl NonFungibleToken {
pub(crate) fn assert_token_holder(&self, token_id: &TokenId) -> AccountId {
let sender_id = env::predecessor_account_id();
let owner_id = self
.owner_by_id
.get(token_id)
.unwrap_or_else(|| env::panic_str("Not found token"));
assert_eq!(&owner_id, &sender_id, "Unauthorized");
owner_id
}
pub fn internal_transfer_unguarded(
&mut self,
#[allow(clippy::ptr_arg)] token_id: &TokenId,
from: &AccountId,
to: &AccountId,
) {
self.owner_by_id.insert(token_id, to);
if let Some(tokens_per_owner) = &mut self.tokens_per_owner {
let mut owner_tokens = tokens_per_owner.get(from).unwrap_or_else(|| {
env::panic_str("Unable to access tokens per owner in unguarded call.")
});
owner_tokens.remove(token_id);
if owner_tokens.is_empty() {
tokens_per_owner.remove(from);
} else {
tokens_per_owner.insert(from, &owner_tokens);
}
let mut receiver_tokens = tokens_per_owner.get(to).unwrap_or_else(|| {
UnorderedSet::new(StorageKey::TokensPerOwner {
account_hash: env::sha256(to.as_bytes()),
})
});
receiver_tokens.insert(token_id);
tokens_per_owner.insert(to, &receiver_tokens);
}
(NftTransfer {
old_owner_id: &from,
new_owner_id: &to,
token_ids: &[token_id],
authorized_id: None,
memo: None,
})
.emit();
}
pub fn internal_transfer(
&mut self,
sender_id: &AccountId,
receiver_id: &AccountId,
#[allow(clippy::ptr_arg)] token_id: &TokenId,
approval_id: Option<u64>,
_memo: Option<String>,
) -> (AccountId, Option<HashMap<AccountId, u64>>) {
let owner_id = self
.owner_by_id
.get(token_id)
.unwrap_or_else(|| env::panic_str("Token not found"));
let approved_account_ids = self
.approvals_by_id
.as_mut()
.and_then(|by_id| by_id.remove(token_id));
if sender_id != &owner_id {
let app_acc_ids = approved_account_ids
.as_ref()
.unwrap_or_else(|| env::panic_str("Unauthorized"));
let actual_approval_id = app_acc_ids.get(sender_id);
if actual_approval_id.is_none() {
env::panic_str("Sender not approved");
}
require!(
approval_id.is_none() || actual_approval_id == approval_id.as_ref(),
format!(
"The actual approval_id {:?} is different from the given approval_id {:?}",
actual_approval_id, approval_id
)
);
}
require!(
&owner_id != receiver_id,
"Current and next owner must differ"
);
self.internal_transfer_unguarded(token_id, &owner_id, receiver_id);
(owner_id, approved_account_ids)
}
}