@bananapus/suckers-v6 0.0.32 → 0.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/suckers-v6",
3
- "version": "0.0.32",
3
+ "version": "0.0.34",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -4,6 +4,7 @@ pragma solidity 0.8.28;
4
4
  import {IInbox} from "@arbitrum/nitro-contracts/src/bridge/IInbox.sol";
5
5
  import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
6
6
  import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
7
+ import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
7
8
  import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
8
9
  import {CoreDeployment, CoreDeploymentLib} from "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
9
10
  import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
@@ -224,7 +225,7 @@ contract DeployScript is Script, Sphinx {
224
225
  deployer: _opDeployer,
225
226
  directory: core.directory,
226
227
  permissions: core.permissions,
227
- prices: address(core.prices),
228
+ prices: core.prices,
228
229
  tokens: core.tokens,
229
230
  feeProjectId: 1,
230
231
  registry: REGISTRY,
@@ -276,7 +277,7 @@ contract DeployScript is Script, Sphinx {
276
277
  deployer: _opDeployer,
277
278
  directory: core.directory,
278
279
  permissions: core.permissions,
279
- prices: address(core.prices),
280
+ prices: core.prices,
280
281
  tokens: core.tokens,
281
282
  feeProjectId: 1,
282
283
  registry: REGISTRY,
@@ -359,7 +360,7 @@ contract DeployScript is Script, Sphinx {
359
360
  deployer: _baseDeployer,
360
361
  directory: core.directory,
361
362
  permissions: core.permissions,
362
- prices: address(core.prices),
363
+ prices: core.prices,
363
364
  tokens: core.tokens,
364
365
  feeProjectId: 1,
365
366
  registry: REGISTRY,
@@ -411,7 +412,7 @@ contract DeployScript is Script, Sphinx {
411
412
  deployer: _baseDeployer,
412
413
  directory: core.directory,
413
414
  permissions: core.permissions,
414
- prices: address(core.prices),
415
+ prices: core.prices,
415
416
  tokens: core.tokens,
416
417
  feeProjectId: 1,
417
418
  registry: REGISTRY,
@@ -490,7 +491,7 @@ contract DeployScript is Script, Sphinx {
490
491
  deployer: _arbDeployer,
491
492
  directory: core.directory,
492
493
  permissions: core.permissions,
493
- prices: address(core.prices),
494
+ prices: core.prices,
494
495
  tokens: core.tokens,
495
496
  feeProjectId: 1,
496
497
  registry: REGISTRY,
@@ -545,7 +546,7 @@ contract DeployScript is Script, Sphinx {
545
546
  deployer: _arbDeployer,
546
547
  directory: core.directory,
547
548
  permissions: core.permissions,
548
- prices: address(core.prices),
549
+ prices: core.prices,
549
550
  tokens: core.tokens,
550
551
  feeProjectId: 1,
551
552
  registry: REGISTRY,
@@ -721,7 +722,7 @@ contract DeployScript is Script, Sphinx {
721
722
  salt: salt,
722
723
  directory: core.directory,
723
724
  permissions: core.permissions,
724
- prices: address(core.prices),
725
+ prices: core.prices,
725
726
  tokens: core.tokens,
726
727
  configurator: safeAddress(),
727
728
  trustedForwarder: TRUSTED_FORWARDER,
@@ -738,7 +739,7 @@ contract DeployScript is Script, Sphinx {
738
739
  bytes32 salt,
739
740
  IJBDirectory directory,
740
741
  IJBPermissions permissions,
741
- address prices,
742
+ IJBPrices prices,
742
743
  IJBTokens tokens,
743
744
  address configurator,
744
745
  address trustedForwarder,
@@ -8,6 +8,7 @@ import {AddressAliasHelper} from "@arbitrum/nitro-contracts/src/libraries/Addres
8
8
  import {ArbSys} from "@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol";
9
9
  import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
10
10
  import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
11
+ import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
11
12
  import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
12
13
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
13
14
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
@@ -26,7 +27,9 @@ import {ARBChains} from "./libraries/ARBChains.sol";
26
27
  import {JBMessageRoot} from "./structs/JBMessageRoot.sol";
27
28
  import {JBRemoteToken} from "./structs/JBRemoteToken.sol";
28
29
 
29
- /// @notice A `JBSucker` implementation to suck tokens between two chains connected by an Arbitrum bridge.
30
+ /// @notice A `JBSucker` implementation that bridges Juicebox project tokens and terminal-token funds between Ethereum
31
+ /// L1 and Arbitrum L2 using the native Arbitrum Inbox/Outbox (for messages) and Gateway Router (for ERC-20 transfers).
32
+ /// Deploys on both layers — L1 instances create retryable tickets, L2 instances call `ArbSys` for L2-to-L1 messages.
30
33
  contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
31
34
  //*********************************************************************//
32
35
  // --------------------------- custom errors ------------------------- //
@@ -59,7 +62,7 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
59
62
  JBArbitrumSuckerDeployer deployer,
60
63
  IJBDirectory directory,
61
64
  IJBPermissions permissions,
62
- address prices,
65
+ IJBPrices prices,
63
66
  IJBTokens tokens,
64
67
  uint256 feeProjectId,
65
68
  IJBSuckerRegistry registry,
@@ -3,6 +3,7 @@ pragma solidity 0.8.28;
3
3
 
4
4
  import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
5
5
  import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
6
+ import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
6
7
  import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
7
8
 
8
9
  import {JBOptimismSucker} from "./JBOptimismSucker.sol";
@@ -24,7 +25,7 @@ contract JBBaseSucker is JBOptimismSucker {
24
25
  JBOptimismSuckerDeployer deployer,
25
26
  IJBDirectory directory,
26
27
  IJBPermissions permissions,
27
- address prices,
28
+ IJBPrices prices,
28
29
  IJBTokens tokens,
29
30
  uint256 feeProjectId,
30
31
  IJBSuckerRegistry registry,
@@ -4,6 +4,7 @@ pragma solidity 0.8.28;
4
4
  // External packages (alphabetized)
5
5
  import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
6
6
  import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
7
+ import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
7
8
  import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
8
9
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
9
10
  import {IAny2EVMMessageReceiver} from "@chainlink/contracts-ccip/contracts/interfaces/IAny2EVMMessageReceiver.sol";
@@ -28,7 +29,9 @@ import {JBMessageRoot} from "./structs/JBMessageRoot.sol";
28
29
  import {JBRemoteToken} from "./structs/JBRemoteToken.sol";
29
30
  import {JBTokenMapping} from "./structs/JBTokenMapping.sol";
30
31
 
31
- /// @notice A `JBSucker` implementation to suck tokens between chains with Chainlink CCIP
32
+ /// @notice A `JBSucker` implementation that bridges Juicebox project tokens and terminal-token funds across any pair of
33
+ /// chains supported by Chainlink CCIP. Messages and token transfers are bundled into a single CCIP lane message, with
34
+ /// the CCIP Router handling cross-chain delivery and fee estimation.
32
35
  contract JBCCIPSucker is JBSucker, IAny2EVMMessageReceiver {
33
36
  //*********************************************************************//
34
37
  // --------------------------- custom errors ------------------------- //
@@ -84,7 +87,7 @@ contract JBCCIPSucker is JBSucker, IAny2EVMMessageReceiver {
84
87
  JBCCIPSuckerDeployer deployer,
85
88
  IJBDirectory directory,
86
89
  IJBPermissions permissions,
87
- address prices,
90
+ IJBPrices prices,
88
91
  IJBTokens tokens,
89
92
  uint256 feeProjectId,
90
93
  IJBSuckerRegistry registry,
@@ -3,6 +3,7 @@ pragma solidity 0.8.28;
3
3
 
4
4
  import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
5
5
  import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
6
+ import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
6
7
  import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
7
8
  import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
8
9
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
@@ -43,7 +44,7 @@ contract JBCeloSucker is JBOptimismSucker {
43
44
  JBCeloSuckerDeployer deployer,
44
45
  IJBDirectory directory,
45
46
  IJBPermissions permissions,
46
- address prices,
47
+ IJBPrices prices,
47
48
  IJBTokens tokens,
48
49
  uint256 feeProjectId,
49
50
  IJBSuckerRegistry registry,
@@ -3,6 +3,7 @@ pragma solidity 0.8.28;
3
3
 
4
4
  import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
5
5
  import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
6
+ import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
6
7
  import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
7
8
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
8
9
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
@@ -17,7 +18,9 @@ import {IOPStandardBridge} from "./interfaces/IOPStandardBridge.sol";
17
18
  import {JBMessageRoot} from "./structs/JBMessageRoot.sol";
18
19
  import {JBRemoteToken} from "./structs/JBRemoteToken.sol";
19
20
 
20
- /// @notice A `JBSucker` implementation to suck tokens between two chains connected by an OP Bridge.
21
+ /// @notice A `JBSucker` implementation that bridges Juicebox project tokens and terminal-token funds between two
22
+ /// chains connected by an OP Stack bridge (Optimism, Base, etc.). Uses the `CrossDomainMessenger` for merkle-root
23
+ /// messages and the `StandardBridge` for ERC-20/native token transfers.
21
24
  contract JBOptimismSucker is JBSucker, IJBOptimismSucker {
22
25
  //*********************************************************************//
23
26
  // --------------- public immutable stored properties ---------------- //
@@ -42,7 +45,7 @@ contract JBOptimismSucker is JBSucker, IJBOptimismSucker {
42
45
  JBOptimismSuckerDeployer deployer,
43
46
  IJBDirectory directory,
44
47
  IJBPermissions permissions,
45
- address prices,
48
+ IJBPrices prices,
46
49
  IJBTokens tokens,
47
50
  uint256 feeProjectId,
48
51
  IJBSuckerRegistry registry,
package/src/JBSucker.sol CHANGED
@@ -43,17 +43,19 @@ import {JBOutboxTree} from "./structs/JBOutboxTree.sol";
43
43
  import {JBRemoteToken} from "./structs/JBRemoteToken.sol";
44
44
  import {JBTokenMapping} from "./structs/JBTokenMapping.sol";
45
45
 
46
- /// @notice An abstract contract for bridging a Juicebox project's tokens and the corresponding funds to and from a
47
- /// remote chain.
48
- /// @dev Beneficiaries and balances are tracked on two merkle trees: the outbox tree is used to send from the local
49
- /// chain to the remote chain, and the inbox tree is used to receive from the remote chain to the local chain.
46
+ /// @notice Bridges a Juicebox project's tokens and their backing terminal-token funds between two chains. Token
47
+ /// holders call `prepare` to cash out their project tokens and queue the resulting funds+tokens into an outbox merkle
48
+ /// tree. Anyone can then call `toRemote` to send that tree's root (and the locked funds) across the bridge to the
49
+ /// peer sucker on the remote chain. Once the root arrives, beneficiaries call `claim` with a merkle proof to mint
50
+ /// project tokens and deposit the corresponding terminal tokens into the remote project's balance.
51
+ ///
52
+ /// @dev Dual merkle trees: the **outbox** accumulates leaves for tokens leaving the local chain; the **inbox** stores
53
+ /// the root received from the remote chain so claims can be verified locally.
50
54
  /// @dev Throughout this contract, "terminal token" refers to any token accepted by a project's terminal.
51
- /// @dev This contract does *NOT* support tokens that have a fee on regular transfers and rebasing tokens.
52
- /// @dev Cross-chain message authentication is delegated entirely to each bridge-specific subclass via the
53
- /// `_isRemotePeer` virtual function. Each implementation authenticates differently: Optimism uses its native
54
- /// `CrossDomainMessenger`, Arbitrum validates against the `Bridge` and `Outbox` contracts, and CCIP verifies
55
- /// through the Chainlink `Router`. Deployers of new bridge integrations must implement `_isRemotePeer` to
56
- /// guarantee that only messages from the legitimate remote peer are accepted.
55
+ /// @dev This contract does *NOT* support fee-on-transfer or rebasing tokens.
56
+ /// @dev Cross-chain message authentication is delegated to each bridge-specific subclass via `_isRemotePeer`.
57
+ /// Optimism uses `CrossDomainMessenger`, Arbitrum validates against `Bridge`/`Outbox`, and CCIP verifies through
58
+ /// Chainlink's `Router`.
57
59
  abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC165, IJBSuckerExtended {
58
60
  using BitMaps for BitMaps.BitMap;
59
61
  using MerkleLib for MerkleLib.Tree;
@@ -223,7 +225,7 @@ abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC
223
225
  constructor(
224
226
  IJBDirectory directory,
225
227
  IJBPermissions permissions,
226
- address prices,
228
+ IJBPrices prices,
227
229
  IJBTokens tokens,
228
230
  uint256 feeProjectId,
229
231
  IJBSuckerRegistry registry,
@@ -234,7 +236,7 @@ abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC
234
236
  {
235
237
  DIRECTORY = directory;
236
238
  FEE_PROJECT_ID = feeProjectId;
237
- PRICES = IJBPrices(prices);
239
+ PRICES = prices;
238
240
  PROJECTS = directory.PROJECTS();
239
241
  REGISTRY = registry;
240
242
  TOKENS = tokens;
@@ -265,7 +267,8 @@ abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC
265
267
  // --------------------- external transactions ----------------------- //
266
268
  //*********************************************************************//
267
269
 
268
- /// @notice Performs multiple claims.
270
+ /// @notice Claim multiple bridged entries in a single transaction. Each claim mints project tokens for the
271
+ /// beneficiary and deposits the corresponding terminal tokens into the project's local balance.
269
272
  /// @param claims A list of claims to perform (including the terminal token, merkle tree leaf, and proof for each
270
273
  /// claim).
271
274
  function claim(JBClaim[] calldata claims) external override {
@@ -278,7 +281,8 @@ abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC
278
281
  }
279
282
  }
280
283
 
281
- /// @notice `JBClaim` project tokens which have been bridged from the remote chain for their beneficiary.
284
+ /// @notice Claim a single bridged entry: verifies the merkle proof against the inbox root, mints the specified
285
+ /// project tokens for the beneficiary, and deposits the terminal tokens into the project's local balance.
282
286
  /// @param claimData The terminal token, merkle tree leaf, and proof for the claim.
283
287
  function claim(JBClaim calldata claimData) public virtual override {
284
288
  // Attempt to validate the proof against the inbox tree for the terminal token.
@@ -334,8 +338,10 @@ abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC
334
338
  emit EmergencyHatchOpened({tokens: tokens, caller: _msgSender()});
335
339
  }
336
340
 
337
- /// @notice Lets user exit on the chain they deposited in a scenario where the bridge is no longer functional.
338
- /// @param claimData The terminal token, merkle tree leaf, and proof for the claim
341
+ /// @notice Emergency escape hatch: lets a user reclaim their project tokens and terminal tokens on the chain they
342
+ /// originally deposited from, when the bridge has become permanently non-functional. Must be enabled by the project
343
+ /// owner via the registry's `setEmergencyHatchStatusOf`.
344
+ /// @param claimData The terminal token, merkle tree leaf, and proof for the claim.
339
345
  function exitThroughEmergencyHatch(JBClaim calldata claimData) external override {
340
346
  // Does all the needed validation to ensure that the claim is valid *and* that claiming through the emergency
341
347
  // hatch is allowed.
@@ -368,7 +374,8 @@ abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC
368
374
  });
369
375
  }
370
376
 
371
- /// @notice Receive a merkle root for a terminal token from the remote project.
377
+ /// @notice Receive a merkle root and peer-chain accounting snapshot from the remote sucker. Updates the inbox tree
378
+ /// so that users can claim bridged tokens. Also accepts any native-token funds delivered with the message.
372
379
  /// @dev This can only be called by the messenger contract on the local chain, with a message from the remote peer.
373
380
  /// @dev Nonce ordering: This function accepts any nonce strictly greater than the current inbox nonce, rather than
374
381
  /// requiring sequential (nonce == inbox.nonce + 1) processing. This is intentional because some bridges (e.g.,
@@ -448,8 +455,10 @@ abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC
448
455
  }
449
456
  }
450
457
 
451
- /// @notice Map multiple ERC-20 tokens on the local chain to ERC-20 tokens on the remote chain, allowing those
452
- /// tokens to be bridged.
458
+ /// @notice Configure which remote-chain tokens each local terminal token maps to, enabling (or disabling) those
459
+ /// tokens for cross-chain bridging. Setting a remote token to `bytes32(0)` disables bridging and flushes any
460
+ /// pending outbox entries. Requires `MAP_SUCKER_TOKEN` permission from the project owner (or called by the
461
+ /// registry during deployment).
453
462
  /// @param maps A list of local and remote terminal token addresses to map, and minimum amount/gas limits for
454
463
  /// bridging them.
455
464
  function mapTokens(JBTokenMapping[] calldata maps) external payable override {
@@ -495,7 +504,9 @@ abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC
495
504
  }
496
505
  }
497
506
 
498
- /// @notice Prepare project tokens and the cash out amount backing them to be bridged to the remote chain.
507
+ /// @notice Queue project tokens for bridging to the remote chain. Transfers the caller's project tokens into this
508
+ /// contract, cashes them out for the specified terminal token, and inserts a leaf into the outbox merkle tree. The
509
+ /// queued entry will be bridged the next time anyone calls `toRemote` for the same `token`.
499
510
  /// @dev This adds the tokens and funds to the outbox tree for the `token`. They will be bridged by the next call to
500
511
  /// `toRemote` for the same `token`.
501
512
  /// @dev Reentrancy protection: This function has implicit reentrancy protection through `_pullBackingAssets`.
@@ -562,8 +573,9 @@ abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC
562
573
  });
563
574
  }
564
575
 
565
- /// @notice Set or remove the time after which this sucker will be deprecated, once deprecated the sucker will no
566
- /// longer be functional and it will let all users exit.
576
+ /// @notice Schedule (or cancel) the deprecation of this sucker. Once deprecated, no new outbound transfers are
577
+ /// accepted and users can exit via the emergency hatch. Requires `SET_SUCKER_DEPRECATION` permission. A mandatory
578
+ /// 14-day buffer ensures in-flight messages have time to arrive before the sucker fully shuts down.
567
579
  /// @param timestamp The time after which the sucker will be deprecated. Or `0` to remove the upcoming deprecation.
568
580
  function setDeprecation(uint40 timestamp) external override {
569
581
  // As long as the sucker has not started letting users withdrawal, its deprecation time can be
@@ -599,9 +611,9 @@ abstract contract JBSucker is ERC2771Context, JBPermissioned, Initializable, ERC
599
611
  emit DeprecationTimeUpdated({timestamp: timestamp, caller: _msgSender()});
600
612
  }
601
613
 
602
- /// @notice Bridge the project tokens, cashed out funds, and beneficiary information for a given `token` to the
603
- /// remote
604
- /// chain.
614
+ /// @notice Send the accumulated outbox merkle root and locked terminal-token funds for a given `token` across the
615
+ /// bridge to the remote peer sucker. Anyone can call this once entries exist in the outbox. Requires `msg.value`
616
+ /// to cover the registry's `toRemoteFee` plus any bridge transport payment.
605
617
  /// @dev This sends the outbox root for the specified `token` to the remote chain.
606
618
  /// @dev Fee payment failure handling: The registry fee payment uses a best-effort pattern (try/catch). If the
607
619
  /// fee project's terminal doesn't exist or the `pay` call reverts, the fee ETH is retained as a refundable balance
@@ -19,7 +19,10 @@ import {IJBSuckerRegistry} from "./interfaces/IJBSuckerRegistry.sol";
19
19
  import {JBSuckerDeployerConfig} from "./structs/JBSuckerDeployerConfig.sol";
20
20
  import {JBSuckersPair} from "./structs/JBSuckersPair.sol";
21
21
 
22
- /// @notice A registry for deploying and tracking suckers across projects.
22
+ /// @notice The canonical registry that deploys, tracks, and governs cross-chain suckers for Juicebox projects. It
23
+ /// maintains an allowlist of approved deployer contracts, enforces one active sucker per peer chain per project,
24
+ /// manages the global `toRemoteFee` (paid into the protocol fee project on each bridge send), and provides aggregate
25
+ /// views of remote-chain balances, surplus, and token supply across all of a project's suckers.
23
26
  contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerRegistry {
24
27
  using EnumerableMap for EnumerableMap.AddressToUintMap;
25
28
 
@@ -55,7 +58,7 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
55
58
  // --------------- public immutable stored properties ---------------- //
56
59
  //*********************************************************************//
57
60
 
58
- /// @notice The juicebox directory.
61
+ /// @notice The Juicebox directory used to look up project terminals and controllers.
59
62
  IJBDirectory public immutable override DIRECTORY;
60
63
 
61
64
  /// @notice A contract which mints ERC-721s that represent project ownership and transfers.
@@ -105,8 +108,8 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
105
108
  // ------------------------- external views -------------------------- //
106
109
  //*********************************************************************//
107
110
 
108
- /// @notice Returns true if the specified sucker belongs to the specified project, and was deployed through this
109
- /// registry.
111
+ /// @notice Whether the given address is a sucker (active or deprecated) that was deployed through this registry for
112
+ /// the specified project. Used by controllers to authorize mint calls from suckers.
110
113
  /// @param projectId The ID of the project to check for.
111
114
  /// @param addr The address of the sucker to check.
112
115
  /// @return flag A flag indicating if the sucker belongs to the project, and was deployed through this registry.
@@ -115,7 +118,7 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
115
118
  return exists && (val == _SUCKER_EXISTS || val == _SUCKER_DEPRECATED);
116
119
  }
117
120
 
118
- /// @notice Helper function for retrieving the projects suckers and their metadata.
121
+ /// @notice All active (non-deprecated) suckers for a project, with their remote peer address and chain ID.
119
122
  /// @param projectId The ID of the project to get the suckers of.
120
123
  /// @return pairs The pairs of suckers and their metadata.
121
124
  function suckerPairsOf(uint256 projectId) external view override returns (JBSuckersPair[] memory pairs) {
@@ -498,10 +501,10 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
498
501
  }
499
502
  }
500
503
 
501
- /// @notice Deploy one or more suckers for the specified project.
502
- /// @dev The caller must be the project's owner or have `JBPermissionIds.DEPLOY_SUCKERS` from the project's owner.
503
- /// Each newly created sucker is immediately configured by calling `mapTokens`, so successful execution also
504
- /// depends on this registry being authorized to perform `MAP_SUCKER_TOKEN` for the project.
504
+ /// @notice Deploy one or more cross-chain suckers for a project in a single transaction. Each sucker is created via
505
+ /// its deployer, registered in this registry, checked for duplicate peer chains, and immediately configured with
506
+ /// its token mappings. The caller must have `DEPLOY_SUCKERS` permission, and this registry must hold
507
+ /// `MAP_SUCKER_TOKEN` permission for the project.
505
508
  /// @param projectId The ID of the project to deploy suckers for.
506
509
  /// @param salt The salt used to deploy the contract. For the suckers to be peers, this must be the same value on
507
510
  /// each chain where suckers are deployed.
@@ -4,6 +4,7 @@ pragma solidity 0.8.28;
4
4
  // Core JB imports.
5
5
  import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
6
6
  import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
7
+ import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
7
8
  import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
8
9
  // CCIP imports.
9
10
  import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol";
@@ -209,7 +210,7 @@ contract JBSwapCCIPSucker is JBCCIPSucker, IUnlockCallback, IUniswapV3SwapCallba
209
210
  JBSwapCCIPSuckerDeployer deployer,
210
211
  IJBDirectory directory,
211
212
  IJBPermissions permissions,
212
- address prices,
213
+ IJBPrices prices,
213
214
  IJBTokens tokens,
214
215
  uint256 feeProjectId,
215
216
  IJBSuckerRegistry registry,
@@ -17,7 +17,8 @@ import {IJBArbitrumSuckerDeployer} from "../interfaces/IJBArbitrumSuckerDeployer
17
17
  // Local: deployers.
18
18
  import {JBSuckerDeployer} from "./JBSuckerDeployer.sol";
19
19
 
20
- /// @notice An `IJBSuckerDeployer` implementation to deploy `JBArbitrumSucker` contracts.
20
+ /// @notice Deployer for Arbitrum suckers. Stores the Inbox and Gateway Router for the target layer (L1 or L2) and
21
+ /// clones `JBArbitrumSucker` instances via CREATE2.
21
22
  contract JBArbitrumSuckerDeployer is JBSuckerDeployer, IJBArbitrumSuckerDeployer {
22
23
  //*********************************************************************//
23
24
  // ---------------------- public stored properties ------------------- //
@@ -13,7 +13,8 @@ import {IJBCCIPSuckerDeployer} from "../interfaces/IJBCCIPSuckerDeployer.sol";
13
13
  // Local: deployers.
14
14
  import {JBSuckerDeployer} from "./JBSuckerDeployer.sol";
15
15
 
16
- /// @notice An `IJBSuckerDeployer` implementation to deploy `JBCCIPSucker` contracts.
16
+ /// @notice Deployer for Chainlink CCIP suckers. Stores the CCIP router, remote chain ID, and remote chain selector,
17
+ /// then clones `JBCCIPSucker` instances via CREATE2.
17
18
  contract JBCCIPSuckerDeployer is JBSuckerDeployer, IJBCCIPSuckerDeployer {
18
19
  //*********************************************************************//
19
20
  // ---------------------- public stored properties ------------------- //
@@ -14,7 +14,8 @@ import {IOPStandardBridge} from "../interfaces/IOPStandardBridge.sol";
14
14
  // Local: deployers.
15
15
  import {JBSuckerDeployer} from "./JBSuckerDeployer.sol";
16
16
 
17
- /// @notice An `IJBSuckerDeployer` implementation to deploy `JBOptimismSucker` contracts.
17
+ /// @notice Deployer for OP Stack suckers (Optimism, Base, etc.). Stores the CrossDomainMessenger and StandardBridge
18
+ /// for this chain and clones `JBOptimismSucker` instances via CREATE2.
18
19
  contract JBOptimismSuckerDeployer is JBSuckerDeployer, IJBOpSuckerDeployer {
19
20
  //*********************************************************************//
20
21
  // ---------------------- public stored properties ------------------- //
@@ -17,7 +17,10 @@ import {JBSucker} from "../JBSucker.sol";
17
17
  import {IJBSucker} from "../interfaces/IJBSucker.sol";
18
18
  import {IJBSuckerDeployer} from "../interfaces/IJBSuckerDeployer.sol";
19
19
 
20
- /// @notice A base implementation for deploying suckers.
20
+ /// @notice Base factory for deploying cross-chain suckers using CREATE2 clones. Each bridge-specific deployer (OP,
21
+ /// Arbitrum, CCIP) extends this contract with its own chain configuration. Setup is two-step: first the configurator
22
+ /// calls `setChainSpecificConstants` (bridge addresses, chain selectors), then `configureSingleton` (the
23
+ /// implementation to clone). After setup, anyone may call `createForSender` to deploy a new sucker for a project.
21
24
  abstract contract JBSuckerDeployer is ERC2771Context, JBPermissioned, IJBSuckerDeployer {
22
25
  //*********************************************************************//
23
26
  // --------------------------- custom errors ------------------------- //
@@ -47,7 +50,7 @@ abstract contract JBSuckerDeployer is ERC2771Context, JBPermissioned, IJBSuckerD
47
50
  // ---------------------- public stored properties ------------------- //
48
51
  //*********************************************************************//
49
52
 
50
- /// @notice A mapping of suckers deployed by this contract.
53
+ /// @notice Whether a given address was deployed by this deployer.
51
54
  mapping(address => bool) public override isSucker;
52
55
 
53
56
  /// @notice The singleton used to clone suckers.
@@ -117,8 +120,8 @@ abstract contract JBSuckerDeployer is ERC2771Context, JBPermissioned, IJBSuckerD
117
120
  // --------------------- external transactions ----------------------- //
118
121
  //*********************************************************************//
119
122
 
120
- /// @notice Configure the singleton instance that is used to clone suckers.
121
- /// @dev Can only be called *once* by the layer specific configurator.
123
+ /// @notice Set the implementation contract that all future suckers will be cloned from. Can only be called once.
124
+ /// @dev Must be called by the layer-specific configurator after `setChainSpecificConstants`.
122
125
  /// @param _singleton The address of the singleton.
123
126
  function configureSingleton(JBSucker _singleton) external {
124
127
  // Make sure only the configurator can call this function.
@@ -138,8 +141,9 @@ abstract contract JBSuckerDeployer is ERC2771Context, JBPermissioned, IJBSuckerD
138
141
  singleton = _singleton;
139
142
  }
140
143
 
141
- /// @notice Create a new `JBSucker` for a specific project with an explicit remote peer.
142
- /// @dev Uses the sender address as the salt, which means the same sender must call this function on both chains.
144
+ /// @notice Deploy a new sucker clone for a project via CREATE2. The same sender must call this on both chains to
145
+ /// produce matching deterministic addresses.
146
+ /// @dev Called by the registry during `deploySuckersFor`.
143
147
  /// @param localProjectId The project's ID on the local chain.
144
148
  /// @param salt The salt to use for the `create2` address.
145
149
  /// @param peer The remote peer address. Leave zero to use the default deterministic same-address peer.
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.28;
3
3
 
4
- /// @notice Global constants used across Juicebox contracts.
4
+ /// @notice Arbitrum bridge infrastructure addresses (Inbox and Gateway Routers) for mainnet and Sepolia.
5
5
  library ARBAddresses {
6
6
  /// @notice The respective Inbox used by L1 or Testnet L1
7
7
  address public constant L1_ETH_INBOX = 0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f;
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.28;
3
3
 
4
- /// @notice Global constants used across Juicebox contracts.
4
+ /// @notice Arbitrum chain IDs for mainnet and Sepolia testnet pairs.
5
5
  library ARBChains {
6
6
  /// @notice Arbitrum relevant chains and their respective ids.
7
7
  uint256 public constant ETH_CHAINID = 1;