文件 1 的 1:MCDMonitor.sol
pragma solidity ^0.5.0;
contract Static {
enum Method { Boost, Repay }
}
contract ISubscriptions is Static {
function canCall(Method _method, uint _cdpId) external view returns(bool, uint);
function getOwner(uint _cdpId) external view returns(address);
function ratioGoodAfter(Method _method, uint _cdpId) external view returns(bool, uint);
function getRatio(uint _cdpId) public view returns (uint);
}
contract DSProxyInterface {
function execute(bytes memory _code, bytes memory _data) public payable returns (address, bytes32);
function execute(address _target, bytes memory _data) public payable returns (bytes32);
function setCache(address _cacheAddr) public payable returns (bool);
function owner() public returns (address);
}
contract MCDMonitorProxy {
uint public CHANGE_PERIOD;
address public monitor;
address public owner;
address public newMonitor;
uint public changeRequestedTimestamp;
mapping(address => bool) public allowed;
modifier onlyAllowed() {
require(allowed[msg.sender] || msg.sender == owner);
_;
}
modifier onlyMonitor() {
require (msg.sender == monitor);
_;
}
constructor(uint _changePeriod) public {
owner = msg.sender;
CHANGE_PERIOD = _changePeriod * 1 days;
}
function setMonitor(address _monitor) public onlyAllowed {
require(monitor == address(0));
monitor = _monitor;
}
function callExecute(address _owner, address _saverProxy, bytes memory _data) public onlyMonitor {
DSProxyInterface(_owner).execute(_saverProxy, _data);
}
function changeMonitor(address _newMonitor) public onlyAllowed {
changeRequestedTimestamp = now;
newMonitor = _newMonitor;
}
function cancelMonitorChange() public onlyAllowed {
changeRequestedTimestamp = 0;
newMonitor = address(0);
}
function confirmNewMonitor() public onlyAllowed {
require((changeRequestedTimestamp + CHANGE_PERIOD) < now);
require(changeRequestedTimestamp != 0);
require(newMonitor != address(0));
monitor = newMonitor;
newMonitor = address(0);
changeRequestedTimestamp = 0;
}
function addAllowed(address _user) public onlyAllowed {
allowed[_user] = true;
}
function removeAllowed(address _user) public onlyAllowed {
allowed[_user] = false;
}
}
contract ConstantAddressesMainnet {
address public constant MAKER_DAI_ADDRESS = 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359;
address public constant IDAI_ADDRESS = 0x14094949152EDDBFcd073717200DA82fEd8dC960;
address public constant SOLO_MARGIN_ADDRESS = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
address public constant CDAI_ADDRESS = 0xF5DCe57282A584D2746FaF1593d3121Fcac444dC;
address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant MKR_ADDRESS = 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2;
address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant VOX_ADDRESS = 0x9B0F70Df76165442ca6092939132bBAEA77f2d7A;
address public constant PETH_ADDRESS = 0xf53AD2c6851052A81B42133467480961B2321C09;
address public constant TUB_ADDRESS = 0x448a5065aeBB8E423F0896E6c5D525C040f59af3;
address payable public constant WALLET_ID = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08;
address public constant LOGGER_ADDRESS = 0xeCf88e1ceC2D2894A0295DB3D86Fe7CE4991E6dF;
address public constant OTC_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
address public constant DISCOUNT_ADDRESS = 0x1b14E8D511c9A4395425314f849bD737BAF8208F;
address public constant KYBER_WRAPPER = 0x8F337bD3b7F2b05d9A8dC8Ac518584e833424893;
address public constant UNISWAP_WRAPPER = 0x1e30124FDE14533231216D95F7798cD0061e5cf8;
address public constant ETH2DAI_WRAPPER = 0xd7BBB1777E13b6F535Dec414f575b858ed300baF;
address public constant OASIS_WRAPPER = 0x9aBE2715D2d99246269b8E17e9D1b620E9bf6558;
address public constant KYBER_INTERFACE = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
address public constant UNISWAP_FACTORY = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
address public constant FACTORY_ADDRESS = 0x5a15566417e6C1c9546523066500bDDBc53F88C7;
address public constant PIP_INTERFACE_ADDRESS = 0x729D19f657BD0614b4985Cf1D82531c67569197B;
address public constant PROXY_REGISTRY_INTERFACE_ADDRESS = 0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4;
address public constant GAS_TOKEN_INTERFACE_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04;
address public constant SAVINGS_LOGGER_ADDRESS = 0x89b3635BD2bAD145C6f92E82C9e83f06D5654984;
address public constant SAVER_EXCHANGE_ADDRESS = 0x865B41584A22F8345Fca4B71c42a1E7aBcD67eCB;
address public constant COMPOUND_DAI_ADDRESS = 0x25a01a05C188DaCBCf1D61Af55D4a5B4021F7eeD;
address public constant STUPID_EXCHANGE = 0x863E41FE88288ebf3fcd91d8Dbb679fb83fdfE17;
address public constant MANAGER_ADDRESS = 0x5ef30b9986345249bc32d8928B7ee64DE9435E39;
address public constant VAT_ADDRESS = 0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B;
address public constant SPOTTER_ADDRESS = 0x65C79fcB50Ca1594B025960e539eD7A9a6D434A3;
address public constant PROXY_ACTIONS = 0x82ecD135Dce65Fbc6DbdD0e4237E0AF93FFD5038;
address public constant JUG_ADDRESS = 0x19c0976f590D67707E62397C87829d896Dc0f1F1;
address public constant DAI_JOIN_ADDRESS = 0x9759A6Ac90977b93B58547b4A71c78317f391A28;
address public constant ETH_JOIN_ADDRESS = 0x2F0b23f53734252Bda2277357e97e1517d6B042A;
address public constant MIGRATION_ACTIONS_PROXY = 0xe4B22D484958E582098A98229A24e8A43801b674;
address public constant SAI_ADDRESS = 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address payable public constant SCD_MCD_MIGRATION = 0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849;
address public constant SUBSCRIPTION_ADDRESS = 0x05A78A2a1Afeb699d73363D096659B53D3B1969E;
address public constant MONITOR_ADDRESS = 0x3F4339816EDEF8D3d3970DB2993e2e0Ec6010760;
}
contract ConstantAddressesKovan {
address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant WETH_ADDRESS = 0xd0A1E359811322d97991E03f863a0C30C2cF029C;
address public constant MAKER_DAI_ADDRESS = 0xC4375B7De8af5a38a93548eb8453a498222C4fF2;
address public constant MKR_ADDRESS = 0xAaF64BFCC32d0F15873a02163e7E500671a4ffcD;
address public constant VOX_ADDRESS = 0xBb4339c0aB5B1d9f14Bd6e3426444A1e9d86A1d9;
address public constant PETH_ADDRESS = 0xf4d791139cE033Ad35DB2B2201435fAd668B1b64;
address public constant TUB_ADDRESS = 0xa71937147b55Deb8a530C7229C442Fd3F31b7db2;
address public constant LOGGER_ADDRESS = 0x32d0e18f988F952Eb3524aCE762042381a2c39E5;
address payable public constant WALLET_ID = 0x54b44C6B18fc0b4A1010B21d524c338D1f8065F6;
address public constant OTC_ADDRESS = 0x4A6bC4e803c62081ffEbCc8d227B5a87a58f1F8F;
address public constant COMPOUND_DAI_ADDRESS = 0x25a01a05C188DaCBCf1D61Af55D4a5B4021F7eeD;
address public constant SOLO_MARGIN_ADDRESS = 0x4EC3570cADaAEE08Ae384779B0f3A45EF85289DE;
address public constant IDAI_ADDRESS = 0xA1e58F3B1927743393b25f261471E1f2D3D9f0F6;
address public constant CDAI_ADDRESS = 0xb6b09fBffBa6A5C4631e5F7B2e3Ee183aC259c0d;
address public constant STUPID_EXCHANGE = 0x863E41FE88288ebf3fcd91d8Dbb679fb83fdfE17;
address public constant DISCOUNT_ADDRESS = 0x1297c1105FEDf45E0CF6C102934f32C4EB780929;
address public constant SAI_SAVER_PROXY = 0xADB7c74bCe932fC6C27ddA3Ac2344707d2fBb0E6;
address public constant KYBER_WRAPPER = 0x68c56FF0E7BBD30AF9Ad68225479449869fC1bA0;
address public constant UNISWAP_WRAPPER = 0x2A4ee140F05f1Ba9A07A020b07CCFB76CecE4b43;
address public constant ETH2DAI_WRAPPER = 0x823cde416973a19f98Bb9C96d97F4FE6C9A7238B;
address public constant OASIS_WRAPPER = 0x0257Ba4876863143bbeDB7847beC583e4deb6fE6;
address public constant SAVER_EXCHANGE_ADDRESS = 0xACA7d11e3f482418C324aAC8e90AaD0431f692A6;
address public constant FACTORY_ADDRESS = 0xc72E74E474682680a414b506699bBcA44ab9a930;
address public constant PIP_INTERFACE_ADDRESS = 0xA944bd4b25C9F186A846fd5668941AA3d3B8425F;
address public constant PROXY_REGISTRY_INTERFACE_ADDRESS = 0x64A436ae831C1672AE81F674CAb8B6775df3475C;
address public constant GAS_TOKEN_INTERFACE_ADDRESS = 0x0000000000170CcC93903185bE5A2094C870Df62;
address public constant KYBER_INTERFACE = 0x692f391bCc85cefCe8C237C01e1f636BbD70EA4D;
address public constant SAVINGS_LOGGER_ADDRESS = 0xA6E5d5F489b1c00d9C11E1caF45BAb6e6e26443d;
address public constant UNISWAP_FACTORY = 0xf5D915570BC477f9B8D6C0E980aA81757A3AaC36;
address public constant MANAGER_ADDRESS = 0x1476483dD8C35F25e568113C5f70249D3976ba21;
address public constant VAT_ADDRESS = 0xbA987bDB501d131f766fEe8180Da5d81b34b69d9;
address public constant SPOTTER_ADDRESS = 0x3a042de6413eDB15F2784f2f97cC68C7E9750b2D;
address public constant JUG_ADDRESS = 0xcbB7718c9F39d05aEEDE1c472ca8Bf804b2f1EaD;
address public constant DAI_JOIN_ADDRESS = 0x5AA71a3ae1C0bd6ac27A1f28e1415fFFB6F15B8c;
address public constant ETH_JOIN_ADDRESS = 0x775787933e92b709f2a3C70aa87999696e74A9F8;
address public constant MIGRATION_ACTIONS_PROXY = 0x433870076aBd08865f0e038dcC4Ac6450e313Bd8;
address public constant PROXY_ACTIONS = 0xd1D24637b9109B7f61459176EdcfF9Be56283a7B;
address public constant SAI_ADDRESS = 0xC4375B7De8af5a38a93548eb8453a498222C4fF2;
address public constant DAI_ADDRESS = 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa;
address payable public constant SCD_MCD_MIGRATION = 0x411B2Faa662C8e3E5cF8f01dFdae0aeE482ca7b0;
address public constant SUBSCRIPTION_ADDRESS = 0xFC41f79776061a396635aD0b9dF7a640A05063C1;
address public constant MONITOR_ADDRESS = 0xfC1Fc0502e90B7A3766f93344E1eDb906F8A75DD;
}
contract ConstantAddresses is ConstantAddressesMainnet {
}
interface ERC20 {
function totalSupply() external view returns (uint supply);
function balanceOf(address _owner) external view returns (uint balance);
function transfer(address _to, uint _value) external returns (bool success);
function transferFrom(address _from, address _to, uint _value) external returns (bool success);
function approve(address _spender, uint _value) external returns (bool success);
function allowance(address _owner, address _spender) external view returns (uint remaining);
function decimals() external view returns(uint digits);
event Approval(address indexed _owner, address indexed _spender, uint _value);
}
contract GasTokenInterface is ERC20 {
function free(uint256 value) public returns (bool success);
function freeUpTo(uint256 value) public returns (uint256 freed);
function freeFrom(address from, uint256 value) public returns (bool success);
function freeFromUpTo(address from, uint256 value) public returns (uint256 freed);
}
contract DSMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x);
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x);
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x);
}
function min(uint x, uint y) internal pure returns (uint z) {
return x <= y ? x : y;
}
function max(uint x, uint y) internal pure returns (uint z) {
return x >= y ? x : y;
}
function imin(int x, int y) internal pure returns (int z) {
return x <= y ? x : y;
}
function imax(int x, int y) internal pure returns (int z) {
return x >= y ? x : y;
}
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
function wmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, WAD), y / 2) / y;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, RAY), y / 2) / y;
}
function rpow(uint x, uint n) internal pure returns (uint z) {
z = n % 2 != 0 ? x : RAY;
for (n /= 2; n != 0; n /= 2) {
x = rmul(x, x);
if (n % 2 != 0) {
z = rmul(z, x);
}
}
}
}
contract MCDMonitor is ConstantAddresses, DSMath, Static {
uint constant public REPAY_GAS_TOKEN = 30;
uint constant public BOOST_GAS_TOKEN = 19;
uint constant public MAX_GAS_PRICE = 40000000000;
uint public REPAY_GAS_COST = 1800000;
uint public BOOST_GAS_COST = 1250000;
MCDMonitorProxy public monitorProxyContract;
ISubscriptions public subscriptionsContract;
GasTokenInterface gasToken = GasTokenInterface(GAS_TOKEN_INTERFACE_ADDRESS);
address public owner;
address public mcdSaverProxyAddress;
mapping(address => bool) public approvedCallers;
event CdpRepay(uint indexed cdpId, address indexed caller, uint amount, uint beforeRatio, uint afterRatio);
event CdpBoost(uint indexed cdpId, address indexed caller, uint amount, uint beforeRatio, uint afterRatio);
modifier onlyApproved() {
require(approvedCallers[msg.sender]);
_;
}
modifier onlyOwner() {
require(owner == msg.sender);
_;
}
constructor(address _monitorProxy, address _subscriptions, address _mcdSaverProxyAddress) public {
approvedCallers[msg.sender] = true;
owner = msg.sender;
monitorProxyContract = MCDMonitorProxy(_monitorProxy);
subscriptionsContract = ISubscriptions(_subscriptions);
mcdSaverProxyAddress = _mcdSaverProxyAddress;
}
function repayFor(uint _cdpId, uint _amount, address _collateralJoin, uint _exchangeType) public onlyApproved {
if (gasToken.balanceOf(address(this)) >= BOOST_GAS_TOKEN) {
gasToken.free(BOOST_GAS_TOKEN);
}
uint ratioBefore;
bool canCall;
(canCall, ratioBefore) = subscriptionsContract.canCall(Method.Repay, _cdpId);
require(canCall);
uint gasCost = calcGasCost(REPAY_GAS_COST);
monitorProxyContract.callExecute(subscriptionsContract.getOwner(_cdpId), mcdSaverProxyAddress, abi.encodeWithSignature("repay(uint256,address,uint256,uint256,uint256,uint256)", _cdpId, _collateralJoin, _amount, 0, _exchangeType, gasCost));
uint ratioAfter;
bool ratioGoodAfter;
(ratioGoodAfter, ratioAfter) = subscriptionsContract.ratioGoodAfter(Method.Repay, _cdpId);
require(ratioGoodAfter);
emit CdpRepay(_cdpId, msg.sender, _amount, ratioBefore, ratioAfter);
}
function boostFor(uint _cdpId, uint _amount, address _collateralJoin, uint _exchangeType) public onlyApproved {
if (gasToken.balanceOf(address(this)) >= REPAY_GAS_TOKEN) {
gasToken.free(REPAY_GAS_TOKEN);
}
uint ratioBefore;
bool canCall;
(canCall, ratioBefore) = subscriptionsContract.canCall(Method.Boost, _cdpId);
require(canCall);
uint gasCost = calcGasCost(BOOST_GAS_COST);
monitorProxyContract.callExecute(subscriptionsContract.getOwner(_cdpId), mcdSaverProxyAddress, abi.encodeWithSignature("boost(uint256,address,uint256,uint256,uint256,uint256)", _cdpId, _collateralJoin, _amount, 0, _exchangeType, gasCost));
uint ratioAfter;
bool ratioGoodAfter;
(ratioGoodAfter, ratioAfter) = subscriptionsContract.ratioGoodAfter(Method.Boost, _cdpId);
require(ratioGoodAfter);
emit CdpBoost(_cdpId, msg.sender, _amount, ratioBefore, ratioAfter);
}
function calcGasCost(uint _gasAmount) internal view returns (uint) {
uint gasPrice = tx.gasprice <= MAX_GAS_PRICE ? tx.gasprice : MAX_GAS_PRICE;
return mul(gasPrice, _gasAmount);
}
function changeBoostGasCost(uint _gasCost) public onlyOwner {
require(_gasCost < 3000000);
BOOST_GAS_COST = _gasCost;
}
function changeRepayGasCost(uint _gasCost) public onlyOwner {
require(_gasCost < 3000000);
REPAY_GAS_COST = _gasCost;
}
function addCaller(address _caller) public onlyOwner {
approvedCallers[_caller] = true;
}
function removeCaller(address _caller) public onlyOwner {
approvedCallers[_caller] = false;
}
function transferERC20(address _tokenAddress, address _to, uint _amount) public onlyOwner {
ERC20(_tokenAddress).transfer(_to, _amount);
}
function transferEth(address payable _to, uint _amount) public onlyOwner {
_to.transfer(_amount);
}
}