@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,147 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
5
+ import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
6
+ import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
7
+ import {IJBSuckerDeployer} from "./../interfaces/IJBSuckerDeployer.sol";
8
+ import {IJBSucker} from "./../interfaces/IJBSucker.sol";
9
+
10
+ import {JBPermissioned} from "@bananapus/core-v6/src/abstract/JBPermissioned.sol";
11
+ import {LibClone} from "solady/src/utils/LibClone.sol";
12
+ import {JBSucker} from "../JBSucker.sol";
13
+ import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
14
+ import {Context} from "@openzeppelin/contracts/utils/Context.sol";
15
+
16
+ /// @notice A base implementation for deploying suckers.
17
+ abstract contract JBSuckerDeployer is ERC2771Context, JBPermissioned, IJBSuckerDeployer {
18
+ //*********************************************************************//
19
+ // --------------- public immutable stored properties ---------------- //
20
+ //*********************************************************************//
21
+
22
+ /// @notice The directory of terminals and controllers for projects.
23
+ IJBDirectory public immutable override DIRECTORY;
24
+
25
+ /// @notice Only this address can configure this deployer, can only be used once.
26
+ address public immutable override LAYER_SPECIFIC_CONFIGURATOR;
27
+
28
+ /// @notice The contract that manages token minting and burning.
29
+ IJBTokens public immutable override TOKENS;
30
+
31
+ //*********************************************************************//
32
+ // ---------------------- public stored properties ------------------- //
33
+ //*********************************************************************//
34
+
35
+ /// @notice A mapping of suckers deployed by this contract.
36
+ mapping(address => bool) public override isSucker;
37
+
38
+ /// @notice The singleton used to clone suckers.
39
+ JBSucker public singleton;
40
+
41
+ //*********************************************************************//
42
+ // ---------------------------- constructor -------------------------- //
43
+ //*********************************************************************//
44
+
45
+ /// @param directory The directory of terminals and controllers for projects.
46
+ /// @param permissions The permissions contract for the deployer.
47
+ /// @param tokens The contract that manages token minting and burning.
48
+ /// @param configurator The address of the configurator.
49
+ constructor(
50
+ IJBDirectory directory,
51
+ IJBPermissions permissions,
52
+ IJBTokens tokens,
53
+ address configurator,
54
+ address trustedForwarder
55
+ )
56
+ ERC2771Context(trustedForwarder)
57
+ JBPermissioned(permissions)
58
+ {
59
+ DIRECTORY = directory;
60
+ TOKENS = tokens;
61
+ LAYER_SPECIFIC_CONFIGURATOR = configurator;
62
+
63
+ // There has to be a configurator address or the layer specific configuration has to already be configured.
64
+ if (configurator == address(0) && !_layerSpecificConfigurationIsSet()) {
65
+ revert JBSuckerDeployer_ZeroConfiguratorAddress();
66
+ }
67
+ }
68
+
69
+ //*********************************************************************//
70
+ // ------------------------ internal views --------------------------- //
71
+ //*********************************************************************//
72
+
73
+ /// @notice Check if the layer specific configuration is set or not. Used as a sanity check.
74
+ function _layerSpecificConfigurationIsSet() internal view virtual returns (bool);
75
+
76
+ /// @notice The message's sender. Preferred to use over `msg.sender`.
77
+ /// @return sender The address which sent this call.
78
+ function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
79
+ return ERC2771Context._msgSender();
80
+ }
81
+
82
+ /// @notice The calldata. Preferred to use over `msg.data`.
83
+ /// @return calldata The `msg.data` of this call.
84
+ function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
85
+ return ERC2771Context._msgData();
86
+ }
87
+
88
+ /// @dev ERC-2771 specifies the context as being a single address (20 bytes).
89
+ function _contextSuffixLength() internal view virtual override(ERC2771Context, Context) returns (uint256) {
90
+ return ERC2771Context._contextSuffixLength();
91
+ }
92
+
93
+ //*********************************************************************//
94
+ // --------------------- external transactions ----------------------- //
95
+ //*********************************************************************//
96
+
97
+ /// @notice Configure the singleton instance that is used to clone suckers.
98
+ /// @dev Can only be called *once* by the layer specific configurator.
99
+ /// @param _singleton The address of the singleton.
100
+ function configureSingleton(JBSucker _singleton) external {
101
+ // Make sure only the configurator can call this function.
102
+ if (_msgSender() != LAYER_SPECIFIC_CONFIGURATOR) {
103
+ revert JBSuckerDeployer_Unauthorized(_msgSender(), LAYER_SPECIFIC_CONFIGURATOR);
104
+ }
105
+
106
+ // Ensure that the layer specific configuration is set.
107
+ if (!_layerSpecificConfigurationIsSet()) {
108
+ revert JBSuckerDeployer_LayerSpecificNotConfigured();
109
+ }
110
+
111
+ // Make sure the singleton is not already configured.
112
+ if (address(singleton) != address(0)) revert JBSuckerDeployer_AlreadyConfigured();
113
+
114
+ singleton = _singleton;
115
+ }
116
+
117
+ /// @notice Create a new `JBSucker` for a specific project.
118
+ /// @dev Uses the sender address as the salt, which means the same sender must call this function on both chains.
119
+ /// @param localProjectId The project's ID on the local chain.
120
+ /// @param salt The salt to use for the `create2` address.
121
+ /// @return sucker The address of the new sucker.
122
+ function createForSender(
123
+ uint256 localProjectId,
124
+ bytes32 salt
125
+ )
126
+ external
127
+ override(IJBSuckerDeployer)
128
+ returns (IJBSucker sucker)
129
+ {
130
+ // Make sure that this deployer is configured properly.
131
+ if (address(singleton) == address(0)) {
132
+ revert JBSuckerDeployer_DeployerIsNotConfigured();
133
+ }
134
+
135
+ // Hash the salt with the sender address to ensure only a specific sender can create this sucker.
136
+ salt = keccak256(abi.encodePacked(_msgSender(), salt));
137
+
138
+ // Clone the singleton.
139
+ sucker = IJBSucker(LibClone.cloneDeterministic(address(singleton), salt));
140
+
141
+ // Mark it as a sucker that was deployed by this deployer.
142
+ isSucker[address(sucker)] = true;
143
+
144
+ // Initialize the clone.
145
+ JBSucker(payable(address(sucker))).initialize(localProjectId);
146
+ }
147
+ }
@@ -0,0 +1,11 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ /// @notice Options for how a `JBSucker`'s `amountToAddToBalance` gets added to its project's balance.
5
+ /// @custom:element MANUAL The amount gets added to the project's balance manually by calling
6
+ /// `addOutstandingAmountToBalance`.
7
+ /// @custom:element ON_CLAIM The amount gets added to the project's balance automatically when `claim` is called.
8
+ enum JBAddToBalanceMode {
9
+ MANUAL,
10
+ ON_CLAIM
11
+ }
@@ -0,0 +1,8 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ /// @notice Whether a `JBArbitrumSucker` is on L1 or L2.
5
+ enum JBLayer {
6
+ L1,
7
+ L2
8
+ }
@@ -0,0 +1,14 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ /// @notice Options for the deprecation state of a `JBSucker`.
5
+ /// @custom:member ENABLED The `JBSucker` is not deprecated.
6
+ /// @custom:member DEPRECATION_PENDING The `JBSucker` has a deprecation set, but it is still fully functional.
7
+ /// @custom:member SENDING_DISABLED The `JBSucker` is deprecated and sending to the pair sucker is disabled.
8
+ /// @custom:member DEPRECATED The `JBSucker` is deprecated, but it continues to let users claim their funds.
9
+ enum JBSuckerState {
10
+ ENABLED,
11
+ DEPRECATION_PENDING,
12
+ SENDING_DISABLED,
13
+ DEPRECATED
14
+ }
@@ -0,0 +1,11 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ /**
5
+ * @title Common interface for L1 and L2 Gateway Routers
6
+ */
7
+ interface IArbGatewayRouter {
8
+ function defaultGateway() external view returns (address gateway);
9
+
10
+ function getGateway(address _token) external view returns (address gateway);
11
+ }
@@ -0,0 +1,17 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ interface IArbL1GatewayRouter {
5
+ function outboundTransferCustomRefund(
6
+ address token,
7
+ address refundTo,
8
+ address to,
9
+ uint256 amount,
10
+ uint256 maxGas,
11
+ uint256 gasPriceBid,
12
+ bytes calldata data
13
+ )
14
+ external
15
+ payable
16
+ returns (bytes memory);
17
+ }
@@ -0,0 +1,14 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ interface IArbL2GatewayRouter {
5
+ function outboundTransfer(
6
+ address l1Token,
7
+ address to,
8
+ uint256 amount,
9
+ bytes calldata data
10
+ )
11
+ external
12
+ payable
13
+ returns (bytes memory);
14
+ }
@@ -0,0 +1,11 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
5
+ import {IWrappedNativeToken} from "./IWrappedNativeToken.sol";
6
+
7
+ // https://github.com/smartcontractkit/ccip/blob/ccip-develop/contracts/src/v0.8/ccip/applications/EtherSenderReceiver.sol
8
+
9
+ interface ICCIPRouter is IRouterClient {
10
+ function getWrappedNative() external view returns (IWrappedNativeToken);
11
+ }
@@ -0,0 +1,13 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IInbox} from "@arbitrum/nitro-contracts/src/bridge/IInbox.sol";
5
+
6
+ import {IArbGatewayRouter} from "./IArbGatewayRouter.sol";
7
+ import {JBLayer} from "./../enums/JBLayer.sol";
8
+
9
+ interface IJBArbitrumSucker {
10
+ function ARBINBOX() external view returns (IInbox);
11
+ function GATEWAYROUTER() external view returns (IArbGatewayRouter);
12
+ function LAYER() external view returns (JBLayer);
13
+ }
@@ -0,0 +1,12 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {JBLayer} from "../enums/JBLayer.sol";
5
+ import {IArbGatewayRouter} from "../interfaces/IArbGatewayRouter.sol";
6
+ import {IInbox} from "@arbitrum/nitro-contracts/src/bridge/IInbox.sol";
7
+
8
+ interface IJBArbitrumSuckerDeployer {
9
+ function arbGatewayRouter() external view returns (IArbGatewayRouter);
10
+ function arbInbox() external view returns (IInbox);
11
+ function arbLayer() external view returns (JBLayer);
12
+ }
@@ -0,0 +1,15 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IJBSucker} from "./IJBSucker.sol";
5
+ import {ICCIPRouter} from "./ICCIPRouter.sol";
6
+
7
+ interface IJBCCIPSuckerDeployer {
8
+ event CCIPConstantsSet(
9
+ address ccipRouter, uint256 ccipRemoteChainId, uint64 ccipRemoteChainSelector, address caller
10
+ );
11
+
12
+ function ccipRouter() external view returns (ICCIPRouter);
13
+ function ccipRemoteChainId() external view returns (uint256);
14
+ function ccipRemoteChainSelector() external view returns (uint64);
15
+ }
@@ -0,0 +1,11 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IOPStandardBridge} from "./IOPStandardBridge.sol";
5
+ import {IOPMessenger} from "./IOPMessenger.sol";
6
+
7
+ interface IJBOpSuckerDeployer {
8
+ function opBridge() external view returns (IOPStandardBridge);
9
+ function opMessenger() external view returns (IOPMessenger);
10
+ function setChainSpecificConstants(IOPMessenger messenger, IOPStandardBridge bridge) external;
11
+ }
@@ -0,0 +1,10 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IOPMessenger} from "./IOPMessenger.sol";
5
+ import {IOPStandardBridge} from "./IOPStandardBridge.sol";
6
+
7
+ interface IJBOptimismSucker {
8
+ function OPBRIDGE() external view returns (IOPStandardBridge);
9
+ function OPMESSENGER() external view returns (IOPMessenger);
10
+ }
@@ -0,0 +1,144 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
5
+ import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
6
+ import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
7
+ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
8
+
9
+ import {JBAddToBalanceMode} from "../enums/JBAddToBalanceMode.sol";
10
+ import {JBSuckerState} from "../enums/JBSuckerState.sol";
11
+ import {JBClaim} from "../structs/JBClaim.sol";
12
+ import {JBInboxTreeRoot} from "../structs/JBInboxTreeRoot.sol";
13
+ import {JBOutboxTree} from "../structs/JBOutboxTree.sol";
14
+ import {JBRemoteToken} from "../structs/JBRemoteToken.sol";
15
+ import {JBTokenMapping} from "../structs/JBTokenMapping.sol";
16
+ import {JBMessageRoot} from "../structs/JBMessageRoot.sol";
17
+
18
+ /// @notice The minimal interface for a sucker contract.
19
+ interface IJBSucker is IERC165 {
20
+ event Claimed(
21
+ bytes32 beneficiary,
22
+ address token,
23
+ uint256 projectTokenCount,
24
+ uint256 terminalTokenAmount,
25
+ uint256 index,
26
+ bool autoAddedToBalance,
27
+ address caller
28
+ );
29
+ event InsertToOutboxTree(
30
+ bytes32 indexed beneficiary,
31
+ address indexed token,
32
+ bytes32 hashed,
33
+ uint256 index,
34
+ bytes32 root,
35
+ uint256 projectTokenCount,
36
+ uint256 terminalTokenAmount,
37
+ address caller
38
+ );
39
+ event NewInboxTreeRoot(address indexed token, uint64 nonce, bytes32 root, address caller);
40
+ event RootToRemote(bytes32 indexed root, address indexed token, uint256 index, uint64 nonce, address caller);
41
+ event StaleRootRejected(address indexed token, uint64 receivedNonce, uint64 currentNonce);
42
+
43
+ /// @notice The minimum gas required for a basic cross-chain call.
44
+ /// @return The base gas limit.
45
+ function MESSENGER_BASE_GAS_LIMIT() external view returns (uint32);
46
+
47
+ /// @notice The minimum gas required for bridging ERC-20 tokens.
48
+ /// @return The ERC-20 minimum gas limit.
49
+ function MESSENGER_ERC20_MIN_GAS_LIMIT() external view returns (uint32);
50
+
51
+ /// @notice The mode used when adding reclaimed tokens to the project's balance.
52
+ /// @return The add-to-balance mode.
53
+ function ADD_TO_BALANCE_MODE() external view returns (JBAddToBalanceMode);
54
+
55
+ /// @notice The directory of terminals and controllers.
56
+ /// @return The directory contract.
57
+ function DIRECTORY() external view returns (IJBDirectory);
58
+
59
+ /// @notice The token registry.
60
+ /// @return The tokens contract.
61
+ function TOKENS() external view returns (IJBTokens);
62
+
63
+ /// @notice The address of the deployer that created this sucker.
64
+ /// @return The deployer address.
65
+ function deployer() external view returns (address);
66
+
67
+ /// @notice The address of the peer sucker on the remote chain (as bytes32 for cross-VM compatibility).
68
+ /// @return The peer address.
69
+ function peer() external view returns (bytes32);
70
+
71
+ /// @notice The ID of the project on the local chain that this sucker is associated with.
72
+ /// @return The project ID.
73
+ function projectId() external view returns (uint256);
74
+
75
+ /// @notice The amount of tokens waiting to be added to the project's terminal balance.
76
+ /// @param token The terminal token address.
77
+ /// @return amount The outstanding amount.
78
+ function amountToAddToBalanceOf(address token) external view returns (uint256 amount);
79
+
80
+ /// @notice The inbox merkle tree root for a given token.
81
+ /// @param token The local terminal token.
82
+ /// @return The inbox tree root.
83
+ function inboxOf(address token) external view returns (JBInboxTreeRoot memory);
84
+
85
+ /// @notice Whether a token has been mapped for bridging.
86
+ /// @param token The local token address.
87
+ /// @return Whether the token is mapped.
88
+ function isMapped(address token) external view returns (bool);
89
+
90
+ /// @notice The outbox merkle tree for a given token.
91
+ /// @param token The local terminal token.
92
+ /// @return The outbox tree.
93
+ function outboxOf(address token) external view returns (JBOutboxTree memory);
94
+
95
+ /// @notice The chain ID of the remote peer.
96
+ /// @return chainId The remote chain ID.
97
+ function peerChainId() external view returns (uint256 chainId);
98
+
99
+ /// @notice Information about the remote token that a local token is mapped to.
100
+ /// @param token The local terminal token.
101
+ /// @return The remote token info.
102
+ function remoteTokenFor(address token) external view returns (JBRemoteToken memory);
103
+
104
+ /// @notice The current deprecation state of this sucker.
105
+ /// @return The sucker state.
106
+ function state() external view returns (JBSuckerState);
107
+
108
+ /// @notice Add the outstanding reclaimed token balance to the project's terminal.
109
+ /// @param token The terminal token to add to balance.
110
+ function addOutstandingAmountToBalance(address token) external;
111
+
112
+ /// @notice Perform multiple claims of bridged project tokens.
113
+ /// @param claims The claims to perform.
114
+ function claim(JBClaim[] calldata claims) external;
115
+
116
+ /// @notice Claim bridged project tokens for a beneficiary.
117
+ /// @param claimData The claim data including token, leaf, and proof.
118
+ function claim(JBClaim calldata claimData) external;
119
+
120
+ /// @notice Map a local token to a remote token for bridging.
121
+ /// @param map The token mapping to add.
122
+ function mapToken(JBTokenMapping calldata map) external payable;
123
+
124
+ /// @notice Map multiple local tokens to remote tokens for bridging.
125
+ /// @param maps The token mappings to add.
126
+ function mapTokens(JBTokenMapping[] calldata maps) external payable;
127
+
128
+ /// @notice Cash out project tokens and add a leaf to the outbox tree for bridging.
129
+ /// @param projectTokenCount The number of project tokens to cash out.
130
+ /// @param beneficiary The beneficiary on the remote chain (bytes32 for cross-VM compatibility).
131
+ /// @param minTokensReclaimed The minimum terminal tokens to receive from the cash out.
132
+ /// @param token The terminal token to cash out into.
133
+ function prepare(
134
+ uint256 projectTokenCount,
135
+ bytes32 beneficiary,
136
+ uint256 minTokensReclaimed,
137
+ address token
138
+ )
139
+ external;
140
+
141
+ /// @notice Send the outbox tree root and bridged assets to the remote peer.
142
+ /// @param token The terminal token to bridge.
143
+ function toRemote(address token) external payable;
144
+ }
@@ -0,0 +1,40 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
5
+ import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
6
+
7
+ import {IJBSucker} from "./IJBSucker.sol";
8
+
9
+ /// @notice The interface for deploying sucker contracts.
10
+ interface IJBSuckerDeployer {
11
+ error JBSuckerDeployer_AlreadyConfigured();
12
+ error JBSuckerDeployer_DeployerIsNotConfigured();
13
+ error JBSuckerDeployer_InvalidLayerSpecificConfiguration();
14
+ error JBSuckerDeployer_LayerSpecificNotConfigured();
15
+ error JBSuckerDeployer_Unauthorized(address caller, address expected);
16
+ error JBSuckerDeployer_ZeroConfiguratorAddress();
17
+
18
+ /// @notice The Juicebox directory.
19
+ /// @return The directory contract.
20
+ function DIRECTORY() external view returns (IJBDirectory);
21
+
22
+ /// @notice The token registry.
23
+ /// @return The tokens contract.
24
+ function TOKENS() external view returns (IJBTokens);
25
+
26
+ /// @notice The address authorized to set layer-specific configuration.
27
+ /// @return The configurator address.
28
+ function LAYER_SPECIFIC_CONFIGURATOR() external view returns (address);
29
+
30
+ /// @notice Whether the given address is a sucker deployed by this deployer.
31
+ /// @param sucker The address to check.
32
+ /// @return Whether the address is a deployed sucker.
33
+ function isSucker(address sucker) external view returns (bool);
34
+
35
+ /// @notice Deploy a new sucker for the given project.
36
+ /// @param localProjectId The project's ID on the local chain.
37
+ /// @param salt The salt for deterministic deployment.
38
+ /// @return sucker The newly deployed sucker.
39
+ function createForSender(uint256 localProjectId, bytes32 salt) external returns (IJBSucker sucker);
40
+ }
@@ -0,0 +1,22 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IJBSucker, JBClaim} from "./IJBSucker.sol";
5
+
6
+ /// @notice Contains the IJBSucker interface and extends it with additional functions and events.
7
+ interface IJBSuckerExtended is IJBSucker {
8
+ event EmergencyHatchOpened(address[] tokens, address caller);
9
+ event DeprecationTimeUpdated(uint40 timestamp, address caller);
10
+
11
+ /// @notice Open the emergency hatch for the specified tokens, allowing direct claims without bridging.
12
+ /// @param tokens The tokens to enable the emergency hatch for.
13
+ function enableEmergencyHatchFor(address[] calldata tokens) external;
14
+
15
+ /// @notice Claim tokens through the emergency hatch when bridging is unavailable.
16
+ /// @param claimData The claim data including token, leaf, and proof.
17
+ function exitThroughEmergencyHatch(JBClaim calldata claimData) external;
18
+
19
+ /// @notice Set or update the deprecation timestamp for this sucker.
20
+ /// @param timestamp The timestamp after which the sucker is deprecated.
21
+ function setDeprecation(uint40 timestamp) external;
22
+ }
@@ -0,0 +1,75 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
5
+ import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
6
+ import {JBSuckerDeployerConfig} from "../structs/JBSuckerDeployerConfig.sol";
7
+ import {JBSuckersPair} from "../structs/JBSuckersPair.sol";
8
+
9
+ /// @notice The interface for the sucker registry, which tracks deployed suckers and manages deployer allowlists.
10
+ interface IJBSuckerRegistry {
11
+ event SuckerDeployedFor(uint256 projectId, address sucker, JBSuckerDeployerConfig configuration, address caller);
12
+ event SuckerDeployerAllowed(address deployer, address caller);
13
+ event SuckerDeployerRemoved(address deployer, address caller);
14
+ event SuckerDeprecated(uint256 projectId, address sucker, address caller);
15
+
16
+ /// @notice The Juicebox directory.
17
+ /// @return The directory contract.
18
+ function DIRECTORY() external view returns (IJBDirectory);
19
+
20
+ /// @notice The project registry.
21
+ /// @return The projects contract.
22
+ function PROJECTS() external view returns (IJBProjects);
23
+
24
+ /// @notice Returns true if the specified sucker belongs to the specified project and was deployed through this
25
+ /// registry.
26
+ /// @param projectId The ID of the project to check for.
27
+ /// @param addr The address of the sucker to check.
28
+ /// @return Whether the sucker belongs to the project.
29
+ function isSuckerOf(uint256 projectId, address addr) external view returns (bool);
30
+
31
+ /// @notice Whether the specified sucker deployer is approved by this registry.
32
+ /// @param deployer The address of the deployer to check.
33
+ /// @return Whether the deployer is allowed.
34
+ function suckerDeployerIsAllowed(address deployer) external view returns (bool);
35
+
36
+ /// @notice Returns the pairs of suckers and their metadata for a project.
37
+ /// @param projectId The ID of the project.
38
+ /// @return pairs The local/remote sucker pairs.
39
+ function suckerPairsOf(uint256 projectId) external view returns (JBSuckersPair[] memory pairs);
40
+
41
+ /// @notice Returns all suckers for a project.
42
+ /// @param projectId The ID of the project.
43
+ /// @return The addresses of the suckers.
44
+ function suckersOf(uint256 projectId) external view returns (address[] memory);
45
+
46
+ /// @notice Add a sucker deployer to the allowlist.
47
+ /// @param deployer The address of the deployer to allow.
48
+ function allowSuckerDeployer(address deployer) external;
49
+
50
+ /// @notice Add multiple sucker deployers to the allowlist.
51
+ /// @param deployers The addresses of the deployers to allow.
52
+ function allowSuckerDeployers(address[] calldata deployers) external;
53
+
54
+ /// @notice Deploy one or more suckers for the specified project.
55
+ /// @param projectId The ID of the project to deploy suckers for.
56
+ /// @param salt The salt used for deterministic deployment.
57
+ /// @param configurations The deployer configs to use.
58
+ /// @return suckers The addresses of the deployed suckers.
59
+ function deploySuckersFor(
60
+ uint256 projectId,
61
+ bytes32 salt,
62
+ JBSuckerDeployerConfig[] calldata configurations
63
+ )
64
+ external
65
+ returns (address[] memory suckers);
66
+
67
+ /// @notice Remove a deprecated sucker from a project.
68
+ /// @param projectId The ID of the project.
69
+ /// @param sucker The address of the deprecated sucker to remove.
70
+ function removeDeprecatedSucker(uint256 projectId, address sucker) external;
71
+
72
+ /// @notice Remove a sucker deployer from the allowlist.
73
+ /// @param deployer The address of the deployer to remove.
74
+ function removeSuckerDeployer(address deployer) external;
75
+ }
@@ -0,0 +1,18 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ interface IOPMessenger {
5
+ function xDomainMessageSender() external returns (address);
6
+
7
+ function bridgeERC20To(
8
+ address localToken,
9
+ address remoteToken,
10
+ address to,
11
+ uint256 amount,
12
+ uint32 minGasLimit,
13
+ bytes calldata extraData
14
+ )
15
+ external;
16
+
17
+ function sendMessage(address target, bytes memory message, uint32 gasLimit) external payable;
18
+ }
@@ -0,0 +1,29 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ interface IOPStandardBridge {
5
+ /**
6
+ * @notice Sends ERC20 tokens to a receiver's address on the other chain. Note that if the
7
+ * ERC20 token on the other chain does not recognize the local token as the correct
8
+ * pair token, the ERC20 bridge will fail and the tokens will be returned to sender on
9
+ * this chain.
10
+ *
11
+ * @param localToken Address of the ERC20 on this chain.
12
+ * @param remoteToken Address of the corresponding token on the remote chain.
13
+ * @param to Address of the receiver.
14
+ * @param amount Amount of local tokens to deposit.
15
+ * @param minGasLimit Minimum amount of gas that the bridge can be relayed with.
16
+ * @param extraData Extra data to be sent with the transaction. Note that the recipient will
17
+ * not be triggered with this data, but it will be emitted and can be used
18
+ * to identify the transaction.
19
+ */
20
+ function bridgeERC20To(
21
+ address localToken,
22
+ address remoteToken,
23
+ address to,
24
+ uint256 amount,
25
+ uint32 minGasLimit,
26
+ bytes calldata extraData
27
+ )
28
+ external;
29
+ }
@@ -0,0 +1,13 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5
+
6
+ /// @title Interface for a wrappned native token
7
+ interface IWrappedNativeToken is IERC20 {
8
+ /// @notice Deposit ether to get wrapped ether
9
+ function deposit() external payable;
10
+
11
+ /// @notice Withdraw wrapped ether to get ether
12
+ function withdraw(uint256) external;
13
+ }