Skip to content

Commit

Permalink
Token Merger Deploy Script (#418)
Browse files Browse the repository at this point in the history
* Add OGNRewardsSource contract

* Make collectRewards only callable by RewardsTarget

* Draft xOGN staking contract

* Correct maxStakeDuration

* Add penalty event

* Change names

* Fix lockup ID

* Revert change and cast properly

* Gas opts

* Remove casting

* Add `getLockupsCount` method (#411)

* Allow non-duration change amount increase staking extends

* Add tests, add move lockupid code

* Add Migrator (#410)

* Add Migrator contract

* Fix some tests

* Code review changes

* Update OgvStaking tests

* Disable delegation tests

* Allow just unstakes

* Fix comment

* More cleanup

* Fix brownie tests

* Return excess OGN rather than burn

* Simplify calculation

* Return 0 if uninitialized (#415)

* Check available balance in `previewRewards` (#413)

* Check available balance in `previewRewards`

* Chore: forge fmt

---------

Co-authored-by: Daniel Von Fange <[email protected]>

* Fix: Remove unused errors (#416)

* First draft of deploy file

* Add fork test tooling (#419)

---------

Co-authored-by: Shahul Hameed <[email protected]>
  • Loading branch information
DanielVF and shahthepro authored May 22, 2024
1 parent ab55599 commit 012b8ab
Show file tree
Hide file tree
Showing 33 changed files with 1,418 additions and 45 deletions.
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ out/
.vscode
brownie-deploy/
.idea
deployments-fork*.json
broadcast/*
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
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ forge install
forge test
```

## Running fork tests (forge)

```bash
forge install
forge test --fork-url $ALCHEMY_PROVIDER_URL -vvv --mc "ForkTest"
```

## Running a local node

Copy `dev.env` to `.env` and fill out the `PROVIDER_URL`
Expand Down
4 changes: 4 additions & 0 deletions brownie-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ dependencies:
- OpenZeppelin/[email protected]
- OpenZeppelin/[email protected]
- paulrberg/[email protected]
compiler:
solc:
remappings:
- forge-std/=./lib/forge-std/src/
13 changes: 13 additions & 0 deletions build/deployments.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"1": {
"executions": {
"010_xOGNSetup": 1716312107
},
"contracts": {
"OGN_REWARDS_SOURCE": "0x7609c88E5880e934dd3A75bCFef44E31b1Badb8b",
"OGN_REWARDS_SOURCE_IMPL": "0x16890bdd817Ed1c4654430d67329CB20b0B71bB0",
"XOGN": "0x63898b3b6Ef3d39332082178656E9862bee45C57",
"XOGN_IMPL": "0x97711c7a5D64A064a95d10e37f786d2bD8b1F3c8"
}
}
}
21 changes: 10 additions & 11 deletions contracts/FixedRateRewardsSource.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,12 @@ contract FixedRateRewardsSource is Governable, Initializable {
/// @dev Initialize the proxy implementation
/// @param _strategistAddr Address of the Strategist
/// @param _rewardsTarget Address that receives rewards
/// @param _rewardsPerSecond Rate of reward emission
function initialize(address _strategistAddr, address _rewardsTarget, uint192 _rewardsPerSecond)
external
initializer
{
function initialize(address _strategistAddr, address _rewardsTarget) external initializer {
_setStrategistAddr(_strategistAddr);
_setRewardsTarget(_rewardsTarget);

// Rewards start from the moment the contract is initialized
rewardConfig.lastCollect = uint64(block.timestamp);

_setRewardsPerSecond(_rewardsPerSecond);
}

/// @dev Collect pending rewards
Expand Down Expand Up @@ -90,10 +84,6 @@ contract FixedRateRewardsSource is Governable, Initializable {
function previewRewards() public view returns (uint256 rewardAmount) {
RewardConfig memory _config = rewardConfig;

if (_config.lastCollect == 0) {
return 0;
}

rewardAmount = (block.timestamp - _config.lastCollect) * _config.rewardsPerSecond;
uint256 balance = IERC20(rewardToken).balanceOf(address(this));
if (rewardAmount > balance) {
Expand Down Expand Up @@ -139,6 +129,15 @@ contract FixedRateRewardsSource is Governable, Initializable {
// Update storage
RewardConfig storage _config = rewardConfig;
emit RewardsPerSecondChanged(_rewardsPerSecond, _config.rewardsPerSecond);
if (_config.rewardsPerSecond == 0) {
/* This contract code allows for contract deployment & initialization and then the contract can be live for quite
* some time before it is funded and `_rewardsPerSecond` are set to non 0 value. In that case the vesting period
* from contract initialization until now would be taken into account instead of the time since the contract has been
* "activated" by setting the `setRewardsPerSecond`. To mitigate the issue we update the `_config.lastCollect`
* to current time.
*/
_config.lastCollect = uint64(block.timestamp);
}
_config.rewardsPerSecond = _rewardsPerSecond;
}
}
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
2 changes: 1 addition & 1 deletion contracts/OgvStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ contract OgvStaking is ERC20Votes {
/// @param duration number of seconds to stake for
/// @return points staking points that would be returned
/// @return end staking period end date
function previewPoints(uint256 amount, uint256 duration) public view returns (uint256, uint256) {
function previewPoints(uint256 amount, uint256 duration) public pure returns (uint256, uint256) {
revert StakingDisabled();
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/Timelock.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma solidity ^0.8.10;

import "OpenZeppelin/[email protected]/contracts/governance/TimelockController.sol";

Expand Down
10 changes: 10 additions & 0 deletions contracts/interfaces/IMintableERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.10;

interface IMintableERC20 {
function mint(address to, uint256 amount) external;
function balanceOf(address owner) external view returns (uint256);
function totalSupply() external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 allowance) external;
}
15 changes: 15 additions & 0 deletions contracts/interfaces/IOGNGovernance.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.10;

interface IOGNGovernance {
function state(uint256 proposalId) external view returns (uint256);
function proposalCount() external view returns (uint256);
function queue(uint256 proposalId) external;
function execute(uint256 proposalId) external;
function propose(
address[] memory targets,
string[] memory signatures,
bytes[] memory calldatas,
string memory description
) external returns (uint256);
}
2 changes: 1 addition & 1 deletion contracts/tests/MockRewardsSource.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity 0.8.10;
contract MockRewardsSource {
constructor() {}

function previewRewards() external view returns (uint256) {
function previewRewards() external pure returns (uint256) {
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/tests/TestToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.4;
import "../GovernanceToken.sol";

contract TestToken is OriginDollarGovernance {
function proof() public {
function proof() public pure {
revert("Upgraded");
}
}
7 changes: 7 additions & 0 deletions contracts/upgrades/ExponentialStakingProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

contract ExponentialStakingProxy is InitializeGovernedUpgradeabilityProxy {}
22 changes: 22 additions & 0 deletions contracts/utils/Addresses.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

library Addresses {
address public constant TIMELOCK = 0x35918cDE7233F2dD33fA41ae3Cb6aE0e42E0e69F;
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 = 0xD7B28d06365b85933c64E11e639EA0d3bC0e3BaB;
address public constant OETH_BUYBACK = 0xFD6c58850caCF9cCF6e8Aee479BFb4Df14a362D2;
address public constant OUSD_BUYBACK_IMPL = 0x386d8fEC5b6d5B5E36a48A376644e36239dB65d6;
address public constant OETH_BUYBACK_IMPL = 0x4F11d31f781B57051764a3823b24d520626b4833;
}
67 changes: 67 additions & 0 deletions contracts/utils/GovFive.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import {Vm} from "forge-std/Vm.sol";
import {Addresses} from "contracts/utils/Addresses.sol";
import "forge-std/console.sol";

import "OpenZeppelin/[email protected]/contracts/utils/Strings.sol";

library GovFive {
struct GovFiveAction {
address receiver;
string fullsig;
bytes data;
}

struct GovFiveProposal {
string name;
string description;
GovFiveAction[] actions;
}

function setName(GovFiveProposal storage prop, string memory name) internal {
prop.name = name;
}

function setDescription(GovFiveProposal storage prop, string memory description) internal {
prop.description = description;
}

function action(GovFiveProposal storage prop, address receiver, string memory fullsig, bytes memory data)
internal
{
prop.actions.push(GovFiveAction({receiver: receiver, fullsig: fullsig, data: data}));
}

function printTxData(GovFiveProposal storage prop) internal {
console.log("-----------------------------------");
console.log("Create following tx on Gnosis safe:");
console.log("-----------------------------------");
for (uint256 i = 0; i < prop.actions.length; i++) {
GovFiveAction memory propAction = prop.actions[i];
bytes memory sig = abi.encodePacked(bytes4(keccak256(bytes(propAction.fullsig))));

console.log("### Tx", i + 1);
console.log("Address:", propAction.receiver);
console.log("Data:");
console.logBytes(abi.encodePacked(sig, propAction.data));
}
}

function execute(GovFiveProposal storage prop) internal {
address VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
Vm vm = Vm(VM_ADDRESS);
for (uint256 i = 0; i < prop.actions.length; i++) {
GovFiveAction memory propAction = prop.actions[i];
bytes memory sig = abi.encodePacked(bytes4(keccak256(bytes(propAction.fullsig))));
vm.prank(Addresses.TIMELOCK);
(bool success, bytes memory data) = propAction.receiver.call(abi.encodePacked(sig, propAction.data));
if (!success) {
console.log(propAction.fullsig);
revert("Multisig action failed");
}
}
}
}
6 changes: 6 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ src = 'contracts'
test = 'tests'
remappings = [
"contracts/=./contracts",
"script/=./script",
"tests/=./tests",
"OpenZeppelin/openzeppelin-contracts@02fcc75bb7f35376c22def91b0fb9bc7a50b9458/=./lib/openzeppelin-contracts",
"OpenZeppelin/openzeppelin-contracts-upgradeable@a16f26a063cd018c4c986832c3df332a131f53b9/=./lib/openzeppelin-contracts-upgradeable",
"OpenZeppelin/[email protected]/=./lib/openzeppelin-contracts",
"OpenZeppelin/[email protected]/=./lib/openzeppelin-contracts-upgradeable",
"paulrberg/[email protected]/=./lib/prb-math"
]
fs_permissions = [{ access = "read-write", path = "./build"}]
extra_output_files = [
"metadata"
]
2 changes: 1 addition & 1 deletion lib/forge-std
Submodule forge-std updated 63 files
+1 −0 .gitattributes
+128 −0 .github/workflows/ci.yml
+31 −0 .github/workflows/sync.yml
+0 −27 .github/workflows/tests.yml
+1 −1 .gitignore
+0 −3 .gitmodules
+1 −1 LICENSE-APACHE
+1 −1 LICENSE-MIT
+9 −5 README.md
+19 −0 foundry.toml
+0 −1 lib/ds-test
+16 −0 package.json
+635 −0 scripts/vm.py
+35 −0 src/Base.sol
+21 −33 src/Script.sol
+669 −0 src/StdAssertions.sol
+250 −0 src/StdChains.sol
+817 −0 src/StdCheats.sol
+15 −0 src/StdError.sol
+113 −0 src/StdInvariant.sol
+122 −61 src/StdJson.sol
+43 −0 src/StdMath.sol
+473 −0 src/StdStorage.sol
+333 −0 src/StdStyle.sol
+179 −0 src/StdToml.sol
+226 −0 src/StdUtils.sol
+29 −1,134 src/Test.sol
+1,735 −215 src/Vm.sol
+406 −386 src/console2.sol
+105 −0 src/interfaces/IERC1155.sol
+12 −0 src/interfaces/IERC165.sol
+43 −0 src/interfaces/IERC20.sol
+190 −0 src/interfaces/IERC4626.sol
+164 −0 src/interfaces/IERC721.sol
+73 −0 src/interfaces/IMulticall3.sol
+234 −0 src/mocks/MockERC20.sol
+235 −0 src/mocks/MockERC721.sol
+13,248 −0 src/safeconsole.sol
+0 −12 src/test/Script.t.sol
+0 −602 src/test/StdAssertions.t.sol
+0 −282 src/test/StdCheats.t.sol
+0 −200 src/test/StdMath.t.sol
+0 −321 src/test/StdStorage.t.sol
+145 −0 test/StdAssertions.t.sol
+221 −0 test/StdChains.t.sol
+618 −0 test/StdCheats.t.sol
+14 −18 test/StdError.t.sol
+49 −0 test/StdJson.t.sol
+212 −0 test/StdMath.t.sol
+463 −0 test/StdStorage.t.sol
+110 −0 test/StdStyle.t.sol
+49 −0 test/StdToml.t.sol
+342 −0 test/StdUtils.t.sol
+15 −0 test/Vm.t.sol
+10 −0 test/compilation/CompilationScript.sol
+10 −0 test/compilation/CompilationScriptBase.sol
+10 −0 test/compilation/CompilationTest.sol
+10 −0 test/compilation/CompilationTestBase.sol
+0 −0 test/fixtures/broadcast.log.json
+8 −0 test/fixtures/test.json
+6 −0 test/fixtures/test.toml
+441 −0 test/mocks/MockERC20.t.sol
+721 −0 test/mocks/MockERC721.t.sol
Loading

0 comments on commit 012b8ab

Please sign in to comment.