@bananapus/omnichain-deployers-v6 0.0.25 → 0.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/JBOmnichainDeployer.sol +364 -362
package/package.json
CHANGED
|
@@ -129,6 +129,246 @@ contract JBOmnichainDeployer is
|
|
|
129
129
|
PERMISSIONS.setPermissionsFor({account: address(this), permissionsData: permissionData});
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
//*********************************************************************//
|
|
133
|
+
// ---------------------- external transactions ---------------------- //
|
|
134
|
+
//*********************************************************************//
|
|
135
|
+
|
|
136
|
+
/// @notice Deploy new suckers for an existing project.
|
|
137
|
+
/// @dev Only the juicebox's owner or an operator with `JBPermissionIds.DEPLOY_SUCKERS` can call this entrypoint.
|
|
138
|
+
/// The downstream registry call also maps the configured tokens on each newly created sucker, so the same
|
|
139
|
+
/// end-to-end operation depends on the project's token-mapping authority being arranged for the registry.
|
|
140
|
+
/// @param projectId The ID of the project to deploy suckers for.
|
|
141
|
+
/// @param suckerDeploymentConfiguration The suckers to set up for the project.
|
|
142
|
+
function deploySuckersFor(
|
|
143
|
+
uint256 projectId,
|
|
144
|
+
JBSuckerDeploymentConfig calldata suckerDeploymentConfiguration
|
|
145
|
+
)
|
|
146
|
+
external
|
|
147
|
+
override
|
|
148
|
+
returns (address[] memory suckers)
|
|
149
|
+
{
|
|
150
|
+
// Enforce permissions.
|
|
151
|
+
_requirePermissionFrom({
|
|
152
|
+
account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.DEPLOY_SUCKERS
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Deploy the suckers.
|
|
156
|
+
// Note: the salt includes `_msgSender()` for replay protection. Cross-chain deterministic
|
|
157
|
+
// address matching requires using the same sender address on each chain.
|
|
158
|
+
// slither-disable-next-line unused-return
|
|
159
|
+
suckers = SUCKER_REGISTRY.deploySuckersFor({
|
|
160
|
+
projectId: projectId,
|
|
161
|
+
salt: keccak256(abi.encode(suckerDeploymentConfiguration.salt, _msgSender())),
|
|
162
|
+
configurations: suckerDeploymentConfiguration.deployerConfigurations
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// @notice Creates a project with a 721 tiers hook attached and with suckers.
|
|
167
|
+
/// @param owner The address to set as the owner of the project. The ERC-721 which confers this project's ownership
|
|
168
|
+
/// will be sent to this address.
|
|
169
|
+
/// @param projectUri The project's metadata URI.
|
|
170
|
+
/// @param deploy721Config The 721 hook deployment config (hook config + cash-out flag + salt).
|
|
171
|
+
/// @param rulesetConfigurations The rulesets to queue. Custom data hooks are read from each ruleset's metadata.
|
|
172
|
+
/// @param terminalConfigurations The terminals to set up for the project.
|
|
173
|
+
/// @param memo A memo to pass along to the emitted event.
|
|
174
|
+
/// @param suckerDeploymentConfiguration The suckers to set up for the project. Suckers facilitate cross-chain
|
|
175
|
+
/// token transfers between peer projects on different networks.
|
|
176
|
+
/// @param controller The controller to use for launching the project.
|
|
177
|
+
/// @return projectId The ID of the newly launched project.
|
|
178
|
+
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
179
|
+
/// @return suckers The addresses of the deployed suckers.
|
|
180
|
+
function launchProjectFor(
|
|
181
|
+
address owner,
|
|
182
|
+
string calldata projectUri,
|
|
183
|
+
JBOmnichain721Config calldata deploy721Config,
|
|
184
|
+
JBRulesetConfig[] memory rulesetConfigurations,
|
|
185
|
+
JBTerminalConfig[] calldata terminalConfigurations,
|
|
186
|
+
string calldata memo,
|
|
187
|
+
JBSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
|
|
188
|
+
IJBController controller
|
|
189
|
+
)
|
|
190
|
+
external
|
|
191
|
+
override
|
|
192
|
+
returns (uint256 projectId, IJB721TiersHook hook, address[] memory suckers)
|
|
193
|
+
{
|
|
194
|
+
return _launchProjectFor({
|
|
195
|
+
owner: owner,
|
|
196
|
+
projectUri: projectUri,
|
|
197
|
+
deploy721Config: deploy721Config,
|
|
198
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
199
|
+
terminalConfigurations: terminalConfigurations,
|
|
200
|
+
memo: memo,
|
|
201
|
+
suckerDeploymentConfiguration: suckerDeploymentConfiguration,
|
|
202
|
+
controller: controller
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/// @notice Creates a project with a default (empty-tier) 721 hook and with suckers.
|
|
207
|
+
/// @dev Uses `baseCurrency` from the first ruleset and `decimals = 18` for the default 721 config.
|
|
208
|
+
/// @param owner The address to set as the owner of the project.
|
|
209
|
+
/// @param projectUri The project's metadata URI.
|
|
210
|
+
/// @param rulesetConfigurations The rulesets to queue.
|
|
211
|
+
/// @param terminalConfigurations The terminals to set up for the project.
|
|
212
|
+
/// @param memo A memo to pass along to the emitted event.
|
|
213
|
+
/// @param suckerDeploymentConfiguration The suckers to set up for the project.
|
|
214
|
+
/// @param controller The controller to use for launching the project.
|
|
215
|
+
/// @return projectId The ID of the newly launched project.
|
|
216
|
+
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
217
|
+
/// @return suckers The addresses of the deployed suckers.
|
|
218
|
+
function launchProjectFor(
|
|
219
|
+
address owner,
|
|
220
|
+
string calldata projectUri,
|
|
221
|
+
JBRulesetConfig[] memory rulesetConfigurations,
|
|
222
|
+
JBTerminalConfig[] calldata terminalConfigurations,
|
|
223
|
+
string calldata memo,
|
|
224
|
+
JBSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
|
|
225
|
+
IJBController controller
|
|
226
|
+
)
|
|
227
|
+
external
|
|
228
|
+
override
|
|
229
|
+
returns (uint256 projectId, IJB721TiersHook hook, address[] memory suckers)
|
|
230
|
+
{
|
|
231
|
+
return _launchProjectFor({
|
|
232
|
+
owner: owner,
|
|
233
|
+
projectUri: projectUri,
|
|
234
|
+
deploy721Config: _default721Config(rulesetConfigurations),
|
|
235
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
236
|
+
terminalConfigurations: terminalConfigurations,
|
|
237
|
+
memo: memo,
|
|
238
|
+
suckerDeploymentConfiguration: suckerDeploymentConfiguration,
|
|
239
|
+
controller: controller
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/// @notice Launches new rulesets for a project with a 721 tiers hook attached, using this contract as the data
|
|
244
|
+
/// hook.
|
|
245
|
+
/// @param projectId The ID of the project to launch the rulesets for.
|
|
246
|
+
/// @param deploy721Config The 721 hook deployment config (hook config + cash-out flag + salt).
|
|
247
|
+
/// @param rulesetConfigurations The rulesets to launch. Custom data hooks are read from each ruleset's metadata.
|
|
248
|
+
/// @param terminalConfigurations The terminals to set up for the project.
|
|
249
|
+
/// @param memo A memo to pass along to the emitted event.
|
|
250
|
+
/// @param controller The controller to use for launching the rulesets.
|
|
251
|
+
/// @return rulesetId The ID of the newly launched rulesets.
|
|
252
|
+
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
253
|
+
function launchRulesetsFor(
|
|
254
|
+
uint256 projectId,
|
|
255
|
+
JBOmnichain721Config memory deploy721Config,
|
|
256
|
+
JBRulesetConfig[] memory rulesetConfigurations,
|
|
257
|
+
JBTerminalConfig[] calldata terminalConfigurations,
|
|
258
|
+
string calldata memo,
|
|
259
|
+
IJBController controller
|
|
260
|
+
)
|
|
261
|
+
external
|
|
262
|
+
override
|
|
263
|
+
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
264
|
+
{
|
|
265
|
+
return _launchRulesetsFor({
|
|
266
|
+
projectId: projectId,
|
|
267
|
+
deploy721Config: deploy721Config,
|
|
268
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
269
|
+
terminalConfigurations: terminalConfigurations,
|
|
270
|
+
memo: memo,
|
|
271
|
+
controller: controller
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/// @notice Launches new rulesets for a project with a default (empty-tier) 721 hook.
|
|
276
|
+
/// @dev Uses `baseCurrency` from the first ruleset and `decimals = 18` for the default 721 config.
|
|
277
|
+
/// @param projectId The ID of the project to launch the rulesets for.
|
|
278
|
+
/// @param rulesetConfigurations The rulesets to launch.
|
|
279
|
+
/// @param terminalConfigurations The terminals to set up for the project.
|
|
280
|
+
/// @param memo A memo to pass along to the emitted event.
|
|
281
|
+
/// @param controller The controller to use for launching the rulesets.
|
|
282
|
+
/// @return rulesetId The ID of the newly launched rulesets.
|
|
283
|
+
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
284
|
+
function launchRulesetsFor(
|
|
285
|
+
uint256 projectId,
|
|
286
|
+
JBRulesetConfig[] memory rulesetConfigurations,
|
|
287
|
+
JBTerminalConfig[] calldata terminalConfigurations,
|
|
288
|
+
string calldata memo,
|
|
289
|
+
IJBController controller
|
|
290
|
+
)
|
|
291
|
+
external
|
|
292
|
+
override
|
|
293
|
+
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
294
|
+
{
|
|
295
|
+
return _launchRulesetsFor({
|
|
296
|
+
projectId: projectId,
|
|
297
|
+
deploy721Config: _default721Config(rulesetConfigurations),
|
|
298
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
299
|
+
terminalConfigurations: terminalConfigurations,
|
|
300
|
+
memo: memo,
|
|
301
|
+
controller: controller
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/// @dev Make sure this contract can only receive project NFTs from `JBProjects`.
|
|
306
|
+
function onERC721Received(address, address, uint256, bytes calldata) external view returns (bytes4) {
|
|
307
|
+
// Make sure the 721 received is from the `JBProjects` contract.
|
|
308
|
+
if (msg.sender != address(PROJECTS)) revert JBOmnichainDeployer_UnexpectedNFTReceived();
|
|
309
|
+
|
|
310
|
+
return IERC721Receiver.onERC721Received.selector;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/// @notice Queues new rulesets for a project with a 721 tiers hook attached, using this contract as the data hook.
|
|
314
|
+
/// @dev If `deploy721Config.deployTiersHookConfig.tiersConfig.tiers.length > 0`, a new 721 hook is deployed.
|
|
315
|
+
/// Otherwise, the 721 hook from the latest ruleset is carried forward.
|
|
316
|
+
/// @param projectId The ID of the project to queue the rulesets for.
|
|
317
|
+
/// @param deploy721Config The 721 hook deployment config (hook config + cash-out flag + salt).
|
|
318
|
+
/// @param rulesetConfigurations The rulesets to queue. Custom data hooks are read from each ruleset's metadata.
|
|
319
|
+
/// @param memo A memo to pass along to the emitted event.
|
|
320
|
+
/// @param controller The controller to use for queuing the rulesets.
|
|
321
|
+
/// @return rulesetId The ID of the newly queued rulesets.
|
|
322
|
+
/// @return hook The 721 tiers hook (newly deployed or carried forward from the previous ruleset).
|
|
323
|
+
function queueRulesetsOf(
|
|
324
|
+
uint256 projectId,
|
|
325
|
+
JBOmnichain721Config memory deploy721Config,
|
|
326
|
+
JBRulesetConfig[] memory rulesetConfigurations,
|
|
327
|
+
string calldata memo,
|
|
328
|
+
IJBController controller
|
|
329
|
+
)
|
|
330
|
+
external
|
|
331
|
+
override
|
|
332
|
+
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
333
|
+
{
|
|
334
|
+
return _queueRulesetsOf({
|
|
335
|
+
projectId: projectId,
|
|
336
|
+
deploy721Config: deploy721Config,
|
|
337
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
338
|
+
memo: memo,
|
|
339
|
+
controller: controller
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/// @notice Queues new rulesets for a project with a default (empty-tier) 721 hook, carrying forward the existing
|
|
344
|
+
/// hook.
|
|
345
|
+
/// @dev Uses `baseCurrency` from the first ruleset and `decimals = 18` for the default 721 config. With 0 tiers in
|
|
346
|
+
/// the default config, the existing hook is always carried forward.
|
|
347
|
+
/// @param projectId The ID of the project to queue the rulesets for.
|
|
348
|
+
/// @param rulesetConfigurations The rulesets to queue.
|
|
349
|
+
/// @param memo A memo to pass along to the emitted event.
|
|
350
|
+
/// @param controller The controller to use for queuing the rulesets.
|
|
351
|
+
/// @return rulesetId The ID of the newly queued rulesets.
|
|
352
|
+
/// @return hook The 721 tiers hook carried forward from the previous ruleset.
|
|
353
|
+
function queueRulesetsOf(
|
|
354
|
+
uint256 projectId,
|
|
355
|
+
JBRulesetConfig[] memory rulesetConfigurations,
|
|
356
|
+
string calldata memo,
|
|
357
|
+
IJBController controller
|
|
358
|
+
)
|
|
359
|
+
external
|
|
360
|
+
override
|
|
361
|
+
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
362
|
+
{
|
|
363
|
+
return _queueRulesetsOf({
|
|
364
|
+
projectId: projectId,
|
|
365
|
+
deploy721Config: _default721Config(rulesetConfigurations),
|
|
366
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
367
|
+
memo: memo,
|
|
368
|
+
controller: controller
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
132
372
|
//*********************************************************************//
|
|
133
373
|
// ------------------------- external views -------------------------- //
|
|
134
374
|
//*********************************************************************//
|
|
@@ -171,7 +411,9 @@ contract JBOmnichainDeployer is
|
|
|
171
411
|
// Compute the cross-chain surplus: local surplus + sum of known peer chain surpluses.
|
|
172
412
|
// This prevents disproportionate reclaim when tokens bridge away but surplus stays.
|
|
173
413
|
effectiveSurplusValue = context.surplus.value
|
|
174
|
-
+ SUCKER_REGISTRY.remoteSurplusOf(
|
|
414
|
+
+ SUCKER_REGISTRY.remoteSurplusOf({
|
|
415
|
+
projectId: context.projectId, decimals: 18, currency: uint256(uint160(context.surplus.token))
|
|
416
|
+
});
|
|
175
417
|
|
|
176
418
|
// Will hold the 721 hook's cash out specifications (always 0 or 1 element).
|
|
177
419
|
JBCashOutHookSpecification[] memory tiered721HookSpecifications;
|
|
@@ -278,385 +520,122 @@ contract JBOmnichainDeployer is
|
|
|
278
520
|
|
|
279
521
|
// The amount entering the project after tier splits.
|
|
280
522
|
uint256 projectAmount = totalSplitAmount >= context.amount.value ? 0 : context.amount.value - totalSplitAmount;
|
|
281
|
-
|
|
282
|
-
// Get the custom data hook's weight and specs. Reduce the amount so it only considers funds entering the
|
|
283
|
-
// project, and pass the 721 hook's weight so the data hook sees the split-adjusted weight.
|
|
284
|
-
JBPayHookSpecification[] memory dataHookSpecs;
|
|
285
|
-
bool customHookCalled;
|
|
286
|
-
{
|
|
287
|
-
JBDeployerHookConfig memory extraHook = _extraDataHookOf[context.projectId][context.rulesetId];
|
|
288
|
-
if (address(extraHook.dataHook) != address(0) && extraHook.useDataHookForPay) {
|
|
289
|
-
JBBeforePayRecordedContext memory hookContext = context;
|
|
290
|
-
hookContext.amount.value = projectAmount;
|
|
291
|
-
// Pass the 721 hook's weight (which accounts for split deductions) so the data hook
|
|
292
|
-
// makes its decisions (e.g. mint-vs-swap) based on the correct post-split weight.
|
|
293
|
-
if (has721Hook) hookContext.weight = tiered721Weight;
|
|
294
|
-
(weight, dataHookSpecs) = extraHook.dataHook.beforePayRecordedWith(hookContext);
|
|
295
|
-
customHookCalled = true;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (!customHookCalled) {
|
|
300
|
-
// Use the 721 hook's weight directly (already scaled for splits) or fall back to context weight.
|
|
301
|
-
weight = has721Hook ? tiered721Weight : context.weight;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Merge specifications: 721 hook spec first, then data hook specs.
|
|
305
|
-
bool hasDataHookSpecs = dataHookSpecs.length > 0;
|
|
306
|
-
if (!hasTiered721Spec && !hasDataHookSpecs) return (weight, hookSpecifications);
|
|
307
|
-
|
|
308
|
-
hookSpecifications = new JBPayHookSpecification[]((hasTiered721Spec ? 1 : 0) + dataHookSpecs.length);
|
|
309
|
-
|
|
310
|
-
uint256 specIndex;
|
|
311
|
-
if (hasTiered721Spec) hookSpecifications[specIndex++] = tiered721HookSpec;
|
|
312
|
-
for (uint256 i; i < dataHookSpecs.length; i++) {
|
|
313
|
-
hookSpecifications[specIndex + i] = dataHookSpecs[i];
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/// @notice Get the extra data hook for a project and ruleset.
|
|
318
|
-
/// @param projectId The ID of the project to get the extra data hook for.
|
|
319
|
-
/// @param rulesetId The ID of the ruleset to get the extra data hook for.
|
|
320
|
-
/// @return hook The extra data hook configured for the project/ruleset.
|
|
321
|
-
function extraDataHookOf(
|
|
322
|
-
uint256 projectId,
|
|
323
|
-
uint256 rulesetId
|
|
324
|
-
)
|
|
325
|
-
external
|
|
326
|
-
view
|
|
327
|
-
override
|
|
328
|
-
returns (JBDeployerHookConfig memory hook)
|
|
329
|
-
{
|
|
330
|
-
return _extraDataHookOf[projectId][rulesetId];
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/// @notice A flag indicating whether an address has permission to mint a project's tokens on-demand.
|
|
334
|
-
/// @dev A project's data hook can allow any address to mint its tokens.
|
|
335
|
-
/// @param projectId The ID of the project whose token can be minted.
|
|
336
|
-
/// @param ruleset The ruleset to check the token minting permission of.
|
|
337
|
-
/// @param addr The address to check the token minting permission of.
|
|
338
|
-
/// @return flag A flag indicating whether the address has permission to mint the project's tokens on-demand.
|
|
339
|
-
function hasMintPermissionFor(
|
|
340
|
-
uint256 projectId,
|
|
341
|
-
JBRuleset memory ruleset,
|
|
342
|
-
address addr
|
|
343
|
-
)
|
|
344
|
-
external
|
|
345
|
-
view
|
|
346
|
-
override
|
|
347
|
-
returns (bool)
|
|
348
|
-
{
|
|
349
|
-
// Suckers always get mint permission.
|
|
350
|
-
if (SUCKER_REGISTRY.isSuckerOf({projectId: projectId, addr: addr})) return true;
|
|
351
|
-
|
|
352
|
-
// Check the extra data hook (the 721 hook doesn't grant mint permission).
|
|
353
|
-
JBDeployerHookConfig memory extraHook = _extraDataHookOf[projectId][ruleset.id];
|
|
354
|
-
if (address(extraHook.dataHook) != address(0)) {
|
|
355
|
-
if (extraHook.dataHook.hasMintPermissionFor({projectId: projectId, ruleset: ruleset, addr: addr})) {
|
|
356
|
-
return true;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
return false;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/// @notice Get the tiered 721 hook config for a project and ruleset.
|
|
364
|
-
/// @param projectId The ID of the project to get the 721 hook for.
|
|
365
|
-
/// @param rulesetId The ID of the ruleset to get the 721 hook for.
|
|
366
|
-
/// @return hook The 721 tiers hook.
|
|
367
|
-
/// @return useDataHookForCashOut Whether the 721 hook is used for cash outs.
|
|
368
|
-
function tiered721HookOf(
|
|
369
|
-
uint256 projectId,
|
|
370
|
-
uint256 rulesetId
|
|
371
|
-
)
|
|
372
|
-
external
|
|
373
|
-
view
|
|
374
|
-
override
|
|
375
|
-
returns (IJB721TiersHook hook, bool useDataHookForCashOut)
|
|
376
|
-
{
|
|
377
|
-
JBTiered721HookConfig memory config = _tiered721HookOf[projectId][rulesetId];
|
|
378
|
-
return (config.hook, config.useDataHookForCashOut);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
//*********************************************************************//
|
|
382
|
-
// -------------------------- public views --------------------------- //
|
|
383
|
-
//*********************************************************************//
|
|
384
|
-
|
|
385
|
-
/// @notice Indicates if this contract adheres to the specified interface.
|
|
386
|
-
/// @dev See `IERC165.supportsInterface`.
|
|
387
|
-
/// @return A flag indicating if the provided interface ID is supported.
|
|
388
|
-
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
389
|
-
return interfaceId == type(IJBOmnichainDeployer).interfaceId
|
|
390
|
-
|| interfaceId == type(IJBRulesetDataHook).interfaceId || interfaceId == type(IERC721Receiver).interfaceId
|
|
391
|
-
|| interfaceId == type(IERC165).interfaceId;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
//*********************************************************************//
|
|
395
|
-
// --------------------- external transactions ----------------------- //
|
|
396
|
-
//*********************************************************************//
|
|
397
|
-
|
|
398
|
-
/// @notice Deploy new suckers for an existing project.
|
|
399
|
-
/// @dev Only the juicebox's owner or an operator with `JBPermissionIds.DEPLOY_SUCKERS` can call this entrypoint.
|
|
400
|
-
/// The downstream registry call also maps the configured tokens on each newly created sucker, so the same
|
|
401
|
-
/// end-to-end operation depends on the project's token-mapping authority being arranged for the registry.
|
|
402
|
-
/// @param projectId The ID of the project to deploy suckers for.
|
|
403
|
-
/// @param suckerDeploymentConfiguration The suckers to set up for the project.
|
|
404
|
-
function deploySuckersFor(
|
|
405
|
-
uint256 projectId,
|
|
406
|
-
JBSuckerDeploymentConfig calldata suckerDeploymentConfiguration
|
|
407
|
-
)
|
|
408
|
-
external
|
|
409
|
-
override
|
|
410
|
-
returns (address[] memory suckers)
|
|
411
|
-
{
|
|
412
|
-
// Enforce permissions.
|
|
413
|
-
_requirePermissionFrom({
|
|
414
|
-
account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.DEPLOY_SUCKERS
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
// Deploy the suckers.
|
|
418
|
-
// Note: the salt includes `_msgSender()` for replay protection. Cross-chain deterministic
|
|
419
|
-
// address matching requires using the same sender address on each chain.
|
|
420
|
-
// slither-disable-next-line unused-return
|
|
421
|
-
suckers = SUCKER_REGISTRY.deploySuckersFor({
|
|
422
|
-
projectId: projectId,
|
|
423
|
-
salt: keccak256(abi.encode(suckerDeploymentConfiguration.salt, _msgSender())),
|
|
424
|
-
configurations: suckerDeploymentConfiguration.deployerConfigurations
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/// @notice Creates a project with a 721 tiers hook attached and with suckers.
|
|
429
|
-
/// @param owner The address to set as the owner of the project. The ERC-721 which confers this project's ownership
|
|
430
|
-
/// will be sent to this address.
|
|
431
|
-
/// @param projectUri The project's metadata URI.
|
|
432
|
-
/// @param deploy721Config The 721 hook deployment config (hook config + cash-out flag + salt).
|
|
433
|
-
/// @param rulesetConfigurations The rulesets to queue. Custom data hooks are read from each ruleset's metadata.
|
|
434
|
-
/// @param terminalConfigurations The terminals to set up for the project.
|
|
435
|
-
/// @param memo A memo to pass along to the emitted event.
|
|
436
|
-
/// @param suckerDeploymentConfiguration The suckers to set up for the project. Suckers facilitate cross-chain
|
|
437
|
-
/// token transfers between peer projects on different networks.
|
|
438
|
-
/// @param controller The controller to use for launching the project.
|
|
439
|
-
/// @return projectId The ID of the newly launched project.
|
|
440
|
-
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
441
|
-
/// @return suckers The addresses of the deployed suckers.
|
|
442
|
-
function launchProjectFor(
|
|
443
|
-
address owner,
|
|
444
|
-
string calldata projectUri,
|
|
445
|
-
JBOmnichain721Config calldata deploy721Config,
|
|
446
|
-
JBRulesetConfig[] memory rulesetConfigurations,
|
|
447
|
-
JBTerminalConfig[] calldata terminalConfigurations,
|
|
448
|
-
string calldata memo,
|
|
449
|
-
JBSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
|
|
450
|
-
IJBController controller
|
|
451
|
-
)
|
|
452
|
-
external
|
|
453
|
-
override
|
|
454
|
-
returns (uint256 projectId, IJB721TiersHook hook, address[] memory suckers)
|
|
455
|
-
{
|
|
456
|
-
return _launchProjectFor({
|
|
457
|
-
owner: owner,
|
|
458
|
-
projectUri: projectUri,
|
|
459
|
-
deploy721Config: deploy721Config,
|
|
460
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
461
|
-
terminalConfigurations: terminalConfigurations,
|
|
462
|
-
memo: memo,
|
|
463
|
-
suckerDeploymentConfiguration: suckerDeploymentConfiguration,
|
|
464
|
-
controller: controller
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/// @notice Creates a project with a default (empty-tier) 721 hook and with suckers.
|
|
469
|
-
/// @dev Uses `baseCurrency` from the first ruleset and `decimals = 18` for the default 721 config.
|
|
470
|
-
/// @param owner The address to set as the owner of the project.
|
|
471
|
-
/// @param projectUri The project's metadata URI.
|
|
472
|
-
/// @param rulesetConfigurations The rulesets to queue.
|
|
473
|
-
/// @param terminalConfigurations The terminals to set up for the project.
|
|
474
|
-
/// @param memo A memo to pass along to the emitted event.
|
|
475
|
-
/// @param suckerDeploymentConfiguration The suckers to set up for the project.
|
|
476
|
-
/// @param controller The controller to use for launching the project.
|
|
477
|
-
/// @return projectId The ID of the newly launched project.
|
|
478
|
-
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
479
|
-
/// @return suckers The addresses of the deployed suckers.
|
|
480
|
-
function launchProjectFor(
|
|
481
|
-
address owner,
|
|
482
|
-
string calldata projectUri,
|
|
483
|
-
JBRulesetConfig[] memory rulesetConfigurations,
|
|
484
|
-
JBTerminalConfig[] calldata terminalConfigurations,
|
|
485
|
-
string calldata memo,
|
|
486
|
-
JBSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
|
|
487
|
-
IJBController controller
|
|
488
|
-
)
|
|
489
|
-
external
|
|
490
|
-
override
|
|
491
|
-
returns (uint256 projectId, IJB721TiersHook hook, address[] memory suckers)
|
|
492
|
-
{
|
|
493
|
-
return _launchProjectFor({
|
|
494
|
-
owner: owner,
|
|
495
|
-
projectUri: projectUri,
|
|
496
|
-
deploy721Config: _default721Config(rulesetConfigurations),
|
|
497
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
498
|
-
terminalConfigurations: terminalConfigurations,
|
|
499
|
-
memo: memo,
|
|
500
|
-
suckerDeploymentConfiguration: suckerDeploymentConfiguration,
|
|
501
|
-
controller: controller
|
|
502
|
-
});
|
|
523
|
+
|
|
524
|
+
// Get the custom data hook's weight and specs. Reduce the amount so it only considers funds entering the
|
|
525
|
+
// project, and pass the 721 hook's weight so the data hook sees the split-adjusted weight.
|
|
526
|
+
JBPayHookSpecification[] memory dataHookSpecs;
|
|
527
|
+
bool customHookCalled;
|
|
528
|
+
{
|
|
529
|
+
JBDeployerHookConfig memory extraHook = _extraDataHookOf[context.projectId][context.rulesetId];
|
|
530
|
+
if (address(extraHook.dataHook) != address(0) && extraHook.useDataHookForPay) {
|
|
531
|
+
JBBeforePayRecordedContext memory hookContext = context;
|
|
532
|
+
hookContext.amount.value = projectAmount;
|
|
533
|
+
// Pass the 721 hook's weight (which accounts for split deductions) so the data hook
|
|
534
|
+
// makes its decisions (e.g. mint-vs-swap) based on the correct post-split weight.
|
|
535
|
+
if (has721Hook) hookContext.weight = tiered721Weight;
|
|
536
|
+
(weight, dataHookSpecs) = extraHook.dataHook.beforePayRecordedWith(hookContext);
|
|
537
|
+
customHookCalled = true;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (!customHookCalled) {
|
|
542
|
+
// Use the 721 hook's weight directly (already scaled for splits) or fall back to context weight.
|
|
543
|
+
weight = has721Hook ? tiered721Weight : context.weight;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Merge specifications: 721 hook spec first, then data hook specs.
|
|
547
|
+
bool hasDataHookSpecs = dataHookSpecs.length > 0;
|
|
548
|
+
if (!hasTiered721Spec && !hasDataHookSpecs) return (weight, hookSpecifications);
|
|
549
|
+
|
|
550
|
+
hookSpecifications = new JBPayHookSpecification[]((hasTiered721Spec ? 1 : 0) + dataHookSpecs.length);
|
|
551
|
+
|
|
552
|
+
uint256 specIndex;
|
|
553
|
+
if (hasTiered721Spec) hookSpecifications[specIndex++] = tiered721HookSpec;
|
|
554
|
+
for (uint256 i; i < dataHookSpecs.length; i++) {
|
|
555
|
+
hookSpecifications[specIndex + i] = dataHookSpecs[i];
|
|
556
|
+
}
|
|
503
557
|
}
|
|
504
558
|
|
|
505
|
-
/// @notice
|
|
506
|
-
/// hook.
|
|
507
|
-
/// @param
|
|
508
|
-
/// @
|
|
509
|
-
|
|
510
|
-
/// @param terminalConfigurations The terminals to set up for the project.
|
|
511
|
-
/// @param memo A memo to pass along to the emitted event.
|
|
512
|
-
/// @param controller The controller to use for launching the rulesets.
|
|
513
|
-
/// @return rulesetId The ID of the newly launched rulesets.
|
|
514
|
-
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
515
|
-
function launchRulesetsFor(
|
|
559
|
+
/// @notice Get the extra data hook for a project and ruleset.
|
|
560
|
+
/// @param projectId The ID of the project to get the extra data hook for.
|
|
561
|
+
/// @param rulesetId The ID of the ruleset to get the extra data hook for.
|
|
562
|
+
/// @return hook The extra data hook configured for the project/ruleset.
|
|
563
|
+
function extraDataHookOf(
|
|
516
564
|
uint256 projectId,
|
|
517
|
-
|
|
518
|
-
JBRulesetConfig[] memory rulesetConfigurations,
|
|
519
|
-
JBTerminalConfig[] calldata terminalConfigurations,
|
|
520
|
-
string calldata memo,
|
|
521
|
-
IJBController controller
|
|
565
|
+
uint256 rulesetId
|
|
522
566
|
)
|
|
523
567
|
external
|
|
568
|
+
view
|
|
524
569
|
override
|
|
525
|
-
returns (
|
|
570
|
+
returns (JBDeployerHookConfig memory hook)
|
|
526
571
|
{
|
|
527
|
-
return
|
|
528
|
-
projectId: projectId,
|
|
529
|
-
deploy721Config: deploy721Config,
|
|
530
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
531
|
-
terminalConfigurations: terminalConfigurations,
|
|
532
|
-
memo: memo,
|
|
533
|
-
controller: controller
|
|
534
|
-
});
|
|
572
|
+
return _extraDataHookOf[projectId][rulesetId];
|
|
535
573
|
}
|
|
536
574
|
|
|
537
|
-
/// @notice
|
|
538
|
-
/// @dev
|
|
539
|
-
/// @param projectId The ID of the project
|
|
540
|
-
/// @param
|
|
541
|
-
/// @param
|
|
542
|
-
/// @
|
|
543
|
-
|
|
544
|
-
/// @return rulesetId The ID of the newly launched rulesets.
|
|
545
|
-
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
546
|
-
function launchRulesetsFor(
|
|
575
|
+
/// @notice A flag indicating whether an address has permission to mint a project's tokens on-demand.
|
|
576
|
+
/// @dev A project's data hook can allow any address to mint its tokens.
|
|
577
|
+
/// @param projectId The ID of the project whose token can be minted.
|
|
578
|
+
/// @param ruleset The ruleset to check the token minting permission of.
|
|
579
|
+
/// @param addr The address to check the token minting permission of.
|
|
580
|
+
/// @return flag A flag indicating whether the address has permission to mint the project's tokens on-demand.
|
|
581
|
+
function hasMintPermissionFor(
|
|
547
582
|
uint256 projectId,
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
string calldata memo,
|
|
551
|
-
IJBController controller
|
|
583
|
+
JBRuleset memory ruleset,
|
|
584
|
+
address addr
|
|
552
585
|
)
|
|
553
586
|
external
|
|
587
|
+
view
|
|
554
588
|
override
|
|
555
|
-
returns (
|
|
589
|
+
returns (bool)
|
|
556
590
|
{
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
deploy721Config: _default721Config(rulesetConfigurations),
|
|
560
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
561
|
-
terminalConfigurations: terminalConfigurations,
|
|
562
|
-
memo: memo,
|
|
563
|
-
controller: controller
|
|
564
|
-
});
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
/// @dev Make sure this contract can only receive project NFTs from `JBProjects`.
|
|
568
|
-
function onERC721Received(address, address, uint256, bytes calldata) external view returns (bytes4) {
|
|
569
|
-
// Make sure the 721 received is from the `JBProjects` contract.
|
|
570
|
-
if (msg.sender != address(PROJECTS)) revert JBOmnichainDeployer_UnexpectedNFTReceived();
|
|
591
|
+
// Suckers always get mint permission.
|
|
592
|
+
if (SUCKER_REGISTRY.isSuckerOf({projectId: projectId, addr: addr})) return true;
|
|
571
593
|
|
|
572
|
-
|
|
573
|
-
|
|
594
|
+
// Check the extra data hook (the 721 hook doesn't grant mint permission).
|
|
595
|
+
JBDeployerHookConfig memory extraHook = _extraDataHookOf[projectId][ruleset.id];
|
|
596
|
+
if (address(extraHook.dataHook) != address(0)) {
|
|
597
|
+
if (extraHook.dataHook.hasMintPermissionFor({projectId: projectId, ruleset: ruleset, addr: addr})) {
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
574
601
|
|
|
575
|
-
|
|
576
|
-
/// @dev If `deploy721Config.deployTiersHookConfig.tiersConfig.tiers.length > 0`, a new 721 hook is deployed.
|
|
577
|
-
/// Otherwise, the 721 hook from the latest ruleset is carried forward.
|
|
578
|
-
/// @param projectId The ID of the project to queue the rulesets for.
|
|
579
|
-
/// @param deploy721Config The 721 hook deployment config (hook config + cash-out flag + salt).
|
|
580
|
-
/// @param rulesetConfigurations The rulesets to queue. Custom data hooks are read from each ruleset's metadata.
|
|
581
|
-
/// @param memo A memo to pass along to the emitted event.
|
|
582
|
-
/// @param controller The controller to use for queuing the rulesets.
|
|
583
|
-
/// @return rulesetId The ID of the newly queued rulesets.
|
|
584
|
-
/// @return hook The 721 tiers hook (newly deployed or carried forward from the previous ruleset).
|
|
585
|
-
function queueRulesetsOf(
|
|
586
|
-
uint256 projectId,
|
|
587
|
-
JBOmnichain721Config memory deploy721Config,
|
|
588
|
-
JBRulesetConfig[] memory rulesetConfigurations,
|
|
589
|
-
string calldata memo,
|
|
590
|
-
IJBController controller
|
|
591
|
-
)
|
|
592
|
-
external
|
|
593
|
-
override
|
|
594
|
-
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
595
|
-
{
|
|
596
|
-
return _queueRulesetsOf({
|
|
597
|
-
projectId: projectId,
|
|
598
|
-
deploy721Config: deploy721Config,
|
|
599
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
600
|
-
memo: memo,
|
|
601
|
-
controller: controller
|
|
602
|
-
});
|
|
602
|
+
return false;
|
|
603
603
|
}
|
|
604
604
|
|
|
605
|
-
/// @notice
|
|
606
|
-
/// hook.
|
|
607
|
-
/// @
|
|
608
|
-
///
|
|
609
|
-
/// @
|
|
610
|
-
|
|
611
|
-
/// @param memo A memo to pass along to the emitted event.
|
|
612
|
-
/// @param controller The controller to use for queuing the rulesets.
|
|
613
|
-
/// @return rulesetId The ID of the newly queued rulesets.
|
|
614
|
-
/// @return hook The 721 tiers hook carried forward from the previous ruleset.
|
|
615
|
-
function queueRulesetsOf(
|
|
605
|
+
/// @notice Get the tiered 721 hook config for a project and ruleset.
|
|
606
|
+
/// @param projectId The ID of the project to get the 721 hook for.
|
|
607
|
+
/// @param rulesetId The ID of the ruleset to get the 721 hook for.
|
|
608
|
+
/// @return hook The 721 tiers hook.
|
|
609
|
+
/// @return useDataHookForCashOut Whether the 721 hook is used for cash outs.
|
|
610
|
+
function tiered721HookOf(
|
|
616
611
|
uint256 projectId,
|
|
617
|
-
|
|
618
|
-
string calldata memo,
|
|
619
|
-
IJBController controller
|
|
612
|
+
uint256 rulesetId
|
|
620
613
|
)
|
|
621
614
|
external
|
|
615
|
+
view
|
|
622
616
|
override
|
|
623
|
-
returns (
|
|
617
|
+
returns (IJB721TiersHook hook, bool useDataHookForCashOut)
|
|
624
618
|
{
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
deploy721Config: _default721Config(rulesetConfigurations),
|
|
628
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
629
|
-
memo: memo,
|
|
630
|
-
controller: controller
|
|
631
|
-
});
|
|
619
|
+
JBTiered721HookConfig memory config = _tiered721HookOf[projectId][rulesetId];
|
|
620
|
+
return (config.hook, config.useDataHookForCashOut);
|
|
632
621
|
}
|
|
633
622
|
|
|
634
623
|
//*********************************************************************//
|
|
635
|
-
// --------------------------
|
|
636
|
-
//*********************************************************************//
|
|
637
|
-
|
|
638
|
-
//*********************************************************************//
|
|
639
|
-
// ------------------------ internal functions ----------------------- //
|
|
624
|
+
// -------------------------- public views --------------------------- //
|
|
640
625
|
//*********************************************************************//
|
|
641
626
|
|
|
642
|
-
/// @
|
|
643
|
-
|
|
644
|
-
|
|
627
|
+
/// @notice Indicates if this contract adheres to the specified interface.
|
|
628
|
+
/// @dev See `IERC165.supportsInterface`.
|
|
629
|
+
/// @return A flag indicating if the provided interface ID is supported.
|
|
630
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
631
|
+
return interfaceId == type(IJBOmnichainDeployer).interfaceId
|
|
632
|
+
|| interfaceId == type(IJBRulesetDataHook).interfaceId || interfaceId == type(IERC721Receiver).interfaceId
|
|
633
|
+
|| interfaceId == type(IERC165).interfaceId;
|
|
645
634
|
}
|
|
646
635
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
/// @return config The default 721 config.
|
|
651
|
-
function _default721Config(JBRulesetConfig[] memory rulesetConfigurations)
|
|
652
|
-
internal
|
|
653
|
-
pure
|
|
654
|
-
returns (JBOmnichain721Config memory config)
|
|
655
|
-
{
|
|
656
|
-
if (rulesetConfigurations.length == 0) revert JBOmnichainDeployer_NoRulesetConfigurations();
|
|
657
|
-
config.deployTiersHookConfig.tiersConfig.currency = rulesetConfigurations[0].metadata.baseCurrency;
|
|
658
|
-
config.deployTiersHookConfig.tiersConfig.decimals = 18;
|
|
659
|
-
}
|
|
636
|
+
//*********************************************************************//
|
|
637
|
+
// ---------------------- internal transactions ---------------------- //
|
|
638
|
+
//*********************************************************************//
|
|
660
639
|
|
|
661
640
|
/// @notice Deploys a 721 tiers hook for a project.
|
|
662
641
|
/// @dev The caller is responsible for transferring ownership to the project via
|
|
@@ -782,18 +761,6 @@ contract JBOmnichainDeployer is
|
|
|
782
761
|
});
|
|
783
762
|
}
|
|
784
763
|
|
|
785
|
-
/// @notice The calldata. Preferred to use over `msg.data`.
|
|
786
|
-
/// @return calldata The `msg.data` of this call.
|
|
787
|
-
function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
|
|
788
|
-
return ERC2771Context._msgData();
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
/// @notice The message's sender. Preferred to use over `msg.sender`.
|
|
792
|
-
/// @return sender The address which sent this call.
|
|
793
|
-
function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
|
|
794
|
-
return ERC2771Context._msgSender();
|
|
795
|
-
}
|
|
796
|
-
|
|
797
764
|
/// @notice Internal implementation of `queueRulesetsOf`.
|
|
798
765
|
function _queueRulesetsOf(
|
|
799
766
|
uint256 projectId,
|
|
@@ -914,6 +881,41 @@ contract JBOmnichainDeployer is
|
|
|
914
881
|
return rulesetConfigurations;
|
|
915
882
|
}
|
|
916
883
|
|
|
884
|
+
//*********************************************************************//
|
|
885
|
+
// ----------------------- internal views ---------------------------- //
|
|
886
|
+
//*********************************************************************//
|
|
887
|
+
|
|
888
|
+
/// @dev ERC-2771 specifies the context as being a single address (20 bytes).
|
|
889
|
+
function _contextSuffixLength() internal view virtual override(ERC2771Context, Context) returns (uint256) {
|
|
890
|
+
return ERC2771Context._contextSuffixLength();
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/// @notice Returns a default `JBOmnichain721Config` with `currency` from the first ruleset's `baseCurrency`,
|
|
894
|
+
/// `decimals = 18`, empty tiers, no cash-out handling, and no salt.
|
|
895
|
+
/// @param rulesetConfigurations The ruleset configurations to derive defaults from.
|
|
896
|
+
/// @return config The default 721 config.
|
|
897
|
+
function _default721Config(JBRulesetConfig[] memory rulesetConfigurations)
|
|
898
|
+
internal
|
|
899
|
+
pure
|
|
900
|
+
returns (JBOmnichain721Config memory config)
|
|
901
|
+
{
|
|
902
|
+
if (rulesetConfigurations.length == 0) revert JBOmnichainDeployer_NoRulesetConfigurations();
|
|
903
|
+
config.deployTiersHookConfig.tiersConfig.currency = rulesetConfigurations[0].metadata.baseCurrency;
|
|
904
|
+
config.deployTiersHookConfig.tiersConfig.decimals = 18;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/// @notice The calldata. Preferred to use over `msg.data`.
|
|
908
|
+
/// @return calldata The `msg.data` of this call.
|
|
909
|
+
function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
|
|
910
|
+
return ERC2771Context._msgData();
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/// @notice The message's sender. Preferred to use over `msg.sender`.
|
|
914
|
+
/// @return sender The address which sent this call.
|
|
915
|
+
function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
|
|
916
|
+
return ERC2771Context._msgSender();
|
|
917
|
+
}
|
|
918
|
+
|
|
917
919
|
/// @notice Validates that the provided controller matches the project's controller in the directory.
|
|
918
920
|
/// @dev The reflexive lookup (controller.DIRECTORY().controllerOf()) is intentional — it confirms the
|
|
919
921
|
/// caller-provided controller is the one the directory recognizes for this project, preventing a
|