@artblocks/contracts 1.2.0 → 1.2.1

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.
Files changed (164) hide show
  1. package/README.md +22 -38
  2. package/artifacts/contracts/AdminACLV1.sol/AdminACLV1.json +2 -2
  3. package/artifacts/contracts/BytecodeStorageReaders/BytecodeStorageReaderContractV2.sol/BytecodeStorageReaderContractV2.json +201 -0
  4. package/artifacts/contracts/BytecodeStorageReaders/UniversalBytecodeStorageReader.sol/UniversalBytecodeStorageReader.json +154 -0
  5. package/artifacts/contracts/BytecodeStorageV2Writer.sol/BytecodeStorageV2Writer.json +87 -0
  6. package/artifacts/contracts/DependencyRegistryV0.sol/DependencyRegistryV0.json +144 -14
  7. package/artifacts/contracts/GenArt721CoreV3_Curated.sol/GenArt721CoreV3_Curated.json +2493 -0
  8. package/artifacts/contracts/OwnedCreate2FactoryV0.sol/OwnedCreate2FactoryV0.json +311 -0
  9. package/artifacts/contracts/archive/GenArt721CoreV3.sol/GenArt721CoreV3.json +15 -2
  10. package/artifacts/contracts/archive/GenArt721CoreV3_Explorations.sol/GenArt721CoreV3_Explorations.json +15 -2
  11. package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV2.sol/MinterDAExpV2.json +2 -2
  12. package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV3.sol/MinterDAExpV3.json +2 -2
  13. package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV4.sol/MinterDAExpV4.json +2 -2
  14. package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV0.sol/MinterDAExpSettlementV0.json +2 -2
  15. package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV1.sol/MinterDAExpSettlementV1.json +2 -2
  16. package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV2.sol/MinterDAExpSettlementV2.json +2 -2
  17. package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV2.sol/MinterDALinV2.json +2 -2
  18. package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV3.sol/MinterDALinV3.json +2 -2
  19. package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV4.sol/MinterDALinV4.json +2 -2
  20. package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV1.sol/MinterHolderV1.json +2 -2
  21. package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV2.sol/MinterHolderV2.json +2 -2
  22. package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV3.sol/MinterHolderV3.json +2 -2
  23. package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV4.sol/MinterHolderV4.json +2 -2
  24. package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV1.sol/MinterMerkleV1.json +2 -2
  25. package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV2.sol/MinterMerkleV2.json +2 -2
  26. package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV3.sol/MinterMerkleV3.json +2 -2
  27. package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV4.sol/MinterMerkleV4.json +2 -2
  28. package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV5.sol/MinterMerkleV5.json +2 -2
  29. package/artifacts/contracts/archive/minter-suite/Minters/MinterPolyptych/MinterPolyptychV0.sol/IGenArt721CoreContractV3WithRandomizer.json +37 -0
  30. package/artifacts/contracts/archive/minter-suite/Minters/MinterPolyptych/MinterPolyptychV0.sol/MinterPolyptychV0.json +2 -2
  31. package/artifacts/contracts/archive/minter-suite/Minters/MinterSEA/MinterSEAV0.sol/MinterSEAV0.json +2 -2
  32. package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV2.sol/MinterSetPriceV2.json +2 -2
  33. package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV3.sol/MinterSetPriceV3.json +2 -2
  34. package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV4.sol/MinterSetPriceV4.json +2 -2
  35. package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V2.sol/MinterSetPriceERC20V2.json +2 -2
  36. package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V3.sol/MinterSetPriceERC20V3.json +2 -2
  37. package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V4.sol/MinterSetPriceERC20V4.json +2 -2
  38. package/artifacts/contracts/engine/V3/EngineFactoryV0.sol/EngineFactoryV0.json +20 -2
  39. package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine.sol/GenArt721CoreV3_Engine.json +48 -12
  40. package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol/GenArt721CoreV3_Engine_Flex.json +76 -40
  41. package/artifacts/contracts/engine/V3/forks/GenArt721CoreV3_Engine_Flex_PROOF.sol/GenArt721CoreV3_Engine_Flex_PROOF.json +15 -2
  42. package/artifacts/contracts/engine/V3/forks/PROHIBITION/AdminACLV0_PROHIBITION.sol/AdminACLV0_PROHIBITION.json +2 -2
  43. package/artifacts/contracts/engine/V3/forks/PROHIBITION/GenArt721CoreV3_Engine_Flex_PROHIBITION.sol/GenArt721CoreV3_Engine_Flex_PROHIBITION.json +15 -2
  44. package/artifacts/contracts/engine/V3/forks/PROHIBITION/interfaces/IGenArt721CoreContractV3_Engine_Flex_PROHIBITION.sol/IGenArt721CoreContractV3_Engine_Flex_PROHIBITION.json +37 -0
  45. package/artifacts/contracts/engine-registry/CoreRegistryV1.sol/CoreRegistryV1.json +2 -2
  46. package/artifacts/contracts/generator/AddressChunks.sol/AddressChunks.json +10 -0
  47. package/artifacts/contracts/generator/GenArt721GeneratorV0.sol/GenArt721GeneratorV0.json +333 -0
  48. package/artifacts/contracts/generator/GenArt721GeneratorV0.sol/ILegacyGenArt721CoreV2_PBAB_Flex.json +47 -0
  49. package/artifacts/contracts/interfaces/v0.8.x/IBytecodeStorageReader.sol/IBytecodeStorageReader.json +7 -7
  50. package/artifacts/contracts/interfaces/v0.8.x/IBytecodeStorageReaderV2.sol/IBytecodeStorageReaderV2.json +7 -7
  51. package/artifacts/contracts/interfaces/v0.8.x/IBytecodeStorageReader_Base.sol/IBytecodeStorageReader_Base.json +30 -0
  52. package/artifacts/contracts/interfaces/v0.8.x/ICoreRegistryV1.sol/ICoreRegistryV1.json +13 -0
  53. package/artifacts/contracts/interfaces/v0.8.x/IDependencyRegistryV0.sol/IDependencyRegistryV0.json +170 -0
  54. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3.sol/IGenArt721CoreContractV3.json +37 -0
  55. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Base.sol/IGenArt721CoreContractV3_Base.json +37 -0
  56. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine.sol/IGenArt721CoreContractV3_Engine.json +42 -0
  57. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_Flex.sol/IGenArt721CoreContractV3_Engine_Flex.json +42 -0
  58. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_Flex_PreV3p2.sol/IGenArt721CoreContractV3_Engine_Flex_PreV3p2.json +37 -0
  59. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_PreV3p2.sol/IGenArt721CoreContractV3_Engine_PreV3p2.json +37 -0
  60. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreProjectScriptV0.sol/IGenArt721CoreProjectScriptV0.json +59 -0
  61. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreProjectScriptV1.sol/IGenArt721CoreProjectScriptV1.json +64 -0
  62. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreTokenHashProviderV0.sol/IGenArt721CoreTokenHashProviderV0.json +30 -0
  63. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreTokenHashProviderV1.sol/IGenArt721CoreTokenHashProviderV1.json +30 -0
  64. package/artifacts/contracts/interfaces/v0.8.x/IGenArt721GeneratorV0.sol/IGenArt721GeneratorV0.json +63 -0
  65. package/artifacts/contracts/interfaces/v0.8.x/IOwnedCreate2FactoryV0.sol/IOwnedCreate2FactoryV0.json +74 -0
  66. package/artifacts/contracts/interfaces/v0.8.x/ISeaDropShimForContract.sol/ISeaDropShimForContract.json +37 -0
  67. package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterMinPriceV0.sol/ISharedMinterMinPriceV0.json +37 -0
  68. package/artifacts/contracts/interfaces/v0.8.x/IUniversalBytecodeStorageReader.sol/IUniversalBytecodeStorageReader.json +56 -0
  69. package/artifacts/contracts/interfaces/v0.8.x/integration-refs/OpenSea/ERC721SeaDropStructsErrorsAndEvents.sol/ERC721SeaDropStructsErrorsAndEvents.json +43 -0
  70. package/artifacts/contracts/interfaces/v0.8.x/integration-refs/OpenSea/INonFungibleSeaDropToken.sol/INonFungibleSeaDropToken.json +715 -0
  71. package/artifacts/contracts/interfaces/v0.8.x/integration-refs/OpenSea/ISeaDrop.sol/ISeaDrop.json +1571 -0
  72. package/artifacts/contracts/interfaces/v0.8.x/integration-refs/OpenSea/ISeaDropTokenContractMetadata.sol/ISeaDropTokenContractMetadata.json +345 -0
  73. package/artifacts/contracts/interfaces/v0.8.x/integration-refs/OpenSea/SeaDropErrorsAndEvents.sol/SeaDropErrorsAndEvents.json +717 -0
  74. package/artifacts/contracts/libs/v0.8.x/AuthLib.sol/AuthLib.json +2 -2
  75. package/artifacts/contracts/libs/v0.8.x/Bytes32Strings.sol/Bytes32Strings.json +2 -2
  76. package/artifacts/contracts/libs/v0.8.x/DependencyRegistryStorageLib.sol/DependencyRegistryStorageLib.json +2 -2
  77. package/artifacts/contracts/libs/v0.8.x/JsonStatic.sol/JsonStatic.json +10 -0
  78. package/artifacts/contracts/libs/v0.8.x/V3FlexLib.sol/V3FlexLib.json +9 -22
  79. package/artifacts/contracts/libs/v0.8.x/minter-libs/MaxInvocationsLib.sol/MaxInvocationsLib.json +2 -2
  80. package/artifacts/contracts/libs/v0.8.x/minter-libs/MinPriceLib.sol/MinPriceLib.json +24 -0
  81. package/artifacts/contracts/libs/v0.8.x/minter-libs/PolyptychLib.sol/PolyptychLib.json +2 -2
  82. package/artifacts/contracts/libs/v0.8.x/minter-libs/RAMLib.sol/RAMLib.json +2 -2
  83. package/artifacts/contracts/libs/v0.8.x/minter-libs/SEALib.sol/SEALib.json +2 -2
  84. package/artifacts/contracts/libs/v0.8.x/minter-libs/SettlementExpLib.sol/SettlementExpLib.json +2 -2
  85. package/artifacts/contracts/libs/v0.8.x/minter-libs/SplitFundsLib.sol/SplitFundsLib.json +2 -2
  86. package/artifacts/contracts/minter-suite/MinterFilter/MinterFilterV1.sol/MinterFilterV1.json +2 -2
  87. package/artifacts/contracts/minter-suite/MinterFilter/MinterFilterV2.sol/MinterFilterV2.json +2 -2
  88. package/artifacts/contracts/minter-suite/Minters/MinterDAExpHolderV5.sol/MinterDAExpHolderV5.json +2 -2
  89. package/artifacts/contracts/minter-suite/Minters/MinterDAExpSettlementV3.sol/MinterDAExpSettlementV3.json +2 -2
  90. package/artifacts/contracts/minter-suite/Minters/MinterDAExpV5.sol/MinterDAExpV5.json +2 -2
  91. package/artifacts/contracts/minter-suite/Minters/MinterDALinHolderV5.sol/MinterDALinHolderV5.json +2 -2
  92. package/artifacts/contracts/minter-suite/Minters/MinterDALinV5.sol/MinterDALinV5.json +2 -2
  93. package/artifacts/contracts/minter-suite/Minters/MinterMinPriceMerkleV0.sol/MinterMinPriceMerkleV0.json +664 -0
  94. package/artifacts/contracts/minter-suite/Minters/MinterMinPriceV0.sol/MinterMinPriceV0.json +387 -0
  95. package/artifacts/contracts/minter-suite/Minters/MinterRAMV0.sol/MinterRAMV0.json +2 -2
  96. package/artifacts/contracts/minter-suite/Minters/MinterSEAV1.sol/MinterSEAV1.json +2 -2
  97. package/artifacts/contracts/minter-suite/Minters/MinterSetPriceERC20V5.sol/MinterSetPriceERC20V5.json +2 -2
  98. package/artifacts/contracts/minter-suite/Minters/MinterSetPriceHolderV5.sol/MinterSetPriceHolderV5.json +2 -2
  99. package/artifacts/contracts/minter-suite/Minters/MinterSetPriceMerkleV5.sol/MinterSetPriceMerkleV5.json +2 -2
  100. package/artifacts/contracts/minter-suite/Minters/MinterSetPricePolyptychERC20V5.sol/MinterSetPricePolyptychERC20V5.json +2 -2
  101. package/artifacts/contracts/minter-suite/Minters/MinterSetPricePolyptychV5.sol/MinterSetPricePolyptychV5.json +2 -2
  102. package/artifacts/contracts/minter-suite/Minters/MinterSetPriceV5.sol/MinterSetPriceV5.json +2 -2
  103. package/artifacts/contracts/minter-suite/Minters/one-off/MinterSetPriceV5_SingleCore.sol/MinterSetPriceV5_SingleCore.json +2 -2
  104. package/artifacts/contracts/minter-suite/Minters/one-off/SeaDropXArtBlocksShim.sol/SeaDropXArtBlocksShim.json +1206 -0
  105. package/artifacts/contracts/mock/BytecodeV1LibCallsMock.sol/BytecodeV1LibCallsMock.json +2 -2
  106. package/artifacts/contracts/mock/BytecodeV2LibCallsMock.sol/BytecodeV2LibCallsMock.json +2 -2
  107. package/artifacts/contracts/mock/DummySharedMinter.sol/DummySharedMinter.json +2 -2
  108. package/artifacts/contracts/mock/ERC20MockAltDecimals.sol/ERC20MockAltDecimals.json +318 -0
  109. package/artifacts/contracts/mock/ForceSendMock.sol/ForceSendMock.json +2 -2
  110. package/artifacts/contracts/mock/GenArt721CoreV3_Engine_IncorrectCoreType.sol/GenArt721CoreV3_Engine_IncorrectCoreType.json +2 -2
  111. package/artifacts/contracts/mock/MockAdminACLV0_PROHIBITION.sol/MockAdminACLV0Events_PROHIBITION.json +2 -2
  112. package/artifacts/contracts/mock/MockFileStore.sol/MockFileStore.json +35 -0
  113. package/artifacts/contracts/mock/OriginRegisterMock.sol/OriginRegisterMock.json +2 -2
  114. package/artifacts/contracts/mock/RandomizerV2_NoAssignMock.sol/RandomizerV2_NoAssignMock.json +2 -2
  115. package/artifacts/contracts/randomizer/deprecated/PolyptychRandomizerV0.sol/BasicPolyptychRandomizerV0.json +2 -2
  116. package/artifacts/contracts/randomizer/deprecated/RandomizerV2.sol/BasicRandomizerV2.json +2 -2
  117. package/artifacts/contracts/randomizer/shared/SharedRandomizerV0.sol/SharedRandomizerV0.json +2 -2
  118. package/contracts/BytecodeStorageReaders/BytecodeStorageReaderContractV2.sol +103 -0
  119. package/contracts/BytecodeStorageReaders/UniversalBytecodeStorageReader.sol +70 -0
  120. package/contracts/BytecodeStorageV2Writer.sol +69 -0
  121. package/contracts/DependencyRegistryV0.sol +229 -60
  122. package/contracts/GenArt721CoreV3_Curated.sol +133 -0
  123. package/contracts/OwnedCreate2FactoryV0.sol +173 -0
  124. package/contracts/engine/V3/EngineFactoryV0.sol +10 -2
  125. package/contracts/engine/V3/GenArt721CoreV3_Engine.sol +139 -70
  126. package/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol +141 -71
  127. package/contracts/generator/AddressChunks.sol +106 -0
  128. package/contracts/generator/GenArt721GeneratorV0.sol +1094 -0
  129. package/contracts/generator/scripty-support/Scripty.sol +5 -0
  130. package/contracts/interfaces/v0.8.x/IBytecodeStorageReader.sol +34 -36
  131. package/contracts/interfaces/v0.8.x/IBytecodeStorageReaderV2.sol +5 -3
  132. package/contracts/interfaces/v0.8.x/IBytecodeStorageReader_Base.sol +20 -0
  133. package/contracts/interfaces/v0.8.x/ICoreRegistryV1.sol +5 -0
  134. package/contracts/interfaces/v0.8.x/IDependencyRegistryV0.sol +94 -0
  135. package/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Base.sol +13 -2
  136. package/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine.sol +3 -1
  137. package/contracts/interfaces/v0.8.x/IGenArt721CoreProjectScriptV0.sol +22 -0
  138. package/contracts/interfaces/v0.8.x/IGenArt721CoreProjectScriptV1.sol +23 -0
  139. package/contracts/interfaces/v0.8.x/IGenArt721CoreTokenHashProviderV0.sol +11 -0
  140. package/contracts/interfaces/v0.8.x/IGenArt721CoreTokenHashProviderV1.sol +9 -0
  141. package/contracts/interfaces/v0.8.x/IGenArt721GeneratorV0.sol +14 -0
  142. package/contracts/interfaces/v0.8.x/IOwnedCreate2FactoryV0.sol +40 -0
  143. package/contracts/interfaces/v0.8.x/ISeaDropShimForContract.sol +19 -0
  144. package/contracts/interfaces/v0.8.x/ISharedMinterMinPriceV0.sol +22 -0
  145. package/contracts/interfaces/v0.8.x/ISharedMinterRequired.sol +10 -4
  146. package/contracts/interfaces/v0.8.x/IUniversalBytecodeStorageReader.sol +28 -0
  147. package/contracts/interfaces/v0.8.x/integration-refs/OpenSea/ERC721SeaDropStructsErrorsAndEvents.sol +58 -0
  148. package/contracts/interfaces/v0.8.x/integration-refs/OpenSea/INonFungibleSeaDropToken.sol +186 -0
  149. package/contracts/interfaces/v0.8.x/integration-refs/OpenSea/ISeaDrop.sol +337 -0
  150. package/contracts/interfaces/v0.8.x/integration-refs/OpenSea/ISeaDropTokenContractMetadata.sol +152 -0
  151. package/contracts/interfaces/v0.8.x/integration-refs/OpenSea/SeaDropErrorsAndEvents.sol +320 -0
  152. package/contracts/interfaces/v0.8.x/integration-refs/OpenSea/SeaDropStructs.sol +146 -0
  153. package/contracts/libs/v0.8.x/Bytes32Strings.sol +20 -0
  154. package/contracts/libs/v0.8.x/DependencyRegistryStorageLib.sol +11 -3
  155. package/contracts/libs/v0.8.x/JsonStatic.sol +373 -0
  156. package/contracts/libs/v0.8.x/V3FlexLib.sol +9 -3
  157. package/contracts/libs/v0.8.x/minter-libs/MinPriceLib.sol +64 -0
  158. package/contracts/libs/v0.8.x/minter-libs/SplitFundsLib.sol +107 -0
  159. package/contracts/minter-suite/Minters/MinterMinPriceMerkleV0.sol +765 -0
  160. package/contracts/minter-suite/Minters/MinterMinPriceV0.sol +462 -0
  161. package/contracts/minter-suite/Minters/one-off/SeaDropXArtBlocksShim.sol +869 -0
  162. package/contracts/mock/ERC20MockAltDecimals.sol +31 -0
  163. package/contracts/mock/MockFileStore.sol +22 -0
  164. package/package.json +20 -18
@@ -0,0 +1,1094 @@
1
+ // SPDX-License-Identifier: LGPL-3.0-only
2
+ pragma solidity 0.8.22;
3
+
4
+ import "../interfaces/v0.8.x/IDependencyRegistryV0.sol";
5
+ import "../interfaces/v0.8.x/IGenArt721CoreProjectScriptV0.sol";
6
+ import "../interfaces/v0.8.x/IGenArt721CoreProjectScriptV1.sol";
7
+ import "../interfaces/v0.8.x/IGenArt721CoreTokenHashProviderV0.sol";
8
+ import "../interfaces/v0.8.x/IGenArt721CoreTokenHashProviderV1.sol";
9
+ import "../interfaces/v0.8.x/IGenArt721GeneratorV0.sol";
10
+ import {IGenArt721CoreContractV3_Engine_Flex} from "../interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_Flex.sol";
11
+ import {IUniversalBytecodeStorageReader} from "../interfaces/v0.8.x/IUniversalBytecodeStorageReader.sol";
12
+ import "../libs/v0.8.x/Bytes32Strings.sol";
13
+ import {JsonStatic} from "../libs/v0.8.x/JsonStatic.sol";
14
+ import {ABHelpers} from "../libs/v0.8.x/ABHelpers.sol";
15
+ import {AddressChunks} from "./AddressChunks.sol";
16
+
17
+ import "@openzeppelin-4.7/contracts/utils/Strings.sol";
18
+ import "@openzeppelin-4.8/contracts-upgradeable/proxy/utils/Initializable.sol";
19
+
20
+ import {IScriptyBuilderV2, HTMLRequest, HTMLTagType, HTMLTag} from "scripty.sol/contracts/scripty/interfaces/IScriptyBuilderV2.sol";
21
+
22
+ // @dev legacy interface for V2 flex contracts - used to get external legacy asset dependencies
23
+ interface ILegacyGenArt721CoreV2_PBAB_Flex {
24
+ enum LegacyExternalAssetDependencyType {
25
+ IPFS,
26
+ ARWEAVE
27
+ }
28
+ // legacy struct for V2 flex contracts
29
+ struct LegacyExternalAssetDependencyWithoutData {
30
+ string cid;
31
+ LegacyExternalAssetDependencyType dependencyType;
32
+ }
33
+
34
+ function projectExternalAssetDependencyByIndex(
35
+ uint256 _projectId,
36
+ uint256 _index
37
+ ) external view returns (LegacyExternalAssetDependencyWithoutData memory);
38
+ }
39
+
40
+ /**
41
+ * @title GenArt721GeneratorV0
42
+ * @author Art Blocks Inc.
43
+ * @notice This contract is used to generate the HTML for Art Blocks tokens
44
+ * by combining the dependency script, project script, token data. It utilizes
45
+ * the ScriptyBuilder contract to generate the HTML.
46
+ */
47
+ contract GenArt721GeneratorV0 is Initializable, IGenArt721GeneratorV0 {
48
+ using Bytes32Strings for bytes32;
49
+ using Bytes32Strings for string;
50
+ using JsonStatic for JsonStatic.Json;
51
+
52
+ // @dev This is an upgradable contract so we need to maintain
53
+ // the order of the variables to ensure we don't overwrite
54
+ // storage when upgrading.
55
+ IDependencyRegistryV0 public dependencyRegistry;
56
+ IScriptyBuilderV2 public scriptyBuilder;
57
+ address public gunzipScriptBytecodeAddress;
58
+ IUniversalBytecodeStorageReader public universalBytecodeStorageReader;
59
+
60
+ // @dev contants do not use sequential storage slots, and may be added/removed from upgradeable contracts
61
+ bytes32 constant JS_AT_NA_BYTES32 =
62
+ 0x6a73406e61000000000000000000000000000000000000000000000000000000; // "js@na"
63
+ bytes32 constant SVG_AT_NA_BYTES32 =
64
+ 0x737667406e610000000000000000000000000000000000000000000000000000; // "svg@na"
65
+
66
+ function _onlySupportedCoreContract(address coreContract) internal view {
67
+ require(
68
+ dependencyRegistry.isSupportedCoreContract(coreContract),
69
+ "Unsupported core contract"
70
+ );
71
+ }
72
+
73
+ function _onlyDependencyRegistryAdminACL(bytes4 selector) internal {
74
+ require(
75
+ dependencyRegistry.adminACLAllowed({
76
+ sender: msg.sender,
77
+ contract_: address(this),
78
+ selector: selector
79
+ }),
80
+ "Only DependencyRegistry AdminACL"
81
+ );
82
+ }
83
+
84
+ /**
85
+ * @notice Initializer for the GenArt721GeneratorV0 contract.
86
+ * @param _dependencyRegistry The address of the DependencyRegistry
87
+ * contract to be used for retrieving dependency scripts.
88
+ * @param _scriptyBuilder The address of the ScriptyBuilderV2 contract
89
+ * to be used for generating the HTML for tokens.
90
+ * @param _gunzipScriptBytecodeAddress The address of the gunzip script bytecode
91
+ * storage contract used to gunzip the dependency scripts in the browser.
92
+ * @param _universalBytecodeStorageReader The address of the universal bytecode storage reader contract.
93
+ */
94
+ function initialize(
95
+ address _dependencyRegistry,
96
+ address _scriptyBuilder,
97
+ address _gunzipScriptBytecodeAddress,
98
+ address _universalBytecodeStorageReader
99
+ ) public initializer {
100
+ dependencyRegistry = IDependencyRegistryV0(_dependencyRegistry);
101
+ scriptyBuilder = IScriptyBuilderV2(_scriptyBuilder);
102
+ gunzipScriptBytecodeAddress = _gunzipScriptBytecodeAddress;
103
+ universalBytecodeStorageReader = IUniversalBytecodeStorageReader(
104
+ _universalBytecodeStorageReader
105
+ );
106
+
107
+ emit DependencyRegistryUpdated(_dependencyRegistry);
108
+ emit ScriptyBuilderUpdated(_scriptyBuilder);
109
+ emit GunzipScriptBytecodeAddressUpdated(_gunzipScriptBytecodeAddress);
110
+ emit UniversalBytecodeStorageReaderUpdated(
111
+ _universalBytecodeStorageReader
112
+ );
113
+ }
114
+
115
+ /**
116
+ * @notice Set the DependencyRegistry contract address.
117
+ * @param _dependencyRegistry The address of the DependencyRegistry
118
+ * contract to be used for retrieving dependency scripts.
119
+ * @dev This function is gated to only the DependencyRegistry AdminACL.
120
+ * If an address is passed that does not implement the adminACLAllowed
121
+ * function, we will lose access to the write functions on this contract.
122
+ */
123
+ function updateDependencyRegistry(address _dependencyRegistry) external {
124
+ _onlyDependencyRegistryAdminACL(this.updateDependencyRegistry.selector);
125
+
126
+ dependencyRegistry = IDependencyRegistryV0(_dependencyRegistry);
127
+ emit DependencyRegistryUpdated(_dependencyRegistry);
128
+ }
129
+
130
+ /**
131
+ * @notice Set the ScriptyBuilder contract address.
132
+ * @param _scriptyBuilder The address of the ScriptyBuilderV2 contract
133
+ * to be used for generating the HTML for tokens.
134
+ * @dev This function is gated to only the DependencyRegistry AdminACL.
135
+ */
136
+ function updateScriptyBuilder(address _scriptyBuilder) external {
137
+ _onlyDependencyRegistryAdminACL(this.updateScriptyBuilder.selector);
138
+
139
+ scriptyBuilder = IScriptyBuilderV2(_scriptyBuilder);
140
+ emit ScriptyBuilderUpdated(_scriptyBuilder);
141
+ }
142
+
143
+ /**
144
+ * @notice Set the gunzip script address.
145
+ * @param _gunzipScriptBytecodeAddress The address of the gunzip script bytecode
146
+ * storage contract used to gunzip the dependency scripts in the browser.
147
+ * @dev This function is gated to only the DependencyRegistry AdminACL.
148
+ */
149
+ function updateGunzipScriptBytecodeAddress(
150
+ address _gunzipScriptBytecodeAddress
151
+ ) external {
152
+ _onlyDependencyRegistryAdminACL(
153
+ this.updateGunzipScriptBytecodeAddress.selector
154
+ );
155
+
156
+ gunzipScriptBytecodeAddress = _gunzipScriptBytecodeAddress;
157
+ emit GunzipScriptBytecodeAddressUpdated(_gunzipScriptBytecodeAddress);
158
+ }
159
+
160
+ /**
161
+ * @notice Set the universalBytecodeStorageReader contract address.
162
+ * @param _universalBytecodeStorageReader The address of the universal bytecode storage reader contract.
163
+ * @dev This function is gated to only the DependencyRegistry AdminACL.
164
+ */
165
+ function updateUniversalBytecodeStorageReader(
166
+ address _universalBytecodeStorageReader
167
+ ) external {
168
+ _onlyDependencyRegistryAdminACL(
169
+ this.updateUniversalBytecodeStorageReader.selector
170
+ );
171
+
172
+ universalBytecodeStorageReader = IUniversalBytecodeStorageReader(
173
+ _universalBytecodeStorageReader
174
+ );
175
+ emit UniversalBytecodeStorageReaderUpdated(
176
+ _universalBytecodeStorageReader
177
+ );
178
+ }
179
+
180
+ /**
181
+ * @notice Get the dependency script for a given dependency name and version string.
182
+ * @param dependencyNameAndVersion The name and version of the dependency
183
+ * to retrieve the script for.
184
+ * @return The dependency script stiched together from all of the script chunks as a string.
185
+ * @dev This function will revert if the dependency name and version is not
186
+ * supported by the DependencyRegistry or if the script storage version is
187
+ * not supported.
188
+ */
189
+ function getDependencyScript(
190
+ string memory dependencyNameAndVersion
191
+ ) external view returns (string memory) {
192
+ bytes memory dependencyScript = _getDependencyScriptBytes(
193
+ dependencyNameAndVersion.stringToBytes32()
194
+ );
195
+
196
+ return string(dependencyScript);
197
+ }
198
+
199
+ /**
200
+ * @notice Get the project script for a given core contract address and
201
+ * project ID.
202
+ * @param coreContract The address of the core contract to retrieve
203
+ * the project script from.
204
+ * @param projectId The ID of the project to retrieve the script for.
205
+ * @return The project script stiched together from all of the script chunks as a string.
206
+ * @dev This function will revert if the core contract address is not
207
+ * supported by the DependencyRegistry or if the contract at the address
208
+ * does not implement the IGenArt721CoreProjectScriptV0 or IGenArt721CoreProjectScriptV1.
209
+ */
210
+ function getProjectScript(
211
+ address coreContract,
212
+ uint256 projectId
213
+ ) external view returns (string memory) {
214
+ bytes memory projectScript = _getProjectScriptBytes(
215
+ coreContract,
216
+ projectId
217
+ );
218
+
219
+ return string(projectScript);
220
+ }
221
+
222
+ /**
223
+ * @notice Get the data URI for the HTML for a given token (e.g. data:text/html;base64,[html])
224
+ * @param coreContract The address of the core contract the token belongs to.
225
+ * @param tokenId The ID of the token to retrieve the HTML for.
226
+ * @return The data URI for the HTML for the token.
227
+ */
228
+ function getTokenHtmlBase64EncodedDataUri(
229
+ address coreContract,
230
+ uint256 tokenId
231
+ ) external view returns (string memory) {
232
+ HTMLRequest memory htmlRequest = _getTokenHtmlRequest(
233
+ coreContract,
234
+ tokenId
235
+ );
236
+ string memory base64EncodedHTMLDataURI = scriptyBuilder
237
+ .getEncodedHTMLString(htmlRequest);
238
+
239
+ return base64EncodedHTMLDataURI;
240
+ }
241
+
242
+ /**
243
+ * @notice Get the HTML for a given token.
244
+ * @param coreContract The address of the core contract the token belongs to.
245
+ * @param tokenId The ID of the token to retrieve the HTML for.
246
+ * @return The HTML for the token.
247
+ */
248
+ function getTokenHtml(
249
+ address coreContract,
250
+ uint256 tokenId
251
+ ) external view returns (string memory) {
252
+ HTMLRequest memory htmlRequest = _getTokenHtmlRequest(
253
+ coreContract,
254
+ tokenId
255
+ );
256
+ string memory html = scriptyBuilder.getHTMLString(htmlRequest);
257
+
258
+ return html;
259
+ }
260
+
261
+ /**
262
+ * @notice Gets summary of details of how on-chain a project is.
263
+ * @param coreContract The core contract address to query.
264
+ * @param projectId The project ID to query.
265
+ * @return dependencyFullyOnChain Whether the project's dependency is fully on-chain.
266
+ * @return injectsDecentralizedStorageNetworkAssets Whether the project injects decentralized storage network assets.
267
+ * @return hasOffChainFlexDepRegDependencies True if the project uses flex assets of type ART_BLOCKS_DEPENDENCY_REGISTRY
268
+ * that are not fully on-chain; false otherwise.
269
+ */
270
+ function getOnChainStatus(
271
+ address coreContract,
272
+ uint256 projectId
273
+ )
274
+ external
275
+ view
276
+ returns (
277
+ bool dependencyFullyOnChain,
278
+ bool injectsDecentralizedStorageNetworkAssets,
279
+ bool hasOffChainFlexDepRegDependencies
280
+ )
281
+ {
282
+ // get dependency name and version
283
+ bytes32 dependencyNameAndVersion = dependencyRegistry
284
+ .getDependencyNameAndVersionForProject(coreContract, projectId)
285
+ .stringToBytes32();
286
+ dependencyFullyOnChain = _getIsDependencyOnChain(
287
+ dependencyNameAndVersion
288
+ );
289
+
290
+ // iterate over project's flex dependencies to check if they are fully on-chain
291
+ if (_getIsFlex(coreContract)) {
292
+ // @dev all flex (V2, V3) contracts have the function projectExternalAssetDependencyCount()
293
+ uint256 externalAssetDependencyCount = IGenArt721CoreContractV3_Engine_Flex(
294
+ coreContract
295
+ ).projectExternalAssetDependencyCount({_projectId: projectId});
296
+ for (uint256 i = 0; i < externalAssetDependencyCount; i++) {
297
+ // get external asset dependency with data
298
+ IGenArt721CoreContractV3_Engine_Flex.ExternalAssetDependencyWithData
299
+ memory externalAssetDependencyWithData = _getProjectExternalAssetDependencyByIndex({
300
+ coreContract: coreContract,
301
+ projectId: projectId,
302
+ index: i
303
+ });
304
+ // if ipfs or arweave, label injectsDecentralizedStorageNetworkAssets as true
305
+ if (
306
+ externalAssetDependencyWithData.dependencyType ==
307
+ IGenArt721CoreContractV3_Engine_Flex
308
+ .ExternalAssetDependencyType
309
+ .IPFS ||
310
+ externalAssetDependencyWithData.dependencyType ==
311
+ IGenArt721CoreContractV3_Engine_Flex
312
+ .ExternalAssetDependencyType
313
+ .ARWEAVE
314
+ ) {
315
+ // if any dependency is IPFS or ARWEAVE, label injectsDecentralizedStorageNetworkAssets as true
316
+ injectsDecentralizedStorageNetworkAssets = true;
317
+ } else if (
318
+ externalAssetDependencyWithData.dependencyType ==
319
+ IGenArt721CoreContractV3_Engine_Flex
320
+ .ExternalAssetDependencyType
321
+ .ART_BLOCKS_DEPENDENCY_REGISTRY
322
+ ) {
323
+ // get the bytes representation of the dependencyRegistryAsset
324
+ bytes32 currentDependencyNameAndVersion = externalAssetDependencyWithData
325
+ .cid
326
+ .stringToBytes32();
327
+ bool currentDependencyFullyOnChain = _getIsDependencyOnChain(
328
+ currentDependencyNameAndVersion
329
+ );
330
+ if (!(currentDependencyFullyOnChain)) {
331
+ // return (true, true, true);
332
+ // // if any dependency is not fully on-chain, label usesDependencyRegistryFlexAssetsNotFullyOnChain as true
333
+ hasOffChainFlexDepRegDependencies = true;
334
+ }
335
+ }
336
+ }
337
+ }
338
+
339
+ // @dev all return values previously populated or remain at initial values of false
340
+ }
341
+
342
+ /**
343
+ * @notice Get the dependency script for a given dependency name and version.
344
+ * @param dependencyNameAndVersion The name and version of the dependency
345
+ * to retrieve the script for.
346
+ * @return The dependency script stiched together from all of the script chunks.
347
+ * @dev This function will revert if the dependency name and version is not
348
+ * supported by the DependencyRegistry or if the script storage version is
349
+ * not supported.
350
+ */
351
+ function _getDependencyScriptBytes(
352
+ bytes32 dependencyNameAndVersion
353
+ ) internal view returns (bytes memory) {
354
+ uint256 scriptCount = dependencyRegistry.getDependencyScriptCount(
355
+ dependencyNameAndVersion
356
+ );
357
+
358
+ if (scriptCount == 0) {
359
+ return "";
360
+ }
361
+
362
+ address[] memory scriptBytecodeAddresses = new address[](scriptCount);
363
+
364
+ for (uint256 i = 0; i < scriptCount; i++) {
365
+ scriptBytecodeAddresses[i] = dependencyRegistry
366
+ .getDependencyScriptBytecodeAddress(
367
+ dependencyNameAndVersion,
368
+ i
369
+ );
370
+ }
371
+
372
+ // @dev We concatenate the script chunks together with assembly
373
+ // in AddressChunks for gas efficiency.
374
+ return
375
+ AddressChunks.mergeChunks(
376
+ scriptBytecodeAddresses,
377
+ address(universalBytecodeStorageReader)
378
+ );
379
+ }
380
+
381
+ /**
382
+ * @notice Get the project script for a given core contract address and
383
+ * project ID.
384
+ * @param coreContract The address of the core contract to retrieve
385
+ * the project script from.
386
+ * @param projectId The ID of the project to retrieve the script for.
387
+ * @return The project script stiched together from all of the script chunks.
388
+ * @dev This function will revert if the core contract address is not
389
+ * supported by the DependencyRegistry or if the contract at the address
390
+ * does not implement the IGenArt721CoreProjectScriptV0 or IGenArt721CoreProjectScriptV1.
391
+ */
392
+ function _getProjectScriptBytes(
393
+ address coreContract,
394
+ uint256 projectId
395
+ ) internal view returns (bytes memory) {
396
+ _onlySupportedCoreContract(coreContract);
397
+
398
+ // @dev Attempt to get project script info from V3 and up core contracts first.
399
+ try
400
+ IGenArt721CoreProjectScriptV1(coreContract).projectScriptDetails(
401
+ projectId
402
+ )
403
+ returns (string memory, string memory, uint256 scriptCount) {
404
+ if (scriptCount == 0) {
405
+ return "";
406
+ }
407
+
408
+ address[] memory scriptBytecodeAddresses = new address[](
409
+ scriptCount
410
+ );
411
+
412
+ for (uint256 i = 0; i < scriptCount; i++) {
413
+ scriptBytecodeAddresses[i] = IGenArt721CoreProjectScriptV1(
414
+ coreContract
415
+ ).projectScriptBytecodeAddressByIndex(projectId, i);
416
+ }
417
+
418
+ // @dev We concatenate the script chunks together with assembly
419
+ // in AddressChunks for gas efficiency.
420
+ return
421
+ AddressChunks.mergeChunks(
422
+ scriptBytecodeAddresses,
423
+ address(universalBytecodeStorageReader)
424
+ );
425
+ } catch {
426
+ // Noop try again for older contracts.
427
+ }
428
+
429
+ // @dev If we failed to get the project script info try again using the interface
430
+ // for V2 and older core contracts.
431
+ try
432
+ IGenArt721CoreProjectScriptV0(coreContract).projectScriptInfo(
433
+ projectId
434
+ )
435
+ returns (string memory, uint256 scriptCount) {
436
+ if (scriptCount == 0) {
437
+ return "";
438
+ }
439
+
440
+ string memory script;
441
+ for (uint256 i = 0; i < scriptCount; i++) {
442
+ string memory scriptChunk = IGenArt721CoreProjectScriptV0(
443
+ coreContract
444
+ ).projectScriptByIndex(projectId, i);
445
+ script = string.concat(script, scriptChunk);
446
+ }
447
+
448
+ return bytes(script);
449
+ } catch {
450
+ revert("Unable to retrieve project script info");
451
+ }
452
+ }
453
+
454
+ /**
455
+ * @notice Get the isFlex status for a given core contract.
456
+ * @dev uses the existence of preferredIPFSGateway function as indicator for flex contracts.
457
+ * @param coreContract The core contract address to check if it is a flex contract.
458
+ */
459
+ function _getIsFlex(address coreContract) internal view returns (bool) {
460
+ try
461
+ // @dev all flex (V2, V3) contracts have this function, so use as isFlex indicator
462
+ IGenArt721CoreContractV3_Engine_Flex(coreContract)
463
+ .preferredIPFSGateway()
464
+ returns (string memory) {
465
+ // if contract did not revert, interpret it is a flex contract
466
+ return true;
467
+ } catch {
468
+ // if contract reverted, interpret it is not a flex contract
469
+ return false;
470
+ }
471
+ }
472
+
473
+ /**
474
+ * @notice Get if a flex contract is a V2 flex contract.
475
+ * Assumes that the core contract is a flex contract.
476
+ * @param flexCoreContract The core contract address to check if it is a V2 flex contract.
477
+ * @return isV2Flex Whether the core contract is a V2 flex contract.
478
+ */
479
+ function _getIsV2Flex(
480
+ address flexCoreContract
481
+ ) internal view returns (bool) {
482
+ // @dev all flex (V2, V3) contracts have the function coreType(),
483
+ // and all V2 flex contracts have the coreType "GenArt721CoreV2_ENGINE_FLEX"
484
+ string memory coreType = IGenArt721CoreContractV3_Engine_Flex(
485
+ flexCoreContract
486
+ ).coreType();
487
+ return
488
+ keccak256(abi.encodePacked(coreType)) ==
489
+ keccak256(abi.encodePacked("GenArt721CoreV2_ENGINE_FLEX"));
490
+ }
491
+
492
+ /**
493
+ * @notice Get the external asset dependency for a given project and index.
494
+ * @dev This function handles both V2 and V3 flex contracts, and converts the legacy V2 external asset dependency
495
+ * type to the V3 external asset dependency type, as the V3 type is a superset of the V2 type.
496
+ * @param coreContract The core contract address the project belongs to.
497
+ * @param projectId The ID of the project to retrieve the external asset dependency for.
498
+ * @param index The index of the external asset dependency to retrieve.
499
+ * @return The external asset dependency for the project and index.
500
+ */
501
+ function _getProjectExternalAssetDependencyByIndex(
502
+ address coreContract,
503
+ uint256 projectId,
504
+ uint256 index
505
+ )
506
+ internal
507
+ view
508
+ returns (
509
+ IGenArt721CoreContractV3_Engine_Flex.ExternalAssetDependencyWithData
510
+ memory
511
+ )
512
+ {
513
+ // pre-allocate generic externalAssetDependencyWithData to avoid dynamic memory allocation
514
+ IGenArt721CoreContractV3_Engine_Flex.ExternalAssetDependencyWithData
515
+ memory externalAssetDependencyWithData = IGenArt721CoreContractV3_Engine_Flex
516
+ .ExternalAssetDependencyWithData({
517
+ cid: "",
518
+ dependencyType: IGenArt721CoreContractV3_Engine_Flex
519
+ .ExternalAssetDependencyType
520
+ .IPFS, // default to IPFS, index 0 of enum
521
+ bytecodeAddress: address(0),
522
+ data: ""
523
+ });
524
+ // @dev flex V2 and V3 have different return types for the function projectExternalAssetDependencyByIndex - must branch logic
525
+ // @dev reference change in return type between V2 and V3 here: https://github.com/ArtBlocks/artblocks-contracts/pull/450
526
+ // @dev acknowledge that this could be function input parameter to avoid one call per dependency, but
527
+ // stack to deep error limits memoization opportunity in functions calling this function
528
+ if (_getIsV2Flex(coreContract)) {
529
+ ILegacyGenArt721CoreV2_PBAB_Flex.LegacyExternalAssetDependencyWithoutData
530
+ memory legacyExternalAssetDependencyWithoutData = ILegacyGenArt721CoreV2_PBAB_Flex(
531
+ coreContract
532
+ ).projectExternalAssetDependencyByIndex({
533
+ _projectId: projectId,
534
+ _index: index
535
+ });
536
+ // populate external asset dependency json object
537
+ externalAssetDependencyWithData
538
+ .cid = legacyExternalAssetDependencyWithoutData.cid;
539
+ // @dev legacy external asset dependency types are a subset of V3 external asset dependency types,
540
+ // so we can safely cast the legacy type to the V3 type
541
+ externalAssetDependencyWithData
542
+ .dependencyType = IGenArt721CoreContractV3_Engine_Flex
543
+ .ExternalAssetDependencyType(
544
+ uint256(
545
+ legacyExternalAssetDependencyWithoutData.dependencyType
546
+ )
547
+ );
548
+ // leave data as empty string - V2 contracts do not support data
549
+ } else {
550
+ externalAssetDependencyWithData = IGenArt721CoreContractV3_Engine_Flex(
551
+ coreContract
552
+ ).projectExternalAssetDependencyByIndex({
553
+ _projectId: projectId,
554
+ _index: index
555
+ });
556
+ }
557
+ return externalAssetDependencyWithData;
558
+ }
559
+
560
+ /**
561
+ * @notice get external asset dependency and populate json keys and values,
562
+ * as well as any dependency name and version if the dependency is an
563
+ * ART_BLOCKS_DEPENDENCY_REGISTRY dependency.
564
+ * @param coreContract The core contract address the project belongs to.
565
+ * @param projectId The ID of the project to retrieve the external asset dependency for.
566
+ * @param index The index of the external asset dependency to retrieve.
567
+ */
568
+ function _getExternalAssetDependencyKeysAndValues(
569
+ address coreContract,
570
+ uint256 projectId,
571
+ uint256 index
572
+ )
573
+ internal
574
+ view
575
+ returns (
576
+ string[] memory /*keys*/,
577
+ JsonStatic.Json[] memory /*values*/,
578
+ bytes32 /*dependencyNameAndVersion*/
579
+ )
580
+ {
581
+ // default as not an art blocks dependency registry dependency
582
+ bytes32 dependencyNameAndVersion; // default as not an art blocks dependency registry dependency
583
+ // each external asset dependency has 3 fields, so pre-allocate array to avoid dynamic memory allocation
584
+ JsonStatic.Json[] memory dependencyValues = JsonStatic.newValuesArray(
585
+ 3
586
+ );
587
+ string[] memory dependencyKeys = JsonStatic.newKeysArray(3);
588
+ // get external asset dependency with data
589
+ IGenArt721CoreContractV3_Engine_Flex.ExternalAssetDependencyWithData
590
+ memory externalAssetDependencyWithData = _getProjectExternalAssetDependencyByIndex({
591
+ coreContract: coreContract,
592
+ projectId: projectId,
593
+ index: index
594
+ });
595
+ // populate external asset dependency json object
596
+ dependencyKeys[0] = "dependency_type";
597
+ dependencyValues[0] = JsonStatic.newStringElement({
598
+ value: _dependencyTypeToString(
599
+ externalAssetDependencyWithData.dependencyType
600
+ ),
601
+ stringEncodingFlag: JsonStatic.StringEncodingFlag.NONE
602
+ });
603
+ dependencyKeys[1] = "cid";
604
+ dependencyValues[1] = JsonStatic.newStringElement({
605
+ value: externalAssetDependencyWithData.cid,
606
+ stringEncodingFlag: JsonStatic.StringEncodingFlag.NONE
607
+ });
608
+ dependencyKeys[2] = "data";
609
+ if (
610
+ externalAssetDependencyWithData.dependencyType ==
611
+ IGenArt721CoreContractV3_Engine_Flex
612
+ .ExternalAssetDependencyType
613
+ .ONCHAIN
614
+ ) {
615
+ dependencyValues[2] = JsonStatic.newStringElement({
616
+ value: externalAssetDependencyWithData.data, // assign data for ONCHAIN dependencies
617
+ stringEncodingFlag: JsonStatic.StringEncodingFlag.BASE64
618
+ });
619
+ } else {
620
+ dependencyValues[2] = JsonStatic.newStringElement({
621
+ value: "", // empty string for non-ONCHAIN dependencies
622
+ stringEncodingFlag: JsonStatic.StringEncodingFlag.BASE64
623
+ });
624
+ if (
625
+ externalAssetDependencyWithData.dependencyType ==
626
+ IGenArt721CoreContractV3_Engine_Flex
627
+ .ExternalAssetDependencyType
628
+ .ART_BLOCKS_DEPENDENCY_REGISTRY
629
+ ) {
630
+ // get the bytes representation of the dependencyRegistryAsset
631
+ dependencyNameAndVersion = externalAssetDependencyWithData
632
+ .cid
633
+ .stringToBytes32();
634
+ }
635
+ }
636
+ return (dependencyKeys, dependencyValues, dependencyNameAndVersion);
637
+ }
638
+
639
+ /**
640
+ * @notice Get the token data for a given token.
641
+ * @param coreContract The core contract address the token belongs to.
642
+ * @param tokenId The ID of the token to retrieve the data for.
643
+ * @return tokenDataJson The token data as a JSON string as bytes.
644
+ * @return dependencyRegistryAssetNameAndVersions Any dependency registry asset name and versions
645
+ * as bytes32 (will contain default-value bytes32 if not an ART_BLOCKS_DEPENDENCY_REGISTRY dependency).
646
+ */
647
+ function _getTokenDataAndDependencyRegistryAssets(
648
+ address coreContract,
649
+ uint256 tokenId
650
+ )
651
+ internal
652
+ view
653
+ returns (
654
+ bytes memory tokenDataJson,
655
+ bytes32[] memory dependencyRegistryAssetNameAndVersions
656
+ )
657
+ {
658
+ // get any flex assets
659
+ bool isFlex = _getIsFlex({coreContract: coreContract});
660
+
661
+ // build tokenData json object
662
+ string[] memory tokenDataKeys = isFlex
663
+ ? JsonStatic.newKeysArray(5)
664
+ : JsonStatic.newKeysArray(2);
665
+ JsonStatic.Json[] memory tokenDataValues = isFlex
666
+ ? JsonStatic.newValuesArray(5)
667
+ : JsonStatic.newValuesArray(2);
668
+
669
+ // token id
670
+ tokenDataKeys[0] = "tokenId";
671
+ tokenDataValues[0] = JsonStatic.newStringElement({
672
+ value: Strings.toString(tokenId),
673
+ stringEncodingFlag: JsonStatic.StringEncodingFlag.NONE
674
+ });
675
+
676
+ // token hash
677
+ // @dev block scope to avoid stack too deep error
678
+ {
679
+ // @dev Attempt to get token hash from V1 and up core contracts first.
680
+ (bytes32 tokenHash, bool isV0CoreContract) = _getTokenHash(
681
+ coreContract,
682
+ tokenId
683
+ );
684
+ if (isV0CoreContract) {
685
+ // @dev V0 contracts return an array of hashes, with only one hash
686
+ tokenDataKeys[1] = "hashes";
687
+ JsonStatic.Json[] memory tokenDataValuesHashes = JsonStatic
688
+ .newValuesArray(1);
689
+ tokenDataValuesHashes[0] = JsonStatic.newStringElement({
690
+ value: Strings.toHexString(uint256(tokenHash)),
691
+ stringEncodingFlag: JsonStatic.StringEncodingFlag.NONE
692
+ });
693
+ tokenDataValues[1] = JsonStatic.newArrayElement({
694
+ values: tokenDataValuesHashes
695
+ });
696
+ } else {
697
+ tokenDataKeys[1] = "hash";
698
+ tokenDataValues[1] = JsonStatic.newStringElement({
699
+ value: Strings.toHexString(uint256(tokenHash)),
700
+ stringEncodingFlag: JsonStatic.StringEncodingFlag.NONE
701
+ });
702
+ }
703
+ }
704
+
705
+ // flex contracts have additional fields
706
+ dependencyRegistryAssetNameAndVersions = new bytes32[](0); // default if no assets or not flex
707
+ if (isFlex) {
708
+ // preferredIPFSGateway
709
+ tokenDataKeys[2] = "preferredArweaveGateway";
710
+ // @dev all flex (V2, V3) contracts have the function preferredArweaveGateway()
711
+ tokenDataValues[2] = JsonStatic.newStringElement({
712
+ value: IGenArt721CoreContractV3_Engine_Flex(coreContract)
713
+ .preferredArweaveGateway(),
714
+ stringEncodingFlag: JsonStatic.StringEncodingFlag.NONE
715
+ });
716
+
717
+ // preferredArweaveGateway
718
+ tokenDataKeys[3] = "preferredIPFSGateway";
719
+ // @dev all flex (V2, V3) contracts have the function preferredIPFSGateway()
720
+ tokenDataValues[3] = JsonStatic.newStringElement({
721
+ value: IGenArt721CoreContractV3_Engine_Flex(coreContract)
722
+ .preferredIPFSGateway(),
723
+ stringEncodingFlag: JsonStatic.StringEncodingFlag.NONE
724
+ });
725
+
726
+ // externalAssetDependencies (variable length array)
727
+ tokenDataKeys[4] = "externalAssetDependencies";
728
+ // @dev pre-allocate array to avoid dynamic memory allocation of variable-length array
729
+ uint256 projectId = ABHelpers.tokenIdToProjectId(tokenId);
730
+ // @dev all flex (V2, V3) contracts have the function projectExternalAssetDependencyCount()
731
+ uint256 externalAssetDependencyCount = IGenArt721CoreContractV3_Engine_Flex(
732
+ coreContract
733
+ ).projectExternalAssetDependencyCount({_projectId: projectId});
734
+ JsonStatic.Json[] memory externalAssetDependencies = JsonStatic
735
+ .newValuesArray(externalAssetDependencyCount);
736
+ // populate the type and version of all ART_BLOCKS_DEPENDENCY_REGISTRY dependencies
737
+ dependencyRegistryAssetNameAndVersions = new bytes32[](
738
+ externalAssetDependencyCount
739
+ );
740
+ for (uint256 i = 0; i < externalAssetDependencyCount; i++) {
741
+ (
742
+ string[] memory dependencyKeys,
743
+ JsonStatic.Json[] memory dependencyValues,
744
+ bytes32 dependencyNameAndVersion
745
+ ) = _getExternalAssetDependencyKeysAndValues({
746
+ coreContract: coreContract,
747
+ projectId: projectId,
748
+ index: i
749
+ });
750
+ // handle ART_BLOCKS_DEPENDENCY_REGISTRY dependency type
751
+ if (dependencyNameAndVersion != bytes32(0)) {
752
+ dependencyRegistryAssetNameAndVersions[
753
+ i
754
+ ] = dependencyNameAndVersion;
755
+ }
756
+
757
+ // build tokenData json object
758
+ externalAssetDependencies[i] = JsonStatic.newObjectElement({
759
+ keys: dependencyKeys,
760
+ values: dependencyValues
761
+ });
762
+ }
763
+
764
+ // assign externalAssetDependencies array to tokenDataValues
765
+ tokenDataValues[4] = JsonStatic.newArrayElement(
766
+ externalAssetDependencies
767
+ );
768
+ }
769
+
770
+ // build tokenData json object
771
+ JsonStatic.Json memory tokenData = JsonStatic.newObjectElement({
772
+ keys: tokenDataKeys,
773
+ values: tokenDataValues
774
+ });
775
+
776
+ // return tokenData as bytes-encoded JSON string via write function
777
+ return (
778
+ bytes(tokenData.write()),
779
+ dependencyRegistryAssetNameAndVersions
780
+ );
781
+ }
782
+
783
+ /**
784
+ * @notice populates an empty HTMLTag with script information for a given dependency.
785
+ * Assumes the dependency is available on the dependencyRegistry.
786
+ * Populates the script via on-chain information if available, otherwise injects script tag with src
787
+ * pointing to the preferred CDN.
788
+ * @param dependencyNameAndVersion The name and version of the dependency to populate the script for.
789
+ * @param htmlTag The HTMLTag to populate with the script information, memory reference; modified in place.
790
+ */
791
+ function _populateDependencyScriptHtmlTag(
792
+ bytes32 dependencyNameAndVersion,
793
+ HTMLTag memory htmlTag
794
+ ) internal view {
795
+ // Get script count and preferred CDN for the dependency.
796
+ (
797
+ ,
798
+ ,
799
+ string memory preferredCDN,
800
+ ,
801
+ ,
802
+ ,
803
+ ,
804
+ ,
805
+ uint24 scriptCount
806
+ ) = dependencyRegistry.getDependencyDetails(dependencyNameAndVersion);
807
+
808
+ // If no scripts on-chain, load the script from the preferred CDN.
809
+ if (scriptCount == 0) {
810
+ bool cdnAvailable = bytes(preferredCDN).length > 0;
811
+ // If no CDN is available, we don't need to add any tags.
812
+ // Expected for dependencies like "js@na" and "svg@na".
813
+ htmlTag.tagOpen = cdnAvailable
814
+ ? abi.encodePacked(
815
+ '<script type="text/javascript" src="',
816
+ preferredCDN,
817
+ '">'
818
+ )
819
+ : bytes("");
820
+ htmlTag.tagClose = bytes(cdnAvailable ? "</script>" : "");
821
+ } else {
822
+ bytes memory dependencyScript = _getDependencyScriptBytes(
823
+ dependencyNameAndVersion
824
+ );
825
+ htmlTag.tagContent = dependencyScript;
826
+ htmlTag.tagType = HTMLTagType.scriptGZIPBase64DataURI; // <script type="text/javascript+gzip" src="data:text/javascript;base64,[script]"></script>
827
+ }
828
+ }
829
+
830
+ /**
831
+ * @notice Get the HTMLRequest for a given token.
832
+ * @param coreContract The core contract address the token belongs to.
833
+ * @param tokenId The ID of the token to retrieve the HTMLRequest for.
834
+ * @return The HTMLRequest for the token.
835
+ */
836
+ function _getTokenHtmlRequest(
837
+ address coreContract,
838
+ uint256 tokenId
839
+ ) internal view returns (HTMLRequest memory) {
840
+ _onlySupportedCoreContract(coreContract);
841
+
842
+ uint256 projectId = ABHelpers.tokenIdToProjectId(tokenId);
843
+ // This will revert for older contracts that do not have an override set.
844
+ bytes32 dependencyNameAndVersion = dependencyRegistry
845
+ .getDependencyNameAndVersionForProject(coreContract, projectId)
846
+ .stringToBytes32();
847
+
848
+ // Create head tags
849
+ // pre-fetch data to properly allocate memory for HTML tags
850
+ (
851
+ bytes memory tokenDataJson,
852
+ bytes32[] memory dependencyRegistryAssetNameAndVersions
853
+ ) = _getTokenDataAndDependencyRegistryAssets({
854
+ coreContract: coreContract,
855
+ tokenId: tokenId
856
+ });
857
+ // @dev memoize length for efficiency
858
+ uint256 dependencyRegistryAssetNamesAndVersionsLength = dependencyRegistryAssetNameAndVersions
859
+ .length;
860
+ // @dev length is 2 (style, tokenData) + number of external asset dependencies
861
+ HTMLTag[] memory headTags = new HTMLTag[](
862
+ 2 + dependencyRegistryAssetNamesAndVersionsLength
863
+ );
864
+ headTags[0].tagOpen = "<style>";
865
+ headTags[0]
866
+ .tagContent = "html{height:100%}body{min-height:100%;margin:0;padding:0}canvas{padding:0;margin:auto;display:block;position:absolute;top:0;bottom:0;left:0;right:0}";
867
+ headTags[0].tagClose = "</style>";
868
+
869
+ // @dev decode any base64 encoded flex data in the browser while parsing the json
870
+ headTags[1].tagContent = abi.encodePacked(
871
+ "let tokenData = JSON.parse(`",
872
+ tokenDataJson,
873
+ '`, (key, value) => key === "data" && value !== null ? atob(value) : value);'
874
+ );
875
+ headTags[1].tagType = HTMLTagType.script;
876
+ for (
877
+ uint256 i = 0;
878
+ i < dependencyRegistryAssetNamesAndVersionsLength;
879
+ i++
880
+ ) {
881
+ // skip if empty (not a dependency registry asset)
882
+ // @dev okay to have empty html tags - they will be ignored
883
+ if (dependencyRegistryAssetNameAndVersions[i] == bytes32(0)) {
884
+ continue;
885
+ }
886
+ // populate head tags with dependency registry scripts
887
+ _populateDependencyScriptHtmlTag(
888
+ dependencyRegistryAssetNameAndVersions[i],
889
+ headTags[2 + i]
890
+ );
891
+ }
892
+
893
+ // Create body tags
894
+ HTMLTag[] memory bodyTags = new HTMLTag[](4);
895
+
896
+ // Dependency script tag
897
+ _populateDependencyScriptHtmlTag(dependencyNameAndVersion, bodyTags[0]);
898
+
899
+ // @dev We expect all of our dependencies to be added gzip'd and base64 encoded
900
+ // so we need to include this so we can gunzip them in the browser.
901
+ bodyTags[1].name = "gunzipScripts-0.0.1.js";
902
+ bodyTags[1].tagType = HTMLTagType.scriptBase64DataURI; // <script src="data:text/javascript;base64,[script]"></script>
903
+ bodyTags[1].tagContent = bytes(
904
+ universalBytecodeStorageReader.readFromBytecode(
905
+ gunzipScriptBytecodeAddress
906
+ )
907
+ );
908
+
909
+ HTMLTag memory canvasTag = _createCanvasTagIfNeeded(
910
+ dependencyNameAndVersion
911
+ );
912
+
913
+ bool isProcessingDep = dependencyNameAndVersion ==
914
+ bytes32("processing-js@1.4.6");
915
+
916
+ bytes memory projectScript = _getProjectScriptBytes(
917
+ coreContract,
918
+ projectId
919
+ );
920
+
921
+ HTMLTag memory projectScriptTag = HTMLTag({
922
+ tagOpen: isProcessingDep
923
+ ? bytes("<script type='application/processing'>")
924
+ : bytes("<script>"),
925
+ tagClose: bytes("</script>"),
926
+ tagType: HTMLTagType.useTagOpenAndClose,
927
+ name: "",
928
+ contractAddress: address(0),
929
+ contractData: "",
930
+ tagContent: projectScript
931
+ });
932
+
933
+ if (isProcessingDep) {
934
+ bodyTags[2] = projectScriptTag;
935
+ bodyTags[3] = canvasTag;
936
+ } else {
937
+ bodyTags[3] = projectScriptTag;
938
+ bodyTags[2] = canvasTag;
939
+ }
940
+
941
+ HTMLRequest memory htmlRequest;
942
+ htmlRequest.headTags = headTags;
943
+ htmlRequest.bodyTags = bodyTags;
944
+
945
+ return htmlRequest;
946
+ }
947
+
948
+ /**
949
+ * @dev Helper function to get token hash with fallback support
950
+ * @return tokenHash The hash for the token
951
+ * @return isV0CoreContract Whether the contract is a V0 core contract
952
+ */
953
+ function _getTokenHash(
954
+ address coreContract,
955
+ uint256 tokenId
956
+ ) private view returns (bytes32 tokenHash, bool isV0CoreContract) {
957
+ // Try V1+ contracts first
958
+ try
959
+ IGenArt721CoreTokenHashProviderV1(coreContract).tokenIdToHash(
960
+ tokenId
961
+ )
962
+ returns (bytes32 hash) {
963
+ if (hash != bytes32(0)) {
964
+ return (hash, false);
965
+ }
966
+ } catch {}
967
+
968
+ // Fallback to V0 contracts
969
+ try
970
+ IGenArt721CoreTokenHashProviderV0(coreContract).showTokenHashes(
971
+ tokenId
972
+ )
973
+ returns (bytes32[] memory hashes) {
974
+ require(hashes[0] != bytes32(0), "Invalid token hash");
975
+ return (hashes[0], true);
976
+ } catch {
977
+ revert("Unable to retrieve token hash");
978
+ }
979
+ }
980
+
981
+ /**
982
+ * @dev Helper function to check if a dependency is on chain.
983
+ * @param dependencyNameAndVersion The name and version of the dependency to check.
984
+ */
985
+ function _getIsDependencyOnChain(
986
+ bytes32 dependencyNameAndVersion
987
+ ) internal view returns (bool availableOnChain) {
988
+ // special case for "js@na" and "svg@na" - consider fully on chain
989
+ if (
990
+ dependencyNameAndVersion == JS_AT_NA_BYTES32 ||
991
+ dependencyNameAndVersion == SVG_AT_NA_BYTES32
992
+ ) {
993
+ return true;
994
+ }
995
+ // query and return result of dependency registry for on-chain status
996
+ (, , , , , , , availableOnChain, ) = dependencyRegistry
997
+ .getDependencyDetails(dependencyNameAndVersion);
998
+ }
999
+
1000
+ /**
1001
+ * @dev Helper function to get a canvas tag or an empty tag depending on the dependency name.
1002
+ * @return The canvas tag or an empty tag.
1003
+ */
1004
+ function _createCanvasTagIfNeeded(
1005
+ bytes32 dependencyNameAndVersion
1006
+ ) internal pure returns (HTMLTag memory) {
1007
+ // Extract dependency name before @ symbol
1008
+ uint atSignIndex;
1009
+ for (uint i = 0; i < dependencyNameAndVersion.length; i++) {
1010
+ if (dependencyNameAndVersion[i] == "@") {
1011
+ atSignIndex = i;
1012
+ break;
1013
+ }
1014
+ }
1015
+
1016
+ bytes memory nameBeforeAt = new bytes(atSignIndex);
1017
+ for (uint i = 0; i < atSignIndex; i++) {
1018
+ nameBeforeAt[i] = dependencyNameAndVersion[i];
1019
+ }
1020
+ string memory depNameStr = string(nameBeforeAt);
1021
+
1022
+ // Check if dependency needs canvas
1023
+ bytes32 nameHash = keccak256(nameBeforeAt);
1024
+ if (
1025
+ nameHash == keccak256(bytes("js")) ||
1026
+ nameHash == keccak256(bytes("babylon")) ||
1027
+ nameHash == keccak256(bytes("tone")) ||
1028
+ nameHash == keccak256(bytes("zdog")) ||
1029
+ nameHash == keccak256(bytes("processing-js"))
1030
+ ) {
1031
+ return
1032
+ HTMLTag({
1033
+ tagOpen: abi.encodePacked(
1034
+ "<canvas id='",
1035
+ depNameStr,
1036
+ "-canvas'>"
1037
+ ),
1038
+ tagClose: bytes("</canvas>"),
1039
+ tagType: HTMLTagType.useTagOpenAndClose,
1040
+ name: "",
1041
+ contractAddress: address(0),
1042
+ contractData: "",
1043
+ tagContent: ""
1044
+ });
1045
+ } else {
1046
+ return
1047
+ HTMLTag({
1048
+ tagOpen: "",
1049
+ tagClose: "",
1050
+ tagType: HTMLTagType.useTagOpenAndClose,
1051
+ name: "",
1052
+ contractAddress: address(0),
1053
+ contractData: "",
1054
+ tagContent: ""
1055
+ });
1056
+ }
1057
+ }
1058
+
1059
+ function _dependencyTypeToString(
1060
+ IGenArt721CoreContractV3_Engine_Flex.ExternalAssetDependencyType dependencyType
1061
+ ) internal pure returns (string memory) {
1062
+ if (
1063
+ dependencyType ==
1064
+ IGenArt721CoreContractV3_Engine_Flex
1065
+ .ExternalAssetDependencyType
1066
+ .IPFS
1067
+ ) {
1068
+ return "IPFS";
1069
+ } else if (
1070
+ dependencyType ==
1071
+ IGenArt721CoreContractV3_Engine_Flex
1072
+ .ExternalAssetDependencyType
1073
+ .ARWEAVE
1074
+ ) {
1075
+ return "ARWEAVE";
1076
+ } else if (
1077
+ dependencyType ==
1078
+ IGenArt721CoreContractV3_Engine_Flex
1079
+ .ExternalAssetDependencyType
1080
+ .ONCHAIN
1081
+ ) {
1082
+ return "ONCHAIN";
1083
+ } else if (
1084
+ dependencyType ==
1085
+ IGenArt721CoreContractV3_Engine_Flex
1086
+ .ExternalAssetDependencyType
1087
+ .ART_BLOCKS_DEPENDENCY_REGISTRY
1088
+ ) {
1089
+ return "ART_BLOCKS_DEPENDENCY_REGISTRY";
1090
+ } else {
1091
+ return "UNKNOWN"; // never expected to happen
1092
+ }
1093
+ }
1094
+ }