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

Add fork test tooling #419

Merged
merged 13 commits into from
May 22, 2024
18 changes: 17 additions & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,20 @@ jobs:
uses: foundry-rs/foundry-toolchain@v1

- name: Run tests
run: forge test -vvv
run: forge test --no-match-contract "(Fork)" -vvv

foundry-fork-tests:
name: Foundry Fork tests
runs-on: ubuntu-latest
env:
PROVIDER_URL: ${{ secrets.PROVIDER_URL }}
steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Run tests
run: forge test --match-contract "ForkTest" --fork-url $PROVIDER_URL
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ out/
.vscode
brownie-deploy/
.idea
deployments-fork.json
3 changes: 2 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
url = https://github.com/openzeppelin/openzeppelin-contracts-upgradeable
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/brockelmore/forge-std
url = https://github.com/foundry-rs/forge-std
branch = 978ac6fadb62f5f0b723c996f64be52eddba6801
[submodule "lib/prb-math"]
path = lib/prb-math
url = https://github.com/paulrberg/prb-math
6 changes: 6 additions & 0 deletions build/deployments.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"1": {
"executions": {},
"contracts": {}
}
}
6 changes: 3 additions & 3 deletions contracts/Governance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ contract Governance is
GovernorPreventLateQuorum
{
constructor(ERC20Votes _token, TimelockController _timelock)
Governor("OUSD Governance")
GovernorSettings(1, /* 1 block */ 17280, /* ~3 days (86400 / 15) * 3 */ 10000000 * 1e18 /* 10 mio veOgv */ )
Governor("Origin DeFi Governance")
GovernorSettings(1, /* 1 block */ 14416, /* ~2 days (86400 / 12) * 2 */ 100000 * 1e18 /* 100k xOGN */ )
GovernorVotes(_token)
GovernorVotesQuorumFraction(20) // Default quorum denominator is 100, so 20/100 or 20%
GovernorTimelockControl(_timelock)
GovernorPreventLateQuorum(11520) // ~2 days (86400 / 15) * 2
GovernorPreventLateQuorum(7208) // ~1 days (86400 / 12)
{}

// The following functions are overrides required by Solidity.
Expand Down
11 changes: 7 additions & 4 deletions contracts/utils/Addresses.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ library Addresses {
address public constant STRATEGIST = 0xF14BBdf064E3F67f51cd9BD646aE3716aD938FDC;
address public constant GOVERNOR_FIVE = 0x3cdD07c16614059e66344a7b579DAB4f9516C0b6;

address public constant OGN_GOVERNOR = 0x72426BA137DEC62657306b12B1E869d43FeC6eC7;
address public constant GOV_MULTISIG = 0xbe2AB3d3d8F6a32b96414ebbd865dBD276d3d899;

address public constant INITIAL_DEPLOYER = address(0x1001);
address public constant OGN = 0x8207c1FfC5B6804F6024322CcF34F29c3541Ae26;
address public constant OGV = 0x9c354503C38481a7A7a51629142963F98eCC12D0;
address public constant OGV_REWARDS_PROXY = 0x7d82E86CF1496f9485a8ea04012afeb3C7489397;
address public constant VEOGV = 0x0C4576Ca1c365868E162554AF8e385dc3e7C66D9;

address public constant OUSD_BUYBACK = address(34);
address public constant OETH_BUYBACK = address(35);
address public constant OUSD_BUYBACK_IMPL = address(34);
address public constant OETH_BUYBACK_IMPL = address(35);
address public constant OUSD_BUYBACK = 0xD7B28d06365b85933c64E11e639EA0d3bC0e3BaB;
address public constant OETH_BUYBACK = 0xFD6c58850caCF9cCF6e8Aee479BFb4Df14a362D2;
address public constant OUSD_BUYBACK_IMPL = 0xbc77B8EFafabdF46f94Dfb4A422d541c5037799C;
address public constant OETH_BUYBACK_IMPL = 0x69D343A52bC13Dc19cBD0d2A77baC320CCB69B9a;
}
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ remappings = [
"OpenZeppelin/[email protected]/=./lib/openzeppelin-contracts-upgradeable",
"paulrberg/[email protected]/=./lib/prb-math"
]
fs_permissions = [{ access = "read-write", path = "./build"}]
143 changes: 143 additions & 0 deletions script/deploy/DeployManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.10;

import "forge-std/Script.sol";
import "OpenZeppelin/[email protected]/contracts/utils/Strings.sol";

import {BaseMainnetScript} from "./mainnet/BaseMainnetScript.sol";

import {XOGNSetupScript} from "./mainnet/010_xOGNSetupScript.sol";
import {OgnOgvMigrationScript} from "./mainnet/011_OgnOgvMigrationScript.sol";
import {XOGNGovernanceScript} from "./mainnet/012_xOGNGovernanceScript.sol";

contract DeployManager is Script {
mapping(string => address) public deployedContracts;
mapping(string => bool) public scriptsExecuted;

function isForked() public view returns (bool) {
return vm.isContext(VmSafe.ForgeContext.ScriptDryRun) || vm.isContext(VmSafe.ForgeContext.Test)
|| vm.isContext(VmSafe.ForgeContext.TestGroup);
}

function getDeploymentFilePath() public view returns (string memory) {
return isForked() ? getForkDeploymentFilePath() : getMainnetDeploymentFilePath();
}

function getMainnetDeploymentFilePath() public view returns (string memory) {
return string(abi.encodePacked(vm.projectRoot(), "/build/deployments.json"));
}

function getForkDeploymentFilePath() public view returns (string memory) {
return string(abi.encodePacked(vm.projectRoot(), "/build/deployments-fork.json"));
}

function setUp() external {
string memory chainIdStr = Strings.toString(block.chainid);
string memory chainIdKey = string(abi.encodePacked(".", chainIdStr));

string memory mainnetFilePath = getMainnetDeploymentFilePath();
if (!vm.isFile(mainnetFilePath)) {
// Create mainnet deployment file if it doesn't exist
vm.writeFile(
mainnetFilePath,
string(abi.encodePacked('{ "', chainIdStr, '": { "executions": {}, "contracts": {} } }'))
);
} else if (!vm.keyExistsJson(vm.readFile(mainnetFilePath), chainIdKey)) {
// Create network entry if it doesn't exist
vm.writeJson(
vm.serializeJson(chainIdStr, '{ "executions": {}, "contracts": {} }'), mainnetFilePath, chainIdKey
);
}

if (isForked()) {
// Duplicate Mainnet File
vm.writeFile(getForkDeploymentFilePath(), vm.readFile(mainnetFilePath));
}
}

function run() external {
// TODO: Use vm.readDir to recursively build this?
_runDeployFile(new XOGNSetupScript());
_runDeployFile(new OgnOgvMigrationScript());
_runDeployFile(new XOGNGovernanceScript());
}

function _runDeployFile(BaseMainnetScript deployScript) internal {
string memory chainIdStr = Strings.toString(block.chainid);
string memory chainIdKey = string(abi.encodePacked(".", chainIdStr));

string memory contractsKey = string(abi.encodePacked(chainIdKey, ".contracts"));
string memory executionsKey = string(abi.encodePacked(chainIdKey, ".executions"));

string memory deploymentsFilePath = getDeploymentFilePath();
string memory fileContents = vm.readFile(deploymentsFilePath);

/**
* Execution History
*/
string memory currentExecutions = "";
string[] memory executionKeys = vm.parseJsonKeys(fileContents, executionsKey);

for (uint256 i = 0; i < executionKeys.length; ++i) {
uint256 deployedTimestamp =
vm.parseJsonUint(fileContents, string(abi.encodePacked(executionsKey, ".", executionKeys[i])));

currentExecutions = vm.serializeUint(executionsKey, executionKeys[i], deployedTimestamp);
scriptsExecuted[executionKeys[i]] = true;
}

if (scriptsExecuted[deployScript.DEPLOY_NAME()]) {
// TODO: Handle any active governance proposal
console.log("Skipping already deployed script");
return;
}

/**
* Pre-deployment
*/
BaseMainnetScript.DeployRecord[] memory deploys;
string memory networkDeployments = "";
string[] memory existingContracts = vm.parseJsonKeys(fileContents, contractsKey);
for (uint256 i = 0; i < existingContracts.length; ++i) {
address deployedAddr =
vm.parseJsonAddress(fileContents, string(abi.encodePacked(contractsKey, ".", existingContracts[i])));

networkDeployments = vm.serializeAddress(contractsKey, existingContracts[i], deployedAddr);

deployedContracts[existingContracts[i]] = deployedAddr;

deployScript.preloadDeployedContract(existingContracts[i], deployedAddr);
}

// Deployment
deployScript.setUp();
deployScript.run();

/**
* Post-deployment
*/
BaseMainnetScript.DeployRecord[] memory records = deployScript.getAllDeployRecords();

for (uint256 i = 0; i < records.length; ++i) {
string memory name = records[i].name;
address addr = records[i].addr;

console.log(string(abi.encodePacked("> Recorded Deploy of ", name, " at")), addr);
networkDeployments = vm.serializeAddress(contractsKey, name, addr);
deployedContracts[name] = addr;
}

vm.writeJson(networkDeployments, deploymentsFilePath, contractsKey);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm still getting a lot of random failure on these writeJson's (about 2/3 of the 50% of tests fail, about 1/6 of the time, all tests succeed)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah. It's mostly about writing twice to the same file back to back. Thats why I added a small delay. Will work on a clean fix to do a single write instead


/**
* Write Execution History
*/
currentExecutions = vm.serializeUint(executionsKey, deployScript.DEPLOY_NAME(), block.timestamp);

vm.writeJson(currentExecutions, deploymentsFilePath, executionsKey);
}

function getDeployment(string calldata contractName) external view returns (address) {
return deployedContracts[contractName];
}
}
Loading
Loading