// SPDX-License-Identifier: MIT pragma solidity 0.8.28; import {CoreDeployment, CoreDeploymentLib} from "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol"; import { Univ4RouterDeployment, Univ4RouterDeploymentLib } from "@bananapus/univ4-router-v6/script/helpers/Univ4RouterDeploymentLib.sol"; import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol"; import {Script} from "forge-std/Script.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {JBBuybackHook} from "src/JBBuybackHook.sol"; import {JBBuybackHookRegistry} from "src/JBBuybackHookRegistry.sol"; contract DeployScript is Script, Sphinx { /// @notice tracks the deployment of the core contracts for the chain we are deploying to. CoreDeployment core; /// @notice tracks the deployment of the univ4-router contracts for the chain we are deploying to. Univ4RouterDeployment router; /// @notice the salts that are used to deploy the contracts. bytes32 buybackHook = "JBBuybackHookV6"; /// @notice tracks the addresses that are required for the chain we are deploying to. address poolManager; address trustedForwarder; function configureSphinx() public override { sphinxConfig.projectName = "nana-buyback-hook-v6"; sphinxConfig.mainnets = ["ethereum", "optimism", "base", "arbitrum"]; sphinxConfig.testnets = ["ethereum_sepolia", "optimism_sepolia", "base_sepolia", "arbitrum_sepolia"]; } function run() public { // Get the deployment addresses for the nana CORE for this chain. core = CoreDeploymentLib.getDeployment( vm.envOr("NANA_CORE_DEPLOYMENT_PATH", string("node_modules/@bananapus/core-v6/deployments/")) ); // Get the deployment addresses for the univ4-router for this chain. router = Univ4RouterDeploymentLib.getDeployment( vm.envOr( "NANA_UNIV4_ROUTER_DEPLOYMENT_PATH", string("node_modules/@bananapus/univ4-router-v6/deployments/") ) ); trustedForwarder = core.permissions.trustedForwarder(); // Uniswap V4 PoolManager addresses per chain. // Verify at https://docs.uniswap.org/contracts/v4/deployments if (block.chainid == 1) { poolManager = 0x000000000004444c5dc75cB358380D2e3dE08A90; // Ethereum Mainnet } else if (block.chainid == 11_155_111) { poolManager = 0xE03A1074c86CFeDd5C142C4F04F1a1536e203543; // Ethereum Sepolia } else if (block.chainid == 10) { poolManager = 0x9a13F98Cb987694C9F086b1F5eB990EeA8264Ec3; // Optimism Mainnet } else if (block.chainid == 8453) { poolManager = 0x498581fF718922c3f8e6A244956aF099B2652b2b; // Base Mainnet } else if (block.chainid == 11_155_420) { // Optimism Sepolia — no official V4 PoolManager listed at // https://docs.uniswap.org/contracts/v4/deployments as of 2026-03-24. // Deploy registry only (no buyback hook) until a verified PoolManager is available. poolManager = address(0); } else if (block.chainid == 84_532) { poolManager = 0x05E73354cFDd6745C338b50BcFDfA3Aa6fA03408; // Base Sepolia } else if (block.chainid == 42_161) { poolManager = 0x360E68faCcca8cA495c1B759Fd9EEe466db9FB32; // Arbitrum Mainnet } else if (block.chainid == 421_614) { poolManager = 0xFB3e0C6F74eB1a21CC1Da29aeC80D2Dfe6C9a317; // Arbitrum Sepolia } else { revert("Invalid RPC / no juice contracts deployed on this network"); } // Perform the deployment transactions. deploy(); } function deploy() public sphinx { // Deploy the registry. JBBuybackHookRegistry registry = new JBBuybackHookRegistry{salt: buybackHook}({ permissions: core.permissions, projects: core.projects, owner: safeAddress(), trustedForwarder: trustedForwarder }); // Skip the buyback hook when no verified PoolManager is available (e.g. Optimism Sepolia). // The registry is still deployed so it can be configured later once a PoolManager is verified. if (poolManager == address(0)) return; // Deploy the V4 buyback hook with chain-identical CREATE2 inputs; chain-specific constants // (PoolManager + ORACLE_HOOK) are configured one-shot via setChainSpecificConstants below. JBBuybackHook hook = new JBBuybackHook{salt: buybackHook}({ directory: core.directory, permissions: core.permissions, prices: core.prices, projects: core.projects, tokens: core.tokens, deployer: safeAddress(), trustedForwarder: trustedForwarder }); hook.setChainSpecificConstants({newPoolManager: IPoolManager(poolManager), newOracleHook: router.hook}); // Configure the hook to be the default. registry.setDefaultHook(hook); } /// @dev This uses the deterministic CREATE2 deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C), /// but Sphinx deployments use a different deployer address. As a result, this check will not /// detect contracts deployed via the Sphinx pipeline. Only useful for non-Sphinx deployments. function _isDeployed(bytes32 salt, bytes memory creationCode, bytes memory arguments) internal view returns (bool) { address _deployedTo = vm.computeCreate2Address({ salt: salt, initCodeHash: keccak256(abi.encodePacked(creationCode, arguments)), deployer: address(0x4e59b44847b379578588920cA78FbF26c0B4956C) }); return address(_deployedTo).code.length != 0; } }