@bananapus/721-hook-v6 0.0.70 → 0.0.72
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 +4 -4
- package/package.json +6 -6
- package/src/JB721Checkpoints.sol +168 -49
- package/src/JB721TiersHook.sol +3 -5
- package/src/JB721TiersHookProjectDeployer.sol +2 -4
- package/src/JB721TiersHookStore.sol +2 -4
- package/src/abstract/JB721Hook.sol +3 -6
- package/src/interfaces/IJB721Checkpoints.sol +29 -20
- package/src/interfaces/IJB721TiersHook.sol +3 -5
- package/src/libraries/JB721TiersHookLib.sol +1 -2
- package/src/structs/JB721TiersRulesetMetadata.sol +1 -2
- package/src/structs/JBLaunchProjectConfig.sol +1 -2
- package/src/structs/JBPayDataHookRulesetConfig.sol +7 -10
- package/src/structs/JBPayDataHookRulesetMetadata.sol +2 -4
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
- [AUDIT_INSTRUCTIONS.md](./AUDIT_INSTRUCTIONS.md) — what to focus on for a security audit and how to start.
|
|
11
11
|
- [SKILLS.md](./SKILLS.md) — implementation nuances, gotchas, and reading order for working on this codebase.
|
|
12
12
|
- [STYLE_GUIDE.md](./STYLE_GUIDE.md) — Solidity conventions and repo layout used across the V6 ecosystem.
|
|
13
|
-
- [CHANGELOG.md](./CHANGELOG.md)
|
|
13
|
+
- [CHANGELOG.md](./CHANGELOG.md) - V5 to V6 ABI and behavior deltas.
|
|
14
14
|
- [references/runtime.md](./references/runtime.md) — contract roles, the runtime pay and cash-out path, and high-risk areas.
|
|
15
15
|
- [references/operations.md](./references/operations.md) — deployment surface, change checklist, and common failure modes.
|
|
16
16
|
|
|
@@ -38,7 +38,7 @@ This repo does more than "mint NFTs on pay." It changes how payment value, tier
|
|
|
38
38
|
| `JB721TiersHookDeployer` | Clone factory for deploying a hook for an existing project. |
|
|
39
39
|
| `JB721TiersHookProjectDeployer` | Convenience deployer for launching a project with a hook already wired in. |
|
|
40
40
|
| `JB721Hook` | Abstract base for 721 pay and cash-out hook behavior. |
|
|
41
|
-
| `JB721Checkpoints` | Per-hook IVotes checkpoint module. Tracks historical owner checkpoints, per-tier
|
|
41
|
+
| `JB721Checkpoints` | Per-hook IVotes checkpoint module. Tracks historical owner checkpoints, per-tier owner-tracked voting units (`getPastTierVotingUnits`), global active vote totals (`getPastTotalActiveVotes`), and per-tier active vote totals (`getPastTierActiveVotes`). |
|
|
42
42
|
|
|
43
43
|
## Mental model
|
|
44
44
|
|
|
@@ -64,8 +64,8 @@ If a bug affects supply, reserve minting, or tier lookup, it usually lives in th
|
|
|
64
64
|
- custom token URI resolvers should be treated as part of the trusted surface
|
|
65
65
|
- adding a 721 hook through a deployer is easy; carrying the right ruleset behavior forward is where mistakes happen
|
|
66
66
|
- projects should be explicit about whether the hook affects pay, cash out, or only metadata-facing paths
|
|
67
|
-
- per-tier
|
|
68
|
-
- active delegated vote totals are queryable via `getPastTotalActiveVotes(blockNumber)`
|
|
67
|
+
- per-tier owner-tracked voting units are queryable via `getPastTierVotingUnits(tierId, blockNumber)`: mints, transfers, and burns write ownership history, so the trace follows owned units regardless of delegation
|
|
68
|
+
- active delegated vote totals are queryable globally via `getPastTotalActiveVotes(blockNumber)` / `getTotalActiveVotes()` and per tier via `getPastTierActiveVotes(tierId, blockNumber)` / `getTierActiveVotes(tierId)`. These totals include only voting units held by accounts with a nonzero delegate, so a token in undelegated custody does not count and returned tokens become active again if the holder's delegation is still set.
|
|
69
69
|
|
|
70
70
|
## Where state lives
|
|
71
71
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bananapus/721-hook-v6",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.72",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
"artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'nana-721-hook-v6'"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@bananapus/address-registry-v6": "^0.0.
|
|
29
|
-
"@bananapus/core-v6": "^0.0.
|
|
30
|
-
"@bananapus/ownable-v6": "^0.0.
|
|
31
|
-
"@bananapus/permission-ids-v6": "^0.0.
|
|
28
|
+
"@bananapus/address-registry-v6": "^0.0.34",
|
|
29
|
+
"@bananapus/core-v6": "^0.0.86",
|
|
30
|
+
"@bananapus/ownable-v6": "^0.0.37",
|
|
31
|
+
"@bananapus/permission-ids-v6": "^0.0.30",
|
|
32
32
|
"@openzeppelin/contracts": "5.6.1",
|
|
33
|
-
"@prb/math": "4.1.
|
|
33
|
+
"@prb/math": "4.1.2",
|
|
34
34
|
"solady": "0.1.26"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
package/src/JB721Checkpoints.sol
CHANGED
|
@@ -29,7 +29,7 @@ contract JB721Checkpoints is Votes, IJB721Checkpoints {
|
|
|
29
29
|
/// @notice Thrown when `initialize` is called on a module whose hook has already been set.
|
|
30
30
|
error JB721Checkpoints_AlreadyInitialized(address hook);
|
|
31
31
|
|
|
32
|
-
/// @notice Thrown when the caller tries to
|
|
32
|
+
/// @notice Thrown when the caller tries to backfill a token they do not currently own.
|
|
33
33
|
error JB721Checkpoints_NotOwner(uint256 tokenId, address caller);
|
|
34
34
|
|
|
35
35
|
/// @notice Thrown when a hook-only function is called by an address other than the module's hook.
|
|
@@ -40,6 +40,7 @@ contract JB721Checkpoints is Votes, IJB721Checkpoints {
|
|
|
40
40
|
//*********************************************************************//
|
|
41
41
|
|
|
42
42
|
/// @notice The store that holds tier and voting data for the hook's NFTs.
|
|
43
|
+
/// @dev All tier lookups are scoped by `hook`; this immutable only identifies the shared store contract.
|
|
43
44
|
IJB721TiersHookStore public immutable override STORE;
|
|
44
45
|
|
|
45
46
|
//*********************************************************************//
|
|
@@ -47,33 +48,43 @@ contract JB721Checkpoints is Votes, IJB721Checkpoints {
|
|
|
47
48
|
//*********************************************************************//
|
|
48
49
|
|
|
49
50
|
/// @notice The hook that this module tracks voting power for.
|
|
51
|
+
/// @dev Clones set this once in `initialize`; the implementation uses `address(1)` as a locked sentinel.
|
|
50
52
|
address public override hook;
|
|
51
53
|
|
|
52
54
|
//*********************************************************************//
|
|
53
55
|
// -------------------- internal stored properties ------------------- //
|
|
54
56
|
//*********************************************************************//
|
|
55
57
|
|
|
56
|
-
/// @notice Checkpointed token owners for historical reward eligibility.
|
|
58
|
+
/// @notice Checkpointed token owners for historical reward eligibility.
|
|
59
|
+
/// @dev Mint and transfer hooks write this automatically; `delegate` only backfills missing pre-upgrade history.
|
|
57
60
|
/// @custom:param tokenId The token ID to get historical owner checkpoints for.
|
|
58
61
|
mapping(uint256 tokenId => Checkpoints.Trace160) internal _ownerCheckpointsOf;
|
|
59
62
|
|
|
60
|
-
/// @notice Checkpointed total
|
|
61
|
-
///
|
|
62
|
-
///
|
|
63
|
-
/// @custom:param tierId The tier to get the historical
|
|
63
|
+
/// @notice Checkpointed total active voting units per tier.
|
|
64
|
+
/// @dev Maintained when delegation changes activate/deactivate all of an account's tier units, and when transfers
|
|
65
|
+
/// move one token's tier units between delegated and undelegated custody.
|
|
66
|
+
/// @custom:param tierId The tier to get the historical delegated voting units for.
|
|
67
|
+
mapping(uint256 tierId => Checkpoints.Trace160) internal _tierActiveSupplyCheckpointsOf;
|
|
68
|
+
|
|
69
|
+
/// @notice Checkpointed total owner-tracked voting units per tier.
|
|
70
|
+
/// @dev Increased on mint or backfill and decreased on burn. Transfers keep the total unchanged because the token
|
|
71
|
+
/// still has a nonzero owner.
|
|
72
|
+
/// @custom:param tierId The tier to get the historical owner-tracked voting units for.
|
|
64
73
|
mapping(uint256 tierId => Checkpoints.Trace160) internal _tierEligibleUnitsOf;
|
|
65
74
|
|
|
66
75
|
//*********************************************************************//
|
|
67
76
|
// -------------------- private stored properties -------------------- //
|
|
68
77
|
//*********************************************************************//
|
|
69
78
|
|
|
70
|
-
/// @notice
|
|
79
|
+
/// @notice Checkpointed total voting units held by accounts with nonzero delegates.
|
|
80
|
+
/// @dev Maintained by `_delegate` and `_transferVotingUnits` using the same clock as OZ `Votes`.
|
|
71
81
|
Checkpoints.Trace208 private _activeSupplyCheckpoints;
|
|
72
82
|
|
|
73
83
|
//*********************************************************************//
|
|
74
84
|
// -------------------------- constructor ---------------------------- //
|
|
75
85
|
//*********************************************************************//
|
|
76
86
|
|
|
87
|
+
/// @notice Initializes the checkpoint implementation and locks it against direct use.
|
|
77
88
|
/// @dev The implementation contract is initialized in the constructor to prevent direct use. Clones are initialized
|
|
78
89
|
/// via `initialize()`.
|
|
79
90
|
/// @param store The store that holds tier data for each hook's NFTs.
|
|
@@ -86,26 +97,25 @@ contract JB721Checkpoints is Votes, IJB721Checkpoints {
|
|
|
86
97
|
// ---------------------- external transactions ---------------------- //
|
|
87
98
|
//*********************************************************************//
|
|
88
99
|
|
|
89
|
-
/// @notice Delegates voting power and
|
|
90
|
-
/// @dev
|
|
91
|
-
///
|
|
92
|
-
/// distribution. The existing `delegate(address)` from OZ Votes still works for pure delegation without enrollment.
|
|
100
|
+
/// @notice Delegates voting power and backfills ownership history for listed tokens if needed.
|
|
101
|
+
/// @dev Mint and transfer hooks normally write owner checkpoints automatically. The token ID list keeps
|
|
102
|
+
/// pre-upgrade or otherwise uncheckpointed tokens recoverable while preserving the owner-only authorization check.
|
|
93
103
|
/// @param delegatee The address to delegate voting power to. Use your own address for self-delegation.
|
|
94
|
-
/// @param tokenIds The token IDs
|
|
104
|
+
/// @param tokenIds The token IDs whose owner checkpoints should be backfilled if missing.
|
|
95
105
|
function delegate(address delegatee, uint256[] calldata tokenIds) external override {
|
|
96
106
|
// Delegate voting power (reuses OZ Votes internals).
|
|
97
107
|
_delegate({account: msg.sender, delegatee: delegatee});
|
|
98
108
|
|
|
99
|
-
// Write per-token owner checkpoints for
|
|
109
|
+
// Write any missing per-token owner checkpoints for historical reward eligibility.
|
|
100
110
|
for (uint256 i; i < tokenIds.length;) {
|
|
101
111
|
uint256 tokenId = tokenIds[i];
|
|
102
112
|
|
|
103
|
-
// Only the current owner can
|
|
113
|
+
// Only the current owner can backfill their token's ownership checkpoint.
|
|
104
114
|
if (IERC721(hook).ownerOf(tokenId) != msg.sender) {
|
|
105
115
|
revert JB721Checkpoints_NotOwner({tokenId: tokenId, caller: msg.sender});
|
|
106
116
|
}
|
|
107
117
|
|
|
108
|
-
// Write an owner checkpoint if the token has none yet, and
|
|
118
|
+
// Write an owner checkpoint if the token has none yet, and track its tier voting units.
|
|
109
119
|
if (_ownerCheckpointsOf[tokenId].length() == 0) {
|
|
110
120
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
111
121
|
_ownerCheckpointsOf[tokenId].push({key: uint96(block.number), value: uint160(msg.sender)});
|
|
@@ -139,54 +149,105 @@ contract JB721Checkpoints is Votes, IJB721Checkpoints {
|
|
|
139
149
|
function onTransfer(address from, address to, uint256 tokenId) external override {
|
|
140
150
|
if (msg.sender != hook) revert JB721Checkpoints_Unauthorized({caller: msg.sender, hook: hook});
|
|
141
151
|
|
|
152
|
+
// Look up this token's tier ID and voting units once; both the owner and active traces need them.
|
|
153
|
+
uint256 tierId = STORE.tierIdOfToken(tokenId);
|
|
154
|
+
|
|
142
155
|
// Look up this token's tier voting units (lightweight getter — avoids full tier struct construction).
|
|
143
156
|
uint256 votingUnits = STORE.tierVotingUnitsOfTokenId({hook: hook, tokenId: tokenId});
|
|
144
157
|
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
158
|
+
// Keep a reference to the token's historical owner trace.
|
|
159
|
+
Checkpoints.Trace160 storage ownerTrace = _ownerCheckpointsOf[tokenId];
|
|
160
|
+
|
|
161
|
+
// Existing deployments may have tokens that predate mint checkpointing; detect the first written owner.
|
|
162
|
+
bool wasEligible = ownerTrace.length() != 0;
|
|
150
163
|
|
|
164
|
+
// Mints, transfers, and burns all write ownership history so reward claims can prove snapshot ownership.
|
|
165
|
+
if (to != address(0) || from != address(0)) {
|
|
151
166
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
152
167
|
ownerTrace.push({key: uint96(block.number), value: uint160(to)});
|
|
168
|
+
}
|
|
153
169
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
} else if (!wasEligible) {
|
|
162
|
-
// First transfer of a never-enrolled token makes it eligible: add the tier's units.
|
|
163
|
-
_updateTierEligibleUnits({tierId: STORE.tierIdOfToken(tokenId), amount: votingUnits, increase: true});
|
|
170
|
+
if (from == address(0) && to != address(0)) {
|
|
171
|
+
// Mint: add the token's tier units to the owner-tracked tier supply.
|
|
172
|
+
_updateTierEligibleUnits({tierId: tierId, amount: votingUnits, increase: true});
|
|
173
|
+
} else if (to == address(0)) {
|
|
174
|
+
// Burn: remove the tier's units only if the token was already part of the owner-tracked supply.
|
|
175
|
+
if (wasEligible) {
|
|
176
|
+
_updateTierEligibleUnits({tierId: tierId, amount: votingUnits, increase: false});
|
|
164
177
|
}
|
|
178
|
+
} else if (!wasEligible) {
|
|
179
|
+
// First transfer of a pre-upgrade uncheckpointed token makes its ownership history trackable.
|
|
180
|
+
_updateTierEligibleUnits({tierId: tierId, amount: votingUnits, increase: true});
|
|
165
181
|
}
|
|
166
182
|
|
|
183
|
+
// The tier active total decreases if units leave an account that already has a nonzero delegate.
|
|
184
|
+
bool decreaseTierActiveVotes = from != address(0) && delegates(from) != address(0);
|
|
185
|
+
|
|
186
|
+
// The tier active total increases if units arrive at an account that already has a nonzero delegate.
|
|
187
|
+
bool increaseTierActiveVotes = to != address(0) && delegates(to) != address(0);
|
|
188
|
+
|
|
167
189
|
// Move checkpointed voting power from the previous owner to the new owner.
|
|
168
190
|
_transferVotingUnits({from: from, to: to, amount: votingUnits});
|
|
191
|
+
|
|
192
|
+
// If both sides are delegated or both sides are undelegated, this tier's active total is unchanged.
|
|
193
|
+
if (decreaseTierActiveVotes != increaseTierActiveVotes) {
|
|
194
|
+
// Otherwise apply the one-sided active-tier delta implied by the receiver's delegated status.
|
|
195
|
+
_adjustTierActiveVotes({tierId: tierId, amount: votingUnits, increase: increaseTierActiveVotes});
|
|
196
|
+
}
|
|
169
197
|
}
|
|
170
198
|
|
|
171
199
|
//*********************************************************************//
|
|
172
200
|
// ----------------------- external views ---------------------------- //
|
|
173
201
|
//*********************************************************************//
|
|
174
202
|
|
|
175
|
-
/// @notice The total
|
|
176
|
-
/// @
|
|
203
|
+
/// @notice The total delegated voting units of a tier at a past block.
|
|
204
|
+
/// @dev Counts only tier voting units held by accounts with a nonzero delegate.
|
|
205
|
+
/// @param tierId The tier to get the delegated voting units of.
|
|
206
|
+
/// @param blockNumber The past block number to look up.
|
|
207
|
+
/// @return activeVotes The tier's delegated voting units at `blockNumber`.
|
|
208
|
+
function getPastTierActiveVotes(
|
|
209
|
+
uint256 tierId,
|
|
210
|
+
uint256 blockNumber
|
|
211
|
+
)
|
|
212
|
+
external
|
|
213
|
+
view
|
|
214
|
+
override
|
|
215
|
+
returns (uint256 activeVotes)
|
|
216
|
+
{
|
|
217
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
218
|
+
activeVotes = _tierActiveSupplyCheckpointsOf[tierId].upperLookupRecent(uint96(_validateTimepoint(blockNumber)));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/// @notice The total owner-checkpointed voting units of a tier at a past block.
|
|
222
|
+
/// @param tierId The tier to get the owner-checkpointed voting units of.
|
|
177
223
|
/// @param blockNumber The block number to look up (must be strictly in the past).
|
|
178
|
-
/// @return The tier's
|
|
179
|
-
function getPastTierVotingUnits(
|
|
224
|
+
/// @return votingUnits The tier's owner-checkpointed voting units at `blockNumber`.
|
|
225
|
+
function getPastTierVotingUnits(
|
|
226
|
+
uint256 tierId,
|
|
227
|
+
uint256 blockNumber
|
|
228
|
+
)
|
|
229
|
+
external
|
|
230
|
+
view
|
|
231
|
+
override
|
|
232
|
+
returns (uint256 votingUnits)
|
|
233
|
+
{
|
|
180
234
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
181
|
-
|
|
235
|
+
votingUnits = _tierEligibleUnitsOf[tierId].upperLookupRecent(uint96(_validateTimepoint(blockNumber)));
|
|
182
236
|
}
|
|
183
237
|
|
|
184
238
|
/// @notice The total delegated voting units at a past block.
|
|
185
239
|
/// @dev This tracks delegated vote participation and is separate from tier reward eligibility.
|
|
186
|
-
/// @param
|
|
187
|
-
/// @return activeVotes The total voting units delegated to nonzero delegates at `
|
|
188
|
-
function getPastTotalActiveVotes(uint256
|
|
189
|
-
activeVotes = _activeSupplyCheckpoints.upperLookupRecent(_validateTimepoint(
|
|
240
|
+
/// @param blockNumber The past block number to look up.
|
|
241
|
+
/// @return activeVotes The total voting units delegated to nonzero delegates at `blockNumber`.
|
|
242
|
+
function getPastTotalActiveVotes(uint256 blockNumber) external view override returns (uint256 activeVotes) {
|
|
243
|
+
activeVotes = _activeSupplyCheckpoints.upperLookupRecent(_validateTimepoint(blockNumber));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/// @notice The current total delegated voting units of a tier.
|
|
247
|
+
/// @param tierId The tier to get the current delegated voting units of.
|
|
248
|
+
/// @return activeVotes The tier's current delegated voting units.
|
|
249
|
+
function getTierActiveVotes(uint256 tierId) external view override returns (uint256 activeVotes) {
|
|
250
|
+
activeVotes = _tierActiveSupplyCheckpointsOf[tierId].latest();
|
|
190
251
|
}
|
|
191
252
|
|
|
192
253
|
/// @notice The current total delegated voting units.
|
|
@@ -197,22 +258,21 @@ contract JB721Checkpoints is Votes, IJB721Checkpoints {
|
|
|
197
258
|
}
|
|
198
259
|
|
|
199
260
|
/// @notice The owner of an NFT at a past block.
|
|
200
|
-
/// @dev Returns `address(0)`
|
|
201
|
-
/// transferred. Unenrolled tokens are ineligible for snapshot-based distribution.
|
|
261
|
+
/// @dev Returns `address(0)` if no ownership checkpoint exists or the query predates the first checkpoint.
|
|
202
262
|
/// @param tokenId The token ID of the NFT to get the historical owner of.
|
|
203
263
|
/// @param blockNumber The block number to look up.
|
|
204
|
-
/// @return The owner of the token at `blockNumber`, or zero if
|
|
205
|
-
function ownerOfAt(uint256 tokenId, uint256 blockNumber) external view override returns (address) {
|
|
264
|
+
/// @return owner The owner of the token at `blockNumber`, or zero if no owner is proven at that block.
|
|
265
|
+
function ownerOfAt(uint256 tokenId, uint256 blockNumber) external view override returns (address owner) {
|
|
206
266
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
207
267
|
uint96 blockNumber96 = uint96(blockNumber);
|
|
208
268
|
|
|
209
269
|
Checkpoints.Trace160 storage checkpoints = _ownerCheckpointsOf[tokenId];
|
|
210
270
|
uint256 checkpointCount = checkpoints.length();
|
|
211
271
|
|
|
212
|
-
// No checkpoints
|
|
272
|
+
// No checkpoints means no historical owner can be proven for this token.
|
|
213
273
|
if (checkpointCount == 0) return address(0);
|
|
214
274
|
|
|
215
|
-
// Query is before the first checkpoint
|
|
275
|
+
// Query is before the first checkpoint, so this token had no proven owner at that block.
|
|
216
276
|
if (checkpoints.at(0)._key > blockNumber96) return address(0);
|
|
217
277
|
|
|
218
278
|
return address(uint160(checkpoints.upperLookupRecent(blockNumber96)));
|
|
@@ -242,9 +302,15 @@ contract JB721Checkpoints is Votes, IJB721Checkpoints {
|
|
|
242
302
|
if (oldDelegate == address(0) && delegatee != address(0)) {
|
|
243
303
|
// Add the account's voting units to the checkpointed active total.
|
|
244
304
|
_updateActiveVotes({amount: votingUnits, increase: true});
|
|
305
|
+
|
|
306
|
+
// Add the account's voting units to each tier-level active total it currently contributes to.
|
|
307
|
+
_applyAccountDelegationToTierActiveVotes({account: account, increase: true});
|
|
245
308
|
} else if (oldDelegate != address(0) && delegatee == address(0)) {
|
|
246
309
|
// If the account had a delegate and now has none, its voting units just became inactive.
|
|
247
310
|
_updateActiveVotes({amount: votingUnits, increase: false});
|
|
311
|
+
|
|
312
|
+
// Remove the account's voting units from each tier-level active total it currently contributes to.
|
|
313
|
+
_applyAccountDelegationToTierActiveVotes({account: account, increase: false});
|
|
248
314
|
}
|
|
249
315
|
}
|
|
250
316
|
|
|
@@ -279,8 +345,8 @@ contract JB721Checkpoints is Votes, IJB721Checkpoints {
|
|
|
279
345
|
/// @notice Returns the total voting units held by an account (across all tiers).
|
|
280
346
|
/// @dev Called by OZ Votes when re-delegating to compute the account's total voting units.
|
|
281
347
|
/// @param account The address to get the voting units of.
|
|
282
|
-
/// @return The total voting units the account holds.
|
|
283
|
-
function _getVotingUnits(address account) internal view override returns (uint256) {
|
|
348
|
+
/// @return votingUnits The total voting units the account holds.
|
|
349
|
+
function _getVotingUnits(address account) internal view override returns (uint256 votingUnits) {
|
|
284
350
|
return STORE.votingUnitsOf({hook: hook, account: account});
|
|
285
351
|
}
|
|
286
352
|
|
|
@@ -288,6 +354,51 @@ contract JB721Checkpoints is Votes, IJB721Checkpoints {
|
|
|
288
354
|
// ------------------------ private helpers -------------------------- //
|
|
289
355
|
//*********************************************************************//
|
|
290
356
|
|
|
357
|
+
/// @notice Add or remove units from a tier's active-voting-units checkpoint at the current block.
|
|
358
|
+
/// @param tierId The tier whose active-voting-units trace to update.
|
|
359
|
+
/// @param amount The voting units to add or remove.
|
|
360
|
+
/// @param increase Whether to add `amount`; if false, `amount` is removed.
|
|
361
|
+
function _adjustTierActiveVotes(uint256 tierId, uint256 amount, bool increase) private {
|
|
362
|
+
// Ignore zero-unit updates because they do not change this tier's active total.
|
|
363
|
+
if (amount == 0) return;
|
|
364
|
+
|
|
365
|
+
// Keep a reference to the tier's active-voting-units trace.
|
|
366
|
+
Checkpoints.Trace160 storage trace = _tierActiveSupplyCheckpointsOf[tierId];
|
|
367
|
+
|
|
368
|
+
// Calculate the next tier active total by adding or subtracting from the latest checkpointed value.
|
|
369
|
+
uint256 updated = increase ? trace.latest() + amount : trace.latest() - amount;
|
|
370
|
+
|
|
371
|
+
// Write the new tier active total at the current block.
|
|
372
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
373
|
+
trace.push({key: uint96(block.number), value: uint160(updated)});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/// @notice Apply an account delegation change to every tier-level active total the account contributes to.
|
|
377
|
+
/// @dev Delegation is account-wide in OZ Votes, so changing an account's delegate activates or deactivates every
|
|
378
|
+
/// tier balance currently held by the account. Transfer hooks handle one-token tier deltas separately.
|
|
379
|
+
/// @param account The account whose tier voting units should be added or removed.
|
|
380
|
+
/// @param increase Whether to add `account`'s tier voting units; if false, they are removed.
|
|
381
|
+
function _applyAccountDelegationToTierActiveVotes(address account, bool increase) private {
|
|
382
|
+
// Read the largest tier ID once; tier IDs are sequential and 1-indexed for each hook.
|
|
383
|
+
uint256 tierId = STORE.maxTierIdOf(hook);
|
|
384
|
+
|
|
385
|
+
// Walk each tier from max to 1 so empty hooks skip cleanly when maxTierId is zero.
|
|
386
|
+
while (tierId != 0) {
|
|
387
|
+
// Read only this account's units for the tier; empty tiers return zero and are ignored below.
|
|
388
|
+
uint256 tierVotingUnits = STORE.tierVotingUnitsOf({hook: hook, account: account, tierId: tierId});
|
|
389
|
+
|
|
390
|
+
// Only write checkpoints for tiers whose active totals actually change.
|
|
391
|
+
if (tierVotingUnits != 0) {
|
|
392
|
+
_adjustTierActiveVotes({tierId: tierId, amount: tierVotingUnits, increase: increase});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
unchecked {
|
|
396
|
+
// The loop condition proves tierId is nonzero, so the decrement cannot underflow.
|
|
397
|
+
--tierId;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
291
402
|
/// @notice Update the checkpointed total of delegated voting units.
|
|
292
403
|
/// @dev Writes at most one active-total checkpoint at the current OZ clock. A zero amount is ignored so zero-value
|
|
293
404
|
/// delegation or transfer hooks do not create empty checkpoints.
|
|
@@ -305,13 +416,21 @@ contract JB721Checkpoints is Votes, IJB721Checkpoints {
|
|
|
305
416
|
_activeSupplyCheckpoints.push({key: clock(), value: SafeCast.toUint208(updated)});
|
|
306
417
|
}
|
|
307
418
|
|
|
308
|
-
/// @notice Add or remove units from a tier's
|
|
309
|
-
/// @param tierId The tier whose
|
|
419
|
+
/// @notice Add or remove units from a tier's owner-tracked voting-units checkpoint at the current block.
|
|
420
|
+
/// @param tierId The tier whose owner-tracked voting-units trace to update.
|
|
310
421
|
/// @param amount The voting units to add or remove.
|
|
311
422
|
/// @param increase Whether to add `amount`; if false, `amount` is removed.
|
|
312
423
|
function _updateTierEligibleUnits(uint256 tierId, uint256 amount, bool increase) private {
|
|
424
|
+
// Ignore zero-unit updates because they do not change this tier's owner-tracked total.
|
|
425
|
+
if (amount == 0) return;
|
|
426
|
+
|
|
427
|
+
// Keep a reference to the tier's owner-tracked voting-units trace.
|
|
313
428
|
Checkpoints.Trace160 storage trace = _tierEligibleUnitsOf[tierId];
|
|
429
|
+
|
|
430
|
+
// Calculate the next owner-tracked total by adding or subtracting from the latest checkpointed value.
|
|
314
431
|
uint256 updated = increase ? trace.latest() + amount : trace.latest() - amount;
|
|
432
|
+
|
|
433
|
+
// Write the new owner-tracked total at the current block.
|
|
315
434
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
316
435
|
trace.push({key: uint96(block.number), value: uint160(updated)});
|
|
317
436
|
}
|
package/src/JB721TiersHook.sol
CHANGED
|
@@ -244,8 +244,7 @@ contract JB721TiersHook is JBOwnable, ERC2771Context, JB721Hook, IJB721TiersHook
|
|
|
244
244
|
/// @notice Initialize a cloned copy of the hook. Sets the project association, ERC-721 name/symbol, pricing
|
|
245
245
|
/// context (currency + decimals), metadata URIs, initial tiers, and behavioral flags. Can only be called once
|
|
246
246
|
/// per clone — the implementation contract is pre-initialized in its constructor to prevent misuse.
|
|
247
|
-
/// @dev Called by `JB721TiersHookDeployer`
|
|
248
|
-
/// project ID is zero.
|
|
247
|
+
/// @dev Called by `JB721TiersHookDeployer` after cloning. Reverts if called twice or if the project ID is zero.
|
|
249
248
|
/// @param initialProjectId The ID of the project this hook is associated with.
|
|
250
249
|
/// @param name The name of the NFT collection.
|
|
251
250
|
/// @param symbol The symbol representing the NFT collection.
|
|
@@ -461,9 +460,8 @@ contract JB721TiersHook is JBOwnable, ERC2771Context, JB721Hook, IJB721TiersHook
|
|
|
461
460
|
/// @param symbol The new collection symbol. Send empty to leave unchanged.
|
|
462
461
|
/// @param baseUri The new base URI. Send empty to leave unchanged.
|
|
463
462
|
/// @param contractUri The new contract URI. Send empty to leave unchanged.
|
|
464
|
-
/// @param tokenUriResolver The new URI resolver. Pass `IJB721TokenUriResolver(address(this))`
|
|
465
|
-
///
|
|
466
|
-
/// clears the resolver.
|
|
463
|
+
/// @param tokenUriResolver The new URI resolver. Pass `IJB721TokenUriResolver(address(this))` to leave it
|
|
464
|
+
/// unchanged; `address(0)` clears the resolver.
|
|
467
465
|
/// @param encodedIpfsUriTierId The ID of the tier to set the encoded IPFS URI of.
|
|
468
466
|
/// @param encodedIpfsUri The encoded IPFS URI to set.
|
|
469
467
|
function setMetadata(
|
|
@@ -114,8 +114,7 @@ contract JB721TiersHookProjectDeployer is
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/// @notice Launches rulesets for a project with an attached 721 tiers hook.
|
|
117
|
-
/// @dev Only a project's owner or an operator with
|
|
118
|
-
/// rulesets.
|
|
117
|
+
/// @dev Only a project's owner or an operator with `LAUNCH_RULESETS & SET_TERMINALS` can launch its rulesets.
|
|
119
118
|
/// @param projectId The ID of the project to launch rulesets for.
|
|
120
119
|
/// @param deployTiersHookConfig Configuration which dictates the behavior of the 721 tiers hook to deploy.
|
|
121
120
|
/// @param launchRulesetsConfig Configuration which dictates the project's new rulesets.
|
|
@@ -233,8 +232,7 @@ contract JB721TiersHookProjectDeployer is
|
|
|
233
232
|
//*********************************************************************//
|
|
234
233
|
|
|
235
234
|
/// @notice Configure and launch rulesets for a newly created project. Converts `JBPayDataHookRulesetConfig` entries
|
|
236
|
-
/// into standard `JBRulesetConfig` entries
|
|
237
|
-
/// the data hook.
|
|
235
|
+
/// into standard `JBRulesetConfig` entries that use the deployed hook as their data hook.
|
|
238
236
|
/// @param projectId The ID of the reserved project.
|
|
239
237
|
/// @param launchProjectConfig Configuration which dictates the behavior of the project to launch.
|
|
240
238
|
/// @param dataHook The data hook to use for the project.
|
|
@@ -148,8 +148,7 @@ contract JB721TiersHookStore is IJB721TiersHookStore {
|
|
|
148
148
|
/// @custom:param hook The 721 contract to get the custom token URI resolver of.
|
|
149
149
|
mapping(address hook => IJB721TokenUriResolver) public override tokenUriResolverOf;
|
|
150
150
|
|
|
151
|
-
/// @notice The combined cash-out weight of all
|
|
152
|
-
/// O(1) instead of O(maxTierId).
|
|
151
|
+
/// @notice The combined cash-out weight of all hook NFTs, tracked so cash-out pricing is O(1).
|
|
153
152
|
/// @dev Maintained incrementally in `recordMint` (+ the tier's full price for the new outstanding NFT plus any
|
|
154
153
|
/// newly-accrued pending reserve) and `recordBurn` (- the tier's full price). It is invariant under everything
|
|
155
154
|
/// else: reserve mints are weight-neutral (a pending reserve becomes an outstanding NFT), removed tiers keep
|
|
@@ -610,8 +609,7 @@ contract JB721TiersHookStore is IJB721TiersHookStore {
|
|
|
610
609
|
/// @param hook The 721 contract to get the tier from.
|
|
611
610
|
/// @param tierId The ID of the tier to get.
|
|
612
611
|
/// @param storedTier The stored tier to get the corresponding tier for.
|
|
613
|
-
/// @param includeResolvedUri If
|
|
614
|
-
/// resolved and included.
|
|
612
|
+
/// @param includeResolvedUri If true and the contract has a token URI resolver, resolve and include its content.
|
|
615
613
|
/// @return tier The tier as a `JB721Tier` struct.
|
|
616
614
|
function _getTierFrom(
|
|
617
615
|
address hook,
|
|
@@ -135,8 +135,7 @@ abstract contract JB721Hook is ERC721, IJB721Hook {
|
|
|
135
135
|
cashOutTaxRate = context.cashOutTaxRate;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
/// @notice The data calculated before a payment is recorded in the terminal store
|
|
139
|
-
/// terminal's `pay(...)` transaction.
|
|
138
|
+
/// @notice The data calculated before a payment is recorded in the terminal store for `pay(...)`.
|
|
140
139
|
/// @dev Sets this contract as the pay hook. Part of `IJBRulesetDataHook`.
|
|
141
140
|
/// @param context The payment context passed to this contract by the `pay(...)` function.
|
|
142
141
|
/// @return weight The new `weight` to use, overriding the ruleset's `weight`.
|
|
@@ -164,8 +163,7 @@ abstract contract JB721Hook is ERC721, IJB721Hook {
|
|
|
164
163
|
// -------------------------- public views --------------------------- //
|
|
165
164
|
//*********************************************************************//
|
|
166
165
|
|
|
167
|
-
/// @notice Returns the cumulative cash out weight of the specified token IDs relative to
|
|
168
|
-
/// `totalCashOutWeight`.
|
|
166
|
+
/// @notice Returns the cumulative cash out weight of the specified token IDs relative to `totalCashOutWeight`.
|
|
169
167
|
/// @param tokenIds The NFT token IDs to calculate the cumulative cash out weight of.
|
|
170
168
|
/// @return The cumulative cash out weight of the specified token IDs.
|
|
171
169
|
function cashOutWeightOf(uint256[] memory tokenIds) public view virtual returns (uint256) {
|
|
@@ -248,8 +246,7 @@ abstract contract JB721Hook is ERC721, IJB721Hook {
|
|
|
248
246
|
_didBurn(decodedTokenIds);
|
|
249
247
|
}
|
|
250
248
|
|
|
251
|
-
/// @notice Mints
|
|
252
|
-
/// `IJBPayHook`.
|
|
249
|
+
/// @notice Mints NFTs to `context.beneficiary` upon payment if conditions are met. Part of `IJBPayHook`.
|
|
253
250
|
/// @dev Reverts if the calling contract is not one of the project's terminals.
|
|
254
251
|
/// @param context The payment context passed in by the terminal.
|
|
255
252
|
function afterPayRecordedWith(JBAfterPayRecordedContext calldata context) external payable virtual override {
|
|
@@ -3,6 +3,7 @@ pragma solidity ^0.8.0;
|
|
|
3
3
|
|
|
4
4
|
import {IJBActiveVotes} from "@bananapus/core-v6/src/interfaces/IJBActiveVotes.sol";
|
|
5
5
|
import {IERC5805} from "@openzeppelin/contracts/interfaces/IERC5805.sol";
|
|
6
|
+
|
|
6
7
|
import {IJB721TiersHookStore} from "./IJB721TiersHookStore.sol";
|
|
7
8
|
|
|
8
9
|
/// @notice A checkpoint module that provides IVotes-compatible checkpointed voting power for a JB721TiersHook.
|
|
@@ -10,38 +11,46 @@ import {IJB721TiersHookStore} from "./IJB721TiersHookStore.sol";
|
|
|
10
11
|
/// Pass this address to JBTokenDistributor as the IVotes token.
|
|
11
12
|
interface IJB721Checkpoints is IERC5805, IJBActiveVotes {
|
|
12
13
|
/// @notice The store that holds tier and voting data for the hook's NFTs.
|
|
13
|
-
/// @return The store contract.
|
|
14
|
+
/// @return store The store contract.
|
|
14
15
|
// forge-lint: disable-next-line(mixed-case-function)
|
|
15
|
-
function STORE() external view returns (IJB721TiersHookStore);
|
|
16
|
+
function STORE() external view returns (IJB721TiersHookStore store);
|
|
17
|
+
|
|
18
|
+
/// @notice The total delegated voting units of a tier at a past block.
|
|
19
|
+
/// @dev Counts only tier voting units held by accounts with a nonzero delegate.
|
|
20
|
+
/// @param tierId The tier to get the delegated voting units of.
|
|
21
|
+
/// @param blockNumber The past block number to look up.
|
|
22
|
+
/// @return activeVotes The tier's delegated voting units at `blockNumber`.
|
|
23
|
+
function getPastTierActiveVotes(uint256 tierId, uint256 blockNumber) external view returns (uint256 activeVotes);
|
|
16
24
|
|
|
17
|
-
/// @notice The total
|
|
18
|
-
/// @dev
|
|
19
|
-
///
|
|
20
|
-
/// mints never write to this trace. Distributors use this as the denominator for tier-scoped reward pots.
|
|
21
|
-
/// @param tierId The tier to get the eligible voting units of.
|
|
25
|
+
/// @notice The total owner-checkpointed voting units of a tier at a past block.
|
|
26
|
+
/// @dev Owner-checkpointed voting units are the tier's total owned units, regardless of delegation status.
|
|
27
|
+
/// @param tierId The tier to get the owner-checkpointed voting units of.
|
|
22
28
|
/// @param blockNumber The block number to look up (must be strictly in the past).
|
|
23
|
-
/// @return The tier's
|
|
24
|
-
function getPastTierVotingUnits(uint256 tierId, uint256 blockNumber) external view returns (uint256);
|
|
29
|
+
/// @return votingUnits The tier's owner-checkpointed voting units at `blockNumber`.
|
|
30
|
+
function getPastTierVotingUnits(uint256 tierId, uint256 blockNumber) external view returns (uint256 votingUnits);
|
|
31
|
+
|
|
32
|
+
/// @notice The current total delegated voting units of a tier.
|
|
33
|
+
/// @param tierId The tier to get the current delegated voting units of.
|
|
34
|
+
/// @return activeVotes The tier's current delegated voting units.
|
|
35
|
+
function getTierActiveVotes(uint256 tierId) external view returns (uint256 activeVotes);
|
|
25
36
|
|
|
26
37
|
/// @notice The hook that this module tracks voting power for.
|
|
27
|
-
/// @return The hook address.
|
|
38
|
+
/// @return hookAddress The hook address.
|
|
28
39
|
// forge-lint: disable-next-line(mixed-case-function)
|
|
29
|
-
function hook() external view returns (address);
|
|
40
|
+
function hook() external view returns (address hookAddress);
|
|
30
41
|
|
|
31
42
|
/// @notice The owner of an NFT at a past block.
|
|
32
|
-
/// @dev Returns `address(0)`
|
|
33
|
-
/// transferred. Unenrolled tokens are ineligible for snapshot-based distribution.
|
|
43
|
+
/// @dev Returns `address(0)` if no ownership checkpoint exists or the query predates the first checkpoint.
|
|
34
44
|
/// @param tokenId The token ID of the NFT to get the historical owner of.
|
|
35
45
|
/// @param blockNumber The block number to look up.
|
|
36
|
-
/// @return The owner of the token at `blockNumber`, or zero if
|
|
37
|
-
function ownerOfAt(uint256 tokenId, uint256 blockNumber) external view returns (address);
|
|
46
|
+
/// @return owner The owner of the token at `blockNumber`, or zero if no owner is proven at that block.
|
|
47
|
+
function ownerOfAt(uint256 tokenId, uint256 blockNumber) external view returns (address owner);
|
|
38
48
|
|
|
39
|
-
/// @notice Delegates voting power and
|
|
40
|
-
/// @dev
|
|
41
|
-
///
|
|
42
|
-
/// distribution.
|
|
49
|
+
/// @notice Delegates voting power and backfills ownership history for listed tokens if needed.
|
|
50
|
+
/// @dev Mint and transfer hooks normally write owner checkpoints automatically. The token ID list keeps
|
|
51
|
+
/// pre-upgrade or otherwise uncheckpointed tokens recoverable while preserving the owner-only authorization check.
|
|
43
52
|
/// @param delegatee The address to delegate voting power to. Use your own address for self-delegation.
|
|
44
|
-
/// @param tokenIds The token IDs
|
|
53
|
+
/// @param tokenIds The token IDs whose owner checkpoints should be backfilled if missing.
|
|
45
54
|
function delegate(address delegatee, uint256[] calldata tokenIds) external;
|
|
46
55
|
|
|
47
56
|
/// @notice Initializes a cloned module with its hook reference.
|
|
@@ -96,8 +96,7 @@ interface IJB721TiersHook is IJB721Hook {
|
|
|
96
96
|
/// @param caller The address that called the function.
|
|
97
97
|
event SetTokenUriResolver(IJB721TokenUriResolver indexed resolver, address caller);
|
|
98
98
|
|
|
99
|
-
/// @notice Emitted when a split payout reverts during distribution
|
|
100
|
-
/// project's balance.
|
|
99
|
+
/// @notice Emitted when a split payout reverts during distribution, routing funds to the project's balance.
|
|
101
100
|
/// @param projectId The project ID the split belongs to.
|
|
102
101
|
/// @param split The split that reverted.
|
|
103
102
|
/// @param amount The amount that was paid out.
|
|
@@ -213,9 +212,8 @@ interface IJB721TiersHook is IJB721Hook {
|
|
|
213
212
|
/// @param symbol The new collection symbol. Send empty to leave unchanged.
|
|
214
213
|
/// @param baseUri The new base URI. Send empty to leave unchanged.
|
|
215
214
|
/// @param contractUri The new contract URI. Send empty to leave unchanged.
|
|
216
|
-
/// @param tokenUriResolver The new URI resolver. Pass `IJB721TokenUriResolver(address(this))`
|
|
217
|
-
///
|
|
218
|
-
/// clears the resolver.
|
|
215
|
+
/// @param tokenUriResolver The new URI resolver. Pass `IJB721TokenUriResolver(address(this))` to leave it
|
|
216
|
+
/// unchanged; `address(0)` clears the resolver.
|
|
219
217
|
/// @param encodedIpfsUriTierId The ID of the tier to set the encoded IPFS URI of.
|
|
220
218
|
/// @param encodedIpfsUri The encoded IPFS URI to set.
|
|
221
219
|
function setMetadata(
|
|
@@ -73,8 +73,7 @@ library JB721TiersHookLib {
|
|
|
73
73
|
/// @param caller The address that called the function.
|
|
74
74
|
event SetDiscountPercent(uint256 indexed tierId, uint256 discountPercent, address caller);
|
|
75
75
|
|
|
76
|
-
/// @notice Emitted when a split payout reverts during distribution
|
|
77
|
-
/// project's balance.
|
|
76
|
+
/// @notice Emitted when a split payout reverts during distribution, routing funds to the project's balance.
|
|
78
77
|
/// @param projectId The project ID the split belongs to.
|
|
79
78
|
/// @param split The split that reverted.
|
|
80
79
|
/// @param amount The amount that was paid out.
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
|
-
/// @notice `JB721TiersHook` options
|
|
5
|
-
/// per-ruleset basis.
|
|
4
|
+
/// @notice `JB721TiersHook` options packed into each ruleset's `JBRulesetMetadata.metadata`.
|
|
6
5
|
/// @custom:member pauseTransfers A boolean indicating whether NFT transfers are paused during this ruleset.
|
|
7
6
|
/// @custom:member pauseMintPendingReserves A boolean indicating whether pending/outstanding NFT reserves can be minted
|
|
8
7
|
/// during this ruleset.
|
|
@@ -5,8 +5,7 @@ import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.
|
|
|
5
5
|
|
|
6
6
|
import {JBPayDataHookRulesetConfig} from "./JBPayDataHookRulesetConfig.sol";
|
|
7
7
|
|
|
8
|
-
/// @custom:member projectUri Metadata URI to associate with the project
|
|
9
|
-
/// the project.
|
|
8
|
+
/// @custom:member projectUri Metadata URI to associate with the project, updatable by the project owner.
|
|
10
9
|
/// @custom:member rulesetConfigurations The ruleset configurations to queue.
|
|
11
10
|
/// @custom:member terminalConfigurations The terminal configurations to add for the project.
|
|
12
11
|
/// @custom:member memo A memo to pass along to the emitted event.
|
|
@@ -14,17 +14,14 @@ import {JBPayDataHookRulesetMetadata} from "./JBPayDataHookRulesetMetadata.sol";
|
|
|
14
14
|
/// a project owner cannot make changes to a ruleset's parameters while it is active – any proposed changes will apply
|
|
15
15
|
/// to the subsequent ruleset. If no changes are proposed, a ruleset rolls over to another one with the same properties
|
|
16
16
|
/// but new `start` timestamp and a decayed `weight`.
|
|
17
|
-
/// @custom:member weight A fixed point number with 18 decimals that contracts can use
|
|
18
|
-
///
|
|
19
|
-
///
|
|
20
|
-
///
|
|
21
|
-
/// the
|
|
22
|
-
/// project owner hasn't queued the subsequent ruleset with an explicit `weight`. If it's 0, each ruleset will have
|
|
23
|
-
/// equal weight. If the number is 90%, the next ruleset will have a 10% smaller weight. This weight is out of
|
|
17
|
+
/// @custom:member weight A fixed point number with 18 decimals that contracts can use for calculations. For example,
|
|
18
|
+
/// payment terminals can use this to determine how many tokens should be minted when a payment is received.
|
|
19
|
+
/// @custom:member weightCutPercent A percent by how much the `weight` of the subsequent ruleset should be reduced if
|
|
20
|
+
/// the project owner hasn't queued the subsequent ruleset with an explicit `weight`. If it's 0, each ruleset will
|
|
21
|
+
/// have equal weight. If the number is 90%, the next ruleset will have a 10% smaller weight. This weight is out of
|
|
24
22
|
/// `JBConstants.MAX_WEIGHT_CUT_PERCENT`.
|
|
25
|
-
/// @custom:member approvalHook
|
|
26
|
-
///
|
|
27
|
-
/// can be used to create rules around how a project owner can change ruleset parameters over time.
|
|
23
|
+
/// @custom:member approvalHook A contract that says whether a proposed ruleset should be accepted or rejected. It can
|
|
24
|
+
/// create rules around how a project owner changes ruleset parameters over time.
|
|
28
25
|
/// @custom:member metadata Metadata specifying the controller-specific parameters that a ruleset can have. These
|
|
29
26
|
/// properties cannot change until the next ruleset starts.
|
|
30
27
|
/// @custom:member splitGroups An array of splits to use for any number of groups while the ruleset is active.
|
|
@@ -13,12 +13,10 @@ pragma solidity ^0.8.0;
|
|
|
13
13
|
/// permission from the owner should be allowed to mint project tokens on demand during this ruleset.
|
|
14
14
|
/// @custom:member allowSetCustomToken A flag indicating if the project owner can set the project's token to a custom
|
|
15
15
|
/// ERC-20.
|
|
16
|
-
/// @custom:member allowTerminalMigration A flag indicating if
|
|
17
|
-
/// ruleset.
|
|
16
|
+
/// @custom:member allowTerminalMigration A flag indicating if terminal migration is allowed during this ruleset.
|
|
18
17
|
/// @custom:member allowSetTerminals A flag indicating if a project's terminals can be added or removed.
|
|
19
18
|
/// @custom:member allowSetController A flag indicating if a project's controller can be changed.
|
|
20
|
-
/// @custom:member allowAddAccountingContext A flag indicating if a project can add
|
|
21
|
-
/// terminals to use.
|
|
19
|
+
/// @custom:member allowAddAccountingContext A flag indicating if a project can add accounting contexts to terminals.
|
|
22
20
|
/// @custom:member allowAddPriceFeed A flag indicating if a project can add new price feeds to calculate exchange rates
|
|
23
21
|
/// between its tokens.
|
|
24
22
|
/// @custom:member ownerMustSendPayouts A flag indicating if the owner must manually trigger payout distributions.
|