@bananapus/suckers-v6 0.0.1

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.
Files changed (149) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +422 -0
  3. package/SECURITY.md +55 -0
  4. package/SKILLS.md +163 -0
  5. package/deployments/nana-suckers-v5/arbitrum/JBArbitrumSucker.json +1425 -0
  6. package/deployments/nana-suckers-v5/arbitrum/JBArbitrumSuckerDeployer.json +391 -0
  7. package/deployments/nana-suckers-v5/arbitrum/JBCCIPSucker.json +1479 -0
  8. package/deployments/nana-suckers-v5/arbitrum/JBCCIPSuckerDeployer.json +433 -0
  9. package/deployments/nana-suckers-v5/arbitrum/JBCCIPSuckerDeployer_1.json +433 -0
  10. package/deployments/nana-suckers-v5/arbitrum/JBCCIPSuckerDeployer_2.json +433 -0
  11. package/deployments/nana-suckers-v5/arbitrum/JBCCIPSucker_1.json +1479 -0
  12. package/deployments/nana-suckers-v5/arbitrum/JBCCIPSucker_2.json +1479 -0
  13. package/deployments/nana-suckers-v5/arbitrum/JBSuckerRegistry.json +690 -0
  14. package/deployments/nana-suckers-v5/arbitrum_sepolia/JBArbitrumSucker.json +1425 -0
  15. package/deployments/nana-suckers-v5/arbitrum_sepolia/JBArbitrumSuckerDeployer.json +391 -0
  16. package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSucker.json +1479 -0
  17. package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSuckerDeployer.json +433 -0
  18. package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSuckerDeployer_1.json +433 -0
  19. package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSuckerDeployer_2.json +433 -0
  20. package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSucker_1.json +1479 -0
  21. package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSucker_2.json +1479 -0
  22. package/deployments/nana-suckers-v5/arbitrum_sepolia/JBSuckerRegistry.json +690 -0
  23. package/deployments/nana-suckers-v5/base/JBBaseSucker.json +1389 -0
  24. package/deployments/nana-suckers-v5/base/JBBaseSuckerDeployer.json +376 -0
  25. package/deployments/nana-suckers-v5/base/JBCCIPSucker.json +1483 -0
  26. package/deployments/nana-suckers-v5/base/JBCCIPSuckerDeployer.json +436 -0
  27. package/deployments/nana-suckers-v5/base/JBCCIPSuckerDeployer_1.json +436 -0
  28. package/deployments/nana-suckers-v5/base/JBCCIPSuckerDeployer_2.json +436 -0
  29. package/deployments/nana-suckers-v5/base/JBCCIPSucker_1.json +1483 -0
  30. package/deployments/nana-suckers-v5/base/JBCCIPSucker_2.json +1483 -0
  31. package/deployments/nana-suckers-v5/base/JBSuckerRegistry.json +694 -0
  32. package/deployments/nana-suckers-v5/base_sepolia/JBBaseSucker.json +1389 -0
  33. package/deployments/nana-suckers-v5/base_sepolia/JBBaseSuckerDeployer.json +376 -0
  34. package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSucker.json +1483 -0
  35. package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSuckerDeployer.json +436 -0
  36. package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSuckerDeployer_1.json +436 -0
  37. package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSuckerDeployer_2.json +436 -0
  38. package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSucker_1.json +1483 -0
  39. package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSucker_2.json +1483 -0
  40. package/deployments/nana-suckers-v5/base_sepolia/JBSuckerRegistry.json +694 -0
  41. package/deployments/nana-suckers-v5/ethereum/JBArbitrumSucker.json +1429 -0
  42. package/deployments/nana-suckers-v5/ethereum/JBArbitrumSuckerDeployer.json +394 -0
  43. package/deployments/nana-suckers-v5/ethereum/JBBaseSucker.json +1389 -0
  44. package/deployments/nana-suckers-v5/ethereum/JBBaseSuckerDeployer.json +376 -0
  45. package/deployments/nana-suckers-v5/ethereum/JBCCIPSucker.json +1483 -0
  46. package/deployments/nana-suckers-v5/ethereum/JBCCIPSuckerDeployer.json +436 -0
  47. package/deployments/nana-suckers-v5/ethereum/JBCCIPSuckerDeployer_1.json +436 -0
  48. package/deployments/nana-suckers-v5/ethereum/JBCCIPSuckerDeployer_2.json +436 -0
  49. package/deployments/nana-suckers-v5/ethereum/JBCCIPSucker_1.json +1483 -0
  50. package/deployments/nana-suckers-v5/ethereum/JBCCIPSucker_2.json +1483 -0
  51. package/deployments/nana-suckers-v5/ethereum/JBOptimismSucker.json +1389 -0
  52. package/deployments/nana-suckers-v5/ethereum/JBOptimismSuckerDeployer.json +376 -0
  53. package/deployments/nana-suckers-v5/ethereum/JBSuckerRegistry.json +694 -0
  54. package/deployments/nana-suckers-v5/optimism/JBCCIPSucker.json +1479 -0
  55. package/deployments/nana-suckers-v5/optimism/JBCCIPSuckerDeployer.json +433 -0
  56. package/deployments/nana-suckers-v5/optimism/JBCCIPSuckerDeployer_1.json +433 -0
  57. package/deployments/nana-suckers-v5/optimism/JBCCIPSuckerDeployer_2.json +433 -0
  58. package/deployments/nana-suckers-v5/optimism/JBCCIPSucker_1.json +1479 -0
  59. package/deployments/nana-suckers-v5/optimism/JBCCIPSucker_2.json +1479 -0
  60. package/deployments/nana-suckers-v5/optimism/JBOptimismSucker.json +1385 -0
  61. package/deployments/nana-suckers-v5/optimism/JBOptimismSuckerDeployer.json +373 -0
  62. package/deployments/nana-suckers-v5/optimism/JBSuckerRegistry.json +690 -0
  63. package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSucker.json +1483 -0
  64. package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSuckerDeployer.json +436 -0
  65. package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSuckerDeployer_1.json +436 -0
  66. package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSuckerDeployer_2.json +436 -0
  67. package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSucker_1.json +1483 -0
  68. package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSucker_2.json +1483 -0
  69. package/deployments/nana-suckers-v5/optimism_sepolia/JBOptimismSucker.json +1389 -0
  70. package/deployments/nana-suckers-v5/optimism_sepolia/JBOptimismSuckerDeployer.json +376 -0
  71. package/deployments/nana-suckers-v5/optimism_sepolia/JBSuckerRegistry.json +694 -0
  72. package/deployments/nana-suckers-v5/sepolia/JBArbitrumSucker.json +1429 -0
  73. package/deployments/nana-suckers-v5/sepolia/JBArbitrumSuckerDeployer.json +394 -0
  74. package/deployments/nana-suckers-v5/sepolia/JBBaseSucker.json +1389 -0
  75. package/deployments/nana-suckers-v5/sepolia/JBBaseSuckerDeployer.json +376 -0
  76. package/deployments/nana-suckers-v5/sepolia/JBCCIPSucker.json +1483 -0
  77. package/deployments/nana-suckers-v5/sepolia/JBCCIPSuckerDeployer.json +436 -0
  78. package/deployments/nana-suckers-v5/sepolia/JBCCIPSuckerDeployer_1.json +436 -0
  79. package/deployments/nana-suckers-v5/sepolia/JBCCIPSuckerDeployer_2.json +436 -0
  80. package/deployments/nana-suckers-v5/sepolia/JBCCIPSucker_1.json +1483 -0
  81. package/deployments/nana-suckers-v5/sepolia/JBCCIPSucker_2.json +1483 -0
  82. package/deployments/nana-suckers-v5/sepolia/JBOptimismSucker.json +1389 -0
  83. package/deployments/nana-suckers-v5/sepolia/JBOptimismSuckerDeployer.json +376 -0
  84. package/deployments/nana-suckers-v5/sepolia/JBSuckerRegistry.json +694 -0
  85. package/foundry.lock +11 -0
  86. package/foundry.toml +22 -0
  87. package/package.json +33 -0
  88. package/remappings.txt +1 -0
  89. package/script/Deploy.s.sol +506 -0
  90. package/script/helpers/SuckerDeploymentLib.sol +97 -0
  91. package/slither-ci.config.json +10 -0
  92. package/sphinx.lock +476 -0
  93. package/src/JBArbitrumSucker.sol +311 -0
  94. package/src/JBBaseSucker.sol +41 -0
  95. package/src/JBCCIPSucker.sol +303 -0
  96. package/src/JBOptimismSucker.sol +143 -0
  97. package/src/JBSucker.sol +1159 -0
  98. package/src/JBSuckerRegistry.sol +262 -0
  99. package/src/deployers/JBArbitrumSuckerDeployer.sol +86 -0
  100. package/src/deployers/JBBaseSuckerDeployer.sol +26 -0
  101. package/src/deployers/JBCCIPSuckerDeployer.sol +88 -0
  102. package/src/deployers/JBOptimismSuckerDeployer.sol +82 -0
  103. package/src/deployers/JBSuckerDeployer.sol +147 -0
  104. package/src/enums/JBAddToBalanceMode.sol +11 -0
  105. package/src/enums/JBLayer.sol +8 -0
  106. package/src/enums/JBSuckerState.sol +14 -0
  107. package/src/interfaces/IArbGatewayRouter.sol +11 -0
  108. package/src/interfaces/IArbL1GatewayRouter.sol +17 -0
  109. package/src/interfaces/IArbL2GatewayRouter.sol +14 -0
  110. package/src/interfaces/ICCIPRouter.sol +11 -0
  111. package/src/interfaces/IJBArbitrumSucker.sol +13 -0
  112. package/src/interfaces/IJBArbitrumSuckerDeployer.sol +12 -0
  113. package/src/interfaces/IJBCCIPSuckerDeployer.sol +15 -0
  114. package/src/interfaces/IJBOpSuckerDeployer.sol +11 -0
  115. package/src/interfaces/IJBOptimismSucker.sol +10 -0
  116. package/src/interfaces/IJBSucker.sol +144 -0
  117. package/src/interfaces/IJBSuckerDeployer.sol +40 -0
  118. package/src/interfaces/IJBSuckerExtended.sol +22 -0
  119. package/src/interfaces/IJBSuckerRegistry.sol +75 -0
  120. package/src/interfaces/IOPMessenger.sol +18 -0
  121. package/src/interfaces/IOPStandardBridge.sol +29 -0
  122. package/src/interfaces/IWrappedNativeToken.sol +13 -0
  123. package/src/libraries/ARBAddresses.sol +17 -0
  124. package/src/libraries/ARBChains.sol +11 -0
  125. package/src/libraries/CCIPHelper.sol +136 -0
  126. package/src/structs/JBClaim.sol +13 -0
  127. package/src/structs/JBInboxTreeRoot.sol +12 -0
  128. package/src/structs/JBLeaf.sol +14 -0
  129. package/src/structs/JBMessageRoot.sol +16 -0
  130. package/src/structs/JBOutboxTree.sol +18 -0
  131. package/src/structs/JBRemoteToken.sol +17 -0
  132. package/src/structs/JBSuckerDeployerConfig.sol +12 -0
  133. package/src/structs/JBSuckersPair.sol +11 -0
  134. package/src/structs/JBTokenMapping.sol +13 -0
  135. package/src/utils/MerkleLib.sol +1020 -0
  136. package/test/Fork.t.sol +514 -0
  137. package/test/InteropCompat.t.sol +676 -0
  138. package/test/SuckerAttacks.t.sol +509 -0
  139. package/test/SuckerDeepAttacks.t.sol +1563 -0
  140. package/test/mocks/ERC20Mock.sol +36 -0
  141. package/test/mocks/MockMessenger.sol +42 -0
  142. package/test/unit/arb.t.sol +28 -0
  143. package/test/unit/ccip_native_interop.t.sol +719 -0
  144. package/test/unit/ccip_refund.t.sol +234 -0
  145. package/test/unit/deployer.t.sol +475 -0
  146. package/test/unit/emergency.t.sol +305 -0
  147. package/test/unit/merkle.t.sol +212 -0
  148. package/test/unit/multi_chain_evolution.t.sol +622 -0
  149. package/test/unit/registry.t.sol +26 -0
@@ -0,0 +1,262 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import {JBPermissioned} from "@bananapus/core-v6/src/abstract/JBPermissioned.sol";
5
+ import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
6
+ import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
7
+ import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
8
+ import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
9
+ import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
10
+ import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
11
+ import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
12
+ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
13
+ import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
14
+ import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
15
+ import {Context} from "@openzeppelin/contracts/utils/Context.sol";
16
+
17
+ import {IJBSucker} from "./interfaces/IJBSucker.sol";
18
+ import {IJBSuckerDeployer} from "./interfaces/IJBSuckerDeployer.sol";
19
+ import {IJBSuckerRegistry} from "./interfaces/IJBSuckerRegistry.sol";
20
+ import {JBSuckerDeployerConfig} from "./structs/JBSuckerDeployerConfig.sol";
21
+ import {JBSuckersPair} from "./structs/JBSuckersPair.sol";
22
+ import {JBSuckerState} from "./enums/JBSuckerState.sol";
23
+
24
+ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerRegistry {
25
+ using EnumerableMap for EnumerableMap.AddressToUintMap;
26
+
27
+ //*********************************************************************//
28
+ // --------------------------- custom errors ------------------------- //
29
+ //*********************************************************************//
30
+
31
+ error JBSuckerRegistry_InvalidDeployer(IJBSuckerDeployer deployer);
32
+ error JBSuckerRegistry_SuckerDoesNotBelongToProject(uint256 projectId, address sucker);
33
+ error JBSuckerRegistry_SuckerIsNotDeprecated(address sucker, JBSuckerState suckerState);
34
+
35
+ //*********************************************************************//
36
+ // ------------------------- internal constants ----------------------- //
37
+ //*********************************************************************//
38
+
39
+ /// @notice A constant indicating that this sucker exists and belongs to a specific project.
40
+ uint256 internal constant _SUCKER_EXISTS = 1;
41
+
42
+ //*********************************************************************//
43
+ // --------------- public immutable stored properties ---------------- //
44
+ //*********************************************************************//
45
+
46
+ /// @notice The juicebox directory.
47
+ IJBDirectory public immutable override DIRECTORY;
48
+
49
+ /// @notice A contract which mints ERC-721s that represent project ownership and transfers.
50
+ IJBProjects public immutable override PROJECTS;
51
+
52
+ //*********************************************************************//
53
+ // --------------------- public stored properties -------------------- //
54
+ //*********************************************************************//
55
+
56
+ /// @notice Tracks whether the specified sucker deployer is approved by this registry.
57
+ /// @custom:member deployer The address of the deployer to check.
58
+ mapping(address deployer => bool) public override suckerDeployerIsAllowed;
59
+
60
+ //*********************************************************************//
61
+ // --------------------- internal stored properties ------------------- //
62
+ //*********************************************************************//
63
+
64
+ /// @notice Tracks the suckers for the specified project.
65
+ mapping(uint256 => EnumerableMap.AddressToUintMap) internal _suckersOf;
66
+
67
+ //*********************************************************************//
68
+ // -------------------------- constructor ---------------------------- //
69
+ //*********************************************************************//
70
+
71
+ /// @param directory The juicebox directory.
72
+ /// @param permissions A contract storing permissions.
73
+ /// @param initialOwner The initial owner of this contract.
74
+ constructor(
75
+ IJBDirectory directory,
76
+ IJBPermissions permissions,
77
+ address initialOwner,
78
+ address trustedForwarder
79
+ )
80
+ ERC2771Context(trustedForwarder)
81
+ JBPermissioned(permissions)
82
+ Ownable(initialOwner)
83
+ {
84
+ DIRECTORY = directory;
85
+ PROJECTS = directory.PROJECTS();
86
+ }
87
+
88
+ //*********************************************************************//
89
+ // ------------------------- external views -------------------------- //
90
+ //*********************************************************************//
91
+
92
+ /// @notice Returns true if the specified sucker belongs to the specified project, and was deployed through this
93
+ /// registry.
94
+ /// @param projectId The ID of the project to check for.
95
+ /// @param addr The address of the sucker to check.
96
+ /// @return flag A flag indicating if the sucker belongs to the project, and was deployed through this registry.
97
+ function isSuckerOf(uint256 projectId, address addr) external view override returns (bool) {
98
+ (bool exists, uint256 val) = _suckersOf[projectId].tryGet(addr);
99
+ return exists && val == _SUCKER_EXISTS;
100
+ }
101
+
102
+ /// @notice Helper function for retrieving the projects suckers and their metadata.
103
+ /// @param projectId The ID of the project to get the suckers of.
104
+ /// @return pairs The pairs of suckers and their metadata.
105
+ function suckerPairsOf(uint256 projectId) external view override returns (JBSuckersPair[] memory pairs) {
106
+ // Get the suckers of the project.
107
+ address[] memory suckers = _suckersOf[projectId].keys();
108
+
109
+ // Initialize the array of pairs.
110
+ pairs = new JBSuckersPair[](suckers.length);
111
+
112
+ // Populate the array of pairs.
113
+ for (uint256 i; i < suckers.length; i++) {
114
+ // Get the sucker being iterated over.
115
+ IJBSucker sucker = IJBSucker(suckers[i]);
116
+
117
+ // slither-disable-next-line calls-loop
118
+ pairs[i] =
119
+ JBSuckersPair({local: address(sucker), remote: sucker.peer(), remoteChainId: sucker.peerChainId()});
120
+ }
121
+ }
122
+
123
+ /// @notice Gets all of the specified project's suckers which were deployed through this registry.
124
+ /// @param projectId The ID of the project to get the suckers of.
125
+ /// @return suckers The addresses of the suckers.
126
+ function suckersOf(uint256 projectId) external view override returns (address[] memory) {
127
+ return _suckersOf[projectId].keys();
128
+ }
129
+
130
+ //*********************************************************************//
131
+ // ------------------------ internal views --------------------------- //
132
+ //*********************************************************************//
133
+
134
+ /// @notice The calldata. Preferred to use over `msg.data`.
135
+ /// @return calldata The `msg.data` of this call.
136
+ function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
137
+ return ERC2771Context._msgData();
138
+ }
139
+
140
+ /// @notice The message's sender. Preferred to use over `msg.sender`.
141
+ /// @return sender The address which sent this call.
142
+ function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
143
+ return ERC2771Context._msgSender();
144
+ }
145
+
146
+ /// @dev ERC-2771 specifies the context as being a single address (20 bytes).
147
+ function _contextSuffixLength() internal view virtual override(ERC2771Context, Context) returns (uint256) {
148
+ return ERC2771Context._contextSuffixLength();
149
+ }
150
+
151
+ //*********************************************************************//
152
+ // ---------------------- external transactions ---------------------- //
153
+ //*********************************************************************//
154
+
155
+ /// @notice Adds a suckers deployer to the allowlist.
156
+ /// @dev Can only be called by this contract's owner (initially project ID 1, or JuiceboxDAO).
157
+ /// @param deployer The address of the deployer to add.
158
+ function allowSuckerDeployer(address deployer) public override onlyOwner {
159
+ suckerDeployerIsAllowed[deployer] = true;
160
+ emit SuckerDeployerAllowed({deployer: deployer, caller: _msgSender()});
161
+ }
162
+
163
+ /// @notice Adds multiple suckers deployer to the allowlist.
164
+ /// @dev Can only be called by this contract's owner (initially project ID 1, or JuiceboxDAO).
165
+ /// @param deployers The address of the deployer to add.
166
+ function allowSuckerDeployers(address[] calldata deployers) public override onlyOwner {
167
+ // Iterate through the deployers and allow them.
168
+ for (uint256 i; i < deployers.length; i++) {
169
+ // Get the deployer being iterated over.
170
+ address deployer = deployers[i];
171
+
172
+ // Allow the deployer.
173
+ suckerDeployerIsAllowed[deployer] = true;
174
+ emit SuckerDeployerAllowed({deployer: deployer, caller: _msgSender()});
175
+ }
176
+ }
177
+
178
+ /// @notice Deploy one or more suckers for the specified project.
179
+ /// @dev The caller must be the project's owner or have `JBPermissionIds.DEPLOY_SUCKERS` from the project's owner.
180
+ /// @param projectId The ID of the project to deploy suckers for.
181
+ /// @param salt The salt used to deploy the contract. For the suckers to be peers, this must be the same value on
182
+ /// each chain where suckers are deployed.
183
+ /// @param configurations The sucker deployer configs to use to deploy the suckers.
184
+ /// @return suckers The addresses of the deployed suckers.
185
+ function deploySuckersFor(
186
+ uint256 projectId,
187
+ bytes32 salt,
188
+ JBSuckerDeployerConfig[] calldata configurations
189
+ )
190
+ public
191
+ override
192
+ returns (address[] memory suckers)
193
+ {
194
+ _requirePermissionFrom({
195
+ account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.DEPLOY_SUCKERS
196
+ });
197
+
198
+ // Create an array to store the suckers as they are deployed.
199
+ suckers = new address[](configurations.length);
200
+
201
+ // Calculate the salt using the sender's address and the provided `salt`.
202
+ // This means that for suckers to be peers, the sender has to be the same on each chain.
203
+ salt = keccak256(abi.encode(_msgSender(), salt));
204
+
205
+ // Iterate through the configurations and deploy the suckers.
206
+ for (uint256 i; i < configurations.length; i++) {
207
+ // Get the configuration being iterated over.
208
+ JBSuckerDeployerConfig memory configuration = configurations[i];
209
+
210
+ // Make sure the deployer is allowed.
211
+ if (!suckerDeployerIsAllowed[address(configuration.deployer)]) {
212
+ revert JBSuckerRegistry_InvalidDeployer(configuration.deployer);
213
+ }
214
+
215
+ // Create the sucker.
216
+ // slither-disable-next-line reentrancy-event,calls-loop
217
+ IJBSucker sucker = configuration.deployer.createForSender({localProjectId: projectId, salt: salt});
218
+ suckers[i] = address(sucker);
219
+
220
+ // Store the sucker as being deployed for this project.
221
+ // slither-disable-next-line unused-return
222
+ _suckersOf[projectId].set({key: address(sucker), value: _SUCKER_EXISTS});
223
+
224
+ // Map the tokens for the sucker.
225
+ // slither-disable-next-line reentrancy-events,calls-loop
226
+ sucker.mapTokens(configuration.mappings);
227
+ emit SuckerDeployedFor({
228
+ projectId: projectId, sucker: address(sucker), configuration: configuration, caller: _msgSender()
229
+ });
230
+ }
231
+ }
232
+
233
+ /// @notice Lets anyone remove a deprecated sucker from a project.
234
+ /// @param projectId The ID of the project to remove the sucker from.
235
+ /// @param sucker The address of the deprecated sucker to remove.
236
+ function removeDeprecatedSucker(uint256 projectId, address sucker) public override {
237
+ // Sanity check, make sure that the sucker does actually belong to the project.
238
+ (bool belongsToProject, uint256 val) = _suckersOf[projectId].tryGet(sucker);
239
+ if (!belongsToProject || val != _SUCKER_EXISTS) {
240
+ revert JBSuckerRegistry_SuckerDoesNotBelongToProject(projectId, address(sucker));
241
+ }
242
+
243
+ // Check if the sucker is deprecated.
244
+ JBSuckerState state = IJBSucker(sucker).state();
245
+ if (state != JBSuckerState.DEPRECATED) {
246
+ revert JBSuckerRegistry_SuckerIsNotDeprecated(address(sucker), state);
247
+ }
248
+
249
+ // Remove the sucker from the registry.
250
+ // slither-disable-next-line unused-return
251
+ _suckersOf[projectId].remove(address(sucker));
252
+ emit SuckerDeprecated({projectId: projectId, sucker: address(sucker), caller: _msgSender()});
253
+ }
254
+
255
+ /// @notice Removes a sucker deployer from the allowlist.
256
+ /// @dev Can only be called by this contract's owner (initially project ID 1, or JuiceboxDAO).
257
+ /// @param deployer The address of the deployer to remove.
258
+ function removeSuckerDeployer(address deployer) public override onlyOwner {
259
+ suckerDeployerIsAllowed[deployer] = false;
260
+ emit SuckerDeployerRemoved({deployer: deployer, caller: _msgSender()});
261
+ }
262
+ }
@@ -0,0 +1,86 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import "./JBSuckerDeployer.sol";
5
+ import "../interfaces/IJBArbitrumSuckerDeployer.sol";
6
+
7
+ import {JBArbitrumSucker} from "../JBArbitrumSucker.sol";
8
+ import {JBLayer} from "../enums/JBLayer.sol";
9
+ import {IArbGatewayRouter} from "../interfaces/IArbGatewayRouter.sol";
10
+ import {ARBAddresses} from "../libraries/ARBAddresses.sol";
11
+ import {ARBChains} from "../libraries/ARBChains.sol";
12
+
13
+ /// @notice An `IJBSuckerDeployer` implementation to deploy `JBArbitrumSucker` contracts.
14
+ contract JBArbitrumSuckerDeployer is JBSuckerDeployer, IJBArbitrumSuckerDeployer {
15
+ //*********************************************************************//
16
+ // ---------------------- public stored properties ------------------- //
17
+ //*********************************************************************//
18
+
19
+ /// @notice The layer that this contract is on.
20
+ JBLayer public arbLayer;
21
+
22
+ /// @notice The inbox used to send messages between the local and remote sucker.
23
+ IInbox public override arbInbox;
24
+
25
+ /// @notice The gateway router for the specific chain
26
+ IArbGatewayRouter public override arbGatewayRouter;
27
+
28
+ //*********************************************************************//
29
+ // ---------------------------- constructor -------------------------- //
30
+ //*********************************************************************//
31
+
32
+ /// @param directory The directory of terminals and controllers for projects.
33
+ /// @param permissions The permissions contract for the deployer.
34
+ /// @param tokens The contract that manages token minting and burning.
35
+ /// @param configurator The address of the configurator.
36
+ constructor(
37
+ IJBDirectory directory,
38
+ IJBPermissions permissions,
39
+ IJBTokens tokens,
40
+ address configurator,
41
+ address trustedForwarder
42
+ )
43
+ JBSuckerDeployer(directory, permissions, tokens, configurator, trustedForwarder)
44
+ {}
45
+
46
+ //*********************************************************************//
47
+ // ------------------------ internal views --------------------------- //
48
+ //*********************************************************************//
49
+
50
+ /// @notice Check if the layer specific configuration is set or not. Used as a sanity check.
51
+ function _layerSpecificConfigurationIsSet() internal view override returns (bool) {
52
+ // We don't check arbLayer here because JBLayer.L1 == 0 which is the default/unset value.
53
+ // Since all fields are set atomically in setChainSpecificConstants, checking inbox + gateway is sufficient.
54
+ return address(arbInbox) != address(0) && address(arbGatewayRouter) != address(0);
55
+ }
56
+
57
+ //*********************************************************************//
58
+ // --------------------- external transactions ----------------------- //
59
+ //*********************************************************************//
60
+
61
+ /// @notice Handles some layer specific configuration that can't be done in the constructor otherwise deployment
62
+ /// addresses would change.
63
+ /// @param layer The Arbitrum layer (L1 or L2).
64
+ /// @param inbox The Arbitrum inbox on this layer.
65
+ /// @param gatewayRouter The Arbitrum gateway router on this layer.
66
+ function setChainSpecificConstants(JBLayer layer, IInbox inbox, IArbGatewayRouter gatewayRouter) external {
67
+ if (_layerSpecificConfigurationIsSet()) {
68
+ revert JBSuckerDeployer_AlreadyConfigured();
69
+ }
70
+
71
+ if (_msgSender() != LAYER_SPECIFIC_CONFIGURATOR) {
72
+ revert JBSuckerDeployer_Unauthorized(_msgSender(), LAYER_SPECIFIC_CONFIGURATOR);
73
+ }
74
+
75
+ // Configure these layer specific properties.
76
+ // This is done in a separate call to make the deployment code chain agnostic.
77
+ arbLayer = layer;
78
+ arbInbox = inbox;
79
+ arbGatewayRouter = gatewayRouter;
80
+
81
+ // Make sure the layer specific configuration is properly configured.
82
+ if (!_layerSpecificConfigurationIsSet()) {
83
+ revert JBSuckerDeployer_InvalidLayerSpecificConfiguration();
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,26 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import "./JBOptimismSuckerDeployer.sol";
5
+ import "../JBBaseSucker.sol";
6
+
7
+ // Exact same as JBOptimismSuckerDeployer, we do this so we get a seperate artifact for Base.
8
+ contract JBBaseSuckerDeployer is JBOptimismSuckerDeployer {
9
+ //*********************************************************************//
10
+ // ---------------------------- constructor -------------------------- //
11
+ //*********************************************************************//
12
+
13
+ /// @param directory The directory of terminals and controllers for projects.
14
+ /// @param permissions The permissions contract for the deployer.
15
+ /// @param tokens The contract that manages token minting and burning.
16
+ /// @param configurator The address of the configurator.
17
+ constructor(
18
+ IJBDirectory directory,
19
+ IJBPermissions permissions,
20
+ IJBTokens tokens,
21
+ address configurator,
22
+ address trustedForwarder
23
+ )
24
+ JBOptimismSuckerDeployer(directory, permissions, tokens, configurator, trustedForwarder)
25
+ {}
26
+ }
@@ -0,0 +1,88 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import "./JBSuckerDeployer.sol";
5
+ import "../interfaces/IJBArbitrumSuckerDeployer.sol";
6
+
7
+ import {JBCCIPSucker} from "../JBCCIPSucker.sol";
8
+ import {JBAddToBalanceMode} from "../enums/JBAddToBalanceMode.sol";
9
+ import {IJBSucker} from "./../interfaces/IJBSucker.sol";
10
+ import {IJBSuckerDeployer} from "./../interfaces/IJBSuckerDeployer.sol";
11
+ import {IJBCCIPSuckerDeployer} from "./../interfaces/IJBCCIPSuckerDeployer.sol";
12
+ import {ICCIPRouter} from "src/interfaces/ICCIPRouter.sol";
13
+ import {CCIPHelper} from "src/libraries/CCIPHelper.sol";
14
+
15
+ /// @notice An `IJBSuckerDeployer` implementation to deploy contracts.
16
+ contract JBCCIPSuckerDeployer is JBSuckerDeployer, IJBCCIPSuckerDeployer {
17
+ error JBCCIPSuckerDeployer_InvalidCCIPRouter(address router);
18
+
19
+ //*********************************************************************//
20
+ // ---------------------- public stored properties ------------------- //
21
+ //*********************************************************************//
22
+
23
+ /// @notice Store the remote chain id
24
+ uint256 public ccipRemoteChainId;
25
+
26
+ /// @notice The remote chain selector target of all sucker deployed by this contract.
27
+ uint64 public ccipRemoteChainSelector;
28
+
29
+ /// @notice Store the address of the CCIP router for this chain.
30
+ ICCIPRouter public ccipRouter;
31
+
32
+ //*********************************************************************//
33
+ // ---------------------------- constructor -------------------------- //
34
+ //*********************************************************************//
35
+
36
+ /// @param directory The directory of terminals and controllers for projects.
37
+ /// @param permissions The permissions contract for the deployer.
38
+ /// @param tokens The contract that manages token minting and burning.
39
+ /// @param configurator The address of the configurator.
40
+ constructor(
41
+ IJBDirectory directory,
42
+ IJBPermissions permissions,
43
+ IJBTokens tokens,
44
+ address configurator,
45
+ address trustedForwarder
46
+ )
47
+ JBSuckerDeployer(directory, permissions, tokens, configurator, trustedForwarder)
48
+ {}
49
+
50
+ //*********************************************************************//
51
+ // ------------------------ internal views --------------------------- //
52
+ //*********************************************************************//
53
+
54
+ /// @notice Check if the layer specific configuration is set or not. Used as a sanity check.
55
+ function _layerSpecificConfigurationIsSet() internal view override returns (bool) {
56
+ return ccipRemoteChainId != 0 && ccipRemoteChainSelector != 0 && address(ccipRouter) != address(0);
57
+ }
58
+
59
+ //*********************************************************************//
60
+ // --------------------- external transactions ----------------------- //
61
+ //*********************************************************************//
62
+
63
+ /// @notice handles some layer specific configuration that can't be done in the constructor otherwise deployment
64
+ /// addresses would change.
65
+ /// @param remoteChainId The remote chain id.
66
+ /// @param remoteChainSelector The CCIP remote chain selector.
67
+ /// @param router The CCIP router for this chain.
68
+ function setChainSpecificConstants(uint256 remoteChainId, uint64 remoteChainSelector, ICCIPRouter router) external {
69
+ if (_layerSpecificConfigurationIsSet()) {
70
+ revert JBSuckerDeployer_AlreadyConfigured();
71
+ }
72
+
73
+ if (_msgSender() != LAYER_SPECIFIC_CONFIGURATOR) {
74
+ revert JBSuckerDeployer_Unauthorized(_msgSender(), LAYER_SPECIFIC_CONFIGURATOR);
75
+ }
76
+
77
+ ccipRemoteChainId = remoteChainId;
78
+ ccipRemoteChainSelector = remoteChainSelector;
79
+ ccipRouter = router;
80
+
81
+ // Make sure the layer specific configuration is properly configured.
82
+ if (!_layerSpecificConfigurationIsSet()) {
83
+ revert JBSuckerDeployer_InvalidLayerSpecificConfiguration();
84
+ }
85
+
86
+ emit CCIPConstantsSet(address(ccipRouter), ccipRemoteChainId, ccipRemoteChainSelector, _msgSender());
87
+ }
88
+ }
@@ -0,0 +1,82 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import "./JBSuckerDeployer.sol";
5
+ import "../interfaces/IJBArbitrumSuckerDeployer.sol";
6
+
7
+ import {JBOptimismSucker} from "../JBOptimismSucker.sol";
8
+ import {JBAddToBalanceMode} from "../enums/JBAddToBalanceMode.sol";
9
+ import {IJBOpSuckerDeployer} from "./../interfaces/IJBOpSuckerDeployer.sol";
10
+ import {IJBSuckerDeployer} from "./../interfaces/IJBSuckerDeployer.sol";
11
+ import {IOPMessenger} from "../interfaces/IOPMessenger.sol";
12
+ import {IOPStandardBridge} from "../interfaces/IOPStandardBridge.sol";
13
+
14
+ /// @notice An `IJBSuckerDeployer` implementation to deploy `JBOptimismSucker` contracts.
15
+ contract JBOptimismSuckerDeployer is JBSuckerDeployer, IJBOpSuckerDeployer {
16
+ //*********************************************************************//
17
+ // ---------------------- public stored properties ------------------- //
18
+ //*********************************************************************//
19
+
20
+ /// @notice The messenger used to send messages between the local and remote sucker.
21
+ IOPMessenger public override opMessenger;
22
+
23
+ /// @notice The bridge used to bridge tokens between the local and remote chain.
24
+ IOPStandardBridge public override opBridge;
25
+
26
+ //*********************************************************************//
27
+ // ---------------------------- constructor -------------------------- //
28
+ //*********************************************************************//
29
+
30
+ /// @param directory The directory of terminals and controllers for projects.
31
+ /// @param permissions The permissions contract for the deployer.
32
+ /// @param tokens The contract that manages token minting and burning.
33
+ /// @param configurator The address of the configurator.
34
+ constructor(
35
+ IJBDirectory directory,
36
+ IJBPermissions permissions,
37
+ IJBTokens tokens,
38
+ address configurator,
39
+ address trustedForwarder
40
+ )
41
+ JBSuckerDeployer(directory, permissions, tokens, configurator, trustedForwarder)
42
+ {}
43
+
44
+ //*********************************************************************//
45
+ // ------------------------ internal views --------------------------- //
46
+ //*********************************************************************//
47
+
48
+ /// @notice Check if the layer specific configuration is set or not. Used as a sanity check.
49
+ function _layerSpecificConfigurationIsSet() internal view override returns (bool) {
50
+ // Use && (not ||) so the post-set check in setChainSpecificConstants rejects partial configurations
51
+ // where only one of messenger/bridge is provided. Both are required for the sucker to function.
52
+ return address(opMessenger) != address(0) && address(opBridge) != address(0);
53
+ }
54
+
55
+ //*********************************************************************//
56
+ // --------------------- external transactions ----------------------- //
57
+ //*********************************************************************//
58
+
59
+ /// @notice Handles some layer specific configuration that can't be done in the constructor otherwise deployment
60
+ /// addresses would change.
61
+ /// @param messenger The OPMessenger on this layer.
62
+ /// @param bridge The OPStandardBridge on this layer.
63
+ function setChainSpecificConstants(IOPMessenger messenger, IOPStandardBridge bridge) external {
64
+ if (_layerSpecificConfigurationIsSet()) {
65
+ revert JBSuckerDeployer_AlreadyConfigured();
66
+ }
67
+
68
+ if (_msgSender() != LAYER_SPECIFIC_CONFIGURATOR) {
69
+ revert JBSuckerDeployer_Unauthorized(_msgSender(), LAYER_SPECIFIC_CONFIGURATOR);
70
+ }
71
+
72
+ // Configure these layer specific properties.
73
+ // This is done in a separate call to make the deployment code chain agnostic.
74
+ opMessenger = messenger;
75
+ opBridge = bridge;
76
+
77
+ // Make sure the layer specific configuration is properly configured.
78
+ if (!_layerSpecificConfigurationIsSet()) {
79
+ revert JBSuckerDeployer_InvalidLayerSpecificConfiguration();
80
+ }
81
+ }
82
+ }