@zoralabs/comments-contracts 0.0.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 (140) hide show
  1. package/.env.example +11 -0
  2. package/.turbo/turbo-build.log +60 -0
  3. package/LICENSE +21 -0
  4. package/README.md +70 -0
  5. package/_imagine/Enjoy.sol +41 -0
  6. package/abis/AccessControlUpgradeable.json +250 -0
  7. package/abis/Address.json +29 -0
  8. package/abis/Comments.json +62 -0
  9. package/abis/CommentsDeployerBase.json +15 -0
  10. package/abis/CommentsImpl.json +1750 -0
  11. package/abis/CommentsPermitTest.json +847 -0
  12. package/abis/CommentsTest.json +986 -0
  13. package/abis/CommentsTestBase.json +577 -0
  14. package/abis/Comments_mintAndCommentTest.json +690 -0
  15. package/abis/ContextUpgradeable.json +25 -0
  16. package/abis/ContractVersionBase.json +15 -0
  17. package/abis/Create2.json +28 -0
  18. package/abis/DeployImpl.json +22 -0
  19. package/abis/DeployNonDeterministic.json +22 -0
  20. package/abis/DeployScript.json +22 -0
  21. package/abis/DeterministicDeployerAndCaller.json +315 -0
  22. package/abis/DeterministicUUPSProxyDeployer.json +167 -0
  23. package/abis/ECDSA.json +29 -0
  24. package/abis/EIP712.json +67 -0
  25. package/abis/EIP712UpgradeableWithChainId.json +25 -0
  26. package/abis/ERC1155.json +416 -0
  27. package/abis/ERC1155Holder.json +99 -0
  28. package/abis/ERC165.json +21 -0
  29. package/abis/ERC165Upgradeable.json +44 -0
  30. package/abis/ERC1967Proxy.json +67 -0
  31. package/abis/ERC1967Utils.json +85 -0
  32. package/abis/GenerateDeterministicParams.json +22 -0
  33. package/abis/IAccessControl.json +195 -0
  34. package/abis/IBeacon.json +15 -0
  35. package/abis/IComments.json +654 -0
  36. package/abis/IContractMetadata.json +28 -0
  37. package/abis/IERC1155.json +295 -0
  38. package/abis/IERC1155Errors.json +104 -0
  39. package/abis/IERC1155MetadataURI.json +314 -0
  40. package/abis/IERC1155Receiver.json +99 -0
  41. package/abis/IERC1271.json +26 -0
  42. package/abis/IERC165.json +21 -0
  43. package/abis/IERC1822Proxiable.json +15 -0
  44. package/abis/IERC20.json +224 -0
  45. package/abis/IERC20Errors.json +88 -0
  46. package/abis/IERC5267.json +51 -0
  47. package/abis/IERC721.json +287 -0
  48. package/abis/IERC721Enumerable.json +343 -0
  49. package/abis/IERC721Errors.json +105 -0
  50. package/abis/IERC721Metadata.json +332 -0
  51. package/abis/IERC721TokenReceiver.json +36 -0
  52. package/abis/IHasContractName.json +15 -0
  53. package/abis/IImmutableCreate2Factory.json +93 -0
  54. package/abis/IMulticall3.json +440 -0
  55. package/abis/IProtocolRewards.json +342 -0
  56. package/abis/ISafe.json +15 -0
  57. package/abis/ISymbol.json +15 -0
  58. package/abis/IVersionedContract.json +15 -0
  59. package/abis/IZoraCreator1155.json +343 -0
  60. package/abis/ImmutableCreate2FactoryUtils.json +15 -0
  61. package/abis/Initializable.json +25 -0
  62. package/abis/LibString.json +7 -0
  63. package/abis/Math.json +7 -0
  64. package/abis/Mock1155.json +547 -0
  65. package/abis/MockERC20.json +322 -0
  66. package/abis/MockERC721.json +350 -0
  67. package/abis/MockMinter.json +64 -0
  68. package/abis/OwnableUpgradeable.json +99 -0
  69. package/abis/ProtocolRewards.json +494 -0
  70. package/abis/Proxy.json +6 -0
  71. package/abis/ProxyDeployerScript.json +15 -0
  72. package/abis/ProxyShim.json +112 -0
  73. package/abis/Script.json +15 -0
  74. package/abis/ShortStrings.json +18 -0
  75. package/abis/StdAssertions.json +379 -0
  76. package/abis/StdInvariant.json +180 -0
  77. package/abis/Strings.json +18 -0
  78. package/abis/Test.json +570 -0
  79. package/abis/UUPSUpgradeable.json +130 -0
  80. package/abis/UnorderedNoncesUpgradeable.json +42 -0
  81. package/abis/Vm.json +8627 -0
  82. package/abis/VmSafe.json +7297 -0
  83. package/abis/stdError.json +119 -0
  84. package/abis/stdStorageSafe.json +52 -0
  85. package/addresses/999999999.json +4 -0
  86. package/deterministicConfig/comments.json +8 -0
  87. package/dist/index.cjs +935 -0
  88. package/dist/index.cjs.map +1 -0
  89. package/dist/index.d.ts +2 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +908 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/types.d.ts +4 -0
  94. package/dist/types.d.ts.map +1 -0
  95. package/dist/wagmiGenerated.d.ts +1354 -0
  96. package/dist/wagmiGenerated.d.ts.map +1 -0
  97. package/foundry.toml +24 -0
  98. package/package/index.ts +4 -0
  99. package/package/types.ts +5 -0
  100. package/package/wagmiGenerated.ts +907 -0
  101. package/package.json +62 -0
  102. package/remappings.txt +8 -0
  103. package/script/CommentsDeployerBase.sol +60 -0
  104. package/script/Deploy.s.sol +66 -0
  105. package/script/DeployImpl.s.sol +26 -0
  106. package/script/DeployNonDeterministic.s.sol +43 -0
  107. package/script/GenerateDeterministicParams.s.sol +55 -0
  108. package/script/bundle-abis.ts +109 -0
  109. package/script/storage-check.sh +57 -0
  110. package/script/update-contract-version.ts +63 -0
  111. package/scripts/abis.ts +3 -0
  112. package/scripts/backfillComments.ts +176 -0
  113. package/scripts/generateCommentsTestData.ts +247 -0
  114. package/scripts/getCommentsAddresses.ts +10 -0
  115. package/scripts/queries.ts +73 -0
  116. package/scripts/queryAndSaveComments.ts +48 -0
  117. package/scripts/queryQuantityOfComments.ts +53 -0
  118. package/scripts/signDeployAndCall.ts +51 -0
  119. package/scripts/turnkey.ts +36 -0
  120. package/scripts/utils.ts +127 -0
  121. package/scripts/writeComments.ts +198 -0
  122. package/slither.config.json +7 -0
  123. package/src/CommentsImpl.sol +552 -0
  124. package/src/deployments/CommentsDeployment.sol +14 -0
  125. package/src/interfaces/IComments.sol +156 -0
  126. package/src/interfaces/IZoraCreator1155.sol +12 -0
  127. package/src/proxy/Comments.sol +43 -0
  128. package/src/utils/EIP712UpgradeableWithChainId.sol +36 -0
  129. package/src/version/ContractVersionBase.sol +14 -0
  130. package/test/Comments.t.sol +482 -0
  131. package/test/CommentsTestBase.sol +86 -0
  132. package/test/Comments_mintAndComment.t.sol +101 -0
  133. package/test/Comments_permit.t.sol +397 -0
  134. package/test/mocks/Mock1155.sol +50 -0
  135. package/test/mocks/MockMinter.sol +29 -0
  136. package/test/mocks/ProtocolRewards.sol +1497 -0
  137. package/tsconfig.build.json +10 -0
  138. package/tsconfig.json +9 -0
  139. package/tsup.config.ts +11 -0
  140. package/wagmi.config.ts +14 -0
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@zoralabs/comments-contracts",
3
+ "version": "0.0.1",
4
+ "author": "oveddan",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "sideEffects": false,
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "default": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "devDependencies": {
19
+ "@turnkey/api-key-stamper": "^0.3.1",
20
+ "@turnkey/http": "^2.5.1",
21
+ "@turnkey/viem": "^0.4.4",
22
+ "@types/node": "^20.1.2",
23
+ "@wagmi/cli": "^1.0.1",
24
+ "@zoralabs/chains": "^1.3.1",
25
+ "@openzeppelin/contracts": "5.0.2",
26
+ "@openzeppelin/contracts-upgradeable": "5.0.2",
27
+ "ds-test": "https://github.com/dapphub/ds-test#cd98eff28324bfac652e63a239a60632a761790b",
28
+ "forge-std": "https://github.com/foundry-rs/forge-std#v1.9.1",
29
+ "solady": "0.0.132",
30
+ "glob": "^10.2.2",
31
+ "pathe": "^1.1.2",
32
+ "prettier": "^3.0.3",
33
+ "prettier-plugin-solidity": "^1.3.1",
34
+ "tsup": "^7.2.0",
35
+ "tsx": "^3.13.0",
36
+ "typescript": "^5.2.2",
37
+ "viem": "^1.10.0",
38
+ "@zoralabs/tsconfig": "^0.0.1",
39
+ "@zoralabs/protocol-rewards": "^1.2.4",
40
+ "@zoralabs/shared-contracts": "^0.0.1",
41
+ "@zoralabs/sparks-contracts": "^0.2.2",
42
+ "@zoralabs/zora-1155-contracts": "^2.12.4"
43
+ },
44
+ "dependencies": {
45
+ "abitype": "^1.0.2"
46
+ },
47
+ "scripts": {
48
+ "prettier:check": "prettier --check 'src/**/*.sol' 'test/**/*.sol' 'script/**/*.sol'",
49
+ "prettier:write": "prettier --write 'src/**/*.sol' 'test/**/*.sol' 'script/**/*.sol'",
50
+ "test": "forge test -vv",
51
+ "dev": "FOUNDRY_PROFILE=dev forge test --watch -vvv",
52
+ "test-gas": "forge test --gas-report",
53
+ "storage-inspect:check": "./script/storage-check.sh check ZoraTimedSaleStrategyImpl",
54
+ "storage-inspect:generate": "./script/storage-check.sh generate ZoraTimedSaleStrategyImpl",
55
+ "build:sizes": "forge build --sizes",
56
+ "copy-abis": "pnpm tsx script/bundle-abis.ts",
57
+ "coverage": "FOUNDRY_PROFILE=default forge coverage --report lcov",
58
+ "build": "pnpm run wagmi:generate && pnpm run copy-abis && pnpm run prettier:write && tsup",
59
+ "wagmi:generate": "FOUNDRY_PROFILE=dev forge build && wagmi generate",
60
+ "update-contract-version": "pnpm tsx script/update-contract-version.ts"
61
+ }
62
+ }
package/remappings.txt ADDED
@@ -0,0 +1,8 @@
1
+ ds-test/=node_modules/ds-test/src/
2
+ forge-std/=node_modules/forge-std/src/
3
+ @openzeppelin/=node_modules/@openzeppelin/
4
+ @zoralabs/protocol-rewards/=node_modules/@zoralabs/protocol-rewards/
5
+ @zoralabs/shared-contracts/=node_modules/@zoralabs/shared-contracts/src/
6
+ @zoralabs/sparks-contracts/=node_modules/@zoralabs/sparks-contracts/src/
7
+ @zoralabs/erc20z/=node_modules/@zoralabs/erc20z/src/
8
+ solady/=node_modules/solady/src/
@@ -0,0 +1,60 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ import "forge-std/Script.sol";
5
+
6
+ import {ProxyDeployerScript} from "@zoralabs/shared-contracts/deployment/ProxyDeployerScript.sol";
7
+ import {CommentsImpl} from "../src/CommentsImpl.sol";
8
+ import {IProtocolRewards} from "@zoralabs/protocol-rewards/src/interfaces/IProtocolRewards.sol";
9
+
10
+ // Temp script
11
+ contract CommentsDeployerBase is ProxyDeployerScript {
12
+ uint256 internal constant SPARK_VALUE = 0.000001 ether;
13
+ address internal constant PROTOCOL_REWARDS = 0x7777777F279eba3d3Ad8F4E708545291A6fDBA8B;
14
+ address internal constant ZORA_TIMED_SALE_STRATEGY = 0x777777722D078c97c6ad07d9f36801e653E356Ae;
15
+ using stdJson for string;
16
+
17
+ struct CommentsDeployment {
18
+ address comments;
19
+ address commentsImpl;
20
+ string commentsVersion;
21
+ }
22
+
23
+ function saveDeployment(CommentsDeployment memory deployment) internal {
24
+ string memory objectKey = "config";
25
+
26
+ vm.serializeAddress(objectKey, "COMMENTS", deployment.comments);
27
+ string memory result = vm.serializeAddress(objectKey, "COMMENTS_IMPL", deployment.commentsImpl);
28
+
29
+ vm.writeJson(result, string.concat("./addresses/", vm.toString(block.chainid), ".json"));
30
+ }
31
+
32
+ function readDeployment() internal view returns (CommentsDeployment memory) {
33
+ string memory json = vm.readFile(string.concat("./addresses/", vm.toString(block.chainid), ".json"));
34
+
35
+ return
36
+ CommentsDeployment({
37
+ comments: readAddressOrDefaultToZero(json, "COMMENTS"),
38
+ commentsImpl: readAddressOrDefaultToZero(json, "COMMENTS_IMPL"),
39
+ commentsVersion: readStringOrDefaultToEmpty(json, "COMMENTS_VERSION")
40
+ });
41
+ }
42
+
43
+ function commentsImplCreationCode() internal pure returns (bytes memory) {
44
+ return abi.encodePacked(type(CommentsImpl).creationCode, abi.encode(SPARK_VALUE, PROTOCOL_REWARDS));
45
+ }
46
+
47
+ function getBackfillerAccount() internal pure returns (address) {
48
+ // todo: figure out backfiller. right now this is made from cast wallet new
49
+ return 0x9AfA68161f094DAEA62816b6264b3D777978a164;
50
+ }
51
+
52
+ function defaultDelegateCommenters() internal pure returns (address[] memory delegateCommenters) {
53
+ delegateCommenters = new address[](1);
54
+ delegateCommenters[0] = ZORA_TIMED_SALE_STRATEGY;
55
+ }
56
+
57
+ function deployCommentsImpl() internal returns (CommentsImpl) {
58
+ return new CommentsImpl(SPARK_VALUE, PROTOCOL_REWARDS);
59
+ }
60
+ }
@@ -0,0 +1,66 @@
1
+ // SPDX-License-Identifier: UNLICENSED
2
+ pragma solidity ^0.8.13;
3
+
4
+ import "forge-std/Script.sol";
5
+
6
+ import {ProxyDeployerScript} from "@zoralabs/shared-contracts/deployment/ProxyDeployerScript.sol";
7
+ import {ImmutableCreate2FactoryUtils} from "@zoralabs/shared-contracts/utils/ImmutableCreate2FactoryUtils.sol";
8
+ import {ProxyDeployerScript, DeterministicDeployerAndCaller, DeterministicContractConfig} from "@zoralabs/shared-contracts/deployment/ProxyDeployerScript.sol";
9
+ import {CommentsImpl} from "../src/CommentsImpl.sol";
10
+ import {CommentsDeployment} from "../src/deployments/CommentsDeployment.sol";
11
+ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
12
+ import {CommentsDeployerBase} from "./CommentsDeployerBase.sol";
13
+
14
+ // Temp script
15
+ contract DeployScript is CommentsDeployerBase {
16
+ function run() public {
17
+ CommentsDeployment memory deployment = readDeployment();
18
+
19
+ address owner = getProxyAdmin();
20
+
21
+ // todo: figure out backfiller. right now this is made from cast wallet new
22
+ address backfiller = 0x9AfA68161f094DAEA62816b6264b3D777978a164;
23
+ address zoraRecipient = getZoraRecipient();
24
+
25
+ // get deployed implementation address. it it's not deployed, revert
26
+ address implAddress = deployment.commentsImpl;
27
+
28
+ if (implAddress.code.length == 0) {
29
+ revert("Impl not yet deployed. Make sure to deploy it with DeployImpl.s.sol");
30
+ }
31
+
32
+ vm.startBroadcast();
33
+
34
+ // get deployer contract
35
+ DeterministicDeployerAndCaller deployer = createOrGetDeployerAndCaller();
36
+
37
+ // read previously saved deterministic royalties config
38
+ DeterministicContractConfig memory commentsConfig = readDeterministicContractConfig("comments");
39
+
40
+ address[] memory delegateCommenters = defaultDelegateCommenters();
41
+
42
+ // build upgrade to and call for comments, with init call
43
+ bytes memory upgradeToAndCall = abi.encodeWithSelector(
44
+ UUPSUpgradeable.upgradeToAndCall.selector,
45
+ implAddress,
46
+ abi.encodeWithSelector(CommentsImpl.initialize.selector, zoraRecipient, owner, backfiller, delegateCommenters)
47
+ );
48
+
49
+ // sign royalties deployment with turnkey account
50
+ bytes memory commentsSignature = signDeploymentWithTurnkey(commentsConfig, upgradeToAndCall, deployer);
51
+
52
+ // deterministically deploy royalties contract using the signature
53
+ deployment.comments = deployer.permitSafeCreate2AndCall(
54
+ commentsSignature,
55
+ commentsConfig.salt,
56
+ commentsConfig.creationCode,
57
+ upgradeToAndCall,
58
+ commentsConfig.deployedAddress
59
+ );
60
+
61
+ vm.stopBroadcast();
62
+
63
+ // save the deployment json
64
+ saveDeployment(deployment);
65
+ }
66
+ }
@@ -0,0 +1,26 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.13;
3
+
4
+ import "forge-std/console2.sol";
5
+
6
+ import {CommentsDeployerBase} from "./CommentsDeployerBase.sol";
7
+ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
8
+
9
+ contract DeployImpl is CommentsDeployerBase {
10
+ function run() public {
11
+ CommentsDeployment memory config = readDeployment();
12
+ vm.startBroadcast();
13
+
14
+ config.commentsImpl = address(deployCommentsImpl());
15
+
16
+ vm.stopBroadcast();
17
+
18
+ console2.log("CommentsImpl deployed, to upgrade:");
19
+ console2.log("target:", config.comments);
20
+ console2.log("calldata:");
21
+ console2.logBytes(abi.encodeWithSelector(UUPSUpgradeable.upgradeToAndCall.selector, config.commentsImpl, ""));
22
+ console2.log("multisig:", getProxyAdmin());
23
+
24
+ saveDeployment(config);
25
+ }
26
+ }
@@ -0,0 +1,43 @@
1
+ // SPDX-License-Identifier: UNLICENSED
2
+ pragma solidity ^0.8.13;
3
+
4
+ import "forge-std/Script.sol";
5
+
6
+ import {ProxyDeployerScript} from "@zoralabs/shared-contracts/deployment/ProxyDeployerScript.sol";
7
+ import {ImmutableCreate2FactoryUtils} from "@zoralabs/shared-contracts/utils/ImmutableCreate2FactoryUtils.sol";
8
+ import {ProxyDeployerScript, DeterministicDeployerAndCaller, DeterministicContractConfig} from "@zoralabs/shared-contracts/deployment/ProxyDeployerScript.sol";
9
+ import {Comments} from "../src/proxy/Comments.sol";
10
+ import {CommentsImpl} from "../src/CommentsImpl.sol";
11
+ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
12
+ import {CommentsDeployerBase} from "./CommentsDeployerBase.sol";
13
+
14
+ contract DeployNonDeterministic is CommentsDeployerBase {
15
+ function run() public {
16
+ CommentsDeployment memory deployment = readDeployment();
17
+
18
+ address owner = getProxyAdmin();
19
+
20
+ // todo: figure out backfiller. right now this is made from cast wallet new
21
+ address backfiller = 0x9AfA68161f094DAEA62816b6264b3D777978a164;
22
+ address zoraRecipient = getZoraRecipient();
23
+
24
+ vm.startBroadcast();
25
+ // deploy comments backfiller
26
+
27
+ address implAddress = address(deployCommentsImpl());
28
+
29
+ Comments comments = new Comments(implAddress);
30
+
31
+ address[] memory delegateCommenters = defaultDelegateCommenters();
32
+
33
+ CommentsImpl(payable(address(comments))).initialize(zoraRecipient, owner, backfiller, delegateCommenters);
34
+
35
+ vm.stopBroadcast();
36
+
37
+ deployment.comments = address(comments);
38
+ deployment.commentsImpl = implAddress;
39
+
40
+ // save the deployment json
41
+ saveDeployment(deployment);
42
+ }
43
+ }
@@ -0,0 +1,55 @@
1
+ // spdx-license-identifier: mit
2
+ pragma solidity ^0.8.20;
3
+
4
+ import "forge-std/Script.sol";
5
+
6
+ import {LibString} from "solady/utils/LibString.sol";
7
+ import {ImmutableCreate2FactoryUtils} from "@zoralabs/shared-contracts/utils/ImmutableCreate2FactoryUtils.sol";
8
+ import {ProxyDeployerScript, DeterministicDeployerAndCaller, DeterministicContractConfig} from "@zoralabs/shared-contracts/deployment/ProxyDeployerScript.sol";
9
+ import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
10
+ import {Comments} from "../src/proxy/Comments.sol";
11
+
12
+ /// @dev This script saves the current bytecode, and initialization parameters for the Sparks proxy,
13
+ /// which then need to be populated with a salt and expected address, which can be achieved by
14
+ /// running the printed create2crunch command. The resulting config only needs to be generated once
15
+ /// and is reusable for all chains.
16
+ contract GenerateDeterministicParams is ProxyDeployerScript {
17
+ function mineForCommentsAddress(DeterministicDeployerAndCaller deployer, address caller) private returns (DeterministicContractConfig memory config) {
18
+ // get proxy creation code
19
+ // get the expected init code for the proxy from the uupsProxyDeployer
20
+ bytes memory initCode = deployer.proxyCreationCode(type(Comments).creationCode);
21
+ bytes32 initCodeHash = keccak256(initCode);
22
+
23
+ // uupsProxyDeployer is deployer
24
+ (bytes32 salt, address expectedAddress) = mineSalt(address(deployer), initCodeHash, "7777777", caller);
25
+
26
+ // test deployment
27
+ // Create2.deploy(0, salt, initCode);
28
+
29
+ console2.log("salt");
30
+ console2.log(vm.toString(salt));
31
+
32
+ config.salt = salt;
33
+ config.deployedAddress = expectedAddress;
34
+ config.creationCode = initCode;
35
+ config.constructorArgs = deployer.proxyConstructorArgs();
36
+ config.contractName = "Comments";
37
+ config.deploymentCaller = caller;
38
+ }
39
+
40
+ function run() public {
41
+ address caller = vm.envAddress("DEPLOYER");
42
+
43
+ vm.startBroadcast();
44
+
45
+ // create a proxy deployer, which we can use to generated determistic addresses and corresponding params.
46
+ // proxy deployer code is based on code saved to file from running the script SaveProxyDeployerConfig.s.sol
47
+ DeterministicDeployerAndCaller deployer = createOrGetDeployerAndCaller();
48
+
49
+ vm.stopBroadcast();
50
+
51
+ DeterministicContractConfig memory commentsConfig = mineForCommentsAddress(deployer, caller);
52
+
53
+ saveDeterministicContractConfig(commentsConfig, "comments");
54
+ }
55
+ }
@@ -0,0 +1,109 @@
1
+ import { promises as fs } from "fs";
2
+ import { basename, extname, join, resolve } from "pathe";
3
+ import { glob } from "glob";
4
+ import { ContractConfig } from "@wagmi/cli";
5
+
6
+ const defaultExcludes = [
7
+ "Common.sol/**",
8
+ "Components.sol/**",
9
+ "Script.sol/**",
10
+ "StdAssertions.sol/**",
11
+ "StdInvariant.sol/**",
12
+ "StdError.sol/**",
13
+ "StdCheats.sol/**",
14
+ "StdMath.sol/**",
15
+ "StdJson.sol/**",
16
+ "StdStorage.sol/**",
17
+ "StdUtils.sol/**",
18
+ "Vm.sol/**",
19
+ "console.sol/**",
20
+ "console2.sol/**",
21
+ "test.sol/**",
22
+ "**.s.sol/*.json",
23
+ "**.t.sol/*.json",
24
+ ];
25
+
26
+ // design inspired by https://github.com/wagmi-dev/wagmi/blob/main/packages/cli/src/plugins/foundry.ts
27
+
28
+ export const readContracts = async ({
29
+ deployments = {} as any,
30
+ exclude = defaultExcludes,
31
+ include = ["*.json"],
32
+ namePrefix = "",
33
+ project_ = "./",
34
+ }) => {
35
+ // get all the files in ./out
36
+ function getContractName(artifactPath: string, usePrefix = true) {
37
+ const filename = basename(artifactPath);
38
+ const extension = extname(artifactPath);
39
+ return `${usePrefix ? namePrefix : ""}${filename.replace(extension, "")}`;
40
+ }
41
+
42
+ async function getContract(artifactPath: string) {
43
+ const artifact = JSON.parse(await fs.readFile(artifactPath, "utf-8"));
44
+ return {
45
+ abi: artifact.abi,
46
+ address: (deployments as Record<string, ContractConfig["address"]>)[
47
+ getContractName(artifactPath, false)
48
+ ],
49
+ name: getContractName(artifactPath),
50
+ };
51
+ }
52
+
53
+ async function getArtifactPaths(artifactsDirectory: string) {
54
+ return await glob([
55
+ ...include.map((x) => `${artifactsDirectory}/**/${x}`),
56
+ ...exclude.map((x) => `!${artifactsDirectory}/**/${x}`),
57
+ ]);
58
+ }
59
+
60
+ const project = resolve(process.cwd(), project_ ?? "");
61
+
62
+ const config = {
63
+ out: "out",
64
+ src: "src",
65
+ };
66
+
67
+ const artifactsDirectory = join(project, config.out);
68
+
69
+ const artifactPaths = await getArtifactPaths(artifactsDirectory);
70
+ const contracts = [];
71
+ for (const artifactPath of artifactPaths) {
72
+ const contract = await getContract(artifactPath);
73
+ if (!contract.abi?.length) continue;
74
+ contracts.push(contract);
75
+ }
76
+ return contracts;
77
+ };
78
+
79
+ async function saveContractsAbisJson(contracts: { abi: any; name: string }[]) {
80
+ // for each contract, write abi to ./abis/{contractName}.json
81
+
82
+ const abisFolder = "./abis";
83
+
84
+ // mkdir - p ./abis:
85
+ await fs.mkdir(abisFolder, { recursive: true });
86
+ // remove abis folder:
87
+ await fs.rm(abisFolder, { recursive: true });
88
+ // add it back
89
+ // mkdir - p ./abis:
90
+ await fs.mkdir(abisFolder, { recursive: true });
91
+
92
+ // now write abis:
93
+ await Promise.all(
94
+ contracts.map(async (contract) => {
95
+ const abiJson = JSON.stringify(contract.abi, null, 2);
96
+ const abiJsonPath = `${abisFolder}/${contract.name}.json`;
97
+
98
+ await fs.writeFile(abiJsonPath, abiJson);
99
+ }),
100
+ );
101
+ }
102
+
103
+ async function main() {
104
+ const contracts = await readContracts({});
105
+
106
+ await saveContractsAbisJson(contracts);
107
+ }
108
+
109
+ main();
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ generate() {
6
+ file=$1
7
+ if [[ $func == "generate" ]]; then
8
+ echo "Creating storage layout diagrams for the following contracts: $contracts"
9
+ echo "..."
10
+ fi
11
+
12
+ echo "=======================" > "$file"
13
+ echo "👁👁 STORAGE LAYOUT snapshot 👁👁" >"$file"
14
+ echo "=======================" >> "$file"
15
+ # shellcheck disable=SC2068
16
+ for contract in ${contracts[@]}
17
+ do
18
+ { echo -e "\n======================="; echo "➡ $contract" ; echo -e "=======================\n"; } >> "$file"
19
+ FOUNDRY_PROFILE=dev forge inspect --pretty "$contract" storage-layout >> "$file"
20
+ done
21
+ if [[ $func == "generate" ]]; then
22
+ echo "Storage layout snapshot stored at $file"
23
+ fi
24
+ }
25
+
26
+ if ! command -v forge &> /dev/null
27
+ then
28
+ echo "forge could not be found. Please install forge by running:"
29
+ echo "curl -L https://foundry.paradigm.xyz | bash"
30
+ exit
31
+ fi
32
+
33
+ # shellcheck disable=SC2124
34
+ contracts="${@:2}"
35
+ func=$1
36
+ filename=.storage-layout
37
+ new_filename=.storage-layout.temp
38
+
39
+ if [[ $func == "check" ]]; then
40
+ generate $new_filename
41
+ if ! cmp -s .storage-layout $new_filename ; then
42
+ echo "storage-layout test: fails ❌"
43
+ echo "The following lines are different:"
44
+ diff -a --suppress-common-lines "$filename" "$new_filename"
45
+ rm $new_filename
46
+ exit 1
47
+ else
48
+ echo "storage-layout test: passes ✅"
49
+ rm $new_filename
50
+ exit 0
51
+ fi
52
+ elif [[ $func == "generate" ]]; then
53
+ generate "$filename"
54
+ else
55
+ echo "unknown command. Use 'generate' or 'check' as the first argument."
56
+ exit 1
57
+ fi
@@ -0,0 +1,63 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { promisify } from "util";
4
+ import { fileURLToPath } from "url";
5
+
6
+ const readFileAsync = promisify(fs.readFile);
7
+ const writeFileAsync = promisify(fs.writeFile);
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+
12
+ const makePackageVersionFile = async (version: string): Promise<void> => {
13
+ console.log("updating contract version to ", version);
14
+ // read the version from the root package.json:
15
+
16
+ const packageVersionCode = `// This file is automatically generated by code; do not manually update
17
+ // SPDX-License-Identifier: MIT
18
+ pragma solidity ^0.8.23;
19
+
20
+ import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersionedContract.sol";
21
+
22
+ /// @title ContractVersionBase
23
+ /// @notice Base contract for versioning contracts
24
+ contract ContractVersionBase is IVersionedContract {
25
+ /// @notice The version of the contract
26
+ function contractVersion() external pure override returns (string memory) {
27
+ return "${version}";
28
+ }
29
+ }
30
+ `;
31
+
32
+ // write the file to __dirname__/../src/version/ContractVersionBase.sol:
33
+ const filePath = path.join(
34
+ __dirname,
35
+ "..",
36
+ "src",
37
+ "version",
38
+ "ContractVersionBase.sol",
39
+ );
40
+
41
+ console.log("generated contract version code:", packageVersionCode);
42
+ console.log("writing file to", filePath);
43
+
44
+ await writeFileAsync(filePath, packageVersionCode);
45
+ };
46
+
47
+ const getVersion = async (): Promise<string> => {
48
+ // read package.json file, parse json, then get version:
49
+ const packageJson = JSON.parse(
50
+ await readFileAsync(path.join(__dirname, "..", "package.json"), "utf-8"),
51
+ );
52
+
53
+ return packageJson.version;
54
+ };
55
+
56
+ const main = async (): Promise<void> => {
57
+ const version = await getVersion();
58
+ await makePackageVersionFile(version);
59
+ };
60
+
61
+ main().catch((error) => {
62
+ console.error("Error updating contract version:", error);
63
+ });
@@ -0,0 +1,3 @@
1
+ export const zoraTimedSaleStrategyImplABI = [
2
+ "function mint(address mintTo, uint256 quantity, address collection, uint256 tokenId, address mintReferral, string calldata comment) external returns (uint256)",
3
+ ] as const;