-
Notifications
You must be signed in to change notification settings - Fork 0
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
Draft
petrovska-petro
wants to merge
2
commits into
main
Choose a base branch
from
feat/foundry-factory-test
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
-include .env | ||
|
||
# command: test the whole script without broadcasting the transaction into the chain to spot early errors | ||
deployDry: | ||
forge script foundry_scripts/InjectorInfraDeployment.s.sol \ | ||
--rpc-url polygon \ | ||
--slow \ | ||
-vvvv | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[profile.default] | ||
src = 'contracts' | ||
out = "out" | ||
libs = ['node_modules','lib'] | ||
test = 'foundry_test' | ||
solc = '0.8.25' | ||
|
||
[fmt] | ||
ignore = ['./contracts/**/*'] | ||
|
||
[rpc_endpoints] | ||
polygon = "${POLYGON_RPC_KEY}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.25; | ||
|
||
import {BaseFixture} from "./BaseFixture.sol"; | ||
|
||
import "../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
|
||
import {IChildChainGauge} from "../contracts/interfaces/balancer/IChildChainGauge.sol"; | ||
|
||
import {ChildChainGaugeInjectorV2} from "../contracts/ChildChainGaugeInjectorV2.sol"; | ||
|
||
/// @notice Scope of the file is to test uncovered reverts, setters and getters: | ||
/// 1. revert: `InjectorNotDistributor` | ||
/// 2. revert: `ExceedsTotalInjectorProgramBudget` | ||
/// 3. revert: `OnlyKeepers` | ||
/// 4. getter: `getBalanceDelta` (cases-> deficit, exact balance and surplus) | ||
/// 5. getter: `getFullSchedule` (check: expected values) | ||
// @audit https://github.com/BalancerMaxis/ChildGaugeInjectorV2/issues/31 ? | ||
contract UncoveredLinesTest is BaseFixture { | ||
function test_revertWhen_InjectorNotDistributor() public { | ||
ChildChainGaugeInjectorV2 inj = ChildChainGaugeInjectorV2(_deployDummyInjector()); | ||
|
||
address[] memory recipients = new address[](1); | ||
recipients[0] = GAUGE; | ||
|
||
vm.prank(inj.owner()); | ||
vm.expectRevert(abi.encodeWithSelector(ChildChainGaugeInjectorV2.InjectorNotDistributor.selector, GAUGE, USDT)); | ||
inj.addRecipients(recipients, 50e18, 4, uint56(block.timestamp + 1 days)); | ||
} | ||
|
||
function test_revertWhen_ExceedsTotalInjectorProgramBudget() public { | ||
ChildChainGaugeInjectorV2 inj = ChildChainGaugeInjectorV2(_deployDummyInjector()); | ||
|
||
_enableInjectorAsDistributor(address(inj)); | ||
|
||
uint256 dummyMaxTotalDue = 100e18; | ||
vm.startPrank(inj.owner()); | ||
inj.setMaxTotalDue(dummyMaxTotalDue); | ||
assertEq(inj.MaxTotalDue(), dummyMaxTotalDue); | ||
|
||
address[] memory recipients = new address[](2); | ||
recipients[0] = GAUGE; | ||
recipients[1] = GAUGE_2; | ||
|
||
uint256 amountPerPeriod = 250e18; | ||
vm.expectRevert( | ||
abi.encodeWithSelector( | ||
ChildChainGaugeInjectorV2.ExceedsTotalInjectorProgramBudget.selector, amountPerPeriod | ||
) | ||
); | ||
inj.addRecipients(recipients, 250e18, 1, uint56(block.timestamp + 1 days)); | ||
} | ||
|
||
function test_revertWhen_NotKeepers() public { | ||
address NOT_KEEPER_AGENT = address(543485484845); | ||
|
||
ChildChainGaugeInjectorV2 inj = ChildChainGaugeInjectorV2(_deployDummyInjector()); | ||
|
||
address[] memory needsFunding = new address[](1); | ||
needsFunding[0] = GAUGE; | ||
|
||
vm.prank(NOT_KEEPER_AGENT); | ||
vm.expectRevert(abi.encodeWithSelector(ChildChainGaugeInjectorV2.OnlyKeepers.selector, NOT_KEEPER_AGENT)); | ||
inj.performUpkeep(abi.encode(needsFunding)); | ||
} | ||
|
||
function testGetBalance_When_Deficit() public { | ||
ChildChainGaugeInjectorV2 inj = ChildChainGaugeInjectorV2(_deployDummyInjector()); | ||
|
||
_enableInjectorAsDistributor(address(inj)); | ||
|
||
address[] memory recipients = new address[](1); | ||
recipients[0] = GAUGE; | ||
uint256 amountPerPeriod = 250e18; | ||
vm.prank(inj.owner()); | ||
inj.addRecipients(recipients, amountPerPeriod, 1, uint56(block.timestamp + 1 days)); | ||
|
||
// send partially | ||
deal(USDT, address(inj), 50e18); | ||
|
||
int256 expectedDeficit = -1 * int256(amountPerPeriod - IERC20(USDT).balanceOf(address(inj))); | ||
|
||
// should encounter DEFICIT | ||
assertEq(inj.getBalanceDelta(), expectedDeficit); | ||
} | ||
|
||
function testGetBalance_When_ExactBalance() public { | ||
ChildChainGaugeInjectorV2 inj = ChildChainGaugeInjectorV2(_deployDummyInjector()); | ||
|
||
_enableInjectorAsDistributor(address(inj)); | ||
|
||
address[] memory recipients = new address[](1); | ||
recipients[0] = GAUGE; | ||
uint256 amountPerPeriod = 250e18; | ||
vm.prank(inj.owner()); | ||
inj.addRecipients(recipients, amountPerPeriod, 1, uint56(block.timestamp + 1 days)); | ||
|
||
// send full `amountPerPeriod` | ||
deal(USDT, address(inj), amountPerPeriod); | ||
|
||
// should encounter EXACT | ||
assertEq(inj.getBalanceDelta(), 0); | ||
} | ||
|
||
function testGetBalance_When_Surplus() public { | ||
ChildChainGaugeInjectorV2 inj = ChildChainGaugeInjectorV2(_deployDummyInjector()); | ||
|
||
_enableInjectorAsDistributor(address(inj)); | ||
|
||
address[] memory recipients = new address[](1); | ||
recipients[0] = GAUGE; | ||
uint256 amountPerPeriod = 250e18; | ||
vm.prank(inj.owner()); | ||
inj.addRecipients(recipients, amountPerPeriod, 1, uint56(block.timestamp + 1 days)); | ||
|
||
// send full `amountPerPeriod` * 3 | ||
deal(USDT, address(inj), amountPerPeriod * 3); | ||
|
||
int256 expectedSurplus = int256(IERC20(USDT).balanceOf(address(inj)) - amountPerPeriod); | ||
// should encounter SURPLUS | ||
assertEq(inj.getBalanceDelta(), expectedSurplus); | ||
} | ||
|
||
function testGetFullSchedule() public { | ||
ChildChainGaugeInjectorV2 inj = ChildChainGaugeInjectorV2(_deployDummyInjector()); | ||
|
||
_enableInjectorAsDistributor(address(inj)); | ||
|
||
address[] memory recipients = new address[](2); | ||
recipients[0] = GAUGE; | ||
recipients[1] = GAUGE_2; | ||
|
||
vm.prank(inj.owner()); | ||
inj.addRecipients(recipients, 250e18, 5, uint56(block.timestamp + 1 days)); | ||
|
||
( | ||
address[] memory gauges, | ||
uint256[] memory amountsPerPeriod, | ||
uint8[] memory maxPeriods, | ||
uint8[] memory currentPeriods, | ||
uint56[] memory lastTimestamps, | ||
uint56[] memory doNotStartBeforeTimestamps | ||
) = inj.getFullSchedule(); | ||
|
||
for (uint256 i = 0; i < gauges.length; i++) { | ||
assertEq(gauges[i], recipients[i]); | ||
assertEq(amountsPerPeriod[i], 250e18); | ||
assertEq(maxPeriods[i], 5); | ||
assertEq(currentPeriods[i], 0); | ||
assertEq(lastTimestamps[i], uint56(0)); | ||
assertEq(doNotStartBeforeTimestamps[i], uint56(block.timestamp + 1 days)); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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