1use std::fmt::Debug;
2
3use cosmwasm_std::{
4 to_json_binary, Addr, Api, Binary, Coin, CosmosMsg, CustomMsg, Deps, DepsMut, Empty, Env,
5 MessageInfo, QuerierWrapper, Response, StdResult, Storage, WasmMsg, WasmQuery,
6};
7use cw_ownable::{Action, Ownership};
8use cw_utils::Expiration;
9use schemars::JsonSchema;
10use serde::{de::DeserializeOwned, Serialize};
11
12#[allow(deprecated)]
13use crate::{
14 error::Cw721ContractError,
15 execute::{
16 add_additional_minter, approve, approve_all, burn_nft, initialize_creator,
17 initialize_minter, instantiate, instantiate_with_version, migrate, mint,
18 remove_additional_minter, remove_withdraw_address, revoke, revoke_all, send_nft,
19 set_withdraw_address, transfer_nft, update_collection_info, update_creator_ownership,
20 update_minter_ownership, update_nft_info, withdraw_funds,
21 },
22 msg::{
23 AdditionalMintersResponse, AllNftInfoResponse, ApprovalResponse, ApprovalsResponse,
24 CollectionInfoAndExtensionResponse, CollectionInfoMsg, Cw721ExecuteMsg,
25 Cw721InstantiateMsg, Cw721MigrateMsg, Cw721QueryMsg, MinterResponse, NftInfoResponse,
26 NumTokensResponse, OperatorResponse, OperatorsResponse, OwnerOfResponse, TokensResponse,
27 },
28 query::{
29 query_additional_minters, query_all_nft_info, query_all_tokens, query_approval,
30 query_approvals, query_collection_extension_attributes, query_collection_info,
31 query_collection_info_and_extension, query_creator_ownership, query_minter,
32 query_minter_ownership, query_nft_info, query_num_tokens, query_operator, query_operators,
33 query_owner_of, query_tokens, query_withdraw_address,
34 },
35 state::CollectionInfo,
36 Attribute,
37};
38use crate::{
39 msg::{AllInfoResponse, ConfigResponse},
40 query::{query_all_info, query_config, query_nft_by_extension},
41 Approval,
42};
43
44pub trait Cw721CustomMsg: Serialize + Clone + Debug + PartialEq + JsonSchema {}
54
55pub trait Cw721State: Serialize + DeserializeOwned + Clone + Debug {}
56
57impl Cw721State for Empty {}
58impl<T> Cw721State for Option<T> where T: Cw721State {}
59
60impl Cw721CustomMsg for Empty {}
61impl<T> Cw721CustomMsg for Option<T> where T: Cw721CustomMsg {}
62
63pub trait Contains {
65 fn contains(&self, other: &Self) -> bool;
66}
67
68pub trait StateFactory<TState> {
69 fn create(
70 &self,
71 deps: Deps,
72 env: &Env,
73 info: Option<&MessageInfo>,
74 current: Option<&TState>,
75 ) -> Result<TState, Cw721ContractError>;
76 fn validate(
77 &self,
78 deps: Deps,
79 env: &Env,
80 info: Option<&MessageInfo>,
81 current: Option<&TState>,
82 ) -> Result<(), Cw721ContractError>;
83}
84
85impl StateFactory<Empty> for Empty {
86 fn create(
87 &self,
88 _deps: Deps,
89 _env: &Env,
90 _info: Option<&MessageInfo>,
91 _current: Option<&Empty>,
92 ) -> Result<Empty, Cw721ContractError> {
93 Ok(Empty {})
94 }
95
96 fn validate(
97 &self,
98 _deps: Deps,
99 _env: &Env,
100 _info: Option<&MessageInfo>,
101 _current: Option<&Empty>,
102 ) -> Result<(), Cw721ContractError> {
103 Ok(())
104 }
105}
106
107pub trait ToAttributesState {
108 fn to_attributes_state(&self) -> Result<Vec<Attribute>, Cw721ContractError>;
109}
110
111impl<T> ToAttributesState for Option<T>
112where
113 T: ToAttributesState,
114{
115 fn to_attributes_state(&self) -> Result<Vec<Attribute>, Cw721ContractError> {
116 match self {
117 Some(inner) => inner.to_attributes_state(),
118 None => Ok(vec![]),
119 }
120 }
121}
122
123pub trait FromAttributesState: Sized {
124 fn from_attributes_state(value: &[Attribute]) -> Result<Self, Cw721ContractError>;
125}
126
127impl<T> FromAttributesState for Option<T>
128where
129 T: FromAttributesState,
130{
131 fn from_attributes_state(value: &[Attribute]) -> Result<Self, Cw721ContractError> {
132 if value.is_empty() {
133 Ok(None)
134 } else {
135 T::from_attributes_state(value).map(Some)
136 }
137 }
138}
139
140pub trait Cw721Execute<
142 TNftExtension,
144 TNftExtensionMsg,
146 TCollectionExtension,
148 TCollectionExtensionMsg,
150 TExtensionMsg,
152 TCustomResponseMsg,
154> where
155 TNftExtension: Cw721State,
156 TNftExtensionMsg: Cw721CustomMsg + StateFactory<TNftExtension>,
157 TCollectionExtension: Cw721State + ToAttributesState + FromAttributesState,
158 TCollectionExtensionMsg: Cw721CustomMsg + StateFactory<TCollectionExtension>,
159 TCustomResponseMsg: CustomMsg,
160{
161 fn instantiate_with_version(
162 &self,
163 deps: DepsMut,
164 env: &Env,
165 info: &MessageInfo,
166 msg: Cw721InstantiateMsg<TCollectionExtensionMsg>,
167 contract_name: &str,
168 contract_version: &str,
169 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
170 instantiate_with_version(deps, env, info, msg, contract_name, contract_version)
171 }
172
173 fn instantiate(
174 &self,
175 deps: DepsMut,
176 env: &Env,
177 info: &MessageInfo,
178 msg: Cw721InstantiateMsg<TCollectionExtensionMsg>,
179 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
180 instantiate(deps, env, info, msg)
181 }
182
183 fn execute(
184 &self,
185 deps: DepsMut,
186 env: &Env,
187 info: &MessageInfo,
188 msg: Cw721ExecuteMsg<TNftExtensionMsg, TCollectionExtensionMsg, TExtensionMsg>,
189 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
190 match msg {
191 Cw721ExecuteMsg::UpdateCollectionInfo { collection_info } => {
192 self.update_collection_info(deps, info.into(), env, collection_info)
193 }
194 Cw721ExecuteMsg::Mint {
195 token_id,
196 owner,
197 token_uri,
198 extension,
199 } => self.mint(deps, env, info, token_id, owner, token_uri, extension),
200 Cw721ExecuteMsg::Approve {
201 spender,
202 token_id,
203 expires,
204 } => self.approve(deps, env, info, spender, token_id, expires),
205 Cw721ExecuteMsg::Revoke { spender, token_id } => {
206 self.revoke(deps, env, info, spender, token_id)
207 }
208 Cw721ExecuteMsg::ApproveAll { operator, expires } => {
209 self.approve_all(deps, env, info, operator, expires)
210 }
211 Cw721ExecuteMsg::RevokeAll { operator } => self.revoke_all(deps, env, info, operator),
212 Cw721ExecuteMsg::TransferNft {
213 recipient,
214 token_id,
215 } => self.transfer_nft(deps, env, info, recipient, token_id),
216 Cw721ExecuteMsg::SendNft {
217 contract,
218 token_id,
219 msg,
220 } => self.send_nft(deps, env, info, contract, token_id, msg),
221 Cw721ExecuteMsg::Burn { token_id } => self.burn_nft(deps, env, info, token_id),
222 Cw721ExecuteMsg::AddMinter { minter } => self.add_additional_minter(deps, info, minter),
223 Cw721ExecuteMsg::RemoveMinter { minter } => {
224 self.remove_additional_minter(deps, info, minter)
225 }
226 #[allow(deprecated)]
227 Cw721ExecuteMsg::UpdateOwnership(action) => {
228 self.update_minter_ownership(deps, env, info, action)
229 }
230 Cw721ExecuteMsg::UpdateMinterOwnership(action) => {
231 self.update_minter_ownership(deps, env, info, action)
232 }
233 Cw721ExecuteMsg::UpdateCreatorOwnership(action) => {
234 self.update_creator_ownership(deps, env, info, action)
235 }
236 #[allow(deprecated)]
237 Cw721ExecuteMsg::UpdateExtension { msg } => {
238 self.execute_extension(deps, env, info, msg)
239 }
240 Cw721ExecuteMsg::UpdateNftInfo {
241 token_id,
242 token_uri,
243 extension,
244 } => self.update_nft_info(deps, env, info, token_id, token_uri, extension),
245 Cw721ExecuteMsg::SetWithdrawAddress { address } => {
246 self.set_withdraw_address(deps, &info.sender, address)
247 }
248 Cw721ExecuteMsg::RemoveWithdrawAddress {} => {
249 self.remove_withdraw_address(deps.storage, &info.sender)
250 }
251 Cw721ExecuteMsg::WithdrawFunds { amount } => self.withdraw_funds(deps.storage, &amount),
252 }
253 }
254
255 fn migrate(
256 &self,
257 deps: DepsMut,
258 env: Env,
259 msg: Cw721MigrateMsg,
260 contract_name: &str,
261 contract_version: &str,
262 ) -> Result<Response, Cw721ContractError> {
263 migrate(deps, env, msg, contract_name, contract_version)
264 }
265
266 fn transfer_nft(
268 &self,
269 deps: DepsMut,
270 env: &Env,
271 info: &MessageInfo,
272 recipient: String,
273 token_id: String,
274 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
275 transfer_nft::<TNftExtension>(deps, env, info, &recipient, &token_id)?;
276
277 Ok(Response::new()
278 .add_attribute("action", "transfer_nft")
279 .add_attribute("sender", info.sender.to_string())
280 .add_attribute("recipient", recipient)
281 .add_attribute("token_id", token_id))
282 }
283
284 fn send_nft(
285 &self,
286 deps: DepsMut,
287 env: &Env,
288 info: &MessageInfo,
289 contract: String,
290 token_id: String,
291 msg: Binary,
292 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
293 send_nft::<TNftExtension, TCustomResponseMsg>(deps, env, info, contract, token_id, msg)
294 }
295
296 fn approve(
297 &self,
298 deps: DepsMut,
299 env: &Env,
300 info: &MessageInfo,
301 spender: String,
302 token_id: String,
303 expires: Option<Expiration>,
304 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
305 approve::<TNftExtension, TCustomResponseMsg>(deps, env, info, spender, token_id, expires)
306 }
307
308 fn revoke(
309 &self,
310 deps: DepsMut,
311 env: &Env,
312 info: &MessageInfo,
313 spender: String,
314 token_id: String,
315 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
316 revoke::<TNftExtension, TCustomResponseMsg>(deps, env, info, spender, token_id)
317 }
318
319 fn approve_all(
320 &self,
321 deps: DepsMut,
322 env: &Env,
323 info: &MessageInfo,
324 operator: String,
325 expires: Option<Expiration>,
326 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
327 approve_all::<TCustomResponseMsg>(deps, env, info, operator, expires)
328 }
329
330 fn revoke_all(
331 &self,
332 deps: DepsMut,
333 _env: &Env,
334 info: &MessageInfo,
335 operator: String,
336 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
337 revoke_all::<TCustomResponseMsg>(deps, _env, info, operator)
338 }
339
340 fn burn_nft(
341 &self,
342 deps: DepsMut,
343 env: &Env,
344 info: &MessageInfo,
345 token_id: String,
346 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
347 burn_nft::<TCustomResponseMsg>(deps, env, info, token_id)
348 }
349
350 fn add_additional_minter(
351 &self,
352 deps: DepsMut,
353 info: &MessageInfo,
354 minter: String,
355 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
356 add_additional_minter::<TCustomResponseMsg>(deps, info, minter)
357 }
358
359 fn remove_additional_minter(
360 &self,
361 deps: DepsMut,
362 info: &MessageInfo,
363 minter: String,
364 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
365 remove_additional_minter::<TCustomResponseMsg>(deps, info, minter)
366 }
367
368 fn initialize_creator(
370 &self,
371 storage: &mut dyn Storage,
372 api: &dyn Api,
373 creator: Option<&str>,
374 ) -> StdResult<Ownership<Addr>> {
375 initialize_creator(storage, api, creator)
376 }
377
378 fn initialize_minter(
379 &self,
380 storage: &mut dyn Storage,
381 api: &dyn Api,
382 minter: Option<&str>,
383 ) -> StdResult<Ownership<Addr>> {
384 initialize_minter(storage, api, minter)
385 }
386
387 fn update_collection_info(
388 &self,
389 deps: DepsMut,
390 info: Option<&MessageInfo>,
391 env: &Env,
392 msg: CollectionInfoMsg<TCollectionExtensionMsg>,
393 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
394 update_collection_info::<TCollectionExtension, TCollectionExtensionMsg, TCustomResponseMsg>(
395 deps, info, env, msg,
396 )
397 }
398
399 #[allow(clippy::too_many_arguments)]
400 fn mint(
401 &self,
402 deps: DepsMut,
403 env: &Env,
404 info: &MessageInfo,
405 token_id: String,
406 owner: String,
407 token_uri: Option<String>,
408 extension: TNftExtensionMsg,
409 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
410 mint::<TNftExtension, TNftExtensionMsg, TCustomResponseMsg>(
411 deps, env, info, token_id, owner, token_uri, extension,
412 )
413 }
414
415 fn update_minter_ownership(
416 &self,
417 deps: DepsMut,
418 env: &Env,
419 info: &MessageInfo,
420 action: Action,
421 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
422 update_minter_ownership::<TCustomResponseMsg>(deps, env, info, action)
423 }
424
425 fn update_creator_ownership(
426 &self,
427 deps: DepsMut,
428 env: &Env,
429 info: &MessageInfo,
430 action: Action,
431 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
432 update_creator_ownership::<TCustomResponseMsg>(deps, env, info, action)
433 }
434
435 fn execute_extension(
437 &self,
438 _deps: DepsMut,
439 _env: &Env,
440 _info: &MessageInfo,
441 _msg: TExtensionMsg,
442 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
443 Ok(Response::default())
444 }
445
446 fn update_nft_info(
449 &self,
450 deps: DepsMut,
451 env: &Env,
452 info: &MessageInfo,
453 token_id: String,
454 token_uri: Option<String>,
455 msg: TNftExtensionMsg,
456 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
457 update_nft_info::<TNftExtension, TNftExtensionMsg, TCustomResponseMsg>(
458 deps,
459 env,
460 info.into(),
461 token_id,
462 token_uri,
463 msg,
464 )
465 }
466
467 fn set_withdraw_address(
468 &self,
469 deps: DepsMut,
470 sender: &Addr,
471 address: String,
472 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
473 set_withdraw_address::<TCustomResponseMsg>(deps, sender, address)
474 }
475
476 fn remove_withdraw_address(
477 &self,
478 storage: &mut dyn Storage,
479 sender: &Addr,
480 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
481 remove_withdraw_address::<TCustomResponseMsg>(storage, sender)
482 }
483
484 fn withdraw_funds(
485 &self,
486 storage: &mut dyn Storage,
487 amount: &Coin,
488 ) -> Result<Response<TCustomResponseMsg>, Cw721ContractError> {
489 withdraw_funds::<TCustomResponseMsg>(storage, amount)
490 }
491}
492
493pub trait Cw721Query<
495 TNftExtension,
497 TCollectionExtension,
499 TExtensionQueryMsg,
501> where
502 TNftExtension: Cw721State + Contains,
503 TCollectionExtension: Cw721State + FromAttributesState,
504 TExtensionQueryMsg: Cw721CustomMsg,
505{
506 fn query(
507 &self,
508 deps: Deps,
509 env: &Env,
510 msg: Cw721QueryMsg<TNftExtension, TCollectionExtension, TExtensionQueryMsg>,
511 ) -> Result<Binary, Cw721ContractError> {
512 match msg {
513 #[allow(deprecated)]
514 Cw721QueryMsg::Minter {} => Ok(to_json_binary(&self.query_minter(deps.storage)?)?),
515 #[allow(deprecated)]
516 Cw721QueryMsg::ContractInfo {} => Ok(to_json_binary(
517 &self.query_collection_info_and_extension(deps)?,
518 )?),
519 Cw721QueryMsg::GetConfig {} => Ok(to_json_binary(
520 &self.query_all_collection_info(deps, env.contract.address.to_string())?,
521 )?),
522 Cw721QueryMsg::GetCollectionInfoAndExtension {} => Ok(to_json_binary(
523 &self.query_collection_info_and_extension(deps)?,
524 )?),
525 Cw721QueryMsg::GetAllInfo {} => Ok(to_json_binary(&self.query_all_info(deps, env)?)?),
526 Cw721QueryMsg::GetCollectionExtensionAttributes {} => Ok(to_json_binary(
527 &self.query_collection_extension_attributes(deps)?,
528 )?),
529 Cw721QueryMsg::NftInfo { token_id } => Ok(to_json_binary(
530 &self.query_nft_info(deps.storage, token_id)?,
531 )?),
532 Cw721QueryMsg::GetNftByExtension {
533 extension,
534 start_after,
535 limit,
536 } => Ok(to_json_binary(&self.query_nft_by_extension(
537 deps.storage,
538 extension,
539 start_after,
540 limit,
541 )?)?),
542 Cw721QueryMsg::OwnerOf {
543 token_id,
544 include_expired,
545 } => Ok(to_json_binary(&self.query_owner_of(
546 deps,
547 env,
548 token_id,
549 include_expired.unwrap_or(false),
550 )?)?),
551 Cw721QueryMsg::AllNftInfo {
552 token_id,
553 include_expired,
554 } => Ok(to_json_binary(&self.query_all_nft_info(
555 deps,
556 env,
557 token_id,
558 include_expired.unwrap_or(false),
559 )?)?),
560 Cw721QueryMsg::Operator {
561 owner,
562 operator,
563 include_expired,
564 } => Ok(to_json_binary(&self.query_operator(
565 deps,
566 env,
567 owner,
568 operator,
569 include_expired.unwrap_or(false),
570 )?)?),
571 Cw721QueryMsg::AllOperators {
572 owner,
573 include_expired,
574 start_after,
575 limit,
576 } => Ok(to_json_binary(&self.query_operators(
577 deps,
578 env,
579 owner,
580 include_expired.unwrap_or(false),
581 start_after,
582 limit,
583 )?)?),
584 Cw721QueryMsg::NumTokens {} => {
585 Ok(to_json_binary(&self.query_num_tokens(deps.storage)?)?)
586 }
587 Cw721QueryMsg::Tokens {
588 owner,
589 start_after,
590 limit,
591 } => Ok(to_json_binary(&self.query_tokens(
592 deps,
593 env,
594 owner,
595 start_after,
596 limit,
597 )?)?),
598 Cw721QueryMsg::AllTokens { start_after, limit } => Ok(to_json_binary(
599 &self.query_all_tokens(deps, env, start_after, limit)?,
600 )?),
601 Cw721QueryMsg::Approval {
602 token_id,
603 spender,
604 include_expired,
605 } => Ok(to_json_binary(&self.query_approval(
606 deps,
607 env,
608 token_id,
609 spender,
610 include_expired.unwrap_or(false),
611 )?)?),
612 Cw721QueryMsg::Approvals {
613 token_id,
614 include_expired,
615 } => Ok(to_json_binary(&self.query_approvals(
616 deps,
617 env,
618 token_id,
619 include_expired.unwrap_or(false),
620 )?)?),
621 #[allow(deprecated)]
622 Cw721QueryMsg::Ownership {} => {
623 Ok(to_json_binary(&self.query_minter_ownership(deps.storage)?)?)
624 }
625 Cw721QueryMsg::GetMinterOwnership {} => {
626 Ok(to_json_binary(&self.query_minter_ownership(deps.storage)?)?)
627 }
628 Cw721QueryMsg::GetCreatorOwnership {} => Ok(to_json_binary(
629 &self.query_creator_ownership(deps.storage)?,
630 )?),
631 Cw721QueryMsg::GetAdditionalMinters { start_after, limit } => Ok(to_json_binary(
632 &self.query_additional_minters(deps, start_after, limit)?,
633 )?),
634 Cw721QueryMsg::Extension { msg } => self.query_extension(deps, env, msg),
635 Cw721QueryMsg::GetCollectionExtension { msg } => {
636 self.query_custom_collection_extension(deps, env, msg)
637 }
638 Cw721QueryMsg::GetWithdrawAddress {} => {
639 Ok(to_json_binary(&self.query_withdraw_address(deps)?)?)
640 }
641 }
642 }
643
644 #[deprecated(since = "0.19.0", note = "Please use query_minter_ownership instead")]
645 fn query_minter(&self, storage: &dyn Storage) -> StdResult<MinterResponse> {
647 #[allow(deprecated)]
648 query_minter(storage)
649 }
650
651 fn query_minter_ownership(&self, storage: &dyn Storage) -> StdResult<Ownership<Addr>> {
652 query_minter_ownership(storage)
653 }
654
655 fn query_creator_ownership(&self, storage: &dyn Storage) -> StdResult<Ownership<Addr>> {
656 query_creator_ownership(storage)
657 }
658
659 fn query_additional_minters(
660 &self,
661 deps: Deps,
662 start_after: Option<String>,
663 limit: Option<u32>,
664 ) -> StdResult<AdditionalMintersResponse> {
665 query_additional_minters(deps, start_after, limit)
666 }
667
668 fn query_collection_info(&self, deps: Deps) -> StdResult<CollectionInfo> {
669 query_collection_info(deps.storage)
670 }
671
672 fn query_collection_extension_attributes(&self, deps: Deps) -> StdResult<Vec<Attribute>> {
673 query_collection_extension_attributes(deps)
674 }
675
676 fn query_all_collection_info(
677 &self,
678 deps: Deps,
679 contract_addr: impl Into<String>,
680 ) -> Result<ConfigResponse<TCollectionExtension>, Cw721ContractError>
681 where
682 TCollectionExtension: FromAttributesState,
683 {
684 query_config(deps, contract_addr)
685 }
686
687 fn query_collection_info_and_extension(
688 &self,
689 deps: Deps,
690 ) -> Result<CollectionInfoAndExtensionResponse<TCollectionExtension>, Cw721ContractError>
691 where
692 TCollectionExtension: FromAttributesState,
693 {
694 query_collection_info_and_extension(deps)
695 }
696
697 fn query_all_info(&self, deps: Deps, env: &Env) -> StdResult<AllInfoResponse> {
698 query_all_info(deps, env)
699 }
700
701 fn query_num_tokens(&self, storage: &dyn Storage) -> StdResult<NumTokensResponse> {
702 query_num_tokens(storage)
703 }
704
705 fn query_nft_info(
706 &self,
707 storage: &dyn Storage,
708 token_id: String,
709 ) -> StdResult<NftInfoResponse<TNftExtension>> {
710 query_nft_info::<TNftExtension>(storage, token_id)
711 }
712
713 fn query_nft_by_extension(
714 &self,
715 storage: &dyn Storage,
716 extension: TNftExtension,
717 start_after: Option<String>,
718 limit: Option<u32>,
719 ) -> StdResult<Option<Vec<NftInfoResponse<TNftExtension>>>> {
720 query_nft_by_extension::<TNftExtension>(storage, extension, start_after, limit)
721 }
722
723 fn query_owner_of(
724 &self,
725 deps: Deps,
726 env: &Env,
727 token_id: String,
728 include_expired_approval: bool,
729 ) -> StdResult<OwnerOfResponse> {
730 query_owner_of(deps, env, token_id, include_expired_approval)
731 }
732
733 fn query_operator(
735 &self,
736 deps: Deps,
737 env: &Env,
738 owner: String,
739 operator: String,
740 include_expired_approval: bool,
741 ) -> StdResult<OperatorResponse> {
742 query_operator(deps, env, owner, operator, include_expired_approval)
743 }
744
745 fn query_operators(
747 &self,
748 deps: Deps,
749 env: &Env,
750 owner: String,
751 include_expired_approval: bool,
752 start_after: Option<String>,
753 limit: Option<u32>,
754 ) -> StdResult<OperatorsResponse> {
755 query_operators(
756 deps,
757 env,
758 owner,
759 include_expired_approval,
760 start_after,
761 limit,
762 )
763 }
764
765 fn query_approval(
766 &self,
767 deps: Deps,
768 env: &Env,
769 token_id: String,
770 spender: String,
771 include_expired_approval: bool,
772 ) -> StdResult<ApprovalResponse> {
773 query_approval(
774 deps,
775 env,
776 token_id,
777 deps.api.addr_validate(&spender)?,
778 include_expired_approval,
779 )
780 }
781
782 fn query_approvals(
784 &self,
785 deps: Deps,
786 env: &Env,
787 token_id: String,
788 include_expired_approval: bool,
789 ) -> StdResult<ApprovalsResponse> {
790 query_approvals(deps, env, token_id, include_expired_approval)
791 }
792
793 fn query_tokens(
794 &self,
795 deps: Deps,
796 _env: &Env,
797 owner: String,
798 start_after: Option<String>,
799 limit: Option<u32>,
800 ) -> StdResult<TokensResponse> {
801 query_tokens(deps, _env, owner, start_after, limit)
802 }
803
804 fn query_all_tokens(
805 &self,
806 deps: Deps,
807 _env: &Env,
808 start_after: Option<String>,
809 limit: Option<u32>,
810 ) -> StdResult<TokensResponse> {
811 query_all_tokens(deps, _env, start_after, limit)
812 }
813
814 fn query_all_nft_info(
815 &self,
816 deps: Deps,
817 env: &Env,
818 token_id: String,
819 include_expired_approval: bool,
820 ) -> StdResult<AllNftInfoResponse<TNftExtension>> {
821 query_all_nft_info::<TNftExtension>(deps, env, token_id, include_expired_approval)
822 }
823
824 fn query_extension(
826 &self,
827 _deps: Deps,
828 _env: &Env,
829 _msg: TExtensionQueryMsg,
830 ) -> Result<Binary, Cw721ContractError> {
831 Ok(Binary::default())
832 }
833
834 fn query_custom_collection_extension(
839 &self,
840 _deps: Deps,
841 _env: &Env,
842 _msg: TCollectionExtension,
843 ) -> Result<Binary, Cw721ContractError> {
844 Ok(Binary::default())
845 }
846
847 fn query_withdraw_address(&self, deps: Deps) -> StdResult<Option<String>> {
848 query_withdraw_address(deps)
849 }
850}
851
852pub trait Cw721Calls<
854 TNftExtension,
855 TNftExtensionMsg,
856 TCollectionExtension,
857 TCollectionExtensionMsg,
858 TExtensionMsg,
859 TExtensionQueryMsg,
860> where
861 TNftExtensionMsg: Cw721CustomMsg,
862 TNftExtension: Cw721State,
863 TCollectionExtension: Cw721State,
864 TCollectionExtensionMsg: Cw721CustomMsg,
865 TExtensionMsg: Cw721CustomMsg,
866 TExtensionQueryMsg: Cw721CustomMsg,
867{
868 fn addr(&self) -> Addr;
870
871 fn call(
873 &self,
874 msg: Cw721ExecuteMsg<TNftExtensionMsg, TCollectionExtensionMsg, TExtensionMsg>,
875 ) -> StdResult<CosmosMsg> {
876 let msg = to_json_binary(&msg)?;
877 Ok(WasmMsg::Execute {
878 contract_addr: self.addr().into(),
879 msg,
880 funds: vec![],
881 }
882 .into())
883 }
884
885 fn query<T: DeserializeOwned>(
887 &self,
888 querier: &QuerierWrapper,
889 req: Cw721QueryMsg<TNftExtension, TCollectionExtension, TExtensionQueryMsg>,
890 ) -> StdResult<T> {
891 let query = WasmQuery::Smart {
892 contract_addr: self.addr().into(),
893 msg: to_json_binary(&req)?,
894 }
895 .into();
896 querier.query(&query)
897 }
898
899 fn owner_of<T: Into<String>>(
901 &self,
902 querier: &QuerierWrapper,
903 token_id: T,
904 include_expired: bool,
905 ) -> StdResult<OwnerOfResponse> {
906 let req = Cw721QueryMsg::OwnerOf {
907 token_id: token_id.into(),
908 include_expired: Some(include_expired),
909 };
910 self.query(querier, req)
911 }
912
913 fn approval<T: Into<String>>(
914 &self,
915 querier: &QuerierWrapper,
916 token_id: T,
917 spender: T,
918 include_expired: Option<bool>,
919 ) -> StdResult<ApprovalResponse> {
920 let req = Cw721QueryMsg::Approval {
921 token_id: token_id.into(),
922 spender: spender.into(),
923 include_expired,
924 };
925 let res: ApprovalResponse = self.query(querier, req)?;
926 Ok(res)
927 }
928
929 fn approvals<T: Into<String>>(
930 &self,
931 querier: &QuerierWrapper,
932 token_id: T,
933 include_expired: Option<bool>,
934 ) -> StdResult<ApprovalsResponse> {
935 let req = Cw721QueryMsg::Approvals {
936 token_id: token_id.into(),
937 include_expired,
938 };
939 let res: ApprovalsResponse = self.query(querier, req)?;
940 Ok(res)
941 }
942
943 fn all_operators<T: Into<String>>(
944 &self,
945 querier: &QuerierWrapper,
946 owner: T,
947 include_expired: bool,
948 start_after: Option<String>,
949 limit: Option<u32>,
950 ) -> StdResult<Vec<Approval>> {
951 let req = Cw721QueryMsg::AllOperators {
952 owner: owner.into(),
953 include_expired: Some(include_expired),
954 start_after,
955 limit,
956 };
957 let res: OperatorsResponse = self.query(querier, req)?;
958 Ok(res.operators)
959 }
960
961 fn num_tokens(&self, querier: &QuerierWrapper) -> StdResult<u64> {
962 let req = Cw721QueryMsg::NumTokens {};
963 let res: NumTokensResponse = self.query(querier, req)?;
964 Ok(res.count)
965 }
966
967 fn config<U: DeserializeOwned>(
969 &self,
970 querier: &QuerierWrapper,
971 ) -> StdResult<ConfigResponse<U>> {
972 let req = Cw721QueryMsg::GetConfig {};
973 self.query(querier, req)
974 }
975
976 fn collection_info<U: DeserializeOwned>(
978 &self,
979 querier: &QuerierWrapper,
980 ) -> StdResult<CollectionInfoAndExtensionResponse<U>> {
981 let req = Cw721QueryMsg::GetCollectionInfoAndExtension {};
982 self.query(querier, req)
983 }
984
985 fn nft_info<T: Into<String>, U: DeserializeOwned>(
987 &self,
988 querier: &QuerierWrapper,
989 token_id: T,
990 ) -> StdResult<NftInfoResponse<U>> {
991 let req = Cw721QueryMsg::NftInfo {
992 token_id: token_id.into(),
993 };
994 self.query(querier, req)
995 }
996
997 fn all_nft_info<T: Into<String>, U: DeserializeOwned>(
999 &self,
1000 querier: &QuerierWrapper,
1001 token_id: T,
1002 include_expired: bool,
1003 ) -> StdResult<AllNftInfoResponse<U>> {
1004 let req = Cw721QueryMsg::AllNftInfo {
1005 token_id: token_id.into(),
1006 include_expired: Some(include_expired),
1007 };
1008 self.query(querier, req)
1009 }
1010
1011 fn tokens<T: Into<String>>(
1013 &self,
1014 querier: &QuerierWrapper,
1015 owner: T,
1016 start_after: Option<String>,
1017 limit: Option<u32>,
1018 ) -> StdResult<TokensResponse> {
1019 let req = Cw721QueryMsg::Tokens {
1020 owner: owner.into(),
1021 start_after,
1022 limit,
1023 };
1024 self.query(querier, req)
1025 }
1026
1027 fn all_tokens(
1029 &self,
1030 querier: &QuerierWrapper,
1031 start_after: Option<String>,
1032 limit: Option<u32>,
1033 ) -> StdResult<TokensResponse> {
1034 let req = Cw721QueryMsg::AllTokens { start_after, limit };
1035 self.query(querier, req)
1036 }
1037
1038 fn has_metadata(&self, querier: &QuerierWrapper) -> bool {
1040 self.collection_info::<Empty>(querier).is_ok()
1041 }
1042
1043 fn has_enumerable(&self, querier: &QuerierWrapper) -> bool {
1045 self.tokens(querier, self.addr(), None, Some(1)).is_ok()
1046 }
1047}