@croptop/core-v6 0.0.32 → 0.0.34
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/ADMINISTRATION.md +65 -145
- package/ARCHITECTURE.md +68 -43
- package/AUDIT_INSTRUCTIONS.md +54 -62
- package/README.md +47 -6
- package/RISKS.md +2 -0
- package/SKILLS.md +7 -2
- package/USER_JOURNEYS.md +86 -35
- package/foundry.toml +2 -0
- package/package.json +31 -31
- package/references/operations.md +2 -2
- package/references/runtime.md +3 -3
- package/src/CTDeployer.sol +116 -126
- package/src/CTPublisher.sol +134 -138
- package/src/interfaces/ICTPublisher.sol +1 -2
- package/src/structs/CTAllowedPost.sol +0 -1
- package/src/structs/CTDeployerAllowedPost.sol +0 -1
- package/src/structs/CTPost.sol +0 -2
- package/src/structs/CTProjectConfig.sol +0 -1
- package/src/structs/CTSuckerDeploymentConfig.sol +0 -1
- package/test/CTDeployer.t.sol +5 -4
- package/test/Fork.t.sol +6 -3
- package/test/TestAuditGaps.sol +9 -8
- package/test/audit/CodexNemesisPoCs.t.sol +263 -0
- package/test/fork/PublishFork.t.sol +6 -3
package/src/CTPublisher.sol
CHANGED
|
@@ -27,7 +27,6 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
27
27
|
// --------------------------- custom errors ------------------------- //
|
|
28
28
|
//*********************************************************************//
|
|
29
29
|
|
|
30
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
31
30
|
error CTPublisher_DuplicatePost(bytes32 encodedIPFSUri);
|
|
32
31
|
error CTPublisher_EmptyEncodedIPFSUri();
|
|
33
32
|
error CTPublisher_InsufficientEthSent(uint256 expected, uint256 sent);
|
|
@@ -66,7 +65,6 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
66
65
|
/// @notice The ID of the tier that an IPFS metadata has been saved to.
|
|
67
66
|
/// @custom:param hook The hook for which the tier ID applies.
|
|
68
67
|
/// @custom:param encodedIPFSUri The IPFS URI.
|
|
69
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
70
68
|
mapping(address hook => mapping(bytes32 encodedIPFSUri => uint256)) public override tierIdForEncodedIPFSUriOf;
|
|
71
69
|
|
|
72
70
|
//*********************************************************************//
|
|
@@ -105,141 +103,6 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
105
103
|
FEE_PROJECT_ID = feeProjectId;
|
|
106
104
|
}
|
|
107
105
|
|
|
108
|
-
//*********************************************************************//
|
|
109
|
-
// ------------------------- external views -------------------------- //
|
|
110
|
-
//*********************************************************************//
|
|
111
|
-
|
|
112
|
-
/// @notice Get the tiers for the provided encoded IPFS URIs.
|
|
113
|
-
/// @dev The returned tier IDs may be stale if the corresponding tiers were removed externally via adjustTiers.
|
|
114
|
-
/// In that case, the store's tierOf call will return a tier with default/empty values. Callers should check
|
|
115
|
-
/// the returned tier's initialSupply or other fields to confirm the tier still exists.
|
|
116
|
-
/// @param hook The hook from which to get tiers.
|
|
117
|
-
/// @param encodedIPFSUris The URIs to get tiers of.
|
|
118
|
-
/// @return tiers The tiers that correspond to the provided encoded IPFS URIs. If there's no tier yet, an empty tier
|
|
119
|
-
/// is returned.
|
|
120
|
-
function tiersFor(
|
|
121
|
-
address hook,
|
|
122
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
123
|
-
bytes32[] memory encodedIPFSUris
|
|
124
|
-
)
|
|
125
|
-
external
|
|
126
|
-
view
|
|
127
|
-
override
|
|
128
|
-
returns (JB721Tier[] memory tiers)
|
|
129
|
-
{
|
|
130
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
131
|
-
uint256 numberOfEncodedIPFSUris = encodedIPFSUris.length;
|
|
132
|
-
|
|
133
|
-
// Initialize the tier array being returned.
|
|
134
|
-
tiers = new JB721Tier[](numberOfEncodedIPFSUris);
|
|
135
|
-
|
|
136
|
-
// Get the tier for each provided encoded IPFS URI.
|
|
137
|
-
for (uint256 i; i < numberOfEncodedIPFSUris;) {
|
|
138
|
-
// Check if there's a tier ID stored for the encoded IPFS URI.
|
|
139
|
-
uint256 tierId = tierIdForEncodedIPFSUriOf[hook][encodedIPFSUris[i]];
|
|
140
|
-
|
|
141
|
-
// If there's a tier ID stored, resolve it.
|
|
142
|
-
if (tierId != 0) {
|
|
143
|
-
// slither-disable-next-line calls-loop
|
|
144
|
-
tiers[i] = IJB721TiersHook(hook).STORE().tierOf({hook: hook, id: tierId, includeResolvedUri: false});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
unchecked {
|
|
148
|
-
++i;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
//*********************************************************************//
|
|
154
|
-
// -------------------------- public views --------------------------- //
|
|
155
|
-
//*********************************************************************//
|
|
156
|
-
|
|
157
|
-
/// @notice Post allowances for a particular category on a particular hook.
|
|
158
|
-
/// @param hook The hook contract for which this allowance applies.
|
|
159
|
-
/// @param category The category for which this allowance applies.
|
|
160
|
-
/// @return minimumPrice The minimum price that a poster must pay to record a new NFT.
|
|
161
|
-
/// @return minimumTotalSupply The minimum total number of available tokens that a minter must set to record a new
|
|
162
|
-
/// NFT.
|
|
163
|
-
/// @return maximumTotalSupply The max total supply of NFTs that can be made available when minting. Must be >=
|
|
164
|
-
/// minimumTotalSupply.
|
|
165
|
-
/// @return maximumSplitPercent The maximum split percent that a poster can set. 0 means splits are not allowed.
|
|
166
|
-
/// @return allowedAddresses The addresses allowed to post. Returns empty if all addresses are allowed.
|
|
167
|
-
function allowanceFor(
|
|
168
|
-
address hook,
|
|
169
|
-
uint256 category
|
|
170
|
-
)
|
|
171
|
-
public
|
|
172
|
-
view
|
|
173
|
-
override
|
|
174
|
-
returns (
|
|
175
|
-
uint256 minimumPrice,
|
|
176
|
-
uint256 minimumTotalSupply,
|
|
177
|
-
uint256 maximumTotalSupply,
|
|
178
|
-
uint256 maximumSplitPercent,
|
|
179
|
-
address[] memory allowedAddresses
|
|
180
|
-
)
|
|
181
|
-
{
|
|
182
|
-
// Get a reference to the packed values.
|
|
183
|
-
uint256 packed = _packedAllowanceFor[hook][category];
|
|
184
|
-
|
|
185
|
-
// minimum price in bits 0-103 (104 bits).
|
|
186
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
187
|
-
minimumPrice = uint256(uint104(packed));
|
|
188
|
-
// minimum supply in bits 104-135 (32 bits).
|
|
189
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
190
|
-
minimumTotalSupply = uint256(uint32(packed >> 104));
|
|
191
|
-
// maximum supply in bits 136-167 (32 bits).
|
|
192
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
193
|
-
maximumTotalSupply = uint256(uint32(packed >> 136));
|
|
194
|
-
// maximum split percent in bits 168-199 (32 bits).
|
|
195
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
196
|
-
maximumSplitPercent = uint256(uint32(packed >> 168));
|
|
197
|
-
|
|
198
|
-
allowedAddresses = _allowedAddresses[hook][category];
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
//*********************************************************************//
|
|
202
|
-
// -------------------------- internal views ------------------------- //
|
|
203
|
-
//*********************************************************************//
|
|
204
|
-
|
|
205
|
-
/// @dev ERC-2771 specifies the context as being a single address (20 bytes).
|
|
206
|
-
function _contextSuffixLength() internal view virtual override(ERC2771Context, Context) returns (uint256) {
|
|
207
|
-
return super._contextSuffixLength();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/// @notice Check if an address is included in an allow list.
|
|
211
|
-
/// @dev Uses an O(n) linear scan over the `addresses` array. This is acceptable for typical allow list sizes
|
|
212
|
-
/// (fewer than ~100 addresses), where gas cost is negligible. For very large allow lists, a Merkle proof
|
|
213
|
-
/// pattern would scale better, but the added complexity is not warranted for the expected use case.
|
|
214
|
-
/// @param addrs The candidate address.
|
|
215
|
-
/// @param addresses An array of allowed addresses.
|
|
216
|
-
function _isAllowed(address addrs, address[] memory addresses) internal pure returns (bool) {
|
|
217
|
-
// Keep a reference to the number of address to check against.
|
|
218
|
-
uint256 numberOfAddresses = addresses.length;
|
|
219
|
-
|
|
220
|
-
// Check if the address is included
|
|
221
|
-
for (uint256 i; i < numberOfAddresses;) {
|
|
222
|
-
if (addrs == addresses[i]) return true;
|
|
223
|
-
unchecked {
|
|
224
|
-
++i;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/// @notice Returns the calldata, prefered to use over `msg.data`
|
|
232
|
-
/// @return calldata the `msg.data` of this call
|
|
233
|
-
function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
|
|
234
|
-
return ERC2771Context._msgData();
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/// @notice Returns the sender, prefered to use over `msg.sender`
|
|
238
|
-
/// @return sender the sender address of this call.
|
|
239
|
-
function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
|
|
240
|
-
return ERC2771Context._msgSender();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
106
|
//*********************************************************************//
|
|
244
107
|
// ---------------------- external transactions ---------------------- //
|
|
245
108
|
//*********************************************************************//
|
|
@@ -446,7 +309,98 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
446
309
|
}
|
|
447
310
|
|
|
448
311
|
//*********************************************************************//
|
|
449
|
-
//
|
|
312
|
+
// ------------------------- external views -------------------------- //
|
|
313
|
+
//*********************************************************************//
|
|
314
|
+
|
|
315
|
+
/// @notice Get the tiers for the provided encoded IPFS URIs.
|
|
316
|
+
/// @dev The returned tier IDs may be stale if the corresponding tiers were removed externally via adjustTiers.
|
|
317
|
+
/// In that case, the store's tierOf call will return a tier with default/empty values. Callers should check
|
|
318
|
+
/// the returned tier's initialSupply or other fields to confirm the tier still exists.
|
|
319
|
+
/// @param hook The hook from which to get tiers.
|
|
320
|
+
/// @param encodedIPFSUris The URIs to get tiers of.
|
|
321
|
+
/// @return tiers The tiers that correspond to the provided encoded IPFS URIs. If there's no tier yet, an empty tier
|
|
322
|
+
/// is returned.
|
|
323
|
+
function tiersFor(
|
|
324
|
+
address hook,
|
|
325
|
+
bytes32[] memory encodedIPFSUris
|
|
326
|
+
)
|
|
327
|
+
external
|
|
328
|
+
view
|
|
329
|
+
override
|
|
330
|
+
returns (JB721Tier[] memory tiers)
|
|
331
|
+
{
|
|
332
|
+
uint256 numberOfEncodedIPFSUris = encodedIPFSUris.length;
|
|
333
|
+
|
|
334
|
+
// Initialize the tier array being returned.
|
|
335
|
+
tiers = new JB721Tier[](numberOfEncodedIPFSUris);
|
|
336
|
+
|
|
337
|
+
// Get the tier for each provided encoded IPFS URI.
|
|
338
|
+
for (uint256 i; i < numberOfEncodedIPFSUris;) {
|
|
339
|
+
// Check if there's a tier ID stored for the encoded IPFS URI.
|
|
340
|
+
uint256 tierId = tierIdForEncodedIPFSUriOf[hook][encodedIPFSUris[i]];
|
|
341
|
+
|
|
342
|
+
// If there's a tier ID stored, resolve it.
|
|
343
|
+
if (tierId != 0) {
|
|
344
|
+
// slither-disable-next-line calls-loop
|
|
345
|
+
tiers[i] = IJB721TiersHook(hook).STORE().tierOf({hook: hook, id: tierId, includeResolvedUri: false});
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
unchecked {
|
|
349
|
+
++i;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
//*********************************************************************//
|
|
355
|
+
// -------------------------- public views --------------------------- //
|
|
356
|
+
//*********************************************************************//
|
|
357
|
+
|
|
358
|
+
/// @notice Post allowances for a particular category on a particular hook.
|
|
359
|
+
/// @param hook The hook contract for which this allowance applies.
|
|
360
|
+
/// @param category The category for which this allowance applies.
|
|
361
|
+
/// @return minimumPrice The minimum price that a poster must pay to record a new NFT.
|
|
362
|
+
/// @return minimumTotalSupply The minimum total number of available tokens that a minter must set to record a new
|
|
363
|
+
/// NFT.
|
|
364
|
+
/// @return maximumTotalSupply The max total supply of NFTs that can be made available when minting. Must be >=
|
|
365
|
+
/// minimumTotalSupply.
|
|
366
|
+
/// @return maximumSplitPercent The maximum split percent that a poster can set. 0 means splits are not allowed.
|
|
367
|
+
/// @return allowedAddresses The addresses allowed to post. Returns empty if all addresses are allowed.
|
|
368
|
+
function allowanceFor(
|
|
369
|
+
address hook,
|
|
370
|
+
uint256 category
|
|
371
|
+
)
|
|
372
|
+
public
|
|
373
|
+
view
|
|
374
|
+
override
|
|
375
|
+
returns (
|
|
376
|
+
uint256 minimumPrice,
|
|
377
|
+
uint256 minimumTotalSupply,
|
|
378
|
+
uint256 maximumTotalSupply,
|
|
379
|
+
uint256 maximumSplitPercent,
|
|
380
|
+
address[] memory allowedAddresses
|
|
381
|
+
)
|
|
382
|
+
{
|
|
383
|
+
// Get a reference to the packed values.
|
|
384
|
+
uint256 packed = _packedAllowanceFor[hook][category];
|
|
385
|
+
|
|
386
|
+
// minimum price in bits 0-103 (104 bits).
|
|
387
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
388
|
+
minimumPrice = uint256(uint104(packed));
|
|
389
|
+
// minimum supply in bits 104-135 (32 bits).
|
|
390
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
391
|
+
minimumTotalSupply = uint256(uint32(packed >> 104));
|
|
392
|
+
// maximum supply in bits 136-167 (32 bits).
|
|
393
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
394
|
+
maximumTotalSupply = uint256(uint32(packed >> 136));
|
|
395
|
+
// maximum split percent in bits 168-199 (32 bits).
|
|
396
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
397
|
+
maximumSplitPercent = uint256(uint32(packed >> 168));
|
|
398
|
+
|
|
399
|
+
allowedAddresses = _allowedAddresses[hook][category];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
//*********************************************************************//
|
|
403
|
+
// ------------------------ internal helpers ------------------------- //
|
|
450
404
|
//*********************************************************************//
|
|
451
405
|
|
|
452
406
|
/// @notice Setup the posts.
|
|
@@ -613,4 +567,46 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
613
567
|
}
|
|
614
568
|
}
|
|
615
569
|
}
|
|
570
|
+
|
|
571
|
+
/// @notice Check if an address is included in an allow list.
|
|
572
|
+
/// @dev Uses an O(n) linear scan over the `addresses` array. This is acceptable for typical allow list sizes
|
|
573
|
+
/// (fewer than ~100 addresses), where gas cost is negligible. For very large allow lists, a Merkle proof
|
|
574
|
+
/// pattern would scale better, but the added complexity is not warranted for the expected use case.
|
|
575
|
+
/// @param addrs The candidate address.
|
|
576
|
+
/// @param addresses An array of allowed addresses.
|
|
577
|
+
function _isAllowed(address addrs, address[] memory addresses) internal pure returns (bool) {
|
|
578
|
+
// Keep a reference to the number of address to check against.
|
|
579
|
+
uint256 numberOfAddresses = addresses.length;
|
|
580
|
+
|
|
581
|
+
// Check if the address is included
|
|
582
|
+
for (uint256 i; i < numberOfAddresses;) {
|
|
583
|
+
if (addrs == addresses[i]) return true;
|
|
584
|
+
unchecked {
|
|
585
|
+
++i;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
return false;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
//*********************************************************************//
|
|
593
|
+
// -------------------------- internal views ------------------------- //
|
|
594
|
+
//*********************************************************************//
|
|
595
|
+
|
|
596
|
+
/// @dev ERC-2771 specifies the context as being a single address (20 bytes).
|
|
597
|
+
function _contextSuffixLength() internal view virtual override(ERC2771Context, Context) returns (uint256) {
|
|
598
|
+
return super._contextSuffixLength();
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/// @notice Returns the calldata, prefered to use over `msg.data`
|
|
602
|
+
/// @return calldata the `msg.data` of this call
|
|
603
|
+
function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
|
|
604
|
+
return ERC2771Context._msgData();
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/// @notice Returns the sender, prefered to use over `msg.sender`
|
|
608
|
+
/// @return sender the sender address of this call.
|
|
609
|
+
function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
|
|
610
|
+
return ERC2771Context._msgSender();
|
|
611
|
+
}
|
|
616
612
|
}
|
|
@@ -73,7 +73,7 @@ interface ICTPublisher {
|
|
|
73
73
|
/// @param hook The hook for which the tier ID applies.
|
|
74
74
|
/// @param encodedIPFSUri The encoded IPFS URI to look up.
|
|
75
75
|
/// @return The tier ID, or 0 if the URI has not been published.
|
|
76
|
-
// forge-lint: disable-next-line(mixed-case-function
|
|
76
|
+
// forge-lint: disable-next-line(mixed-case-function)
|
|
77
77
|
function tierIdForEncodedIPFSUriOf(address hook, bytes32 encodedIPFSUri) external view returns (uint256);
|
|
78
78
|
|
|
79
79
|
/// @notice Get the tiers for the provided encoded IPFS URIs.
|
|
@@ -81,7 +81,6 @@ interface ICTPublisher {
|
|
|
81
81
|
/// @param encodedIPFSUris The URIs to get tiers of.
|
|
82
82
|
/// @return tiers The tiers that correspond to the provided encoded IPFS URIs. Empty tiers are returned for URIs
|
|
83
83
|
/// without a tier.
|
|
84
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
85
84
|
function tiersFor(address hook, bytes32[] memory encodedIPFSUris) external view returns (JB721Tier[] memory tiers);
|
|
86
85
|
|
|
87
86
|
/// @notice Configure the allowed criteria for publishing new NFTs to a hook.
|
|
@@ -11,7 +11,6 @@ pragma solidity ^0.8.0;
|
|
|
11
11
|
/// @custom:member maximumSplitPercent The maximum split percent (out of JBConstants.SPLITS_TOTAL_PERCENT) that a
|
|
12
12
|
/// poster can set. 0 means splits are not allowed.
|
|
13
13
|
/// @custom:member allowedAddresses A list of addresses that are allowed to post on the category through Croptop.
|
|
14
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
15
14
|
struct CTAllowedPost {
|
|
16
15
|
address hook;
|
|
17
16
|
uint24 category;
|
|
@@ -10,7 +10,6 @@ pragma solidity ^0.8.0;
|
|
|
10
10
|
/// @custom:member maximumSplitPercent The maximum split percent (out of JBConstants.SPLITS_TOTAL_PERCENT) that a
|
|
11
11
|
/// poster can set. 0 means splits are not allowed.
|
|
12
12
|
/// @custom:member allowedAddresses A list of addresses that are allowed to post on the category through Croptop.
|
|
13
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
14
13
|
struct CTDeployerAllowedPost {
|
|
15
14
|
uint24 category;
|
|
16
15
|
uint104 minimumPrice;
|
package/src/structs/CTPost.sol
CHANGED
|
@@ -12,9 +12,7 @@ import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
|
12
12
|
/// @custom:member splitPercent The percent of the tier's price to route to the splits (out of
|
|
13
13
|
/// JBConstants.SPLITS_TOTAL_PERCENT).
|
|
14
14
|
/// @custom:member splits The splits to route funds to when this tier is minted.
|
|
15
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
16
15
|
struct CTPost {
|
|
17
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
18
16
|
bytes32 encodedIPFSUri;
|
|
19
17
|
uint32 totalSupply;
|
|
20
18
|
uint104 price;
|
|
@@ -11,7 +11,6 @@ import {CTDeployerAllowedPost} from "../structs/CTDeployerAllowedPost.sol";
|
|
|
11
11
|
/// @param name The name of the collection where posts will go.
|
|
12
12
|
/// @param symbol The symbol of the collection where posts will go.
|
|
13
13
|
/// @param salt A salt to use for the deterministic deployment.
|
|
14
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
15
14
|
struct CTProjectConfig {
|
|
16
15
|
JBTerminalConfig[] terminalConfigurations;
|
|
17
16
|
string projectUri;
|
|
@@ -5,7 +5,6 @@ import {JBSuckerDeployerConfig} from "@bananapus/suckers-v6/src/structs/JBSucker
|
|
|
5
5
|
|
|
6
6
|
/// @custom:member deployerConfigurations The information for how to suck tokens to other chains.
|
|
7
7
|
/// @custom:member salt The salt to use for creating suckers so that they use the same address across chains.
|
|
8
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
9
8
|
struct CTSuckerDeploymentConfig {
|
|
10
9
|
JBSuckerDeployerConfig[] deployerConfigurations;
|
|
11
10
|
bytes32 salt;
|
package/test/CTDeployer.t.sol
CHANGED
|
@@ -56,10 +56,11 @@ contract MockDataHook is IJBRulesetDataHook {
|
|
|
56
56
|
uint256 cashOutTaxRate,
|
|
57
57
|
uint256 cashOutCount,
|
|
58
58
|
uint256 totalSupply,
|
|
59
|
+
uint256 surplusValue,
|
|
59
60
|
JBCashOutHookSpecification[] memory hookSpecifications
|
|
60
61
|
)
|
|
61
62
|
{
|
|
62
|
-
return (TAX_RATE, context.cashOutCount, context.totalSupply, hookSpecifications);
|
|
63
|
+
return (TAX_RATE, context.cashOutCount, context.totalSupply, context.surplus.value, hookSpecifications);
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
function beforePayRecordedWith(JBBeforePayRecordedContext calldata)
|
|
@@ -434,7 +435,7 @@ contract TestCTDeployer is Test {
|
|
|
434
435
|
JBBeforeCashOutRecordedContext memory context =
|
|
435
436
|
_buildCashOutContext(deployedProjectId, unauthorized, 100e18, 1000e18);
|
|
436
437
|
|
|
437
|
-
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply
|
|
438
|
+
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply,,) = deployer.beforeCashOutRecordedWith(context);
|
|
438
439
|
|
|
439
440
|
assertEq(taxRate, 5000, "tax rate should come from data hook");
|
|
440
441
|
assertEq(cashOutCount, 100e18, "cashOutCount should be forwarded");
|
|
@@ -455,7 +456,7 @@ contract TestCTDeployer is Test {
|
|
|
455
456
|
JBBeforeCashOutRecordedContext memory context =
|
|
456
457
|
_buildCashOutContext(deployedProjectId, suckerAddr, 100e18, 1000e18);
|
|
457
458
|
|
|
458
|
-
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply
|
|
459
|
+
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply,,) = deployer.beforeCashOutRecordedWith(context);
|
|
459
460
|
|
|
460
461
|
assertEq(taxRate, 0, "sucker should get 0% tax rate");
|
|
461
462
|
assertEq(cashOutCount, 100e18, "cashOutCount should pass through");
|
|
@@ -466,7 +467,7 @@ contract TestCTDeployer is Test {
|
|
|
466
467
|
function test_beforeCashOutRecordedWith_returnsDefaultsWhenNoDataHook() public {
|
|
467
468
|
JBBeforeCashOutRecordedContext memory context = _buildCashOutContext(999, unauthorized, 100e18, 1000e18);
|
|
468
469
|
|
|
469
|
-
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply
|
|
470
|
+
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply,, JBCashOutHookSpecification[] memory specs) =
|
|
470
471
|
deployer.beforeCashOutRecordedWith(context);
|
|
471
472
|
|
|
472
473
|
assertEq(taxRate, context.cashOutTaxRate, "cashOutTaxRate should be returned as-is from context");
|
package/test/Fork.t.sol
CHANGED
|
@@ -21,6 +21,7 @@ import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
|
21
21
|
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
22
22
|
import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
|
|
23
23
|
import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
|
|
24
|
+
import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
|
|
24
25
|
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
25
26
|
|
|
26
27
|
// Suckers — deploy fresh within fork.
|
|
@@ -166,7 +167,7 @@ contract ForkTest is Test {
|
|
|
166
167
|
jbPermissions = new JBPermissions(trustedForwarder);
|
|
167
168
|
jbProjects = new JBProjects(multisig, address(0), trustedForwarder);
|
|
168
169
|
jbDirectory = new JBDirectory(jbPermissions, jbProjects, multisig);
|
|
169
|
-
JBERC20 jbErc20 = new JBERC20();
|
|
170
|
+
JBERC20 jbErc20 = new JBERC20(jbPermissions, jbProjects);
|
|
170
171
|
jbTokens = new JBTokens(jbDirectory, jbErc20);
|
|
171
172
|
jbRulesets = new JBRulesets(jbDirectory);
|
|
172
173
|
jbPrices = new JBPrices(jbDirectory, jbPermissions, jbProjects, multisig, trustedForwarder);
|
|
@@ -193,9 +194,11 @@ contract ForkTest is Test {
|
|
|
193
194
|
function _deploy721Hook() internal {
|
|
194
195
|
JB721TiersHookStore store = new JB721TiersHookStore();
|
|
195
196
|
JBAddressRegistry addressRegistry = new JBAddressRegistry();
|
|
197
|
+
JB721CheckpointsDeployer checkpointsDeployer = new JB721CheckpointsDeployer();
|
|
196
198
|
|
|
197
|
-
JB721TiersHook hookImpl =
|
|
198
|
-
|
|
199
|
+
JB721TiersHook hookImpl = new JB721TiersHook(
|
|
200
|
+
jbDirectory, jbPermissions, jbPrices, jbRulesets, store, jbSplits, checkpointsDeployer, trustedForwarder
|
|
201
|
+
);
|
|
199
202
|
|
|
200
203
|
hookDeployer = new JB721TiersHookDeployer(hookImpl, store, addressRegistry, trustedForwarder);
|
|
201
204
|
}
|
package/test/TestAuditGaps.sol
CHANGED
|
@@ -37,7 +37,7 @@ contract RevertingDataHook is IJBRulesetDataHook {
|
|
|
37
37
|
external
|
|
38
38
|
pure
|
|
39
39
|
override
|
|
40
|
-
returns (uint256, uint256, uint256, JBCashOutHookSpecification[] memory)
|
|
40
|
+
returns (uint256, uint256, uint256, uint256, JBCashOutHookSpecification[] memory)
|
|
41
41
|
{
|
|
42
42
|
revert("DATA_HOOK_REVERTED");
|
|
43
43
|
}
|
|
@@ -81,10 +81,11 @@ contract SuccessDataHook is IJBRulesetDataHook {
|
|
|
81
81
|
uint256 cashOutTaxRate,
|
|
82
82
|
uint256 cashOutCount,
|
|
83
83
|
uint256 totalSupply,
|
|
84
|
+
uint256 surplusValue,
|
|
84
85
|
JBCashOutHookSpecification[] memory hookSpecifications
|
|
85
86
|
)
|
|
86
87
|
{
|
|
87
|
-
return (TAX_RATE, context.cashOutCount, context.totalSupply, hookSpecifications);
|
|
88
|
+
return (TAX_RATE, context.cashOutCount, context.totalSupply, context.surplus.value, hookSpecifications);
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
function beforePayRecordedWith(JBBeforePayRecordedContext calldata context)
|
|
@@ -243,7 +244,7 @@ contract TestAuditGaps is Test {
|
|
|
243
244
|
// dataHookOf[999] is address(0) by default (never set).
|
|
244
245
|
JBBeforeCashOutRecordedContext memory context = _buildCashOutContext(999, unauthorized, 100e18, 1000e18);
|
|
245
246
|
|
|
246
|
-
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply
|
|
247
|
+
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply,, JBCashOutHookSpecification[] memory specs) =
|
|
247
248
|
deployer.beforeCashOutRecordedWith(context);
|
|
248
249
|
|
|
249
250
|
assertEq(taxRate, context.cashOutTaxRate, "cashOutTaxRate should be returned as-is from context");
|
|
@@ -269,7 +270,7 @@ contract TestAuditGaps is Test {
|
|
|
269
270
|
JBBeforeCashOutRecordedContext memory context =
|
|
270
271
|
_buildCashOutContext(hookProjectId, unauthorized, 100e18, 1000e18);
|
|
271
272
|
|
|
272
|
-
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply
|
|
273
|
+
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply,,) = deployer.beforeCashOutRecordedWith(context);
|
|
273
274
|
|
|
274
275
|
assertEq(taxRate, 5000, "tax rate should be forwarded from data hook");
|
|
275
276
|
assertEq(cashOutCount, 100e18, "cashOutCount should be forwarded");
|
|
@@ -302,7 +303,7 @@ contract TestAuditGaps is Test {
|
|
|
302
303
|
JBBeforeCashOutRecordedContext memory context = _buildCashOutContext(hookProjectId, realSucker, 100e18, 1000e18);
|
|
303
304
|
|
|
304
305
|
// Should NOT revert because suckers bypass the data hook entirely.
|
|
305
|
-
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply
|
|
306
|
+
(uint256 taxRate, uint256 cashOutCount, uint256 totalSupply,,) = deployer.beforeCashOutRecordedWith(context);
|
|
306
307
|
|
|
307
308
|
assertEq(taxRate, 0, "sucker should get 0% tax rate");
|
|
308
309
|
assertEq(cashOutCount, 100e18, "cashOutCount should pass through");
|
|
@@ -320,7 +321,7 @@ contract TestAuditGaps is Test {
|
|
|
320
321
|
// fakeSucker is NOT registered as a sucker (default mock returns false).
|
|
321
322
|
JBBeforeCashOutRecordedContext memory context = _buildCashOutContext(hookProjectId, fakeSucker, 100e18, 1000e18);
|
|
322
323
|
|
|
323
|
-
(uint256 taxRate
|
|
324
|
+
(uint256 taxRate,,,,) = deployer.beforeCashOutRecordedWith(context);
|
|
324
325
|
|
|
325
326
|
// Should get the data hook's tax rate (5000), not 0.
|
|
326
327
|
assertEq(taxRate, 5000, "non-sucker should not bypass tax");
|
|
@@ -340,7 +341,7 @@ contract TestAuditGaps is Test {
|
|
|
340
341
|
|
|
341
342
|
JBBeforeCashOutRecordedContext memory context = _buildCashOutContext(hookProjectId, realSucker, 100e18, 1000e18);
|
|
342
343
|
|
|
343
|
-
(uint256 taxRate
|
|
344
|
+
(uint256 taxRate,,,,) = deployer.beforeCashOutRecordedWith(context);
|
|
344
345
|
|
|
345
346
|
// Should get the data hook's tax rate, not 0.
|
|
346
347
|
assertEq(taxRate, 5000, "sucker from wrong project should not bypass tax");
|
|
@@ -359,7 +360,7 @@ contract TestAuditGaps is Test {
|
|
|
359
360
|
|
|
360
361
|
JBBeforeCashOutRecordedContext memory context = _buildCashOutContext(hookProjectId, realSucker, 100e18, 1000e18);
|
|
361
362
|
|
|
362
|
-
(uint256 taxRate
|
|
363
|
+
(uint256 taxRate,,,,) = deployer.beforeCashOutRecordedWith(context);
|
|
363
364
|
|
|
364
365
|
assertEq(taxRate, 0, "valid sucker should get 0% tax");
|
|
365
366
|
}
|