@zoralabs/comments-contracts 0.0.2 → 0.0.3

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.
@@ -4,11 +4,13 @@ pragma solidity ^0.8.23;
4
4
  import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
5
5
  import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
6
6
  import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
7
+ import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
7
8
  import {IHasContractName} from "@zoralabs/shared-contracts/interfaces/IContractMetadata.sol";
8
9
  import {ContractVersionBase} from "./version/ContractVersionBase.sol";
9
10
  import {IZoraCreator1155} from "./interfaces/IZoraCreator1155.sol";
10
11
  import {IComments} from "./interfaces/IComments.sol";
11
- import {IProtocolRewards} from "@zoralabs/protocol-rewards/src/interfaces/IProtocolRewards.sol";
12
+ import {ICoinComments} from "./interfaces/ICoinComments.sol";
13
+ import {IProtocolRewards} from "@zoralabs/shared-contracts/interfaces/IProtocolRewards.sol";
12
14
  import {UnorderedNoncesUpgradeable} from "@zoralabs/shared-contracts/utils/UnorderedNoncesUpgradeable.sol";
13
15
  import {EIP712UpgradeableWithChainId} from "./utils/EIP712UpgradeableWithChainId.sol";
14
16
  import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
@@ -365,31 +367,45 @@ contract CommentsImpl is
365
367
  }
366
368
 
367
369
  function _accountOrSmartWalletIsTokenAdmin(address contractAddress, uint256 tokenId, address user, address smartWallet) internal view returns (bool) {
368
- if (_isTokenAdmin(contractAddress, tokenId, user)) {
369
- return true;
370
- }
371
- if (smartWallet != address(0)) {
372
- return _isTokenAdmin(contractAddress, tokenId, smartWallet);
370
+ bool isCoin = _isCoinComment(contractAddress, tokenId);
371
+
372
+ if (isCoin) {
373
+ return ICoinComments(contractAddress).isOwner(user) || (smartWallet != address(0) && ICoinComments(contractAddress).isOwner(smartWallet));
374
+ } else {
375
+ return _isTokenAdmin(contractAddress, tokenId, user) || (smartWallet != address(0) && _isTokenAdmin(contractAddress, tokenId, smartWallet));
373
376
  }
374
- return false;
375
377
  }
376
378
 
377
379
  function _accountOrSmartWalletIsTokenHolder(address contractAddress, uint256 tokenId, address user, address smartWallet) internal view returns (bool) {
378
- if (_isTokenHolder(contractAddress, tokenId, user)) {
379
- return true;
380
- }
381
- if (smartWallet != address(0)) {
382
- return _isTokenHolder(contractAddress, tokenId, smartWallet);
380
+ bool isCoin = _isCoinComment(contractAddress, tokenId);
381
+
382
+ if (isCoin) {
383
+ return
384
+ ICoinComments(contractAddress).balanceOf(user) >= 1e18 ||
385
+ (smartWallet != address(0) && ICoinComments(contractAddress).balanceOf(smartWallet) >= 1e18);
386
+ } else {
387
+ return _isTokenHolder(contractAddress, tokenId, user) || (smartWallet != address(0) && _isTokenHolder(contractAddress, tokenId, smartWallet));
383
388
  }
384
- return false;
385
389
  }
386
390
 
387
391
  function _isTokenAdmin(address contractAddress, uint256 tokenId, address user) internal view returns (bool) {
388
- return IZoraCreator1155(contractAddress).isAdminOrRole(user, tokenId, PERMISSION_BIT_ADMIN);
392
+ try IZoraCreator1155(contractAddress).isAdminOrRole(user, tokenId, PERMISSION_BIT_ADMIN) returns (bool isAdmin) {
393
+ return isAdmin;
394
+ } catch {
395
+ return false;
396
+ }
389
397
  }
390
398
 
391
399
  function _isTokenHolder(address contractAddress, uint256 tokenId, address user) internal view returns (bool) {
392
- return IERC1155(contractAddress).balanceOf(user, tokenId) > 0;
400
+ try IERC1155(contractAddress).balanceOf(user, tokenId) returns (uint256 balance) {
401
+ return balance > 0;
402
+ } catch {
403
+ return false;
404
+ }
405
+ }
406
+
407
+ function _isCoinComment(address contractAddress, uint256 tokenId) internal view returns (bool) {
408
+ return tokenId == 0 && IERC165(contractAddress).supportsInterface(type(ICoinComments).interfaceId);
393
409
  }
394
410
 
395
411
  function _getCommentSparksRecipient(CommentIdentifier memory commentIdentifier, CommentIdentifier memory replyTo) internal view returns (address) {
@@ -629,6 +645,18 @@ contract CommentsImpl is
629
645
  }
630
646
  }
631
647
 
648
+ function _getCoinPayoutRecipient(address contractAddress, uint256 tokenId) internal view returns (address) {
649
+ if (_isCoinComment(contractAddress, tokenId)) {
650
+ try ICoinComments(contractAddress).payoutRecipient() returns (address payoutRecipient) {
651
+ return payoutRecipient;
652
+ } catch {
653
+ return address(0);
654
+ }
655
+ }
656
+
657
+ return address(0);
658
+ }
659
+
632
660
  function _getFundsRecipient(address contractAddress) internal view returns (address) {
633
661
  try IZoraCreator1155(contractAddress).config() returns (address, uint96, address payable fundsRecipient, uint96, address, uint96) {
634
662
  if (fundsRecipient != address(0)) {
@@ -654,6 +682,11 @@ contract CommentsImpl is
654
682
  }
655
683
 
656
684
  function _getCreatorRewardRecipient(CommentIdentifier memory commentIdentifier) internal view returns (address) {
685
+ address payoutRecipient = _getCoinPayoutRecipient(commentIdentifier.contractAddress, commentIdentifier.tokenId);
686
+ if (payoutRecipient != address(0)) {
687
+ return payoutRecipient;
688
+ }
689
+
657
690
  address creatorRecipient = _tryGetCreatorRewardRecipient(commentIdentifier);
658
691
  if (creatorRecipient != address(0)) {
659
692
  return creatorRecipient;
@@ -0,0 +1,8 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ interface ICoinComments {
5
+ function isOwner(address) external view returns (bool);
6
+ function payoutRecipient() external view returns (address);
7
+ function balanceOf(address) external view returns (uint256);
8
+ }
@@ -9,6 +9,6 @@ import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersion
9
9
  contract ContractVersionBase is IVersionedContract {
10
10
  /// @notice The version of the contract
11
11
  function contractVersion() external pure override returns (string memory) {
12
- return "0.0.2";
12
+ return "0.0.3";
13
13
  }
14
14
  }
@@ -616,4 +616,70 @@ contract CommentsTest is CommentsTestBase {
616
616
  vm.expectRevert(abi.encodeWithSignature("AccessControlUnauthorizedAccount(address,bytes32)", notAdmin, no_role));
617
617
  comments.grantRole(BACKFILLER_ROLE, newBackfiller);
618
618
  }
619
+
620
+ function testCommentAsCoinAdmin() public {
621
+ IComments.CommentIdentifier memory expectedCommentId = _expectedCommentIdentifier(address(mockCoin), tokenId0, tokenAdmin);
622
+
623
+ vm.prank(tokenAdmin);
624
+ IComments.CommentIdentifier memory commentId = comments.comment(
625
+ tokenAdmin,
626
+ address(mockCoin),
627
+ tokenId0,
628
+ "test comment",
629
+ emptyCommentIdentifier,
630
+ address(0),
631
+ address(0)
632
+ );
633
+
634
+ (bytes32 commentIdHash, bool exists) = comments.hashAndCheckCommentExists(commentId);
635
+
636
+ assertEq(exists, true);
637
+ assertEq(commentIdHash, comments.hashCommentIdentifier(expectedCommentId));
638
+ assertEq(comments.commentSparksQuantity(commentId), 0);
639
+ }
640
+
641
+ function testCommentAsCoinHolder() public {
642
+ address commenter = makeAddr("commenter");
643
+
644
+ mockCoin.mint(commenter, 1e18);
645
+ vm.deal(commenter, SPARKS_VALUE);
646
+
647
+ IComments.CommentIdentifier memory expectedCommentId = _expectedCommentIdentifier(address(mockCoin), tokenId0, commenter);
648
+
649
+ vm.prank(commenter);
650
+ IComments.CommentIdentifier memory commentId = comments.comment{value: SPARKS_VALUE}(
651
+ commenter,
652
+ address(mockCoin),
653
+ tokenId0,
654
+ "test comment",
655
+ emptyCommentIdentifier,
656
+ address(0),
657
+ address(0)
658
+ );
659
+
660
+ (bytes32 commentIdHash, bool exists) = comments.hashAndCheckCommentExists(commentId);
661
+ assertEq(exists, true);
662
+ assertEq(commentIdHash, comments.hashCommentIdentifier(expectedCommentId));
663
+
664
+ uint256 zoraReward = (SPARKS_VALUE * (ZORA_REWARD_PCT + REFERRER_REWARD_PCT)) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
665
+ assertEq(protocolRewards.balanceOf(tokenAdmin), SPARKS_VALUE - zoraReward);
666
+ }
667
+
668
+ function testRevertCommentAsCoinHolderWithoutSparks() public {
669
+ address commenter = makeAddr("commenter");
670
+ mockCoin.mint(commenter, 1e18);
671
+
672
+ vm.expectRevert(abi.encodeWithSignature("MustSendAtLeastOneSpark()"));
673
+ vm.prank(commenter);
674
+ comments.comment(commenter, address(mockCoin), tokenId0, "test comment", emptyCommentIdentifier, address(0), address(0));
675
+ }
676
+
677
+ function testRevertCommentAsNonCoinHolder() public {
678
+ address nonHolder = makeAddr("nonHolder");
679
+ vm.deal(nonHolder, SPARKS_VALUE);
680
+
681
+ vm.expectRevert(abi.encodeWithSignature("NotTokenHolderOrAdmin()"));
682
+ vm.prank(nonHolder);
683
+ comments.comment{value: SPARKS_VALUE}(nonHolder, address(mockCoin), tokenId0, "test comment", emptyCommentIdentifier, address(0), address(0));
684
+ }
619
685
  }
@@ -7,12 +7,14 @@ import {CommentsImpl} from "../src/CommentsImpl.sol";
7
7
  import {Comments} from "../src/proxy/Comments.sol";
8
8
  import {IComments} from "../src/interfaces/IComments.sol";
9
9
  import {Mock1155} from "./mocks/Mock1155.sol";
10
+ import {MockCoin} from "./mocks/MockCoin.sol";
10
11
  import {ProtocolRewards} from "./mocks/ProtocolRewards.sol";
11
12
 
12
13
  contract CommentsTestBase is Test {
13
14
  CommentsImpl internal comments;
14
15
  CommentsImpl internal commentsImpl;
15
16
  Mock1155 internal mock1155;
17
+ MockCoin internal mockCoin;
16
18
 
17
19
  uint256 internal constant SPARKS_VALUE = 0.000001 ether;
18
20
 
@@ -30,6 +32,7 @@ contract CommentsTestBase is Test {
30
32
  address internal sparker;
31
33
  uint256 internal sparkerPrivateKey;
32
34
 
35
+ uint256 internal tokenId0 = 0;
33
36
  uint256 internal tokenId1 = 1;
34
37
  uint256 internal tokenId2 = 2;
35
38
 
@@ -52,6 +55,10 @@ contract CommentsTestBase is Test {
52
55
 
53
56
  (collectorWithToken, collectorWithTokenPrivateKey) = makeAddrAndKey("collectorWithToken");
54
57
  (sparker, sparkerPrivateKey) = makeAddrAndKey("sparker");
58
+
59
+ address[] memory owners = new address[](1);
60
+ owners[0] = tokenAdmin;
61
+ mockCoin = new MockCoin(tokenAdmin, owners);
55
62
  }
56
63
 
57
64
  function _expectedCommentIdentifier(
@@ -7,7 +7,7 @@ import {CommentsImpl} from "../src/CommentsImpl.sol";
7
7
  import {Comments} from "../src/proxy/Comments.sol";
8
8
  import {IComments} from "../src/interfaces/IComments.sol";
9
9
  import {Mock1155} from "./mocks/Mock1155.sol";
10
- import {IProtocolRewards} from "@zoralabs/protocol-rewards/src/interfaces/IProtocolRewards.sol";
10
+ import {IProtocolRewards} from "@zoralabs/shared-contracts/interfaces/IProtocolRewards.sol";
11
11
  import {ProtocolRewards} from "./mocks/ProtocolRewards.sol";
12
12
  import {CommentsTestBase} from "./CommentsTestBase.sol";
13
13
  import {UnorderedNoncesUpgradeable} from "@zoralabs/shared-contracts/utils/UnorderedNoncesUpgradeable.sol";
@@ -149,4 +149,101 @@ contract Comments_smartWallet is CommentsTestBase {
149
149
  referrer: address(0)
150
150
  });
151
151
  }
152
+
153
+ function test_commentWithSmartWalletOwner_whenCoinHolder() public {
154
+ address smartWallet = address(new MockMultiOwnable(address(collectorWithoutToken)));
155
+
156
+ mockCoin.mint(smartWallet, 1e18);
157
+
158
+ IComments.CommentIdentifier memory expectedCommentId = _expectedCommentIdentifier(address(mockCoin), tokenId0, collectorWithoutToken);
159
+
160
+ vm.deal(collectorWithoutToken, SPARKS_VALUE);
161
+ vm.prank(collectorWithoutToken);
162
+ comments.comment{value: SPARKS_VALUE}({
163
+ commenter: collectorWithoutToken,
164
+ contractAddress: address(mockCoin),
165
+ tokenId: tokenId0,
166
+ text: "test comment",
167
+ replyTo: emptyCommentIdentifier,
168
+ commenterSmartWallet: smartWallet,
169
+ referrer: address(0)
170
+ });
171
+
172
+ (, bool exists) = comments.hashAndCheckCommentExists(expectedCommentId);
173
+ assertTrue(exists);
174
+ }
175
+
176
+ function test_commentWithSmartWalletOwner_whenCoinOwner() public {
177
+ address smartWallet = address(new MockMultiOwnable(address(tokenAdmin)));
178
+
179
+ IComments.CommentIdentifier memory expectedCommentId = _expectedCommentIdentifier(address(mockCoin), tokenId0, tokenAdmin);
180
+
181
+ vm.prank(tokenAdmin);
182
+ comments.comment({
183
+ commenter: tokenAdmin,
184
+ contractAddress: address(mockCoin),
185
+ tokenId: tokenId0,
186
+ text: "test comment",
187
+ replyTo: emptyCommentIdentifier,
188
+ commenterSmartWallet: smartWallet,
189
+ referrer: address(0)
190
+ });
191
+
192
+ (, bool exists) = comments.hashAndCheckCommentExists(expectedCommentId);
193
+ assertTrue(exists);
194
+ }
195
+
196
+ function test_commentWithSmartWalletOwner_revertsWhenNotCoinHolder() public {
197
+ address smartWallet = address(new MockMultiOwnable(address(collectorWithoutToken)));
198
+
199
+ vm.expectRevert(abi.encodeWithSelector(IComments.NotTokenHolderOrAdmin.selector));
200
+ vm.prank(collectorWithoutToken);
201
+ vm.deal(collectorWithoutToken, SPARKS_VALUE);
202
+ comments.comment{value: SPARKS_VALUE}({
203
+ commenter: collectorWithoutToken,
204
+ contractAddress: address(mockCoin),
205
+ tokenId: tokenId0,
206
+ text: "test comment",
207
+ replyTo: emptyCommentIdentifier,
208
+ commenterSmartWallet: smartWallet,
209
+ referrer: address(0)
210
+ });
211
+ }
212
+
213
+ function test_commentWithSmartWalletOwner_revertsWhenNotCoinSmartWalletOwner() public {
214
+ address smartWallet = address(new MockMultiOwnable(address(makeAddr("notOwner"))));
215
+
216
+ mockCoin.mint(smartWallet, 1e18);
217
+
218
+ vm.expectRevert(IComments.NotSmartWalletOwner.selector);
219
+ vm.prank(collectorWithoutToken);
220
+ vm.deal(collectorWithoutToken, SPARKS_VALUE);
221
+ comments.comment{value: SPARKS_VALUE}({
222
+ commenter: collectorWithoutToken,
223
+ contractAddress: address(mockCoin),
224
+ tokenId: tokenId0,
225
+ text: "test comment",
226
+ replyTo: emptyCommentIdentifier,
227
+ commenterSmartWallet: smartWallet,
228
+ referrer: address(0)
229
+ });
230
+ }
231
+
232
+ function test_commentWithSmartWalletOwner_revertsWhenNotCoinSmartWallet() public {
233
+ address smartWallet = makeAddr("smartWallet");
234
+
235
+ mockCoin.mint(smartWallet, 1e18);
236
+
237
+ vm.expectRevert(IComments.NotSmartWallet.selector);
238
+ vm.prank(collectorWithoutToken);
239
+ comments.comment({
240
+ commenter: collectorWithoutToken,
241
+ contractAddress: address(mockCoin),
242
+ tokenId: tokenId0,
243
+ text: "test comment",
244
+ replyTo: emptyCommentIdentifier,
245
+ commenterSmartWallet: smartWallet,
246
+ referrer: address(0)
247
+ });
248
+ }
152
249
  }
@@ -0,0 +1,42 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.20;
3
+
4
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5
+ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
6
+ import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
7
+ import {ICoinComments} from "../../src/interfaces/ICoinComments.sol";
8
+
9
+ contract MockCoin is ICoinComments, IERC165, ERC20 {
10
+ using EnumerableSet for EnumerableSet.AddressSet;
11
+
12
+ address internal _payoutRecipient;
13
+ EnumerableSet.AddressSet internal _owners;
14
+
15
+ constructor(address payoutRecipient_, address[] memory owners_) ERC20("MockCoin", "MC") {
16
+ _payoutRecipient = payoutRecipient_;
17
+
18
+ for (uint256 i; i < owners_.length; i++) {
19
+ _owners.add(owners_[i]);
20
+ }
21
+ }
22
+
23
+ function mint(address to, uint256 amount) public {
24
+ _mint(to, amount);
25
+ }
26
+
27
+ function balanceOf(address account) public view override(ERC20, ICoinComments) returns (uint256) {
28
+ return super.balanceOf(account);
29
+ }
30
+
31
+ function payoutRecipient() public view override(ICoinComments) returns (address) {
32
+ return _payoutRecipient;
33
+ }
34
+
35
+ function isOwner(address account) public view override(ICoinComments) returns (bool) {
36
+ return _owners.contains(account);
37
+ }
38
+
39
+ function supportsInterface(bytes4 interfaceId) public pure returns (bool) {
40
+ return type(ICoinComments).interfaceId == interfaceId;
41
+ }
42
+ }
@@ -1,109 +0,0 @@
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();
@@ -1,63 +0,0 @@
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
- });