@bananapus/721-hook-v6 0.0.34 → 0.0.36
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 +62 -164
- package/ARCHITECTURE.md +59 -44
- package/AUDIT_INSTRUCTIONS.md +35 -32
- package/README.md +22 -3
- package/RISKS.md +7 -1
- package/SKILLS.md +8 -2
- package/USER_JOURNEYS.md +144 -49
- package/foundry.toml +2 -0
- package/package.json +1 -1
- package/references/operations.md +7 -3
- package/references/runtime.md +5 -4
- package/src/JB721TiersHook.sol +6 -6
- package/src/JB721TiersHookProjectDeployer.sol +0 -1
- package/src/JB721TiersHookStore.sol +1 -2
- package/src/abstract/JB721Hook.sol +0 -1
- package/src/interfaces/IJB721TiersHook.sol +0 -2
- package/src/interfaces/IJB721TiersHookStore.sol +1 -1
- package/src/libraries/JB721Constants.sol +0 -1
- package/src/structs/JB721InitTiersConfig.sol +0 -1
- package/src/structs/JB721Tier.sol +0 -2
- package/src/structs/JB721TierConfig.sol +0 -2
- package/src/structs/JB721TierConfigFlags.sol +0 -1
- package/src/structs/JB721TierFlags.sol +0 -1
- package/src/structs/JB721TiersHookFlags.sol +0 -1
- package/src/structs/JB721TiersMintReservesConfig.sol +0 -1
- package/src/structs/JB721TiersRulesetMetadata.sol +0 -1
- package/src/structs/JB721TiersSetDiscountPercentConfig.sol +0 -1
- package/src/structs/JBBitmapWord.sol +0 -1
- package/src/structs/JBDeploy721TiersHookConfig.sol +0 -1
- package/src/structs/JBLaunchProjectConfig.sol +0 -1
- package/src/structs/JBLaunchRulesetsConfig.sol +0 -1
- package/src/structs/JBPayDataHookRulesetConfig.sol +0 -1
- package/src/structs/JBPayDataHookRulesetMetadata.sol +0 -1
- package/src/structs/JBQueueRulesetsConfig.sol +0 -1
- package/src/structs/JBStored721Tier.sol +0 -1
- package/test/TestCheckpoints.t.sol +16 -4
package/SKILLS.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Use This File For
|
|
4
4
|
|
|
5
5
|
- Use this file when the task involves tiered NFT issuance, reserve minting, voting units, tier splits, or token URI resolver integration for Juicebox projects.
|
|
6
|
-
- Start here, then
|
|
6
|
+
- Start here, then decide whether the bug is in hook runtime logic, store accounting, deployer initialization, or downstream token-URI resolution. This repo spans all four and they are easy to conflate.
|
|
7
7
|
|
|
8
8
|
## Read This Next
|
|
9
9
|
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
| Tier storage and accounting | [`src/JB721TiersHookStore.sol`](./src/JB721TiersHookStore.sol) |
|
|
15
15
|
| Deployment or project launch helpers | [`src/JB721TiersHookDeployer.sol`](./src/JB721TiersHookDeployer.sol), [`src/JB721TiersHookProjectDeployer.sol`](./src/JB721TiersHookProjectDeployer.sol), [`script/Deploy.s.sol`](./script/Deploy.s.sol) |
|
|
16
16
|
| Shared libraries, interfaces, and resolver surface | [`src/libraries/`](./src/libraries/), [`src/interfaces/`](./src/interfaces/), [`src/structs/`](./src/structs/) |
|
|
17
|
-
|
|
|
17
|
+
| Mint, pricing, voting, and checkpoint behavior | [`test/TestVotingUnitsLifecycle.t.sol`](./test/TestVotingUnitsLifecycle.t.sol), [`test/TestCheckpoints.t.sol`](./test/TestCheckpoints.t.sol) |
|
|
18
|
+
| Reentrancy, forks, and pinned edge cases | [`test/TestSafeTransferReentrancy.t.sol`](./test/TestSafeTransferReentrancy.t.sol), [`test/721HookAttacks.t.sol`](./test/721HookAttacks.t.sol), [`test/Fork.t.sol`](./test/Fork.t.sol), [`test/TestAuditGaps.sol`](./test/TestAuditGaps.sol) |
|
|
18
19
|
|
|
19
20
|
## Repo Map
|
|
20
21
|
|
|
@@ -37,6 +38,11 @@ Tiered ERC-721 NFT issuance and cash-out hook for Juicebox V6. This repo control
|
|
|
37
38
|
## Working Rules
|
|
38
39
|
|
|
39
40
|
- Start in [`src/JB721TiersHook.sol`](./src/JB721TiersHook.sol) for pay and cash-out behavior, but verify storage-side assumptions in [`src/JB721TiersHookStore.sol`](./src/JB721TiersHookStore.sol) before changing mint, burn, reserve, or supply logic.
|
|
41
|
+
- The store is the source of truth for supply, reserve, removal, and tier-order invariants. Do not “fix” those concepts only in the hook layer.
|
|
42
|
+
- Pending reserves are part of live economics, not deferred bookkeeping. Cash-out denominators and tier availability both depend on them before reserves are minted.
|
|
43
|
+
- Pay credits, overspending protection, and tier split forwarding are economically relevant. Treat them like accounting, not just UX.
|
|
40
44
|
- Treat tier splits, reserve minting, and discounted pricing as treasury-sensitive. Check both runtime code and regression coverage before assuming a change is local.
|
|
45
|
+
- Discounted mint price and cash-out weight are intentionally not the same thing. Free or discounted mints can still carry full tier cash-out weight by design.
|
|
46
|
+
- Changing the default reserve beneficiary is not cosmetic. It can change which tiers have pending reserves and therefore change redemption economics for existing mints.
|
|
41
47
|
- When a task mentions token metadata or rendering, confirm whether the behavior lives in this repo or in an external resolver. Do not over-edit the hook when the real change belongs downstream.
|
|
42
48
|
- When changing deployers or initialization, verify the hook, store, and project-launch path stay aligned. These flows are tightly coupled.
|
package/USER_JOURNEYS.md
CHANGED
|
@@ -1,96 +1,191 @@
|
|
|
1
1
|
# User Journeys
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Repo Purpose
|
|
4
|
+
|
|
5
|
+
This repo is the standard tiered NFT hook for V6 projects.
|
|
6
|
+
It owns tier issuance, reserve accounting, hook-aware mint and cash-out behavior, and deployer packaging for hook
|
|
7
|
+
clones or hook-shaped project launches. It does not own collection-specific rendering or app-layer policy built on top
|
|
8
|
+
of the hook.
|
|
9
|
+
|
|
10
|
+
## Primary Actors
|
|
4
11
|
|
|
5
12
|
- project owners selling or rewarding supporters with tiered NFTs
|
|
6
13
|
- operators managing tier supply, pricing, reserves, and ruleset-aware hook behavior
|
|
7
14
|
- supporters minting or cashing out tier positions through normal Juicebox flows
|
|
8
|
-
- integrators composing custom token URI resolvers on top of the
|
|
15
|
+
- integrators composing custom token URI resolvers or downstream products on top of the hook
|
|
16
|
+
|
|
17
|
+
## Key Surfaces
|
|
18
|
+
|
|
19
|
+
- `JB721TiersHook`: project-facing hook behavior for minting, reserves, metadata, and cash out
|
|
20
|
+
- `JB721TiersHookStore`: tier definitions and accounting backend
|
|
21
|
+
- `JB721TiersHookDeployer`: clone factory for existing projects
|
|
22
|
+
- `JB721TiersHookProjectDeployer`: project-launch packaging for new hook-backed projects
|
|
9
23
|
|
|
10
24
|
## Journey 1: Add A Tiered 721 Hook To An Existing Project
|
|
11
25
|
|
|
12
|
-
**
|
|
26
|
+
**Actor:** project owner or deployer.
|
|
27
|
+
|
|
28
|
+
**Intent:** attach tiered NFT behavior to an existing project without relaunching it.
|
|
29
|
+
|
|
30
|
+
**Preconditions**
|
|
31
|
+
- the project already exists in Juicebox
|
|
32
|
+
- the owner knows the tier config, reserve behavior, and resolver assumptions it wants
|
|
33
|
+
- the next ruleset metadata can be updated safely
|
|
34
|
+
|
|
35
|
+
**Main Flow**
|
|
36
|
+
1. Use `JB721TiersHookDeployer` to clone a hook for the project.
|
|
37
|
+
2. Define tier config, reserve behavior, resolver choice, and per-ruleset flags.
|
|
38
|
+
3. Queue or install ruleset metadata that points at the hook.
|
|
39
|
+
4. Future payments can now mint tiers under the configured constraints.
|
|
13
40
|
|
|
14
|
-
**
|
|
41
|
+
**Failure Modes**
|
|
42
|
+
- the hook is deployed correctly but the ruleset metadata does not actually activate it
|
|
43
|
+
- teams treat the resolver as cosmetic when it is part of the trusted surface
|
|
15
44
|
|
|
16
|
-
**
|
|
17
|
-
|
|
18
|
-
2. Define tier config, reserve behavior, token URI resolver, and per-ruleset flags.
|
|
19
|
-
3. Queue or install ruleset metadata that tells the project when the hook should participate in pay and cash-out flows.
|
|
20
|
-
4. Future payments into the project can now mint tiers under the configured constraints.
|
|
45
|
+
**Postconditions**
|
|
46
|
+
- the project has an attached hook and future rulesets can mint tiers under the configured constraints
|
|
21
47
|
|
|
22
48
|
## Journey 2: Launch A New Project With A 721 Hook Already Wired In
|
|
23
49
|
|
|
24
|
-
**
|
|
50
|
+
**Actor:** product team or deployer.
|
|
25
51
|
|
|
26
|
-
**
|
|
52
|
+
**Intent:** launch a project whose treasury and tiered NFT logic are aligned from the first ruleset.
|
|
27
53
|
|
|
28
|
-
**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
54
|
+
**Preconditions**
|
|
55
|
+
- the team has launch config, terminal config, and initial tier config ready
|
|
56
|
+
|
|
57
|
+
**Main Flow**
|
|
58
|
+
1. Use `JB721TiersHookProjectDeployer` with launch and hook config.
|
|
59
|
+
2. Launch the project and deploy the hook in the same packaged flow.
|
|
60
|
+
3. Ensure the first ruleset already points at the created hook.
|
|
61
|
+
4. Start life as a hook-backed project instead of converting later.
|
|
62
|
+
|
|
63
|
+
**Failure Modes**
|
|
64
|
+
- deployers assume the package is purely convenience and miss the initial ruleset implications
|
|
65
|
+
- launch-time metadata drifts from the actual hook config
|
|
66
|
+
|
|
67
|
+
**Postconditions**
|
|
68
|
+
- the project launches with tiered NFT logic active from the first ruleset
|
|
33
69
|
|
|
34
70
|
## Journey 3: Mint Specific Tiers Through A Payment
|
|
35
71
|
|
|
36
|
-
**
|
|
72
|
+
**Actor:** payer.
|
|
37
73
|
|
|
38
|
-
**
|
|
74
|
+
**Intent:** mint one or more tiers through a normal payment flow.
|
|
39
75
|
|
|
40
|
-
**
|
|
41
|
-
|
|
42
|
-
|
|
76
|
+
**Preconditions**
|
|
77
|
+
- the project has live tiers
|
|
78
|
+
- the payer submits metadata encoding the intended tier selections
|
|
79
|
+
|
|
80
|
+
**Main Flow**
|
|
81
|
+
1. Submit a payment with tier-selection metadata.
|
|
82
|
+
2. `JB721TiersHook` validates availability, quantity rules, discounts, and ruleset flags.
|
|
43
83
|
3. `JB721TiersHookStore` updates supply and reserve accounting.
|
|
44
|
-
4. The hook mints the
|
|
84
|
+
4. The hook mints the intended NFTs and the terminal completes treasury accounting.
|
|
85
|
+
|
|
86
|
+
**Failure Modes**
|
|
87
|
+
- sold-out tiers, malformed metadata, or cross-currency pricing mistakes
|
|
88
|
+
- pay-hook participation flags do not match the user's assumptions
|
|
89
|
+
- split-routing or hook behavior changes what part of the payment actually mints
|
|
45
90
|
|
|
46
|
-
**
|
|
91
|
+
**Postconditions**
|
|
92
|
+
- the intended tiers are minted and store accounting reflects the updated supply and reserve state
|
|
47
93
|
|
|
48
94
|
## Journey 4: Mint Reserves And Operate Tier Inventory Over Time
|
|
49
95
|
|
|
50
|
-
**
|
|
96
|
+
**Actor:** owner or authorized operator.
|
|
97
|
+
|
|
98
|
+
**Intent:** manage tier inventory and reserve behavior after launch.
|
|
51
99
|
|
|
52
|
-
**
|
|
100
|
+
**Preconditions**
|
|
101
|
+
- the collection is live
|
|
102
|
+
- the operator has the required permission surfaces to mutate tiers or mint reserves
|
|
53
103
|
|
|
54
|
-
**Flow**
|
|
55
|
-
1.
|
|
56
|
-
2.
|
|
57
|
-
3.
|
|
58
|
-
4.
|
|
104
|
+
**Main Flow**
|
|
105
|
+
1. Use tier-management surfaces to add, remove, or adjust tiers.
|
|
106
|
+
2. Mint reserves through the configured reserve logic.
|
|
107
|
+
3. Let the store preserve historical tier state so old token IDs still resolve correctly.
|
|
108
|
+
4. Keep downstream products assuming stable tier semantics whenever possible.
|
|
109
|
+
|
|
110
|
+
**Failure Modes**
|
|
111
|
+
- tier mutations surprise downstream products or resolvers
|
|
112
|
+
- reserve accounting is misread as ordinary minting
|
|
113
|
+
|
|
114
|
+
**Postconditions**
|
|
115
|
+
- live tier inventory and reserve state match the operator's configured collection policy
|
|
59
116
|
|
|
60
117
|
## Journey 5: Let Holders Cash Out Tier Positions
|
|
61
118
|
|
|
62
|
-
**
|
|
119
|
+
**Actor:** holder.
|
|
120
|
+
|
|
121
|
+
**Intent:** exit a tier position through the project's cash-out path.
|
|
63
122
|
|
|
64
|
-
**
|
|
123
|
+
**Preconditions**
|
|
124
|
+
- the holder owns one or more NFTs from the hook-enabled project
|
|
125
|
+
- the active ruleset allows a surplus-backed exit
|
|
65
126
|
|
|
66
|
-
**Flow**
|
|
67
|
-
1.
|
|
68
|
-
2.
|
|
69
|
-
3.
|
|
127
|
+
**Main Flow**
|
|
128
|
+
1. Call the project's cash-out path on the terminal.
|
|
129
|
+
2. Let the hook participate in cash-out calculation so tier state is reflected.
|
|
130
|
+
3. Burn or consume the tier exposure as required by the exit path.
|
|
131
|
+
4. Receive the reclaim value through the terminal that holds the asset.
|
|
70
132
|
|
|
71
|
-
**
|
|
133
|
+
**Failure Modes**
|
|
134
|
+
- the project uses the hook for metadata only and the holder assumes an economic cash-out path exists
|
|
135
|
+
- terminal behavior or reserve drift changes reclaim expectations
|
|
136
|
+
|
|
137
|
+
**Postconditions**
|
|
138
|
+
- the holder exits the tier position through the hook-aware terminal path or learns that no such economic path is active
|
|
72
139
|
|
|
73
140
|
## Journey 6: Compose A Custom Product On Top Of The Standard Hook
|
|
74
141
|
|
|
75
|
-
**
|
|
142
|
+
**Actor:** integrator or downstream product team.
|
|
143
|
+
|
|
144
|
+
**Intent:** build collection-specific behavior without reimplementing hook economics.
|
|
145
|
+
|
|
146
|
+
**Preconditions**
|
|
147
|
+
- the team wants custom presentation or app-layer logic
|
|
148
|
+
- the team does not want to fork pricing, reserve, and treasury behavior
|
|
76
149
|
|
|
77
|
-
**
|
|
150
|
+
**Main Flow**
|
|
151
|
+
1. Plug a custom resolver or wrapper into the hook.
|
|
152
|
+
2. Keep collection-specific behavior outside this repo.
|
|
153
|
+
3. Audit hook-store interactions here first, then audit the downstream wrapper.
|
|
78
154
|
|
|
79
|
-
**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
155
|
+
**Failure Modes**
|
|
156
|
+
- downstream products reimplement hook behavior and drift from canonical accounting
|
|
157
|
+
- teams blame the hook for bugs that actually live in the resolver or wrapper
|
|
158
|
+
|
|
159
|
+
**Postconditions**
|
|
160
|
+
- the custom product reuses canonical hook economics while isolating collection-specific behavior downstream
|
|
83
161
|
|
|
84
162
|
## Journey 7: Mint NFTs To The Correct Beneficiary During Cross-Chain Payments
|
|
85
163
|
|
|
86
|
-
**
|
|
164
|
+
**Actor:** cross-chain payer or integrator.
|
|
165
|
+
|
|
166
|
+
**Intent:** preserve the real remote beneficiary when a sucker relays a payment.
|
|
167
|
+
|
|
168
|
+
**Preconditions**
|
|
169
|
+
- a sucker or relay path pays on behalf of a remote user
|
|
170
|
+
- relay-beneficiary metadata is encoded correctly
|
|
171
|
+
|
|
172
|
+
**Main Flow**
|
|
173
|
+
1. The sucker calls `terminal.pay()` with relay-beneficiary metadata.
|
|
174
|
+
2. `_mintAndUpdateCredits` resolves the relay beneficiary when `payer == beneficiary`.
|
|
175
|
+
3. NFT minting and credit accounting use the resolved remote user.
|
|
176
|
+
|
|
177
|
+
**Failure Modes**
|
|
178
|
+
- relay metadata is missing or malformed
|
|
179
|
+
- downstream systems attribute NFTs or credits to the sucker instead of the user
|
|
180
|
+
|
|
181
|
+
**Postconditions**
|
|
182
|
+
- NFT minting and credit accounting attribute the remote payment to the correct beneficiary
|
|
87
183
|
|
|
88
|
-
|
|
184
|
+
## Trust Boundaries
|
|
89
185
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
3. All NFT minting and credit accounting uses the resolved relay beneficiary instead of the sucker address.
|
|
186
|
+
- `JB721TiersHookStore` is the accounting backend and should be treated as part of the same economic surface as the hook
|
|
187
|
+
- custom token URI resolvers are part of the trusted collection surface
|
|
188
|
+
- core terminals remain the source of treasury accounting truth around the hook
|
|
94
189
|
|
|
95
190
|
## Hand-Offs
|
|
96
191
|
|
package/foundry.toml
CHANGED
package/package.json
CHANGED
package/references/operations.md
CHANGED
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
## Change Checklist
|
|
10
10
|
|
|
11
11
|
- If you edit hook initialization, verify deployer config structs and project-launch helpers still encode the same assumptions.
|
|
12
|
-
- If you edit tier config or metadata behavior, inspect
|
|
12
|
+
- If you edit tier config or metadata behavior, inspect the corresponding structs and interfaces in `src/structs/` and `src/interfaces/`.
|
|
13
|
+
- If you edit reserve behavior, verify pending reserve counts, default reserve beneficiary semantics, and cash-out denominator effects together.
|
|
14
|
+
- If you edit discount behavior, verify mint price and cash-out weight separately. They are intentionally not the same quantity.
|
|
13
15
|
- If you touch permissions, verify the caller path and permission constants still line up with the downstream ecosystem package that defines them.
|
|
14
16
|
- If you touch URI behavior, confirm whether the issue belongs in this repo or in a downstream resolver contract that the hook calls.
|
|
15
17
|
|
|
@@ -24,5 +26,7 @@
|
|
|
24
26
|
|
|
25
27
|
- [`test/Fork.t.sol`](../test/Fork.t.sol) for live-integration assumptions.
|
|
26
28
|
- [`test/TestAuditGaps.sol`](../test/TestAuditGaps.sol) for known edge cases the repo authors considered worth pinning down.
|
|
27
|
-
- [`test/
|
|
28
|
-
- [`
|
|
29
|
+
- [`test/TestCheckpoints.t.sol`](../test/TestCheckpoints.t.sol) when you need a narrow function-level proof before editing a broad runtime path.
|
|
30
|
+
- [`test/invariants/TierLifecycleInvariant.t.sol`](../test/invariants/TierLifecycleInvariant.t.sol) and [`test/invariants/TieredHookStoreInvariant.t.sol`](../test/invariants/TieredHookStoreInvariant.t.sol) when a local patch may have broken store-level relationships.
|
|
31
|
+
- [`test/audit/CodexRetroactiveReserveBeneficiaryDilution.t.sol`](../test/audit/CodexRetroactiveReserveBeneficiaryDilution.t.sol) when reserve-beneficiary or pending-reserve behavior changes.
|
|
32
|
+
- [`script/Deploy.s.sol`](../script/Deploy.s.sol) when a deployment or launch question is really about config assembly rather than contract behavior.
|
package/references/runtime.md
CHANGED
|
@@ -22,11 +22,12 @@
|
|
|
22
22
|
- Discount behavior: price discounts affect mint eligibility but cash-out weight still tracks the original tier price. Do not conflate the two.
|
|
23
23
|
- Voting units: verify whether a tier uses explicit voting units or falls back to price-based voting power before changing governance-facing math.
|
|
24
24
|
- Tier removal and cleanup: removing tiers is not the same as cleaning the sorted tier list. Storage cleanup behavior matters.
|
|
25
|
+
- Default reserve beneficiary changes: they affect which tiers count pending reserves unless a tier-specific beneficiary overrides it. That is an economic change, not just an admin update.
|
|
25
26
|
|
|
26
27
|
## Tests To Trust First
|
|
27
28
|
|
|
28
|
-
- [`test/
|
|
29
|
-
- [`test/E2E/`](../test/E2E/) for launch and end-to-end payment flows.
|
|
30
|
-
- [`test/regression/`](../test/regression/) for previously broken edge cases.
|
|
29
|
+
- [`test/Fork.t.sol`](../test/Fork.t.sol) for launch and live integration flows.
|
|
31
30
|
- [`test/TestVotingUnitsLifecycle.t.sol`](../test/TestVotingUnitsLifecycle.t.sol) for voting-unit lifecycle behavior.
|
|
32
|
-
- [`test/
|
|
31
|
+
- [`test/TestCheckpoints.t.sol`](../test/TestCheckpoints.t.sol) for checkpoint/module behavior.
|
|
32
|
+
- [`test/invariants/TierLifecycleInvariant.t.sol`](../test/invariants/TierLifecycleInvariant.t.sol) and [`test/invariants/TieredHookStoreInvariant.t.sol`](../test/invariants/TieredHookStoreInvariant.t.sol) for store-level lifecycle invariants.
|
|
33
|
+
- [`test/TestSafeTransferReentrancy.t.sol`](../test/TestSafeTransferReentrancy.t.sol), [`test/721HookAttacks.t.sol`](../test/721HookAttacks.t.sol), [`test/audit/CodexRetroactiveReserveBeneficiaryDilution.t.sol`](../test/audit/CodexRetroactiveReserveBeneficiaryDilution.t.sol), and [`test/TestAuditGaps.sol`](../test/TestAuditGaps.sol) for reentrancy and attack-surface checks.
|
package/src/JB721TiersHook.sol
CHANGED
|
@@ -110,7 +110,7 @@ contract JB721TiersHook is JBOwnable, ERC2771Context, JB721Hook, IJB721TiersHook
|
|
|
110
110
|
uint256 internal _packedPricingContext;
|
|
111
111
|
|
|
112
112
|
/// @notice The checkpoint module that manages IVotes-compatible checkpointed voting power for this hook's NFTs.
|
|
113
|
-
/// @dev
|
|
113
|
+
/// @dev Lazily deployed on the first transfer. Pass this to JBTokenDistributor as the IVotes token.
|
|
114
114
|
IJB721Checkpoints public override CHECKPOINTS;
|
|
115
115
|
|
|
116
116
|
//*********************************************************************//
|
|
@@ -307,9 +307,6 @@ contract JB721TiersHook is JBOwnable, ERC2771Context, JB721Hook, IJB721TiersHook
|
|
|
307
307
|
|| flags.preventOverspending || flags.issueTokensForSplits
|
|
308
308
|
) STORE.recordFlags(flags);
|
|
309
309
|
|
|
310
|
-
// Deploy the checkpoint module for IVotes-compatible voting power.
|
|
311
|
-
CHECKPOINTS = CHECKPOINTS_DEPLOYER.deploy({hook: address(this), store: STORE});
|
|
312
|
-
|
|
313
310
|
// Transfer ownership to the initializer.
|
|
314
311
|
_transferOwnership(_msgSender());
|
|
315
312
|
}
|
|
@@ -460,9 +457,7 @@ contract JB721TiersHook is JBOwnable, ERC2771Context, JB721Hook, IJB721TiersHook
|
|
|
460
457
|
string calldata baseUri,
|
|
461
458
|
string calldata contractUri,
|
|
462
459
|
IJB721TokenUriResolver tokenUriResolver,
|
|
463
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
464
460
|
uint256 encodedIPFSUriTierId,
|
|
465
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
466
461
|
bytes32 encodedIPFSUri
|
|
467
462
|
)
|
|
468
463
|
external
|
|
@@ -794,6 +789,11 @@ contract JB721TiersHook is JBOwnable, ERC2771Context, JB721Hook, IJB721TiersHook
|
|
|
794
789
|
// slither-disable-next-line reentrency-events,calls-loop
|
|
795
790
|
STORE.recordTransferForTier({tierId: tierId, from: from, to: to});
|
|
796
791
|
|
|
792
|
+
// Deploy the checkpoint module lazily on the first transfer.
|
|
793
|
+
if (address(CHECKPOINTS) == address(0)) {
|
|
794
|
+
CHECKPOINTS = CHECKPOINTS_DEPLOYER.deploy({hook: address(this), store: STORE});
|
|
795
|
+
}
|
|
796
|
+
|
|
797
797
|
// Notify the checkpoint module to update checkpointed voting power.
|
|
798
798
|
CHECKPOINTS.onTransfer({from: from, to: to, tokenId: tokenId});
|
|
799
799
|
}
|
|
@@ -124,7 +124,6 @@ contract JB721TiersHookProjectDeployer is ERC2771Context, JBPermissioned, IJB721
|
|
|
124
124
|
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
125
125
|
{
|
|
126
126
|
// Get the project's projects contract.
|
|
127
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
128
127
|
IJBProjects PROJECTS = DIRECTORY.PROJECTS();
|
|
129
128
|
|
|
130
129
|
// Enforce permissions.
|
|
@@ -66,7 +66,6 @@ contract JB721TiersHookStore is IJB721TiersHookStore {
|
|
|
66
66
|
/// @custom:param hook The 721 contract that the tier belongs to.
|
|
67
67
|
/// @custom:param tierId The ID of the tier to get the encoded IPFS URI of.
|
|
68
68
|
/// @custom:returns The encoded IPFS URI.
|
|
69
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
70
69
|
mapping(address hook => mapping(uint256 tierId => bytes32)) public override encodedIPFSUriOf;
|
|
71
70
|
|
|
72
71
|
/// @notice Returns the largest tier ID currently used on the provided 721 contract.
|
|
@@ -1344,7 +1343,7 @@ contract JB721TiersHookStore is IJB721TiersHookStore {
|
|
|
1344
1343
|
/// @notice Record a new encoded IPFS URI for a tier.
|
|
1345
1344
|
/// @param tierId The ID of the tier to set the encoded IPFS URI of.
|
|
1346
1345
|
/// @param encodedIPFSUri The encoded IPFS URI to set for the tier.
|
|
1347
|
-
// forge-lint: disable-next-line(mixed-case-function
|
|
1346
|
+
// forge-lint: disable-next-line(mixed-case-function)
|
|
1348
1347
|
function recordSetEncodedIPFSUriOf(uint256 tierId, bytes32 encodedIPFSUri) external override {
|
|
1349
1348
|
encodedIPFSUriOf[msg.sender][tierId] = encodedIPFSUri;
|
|
1350
1349
|
}
|
|
@@ -49,7 +49,6 @@ abstract contract JB721Hook is ERC721, IJB721Hook {
|
|
|
49
49
|
//*********************************************************************//
|
|
50
50
|
|
|
51
51
|
/// @notice The ID of the project that this contract is associated with.
|
|
52
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
53
52
|
uint256 public override PROJECT_ID;
|
|
54
53
|
|
|
55
54
|
//*********************************************************************//
|
|
@@ -234,9 +234,7 @@ interface IJB721TiersHook is IJB721Hook {
|
|
|
234
234
|
string calldata baseUri,
|
|
235
235
|
string calldata contractUri,
|
|
236
236
|
IJB721TokenUriResolver tokenUriResolver,
|
|
237
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
238
237
|
uint256 encodedIPFSUriTierId,
|
|
239
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
240
238
|
bytes32 encodedIPFSUri
|
|
241
239
|
)
|
|
242
240
|
external;
|
|
@@ -247,7 +247,7 @@ interface IJB721TiersHookStore {
|
|
|
247
247
|
/// @notice Record a new encoded IPFS URI for a tier.
|
|
248
248
|
/// @param tierId The ID of the tier to set the encoded IPFS URI of.
|
|
249
249
|
/// @param encodedIPFSUri The encoded IPFS URI to set for the tier.
|
|
250
|
-
// forge-lint: disable-next-line(mixed-case-function
|
|
250
|
+
// forge-lint: disable-next-line(mixed-case-function)
|
|
251
251
|
function recordSetEncodedIPFSUriOf(uint256 tierId, bytes32 encodedIPFSUri) external;
|
|
252
252
|
|
|
253
253
|
/// @notice Record a newly set token URI resolver.
|
|
@@ -8,6 +8,5 @@ library JB721Constants {
|
|
|
8
8
|
/// @notice The metadata ID used to identify the 721 beneficiary entry in payment metadata.
|
|
9
9
|
/// @dev When a sucker pays on behalf of a remote user, the real user's address is embedded under this key
|
|
10
10
|
/// so NFTs mint to the correct recipient.
|
|
11
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
12
11
|
bytes4 public constant BENEFICIARY_METADATA_ID = bytes4(keccak256("JB_721_BENEFICIARY"));
|
|
13
12
|
}
|
|
@@ -8,7 +8,6 @@ import {JB721TierConfig} from "./JB721TierConfig.sol";
|
|
|
8
8
|
/// @custom:member tiers The tiers to initialize the hook with.
|
|
9
9
|
/// @custom:member currency The currency that the tier prices are denoted in. See `JBPrices`.
|
|
10
10
|
/// @custom:member decimals The number of decimals in the fixed point tier prices.
|
|
11
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
12
11
|
struct JB721InitTiersConfig {
|
|
13
12
|
JB721TierConfig[] tiers;
|
|
14
13
|
uint32 currency;
|
|
@@ -21,7 +21,6 @@ import {JB721TierFlags} from "./JB721TierFlags.sol";
|
|
|
21
21
|
/// an NFT from this tier is minted. Out of `JBConstants.SPLITS_TOTAL_PERCENT`.
|
|
22
22
|
/// @custom:member resolvedUri A resolved token URI for NFTs in this tier. Only available if the NFT this tier belongs
|
|
23
23
|
/// to has a resolver.
|
|
24
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
25
24
|
struct JB721Tier {
|
|
26
25
|
uint32 id;
|
|
27
26
|
uint104 price;
|
|
@@ -30,7 +29,6 @@ struct JB721Tier {
|
|
|
30
29
|
uint104 votingUnits;
|
|
31
30
|
uint16 reserveFrequency;
|
|
32
31
|
address reserveBeneficiary;
|
|
33
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
34
32
|
bytes32 encodedIPFSUri;
|
|
35
33
|
uint24 category;
|
|
36
34
|
uint8 discountPercent;
|
|
@@ -23,14 +23,12 @@ import {JB721TierConfigFlags} from "./JB721TierConfigFlags.sol";
|
|
|
23
23
|
/// an NFT from this tier is minted. Out of `JBConstants.SPLITS_TOTAL_PERCENT`.
|
|
24
24
|
/// @custom:member splits The splits to use for this tier's split group. These define where the split portion of the
|
|
25
25
|
/// tier's price gets routed when an NFT from this tier is minted.
|
|
26
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
27
26
|
struct JB721TierConfig {
|
|
28
27
|
uint104 price;
|
|
29
28
|
uint32 initialSupply;
|
|
30
29
|
uint32 votingUnits;
|
|
31
30
|
uint16 reserveFrequency;
|
|
32
31
|
address reserveBeneficiary;
|
|
33
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
34
32
|
bytes32 encodedIPFSUri;
|
|
35
33
|
uint24 category;
|
|
36
34
|
uint8 discountPercent;
|
|
@@ -14,7 +14,6 @@ pragma solidity ^0.8.0;
|
|
|
14
14
|
/// @custom:member cantIncreaseDiscountPercent If the tier cannot have its discount increased.
|
|
15
15
|
/// @custom:member cantBuyWithCredits If true, this tier cannot be purchased using accumulated pay credits. Only fresh
|
|
16
16
|
/// payment value counts toward this tier's price.
|
|
17
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
18
17
|
struct JB721TierConfigFlags {
|
|
19
18
|
bool allowOwnerMint;
|
|
20
19
|
bool useReserveBeneficiaryAsDefault;
|
|
@@ -7,7 +7,6 @@ pragma solidity ^0.8.0;
|
|
|
7
7
|
/// @custom:member cantBeRemoved A boolean indicating whether attempts to remove this tier will revert.
|
|
8
8
|
/// @custom:member cantIncreaseDiscountPercent If the tier cannot have its discount increased.
|
|
9
9
|
/// @custom:member cantBuyWithCredits If true, this tier cannot be purchased using accumulated pay credits.
|
|
10
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
11
10
|
struct JB721TierFlags {
|
|
12
11
|
bool allowOwnerMint;
|
|
13
12
|
bool transfersPausable;
|
|
@@ -11,7 +11,6 @@ pragma solidity ^0.8.0;
|
|
|
11
11
|
/// the NFTs being minted will revert.
|
|
12
12
|
/// @custom:member issueTokensForSplits A boolean indicating whether payers receive token credit for the portion of
|
|
13
13
|
/// their payment that is routed to tier splits. When false (default), weight is reduced proportionally.
|
|
14
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
15
14
|
struct JB721TiersHookFlags {
|
|
16
15
|
bool noNewTiersWithReserves;
|
|
17
16
|
bool noNewTiersWithVotes;
|
|
@@ -3,7 +3,6 @@ pragma solidity ^0.8.0;
|
|
|
3
3
|
|
|
4
4
|
/// @custom:member tierId The ID of the tier to mint from.
|
|
5
5
|
/// @custom:member count The number of NFTs to mint from that tier.
|
|
6
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
7
6
|
struct JB721TiersMintReservesConfig {
|
|
8
7
|
uint32 tierId;
|
|
9
8
|
uint16 count;
|
|
@@ -6,7 +6,6 @@ pragma solidity ^0.8.0;
|
|
|
6
6
|
/// @custom:member pauseTransfers A boolean indicating whether NFT transfers are paused during this ruleset.
|
|
7
7
|
/// @custom:member pauseMintPendingReserves A boolean indicating whether pending/outstanding NFT reserves can be minted
|
|
8
8
|
/// during this ruleset.
|
|
9
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
10
9
|
struct JB721TiersRulesetMetadata {
|
|
11
10
|
bool pauseTransfers;
|
|
12
11
|
bool pauseMintPendingReserves;
|
|
@@ -3,7 +3,6 @@ pragma solidity ^0.8.0;
|
|
|
3
3
|
|
|
4
4
|
/// @custom:member tierId The ID of the tier to set the discount percent for.
|
|
5
5
|
/// @custom:member discountPercent The discount percent to set for the tier.
|
|
6
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
7
6
|
struct JB721TiersSetDiscountPercentConfig {
|
|
8
7
|
uint32 tierId;
|
|
9
8
|
uint16 discountPercent;
|
|
@@ -5,7 +5,6 @@ pragma solidity ^0.8.0;
|
|
|
5
5
|
/// `JBBitmap` matrix is a "word".
|
|
6
6
|
/// @custom:member The information stored at the index.
|
|
7
7
|
/// @custom:member The index.
|
|
8
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
9
8
|
struct JBBitmapWord {
|
|
10
9
|
uint256 currentWord;
|
|
11
10
|
uint256 currentDepth;
|
|
@@ -12,7 +12,6 @@ import {IJB721TokenUriResolver} from "../interfaces/IJB721TokenUriResolver.sol";
|
|
|
12
12
|
/// @custom:member contractUri The URI where this contract's metadata can be found.
|
|
13
13
|
/// @custom:member tiersConfig The NFT tiers and pricing config to launch the hook with.
|
|
14
14
|
/// @custom:member flags A set of boolean options to configure the hook with.
|
|
15
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
16
15
|
struct JBDeploy721TiersHookConfig {
|
|
17
16
|
string name;
|
|
18
17
|
string symbol;
|
|
@@ -10,7 +10,6 @@ import {JBPayDataHookRulesetConfig} from "./JBPayDataHookRulesetConfig.sol";
|
|
|
10
10
|
/// @custom:member rulesetConfigurations The ruleset configurations to queue.
|
|
11
11
|
/// @custom:member terminalConfigurations The terminal configurations to add for the project.
|
|
12
12
|
/// @custom:member memo A memo to pass along to the emitted event.
|
|
13
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
14
13
|
struct JBLaunchProjectConfig {
|
|
15
14
|
string projectUri;
|
|
16
15
|
JBPayDataHookRulesetConfig[] rulesetConfigurations;
|
|
@@ -9,7 +9,6 @@ import {JBPayDataHookRulesetConfig} from "./JBPayDataHookRulesetConfig.sol";
|
|
|
9
9
|
/// @custom:member rulesetConfigurations The ruleset configurations to queue.
|
|
10
10
|
/// @custom:member terminalConfigurations The terminal configurations to add for the project.
|
|
11
11
|
/// @custom:member memo A memo to pass along to the emitted event.
|
|
12
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
13
12
|
struct JBLaunchRulesetsConfig {
|
|
14
13
|
uint56 projectId;
|
|
15
14
|
JBPayDataHookRulesetConfig[] rulesetConfigurations;
|
|
@@ -32,7 +32,6 @@ import {JBPayDataHookRulesetMetadata} from "./JBPayDataHookRulesetMetadata.sol";
|
|
|
32
32
|
/// its balance in each payment terminal while the ruleset is active. Amounts are fixed point numbers using the same
|
|
33
33
|
/// number of decimals as the corresponding terminal. The `payoutLimit` and `surplusAllowance` parameters must fit in
|
|
34
34
|
/// a `uint232`.
|
|
35
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
36
35
|
struct JBPayDataHookRulesetConfig {
|
|
37
36
|
uint48 mustStartAtOrAfter;
|
|
38
37
|
uint32 duration;
|
|
@@ -28,7 +28,6 @@ pragma solidity ^0.8.0;
|
|
|
28
28
|
/// during
|
|
29
29
|
/// this ruleset.
|
|
30
30
|
/// @custom:member metadata Metadata of the metadata, up to uint8 in size.
|
|
31
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
32
31
|
struct JBPayDataHookRulesetMetadata {
|
|
33
32
|
uint16 reservedPercent;
|
|
34
33
|
uint16 cashOutTaxRate;
|
|
@@ -6,7 +6,6 @@ import {JBPayDataHookRulesetConfig} from "./JBPayDataHookRulesetConfig.sol";
|
|
|
6
6
|
/// @custom:member projectId The ID of the project to queue rulesets for.
|
|
7
7
|
/// @custom:member rulesetConfigurations The ruleset configurations to queue.
|
|
8
8
|
/// @custom:member memo A memo to pass along to the emitted event.
|
|
9
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
10
9
|
struct JBQueueRulesetsConfig {
|
|
11
10
|
uint56 projectId;
|
|
12
11
|
JBPayDataHookRulesetConfig[] rulesetConfigurations;
|
|
@@ -13,7 +13,6 @@ pragma solidity ^0.8.0;
|
|
|
13
13
|
/// purchased.
|
|
14
14
|
/// @custom:member packedBools Packed boolean flags: allowOwnerMint, transfersPausable, useVotingUnits,
|
|
15
15
|
/// cantBeRemoved, cantIncreaseDiscountPercent, cantBuyWithCredits.
|
|
16
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
17
16
|
struct JBStored721Tier {
|
|
18
17
|
uint104 price;
|
|
19
18
|
uint32 remainingSupply;
|