1use schemars::JsonSchema;
2use serde::de::DeserializeOwned;
3use serde::{Deserialize, Serialize};
4use std::marker::PhantomData;
5
6use cosmwasm_std::{Addr, BlockInfo, Decimal, StdResult, Storage};
7use cw721::Expiration;
8
9use cw_storage_plus::{Index, IndexList, IndexedMap, Item, Map, MultiIndex};
10
11use crate::msg::{ContractInfoResponse};
12
13pub struct AnoneCw721Contract<'a, T, C>
14where
15 T: Serialize + DeserializeOwned + Clone,
16{
17 pub contract_info: Item<'a, ContractInfoResponse>,
18 pub minter: Item<'a, Addr>,
19 pub token_count: Item<'a, u64>,
20 pub model_count: Item<'a, u64>,
21 pub operators: Map<'a, (&'a Addr, &'a Addr), Expiration>,
23 pub tokens: IndexedMap<'a, &'a str, TokenInfo<T>, TokenIndexes<'a, T>>,
24 pub models: IndexedMap<'a, &'a str, ModelInfo<T>, ModelIndexes<'a, T>>,
25
26 pub(crate) _custom_response: PhantomData<C>,
27}
28
29impl<T, C> Default for AnoneCw721Contract<'static, T, C>
30where
31 T: Serialize + DeserializeOwned + Clone,
32{
33 fn default() -> Self {
34 Self::new(
35 "nft_info",
36 "minter",
37 "num_tokens",
38 "num_models",
39 "operators",
40 "tokens",
41 "tokens__owner",
42 "models",
43 "models_owner",
44 )
45 }
46}
47
48impl<'a, T, C> AnoneCw721Contract<'a, T, C>
49where
50 T: Serialize + DeserializeOwned + Clone,
51{
52 fn new(
53 contract_key: &'a str,
54 minter_key: &'a str,
55 token_count_key: &'a str,
56 model_count_key: &'a str,
57 operator_key: &'a str,
58 tokens_key: &'a str,
59 tokens_owner_key: &'a str,
60 models_key: &'a str,
61 models_owner_key: &'a str,
62 ) -> Self {
63 let indexes = TokenIndexes {
64 owner: MultiIndex::new(token_owner_idx, tokens_key, tokens_owner_key),
65 };
66 let model_indexes = ModelIndexes {
67 owner: MultiIndex::new(model_owner_idx, models_key, models_owner_key),
68 };
69 Self {
70 contract_info: Item::new(contract_key),
71 minter: Item::new(minter_key),
72 token_count: Item::new(token_count_key),
73 model_count: Item::new(model_count_key),
74 operators: Map::new(operator_key),
75 tokens: IndexedMap::new(tokens_key, indexes),
76 models: IndexedMap::new(models_key, model_indexes),
77 _custom_response: PhantomData,
78 }
79 }
80
81 pub fn token_count(&self, storage: &dyn Storage) -> StdResult<u64> {
82 Ok(self.token_count.may_load(storage)?.unwrap_or_default())
83 }
84
85 pub fn model_count(&self, storage: &dyn Storage) -> StdResult<u64> {
86 Ok(self.model_count.may_load(storage)?.unwrap_or_default())
87 }
88
89 pub fn increment_tokens(&self, storage: &mut dyn Storage) -> StdResult<u64> {
90 let val = self.token_count(storage)? + 1;
91 self.token_count.save(storage, &val)?;
92 Ok(val)
93 }
94
95 pub fn decrement_tokens(&self, storage: &mut dyn Storage) -> StdResult<u64> {
96 let val = self.token_count(storage)? - 1;
97 self.token_count.save(storage, &val)?;
98 Ok(val)
99 }
100
101 pub fn increment_models(&self, storage: &mut dyn Storage) -> StdResult<u64> {
102 let val = self.model_count(storage)? + 1;
103 self.model_count.save(storage, &val)?;
104 Ok(val)
105 }
106
107 pub fn decrement_models(&self, storage: &mut dyn Storage) -> StdResult<u64> {
108 let val = self.model_count(storage)? - 1;
109 self.model_count.save(storage, &val)?;
110 Ok(val)
111 }
112}
113
114#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
115pub struct CollectionInfo<T> {
116 pub creator: String,
117 pub description: String,
118 pub image: String,
119 pub external_link: Option<String>,
120 pub royalty_info: Option<T>,
121}
122
123#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
124pub struct RoyaltyInfo {
125 pub payment_address: Addr,
126 pub share: Decimal,
127}
128
129#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
130pub struct TokenInfo<T> {
131 pub token_id: String,
133
134 pub owner: Addr,
136
137 pub approvals: Vec<Approval>,
139
140 pub model_id: String,
142
143 pub token_uri: String,
145
146 pub size: String,
148
149 pub extension: T,
151}
152
153#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
154pub struct ModelInfo<T> {
155 pub model_id: String,
157
158 pub owner: Addr,
160
161 pub model_uri: String,
162
163 pub extension: T,
164}
165
166#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
167pub struct Approval {
168 pub spender: Addr,
170 pub expires: Expiration,
172}
173
174impl Approval {
175 pub fn is_expired(&self, block: &BlockInfo) -> bool {
176 self.expires.is_expired(block)
177 }
178}
179
180pub struct TokenIndexes<'a, T>
181where
182 T: Serialize + DeserializeOwned + Clone,
183{
184 pub owner: MultiIndex<'a, Addr, TokenInfo<T>, Addr>,
185}
186
187impl<'a, T> IndexList<TokenInfo<T>> for TokenIndexes<'a, T>
188where
189 T: Serialize + DeserializeOwned + Clone,
190{
191 fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<TokenInfo<T>>> + '_> {
192 let v: Vec<&dyn Index<TokenInfo<T>>> = vec![&self.owner];
193 Box::new(v.into_iter())
194 }
195}
196
197pub fn token_owner_idx<T>(d: &TokenInfo<T>) -> Addr {
198 d.owner.clone()
199}
200
201pub struct ModelIndexes<'a, T>
202where
203 T: Serialize + DeserializeOwned + Clone,
204{
205 pub owner: MultiIndex<'a, Addr, ModelInfo<T>, Addr>,
206}
207
208impl<'a, T> IndexList<ModelInfo<T>> for ModelIndexes<'a, T>
209where
210 T: Serialize + DeserializeOwned + Clone,
211{
212 fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<ModelInfo<T>>> + '_> {
213 let v: Vec<&dyn Index<ModelInfo<T>>> = vec![&self.owner];
214 Box::new(v.into_iter())
215 }
216}
217
218pub fn model_owner_idx<T>(d: &ModelInfo<T>) -> Addr {
219 d.owner.clone()
220}
221
222pub const COLLECTION_INFO: Item<CollectionInfo<RoyaltyInfo>> = Item::new("collection_info");