1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
use cosmwasm_std::{Addr, Binary, BlockInfo};
use cw0::Expiration;
use cw_storage_plus::{Index, IndexList, MultiIndex};
use schemars::JsonSchema;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
pub base_node: String,
pub base_name: String,
pub registry_address: String,
pub grace_period: Option<u64>,
/// Name of the NFT contract
pub name: String,
/// Symbol of the NFT contract
pub symbol: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
IsAvailable {
id: String,
},
GetExpires {
id: String,
},
GetBaseNode {},
GetRegistry {},
GetGracePeriod {},
GetConfig {},
Minter {},
/// Return the owner of the given token, error if token does not exist
/// Return type: OwnerOfResponse
OwnerOf {
token_id: String,
/// unset or false will filter out expired approvals, you must set to true to see them
include_expired: Option<bool>,
},
/// List all operators that can access all of the owner's tokens.
/// Return type: `ApprovedForAllResponse`
ApprovedForAll {
owner: String,
/// unset or false will filter out expired approvals, you must set to true to see them
include_expired: Option<bool>,
start_after: Option<String>,
limit: Option<u32>,
},
/// Total number of tokens issued
NumTokens {},
/// With MetaData Extension.
/// Returns top-level metadata about the contract: `ContractInfoResponse`
ContractInfo {},
/// With MetaData Extension.
/// Returns metadata about one particular token, based on *ERC721 Metadata JSON Schema*
/// but directly from the contract: `NftInfoResponse`
NftInfo {
token_id: String,
},
/// With MetaData Extension.
/// Returns the result of both `NftInfo` and `OwnerOf` as one query as an optimization
/// for clients: `AllNftInfo`
AllNftInfo {
token_id: String,
/// unset or false will filter out expired approvals, you must set to true to see them
include_expired: Option<bool>,
},
/// With Enumerable extension.
/// Returns all tokens owned by the given address, [] if unset.
/// Return type: TokensResponse.
Tokens {
owner: String,
start_after: Option<String>,
limit: Option<u32>,
},
/// With Enumerable extension.
/// Requires pagination. Lists all token_ids controlled by the contract.
/// Return type: TokensResponse.
AllTokens {
start_after: Option<String>,
limit: Option<u32>,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg<T> {
Register {
id: String,
owner: String,
duration: u64,
name: String
},
AddController {
address: String,
},
RemoveController {
address: String,
},
SetConfig {
grace_period: u64,
registry_address: String,
owner: String
},
Renew {
id: String,
duration: u64,
},
Reclaim {
id: String,
owner: String,
},
/// Transfer is a base message to move a token to another account without triggering actions
TransferNft {
recipient: String,
token_id: String,
},
/// Send is a base message to transfer a token to a contract and trigger an action
/// on the receiving contract.
SendNft {
contract: String,
token_id: String,
msg: Binary,
},
/// Allows operator to transfer / send the token from the owner's account.
/// If expiration is set, then this allowance has a time/height limit
Approve {
spender: String,
token_id: String,
expires: Option<Expiration>,
},
/// Remove previously granted Approval
Revoke {
spender: String,
token_id: String,
},
/// Allows operator to transfer / send any token from the owner's account.
/// If expiration is set, then this allowance has a time/height limit
ApproveAll {
operator: String,
expires: Option<Expiration>,
},
/// Remove previously granted ApproveAll permission
RevokeAll {
operator: String,
},
/// Mint a new NFT, can only be called by the contract minter
Mint(MintMsg<T>),
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct IsAvailableResponse {
pub available: bool,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct GetExpiresResponse {
pub expires: u64,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct GetBaseNodeResponse {
pub base_node: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct GetRegistryResponse {
pub registry: Addr,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct GetGracePeriodResponse {
pub grace_period: u64,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct ConfigResponse {
pub grace_period: u64,
pub registry_address: Addr,
pub owner: Addr,
pub base_node: Vec<u8>,
pub base_name: String,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct OwnerOfResponse {
/// Owner of the token
pub owner: String,
/// If set this address is approved to transfer/send the token as well
pub approvals: Vec<Approval>,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct Approval {
/// Account that can transfer/send the token
pub spender: String,
/// When the Approval expires (maybe Expiration::never)
pub expires: Expiration,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct ApprovedForAllResponse {
pub operators: Vec<Approval>,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct NumTokensResponse {
pub count: u64,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct ContractInfoResponse {
pub name: String,
pub symbol: String,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct NftInfoResponse<T> {
/// Identifies the asset to which this NFT represents
pub name: String,
/// Describes the asset to which this NFT represents
pub description: String,
/// "A URI pointing to a resource with mime type image/* representing the asset to which this
/// NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect
/// ratio between 1.91:1 and 4:5 inclusive.
/// TODO: Use https://docs.rs/url_serde for type-safety
pub image: Option<String>,
/// You can add any custom metadata here when you extend cw721-base
pub extension: T,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct AllNftInfoResponse<T> {
/// Who can transfer the token
pub access: OwnerOfResponse,
/// Data on the token itself,
pub info: NftInfoResponse<T>,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct TokensResponse {
/// Contains all token_ids in lexicographical ordering
/// If there are more than `limit`, use `start_from` in future queries
/// to achieve pagination.
pub tokens: Vec<String>,
}
/// Shows who can mint these tokens
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct MinterResponse {
pub minter: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct TokenInfo<T> {
/// The owner of the newly minted NFT
pub owner: Addr,
/// Approvals are stored here, as we clear them all upon transfer and cannot accumulate much
pub approvals: Vec<Approval>,
/// Identifies the asset to which this NFT represents
pub name: String,
/// Describes the asset to which this NFT represents
pub description: String,
/// A URI pointing to an image representing the asset
pub image: Option<String>,
/// You can add any custom metadata here when you extend cw721-base
pub extension: T,
}
impl Approval {
pub fn is_expired(&self, block: &BlockInfo) -> bool {
self.expires.is_expired(block)
}
}
pub struct TokenIndexes<'a, T>
where
T: Serialize + DeserializeOwned + Clone,
{
// pk goes to second tuple element
pub owner: MultiIndex<'a, (Addr, Vec<u8>), TokenInfo<T>>,
}
impl<'a, T> IndexList<TokenInfo<T>> for TokenIndexes<'a, T>
where
T: Serialize + DeserializeOwned + Clone,
{
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<TokenInfo<T>>> + '_> {
let v: Vec<&dyn Index<TokenInfo<T>>> = vec![&self.owner];
Box::new(v.into_iter())
}
}
pub fn token_owner_idx<T>(d: &TokenInfo<T>, k: Vec<u8>) -> (Addr, Vec<u8>) {
(d.owner.clone(), k)
}
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)]
pub struct Extension {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct MintMsg<T> {
/// Unique ID of the NFT
pub token_id: String,
/// The owner of the newly minter NFT
pub owner: String,
/// Identifies the asset to which this NFT represents
pub name: String,
/// Describes the asset to which this NFT represents (may be empty)
pub description: Option<String>,
/// A URI pointing to an image representing the asset
pub image: Option<String>,
/// Any custom extension used by this contract
pub extension: T,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct MigrateMsg {}