Skip to content

Commit

Permalink
add a second pool deploy script
Browse files Browse the repository at this point in the history
  • Loading branch information
MattPereira committed Jun 23, 2024
1 parent d4fcc52 commit 661c8d0
Show file tree
Hide file tree
Showing 7 changed files with 890 additions and 40 deletions.
4 changes: 2 additions & 2 deletions packages/foundry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"account": "node script/ListAccount.js",
"chain": "anvil --config-out localhost.json",
"compile": "forge compile",
"deploy:tokens": "forge build --build-info --build-info-path out/build-info/ && forge script script/00_DeployMockTokens.s.sol --rpc-url ${1:-default_network} --broadcast --legacy",
"deploy:factory": "forge build --build-info --build-info-path out/build-info/ && forge script script/01_DeployFactory.s.sol --rpc-url ${1:-default_network} --broadcast --legacy && node script/generateTsAbis.js",
"deploy:pool": "forge build --build-info --build-info-path out/build-info/ && forge script script/02_DeployPool.s.sol --rpc-url ${1:-default_network} --broadcast",
"deploy:pool1": "forge script script/02_DeployPool1.s.sol --rpc-url ${1:-default_network} --broadcast",
"deploy:pool2": "forge script script/03_DeployPool2.s.sol --rpc-url ${1:-default_network} --broadcast",
"deploy:verify": "forge build --build-info --build-info-path out/build-info/ && forge script script/DeployFactoryAndPool.s.sol --rpc-url ${1:-default_network} --broadcast --legacy --verify ; node script/generateTsAbis.js",
"flatten": "forge flatten",
"fork": "anvil --fork-url ${0:-sepolia} --chain-id 31337 --config-out localhost.json",
Expand Down
63 changes: 34 additions & 29 deletions packages/foundry/script/00_DeployMockTokens.s.sol
Original file line number Diff line number Diff line change
@@ -1,36 +1,41 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import { ScaffoldETHDeploy, console } from "./ScaffoldETHDeploy.s.sol";
import { MockToken1 } from "../contracts/MockToken1.sol";
import { MockToken2 } from "../contracts/MockToken2.sol";

/**
* @title Deploy Mock Tokens
* @dev Run this script with `yarn deploy:tokens`
* @notice TODO - to use this deploy script, must figure out how to carry contract info from foundry/ to nextjs/ for more than a single deploy script
* @dev See `ScaffoldETHDeploy.s.sol` and `generateTsAbis.js` to understand why
*/
contract DeployMockTokens is ScaffoldETHDeploy {
function run() external virtual {
uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY");
if (deployerPrivateKey == 0) {
revert InvalidPrivateKey(
"You don't have a deployer account. Make sure you have set DEPLOYER_PRIVATE_KEY in .env or use `yarn generate` to generate a new random account"
);
}

vm.startBroadcast(deployerPrivateKey);
MockToken1 scUSD = new MockToken1("Scaffold USD", "scUSD");
MockToken2 scDAI = new MockToken2("Scaffold DAI", "scDAI");
console.log("Deployed MockToken1 Address: %s", address(scUSD));
console.log("Deployed MockToken2 Address: %s", address(scDAI));
vm.stopBroadcast();
// import { ScaffoldETHDeploy, console } from "./ScaffoldETHDeploy.s.sol";
// import { MockToken1 } from "../contracts/MockToken1.sol";
// import { MockToken2 } from "../contracts/MockToken2.sol";

// /**
// * @title Deploy Mock Tokens
// * @dev Run this script with `yarn deploy:tokens`
// */
// contract DeployMockTokens is ScaffoldETHDeploy {
// function run() external virtual {
// uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY");
// if (deployerPrivateKey == 0) {
// revert InvalidPrivateKey(
// "You don't have a deployer account. Make sure you have set DEPLOYER_PRIVATE_KEY in .env or use `yarn generate` to generate a new random account"
// );
// }

// vm.startBroadcast(deployerPrivateKey);
// MockToken1 scUSD = new MockToken1("Scaffold USD", "scUSD");
// MockToken2 scDAI = new MockToken2("Scaffold DAI", "scDAI");
// console.log("Deployed MockToken1 Address: %s", address(scUSD));
// console.log("Deployed MockToken2 Address: %s", address(scDAI));
// vm.stopBroadcast();

// TODO: figure out how to carry contract info from foundry to nextjs for more than a single deploy script
// /**
// * This function generates the file containing the contracts Abi definitions.
// * These definitions are used to derive the types needed in the custom scaffold-eth hooks, for example.
// * This function should be called last.
// */
// exportDeployments();
}
}
//
// // /**
// // * This function generates the file containing the contracts Abi definitions.
// // * These definitions are used to derive the types needed in the custom scaffold-eth hooks, for example.
// // * This function should be called last.
// // */
// // exportDeployments();
// }
// }
15 changes: 15 additions & 0 deletions packages/foundry/script/01_DeployFactory.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pragma solidity ^0.8.24;
import { ScaffoldETHDeploy, console } from "./ScaffoldETHDeploy.s.sol";
import { ConstantSumFactory } from "../contracts/ConstantSumFactory.sol";
import { HelperConfig } from "../utils/HelperConfig.sol";
import { MockToken1 } from "../contracts/MockToken1.sol";
import { MockToken2 } from "../contracts/MockToken2.sol";

/**
* @title Deploy Factory
Expand All @@ -20,7 +22,20 @@ contract DeployFactory is HelperConfig, ScaffoldETHDeploy {
}

uint32 pauseWindowDuration = getFactoryConfig();

vm.startBroadcast(deployerPrivateKey);
/**
* @notice Deploy mock tokens to be used for initializing pools
* @dev remove this if you plan to use already deployed tokens
*/
MockToken1 scUSD = new MockToken1("Scaffold USD", "scUSD");
MockToken2 scDAI = new MockToken2("Scaffold DAI", "scDAI");
console.log("Deployed MockToken1 Address: %s", address(scUSD));
console.log("Deployed MockToken2 Address: %s", address(scDAI));

/**
* @notice Deploys the factory contract using the pauseWindowDuration set in `HelperConfig.sol`
*/
ConstantSumFactory factory = new ConstantSumFactory(vault, pauseWindowDuration);
console.log("Deployed Factory Address: %s", address(factory));
vm.stopBroadcast();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { DevOpsTools } from "lib/foundry-devops/src/DevOpsTools.sol";
import { Script, console } from "forge-std/Script.sol";
import { RegistrationConfig, InitializationConfig } from "../utils/PoolTypes.sol";

import { InputHelpers } from "@balancer-labs/v3-solidity-utils/contracts/helpers/InputHelpers.sol";

/**
* @title Deploy Pool Script
* @notice This script deploys a new pool using the most recently deployed pool factory and mock tokens
Expand All @@ -26,7 +24,9 @@ contract DeployPool is HelperConfig, Script {
"You don't have a deployer account. Make sure you have set DEPLOYER_PRIVATE_KEY in .env or use `yarn generate` to generate a new random account"
);
}
// Set the pool registration and initialization configurations in `HelperConfig.sol`
/**
* @dev Set the pool registration and initialization configurations in `HelperConfig.sol`
*/
RegistrationConfig memory regConfig = getPoolConfig();
InitializationConfig memory initConfig = getInitializationConfig(regConfig.tokenConfig);
// Grab the most recently deployed address of the pool factory
Expand All @@ -42,7 +42,7 @@ contract DeployPool is HelperConfig, Script {
regConfig.name,
regConfig.symbol,
regConfig.salt,
sortTokenConfig(regConfig.tokenConfig),
regConfig.tokenConfig,
regConfig.swapFeePercentage,
regConfig.protocolFeeExempt,
regConfig.roleAccounts,
Expand All @@ -53,7 +53,7 @@ contract DeployPool is HelperConfig, Script {
// Initialize the pool
initializePool(
newPool,
InputHelpers.sortTokens(initConfig.tokens),
initConfig.tokens,
initConfig.exactAmountsIn,
initConfig.minBptAmountOut,
initConfig.wethIsEth,
Expand Down
123 changes: 123 additions & 0 deletions packages/foundry/script/03_DeployPool2.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import { LiquidityManagement, PoolRoleAccounts } from "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";

import { HelperConfig } from "../utils/HelperConfig.sol";
import { ConstantSumFactory } from "../contracts/ConstantSumFactory.sol";
import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
import { DevOpsTools } from "lib/foundry-devops/src/DevOpsTools.sol";
import { Script, console } from "forge-std/Script.sol";
import { RegistrationConfig, InitializationConfig } from "../utils/PoolTypes.sol";

/**
* @title Deploy Pool Script
* @notice This script deploys a new pool using the most recently deployed pool factory and mock tokens
* @dev Some of the pool registration/initialization configurations are set in `HelperConfig.sol`, some are set directly in this script
* @dev Run this script with `yarn deploy:pool`
*/
contract DeployPool is HelperConfig, Script {
error InvalidPrivateKey(string);

function run() external virtual {
uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY");
if (deployerPrivateKey == 0) {
revert InvalidPrivateKey(
"You don't have a deployer account. Make sure you have set DEPLOYER_PRIVATE_KEY in .env or use `yarn generate` to generate a new random account"
);
}
// Set the pool registration and initialization configurations in `HelperConfig.sol`
RegistrationConfig memory regConfig = getPoolConfig();
InitializationConfig memory initConfig = getInitializationConfig(regConfig.tokenConfig);
// Grab the most recently deployed address of the pool factory
address poolFactoryAddress = DevOpsTools.get_most_recent_deployment(
"ConstantSumFactory", // Must match the pool factory contract name
block.chainid
);
ConstantSumFactory factory = ConstantSumFactory(poolFactoryAddress);
/**
* @notice Altering some of the config for this second pool
* @dev watch out for "stack too deep" error if you declare too many vars directly in this `run()` function
*/
PoolRoleAccounts memory roleAccounts = PoolRoleAccounts({
pauseManager: msg.sender, // Account empowered to pause/unpause the pool (or 0 to delegate to governance)
swapFeeManager: msg.sender, // Account empowered to set static swap fees for a pool (or 0 to delegate to goverance)
poolCreator: msg.sender // Account empowered to set the pool creator fee percentage
});
LiquidityManagement memory liquidityManagement = LiquidityManagement({
disableUnbalancedLiquidity: false,
enableAddLiquidityCustom: true,
enableRemoveLiquidityCustom: true
});
// Send the transactions
vm.startBroadcast(deployerPrivateKey);
// Deploy the pool (and register it with the vault)
address newPool = factory.create(
"Constant Sum Pool #2", // name
"CS2-50scUSD-50scDAI", // symbol
keccak256(abi.encode("Constant Sum Pool #2")), // salt
regConfig.tokenConfig, // tokenConfigs
33e12, // swapFeePercentage of 0.000033%
regConfig.protocolFeeExempt,
roleAccounts,
regConfig.poolHooksContract,
liquidityManagement
);
console.log("Deployed pool at address: %s", newPool);
// Initialize the pool
initializePool(
newPool,
initConfig.tokens,
initConfig.exactAmountsIn,
initConfig.minBptAmountOut,
initConfig.wethIsEth,
initConfig.userData
);
console.log("Pool initialized successfully!");
vm.stopBroadcast();
}

/**
* @notice Approves the vault to spend tokens and then initializes the pool
*/
function initializePool(
address pool,
IERC20[] memory tokens,
uint256[] memory exactAmountsIn,
uint256 minBptAmountOut,
bool wethIsEth,
bytes memory userData
) internal {
// Approve Permit2 to spend account tokens
approveSpenderOnToken(address(permit2), tokens);
// Approve Router to spend account tokens using Permit2
approveSpenderOnPermit2(address(router), tokens);
// Initialize pool with the tokens that have been permitted
router.initialize(pool, tokens, exactAmountsIn, minBptAmountOut, wethIsEth, userData);
}

/**
* @notice Max approving to speed up UX on frontend
* @param tokens Array of tokens to approve
* @param spender Address of the spender
*/
function approveSpenderOnToken(address spender, IERC20[] memory tokens) internal {
uint256 maxAmount = type(uint256).max;
for (uint256 i = 0; i < tokens.length; ++i) {
tokens[i].approve(spender, maxAmount);
}
}

/**
* @notice Max approving to speed up UX on frontend
* @param tokens Array of tokens to approve
* @param spender Address of the spender
*/
function approveSpenderOnPermit2(address spender, IERC20[] memory tokens) internal {
uint160 maxAmount = type(uint160).max;
uint48 maxExpiration = type(uint48).max;
for (uint256 i = 0; i < tokens.length; ++i) {
permit2.approve(address(tokens[i]), spender, maxAmount, maxExpiration);
}
}
}
9 changes: 5 additions & 4 deletions packages/foundry/utils/HelperConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol";
import { IRouter } from "@balancer-labs/v3-interfaces/contracts/vault/IRouter.sol";
import { IRateProvider } from "@balancer-labs/v3-interfaces/contracts/vault/IRateProvider.sol";
import { InputHelpers } from "@balancer-labs/v3-solidity-utils/contracts/helpers/InputHelpers.sol";
import { IPermit2 } from "permit2/src/interfaces/IPermit2.sol";

import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
Expand Down Expand Up @@ -41,8 +42,8 @@ contract HelperConfig {
* @dev Set all of the configurations for deploying and registering a pool here
*/
function getPoolConfig() internal view returns (RegistrationConfig memory regConfig) {
string memory name = "Scaffold Balancer Constant Sum Pool #1"; // name for the pool
string memory symbol = "SB-50scUSD-50scDAI"; // symbol for the BPT
string memory name = "Constant Sum Pool #1"; // name for the pool
string memory symbol = "CS1-50scUSD-50scDAI"; // symbol for the BPT
bytes32 salt = keccak256(abi.encode(name)); // salt for the pool deployment via factory
// Grab the most recently deployed addresses of mock tokens
address mockToken1 = DevOpsTools.get_most_recent_deployment(
Expand Down Expand Up @@ -88,7 +89,7 @@ contract HelperConfig {
name: name,
symbol: symbol,
salt: salt,
tokenConfig: tokenConfig,
tokenConfig: sortTokenConfig(tokenConfig),
swapFeePercentage: swapFeePercentage,
protocolFeeExempt: protocolFeeExempt,
roleAccounts: roleAccounts,
Expand All @@ -115,7 +116,7 @@ contract HelperConfig {
bytes memory userData = bytes(""); // Additional (optional) data required for adding initial liquidity

poolInitConfig = InitializationConfig({
tokens: tokens,
tokens: InputHelpers.sortTokens(tokens),
exactAmountsIn: exactAmountsIn,
minBptAmountOut: minBptAmountOut,
wethIsEth: wethIsEth,
Expand Down
Loading

0 comments on commit 661c8d0

Please sign in to comment.