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: foundry support for missing test and deployment script #45

Merged
merged 3 commits into from
Oct 17, 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
20 changes: 20 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Deployer private key
PRIVATE_KEY=

# RPCs
ARBITRUM_RPC_URL=
BASE_RPC_URL=
ETHEREUM_RPC_URL=
FRAXTAL_RPC_URL=
GNOSIS_RPC_URL=
OPTIMISM_RPC_URL=
POLYGON_RPC_URL=

# Etherscan APIs
ETHERSCAN_ARBITRUM_API_KEY=
ETHERSCAN_BASE_API_KEY=
ETHERSCAN_ETHEREUM_API_KEY=
ETHERSCAN_FRAXTAL_API_KEY=
ETHERSCAN_GNOSIS_API_KEY=
ETHERSCAN_OPTIMISM_API_KEY=
ETHERSCAN_POLYGON_API_KEY=
18 changes: 17 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
Expand Down Expand Up @@ -145,3 +144,20 @@ node_modules

# Hardhat Ignition default folder for deployments against a local node
ignition/deployments/chain-31337

# Foundry
cache/
out/

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

# Codecov
lcov.info

# Testing
.gas-snapshot

# vscode - audit docs
.vscode/
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std.git
34 changes: 34 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
-include .env

# command: test the whole script without broadcasting the transaction into the chain to spot early errors
deployPolygonDry:
forge script foundry_scripts/InjectorInfraDeployment.s.sol \
--rpc-url polygon \
--slow \
-vvvv

deployPolygonBroadcastAndVerify:
forge script foundry_scripts/InjectorInfraDeployment.s.sol \
--rpc-url polygon \
--slow \
--broadcast \
--verify \
-vvvv

deployMultiChainDry:
forge script foundry_scripts/InjectorInfraMultiChainDeployment.s.sol \
--rpc-url polygon \
--slow \
-- multi \
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@note here that this flag --multi it is for multichain deployments

--multi
          If present, --resume or --verify will be assumed to be a multi chain
          deployment

-vvvv

deployMultiChainBroadcastAndVerify:
forge script foundry_scripts/InjectorInfraMultiChainDeployment.s.sol \
--rpc-url polygon \
--slow \
-- multi \
--broadcast \
--verify \
-vvvv


18 changes: 18 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[profile.default]
src = 'contracts'
out = "out"
libs = ['node_modules','lib']
test = 'foundry_test'
solc = '0.8.25'

[fmt]
ignore = ['./contracts/**/*']
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@note here i'm opting to avoid linting the contracts all together. it can be something to consider tho once all issues/prs are close


[rpc_endpoints]
arbitrum = "${ARBITRUM_RPC_URL}"
base = "${BASE_RPC_URL}"
ethereum = "${ETHEREUM_RPC_URL}"
fraxtal = "${FRAXTAL_RPC_URL}"
gnosis = "${GNOSIS_RPC_URL}"
optimism = "${OPTIMISM_RPC_URL}"
polygon = "${POLYGON_RPC_URL}"
28 changes: 28 additions & 0 deletions foundry_scripts/InjectorInfraDeployment.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.25;

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

import {ChildChainGaugeInjectorV2} from "../contracts/ChildChainGaugeInjectorV2.sol";
import {ChildChainGaugeInjectorV2Factory} from "../contracts/injectorFactoryV2.sol";

/// @notice Deploys the v2 infrastructure for the injectors in the following order:
/// 1. {ChildChainGaugeInjectorV2} -> singleton/implementation purposes (helps verifying in etherscan etc)
/// 2. {ChildChainGaugeInjectorV2Factory}
contract InjectorInfraDeployment is Script {
// injector infrastructure
ChildChainGaugeInjectorV2 injectorImpl;
ChildChainGaugeInjectorV2Factory injectorFactory;

function run() public {
// read pk from `.env`
uint256 pk = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(pk);

// 1. {ChildChainGaugeInjectorV2}
injectorImpl = new ChildChainGaugeInjectorV2();

// 2. {ChildChainGaugeInjectorV2Factory}
injectorFactory = new ChildChainGaugeInjectorV2Factory(address(injectorImpl));
}
}
88 changes: 88 additions & 0 deletions foundry_scripts/InjectorInfraMultiChainDeployment.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.25;

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

import {ChildChainGaugeInjectorV2} from "../contracts/ChildChainGaugeInjectorV2.sol";
import {ChildChainGaugeInjectorV2Factory} from "../contracts/injectorFactoryV2.sol";

/// @notice Deploys the v2 infrastructure for the injectors in all chains in `foundry.toml` in the following order:
/// 1. {ChildChainGaugeInjectorV2} -> singleton/implementation purposes (helps verifying in etherscan etc)
/// 2. {ChildChainGaugeInjectorV2Factory}
contract InjectorInfraMultiChainDeployment is Script {
enum Chains {
ARBITRUM,
BASE,
ETHEREUM,
FRAXTAL,
GNOSIS,
OPTIMISM,
POLYGON
}

// injector infrastructure
ChildChainGaugeInjectorV2 injectorImpl;
ChildChainGaugeInjectorV2Factory injectorFactory;

mapping(Chains chain => string rpcAlias) public availableChains;

constructor() {
availableChains[Chains.ARBITRUM] = "arbitrum";
availableChains[Chains.BASE] = "base";
availableChains[Chains.ETHEREUM] = "ethereum";
availableChains[Chains.FRAXTAL] = "fraxtal";
availableChains[Chains.GNOSIS] = "gnosis";
availableChains[Chains.OPTIMISM] = "optimism";
availableChains[Chains.POLYGON] = "polygon";
}

/// @dev broadcast transaction modifier
/// @param pk private key to broadcast transaction
modifier broadcast(uint256 pk) {
vm.startBroadcast(pk);

_;

vm.stopBroadcast();
}

function run() public {
// read pk from `.env`
uint256 pk = vm.envUint("PRIVATE_KEY");

// @note the array can be updated depending on your target chains to deploy
// @note by default the script will deploy in all chains available in the toml file
Chains[] memory targetDeploymentChains = new Chains[](6);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here you can target the specifics chains which you will like to deploy at once, remove as you may see fit, but also remember to adapt the length of the array


targetDeploymentChains[0] = Chains.ARBITRUM;
targetDeploymentChains[1] = Chains.BASE;
targetDeploymentChains[2] = Chains.ETHEREUM;
targetDeploymentChains[3] = Chains.GNOSIS;
targetDeploymentChains[4] = Chains.OPTIMISM;
targetDeploymentChains[5] = Chains.POLYGON;
// @note fraxtal rpc gives sometimes problems

for (uint256 i = 0; i < targetDeploymentChains.length; i++) {
_deploy(targetDeploymentChains[i], pk);
}
}

/// @dev Helper to point into a specific chain
/// @param _targetChain chain to deploy
/// @param _pk private key to broadcast transaction
function _deploy(Chains _targetChain, uint256 _pk) internal {
vm.createSelectFork(availableChains[_targetChain]);

_infraDeployment(_pk);
}

/// @dev Helper to deploy the factory and singleton
/// @param _pk private key to broadcast transaction
function _infraDeployment(uint256 _pk) internal broadcast(_pk) {
// 1. {ChildChainGaugeInjectorV2}
injectorImpl = new ChildChainGaugeInjectorV2();

// 2. {ChildChainGaugeInjectorV2Factory}
injectorFactory = new ChildChainGaugeInjectorV2Factory(address(injectorImpl));
}
}
72 changes: 72 additions & 0 deletions foundry_test/BaseFixture.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;

import "forge-std/Test.sol";

import {IChildChainGauge} from "../contracts/interfaces/balancer/IChildChainGauge.sol";

import {ChildChainGaugeInjectorV2} from "../contracts/ChildChainGaugeInjectorV2.sol";
import {ChildChainGaugeInjectorV2Factory} from "../contracts/injectorFactoryV2.sol";

contract BaseFixture is Test {
// injector instance
ChildChainGaugeInjectorV2 injector;

// factory instance
ChildChainGaugeInjectorV2Factory factory;

// constants
address constant GAUGE = 0x3Eae4a1c2E36870A006E816930d9f55DF0a72a13;
address constant GAUGE_2 = 0xc7e5FE004416A96Cb2C7D6440c28aE92262f7695;
address constant LM_MULTISIG = 0xc38c5f97B34E175FFd35407fc91a937300E33860;
address constant AUTHORIZER_ADAPTER = 0xAB093cd16e765b5B23D34030aaFaF026558e0A19;
address constant TEST_TOKEN_WHALE = 0xF977814e90dA44bFA03b6295A0616a897441aceC;

// token address constants
address constant USDT = 0xc2132D05D31c914a87C6611C10748AEb04B58e8F;
address constant USDC = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174;

// agents
address constant KEEPER = address(5);

address[] KEEPER_ADDRESSES = new address[](1);

// dummy constants
uint256 MIN_WAIT_PERIOD_SECONDS = 1 days;
uint256 MAX_INJECTION_AMOUNT = 1_000e18;
address OWNER = address(56565);

event InjectorCreated(
address indexed injector, address[] keeperAddresses, address injectTokenAddress, address owner
);

function setUp() public {
vm.createSelectFork("polygon");

injector = new ChildChainGaugeInjectorV2();
factory = new ChildChainGaugeInjectorV2Factory(address(injector));

assert(factory.implementation() == address(injector));
}

function _deployDummyInjector() internal returns (address injectorDeployed_) {
KEEPER_ADDRESSES[0] = KEEPER;

// check: event emitted
vm.expectEmit(false, true, true, true); // @note topic0 is not checkeds
emit InjectorCreated(address(0), KEEPER_ADDRESSES, USDT, OWNER);

injectorDeployed_ =
factory.createInjector(KEEPER_ADDRESSES, MIN_WAIT_PERIOD_SECONDS, USDT, MAX_INJECTION_AMOUNT, OWNER);
}

function _enableInjectorAsDistributor(address _injector) internal {
IChildChainGauge gaugeFirst = IChildChainGauge(GAUGE);
IChildChainGauge gaugeSecond = IChildChainGauge(GAUGE_2);

vm.prank(gaugeFirst.authorizer_adaptor());
gaugeFirst.add_reward(USDT, _injector);
vm.prank(gaugeSecond.authorizer_adaptor());
gaugeSecond.add_reward(USDT, _injector);
}
}
26 changes: 26 additions & 0 deletions foundry_test/FactoryTest.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;

import {BaseFixture} from "./BaseFixture.sol";

import {ChildChainGaugeInjectorV2} from "../contracts/ChildChainGaugeInjectorV2.sol";

contract FactoryTest is BaseFixture {
function testCreateInjector() public {
// 1. create a new injector via factory
address injectorDeployed = _deployDummyInjector();
ChildChainGaugeInjectorV2 injectorFactoryDeployed = ChildChainGaugeInjectorV2(injectorDeployed);

// 2. asserts:
// 2.1. check `getDeployedInjectors` returns the correct number of injectors
address[] memory injectorsDeployed = factory.getDeployedInjectors();
assertEq(injectorsDeployed.length, 1);
assertEq(injectorsDeployed[0], injectorDeployed);

// 2.2. check params of the injector correctness at deployment time
assertEq(injectorFactoryDeployed.owner(), OWNER);
assertEq(injectorFactoryDeployed.getKeeperAddresses()[0], KEEPER);
assertEq(injectorFactoryDeployed.MinWaitPeriodSeconds(), MIN_WAIT_PERIOD_SECONDS);
assertEq(injectorFactoryDeployed.InjectTokenAddress(), USDT);
}
}
Loading
Loading