文件 1 的 1:gOHM_flat.sol
pragma solidity ^0.7.5;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
assert(a == b * c + a % b);
return c;
}
function sqrrt(uint256 a) internal pure returns (uint c) {
if (a > 3) {
c = a;
uint b = add( div( a, 2), 1 );
while (b < c) {
c = b;
b = div( add( div( a, b ), b), 2 );
}
} else if (a != 0) {
c = 1;
}
}
}
pragma solidity =0.7.5;
interface IOlympusAuthority {
event GovernorPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event GuardianPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event PolicyPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event VaultPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event GovernorPulled(address indexed from, address indexed to);
event GuardianPulled(address indexed from, address indexed to);
event PolicyPulled(address indexed from, address indexed to);
event VaultPulled(address indexed from, address indexed to);
function governor() external view returns (address);
function guardian() external view returns (address);
function policy() external view returns (address);
function vault() external view returns (address);
}
pragma solidity >=0.7.5;
abstract contract OlympusAccessControlled {
event AuthorityUpdated(IOlympusAuthority indexed authority);
string UNAUTHORIZED = "UNAUTHORIZED";
IOlympusAuthority public authority;
constructor(IOlympusAuthority _authority) {
authority = _authority;
emit AuthorityUpdated(_authority);
}
modifier onlyGovernor() {
require(msg.sender == authority.governor(), UNAUTHORIZED);
_;
}
modifier onlyGuardian() {
require(msg.sender == authority.guardian(), UNAUTHORIZED);
_;
}
modifier onlyPolicy() {
require(msg.sender == authority.policy(), UNAUTHORIZED);
_;
}
modifier onlyVault() {
require(msg.sender == authority.vault(), UNAUTHORIZED);
_;
}
function setAuthority(IOlympusAuthority _newAuthority) external onlyGovernor {
authority = _newAuthority;
emit AuthorityUpdated(_newAuthority);
}
}
pragma solidity >=0.7.5;
interface ITreasuryV1 {
function withdraw(uint256 amount, address token) external;
function manage(address token, uint256 amount) external;
function valueOf(address token, uint256 amount) external view returns (uint256);
function excessReserves() external view returns (uint256);
}
pragma solidity >=0.7.5;
interface IStakingV1 {
function unstake(uint256 _amount, bool _trigger) external;
function index() external view returns (uint256);
}
pragma solidity >=0.7.5;
interface IUniswapV2Router {
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function addLiquidity(
address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function removeLiquidity(
address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline
) external returns (uint amountA, uint amountB);
}
pragma solidity >=0.7.5;
interface IOwnable {
function owner() external view returns (address);
function renounceManagement() external;
function pushManagement( address newOwner_ ) external;
function pullManagement() external;
}
pragma solidity >=0.7.5;
interface IStaking {
function stake(
address _to,
uint256 _amount,
bool _rebasing,
bool _claim
) external returns (uint256);
function claim(address _recipient, bool _rebasing) external returns (uint256);
function forfeit() external returns (uint256);
function toggleLock() external;
function unstake(
address _to,
uint256 _amount,
bool _trigger,
bool _rebasing
) external returns (uint256);
function wrap(address _to, uint256 _amount) external returns (uint256 gBalance_);
function unwrap(address _to, uint256 _amount) external returns (uint256 sBalance_);
function rebase() external;
function index() external view returns (uint256);
function contractBalance() external view returns (uint256);
function totalStaked() external view returns (uint256);
function supplyInWarmup() external view returns (uint256);
}
pragma solidity >=0.7.5;
interface ITreasury {
function deposit(
uint256 _amount,
address _token,
uint256 _profit
) external returns (uint256);
function withdraw(uint256 _amount, address _token) external;
function tokenValue(address _token, uint256 _amount) external view returns (uint256 value_);
function mint(address _recipient, uint256 _amount) external;
function manage(address _token, uint256 _amount) external;
function incurDebt(uint256 amount_, address token_) external;
function repayDebtWithReserve(uint256 amount_, address token_) external;
function excessReserves() external view returns (uint256);
}
pragma solidity >=0.7.5;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity >=0.7.5;
library SafeERC20 {
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FROM_FAILED");
}
function safeTransfer(
IERC20 token,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(IERC20.transfer.selector, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FAILED");
}
function safeApprove(
IERC20 token,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(IERC20.approve.selector, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "APPROVE_FAILED");
}
function safeTransferETH(address to, uint256 amount) internal {
(bool success, ) = to.call{value: amount}(new bytes(0));
require(success, "ETH_TRANSFER_FAILED");
}
}
pragma solidity >=0.7.5;
interface IgOHM is IERC20 {
function mint(address _to, uint256 _amount) external;
function burn(address _from, uint256 _amount) external;
function index() external view returns (uint256);
function balanceFrom(uint256 _amount) external view returns (uint256);
function balanceTo(uint256 _amount) external view returns (uint256);
function migrate( address _staking, address _sOHM ) external;
}
pragma solidity >=0.7.5;
interface IwsOHM is IERC20 {
function wrap(uint256 _amount) external returns (uint256);
function unwrap(uint256 _amount) external returns (uint256);
function wOHMTosOHM(uint256 _amount) external view returns (uint256);
function sOHMTowOHM(uint256 _amount) external view returns (uint256);
}
pragma solidity >=0.7.5;
interface IsOHM is IERC20 {
function rebase( uint256 ohmProfit_, uint epoch_) external returns (uint256);
function circulatingSupply() external view returns (uint256);
function gonsForBalance( uint amount ) external view returns ( uint );
function balanceForGons( uint gons ) external view returns ( uint );
function index() external view returns ( uint );
function toG(uint amount) external view returns (uint);
function fromG(uint amount) external view returns (uint);
function changeDebt(
uint256 amount,
address debtor,
bool add
) external;
function debtBalances(address _address) external view returns (uint256);
}
pragma solidity 0.7.5;
contract OlympusTokenMigrator is OlympusAccessControlled {
using SafeMath for uint256;
using SafeERC20 for IERC20;
using SafeERC20 for IgOHM;
using SafeERC20 for IsOHM;
using SafeERC20 for IwsOHM;
event TimelockStarted(uint256 block, uint256 end);
event Migrated(address staking, address treasury);
event Funded(uint256 amount);
event Defunded(uint256 amount);
IERC20 public immutable oldOHM;
IsOHM public immutable oldsOHM;
IwsOHM public immutable oldwsOHM;
ITreasuryV1 public immutable oldTreasury;
IStakingV1 public immutable oldStaking;
IUniswapV2Router public immutable sushiRouter;
IUniswapV2Router public immutable uniRouter;
IgOHM public gOHM;
ITreasury public newTreasury;
IStaking public newStaking;
IERC20 public newOHM;
bool public ohmMigrated;
bool public shutdown;
uint256 public immutable timelockLength;
uint256 public timelockEnd;
uint256 public oldSupply;
constructor(
address _oldOHM,
address _oldsOHM,
address _oldTreasury,
address _oldStaking,
address _oldwsOHM,
address _sushi,
address _uni,
uint256 _timelock,
address _authority
) OlympusAccessControlled(IOlympusAuthority(_authority)) {
require(_oldOHM != address(0), "Zero address: OHM");
oldOHM = IERC20(_oldOHM);
require(_oldsOHM != address(0), "Zero address: sOHM");
oldsOHM = IsOHM(_oldsOHM);
require(_oldTreasury != address(0), "Zero address: Treasury");
oldTreasury = ITreasuryV1(_oldTreasury);
require(_oldStaking != address(0), "Zero address: Staking");
oldStaking = IStakingV1(_oldStaking);
require(_oldwsOHM != address(0), "Zero address: wsOHM");
oldwsOHM = IwsOHM(_oldwsOHM);
require(_sushi != address(0), "Zero address: Sushi");
sushiRouter = IUniswapV2Router(_sushi);
require(_uni != address(0), "Zero address: Uni");
uniRouter = IUniswapV2Router(_uni);
timelockLength = _timelock;
}
enum TYPE {
UNSTAKED,
STAKED,
WRAPPED
}
function migrate(
uint256 _amount,
TYPE _from,
TYPE _to
) external {
require(!shutdown, "Shut down");
uint256 wAmount = oldwsOHM.sOHMTowOHM(_amount);
if (_from == TYPE.UNSTAKED) {
require(ohmMigrated, "Only staked until migration");
oldOHM.safeTransferFrom(msg.sender, address(this), _amount);
} else if (_from == TYPE.STAKED) {
oldsOHM.safeTransferFrom(msg.sender, address(this), _amount);
} else {
oldwsOHM.safeTransferFrom(msg.sender, address(this), _amount);
wAmount = _amount;
}
if (ohmMigrated) {
require(oldSupply >= oldOHM.totalSupply(), "OHMv1 minted");
_send(wAmount, _to);
} else {
gOHM.mint(msg.sender, wAmount);
}
}
function migrateAll(TYPE _to) external {
require(!shutdown, "Shut down");
uint256 ohmBal = 0;
uint256 sOHMBal = oldsOHM.balanceOf(msg.sender);
uint256 wsOHMBal = oldwsOHM.balanceOf(msg.sender);
if (oldOHM.balanceOf(msg.sender) > 0 && ohmMigrated) {
ohmBal = oldOHM.balanceOf(msg.sender);
oldOHM.safeTransferFrom(msg.sender, address(this), ohmBal);
}
if (sOHMBal > 0) {
oldsOHM.safeTransferFrom(msg.sender, address(this), sOHMBal);
}
if (wsOHMBal > 0) {
oldwsOHM.safeTransferFrom(msg.sender, address(this), wsOHMBal);
}
uint256 wAmount = wsOHMBal.add(oldwsOHM.sOHMTowOHM(ohmBal.add(sOHMBal)));
if (ohmMigrated) {
require(oldSupply >= oldOHM.totalSupply(), "OHMv1 minted");
_send(wAmount, _to);
} else {
gOHM.mint(msg.sender, wAmount);
}
}
function _send(uint256 wAmount, TYPE _to) internal {
if (_to == TYPE.WRAPPED) {
gOHM.safeTransfer(msg.sender, wAmount);
} else if (_to == TYPE.STAKED) {
newStaking.unwrap(msg.sender, wAmount);
} else if (_to == TYPE.UNSTAKED) {
newStaking.unstake(msg.sender, wAmount, false, false);
}
}
function bridgeBack(uint256 _amount, TYPE _to) external {
if (!ohmMigrated) {
gOHM.burn(msg.sender, _amount);
} else {
gOHM.safeTransferFrom(msg.sender, address(this), _amount);
}
uint256 amount = oldwsOHM.wOHMTosOHM(_amount);
if (_to == TYPE.UNSTAKED) {
oldOHM.safeTransfer(msg.sender, amount);
} else if (_to == TYPE.STAKED) {
oldsOHM.safeTransfer(msg.sender, amount);
} else if (_to == TYPE.WRAPPED) {
oldwsOHM.safeTransfer(msg.sender, _amount);
}
}
function halt() external onlyPolicy {
require(!ohmMigrated, "Migration has occurred");
shutdown = !shutdown;
}
function defund(address reserve) external onlyGovernor {
require(ohmMigrated, "Migration has not begun");
require(timelockEnd < block.number && timelockEnd != 0, "Timelock not complete");
oldwsOHM.unwrap(oldwsOHM.balanceOf(address(this)));
uint256 amountToUnstake = oldsOHM.balanceOf(address(this));
oldsOHM.approve(address(oldStaking), amountToUnstake);
oldStaking.unstake(amountToUnstake, false);
uint256 balance = oldOHM.balanceOf(address(this));
if(balance > oldSupply) {
oldSupply = 0;
} else {
oldSupply -= balance;
}
uint256 amountToWithdraw = balance.mul(1e9);
oldOHM.approve(address(oldTreasury), amountToWithdraw);
oldTreasury.withdraw(amountToWithdraw, reserve);
IERC20(reserve).safeTransfer(address(newTreasury), IERC20(reserve).balanceOf(address(this)));
emit Defunded(balance);
}
function startTimelock() external onlyGovernor {
require(timelockEnd == 0, "Timelock set");
timelockEnd = block.number.add(timelockLength);
emit TimelockStarted(block.number, timelockEnd);
}
function setgOHM(address _gOHM) external onlyGovernor {
require(address(gOHM) == address(0), "Already set");
require(_gOHM != address(0), "Zero address: gOHM");
gOHM = IgOHM(_gOHM);
}
function migrateToken(address token) external onlyGovernor {
_migrateToken(token, false);
}
function migrateLP(
address pair,
bool sushi,
address token,
uint256 _minA,
uint256 _minB
) external onlyGovernor {
uint256 oldLPAmount = IERC20(pair).balanceOf(address(oldTreasury));
oldTreasury.manage(pair, oldLPAmount);
IUniswapV2Router router = sushiRouter;
if (!sushi) {
router = uniRouter;
}
IERC20(pair).approve(address(router), oldLPAmount);
(uint256 amountA, uint256 amountB) = router.removeLiquidity(
token,
address(oldOHM),
oldLPAmount,
_minA,
_minB,
address(this),
block.timestamp
);
newTreasury.mint(address(this), amountB);
IERC20(token).approve(address(router), amountA);
newOHM.approve(address(router), amountB);
router.addLiquidity(
token,
address(newOHM),
amountA,
amountB,
amountA,
amountB,
address(newTreasury),
block.timestamp
);
}
function withdrawToken(
address tokenAddress,
uint256 amount,
address recipient
) external onlyGovernor {
require(tokenAddress != address(0), "Token address cannot be 0x0");
require(tokenAddress != address(gOHM), "Cannot withdraw: gOHM");
require(tokenAddress != address(oldOHM), "Cannot withdraw: old-OHM");
require(tokenAddress != address(oldsOHM), "Cannot withdraw: old-sOHM");
require(tokenAddress != address(oldwsOHM), "Cannot withdraw: old-wsOHM");
require(amount > 0, "Withdraw value must be greater than 0");
if (recipient == address(0)) {
recipient = msg.sender;
}
IERC20 tokenContract = IERC20(tokenAddress);
uint256 contractBalance = tokenContract.balanceOf(address(this));
if (amount > contractBalance) {
amount = contractBalance;
}
tokenContract.safeTransfer(recipient, amount);
}
function migrateContracts(
address _newTreasury,
address _newStaking,
address _newOHM,
address _newsOHM,
address _reserve
) external onlyGovernor {
require(!ohmMigrated, "Already migrated");
ohmMigrated = true;
shutdown = false;
require(_newTreasury != address(0), "Zero address: Treasury");
newTreasury = ITreasury(_newTreasury);
require(_newStaking != address(0), "Zero address: Staking");
newStaking = IStaking(_newStaking);
require(_newOHM != address(0), "Zero address: OHM");
newOHM = IERC20(_newOHM);
oldSupply = oldOHM.totalSupply();
gOHM.migrate(_newStaking, _newsOHM);
_migrateToken(_reserve, true);
_fund(oldsOHM.circulatingSupply());
emit Migrated(_newStaking, _newTreasury);
}
function _fund(uint256 _amount) internal {
newTreasury.mint(address(this), _amount);
newOHM.approve(address(newStaking), _amount);
newStaking.stake(address(this), _amount, false, true);
emit Funded(_amount);
}
function _migrateToken(address token, bool deposit) internal {
uint256 balance = IERC20(token).balanceOf(address(oldTreasury));
uint256 excessReserves = oldTreasury.excessReserves();
uint256 tokenValue = oldTreasury.valueOf(token, balance);
if (tokenValue > excessReserves) {
tokenValue = excessReserves;
balance = excessReserves * 10**9;
}
oldTreasury.manage(token, balance);
if (deposit) {
IERC20(token).safeApprove(address(newTreasury), balance);
newTreasury.deposit(balance, token, tokenValue);
} else {
IERC20(token).safeTransfer(address(newTreasury), balance);
}
}
}