-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
987fd45
commit 5565133
Showing
9 changed files
with
231 additions
and
11 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.10; | ||
|
||
import {IStaking} from "./interfaces/IStaking.sol"; | ||
import {IMigrator} from "./interfaces/IMigrator.sol"; | ||
import {IMintableERC20} from "./interfaces/IMintableERC20.sol"; | ||
|
||
contract MigrationZapper { | ||
IMintableERC20 public immutable ogv; | ||
IMintableERC20 public immutable ogn; | ||
|
||
IMigrator public immutable migrator; | ||
IStaking public immutable ognStaking; | ||
|
||
constructor(address _ogv, address _ogn, address _migrator, address _ognStaking) { | ||
ogv = IMintableERC20(_ogv); | ||
ogn = IMintableERC20(_ogn); | ||
migrator = IMigrator(_migrator); | ||
ognStaking = IStaking(_ognStaking); | ||
} | ||
|
||
function initialize() external { | ||
// Migrator can move OGV and OGN from this contract | ||
ogv.approve(address(migrator), type(uint256).max); | ||
ogn.approve(address(ognStaking), type(uint256).max); | ||
} | ||
|
||
/** | ||
* @notice Migrates the specified amount of OGV to OGN. | ||
* @param ogvAmount Amount of OGV to migrate | ||
*/ | ||
function migrate(uint256 ogvAmount) external { | ||
// Take tokens in | ||
ogv.transferFrom(msg.sender, address(this), ogvAmount); | ||
|
||
// Proxy migrate call | ||
uint256 ognReceived = migrator.migrate(ogvAmount); | ||
|
||
// Transfer OGN to the receiver | ||
ogn.transfer(msg.sender, ognReceived); | ||
} | ||
|
||
/** | ||
* @notice Migrates the specified amount of OGV to OGN | ||
* and stakes it. | ||
* @param ogvAmount Amount of OGV to migrate | ||
*/ | ||
function migrate(uint256 ogvAmount, uint256 newStakeAmount, uint256 newStakeDuration) external { | ||
// Take tokens in | ||
ogv.transferFrom(msg.sender, address(this), ogvAmount); | ||
|
||
// Migrate | ||
uint256 ognReceived = migrator.migrate(ogvAmount); | ||
|
||
// Stake on behalf of user | ||
ognStaking.stake( | ||
newStakeAmount, | ||
newStakeDuration, | ||
msg.sender, | ||
false, | ||
-1 // New stake | ||
); | ||
} | ||
} |
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,15 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.10; | ||
|
||
interface IMigrator { | ||
function migrate(uint256 ogvAmount) external returns (uint256); | ||
|
||
function migrate( | ||
uint256[] calldata lockupIds, | ||
uint256 ogvAmountFromWallet, | ||
uint256 ognAmountFromWallet, | ||
bool migrateRewards, | ||
uint256 newStakeAmount, | ||
uint256 newStakeDuration | ||
) external; | ||
} |
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,12 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.10; | ||
|
||
interface IStaking { | ||
function delegates(address staker) external view returns (address); | ||
|
||
// From OGVStaking.sol | ||
function unstakeFrom(address staker, uint256[] memory lockupIds) external returns (uint256, uint256); | ||
|
||
// From ExponentialStaking.sol | ||
function stake(uint256 amountIn, uint256 duration, address to, bool stakeRewards, int256 lockupId) external; | ||
} |
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,47 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity 0.8.10; | ||
|
||
import "./BaseMainnetScript.sol"; | ||
import {Vm} from "forge-std/Vm.sol"; | ||
|
||
import {Addresses} from "contracts/utils/Addresses.sol"; | ||
|
||
import {Timelock} from "contracts/Timelock.sol"; | ||
import {Governance} from "contracts/Governance.sol"; | ||
|
||
import {GovFive} from "contracts/utils/GovFive.sol"; | ||
|
||
import {VmHelper} from "utils/VmHelper.sol"; | ||
|
||
import {MigrationZapper} from "contracts/MigrationZapper.sol"; | ||
|
||
import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/token/ERC20/extensions/ERC20Votes.sol"; | ||
import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/governance/TimelockController.sol"; | ||
|
||
contract MigrationZapperScript is BaseMainnetScript { | ||
using GovFive for GovFive.GovFiveProposal; | ||
using VmHelper for Vm; | ||
|
||
GovFive.GovFiveProposal public govProposal; | ||
|
||
string public constant override DEPLOY_NAME = "012_MigrationZapper"; | ||
|
||
constructor() {} | ||
|
||
function _execute() internal override { | ||
console.log("Deploy:"); | ||
console.log("------------"); | ||
|
||
MigrationZapper zapper = | ||
new MigrationZapper(Addresses.OGV, Addresses.OGN, deployedContracts["MIGRATOR"], deployedContracts["XOGN"]); | ||
_recordDeploy("MIGRATION_ZAPPER", address(zapper)); | ||
|
||
// Make sure Migrator can move OGV and OGN | ||
zapper.initialize(); | ||
} | ||
|
||
function _buildGovernanceProposal() internal override {} | ||
|
||
function _fork() internal override {} | ||
} |
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,87 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity 0.8.10; | ||
|
||
import "forge-std/Test.sol"; | ||
|
||
import {Addresses} from "contracts/utils/Addresses.sol"; | ||
import {DeployManager} from "script/deploy/DeployManager.sol"; | ||
|
||
import {Migrator} from "contracts/Migrator.sol"; | ||
import {MigrationZapper} from "contracts/MigrationZapper.sol"; | ||
import {OgvStaking} from "contracts/OgvStaking.sol"; | ||
import {ExponentialStaking} from "contracts/ExponentialStaking.sol"; | ||
|
||
import {IMintableERC20} from "contracts/interfaces/IMintableERC20.sol"; | ||
|
||
contract ZapperForkTest is Test { | ||
DeployManager public deployManager; | ||
|
||
Migrator public migrator; | ||
MigrationZapper public zapper; | ||
OgvStaking public veogv; | ||
ExponentialStaking public xogn; | ||
IMintableERC20 public ogv; | ||
IMintableERC20 public ogn; | ||
|
||
address public ogvWhale = Addresses.GOV_MULTISIG; | ||
|
||
constructor() { | ||
deployManager = new DeployManager(); | ||
|
||
deployManager.setUp(); | ||
deployManager.run(); | ||
} | ||
|
||
function setUp() external { | ||
migrator = Migrator(deployManager.getDeployment("MIGRATOR")); | ||
zapper = MigrationZapper(deployManager.getDeployment("MIGRATION_ZAPPER")); | ||
|
||
veogv = OgvStaking(Addresses.VEOGV); | ||
ogv = IMintableERC20(Addresses.OGV); | ||
ogn = IMintableERC20(Addresses.OGN); | ||
xogn = ExponentialStaking(deployManager.getDeployment("XOGN")); | ||
|
||
vm.startPrank(ogvWhale); | ||
ogv.approve(address(migrator), type(uint256).max); | ||
ogv.approve(address(zapper), type(uint256).max); | ||
ogn.approve(address(migrator), type(uint256).max); | ||
ogv.approve(address(veogv), type(uint256).max); | ||
vm.stopPrank(); | ||
} | ||
|
||
function testBalanceMigration() external { | ||
vm.startPrank(ogvWhale); | ||
|
||
uint256 migratorOGNReserve = ogn.balanceOf(address(migrator)); | ||
uint256 ogvSupply = ogv.totalSupply(); | ||
uint256 ogvBalanceBefore = ogv.balanceOf(ogvWhale); | ||
uint256 ognBalanceBefore = ogn.balanceOf(ogvWhale); | ||
|
||
// Should be able to swap OGV to OGN at fixed rate | ||
zapper.migrate(100 ether); | ||
|
||
assertEq(ogv.balanceOf(ogvWhale), ogvBalanceBefore - 100 ether, "More OGV burnt"); | ||
assertEq(ogv.totalSupply(), ogvSupply - 100 ether, "OGV supply mismatch"); | ||
|
||
assertEq(ogn.balanceOf(ogvWhale), ognBalanceBefore + 9.137 ether, "Less OGN received"); | ||
assertEq(ogn.balanceOf(address(migrator)), migratorOGNReserve - 9.137 ether, "More OGN sent"); | ||
|
||
vm.stopPrank(); | ||
} | ||
|
||
function testMigrateBalanceAndStake() public { | ||
vm.startPrank(ogvWhale); | ||
|
||
uint256[] memory lockupIds = new uint256[](0); | ||
uint256 stakeAmount = (100 ether * 0.09137 ether) / 1 ether; | ||
|
||
zapper.migrate(100 ether, 1 ether, 300 days); | ||
|
||
// Should have it in a single OGN lockup | ||
(uint128 amount, uint128 end, uint256 points) = xogn.lockups(ogvWhale, 0); | ||
assertEq(amount, stakeAmount, "Balance not staked"); | ||
|
||
vm.stopPrank(); | ||
} | ||
} |