@croptop/core-v6 0.0.36 → 0.0.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -8
- package/src/CTPublisher.sol +20 -5
- package/test/audit/CodexNemesisCroptopPublisherBoundary.t.sol +329 -0
- package/test/audit/CodexNemesisCurrencyPoCs.t.sol +371 -0
- package/test/audit/CodexNemesisFreshRound.t.sol +395 -0
- package/test/audit/CodexNemesisMetadataShadow.t.sol +196 -0
- package/test/audit/CodexNemesisPolicyReuse.t.sol +168 -0
- package/test/audit/CodexNemesisUriDrift.t.sol +252 -0
- package/test/audit/Pass12Fixes.t.sol +388 -0
- package/test/fork/PublishFork.t.sol +2 -2
- package/test/regression/StaleTierIdMapping.t.sol +10 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.28;
|
|
3
|
+
|
|
4
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
5
|
+
import "forge-std/Test.sol";
|
|
6
|
+
|
|
7
|
+
import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
8
|
+
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
9
|
+
import {IJBOwnable} from "@bananapus/ownable-v6/src/interfaces/IJBOwnable.sol";
|
|
10
|
+
import {IJB721Hook} from "@bananapus/721-hook-v6/src/interfaces/IJB721Hook.sol";
|
|
11
|
+
import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
|
|
12
|
+
import {IJB721TiersHookStore} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookStore.sol";
|
|
13
|
+
import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
|
|
14
|
+
import {JB721TierFlags} from "@bananapus/721-hook-v6/src/structs/JB721TierFlags.sol";
|
|
15
|
+
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
16
|
+
|
|
17
|
+
import {CTAllowedPost} from "../../src/structs/CTAllowedPost.sol";
|
|
18
|
+
import {CTPost} from "../../src/structs/CTPost.sol";
|
|
19
|
+
import {CTPublisher} from "../../src/CTPublisher.sol";
|
|
20
|
+
|
|
21
|
+
contract CodexNemesisPolicyReuseTest is Test {
|
|
22
|
+
CTPublisher internal publisher;
|
|
23
|
+
|
|
24
|
+
IJBPermissions internal permissions = IJBPermissions(makeAddr("permissions"));
|
|
25
|
+
IJBDirectory internal directory = IJBDirectory(makeAddr("directory"));
|
|
26
|
+
|
|
27
|
+
address internal hookOwner = makeAddr("hookOwner");
|
|
28
|
+
address internal hookAddr = makeAddr("hook");
|
|
29
|
+
address internal hookStoreAddr = makeAddr("hookStore");
|
|
30
|
+
address internal projectTerminal = makeAddr("projectTerminal");
|
|
31
|
+
address internal feeTerminal = makeAddr("feeTerminal");
|
|
32
|
+
address internal alice = makeAddr("alice");
|
|
33
|
+
address internal bob = makeAddr("bob");
|
|
34
|
+
|
|
35
|
+
uint256 internal constant FEE_PROJECT_ID = 1;
|
|
36
|
+
uint256 internal constant PROJECT_ID = 42;
|
|
37
|
+
bytes32 internal constant URI = keccak256("stale-policy-uri");
|
|
38
|
+
uint104 internal constant PRICE = 1 ether;
|
|
39
|
+
|
|
40
|
+
function setUp() public {
|
|
41
|
+
publisher = new CTPublisher(directory, permissions, FEE_PROJECT_ID, address(0));
|
|
42
|
+
|
|
43
|
+
vm.mockCall(hookAddr, abi.encodeWithSelector(IJBOwnable.owner.selector), abi.encode(hookOwner));
|
|
44
|
+
vm.mockCall(hookAddr, abi.encodeWithSelector(IJB721Hook.PROJECT_ID.selector), abi.encode(PROJECT_ID));
|
|
45
|
+
vm.mockCall(hookAddr, abi.encodeWithSelector(IJB721TiersHook.STORE.selector), abi.encode(hookStoreAddr));
|
|
46
|
+
|
|
47
|
+
vm.mockCall(
|
|
48
|
+
address(permissions), abi.encodeWithSelector(IJBPermissions.hasPermission.selector), abi.encode(true)
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
vm.mockCall(
|
|
52
|
+
address(directory),
|
|
53
|
+
abi.encodeWithSelector(IJBDirectory.primaryTerminalOf.selector, PROJECT_ID),
|
|
54
|
+
abi.encode(projectTerminal)
|
|
55
|
+
);
|
|
56
|
+
vm.mockCall(
|
|
57
|
+
address(directory),
|
|
58
|
+
abi.encodeWithSelector(IJBDirectory.primaryTerminalOf.selector, FEE_PROJECT_ID),
|
|
59
|
+
abi.encode(feeTerminal)
|
|
60
|
+
);
|
|
61
|
+
vm.mockCall(projectTerminal, "", abi.encode(uint256(0)));
|
|
62
|
+
vm.mockCall(feeTerminal, "", abi.encode(uint256(0)));
|
|
63
|
+
vm.mockCall(
|
|
64
|
+
hookStoreAddr, abi.encodeWithSelector(IJB721TiersHookStore.isTierRemoved.selector), abi.encode(false)
|
|
65
|
+
);
|
|
66
|
+
vm.mockCall(hookAddr, abi.encodeWithSelector(IJB721TiersHook.adjustTiers.selector), abi.encode());
|
|
67
|
+
vm.mockCall(hookAddr, abi.encodeWithSelector(bytes4(keccak256("METADATA_ID_TARGET()"))), abi.encode(address(0)));
|
|
68
|
+
|
|
69
|
+
vm.deal(alice, 10 ether);
|
|
70
|
+
vm.deal(bob, 10 ether);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function test_existingTierReuseIgnoresUpdatedAllowlist() public {
|
|
74
|
+
uint256 mintValue = PRICE + (PRICE / publisher.FEE_DIVISOR());
|
|
75
|
+
|
|
76
|
+
_configureAllowlist(alice);
|
|
77
|
+
|
|
78
|
+
vm.mockCall(
|
|
79
|
+
hookStoreAddr, abi.encodeWithSelector(IJB721TiersHookStore.maxTierIdOf.selector), abi.encode(uint256(0))
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
CTPost[] memory initialPosts = _singlePost();
|
|
83
|
+
|
|
84
|
+
vm.prank(alice);
|
|
85
|
+
publisher.mintFrom{value: mintValue}(IJB721TiersHook(hookAddr), initialPosts, alice, alice, "", "");
|
|
86
|
+
|
|
87
|
+
assertEq(publisher.tierIdForEncodedIPFSUriOf(hookAddr, URI), 1, "initial publish should store tier id");
|
|
88
|
+
|
|
89
|
+
_configureAllowlist(bob);
|
|
90
|
+
|
|
91
|
+
CTPost[] memory blockedNewUri = new CTPost[](1);
|
|
92
|
+
blockedNewUri[0] = CTPost({
|
|
93
|
+
encodedIPFSUri: keccak256("new-uri"),
|
|
94
|
+
totalSupply: 10,
|
|
95
|
+
price: PRICE,
|
|
96
|
+
category: 7,
|
|
97
|
+
splitPercent: 0,
|
|
98
|
+
splits: new JBSplit[](0)
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
vm.mockCall(
|
|
102
|
+
hookStoreAddr, abi.encodeWithSelector(IJB721TiersHookStore.maxTierIdOf.selector), abi.encode(uint256(1))
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
vm.prank(alice);
|
|
106
|
+
vm.expectRevert(abi.encodeWithSelector(CTPublisher.CTPublisher_NotInAllowList.selector, alice, _asArray(bob)));
|
|
107
|
+
publisher.mintFrom{value: mintValue}(IJB721TiersHook(hookAddr), blockedNewUri, alice, alice, "", "");
|
|
108
|
+
|
|
109
|
+
JB721Tier memory existingTier = JB721Tier({
|
|
110
|
+
id: 1,
|
|
111
|
+
price: PRICE,
|
|
112
|
+
remainingSupply: 9,
|
|
113
|
+
initialSupply: 10,
|
|
114
|
+
votingUnits: 0,
|
|
115
|
+
reserveFrequency: 0,
|
|
116
|
+
reserveBeneficiary: address(0),
|
|
117
|
+
encodedIPFSUri: URI,
|
|
118
|
+
category: 7,
|
|
119
|
+
discountPercent: 0,
|
|
120
|
+
flags: JB721TierFlags({
|
|
121
|
+
allowOwnerMint: false,
|
|
122
|
+
transfersPausable: false,
|
|
123
|
+
cantBeRemoved: false,
|
|
124
|
+
cantIncreaseDiscountPercent: false,
|
|
125
|
+
cantBuyWithCredits: false
|
|
126
|
+
}),
|
|
127
|
+
splitPercent: 0,
|
|
128
|
+
resolvedUri: ""
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
vm.mockCall(
|
|
132
|
+
hookStoreAddr,
|
|
133
|
+
abi.encodeWithSelector(IJB721TiersHookStore.tierOf.selector, hookAddr, 1, false),
|
|
134
|
+
abi.encode(existingTier)
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
vm.prank(alice);
|
|
138
|
+
publisher.mintFrom{value: mintValue}(IJB721TiersHook(hookAddr), initialPosts, alice, alice, "", "");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function _configureAllowlist(address allowedPoster) internal {
|
|
142
|
+
CTAllowedPost[] memory allowedPosts = new CTAllowedPost[](1);
|
|
143
|
+
allowedPosts[0] = CTAllowedPost({
|
|
144
|
+
hook: hookAddr,
|
|
145
|
+
category: 7,
|
|
146
|
+
minimumPrice: PRICE,
|
|
147
|
+
minimumTotalSupply: 1,
|
|
148
|
+
maximumTotalSupply: 10,
|
|
149
|
+
maximumSplitPercent: 0,
|
|
150
|
+
allowedAddresses: _asArray(allowedPoster)
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
vm.prank(hookOwner);
|
|
154
|
+
publisher.configurePostingCriteriaFor(allowedPosts);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function _singlePost() internal pure returns (CTPost[] memory posts) {
|
|
158
|
+
posts = new CTPost[](1);
|
|
159
|
+
posts[0] = CTPost({
|
|
160
|
+
encodedIPFSUri: URI, totalSupply: 10, price: PRICE, category: 7, splitPercent: 0, splits: new JBSplit[](0)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function _asArray(address addr) internal pure returns (address[] memory values) {
|
|
165
|
+
values = new address[](1);
|
|
166
|
+
values[0] = addr;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Test} from "forge-std/Test.sol";
|
|
5
|
+
|
|
6
|
+
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
7
|
+
import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
8
|
+
import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
|
|
9
|
+
import {JBPermissions} from "@bananapus/core-v6/src/JBPermissions.sol";
|
|
10
|
+
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
11
|
+
import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
|
|
12
|
+
import {IJB721TiersHookStore} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookStore.sol";
|
|
13
|
+
import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
|
|
14
|
+
import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfig.sol";
|
|
15
|
+
import {JB721TierFlags} from "@bananapus/721-hook-v6/src/structs/JB721TierFlags.sol";
|
|
16
|
+
|
|
17
|
+
import {CTAllowedPost} from "../../src/structs/CTAllowedPost.sol";
|
|
18
|
+
import {CTPost} from "../../src/structs/CTPost.sol";
|
|
19
|
+
import {CTPublisher} from "../../src/CTPublisher.sol";
|
|
20
|
+
|
|
21
|
+
contract CodexNemesisUriDriftTest is Test {
|
|
22
|
+
bytes32 internal constant URI_A = keccak256("uri-a");
|
|
23
|
+
bytes32 internal constant URI_B = keccak256("uri-b");
|
|
24
|
+
|
|
25
|
+
JBPermissions internal permissions;
|
|
26
|
+
MockTerminal internal terminal;
|
|
27
|
+
MockDirectory internal directory;
|
|
28
|
+
MockStore internal store;
|
|
29
|
+
MockHook internal hook;
|
|
30
|
+
CTPublisher internal publisher;
|
|
31
|
+
|
|
32
|
+
address internal hookOwner = makeAddr("hookOwner");
|
|
33
|
+
address internal poster = makeAddr("poster");
|
|
34
|
+
uint256 internal constant FEE_PROJECT_ID = 1;
|
|
35
|
+
uint256 internal constant PROJECT_ID = 42;
|
|
36
|
+
|
|
37
|
+
function setUp() public {
|
|
38
|
+
permissions = new JBPermissions(address(0));
|
|
39
|
+
terminal = new MockTerminal();
|
|
40
|
+
directory = new MockDirectory(IJBTerminal(address(terminal)));
|
|
41
|
+
store = new MockStore();
|
|
42
|
+
hook = new MockHook(hookOwner, PROJECT_ID, store);
|
|
43
|
+
publisher = new CTPublisher(
|
|
44
|
+
IJBDirectory(address(directory)), IJBPermissions(address(permissions)), FEE_PROJECT_ID, address(0)
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
vm.deal(poster, 10 ether);
|
|
48
|
+
|
|
49
|
+
CTAllowedPost[] memory allowedPosts = new CTAllowedPost[](1);
|
|
50
|
+
allowedPosts[0] = CTAllowedPost({
|
|
51
|
+
hook: address(hook),
|
|
52
|
+
category: 7,
|
|
53
|
+
minimumPrice: 1 ether,
|
|
54
|
+
minimumTotalSupply: 1,
|
|
55
|
+
maximumTotalSupply: 100,
|
|
56
|
+
maximumSplitPercent: 0,
|
|
57
|
+
allowedAddresses: new address[](0)
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
vm.prank(hookOwner);
|
|
61
|
+
publisher.configurePostingCriteriaFor(allowedPosts);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function test_uriMutationDesyncAllowsDuplicateContentPublication() public {
|
|
65
|
+
_publish(URI_A);
|
|
66
|
+
|
|
67
|
+
assertEq(publisher.tierIdForEncodedIPFSUriOf(address(hook), URI_A), 1, "publisher should index URI_A -> tier 1");
|
|
68
|
+
assertEq(store.tierUri(1), URI_A, "store should record tier 1 as URI_A");
|
|
69
|
+
|
|
70
|
+
vm.prank(hookOwner);
|
|
71
|
+
hook.setMetadata("", "", "", "", address(this), 1, URI_B);
|
|
72
|
+
|
|
73
|
+
assertEq(store.tierUri(1), URI_B, "owner metadata update should move tier 1 to URI_B");
|
|
74
|
+
assertEq(
|
|
75
|
+
publisher.tierIdForEncodedIPFSUriOf(address(hook), URI_A),
|
|
76
|
+
1,
|
|
77
|
+
"publisher mapping remains stale at URI_A -> tier 1"
|
|
78
|
+
);
|
|
79
|
+
assertEq(
|
|
80
|
+
publisher.tierIdForEncodedIPFSUriOf(address(hook), URI_B), 0, "publisher has no entry for the new URI yet"
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
_publish(URI_B);
|
|
84
|
+
|
|
85
|
+
assertEq(store.maxTierId(), 2, "publishing URI_B again should create a fresh tier");
|
|
86
|
+
assertEq(store.tierUri(1), URI_B, "tier 1 still points at URI_B after mutation");
|
|
87
|
+
assertEq(store.tierUri(2), URI_B, "tier 2 now also points at URI_B");
|
|
88
|
+
assertEq(
|
|
89
|
+
publisher.tierIdForEncodedIPFSUriOf(address(hook), URI_B),
|
|
90
|
+
2,
|
|
91
|
+
"publisher now tracks URI_B as a second tier instead of rejecting the duplicate"
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function _publish(bytes32 uri) internal {
|
|
96
|
+
CTPost[] memory posts = new CTPost[](1);
|
|
97
|
+
posts[0] = CTPost({
|
|
98
|
+
encodedIPFSUri: uri, totalSupply: 10, price: 1 ether, category: 7, splitPercent: 0, splits: new JBSplit[](0)
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
vm.prank(poster);
|
|
102
|
+
publisher.mintFrom{value: 1.05 ether}(IJB721TiersHook(address(hook)), posts, poster, poster, "", "");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
contract MockDirectory {
|
|
107
|
+
// forge-lint: disable-next-line(screaming-snake-case-immutable)
|
|
108
|
+
IJBTerminal internal immutable _terminal;
|
|
109
|
+
|
|
110
|
+
constructor(IJBTerminal terminal) {
|
|
111
|
+
_terminal = terminal;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function primaryTerminalOf(uint256, address) external view returns (IJBTerminal) {
|
|
115
|
+
return _terminal;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
contract MockTerminal {
|
|
120
|
+
function pay(
|
|
121
|
+
uint256,
|
|
122
|
+
address,
|
|
123
|
+
uint256,
|
|
124
|
+
address,
|
|
125
|
+
uint256,
|
|
126
|
+
string calldata,
|
|
127
|
+
bytes calldata
|
|
128
|
+
)
|
|
129
|
+
external
|
|
130
|
+
payable
|
|
131
|
+
returns (uint256)
|
|
132
|
+
{
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
contract MockStore {
|
|
138
|
+
struct TierData {
|
|
139
|
+
bytes32 uri;
|
|
140
|
+
uint104 price;
|
|
141
|
+
uint24 category;
|
|
142
|
+
uint32 supply;
|
|
143
|
+
bool removed;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
uint256 internal _maxTierId;
|
|
147
|
+
mapping(uint256 tierId => TierData) internal _tiers;
|
|
148
|
+
|
|
149
|
+
function maxTierIdOf(address) external view returns (uint256) {
|
|
150
|
+
return _maxTierId;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function isTierRemoved(address, uint256 tierId) external view returns (bool) {
|
|
154
|
+
return _tiers[tierId].removed;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function tierOf(address, uint256 tierId, bool) external view returns (JB721Tier memory) {
|
|
158
|
+
TierData memory tier = _tiers[tierId];
|
|
159
|
+
return JB721Tier({
|
|
160
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
161
|
+
id: uint32(tierId),
|
|
162
|
+
price: tier.price,
|
|
163
|
+
remainingSupply: tier.supply,
|
|
164
|
+
initialSupply: tier.supply,
|
|
165
|
+
votingUnits: 0,
|
|
166
|
+
reserveFrequency: 0,
|
|
167
|
+
reserveBeneficiary: address(0),
|
|
168
|
+
encodedIPFSUri: tier.uri,
|
|
169
|
+
category: tier.category,
|
|
170
|
+
discountPercent: 0,
|
|
171
|
+
flags: JB721TierFlags({
|
|
172
|
+
allowOwnerMint: false,
|
|
173
|
+
transfersPausable: false,
|
|
174
|
+
cantBeRemoved: false,
|
|
175
|
+
cantIncreaseDiscountPercent: false,
|
|
176
|
+
cantBuyWithCredits: false
|
|
177
|
+
}),
|
|
178
|
+
splitPercent: 0,
|
|
179
|
+
resolvedUri: ""
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function addTier(JB721TierConfig calldata config) external returns (uint256 tierId) {
|
|
184
|
+
tierId = ++_maxTierId;
|
|
185
|
+
_tiers[tierId] = TierData({
|
|
186
|
+
uri: config.encodedIPFSUri,
|
|
187
|
+
price: config.price,
|
|
188
|
+
category: config.category,
|
|
189
|
+
supply: config.initialSupply,
|
|
190
|
+
removed: false
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// forge-lint: disable-next-line(mixed-case-function)
|
|
195
|
+
function setEncodedIPFSUriOf(uint256 tierId, bytes32 uri) external {
|
|
196
|
+
_tiers[tierId].uri = uri;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function tierUri(uint256 tierId) external view returns (bytes32) {
|
|
200
|
+
return _tiers[tierId].uri;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function maxTierId() external view returns (uint256) {
|
|
204
|
+
return _maxTierId;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
contract MockHook {
|
|
209
|
+
address internal _owner;
|
|
210
|
+
uint256 public immutable PROJECT_ID;
|
|
211
|
+
// forge-lint: disable-next-line(screaming-snake-case-immutable)
|
|
212
|
+
MockStore internal immutable _store;
|
|
213
|
+
|
|
214
|
+
constructor(address owner_, uint256 projectId, MockStore store_) {
|
|
215
|
+
_owner = owner_;
|
|
216
|
+
PROJECT_ID = projectId;
|
|
217
|
+
_store = store_;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function owner() external view returns (address) {
|
|
221
|
+
return _owner;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function STORE() external view returns (IJB721TiersHookStore) {
|
|
225
|
+
return IJB721TiersHookStore(address(_store));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function METADATA_ID_TARGET() external view returns (address) {
|
|
229
|
+
return address(this);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function adjustTiers(JB721TierConfig[] calldata tiersToAdd, uint256[] calldata) external {
|
|
233
|
+
for (uint256 i; i < tiersToAdd.length; i++) {
|
|
234
|
+
_store.addTier(tiersToAdd[i]);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function setMetadata(
|
|
239
|
+
string calldata,
|
|
240
|
+
string calldata,
|
|
241
|
+
string calldata,
|
|
242
|
+
string calldata,
|
|
243
|
+
address,
|
|
244
|
+
uint256 encodedIPFSUriTierId,
|
|
245
|
+
bytes32 encodedIPFSUri
|
|
246
|
+
)
|
|
247
|
+
external
|
|
248
|
+
{
|
|
249
|
+
require(msg.sender == _owner, "not owner");
|
|
250
|
+
_store.setEncodedIPFSUriOf(encodedIPFSUriTierId, encodedIPFSUri);
|
|
251
|
+
}
|
|
252
|
+
}
|