@croptop/core-v6 0.0.30 → 0.0.32
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/README.md +2 -0
- package/USER_JOURNEYS.md +11 -0
- package/package.json +10 -10
- package/src/CTDeployer.sol +24 -1
- package/src/CTPublisher.sol +30 -16
package/README.md
CHANGED
|
@@ -90,4 +90,6 @@ script/
|
|
|
90
90
|
- fee routing depends on the designated fee project remaining correctly configured; if its terminal rejects payments,
|
|
91
91
|
Croptop refunds the fee to `_msgSender()` instead of trapping ETH in `CTPublisher`
|
|
92
92
|
- burn-lock ownership is intentionally irreversible and should only be used when immutability is desired
|
|
93
|
+
- after burn-locking into `CTProjectOwner`, the previous owner no longer holds the project NFT directly; control is
|
|
94
|
+
intentionally mediated through Croptop's owner helper and hook-admin surface instead of remaining a plain owner EOA
|
|
93
95
|
- duplicate-content and stale-tier edge cases are guarded by tests, but integrations should still treat metadata reuse carefully
|
package/USER_JOURNEYS.md
CHANGED
|
@@ -52,6 +52,17 @@
|
|
|
52
52
|
2. Restrict future edits to the paths Croptop intentionally exposes.
|
|
53
53
|
3. Accept that this is a product-shaping choice, not a cosmetic deployment detail.
|
|
54
54
|
|
|
55
|
+
## Journey 5: Support Cross-Chain Payments Through Data Hooks
|
|
56
|
+
|
|
57
|
+
**Starting state:** a sucker pays the Croptop project on behalf of a remote user via `payRemote`, and `CTDeployer.beforePayRecordedWith` needs to forward the correct beneficiary to downstream hooks.
|
|
58
|
+
|
|
59
|
+
**Success:** downstream data hooks see the real remote user so any hook-specific accounting accrues to the right person.
|
|
60
|
+
|
|
61
|
+
**Flow**
|
|
62
|
+
1. The sucker calls `terminal.pay()` with relay-beneficiary metadata.
|
|
63
|
+
2. `CTDeployer.beforePayRecordedWith()` resolves the relay beneficiary when the payer is a registered sucker.
|
|
64
|
+
3. The swapped beneficiary is forwarded to the downstream data hook.
|
|
65
|
+
|
|
55
66
|
## Hand-Offs
|
|
56
67
|
|
|
57
68
|
- Use [nana-721-hook-v6](../nana-721-hook-v6/USER_JOURNEYS.md) for the underlying tier issuance behavior Croptop wraps.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@croptop/core-v6",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.32",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,18 +16,18 @@
|
|
|
16
16
|
"artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'croptop-core-v5'"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@bananapus/721-hook-v6": "^0.0.
|
|
20
|
-
"@bananapus/buyback-hook-v6": "^0.0.
|
|
21
|
-
"@bananapus/core-v6": "^0.0.
|
|
19
|
+
"@bananapus/721-hook-v6": "^0.0.33",
|
|
20
|
+
"@bananapus/buyback-hook-v6": "^0.0.27",
|
|
21
|
+
"@bananapus/core-v6": "^0.0.34",
|
|
22
22
|
"@bananapus/ownable-v6": "^0.0.17",
|
|
23
|
-
"@bananapus/permission-ids-v6": "^0.0.
|
|
24
|
-
"@bananapus/router-terminal-v6": "^0.0.
|
|
25
|
-
"@bananapus/suckers-v6": "^0.0.
|
|
23
|
+
"@bananapus/permission-ids-v6": "^0.0.17",
|
|
24
|
+
"@bananapus/router-terminal-v6": "^0.0.26",
|
|
25
|
+
"@bananapus/suckers-v6": "^0.0.25",
|
|
26
26
|
"@openzeppelin/contracts": "^5.6.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@bananapus/address-registry-v6": "^0.0.17",
|
|
30
|
-
"@rev-net/core-v6": "^0.0.
|
|
31
|
-
"@sphinx-labs/plugins": "^0.33.
|
|
30
|
+
"@rev-net/core-v6": "^0.0.30",
|
|
31
|
+
"@sphinx-labs/plugins": "^0.33.3"
|
|
32
32
|
}
|
|
33
|
-
}
|
|
33
|
+
}
|
package/src/CTDeployer.sol
CHANGED
|
@@ -28,6 +28,7 @@ import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.so
|
|
|
28
28
|
import {JBOwnable} from "@bananapus/ownable-v6/src/JBOwnable.sol";
|
|
29
29
|
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
30
30
|
import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
|
|
31
|
+
import {JBRelayBeneficiary} from "@bananapus/suckers-v6/src/libraries/JBRelayBeneficiary.sol";
|
|
31
32
|
|
|
32
33
|
import {ICTDeployer} from "./interfaces/ICTDeployer.sol";
|
|
33
34
|
import {ICTPublisher} from "./interfaces/ICTPublisher.sol";
|
|
@@ -172,6 +173,24 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
|
|
|
172
173
|
if (address(hook) == address(0)) {
|
|
173
174
|
return (context.weight, hookSpecifications);
|
|
174
175
|
}
|
|
176
|
+
|
|
177
|
+
// Resolve the relay beneficiary — if the payer is a sucker with relay metadata,
|
|
178
|
+
// swap the beneficiary so downstream hooks see the real user.
|
|
179
|
+
address effectiveBeneficiary = JBRelayBeneficiary.resolve({
|
|
180
|
+
payer: context.payer,
|
|
181
|
+
beneficiary: context.beneficiary,
|
|
182
|
+
projectId: context.projectId,
|
|
183
|
+
metadata: context.metadata,
|
|
184
|
+
registry: SUCKER_REGISTRY
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// If the beneficiary was swapped, create a memory copy with the new beneficiary.
|
|
188
|
+
if (effectiveBeneficiary != context.beneficiary) {
|
|
189
|
+
JBBeforePayRecordedContext memory hookContext = context;
|
|
190
|
+
hookContext.beneficiary = effectiveBeneficiary;
|
|
191
|
+
return hook.beforePayRecordedWith(hookContext);
|
|
192
|
+
}
|
|
193
|
+
|
|
175
194
|
// slither-disable-next-line unused-return
|
|
176
195
|
return hook.beforePayRecordedWith(context);
|
|
177
196
|
}
|
|
@@ -407,7 +426,7 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
|
|
|
407
426
|
CTDeployerAllowedPost memory post;
|
|
408
427
|
|
|
409
428
|
// Iterate through each post to add it to the formatted list.
|
|
410
|
-
for (uint256 i; i < numberOfAllowedPosts;
|
|
429
|
+
for (uint256 i; i < numberOfAllowedPosts;) {
|
|
411
430
|
// Set the post being iterated on.
|
|
412
431
|
post = allowedPosts[i];
|
|
413
432
|
|
|
@@ -421,6 +440,10 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
|
|
|
421
440
|
maximumSplitPercent: post.maximumSplitPercent,
|
|
422
441
|
allowedAddresses: post.allowedAddresses
|
|
423
442
|
});
|
|
443
|
+
|
|
444
|
+
unchecked {
|
|
445
|
+
++i;
|
|
446
|
+
}
|
|
424
447
|
}
|
|
425
448
|
|
|
426
449
|
// Set up the allowed posts in the publisher.
|
package/src/CTPublisher.sol
CHANGED
|
@@ -134,7 +134,7 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
134
134
|
tiers = new JB721Tier[](numberOfEncodedIPFSUris);
|
|
135
135
|
|
|
136
136
|
// Get the tier for each provided encoded IPFS URI.
|
|
137
|
-
for (uint256 i; i < numberOfEncodedIPFSUris;
|
|
137
|
+
for (uint256 i; i < numberOfEncodedIPFSUris;) {
|
|
138
138
|
// Check if there's a tier ID stored for the encoded IPFS URI.
|
|
139
139
|
uint256 tierId = tierIdForEncodedIPFSUriOf[hook][encodedIPFSUris[i]];
|
|
140
140
|
|
|
@@ -143,6 +143,10 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
143
143
|
// slither-disable-next-line calls-loop
|
|
144
144
|
tiers[i] = IJB721TiersHook(hook).STORE().tierOf({hook: hook, id: tierId, includeResolvedUri: false});
|
|
145
145
|
}
|
|
146
|
+
|
|
147
|
+
unchecked {
|
|
148
|
+
++i;
|
|
149
|
+
}
|
|
146
150
|
}
|
|
147
151
|
}
|
|
148
152
|
|
|
@@ -214,8 +218,11 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
214
218
|
uint256 numberOfAddresses = addresses.length;
|
|
215
219
|
|
|
216
220
|
// Check if the address is included
|
|
217
|
-
for (uint256 i; i < numberOfAddresses;
|
|
221
|
+
for (uint256 i; i < numberOfAddresses;) {
|
|
218
222
|
if (addrs == addresses[i]) return true;
|
|
223
|
+
unchecked {
|
|
224
|
+
++i;
|
|
225
|
+
}
|
|
219
226
|
}
|
|
220
227
|
|
|
221
228
|
return false;
|
|
@@ -247,7 +254,7 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
247
254
|
uint256 numberOfAllowedPosts = allowedPosts.length;
|
|
248
255
|
|
|
249
256
|
// For each post criteria, save the specifications.
|
|
250
|
-
for (uint256 i; i < numberOfAllowedPosts;
|
|
257
|
+
for (uint256 i; i < numberOfAllowedPosts;) {
|
|
251
258
|
// Set the post criteria being iterated on.
|
|
252
259
|
CTAllowedPost memory allowedPost = allowedPosts[i];
|
|
253
260
|
|
|
@@ -285,16 +292,16 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
285
292
|
// Store the packed value.
|
|
286
293
|
_packedAllowanceFor[allowedPost.hook][allowedPost.category] = packed;
|
|
287
294
|
|
|
288
|
-
// Store the allow list.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
295
|
+
// Store the allow list. Direct assignment replaces the entire storage array in one operation,
|
|
296
|
+
// avoiding the gas overhead of delete + individual push() calls in a loop.
|
|
297
|
+
if (allowedPost.allowedAddresses.length != 0) {
|
|
298
|
+
_allowedAddresses[allowedPost.hook][allowedPost.category] = allowedPost.allowedAddresses;
|
|
299
|
+
} else {
|
|
300
|
+
delete _allowedAddresses[allowedPost.hook][allowedPost.category];
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
unchecked {
|
|
304
|
+
++i;
|
|
298
305
|
}
|
|
299
306
|
}
|
|
300
307
|
}
|
|
@@ -473,7 +480,7 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
473
480
|
|
|
474
481
|
// For each post, create tiers after validating to make sure they fulfill the allowance specified by the
|
|
475
482
|
// project's owner.
|
|
476
|
-
for (uint256 i; i < posts.length;
|
|
483
|
+
for (uint256 i; i < posts.length;) {
|
|
477
484
|
// Get the current post being iterated on.
|
|
478
485
|
CTPost memory post = posts[i];
|
|
479
486
|
|
|
@@ -484,10 +491,13 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
484
491
|
}
|
|
485
492
|
|
|
486
493
|
// Check for duplicate encodedIPFSUri within the same batch to prevent fee evasion.
|
|
487
|
-
for (uint256 j; j < i;
|
|
494
|
+
for (uint256 j; j < i;) {
|
|
488
495
|
if (posts[j].encodedIPFSUri == post.encodedIPFSUri) {
|
|
489
496
|
revert CTPublisher_DuplicatePost(post.encodedIPFSUri);
|
|
490
497
|
}
|
|
498
|
+
unchecked {
|
|
499
|
+
++j;
|
|
500
|
+
}
|
|
491
501
|
}
|
|
492
502
|
|
|
493
503
|
// Scoped section to prevent stack too deep.
|
|
@@ -499,7 +509,7 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
499
509
|
// If the tier was removed externally (via adjustTiers), clear the stale mapping
|
|
500
510
|
// so the code falls through to create a new tier.
|
|
501
511
|
// slither-disable-next-line calls-loop
|
|
502
|
-
if (
|
|
512
|
+
if (store.isTierRemoved(address(hook), tierId)) {
|
|
503
513
|
delete tierIdForEncodedIPFSUriOf[address(hook)][post.encodedIPFSUri];
|
|
504
514
|
} else {
|
|
505
515
|
tierIdsToMint[i] = tierId;
|
|
@@ -590,6 +600,10 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
|
|
|
590
600
|
// For new tiers, use the post's price for totalPrice accumulation.
|
|
591
601
|
totalPrice += post.price;
|
|
592
602
|
}
|
|
603
|
+
|
|
604
|
+
unchecked {
|
|
605
|
+
++i;
|
|
606
|
+
}
|
|
593
607
|
}
|
|
594
608
|
|
|
595
609
|
// Resize the array if there's a mismatch in length.
|