@buenos_andres/contracts 0.1.1 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +31 -11
- package/security/Initializable.compact +2 -2
- package/security/Pausable.compact +2 -2
- package/security/witnesses/InitializableWitnesses.js +1 -1
- package/security/witnesses/PausableWitnesses.js +1 -1
- package/utils/Utils.compact +2 -2
- package/utils/witnesses/UtilsWitnesses.js +1 -1
- package/access/AccessControl.compact +0 -322
- package/access/Ownable.compact +0 -213
- package/access/witnesses/AccessControlWitnesses.d.ts +0 -2
- package/access/witnesses/AccessControlWitnesses.js +0 -3
- package/access/witnesses/OwnableWitnesses.d.ts +0 -2
- package/access/witnesses/OwnableWitnesses.js +0 -3
- package/token/FungibleToken.compact +0 -607
- package/token/MultiToken.compact +0 -546
- package/token/NonFungibleToken.compact +0 -806
- package/token/witnesses/FungibleTokenWitnesses.d.ts +0 -2
- package/token/witnesses/FungibleTokenWitnesses.js +0 -3
- package/token/witnesses/MultiTokenWitnesses.d.ts +0 -2
- package/token/witnesses/MultiTokenWitnesses.js +0 -3
- package/token/witnesses/NonFungibleTokenWitnesses.d.ts +0 -2
- package/token/witnesses/NonFungibleTokenWitnesses.js +0 -3
|
@@ -1,806 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
// MyFun Contracts v0.1.1 (token/NonFungibleToken.compact)
|
|
3
|
-
|
|
4
|
-
pragma language_version >= 0.16.0;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @module NonFungibleToken
|
|
8
|
-
* @description An unshielded Non-Fungible Token library.
|
|
9
|
-
*
|
|
10
|
-
* @notice One notable difference regarding this implementation and the EIP721 spec
|
|
11
|
-
* consists of the token size. Uint<128> is used as the token size because Uint<256>
|
|
12
|
-
* cannot be supported.
|
|
13
|
-
* This is due to encoding limits on the midnight circuit backend:
|
|
14
|
-
* https://github.com/midnightntwrk/compactc/issues/929
|
|
15
|
-
*
|
|
16
|
-
* @notice At the moment Midnight does not support contract-to-contract communication, but
|
|
17
|
-
* there are ongoing efforts to enable this in the future. Thus, the main circuits of this module
|
|
18
|
-
* restrict developers from sending tokens to contracts; however, we provide developers
|
|
19
|
-
* the ability to experiment with sending tokens to contracts using the `_unsafe`
|
|
20
|
-
* transfer methods. Once contract-to-contract communication is available we will follow the
|
|
21
|
-
* deprecation plan outlined below:
|
|
22
|
-
*
|
|
23
|
-
* Initial Minor Version Change:
|
|
24
|
-
*
|
|
25
|
-
* - Mark _unsafeTransfer as deprecated and emit a warning if possible.
|
|
26
|
-
* - Keep its implementation intact so existing callers continue to work.
|
|
27
|
-
*
|
|
28
|
-
* Later Major Version Change:
|
|
29
|
-
*
|
|
30
|
-
* - Drop _unsafeTransfer and remove `isContract` guard from `transfer`.
|
|
31
|
-
* - By this point, anyone using _unsafeTransfer should have migrated to the now C2C-capable `transfer`.
|
|
32
|
-
*
|
|
33
|
-
* @notice Missing Features and Improvements:
|
|
34
|
-
*
|
|
35
|
-
* - Uint256 token IDs
|
|
36
|
-
* - Transfer/Approval events
|
|
37
|
-
* - safeTransfer functions
|
|
38
|
-
* - _baseURI() support
|
|
39
|
-
* - An ERC165-like interface
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
module NonFungibleToken {
|
|
43
|
-
import CompactStandardLibrary;
|
|
44
|
-
import "../security/Initializable" prefix Initializable_;
|
|
45
|
-
import "../utils/Utils" prefix Utils_;
|
|
46
|
-
|
|
47
|
-
/// Public state
|
|
48
|
-
export sealed ledger _name: Opaque<"string">;
|
|
49
|
-
export sealed ledger _symbol: Opaque<"string">;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* @description Mapping from token IDs to their owner addresses.
|
|
53
|
-
* @type {Uint<128>} tokenId - The unique identifier for a token.
|
|
54
|
-
* @type {Either<ZswapCoinPublicKey, ContractAddress>} owner - The owner address (public key or contract).
|
|
55
|
-
* @type {Map<tokenId, owner>}
|
|
56
|
-
* @type {Map<Uint<128>, Either<ZswapCoinPublicKey, ContractAddress>>} _owners
|
|
57
|
-
*/
|
|
58
|
-
export ledger _owners: Map<Uint<128>, Either<ZswapCoinPublicKey, ContractAddress>>;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @description Mapping from account addresses to their token balances.
|
|
62
|
-
* @type {Either<ZswapCoinPublicKey, ContractAddress>} owner - The owner address.
|
|
63
|
-
* @type {Uint<128>} balance - The balance of the owner.
|
|
64
|
-
* @type {Map<owner, balance>}
|
|
65
|
-
* @type {Map<Either<ZswapCoinPublicKey, ContractAddress>, Uint<128>>} _balances
|
|
66
|
-
*/
|
|
67
|
-
export ledger _balances: Map<Either<ZswapCoinPublicKey, ContractAddress>, Uint<128>>;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* @description Mapping from token IDs to approved addresses.
|
|
71
|
-
* @type {Uint<128>} tokenId - The unique identifier for a token.
|
|
72
|
-
* @type {Either<ZswapCoinPublicKey, ContractAddress>} approved - The approved address (public key or contract).
|
|
73
|
-
* @type {Map<tokenId, approved>}
|
|
74
|
-
* @type {Map<Uint<128>, Either<ZswapCoinPublicKey, ContractAddress>>} _tokenApprovals
|
|
75
|
-
*/
|
|
76
|
-
export ledger _tokenApprovals: Map<Uint<128>, Either<ZswapCoinPublicKey, ContractAddress>>;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* @description Mapping from owner addresses to operator approvals.
|
|
80
|
-
* @type {Either<ZswapCoinPublicKey, ContractAddress>} owner - The owner address.
|
|
81
|
-
* @type {Either<ZswapCoinPublicKey, ContractAddress>} operator - The operator address.
|
|
82
|
-
* @type {Boolean} approved - Whether the operator is approved.
|
|
83
|
-
* @type {Map<owner, Map<operator, approved>>}
|
|
84
|
-
* @type {Map<Either<ZswapCoinPublicKey, ContractAddress>, Map<Either<ZswapCoinPublicKey, ContractAddress>, Boolean>>} _operatorApprovals
|
|
85
|
-
*/
|
|
86
|
-
export ledger _operatorApprovals: Map<Either<ZswapCoinPublicKey, ContractAddress>, Map<Either<ZswapCoinPublicKey, ContractAddress>, Boolean>>;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @description Mapping from token IDs to their metadata URIs.
|
|
90
|
-
* @type {Uint<128>} tokenId - The unique identifier for a token.
|
|
91
|
-
* @type {Opaque<"string">} uri - The metadata URI for the token.
|
|
92
|
-
* @type {Map<tokenId, uri>}
|
|
93
|
-
* @type {Map<Uint<128>, Opaque<"string">>} _tokenURIs
|
|
94
|
-
*/
|
|
95
|
-
export ledger _tokenURIs: Map<Uint<128>, Opaque<"string">>;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* @description Initializes the contract by setting the name and symbol.
|
|
99
|
-
*
|
|
100
|
-
* This MUST be called in the implementing contract's constructor.
|
|
101
|
-
* Failure to do so can lead to an irreparable contract.
|
|
102
|
-
*
|
|
103
|
-
* @circuitInfo k=10, rows=65
|
|
104
|
-
*
|
|
105
|
-
* Requirements:
|
|
106
|
-
*
|
|
107
|
-
* - Contract is not initialized.
|
|
108
|
-
*
|
|
109
|
-
* @param {Opaque<"string">} name_ - The name of the token.
|
|
110
|
-
* @param {Opaque<"string">} symbol_ - The symbol of the token.
|
|
111
|
-
* @return {[]} - Empty tuple.
|
|
112
|
-
*/
|
|
113
|
-
export circuit initialize(name_: Opaque<"string">, symbol_: Opaque<"string">): [] {
|
|
114
|
-
Initializable_initialize();
|
|
115
|
-
_name = disclose(name_);
|
|
116
|
-
_symbol = disclose(symbol_);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* @description Returns the number of tokens in `owner`'s account.
|
|
121
|
-
*
|
|
122
|
-
* @circuitInfo k=10, rows=309
|
|
123
|
-
*
|
|
124
|
-
* Requirements:
|
|
125
|
-
*
|
|
126
|
-
* - The contract is initialized.
|
|
127
|
-
*
|
|
128
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>)} owner - The account to query.
|
|
129
|
-
* @return {Uint<128>} - The number of tokens in `owner`'s account.
|
|
130
|
-
*/
|
|
131
|
-
export circuit balanceOf(owner: Either<ZswapCoinPublicKey, ContractAddress>): Uint<128> {
|
|
132
|
-
Initializable_assertInitialized();
|
|
133
|
-
if (!_balances.member(disclose(owner))) {
|
|
134
|
-
return 0;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return _balances.lookup(disclose(owner));
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* @description Returns the owner of the `tokenId` token.
|
|
142
|
-
*
|
|
143
|
-
* @circuitInfo k=10, rows=290
|
|
144
|
-
*
|
|
145
|
-
* Requirements:
|
|
146
|
-
*
|
|
147
|
-
* - The contract is initialized.
|
|
148
|
-
* - The `tokenId` must exist.
|
|
149
|
-
*
|
|
150
|
-
* @param {Uint<128>} tokenId - The identifier for a token.
|
|
151
|
-
* @return {Either<ZswapCoinPublicKey, ContractAddress>} - The account that owns the token.
|
|
152
|
-
*/
|
|
153
|
-
export circuit ownerOf(tokenId: Uint<128>): Either<ZswapCoinPublicKey, ContractAddress> {
|
|
154
|
-
Initializable_assertInitialized();
|
|
155
|
-
return _requireOwned(tokenId);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* @description Returns the token name.
|
|
160
|
-
*
|
|
161
|
-
* @circuitInfo k=10, rows=36
|
|
162
|
-
*
|
|
163
|
-
* Requirements:
|
|
164
|
-
*
|
|
165
|
-
* - The contract is initialized.
|
|
166
|
-
*
|
|
167
|
-
* @return {Opaque<"string">} - The token name.
|
|
168
|
-
*/
|
|
169
|
-
export circuit name(): Opaque<"string"> {
|
|
170
|
-
Initializable_assertInitialized();
|
|
171
|
-
return _name;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* @description Returns the symbol of the token.
|
|
176
|
-
*
|
|
177
|
-
* @circuitInfo k=10, rows=36
|
|
178
|
-
*
|
|
179
|
-
* Requirements:
|
|
180
|
-
*
|
|
181
|
-
* - The contract is initialized.
|
|
182
|
-
*
|
|
183
|
-
* @return {Opaque<"string">} - The token symbol.
|
|
184
|
-
*/
|
|
185
|
-
export circuit symbol(): Opaque<"string"> {
|
|
186
|
-
Initializable_assertInitialized();
|
|
187
|
-
return _symbol;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* @description Returns the token URI for the given `tokenId`. Returns the empty
|
|
192
|
-
* string if a tokenURI does not exist.
|
|
193
|
-
*
|
|
194
|
-
* @circuitInfo k=10, rows=296
|
|
195
|
-
*
|
|
196
|
-
* Requirements:
|
|
197
|
-
*
|
|
198
|
-
* - The contract is initialized.
|
|
199
|
-
* - The `tokenId` must exist.
|
|
200
|
-
*
|
|
201
|
-
* @notice Native strings and string operations aren't supported within the Compact language,
|
|
202
|
-
* e.g. concatenating a base URI + token ID is not possible like in other NFT implementations.
|
|
203
|
-
* Therefore, we propose the URI storage approach; whereby, NFTs may or may not have unique "base" URIs.
|
|
204
|
-
* It's up to the implementation to decide on how to handle this.
|
|
205
|
-
*
|
|
206
|
-
* @param {Uint<128>} tokenId - The identifier for a token.
|
|
207
|
-
* @return {Opaque<"string">} - the token id's URI.
|
|
208
|
-
*/
|
|
209
|
-
export circuit tokenURI(tokenId: Uint<128>): Opaque<"string"> {
|
|
210
|
-
Initializable_assertInitialized();
|
|
211
|
-
_requireOwned(tokenId);
|
|
212
|
-
|
|
213
|
-
if (!_tokenURIs.member(disclose(tokenId))) {
|
|
214
|
-
return Utils_emptyString();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return _tokenURIs.lookup(disclose(tokenId));
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* @description Sets the the URI as `tokenURI` for the given `tokenId`.
|
|
222
|
-
*
|
|
223
|
-
* @circuitInfo k=10, rows=253
|
|
224
|
-
*
|
|
225
|
-
* Requirements:
|
|
226
|
-
*
|
|
227
|
-
* - The contract is initialized.
|
|
228
|
-
* - The `tokenId` must exist.
|
|
229
|
-
*
|
|
230
|
-
* @notice The URI for a given NFT is usually set when the NFT is minted.
|
|
231
|
-
*
|
|
232
|
-
* @param {Uint<128>} tokenId - The identifier of the token.
|
|
233
|
-
* @param {Opaque<"string">} tokenURI - The URI of `tokenId`.
|
|
234
|
-
* @return {[]} - Empty tuple.
|
|
235
|
-
*/
|
|
236
|
-
export circuit _setTokenURI(tokenId: Uint<128>, tokenURI: Opaque<"string">): [] {
|
|
237
|
-
Initializable_assertInitialized();
|
|
238
|
-
_requireOwned(tokenId);
|
|
239
|
-
|
|
240
|
-
return _tokenURIs.insert(disclose(tokenId), disclose(tokenURI));
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* @description Gives permission to `to` to transfer `tokenId` token to another account.
|
|
245
|
-
* The approval is cleared when the token is transferred.
|
|
246
|
-
*
|
|
247
|
-
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
|
|
248
|
-
*
|
|
249
|
-
* @circuitInfo k=10, rows=966
|
|
250
|
-
*
|
|
251
|
-
* Requirements:
|
|
252
|
-
*
|
|
253
|
-
* - The contract is initialized.
|
|
254
|
-
* - The caller must either own the token or be an approved operator.
|
|
255
|
-
* - `tokenId` must exist.
|
|
256
|
-
*
|
|
257
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} to - The account receiving the approval
|
|
258
|
-
* @param {Uint<128>} tokenId - The token `to` may be permitted to transfer
|
|
259
|
-
* @return {[]} - Empty tuple.
|
|
260
|
-
*/
|
|
261
|
-
export circuit approve(
|
|
262
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
263
|
-
tokenId: Uint<128>
|
|
264
|
-
): [] {
|
|
265
|
-
Initializable_assertInitialized();
|
|
266
|
-
const auth = left<ZswapCoinPublicKey,ContractAddress>(ownPublicKey());
|
|
267
|
-
_approve(
|
|
268
|
-
to,
|
|
269
|
-
tokenId,
|
|
270
|
-
auth
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* @description Returns the account approved for `tokenId` token.
|
|
276
|
-
*
|
|
277
|
-
* @circuitInfo k=10, rows=409
|
|
278
|
-
*
|
|
279
|
-
* Requirements:
|
|
280
|
-
*
|
|
281
|
-
* - The contract is initialized.
|
|
282
|
-
* - `tokenId` must exist.
|
|
283
|
-
*
|
|
284
|
-
* @param {Uint<128>} tokenId - The token an account may be approved to manage
|
|
285
|
-
* @return {Either<ZswapCoinPublicKey, ContractAddress>} Operator- The account approved to manage the token
|
|
286
|
-
*/
|
|
287
|
-
export circuit getApproved(tokenId: Uint<128>): Either<ZswapCoinPublicKey, ContractAddress> {
|
|
288
|
-
Initializable_assertInitialized();
|
|
289
|
-
_requireOwned(tokenId);
|
|
290
|
-
|
|
291
|
-
return _getApproved(tokenId);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* @description Approve or remove `operator` as an operator for the caller.
|
|
296
|
-
* Operators can call {transferFrom} for any token owned by the caller.
|
|
297
|
-
*
|
|
298
|
-
* @circuitInfo k=10, rows=409
|
|
299
|
-
*
|
|
300
|
-
* Requirements:
|
|
301
|
-
*
|
|
302
|
-
* - The contract is initialized.
|
|
303
|
-
* - The `operator` cannot be the address zero.
|
|
304
|
-
*
|
|
305
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} operator - An operator to manage the caller's tokens
|
|
306
|
-
* @param {Boolean} approved - A boolean determining if `operator` may manage all tokens of the caller
|
|
307
|
-
* @return {[]} - Empty tuple.
|
|
308
|
-
*/
|
|
309
|
-
export circuit setApprovalForAll(
|
|
310
|
-
operator: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
311
|
-
approved: Boolean
|
|
312
|
-
): [] {
|
|
313
|
-
Initializable_assertInitialized();
|
|
314
|
-
const owner = left<ZswapCoinPublicKey,ContractAddress>(ownPublicKey());
|
|
315
|
-
_setApprovalForAll(
|
|
316
|
-
owner,
|
|
317
|
-
operator,
|
|
318
|
-
approved
|
|
319
|
-
);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* @description Returns if the `operator` is allowed to manage all of the assets of `owner`.
|
|
324
|
-
*
|
|
325
|
-
* @circuitInfo k=10, rows=621
|
|
326
|
-
*
|
|
327
|
-
* Requirements:
|
|
328
|
-
*
|
|
329
|
-
* - The contract is initialized.
|
|
330
|
-
*
|
|
331
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} owner - The owner of a token
|
|
332
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} operator - An account that may operate on `owner`'s tokens
|
|
333
|
-
* @return {Boolean} - A boolean determining if `operator` is allowed to manage all of the tokens of `owner`
|
|
334
|
-
*/
|
|
335
|
-
export circuit isApprovedForAll(
|
|
336
|
-
owner: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
337
|
-
operator: Either<ZswapCoinPublicKey, ContractAddress>
|
|
338
|
-
): Boolean {
|
|
339
|
-
Initializable_assertInitialized();
|
|
340
|
-
if (_operatorApprovals.member(disclose(owner)) && _operatorApprovals.lookup(owner).member(disclose(operator))) {
|
|
341
|
-
return _operatorApprovals.lookup(owner).lookup(disclose(operator));
|
|
342
|
-
} else {
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* @description Transfers `tokenId` token from `from` to `to`.
|
|
349
|
-
*
|
|
350
|
-
* @notice Transfers to contract addresses are currently disallowed until contract-to-contract interactions
|
|
351
|
-
* are supported in Compact. This restriction prevents assets from being inadvertently locked in contracts that cannot
|
|
352
|
-
* currently handle token receipt.
|
|
353
|
-
*
|
|
354
|
-
* @circuitInfo k=11, rows=1966
|
|
355
|
-
*
|
|
356
|
-
* Requirements:
|
|
357
|
-
*
|
|
358
|
-
* - The contract is initialized.
|
|
359
|
-
* - `from` is not the zero address.
|
|
360
|
-
* - `to` is not the zero address.
|
|
361
|
-
* - `to` is not a ContractAddress.
|
|
362
|
-
* - `tokenId` token must be owned by `from`.
|
|
363
|
-
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
|
|
364
|
-
*
|
|
365
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} from - The source account from which the token is being transfered
|
|
366
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} to - The target account to transfer token to
|
|
367
|
-
* @param {Uint<128>} tokenId - The token being transfered
|
|
368
|
-
* @return {[]} - Empty tuple.
|
|
369
|
-
*/
|
|
370
|
-
export circuit transferFrom(
|
|
371
|
-
from: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
372
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
373
|
-
tokenId: Uint<128>
|
|
374
|
-
): [] {
|
|
375
|
-
Initializable_assertInitialized();
|
|
376
|
-
assert(!Utils_isContractAddress(to), "NonFungibleToken: Unsafe Transfer");
|
|
377
|
-
|
|
378
|
-
_unsafeTransferFrom(from, to, tokenId);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress.
|
|
383
|
-
*
|
|
384
|
-
* WARNING: Transfers to contract addresses are considered unsafe because contract-to-contract calls
|
|
385
|
-
* are not currently supported. Tokens sent to a contract address may become irretrievable.
|
|
386
|
-
* Once contract-to-contract calls are supported, this circuit may be deprecated.
|
|
387
|
-
*
|
|
388
|
-
* @circuitInfo k=11, rows=1963
|
|
389
|
-
*
|
|
390
|
-
* Requirements:
|
|
391
|
-
*
|
|
392
|
-
* - The contract is initialized.
|
|
393
|
-
* - `from` is not the zero address.
|
|
394
|
-
* - `to` is not the zero address.
|
|
395
|
-
* - `tokenId` token must be owned by `from`.
|
|
396
|
-
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
|
|
397
|
-
*
|
|
398
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} from - The source account from which the token is being transfered
|
|
399
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} to - The target account to transfer token to
|
|
400
|
-
* @param {Uint<128>} tokenId - The token being transfered
|
|
401
|
-
* @return {[]} - Empty tuple.
|
|
402
|
-
*/
|
|
403
|
-
export circuit _unsafeTransferFrom(
|
|
404
|
-
from: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
405
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
406
|
-
tokenId: Uint<128>
|
|
407
|
-
): [] {
|
|
408
|
-
Initializable_assertInitialized();
|
|
409
|
-
assert(!Utils_isKeyOrAddressZero(to), "NonFungibleToken: Invalid Receiver");
|
|
410
|
-
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
|
|
411
|
-
// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
|
|
412
|
-
const auth = left<ZswapCoinPublicKey,ContractAddress>(ownPublicKey());
|
|
413
|
-
const previousOwner = _update(
|
|
414
|
-
to,
|
|
415
|
-
tokenId,
|
|
416
|
-
auth
|
|
417
|
-
);
|
|
418
|
-
assert(previousOwner == from, "NonFungibleToken: Incorrect Owner");
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* @description Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
|
|
423
|
-
*
|
|
424
|
-
* @circuitInfo k=10, rows=253
|
|
425
|
-
*
|
|
426
|
-
* Requirements:
|
|
427
|
-
*
|
|
428
|
-
* - The contract is initialized.
|
|
429
|
-
*
|
|
430
|
-
* @param {Uint<128>} tokenId - The target token of the owner query
|
|
431
|
-
* @return {Either<ZswapCoinPublicKey, ContractAddress>} - The owner of the token
|
|
432
|
-
*/
|
|
433
|
-
export circuit _ownerOf(tokenId: Uint<128>): Either<ZswapCoinPublicKey, ContractAddress> {
|
|
434
|
-
Initializable_assertInitialized();
|
|
435
|
-
if (!_owners.member(disclose(tokenId))) {
|
|
436
|
-
return burnAddress();
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
return _owners.lookup(disclose(tokenId));
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* @description Returns the approved address for `tokenId`. Returns the zero address if `tokenId` is not minted.
|
|
444
|
-
*
|
|
445
|
-
* @circuitInfo k=10, rows=253
|
|
446
|
-
*
|
|
447
|
-
* Requirements:
|
|
448
|
-
*
|
|
449
|
-
* - The contract is initialized.
|
|
450
|
-
*
|
|
451
|
-
* @param {Uint<128>} tokenId - The token to query
|
|
452
|
-
* @return {Either<ZswapCoinPublicKey, ContractAddress>} - An account approved to spend `tokenId`
|
|
453
|
-
*/
|
|
454
|
-
export circuit _getApproved(tokenId: Uint<128>): Either<ZswapCoinPublicKey, ContractAddress> {
|
|
455
|
-
Initializable_assertInitialized();
|
|
456
|
-
if (!_tokenApprovals.member(disclose(tokenId))) {
|
|
457
|
-
return burnAddress();
|
|
458
|
-
}
|
|
459
|
-
return _tokenApprovals.lookup(disclose(tokenId));
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* @description Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
|
|
464
|
-
* particular (ignoring whether it is owned by `owner`).
|
|
465
|
-
*
|
|
466
|
-
* @circuitInfo k=11, rows=1098
|
|
467
|
-
*
|
|
468
|
-
* Requirements:
|
|
469
|
-
*
|
|
470
|
-
* - The contract is initialized.
|
|
471
|
-
*
|
|
472
|
-
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
|
|
473
|
-
* assumption.
|
|
474
|
-
*
|
|
475
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} owner - Owner of the token
|
|
476
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} spender - Account that wishes to spend `tokenId`
|
|
477
|
-
* @param {Uint<128>} tokenId - Token to spend
|
|
478
|
-
* @return {Boolean} - A boolean determining if `spender` may manage `tokenId`
|
|
479
|
-
*/
|
|
480
|
-
export circuit _isAuthorized(
|
|
481
|
-
owner: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
482
|
-
spender: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
483
|
-
tokenId: Uint<128>
|
|
484
|
-
): Boolean {
|
|
485
|
-
Initializable_assertInitialized();
|
|
486
|
-
return (
|
|
487
|
-
!Utils_isKeyOrAddressZero(disclose(spender)) &&
|
|
488
|
-
(disclose(owner) == disclose(spender) || isApprovedForAll(owner, spender) || _getApproved(tokenId) == disclose(spender))
|
|
489
|
-
);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* @description Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
|
|
494
|
-
*
|
|
495
|
-
* @circuitInfo k=11, rows=1121
|
|
496
|
-
*
|
|
497
|
-
* Requirements:
|
|
498
|
-
*
|
|
499
|
-
* - The contract is initialized.
|
|
500
|
-
* - `spender` has approval from `owner` for `tokenId` OR `spender` has approval to manage all of `owner`'s assets.
|
|
501
|
-
*
|
|
502
|
-
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
|
|
503
|
-
* assumption.
|
|
504
|
-
*
|
|
505
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} owner - Owner of the token
|
|
506
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} spender - Account operating on `tokenId`
|
|
507
|
-
* @param {Uint<128>} tokenId - The token to spend
|
|
508
|
-
* @return {[]} - Empty tuple.
|
|
509
|
-
*/
|
|
510
|
-
export circuit _checkAuthorized(
|
|
511
|
-
owner: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
512
|
-
spender: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
513
|
-
tokenId: Uint<128>
|
|
514
|
-
): [] {
|
|
515
|
-
Initializable_assertInitialized();
|
|
516
|
-
if (!_isAuthorized(owner, spender, tokenId)) {
|
|
517
|
-
assert(!Utils_isKeyOrAddressZero(owner), "NonFungibleToken: Nonexistent Token");
|
|
518
|
-
assert(false, "NonFungibleToken: Insufficient Approval");
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
/**
|
|
523
|
-
* @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
|
|
524
|
-
* (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
|
|
525
|
-
*
|
|
526
|
-
* @circuitInfo k=11, rows=1959
|
|
527
|
-
*
|
|
528
|
-
* Requirements:
|
|
529
|
-
*
|
|
530
|
-
* - The contract is initialized.
|
|
531
|
-
* - If `auth` is non 0, then this function will check that `auth` is either the owner of the token,
|
|
532
|
-
* or approved to operate on the token (by the owner).
|
|
533
|
-
*
|
|
534
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} to - The intended recipient of the token transfer
|
|
535
|
-
* @param {Uint<128>} tokenId - The token being transfered
|
|
536
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} auth - An account authorized to transfer the token
|
|
537
|
-
* @return {Either<ZswapCoinPublicKey, ContractAddress>} - Owner of the token before it was transfered
|
|
538
|
-
*/
|
|
539
|
-
circuit _update(
|
|
540
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
541
|
-
tokenId: Uint<128>,
|
|
542
|
-
auth: Either<ZswapCoinPublicKey, ContractAddress>
|
|
543
|
-
): Either<ZswapCoinPublicKey, ContractAddress> {
|
|
544
|
-
Initializable_assertInitialized();
|
|
545
|
-
const from = _ownerOf(tokenId);
|
|
546
|
-
|
|
547
|
-
// Perform (optional) operator check
|
|
548
|
-
if (!Utils_isKeyOrAddressZero(disclose(auth))) {
|
|
549
|
-
_checkAuthorized(from, auth, tokenId);
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// Execute the update
|
|
553
|
-
if (!Utils_isKeyOrAddressZero(disclose(from))) {
|
|
554
|
-
// Clear approval. No need to re-authorize
|
|
555
|
-
_approve(burnAddress(), tokenId, burnAddress());
|
|
556
|
-
const newBalance = _balances.lookup(disclose(from)) - 1 as Uint<128>;
|
|
557
|
-
_balances.insert(disclose(from), disclose(newBalance));
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
if (!Utils_isKeyOrAddressZero(disclose(to))) {
|
|
561
|
-
if (!_balances.member(disclose(to))) {
|
|
562
|
-
_balances.insert(disclose(to), 0);
|
|
563
|
-
}
|
|
564
|
-
const newBalance = _balances.lookup(disclose(to)) + 1 as Uint<128>;
|
|
565
|
-
_balances.insert(disclose(to), disclose(newBalance));
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
_owners.insert(disclose(tokenId), disclose(to));
|
|
569
|
-
|
|
570
|
-
return from;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
/**
|
|
574
|
-
* @description Mints `tokenId` and transfers it to `to`.
|
|
575
|
-
*
|
|
576
|
-
* @circuitInfo k=11, rows=1013
|
|
577
|
-
*
|
|
578
|
-
* Requirements:
|
|
579
|
-
*
|
|
580
|
-
* - The contract is initialized.
|
|
581
|
-
* - `tokenId` must not exist.
|
|
582
|
-
* - `to` is not the zero address.
|
|
583
|
-
* - `to` is not a ContractAddress.
|
|
584
|
-
*
|
|
585
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} to - The account receiving `tokenId`
|
|
586
|
-
* @param {Uint<128>} tokenId - The token to transfer
|
|
587
|
-
* @return {[]} - Empty tuple.
|
|
588
|
-
*/
|
|
589
|
-
export circuit _mint(
|
|
590
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
591
|
-
tokenId: Uint<128>
|
|
592
|
-
): [] {
|
|
593
|
-
Initializable_assertInitialized();
|
|
594
|
-
assert(!Utils_isContractAddress(to), "NonFungibleToken: Unsafe Transfer");
|
|
595
|
-
|
|
596
|
-
_unsafeMint(to, tokenId);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
/**
|
|
600
|
-
* @description Mints `tokenId` and transfers it to `to`. It does NOT check if the recipient is a ContractAddress.
|
|
601
|
-
*
|
|
602
|
-
* @circuitInfo k=11, rows=1010
|
|
603
|
-
*
|
|
604
|
-
* Requirements:
|
|
605
|
-
*
|
|
606
|
-
* - The contract is initialized.
|
|
607
|
-
* - `tokenId` must not exist.
|
|
608
|
-
* - `to` is not the zero address.
|
|
609
|
-
*
|
|
610
|
-
* WARNING: Transfers to contract addresses are considered unsafe because contract-to-contract
|
|
611
|
-
* calls are not currently supported. Tokens sent to a contract address may become irretrievable.
|
|
612
|
-
* Once contract-to-contract calls are supported, this circuit may be deprecated.
|
|
613
|
-
*
|
|
614
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} to - The account receiving `tokenId`
|
|
615
|
-
* @param {Uint<128>} tokenId - The token to transfer
|
|
616
|
-
* @return {[]} - Empty tuple.
|
|
617
|
-
*/
|
|
618
|
-
export circuit _unsafeMint(
|
|
619
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
620
|
-
tokenId: Uint<128>
|
|
621
|
-
): [] {
|
|
622
|
-
Initializable_assertInitialized();
|
|
623
|
-
assert(!Utils_isKeyOrAddressZero(to), "NonFungibleToken: Invalid Receiver");
|
|
624
|
-
|
|
625
|
-
const previousOwner = _update(to, tokenId, burnAddress());
|
|
626
|
-
|
|
627
|
-
assert(Utils_isKeyOrAddressZero(previousOwner), "NonFungibleToken: Invalid Sender");
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
/**
|
|
631
|
-
* @description Destroys `tokenId`.
|
|
632
|
-
* The approval is cleared when the token is burned.
|
|
633
|
-
* This circuit does not check if the sender is authorized to operate on the token.
|
|
634
|
-
*
|
|
635
|
-
* @circuitInfo k=10, rows=479
|
|
636
|
-
*
|
|
637
|
-
* Requirements:
|
|
638
|
-
*
|
|
639
|
-
* - The contract is initialized.
|
|
640
|
-
* - `tokenId` must exist.
|
|
641
|
-
*
|
|
642
|
-
* @param {Uint<128>} tokenId - The token to burn
|
|
643
|
-
* @return {[]} - Empty tuple.
|
|
644
|
-
*/
|
|
645
|
-
export circuit _burn(tokenId: Uint<128>): [] {
|
|
646
|
-
Initializable_assertInitialized();
|
|
647
|
-
const previousOwner = _update(burnAddress(), tokenId, burnAddress());
|
|
648
|
-
assert(!Utils_isKeyOrAddressZero(previousOwner), "NonFungibleToken: Invalid Sender");
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
/**
|
|
652
|
-
* @description Transfers `tokenId` from `from` to `to`.
|
|
653
|
-
* As opposed to {transferFrom}, this imposes no restrictions on ownPublicKey().
|
|
654
|
-
*
|
|
655
|
-
* @notice Transfers to contract addresses are currently disallowed until contract-to-contract
|
|
656
|
-
* interactions are supported in Compact. This restriction prevents assets from being inadvertently
|
|
657
|
-
* locked in contracts that cannot currently handle token receipt.
|
|
658
|
-
*
|
|
659
|
-
* @circuitInfo k=11, rows=1224
|
|
660
|
-
*
|
|
661
|
-
* Requirements:
|
|
662
|
-
*
|
|
663
|
-
* - The contract is initialized.
|
|
664
|
-
* - `to` is not the zero address.
|
|
665
|
-
* - `to` is not a ContractAddress.
|
|
666
|
-
* - `tokenId` token must be owned by `from`.
|
|
667
|
-
*
|
|
668
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} from - The source account of the token transfer
|
|
669
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} to - The target account of the token transfer
|
|
670
|
-
* @param {Uint<128>} tokenId - The token to transfer
|
|
671
|
-
* @return {[]} - Empty tuple.
|
|
672
|
-
*/
|
|
673
|
-
export circuit _transfer(
|
|
674
|
-
from: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
675
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
676
|
-
tokenId: Uint<128>
|
|
677
|
-
): [] {
|
|
678
|
-
Initializable_assertInitialized();
|
|
679
|
-
assert(!Utils_isContractAddress(to), "NonFungibleToken: Unsafe Transfer");
|
|
680
|
-
|
|
681
|
-
_unsafeTransfer(from, to, tokenId);
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
/**
|
|
685
|
-
* @description Transfers `tokenId` from `from` to `to`.
|
|
686
|
-
* As opposed to {_unsafeTransferFrom}, this imposes no restrictions on ownPublicKey().
|
|
687
|
-
* It does NOT check if the recipient is a ContractAddress.
|
|
688
|
-
*
|
|
689
|
-
* @circuitInfo k=11, rows=1221
|
|
690
|
-
*
|
|
691
|
-
* Requirements:
|
|
692
|
-
*
|
|
693
|
-
* - The contract is initialized.
|
|
694
|
-
* - `to` is not the zero address.
|
|
695
|
-
* - `tokenId` token must be owned by `from`.
|
|
696
|
-
*
|
|
697
|
-
* WARNING: Transfers to contract addresses are considered unsafe because contract-to-contract
|
|
698
|
-
* calls are not currently supported. Tokens sent to a contract address may become irretrievable.
|
|
699
|
-
* Once contract-to-contract calls are supported, this circuit may be deprecated.
|
|
700
|
-
*
|
|
701
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} from - The source account of the token transfer
|
|
702
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} to - The target account of the token transfer
|
|
703
|
-
* @param {Uint<128>} tokenId - The token to transfer
|
|
704
|
-
* @return {[]} - Empty tuple.
|
|
705
|
-
*/
|
|
706
|
-
export circuit _unsafeTransfer(
|
|
707
|
-
from: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
708
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
709
|
-
tokenId: Uint<128>
|
|
710
|
-
): [] {
|
|
711
|
-
Initializable_assertInitialized();
|
|
712
|
-
assert(!Utils_isKeyOrAddressZero(to), "NonFungibleToken: Invalid Receiver");
|
|
713
|
-
|
|
714
|
-
const previousOwner = _update(to, tokenId, burnAddress());
|
|
715
|
-
|
|
716
|
-
assert(!Utils_isKeyOrAddressZero(previousOwner), "NonFungibleToken: Nonexistent Token");
|
|
717
|
-
assert(previousOwner == from, "NonFungibleToken: Incorrect Owner");
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
/**
|
|
721
|
-
* @description Approve `to` to operate on `tokenId`
|
|
722
|
-
*
|
|
723
|
-
* @circuitInfo k=11, rows=1109
|
|
724
|
-
*
|
|
725
|
-
* Requirements:
|
|
726
|
-
*
|
|
727
|
-
* - The contract is initialized.
|
|
728
|
-
* - If `auth` is non 0, then this function will check that `auth` is either the owner of the token,
|
|
729
|
-
* or approved to operate on the token (by the owner).
|
|
730
|
-
*
|
|
731
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} to - The target account to approve
|
|
732
|
-
* @param {Uint<128>} tokenId - The token to approve
|
|
733
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} auth - An account authorized to operate on all tokens held by the owner the token
|
|
734
|
-
* @return {[]} - Empty tuple.
|
|
735
|
-
*/
|
|
736
|
-
export circuit _approve(
|
|
737
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
738
|
-
tokenId: Uint<128>,
|
|
739
|
-
auth: Either<ZswapCoinPublicKey, ContractAddress>
|
|
740
|
-
): [] {
|
|
741
|
-
Initializable_assertInitialized();
|
|
742
|
-
if (!Utils_isKeyOrAddressZero(disclose(auth))) {
|
|
743
|
-
const owner = _requireOwned(tokenId);
|
|
744
|
-
|
|
745
|
-
// We do not use _isAuthorized because single-token approvals should not be able to call approve
|
|
746
|
-
assert((owner == disclose(auth) || isApprovedForAll(owner, auth)), "NonFungibleToken: Invalid Approver");
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
_tokenApprovals.insert(disclose(tokenId), disclose(to));
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
/**
|
|
753
|
-
* @description Approve `operator` to operate on all of `owner` tokens
|
|
754
|
-
*
|
|
755
|
-
* @circuitInfo k=10, rows=524
|
|
756
|
-
*
|
|
757
|
-
* Requirements:
|
|
758
|
-
*
|
|
759
|
-
* - The contract is initialized.
|
|
760
|
-
* - `operator` is not the address zero.
|
|
761
|
-
*
|
|
762
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} owner - Owner of a token
|
|
763
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} operator - The account to approve
|
|
764
|
-
* @param {Boolean} approved - A boolean determining if `operator` may operate on all of `owner` tokens
|
|
765
|
-
* @return {[]} - Empty tuple.
|
|
766
|
-
*/
|
|
767
|
-
export circuit _setApprovalForAll(
|
|
768
|
-
owner: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
769
|
-
operator: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
770
|
-
approved: Boolean
|
|
771
|
-
): [] {
|
|
772
|
-
Initializable_assertInitialized();
|
|
773
|
-
assert(!Utils_isKeyOrAddressZero(operator), "NonFungibleToken: Invalid Operator");
|
|
774
|
-
|
|
775
|
-
if (!_operatorApprovals.member(disclose(owner))) {
|
|
776
|
-
_operatorApprovals.insert(
|
|
777
|
-
disclose(owner),
|
|
778
|
-
default<Map<Either<ZswapCoinPublicKey, ContractAddress>, Boolean>>
|
|
779
|
-
);
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
_operatorApprovals.lookup(owner).insert(disclose(operator), disclose(approved));
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
/**
|
|
786
|
-
* @description Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
|
|
787
|
-
* Returns the owner.
|
|
788
|
-
*
|
|
789
|
-
* @circuitInfo k=10, rows=288
|
|
790
|
-
*
|
|
791
|
-
* Requirements:
|
|
792
|
-
*
|
|
793
|
-
* - The contract is initialized.
|
|
794
|
-
* - `tokenId` must exist.
|
|
795
|
-
*
|
|
796
|
-
* @param {Uint<128>} tokenId - The token that should be owned
|
|
797
|
-
* @return {Either<ZswapCoinPublicKey, ContractAddress>} - The owner of `tokenId`
|
|
798
|
-
*/
|
|
799
|
-
export circuit _requireOwned(tokenId: Uint<128>): Either<ZswapCoinPublicKey, ContractAddress> {
|
|
800
|
-
Initializable_assertInitialized();
|
|
801
|
-
const owner = _ownerOf(tokenId);
|
|
802
|
-
|
|
803
|
-
assert(!Utils_isKeyOrAddressZero(owner), "NonFungibleToken: Nonexistent Token");
|
|
804
|
-
return owner;
|
|
805
|
-
}
|
|
806
|
-
}
|