@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
package/foundry.lock ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "lib/forge-std": {
3
+ "rev": "83c5d212a01f8950727da4095cdfe2654baccb5b"
4
+ },
5
+ "lib/sphinx": {
6
+ "branch": {
7
+ "name": "v0.23.0",
8
+ "rev": "5fb24a825f46bd6ae0b5359fe0da1d2346126b09"
9
+ }
10
+ }
11
+ }
package/foundry.toml ADDED
@@ -0,0 +1,22 @@
1
+ [profile.default]
2
+ solc = '0.8.23'
3
+ evm_version = 'paris'
4
+ optimizer_runs = 2000
5
+ libs = ["node_modules", "lib"]
6
+ fs_permissions = [{ access = "read-write", path = "./"}]
7
+
8
+ [profile.ci_sizes]
9
+ optimizer_runs = 200
10
+
11
+ [fuzz]
12
+ runs = 4096
13
+
14
+ [invariant]
15
+ runs = 1024
16
+ depth = 100
17
+ fail_on_revert = false
18
+
19
+ [fmt]
20
+ number_underscore = "thousands"
21
+ multiline_func_header = "all"
22
+ wrap_comments = true
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@bananapus/suckers-v6",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/Bananapus/nana-suckers-v6"
8
+ },
9
+ "engines": {
10
+ "node": ">=20.0.0"
11
+ },
12
+ "scripts": {
13
+ "test": "forge test",
14
+ "coverage": "forge coverage --match-path \"./src/*.sol\" --report lcov --report summary",
15
+ "deploy:mainnets": "source ./.env && npx sphinx propose ./script/Deploy.s.sol --networks mainnets",
16
+ "deploy:testnets": "source ./.env && npx sphinx propose ./script/Deploy.s.sol --networks testnets",
17
+ "artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'nana-suckers-v6'",
18
+ "analyze": "slither . --config-file slither-ci.config.json"
19
+ },
20
+ "dependencies": {
21
+ "@arbitrum/nitro-contracts": "github:OffchainLabs/nitro-contracts",
22
+ "@bananapus/core-v6": "^0.0.1",
23
+ "@bananapus/permission-ids-v6": "^0.0.1",
24
+ "@chainlink/contracts-ccip": "^1.5.0",
25
+ "@chainlink/local": "github:smartcontractkit/chainlink-local",
26
+ "@openzeppelin/contracts": "^5.2.0",
27
+ "@prb/math": "^4.1.0",
28
+ "solady": "^0.1.8"
29
+ },
30
+ "devDependencies": {
31
+ "@sphinx-labs/plugins": "^0.33.1"
32
+ }
33
+ }
package/remappings.txt ADDED
@@ -0,0 +1 @@
1
+ @sphinx-labs/contracts/=node_modules/@sphinx-labs/contracts/contracts/foundry
@@ -0,0 +1,506 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import "../src/deployers/JBOptimismSuckerDeployer.sol";
5
+ import "../src/deployers/JBBaseSuckerDeployer.sol";
6
+ import "../src/deployers/JBArbitrumSuckerDeployer.sol";
7
+ import "../src/deployers/JBCCIPSuckerDeployer.sol";
8
+ import "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
9
+
10
+ import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
11
+ import {Script} from "forge-std/Script.sol";
12
+ import {JBSuckerRegistry} from "./../src/JBSuckerRegistry.sol";
13
+ import {ICCIPRouter} from "./../src/interfaces/ICCIPRouter.sol";
14
+ import {ARBAddresses} from "../src/libraries/ARBAddresses.sol";
15
+ import {ARBChains} from "../src/libraries/ARBChains.sol";
16
+ import {CCIPHelper} from "../src/libraries/CCIPHelper.sol";
17
+
18
+ contract DeployScript is Script, Sphinx {
19
+ /// @notice tracks the deployment of the core contracts for the chain we are deploying to.
20
+ CoreDeployment core;
21
+ /// @notice tracks the addressed of the deployers that will get pre-approved.
22
+ address[] PRE_APPROVED_DEPLOYERS;
23
+
24
+ address TRUSTED_FORWARDER;
25
+
26
+ /// @notice the nonces that are used to deploy the contracts.
27
+ bytes32 OP_SALT = "_SUCKER_ETH_OP_V6_";
28
+ bytes32 BASE_SALT = "_SUCKER_ETH_BASE_V6_";
29
+ bytes32 ARB_SALT = "_SUCKER_ETH_ARB_V6_";
30
+
31
+ bytes32 ARB_BASE_SALT = "_SUCKER_ARB_BASE_V6_";
32
+ bytes32 ARB_OP_SALT = "_SUCKER_ARB_OP_V6_";
33
+ bytes32 OP_BASE_SALT = "_SUCKER_OP_BASE_V6_";
34
+
35
+ bytes32 REGISTRY_SALT = "REGISTRYV6";
36
+
37
+ function configureSphinx() public override {
38
+ // TODO: Update to contain JB Emergency Developers
39
+ sphinxConfig.projectName = "nana-suckers-v5";
40
+ sphinxConfig.mainnets = ["ethereum", "optimism", "base", "arbitrum"];
41
+ sphinxConfig.testnets = ["ethereum_sepolia", "optimism_sepolia", "base_sepolia", "arbitrum_sepolia"];
42
+ }
43
+
44
+ function run() public {
45
+ // Get the deployment addresses for the nana CORE for this chain.
46
+ // We want to do this outside of the `sphinx` modifier.
47
+ core = CoreDeploymentLib.getDeployment(
48
+ vm.envOr("NANA_CORE_DEPLOYMENT_PATH", string("node_modules/@bananapus/core-v6/deployments/"))
49
+ );
50
+
51
+ // We use the same trusted forwarder as the core deployment.
52
+ TRUSTED_FORWARDER = core.permissions.trustedForwarder();
53
+
54
+ // Perform the deployment transactions.
55
+ deploy();
56
+ }
57
+
58
+ function deploy() public sphinx {
59
+ // Perform the deployments for this chain, then deploy the registry and pre-approve the deployers.
60
+ _optimismSucker();
61
+ _baseSucker();
62
+ _arbitrumSucker();
63
+ _ccipSucker();
64
+
65
+ // If the registry is already deployed we don't have to deploy it
66
+ // (and we can't add more pre_approved deployers etc.)
67
+ if (!_isDeployed(
68
+ REGISTRY_SALT,
69
+ type(JBSuckerRegistry).creationCode,
70
+ abi.encode(core.directory, core.permissions, safeAddress(), TRUSTED_FORWARDER)
71
+ )) {
72
+ // Deploy the registry and pre-aprove the deployers we just deployed.
73
+ JBSuckerRegistry _registry = new JBSuckerRegistry{salt: REGISTRY_SALT}({
74
+ directory: core.directory,
75
+ permissions: core.permissions,
76
+ initialOwner: safeAddress(),
77
+ trustedForwarder: TRUSTED_FORWARDER
78
+ });
79
+
80
+ // Before transferring ownership to JBDAO we approve the deployers.
81
+ if (PRE_APPROVED_DEPLOYERS.length != 0) {
82
+ _registry.allowSuckerDeployers(PRE_APPROVED_DEPLOYERS);
83
+ }
84
+
85
+ // Check what safe this is, if this is the same one as the fee-project owner, then we do not need to
86
+ // transfer. If its not then we transfer to the fee-project safe.
87
+ // NOTE: If this is ran after the configuration of the fee-project, this would transfer it to the
88
+ // REVNET_DEPLOYER. which is *NOT* what we want to happen. In our regular deployment procedure this should
89
+ // never happen though.
90
+ address feeProjectOwner = core.projects.ownerOf(1);
91
+ if (feeProjectOwner != address(0) && feeProjectOwner != safeAddress()) {
92
+ // Transfer ownership to JBDAO.
93
+ _registry.transferOwnership(feeProjectOwner);
94
+ }
95
+ }
96
+ }
97
+
98
+ /// @notice handles the deployment and configuration regarding optimism (this also includes the mainnet
99
+ /// configuration).
100
+ function _optimismSucker() internal {
101
+ // Check if this sucker is already deployed on this chain,
102
+ // if that is the case we don't need to do anything else for this chain.
103
+ if (_isDeployed(
104
+ OP_SALT,
105
+ type(JBOptimismSuckerDeployer).creationCode,
106
+ abi.encode(core.directory, core.permissions, core.tokens, safeAddress(), TRUSTED_FORWARDER)
107
+ )) return;
108
+
109
+ // Check if we should do the L1 portion.
110
+ // ETH Mainnet and ETH Sepolia.
111
+ if (block.chainid == 1 || block.chainid == 11_155_111) {
112
+ JBOptimismSuckerDeployer _opDeployer = new JBOptimismSuckerDeployer{salt: OP_SALT}({
113
+ directory: core.directory,
114
+ permissions: core.permissions,
115
+ tokens: core.tokens,
116
+ configurator: safeAddress(),
117
+ trustedForwarder: TRUSTED_FORWARDER
118
+ });
119
+
120
+ _opDeployer.setChainSpecificConstants(
121
+ IOPMessenger(
122
+ block.chainid == 1
123
+ ? address(0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1)
124
+ : address(0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef)
125
+ ),
126
+ IOPStandardBridge(
127
+ block.chainid == 1
128
+ ? address(0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1)
129
+ : address(0xFBb0621E0B23b5478B630BD55a5f21f67730B0F1)
130
+ )
131
+ );
132
+
133
+ // Deploy the singleton instance.
134
+ JBOptimismSucker _singleton = new JBOptimismSucker{salt: OP_SALT}({
135
+ deployer: _opDeployer,
136
+ directory: core.directory,
137
+ permissions: core.permissions,
138
+ tokens: core.tokens,
139
+ addToBalanceMode: JBAddToBalanceMode.ON_CLAIM,
140
+ trustedForwarder: TRUSTED_FORWARDER
141
+ });
142
+
143
+ // Configure the deployer to use the singleton instance.
144
+ _opDeployer.configureSingleton(_singleton);
145
+
146
+ PRE_APPROVED_DEPLOYERS.push(address(_opDeployer));
147
+ }
148
+
149
+ // Check if we should do the L2 portion.
150
+ // OP & OP Sepolia.
151
+ if (block.chainid == 10 || block.chainid == 11_155_420) {
152
+ JBOptimismSuckerDeployer _opDeployer = new JBOptimismSuckerDeployer{salt: OP_SALT}({
153
+ directory: core.directory,
154
+ permissions: core.permissions,
155
+ tokens: core.tokens,
156
+ configurator: safeAddress(),
157
+ trustedForwarder: TRUSTED_FORWARDER
158
+ });
159
+
160
+ _opDeployer.setChainSpecificConstants(
161
+ IOPMessenger(0x4200000000000000000000000000000000000007),
162
+ IOPStandardBridge(0x4200000000000000000000000000000000000010)
163
+ );
164
+
165
+ // Deploy the singleton instance.
166
+ JBOptimismSucker _singleton = new JBOptimismSucker{salt: OP_SALT}({
167
+ deployer: _opDeployer,
168
+ directory: core.directory,
169
+ permissions: core.permissions,
170
+ tokens: core.tokens,
171
+ addToBalanceMode: JBAddToBalanceMode.ON_CLAIM,
172
+ trustedForwarder: TRUSTED_FORWARDER
173
+ });
174
+
175
+ // Configure the deployer to use the singleton instance.
176
+ _opDeployer.configureSingleton(_singleton);
177
+
178
+ PRE_APPROVED_DEPLOYERS.push(address(_opDeployer));
179
+ }
180
+ }
181
+
182
+ /// @notice handles the deployment and configuration regarding base (this also includes the mainnet configuration).
183
+ function _baseSucker() internal {
184
+ // Check if this sucker is already deployed on this chain,
185
+ // if that is the case we don't need to do anything else for this chain.
186
+ if (_isDeployed(
187
+ BASE_SALT,
188
+ type(JBBaseSuckerDeployer).creationCode,
189
+ abi.encode(core.directory, core.permissions, core.tokens, safeAddress(), TRUSTED_FORWARDER)
190
+ )) return;
191
+
192
+ // Check if we should do the L1 portion.
193
+ // ETH Mainnet and ETH Sepolia.
194
+ if (block.chainid == 1 || block.chainid == 11_155_111) {
195
+ JBBaseSuckerDeployer _baseDeployer = new JBBaseSuckerDeployer{salt: BASE_SALT}({
196
+ directory: core.directory,
197
+ permissions: core.permissions,
198
+ tokens: core.tokens,
199
+ configurator: safeAddress(),
200
+ trustedForwarder: TRUSTED_FORWARDER
201
+ });
202
+
203
+ _baseDeployer.setChainSpecificConstants(
204
+ IOPMessenger(
205
+ block.chainid == 1
206
+ ? address(0x866E82a600A1414e583f7F13623F1aC5d58b0Afa)
207
+ : address(0xC34855F4De64F1840e5686e64278da901e261f20)
208
+ ),
209
+ IOPStandardBridge(
210
+ block.chainid == 1
211
+ ? address(0x3154Cf16ccdb4C6d922629664174b904d80F2C35)
212
+ : address(0xfd0Bf71F60660E2f608ed56e1659C450eB113120)
213
+ )
214
+ );
215
+
216
+ // Deploy the singleton instance.
217
+ JBBaseSucker _singleton = new JBBaseSucker{salt: BASE_SALT}({
218
+ deployer: _baseDeployer,
219
+ directory: core.directory,
220
+ permissions: core.permissions,
221
+ tokens: core.tokens,
222
+ addToBalanceMode: JBAddToBalanceMode.ON_CLAIM,
223
+ trustedForwarder: TRUSTED_FORWARDER
224
+ });
225
+
226
+ // Configure the deployer to use the singleton instance.
227
+ _baseDeployer.configureSingleton(_singleton);
228
+
229
+ PRE_APPROVED_DEPLOYERS.push(address(_baseDeployer));
230
+ }
231
+
232
+ // Check if we should do the L2 portion.
233
+ // BASE & BASE Sepolia.
234
+ if (block.chainid == 8453 || block.chainid == 84_532) {
235
+ JBBaseSuckerDeployer _baseDeployer = new JBBaseSuckerDeployer{salt: BASE_SALT}({
236
+ directory: core.directory,
237
+ permissions: core.permissions,
238
+ tokens: core.tokens,
239
+ configurator: safeAddress(),
240
+ trustedForwarder: TRUSTED_FORWARDER
241
+ });
242
+
243
+ _baseDeployer.setChainSpecificConstants(
244
+ IOPMessenger(0x4200000000000000000000000000000000000007),
245
+ IOPStandardBridge(0x4200000000000000000000000000000000000010)
246
+ );
247
+
248
+ // Deploy the singleton instance.
249
+ JBBaseSucker _singleton = new JBBaseSucker{salt: BASE_SALT}({
250
+ deployer: _baseDeployer,
251
+ directory: core.directory,
252
+ permissions: core.permissions,
253
+ tokens: core.tokens,
254
+ addToBalanceMode: JBAddToBalanceMode.ON_CLAIM,
255
+ trustedForwarder: TRUSTED_FORWARDER
256
+ });
257
+
258
+ // Configure the deployer to use the singleton instance.
259
+ _baseDeployer.configureSingleton(_singleton);
260
+
261
+ PRE_APPROVED_DEPLOYERS.push(address(_baseDeployer));
262
+ }
263
+ }
264
+
265
+ /// @notice handles the deployment and configuration regarding optimism (this also includes the mainnet
266
+ /// configuration).
267
+ function _arbitrumSucker() internal {
268
+ // Check if this sucker is already deployed on this chain,
269
+ // if that is the case we don't need to do anything else for this chain.
270
+ if (_isDeployed(
271
+ ARB_SALT,
272
+ type(JBArbitrumSuckerDeployer).creationCode,
273
+ abi.encode(core.directory, core.permissions, core.tokens, safeAddress(), TRUSTED_FORWARDER)
274
+ )) return;
275
+
276
+ // Check if we should do the L1 portion.
277
+ // ETH Mainnet and ETH Sepolia.
278
+ if (block.chainid == 1 || block.chainid == 11_155_111) {
279
+ JBArbitrumSuckerDeployer _arbDeployer = new JBArbitrumSuckerDeployer{salt: ARB_SALT}({
280
+ directory: core.directory,
281
+ permissions: core.permissions,
282
+ tokens: core.tokens,
283
+ configurator: safeAddress(),
284
+ trustedForwarder: TRUSTED_FORWARDER
285
+ });
286
+
287
+ _arbDeployer.setChainSpecificConstants({
288
+ layer: JBLayer.L1,
289
+ inbox: IInbox(block.chainid == 1 ? ARBAddresses.L1_ETH_INBOX : ARBAddresses.L1_SEP_INBOX),
290
+ gatewayRouter: IArbGatewayRouter(
291
+ block.chainid == 1 ? ARBAddresses.L1_GATEWAY_ROUTER : ARBAddresses.L1_SEP_GATEWAY_ROUTER
292
+ )
293
+ });
294
+
295
+ // Deploy the singleton instance.
296
+ JBArbitrumSucker _singleton = new JBArbitrumSucker{salt: ARB_SALT}({
297
+ deployer: _arbDeployer,
298
+ directory: core.directory,
299
+ permissions: core.permissions,
300
+ tokens: core.tokens,
301
+ addToBalanceMode: JBAddToBalanceMode.ON_CLAIM,
302
+ trustedForwarder: TRUSTED_FORWARDER
303
+ });
304
+
305
+ // Configure the deployer to use the singleton instance.
306
+ _arbDeployer.configureSingleton(_singleton);
307
+
308
+ PRE_APPROVED_DEPLOYERS.push(address(_arbDeployer));
309
+ }
310
+
311
+ // Check if we should do the L2 portion.
312
+ // ARB & ARB Sepolia.
313
+ if (block.chainid == 42_161 || block.chainid == 421_614) {
314
+ JBArbitrumSuckerDeployer _arbDeployer = new JBArbitrumSuckerDeployer{salt: ARB_SALT}({
315
+ directory: core.directory,
316
+ permissions: core.permissions,
317
+ tokens: core.tokens,
318
+ configurator: safeAddress(),
319
+ trustedForwarder: TRUSTED_FORWARDER
320
+ });
321
+
322
+ _arbDeployer.setChainSpecificConstants({
323
+ layer: JBLayer.L2,
324
+ inbox: IInbox(address(0)),
325
+ gatewayRouter: IArbGatewayRouter(
326
+ block.chainid == 42_161 ? ARBAddresses.L2_GATEWAY_ROUTER : ARBAddresses.L2_SEP_GATEWAY_ROUTER
327
+ )
328
+ });
329
+
330
+ // Deploy the singleton instance.
331
+ JBArbitrumSucker _singleton = new JBArbitrumSucker{salt: ARB_SALT}({
332
+ deployer: _arbDeployer,
333
+ directory: core.directory,
334
+ permissions: core.permissions,
335
+ tokens: core.tokens,
336
+ addToBalanceMode: JBAddToBalanceMode.ON_CLAIM,
337
+ trustedForwarder: TRUSTED_FORWARDER
338
+ });
339
+
340
+ // Configure the deployer to use the singleton instance.
341
+ _arbDeployer.configureSingleton(_singleton);
342
+
343
+ PRE_APPROVED_DEPLOYERS.push(address(_arbDeployer));
344
+ }
345
+ }
346
+
347
+ function _ccipSucker() internal {
348
+ // Deploy all the L1 suckers.
349
+ if (block.chainid == 1 || block.chainid == 11_155_111) {
350
+ // Optimsim
351
+ PRE_APPROVED_DEPLOYERS.push(
352
+ address(_deployCCIPSuckerFor(OP_SALT, block.chainid == 1 ? CCIPHelper.OP_ID : CCIPHelper.OP_SEP_ID))
353
+ );
354
+
355
+ // Base
356
+ PRE_APPROVED_DEPLOYERS.push(
357
+ address(
358
+ _deployCCIPSuckerFor(BASE_SALT, block.chainid == 1 ? CCIPHelper.BASE_ID : CCIPHelper.BASE_SEP_ID)
359
+ )
360
+ );
361
+
362
+ // Arbitrum
363
+ PRE_APPROVED_DEPLOYERS.push(
364
+ address(_deployCCIPSuckerFor(ARB_SALT, block.chainid == 1 ? CCIPHelper.ARB_ID : CCIPHelper.ARB_SEP_ID))
365
+ );
366
+ }
367
+
368
+ // Check if we should do the L2 portion.
369
+ // ARB & ARB Sepolia.
370
+ if (block.chainid == 42_161 || block.chainid == 421_614) {
371
+ // L1.
372
+ PRE_APPROVED_DEPLOYERS.push(
373
+ address(
374
+ _deployCCIPSuckerFor(ARB_SALT, block.chainid == 42_161 ? CCIPHelper.ETH_ID : CCIPHelper.ETH_SEP_ID)
375
+ )
376
+ );
377
+
378
+ // ARB -> OP.
379
+ PRE_APPROVED_DEPLOYERS.push(
380
+ address(
381
+ _deployCCIPSuckerFor(ARB_OP_SALT, block.chainid == 42_161 ? CCIPHelper.OP_ID : CCIPHelper.OP_SEP_ID)
382
+ )
383
+ );
384
+
385
+ // ARB -> BASE.
386
+ PRE_APPROVED_DEPLOYERS.push(
387
+ address(
388
+ _deployCCIPSuckerFor(
389
+ ARB_BASE_SALT, block.chainid == 42_161 ? CCIPHelper.BASE_ID : CCIPHelper.BASE_SEP_ID
390
+ )
391
+ )
392
+ );
393
+
394
+ // OP & OP Sepolia.
395
+ } else if (block.chainid == 10 || block.chainid == 11_155_420) {
396
+ // L1.
397
+ PRE_APPROVED_DEPLOYERS.push(
398
+ address(_deployCCIPSuckerFor(OP_SALT, block.chainid == 10 ? CCIPHelper.ETH_ID : CCIPHelper.ETH_SEP_ID))
399
+ );
400
+
401
+ // OP -> ARB.
402
+ PRE_APPROVED_DEPLOYERS.push(
403
+ address(
404
+ _deployCCIPSuckerFor(ARB_OP_SALT, block.chainid == 10 ? CCIPHelper.ARB_ID : CCIPHelper.ARB_SEP_ID)
405
+ )
406
+ );
407
+
408
+ // OP -> BASE.
409
+ PRE_APPROVED_DEPLOYERS.push(
410
+ address(
411
+ _deployCCIPSuckerFor(
412
+ OP_BASE_SALT, block.chainid == 10 ? CCIPHelper.BASE_ID : CCIPHelper.BASE_SEP_ID
413
+ )
414
+ )
415
+ );
416
+
417
+ // BASE & BASE Sepolia.
418
+ } else if (block.chainid == 8453 || block.chainid == 84_532) {
419
+ // L1.
420
+ PRE_APPROVED_DEPLOYERS.push(
421
+ address(
422
+ _deployCCIPSuckerFor(BASE_SALT, block.chainid == 8453 ? CCIPHelper.ETH_ID : CCIPHelper.ETH_SEP_ID)
423
+ )
424
+ );
425
+
426
+ // BASE -> OP.
427
+ PRE_APPROVED_DEPLOYERS.push(
428
+ address(
429
+ _deployCCIPSuckerFor(OP_BASE_SALT, block.chainid == 8453 ? CCIPHelper.OP_ID : CCIPHelper.OP_SEP_ID)
430
+ )
431
+ );
432
+
433
+ // BASE -> ARB.
434
+ PRE_APPROVED_DEPLOYERS.push(
435
+ address(
436
+ _deployCCIPSuckerFor(
437
+ ARB_BASE_SALT, block.chainid == 8453 ? CCIPHelper.ARB_ID : CCIPHelper.ARB_SEP_ID
438
+ )
439
+ )
440
+ );
441
+ }
442
+ }
443
+
444
+ function _deployCCIPSuckerFor(bytes32 salt, uint256 remoteChainId)
445
+ internal
446
+ returns (JBCCIPSuckerDeployer deployer)
447
+ {
448
+ return _deployCCIPSuckerWith(
449
+ salt,
450
+ core.directory,
451
+ core.permissions,
452
+ core.tokens,
453
+ safeAddress(),
454
+ TRUSTED_FORWARDER,
455
+ remoteChainId,
456
+ // Get the selector of the other side.
457
+ CCIPHelper.selectorOfChain(remoteChainId),
458
+ // Get the router for this side.
459
+ ICCIPRouter(CCIPHelper.routerOfChain(block.chainid))
460
+ );
461
+ }
462
+
463
+ function _deployCCIPSuckerWith(
464
+ bytes32 salt,
465
+ IJBDirectory directory,
466
+ IJBPermissions permissions,
467
+ IJBTokens tokens,
468
+ address configurator,
469
+ address trustedForwarder,
470
+ uint256 remoteChainId,
471
+ uint64 remoteChainSelector,
472
+ ICCIPRouter router
473
+ )
474
+ internal
475
+ returns (JBCCIPSuckerDeployer deployer)
476
+ {
477
+ deployer = new JBCCIPSuckerDeployer{salt: salt}(directory, permissions, tokens, configurator, trustedForwarder);
478
+
479
+ deployer.setChainSpecificConstants(remoteChainId, remoteChainSelector, router);
480
+
481
+ // Deploy the singleton instance.
482
+ JBCCIPSucker singleton = new JBCCIPSucker{salt: salt}({
483
+ deployer: deployer,
484
+ directory: directory,
485
+ tokens: tokens,
486
+ permissions: permissions,
487
+ addToBalanceMode: JBAddToBalanceMode.ON_CLAIM,
488
+ trustedForwarder: trustedForwarder
489
+ });
490
+
491
+ // Configure the singleton.
492
+ deployer.configureSingleton(singleton);
493
+ }
494
+
495
+ function _isDeployed(bytes32 salt, bytes memory creationCode, bytes memory arguments) internal view returns (bool) {
496
+ address _deployedTo = vm.computeCreate2Address({
497
+ salt: salt,
498
+ initCodeHash: keccak256(abi.encodePacked(creationCode, arguments)),
499
+ // Arachnid/deterministic-deployment-proxy address.
500
+ deployer: address(0x4e59b44847b379578588920cA78FbF26c0B4956C)
501
+ });
502
+
503
+ // Return if code is already present at this address.
504
+ return address(_deployedTo).code.length != 0;
505
+ }
506
+ }
@@ -0,0 +1,97 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import {stdJson} from "forge-std/Script.sol";
5
+ import {Vm} from "forge-std/Vm.sol";
6
+ import {SphinxConstants, NetworkInfo} from "@sphinx-labs/contracts/SphinxConstants.sol";
7
+
8
+ import {IJBSuckerRegistry} from "./../../src/interfaces/IJBSuckerRegistry.sol";
9
+ import {IJBSuckerDeployer} from "./../../src/interfaces/IJBSuckerDeployer.sol";
10
+
11
+ struct SuckerDeployment {
12
+ IJBSuckerRegistry registry;
13
+ /// @dev only those that are deployed on the requested chain contain an address.
14
+ IJBSuckerDeployer optimismDeployer;
15
+ IJBSuckerDeployer baseDeployer;
16
+ IJBSuckerDeployer arbitrumDeployer;
17
+ }
18
+
19
+ library SuckerDeploymentLib {
20
+ // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D.
21
+ address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
22
+ Vm internal constant vm = Vm(VM_ADDRESS);
23
+
24
+ function getDeployment(string memory path) internal returns (SuckerDeployment memory deployment) {
25
+ // get chainId for which we need to get the deployment.
26
+ uint256 chainId = block.chainid;
27
+
28
+ // Deploy to get the constants.
29
+ // TODO: get constants without deploy.
30
+ SphinxConstants sphinxConstants = new SphinxConstants();
31
+ NetworkInfo[] memory networks = sphinxConstants.getNetworkInfoArray();
32
+
33
+ for (uint256 _i; _i < networks.length; _i++) {
34
+ if (networks[_i].chainId == chainId) {
35
+ return getDeployment(path, networks[_i].name);
36
+ }
37
+ }
38
+
39
+ revert("ChainID is not (currently) supported by Sphinx.");
40
+ }
41
+
42
+ function getDeployment(
43
+ string memory path,
44
+ string memory network_name
45
+ )
46
+ internal
47
+ view
48
+ returns (SuckerDeployment memory deployment)
49
+ {
50
+ // Is deployed on all (supported) chains.
51
+ deployment.registry =
52
+ IJBSuckerRegistry(_getDeploymentAddress(path, "nana-suckers-v5", network_name, "JBSuckerRegistry"));
53
+
54
+ bytes32 _network = keccak256(abi.encodePacked(network_name));
55
+ bool _isMainnet = _network == keccak256("ethereum") || _network == keccak256("sepolia");
56
+ bool _isOP = _network == keccak256("optimism") || _network == keccak256("optimism_sepolia");
57
+ bool _isBase = _network == keccak256("base") || _network == keccak256("base_sepolia");
58
+ bool _isArb = _network == keccak256("arbitrum") || _network == keccak256("arbitrum_sepolia");
59
+
60
+ if (_isMainnet || _isOP) {
61
+ deployment.optimismDeployer = IJBSuckerDeployer(
62
+ _getDeploymentAddress(path, "nana-suckers-v5", network_name, "JBOptimismSuckerDeployer")
63
+ );
64
+ }
65
+
66
+ if (_isMainnet || _isBase) {
67
+ deployment.baseDeployer =
68
+ IJBSuckerDeployer(_getDeploymentAddress(path, "nana-suckers-v5", network_name, "JBBaseSuckerDeployer"));
69
+ }
70
+
71
+ if (_isMainnet || _isArb) {
72
+ deployment.arbitrumDeployer = IJBSuckerDeployer(
73
+ _getDeploymentAddress(path, "nana-suckers-v5", network_name, "JBArbitrumSuckerDeployer")
74
+ );
75
+ }
76
+ }
77
+
78
+ /// @notice Get the address of a contract that was deployed by the Deploy script.
79
+ /// @dev Reverts if the contract was not found.
80
+ /// @param path The path to the deployment file.
81
+ /// @param contractName The name of the contract to get the address of.
82
+ /// @return The address of the contract.
83
+ function _getDeploymentAddress(
84
+ string memory path,
85
+ string memory project_name,
86
+ string memory network_name,
87
+ string memory contractName
88
+ )
89
+ internal
90
+ view
91
+ returns (address)
92
+ {
93
+ string memory deploymentJson =
94
+ vm.readFile(string.concat(path, project_name, "/", network_name, "/", contractName, ".json"));
95
+ return stdJson.readAddress(deploymentJson, ".address");
96
+ }
97
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "detectors_to_exclude": "timestamp,uninitialized-local,naming-convention,solc-version,shadowing-local",
3
+ "exclude_informational": true,
4
+ "exclude_low": false,
5
+ "exclude_medium": false,
6
+ "exclude_high": false,
7
+ "disable_color": false,
8
+ "filter_paths": "(mocks/|test/|node_modules/|lib/)",
9
+ "legacy_ast": false
10
+ }