Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/deployment script #2

Merged
merged 7 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ cache/
out/

# Ignores development broadcast logs
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/
broadcast/

# Docs
docs/
Expand Down
6 changes: 5 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ number_underscore = "preserve"

[profile.default.rpc_endpoints]
mainnet = "${MAINNET_RPC_URL}"
tenderly = "${TENDERLY_FORK_URL}"
sepolia = "${SEPOLIA_RPC_URL}"
tenderly = "${TENDERLY_FORK_URL}"

# forge script --chain mainnet script/DeployLocal.s.sol:DeployLocalScript --rpc-url https://eth-mainnet.alchemyapi.io/v2/B4w2ueJLjihQPuf868vthxg7FvfND5i5
# forge script --chain sepolia script/DeploySepolia.s.sol:DeploySepoliaScript --rpc-url https://eth-sepolia.g.alchemy.com/v2/6U2Z1L4BEW2VkZeHS5NQAWrvciif1DDI
12 changes: 0 additions & 12 deletions script/Counter.s.sol

This file was deleted.

181 changes: 181 additions & 0 deletions script/DeploySepolia.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script} from "forge-std/Script.sol";
import {MockERC20} from "forge-std/mocks/MockERC20.sol";

import {PoolManager, Deployers, Hooks} from "v4-core/test/utils/Deployers.sol";
import {ICurveStableswapFactoryNG} from "../src/interfaces/ICurveStableswapFactoryNG.sol";
import {ICurveStableswapNG} from "../src/interfaces/ICurveStableswapNG.sol";
import {ILiquidityGauge} from "./../src/interfaces/ILiquidityGauge.sol";

import {IGovernance} from "../src/interfaces/IGovernance.sol";

import {Governance} from "../src/Governance.sol";
import {UniV4Donations} from "../src/UniV4Donations.sol";
import {CurveV2GaugeRewards} from "../src/CurveV2GaugeRewards.sol";
import {Hooks} from "../src/utils/BaseHook.sol";

import {MockStakingV1} from "../test/mocks/MockStakingV1.sol";
import {HookMiner} from "./utils/HookMiner.sol";

contract DeploySepoliaScript is Script, Deployers {
// Environment Constants
MockERC20 private lqty;
MockERC20 private bold;
address private stakingV1;
MockERC20 private usdc;

PoolManager private constant poolManager = PoolManager(0xE8E23e97Fa135823143d6b9Cba9c699040D51F70);
ICurveStableswapFactoryNG private constant curveFactory =
ICurveStableswapFactoryNG(address(0xfb37b8D939FFa77114005e61CFc2e543d6F49A81));

// Governance Constants
uint128 private constant REGISTRATION_FEE = 100e18;
uint128 private constant REGISTRATION_THRESHOLD_FACTOR = 0.001e18;
uint128 private constant UNREGISTRATION_THRESHOLD_FACTOR = 3e18;
uint16 private constant REGISTRATION_WARM_UP_PERIOD = 4;
uint16 private constant UNREGISTRATION_AFTER_EPOCHS = 4;
uint128 private constant VOTING_THRESHOLD_FACTOR = 0.03e18;
uint88 private constant MIN_CLAIM = 500e18;
uint88 private constant MIN_ACCRUAL = 1000e18;
uint32 private constant EPOCH_DURATION = 604800;
uint32 private constant EPOCH_VOTING_CUTOFF = 518400;

// UniV4Donations Constants
uint256 private immutable VESTING_EPOCH_START = block.timestamp;
uint256 private constant VESTING_EPOCH_DURATION = 7 days;
uint24 private constant FEE = 400;
int24 constant MAX_TICK_SPACING = 32767;

// CurveV2GaugeRewards Constants
uint256 private constant DURATION = 7 days;

// Contracts
Governance private governance;
address[] private initialInitiatives;
UniV4Donations private uniV4Donations;
CurveV2GaugeRewards private curveV2GaugeRewards;
ICurveStableswapNG private curvePool;
ILiquidityGauge private gauge;

// Deployer
address private deployer;
uint256 private privateKey;
uint256 private nonce;

function setUp() public {
privateKey = vm.envUint("PRIVATE_KEY");
deployer = vm.createWallet(privateKey).addr;
nonce = vm.getNonce(deployer);
}

function deployEnvironment() private {
lqty = deployMockERC20("Liquity", "LQTY", 18);
bold = deployMockERC20("Bold", "BOLD", 18);
usdc = deployMockERC20("USD Coin", "USDC", 6);
stakingV1 = address(new MockStakingV1(address(lqty)));
}

function deployGovernance() private {
governance = new Governance(
address(lqty),
address(bold),
stakingV1,
address(bold),
IGovernance.Configuration({
registrationFee: REGISTRATION_FEE,
registrationThresholdFactor: REGISTRATION_THRESHOLD_FACTOR,
unregistrationThresholdFactor: UNREGISTRATION_THRESHOLD_FACTOR,
registrationWarmUpPeriod: REGISTRATION_WARM_UP_PERIOD,
unregistrationAfterEpochs: UNREGISTRATION_AFTER_EPOCHS,
votingThresholdFactor: VOTING_THRESHOLD_FACTOR,
minClaim: MIN_CLAIM,
minAccrual: MIN_ACCRUAL,
epochStart: uint32(block.timestamp),
epochDuration: EPOCH_DURATION,
epochVotingCutoff: EPOCH_VOTING_CUTOFF
}),
initialInitiatives
);
assert(governance == uniV4Donations.governance());
}

function deployUniV4Donations(uint256 _nonce) private {
address gov = address(vm.computeCreateAddress(deployer, _nonce));
uint160 flags = uint160(Hooks.AFTER_INITIALIZE_FLAG | Hooks.AFTER_ADD_LIQUIDITY_FLAG);

(, bytes32 salt) = HookMiner.find(
0x4e59b44847b379578588920cA78FbF26c0B4956C,
// address(this),
flags,
type(UniV4Donations).creationCode,
abi.encode(
gov,
address(bold),
address(lqty),
block.timestamp,
EPOCH_DURATION,
address(poolManager),
address(usdc),
FEE,
MAX_TICK_SPACING
)
);

uniV4Donations = new UniV4Donations{salt: salt}(
gov,
address(bold),
address(lqty),
block.timestamp,
EPOCH_DURATION,
address(poolManager),
address(usdc),
FEE,
MAX_TICK_SPACING
);

initialInitiatives.push(address(uniV4Donations));
}

function deployCurveV2GaugeRewards(uint256 _nonce) private {
address[] memory _coins = new address[](2);
_coins[0] = address(bold);
_coins[1] = address(usdc);
uint8[] memory _asset_types = new uint8[](2);
_asset_types[0] = 0;
_asset_types[1] = 0;
bytes4[] memory _method_ids = new bytes4[](2);
_method_ids[0] = 0x0;
_method_ids[1] = 0x0;
address[] memory _oracles = new address[](2);
_oracles[0] = address(0x0);
_oracles[1] = address(0x0);

curvePool = ICurveStableswapNG(
curveFactory.deploy_plain_pool(
"BOLD-USDC", "BOLDUSDC", _coins, 200, 1000000, 50000000000, 866, 0, _asset_types, _method_ids, _oracles
)
);

gauge = ILiquidityGauge(curveFactory.deploy_gauge(address(curvePool)));

curveV2GaugeRewards = new CurveV2GaugeRewards(
address(vm.computeCreateAddress(address(this), _nonce)),
address(bold),
address(lqty),
address(gauge),
DURATION
);

initialInitiatives.push(address(curveV2GaugeRewards));
}

function run() public {
vm.startBroadcast(privateKey);
deployEnvironment();
deployUniV4Donations(nonce + 8);
deployGovernance();
vm.stopBroadcast();
}
}
52 changes: 52 additions & 0 deletions script/utils/HookMiner.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.21;

/// @title HookMiner - a library for mining hook addresses
/// @dev This library is intended for `forge test` environments. There may be gotchas when using salts in `forge script` or `forge create`
library HookMiner {
// mask to slice out the bottom 14 bit of the address
uint160 constant FLAG_MASK = 0x3FFF;

// Maximum number of iterations to find a salt, avoid infinite loops
uint256 constant MAX_LOOP = 100_000;

/// @notice Find a salt that produces a hook address with the desired `flags`
/// @param deployer The address that will deploy the hook. In `forge test`, this will be the test contract `address(this)` or the pranking address
/// In `forge script`, this should be `0x4e59b44847b379578588920cA78FbF26c0B4956C` (CREATE2 Deployer Proxy)
/// @param flags The desired flags for the hook address
/// @param creationCode The creation code of a hook contract. Example: `type(Counter).creationCode`
/// @param constructorArgs The encoded constructor arguments of a hook contract. Example: `abi.encode(address(manager))`
/// @return hookAddress salt and corresponding address that was found. The salt can be used in `new Hook{salt: salt}(<constructor arguments>)`
function find(address deployer, uint160 flags, bytes memory creationCode, bytes memory constructorArgs)
internal
view
returns (address, bytes32)
{
address hookAddress;
bytes memory creationCodeWithArgs = abi.encodePacked(creationCode, constructorArgs);

uint256 salt;
for (salt; salt < MAX_LOOP; salt++) {
hookAddress = computeAddress(deployer, salt, creationCodeWithArgs);
if (uint160(hookAddress) & FLAG_MASK == flags && hookAddress.code.length == 0) {
return (hookAddress, bytes32(salt));
}
}
revert("HookMiner: could not find salt");
}

/// @notice Precompute a contract address deployed via CREATE2
/// @param deployer The address that will deploy the hook. In `forge test`, this will be the test contract `address(this)` or the pranking address
/// In `forge script`, this should be `0x4e59b44847b379578588920cA78FbF26c0B4956C` (CREATE2 Deployer Proxy)
/// @param salt The salt used to deploy the hook
/// @param creationCode The creation code of a hook contract
function computeAddress(address deployer, uint256 salt, bytes memory creationCode)
internal
pure
returns (address hookAddress)
{
return address(
uint160(uint256(keccak256(abi.encodePacked(bytes1(0xFF), deployer, salt, keccak256(creationCode)))))
);
}
}
2 changes: 0 additions & 2 deletions test/Governance.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,6 @@ contract GovernanceTest is Test {
address userProxy = governance.deployUserProxy();

vm.store(address(lqty), keccak256(abi.encode(user, 0)), bytes32(abi.encode(uint256(_deltaLQTYVotes))));
console.log(lqty.balanceOf(user));
lqty.approve(address(userProxy), _deltaLQTYVotes);
governance.depositLQTY(_deltaLQTYVotes);

Expand All @@ -948,7 +947,6 @@ contract GovernanceTest is Test {
address userProxy = governance.deployUserProxy();

vm.store(address(lqty), keccak256(abi.encode(user, 0)), bytes32(abi.encode(uint256(_deltaLQTYVetos))));
console.log(lqty.balanceOf(user));
lqty.approve(address(userProxy), _deltaLQTYVetos);
governance.depositLQTY(_deltaLQTYVetos);

Expand Down
2 changes: 1 addition & 1 deletion test/UniV4Donations.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {Test} from "forge-std/Test.sol";

import {IERC20} from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";

import {IPoolManager, PoolManager, Deployers, TickMath, Hooks} from "v4-core/test/utils/Deployers.sol";
import {IPoolManager, PoolManager, Deployers, TickMath, Hooks, IHooks} from "v4-core/test/utils/Deployers.sol";
import {PoolModifyLiquidityTest} from "v4-core/src/test/PoolModifyLiquidityTest.sol";

import {IGovernance} from "../src/interfaces/IGovernance.sol";
Expand Down