near_contract_standards/non_fungible_token/approval/
approval_impl.rsuse crate::non_fungible_token::approval::ext_nft_approval_receiver;
use crate::non_fungible_token::approval::NonFungibleTokenApproval;
use crate::non_fungible_token::token::TokenId;
use crate::non_fungible_token::utils::{
assert_at_least_one_yocto, bytes_for_approved_account_id, refund_approved_account_ids,
refund_approved_account_ids_iter, refund_deposit,
};
use crate::non_fungible_token::NonFungibleToken;
use near_sdk::{assert_one_yocto, env, require, AccountId, Gas, Promise};
const GAS_FOR_NFT_APPROVE: Gas = Gas::from_tgas(10);
fn expect_token_found<T>(option: Option<T>) -> T {
option.unwrap_or_else(|| env::panic_str("Token not found"))
}
fn expect_approval<T>(option: Option<T>) -> T {
option.unwrap_or_else(|| env::panic_str("next_approval_by_id must be set for approval ext"))
}
impl NonFungibleTokenApproval for NonFungibleToken {
fn nft_approve(
&mut self,
token_id: TokenId,
account_id: AccountId,
msg: Option<String>,
) -> Option<Promise> {
assert_at_least_one_yocto();
let approvals_by_id = self
.approvals_by_id
.as_mut()
.unwrap_or_else(|| env::panic_str("NFT does not support Approval Management"));
let owner_id = expect_token_found(self.owner_by_id.get(&token_id));
require!(env::predecessor_account_id() == owner_id, "Predecessor must be token owner.");
let next_approval_id_by_id = expect_approval(self.next_approval_id_by_id.as_mut());
let approved_account_ids = &mut approvals_by_id.get(&token_id).unwrap_or_default();
let approval_id: u64 = next_approval_id_by_id.get(&token_id).unwrap_or(1u64);
let old_approval_id = approved_account_ids.insert(account_id.clone(), approval_id);
approvals_by_id.insert(&token_id, approved_account_ids);
next_approval_id_by_id.insert(&token_id, &(approval_id + 1));
let storage_used =
if old_approval_id.is_none() { bytes_for_approved_account_id(&account_id) } else { 0 };
refund_deposit(storage_used);
msg.map(|msg| {
ext_nft_approval_receiver::ext(account_id)
.with_static_gas(env::prepaid_gas().saturating_sub(GAS_FOR_NFT_APPROVE))
.nft_on_approve(token_id, owner_id, approval_id, msg)
})
}
fn nft_revoke(&mut self, token_id: TokenId, account_id: AccountId) {
assert_one_yocto();
let approvals_by_id = self.approvals_by_id.as_mut().unwrap_or_else(|| {
env::panic_str("NFT does not support Approval Management");
});
let owner_id = expect_token_found(self.owner_by_id.get(&token_id));
let predecessor_account_id = env::predecessor_account_id();
require!(predecessor_account_id == owner_id, "Predecessor must be token owner.");
if let Some(approved_account_ids) = &mut approvals_by_id.get(&token_id) {
if approved_account_ids.remove(&account_id).is_some() {
refund_approved_account_ids_iter(
predecessor_account_id,
core::iter::once(&account_id),
);
if approved_account_ids.is_empty() {
approvals_by_id.remove(&token_id);
} else {
approvals_by_id.insert(&token_id, approved_account_ids);
}
}
}
}
fn nft_revoke_all(&mut self, token_id: TokenId) {
assert_one_yocto();
let approvals_by_id = self.approvals_by_id.as_mut().unwrap_or_else(|| {
env::panic_str("NFT does not support Approval Management");
});
let owner_id = expect_token_found(self.owner_by_id.get(&token_id));
let predecessor_account_id = env::predecessor_account_id();
require!(predecessor_account_id == owner_id, "Predecessor must be token owner.");
if let Some(approved_account_ids) = &mut approvals_by_id.get(&token_id) {
refund_approved_account_ids(predecessor_account_id, approved_account_ids);
approvals_by_id.remove(&token_id);
}
}
fn nft_is_approved(
&self,
token_id: TokenId,
approved_account_id: AccountId,
approval_id: Option<u64>,
) -> bool {
expect_token_found(self.owner_by_id.get(&token_id));
let approvals_by_id = if let Some(a) = self.approvals_by_id.as_ref() {
a
} else {
return false;
};
let approved_account_ids = if let Some(ids) = approvals_by_id.get(&token_id) {
ids
} else {
return false;
};
let actual_approval_id = if let Some(id) = approved_account_ids.get(&approved_account_id) {
id
} else {
return false;
};
if let Some(given_approval_id) = approval_id {
&given_approval_id == actual_approval_id
} else {
true
}
}
}