-
Notifications
You must be signed in to change notification settings - Fork 0
/
Extension.sol
301 lines (251 loc) · 11.4 KB
/
Extension.sol
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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@manifoldxyz/creator-core-solidity/contracts/core/IERC721CreatorCore.sol";
import "@manifoldxyz/creator-core-solidity/contracts/extensions/ICreatorExtensionTokenURI.sol";
import "@manifoldxyz/libraries-solidity/contracts/access/IAdminControl.sol";
import "@manifoldxyz/libraries-solidity/contracts/access/AdminControl.sol";
import "@manifoldxyz/creator-core-solidity/contracts/extensions/CreatorExtension.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./IManifoldERC721Edition.sol";
import "./ProzacYouthEngine_1.sol";
import "./ProzacYouthEngine_2.sol";
//@developed by andrew mitchell (andrewmitchell.eth)
//@shoutouts dom aka dhof (dhof.eth), white lights (whitelights.eth), yungwknd (yungwknd.eth), and chainleft (chainleft.eth)
contract ProzacYouth is AdminControl, CreatorExtension, ICreatorExtensionTokenURI, IManifoldERC721Edition {
using Strings for uint256;
using SafeMath for uint256;
ProzacYouthEngine_1 ProzacYouthEngine1;
ProzacYouthEngine_2 ProzacYouthEngine2;
uint256 public _maxSupply = 1;
uint256 public _totalSupply = 0;
address public _creator;
address public _owner;
uint256 private _maxIndex;
mapping(address => bool) private _accessList;
string public _previewImageDataUri;
string private _description = "";
string private _name = "";
constructor(address owner, address creator, string memory name, string memory description, address ProzacYouthEngine_1_addr, address ProzacYouthEngine_2_addr) Ownable(owner)
{
_name = name;
_description = description;
_creator = creator;
_owner = owner;
ProzacYouthEngine1 = ProzacYouthEngine_1(ProzacYouthEngine_1_addr);
ProzacYouthEngine2 = ProzacYouthEngine_2(ProzacYouthEngine_2_addr);
_accessList[0xF1Da6E2d387e9DA611dAc8a7FC587Eaa4B010013] = true; // Adding default wallet to accessList
}
function supportsInterface(bytes4 interfaceId) public view virtual override(AdminControl, CreatorExtension, IERC165) returns (bool) {
return interfaceId == type(ICreatorExtensionTokenURI).interfaceId || interfaceId == type(IManifoldERC721Edition).interfaceId || interfaceId == type(AdminControl).interfaceId ||
CreatorExtension.supportsInterface(interfaceId);
}
function totalSupply() external view returns(uint256) {
return _totalSupply;
}
function maxSupply() external pure returns(uint256) {
return 1;
}
function grantAccess(address _address) external onlyOwner {
_accessList[_address] = true;
}
function revokeAccess(address _address) external onlyOwner {
_accessList[_address] = false;
}
function mint(address recipient) external payable {
require(msg.sender == _owner || _accessList[msg.sender], "Unauthorized");
require(_totalSupply < 1, "No more tokens left");
IERC721CreatorCore(_creator).mintExtension(recipient);
_totalSupply++;
}
function withdrawAll() public {
require(msg.sender == _owner || _accessList[msg.sender], "Unauthorized");
require(payable(msg.sender).send(address(this).balance));
}
function setProzacYouthEngine_1(address addr) public {
require(msg.sender == _owner || _accessList[msg.sender], "Unauthorized");
ProzacYouthEngine1 = ProzacYouthEngine_1(addr);
}
function setProzacYouthEngine_2(address addr) public {
require(msg.sender == _owner || _accessList[msg.sender], "Unauthorized");
ProzacYouthEngine2 = ProzacYouthEngine_2(addr);
}
function setDescription(string memory des) public {
require(msg.sender == _owner || _accessList[msg.sender], "Unauthorized");
_description = des;
}
function setName(string memory name) public {
require(msg.sender == _owner || _accessList[msg.sender], "Unauthorized");
_name = name;
}
function addPreviewImageDataChunk(string memory chunkData) public {
require(msg.sender == _owner || _accessList[msg.sender], "Unauthorized");
_previewImageDataUri = string(abi.encodePacked(_previewImageDataUri, chunkData));
}
function deletePreviewImageDataChunk() public {
require(msg.sender == _owner || _accessList[msg.sender], "Unauthorized");
_previewImageDataUri = "";
}
function tokenURI(address creator,uint256 tokenId) public view virtual override returns (string memory) {
return formatTokenURI();
}
function formatTokenURI() public view returns (string memory) {
string memory _animURI = animToURI(string(abi.encodePacked(
ProzacYouthEngine1.getAnimHeader(),
ProzacYouthEngine2.getScript(),
ProzacYouthEngine1.getAnimFooter()
)));
string memory byteEncoded = Base64.encode(bytes(abi.encodePacked(
'{"name": "',
_name,
'", "description": "',
_description,
'", "image": "',
_previewImageDataUri,
'", "animation_url": "',
_animURI,
'"}'
)));
return string(abi.encodePacked("data:application/json;base64,", byteEncoded));
}
function animToURI(string memory anim) public pure returns (string memory) {
return string(abi.encodePacked("data:text/html;base64,", Base64.encode(bytes(anim))));
}
function uint2str(uint _i)
public
pure
returns (string memory _uintAsString)
{
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len;
while (_i != 0) {
k = k - 1;
uint8 temp = (48 + uint8(_i - (_i / 10) * 10));
bytes1 b1 = bytes1(temp);
bstr[k] = b1;
_i /= 10;
}
return string(bstr);
}
function bytes32ToHex(bytes32 _bytes32) public pure returns (string memory) {
bytes memory hexString = new bytes(64); // bytes32 will always be 32 bytes long
for (uint256 i = 0; i < 32; i++) {
bytes1 byteValue = bytes1(uint8(uint256(_bytes32) / (2**(8*(31 - i)))));
bytes1 hi = byteValue >> 4;
bytes1 lo = byteValue & 0x0f;
hexString[i*2] = char(hi);
hexString[i*2 + 1] = char(lo);
}
return string(hexString);
}
function char(bytes1 _byte) public pure returns (bytes1) {
if (_byte < 0x0A) return bytes1(uint8(_byte) + 0x30);
else return bytes1(uint8(_byte) + 0x57);
}
}
// OpenZeppelin Contracts (last updated v5.0.2) (utils/Base64.sol)
/**
* @dev Provides a set of functions to operate with Base64 strings.
*/
library Base64 {
/**
* @dev Base64 Encoding/Decoding Table
* See sections 4 and 5 of https://datatracker.ietf.org/doc/html/rfc4648
*/
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
string internal constant _TABLE_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/
function encode(bytes memory data) internal pure returns (string memory) {
return _encode(data, _TABLE, true);
}
/**
* @dev Converts a `bytes` to its Bytes64Url `string` representation.
*/
function encodeURL(bytes memory data) internal pure returns (string memory) {
return _encode(data, _TABLE_URL, false);
}
/**
* @dev Internal table-agnostic conversion
*/
function _encode(bytes memory data, string memory table, bool withPadding) private pure returns (string memory) {
/**
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
*/
if (data.length == 0) return "";
// If padding is enabled, the final length should be `bytes` data length divided by 3 rounded up and then
// multiplied by 4 so that it leaves room for padding the last chunk
// - `data.length + 2` -> Round up
// - `/ 3` -> Number of 3-bytes chunks
// - `4 *` -> 4 characters for each chunk
// If padding is disabled, the final length should be `bytes` data length multiplied by 4/3 rounded up as
// opposed to when padding is required to fill the last chunk.
// - `4 *` -> 4 characters for each chunk
// - `data.length + 2` -> Round up
// - `/ 3` -> Number of 3-bytes chunks
uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3;
string memory result = new string(resultLength);
/// @solidity memory-safe-assembly
assembly {
// Prepare the lookup table (skip the first "length" byte)
let tablePtr := add(table, 1)
// Prepare result pointer, jump over length
let resultPtr := add(result, 0x20)
let dataPtr := data
let endPtr := add(data, mload(data))
// In some cases, the last iteration will read bytes after the end of the data. We cache the value, and
// set it to zero to make sure no dirty bytes are read in that section.
let afterPtr := add(endPtr, 0x20)
let afterCache := mload(afterPtr)
mstore(afterPtr, 0x00)
// Run over the input, 3 bytes at a time
for {
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
// To write each character, shift the 3 byte (24 bits) chunk
// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
// and apply logical AND with 0x3F to bitmask the least significant 6 bits.
// Use this as an index into the lookup table, mload an entire word
// so the desired character is in the least significant byte, and
// mstore8 this least significant byte into the result and continue.
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
}
// Reset the value that was cached
mstore(afterPtr, afterCache)
if withPadding {
// When data `bytes` is not exactly 3 bytes long
// it is padded with `=` characters at the end
switch mod(mload(data), 3)
case 1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
}
return result;
}
}