文件 1 的 152:AaveBasicProxy.sol
pragma solidity ^0.6.0;
import "../utils/GasBurner.sol";
import "../interfaces/IAToken.sol";
import "../interfaces/ILendingPool.sol";
import "../interfaces/ILendingPoolAddressesProvider.sol";
import "../utils/SafeERC20.sol";
contract AaveBasicProxy is GasBurner {
using SafeERC20 for ERC20;
address public constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant AAVE_LENDING_POOL_ADDRESSES = 0x24a42fD28C976A61Df5D00D0599C34c4f90748c8;
uint16 public constant AAVE_REFERRAL_CODE = 64;
function deposit(address _tokenAddr, uint256 _amount) public burnGas(5) payable {
address lendingPoolCore = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolCore();
address lendingPool = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
uint ethValue = _amount;
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransferFrom(msg.sender, address(this), _amount);
approveToken(_tokenAddr, lendingPoolCore);
ethValue = 0;
}
ILendingPool(lendingPool).deposit{value: ethValue}(_tokenAddr, _amount, AAVE_REFERRAL_CODE);
setUserUseReserveAsCollateralIfNeeded(_tokenAddr);
}
function withdraw(address _tokenAddr, address _aTokenAddr, uint256 _amount, bool _wholeAmount) public burnGas(8) {
uint256 amount = _wholeAmount ? ERC20(_aTokenAddr).balanceOf(address(this)) : _amount;
IAToken(_aTokenAddr).redeem(amount);
withdrawTokens(_tokenAddr);
}
function borrow(address _tokenAddr, uint256 _amount, uint256 _type) public burnGas(8) {
address lendingPool = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
ILendingPool(lendingPool).borrow(_tokenAddr, _amount, _type, AAVE_REFERRAL_CODE);
withdrawTokens(_tokenAddr);
}
function payback(address _tokenAddr, address _aTokenAddr, uint256 _amount, bool _wholeDebt) public burnGas(3) payable {
address lendingPoolCore = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolCore();
address lendingPool = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
uint256 amount = _amount;
(,uint256 borrowAmount,,,,,uint256 originationFee,,,) = ILendingPool(lendingPool).getUserReserveData(_tokenAddr, address(this));
if (_wholeDebt) {
amount = borrowAmount;
}
amount += originationFee;
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransferFrom(msg.sender, address(this), amount);
approveToken(_tokenAddr, lendingPoolCore);
}
ILendingPool(lendingPool).repay{value: msg.value}(_tokenAddr, amount, payable(address(this)));
withdrawTokens(_tokenAddr);
}
function paybackOnBehalf(address _tokenAddr, address _aTokenAddr, uint256 _amount, bool _wholeDebt, address payable _onBehalf) public burnGas(3) payable {
address lendingPoolCore = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolCore();
address lendingPool = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
uint256 amount = _amount;
(,uint256 borrowAmount,,,,,uint256 originationFee,,,) = ILendingPool(lendingPool).getUserReserveData(_tokenAddr, _onBehalf);
if (_wholeDebt) {
amount = borrowAmount;
}
amount += originationFee;
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransferFrom(msg.sender, address(this), amount);
approveToken(_tokenAddr, lendingPoolCore);
}
ILendingPool(lendingPool).repay{value: msg.value}(_tokenAddr, amount, _onBehalf);
withdrawTokens(_tokenAddr);
}
function withdrawTokens(address _tokenAddr) public {
uint256 amount = _tokenAddr == ETH_ADDR ? address(this).balance : ERC20(_tokenAddr).balanceOf(address(this));
if (amount > 0) {
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransfer(msg.sender, amount);
} else {
msg.sender.transfer(amount);
}
}
}
function approveToken(address _tokenAddr, address _caller) internal {
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeApprove(_caller, 0);
ERC20(_tokenAddr).safeApprove(_caller, uint256(-1));
}
}
function setUserUseReserveAsCollateralIfNeeded(address _tokenAddr) public {
address lendingPool = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
(,,,,,,,,,bool collateralEnabled) = ILendingPool(lendingPool).getUserReserveData(_tokenAddr, address(this));
if (!collateralEnabled) {
ILendingPool(lendingPool).setUserUseReserveAsCollateral(_tokenAddr, true);
}
}
function setUserUseReserveAsCollateral(address _tokenAddr, bool _true) public {
address lendingPool = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
ILendingPool(lendingPool).setUserUseReserveAsCollateral(_tokenAddr, _true);
}
function swapBorrowRateMode(address _reserve) public {
address lendingPool = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
ILendingPool(lendingPool).swapBorrowRateMode(_reserve);
}
}
文件 2 的 152:AaveHelper.sol
pragma solidity ^0.6.0;
import "../DS/DSMath.sol";
import "../DS/DSProxy.sol";
import "../utils/Discount.sol";
import "../interfaces/IAToken.sol";
import "../interfaces/ILendingPool.sol";
import "../interfaces/ILendingPoolAddressesProvider.sol";
import "../interfaces/IPriceOracleGetterAave.sol";
import "../utils/SafeERC20.sol";
import "../utils/BotRegistry.sol";
contract AaveHelper is DSMath {
using SafeERC20 for ERC20;
address payable public constant WALLET_ADDR = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08;
address public constant DISCOUNT_ADDR = 0x1b14E8D511c9A4395425314f849bD737BAF8208F;
uint public constant MANUAL_SERVICE_FEE = 400;
uint public constant AUTOMATIC_SERVICE_FEE = 333;
address public constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B;
address public constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant AAVE_LENDING_POOL_ADDRESSES = 0x24a42fD28C976A61Df5D00D0599C34c4f90748c8;
uint public constant NINETY_NINE_PERCENT_WEI = 999900000000000000;
uint16 public constant AAVE_REFERRAL_CODE = 64;
function getMaxCollateral(address _collateralAddress, address _user) public view returns (uint256) {
address lendingPoolAddressDataProvider = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolDataProvider();
address lendingPoolCoreAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolCore();
address priceOracleAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getPriceOracle();
uint256 pow10 = 10 ** (18 - _getDecimals(_collateralAddress));
(,uint256 totalCollateralETH, uint256 totalBorrowsETH,,uint256 currentLTV,,,) = ILendingPool(lendingPoolAddressDataProvider).calculateUserGlobalData(_user);
(,uint256 tokenLTV,,) = ILendingPool(lendingPoolCoreAddress).getReserveConfiguration(_collateralAddress);
uint256 collateralPrice = IPriceOracleGetterAave(priceOracleAddress).getAssetPrice(_collateralAddress);
uint256 userTokenBalance = ILendingPool(lendingPoolCoreAddress).getUserUnderlyingAssetBalance(_collateralAddress, _user);
uint256 userTokenBalanceEth = wmul(userTokenBalance * pow10, collateralPrice);
if (totalBorrowsETH == 0) {
return userTokenBalance;
}
uint256 maxCollateralEth = div(sub(mul(currentLTV, totalCollateralETH), mul(totalBorrowsETH, 100)), currentLTV);
maxCollateralEth = maxCollateralEth > userTokenBalanceEth ? userTokenBalanceEth : maxCollateralEth;
if (maxCollateralEth >= totalCollateralETH) {
return wdiv(totalCollateralETH, collateralPrice) / pow10;
}
uint256 a = sub(wmul(currentLTV, totalCollateralETH), wmul(tokenLTV, userTokenBalanceEth));
uint256 newLiquidationThreshold = wdiv(add(a, wmul(sub(userTokenBalanceEth, maxCollateralEth), tokenLTV)), sub(totalCollateralETH, maxCollateralEth));
if (newLiquidationThreshold < currentLTV) {
maxCollateralEth = div(sub(mul(newLiquidationThreshold, totalCollateralETH), mul(totalBorrowsETH, 100)), newLiquidationThreshold);
maxCollateralEth = maxCollateralEth > userTokenBalanceEth ? userTokenBalanceEth : maxCollateralEth;
}
return wmul(wdiv(maxCollateralEth, collateralPrice) / pow10, NINETY_NINE_PERCENT_WEI);
}
function getMaxBorrow(address _borrowAddress, address _user) public view returns (uint256) {
address lendingPoolAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
address priceOracleAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getPriceOracle();
(,,,,uint256 availableBorrowsETH,,,) = ILendingPool(lendingPoolAddress).getUserAccountData(_user);
uint256 borrowPrice = IPriceOracleGetterAave(priceOracleAddress).getAssetPrice(_borrowAddress);
return wmul(wdiv(availableBorrowsETH, borrowPrice) / (10 ** (18 - _getDecimals(_borrowAddress))), NINETY_NINE_PERCENT_WEI);
}
function getFee(uint _amount, address _user, uint _gasCost, address _tokenAddr) internal returns (uint feeAmount) {
address priceOracleAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getPriceOracle();
uint fee = MANUAL_SERVICE_FEE;
if (BotRegistry(BOT_REGISTRY_ADDRESS).botList(tx.origin)) {
fee = AUTOMATIC_SERVICE_FEE;
}
if (Discount(DISCOUNT_ADDR).isCustomFeeSet(_user)) {
fee = Discount(DISCOUNT_ADDR).getCustomServiceFee(_user);
}
feeAmount = (fee == 0) ? 0 : (_amount / fee);
if (_gasCost != 0) {
uint256 price = IPriceOracleGetterAave(priceOracleAddress).getAssetPrice(_tokenAddr);
_gasCost = wmul(_gasCost, price) / (10 ** (18 - _getDecimals(_tokenAddr)));
feeAmount = add(feeAmount, _gasCost);
}
if (feeAmount > (_amount / 5)) {
feeAmount = _amount / 5;
}
if (_tokenAddr == ETH_ADDR) {
WALLET_ADDR.transfer(feeAmount);
} else {
ERC20(_tokenAddr).safeTransfer(WALLET_ADDR, feeAmount);
}
}
function getGasCost(uint _amount, address _user, uint _gasCost, address _tokenAddr) internal returns (uint gasCost) {
address priceOracleAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getPriceOracle();
if (_gasCost != 0) {
uint256 price = IPriceOracleGetterAave(priceOracleAddress).getAssetPrice(_tokenAddr);
_gasCost = wmul(_gasCost, price);
gasCost = _gasCost;
}
if (gasCost > (_amount / 5)) {
gasCost = _amount / 5;
}
if (_tokenAddr == ETH_ADDR) {
WALLET_ADDR.transfer(gasCost);
} else {
ERC20(_tokenAddr).safeTransfer(WALLET_ADDR, gasCost);
}
}
function getUserAddress() internal view returns (address) {
DSProxy proxy = DSProxy(payable(address(this)));
return proxy.owner();
}
function approveToken(address _tokenAddr, address _caller) internal {
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeApprove(_caller, uint256(-1));
}
}
function sendContractBalance(address _token, address _user, uint _amount) public {
if (_amount == 0) return;
if (_token == ETH_ADDR) {
payable(_user).transfer(_amount);
} else {
ERC20(_token).safeTransfer(_user, _amount);
}
}
function sendFullContractBalance(address _token, address _user) public {
if (_token == ETH_ADDR) {
sendContractBalance(_token, _user, address(this).balance);
} else {
sendContractBalance(_token, _user, ERC20(_token).balanceOf(address(this)));
}
}
function _getDecimals(address _token) internal view returns (uint256) {
if (_token == ETH_ADDR) return 18;
return ERC20(_token).decimals();
}
}
文件 3 的 152:AaveImport.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../savings/dydx/ISoloMargin.sol";
import "../../utils/SafeERC20.sol";
import "../../interfaces/TokenInterface.sol";
import "../../DS/DSProxy.sol";
import "../AaveHelper.sol";
import "../../auth/AdminAuth.sol";
contract AaveImport is AaveHelper, AdminAuth {
using SafeERC20 for ERC20;
address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant BASIC_PROXY = 0x0e49911C937357EAA5a56984483b4B8918D0493b;
address public constant AETH_ADDRESS = 0x3a3A65aAb0dd2A17E3F1947bA16138cd37d08c04;
function callFunction(
address sender,
Account.Info memory account,
bytes memory data
) public {
(
address collateralToken,
address borrowToken,
uint256 ethAmount,
address user,
address proxy
)
= abi.decode(data, (address,address,uint256,address,address));
TokenInterface(WETH_ADDRESS).withdraw(ethAmount);
address lendingPoolCoreAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolCore();
address lendingPool = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
address aCollateralToken = ILendingPool(lendingPoolCoreAddress).getReserveATokenAddress(collateralToken);
address aBorrowToken = ILendingPool(lendingPoolCoreAddress).getReserveATokenAddress(borrowToken);
DSProxy(payable(proxy)).execute{value: ethAmount}(BASIC_PROXY, abi.encodeWithSignature("deposit(address,uint256)", ETH_ADDR, ethAmount));
(,uint256 borrowAmount,,uint256 borrowRateMode,,,uint256 originationFee,,,) = ILendingPool(lendingPool).getUserReserveData(borrowToken, user);
borrowAmount += originationFee;
DSProxy(payable(proxy)).execute(BASIC_PROXY, abi.encodeWithSignature("borrow(address,uint256,uint256)", borrowToken, borrowAmount, borrowRateMode));
ERC20(borrowToken).safeApprove(proxy, borrowAmount);
DSProxy(payable(proxy)).execute(BASIC_PROXY, abi.encodeWithSignature("paybackOnBehalf(address,address,uint256,bool,address)", borrowToken, aBorrowToken, 0, true, user));
ERC20(aCollateralToken).safeTransferFrom(user, proxy, ERC20(aCollateralToken).balanceOf(user));
DSProxy(payable(proxy)).execute(BASIC_PROXY, abi.encodeWithSignature("setUserUseReserveAsCollateralIfNeeded(address)", collateralToken));
DSProxy(payable(proxy)).execute(BASIC_PROXY, abi.encodeWithSignature("withdraw(address,address,uint256,bool)", ETH_ADDR, AETH_ADDRESS, ethAmount, false));
TokenInterface(WETH_ADDRESS).deposit.value(address(this).balance)();
ERC20(WETH_ADDRESS).safeTransfer(proxy, ethAmount+2);
}
receive() external payable {
if (msg.sender == owner) {
TokenInterface(WETH_ADDRESS).deposit.value(address(this).balance)();
}
}
}
文件 4 的 152:AaveImportTaker.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../utils/GasBurner.sol";
import "../../auth/AdminAuth.sol";
import "../../auth/ProxyPermission.sol";
import "../../utils/DydxFlashLoanBase.sol";
import "../../loggers/DefisaverLogger.sol";
import "../../interfaces/ProxyRegistryInterface.sol";
import "../../interfaces/TokenInterface.sol";
import "../../interfaces/ERC20.sol";
contract AaveImportTaker is DydxFlashLoanBase, ProxyPermission {
address public constant WETH_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address payable public constant AAVE_IMPORT = 0x2f8ADA783E0696F610e5637CF873B967f47dF2E3;
address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
address public constant PROXY_REGISTRY_ADDRESS = 0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4;
function importLoan(address _collateralToken, address _borrowToken, uint _ethAmount) public {
ISoloMargin solo = ISoloMargin(SOLO_MARGIN_ADDRESS);
uint256 marketId = _getMarketIdFromTokenAddress(WETH_ADDR);
uint256 repayAmount = _getRepaymentAmountInternal(_ethAmount);
ERC20(WETH_ADDR).approve(SOLO_MARGIN_ADDRESS, repayAmount);
Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);
operations[0] = _getWithdrawAction(marketId, _ethAmount, AAVE_IMPORT);
operations[1] = _getCallAction(
abi.encode(_collateralToken, _borrowToken, _ethAmount, msg.sender, address(this)),
AAVE_IMPORT
);
operations[2] = _getDepositAction(marketId, repayAmount, address(this));
Account.Info[] memory accountInfos = new Account.Info[](1);
accountInfos[0] = _getAccountInfo();
givePermission(AAVE_IMPORT);
solo.operate(accountInfos, operations);
removePermission(AAVE_IMPORT);
DefisaverLogger(DEFISAVER_LOGGER).Log(address(this), msg.sender, "AaveImport", abi.encode(_collateralToken, _borrowToken));
}
}
文件 5 的 152:AaveLoanInfo.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./AaveSafetyRatio.sol";
contract AaveLoanInfo is AaveSafetyRatio {
struct LoanData {
address user;
uint128 ratio;
address[] collAddr;
address[] borrowAddr;
uint256[] collAmounts;
uint256[] borrowAmounts;
}
struct TokenInfo {
address aTokenAddress;
address underlyingTokenAddress;
uint256 collateralFactor;
uint256 price;
}
struct TokenInfoFull {
address aTokenAddress;
address underlyingTokenAddress;
uint256 supplyRate;
uint256 borrowRate;
uint256 totalSupply;
uint256 availableLiquidity;
uint256 totalBorrow;
uint256 collateralFactor;
uint256 price;
bool usageAsCollateralEnabled;
}
function getRatio(address _user) public view returns (uint256) {
return getSafetyRatio(_user);
}
function getPrices(address[] memory _tokens) public view returns (uint256[] memory prices) {
address priceOracleAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getPriceOracle();
prices = new uint[](_tokens.length);
for (uint256 i = 0; i < _tokens.length; ++i) {
prices[i] = IPriceOracleGetterAave(priceOracleAddress).getAssetPrice(_tokens[i]);
}
}
function getCollFactors(address[] memory _tokens) public view returns (uint256[] memory collFactors) {
address lendingPoolCoreAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolCore();
collFactors = new uint256[](_tokens.length);
for (uint256 i = 0; i < _tokens.length; ++i) {
(,collFactors[i],,) = ILendingPool(lendingPoolCoreAddress).getReserveConfiguration(_tokens[i]);
}
}
function getTokenBalances(address _user, address[] memory _tokens) public view returns (uint256[] memory balances, uint256[] memory borrows, bool[] memory enabledAsCollateral) {
address lendingPoolAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
balances = new uint256[](_tokens.length);
borrows = new uint256[](_tokens.length);
enabledAsCollateral = new bool[](_tokens.length);
for (uint256 i = 0; i < _tokens.length; i++) {
address asset = _tokens[i];
(balances[i], borrows[i],,,,,,,,enabledAsCollateral[i]) = ILendingPool(lendingPoolAddress).getUserReserveData(asset, _user);
}
}
function getRatios(address[] memory _users) public view returns (uint256[] memory ratios) {
ratios = new uint256[](_users.length);
for (uint256 i = 0; i < _users.length; ++i) {
ratios[i] = getSafetyRatio(_users[i]);
}
}
function getTokensInfo(address[] memory _tokenAddresses) public view returns(TokenInfo[] memory tokens) {
address lendingPoolCoreAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolCore();
address priceOracleAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getPriceOracle();
tokens = new TokenInfo[](_tokenAddresses.length);
for (uint256 i = 0; i < _tokenAddresses.length; ++i) {
(,uint256 ltv,,) = ILendingPool(lendingPoolCoreAddress).getReserveConfiguration(_tokenAddresses[i]);
tokens[i] = TokenInfo({
aTokenAddress: ILendingPool(lendingPoolCoreAddress).getReserveATokenAddress(_tokenAddresses[i]),
underlyingTokenAddress: _tokenAddresses[i],
collateralFactor: ltv,
price: IPriceOracleGetterAave(priceOracleAddress).getAssetPrice(_tokenAddresses[i])
});
}
}
function getFullTokensInfo(address[] memory _tokenAddresses) public view returns(TokenInfoFull[] memory tokens) {
address lendingPoolCoreAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolCore();
address priceOracleAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getPriceOracle();
tokens = new TokenInfoFull[](_tokenAddresses.length);
for (uint256 i = 0; i < _tokenAddresses.length; ++i) {
(,uint256 ltv,,bool usageAsCollateralEnabled) = ILendingPool(lendingPoolCoreAddress).getReserveConfiguration(_tokenAddresses[i]);
tokens[i] = TokenInfoFull({
aTokenAddress: ILendingPool(lendingPoolCoreAddress).getReserveATokenAddress(_tokenAddresses[i]),
underlyingTokenAddress: _tokenAddresses[i],
supplyRate: ILendingPool(lendingPoolCoreAddress).getReserveCurrentLiquidityRate(_tokenAddresses[i]),
borrowRate: ILendingPool(lendingPoolCoreAddress).getReserveCurrentVariableBorrowRate(_tokenAddresses[i]),
totalSupply: ILendingPool(lendingPoolCoreAddress).getReserveTotalLiquidity(_tokenAddresses[i]),
availableLiquidity: ILendingPool(lendingPoolCoreAddress).getReserveAvailableLiquidity(_tokenAddresses[i]),
totalBorrow: ILendingPool(lendingPoolCoreAddress).getReserveTotalBorrowsVariable(_tokenAddresses[i]),
collateralFactor: ltv,
price: IPriceOracleGetterAave(priceOracleAddress).getAssetPrice(_tokenAddresses[i]),
usageAsCollateralEnabled: usageAsCollateralEnabled
});
}
}
function getLoanData(address _user) public view returns (LoanData memory data) {
address lendingPoolAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
address priceOracleAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getPriceOracle();
address[] memory reserves = ILendingPool(lendingPoolAddress).getReserves();
data = LoanData({
user: _user,
ratio: 0,
collAddr: new address[](reserves.length),
borrowAddr: new address[](reserves.length),
collAmounts: new uint[](reserves.length),
borrowAmounts: new uint[](reserves.length)
});
uint64 collPos = 0;
uint64 borrowPos = 0;
for (uint64 i = 0; i < reserves.length; i++) {
address reserve = reserves[i];
(uint256 aTokenBalance, uint256 borrowBalance,,,,,,,,) = ILendingPool(lendingPoolAddress).getUserReserveData(reserve, _user);
uint256 price = IPriceOracleGetterAave(priceOracleAddress).getAssetPrice(reserves[i]);
if (aTokenBalance > 0) {
uint256 userTokenBalanceEth = wmul(aTokenBalance, price) * (10 ** (18 - _getDecimals(reserve)));
data.collAddr[collPos] = reserve;
data.collAmounts[collPos] = userTokenBalanceEth;
collPos++;
}
if (borrowBalance > 0) {
uint256 userBorrowBalanceEth = wmul(borrowBalance, price) * (10 ** (18 - _getDecimals(reserve)));
data.borrowAddr[borrowPos] = reserve;
data.borrowAmounts[borrowPos] = userBorrowBalanceEth;
borrowPos++;
}
}
data.ratio = uint128(getSafetyRatio(_user));
return data;
}
function getLoanDataArr(address[] memory _users) public view returns (LoanData[] memory loans) {
loans = new LoanData[](_users.length);
for (uint i = 0; i < _users.length; ++i) {
loans[i] = getLoanData(_users[i]);
}
}
}
文件 6 的 152:AaveMonitor.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../utils/GasBurner.sol";
import "./AaveMonitorProxy.sol";
import "./AaveSubscriptions.sol";
import "../../DS/DSMath.sol";
import "../../auth/AdminAuth.sol";
import "../../loggers/DefisaverLogger.sol";
import "../AaveSafetyRatio.sol";
import "../../exchange/SaverExchangeCore.sol";
contract AaveMonitor is AdminAuth, DSMath, AaveSafetyRatio, GasBurner {
using SafeERC20 for ERC20;
enum Method { Boost, Repay }
uint public REPAY_GAS_TOKEN = 19;
uint public BOOST_GAS_TOKEN = 19;
uint public MAX_GAS_PRICE = 200000000000;
uint public REPAY_GAS_COST = 2500000;
uint public BOOST_GAS_COST = 2500000;
address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
AaveMonitorProxy public aaveMonitorProxy;
AaveSubscriptions public subscriptionsContract;
address public aaveSaverProxy;
DefisaverLogger public logger = DefisaverLogger(DEFISAVER_LOGGER);
modifier onlyApproved() {
require(BotRegistry(BOT_REGISTRY_ADDRESS).botList(msg.sender), "Not auth bot");
_;
}
constructor(address _aaveMonitorProxy, address _subscriptions, address _aaveSaverProxy) public {
aaveMonitorProxy = AaveMonitorProxy(_aaveMonitorProxy);
subscriptionsContract = AaveSubscriptions(_subscriptions);
aaveSaverProxy = _aaveSaverProxy;
}
function repayFor(
SaverExchangeCore.ExchangeData memory _exData,
address _user
) public payable onlyApproved burnGas(REPAY_GAS_TOKEN) {
(bool isAllowed, uint ratioBefore) = canCall(Method.Repay, _user);
require(isAllowed);
uint256 gasCost = calcGasCost(REPAY_GAS_COST);
aaveMonitorProxy.callExecute{value: msg.value}(
_user,
aaveSaverProxy,
abi.encodeWithSignature(
"repay((address,address,uint256,uint256,uint256,address,address,bytes,uint256),uint256)",
_exData,
gasCost
)
);
(bool isGoodRatio, uint ratioAfter) = ratioGoodAfter(Method.Repay, _user);
require(isGoodRatio);
returnEth();
logger.Log(address(this), _user, "AutomaticAaveRepay", abi.encode(ratioBefore, ratioAfter));
}
function boostFor(
SaverExchangeCore.ExchangeData memory _exData,
address _user
) public payable onlyApproved burnGas(BOOST_GAS_TOKEN) {
(bool isAllowed, uint ratioBefore) = canCall(Method.Boost, _user);
require(isAllowed);
uint256 gasCost = calcGasCost(BOOST_GAS_COST);
aaveMonitorProxy.callExecute{value: msg.value}(
_user,
aaveSaverProxy,
abi.encodeWithSignature(
"boost((address,address,uint256,uint256,uint256,address,address,bytes,uint256),uint256)",
_exData,
gasCost
)
);
(bool isGoodRatio, uint ratioAfter) = ratioGoodAfter(Method.Boost, _user);
require(isGoodRatio);
returnEth();
logger.Log(address(this), _user, "AutomaticAaveBoost", abi.encode(ratioBefore, ratioAfter));
}
function returnEth() internal {
if (address(this).balance > 0) {
msg.sender.transfer(address(this).balance);
}
}
function canCall(Method _method, address _user) public view returns(bool, uint) {
bool subscribed = subscriptionsContract.isSubscribed(_user);
AaveSubscriptions.AaveHolder memory holder = subscriptionsContract.getHolder(_user);
if (!subscribed) return (false, 0);
if (_method == Method.Boost && !holder.boostEnabled) return (false, 0);
uint currRatio = getSafetyRatio(_user);
if (_method == Method.Repay) {
return (currRatio < holder.minRatio, currRatio);
} else if (_method == Method.Boost) {
return (currRatio > holder.maxRatio, currRatio);
}
}
function ratioGoodAfter(Method _method, address _user) public view returns(bool, uint) {
AaveSubscriptions.AaveHolder memory holder;
holder= subscriptionsContract.getHolder(_user);
uint currRatio = getSafetyRatio(_user);
if (_method == Method.Repay) {
return (currRatio < holder.maxRatio, currRatio);
} else if (_method == Method.Boost) {
return (currRatio > holder.minRatio, currRatio);
}
}
function calcGasCost(uint _gasAmount) public 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 changeMaxGasPrice(uint _maxGasPrice) public onlyOwner {
require(_maxGasPrice < 500000000000);
MAX_GAS_PRICE = _maxGasPrice;
}
function changeGasTokenAmount(uint _gasTokenAmount, bool _repay) public onlyOwner {
if (_repay) {
REPAY_GAS_TOKEN = _gasTokenAmount;
} else {
BOOST_GAS_TOKEN = _gasTokenAmount;
}
}
}
文件 7 的 152:AaveMonitorProxy.sol
pragma solidity ^0.6.0;
import "../../interfaces/DSProxyInterface.sol";
import "../../utils/SafeERC20.sol";
import "../../auth/AdminAuth.sol";
contract AaveMonitorProxy is AdminAuth {
using SafeERC20 for ERC20;
uint public CHANGE_PERIOD;
address public monitor;
address public newMonitor;
address public lastMonitor;
uint public changeRequestedTimestamp;
mapping(address => bool) public allowed;
event MonitorChangeInitiated(address oldMonitor, address newMonitor);
event MonitorChangeCanceled();
event MonitorChangeFinished(address monitor);
event MonitorChangeReverted(address monitor);
modifier onlyAllowed() {
require(allowed[msg.sender] || msg.sender == owner);
_;
}
modifier onlyMonitor() {
require (msg.sender == monitor);
_;
}
constructor(uint _changePeriod) public {
CHANGE_PERIOD = _changePeriod * 1 days;
}
function callExecute(address _owner, address _aaveSaverProxy, bytes memory _data) public payable onlyMonitor {
DSProxyInterface(_owner).execute{value: msg.value}(_aaveSaverProxy, _data);
if (address(this).balance > 0) {
msg.sender.transfer(address(this).balance);
}
}
function setMonitor(address _monitor) public onlyAllowed {
require(monitor == address(0));
monitor = _monitor;
}
function changeMonitor(address _newMonitor) public onlyAllowed {
require(changeRequestedTimestamp == 0);
changeRequestedTimestamp = now;
lastMonitor = monitor;
newMonitor = _newMonitor;
emit MonitorChangeInitiated(lastMonitor, newMonitor);
}
function cancelMonitorChange() public onlyAllowed {
require(changeRequestedTimestamp > 0);
changeRequestedTimestamp = 0;
newMonitor = address(0);
emit MonitorChangeCanceled();
}
function confirmNewMonitor() public onlyAllowed {
require((changeRequestedTimestamp + CHANGE_PERIOD) < now);
require(changeRequestedTimestamp != 0);
require(newMonitor != address(0));
monitor = newMonitor;
newMonitor = address(0);
changeRequestedTimestamp = 0;
emit MonitorChangeFinished(monitor);
}
function revertMonitor() public onlyAllowed {
require(lastMonitor != address(0));
monitor = lastMonitor;
emit MonitorChangeReverted(monitor);
}
function addAllowed(address _user) public onlyAllowed {
allowed[_user] = true;
}
function removeAllowed(address _user) public onlyAllowed {
allowed[_user] = false;
}
function setChangePeriod(uint _periodInDays) public onlyAllowed {
require(_periodInDays * 1 days > CHANGE_PERIOD);
CHANGE_PERIOD = _periodInDays * 1 days;
}
function withdrawToken(address _token) public onlyOwner {
uint balance = ERC20(_token).balanceOf(address(this));
ERC20(_token).safeTransfer(msg.sender, balance);
}
function withdrawEth() public onlyOwner {
uint balance = address(this).balance;
msg.sender.transfer(balance);
}
}
文件 8 的 152:AaveSafetyRatio.sol
pragma solidity ^0.6.0;
import "./AaveHelper.sol";
contract AaveSafetyRatio is AaveHelper {
function getSafetyRatio(address _user) public view returns(uint256) {
address lendingPoolAddress = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
(,,uint256 totalBorrowsETH,,uint256 availableBorrowsETH,,,) = ILendingPool(lendingPoolAddress).getUserAccountData(_user);
return wdiv(add(totalBorrowsETH, availableBorrowsETH), totalBorrowsETH);
}
}
文件 9 的 152:AaveSaverProxy.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./AaveHelper.sol";
import "../exchange/SaverExchangeCore.sol";
import "../interfaces/IAToken.sol";
import "../interfaces/ILendingPool.sol";
import "../loggers/DefisaverLogger.sol";
import "../utils/GasBurner.sol";
contract AaveSaverProxy is GasBurner, SaverExchangeCore, AaveHelper {
address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
uint public constant VARIABLE_RATE = 2;
function repay(ExchangeData memory _data, uint _gasCost) public payable burnGas(20) {
address lendingPoolCore = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolCore();
address lendingPool = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
address payable user = payable(getUserAddress());
uint256 maxCollateral = getMaxCollateral(_data.srcAddr, address(this));
_data.srcAmount = _data.srcAmount > maxCollateral ? maxCollateral : _data.srcAmount;
address aTokenCollateral = ILendingPool(lendingPoolCore).getReserveATokenAddress(_data.srcAddr);
IAToken(aTokenCollateral).redeem(_data.srcAmount);
uint256 destAmount = _data.srcAmount;
if (_data.srcAddr != _data.destAddr) {
(, destAmount) = _sell(_data);
destAmount -= getFee(destAmount, user, _gasCost, _data.destAddr);
} else {
destAmount -= getGasCost(destAmount, user, _gasCost, _data.destAddr);
}
if (_data.destAddr == ETH_ADDR) {
ILendingPool(lendingPool).repay{value: destAmount}(_data.destAddr, destAmount, payable(address(this)));
} else {
approveToken(_data.destAddr, lendingPoolCore);
ILendingPool(lendingPool).repay(_data.destAddr, destAmount, payable(address(this)));
}
sendContractBalance(ETH_ADDR, tx.origin, min(address(this).balance, msg.value));
sendFullContractBalance(_data.destAddr, user);
DefisaverLogger(DEFISAVER_LOGGER).Log(address(this), msg.sender, "AaveRepay", abi.encode(_data.srcAddr, _data.destAddr, _data.srcAmount, destAmount));
}
function boost(ExchangeData memory _data, uint _gasCost) public payable burnGas(20) {
address lendingPoolCore = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPoolCore();
address lendingPool = ILendingPoolAddressesProvider(AAVE_LENDING_POOL_ADDRESSES).getLendingPool();
(,,,,,,,,,bool collateralEnabled) = ILendingPool(lendingPool).getUserReserveData(_data.destAddr, address(this));
address payable user = payable(getUserAddress());
uint256 maxBorrow = getMaxBorrow(_data.srcAddr, address(this));
_data.srcAmount = _data.srcAmount > maxBorrow ? maxBorrow : _data.srcAmount;
ILendingPool(lendingPool).borrow(_data.srcAddr, _data.srcAmount, VARIABLE_RATE, AAVE_REFERRAL_CODE);
uint256 destAmount;
if (_data.destAddr != _data.srcAddr) {
_data.srcAmount -= getFee(_data.srcAmount, user, _gasCost, _data.srcAddr);
(, destAmount) = _sell(_data);
} else {
_data.srcAmount -= getGasCost(_data.srcAmount, user, _gasCost, _data.srcAddr);
destAmount = _data.srcAmount;
}
if (_data.destAddr == ETH_ADDR) {
ILendingPool(lendingPool).deposit{value: destAmount}(_data.destAddr, destAmount, AAVE_REFERRAL_CODE);
} else {
approveToken(_data.destAddr, lendingPoolCore);
ILendingPool(lendingPool).deposit(_data.destAddr, destAmount, AAVE_REFERRAL_CODE);
}
if (!collateralEnabled) {
ILendingPool(lendingPool).setUserUseReserveAsCollateral(_data.destAddr, true);
}
sendContractBalance(ETH_ADDR, tx.origin, min(address(this).balance, msg.value));
sendFullContractBalance(_data.destAddr, user);
DefisaverLogger(DEFISAVER_LOGGER).Log(address(this), msg.sender, "AaveBoost", abi.encode(_data.srcAddr, _data.destAddr, _data.srcAmount, destAmount));
}
}
文件 10 的 152:AaveSavingsProtocol.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../ProtocolInterface.sol";
import "../../interfaces/IAToken.sol";
import "../../interfaces/ILendingPool.sol";
import "../../interfaces/ERC20.sol";
import "../../DS/DSAuth.sol";
contract AaveSavingsProtocol is ProtocolInterface, DSAuth {
address public constant ADAI_ADDRESS = 0xfC1E690f61EFd961294b3e1Ce3313fBD8aa4f85d;
address public constant AAVE_LENDING_POOL = 0x398eC7346DcD622eDc5ae82352F02bE94C62d119;
address public constant AAVE_LENDING_POOL_CORE = 0x3dfd23A6c5E8BbcFc9581d2E864a68feb6a076d3;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
function deposit(address _user, uint _amount) public override {
require(msg.sender == _user);
require(ERC20(DAI_ADDRESS).transferFrom(_user, address(this), _amount));
ERC20(DAI_ADDRESS).approve(AAVE_LENDING_POOL_CORE, uint(-1));
ILendingPool(AAVE_LENDING_POOL).deposit(DAI_ADDRESS, _amount, 0);
ERC20(ADAI_ADDRESS).transfer(_user, ERC20(ADAI_ADDRESS).balanceOf(address(this)));
}
function withdraw(address _user, uint _amount) public override {
require(msg.sender == _user);
require(ERC20(ADAI_ADDRESS).transferFrom(_user, address(this), _amount));
IAToken(ADAI_ADDRESS).redeem(_amount);
ERC20(DAI_ADDRESS).transfer(_user, _amount);
}
}
文件 11 的 152:AaveSubscriptions.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../auth/AdminAuth.sol";
contract AaveSubscriptions is AdminAuth {
struct AaveHolder {
address user;
uint128 minRatio;
uint128 maxRatio;
uint128 optimalRatioBoost;
uint128 optimalRatioRepay;
bool boostEnabled;
}
struct SubPosition {
uint arrPos;
bool subscribed;
}
AaveHolder[] public subscribers;
mapping (address => SubPosition) public subscribersPos;
uint public changeIndex;
event Subscribed(address indexed user);
event Unsubscribed(address indexed user);
event Updated(address indexed user);
event ParamUpdates(address indexed user, uint128, uint128, uint128, uint128, bool);
function subscribe(uint128 _minRatio, uint128 _maxRatio, uint128 _optimalBoost, uint128 _optimalRepay, bool _boostEnabled) external {
uint128 localMaxRatio = _boostEnabled ? _maxRatio : uint128(-1);
require(checkParams(_minRatio, localMaxRatio), "Must be correct params");
SubPosition storage subInfo = subscribersPos[msg.sender];
AaveHolder memory subscription = AaveHolder({
minRatio: _minRatio,
maxRatio: localMaxRatio,
optimalRatioBoost: _optimalBoost,
optimalRatioRepay: _optimalRepay,
user: msg.sender,
boostEnabled: _boostEnabled
});
changeIndex++;
if (subInfo.subscribed) {
subscribers[subInfo.arrPos] = subscription;
emit Updated(msg.sender);
emit ParamUpdates(msg.sender, _minRatio, localMaxRatio, _optimalBoost, _optimalRepay, _boostEnabled);
} else {
subscribers.push(subscription);
subInfo.arrPos = subscribers.length - 1;
subInfo.subscribed = true;
emit Subscribed(msg.sender);
}
}
function unsubscribe() external {
_unsubscribe(msg.sender);
}
function checkParams(uint128 _minRatio, uint128 _maxRatio) internal pure returns (bool) {
if (_minRatio > _maxRatio) {
return false;
}
return true;
}
function _unsubscribe(address _user) internal {
require(subscribers.length > 0, "Must have subscribers in the list");
SubPosition storage subInfo = subscribersPos[_user];
require(subInfo.subscribed, "Must first be subscribed");
address lastOwner = subscribers[subscribers.length - 1].user;
SubPosition storage subInfo2 = subscribersPos[lastOwner];
subInfo2.arrPos = subInfo.arrPos;
subscribers[subInfo.arrPos] = subscribers[subscribers.length - 1];
subscribers.pop();
changeIndex++;
subInfo.subscribed = false;
subInfo.arrPos = 0;
emit Unsubscribed(msg.sender);
}
function isSubscribed(address _user) public view returns (bool) {
SubPosition storage subInfo = subscribersPos[_user];
return subInfo.subscribed;
}
function getHolder(address _user) public view returns (AaveHolder memory) {
SubPosition storage subInfo = subscribersPos[_user];
return subscribers[subInfo.arrPos];
}
function getSubscribers() public view returns (AaveHolder[] memory) {
return subscribers;
}
function getSubscribersByPage(uint _page, uint _perPage) public view returns (AaveHolder[] memory) {
AaveHolder[] memory holders = new AaveHolder[](_perPage);
uint start = _page * _perPage;
uint end = start + _perPage;
end = (end > holders.length) ? holders.length : end;
uint count = 0;
for (uint i = start; i < end; i++) {
holders[count] = subscribers[i];
count++;
}
return holders;
}
function unsubscribeByAdmin(address _user) public onlyOwner {
SubPosition storage subInfo = subscribersPos[_user];
if (subInfo.subscribed) {
_unsubscribe(_user);
}
}
}
文件 12 的 152:AaveSubscriptionsProxy.sol
pragma solidity ^0.6.0;
import "../../auth/ProxyPermission.sol";
import "../../interfaces/IAaveSubscription.sol";
contract AaveSubscriptionsProxy is ProxyPermission {
address public constant AAVE_SUBSCRIPTION_ADDRESS = 0xe08ff7A2BADb634F0b581E675E6B3e583De086FC;
address public constant AAVE_MONITOR_PROXY = 0xfA560Dba3a8D0B197cA9505A2B98120DD89209AC;
function subscribe(
uint128 _minRatio,
uint128 _maxRatio,
uint128 _optimalRatioBoost,
uint128 _optimalRatioRepay,
bool _boostEnabled
) public {
givePermission(AAVE_MONITOR_PROXY);
IAaveSubscription(AAVE_SUBSCRIPTION_ADDRESS).subscribe(
_minRatio, _maxRatio, _optimalRatioBoost, _optimalRatioRepay, _boostEnabled);
}
function update(
uint128 _minRatio,
uint128 _maxRatio,
uint128 _optimalRatioBoost,
uint128 _optimalRatioRepay,
bool _boostEnabled
) public {
IAaveSubscription(AAVE_SUBSCRIPTION_ADDRESS).subscribe(_minRatio, _maxRatio, _optimalRatioBoost, _optimalRatioRepay, _boostEnabled);
}
function unsubscribe() public {
removePermission(AAVE_MONITOR_PROXY);
IAaveSubscription(AAVE_SUBSCRIPTION_ADDRESS).unsubscribe();
}
}
文件 13 的 152:Account.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import { Types } from "./Types.sol";
library Account {
enum Status {
Normal,
Liquid,
Vapor
}
struct Info {
address owner;
uint256 number;
}
struct Storage {
mapping (uint256 => Types.Par) balances;
Status status;
}
function equals(
Info memory a,
Info memory b
)
internal
pure
returns (bool)
{
return a.owner == b.owner && a.number == b.number;
}
}
文件 14 的 152:Actions.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import { Account } from "./Account.sol";
import { Types } from "./Types.sol";
library Actions {
bytes32 constant FILE = "Actions";
enum ActionType {
Deposit,
Withdraw,
Transfer,
Buy,
Sell,
Trade,
Liquidate,
Vaporize,
Call
}
enum AccountLayout {
OnePrimary,
TwoPrimary,
PrimaryAndSecondary
}
enum MarketLayout {
ZeroMarkets,
OneMarket,
TwoMarkets
}
struct ActionArgs {
ActionType actionType;
uint256 accountId;
Types.AssetAmount amount;
uint256 primaryMarketId;
uint256 secondaryMarketId;
address otherAddress;
uint256 otherAccountId;
bytes data;
}
struct DepositArgs {
Types.AssetAmount amount;
Account.Info account;
uint256 market;
address from;
}
struct WithdrawArgs {
Types.AssetAmount amount;
Account.Info account;
uint256 market;
address to;
}
struct TransferArgs {
Types.AssetAmount amount;
Account.Info accountOne;
Account.Info accountTwo;
uint256 market;
}
struct BuyArgs {
Types.AssetAmount amount;
Account.Info account;
uint256 makerMarket;
uint256 takerMarket;
address exchangeWrapper;
bytes orderData;
}
struct SellArgs {
Types.AssetAmount amount;
Account.Info account;
uint256 takerMarket;
uint256 makerMarket;
address exchangeWrapper;
bytes orderData;
}
struct TradeArgs {
Types.AssetAmount amount;
Account.Info takerAccount;
Account.Info makerAccount;
uint256 inputMarket;
uint256 outputMarket;
address autoTrader;
bytes tradeData;
}
struct LiquidateArgs {
Types.AssetAmount amount;
Account.Info solidAccount;
Account.Info liquidAccount;
uint256 owedMarket;
uint256 heldMarket;
}
struct VaporizeArgs {
Types.AssetAmount amount;
Account.Info solidAccount;
Account.Info vaporAccount;
uint256 owedMarket;
uint256 heldMarket;
}
struct CallArgs {
Account.Info account;
address callee;
bytes data;
}
function getMarketLayout(
ActionType actionType
)
internal
pure
returns (MarketLayout)
{
if (
actionType == Actions.ActionType.Deposit
|| actionType == Actions.ActionType.Withdraw
|| actionType == Actions.ActionType.Transfer
) {
return MarketLayout.OneMarket;
}
else if (actionType == Actions.ActionType.Call) {
return MarketLayout.ZeroMarkets;
}
return MarketLayout.TwoMarkets;
}
function getAccountLayout(
ActionType actionType
)
internal
pure
returns (AccountLayout)
{
if (
actionType == Actions.ActionType.Transfer
|| actionType == Actions.ActionType.Trade
) {
return AccountLayout.TwoPrimary;
} else if (
actionType == Actions.ActionType.Liquidate
|| actionType == Actions.ActionType.Vaporize
) {
return AccountLayout.PrimaryAndSecondary;
}
return AccountLayout.OnePrimary;
}
function parseDepositArgs(
Account.Info[] memory accounts,
ActionArgs memory args
)
internal
pure
returns (DepositArgs memory)
{
assert(args.actionType == ActionType.Deposit);
return DepositArgs({
amount: args.amount,
account: accounts[args.accountId],
market: args.primaryMarketId,
from: args.otherAddress
});
}
function parseWithdrawArgs(
Account.Info[] memory accounts,
ActionArgs memory args
)
internal
pure
returns (WithdrawArgs memory)
{
assert(args.actionType == ActionType.Withdraw);
return WithdrawArgs({
amount: args.amount,
account: accounts[args.accountId],
market: args.primaryMarketId,
to: args.otherAddress
});
}
function parseTransferArgs(
Account.Info[] memory accounts,
ActionArgs memory args
)
internal
pure
returns (TransferArgs memory)
{
assert(args.actionType == ActionType.Transfer);
return TransferArgs({
amount: args.amount,
accountOne: accounts[args.accountId],
accountTwo: accounts[args.otherAccountId],
market: args.primaryMarketId
});
}
function parseBuyArgs(
Account.Info[] memory accounts,
ActionArgs memory args
)
internal
pure
returns (BuyArgs memory)
{
assert(args.actionType == ActionType.Buy);
return BuyArgs({
amount: args.amount,
account: accounts[args.accountId],
makerMarket: args.primaryMarketId,
takerMarket: args.secondaryMarketId,
exchangeWrapper: args.otherAddress,
orderData: args.data
});
}
function parseSellArgs(
Account.Info[] memory accounts,
ActionArgs memory args
)
internal
pure
returns (SellArgs memory)
{
assert(args.actionType == ActionType.Sell);
return SellArgs({
amount: args.amount,
account: accounts[args.accountId],
takerMarket: args.primaryMarketId,
makerMarket: args.secondaryMarketId,
exchangeWrapper: args.otherAddress,
orderData: args.data
});
}
function parseTradeArgs(
Account.Info[] memory accounts,
ActionArgs memory args
)
internal
pure
returns (TradeArgs memory)
{
assert(args.actionType == ActionType.Trade);
return TradeArgs({
amount: args.amount,
takerAccount: accounts[args.accountId],
makerAccount: accounts[args.otherAccountId],
inputMarket: args.primaryMarketId,
outputMarket: args.secondaryMarketId,
autoTrader: args.otherAddress,
tradeData: args.data
});
}
function parseLiquidateArgs(
Account.Info[] memory accounts,
ActionArgs memory args
)
internal
pure
returns (LiquidateArgs memory)
{
assert(args.actionType == ActionType.Liquidate);
return LiquidateArgs({
amount: args.amount,
solidAccount: accounts[args.accountId],
liquidAccount: accounts[args.otherAccountId],
owedMarket: args.primaryMarketId,
heldMarket: args.secondaryMarketId
});
}
function parseVaporizeArgs(
Account.Info[] memory accounts,
ActionArgs memory args
)
internal
pure
returns (VaporizeArgs memory)
{
assert(args.actionType == ActionType.Vaporize);
return VaporizeArgs({
amount: args.amount,
solidAccount: accounts[args.accountId],
vaporAccount: accounts[args.otherAccountId],
owedMarket: args.primaryMarketId,
heldMarket: args.secondaryMarketId
});
}
function parseCallArgs(
Account.Info[] memory accounts,
ActionArgs memory args
)
internal
pure
returns (CallArgs memory)
{
assert(args.actionType == ActionType.Call);
return CallArgs({
account: accounts[args.accountId],
callee: args.otherAddress,
data: args.data
});
}
}
文件 15 的 152:Address.sol
pragma solidity ^0.6.0;
library Address {
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 16 的 152:AdminAuth.sol
pragma solidity ^0.6.0;
import "../utils/SafeERC20.sol";
contract AdminAuth {
using SafeERC20 for ERC20;
address public owner;
address public admin;
modifier onlyOwner() {
require(owner == msg.sender);
_;
}
constructor() public {
owner = msg.sender;
}
function setAdminByOwner(address _admin) public {
require(msg.sender == owner);
require(admin == address(0));
admin = _admin;
}
function setAdminByAdmin(address _admin) public {
require(msg.sender == admin);
admin = _admin;
}
function setOwnerByAdmin(address _owner) public {
require(msg.sender == admin);
owner = _owner;
}
function kill() public onlyOwner {
selfdestruct(payable(owner));
}
function withdrawStuckFunds(address _token, uint _amount) public onlyOwner {
if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
payable(owner).transfer(_amount);
} else {
ERC20(_token).safeTransfer(owner, _amount);
}
}
}
文件 17 的 152:AllowanceProxy.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../auth/AdminAuth.sol";
import "./SaverExchange.sol";
import "../utils/SafeERC20.sol";
contract AllowanceProxy is AdminAuth {
using SafeERC20 for ERC20;
address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
SaverExchange saverExchange = SaverExchange(0x235abFAd01eb1BDa28Ef94087FBAA63E18074926);
function callSell(SaverExchangeCore.ExchangeData memory exData) public payable {
pullAndSendTokens(exData.srcAddr, exData.srcAmount);
saverExchange.sell{value: msg.value}(exData, msg.sender);
}
function callBuy(SaverExchangeCore.ExchangeData memory exData) public payable {
pullAndSendTokens(exData.srcAddr, exData.srcAmount);
saverExchange.buy{value: msg.value}(exData, msg.sender);
}
function pullAndSendTokens(address _tokenAddr, uint _amount) internal {
if (_tokenAddr == KYBER_ETH_ADDRESS) {
require(msg.value >= _amount, "msg.value smaller than amount");
} else {
ERC20(_tokenAddr).safeTransferFrom(msg.sender, address(saverExchange), _amount);
}
}
function ownerChangeExchange(address payable _newExchange) public onlyOwner {
saverExchange = SaverExchange(_newExchange);
}
}
文件 18 的 152:Auth.sol
pragma solidity ^0.6.0;
import "./AdminAuth.sol";
contract Auth is AdminAuth {
bool public ALL_AUTHORIZED = false;
mapping(address => bool) public authorized;
modifier onlyAuthorized() {
require(ALL_AUTHORIZED || authorized[msg.sender]);
_;
}
constructor() public {
authorized[msg.sender] = true;
}
function setAuthorized(address _user, bool _approved) public onlyOwner {
authorized[_user] = _approved;
}
function setAllAuthorized(bool _authorized) public onlyOwner {
ALL_AUTHORIZED = _authorized;
}
}
文件 19 的 152:BidProxy.sol
pragma solidity ^0.6.0;
import "../../interfaces/Join.sol";
import "../../interfaces/ERC20.sol";
import "../../interfaces/Vat.sol";
import "../../interfaces/Flipper.sol";
import "../../interfaces/Gem.sol";
contract BidProxy {
address public constant DAI_JOIN = 0x9759A6Ac90977b93B58547b4A71c78317f391A28;
address public constant VAT_ADDRESS = 0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
function daiBid(uint _bidId, uint _amount, address _flipper) public {
uint tendAmount = _amount * (10 ** 27);
joinDai(_amount);
(, uint lot, , , , , , ) = Flipper(_flipper).bids(_bidId);
Vat(VAT_ADDRESS).hope(_flipper);
Flipper(_flipper).tend(_bidId, lot, tendAmount);
}
function collateralBid(uint _bidId, uint _amount, address _flipper) public {
(uint bid, , , , , , , ) = Flipper(_flipper).bids(_bidId);
joinDai(bid / (10**27));
Vat(VAT_ADDRESS).hope(_flipper);
Flipper(_flipper).dent(_bidId, _amount, bid);
}
function closeBid(uint _bidId, address _flipper, address _joinAddr) public {
bytes32 ilk = Join(_joinAddr).ilk();
Flipper(_flipper).deal(_bidId);
uint amount = Vat(VAT_ADDRESS).gem(ilk, address(this));
Vat(VAT_ADDRESS).hope(_joinAddr);
Gem(_joinAddr).exit(msg.sender, amount);
}
function exitCollateral(address _joinAddr) public {
bytes32 ilk = Join(_joinAddr).ilk();
uint amount = Vat(VAT_ADDRESS).gem(ilk, address(this));
Vat(VAT_ADDRESS).hope(_joinAddr);
Gem(_joinAddr).exit(msg.sender, amount);
}
function exitDai() public {
uint amount = Vat(VAT_ADDRESS).dai(address(this)) / (10**27);
Vat(VAT_ADDRESS).hope(DAI_JOIN);
Gem(DAI_JOIN).exit(msg.sender, amount);
}
function withdrawToken(address _token) public {
uint balance = ERC20(_token).balanceOf(address(this));
ERC20(_token).transfer(msg.sender, balance);
}
function withdrawEth() public {
uint balance = address(this).balance;
msg.sender.transfer(balance);
}
function joinDai(uint _amount) internal {
uint amountInVat = Vat(VAT_ADDRESS).dai(address(this)) / (10**27);
if (_amount > amountInVat) {
uint amountDiff = (_amount - amountInVat) + 1;
ERC20(DAI_ADDRESS).transferFrom(msg.sender, address(this), amountDiff);
ERC20(DAI_ADDRESS).approve(DAI_JOIN, amountDiff);
Join(DAI_JOIN).join(address(this), amountDiff);
}
}
}
文件 20 的 152:BotRegistry.sol
pragma solidity ^0.6.0;
import "../auth/AdminAuth.sol";
contract BotRegistry is AdminAuth {
mapping (address => bool) public botList;
constructor() public {
botList[0x776B4a13093e30B05781F97F6A4565B6aa8BE330] = true;
botList[0xAED662abcC4FA3314985E67Ea993CAD064a7F5cF] = true;
botList[0xa5d330F6619d6bF892A5B87D80272e1607b3e34D] = true;
botList[0x5feB4DeE5150B589a7f567EA7CADa2759794A90A] = true;
botList[0x7ca06417c1d6f480d3bB195B80692F95A6B66158] = true;
}
function setBot(address _botAddr, bool _state) public onlyOwner {
botList[_botAddr] = _state;
}
}
文件 21 的 152:CEtherInterface.sol
pragma solidity ^0.6.0;
abstract contract CEtherInterface {
function mint() external virtual payable;
function repayBorrow() external virtual payable;
}
文件 22 的 152:CTokenInterface.sol
pragma solidity ^0.6.0;
import "./ERC20.sol";
abstract contract CTokenInterface is ERC20 {
function mint(uint256 mintAmount) external virtual returns (uint256);
function accrueInterest() public virtual returns (uint);
function redeem(uint256 redeemTokens) external virtual returns (uint256);
function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256);
function borrow(uint256 borrowAmount) external virtual returns (uint256);
function repayBorrow(uint256 repayAmount) external virtual returns (uint256);
function repayBorrow() external virtual payable;
function repayBorrowBehalf(address borrower, uint256 repayAmount) external virtual returns (uint256);
function repayBorrowBehalf(address borrower) external virtual payable;
function liquidateBorrow(address borrower, uint256 repayAmount, address cTokenCollateral)
external virtual
returns (uint256);
function liquidateBorrow(address borrower, address cTokenCollateral) external virtual payable;
function exchangeRateCurrent() external virtual returns (uint256);
function supplyRatePerBlock() external virtual returns (uint256);
function borrowRatePerBlock() external virtual returns (uint256);
function totalReserves() external virtual returns (uint256);
function reserveFactorMantissa() external virtual returns (uint256);
function borrowBalanceCurrent(address account) external virtual returns (uint256);
function totalBorrowsCurrent() external virtual returns (uint256);
function getCash() external virtual returns (uint256);
function balanceOfUnderlying(address owner) external virtual returns (uint256);
function underlying() external virtual returns (address);
function getAccountSnapshot(address account) external virtual view returns (uint, uint, uint, uint);
}
文件 23 的 152:CarefulMath.sol
pragma solidity ^0.6.0;
contract CarefulMath {
enum MathError {
NO_ERROR,
DIVISION_BY_ZERO,
INTEGER_OVERFLOW,
INTEGER_UNDERFLOW
}
function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (a == 0) {
return (MathError.NO_ERROR, 0);
}
uint c = a * b;
if (c / a != b) {
return (MathError.INTEGER_OVERFLOW, 0);
} else {
return (MathError.NO_ERROR, c);
}
}
function divUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (b == 0) {
return (MathError.DIVISION_BY_ZERO, 0);
}
return (MathError.NO_ERROR, a / b);
}
function subUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (b <= a) {
return (MathError.NO_ERROR, a - b);
} else {
return (MathError.INTEGER_UNDERFLOW, 0);
}
}
function addUInt(uint a, uint b) internal pure returns (MathError, uint) {
uint c = a + b;
if (c >= a) {
return (MathError.NO_ERROR, c);
} else {
return (MathError.INTEGER_OVERFLOW, 0);
}
}
function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) {
(MathError err0, uint sum) = addUInt(a, b);
if (err0 != MathError.NO_ERROR) {
return (err0, 0);
}
return subUInt(sum, c);
}
}
文件 24 的 152:Cat.sol
pragma solidity ^0.6.0;
abstract contract Cat {
struct Ilk {
address flip;
uint256 chop;
uint256 lump;
}
mapping (bytes32 => Ilk) public ilks;
}
文件 25 的 152:CompShifter.sol
pragma solidity ^0.6.0;
import "../../compound/helpers/CompoundSaverHelper.sol";
contract CompShifter is CompoundSaverHelper {
address public constant COMPTROLLER_ADDR = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B;
function getWholeDebt(uint _cdpId, address _joinAddr) public virtual returns(uint loanAmount) {
return CTokenInterface(_joinAddr).borrowBalanceCurrent(msg.sender);
}
function close(
address _cCollAddr,
address _cBorrowAddr,
uint _collAmount,
uint _debtAmount
) public {
address collAddr = getUnderlyingAddr(_cCollAddr);
paybackDebt(_debtAmount, _cBorrowAddr, getUnderlyingAddr(_cBorrowAddr), tx.origin);
if (CTokenInterface(_cBorrowAddr).borrowBalanceCurrent(address(this)) == 0) {
uint cTokenBalance = CTokenInterface(_cCollAddr).balanceOf(address(this));
require(CTokenInterface(_cCollAddr).redeem(cTokenBalance) == 0);
} else {
require(CTokenInterface(_cCollAddr).redeemUnderlying(_collAmount) == 0);
}
if (collAddr == ETH_ADDRESS) {
msg.sender.transfer(address(this).balance);
} else {
ERC20(collAddr).transfer(msg.sender, ERC20(collAddr).balanceOf(address(this)));
}
}
function changeDebt(
address _cBorrowAddrOld,
address _cBorrowAddrNew,
uint _debtAmountOld,
uint _debtAmountNew
) public {
address borrowAddrNew = getUnderlyingAddr(_cBorrowAddrNew);
paybackDebt(_debtAmountOld, _cBorrowAddrOld, getUnderlyingAddr(_cBorrowAddrOld), tx.origin);
borrowCompound(_cBorrowAddrNew, _debtAmountNew);
if (borrowAddrNew == ETH_ADDRESS) {
msg.sender.transfer(address(this).balance);
} else {
ERC20(borrowAddrNew).transfer(msg.sender, ERC20(borrowAddrNew).balanceOf(address(this)));
}
}
function open(
address _cCollAddr,
address _cBorrowAddr,
uint _debtAmount
) public {
address collAddr = getUnderlyingAddr(_cCollAddr);
address borrowAddr = getUnderlyingAddr(_cBorrowAddr);
uint collAmount = 0;
if (collAddr == ETH_ADDRESS) {
collAmount = address(this).balance;
} else {
collAmount = ERC20(collAddr).balanceOf(address(this));
}
depositCompound(collAddr, _cCollAddr, collAmount);
borrowCompound(_cBorrowAddr, _debtAmount);
if (borrowAddr == ETH_ADDRESS) {
msg.sender.transfer(address(this).balance);
} else {
ERC20(borrowAddr).transfer(msg.sender, ERC20(borrowAddr).balanceOf(address(this)));
}
}
function repayAll(address _cTokenAddr) public {
address tokenAddr = getUnderlyingAddr(_cTokenAddr);
uint amount = ERC20(tokenAddr).balanceOf(address(this));
if (amount != 0) {
paybackDebt(amount, _cTokenAddr, tokenAddr, tx.origin);
}
}
function depositCompound(address _tokenAddr, address _cTokenAddr, uint _amount) internal {
approveCToken(_tokenAddr, _cTokenAddr);
enterMarket(_cTokenAddr);
if (_tokenAddr != ETH_ADDRESS) {
require(CTokenInterface(_cTokenAddr).mint(_amount) == 0, "mint error");
} else {
CEtherInterface(_cTokenAddr).mint{value: _amount}();
}
}
function borrowCompound(address _cTokenAddr, uint _amount) internal {
enterMarket(_cTokenAddr);
require(CTokenInterface(_cTokenAddr).borrow(_amount) == 0);
}
function enterMarket(address _cTokenAddr) public {
address[] memory markets = new address[](1);
markets[0] = _cTokenAddr;
ComptrollerInterface(COMPTROLLER_ADDR).enterMarkets(markets);
}
}
文件 26 的 152:CompoundBasicProxy.sol
pragma solidity ^0.6.0;
import "../utils/GasBurner.sol";
import "../utils/SafeERC20.sol";
import "../interfaces/CTokenInterface.sol";
import "../interfaces/CEtherInterface.sol";
import "../interfaces/ComptrollerInterface.sol";
contract CompoundBasicProxy is GasBurner {
address public constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant COMPTROLLER_ADDR = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B;
using SafeERC20 for ERC20;
function deposit(address _tokenAddr, address _cTokenAddr, uint _amount, bool _inMarket) public burnGas(5) payable {
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransferFrom(msg.sender, address(this), _amount);
}
approveToken(_tokenAddr, _cTokenAddr);
if (!_inMarket) {
enterMarket(_cTokenAddr);
}
if (_tokenAddr != ETH_ADDR) {
require(CTokenInterface(_cTokenAddr).mint(_amount) == 0);
} else {
CEtherInterface(_cTokenAddr).mint{value: msg.value}();
}
}
function withdraw(address _tokenAddr, address _cTokenAddr, uint _amount, bool _isCAmount) public burnGas(5) {
if (_isCAmount) {
require(CTokenInterface(_cTokenAddr).redeem(_amount) == 0);
} else {
require(CTokenInterface(_cTokenAddr).redeemUnderlying(_amount) == 0);
}
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransfer(msg.sender, ERC20(_tokenAddr).balanceOf(address(this)));
} else {
msg.sender.transfer(address(this).balance);
}
}
function borrow(address _tokenAddr, address _cTokenAddr, uint _amount, bool _inMarket) public burnGas(8) {
if (!_inMarket) {
enterMarket(_cTokenAddr);
}
require(CTokenInterface(_cTokenAddr).borrow(_amount) == 0);
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransfer(msg.sender, ERC20(_tokenAddr).balanceOf(address(this)));
} else {
msg.sender.transfer(address(this).balance);
}
}
function payback(address _tokenAddr, address _cTokenAddr, uint _amount, bool _wholeDebt) public burnGas(5) payable {
approveToken(_tokenAddr, _cTokenAddr);
if (_wholeDebt) {
_amount = CTokenInterface(_cTokenAddr).borrowBalanceCurrent(address(this));
}
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransferFrom(msg.sender, address(this), _amount);
require(CTokenInterface(_cTokenAddr).repayBorrow(_amount) == 0);
} else {
CEtherInterface(_cTokenAddr).repayBorrow{value: msg.value}();
msg.sender.transfer(address(this).balance);
}
}
function withdrawTokens(address _tokenAddr) public {
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransfer(msg.sender, ERC20(_tokenAddr).balanceOf(address(this)));
} else {
msg.sender.transfer(address(this).balance);
}
}
function enterMarket(address _cTokenAddr) public {
address[] memory markets = new address[](1);
markets[0] = _cTokenAddr;
ComptrollerInterface(COMPTROLLER_ADDR).enterMarkets(markets);
}
function exitMarket(address _cTokenAddr) public {
ComptrollerInterface(COMPTROLLER_ADDR).exitMarket(_cTokenAddr);
}
function approveToken(address _tokenAddr, address _cTokenAddr) internal {
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeApprove(_cTokenAddr, 0);
ERC20(_tokenAddr).safeApprove(_cTokenAddr, uint(-1));
}
}
}
文件 27 的 152:CompoundBorrowProxy.sol
pragma solidity ^0.6.0;
import "../../interfaces/ERC20.sol";
import "../../interfaces/CTokenInterface.sol";
import "../../interfaces/ComptrollerInterface.sol";
import "../../utils/SafeERC20.sol";
contract CompoundBorrowProxy {
using SafeERC20 for ERC20;
address public constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant COMPTROLLER_ADDR = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B;
function borrow(address _cCollToken, address _cBorrowToken, address _borrowToken, uint _amount) public {
address[] memory markets = new address[](2);
markets[0] = _cCollToken;
markets[1] = _cBorrowToken;
ComptrollerInterface(COMPTROLLER_ADDR).enterMarkets(markets);
require(CTokenInterface(_cBorrowToken).borrow(_amount) == 0);
if (_borrowToken != ETH_ADDR) {
ERC20(_borrowToken).safeTransfer(msg.sender, ERC20(_borrowToken).balanceOf(address(this)));
} else {
msg.sender.transfer(address(this).balance);
}
}
}
文件 28 的 152:CompoundCreateReceiver.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../DS/DSProxy.sol";
import "../../utils/FlashLoanReceiverBase.sol";
import "../../interfaces/DSProxyInterface.sol";
import "../../exchange/SaverExchangeCore.sol";
import "../../shifter/ShifterRegistry.sol";
contract CompoundCreateReceiver is FlashLoanReceiverBase, SaverExchangeCore {
ILendingPoolAddressesProvider public LENDING_POOL_ADDRESS_PROVIDER = ILendingPoolAddressesProvider(0x24a42fD28C976A61Df5D00D0599C34c4f90748c8);
ShifterRegistry public constant shifterRegistry = ShifterRegistry(0x2E82103bD91053C781aaF39da17aE58ceE39d0ab);
address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address payable public constant WALLET_ADDR = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08;
address public constant DISCOUNT_ADDR = 0x1b14E8D511c9A4395425314f849bD737BAF8208F;
constructor() public FlashLoanReceiverBase(LENDING_POOL_ADDRESS_PROVIDER) {}
struct CompCreateData {
address payable proxyAddr;
bytes proxyData;
address cCollAddr;
address cDebtAddr;
}
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params)
external override {
(CompCreateData memory compCreate, ExchangeData memory exchangeData)
= packFunctionCall(_amount, _fee, _params);
address leveragedAsset = _reserve;
if (compCreate.cCollAddr != compCreate.cDebtAddr) {
(, uint sellAmount) = _sell(exchangeData);
getFee(sellAmount, exchangeData.destAddr, compCreate.proxyAddr);
leveragedAsset = exchangeData.destAddr;
}
sendToProxy(compCreate.proxyAddr, leveragedAsset);
address compOpenProxy = shifterRegistry.getAddr("COMP_SHIFTER");
DSProxyInterface(compCreate.proxyAddr).execute(compOpenProxy, compCreate.proxyData);
transferFundsBackToPoolInternal(_reserve, _amount.add(_fee));
if (address(this).balance > 0) {
tx.origin.transfer(address(this).balance);
}
}
function packFunctionCall(uint _amount, uint _fee, bytes memory _params) internal pure returns (CompCreateData memory compCreate, ExchangeData memory exchangeData) {
(
uint[4] memory numData,
address[6] memory cAddresses,
bytes memory callData,
address proxy
)
= abi.decode(_params, (uint256[4],address[6],bytes,address));
bytes memory proxyData = abi.encodeWithSignature(
"open(address,address,uint256)",
cAddresses[0], cAddresses[1], (_amount + _fee));
exchangeData = SaverExchangeCore.ExchangeData({
srcAddr: cAddresses[2],
destAddr: cAddresses[3],
srcAmount: numData[0],
destAmount: numData[1],
minPrice: numData[2],
wrapper: cAddresses[5],
exchangeAddr: cAddresses[4],
callData: callData,
price0x: numData[3]
});
compCreate = CompCreateData({
proxyAddr: payable(proxy),
proxyData: proxyData,
cCollAddr: cAddresses[0],
cDebtAddr: cAddresses[1]
});
return (compCreate, exchangeData);
}
function sendToProxy(address payable _proxy, address _reserve) internal {
if (_reserve != ETH_ADDRESS) {
ERC20(_reserve).safeTransfer(_proxy, ERC20(_reserve).balanceOf(address(this)));
} else {
_proxy.transfer(address(this).balance);
}
}
function getFee(uint _amount, address _tokenAddr, address _proxy) internal returns (uint feeAmount) {
uint fee = 400;
DSProxy proxy = DSProxy(payable(_proxy));
address user = proxy.owner();
if (Discount(DISCOUNT_ADDR).isCustomFeeSet(user)) {
fee = Discount(DISCOUNT_ADDR).getCustomServiceFee(user);
}
feeAmount = (fee == 0) ? 0 : (_amount / fee);
if (feeAmount > (_amount / 5)) {
feeAmount = _amount / 5;
}
if (_tokenAddr == ETH_ADDRESS) {
WALLET_ADDR.transfer(feeAmount);
} else {
ERC20(_tokenAddr).safeTransfer(WALLET_ADDR, feeAmount);
}
}
receive() external override(FlashLoanReceiverBase, SaverExchangeCore) payable {}
}
文件 29 的 152:CompoundCreateTaker.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../interfaces/ILendingPool.sol";
import "../../loggers/DefisaverLogger.sol";
import "../../auth/ProxyPermission.sol";
import "../../exchange/SaverExchangeCore.sol";
import "../../utils/SafeERC20.sol";
contract CompoundCreateTaker is ProxyPermission {
using SafeERC20 for ERC20;
address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
ILendingPool public constant lendingPool = ILendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
DefisaverLogger public constant logger = DefisaverLogger(0x5c55B921f590a89C1Ebe84dF170E655a82b62126);
struct CreateInfo {
address cCollAddress;
address cBorrowAddress;
uint depositAmount;
}
function openLeveragedLoan(
CreateInfo memory _createInfo,
SaverExchangeCore.ExchangeData memory _exchangeData,
address payable _compReceiver
) public payable {
uint loanAmount = _exchangeData.srcAmount;
if (_exchangeData.destAddr != ETH_ADDRESS) {
ERC20(_exchangeData.destAddr).safeTransferFrom(msg.sender, address(this), _createInfo.depositAmount);
} else {
require(msg.value >= _createInfo.depositAmount, "Must send correct amount of eth");
}
sendDeposit(_compReceiver, _exchangeData.destAddr);
(uint[4] memory numData, address[6] memory cAddresses, bytes memory callData)
= _packData(_createInfo, _exchangeData);
bytes memory paramsData = abi.encode(numData, cAddresses, callData, address(this));
givePermission(_compReceiver);
lendingPool.flashLoan(_compReceiver, _exchangeData.srcAddr, loanAmount, paramsData);
removePermission(_compReceiver);
logger.Log(address(this), msg.sender, "CompoundLeveragedLoan",
abi.encode(_exchangeData.srcAddr, _exchangeData.destAddr, _exchangeData.srcAmount, _exchangeData.destAmount));
}
function sendDeposit(address payable _compoundReceiver, address _token) internal {
if (_token != ETH_ADDRESS) {
ERC20(_token).safeTransfer(_compoundReceiver, ERC20(_token).balanceOf(address(this)));
}
_compoundReceiver.transfer(address(this).balance);
}
function _packData(
CreateInfo memory _createInfo,
SaverExchangeCore.ExchangeData memory exchangeData
) internal pure returns (uint[4] memory numData, address[6] memory cAddresses, bytes memory callData) {
numData = [
exchangeData.srcAmount,
exchangeData.destAmount,
exchangeData.minPrice,
exchangeData.price0x
];
cAddresses = [
_createInfo.cCollAddress,
_createInfo.cBorrowAddress,
exchangeData.srcAddr,
exchangeData.destAddr,
exchangeData.exchangeAddr,
exchangeData.wrapper
];
callData = exchangeData.callData;
}
}
文件 30 的 152:CompoundFlashLoanTaker.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../utils/GasBurner.sol";
import "../../interfaces/ILendingPool.sol";
import "./CompoundSaverProxy.sol";
import "../../loggers/DefisaverLogger.sol";
import "../../auth/ProxyPermission.sol";
contract CompoundFlashLoanTaker is CompoundSaverProxy, ProxyPermission, GasBurner {
ILendingPool public constant lendingPool = ILendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
address payable public constant COMPOUND_SAVER_FLASH_LOAN = 0xCeB190A35D9D4804b9CE8d0CF79239f6949BfCcB;
address public constant AAVE_POOL_CORE = 0x3dfd23A6c5E8BbcFc9581d2E864a68feb6a076d3;
function repayWithLoan(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost
) public payable burnGas(25) {
uint maxColl = getMaxCollateral(_cAddresses[0], address(this));
uint availableLiquidity = getAvailableLiquidity(_exData.srcAddr);
if (_exData.srcAmount <= maxColl || availableLiquidity == 0) {
repay(_exData, _cAddresses, _gasCost);
} else {
COMPOUND_SAVER_FLASH_LOAN.transfer(msg.value);
uint loanAmount = (_exData.srcAmount - maxColl);
if (loanAmount > availableLiquidity) loanAmount = availableLiquidity;
bytes memory encoded = packExchangeData(_exData);
bytes memory paramsData = abi.encode(encoded, _cAddresses, _gasCost, true, address(this));
givePermission(COMPOUND_SAVER_FLASH_LOAN);
lendingPool.flashLoan(COMPOUND_SAVER_FLASH_LOAN, getUnderlyingAddr(_cAddresses[0]), loanAmount, paramsData);
removePermission(COMPOUND_SAVER_FLASH_LOAN);
logger.Log(address(this), msg.sender, "CompoundFlashRepay", abi.encode(loanAmount, _exData.srcAmount, _cAddresses[0]));
}
}
function boostWithLoan(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost
) public payable burnGas(20) {
uint maxBorrow = getMaxBorrow(_cAddresses[1], address(this));
uint availableLiquidity = getAvailableLiquidity(_exData.srcAddr);
if (_exData.srcAmount <= maxBorrow || availableLiquidity == 0) {
boost(_exData, _cAddresses, _gasCost);
} else {
COMPOUND_SAVER_FLASH_LOAN.transfer(msg.value);
uint loanAmount = (_exData.srcAmount - maxBorrow);
if (loanAmount > availableLiquidity) loanAmount = availableLiquidity;
bytes memory paramsData = abi.encode(packExchangeData(_exData), _cAddresses, _gasCost, false, address(this));
givePermission(COMPOUND_SAVER_FLASH_LOAN);
lendingPool.flashLoan(COMPOUND_SAVER_FLASH_LOAN, getUnderlyingAddr(_cAddresses[1]), loanAmount, paramsData);
removePermission(COMPOUND_SAVER_FLASH_LOAN);
logger.Log(address(this), msg.sender, "CompoundFlashBoost", abi.encode(loanAmount, _exData.srcAmount, _cAddresses[1]));
}
}
function getAvailableLiquidity(address _tokenAddr) internal view returns (uint liquidity) {
if (_tokenAddr == KYBER_ETH_ADDRESS) {
liquidity = AAVE_POOL_CORE.balance;
} else {
liquidity = ERC20(_tokenAddr).balanceOf(AAVE_POOL_CORE);
}
}
}
文件 31 的 152:CompoundImportFlashLoan.sol
pragma solidity ^0.6.0;
import "../../utils/FlashLoanReceiverBase.sol";
import "../../interfaces/ProxyRegistryInterface.sol";
import "../../interfaces/CTokenInterface.sol";
import "../../utils/SafeERC20.sol";
contract CompoundImportFlashLoan is FlashLoanReceiverBase {
using SafeERC20 for ERC20;
ILendingPoolAddressesProvider public LENDING_POOL_ADDRESS_PROVIDER = ILendingPoolAddressesProvider(0x24a42fD28C976A61Df5D00D0599C34c4f90748c8);
address public constant COMPOUND_BORROW_PROXY = 0xb7EDC39bE76107e2Cc645f0f6a3D164f5e173Ee2;
address public owner;
constructor()
FlashLoanReceiverBase(LENDING_POOL_ADDRESS_PROVIDER)
public {
owner = msg.sender;
}
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params)
external override {
(
address cCollateralToken,
address cBorrowToken,
address user,
address proxy
)
= abi.decode(_params, (address,address,address,address));
ERC20(_reserve).safeApprove(cBorrowToken, 0);
ERC20(_reserve).safeApprove(cBorrowToken, uint(-1));
require(CTokenInterface(cBorrowToken).repayBorrowBehalf(user, uint(-1)) == 0, "Repay borrow behalf fail");
uint cTokenBalance = CTokenInterface(cCollateralToken).balanceOf(user);
require(CTokenInterface(cCollateralToken).transferFrom(user, proxy, cTokenBalance));
bytes memory proxyData = getProxyData(cCollateralToken, cBorrowToken, _reserve, (_amount + _fee));
DSProxyInterface(proxy).execute(COMPOUND_BORROW_PROXY, proxyData);
transferFundsBackToPoolInternal(_reserve, _amount.add(_fee));
}
function getProxyData(address _cCollToken, address _cBorrowToken, address _borrowToken, uint _amount) internal pure returns (bytes memory proxyData) {
proxyData = abi.encodeWithSignature(
"borrow(address,address,address,uint256)",
_cCollToken, _cBorrowToken, _borrowToken, _amount);
}
function withdrawStuckFunds(address _tokenAddr, uint _amount) public {
require(owner == msg.sender, "Must be owner");
if (_tokenAddr == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
msg.sender.transfer(_amount);
} else {
ERC20(_tokenAddr).safeTransfer(owner, _amount);
}
}
}
文件 32 的 152:CompoundImportTaker.sol
pragma solidity ^0.6.0;
import "../../utils/GasBurner.sol";
import "../../auth/ProxyPermission.sol";
import "../../loggers/DefisaverLogger.sol";
import "../../interfaces/ILendingPool.sol";
import "../../interfaces/CTokenInterface.sol";
import "../../interfaces/ProxyRegistryInterface.sol";
import "../helpers/CompoundSaverHelper.sol";
contract CompoundImportTaker is CompoundSaverHelper, ProxyPermission, GasBurner {
ILendingPool public constant lendingPool = ILendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
address payable public constant COMPOUND_IMPORT_FLASH_LOAN = 0x0a9238e14d5A20CDb03811B12D1984587C3CE9a0;
address public constant PROXY_REGISTRY_ADDRESS = 0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4;
DefisaverLogger public constant logger = DefisaverLogger(0x5c55B921f590a89C1Ebe84dF170E655a82b62126);
function importLoan(address _cCollateralToken, address _cBorrowToken) external burnGas(20) {
address proxy = getProxy();
uint loanAmount = CTokenInterface(_cBorrowToken).borrowBalanceCurrent(msg.sender);
bytes memory paramsData = abi.encode(_cCollateralToken, _cBorrowToken, msg.sender, proxy);
givePermission(COMPOUND_IMPORT_FLASH_LOAN);
lendingPool.flashLoan(COMPOUND_IMPORT_FLASH_LOAN, getUnderlyingAddr(_cBorrowToken), loanAmount, paramsData);
removePermission(COMPOUND_IMPORT_FLASH_LOAN);
logger.Log(address(this), msg.sender, "CompoundImport", abi.encode(loanAmount, 0, _cCollateralToken));
}
function getProxy() internal returns (address proxy) {
proxy = ProxyRegistryInterface(PROXY_REGISTRY_ADDRESS).proxies(msg.sender);
if (proxy == address(0)) {
proxy = ProxyRegistryInterface(PROXY_REGISTRY_ADDRESS).build(msg.sender);
}
}
}
文件 33 的 152:CompoundLoanInfo.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./CompoundSafetyRatio.sol";
import "./helpers/CompoundSaverHelper.sol";
contract CompoundLoanInfo is CompoundSafetyRatio {
struct LoanData {
address user;
uint128 ratio;
address[] collAddr;
address[] borrowAddr;
uint[] collAmounts;
uint[] borrowAmounts;
}
struct TokenInfo {
address cTokenAddress;
address underlyingTokenAddress;
uint collateralFactor;
uint price;
}
struct TokenInfoFull {
address underlyingTokenAddress;
uint supplyRate;
uint borrowRate;
uint exchangeRate;
uint marketLiquidity;
uint totalSupply;
uint totalBorrow;
uint collateralFactor;
uint price;
}
address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant CETH_ADDRESS = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5;
function getRatio(address _user) public view returns (uint) {
return getSafetyRatio(_user);
}
function getPrices(address[] memory _cTokens) public view returns (uint[] memory prices) {
prices = new uint[](_cTokens.length);
address oracleAddr = comp.oracle();
for (uint i = 0; i < _cTokens.length; ++i) {
prices[i] = CompoundOracleInterface(oracleAddr).getUnderlyingPrice(_cTokens[i]);
}
}
function getCollFactors(address[] memory _cTokens) public view returns (uint[] memory collFactors) {
collFactors = new uint[](_cTokens.length);
for (uint i = 0; i < _cTokens.length; ++i) {
(, collFactors[i]) = comp.markets(_cTokens[i]);
}
}
function getLoanData(address _user) public view returns (LoanData memory data) {
address[] memory assets = comp.getAssetsIn(_user);
address oracleAddr = comp.oracle();
data = LoanData({
user: _user,
ratio: 0,
collAddr: new address[](assets.length),
borrowAddr: new address[](assets.length),
collAmounts: new uint[](assets.length),
borrowAmounts: new uint[](assets.length)
});
uint collPos = 0;
uint borrowPos = 0;
for (uint i = 0; i < assets.length; i++) {
address asset = assets[i];
(, uint cTokenBalance, uint borrowBalance, uint exchangeRateMantissa)
= CTokenInterface(asset).getAccountSnapshot(_user);
Exp memory oraclePrice;
if (cTokenBalance != 0 || borrowBalance != 0) {
oraclePrice = Exp({mantissa: CompoundOracleInterface(oracleAddr).getUnderlyingPrice(asset)});
}
if (cTokenBalance != 0) {
Exp memory exchangeRate = Exp({mantissa: exchangeRateMantissa});
(, Exp memory tokensToUsd) = mulExp(exchangeRate, oraclePrice);
data.collAddr[collPos] = asset;
(, data.collAmounts[collPos]) = mulScalarTruncate(tokensToUsd, cTokenBalance);
collPos++;
}
if (borrowBalance != 0) {
data.borrowAddr[borrowPos] = asset;
(, data.borrowAmounts[borrowPos]) = mulScalarTruncate(oraclePrice, borrowBalance);
borrowPos++;
}
}
data.ratio = uint128(getSafetyRatio(_user));
return data;
}
function getTokenBalances(address _user, address[] memory _cTokens) public view returns (uint[] memory balances, uint[] memory borrows) {
balances = new uint[](_cTokens.length);
borrows = new uint[](_cTokens.length);
for (uint i = 0; i < _cTokens.length; i++) {
address asset = _cTokens[i];
(, uint cTokenBalance, uint borrowBalance, uint exchangeRateMantissa)
= CTokenInterface(asset).getAccountSnapshot(_user);
Exp memory exchangeRate = Exp({mantissa: exchangeRateMantissa});
(, balances[i]) = mulScalarTruncate(exchangeRate, cTokenBalance);
borrows[i] = borrowBalance;
}
}
function getLoanDataArr(address[] memory _users) public view returns (LoanData[] memory loans) {
loans = new LoanData[](_users.length);
for (uint i = 0; i < _users.length; ++i) {
loans[i] = getLoanData(_users[i]);
}
}
function getRatios(address[] memory _users) public view returns (uint[] memory ratios) {
ratios = new uint[](_users.length);
for (uint i = 0; i < _users.length; ++i) {
ratios[i] = getSafetyRatio(_users[i]);
}
}
function getTokensInfo(address[] memory _cTokenAddresses) public returns(TokenInfo[] memory tokens) {
tokens = new TokenInfo[](_cTokenAddresses.length);
address oracleAddr = comp.oracle();
for (uint i = 0; i < _cTokenAddresses.length; ++i) {
(, uint collFactor) = comp.markets(_cTokenAddresses[i]);
tokens[i] = TokenInfo({
cTokenAddress: _cTokenAddresses[i],
underlyingTokenAddress: getUnderlyingAddr(_cTokenAddresses[i]),
collateralFactor: collFactor,
price: CompoundOracleInterface(oracleAddr).getUnderlyingPrice(_cTokenAddresses[i])
});
}
}
function getFullTokensInfo(address[] memory _cTokenAddresses) public returns(TokenInfoFull[] memory tokens) {
tokens = new TokenInfoFull[](_cTokenAddresses.length);
address oracleAddr = comp.oracle();
for (uint i = 0; i < _cTokenAddresses.length; ++i) {
(, uint collFactor) = comp.markets(_cTokenAddresses[i]);
CTokenInterface cToken = CTokenInterface(_cTokenAddresses[i]);
tokens[i] = TokenInfoFull({
underlyingTokenAddress: getUnderlyingAddr(_cTokenAddresses[i]),
supplyRate: cToken.supplyRatePerBlock(),
borrowRate: cToken.borrowRatePerBlock(),
exchangeRate: cToken.exchangeRateCurrent(),
marketLiquidity: cToken.getCash(),
totalSupply: cToken.totalSupply(),
totalBorrow: cToken.totalBorrowsCurrent(),
collateralFactor: collFactor,
price: CompoundOracleInterface(oracleAddr).getUnderlyingPrice(_cTokenAddresses[i])
});
}
}
function getUnderlyingAddr(address _cTokenAddress) internal returns (address) {
if (_cTokenAddress == CETH_ADDRESS) {
return ETH_ADDRESS;
} else {
return CTokenInterface(_cTokenAddress).underlying();
}
}
}
文件 34 的 152:CompoundMonitor.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../utils/BotRegistry.sol";
import "../../utils/GasBurner.sol";
import "./CompoundMonitorProxy.sol";
import "./CompoundSubscriptions.sol";
import "../../interfaces/GasTokenInterface.sol";
import "../../DS/DSMath.sol";
import "../../auth/AdminAuth.sol";
import "../../loggers/DefisaverLogger.sol";
import "../CompoundSafetyRatio.sol";
import "../../exchange/SaverExchangeCore.sol";
contract CompoundMonitor is AdminAuth, DSMath, CompoundSafetyRatio, GasBurner {
using SafeERC20 for ERC20;
enum Method { Boost, Repay }
uint public REPAY_GAS_TOKEN = 20;
uint public BOOST_GAS_TOKEN = 20;
uint constant public MAX_GAS_PRICE = 500000000000;
uint public REPAY_GAS_COST = 2000000;
uint public BOOST_GAS_COST = 2000000;
address public constant GAS_TOKEN_INTERFACE_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04;
address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
address public constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B;
CompoundMonitorProxy public compoundMonitorProxy;
CompoundSubscriptions public subscriptionsContract;
address public compoundFlashLoanTakerAddress;
DefisaverLogger public logger = DefisaverLogger(DEFISAVER_LOGGER);
modifier onlyApproved() {
require(BotRegistry(BOT_REGISTRY_ADDRESS).botList(msg.sender), "Not auth bot");
_;
}
constructor(address _compoundMonitorProxy, address _subscriptions, address _compoundFlashLoanTaker) public {
compoundMonitorProxy = CompoundMonitorProxy(_compoundMonitorProxy);
subscriptionsContract = CompoundSubscriptions(_subscriptions);
compoundFlashLoanTakerAddress = _compoundFlashLoanTaker;
}
function repayFor(
SaverExchangeCore.ExchangeData memory _exData,
address[2] memory _cAddresses,
address _user
) public payable onlyApproved burnGas(REPAY_GAS_TOKEN) {
(bool isAllowed, uint ratioBefore) = canCall(Method.Repay, _user);
require(isAllowed);
uint256 gasCost = calcGasCost(REPAY_GAS_COST);
compoundMonitorProxy.callExecute{value: msg.value}(
_user,
compoundFlashLoanTakerAddress,
abi.encodeWithSignature(
"repayWithLoan((address,address,uint256,uint256,uint256,address,address,bytes,uint256),address[2],uint256)",
_exData,
_cAddresses,
gasCost
)
);
(bool isGoodRatio, uint ratioAfter) = ratioGoodAfter(Method.Repay, _user);
require(isGoodRatio);
returnEth();
logger.Log(address(this), _user, "AutomaticCompoundRepay", abi.encode(ratioBefore, ratioAfter));
}
function boostFor(
SaverExchangeCore.ExchangeData memory _exData,
address[2] memory _cAddresses,
address _user
) public payable onlyApproved burnGas(BOOST_GAS_TOKEN) {
(bool isAllowed, uint ratioBefore) = canCall(Method.Boost, _user);
require(isAllowed);
uint256 gasCost = calcGasCost(BOOST_GAS_COST);
compoundMonitorProxy.callExecute{value: msg.value}(
_user,
compoundFlashLoanTakerAddress,
abi.encodeWithSignature(
"boostWithLoan((address,address,uint256,uint256,uint256,address,address,bytes,uint256),address[2],uint256)",
_exData,
_cAddresses,
gasCost
)
);
(bool isGoodRatio, uint ratioAfter) = ratioGoodAfter(Method.Boost, _user);
require(isGoodRatio);
returnEth();
logger.Log(address(this), _user, "AutomaticCompoundBoost", abi.encode(ratioBefore, ratioAfter));
}
function returnEth() internal {
if (address(this).balance > 0) {
msg.sender.transfer(address(this).balance);
}
}
function canCall(Method _method, address _user) public view returns(bool, uint) {
bool subscribed = subscriptionsContract.isSubscribed(_user);
CompoundSubscriptions.CompoundHolder memory holder = subscriptionsContract.getHolder(_user);
if (!subscribed) return (false, 0);
if (_method == Method.Boost && !holder.boostEnabled) return (false, 0);
uint currRatio = getSafetyRatio(_user);
if (_method == Method.Repay) {
return (currRatio < holder.minRatio, currRatio);
} else if (_method == Method.Boost) {
return (currRatio > holder.maxRatio, currRatio);
}
}
function ratioGoodAfter(Method _method, address _user) public view returns(bool, uint) {
CompoundSubscriptions.CompoundHolder memory holder;
holder= subscriptionsContract.getHolder(_user);
uint currRatio = getSafetyRatio(_user);
if (_method == Method.Repay) {
return (currRatio < holder.maxRatio, currRatio);
} else if (_method == Method.Boost) {
return (currRatio > holder.minRatio, currRatio);
}
}
function calcGasCost(uint _gasAmount) public 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 transferERC20(address _tokenAddress, address _to, uint _amount) public onlyOwner {
ERC20(_tokenAddress).safeTransfer(_to, _amount);
}
function transferEth(address payable _to, uint _amount) public onlyOwner {
_to.transfer(_amount);
}
}
文件 35 的 152:CompoundMonitorProxy.sol
pragma solidity ^0.6.0;
import "../../interfaces/DSProxyInterface.sol";
import "../../utils/SafeERC20.sol";
import "../../auth/AdminAuth.sol";
contract CompoundMonitorProxy is AdminAuth {
using SafeERC20 for ERC20;
uint public CHANGE_PERIOD;
address public monitor;
address public newMonitor;
address public lastMonitor;
uint public changeRequestedTimestamp;
mapping(address => bool) public allowed;
event MonitorChangeInitiated(address oldMonitor, address newMonitor);
event MonitorChangeCanceled();
event MonitorChangeFinished(address monitor);
event MonitorChangeReverted(address monitor);
modifier onlyAllowed() {
require(allowed[msg.sender] || msg.sender == owner);
_;
}
modifier onlyMonitor() {
require (msg.sender == monitor);
_;
}
constructor(uint _changePeriod) public {
CHANGE_PERIOD = _changePeriod * 1 days;
}
function callExecute(address _owner, address _compoundSaverProxy, bytes memory _data) public payable onlyMonitor {
DSProxyInterface(_owner).execute{value: msg.value}(_compoundSaverProxy, _data);
if (address(this).balance > 0) {
msg.sender.transfer(address(this).balance);
}
}
function setMonitor(address _monitor) public onlyAllowed {
require(monitor == address(0));
monitor = _monitor;
}
function changeMonitor(address _newMonitor) public onlyAllowed {
require(changeRequestedTimestamp == 0);
changeRequestedTimestamp = now;
lastMonitor = monitor;
newMonitor = _newMonitor;
emit MonitorChangeInitiated(lastMonitor, newMonitor);
}
function cancelMonitorChange() public onlyAllowed {
require(changeRequestedTimestamp > 0);
changeRequestedTimestamp = 0;
newMonitor = address(0);
emit MonitorChangeCanceled();
}
function confirmNewMonitor() public onlyAllowed {
require((changeRequestedTimestamp + CHANGE_PERIOD) < now);
require(changeRequestedTimestamp != 0);
require(newMonitor != address(0));
monitor = newMonitor;
newMonitor = address(0);
changeRequestedTimestamp = 0;
emit MonitorChangeFinished(monitor);
}
function revertMonitor() public onlyAllowed {
require(lastMonitor != address(0));
monitor = lastMonitor;
emit MonitorChangeReverted(monitor);
}
function addAllowed(address _user) public onlyAllowed {
allowed[_user] = true;
}
function removeAllowed(address _user) public onlyAllowed {
allowed[_user] = false;
}
function setChangePeriod(uint _periodInDays) public onlyAllowed {
require(_periodInDays * 1 days > CHANGE_PERIOD);
CHANGE_PERIOD = _periodInDays * 1 days;
}
function withdrawToken(address _token) public onlyOwner {
uint balance = ERC20(_token).balanceOf(address(this));
ERC20(_token).safeTransfer(msg.sender, balance);
}
function withdrawEth() public onlyOwner {
uint balance = address(this).balance;
msg.sender.transfer(balance);
}
}
文件 36 的 152:CompoundOracleInterface.sol
pragma solidity ^0.6.0;
abstract contract CompoundOracleInterface {
function getUnderlyingPrice(address cToken) external view virtual returns (uint);
}
文件 37 的 152:CompoundSafetyRatio.sol
pragma solidity ^0.6.0;
import "../DS/DSMath.sol";
import "../interfaces/CompoundOracleInterface.sol";
import "../interfaces/ComptrollerInterface.sol";
import "../interfaces/CTokenInterface.sol";
import "./helpers/Exponential.sol";
contract CompoundSafetyRatio is Exponential, DSMath {
ComptrollerInterface public constant comp = ComptrollerInterface(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B);
function getSafetyRatio(address _user) public view returns (uint) {
address[] memory assets = comp.getAssetsIn(_user);
address oracleAddr = comp.oracle();
uint sumCollateral = 0;
uint sumBorrow = 0;
for (uint i = 0; i < assets.length; i++) {
address asset = assets[i];
(, uint cTokenBalance, uint borrowBalance, uint exchangeRateMantissa)
= CTokenInterface(asset).getAccountSnapshot(_user);
Exp memory oraclePrice;
if (cTokenBalance != 0 || borrowBalance != 0) {
oraclePrice = Exp({mantissa: CompoundOracleInterface(oracleAddr).getUnderlyingPrice(asset)});
}
if (cTokenBalance != 0) {
(, uint collFactorMantissa) = comp.markets(address(asset));
Exp memory collateralFactor = Exp({mantissa: collFactorMantissa});
Exp memory exchangeRate = Exp({mantissa: exchangeRateMantissa});
(, Exp memory tokensToUsd) = mulExp3(collateralFactor, exchangeRate, oraclePrice);
(, sumCollateral) = mulScalarTruncateAddUInt(tokensToUsd, cTokenBalance, sumCollateral);
}
if (borrowBalance != 0) {
(, sumBorrow) = mulScalarTruncateAddUInt(oraclePrice, borrowBalance, sumBorrow);
}
}
if (sumBorrow == 0) return uint(-1);
uint borrowPowerUsed = (sumBorrow * 10**18) / sumCollateral;
return wdiv(1e18, borrowPowerUsed);
}
}
文件 38 的 152:CompoundSaverFlashLoan.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../utils/FlashLoanReceiverBase.sol";
import "../../interfaces/DSProxyInterface.sol";
import "../../exchange/SaverExchangeCore.sol";
contract CompoundSaverFlashLoan is FlashLoanReceiverBase, SaverExchangeCore {
ILendingPoolAddressesProvider public LENDING_POOL_ADDRESS_PROVIDER = ILendingPoolAddressesProvider(0x24a42fD28C976A61Df5D00D0599C34c4f90748c8);
address payable public COMPOUND_SAVER_FLASH_PROXY = 0xcEAb38B5C88F33Dabe4D31BDD384E08215526632;
address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public owner;
using SafeERC20 for ERC20;
constructor()
FlashLoanReceiverBase(LENDING_POOL_ADDRESS_PROVIDER)
public {
owner = msg.sender;
}
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params)
external override {
(bytes memory proxyData, address payable proxyAddr) = packFunctionCall(_amount, _fee, _params);
sendLoanToProxy(proxyAddr, _reserve, _amount);
DSProxyInterface(proxyAddr).execute(COMPOUND_SAVER_FLASH_PROXY, proxyData);
transferFundsBackToPoolInternal(_reserve, _amount.add(_fee));
if (address(this).balance > 0) {
tx.origin.transfer(address(this).balance);
}
}
function packFunctionCall(uint _amount, uint _fee, bytes memory _params) internal pure returns (bytes memory proxyData, address payable) {
(
bytes memory exDataBytes,
address[2] memory cAddresses,
uint256 gasCost,
bool isRepay,
address payable proxyAddr
)
= abi.decode(_params, (bytes,address[2],uint256,bool,address));
ExchangeData memory _exData = unpackExchangeData(exDataBytes);
uint[2] memory flashLoanData = [_amount, _fee];
if (isRepay) {
proxyData = abi.encodeWithSignature("flashRepay((address,address,uint256,uint256,uint256,address,address,bytes,uint256),address[2],uint256,uint256[2])", _exData, cAddresses, gasCost, flashLoanData);
} else {
proxyData = abi.encodeWithSignature("flashBoost((address,address,uint256,uint256,uint256,address,address,bytes,uint256),address[2],uint256,uint256[2])", _exData, cAddresses, gasCost, flashLoanData);
}
return (proxyData, proxyAddr);
}
function sendLoanToProxy(address payable _proxy, address _reserve, uint _amount) internal {
if (_reserve != ETH_ADDRESS) {
ERC20(_reserve).safeTransfer(_proxy, _amount);
}
_proxy.transfer(address(this).balance);
}
receive() external override(SaverExchangeCore, FlashLoanReceiverBase) payable {}
}
文件 39 的 152:CompoundSaverFlashProxy.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../utils/SafeERC20.sol";
import "../../exchange/SaverExchangeCore.sol";
import "../../interfaces/CTokenInterface.sol";
import "../../utils/Discount.sol";
import "../helpers/CompoundSaverHelper.sol";
import "../../loggers/DefisaverLogger.sol";
contract CompoundSaverFlashProxy is SaverExchangeCore, CompoundSaverHelper {
address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
using SafeERC20 for ERC20;
function flashRepay(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost,
uint[2] memory _flashLoanData
) public payable {
enterMarket(_cAddresses[0], _cAddresses[1]);
address payable user = payable(getUserAddress());
uint flashBorrowed = _flashLoanData[0] + _flashLoanData[1];
uint maxColl = getMaxCollateral(_cAddresses[0], address(this));
require(CTokenInterface(_cAddresses[0]).redeemUnderlying(maxColl) == 0);
address collToken = getUnderlyingAddr(_cAddresses[0]);
address borrowToken = getUnderlyingAddr(_cAddresses[1]);
uint swapAmount = 0;
if (collToken != borrowToken) {
_exData.srcAmount = maxColl + _flashLoanData[0];
(,swapAmount) = _sell(_exData);
swapAmount -= getFee(swapAmount, user, _gasCost, _cAddresses[1]);
} else {
swapAmount = (maxColl + _flashLoanData[0]);
swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]);
}
paybackDebt(swapAmount, _cAddresses[1], borrowToken, user);
require(CTokenInterface(_cAddresses[0]).redeemUnderlying(flashBorrowed) == 0);
returnFlashLoan(collToken, flashBorrowed);
DefisaverLogger(DEFISAVER_LOGGER).Log(address(this), msg.sender, "CompoundRepay", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken));
}
function flashBoost(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost,
uint[2] memory _flashLoanData
) public payable {
enterMarket(_cAddresses[0], _cAddresses[1]);
address payable user = payable(getUserAddress());
uint flashBorrowed = _flashLoanData[0] + _flashLoanData[1];
uint borrowAmount = getMaxBorrow(_cAddresses[1], address(this));
require(CTokenInterface(_cAddresses[1]).borrow(borrowAmount) == 0);
address collToken = getUnderlyingAddr(_cAddresses[0]);
address borrowToken = getUnderlyingAddr(_cAddresses[1]);
uint swapAmount = 0;
if (collToken != borrowToken) {
borrowAmount -= getFee((borrowAmount + _flashLoanData[0]), user, _gasCost, _cAddresses[1]);
_exData.srcAmount = (borrowAmount + _flashLoanData[0]);
(,swapAmount) = _sell(_exData);
} else {
swapAmount = (borrowAmount + _flashLoanData[0]);
swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]);
}
depositCollateral(collToken, _cAddresses[0], swapAmount);
require(CTokenInterface(_cAddresses[1]).borrow(flashBorrowed) == 0);
returnFlashLoan(borrowToken, flashBorrowed);
DefisaverLogger(DEFISAVER_LOGGER).Log(address(this), msg.sender, "CompoundBoost", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken));
}
function depositCollateral(address _collToken, address _cCollToken, uint _depositAmount) internal {
approveCToken(_collToken, _cCollToken);
if (_collToken != ETH_ADDRESS) {
require(CTokenInterface(_cCollToken).mint(_depositAmount) == 0);
} else {
CEtherInterface(_cCollToken).mint{value: _depositAmount}();
}
}
function returnFlashLoan(address _tokenAddr, uint _amount) internal {
if (_tokenAddr != ETH_ADDRESS) {
ERC20(_tokenAddr).safeTransfer(msg.sender, _amount);
}
msg.sender.transfer(address(this).balance);
}
}
文件 40 的 152:CompoundSaverHelper.sol
pragma solidity ^0.6.0;
import "../../interfaces/CEtherInterface.sol";
import "../../interfaces/CompoundOracleInterface.sol";
import "../../interfaces/CTokenInterface.sol";
import "../../interfaces/ComptrollerInterface.sol";
import "../../utils/Discount.sol";
import "../../DS/DSMath.sol";
import "../../DS/DSProxy.sol";
import "./Exponential.sol";
import "../../utils/BotRegistry.sol";
import "../../utils/SafeERC20.sol";
contract CompoundSaverHelper is DSMath, Exponential {
using SafeERC20 for ERC20;
address payable public constant WALLET_ADDR = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08;
address public constant DISCOUNT_ADDR = 0x1b14E8D511c9A4395425314f849bD737BAF8208F;
uint public constant MANUAL_SERVICE_FEE = 400;
uint public constant AUTOMATIC_SERVICE_FEE = 333;
address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant CETH_ADDRESS = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5;
address public constant COMPTROLLER = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B;
address public constant COMPOUND_LOGGER = 0x3DD0CDf5fFA28C6847B4B276e2fD256046a44bb7;
address public constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B;
function paybackDebt(uint _amount, address _cBorrowToken, address _borrowToken, address payable _user) internal {
uint wholeDebt = CTokenInterface(_cBorrowToken).borrowBalanceCurrent(address(this));
if (_amount > wholeDebt) {
if (_borrowToken == ETH_ADDRESS) {
_user.transfer((_amount - wholeDebt));
} else {
ERC20(_borrowToken).safeTransfer(_user, (_amount - wholeDebt));
}
_amount = wholeDebt;
}
approveCToken(_borrowToken, _cBorrowToken);
if (_borrowToken == ETH_ADDRESS) {
CEtherInterface(_cBorrowToken).repayBorrow{value: _amount}();
} else {
require(CTokenInterface(_cBorrowToken).repayBorrow(_amount) == 0);
}
}
function getFee(uint _amount, address _user, uint _gasCost, address _cTokenAddr) internal returns (uint feeAmount) {
uint fee = MANUAL_SERVICE_FEE;
if (BotRegistry(BOT_REGISTRY_ADDRESS).botList(tx.origin)) {
fee = AUTOMATIC_SERVICE_FEE;
}
address tokenAddr = getUnderlyingAddr(_cTokenAddr);
if (Discount(DISCOUNT_ADDR).isCustomFeeSet(_user)) {
fee = Discount(DISCOUNT_ADDR).getCustomServiceFee(_user);
}
feeAmount = (fee == 0) ? 0 : (_amount / fee);
if (_gasCost != 0) {
address oracle = ComptrollerInterface(COMPTROLLER).oracle();
uint usdTokenPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cTokenAddr);
uint ethPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(CETH_ADDRESS);
uint tokenPriceInEth = wdiv(usdTokenPrice, ethPrice);
_gasCost = wdiv(_gasCost, tokenPriceInEth);
feeAmount = add(feeAmount, _gasCost);
}
if (feeAmount > (_amount / 5)) {
feeAmount = _amount / 5;
}
if (tokenAddr == ETH_ADDRESS) {
WALLET_ADDR.transfer(feeAmount);
} else {
ERC20(tokenAddr).safeTransfer(WALLET_ADDR, feeAmount);
}
}
function getGasCost(uint _amount, uint _gasCost, address _cTokenAddr) internal returns (uint feeAmount) {
address tokenAddr = getUnderlyingAddr(_cTokenAddr);
if (_gasCost != 0) {
address oracle = ComptrollerInterface(COMPTROLLER).oracle();
uint usdTokenPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cTokenAddr);
uint ethPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(CETH_ADDRESS);
uint tokenPriceInEth = wdiv(usdTokenPrice, ethPrice);
feeAmount = wdiv(_gasCost, tokenPriceInEth);
}
if (feeAmount > (_amount / 5)) {
feeAmount = _amount / 5;
}
if (tokenAddr == ETH_ADDRESS) {
WALLET_ADDR.transfer(feeAmount);
} else {
ERC20(tokenAddr).safeTransfer(WALLET_ADDR, feeAmount);
}
}
function enterMarket(address _cTokenAddrColl, address _cTokenAddrBorrow) internal {
address[] memory markets = new address[](2);
markets[0] = _cTokenAddrColl;
markets[1] = _cTokenAddrBorrow;
ComptrollerInterface(COMPTROLLER).enterMarkets(markets);
}
function approveCToken(address _tokenAddr, address _cTokenAddr) internal {
if (_tokenAddr != ETH_ADDRESS) {
ERC20(_tokenAddr).safeApprove(_cTokenAddr, 0);
ERC20(_tokenAddr).safeApprove(_cTokenAddr, uint(-1));
}
}
function getUnderlyingAddr(address _cTokenAddress) internal returns (address) {
if (_cTokenAddress == CETH_ADDRESS) {
return ETH_ADDRESS;
} else {
return CTokenInterface(_cTokenAddress).underlying();
}
}
function getUserAddress() internal view returns (address) {
DSProxy proxy = DSProxy(uint160(address(this)));
return proxy.owner();
}
function getMaxCollateral(address _cCollAddress, address _account) public returns (uint) {
(, uint liquidityInUsd, ) = ComptrollerInterface(COMPTROLLER).getAccountLiquidity(_account);
uint usersBalance = CTokenInterface(_cCollAddress).balanceOfUnderlying(_account);
address oracle = ComptrollerInterface(COMPTROLLER).oracle();
if (liquidityInUsd == 0) return usersBalance;
CTokenInterface(_cCollAddress).accrueInterest();
(, uint collFactorMantissa) = ComptrollerInterface(COMPTROLLER).markets(_cCollAddress);
Exp memory collateralFactor = Exp({mantissa: collFactorMantissa});
(, uint tokensToUsd) = divScalarByExpTruncate(liquidityInUsd, collateralFactor);
uint usdPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cCollAddress);
uint liqInToken = wdiv(tokensToUsd, usdPrice);
if (liqInToken > usersBalance) return usersBalance;
return sub(liqInToken, (liqInToken / 100));
}
function getMaxBorrow(address _cBorrowAddress, address _account) public returns (uint) {
(, uint liquidityInUsd, ) = ComptrollerInterface(COMPTROLLER).getAccountLiquidity(_account);
address oracle = ComptrollerInterface(COMPTROLLER).oracle();
CTokenInterface(_cBorrowAddress).accrueInterest();
uint usdPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cBorrowAddress);
uint liquidityInToken = wdiv(liquidityInUsd, usdPrice);
return sub(liquidityInToken, (liquidityInToken / 100));
}
}
文件 41 的 152:CompoundSaverProxy.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../exchange/SaverExchangeCore.sol";
import "../../loggers/DefisaverLogger.sol";
import "../helpers/CompoundSaverHelper.sol";
contract CompoundSaverProxy is CompoundSaverHelper, SaverExchangeCore {
DefisaverLogger public constant logger = DefisaverLogger(0x5c55B921f590a89C1Ebe84dF170E655a82b62126);
function repay(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost
) public payable {
enterMarket(_cAddresses[0], _cAddresses[1]);
address payable user = payable(getUserAddress());
uint maxColl = getMaxCollateral(_cAddresses[0], address(this));
uint collAmount = (_exData.srcAmount > maxColl) ? maxColl : _exData.srcAmount;
require(CTokenInterface(_cAddresses[0]).redeemUnderlying(collAmount) == 0);
address collToken = getUnderlyingAddr(_cAddresses[0]);
address borrowToken = getUnderlyingAddr(_cAddresses[1]);
uint swapAmount = 0;
if (collToken != borrowToken) {
(, swapAmount) = _sell(_exData);
swapAmount -= getFee(swapAmount, user, _gasCost, _cAddresses[1]);
} else {
swapAmount = collAmount;
swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]);
}
paybackDebt(swapAmount, _cAddresses[1], borrowToken, user);
tx.origin.transfer(address(this).balance);
logger.Log(address(this), msg.sender, "CompoundRepay", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken));
}
function boost(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost
) public payable {
enterMarket(_cAddresses[0], _cAddresses[1]);
address payable user = payable(getUserAddress());
uint maxBorrow = getMaxBorrow(_cAddresses[1], address(this));
uint borrowAmount = (_exData.srcAmount > maxBorrow) ? maxBorrow : _exData.srcAmount;
require(CTokenInterface(_cAddresses[1]).borrow(borrowAmount) == 0);
address collToken = getUnderlyingAddr(_cAddresses[0]);
address borrowToken = getUnderlyingAddr(_cAddresses[1]);
uint swapAmount = 0;
if (collToken != borrowToken) {
borrowAmount -= getFee(borrowAmount, user, _gasCost, _cAddresses[1]);
_exData.srcAmount = borrowAmount;
(,swapAmount) = _sell(_exData);
} else {
swapAmount = borrowAmount;
swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]);
}
approveCToken(collToken, _cAddresses[0]);
if (collToken != ETH_ADDRESS) {
require(CTokenInterface(_cAddresses[0]).mint(swapAmount) == 0);
} else {
CEtherInterface(_cAddresses[0]).mint{value: swapAmount}();
}
tx.origin.transfer(address(this).balance);
logger.Log(address(this), msg.sender, "CompoundBoost", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken));
}
}
文件 42 的 152:CompoundSavingsProtocol.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../ProtocolInterface.sol";
import "../../interfaces/CTokenInterface.sol";
import "../../compound/helpers/Exponential.sol";
import "../../interfaces/ERC20.sol";
contract CompoundSavingsProtocol {
address public constant NEW_CDAI_ADDRESS = 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
CTokenInterface public constant cDaiContract = CTokenInterface(NEW_CDAI_ADDRESS);
function compDeposit(address _user, uint _amount) internal {
require(ERC20(DAI_ADDRESS).transferFrom(_user, address(this), _amount));
ERC20(DAI_ADDRESS).approve(NEW_CDAI_ADDRESS, uint(-1));
require(cDaiContract.mint(_amount) == 0, "Failed Mint");
}
function compWithdraw(address _user, uint _amount) internal {
require(cDaiContract.transferFrom(_user, address(this), ERC20(NEW_CDAI_ADDRESS).balanceOf(_user)));
cDaiContract.approve(NEW_CDAI_ADDRESS, uint(-1));
require(cDaiContract.redeemUnderlying(_amount) == 0, "Reedem Failed");
uint cDaiBalance = cDaiContract.balanceOf(address(this));
if (cDaiBalance > 0) {
cDaiContract.transfer(_user, cDaiBalance);
}
ERC20(DAI_ADDRESS).transfer(_user, _amount);
}
}
文件 43 的 152:CompoundSubscriptions.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../auth/AdminAuth.sol";
contract CompoundSubscriptions is AdminAuth {
struct CompoundHolder {
address user;
uint128 minRatio;
uint128 maxRatio;
uint128 optimalRatioBoost;
uint128 optimalRatioRepay;
bool boostEnabled;
}
struct SubPosition {
uint arrPos;
bool subscribed;
}
CompoundHolder[] public subscribers;
mapping (address => SubPosition) public subscribersPos;
uint public changeIndex;
event Subscribed(address indexed user);
event Unsubscribed(address indexed user);
event Updated(address indexed user);
event ParamUpdates(address indexed user, uint128, uint128, uint128, uint128, bool);
function subscribe(uint128 _minRatio, uint128 _maxRatio, uint128 _optimalBoost, uint128 _optimalRepay, bool _boostEnabled) external {
uint128 localMaxRatio = _boostEnabled ? _maxRatio : uint128(-1);
require(checkParams(_minRatio, localMaxRatio), "Must be correct params");
SubPosition storage subInfo = subscribersPos[msg.sender];
CompoundHolder memory subscription = CompoundHolder({
minRatio: _minRatio,
maxRatio: localMaxRatio,
optimalRatioBoost: _optimalBoost,
optimalRatioRepay: _optimalRepay,
user: msg.sender,
boostEnabled: _boostEnabled
});
changeIndex++;
if (subInfo.subscribed) {
subscribers[subInfo.arrPos] = subscription;
emit Updated(msg.sender);
emit ParamUpdates(msg.sender, _minRatio, localMaxRatio, _optimalBoost, _optimalRepay, _boostEnabled);
} else {
subscribers.push(subscription);
subInfo.arrPos = subscribers.length - 1;
subInfo.subscribed = true;
emit Subscribed(msg.sender);
}
}
function unsubscribe() external {
_unsubscribe(msg.sender);
}
function checkParams(uint128 _minRatio, uint128 _maxRatio) internal pure returns (bool) {
if (_minRatio > _maxRatio) {
return false;
}
return true;
}
function _unsubscribe(address _user) internal {
require(subscribers.length > 0, "Must have subscribers in the list");
SubPosition storage subInfo = subscribersPos[_user];
require(subInfo.subscribed, "Must first be subscribed");
address lastOwner = subscribers[subscribers.length - 1].user;
SubPosition storage subInfo2 = subscribersPos[lastOwner];
subInfo2.arrPos = subInfo.arrPos;
subscribers[subInfo.arrPos] = subscribers[subscribers.length - 1];
subscribers.pop();
changeIndex++;
subInfo.subscribed = false;
subInfo.arrPos = 0;
emit Unsubscribed(msg.sender);
}
function isSubscribed(address _user) public view returns (bool) {
SubPosition storage subInfo = subscribersPos[_user];
return subInfo.subscribed;
}
function getHolder(address _user) public view returns (CompoundHolder memory) {
SubPosition storage subInfo = subscribersPos[_user];
return subscribers[subInfo.arrPos];
}
function getSubscribers() public view returns (CompoundHolder[] memory) {
return subscribers;
}
function getSubscribersByPage(uint _page, uint _perPage) public view returns (CompoundHolder[] memory) {
CompoundHolder[] memory holders = new CompoundHolder[](_perPage);
uint start = _page * _perPage;
uint end = start + _perPage;
end = (end > holders.length) ? holders.length : end;
uint count = 0;
for (uint i = start; i < end; i++) {
holders[count] = subscribers[i];
count++;
}
return holders;
}
function unsubscribeByAdmin(address _user) public onlyOwner {
SubPosition storage subInfo = subscribersPos[_user];
if (subInfo.subscribed) {
_unsubscribe(_user);
}
}
}
文件 44 的 152:CompoundSubscriptionsProxy.sol
pragma solidity ^0.6.0;
import "../../auth/ProxyPermission.sol";
import "../../interfaces/ICompoundSubscription.sol";
contract CompoundSubscriptionsProxy is ProxyPermission {
address public constant COMPOUND_SUBSCRIPTION_ADDRESS = 0x52015EFFD577E08f498a0CCc11905925D58D6207;
address public constant COMPOUND_MONITOR_PROXY = 0xB1cF8DE8e791E4Ed1Bd86c03E2fc1f14389Cb10a;
function subscribe(
uint128 _minRatio,
uint128 _maxRatio,
uint128 _optimalRatioBoost,
uint128 _optimalRatioRepay,
bool _boostEnabled
) public {
givePermission(COMPOUND_MONITOR_PROXY);
ICompoundSubscription(COMPOUND_SUBSCRIPTION_ADDRESS).subscribe(
_minRatio, _maxRatio, _optimalRatioBoost, _optimalRatioRepay, _boostEnabled);
}
function update(
uint128 _minRatio,
uint128 _maxRatio,
uint128 _optimalRatioBoost,
uint128 _optimalRatioRepay,
bool _boostEnabled
) public {
ICompoundSubscription(COMPOUND_SUBSCRIPTION_ADDRESS).subscribe(_minRatio, _maxRatio, _optimalRatioBoost, _optimalRatioRepay, _boostEnabled);
}
function unsubscribe() public {
removePermission(COMPOUND_MONITOR_PROXY);
ICompoundSubscription(COMPOUND_SUBSCRIPTION_ADDRESS).unsubscribe();
}
}
文件 45 的 152:ComptrollerInterface.sol
pragma solidity ^0.6.0;
abstract contract ComptrollerInterface {
function enterMarkets(address[] calldata cTokens) external virtual returns (uint256[] memory);
function exitMarket(address cToken) external virtual returns (uint256);
function getAssetsIn(address account) external virtual view returns (address[] memory);
function markets(address account) public virtual view returns (bool, uint256);
function getAccountLiquidity(address account) external virtual view returns (uint256, uint256, uint256);
function claimComp(address holder) virtual public;
function oracle() public virtual view returns (address);
}
文件 46 的 152:CreamBasicProxy.sol
pragma solidity ^0.6.0;
import "../utils/GasBurner.sol";
import "../utils/SafeERC20.sol";
import "../interfaces/CTokenInterface.sol";
import "../interfaces/CEtherInterface.sol";
import "../interfaces/ComptrollerInterface.sol";
contract CreamBasicProxy is GasBurner {
address public constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant COMPTROLLER_ADDR = 0x3d5BC3c8d13dcB8bF317092d84783c2697AE9258;
using SafeERC20 for ERC20;
function deposit(address _tokenAddr, address _cTokenAddr, uint _amount, bool _inMarket) public burnGas(5) payable {
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransferFrom(msg.sender, address(this), _amount);
}
approveToken(_tokenAddr, _cTokenAddr);
if (!_inMarket) {
enterMarket(_cTokenAddr);
}
if (_tokenAddr != ETH_ADDR) {
require(CTokenInterface(_cTokenAddr).mint(_amount) == 0);
} else {
CEtherInterface(_cTokenAddr).mint{value: msg.value}();
}
}
function withdraw(address _tokenAddr, address _cTokenAddr, uint _amount, bool _isCAmount) public burnGas(5) {
if (_isCAmount) {
require(CTokenInterface(_cTokenAddr).redeem(_amount) == 0);
} else {
require(CTokenInterface(_cTokenAddr).redeemUnderlying(_amount) == 0);
}
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransfer(msg.sender, ERC20(_tokenAddr).balanceOf(address(this)));
} else {
msg.sender.transfer(address(this).balance);
}
}
function borrow(address _tokenAddr, address _cTokenAddr, uint _amount, bool _inMarket) public burnGas(8) {
if (!_inMarket) {
enterMarket(_cTokenAddr);
}
require(CTokenInterface(_cTokenAddr).borrow(_amount) == 0);
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransfer(msg.sender, ERC20(_tokenAddr).balanceOf(address(this)));
} else {
msg.sender.transfer(address(this).balance);
}
}
function payback(address _tokenAddr, address _cTokenAddr, uint _amount, bool _wholeDebt) public burnGas(5) payable {
approveToken(_tokenAddr, _cTokenAddr);
if (_wholeDebt) {
_amount = CTokenInterface(_cTokenAddr).borrowBalanceCurrent(address(this));
}
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransferFrom(msg.sender, address(this), _amount);
require(CTokenInterface(_cTokenAddr).repayBorrow(_amount) == 0);
} else {
CEtherInterface(_cTokenAddr).repayBorrow{value: msg.value}();
msg.sender.transfer(address(this).balance);
}
}
function withdrawTokens(address _tokenAddr) public {
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeTransfer(msg.sender, ERC20(_tokenAddr).balanceOf(address(this)));
} else {
msg.sender.transfer(address(this).balance);
}
}
function enterMarket(address _cTokenAddr) public {
address[] memory markets = new address[](1);
markets[0] = _cTokenAddr;
ComptrollerInterface(COMPTROLLER_ADDR).enterMarkets(markets);
}
function exitMarket(address _cTokenAddr) public {
ComptrollerInterface(COMPTROLLER_ADDR).exitMarket(_cTokenAddr);
}
function approveToken(address _tokenAddr, address _cTokenAddr) internal {
if (_tokenAddr != ETH_ADDR) {
ERC20(_tokenAddr).safeApprove(_cTokenAddr, 0);
ERC20(_tokenAddr).safeApprove(_cTokenAddr, uint(-1));
}
}
}
文件 47 的 152:CreamFlashLoanTaker.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../utils/GasBurner.sol";
import "../../interfaces/ILendingPool.sol";
import "./CreamSaverProxy.sol";
import "../../loggers/DefisaverLogger.sol";
import "../../auth/ProxyPermission.sol";
contract CreamFlashLoanTaker is CreamSaverProxy, ProxyPermission, GasBurner {
ILendingPool public constant lendingPool = ILendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
address payable public constant COMPOUND_SAVER_FLASH_LOAN = 0xCeB190A35D9D4804b9CE8d0CF79239f6949BfCcB;
function repayWithLoan(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost
) public payable burnGas(25) {
uint maxColl = getMaxCollateral(_cAddresses[0], address(this));
if (_exData.srcAmount <= maxColl) {
repay(_exData, _cAddresses, _gasCost);
} else {
COMPOUND_SAVER_FLASH_LOAN.transfer(msg.value);
uint loanAmount = (_exData.srcAmount - maxColl);
bytes memory encoded = packExchangeData(_exData);
bytes memory paramsData = abi.encode(encoded, _cAddresses, _gasCost, true, address(this));
givePermission(COMPOUND_SAVER_FLASH_LOAN);
lendingPool.flashLoan(COMPOUND_SAVER_FLASH_LOAN, getUnderlyingAddr(_cAddresses[0]), loanAmount, paramsData);
removePermission(COMPOUND_SAVER_FLASH_LOAN);
logger.Log(address(this), msg.sender, "CreamFlashRepay", abi.encode(loanAmount, _exData.srcAmount, _cAddresses[0]));
}
}
function boostWithLoan(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost
) public payable burnGas(20) {
uint maxBorrow = getMaxBorrow(_cAddresses[1], address(this));
if (_exData.srcAmount <= maxBorrow) {
boost(_exData, _cAddresses, _gasCost);
} else {
COMPOUND_SAVER_FLASH_LOAN.transfer(msg.value);
uint loanAmount = (_exData.srcAmount - maxBorrow);
bytes memory paramsData = abi.encode(packExchangeData(_exData), _cAddresses, _gasCost, false, address(this));
givePermission(COMPOUND_SAVER_FLASH_LOAN);
lendingPool.flashLoan(COMPOUND_SAVER_FLASH_LOAN, getUnderlyingAddr(_cAddresses[1]), loanAmount, paramsData);
removePermission(COMPOUND_SAVER_FLASH_LOAN);
logger.Log(address(this), msg.sender, "CreamFlashBoost", abi.encode(loanAmount, _exData.srcAmount, _cAddresses[1]));
}
}
}
文件 48 的 152:CreamLoanInfo.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./CreamSafetyRatio.sol";
import "./helpers/CreamSaverHelper.sol";
contract CreamLoanInfo is CreamSafetyRatio {
struct LoanData {
address user;
uint128 ratio;
address[] collAddr;
address[] borrowAddr;
uint[] collAmounts;
uint[] borrowAmounts;
}
struct TokenInfo {
address cTokenAddress;
address underlyingTokenAddress;
uint collateralFactor;
uint price;
}
struct TokenInfoFull {
address underlyingTokenAddress;
uint supplyRate;
uint borrowRate;
uint exchangeRate;
uint marketLiquidity;
uint totalSupply;
uint totalBorrow;
uint collateralFactor;
uint price;
}
address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant CETH_ADDRESS = 0xD06527D5e56A3495252A528C4987003b712860eE;
function getRatio(address _user) public view returns (uint) {
return getSafetyRatio(_user);
}
function getPrices(address[] memory _cTokens) public view returns (uint[] memory prices) {
prices = new uint[](_cTokens.length);
address oracleAddr = comp.oracle();
for (uint i = 0; i < _cTokens.length; ++i) {
prices[i] = CompoundOracleInterface(oracleAddr).getUnderlyingPrice(_cTokens[i]);
}
}
function getCollFactors(address[] memory _cTokens) public view returns (uint[] memory collFactors) {
collFactors = new uint[](_cTokens.length);
for (uint i = 0; i < _cTokens.length; ++i) {
(, collFactors[i]) = comp.markets(_cTokens[i]);
}
}
function getLoanData(address _user) public view returns (LoanData memory data) {
address[] memory assets = comp.getAssetsIn(_user);
address oracleAddr = comp.oracle();
data = LoanData({
user: _user,
ratio: 0,
collAddr: new address[](assets.length),
borrowAddr: new address[](assets.length),
collAmounts: new uint[](assets.length),
borrowAmounts: new uint[](assets.length)
});
uint collPos = 0;
uint borrowPos = 0;
for (uint i = 0; i < assets.length; i++) {
address asset = assets[i];
(, uint cTokenBalance, uint borrowBalance, uint exchangeRateMantissa)
= CTokenInterface(asset).getAccountSnapshot(_user);
Exp memory oraclePrice;
if (cTokenBalance != 0 || borrowBalance != 0) {
oraclePrice = Exp({mantissa: CompoundOracleInterface(oracleAddr).getUnderlyingPrice(asset)});
}
if (cTokenBalance != 0) {
Exp memory exchangeRate = Exp({mantissa: exchangeRateMantissa});
(, Exp memory tokensToEth) = mulExp(exchangeRate, oraclePrice);
data.collAddr[collPos] = asset;
(, data.collAmounts[collPos]) = mulScalarTruncate(tokensToEth, cTokenBalance);
collPos++;
}
if (borrowBalance != 0) {
data.borrowAddr[borrowPos] = asset;
(, data.borrowAmounts[borrowPos]) = mulScalarTruncate(oraclePrice, borrowBalance);
borrowPos++;
}
}
data.ratio = uint128(getSafetyRatio(_user));
return data;
}
function getTokenBalances(address _user, address[] memory _cTokens) public view returns (uint[] memory balances, uint[] memory borrows) {
balances = new uint[](_cTokens.length);
borrows = new uint[](_cTokens.length);
for (uint i = 0; i < _cTokens.length; i++) {
address asset = _cTokens[i];
(, uint cTokenBalance, uint borrowBalance, uint exchangeRateMantissa)
= CTokenInterface(asset).getAccountSnapshot(_user);
Exp memory exchangeRate = Exp({mantissa: exchangeRateMantissa});
(, balances[i]) = mulScalarTruncate(exchangeRate, cTokenBalance);
borrows[i] = borrowBalance;
}
}
function getLoanDataArr(address[] memory _users) public view returns (LoanData[] memory loans) {
loans = new LoanData[](_users.length);
for (uint i = 0; i < _users.length; ++i) {
loans[i] = getLoanData(_users[i]);
}
}
function getRatios(address[] memory _users) public view returns (uint[] memory ratios) {
ratios = new uint[](_users.length);
for (uint i = 0; i < _users.length; ++i) {
ratios[i] = getSafetyRatio(_users[i]);
}
}
function getTokensInfo(address[] memory _cTokenAddresses) public returns(TokenInfo[] memory tokens) {
tokens = new TokenInfo[](_cTokenAddresses.length);
address oracleAddr = comp.oracle();
for (uint i = 0; i < _cTokenAddresses.length; ++i) {
(, uint collFactor) = comp.markets(_cTokenAddresses[i]);
tokens[i] = TokenInfo({
cTokenAddress: _cTokenAddresses[i],
underlyingTokenAddress: getUnderlyingAddr(_cTokenAddresses[i]),
collateralFactor: collFactor,
price: CompoundOracleInterface(oracleAddr).getUnderlyingPrice(_cTokenAddresses[i])
});
}
}
function getFullTokensInfo(address[] memory _cTokenAddresses) public returns(TokenInfoFull[] memory tokens) {
tokens = new TokenInfoFull[](_cTokenAddresses.length);
address oracleAddr = comp.oracle();
for (uint i = 0; i < _cTokenAddresses.length; ++i) {
(, uint collFactor) = comp.markets(_cTokenAddresses[i]);
CTokenInterface cToken = CTokenInterface(_cTokenAddresses[i]);
tokens[i] = TokenInfoFull({
underlyingTokenAddress: getUnderlyingAddr(_cTokenAddresses[i]),
supplyRate: cToken.supplyRatePerBlock(),
borrowRate: cToken.borrowRatePerBlock(),
exchangeRate: cToken.exchangeRateCurrent(),
marketLiquidity: cToken.getCash(),
totalSupply: cToken.totalSupply(),
totalBorrow: cToken.totalBorrowsCurrent(),
collateralFactor: collFactor,
price: CompoundOracleInterface(oracleAddr).getUnderlyingPrice(_cTokenAddresses[i])
});
}
}
function getUnderlyingAddr(address _cTokenAddress) internal returns (address) {
if (_cTokenAddress == CETH_ADDRESS) {
return ETH_ADDRESS;
} else {
return CTokenInterface(_cTokenAddress).underlying();
}
}
}
文件 49 的 152:CreamSafetyRatio.sol
pragma solidity ^0.6.0;
import "../DS/DSMath.sol";
import "../interfaces/CompoundOracleInterface.sol";
import "../interfaces/ComptrollerInterface.sol";
import "../interfaces/CTokenInterface.sol";
import "../compound/helpers/Exponential.sol";
contract CreamSafetyRatio is Exponential, DSMath {
ComptrollerInterface public constant comp = ComptrollerInterface(0x3d5BC3c8d13dcB8bF317092d84783c2697AE9258);
function getSafetyRatio(address _user) public view returns (uint) {
address[] memory assets = comp.getAssetsIn(_user);
address oracleAddr = comp.oracle();
uint sumCollateral = 0;
uint sumBorrow = 0;
for (uint i = 0; i < assets.length; i++) {
address asset = assets[i];
(, uint cTokenBalance, uint borrowBalance, uint exchangeRateMantissa)
= CTokenInterface(asset).getAccountSnapshot(_user);
Exp memory oraclePrice;
if (cTokenBalance != 0 || borrowBalance != 0) {
oraclePrice = Exp({mantissa: CompoundOracleInterface(oracleAddr).getUnderlyingPrice(asset)});
}
if (cTokenBalance != 0) {
(, uint collFactorMantissa) = comp.markets(address(asset));
Exp memory collateralFactor = Exp({mantissa: collFactorMantissa});
Exp memory exchangeRate = Exp({mantissa: exchangeRateMantissa});
(, Exp memory tokensToEther) = mulExp3(collateralFactor, exchangeRate, oraclePrice);
(, sumCollateral) = mulScalarTruncateAddUInt(tokensToEther, cTokenBalance, sumCollateral);
}
if (borrowBalance != 0) {
(, sumBorrow) = mulScalarTruncateAddUInt(oraclePrice, borrowBalance, sumBorrow);
}
}
if (sumBorrow == 0) return uint(-1);
uint borrowPowerUsed = (sumBorrow * 10**18) / sumCollateral;
return wdiv(1e18, borrowPowerUsed);
}
}
文件 50 的 152:CreamSaverFlashLoan.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../utils/FlashLoanReceiverBase.sol";
import "../../interfaces/DSProxyInterface.sol";
import "../../exchange/SaverExchangeCore.sol";
contract CreamSaverFlashLoan is FlashLoanReceiverBase, SaverExchangeCore {
ILendingPoolAddressesProvider public LENDING_POOL_ADDRESS_PROVIDER = ILendingPoolAddressesProvider(0x24a42fD28C976A61Df5D00D0599C34c4f90748c8);
address payable public COMPOUND_SAVER_FLASH_PROXY = 0xcEAb38B5C88F33Dabe4D31BDD384E08215526632;
address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public owner;
using SafeERC20 for ERC20;
constructor()
FlashLoanReceiverBase(LENDING_POOL_ADDRESS_PROVIDER)
public {
owner = msg.sender;
}
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params)
external override {
(bytes memory proxyData, address payable proxyAddr) = packFunctionCall(_amount, _fee, _params);
sendLoanToProxy(proxyAddr, _reserve, _amount);
DSProxyInterface(proxyAddr).execute(COMPOUND_SAVER_FLASH_PROXY, proxyData);
transferFundsBackToPoolInternal(_reserve, _amount.add(_fee));
if (address(this).balance > 0) {
tx.origin.transfer(address(this).balance);
}
}
function packFunctionCall(uint _amount, uint _fee, bytes memory _params) internal pure returns (bytes memory proxyData, address payable) {
(
bytes memory exDataBytes,
address[2] memory cAddresses,
uint256 gasCost,
bool isRepay,
address payable proxyAddr
)
= abi.decode(_params, (bytes,address[2],uint256,bool,address));
ExchangeData memory _exData = unpackExchangeData(exDataBytes);
uint[2] memory flashLoanData = [_amount, _fee];
if (isRepay) {
proxyData = abi.encodeWithSignature("flashRepay((address,address,uint256,uint256,uint256,address,address,bytes,uint256),address[2],uint256,uint256[2])", _exData, cAddresses, gasCost, flashLoanData);
} else {
proxyData = abi.encodeWithSignature("flashBoost((address,address,uint256,uint256,uint256,address,address,bytes,uint256),address[2],uint256,uint256[2])", _exData, cAddresses, gasCost, flashLoanData);
}
return (proxyData, proxyAddr);
}
function sendLoanToProxy(address payable _proxy, address _reserve, uint _amount) internal {
if (_reserve != ETH_ADDRESS) {
ERC20(_reserve).safeTransfer(_proxy, _amount);
}
_proxy.transfer(address(this).balance);
}
receive() external override(SaverExchangeCore, FlashLoanReceiverBase) payable {}
}
文件 51 的 152:CreamSaverFlashProxy.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../utils/SafeERC20.sol";
import "../../exchange/SaverExchangeCore.sol";
import "../../interfaces/CTokenInterface.sol";
import "../../utils/Discount.sol";
import "../helpers/CreamSaverHelper.sol";
import "../../loggers/DefisaverLogger.sol";
contract CreamSaverFlashProxy is SaverExchangeCore, CreamSaverHelper {
address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
using SafeERC20 for ERC20;
function flashRepay(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost,
uint[2] memory _flashLoanData
) public payable {
enterMarket(_cAddresses[0], _cAddresses[1]);
address payable user = payable(getUserAddress());
uint flashBorrowed = _flashLoanData[0] + _flashLoanData[1];
uint maxColl = getMaxCollateral(_cAddresses[0], address(this));
require(CTokenInterface(_cAddresses[0]).redeemUnderlying(maxColl) == 0);
address collToken = getUnderlyingAddr(_cAddresses[0]);
address borrowToken = getUnderlyingAddr(_cAddresses[1]);
uint swapAmount = 0;
if (collToken != borrowToken) {
_exData.srcAmount = maxColl + _flashLoanData[0];
(,swapAmount) = _sell(_exData);
swapAmount -= getFee(swapAmount, user, _gasCost, _cAddresses[1]);
} else {
swapAmount = (maxColl + _flashLoanData[0]);
swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]);
}
paybackDebt(swapAmount, _cAddresses[1], borrowToken, user);
require(CTokenInterface(_cAddresses[0]).redeemUnderlying(flashBorrowed) == 0);
returnFlashLoan(collToken, flashBorrowed);
DefisaverLogger(DEFISAVER_LOGGER).Log(address(this), msg.sender, "CreamRepay", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken));
}
function flashBoost(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost,
uint[2] memory _flashLoanData
) public payable {
enterMarket(_cAddresses[0], _cAddresses[1]);
address payable user = payable(getUserAddress());
uint flashBorrowed = _flashLoanData[0] + _flashLoanData[1];
uint borrowAmount = getMaxBorrow(_cAddresses[1], address(this));
require(CTokenInterface(_cAddresses[1]).borrow(borrowAmount) == 0);
address collToken = getUnderlyingAddr(_cAddresses[0]);
address borrowToken = getUnderlyingAddr(_cAddresses[1]);
uint swapAmount = 0;
if (collToken != borrowToken) {
borrowAmount -= getFee((borrowAmount + _flashLoanData[0]), user, _gasCost, _cAddresses[1]);
_exData.srcAmount = (borrowAmount + _flashLoanData[0]);
(,swapAmount) = _sell(_exData);
} else {
swapAmount = (borrowAmount + _flashLoanData[0]);
swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]);
}
depositCollateral(collToken, _cAddresses[0], swapAmount);
require(CTokenInterface(_cAddresses[1]).borrow(flashBorrowed) == 0);
returnFlashLoan(borrowToken, flashBorrowed);
DefisaverLogger(DEFISAVER_LOGGER).Log(address(this), msg.sender, "CreamBoost", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken));
}
function depositCollateral(address _collToken, address _cCollToken, uint _depositAmount) internal {
approveCToken(_collToken, _cCollToken);
if (_collToken != ETH_ADDRESS) {
require(CTokenInterface(_cCollToken).mint(_depositAmount) == 0);
} else {
CEtherInterface(_cCollToken).mint{value: _depositAmount}();
}
}
function returnFlashLoan(address _tokenAddr, uint _amount) internal {
if (_tokenAddr != ETH_ADDRESS) {
ERC20(_tokenAddr).safeTransfer(msg.sender, _amount);
}
msg.sender.transfer(address(this).balance);
}
}
文件 52 的 152:CreamSaverHelper.sol
pragma solidity ^0.6.0;
import "../../interfaces/CEtherInterface.sol";
import "../../interfaces/CompoundOracleInterface.sol";
import "../../interfaces/CTokenInterface.sol";
import "../../interfaces/ComptrollerInterface.sol";
import "../../utils/Discount.sol";
import "../../DS/DSMath.sol";
import "../../DS/DSProxy.sol";
import "../../compound/helpers/Exponential.sol";
import "../../utils/BotRegistry.sol";
import "../../utils/SafeERC20.sol";
contract CreamSaverHelper is DSMath, Exponential {
using SafeERC20 for ERC20;
address payable public constant WALLET_ADDR = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08;
address public constant DISCOUNT_ADDR = 0x1b14E8D511c9A4395425314f849bD737BAF8208F;
uint public constant MANUAL_SERVICE_FEE = 400;
uint public constant AUTOMATIC_SERVICE_FEE = 333;
address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant CETH_ADDRESS = 0xD06527D5e56A3495252A528C4987003b712860eE;
address public constant COMPTROLLER = 0x3d5BC3c8d13dcB8bF317092d84783c2697AE9258;
address public constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B;
function paybackDebt(uint _amount, address _cBorrowToken, address _borrowToken, address payable _user) internal {
uint wholeDebt = CTokenInterface(_cBorrowToken).borrowBalanceCurrent(address(this));
if (_amount > wholeDebt) {
if (_borrowToken == ETH_ADDRESS) {
_user.transfer((_amount - wholeDebt));
} else {
ERC20(_borrowToken).safeTransfer(_user, (_amount - wholeDebt));
}
_amount = wholeDebt;
}
approveCToken(_borrowToken, _cBorrowToken);
if (_borrowToken == ETH_ADDRESS) {
CEtherInterface(_cBorrowToken).repayBorrow{value: _amount}();
} else {
require(CTokenInterface(_cBorrowToken).repayBorrow(_amount) == 0);
}
}
function getFee(uint _amount, address _user, uint _gasCost, address _cTokenAddr) internal returns (uint feeAmount) {
uint fee = MANUAL_SERVICE_FEE;
if (BotRegistry(BOT_REGISTRY_ADDRESS).botList(tx.origin)) {
fee = AUTOMATIC_SERVICE_FEE;
}
address tokenAddr = getUnderlyingAddr(_cTokenAddr);
if (Discount(DISCOUNT_ADDR).isCustomFeeSet(_user)) {
fee = Discount(DISCOUNT_ADDR).getCustomServiceFee(_user);
}
feeAmount = (fee == 0) ? 0 : (_amount / fee);
if (_gasCost != 0) {
address oracle = ComptrollerInterface(COMPTROLLER).oracle();
uint ethTokenPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cTokenAddr);
_gasCost = wdiv(_gasCost, ethTokenPrice);
feeAmount = add(feeAmount, _gasCost);
}
if (feeAmount > (_amount / 5)) {
feeAmount = _amount / 5;
}
if (tokenAddr == ETH_ADDRESS) {
WALLET_ADDR.transfer(feeAmount);
} else {
ERC20(tokenAddr).safeTransfer(WALLET_ADDR, feeAmount);
}
}
function getGasCost(uint _amount, uint _gasCost, address _cTokenAddr) internal returns (uint feeAmount) {
address tokenAddr = getUnderlyingAddr(_cTokenAddr);
if (_gasCost != 0) {
address oracle = ComptrollerInterface(COMPTROLLER).oracle();
uint ethTokenPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cTokenAddr);
feeAmount = wdiv(_gasCost, ethTokenPrice);
}
if (feeAmount > (_amount / 5)) {
feeAmount = _amount / 5;
}
if (tokenAddr == ETH_ADDRESS) {
WALLET_ADDR.transfer(feeAmount);
} else {
ERC20(tokenAddr).safeTransfer(WALLET_ADDR, feeAmount);
}
}
function enterMarket(address _cTokenAddrColl, address _cTokenAddrBorrow) internal {
address[] memory markets = new address[](2);
markets[0] = _cTokenAddrColl;
markets[1] = _cTokenAddrBorrow;
ComptrollerInterface(COMPTROLLER).enterMarkets(markets);
}
function approveCToken(address _tokenAddr, address _cTokenAddr) internal {
if (_tokenAddr != ETH_ADDRESS) {
ERC20(_tokenAddr).safeApprove(_cTokenAddr, 0);
ERC20(_tokenAddr).safeApprove(_cTokenAddr, uint(-1));
}
}
function getUnderlyingAddr(address _cTokenAddress) internal returns (address) {
if (_cTokenAddress == CETH_ADDRESS) {
return ETH_ADDRESS;
} else {
return CTokenInterface(_cTokenAddress).underlying();
}
}
function getUserAddress() internal view returns (address) {
DSProxy proxy = DSProxy(uint160(address(this)));
return proxy.owner();
}
function getMaxCollateral(address _cCollAddress, address _account) public returns (uint) {
(, uint liquidityInEth, ) = ComptrollerInterface(COMPTROLLER).getAccountLiquidity(_account);
uint usersBalance = CTokenInterface(_cCollAddress).balanceOfUnderlying(_account);
address oracle = ComptrollerInterface(COMPTROLLER).oracle();
if (liquidityInEth == 0) return usersBalance;
CTokenInterface(_cCollAddress).accrueInterest();
if (_cCollAddress == CETH_ADDRESS) {
if (liquidityInEth > usersBalance) return usersBalance;
return sub(liquidityInEth, (liquidityInEth / 100));
}
uint ethPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cCollAddress);
uint liquidityInToken = wdiv(liquidityInEth, ethPrice);
if (liquidityInToken > usersBalance) return usersBalance;
return sub(liquidityInToken, (liquidityInToken / 100));
}
function getMaxBorrow(address _cBorrowAddress, address _account) public returns (uint) {
(, uint liquidityInEth, ) = ComptrollerInterface(COMPTROLLER).getAccountLiquidity(_account);
address oracle = ComptrollerInterface(COMPTROLLER).oracle();
CTokenInterface(_cBorrowAddress).accrueInterest();
if (_cBorrowAddress == CETH_ADDRESS) return sub(liquidityInEth, (liquidityInEth / 100));
uint ethPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cBorrowAddress);
uint liquidityInToken = wdiv(liquidityInEth, ethPrice);
return sub(liquidityInToken, (liquidityInToken / 100));
}
}
文件 53 的 152:CreamSaverProxy.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../exchange/SaverExchangeCore.sol";
import "../../loggers/DefisaverLogger.sol";
import "../helpers/CreamSaverHelper.sol";
contract CreamSaverProxy is CreamSaverHelper, SaverExchangeCore {
DefisaverLogger public constant logger = DefisaverLogger(0x5c55B921f590a89C1Ebe84dF170E655a82b62126);
function repay(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost
) public payable {
enterMarket(_cAddresses[0], _cAddresses[1]);
address payable user = payable(getUserAddress());
uint maxColl = getMaxCollateral(_cAddresses[0], address(this));
uint collAmount = (_exData.srcAmount > maxColl) ? maxColl : _exData.srcAmount;
require(CTokenInterface(_cAddresses[0]).redeemUnderlying(collAmount) == 0);
address collToken = getUnderlyingAddr(_cAddresses[0]);
address borrowToken = getUnderlyingAddr(_cAddresses[1]);
uint swapAmount = 0;
if (collToken != borrowToken) {
(, swapAmount) = _sell(_exData);
swapAmount -= getFee(swapAmount, user, _gasCost, _cAddresses[1]);
} else {
swapAmount = collAmount;
swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]);
}
paybackDebt(swapAmount, _cAddresses[1], borrowToken, user);
tx.origin.transfer(address(this).balance);
logger.Log(address(this), msg.sender, "CreamRepay", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken));
}
function boost(
ExchangeData memory _exData,
address[2] memory _cAddresses,
uint256 _gasCost
) public payable {
enterMarket(_cAddresses[0], _cAddresses[1]);
address payable user = payable(getUserAddress());
uint maxBorrow = getMaxBorrow(_cAddresses[1], address(this));
uint borrowAmount = (_exData.srcAmount > maxBorrow) ? maxBorrow : _exData.srcAmount;
require(CTokenInterface(_cAddresses[1]).borrow(borrowAmount) == 0);
address collToken = getUnderlyingAddr(_cAddresses[0]);
address borrowToken = getUnderlyingAddr(_cAddresses[1]);
uint swapAmount = 0;
if (collToken != borrowToken) {
borrowAmount -= getFee(borrowAmount, user, _gasCost, _cAddresses[1]);
_exData.srcAmount = borrowAmount;
(,swapAmount) = _sell(_exData);
} else {
swapAmount = borrowAmount;
swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]);
}
approveCToken(collToken, _cAddresses[0]);
if (collToken != ETH_ADDRESS) {
require(CTokenInterface(_cAddresses[0]).mint(swapAmount) == 0);
} else {
CEtherInterface(_cAddresses[0]).mint{value: swapAmount}();
}
tx.origin.transfer(address(this).balance);
logger.Log(address(this), msg.sender, "CreamBoost", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken));
}
}
文件 54 的 152:DFSProxy.sol
pragma solidity ^0.6.0;
import "../auth/Auth.sol";
import "../interfaces/DSProxyInterface.sol";
contract DFSProxy is Auth {
string public constant NAME = "DFSProxy";
string public constant VERSION = "v0.1";
mapping(address => mapping(uint => bool)) public nonces;
bytes32 public DOMAIN_SEPARATOR;
bytes32 public constant PERMIT_TYPEHASH = keccak256("callProxy(address _user,address _proxy,address _contract,bytes _txData,uint256 _nonce)");
constructor(uint256 chainId_) public {
DOMAIN_SEPARATOR = keccak256(abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(NAME)),
keccak256(bytes(VERSION)),
chainId_,
address(this)
));
}
function callProxy(address _user, address _proxy, address _contract, bytes calldata _txData, uint256 _nonce,
uint8 _v, bytes32 _r, bytes32 _s) external payable onlyAuthorized
{
bytes32 digest =
keccak256(abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH,
_user,
_proxy,
_contract,
_txData,
_nonce))
));
require(DSProxyInterface(_proxy).owner() == _user);
require(_user == ecrecover(digest, _v, _r, _s), "DFSProxy/user-not-valid");
require(!nonces[_user][_nonce], "DFSProxy/invalid-nonce");
nonces[_user][_nonce] = true;
DSProxyInterface(_proxy).execute{value: msg.value}(_contract, _txData);
}
}
文件 55 的 152:DSAuth.sol
pragma solidity ^0.6.0;
import "./DSAuthority.sol";
contract DSAuthEvents {
event LogSetAuthority(address indexed authority);
event LogSetOwner(address indexed owner);
}
contract DSAuth is DSAuthEvents {
DSAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_) public auth {
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(DSAuthority authority_) public auth {
authority = authority_;
emit LogSetAuthority(address(authority));
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == address(this)) {
return true;
} else if (src == owner) {
return true;
} else if (authority == DSAuthority(0)) {
return false;
} else {
return authority.canCall(src, address(this), sig);
}
}
}
文件 56 的 152:DSAuthority.sol
pragma solidity ^0.6.0;
abstract contract DSAuthority {
function canCall(address src, address dst, bytes4 sig) public virtual view returns (bool);
}
文件 57 的 152:DSGuard.sol
pragma solidity ^0.6.0;
abstract contract DSGuard {
function canCall(address src_, address dst_, bytes4 sig) public view virtual returns (bool);
function permit(bytes32 src, bytes32 dst, bytes32 sig) public virtual;
function forbid(bytes32 src, bytes32 dst, bytes32 sig) public virtual;
function permit(address src, address dst, bytes32 sig) public virtual;
function forbid(address src, address dst, bytes32 sig) public virtual;
}
abstract contract DSGuardFactory {
function newGuard() public virtual returns (DSGuard guard);
}
文件 58 的 152:DSMath.sol
pragma solidity ^0.6.0;
contract DSMath {
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x + y) >= x);
}
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x - y) <= x);
}
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x);
}
function div(uint256 x, uint256 y) internal pure returns (uint256 z) {
return x / y;
}
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
return x <= y ? x : y;
}
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
return x >= y ? x : y;
}
function imin(int256 x, int256 y) internal pure returns (int256 z) {
return x <= y ? x : y;
}
function imax(int256 x, int256 y) internal pure returns (int256 z) {
return x >= y ? x : y;
}
uint256 constant WAD = 10**18;
uint256 constant RAY = 10**27;
function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, WAD), y / 2) / y;
}
function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, RAY), y / 2) / y;
}
function rpow(uint256 x, uint256 n) internal pure returns (uint256 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);
}
}
}
}
文件 59 的 152:DSNote.sol
pragma solidity ^0.6.0;
contract DSNote {
event LogNote(
bytes4 indexed sig,
address indexed guy,
bytes32 indexed foo,
bytes32 indexed bar,
uint256 wad,
bytes fax
) anonymous;
modifier note {
bytes32 foo;
bytes32 bar;
assembly {
foo := calldataload(4)
bar := calldataload(36)
}
emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
_;
}
}
文件 60 的 152:DSProxy.sol
pragma solidity ^0.6.0;
import "./DSAuth.sol";
import "./DSNote.sol";
abstract contract DSProxy is DSAuth, DSNote {
DSProxyCache public cache;
constructor(address _cacheAddr) public {
require(setCache(_cacheAddr));
}
receive() external payable {}
function execute(address _target, bytes memory _data)
public
payable
virtual
returns (bytes32 response);
function setCache(address _cacheAddr) public virtual payable returns (bool);
}
contract DSProxyCache {
mapping(bytes32 => address) cache;
function read(bytes memory _code) public view returns (address) {
bytes32 hash = keccak256(_code);
return cache[hash];
}
function write(bytes memory _code) public returns (address target) {
assembly {
target := create(0, add(_code, 0x20), mload(_code))
switch iszero(extcodesize(target))
case 1 {
revert(0, 0)
}
}
bytes32 hash = keccak256(_code);
cache[hash] = target;
}
}
文件 61 的 152:DSProxyFactoryInterface.sol
pragma solidity ^0.6.0;
import "./DSProxy.sol";
abstract contract DSProxyFactoryInterface {
function build(address owner) public virtual returns (DSProxy proxy);
}
文件 62 的 152:DSProxyInterface.sol
pragma solidity ^0.6.0;
abstract contract DSProxyInterface {
function execute(address _target, bytes memory _data) public virtual payable returns (bytes32);
function setCache(address _cacheAddr) public virtual payable returns (bool);
function owner() public virtual returns (address);
}
文件 63 的 152:DSRSavingsProtocol.sol
pragma solidity ^0.6.0;
import "../../interfaces/Join.sol";
import "../../DS/DSMath.sol";
abstract contract VatLike {
function can(address, address) virtual public view returns (uint);
function ilks(bytes32) virtual public view returns (uint, uint, uint, uint, uint);
function dai(address) virtual public view returns (uint);
function urns(bytes32, address) virtual public view returns (uint, uint);
function frob(bytes32, address, address, address, int, int) virtual public;
function hope(address) virtual public;
function move(address, address, uint) virtual public;
}
abstract contract PotLike {
function pie(address) virtual public view returns (uint);
function drip() virtual public returns (uint);
function join(uint) virtual public;
function exit(uint) virtual public;
}
abstract contract GemLike {
function approve(address, uint) virtual public;
function transfer(address, uint) virtual public;
function transferFrom(address, address, uint) virtual public;
function deposit() virtual public payable;
function withdraw(uint) virtual public;
}
abstract contract DaiJoinLike {
function vat() virtual public returns (VatLike);
function dai() virtual public returns (GemLike);
function join(address, uint) virtual public payable;
function exit(address, uint) virtual public;
}
contract DSRSavingsProtocol is DSMath {
address public constant POT_ADDRESS = 0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7;
address public constant DAI_JOIN_ADDRESS = 0x9759A6Ac90977b93B58547b4A71c78317f391A28;
function dsrDeposit(uint _amount, bool _fromUser) internal {
VatLike vat = DaiJoinLike(DAI_JOIN_ADDRESS).vat();
uint chi = PotLike(POT_ADDRESS).drip();
daiJoin_join(DAI_JOIN_ADDRESS, address(this), _amount, _fromUser);
if (vat.can(address(this), address(POT_ADDRESS)) == 0) {
vat.hope(POT_ADDRESS);
}
PotLike(POT_ADDRESS).join(mul(_amount, RAY) / chi);
}
function dsrWithdraw(uint _amount, bool _toUser) internal {
VatLike vat = DaiJoinLike(DAI_JOIN_ADDRESS).vat();
uint chi = PotLike(POT_ADDRESS).drip();
uint pie = mul(_amount, RAY) / chi;
PotLike(POT_ADDRESS).exit(pie);
uint balance = DaiJoinLike(DAI_JOIN_ADDRESS).vat().dai(address(this));
if (vat.can(address(this), address(DAI_JOIN_ADDRESS)) == 0) {
vat.hope(DAI_JOIN_ADDRESS);
}
address to;
if (_toUser) {
to = msg.sender;
} else {
to = address(this);
}
if (_amount == uint(-1)) {
DaiJoinLike(DAI_JOIN_ADDRESS).exit(to, mul(chi, pie) / RAY);
} else {
DaiJoinLike(DAI_JOIN_ADDRESS).exit(
to,
balance >= mul(_amount, RAY) ? _amount : balance / RAY
);
}
}
function daiJoin_join(address apt, address urn, uint wad, bool _fromUser) internal {
if (_fromUser) {
DaiJoinLike(apt).dai().transferFrom(msg.sender, address(this), wad);
}
DaiJoinLike(apt).dai().approve(apt, wad);
DaiJoinLike(apt).join(urn, wad);
}
}
文件 64 的 152:DSSProxyActions.sol
pragma solidity ^0.6.0;
abstract contract GemLike {
function approve(address, uint) public virtual;
function transfer(address, uint) public virtual;
function transferFrom(address, address, uint) public virtual;
function deposit() public virtual payable;
function withdraw(uint) public virtual;
}
abstract contract ManagerLike {
function cdpCan(address, uint, address) public virtual view returns (uint);
function ilks(uint) public virtual view returns (bytes32);
function owns(uint) public virtual view returns (address);
function urns(uint) public virtual view returns (address);
function vat() public virtual view returns (address);
function open(bytes32) public virtual returns (uint);
function give(uint, address) public virtual;
function cdpAllow(uint, address, uint) public virtual;
function urnAllow(address, uint) public virtual;
function frob(uint, int, int) public virtual;
function frob(uint, address, int, int) public virtual;
function flux(uint, address, uint) public virtual;
function move(uint, address, uint) public virtual;
function exit(address, uint, address, uint) public virtual;
function quit(uint, address) public virtual;
function enter(address, uint) public virtual;
function shift(uint, uint) public virtual;
}
abstract contract VatLike {
function can(address, address) public virtual view returns (uint);
function ilks(bytes32) public virtual view returns (uint, uint, uint, uint, uint);
function dai(address) public virtual view returns (uint);
function urns(bytes32, address) public virtual view returns (uint, uint);
function frob(bytes32, address, address, address, int, int) public virtual;
function hope(address) public virtual;
function move(address, address, uint) public virtual;
}
abstract contract GemJoinLike {
function dec() public virtual returns (uint);
function gem() public virtual returns (GemLike);
function join(address, uint) public virtual payable;
function exit(address, uint) public virtual;
}
abstract contract GNTJoinLike {
function bags(address) public virtual view returns (address);
function make(address) public virtual returns (address);
}
abstract contract DaiJoinLike {
function vat() public virtual returns (VatLike);
function dai() public virtual returns (GemLike);
function join(address, uint) public virtual payable;
function exit(address, uint) public virtual;
}
abstract contract HopeLike {
function hope(address) public virtual;
function nope(address) public virtual;
}
abstract contract EndLike {
function fix(bytes32) public virtual view returns (uint);
function cash(bytes32, uint) public virtual;
function free(bytes32) public virtual;
function pack(uint) public virtual;
function skim(bytes32, address) public virtual;
}
abstract contract JugLike {
function drip(bytes32) public virtual;
}
abstract contract PotLike {
function chi() public virtual view returns (uint);
function pie(address) public virtual view returns (uint);
function drip() public virtual;
function join(uint) public virtual;
function exit(uint) public virtual;
}
abstract contract ProxyRegistryLike {
function proxies(address) public virtual view returns (address);
function build(address) public virtual returns (address);
}
abstract contract ProxyLike {
function owner() public virtual view returns (address);
}
abstract contract DssProxyActions {
function daiJoin_join(address apt, address urn, uint wad) public virtual;
function transfer(address gem, address dst, uint wad) public virtual;
function ethJoin_join(address apt, address urn) public virtual payable;
function gemJoin_join(address apt, address urn, uint wad, bool transferFrom) public virtual payable;
function hope(address obj, address usr) public virtual;
function nope(address obj, address usr) public virtual;
function open(address manager, bytes32 ilk, address usr) public virtual returns (uint cdp);
function give(address manager, uint cdp, address usr) public virtual;
function giveToProxy(address proxyRegistry, address manager, uint cdp, address dst) public virtual;
function cdpAllow(address manager, uint cdp, address usr, uint ok) public virtual;
function urnAllow(address manager, address usr, uint ok) public virtual;
function flux(address manager, uint cdp, address dst, uint wad) public virtual;
function move(address manager, uint cdp, address dst, uint rad) public virtual;
function frob(address manager, uint cdp, int dink, int dart) public virtual;
function frob(address manager, uint cdp, address dst, int dink, int dart) public virtual;
function quit(address manager, uint cdp, address dst) public virtual;
function enter(address manager, address src, uint cdp) public virtual;
function shift(address manager, uint cdpSrc, uint cdpOrg) public virtual;
function makeGemBag(address gemJoin) public virtual returns (address bag);
function lockETH(address manager, address ethJoin, uint cdp) public virtual payable;
function safeLockETH(address manager, address ethJoin, uint cdp, address owner) public virtual payable;
function lockGem(address manager, address gemJoin, uint cdp, uint wad, bool transferFrom) public virtual;
function safeLockGem(address manager, address gemJoin, uint cdp, uint wad, bool transferFrom, address owner) public virtual;
function freeETH(address manager, address ethJoin, uint cdp, uint wad) public virtual;
function freeGem(address manager, address gemJoin, uint cdp, uint wad) public virtual;
function draw(address manager, address jug, address daiJoin, uint cdp, uint wad) public virtual;
function wipe(address manager, address daiJoin, uint cdp, uint wad) public virtual;
function safeWipe(address manager, address daiJoin, uint cdp, uint wad, address owner) public virtual;
function wipeAll(address manager, address daiJoin, uint cdp) public virtual;
function safeWipeAll(address manager, address daiJoin, uint cdp, address owner) public virtual;
function lockETHAndDraw(address manager, address jug, address ethJoin, address daiJoin, uint cdp, uint wadD) public virtual payable;
function openLockETHAndDraw(address manager, address jug, address ethJoin, address daiJoin, bytes32 ilk, uint wadD) public virtual payable returns (uint cdp);
function lockGemAndDraw(address manager, address jug, address gemJoin, address daiJoin, uint cdp, uint wadC, uint wadD, bool transferFrom) public virtual;
function openLockGemAndDraw(address manager, address jug, address gemJoin, address daiJoin, bytes32 ilk, uint wadC, uint wadD, bool transferFrom) public virtual returns (uint cdp);
function openLockGNTAndDraw(address manager, address jug, address gntJoin, address daiJoin, bytes32 ilk, uint wadC, uint wadD) public virtual returns (address bag, uint cdp);
function wipeAndFreeETH(address manager, address ethJoin, address daiJoin, uint cdp, uint wadC, uint wadD) public virtual;
function wipeAllAndFreeETH(address manager, address ethJoin, address daiJoin, uint cdp, uint wadC) public virtual;
function wipeAndFreeGem(address manager, address gemJoin, address daiJoin, uint cdp, uint wadC, uint wadD) public virtual;
function wipeAllAndFreeGem(address manager, address gemJoin, address daiJoin, uint cdp, uint wadC) public virtual;
}
文件 65 的 152:DaiJoin.sol
pragma solidity ^0.6.0;
import "./Vat.sol";
import "./Gem.sol";
abstract contract DaiJoin {
function vat() public virtual returns (Vat);
function dai() public virtual returns (Gem);
function join(address, uint) public virtual payable;
function exit(address, uint) public virtual;
}
文件 66 的 152:DebugInfo.sol
pragma solidity ^0.6.0;
contract DebugInfo {
mapping (string => uint) public uintValues;
mapping (string => address) public addrValues;
mapping (string => string) public stringValues;
mapping (string => bytes32) public bytes32Values;
function logUint(string memory _id, uint _value) public {
uintValues[_id] = _value;
}
function logAddr(string memory _id, address _value) public {
addrValues[_id] = _value;
}
function logString(string memory _id, string memory _value) public {
stringValues[_id] = _value;
}
function logBytes32(string memory _id, bytes32 _value) public {
bytes32Values[_id] = _value;
}
}
文件 67 的 152:DefisaverLogger.sol
pragma solidity ^0.6.0;
contract DefisaverLogger {
event LogEvent(
address indexed contractAddress,
address indexed caller,
string indexed logName,
bytes data
);
function Log(address _contract, address _caller, string memory _logName, bytes memory _data)
public
{
emit LogEvent(_contract, _caller, _logName, _data);
}
}
文件 68 的 152:Discount.sol
pragma solidity ^0.6.0;
contract Discount {
address public owner;
mapping(address => CustomServiceFee) public serviceFees;
uint256 constant MAX_SERVICE_FEE = 400;
struct CustomServiceFee {
bool active;
uint256 amount;
}
constructor() public {
owner = msg.sender;
}
function isCustomFeeSet(address _user) public view returns (bool) {
return serviceFees[_user].active;
}
function getCustomServiceFee(address _user) public view returns (uint256) {
return serviceFees[_user].amount;
}
function setServiceFee(address _user, uint256 _fee) public {
require(msg.sender == owner, "Only owner");
require(_fee >= MAX_SERVICE_FEE || _fee == 0);
serviceFees[_user] = CustomServiceFee({active: true, amount: _fee});
}
function disableServiceFee(address _user) public {
require(msg.sender == owner, "Only owner");
serviceFees[_user] = CustomServiceFee({active: false, amount: 0});
}
}
文件 69 的 152:DssProxyActionsDsr.sol
pragma solidity ^0.6.0;
abstract contract DssProxyActionsDsr {
function join(address daiJoin, address pot, uint wad) virtual public;
function exit(address daiJoin, address pot, uint wad) virtual public;
function exitAll(address daiJoin, address pot) virtual public;
}
文件 70 的 152:DydxFlashLoanBase.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../savings/dydx/ISoloMargin.sol";
contract DydxFlashLoanBase {
using SafeMath for uint256;
address public constant SOLO_MARGIN_ADDRESS = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
function _getMarketIdFromTokenAddress(address token)
internal
view
returns (uint256)
{
return 0;
}
function _getRepaymentAmountInternal(uint256 amount)
internal
view
returns (uint256)
{
return amount.add(2);
}
function _getAccountInfo() internal view returns (Account.Info memory) {
return Account.Info({owner: address(this), number: 1});
}
function _getWithdrawAction(uint marketId, uint256 amount, address contractAddr)
internal
view
returns (Actions.ActionArgs memory)
{
return
Actions.ActionArgs({
actionType: Actions.ActionType.Withdraw,
accountId: 0,
amount: Types.AssetAmount({
sign: false,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: amount
}),
primaryMarketId: marketId,
secondaryMarketId: 0,
otherAddress: contractAddr,
otherAccountId: 0,
data: ""
});
}
function _getCallAction(bytes memory data, address contractAddr)
internal
view
returns (Actions.ActionArgs memory)
{
return
Actions.ActionArgs({
actionType: Actions.ActionType.Call,
accountId: 0,
amount: Types.AssetAmount({
sign: false,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: 0
}),
primaryMarketId: 0,
secondaryMarketId: 0,
otherAddress: contractAddr,
otherAccountId: 0,
data: data
});
}
function _getDepositAction(uint marketId, uint256 amount, address contractAddr)
internal
view
returns (Actions.ActionArgs memory)
{
return
Actions.ActionArgs({
actionType: Actions.ActionType.Deposit,
accountId: 0,
amount: Types.AssetAmount({
sign: true,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: amount
}),
primaryMarketId: marketId,
secondaryMarketId: 0,
otherAddress: contractAddr,
otherAccountId: 0,
data: ""
});
}
}
文件 71 的 152:DydxFlashLoanTaker.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../auth/ProxyPermission.sol";
import "../utils/DydxFlashLoanBase.sol";
import "../loggers/DefisaverLogger.sol";
import "../interfaces/ERC20.sol";
contract DyDxFlashLoanTaker is DydxFlashLoanBase, ProxyPermission {
address public constant WETH_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
function takeLoan(address _receiver, uint256 _ethAmount, bytes memory _encodedData) public {
ISoloMargin solo = ISoloMargin(SOLO_MARGIN_ADDRESS);
uint256 marketId = _getMarketIdFromTokenAddress(WETH_ADDR);
uint256 repayAmount = _getRepaymentAmountInternal(_ethAmount);
ERC20(WETH_ADDR).approve(SOLO_MARGIN_ADDRESS, repayAmount);
Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);
operations[0] = _getWithdrawAction(marketId, _ethAmount, _receiver);
operations[1] = _getCallAction(
_encodedData,
_receiver
);
operations[2] = _getDepositAction(marketId, repayAmount, address(this));
Account.Info[] memory accountInfos = new Account.Info[](1);
accountInfos[0] = _getAccountInfo();
givePermission(_receiver);
solo.operate(accountInfos, operations);
removePermission(_receiver);
DefisaverLogger(DEFISAVER_LOGGER).Log(address(this), msg.sender, "DyDxFlashLoanTaken", abi.encode(_receiver, _ethAmount, _encodedData));
}
}
文件 72 的 152:DydxSavingsProtocol.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../ProtocolInterface.sol";
import "./ISoloMargin.sol";
import "../../interfaces/ERC20.sol";
import "../../DS/DSAuth.sol";
contract DydxSavingsProtocol is ProtocolInterface, DSAuth {
address public constant SOLO_MARGIN_ADDRESS = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
ISoloMargin public soloMargin;
address public savingsProxy;
uint daiMarketId = 3;
constructor() public {
soloMargin = ISoloMargin(SOLO_MARGIN_ADDRESS);
}
function addSavingsProxy(address _savingsProxy) public auth {
savingsProxy = _savingsProxy;
}
function deposit(address _user, uint _amount) public override {
require(msg.sender == _user);
Account.Info[] memory accounts = new Account.Info[](1);
accounts[0] = getAccount(_user, 0);
Actions.ActionArgs[] memory actions = new Actions.ActionArgs[](1);
Types.AssetAmount memory amount = Types.AssetAmount({
sign: true,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: _amount
});
actions[0] = Actions.ActionArgs({
actionType: Actions.ActionType.Deposit,
accountId: 0,
amount: amount,
primaryMarketId: daiMarketId,
otherAddress: _user,
secondaryMarketId: 0,
otherAccountId: 0,
data: ""
});
soloMargin.operate(accounts, actions);
}
function withdraw(address _user, uint _amount) public override {
require(msg.sender == _user);
Account.Info[] memory accounts = new Account.Info[](1);
accounts[0] = getAccount(_user, 0);
Actions.ActionArgs[] memory actions = new Actions.ActionArgs[](1);
Types.AssetAmount memory amount = Types.AssetAmount({
sign: false,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: _amount
});
actions[0] = Actions.ActionArgs({
actionType: Actions.ActionType.Withdraw,
accountId: 0,
amount: amount,
primaryMarketId: daiMarketId,
otherAddress: _user,
secondaryMarketId: 0,
otherAccountId: 0,
data: ""
});
soloMargin.operate(accounts, actions);
}
function getWeiBalance(address _user, uint _index) public view returns(Types.Wei memory) {
Types.Wei[] memory weiBalances;
(,,weiBalances) = soloMargin.getAccountBalances(getAccount(_user, _index));
return weiBalances[daiMarketId];
}
function getParBalance(address _user, uint _index) public view returns(Types.Par memory) {
Types.Par[] memory parBalances;
(,parBalances,) = soloMargin.getAccountBalances(getAccount(_user, _index));
return parBalances[daiMarketId];
}
function getAccount(address _user, uint _index) public pure returns(Account.Info memory) {
Account.Info memory account = Account.Info({
owner: _user,
number: _index
});
return account;
}
}
文件 73 的 152:ERC20.sol
pragma solidity ^0.6.0;
interface ERC20 {
function totalSupply() external view returns (uint256 supply);
function balanceOf(address _owner) external view returns (uint256 balance);
function transfer(address _to, uint256 _value) external returns (bool success);
function transferFrom(address _from, address _to, uint256 _value)
external
returns (bool success);
function approve(address _spender, uint256 _value) external returns (bool success);
function allowance(address _owner, address _spender) external view returns (uint256 remaining);
function decimals() external view returns (uint256 digits);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
文件 74 的 152:ExchangeDataParser.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../exchange/SaverExchangeCore.sol";
contract ExchangeDataParser {
function decodeExchangeData(
SaverExchangeCore.ExchangeData memory exchangeData
) internal pure returns (address[4] memory, uint[4] memory, bytes memory) {
return (
[exchangeData.srcAddr, exchangeData.destAddr, exchangeData.exchangeAddr, exchangeData.wrapper],
[exchangeData.srcAmount, exchangeData.destAmount, exchangeData.minPrice, exchangeData.price0x],
exchangeData.callData
);
}
function encodeExchangeData(
address[4] memory exAddr, uint[4] memory exNum, bytes memory callData
) internal pure returns (SaverExchangeCore.ExchangeData memory) {
return SaverExchangeCore.ExchangeData({
srcAddr: exAddr[0],
destAddr: exAddr[1],
srcAmount: exNum[0],
destAmount: exNum[1],
minPrice: exNum[2],
wrapper: exAddr[3],
exchangeAddr: exAddr[2],
callData: callData,
price0x: exNum[3]
});
}
}
文件 75 的 152:ExchangeInterface.sol
pragma solidity ^0.6.0;
import "./ERC20.sol";
interface ExchangeInterface {
function swapEtherToToken(uint256 _ethAmount, address _tokenAddress, uint256 _maxAmount)
external
payable
returns (uint256, uint256);
function swapTokenToEther(address _tokenAddress, uint256 _amount, uint256 _maxAmount)
external
returns (uint256);
function swapTokenToToken(address _src, address _dest, uint256 _amount)
external
payable
returns (uint256);
function getExpectedRate(address src, address dest, uint256 srcQty)
external
view
returns (uint256 expectedRate);
}
文件 76 的 152:ExchangeInterfaceV2.sol
pragma solidity ^0.6.0;
interface ExchangeInterfaceV2 {
function sell(address _srcAddr, address _destAddr, uint _srcAmount) external payable returns (uint);
function buy(address _srcAddr, address _destAddr, uint _destAmount) external payable returns(uint);
function getSellRate(address _srcAddr, address _destAddr, uint _srcAmount) external view returns (uint);
function getBuyRate(address _srcAddr, address _destAddr, uint _srcAmount) external view returns (uint);
}
文件 77 的 152:Exponential.sol
pragma solidity ^0.6.0;
import "./CarefulMath.sol";
contract Exponential is CarefulMath {
uint constant expScale = 1e18;
uint constant halfExpScale = expScale/2;
uint constant mantissaOne = expScale;
struct Exp {
uint mantissa;
}
function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) {
(MathError err0, uint scaledNumerator) = mulUInt(num, expScale);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
(MathError err1, uint rational) = divUInt(scaledNumerator, denom);
if (err1 != MathError.NO_ERROR) {
return (err1, Exp({mantissa: 0}));
}
return (MathError.NO_ERROR, Exp({mantissa: rational}));
}
function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
(MathError error, uint result) = addUInt(a.mantissa, b.mantissa);
return (error, Exp({mantissa: result}));
}
function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
(MathError error, uint result) = subUInt(a.mantissa, b.mantissa);
return (error, Exp({mantissa: result}));
}
function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
(MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));
}
function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) {
(MathError err, Exp memory product) = mulScalar(a, scalar);
if (err != MathError.NO_ERROR) {
return (err, 0);
}
return (MathError.NO_ERROR, truncate(product));
}
function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) {
(MathError err, Exp memory product) = mulScalar(a, scalar);
if (err != MathError.NO_ERROR) {
return (err, 0);
}
return addUInt(truncate(product), addend);
}
function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
(MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));
}
function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) {
(MathError err0, uint numerator) = mulUInt(expScale, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
return getExp(numerator, divisor.mantissa);
}
function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) {
(MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);
if (err != MathError.NO_ERROR) {
return (err, 0);
}
return (MathError.NO_ERROR, truncate(fraction));
}
function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
(MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
(MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);
if (err1 != MathError.NO_ERROR) {
return (err1, Exp({mantissa: 0}));
}
(MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);
assert(err2 == MathError.NO_ERROR);
return (MathError.NO_ERROR, Exp({mantissa: product}));
}
function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) {
return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));
}
function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) {
(MathError err, Exp memory ab) = mulExp(a, b);
if (err != MathError.NO_ERROR) {
return (err, ab);
}
return mulExp(ab, c);
}
function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
return getExp(a.mantissa, b.mantissa);
}
function truncate(Exp memory exp) pure internal returns (uint) {
return exp.mantissa / expScale;
}
function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
return left.mantissa < right.mantissa;
}
function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {
return left.mantissa <= right.mantissa;
}
function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
return left.mantissa > right.mantissa;
}
function isZeroExp(Exp memory value) pure internal returns (bool) {
return value.mantissa == 0;
}
}
文件 78 的 152:Faucet.sol
pragma solidity ^0.6.0;
abstract contract Faucet {
function gulp(address) public virtual;
}
文件 79 的 152:FlashLoanReceiverBase.sol
pragma solidity ^0.6.0;
import "./SafeERC20.sol";
interface IFlashLoanReceiver {
function executeOperation(address _reserve, uint256 _amount, uint256 _fee, bytes calldata _params) external;
}
abstract contract ILendingPoolAddressesProvider {
function getLendingPool() public view virtual returns (address);
function setLendingPoolImpl(address _pool) public virtual;
function getLendingPoolCore() public virtual view returns (address payable);
function setLendingPoolCoreImpl(address _lendingPoolCore) public virtual;
function getLendingPoolConfigurator() public virtual view returns (address);
function setLendingPoolConfiguratorImpl(address _configurator) public virtual;
function getLendingPoolDataProvider() public virtual view returns (address);
function setLendingPoolDataProviderImpl(address _provider) public virtual;
function getLendingPoolParametersProvider() public virtual view returns (address);
function setLendingPoolParametersProviderImpl(address _parametersProvider) public virtual;
function getTokenDistributor() public virtual view returns (address);
function setTokenDistributor(address _tokenDistributor) public virtual;
function getFeeProvider() public virtual view returns (address);
function setFeeProviderImpl(address _feeProvider) public virtual;
function getLendingPoolLiquidationManager() public virtual view returns (address);
function setLendingPoolLiquidationManager(address _manager) public virtual;
function getLendingPoolManager() public virtual view returns (address);
function setLendingPoolManager(address _lendingPoolManager) public virtual;
function getPriceOracle() public virtual view returns (address);
function setPriceOracle(address _priceOracle) public virtual;
function getLendingRateOracle() public view virtual returns (address);
function setLendingRateOracle(address _lendingRateOracle) public virtual;
}
library EthAddressLib {
function ethAddress() internal pure returns(address) {
return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
}
}
abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
using SafeERC20 for ERC20;
using SafeMath for uint256;
ILendingPoolAddressesProvider public addressesProvider;
constructor(ILendingPoolAddressesProvider _provider) public {
addressesProvider = _provider;
}
receive () external virtual payable {}
function transferFundsBackToPoolInternal(address _reserve, uint256 _amount) internal {
address payable core = addressesProvider.getLendingPoolCore();
transferInternal(core,_reserve, _amount);
}
function transferInternal(address payable _destination, address _reserve, uint256 _amount) internal {
if(_reserve == EthAddressLib.ethAddress()) {
_destination.call{value: _amount}("");
return;
}
ERC20(_reserve).safeTransfer(_destination, _amount);
}
function getBalanceInternal(address _target, address _reserve) internal view returns(uint256) {
if(_reserve == EthAddressLib.ethAddress()) {
return _target.balance;
}
return ERC20(_reserve).balanceOf(_target);
}
}
文件 80 的 152:Flipper.sol
pragma solidity ^0.6.0;
abstract contract Flipper {
function bids(uint _bidId) public virtual returns (uint256, uint256, address, uint48, uint48, address, address, uint256);
function tend(uint id, uint lot, uint bid) virtual external;
function dent(uint id, uint lot, uint bid) virtual external;
function deal(uint id) virtual external;
}
文件 81 的 152:FulcrumSavingsProtocol.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../ProtocolInterface.sol";
import "../../interfaces/ERC20.sol";
import "../../interfaces/ITokenInterface.sol";
import "../../DS/DSAuth.sol";
contract FulcrumSavingsProtocol is ProtocolInterface, DSAuth {
address public constant NEW_IDAI_ADDRESS = 0x493C57C4763932315A328269E1ADaD09653B9081;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address public savingsProxy;
uint public decimals = 10 ** 18;
function addSavingsProxy(address _savingsProxy) public auth {
savingsProxy = _savingsProxy;
}
function deposit(address _user, uint _amount) public override {
require(msg.sender == _user);
require(ERC20(DAI_ADDRESS).transferFrom(_user, address(this), _amount));
ERC20(DAI_ADDRESS).approve(NEW_IDAI_ADDRESS, uint(-1));
ITokenInterface(NEW_IDAI_ADDRESS).mint(_user, _amount);
}
function withdraw(address _user, uint _amount) public override {
require(msg.sender == _user);
require(ERC20(NEW_IDAI_ADDRESS).transferFrom(_user, address(this), ITokenInterface(NEW_IDAI_ADDRESS).balanceOf(_user)));
ERC20(NEW_IDAI_ADDRESS).approve(NEW_IDAI_ADDRESS, uint(-1));
uint tokenPrice = ITokenInterface(NEW_IDAI_ADDRESS).tokenPrice();
ITokenInterface(NEW_IDAI_ADDRESS).burn(_user, _amount * decimals / tokenPrice);
require(ERC20(NEW_IDAI_ADDRESS).transfer(_user, ITokenInterface(NEW_IDAI_ADDRESS).balanceOf(address(this))));
}
}
文件 82 的 152:GasBurner.sol
pragma solidity ^0.6.0;
import "../interfaces/GasTokenInterface.sol";
contract GasBurner {
GasTokenInterface public constant gasToken = GasTokenInterface(0x0000000000b3F879cb30FE243b4Dfee438691c04);
modifier burnGas(uint _amount) {
if (gasToken.balanceOf(address(this)) >= _amount) {
gasToken.free(_amount);
}
_;
}
}
文件 83 的 152:GasTokenInterface.sol
pragma solidity ^0.6.0;
import "./ERC20.sol";
abstract contract GasTokenInterface is ERC20 {
function free(uint256 value) public virtual returns (bool success);
function freeUpTo(uint256 value) public virtual returns (uint256 freed);
function freeFrom(address from, uint256 value) public virtual returns (bool success);
function freeFromUpTo(address from, uint256 value) public virtual returns (uint256 freed);
}
文件 84 的 152:Gem.sol
pragma solidity ^0.6.0;
abstract contract Gem {
function dec() virtual public returns (uint);
function gem() virtual public returns (Gem);
function join(address, uint) virtual public payable;
function exit(address, uint) virtual public;
function approve(address, uint) virtual public;
function transfer(address, uint) virtual public returns (bool);
function transferFrom(address, address, uint) virtual public returns (bool);
function deposit() virtual public payable;
function withdraw(uint) virtual public;
function allowance(address, address) virtual public returns (uint);
}
文件 85 的 152:GetCdps.sol
pragma solidity ^0.6.0;
abstract contract GetCdps {
function getCdpsAsc(address manager, address guy) external view virtual returns (uint[] memory ids, address[] memory urns, bytes32[] memory ilks);
function getCdpsDesc(address manager, address guy) external view virtual returns (uint[] memory ids, address[] memory urns, bytes32[] memory ilks);
}
文件 86 的 152:IAToken.sol
pragma solidity ^0.6.0;
abstract contract IAToken {
function redeem(uint256 _amount) external virtual;
}
文件 87 的 152:IAaveSubscription.sol
pragma solidity ^0.6.0;
abstract contract IAaveSubscription {
function subscribe(uint128 _minRatio, uint128 _maxRatio, uint128 _optimalBoost, uint128 _optimalRepay, bool _boostEnabled) public virtual;
function unsubscribe() public virtual;
}
文件 88 的 152:ICompoundSubscription.sol
pragma solidity ^0.6.0;
abstract contract ICompoundSubscription {
function subscribe(uint128 _minRatio, uint128 _maxRatio, uint128 _optimalBoost, uint128 _optimalRepay, bool _boostEnabled) public virtual;
function unsubscribe() public virtual;
}
文件 89 的 152:ILendingPool.sol
pragma solidity ^0.6.0;
abstract contract ILendingPool {
function flashLoan( address payable _receiver, address _reserve, uint _amount, bytes calldata _params) external virtual;
function deposit(address _reserve, uint256 _amount, uint16 _referralCode) external virtual payable;
function setUserUseReserveAsCollateral(address _reserve, bool _useAsCollateral) external virtual;
function borrow(address _reserve, uint256 _amount, uint256 _interestRateMode, uint16 _referralCode) external virtual;
function repay( address _reserve, uint256 _amount, address payable _onBehalfOf) external virtual payable;
function swapBorrowRateMode(address _reserve) external virtual;
function getReserves() external virtual view returns(address[] memory);
function getReserveData(address _reserve)
external virtual
view
returns (
uint256 totalLiquidity,
uint256 availableLiquidity,
uint256 totalBorrowsStable,
uint256 totalBorrowsVariable,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 utilizationRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
address aTokenAddress,
uint40 lastUpdateTimestamp
);
function getUserAccountData(address _user)
external virtual
view
returns (
uint256 totalLiquidityETH,
uint256 totalCollateralETH,
uint256 totalBorrowsETH,
uint256 totalFeesETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
function getUserReserveData(address _reserve, address _user)
external virtual
view
returns (
uint256 currentATokenBalance,
uint256 currentBorrowBalance,
uint256 principalBorrowBalance,
uint256 borrowRateMode,
uint256 borrowRate,
uint256 liquidityRate,
uint256 originationFee,
uint256 variableBorrowIndex,
uint256 lastUpdateTimestamp,
bool usageAsCollateralEnabled
);
function getReserveConfigurationData(address _reserve)
external virtual
view
returns (
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus,
address rateStrategyAddress,
bool usageAsCollateralEnabled,
bool borrowingEnabled,
bool stableBorrowRateEnabled,
bool isActive
);
function getReserveATokenAddress(address _reserve) public virtual view returns (address);
function getReserveConfiguration(address _reserve)
external virtual
view
returns (uint256, uint256, uint256, bool);
function getUserUnderlyingAssetBalance(address _reserve, address _user)
public virtual
view
returns (uint256);
function getReserveCurrentLiquidityRate(address _reserve)
public virtual
view
returns (uint256);
function getReserveCurrentVariableBorrowRate(address _reserve)
public virtual
view
returns (uint256);
function getReserveTotalLiquidity(address _reserve)
public virtual
view
returns (uint256);
function getReserveAvailableLiquidity(address _reserve)
public virtual
view
returns (uint256);
function getReserveTotalBorrowsVariable(address _reserve)
public virtual
view
returns (uint256);
function calculateUserGlobalData(address _user)
public virtual
view
returns (
uint256 totalLiquidityBalanceETH,
uint256 totalCollateralBalanceETH,
uint256 totalBorrowBalanceETH,
uint256 totalFeesETH,
uint256 currentLtv,
uint256 currentLiquidationThreshold,
uint256 healthFactor,
bool healthFactorBelowThreshold
);
}
文件 90 的 152:ILendingPoolAddressesProvider.sol
pragma solidity ^0.6.0;
abstract contract ILendingPoolAddressesProvider {
function getLendingPool() public virtual view returns (address);
function getLendingPoolCore() public virtual view returns (address payable);
function getLendingPoolConfigurator() public virtual view returns (address);
function getLendingPoolDataProvider() public virtual view returns (address);
function getLendingPoolParametersProvider() public virtual view returns (address);
function getTokenDistributor() public virtual view returns (address);
function getFeeProvider() public virtual view returns (address);
function getLendingPoolLiquidationManager() public virtual view returns (address);
function getLendingPoolManager() public virtual view returns (address);
function getPriceOracle() public virtual view returns (address);
function getLendingRateOracle() public virtual view returns (address);
}
文件 91 的 152:ILoanShifter.sol
pragma solidity ^0.6.0;
abstract contract ILoanShifter {
function getLoanAmount(uint, address) public view virtual returns(uint);
function getUnderlyingAsset(address _addr) public view virtual returns (address);
}
文件 92 的 152:IPriceOracleGetterAave.sol
pragma solidity ^0.6.0;
abstract contract IPriceOracleGetterAave {
function getAssetPrice(address _asset) external virtual view returns (uint256);
function getAssetsPrices(address[] calldata _assets) external virtual view returns(uint256[] memory);
function getSourceOfAsset(address _asset) external virtual view returns(address);
function getFallbackOracle() external virtual view returns(address);
}
文件 93 的 152:ISoloMargin.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./lib/Actions.sol";
import "./lib/Account.sol";
import "./lib/Types.sol";
abstract contract ISoloMargin {
struct OperatorArg {
address operator;
bool trusted;
}
function operate(
Account.Info[] memory accounts,
Actions.ActionArgs[] memory actions
) public virtual;
function getAccountBalances(
Account.Info memory account
) public view virtual returns (
address[] memory,
Types.Par[] memory,
Types.Wei[] memory
);
function setOperators(
OperatorArg[] memory args
) public virtual;
function getNumMarkets() public view virtual returns (uint256);
function getMarketTokenAddress(uint256 marketId)
public
view
virtual
returns (address);
}
文件 94 的 152:ISubscriptionsV2.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./StaticV2.sol";
abstract contract ISubscriptionsV2 is StaticV2 {
function getOwner(uint _cdpId) external view virtual returns(address);
function getSubscribedInfo(uint _cdpId) public view virtual returns(bool, uint128, uint128, uint128, uint128, address, uint coll, uint debt);
function getCdpHolder(uint _cdpId) public view virtual returns (bool subscribed, CdpHolder memory);
}
文件 95 的 152:ITokenInterface.sol
pragma solidity ^0.6.0;
import "./ERC20.sol";
abstract contract ITokenInterface is ERC20 {
function assetBalanceOf(address _owner) public virtual view returns (uint256);
function mint(address receiver, uint256 depositAmount) external virtual returns (uint256 mintAmount);
function burn(address receiver, uint256 burnAmount) external virtual returns (uint256 loanAmountPaid);
function tokenPrice() public virtual view returns (uint256 price);
}
文件 96 的 152:Join.sol
pragma solidity ^0.6.0;
import "./Gem.sol";
abstract contract Join {
bytes32 public ilk;
function dec() virtual public view returns (uint);
function gem() virtual public view returns (Gem);
function join(address, uint) virtual public payable;
function exit(address, uint) virtual public;
}
文件 97 的 152:Jug.sol
pragma solidity ^0.6.0;
abstract contract Jug {
struct Ilk {
uint256 duty;
uint256 rho;
}
mapping (bytes32 => Ilk) public ilks;
function drip(bytes32) public virtual returns (uint);
}
文件 98 的 152:KyberNetworkProxyInterface.sol
pragma solidity ^0.6.0;
import "./ERC20.sol";
abstract contract KyberNetworkProxyInterface {
function maxGasPrice() external virtual view returns (uint256);
function getUserCapInWei(address user) external virtual view returns (uint256);
function getUserCapInTokenWei(address user, ERC20 token) external virtual view returns (uint256);
function enabled() external virtual view returns (bool);
function info(bytes32 id) external virtual view returns (uint256);
function getExpectedRate(ERC20 src, ERC20 dest, uint256 srcQty)
public virtual
view
returns (uint256 expectedRate, uint256 slippageRate);
function tradeWithHint(
ERC20 src,
uint256 srcAmount,
ERC20 dest,
address destAddress,
uint256 maxDestAmount,
uint256 minConversionRate,
address walletId,
bytes memory hint
) public virtual payable returns (uint256);
function trade(
ERC20 src,
uint256 srcAmount,
ERC20 dest,
address destAddress,
uint256 maxDestAmount,
uint256 minConversionRate,
address walletId
) public virtual payable returns (uint256);
function swapEtherToToken(ERC20 token, uint256 minConversionRate)
external virtual
payable
returns (uint256);
function swapTokenToEther(ERC20 token, uint256 tokenQty, uint256 minRate)
external virtual
payable
returns (uint256);
function swapTokenToToken(ERC20 src, uint256 srcAmount, ERC20 dest, uint256 minConversionRate)
public virtual
returns (uint256);
}
文件 99 的 152:KyberWrapper.sol
pragma solidity ^0.6.0;
import "../../utils/SafeERC20.sol";
import "../../interfaces/KyberNetworkProxyInterface.sol";
import "../../interfaces/ExchangeInterfaceV2.sol";
import "../../DS/DSMath.sol";
import "../../auth/AdminAuth.sol";
contract KyberWrapper is DSMath, ExchangeInterfaceV2, AdminAuth {
address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant KYBER_INTERFACE = 0x9AAb3f75489902f3a48495025729a0AF77d4b11e;
address payable public constant WALLET_ID = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08;
using SafeERC20 for ERC20;
function sell(address _srcAddr, address _destAddr, uint _srcAmount) external override payable returns (uint) {
ERC20 srcToken = ERC20(_srcAddr);
ERC20 destToken = ERC20(_destAddr);
KyberNetworkProxyInterface kyberNetworkProxy = KyberNetworkProxyInterface(KYBER_INTERFACE);
if (_srcAddr != KYBER_ETH_ADDRESS) {
srcToken.safeApprove(address(kyberNetworkProxy), _srcAmount);
}
uint destAmount = kyberNetworkProxy.trade{value: msg.value}(
srcToken,
_srcAmount,
destToken,
msg.sender,
uint(-1),
0,
WALLET_ID
);
return destAmount;
}
function buy(address _srcAddr, address _destAddr, uint _destAmount) external override payable returns(uint) {
ERC20 srcToken = ERC20(_srcAddr);
ERC20 destToken = ERC20(_destAddr);
uint srcAmount = 0;
if (_srcAddr != KYBER_ETH_ADDRESS) {
srcAmount = srcToken.balanceOf(address(this));
} else {
srcAmount = msg.value;
}
KyberNetworkProxyInterface kyberNetworkProxy = KyberNetworkProxyInterface(KYBER_INTERFACE);
if (_srcAddr != KYBER_ETH_ADDRESS) {
srcToken.safeApprove(address(kyberNetworkProxy), srcAmount);
}
uint destAmount = kyberNetworkProxy.trade{value: msg.value}(
srcToken,
srcAmount,
destToken,
msg.sender,
_destAmount,
0,
WALLET_ID
);
require(destAmount == _destAmount, "Wrong dest amount");
uint srcAmountAfter = 0;
if (_srcAddr != KYBER_ETH_ADDRESS) {
srcAmountAfter = srcToken.balanceOf(address(this));
} else {
srcAmountAfter = address(this).balance;
}
sendLeftOver(_srcAddr);
return (srcAmount - srcAmountAfter);
}
function getSellRate(address _srcAddr, address _destAddr, uint _srcAmount) public override view returns (uint rate) {
(rate, ) = KyberNetworkProxyInterface(KYBER_INTERFACE)
.getExpectedRate(ERC20(_srcAddr), ERC20(_destAddr), _srcAmount);
rate = rate * (10**(18 - getDecimals(_srcAddr)));
rate = rate / (10**(18 - getDecimals(_destAddr)));
}
function getBuyRate(address _srcAddr, address _destAddr, uint _destAmount) public override view returns (uint rate) {
uint256 srcRate = getSellRate(_destAddr, _srcAddr, _destAmount);
uint256 srcAmount = wmul(srcRate, _destAmount);
rate = getSellRate(_srcAddr, _destAddr, srcAmount);
rate = rate + (rate / 30);
}
function sendLeftOver(address _srcAddr) internal {
msg.sender.transfer(address(this).balance);
if (_srcAddr != KYBER_ETH_ADDRESS) {
ERC20(_srcAddr).safeTransfer(msg.sender, ERC20(_srcAddr).balanceOf(address(this)));
}
}
receive() payable external {}
function getDecimals(address _token) internal view returns (uint256) {
if (_token == KYBER_ETH_ADDRESS) return 18;
return ERC20(_token).decimals();
}
}
文件 100 的 152:LoanShifterReceiver.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../auth/AdminAuth.sol";
import "../utils/FlashLoanReceiverBase.sol";
import "../interfaces/DSProxyInterface.sol";
import "../exchange/SaverExchangeCore.sol";
import "./ShifterRegistry.sol";
contract LoanShifterReceiver is SaverExchangeCore, FlashLoanReceiverBase, AdminAuth {
ILendingPoolAddressesProvider public LENDING_POOL_ADDRESS_PROVIDER = ILendingPoolAddressesProvider(0x24a42fD28C976A61Df5D00D0599C34c4f90748c8);
address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
ShifterRegistry public constant shifterRegistry = ShifterRegistry(0x597C52281b31B9d949a9D8fEbA08F7A2530a965e);
struct ParamData {
bytes proxyData1;
bytes proxyData2;
address proxy;
address debtAddr;
uint8 protocol1;
uint8 protocol2;
uint8 swapType;
}
constructor() FlashLoanReceiverBase(LENDING_POOL_ADDRESS_PROVIDER) public {}
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params)
external override {
(ParamData memory paramData, ExchangeData memory exchangeData)
= packFunctionCall(_amount, _fee, _params);
address protocolAddr1 = shifterRegistry.getAddr(getNameByProtocol(paramData.protocol1));
address protocolAddr2 = shifterRegistry.getAddr(getNameByProtocol(paramData.protocol2));
sendToProxy(payable(paramData.proxy), _reserve, _amount);
DSProxyInterface(paramData.proxy).execute(protocolAddr1, paramData.proxyData1);
if (paramData.swapType == 1) {
exchangeData.srcAmount = getBalance(exchangeData.srcAddr);
(, uint amount) = _sell(exchangeData);
sendToProxy(payable(paramData.proxy), exchangeData.destAddr, amount);
} else if (paramData.swapType == 2) {
exchangeData.destAmount = (_amount + _fee);
_buy(exchangeData);
sendToProxy(payable(paramData.proxy), exchangeData.srcAddr, ERC20(exchangeData.srcAddr).balanceOf(address(this)));
} else {
sendToProxy(payable(paramData.proxy), exchangeData.srcAddr, getBalance(exchangeData.srcAddr));
}
DSProxyInterface(paramData.proxy).execute(protocolAddr2, paramData.proxyData2);
transferFundsBackToPoolInternal(_reserve, _amount.add(_fee));
if (address(this).balance > 0) {
tx.origin.transfer(address(this).balance);
}
}
function packFunctionCall(uint _amount, uint _fee, bytes memory _params)
internal pure returns (ParamData memory paramData, ExchangeData memory exchangeData) {
(
uint[8] memory numData,
address[8] memory addrData,
uint8[3] memory enumData,
bytes memory callData,
address proxy
)
= abi.decode(_params, (uint256[8],address[8],uint8[3],bytes,address));
bytes memory proxyData1;
bytes memory proxyData2;
uint openDebtAmount = (_amount + _fee);
if (enumData[0] == 0) {
proxyData1 = abi.encodeWithSignature("close(uint256,address,uint256,uint256)", numData[2], addrData[0], _amount, numData[0]);
} else if(enumData[0] == 1) {
if (enumData[2] == 2) {
proxyData1 = abi.encodeWithSignature("changeDebt(address,address,uint256,uint256)", addrData[2], addrData[3], (_amount + _fee), numData[4]);
} else {
proxyData1 = abi.encodeWithSignature("close(address,address,uint256,uint256)", addrData[0], addrData[2], numData[0], numData[1]);
}
}
if (enumData[1] == 0) {
proxyData2 = abi.encodeWithSignature("open(uint256,address,uint256)", numData[3], addrData[1], openDebtAmount);
} else if(enumData[1] == 1) {
if (enumData[2] == 2) {
proxyData2 = abi.encodeWithSignature("repayAll(address)", addrData[3]);
} else {
proxyData2 = abi.encodeWithSignature("open(address,address,uint256)", addrData[1], addrData[3], openDebtAmount);
}
}
paramData = ParamData({
proxyData1: proxyData1,
proxyData2: proxyData2,
proxy: proxy,
debtAddr: addrData[2],
protocol1: enumData[0],
protocol2: enumData[1],
swapType: enumData[2]
});
exchangeData = SaverExchangeCore.ExchangeData({
srcAddr: addrData[4],
destAddr: addrData[5],
srcAmount: numData[4],
destAmount: numData[5],
minPrice: numData[6],
wrapper: addrData[7],
exchangeAddr: addrData[6],
callData: callData,
price0x: numData[7]
});
}
function sendToProxy(address payable _proxy, address _reserve, uint _amount) internal {
if (_reserve != ETH_ADDRESS) {
ERC20(_reserve).safeTransfer(_proxy, _amount);
}
_proxy.transfer(address(this).balance);
}
function getNameByProtocol(uint8 _proto) internal pure returns (string memory) {
if (_proto == 0) {
return "MCD_SHIFTER";
} else if (_proto == 1) {
return "COMP_SHIFTER";
}
}
receive() external override(FlashLoanReceiverBase, SaverExchangeCore) payable {}
}
文件 101 的 152:LoanShifterTaker.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../interfaces/ILendingPool.sol";
import "../interfaces/CTokenInterface.sol";
import "../interfaces/ILoanShifter.sol";
import "../interfaces/DSProxyInterface.sol";
import "../interfaces/Vat.sol";
import "../interfaces/Manager.sol";
import "../auth/AdminAuth.sol";
import "../auth/ProxyPermission.sol";
import "../exchange/SaverExchangeCore.sol";
import "./ShifterRegistry.sol";
contract LoanShifterTaker is AdminAuth, ProxyPermission {
ILendingPool public constant lendingPool = ILendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address public constant MANAGER_ADDRESS = 0x5ef30b9986345249bc32d8928B7ee64DE9435E39;
Manager public constant manager = Manager(MANAGER_ADDRESS);
ShifterRegistry public constant shifterRegistry = ShifterRegistry(0x597C52281b31B9d949a9D8fEbA08F7A2530a965e);
enum Protocols { MCD, COMPOUND }
enum SwapType { NO_SWAP, COLL_SWAP, DEBT_SWAP }
struct LoanShiftData {
Protocols fromProtocol;
Protocols toProtocol;
SwapType swapType;
bool wholeDebt;
uint collAmount;
uint debtAmount;
address debtAddr1;
address debtAddr2;
address addrLoan1;
address addrLoan2;
uint id1;
uint id2;
}
function moveLoan(
SaverExchangeCore.ExchangeData memory _exchangeData,
LoanShiftData memory _loanShift
) public {
if (_isSameTypeVaults(_loanShift)) {
_forkVault(_loanShift);
return;
}
_callCloseAndOpen(_exchangeData, _loanShift);
}
function _callCloseAndOpen(
SaverExchangeCore.ExchangeData memory _exchangeData,
LoanShiftData memory _loanShift
) internal {
address protoAddr = shifterRegistry.getAddr(getNameByProtocol(uint8(_loanShift.fromProtocol)));
uint loanAmount = _loanShift.debtAmount;
if (_loanShift.wholeDebt) {
loanAmount = ILoanShifter(protoAddr).getLoanAmount(_loanShift.id1, _loanShift.addrLoan1);
}
(
uint[8] memory numData,
address[8] memory addrData,
uint8[3] memory enumData,
bytes memory callData
)
= _packData(_loanShift, _exchangeData);
bytes memory paramsData = abi.encode(numData, addrData, enumData, callData, address(this));
address payable loanShifterReceiverAddr = payable(shifterRegistry.getAddr("LOAN_SHIFTER_RECEIVER"));
givePermission(loanShifterReceiverAddr);
lendingPool.flashLoan(loanShifterReceiverAddr,
getLoanAddr(_loanShift.debtAddr1, _loanShift.fromProtocol), loanAmount, paramsData);
removePermission(loanShifterReceiverAddr);
}
function _forkVault(LoanShiftData memory _loanShift) internal {
if (_loanShift.id2 == 0) {
_loanShift.id2 = manager.open(manager.ilks(_loanShift.id1), address(this));
}
if (_loanShift.wholeDebt) {
manager.shift(_loanShift.id1, _loanShift.id2);
}
}
function _isSameTypeVaults(LoanShiftData memory _loanShift) internal pure returns (bool) {
return _loanShift.fromProtocol == Protocols.MCD && _loanShift.toProtocol == Protocols.MCD
&& _loanShift.addrLoan1 == _loanShift.addrLoan2;
}
function getNameByProtocol(uint8 _proto) internal pure returns (string memory) {
if (_proto == 0) {
return "MCD_SHIFTER";
} else if (_proto == 1) {
return "COMP_SHIFTER";
}
}
function getLoanAddr(address _address, Protocols _fromProtocol) internal returns (address) {
if (_fromProtocol == Protocols.COMPOUND) {
return CTokenInterface(_address).underlying();
} else if (_fromProtocol == Protocols.MCD) {
return DAI_ADDRESS;
} else {
return address(0);
}
}
function _packData(
LoanShiftData memory _loanShift,
SaverExchangeCore.ExchangeData memory exchangeData
) internal pure returns (uint[8] memory numData, address[8] memory addrData, uint8[3] memory enumData, bytes memory callData) {
numData = [
_loanShift.collAmount,
_loanShift.debtAmount,
_loanShift.id1,
_loanShift.id2,
exchangeData.srcAmount,
exchangeData.destAmount,
exchangeData.minPrice,
exchangeData.price0x
];
addrData = [
_loanShift.addrLoan1,
_loanShift.addrLoan2,
_loanShift.debtAddr1,
_loanShift.debtAddr2,
exchangeData.srcAddr,
exchangeData.destAddr,
exchangeData.exchangeAddr,
exchangeData.wrapper
];
enumData = [
uint8(_loanShift.fromProtocol),
uint8(_loanShift.toProtocol),
uint8(_loanShift.swapType)
];
callData = exchangeData.callData;
}
}
文件 102 的 152:MCDCloseFlashLoan.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../mcd/saver/MCDSaverProxy.sol";
import "../../utils/FlashLoanReceiverBase.sol";
import "../../auth/AdminAuth.sol";
import "../../exchange/SaverExchangeCore.sol";
import "../../mcd/saver/MCDSaverProxyHelper.sol";
contract MCDCloseFlashLoan is SaverExchangeCore, MCDSaverProxyHelper, FlashLoanReceiverBase, AdminAuth {
ILendingPoolAddressesProvider public LENDING_POOL_ADDRESS_PROVIDER = ILendingPoolAddressesProvider(0x24a42fD28C976A61Df5D00D0599C34c4f90748c8);
uint public constant SERVICE_FEE = 400;
bytes32 internal constant ETH_ILK = 0x4554482d41000000000000000000000000000000000000000000000000000000;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address public constant DAI_JOIN_ADDRESS = 0x9759A6Ac90977b93B58547b4A71c78317f391A28;
address public constant ETH_JOIN_ADDRESS = 0x2F0b23f53734252Bda2277357e97e1517d6B042A;
address public constant SPOTTER_ADDRESS = 0x65C79fcB50Ca1594B025960e539eD7A9a6D434A3;
address public constant VAT_ADDRESS = 0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B;
Manager public constant manager = Manager(0x5ef30b9986345249bc32d8928B7ee64DE9435E39);
DaiJoin public constant daiJoin = DaiJoin(DAI_JOIN_ADDRESS);
Spotter public constant spotter = Spotter(SPOTTER_ADDRESS);
Vat public constant vat = Vat(VAT_ADDRESS);
struct CloseData {
uint cdpId;
uint collAmount;
uint daiAmount;
uint minAccepted;
address joinAddr;
address proxy;
uint flFee;
bool toDai;
address reserve;
uint amount;
}
constructor() FlashLoanReceiverBase(LENDING_POOL_ADDRESS_PROVIDER) public {}
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params)
external override {
(
uint[8] memory numData,
address[5] memory addrData,
bytes memory callData,
address proxy,
bool toDai
)
= abi.decode(_params, (uint256[8],address[5],bytes,address,bool));
ExchangeData memory exchangeData = ExchangeData({
srcAddr: addrData[0],
destAddr: addrData[1],
srcAmount: numData[4],
destAmount: numData[5],
minPrice: numData[6],
wrapper: addrData[3],
exchangeAddr: addrData[2],
callData: callData,
price0x: numData[7]
});
CloseData memory closeData = CloseData({
cdpId: numData[0],
collAmount: numData[1],
daiAmount: numData[2],
minAccepted: numData[3],
joinAddr: addrData[4],
proxy: proxy,
flFee: _fee,
toDai: toDai,
reserve: _reserve,
amount: _amount
});
address user = DSProxy(payable(closeData.proxy)).owner();
closeCDP(closeData, exchangeData, user);
}
function closeCDP(
CloseData memory _closeData,
ExchangeData memory _exchangeData,
address _user
) internal {
paybackDebt(_closeData.cdpId, manager.ilks(_closeData.cdpId), _closeData.daiAmount);
drawMaxCollateral(_closeData.cdpId, _closeData.joinAddr, _closeData.collAmount);
uint daiSwaped = 0;
uint dfsFee = 0;
if (_closeData.toDai) {
_exchangeData.srcAmount = _closeData.collAmount;
(, daiSwaped) = _sell(_exchangeData);
dfsFee = getFee(daiSwaped, _user);
} else {
dfsFee = getFee(_closeData.daiAmount, _user);
_exchangeData.destAmount = (_closeData.daiAmount + _closeData.flFee + dfsFee);
(, daiSwaped) = _buy(_exchangeData);
}
takeFee(dfsFee);
address tokenAddr = getVaultCollAddr(_closeData.joinAddr);
if (_closeData.toDai) {
tokenAddr = DAI_ADDRESS;
}
require(getBalance(tokenAddr) >= _closeData.minAccepted, "Below min. number of eth specified");
transferFundsBackToPoolInternal(_closeData.reserve, _closeData.amount.add(_closeData.flFee));
sendLeftover(tokenAddr, DAI_ADDRESS, payable(_user));
}
function drawMaxCollateral(uint _cdpId, address _joinAddr, uint _amount) internal returns (uint) {
manager.frob(_cdpId, -toPositiveInt(_amount), 0);
manager.flux(_cdpId, address(this), _amount);
uint joinAmount = _amount;
if (Join(_joinAddr).dec() != 18) {
joinAmount = _amount / (10 ** (18 - Join(_joinAddr).dec()));
}
Join(_joinAddr).exit(address(this), joinAmount);
if (_joinAddr == ETH_JOIN_ADDRESS) {
Join(_joinAddr).gem().withdraw(joinAmount);
}
return joinAmount;
}
function paybackDebt(uint _cdpId, bytes32 _ilk, uint _daiAmount) internal {
address urn = manager.urns(_cdpId);
daiJoin.dai().approve(DAI_JOIN_ADDRESS, _daiAmount);
daiJoin.join(urn, _daiAmount);
manager.frob(_cdpId, 0, normalizePaybackAmount(VAT_ADDRESS, urn, _ilk));
}
function takeFee(uint _feeAmount) internal returns (uint) {
ERC20(DAI_ADDRESS).transfer(WALLET_ID, _feeAmount);
}
function getFee(uint _amount, address _owner) internal view returns (uint feeAmount) {
uint fee = SERVICE_FEE;
if (Discount(DISCOUNT_ADDRESS).isCustomFeeSet(_owner)) {
fee = Discount(DISCOUNT_ADDRESS).getCustomServiceFee(_owner);
}
feeAmount = (fee == 0) ? 0 : (_amount / fee);
if (feeAmount > (_amount / 5)) {
feeAmount = _amount / 5;
}
}
function getVaultCollAddr(address _joinAddr) internal view returns (address) {
address tokenAddr = address(Join(_joinAddr).gem());
if (tokenAddr == WETH_ADDRESS) {
return KYBER_ETH_ADDRESS;
}
return tokenAddr;
}
function getPrice(bytes32 _ilk) public view returns (uint256) {
(, uint256 mat) = spotter.ilks(_ilk);
(, , uint256 spot, , ) = vat.ilks(_ilk);
return rmul(rmul(spot, spotter.par()), mat);
}
receive() external override(FlashLoanReceiverBase, SaverExchangeCore) payable {}
}
文件 103 的 152:MCDCloseTaker.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../mcd/saver/MCDSaverProxy.sol";
import "../../loggers/DefisaverLogger.sol";
import "../../interfaces/ILendingPool.sol";
import "../../exchange/SaverExchangeCore.sol";
abstract contract IMCDSubscriptions {
function unsubscribe(uint256 _cdpId) external virtual ;
function subscribersPos(uint256 _cdpId) external virtual returns (uint256, bool);
}
contract MCDCloseTaker is MCDSaverProxyHelper {
address public constant SUBSCRIPTION_ADDRESS_NEW = 0xC45d4f6B6bf41b6EdAA58B01c4298B8d9078269a;
address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
ILendingPool public constant lendingPool = ILendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
Manager public constant manager = Manager(0x5ef30b9986345249bc32d8928B7ee64DE9435E39);
address public constant SPOTTER_ADDRESS = 0x65C79fcB50Ca1594B025960e539eD7A9a6D434A3;
address public constant VAT_ADDRESS = 0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
DefisaverLogger public constant logger = DefisaverLogger(DEFISAVER_LOGGER);
struct CloseData {
uint cdpId;
address joinAddr;
uint collAmount;
uint daiAmount;
uint minAccepted;
bool wholeDebt;
bool toDai;
}
Vat public constant vat = Vat(VAT_ADDRESS);
Spotter public constant spotter = Spotter(SPOTTER_ADDRESS);
function closeWithLoan(
SaverExchangeCore.ExchangeData memory _exchangeData,
CloseData memory _closeData,
address payable mcdCloseFlashLoan
) public payable {
mcdCloseFlashLoan.transfer(msg.value);
if (_closeData.wholeDebt) {
_closeData.daiAmount = getAllDebt(
VAT_ADDRESS,
manager.urns(_closeData.cdpId),
manager.urns(_closeData.cdpId),
manager.ilks(_closeData.cdpId)
);
(_closeData.collAmount, )
= getCdpInfo(manager, _closeData.cdpId, manager.ilks(_closeData.cdpId));
}
manager.cdpAllow(_closeData.cdpId, mcdCloseFlashLoan, 1);
(uint[8] memory numData, address[5] memory addrData, bytes memory callData)
= _packData(_closeData, _exchangeData);
bytes memory paramsData = abi.encode(numData, addrData, callData, address(this), _closeData.toDai);
lendingPool.flashLoan(mcdCloseFlashLoan, DAI_ADDRESS, _closeData.daiAmount, paramsData);
manager.cdpAllow(_closeData.cdpId, mcdCloseFlashLoan, 0);
unsubscribe(SUBSCRIPTION_ADDRESS_NEW, _closeData.cdpId);
logger.Log(address(this), msg.sender, "MCDClose", abi.encode(_closeData.cdpId, _closeData.collAmount, _closeData.daiAmount, _closeData.toDai));
}
function getMaxDebt(uint256 _cdpId, bytes32 _ilk) public view returns (uint256) {
uint256 price = getPrice(_ilk);
(, uint256 mat) = spotter.ilks(_ilk);
(uint256 collateral, uint256 debt) = getCdpInfo(manager, _cdpId, _ilk);
return sub(wdiv(wmul(collateral, price), mat), debt);
}
function getPrice(bytes32 _ilk) public view returns (uint256) {
(, uint256 mat) = spotter.ilks(_ilk);
(, , uint256 spot, , ) = vat.ilks(_ilk);
return rmul(rmul(spot, spotter.par()), mat);
}
function unsubscribe(address _subContract, uint _cdpId) internal {
(, bool isSubscribed) = IMCDSubscriptions(_subContract).subscribersPos(_cdpId);
if (isSubscribed) {
IMCDSubscriptions(_subContract).unsubscribe(_cdpId);
}
}
function _packData(
CloseData memory _closeData,
SaverExchangeCore.ExchangeData memory exchangeData
) internal pure returns (uint[8] memory numData, address[5] memory addrData, bytes memory callData) {
numData = [
_closeData.cdpId,
_closeData.collAmount,
_closeData.daiAmount,
_closeData.minAccepted,
exchangeData.srcAmount,
exchangeData.destAmount,
exchangeData.minPrice,
exchangeData.price0x
];
addrData = [
exchangeData.srcAddr,
exchangeData.destAddr,
exchangeData.exchangeAddr,
exchangeData.wrapper,
_closeData.joinAddr
];
callData = exchangeData.callData;
}
}
文件 104 的 152:MCDCreateFlashLoan.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../exchange/SaverExchangeCore.sol";
import "./MCDCreateProxyActions.sol";
import "../../utils/FlashLoanReceiverBase.sol";
import "../../interfaces/Manager.sol";
import "../../interfaces/Join.sol";
import "../../DS/DSProxy.sol";
contract MCDCreateFlashLoan is SaverExchangeCore, AdminAuth, FlashLoanReceiverBase {
address public constant CREATE_PROXY_ACTIONS = 0x6d0984E80a86f26c0dd564ca0CF74a8E9Da03305;
uint public constant SERVICE_FEE = 400;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
ILendingPoolAddressesProvider public LENDING_POOL_ADDRESS_PROVIDER = ILendingPoolAddressesProvider(0x24a42fD28C976A61Df5D00D0599C34c4f90748c8);
address public constant ETH_JOIN_ADDRESS = 0x2F0b23f53734252Bda2277357e97e1517d6B042A;
address public constant DAI_JOIN_ADDRESS = 0x9759A6Ac90977b93B58547b4A71c78317f391A28;
address public constant JUG_ADDRESS = 0x19c0976f590D67707E62397C87829d896Dc0f1F1;
address public constant MANAGER_ADDRESS = 0x5ef30b9986345249bc32d8928B7ee64DE9435E39;
constructor() FlashLoanReceiverBase(LENDING_POOL_ADDRESS_PROVIDER) public {}
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params)
external override {
require(_amount <= getBalanceInternal(address(this), _reserve),
"Invalid balance for the contract");
(
uint[6] memory numData,
address[5] memory addrData,
bytes memory callData,
address proxy
)
= abi.decode(_params, (uint256[6],address[5],bytes,address));
ExchangeData memory exchangeData = ExchangeData({
srcAddr: addrData[0],
destAddr: addrData[1],
srcAmount: numData[2],
destAmount: numData[3],
minPrice: numData[4],
wrapper: addrData[3],
exchangeAddr: addrData[2],
callData: callData,
price0x: numData[5]
});
openAndLeverage(numData[0], numData[1] + _fee, addrData[4], proxy, exchangeData);
transferFundsBackToPoolInternal(_reserve, _amount.add(_fee));
if (address(this).balance > 0) {
tx.origin.transfer(address(this).balance);
}
}
function openAndLeverage(
uint _collAmount,
uint _daiAmountAndFee,
address _joinAddr,
address _proxy,
ExchangeData memory _exchangeData
) public {
uint dfsFee = getFee(_exchangeData.srcAmount, DSProxy(payable(_proxy)).owner());
_exchangeData.srcAmount = (_exchangeData.srcAmount - dfsFee);
(, uint256 collSwaped) = _sell(_exchangeData);
bytes32 ilk = Join(_joinAddr).ilk();
if (_joinAddr == ETH_JOIN_ADDRESS) {
MCDCreateProxyActions(CREATE_PROXY_ACTIONS).openLockETHAndDraw{value: address(this).balance}(
MANAGER_ADDRESS,
JUG_ADDRESS,
ETH_JOIN_ADDRESS,
DAI_JOIN_ADDRESS,
ilk,
_daiAmountAndFee,
_proxy
);
} else {
ERC20(address(Join(_joinAddr).gem())).safeApprove(CREATE_PROXY_ACTIONS, 0);
ERC20(address(Join(_joinAddr).gem())).safeApprove(CREATE_PROXY_ACTIONS, uint256(-1));
MCDCreateProxyActions(CREATE_PROXY_ACTIONS).openLockGemAndDraw(
MANAGER_ADDRESS,
JUG_ADDRESS,
_joinAddr,
DAI_JOIN_ADDRESS,
ilk,
(_collAmount + collSwaped),
_daiAmountAndFee,
true,
_proxy
);
}
}
function getFee(uint _amount, address _owner) internal returns (uint feeAmount) {
uint fee = SERVICE_FEE;
if (Discount(DISCOUNT_ADDRESS).isCustomFeeSet(_owner)) {
fee = Discount(DISCOUNT_ADDRESS).getCustomServiceFee(_owner);
}
feeAmount = (fee == 0) ? 0 : (_amount / fee);
if (feeAmount > (_amount / 5)) {
feeAmount = _amount / 5;
}
ERC20(DAI_ADDRESS).transfer(WALLET_ID, feeAmount);
}
receive() external override(FlashLoanReceiverBase, SaverExchangeCore) payable {}
}
文件 105 的 152:MCDCreateProxyActions.sol
pragma solidity ^0.6.0;
abstract contract GemLike {
function approve(address, uint256) public virtual;
function transfer(address, uint256) public virtual;
function transferFrom(address, address, uint256) public virtual;
function deposit() public virtual payable;
function withdraw(uint256) public virtual;
}
abstract contract ManagerLike {
function cdpCan(address, uint256, address) public virtual view returns (uint256);
function ilks(uint256) public virtual view returns (bytes32);
function owns(uint256) public virtual view returns (address);
function urns(uint256) public virtual view returns (address);
function vat() public virtual view returns (address);
function open(bytes32, address) public virtual returns (uint256);
function give(uint256, address) public virtual;
function cdpAllow(uint256, address, uint256) public virtual;
function urnAllow(address, uint256) public virtual;
function frob(uint256, int256, int256) public virtual;
function flux(uint256, address, uint256) public virtual;
function move(uint256, address, uint256) public virtual;
function exit(address, uint256, address, uint256) public virtual;
function quit(uint256, address) public virtual;
function enter(address, uint256) public virtual;
function shift(uint256, uint256) public virtual;
}
abstract contract VatLike {
function can(address, address) public virtual view returns (uint256);
function ilks(bytes32) public virtual view returns (uint256, uint256, uint256, uint256, uint256);
function dai(address) public virtual view returns (uint256);
function urns(bytes32, address) public virtual view returns (uint256, uint256);
function frob(bytes32, address, address, address, int256, int256) public virtual;
function hope(address) public virtual;
function move(address, address, uint256) public virtual;
}
abstract contract GemJoinLike {
function dec() public virtual returns (uint256);
function gem() public virtual returns (GemLike);
function join(address, uint256) public virtual payable;
function exit(address, uint256) public virtual;
}
abstract contract GNTJoinLike {
function bags(address) public virtual view returns (address);
function make(address) public virtual returns (address);
}
abstract contract DaiJoinLike {
function vat() public virtual returns (VatLike);
function dai() public virtual returns (GemLike);
function join(address, uint256) public virtual payable;
function exit(address, uint256) public virtual;
}
abstract contract HopeLike {
function hope(address) public virtual;
function nope(address) public virtual;
}
abstract contract ProxyRegistryInterface {
function build(address) public virtual returns (address);
}
abstract contract EndLike {
function fix(bytes32) public virtual view returns (uint256);
function cash(bytes32, uint256) public virtual;
function free(bytes32) public virtual;
function pack(uint256) public virtual;
function skim(bytes32, address) public virtual;
}
abstract contract JugLike {
function drip(bytes32) public virtual returns (uint256);
}
abstract contract PotLike {
function pie(address) public virtual view returns (uint256);
function drip() public virtual returns (uint256);
function join(uint256) public virtual;
function exit(uint256) public virtual;
}
abstract contract ProxyRegistryLike {
function proxies(address) public virtual view returns (address);
function build(address) public virtual returns (address);
}
abstract contract ProxyLike {
function owner() public virtual view returns (address);
}
contract Common {
uint256 constant RAY = 10**27;
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x, "mul-overflow");
}
function daiJoin_join(address apt, address urn, uint256 wad) public {
DaiJoinLike(apt).dai().transferFrom(msg.sender, address(this), wad);
DaiJoinLike(apt).dai().approve(apt, wad);
DaiJoinLike(apt).join(urn, wad);
}
}
contract MCDCreateProxyActions is Common {
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x - y) <= x, "sub-overflow");
}
function toInt(uint256 x) internal pure returns (int256 y) {
y = int256(x);
require(y >= 0, "int-overflow");
}
function toRad(uint256 wad) internal pure returns (uint256 rad) {
rad = mul(wad, 10**27);
}
function convertTo18(address gemJoin, uint256 amt) internal returns (uint256 wad) {
wad = mul(amt, 10**(18 - GemJoinLike(gemJoin).dec()));
}
function _getDrawDart(address vat, address jug, address urn, bytes32 ilk, uint256 wad)
internal
returns (int256 dart)
{
uint256 rate = JugLike(jug).drip(ilk);
uint256 dai = VatLike(vat).dai(urn);
if (dai < mul(wad, RAY)) {
dart = toInt(sub(mul(wad, RAY), dai) / rate);
dart = mul(uint256(dart), rate) < mul(wad, RAY) ? dart + 1 : dart;
}
}
function _getWipeDart(address vat, uint256 dai, address urn, bytes32 ilk)
internal
view
returns (int256 dart)
{
(, uint256 rate, , , ) = VatLike(vat).ilks(ilk);
(, uint256 art) = VatLike(vat).urns(ilk, urn);
dart = toInt(dai / rate);
dart = uint256(dart) <= art ? -dart : -toInt(art);
}
function _getWipeAllWad(address vat, address usr, address urn, bytes32 ilk)
internal
view
returns (uint256 wad)
{
(, uint256 rate, , , ) = VatLike(vat).ilks(ilk);
(, uint256 art) = VatLike(vat).urns(ilk, urn);
uint256 dai = VatLike(vat).dai(usr);
uint256 rad = sub(mul(art, rate), dai);
wad = rad / RAY;
wad = mul(wad, RAY) < rad ? wad + 1 : wad;
}
function transfer(address gem, address dst, uint256 wad) public {
GemLike(gem).transfer(dst, wad);
}
function ethJoin_join(address apt, address urn) public payable {
GemJoinLike(apt).gem().deposit{value: msg.value}();
GemJoinLike(apt).gem().approve(address(apt), msg.value);
GemJoinLike(apt).join(urn, msg.value);
}
function gemJoin_join(address apt, address urn, uint256 wad, bool transferFrom) public {
if (transferFrom) {
GemJoinLike(apt).gem().transferFrom(msg.sender, address(this), wad);
GemJoinLike(apt).gem().approve(apt, 0);
GemJoinLike(apt).gem().approve(apt, wad);
}
GemJoinLike(apt).join(urn, wad);
}
function hope(address obj, address usr) public {
HopeLike(obj).hope(usr);
}
function nope(address obj, address usr) public {
HopeLike(obj).nope(usr);
}
function open(address manager, bytes32 ilk, address usr) public returns (uint256 cdp) {
cdp = ManagerLike(manager).open(ilk, usr);
}
function give(address manager, uint256 cdp, address usr) public {
ManagerLike(manager).give(cdp, usr);
}
function move(address manager, uint256 cdp, address dst, uint256 rad) public {
ManagerLike(manager).move(cdp, dst, rad);
}
function frob(address manager, uint256 cdp, int256 dink, int256 dart) public {
ManagerLike(manager).frob(cdp, dink, dart);
}
function lockETH(address manager, address ethJoin, uint256 cdp) public payable {
ethJoin_join(ethJoin, address(this));
VatLike(ManagerLike(manager).vat()).frob(
ManagerLike(manager).ilks(cdp),
ManagerLike(manager).urns(cdp),
address(this),
address(this),
toInt(msg.value),
0
);
}
function lockGem(address manager, address gemJoin, uint256 cdp, uint256 wad, bool transferFrom)
public
{
gemJoin_join(gemJoin, address(this), wad, transferFrom);
VatLike(ManagerLike(manager).vat()).frob(
ManagerLike(manager).ilks(cdp),
ManagerLike(manager).urns(cdp),
address(this),
address(this),
toInt(convertTo18(gemJoin, wad)),
0
);
}
function draw(address manager, address jug, address daiJoin, uint256 cdp, uint256 wad) public {
address urn = ManagerLike(manager).urns(cdp);
address vat = ManagerLike(manager).vat();
bytes32 ilk = ManagerLike(manager).ilks(cdp);
frob(manager, cdp, 0, _getDrawDart(vat, jug, urn, ilk, wad));
move(manager, cdp, address(this), toRad(wad));
if (VatLike(vat).can(address(this), address(daiJoin)) == 0) {
VatLike(vat).hope(daiJoin);
}
DaiJoinLike(daiJoin).exit(msg.sender, wad);
}
function lockETHAndDraw(
address manager,
address jug,
address ethJoin,
address daiJoin,
uint256 cdp,
uint256 wadD
) public payable {
address urn = ManagerLike(manager).urns(cdp);
address vat = ManagerLike(manager).vat();
bytes32 ilk = ManagerLike(manager).ilks(cdp);
ethJoin_join(ethJoin, urn);
frob(manager, cdp, toInt(msg.value), _getDrawDart(vat, jug, urn, ilk, wadD));
move(manager, cdp, address(this), toRad(wadD));
if (VatLike(vat).can(address(this), address(daiJoin)) == 0) {
VatLike(vat).hope(daiJoin);
}
DaiJoinLike(daiJoin).exit(msg.sender, wadD);
}
function openLockETHAndDraw(
address manager,
address jug,
address ethJoin,
address daiJoin,
bytes32 ilk,
uint256 wadD,
address owner
) public payable returns (uint256 cdp) {
cdp = open(manager, ilk, address(this));
lockETHAndDraw(manager, jug, ethJoin, daiJoin, cdp, wadD);
give(manager, cdp, owner);
}
function lockGemAndDraw(
address manager,
address jug,
address gemJoin,
address daiJoin,
uint256 cdp,
uint256 wadC,
uint256 wadD,
bool transferFrom
) public {
address urn = ManagerLike(manager).urns(cdp);
address vat = ManagerLike(manager).vat();
bytes32 ilk = ManagerLike(manager).ilks(cdp);
gemJoin_join(gemJoin, urn, wadC, transferFrom);
frob(
manager,
cdp,
toInt(convertTo18(gemJoin, wadC)),
_getDrawDart(vat, jug, urn, ilk, wadD)
);
move(manager, cdp, address(this), toRad(wadD));
if (VatLike(vat).can(address(this), address(daiJoin)) == 0) {
VatLike(vat).hope(daiJoin);
}
DaiJoinLike(daiJoin).exit(msg.sender, wadD);
}
function openLockGemAndDraw(
address manager,
address jug,
address gemJoin,
address daiJoin,
bytes32 ilk,
uint256 wadC,
uint256 wadD,
bool transferFrom,
address owner
) public returns (uint256 cdp) {
cdp = open(manager, ilk, address(this));
lockGemAndDraw(manager, jug, gemJoin, daiJoin, cdp, wadC, wadD, transferFrom);
give(manager, cdp, owner);
}
}
文件 106 的 152:MCDCreateTaker.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../mcd/saver/MCDSaverProxy.sol";
import "../../loggers/DefisaverLogger.sol";
import "../../interfaces/ILendingPool.sol";
import "../../exchange/SaverExchangeCore.sol";
import "../../utils/SafeERC20.sol";
contract MCDCreateTaker {
using SafeERC20 for ERC20;
address payable public constant MCD_CREATE_FLASH_LOAN = 0x71eC9a4fCE561c3936a511D9ebb05B60CF2bA519;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address public constant ETH_JOIN_ADDRESS = 0x2F0b23f53734252Bda2277357e97e1517d6B042A;
ILendingPool public constant lendingPool = ILendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
Manager public constant manager = Manager(0x5ef30b9986345249bc32d8928B7ee64DE9435E39);
DefisaverLogger public constant logger = DefisaverLogger(0x5c55B921f590a89C1Ebe84dF170E655a82b62126);
struct CreateData {
uint collAmount;
uint daiAmount;
address joinAddr;
}
function openWithLoan(
SaverExchangeCore.ExchangeData memory _exchangeData,
CreateData memory _createData
) public payable {
MCD_CREATE_FLASH_LOAN.transfer(msg.value);
if (_createData.joinAddr != ETH_JOIN_ADDRESS) {
ERC20(getCollateralAddr(_createData.joinAddr)).safeTransferFrom(msg.sender, address(this), _createData.collAmount);
ERC20(getCollateralAddr(_createData.joinAddr)).safeTransfer(MCD_CREATE_FLASH_LOAN, _createData.collAmount);
}
(uint[6] memory numData, address[5] memory addrData, bytes memory callData)
= _packData(_createData, _exchangeData);
bytes memory paramsData = abi.encode(numData, addrData, callData, address(this));
lendingPool.flashLoan(MCD_CREATE_FLASH_LOAN, DAI_ADDRESS, _createData.daiAmount, paramsData);
logger.Log(address(this), msg.sender, "MCDCreate", abi.encode(manager.last(address(this)), _createData.collAmount, _createData.daiAmount));
}
function getCollateralAddr(address _joinAddr) internal view returns (address) {
return address(Join(_joinAddr).gem());
}
function _packData(
CreateData memory _createData,
SaverExchangeCore.ExchangeData memory exchangeData
) internal pure returns (uint[6] memory numData, address[5] memory addrData, bytes memory callData) {
numData = [
_createData.collAmount,
_createData.daiAmount,
exchangeData.srcAmount,
exchangeData.destAmount,
exchangeData.minPrice,
exchangeData.price0x
];
addrData = [
exchangeData.srcAddr,
exchangeData.destAddr,
exchangeData.exchangeAddr,
exchangeData.wrapper,
_createData.joinAddr
];
callData = exchangeData.callData;
}
}
文件 107 的 152:MCDMonitorProxyV2.sol
pragma solidity ^0.6.0;
import "../../interfaces/DSProxyInterface.sol";
import "../../interfaces/ERC20.sol";
import "../../auth/AdminAuth.sol";
contract MCDMonitorProxyV2 is AdminAuth {
uint public CHANGE_PERIOD;
address public monitor;
address public newMonitor;
address public lastMonitor;
uint public changeRequestedTimestamp;
mapping(address => bool) public allowed;
event MonitorChangeInitiated(address oldMonitor, address newMonitor);
event MonitorChangeCanceled();
event MonitorChangeFinished(address monitor);
event MonitorChangeReverted(address monitor);
modifier onlyAllowed() {
require(allowed[msg.sender] || msg.sender == owner);
_;
}
modifier onlyMonitor() {
require (msg.sender == monitor);
_;
}
constructor(uint _changePeriod) public {
CHANGE_PERIOD = _changePeriod * 1 days;
}
function callExecute(address _owner, address _saverProxy, bytes memory _data) public payable onlyMonitor {
DSProxyInterface(_owner).execute{value: msg.value}(_saverProxy, _data);
if (address(this).balance > 0) {
msg.sender.transfer(address(this).balance);
}
}
function setMonitor(address _monitor) public onlyAllowed {
require(monitor == address(0));
monitor = _monitor;
}
function changeMonitor(address _newMonitor) public onlyAllowed {
require(changeRequestedTimestamp == 0);
changeRequestedTimestamp = now;
lastMonitor = monitor;
newMonitor = _newMonitor;
emit MonitorChangeInitiated(lastMonitor, newMonitor);
}
function cancelMonitorChange() public onlyAllowed {
require(changeRequestedTimestamp > 0);
changeRequestedTimestamp = 0;
newMonitor = address(0);
emit MonitorChangeCanceled();
}
function confirmNewMonitor() public onlyAllowed {
require((changeRequestedTimestamp + CHANGE_PERIOD) < now);
require(changeRequestedTimestamp != 0);
require(newMonitor != address(0));
monitor = newMonitor;
newMonitor = address(0);
changeRequestedTimestamp = 0;
emit MonitorChangeFinished(monitor);
}
function revertMonitor() public onlyAllowed {
require(lastMonitor != address(0));
monitor = lastMonitor;
emit MonitorChangeReverted(monitor);
}
function addAllowed(address _user) public onlyAllowed {
allowed[_user] = true;
}
function removeAllowed(address _user) public onlyAllowed {
allowed[_user] = false;
}
function setChangePeriod(uint _periodInDays) public onlyAllowed {
require(_periodInDays * 1 days > CHANGE_PERIOD);
CHANGE_PERIOD = _periodInDays * 1 days;
}
}
文件 108 的 152:MCDMonitorV2.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../interfaces/Manager.sol";
import "../../interfaces/Vat.sol";
import "../../interfaces/Spotter.sol";
import "../../DS/DSMath.sol";
import "../../auth/AdminAuth.sol";
import "../../loggers/DefisaverLogger.sol";
import "../../utils/GasBurner.sol";
import "../../utils/BotRegistry.sol";
import "../../exchange/SaverExchangeCore.sol";
import "./ISubscriptionsV2.sol";
import "./StaticV2.sol";
import "./MCDMonitorProxyV2.sol";
contract MCDMonitorV2 is DSMath, AdminAuth, GasBurner, StaticV2 {
uint public REPAY_GAS_TOKEN = 25;
uint public BOOST_GAS_TOKEN = 25;
uint public MAX_GAS_PRICE = 200000000000;
uint public REPAY_GAS_COST = 2500000;
uint public BOOST_GAS_COST = 2500000;
MCDMonitorProxyV2 public monitorProxyContract;
ISubscriptionsV2 public subscriptionsContract;
address public mcdSaverTakerAddress;
address public constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B;
Manager public manager = Manager(0x5ef30b9986345249bc32d8928B7ee64DE9435E39);
Vat public vat = Vat(0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B);
Spotter public spotter = Spotter(0x65C79fcB50Ca1594B025960e539eD7A9a6D434A3);
DefisaverLogger public constant logger = DefisaverLogger(0x5c55B921f590a89C1Ebe84dF170E655a82b62126);
modifier onlyApproved() {
require(BotRegistry(BOT_REGISTRY_ADDRESS).botList(msg.sender), "Not auth bot");
_;
}
constructor(address _monitorProxy, address _subscriptions, address _mcdSaverTakerAddress) public {
monitorProxyContract = MCDMonitorProxyV2(_monitorProxy);
subscriptionsContract = ISubscriptionsV2(_subscriptions);
mcdSaverTakerAddress = _mcdSaverTakerAddress;
}
function repayFor(
SaverExchangeCore.ExchangeData memory _exchangeData,
uint _cdpId,
uint _nextPrice,
address _joinAddr
) public payable onlyApproved burnGas(REPAY_GAS_TOKEN) {
(bool isAllowed, uint ratioBefore) = canCall(Method.Repay, _cdpId, _nextPrice);
require(isAllowed);
uint gasCost = calcGasCost(REPAY_GAS_COST);
address owner = subscriptionsContract.getOwner(_cdpId);
monitorProxyContract.callExecute{value: msg.value}(
owner,
mcdSaverTakerAddress,
abi.encodeWithSignature(
"repayWithLoan((address,address,uint256,uint256,uint256,address,address,bytes,uint256),uint256,uint256,address)",
_exchangeData, _cdpId, gasCost, _joinAddr));
(bool isGoodRatio, uint ratioAfter) = ratioGoodAfter(Method.Repay, _cdpId, _nextPrice);
require(isGoodRatio);
returnEth();
logger.Log(address(this), owner, "AutomaticMCDRepay", abi.encode(ratioBefore, ratioAfter));
}
function boostFor(
SaverExchangeCore.ExchangeData memory _exchangeData,
uint _cdpId,
uint _nextPrice,
address _joinAddr
) public payable onlyApproved burnGas(BOOST_GAS_TOKEN) {
(bool isAllowed, uint ratioBefore) = canCall(Method.Boost, _cdpId, _nextPrice);
require(isAllowed);
uint gasCost = calcGasCost(BOOST_GAS_COST);
address owner = subscriptionsContract.getOwner(_cdpId);
monitorProxyContract.callExecute{value: msg.value}(
owner,
mcdSaverTakerAddress,
abi.encodeWithSignature(
"boostWithLoan((address,address,uint256,uint256,uint256,address,address,bytes,uint256),uint256,uint256,address)",
_exchangeData, _cdpId, gasCost, _joinAddr));
(bool isGoodRatio, uint ratioAfter) = ratioGoodAfter(Method.Boost, _cdpId, _nextPrice);
require(isGoodRatio);
returnEth();
logger.Log(address(this), owner, "AutomaticMCDBoost", abi.encode(ratioBefore, ratioAfter));
}
function returnEth() internal {
if (address(this).balance > 0) {
msg.sender.transfer(address(this).balance);
}
}
function getOwner(uint _cdpId) public view returns(address) {
return manager.owns(_cdpId);
}
function getCdpInfo(uint _cdpId, bytes32 _ilk) public view returns (uint, uint) {
address urn = manager.urns(_cdpId);
(uint collateral, uint debt) = vat.urns(_ilk, urn);
(,uint rate,,,) = vat.ilks(_ilk);
return (collateral, rmul(debt, rate));
}
function getPrice(bytes32 _ilk) public view returns (uint) {
(, uint mat) = spotter.ilks(_ilk);
(,,uint spot,,) = vat.ilks(_ilk);
return rmul(rmul(spot, spotter.par()), mat);
}
function getRatio(uint _cdpId, uint _nextPrice) public view returns (uint) {
bytes32 ilk = manager.ilks(_cdpId);
uint price = (_nextPrice == 0) ? getPrice(ilk) : _nextPrice;
(uint collateral, uint debt) = getCdpInfo(_cdpId, ilk);
if (debt == 0) return 0;
return rdiv(wmul(collateral, price), debt) / (10 ** 18);
}
function canCall(Method _method, uint _cdpId, uint _nextPrice) public view returns(bool, uint) {
bool subscribed;
CdpHolder memory holder;
(subscribed, holder) = subscriptionsContract.getCdpHolder(_cdpId);
if (!subscribed) return (false, 0);
if (_nextPrice > 0 && !holder.nextPriceEnabled) return (false, 0);
if (_method == Method.Boost && !holder.boostEnabled) return (false, 0);
if (getOwner(_cdpId) != holder.owner) return (false, 0);
uint currRatio = getRatio(_cdpId, _nextPrice);
if (_method == Method.Repay) {
return (currRatio < holder.minRatio, currRatio);
} else if (_method == Method.Boost) {
return (currRatio > holder.maxRatio, currRatio);
}
}
function ratioGoodAfter(Method _method, uint _cdpId, uint _nextPrice) public view returns(bool, uint) {
CdpHolder memory holder;
(, holder) = subscriptionsContract.getCdpHolder(_cdpId);
uint currRatio = getRatio(_cdpId, _nextPrice);
if (_method == Method.Repay) {
return (currRatio < holder.maxRatio, currRatio);
} else if (_method == Method.Boost) {
return (currRatio > holder.minRatio, currRatio);
}
}
function calcGasCost(uint _gasAmount) public 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 changeMaxGasPrice(uint _maxGasPrice) public onlyOwner {
require(_maxGasPrice < 500000000000);
MAX_GAS_PRICE = _maxGasPrice;
}
function changeGasTokenAmount(uint _gasAmount, bool _isRepay) public onlyOwner {
if (_isRepay) {
REPAY_GAS_TOKEN = _gasAmount;
} else {
BOOST_GAS_TOKEN = _gasAmount;
}
}
}
文件 109 的 152:MCDPriceVerifier.sol
pragma solidity ^0.6.0;
import "../../interfaces/OsmMom.sol";
import "../../interfaces/Osm.sol";
import "../../auth/AdminAuth.sol";
import "../../interfaces/Manager.sol";
contract MCDPriceVerifier is AdminAuth {
OsmMom public osmMom = OsmMom(0x76416A4d5190d071bfed309861527431304aA14f);
Manager public manager = Manager(0x5ef30b9986345249bc32d8928B7ee64DE9435E39);
mapping(address => bool) public authorized;
function verifyVaultNextPrice(uint _nextPrice, uint _cdpId) public view returns(bool) {
require(authorized[msg.sender]);
bytes32 ilk = manager.ilks(_cdpId);
return verifyNextPrice(_nextPrice, ilk);
}
function verifyNextPrice(uint _nextPrice, bytes32 _ilk) public view returns(bool) {
require(authorized[msg.sender]);
address osmAddress = osmMom.osms(_ilk);
uint whitelisted = Osm(osmAddress).bud(address(this));
if (whitelisted != 1) return true;
(bytes32 price, bool has) = Osm(osmAddress).peep();
return has ? uint(price) == _nextPrice : false;
}
function setAuthorized(address _address, bool _allowed) public onlyOwner {
authorized[_address] = _allowed;
}
}
文件 110 的 152:MCDSaverFlashLoan.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../mcd/saver/MCDSaverProxy.sol";
import "../../utils/FlashLoanReceiverBase.sol";
import "../../exchange/SaverExchangeCore.sol";
contract MCDSaverFlashLoan is MCDSaverProxy, AdminAuth, FlashLoanReceiverBase {
ILendingPoolAddressesProvider public LENDING_POOL_ADDRESS_PROVIDER = ILendingPoolAddressesProvider(0x24a42fD28C976A61Df5D00D0599C34c4f90748c8);
constructor() FlashLoanReceiverBase(LENDING_POOL_ADDRESS_PROVIDER) public {}
struct SaverData {
uint cdpId;
uint gasCost;
uint loanAmount;
uint fee;
address joinAddr;
}
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params)
external override {
require(_amount <= getBalanceInternal(address(this), _reserve),
"Invalid balance for the contract");
(
bytes memory exDataBytes,
uint cdpId,
uint gasCost,
address joinAddr,
bool isRepay
)
= abi.decode(_params, (bytes,uint256,uint256,address,bool));
ExchangeData memory exchangeData = unpackExchangeData(exDataBytes);
SaverData memory saverData = SaverData({
cdpId: cdpId,
gasCost: gasCost,
loanAmount: _amount,
fee: _fee,
joinAddr: joinAddr
});
if (isRepay) {
repayWithLoan(exchangeData, saverData);
} else {
boostWithLoan(exchangeData, saverData);
}
transferFundsBackToPoolInternal(_reserve, _amount.add(_fee));
if (address(this).balance > 0) {
tx.origin.transfer(address(this).balance);
}
}
function boostWithLoan(
ExchangeData memory _exchangeData,
SaverData memory _saverData
) internal {
address user = getOwner(manager, _saverData.cdpId);
uint maxDebt = getMaxDebt(_saverData.cdpId, manager.ilks(_saverData.cdpId));
uint daiDrawn = drawDai(_saverData.cdpId, manager.ilks(_saverData.cdpId), maxDebt);
uint dsfFee = getFee((daiDrawn + _saverData.loanAmount), _saverData.gasCost, user);
uint afterFee = (daiDrawn + _saverData.loanAmount) - dsfFee;
_exchangeData.srcAmount = afterFee;
(, uint swapedAmount) = _sell(_exchangeData);
addCollateral(_saverData.cdpId, _saverData.joinAddr, swapedAmount);
drawDai(_saverData.cdpId, manager.ilks(_saverData.cdpId), (_saverData.loanAmount + _saverData.fee));
logger.Log(address(this), msg.sender, "MCDFlashBoost", abi.encode(_saverData.cdpId, owner, _exchangeData.srcAmount, swapedAmount));
}
function repayWithLoan(
ExchangeData memory _exchangeData,
SaverData memory _saverData
) internal {
address user = getOwner(manager, _saverData.cdpId);
bytes32 ilk = manager.ilks(_saverData.cdpId);
uint maxColl = getMaxCollateral(_saverData.cdpId, ilk, _saverData.joinAddr);
uint collDrawn = drawCollateral(_saverData.cdpId, _saverData.joinAddr, maxColl);
_exchangeData.srcAmount = (_saverData.loanAmount + collDrawn);
(, uint swapedAmount) = _sell(_exchangeData);
uint paybackAmount = (swapedAmount - getFee(swapedAmount, _saverData.gasCost, user));
paybackAmount = limitLoanAmount(_saverData.cdpId, ilk, paybackAmount, user);
paybackDebt(_saverData.cdpId, ilk, paybackAmount, user);
drawCollateral(_saverData.cdpId, _saverData.joinAddr, (_saverData.loanAmount + _saverData.fee));
logger.Log(address(this), msg.sender, "MCDFlashRepay", abi.encode(_saverData.cdpId, owner, _exchangeData.srcAmount, swapedAmount));
}
function limitLoanAmount(uint _cdpId, bytes32 _ilk, uint _paybackAmount, address _owner) internal returns (uint256) {
uint debt = getAllDebt(address(vat), manager.urns(_cdpId), manager.urns(_cdpId), _ilk);
if (_paybackAmount > debt) {
ERC20(DAI_ADDRESS).transfer(_owner, (_paybackAmount - debt));
return debt;
}
uint debtLeft = debt - _paybackAmount;
(,,,, uint dust) = vat.ilks(_ilk);
dust = dust / 10**27;
if (debtLeft < dust) {
uint amountOverDust = (dust - debtLeft);
ERC20(DAI_ADDRESS).transfer(_owner, amountOverDust);
return (_paybackAmount - amountOverDust);
}
return _paybackAmount;
}
receive() external override(FlashLoanReceiverBase, SaverExchangeCore) payable {}
}
文件 111 的 152:MCDSaverProxy.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../interfaces/ExchangeInterface.sol";
import "../../loggers/DefisaverLogger.sol";
import "../../utils/Discount.sol";
import "../../interfaces/Spotter.sol";
import "../../interfaces/Jug.sol";
import "../../interfaces/DaiJoin.sol";
import "../../interfaces/Join.sol";
import "./MCDSaverProxyHelper.sol";
import "../../utils/BotRegistry.sol";
import "../../exchange/SaverExchangeCore.sol";
contract MCDSaverProxy is SaverExchangeCore, MCDSaverProxyHelper {
uint public constant MANUAL_SERVICE_FEE = 400;
uint public constant AUTOMATIC_SERVICE_FEE = 333;
bytes32 public constant ETH_ILK = 0x4554482d41000000000000000000000000000000000000000000000000000000;
address public constant MANAGER_ADDRESS = 0x5ef30b9986345249bc32d8928B7ee64DE9435E39;
address public constant VAT_ADDRESS = 0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B;
address public constant SPOTTER_ADDRESS = 0x65C79fcB50Ca1594B025960e539eD7A9a6D434A3;
address public constant DAI_JOIN_ADDRESS = 0x9759A6Ac90977b93B58547b4A71c78317f391A28;
address public constant JUG_ADDRESS = 0x19c0976f590D67707E62397C87829d896Dc0f1F1;
address public constant ETH_JOIN_ADDRESS = 0x2F0b23f53734252Bda2277357e97e1517d6B042A;
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address public constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B;
Manager public constant manager = Manager(MANAGER_ADDRESS);
Vat public constant vat = Vat(VAT_ADDRESS);
DaiJoin public constant daiJoin = DaiJoin(DAI_JOIN_ADDRESS);
Spotter public constant spotter = Spotter(SPOTTER_ADDRESS);
DefisaverLogger public constant logger = DefisaverLogger(0x5c55B921f590a89C1Ebe84dF170E655a82b62126);
function repay(
SaverExchangeCore.ExchangeData memory _exchangeData,
uint _cdpId,
uint _gasCost,
address _joinAddr
) public payable {
address owner = getOwner(manager, _cdpId);
bytes32 ilk = manager.ilks(_cdpId);
drawCollateral(_cdpId, _joinAddr, _exchangeData.srcAmount);
(, uint daiAmount) = _sell(_exchangeData);
uint daiAfterFee = sub(daiAmount, getFee(daiAmount, _gasCost, owner));
paybackDebt(_cdpId, ilk, daiAfterFee, owner);
if (address(this).balance > 0) {
tx.origin.transfer(address(this).balance);
}
logger.Log(address(this), msg.sender, "MCDRepay", abi.encode(_cdpId, owner, _exchangeData.srcAmount, daiAmount));
}
function boost(
SaverExchangeCore.ExchangeData memory _exchangeData,
uint _cdpId,
uint _gasCost,
address _joinAddr
) public payable {
address owner = getOwner(manager, _cdpId);
bytes32 ilk = manager.ilks(_cdpId);
uint daiDrawn = drawDai(_cdpId, ilk, _exchangeData.srcAmount);
uint daiAfterFee = sub(daiDrawn, getFee(daiDrawn, _gasCost, owner));
_exchangeData.srcAmount = daiAfterFee;
(, uint swapedColl) = _sell(_exchangeData);
addCollateral(_cdpId, _joinAddr, swapedColl);
if (address(this).balance > 0) {
tx.origin.transfer(address(this).balance);
}
logger.Log(address(this), msg.sender, "MCDBoost", abi.encode(_cdpId, owner, _exchangeData.srcAmount, swapedColl));
}
function drawDai(uint _cdpId, bytes32 _ilk, uint _daiAmount) internal returns (uint) {
uint rate = Jug(JUG_ADDRESS).drip(_ilk);
uint daiVatBalance = vat.dai(manager.urns(_cdpId));
uint maxAmount = getMaxDebt(_cdpId, _ilk);
if (_daiAmount >= maxAmount) {
_daiAmount = sub(maxAmount, 1);
}
manager.frob(_cdpId, int(0), normalizeDrawAmount(_daiAmount, rate, daiVatBalance));
manager.move(_cdpId, address(this), toRad(_daiAmount));
if (vat.can(address(this), address(DAI_JOIN_ADDRESS)) == 0) {
vat.hope(DAI_JOIN_ADDRESS);
}
DaiJoin(DAI_JOIN_ADDRESS).exit(address(this), _daiAmount);
return _daiAmount;
}
function addCollateral(uint _cdpId, address _joinAddr, uint _amount) internal {
int convertAmount = 0;
if (_joinAddr == ETH_JOIN_ADDRESS) {
Join(_joinAddr).gem().deposit{value: _amount}();
convertAmount = toPositiveInt(_amount);
} else {
convertAmount = toPositiveInt(convertTo18(_joinAddr, _amount));
}
ERC20(address(Join(_joinAddr).gem())).safeApprove(_joinAddr, 0);
ERC20(address(Join(_joinAddr).gem())).safeApprove(_joinAddr, _amount);
Join(_joinAddr).join(address(this), _amount);
vat.frob(
manager.ilks(_cdpId),
manager.urns(_cdpId),
address(this),
address(this),
convertAmount,
0
);
}
function drawCollateral(uint _cdpId, address _joinAddr, uint _amount) internal returns (uint) {
uint frobAmount = _amount;
if (Join(_joinAddr).dec() != 18) {
frobAmount = _amount * (10 ** (18 - Join(_joinAddr).dec()));
}
manager.frob(_cdpId, -toPositiveInt(frobAmount), 0);
manager.flux(_cdpId, address(this), frobAmount);
Join(_joinAddr).exit(address(this), _amount);
if (_joinAddr == ETH_JOIN_ADDRESS) {
Join(_joinAddr).gem().withdraw(_amount);
}
return _amount;
}
function paybackDebt(uint _cdpId, bytes32 _ilk, uint _daiAmount, address _owner) internal {
address urn = manager.urns(_cdpId);
uint wholeDebt = getAllDebt(VAT_ADDRESS, urn, urn, _ilk);
if (_daiAmount > wholeDebt) {
ERC20(DAI_ADDRESS).transfer(_owner, sub(_daiAmount, wholeDebt));
_daiAmount = wholeDebt;
}
if (ERC20(DAI_ADDRESS).allowance(address(this), DAI_JOIN_ADDRESS) == 0) {
ERC20(DAI_ADDRESS).approve(DAI_JOIN_ADDRESS, uint(-1));
}
daiJoin.join(urn, _daiAmount);
manager.frob(_cdpId, 0, normalizePaybackAmount(VAT_ADDRESS, urn, _ilk));
}
function getFee(uint _amount, uint _gasCost, address _owner) internal returns (uint feeAmount) {
uint fee = MANUAL_SERVICE_FEE;
if (BotRegistry(BOT_REGISTRY_ADDRESS).botList(tx.origin)) {
fee = AUTOMATIC_SERVICE_FEE;
}
if (Discount(DISCOUNT_ADDRESS).isCustomFeeSet(_owner)) {
fee = Discount(DISCOUNT_ADDRESS).getCustomServiceFee(_owner);
}
feeAmount = (fee == 0) ? 0 : (_amount / fee);
if (_gasCost != 0) {
uint ethDaiPrice = getPrice(ETH_ILK);
_gasCost = rmul(_gasCost, ethDaiPrice);
feeAmount = add(feeAmount, _gasCost);
}
if (feeAmount > (_amount / 5)) {
feeAmount = _amount / 5;
}
ERC20(DAI_ADDRESS).transfer(WALLET_ID, feeAmount);
}
function getMaxCollateral(uint _cdpId, bytes32 _ilk, address _joinAddr) public view returns (uint) {
uint price = getPrice(_ilk);
(uint collateral, uint debt) = getCdpInfo(manager, _cdpId, _ilk);
(, uint mat) = Spotter(SPOTTER_ADDRESS).ilks(_ilk);
uint maxCollateral = sub(sub(collateral, (div(mul(mat, debt), price))), 10);
uint normalizeMaxCollateral = maxCollateral;
if (Join(_joinAddr).dec() != 18) {
normalizeMaxCollateral = maxCollateral / (10 ** (18 - Join(_joinAddr).dec()));
}
return normalizeMaxCollateral;
}
function getMaxDebt(uint _cdpId, bytes32 _ilk) public virtual view returns (uint) {
uint price = getPrice(_ilk);
(, uint mat) = spotter.ilks(_ilk);
(uint collateral, uint debt) = getCdpInfo(manager, _cdpId, _ilk);
return sub(sub(div(mul(collateral, price), mat), debt), 10);
}
function getPrice(bytes32 _ilk) public view returns (uint) {
(, uint mat) = spotter.ilks(_ilk);
(,,uint spot,,) = vat.ilks(_ilk);
return rmul(rmul(spot, spotter.par()), mat);
}
function getRatio(uint _cdpId, bytes32 _ilk) public view returns (uint) {
uint price = getPrice( _ilk);
(uint collateral, uint debt) = getCdpInfo(manager, _cdpId, _ilk);
if (debt == 0) return 0;
return rdiv(wmul(collateral, price), debt);
}
function getCdpDetailedInfo(uint _cdpId) public view returns (uint collateral, uint debt, uint price, bytes32 ilk) {
address urn = manager.urns(_cdpId);
ilk = manager.ilks(_cdpId);
(collateral, debt) = vat.urns(ilk, urn);
(,uint rate,,,) = vat.ilks(ilk);
debt = rmul(debt, rate);
price = getPrice(ilk);
}
}
文件 112 的 152:MCDSaverProxyHelper.sol
pragma solidity ^0.6.0;
import "../../DS/DSMath.sol";
import "../../DS/DSProxy.sol";
import "../../interfaces/Manager.sol";
import "../../interfaces/Join.sol";
import "../../interfaces/Vat.sol";
contract MCDSaverProxyHelper is DSMath {
function normalizeDrawAmount(uint _amount, uint _rate, uint _daiVatBalance) internal pure returns (int dart) {
if (_daiVatBalance < mul(_amount, RAY)) {
dart = toPositiveInt(sub(mul(_amount, RAY), _daiVatBalance) / _rate);
dart = mul(uint(dart), _rate) < mul(_amount, RAY) ? dart + 1 : dart;
}
}
function toRad(uint _wad) internal pure returns (uint) {
return mul(_wad, 10 ** 27);
}
function convertTo18(address _joinAddr, uint256 _amount) internal view returns (uint256) {
return mul(_amount, 10 ** (18 - Join(_joinAddr).dec()));
}
function toPositiveInt(uint _x) internal pure returns (int y) {
y = int(_x);
require(y >= 0, "int-overflow");
}
function normalizePaybackAmount(address _vat, address _urn, bytes32 _ilk) internal view returns (int amount) {
uint dai = Vat(_vat).dai(_urn);
(, uint rate,,,) = Vat(_vat).ilks(_ilk);
(, uint art) = Vat(_vat).urns(_ilk, _urn);
amount = toPositiveInt(dai / rate);
amount = uint(amount) <= art ? - amount : - toPositiveInt(art);
}
function getAllDebt(address _vat, address _usr, address _urn, bytes32 _ilk) internal view returns (uint daiAmount) {
(, uint rate,,,) = Vat(_vat).ilks(_ilk);
(, uint art) = Vat(_vat).urns(_ilk, _urn);
uint dai = Vat(_vat).dai(_usr);
uint rad = sub(mul(art, rate), dai);
daiAmount = rad / RAY;
daiAmount = mul(daiAmount, RAY) < rad ? daiAmount + 1 : daiAmount;
}
function getCollateralAddr(address _joinAddr) internal view returns (address) {
return address(Join(_joinAddr).gem());
}
function getCdpInfo(Manager _manager, uint _cdpId, bytes32 _ilk) public view returns (uint, uint) {
address vat = _manager.vat();
address urn = _manager.urns(_cdpId);
(uint collateral, uint debt) = Vat(vat).urns(_ilk, urn);
(,uint rate,,,) = Vat(vat).ilks(_ilk);
return (collateral, rmul(debt, rate));
}
function getOwner(Manager _manager, uint _cdpId) public view returns (address) {
DSProxy proxy = DSProxy(uint160(_manager.owns(_cdpId)));
return proxy.owner();
}
}
文件 113 的 152:MCDSaverTaker.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../saver/MCDSaverProxy.sol";
import "../../exchange/SaverExchangeCore.sol";
import "../../utils/GasBurner.sol";
abstract contract ILendingPool {
function flashLoan( address payable _receiver, address _reserve, uint _amount, bytes calldata _params) external virtual;
}
contract MCDSaverTaker is MCDSaverProxy, GasBurner {
address payable public constant MCD_SAVER_FLASH_LOAN = 0x28e444b53a9e7E3F6fFe50E93b18dCce7838551F;
address public constant AAVE_POOL_CORE = 0x3dfd23A6c5E8BbcFc9581d2E864a68feb6a076d3;
ILendingPool public constant lendingPool = ILendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
function boostWithLoan(
SaverExchangeCore.ExchangeData memory _exchangeData,
uint _cdpId,
uint _gasCost,
address _joinAddr
) public payable burnGas(25) {
uint256 maxDebt = getMaxDebt(_cdpId, manager.ilks(_cdpId));
if (maxDebt >= _exchangeData.srcAmount) {
boost(_exchangeData, _cdpId, _gasCost, _joinAddr);
return;
}
MCD_SAVER_FLASH_LOAN.transfer(msg.value);
uint256 loanAmount = sub(_exchangeData.srcAmount, maxDebt);
uint maxLiq = getAvailableLiquidity(DAI_JOIN_ADDRESS);
loanAmount = loanAmount > maxLiq ? maxLiq : loanAmount;
manager.cdpAllow(_cdpId, MCD_SAVER_FLASH_LOAN, 1);
bytes memory paramsData = abi.encode(packExchangeData(_exchangeData), _cdpId, _gasCost, _joinAddr, false);
lendingPool.flashLoan(MCD_SAVER_FLASH_LOAN, DAI_ADDRESS, loanAmount, paramsData);
manager.cdpAllow(_cdpId, MCD_SAVER_FLASH_LOAN, 0);
}
function repayWithLoan(
SaverExchangeCore.ExchangeData memory _exchangeData,
uint _cdpId,
uint _gasCost,
address _joinAddr
) public payable burnGas(25) {
uint256 maxColl = getMaxCollateral(_cdpId, manager.ilks(_cdpId), _joinAddr);
if (maxColl >= _exchangeData.srcAmount) {
repay(_exchangeData, _cdpId, _gasCost, _joinAddr);
return;
}
MCD_SAVER_FLASH_LOAN.transfer(msg.value);
uint256 loanAmount = sub(_exchangeData.srcAmount, maxColl);
uint maxLiq = getAvailableLiquidity(_joinAddr);
loanAmount = loanAmount > maxLiq ? maxLiq : loanAmount;
manager.cdpAllow(_cdpId, MCD_SAVER_FLASH_LOAN, 1);
bytes memory paramsData = abi.encode(packExchangeData(_exchangeData), _cdpId, _gasCost, _joinAddr, true);
lendingPool.flashLoan(MCD_SAVER_FLASH_LOAN, getAaveCollAddr(_joinAddr), loanAmount, paramsData);
manager.cdpAllow(_cdpId, MCD_SAVER_FLASH_LOAN, 0);
}
function getMaxDebt(uint256 _cdpId, bytes32 _ilk) public override view returns (uint256) {
uint256 price = getPrice(_ilk);
(, uint256 mat) = spotter.ilks(_ilk);
(uint256 collateral, uint256 debt) = getCdpInfo(manager, _cdpId, _ilk);
return sub(wdiv(wmul(collateral, price), mat), debt);
}
function getAaveCollAddr(address _joinAddr) internal view returns (address) {
if (_joinAddr == 0x2F0b23f53734252Bda2277357e97e1517d6B042A
|| _joinAddr == 0x775787933e92b709f2a3C70aa87999696e74A9F8) {
return KYBER_ETH_ADDRESS;
} else if (_joinAddr == DAI_JOIN_ADDRESS) {
return DAI_ADDRESS;
} else
{
return getCollateralAddr(_joinAddr);
}
}
function getAvailableLiquidity(address _joinAddr) internal view returns (uint liquidity) {
address tokenAddr = getAaveCollAddr(_joinAddr);
if (tokenAddr == KYBER_ETH_ADDRESS) {
liquidity = AAVE_POOL_CORE.balance;
} else {
liquidity = ERC20(tokenAddr).balanceOf(AAVE_POOL_CORE);
}
}
function _packData(
uint _cdpId,
uint _gasCost,
address _joinAddr,
SaverExchangeCore.ExchangeData memory exchangeData
) internal pure returns (uint[6] memory numData, address[5] memory addrData, bytes memory callData) {
numData = [
exchangeData.srcAmount,
exchangeData.destAmount,
exchangeData.minPrice,
exchangeData.price0x,
_cdpId,
_gasCost
];
addrData = [
exchangeData.srcAddr,
exchangeData.destAddr,
exchangeData.exchangeAddr,
exchangeData.wrapper,
_joinAddr
];
callData = exchangeData.callData;
}
}
文件 114 的 152:Manager.sol
pragma solidity ^0.6.0;
abstract contract Manager {
function last(address) virtual public returns (uint);
function cdpCan(address, uint, address) virtual public view returns (uint);
function ilks(uint) virtual public view returns (bytes32);
function owns(uint) virtual public view returns (address);
function urns(uint) virtual public view returns (address);
function vat() virtual public view returns (address);
function open(bytes32, address) virtual public returns (uint);
function give(uint, address) virtual public;
function cdpAllow(uint, address, uint) virtual public;
function urnAllow(address, uint) virtual public;
function frob(uint, int, int) virtual public;
function flux(uint, address, uint) virtual public;
function move(uint, address, uint) virtual public;
function exit(address, uint, address, uint) virtual public;
function quit(uint, address) virtual public;
function enter(address, uint) virtual public;
function shift(uint, uint) virtual public;
}
文件 115 的 152:Math.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import { SafeMath } from "../../../utils/SafeMath.sol";
import { Require } from "./Require.sol";
library Math {
using SafeMath for uint256;
bytes32 constant FILE = "Math";
function getPartial(
uint256 target,
uint256 numerator,
uint256 denominator
)
internal
pure
returns (uint256)
{
return target.mul(numerator).div(denominator);
}
function getPartialRoundUp(
uint256 target,
uint256 numerator,
uint256 denominator
)
internal
pure
returns (uint256)
{
if (target == 0 || numerator == 0) {
return SafeMath.div(0, denominator);
}
return target.mul(numerator).sub(1).div(denominator).add(1);
}
function to128(
uint256 number
)
internal
pure
returns (uint128)
{
uint128 result = uint128(number);
Require.that(
result == number,
FILE,
"Unsafe cast to uint128"
);
return result;
}
function to96(
uint256 number
)
internal
pure
returns (uint96)
{
uint96 result = uint96(number);
Require.that(
result == number,
FILE,
"Unsafe cast to uint96"
);
return result;
}
function to32(
uint256 number
)
internal
pure
returns (uint32)
{
uint32 result = uint32(number);
Require.that(
result == number,
FILE,
"Unsafe cast to uint32"
);
return result;
}
function min(
uint256 a,
uint256 b
)
internal
pure
returns (uint256)
{
return a < b ? a : b;
}
function max(
uint256 a,
uint256 b
)
internal
pure
returns (uint256)
{
return a > b ? a : b;
}
}
文件 116 的 152:McdShifter.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../interfaces/ILoanShifter.sol";
import "../../mcd/saver/MCDSaverProxy.sol";
import "../../mcd/create/MCDCreateProxyActions.sol";
contract McdShifter is MCDSaverProxy {
address public constant OPEN_PROXY_ACTIONS = 0x6d0984E80a86f26c0dd564ca0CF74a8E9Da03305;
function getLoanAmount(uint _cdpId, address _joinAddr) public view virtual returns(uint loanAmount) {
bytes32 ilk = manager.ilks(_cdpId);
(, uint rate,,,) = vat.ilks(ilk);
(, uint art) = vat.urns(ilk, manager.urns(_cdpId));
uint dai = vat.dai(manager.urns(_cdpId));
uint rad = sub(mul(art, rate), dai);
loanAmount = rad / RAY;
loanAmount = mul(loanAmount, RAY) < rad ? loanAmount + 1 : loanAmount;
}
function close(
uint _cdpId,
address _joinAddr,
uint _loanAmount,
uint _collateral
) public {
address owner = getOwner(manager, _cdpId);
bytes32 ilk = manager.ilks(_cdpId);
(uint maxColl, ) = getCdpInfo(manager, _cdpId, ilk);
paybackDebt(_cdpId, ilk, _loanAmount, owner);
maxColl = _collateral > maxColl ? maxColl : _collateral;
drawMaxCollateral(_cdpId, _joinAddr, maxColl);
if (_joinAddr == ETH_JOIN_ADDRESS) {
msg.sender.transfer(address(this).balance);
} else {
ERC20 collToken = ERC20(getCollateralAddr(_joinAddr));
collToken.transfer(msg.sender, collToken.balanceOf(address(this)));
}
}
function open(
uint _cdpId,
address _joinAddr,
uint _debtAmount
) public {
uint collAmount = 0;
if (_joinAddr == ETH_JOIN_ADDRESS) {
collAmount = address(this).balance;
} else {
collAmount = ERC20(address(Join(_joinAddr).gem())).balanceOf(address(this));
}
if (_cdpId == 0) {
openAndWithdraw(collAmount, _debtAmount, address(this), _joinAddr);
} else {
addCollateral(_cdpId, _joinAddr, collAmount);
drawDai(_cdpId, manager.ilks(_cdpId), _debtAmount);
}
ERC20(DAI_ADDRESS).transfer(msg.sender, ERC20(DAI_ADDRESS).balanceOf(address(this)));
if (address(this).balance > 0) {
tx.origin.transfer(address(this).balance);
}
}
function openAndWithdraw(uint _collAmount, uint _debtAmount, address _proxy, address _joinAddrTo) internal {
bytes32 ilk = Join(_joinAddrTo).ilk();
if (_joinAddrTo == ETH_JOIN_ADDRESS) {
MCDCreateProxyActions(OPEN_PROXY_ACTIONS).openLockETHAndDraw{value: address(this).balance}(
address(manager),
JUG_ADDRESS,
ETH_JOIN_ADDRESS,
DAI_JOIN_ADDRESS,
ilk,
_debtAmount,
_proxy
);
} else {
ERC20(getCollateralAddr(_joinAddrTo)).approve(OPEN_PROXY_ACTIONS, uint256(-1));
MCDCreateProxyActions(OPEN_PROXY_ACTIONS).openLockGemAndDraw(
address(manager),
JUG_ADDRESS,
_joinAddrTo,
DAI_JOIN_ADDRESS,
ilk,
_collAmount,
_debtAmount,
true,
_proxy
);
}
}
function drawMaxCollateral(uint _cdpId, address _joinAddr, uint _amount) internal returns (uint) {
manager.frob(_cdpId, -toPositiveInt(_amount), 0);
manager.flux(_cdpId, address(this), _amount);
uint joinAmount = _amount;
if (Join(_joinAddr).dec() != 18) {
joinAmount = _amount / (10 ** (18 - Join(_joinAddr).dec()));
}
Join(_joinAddr).exit(address(this), joinAmount);
if (_joinAddr == ETH_JOIN_ADDRESS) {
Join(_joinAddr).gem().withdraw(joinAmount);
}
return joinAmount;
}
}
文件 117 的 152:Migrations.sol
pragma solidity ^0.6.0;
contract Migrations {
address public owner;
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
constructor() public {
owner = msg.sender;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
文件 118 的 152:OasisInterface.sol
pragma solidity ^0.6.0;
abstract contract OasisInterface {
function getBuyAmount(address tokenToBuy, address tokenToPay, uint256 amountToPay)
external
virtual
view
returns (uint256 amountBought);
function getPayAmount(address tokenToPay, address tokenToBuy, uint256 amountToBuy)
public virtual
view
returns (uint256 amountPaid);
function sellAllAmount(address pay_gem, uint256 pay_amt, address buy_gem, uint256 min_fill_amount)
public virtual
returns (uint256 fill_amt);
function buyAllAmount(address buy_gem, uint256 buy_amt, address pay_gem, uint256 max_fill_amount)
public virtual
returns (uint256 fill_amt);
}
文件 119 的 152:OasisTradeWrapper.sol
pragma solidity ^0.6.0;
import "../../interfaces/ExchangeInterfaceV2.sol";
import "../../interfaces/OasisInterface.sol";
import "../../interfaces/TokenInterface.sol";
import "../../DS/DSMath.sol";
import "../../utils/SafeERC20.sol";
import "../../auth/AdminAuth.sol";
contract OasisTradeWrapper is DSMath, ExchangeInterfaceV2, AdminAuth {
using SafeERC20 for ERC20;
address public constant OTC_ADDRESS = 0x794e6e91555438aFc3ccF1c5076A74F42133d08D;
address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
function sell(address _srcAddr, address _destAddr, uint _srcAmount) external override payable returns (uint) {
address srcAddr = ethToWethAddr(_srcAddr);
address destAddr = ethToWethAddr(_destAddr);
ERC20(srcAddr).safeApprove(OTC_ADDRESS, _srcAmount);
uint destAmount = OasisInterface(OTC_ADDRESS).sellAllAmount(srcAddr, _srcAmount, destAddr, 0);
if (destAddr == WETH_ADDRESS) {
TokenInterface(WETH_ADDRESS).withdraw(destAmount);
msg.sender.transfer(destAmount);
} else {
ERC20(destAddr).safeTransfer(msg.sender, destAmount);
}
return destAmount;
}
function buy(address _srcAddr, address _destAddr, uint _destAmount) external override payable returns(uint) {
address srcAddr = ethToWethAddr(_srcAddr);
address destAddr = ethToWethAddr(_destAddr);
ERC20(srcAddr).safeApprove(OTC_ADDRESS, uint(-1));
uint srcAmount = OasisInterface(OTC_ADDRESS).buyAllAmount(destAddr, _destAmount, srcAddr, uint(-1));
if (destAddr == WETH_ADDRESS) {
TokenInterface(WETH_ADDRESS).withdraw(_destAmount);
msg.sender.transfer(_destAmount);
} else {
ERC20(destAddr).safeTransfer(msg.sender, _destAmount);
}
sendLeftOver(srcAddr);
return srcAmount;
}
function getSellRate(address _srcAddr, address _destAddr, uint _srcAmount) public override view returns (uint) {
address srcAddr = ethToWethAddr(_srcAddr);
address destAddr = ethToWethAddr(_destAddr);
return wdiv(OasisInterface(OTC_ADDRESS).getBuyAmount(destAddr, srcAddr, _srcAmount), _srcAmount);
}
function getBuyRate(address _srcAddr, address _destAddr, uint _destAmount) public override view returns (uint) {
address srcAddr = ethToWethAddr(_srcAddr);
address destAddr = ethToWethAddr(_destAddr);
return wdiv(1 ether, wdiv(OasisInterface(OTC_ADDRESS).getPayAmount(srcAddr, destAddr, _destAmount), _destAmount));
}
function sendLeftOver(address _srcAddr) internal {
msg.sender.transfer(address(this).balance);
if (_srcAddr != KYBER_ETH_ADDRESS) {
ERC20(_srcAddr).safeTransfer(msg.sender, ERC20(_srcAddr).balanceOf(address(this)));
}
}
function ethToWethAddr(address _src) internal pure returns (address) {
return _src == KYBER_ETH_ADDRESS ? WETH_ADDRESS : _src;
}
receive() payable external {}
}
文件 120 的 152:Osm.sol
pragma solidity ^0.6.0;
abstract contract Osm {
mapping(address => uint256) public bud;
function peep() external view virtual returns (bytes32, bool);
}
文件 121 的 152:OsmMom.sol
pragma solidity ^0.6.0;
abstract contract OsmMom {
mapping (bytes32 => address) public osms;
}
文件 122 的 152:OtcInterface.sol
pragma solidity ^0.6.0;
abstract contract OtcInterface {
function buyAllAmount(address, uint256, address, uint256) public virtual returns (uint256);
function getPayAmount(address, address, uint256) public virtual view returns (uint256);
function getBuyAmount(address, address, uint256) public virtual view returns (uint256);
}
文件 123 的 152:PipInterface.sol
pragma solidity ^0.6.0;
abstract contract PipInterface {
function read() public virtual returns (bytes32);
}
文件 124 的 152:Prices.sol
pragma solidity ^0.6.0;
import "../DS/DSMath.sol";
import "../interfaces/TokenInterface.sol";
import "../interfaces/ExchangeInterfaceV2.sol";
import "./SaverExchangeHelper.sol";
contract Prices is DSMath {
address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
enum ActionType { SELL, BUY }
function getBestPrice(
uint256 _amount,
address _srcToken,
address _destToken,
ActionType _type,
address[] memory _wrappers
) public returns (address, uint256) {
uint256[] memory rates = new uint256[](_wrappers.length);
for (uint i=0; i<_wrappers.length; i++) {
rates[i] = getExpectedRate(_wrappers[i], _srcToken, _destToken, _amount, _type);
}
if (_type == ActionType.SELL) {
return getBiggestRate(_wrappers, rates);
} else {
return getSmallestRate(_wrappers, rates);
}
}
function getExpectedRate(
address _wrapper,
address _srcToken,
address _destToken,
uint256 _amount,
ActionType _type
) public returns (uint256) {
bool success;
bytes memory result;
if (_type == ActionType.SELL) {
(success, result) = _wrapper.call(abi.encodeWithSignature(
"getSellRate(address,address,uint256)",
_srcToken,
_destToken,
_amount
));
} else {
(success, result) = _wrapper.call(abi.encodeWithSignature(
"getBuyRate(address,address,uint256)",
_srcToken,
_destToken,
_amount
));
}
if (success) {
return sliceUint(result, 0);
}
return 0;
}
function getBiggestRate(
address[] memory _wrappers,
uint256[] memory _rates
) internal pure returns (address, uint) {
uint256 maxIndex = 0;
for (uint256 i=0; i<_rates.length; i++) {
if (_rates[i] > _rates[maxIndex]) {
maxIndex = i;
}
}
return (_wrappers[maxIndex], _rates[maxIndex]);
}
function getSmallestRate(
address[] memory _wrappers,
uint256[] memory _rates
) internal pure returns (address, uint) {
uint256 minIndex = 0;
for (uint256 i=0; i<_rates.length; i++) {
if ((_rates[i] < _rates[minIndex] && _rates[i] > 0) || _rates[minIndex] == 0) {
minIndex = i;
}
}
return (_wrappers[minIndex], _rates[minIndex]);
}
function getDecimals(address _token) internal view returns (uint256) {
if (_token == KYBER_ETH_ADDRESS) return 18;
return ERC20(_token).decimals();
}
function sliceUint(bytes memory bs, uint256 start) internal pure returns (uint256) {
require(bs.length >= start + 32, "slicing out of range");
uint256 x;
assembly {
x := mload(add(bs, add(0x20, start)))
}
return x;
}
}
文件 125 的 152:ProtocolInterface.sol
pragma solidity ^0.6.0;
abstract contract ProtocolInterface {
function deposit(address _user, uint256 _amount) public virtual;
function withdraw(address _user, uint256 _amount) public virtual;
}
文件 126 的 152:ProxyPermission.sol
pragma solidity ^0.6.0;
import "../DS/DSGuard.sol";
import "../DS/DSAuth.sol";
contract ProxyPermission {
address public constant FACTORY_ADDRESS = 0x5a15566417e6C1c9546523066500bDDBc53F88C7;
function givePermission(address _contractAddr) public {
address currAuthority = address(DSAuth(address(this)).authority());
DSGuard guard = DSGuard(currAuthority);
if (currAuthority == address(0)) {
guard = DSGuardFactory(FACTORY_ADDRESS).newGuard();
DSAuth(address(this)).setAuthority(DSAuthority(address(guard)));
}
guard.permit(_contractAddr, address(this), bytes4(keccak256("execute(address,bytes)")));
}
function removePermission(address _contractAddr) public {
address currAuthority = address(DSAuth(address(this)).authority());
if (currAuthority == address(0)) {
return;
}
DSGuard guard = DSGuard(currAuthority);
guard.forbid(_contractAddr, address(this), bytes4(keccak256("execute(address,bytes)")));
}
}
文件 127 的 152:ProxyRegistryInterface.sol
pragma solidity ^0.6.0;
import "./DSProxyInterface.sol";
abstract contract ProxyRegistryInterface {
function proxies(address _owner) public virtual view returns (address);
function build(address) public virtual returns (address);
}
文件 128 的 152:Require.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
library Require {
uint256 constant ASCII_ZERO = 48;
uint256 constant ASCII_RELATIVE_ZERO = 87;
uint256 constant ASCII_LOWER_EX = 120;
bytes2 constant COLON = 0x3a20;
bytes2 constant COMMA = 0x2c20;
bytes2 constant LPAREN = 0x203c;
byte constant RPAREN = 0x3e;
uint256 constant FOUR_BIT_MASK = 0xf;
function that(
bool must,
bytes32 file,
bytes32 reason
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason)
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
uint256 payloadA
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
uint256 payloadA,
uint256 payloadB
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
COMMA,
stringify(payloadB),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
address payloadA
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
address payloadA,
uint256 payloadB
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
COMMA,
stringify(payloadB),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
address payloadA,
uint256 payloadB,
uint256 payloadC
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
COMMA,
stringify(payloadB),
COMMA,
stringify(payloadC),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
bytes32 payloadA
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
bytes32 payloadA,
uint256 payloadB,
uint256 payloadC
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
COMMA,
stringify(payloadB),
COMMA,
stringify(payloadC),
RPAREN
)
)
);
}
}
function stringifyTruncated(
bytes32 input
)
private
pure
returns (bytes memory)
{
bytes memory result = abi.encodePacked(input);
for (uint256 i = 32; i > 0; ) {
i--;
if (result[i] != 0) {
uint256 length = i + 1;
assembly {
mstore(result, length)
}
return result;
}
}
return new bytes(0);
}
function stringify(
uint256 input
)
private
pure
returns (bytes memory)
{
if (input == 0) {
return "0";
}
uint256 j = input;
uint256 length;
while (j != 0) {
length++;
j /= 10;
}
bytes memory bstr = new bytes(length);
j = input;
for (uint256 i = length; i > 0; ) {
i--;
bstr[i] = byte(uint8(ASCII_ZERO + (j % 10)));
j /= 10;
}
return bstr;
}
function stringify(
address input
)
private
pure
returns (bytes memory)
{
uint256 z = uint256(input);
bytes memory result = new bytes(42);
result[0] = byte(uint8(ASCII_ZERO));
result[1] = byte(uint8(ASCII_LOWER_EX));
for (uint256 i = 0; i < 20; i++) {
uint256 shift = i * 2;
result[41 - shift] = char(z & FOUR_BIT_MASK);
z = z >> 4;
result[40 - shift] = char(z & FOUR_BIT_MASK);
z = z >> 4;
}
return result;
}
function stringify(
bytes32 input
)
private
pure
returns (bytes memory)
{
uint256 z = uint256(input);
bytes memory result = new bytes(66);
result[0] = byte(uint8(ASCII_ZERO));
result[1] = byte(uint8(ASCII_LOWER_EX));
for (uint256 i = 0; i < 32; i++) {
uint256 shift = i * 2;
result[65 - shift] = char(z & FOUR_BIT_MASK);
z = z >> 4;
result[64 - shift] = char(z & FOUR_BIT_MASK);
z = z >> 4;
}
return result;
}
function char(
uint256 input
)
private
pure
returns (byte)
{
if (input < 10) {
return byte(uint8(input + ASCII_ZERO));
}
return byte(uint8(input + ASCII_RELATIVE_ZERO));
}
}
文件 129 的 152:SafeERC20.sol
pragma solidity ^0.6.0;
import "../interfaces/ERC20.sol";
import "./Address.sol";
import "./SafeMath.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(ERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(ERC20 token, address spender, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(ERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(ERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(ERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 130 的 152:SafeMath.sol
pragma solidity ^0.6.0;
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;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
文件 131 的 152:SaverExchange.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../interfaces/GasTokenInterface.sol";
import "./SaverExchangeCore.sol";
import "../DS/DSMath.sol";
import "../loggers/DefisaverLogger.sol";
import "../auth/AdminAuth.sol";
import "../utils/GasBurner.sol";
import "../utils/SafeERC20.sol";
contract SaverExchange is SaverExchangeCore, AdminAuth, GasBurner {
using SafeERC20 for ERC20;
uint256 public constant SERVICE_FEE = 800;
DefisaverLogger public constant logger = DefisaverLogger(0x5c55B921f590a89C1Ebe84dF170E655a82b62126);
uint public burnAmount = 10;
function sell(ExchangeData memory exData, address payable _user) public payable burnGas(burnAmount) {
uint dfsFee = getFee(exData.srcAmount, exData.srcAddr);
exData.srcAmount = sub(exData.srcAmount, dfsFee);
(address wrapper, uint destAmount) = _sell(exData);
sendLeftover(exData.srcAddr, exData.destAddr, _user);
logger.Log(address(this), msg.sender, "ExchangeSell", abi.encode(wrapper, exData.srcAddr, exData.destAddr, exData.srcAmount, destAmount));
}
function buy(ExchangeData memory exData, address payable _user) public payable burnGas(burnAmount){
uint dfsFee = getFee(exData.srcAmount, exData.srcAddr);
exData.srcAmount = sub(exData.srcAmount, dfsFee);
(address wrapper, uint srcAmount) = _buy(exData);
sendLeftover(exData.srcAddr, exData.destAddr, _user);
logger.Log(address(this), msg.sender, "ExchangeBuy", abi.encode(wrapper, exData.srcAddr, exData.destAddr, srcAmount, exData.destAmount));
}
function getFee(uint256 _amount, address _token) internal returns (uint256 feeAmount) {
uint256 fee = SERVICE_FEE;
if (Discount(DISCOUNT_ADDRESS).isCustomFeeSet(msg.sender)) {
fee = Discount(DISCOUNT_ADDRESS).getCustomServiceFee(msg.sender);
}
if (fee == 0) {
feeAmount = 0;
} else {
feeAmount = _amount / fee;
if (_token == KYBER_ETH_ADDRESS) {
WALLET_ID.transfer(feeAmount);
} else {
ERC20(_token).safeTransfer(WALLET_ID, feeAmount);
}
}
}
function changeBurnAmount(uint _newBurnAmount) public {
require(owner == msg.sender);
burnAmount = _newBurnAmount;
}
}
文件 132 的 152:SaverExchangeCore.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../DS/DSMath.sol";
import "../interfaces/TokenInterface.sol";
import "../interfaces/ExchangeInterfaceV2.sol";
import "../utils/ZrxAllowlist.sol";
import "./SaverExchangeHelper.sol";
import "./SaverExchangeRegistry.sol";
contract SaverExchangeCore is SaverExchangeHelper, DSMath {
enum ExchangeType { _, OASIS, KYBER, UNISWAP, ZEROX }
enum ActionType { SELL, BUY }
struct ExchangeData {
address srcAddr;
address destAddr;
uint srcAmount;
uint destAmount;
uint minPrice;
address wrapper;
address exchangeAddr;
bytes callData;
uint256 price0x;
}
function _sell(ExchangeData memory exData) internal returns (address, uint) {
address wrapper;
uint swapedTokens;
bool success;
uint tokensLeft = exData.srcAmount;
if (exData.srcAddr == KYBER_ETH_ADDRESS) {
exData.srcAddr = ethToWethAddr(exData.srcAddr);
TokenInterface(WETH_ADDRESS).deposit.value(exData.srcAmount)();
}
if (exData.price0x > 0) {
approve0xProxy(exData.srcAddr, exData.srcAmount);
uint ethAmount = getProtocolFee(exData.srcAddr, msg.value, exData.srcAmount);
(success, swapedTokens, tokensLeft) = takeOrder(exData, ethAmount, ActionType.SELL);
if (success) {
wrapper = exData.exchangeAddr;
}
}
if (!success) {
swapedTokens = saverSwap(exData, ActionType.SELL);
wrapper = exData.wrapper;
}
require(getBalance(exData.destAddr) >= wmul(exData.minPrice, exData.srcAmount), "Final amount isn't correct");
if (getBalance(WETH_ADDRESS) > 0) {
TokenInterface(WETH_ADDRESS).withdraw(
TokenInterface(WETH_ADDRESS).balanceOf(address(this))
);
}
return (wrapper, swapedTokens);
}
function _buy(ExchangeData memory exData) internal returns (address, uint) {
address wrapper;
uint swapedTokens;
bool success;
require(exData.destAmount != 0, "Dest amount must be specified");
if (exData.srcAddr == KYBER_ETH_ADDRESS) {
exData.srcAddr = ethToWethAddr(exData.srcAddr);
TokenInterface(WETH_ADDRESS).deposit.value(exData.srcAmount)();
}
if (exData.price0x > 0) {
approve0xProxy(exData.srcAddr, exData.srcAmount);
uint ethAmount = getProtocolFee(exData.srcAddr, msg.value, exData.srcAmount);
(success, swapedTokens,) = takeOrder(exData, ethAmount, ActionType.BUY);
if (success) {
wrapper = exData.exchangeAddr;
}
}
if (!success) {
swapedTokens = saverSwap(exData, ActionType.BUY);
wrapper = exData.wrapper;
}
require(swapedTokens >= exData.destAmount, "Final amount isn't correct");
if (getBalance(WETH_ADDRESS) > 0) {
TokenInterface(WETH_ADDRESS).withdraw(
TokenInterface(WETH_ADDRESS).balanceOf(address(this))
);
}
return (wrapper, getBalance(exData.destAddr));
}
function takeOrder(
ExchangeData memory _exData,
uint256 _ethAmount,
ActionType _type
) private returns (bool success, uint256, uint256) {
if (_type == ActionType.SELL) {
writeUint256(_exData.callData, 36, _exData.srcAmount);
} else {
writeUint256(_exData.callData, 36, _exData.destAmount);
}
if (ZrxAllowlist(ZRX_ALLOWLIST_ADDR).isNonPayableAddr(_exData.exchangeAddr)) {
_ethAmount = 0;
}
uint256 tokensBefore = getBalance(_exData.destAddr);
if (ZrxAllowlist(ZRX_ALLOWLIST_ADDR).isZrxAddr(_exData.exchangeAddr)) {
(success, ) = _exData.exchangeAddr.call{value: _ethAmount}(_exData.callData);
} else {
success = false;
}
uint256 tokensSwaped = 0;
uint256 tokensLeft = _exData.srcAmount;
if (success) {
tokensLeft = getBalance(_exData.srcAddr);
if (_exData.destAddr == KYBER_ETH_ADDRESS) {
TokenInterface(WETH_ADDRESS).withdraw(
TokenInterface(WETH_ADDRESS).balanceOf(address(this))
);
}
tokensSwaped = getBalance(_exData.destAddr) - tokensBefore;
}
return (success, tokensSwaped, tokensLeft);
}
function saverSwap(ExchangeData memory _exData, ActionType _type) internal returns (uint swapedTokens) {
require(SaverExchangeRegistry(SAVER_EXCHANGE_REGISTRY).isWrapper(_exData.wrapper), "Wrapper is not valid");
uint ethValue = 0;
ERC20(_exData.srcAddr).safeTransfer(_exData.wrapper, _exData.srcAmount);
if (_type == ActionType.SELL) {
swapedTokens = ExchangeInterfaceV2(_exData.wrapper).
sell{value: ethValue}(_exData.srcAddr, _exData.destAddr, _exData.srcAmount);
} else {
swapedTokens = ExchangeInterfaceV2(_exData.wrapper).
buy{value: ethValue}(_exData.srcAddr, _exData.destAddr, _exData.destAmount);
}
}
function writeUint256(bytes memory _b, uint256 _index, uint _input) internal pure {
if (_b.length < _index + 32) {
revert("Incorrent lengt while writting bytes32");
}
bytes32 input = bytes32(_input);
_index += 32;
assembly {
mstore(add(_b, _index), input)
}
}
function ethToWethAddr(address _src) internal pure returns (address) {
return _src == KYBER_ETH_ADDRESS ? WETH_ADDRESS : _src;
}
function getProtocolFee(address _srcAddr, uint256 _msgValue, uint256 _srcAmount) internal returns(uint256) {
if (_srcAddr != WETH_ADDRESS) return _msgValue;
if (_msgValue > _srcAmount) return _msgValue - _srcAmount;
return _msgValue;
}
function packExchangeData(ExchangeData memory _exData) public pure returns(bytes memory) {
bytes memory part1 = abi.encode(
_exData.srcAddr,
_exData.destAddr,
_exData.srcAmount,
_exData.destAmount
);
bytes memory part2 = abi.encode(
_exData.minPrice,
_exData.wrapper,
_exData.exchangeAddr,
_exData.callData,
_exData.price0x
);
return abi.encode(part1, part2);
}
function unpackExchangeData(bytes memory _data) public pure returns(ExchangeData memory _exData) {
(
bytes memory part1,
bytes memory part2
) = abi.decode(_data, (bytes,bytes));
(
_exData.srcAddr,
_exData.destAddr,
_exData.srcAmount,
_exData.destAmount
) = abi.decode(part1, (address,address,uint256,uint256));
(
_exData.minPrice,
_exData.wrapper,
_exData.exchangeAddr,
_exData.callData,
_exData.price0x
)
= abi.decode(part2, (uint256,address,address,bytes,uint256));
}
receive() external virtual payable {}
}
文件 133 的 152:SaverExchangeHelper.sol
pragma solidity ^0.6.0;
import "../utils/SafeERC20.sol";
import "../utils/Discount.sol";
contract SaverExchangeHelper {
using SafeERC20 for ERC20;
address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address payable public constant WALLET_ID = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08;
address public constant DISCOUNT_ADDRESS = 0x1b14E8D511c9A4395425314f849bD737BAF8208F;
address public constant SAVER_EXCHANGE_REGISTRY = 0x25dd3F51e0C3c3Ff164DDC02A8E4D65Bb9cBB12D;
address public constant ERC20_PROXY_0X = 0x95E6F48254609A6ee006F7D493c8e5fB97094ceF;
address public constant ZRX_ALLOWLIST_ADDR = 0x4BA1f38427b33B8ab7Bb0490200dAE1F1C36823F;
function getDecimals(address _token) internal view returns (uint256) {
if (_token == KYBER_ETH_ADDRESS) return 18;
return ERC20(_token).decimals();
}
function getBalance(address _tokenAddr) internal view returns (uint balance) {
if (_tokenAddr == KYBER_ETH_ADDRESS) {
balance = address(this).balance;
} else {
balance = ERC20(_tokenAddr).balanceOf(address(this));
}
}
function approve0xProxy(address _tokenAddr, uint _amount) internal {
if (_tokenAddr != KYBER_ETH_ADDRESS) {
ERC20(_tokenAddr).safeApprove(address(ERC20_PROXY_0X), _amount);
}
}
function sendLeftover(address _srcAddr, address _destAddr, address payable _to) internal {
if (address(this).balance > 0) {
_to.transfer(address(this).balance);
}
if (getBalance(_srcAddr) > 0) {
ERC20(_srcAddr).safeTransfer(_to, getBalance(_srcAddr));
}
if (getBalance(_destAddr) > 0) {
ERC20(_destAddr).safeTransfer(_to, getBalance(_destAddr));
}
}
function sliceUint(bytes memory bs, uint256 start) internal pure returns (uint256) {
require(bs.length >= start + 32, "slicing out of range");
uint256 x;
assembly {
x := mload(add(bs, add(0x20, start)))
}
return x;
}
}
文件 134 的 152:SaverExchangeInterface.sol
pragma solidity ^0.6.0;
abstract contract SaverExchangeInterface {
function getBestPrice(
uint256 _amount,
address _srcToken,
address _destToken,
uint256 _exchangeType
) public view virtual returns (address, uint256);
}
文件 135 的 152:SaverExchangeRegistry.sol
pragma solidity ^0.6.0;
import "../auth/AdminAuth.sol";
contract SaverExchangeRegistry is AdminAuth {
mapping(address => bool) private wrappers;
constructor() public {
wrappers[0x880A845A85F843a5c67DB2061623c6Fc3bB4c511] = true;
wrappers[0x4c9B55f2083629A1F7aDa257ae984E03096eCD25] = true;
wrappers[0x42A9237b872368E1bec4Ca8D26A928D7d39d338C] = true;
}
function addWrapper(address _wrapper) public onlyOwner {
wrappers[_wrapper] = true;
}
function removeWrapper(address _wrapper) public onlyOwner {
wrappers[_wrapper] = false;
}
function isWrapper(address _wrapper) public view returns(bool) {
return wrappers[_wrapper];
}
}
文件 136 的 152:SaverProxyActions.sol
pragma solidity ^0.6.0;
abstract contract GemLike {
function approve(address, uint) virtual public;
function transfer(address, uint) virtual public;
function transferFrom(address, address, uint) virtual public;
function deposit() virtual public payable;
function withdraw(uint) virtual public;
}
abstract contract ManagerLike {
function cdpCan(address, uint, address) virtual public view returns (uint);
function ilks(uint) virtual public view returns (bytes32);
function owns(uint) virtual public view returns (address);
function urns(uint) virtual public view returns (address);
function vat() virtual public view returns (address);
function open(bytes32, address) virtual public returns (uint);
function give(uint, address) virtual public;
function cdpAllow(uint, address, uint) virtual public;
function urnAllow(address, uint) virtual public;
function frob(uint, int, int) virtual public;
function flux(uint, address, uint) virtual public;
function move(uint, address, uint) virtual public;
function exit(address, uint, address, uint) virtual public;
function quit(uint, address) virtual public;
function enter(address, uint) virtual public;
function shift(uint, uint) virtual public;
}
abstract contract VatLike {
function can(address, address) virtual public view returns (uint);
function ilks(bytes32) virtual public view returns (uint, uint, uint, uint, uint);
function dai(address) virtual public view returns (uint);
function urns(bytes32, address) virtual public view returns (uint, uint);
function frob(bytes32, address, address, address, int, int) virtual public;
function hope(address) virtual public;
function move(address, address, uint) virtual public;
}
abstract contract GemJoinLike {
function dec() virtual public returns (uint);
function gem() virtual public returns (GemLike);
function join(address, uint) virtual public payable;
function exit(address, uint) virtual public;
}
abstract contract GNTJoinLike {
function bags(address) virtual public view returns (address);
function make(address) virtual public returns (address);
}
abstract contract DaiJoinLike {
function vat() virtual public returns (VatLike);
function dai() virtual public returns (GemLike);
function join(address, uint) virtual public payable;
function exit(address, uint) virtual public;
}
abstract contract HopeLike {
function hope(address) virtual public;
function nope(address) virtual public;
}
abstract contract ProxyRegistryInterface {
function proxies(address _owner) virtual public view returns (address);
function build(address) virtual public returns (address);
}
abstract contract EndLike {
function fix(bytes32) virtual public view returns (uint);
function cash(bytes32, uint) virtual public;
function free(bytes32) virtual public;
function pack(uint) virtual public;
function skim(bytes32, address) virtual public;
}
abstract contract JugLike {
function drip(bytes32) virtual public returns (uint);
}
abstract contract PotLike {
function pie(address) virtual public view returns (uint);
function drip() virtual public returns (uint);
function join(uint) virtual public;
function exit(uint) virtual public;
}
abstract contract ProxyRegistryLike {
function proxies(address) virtual public view returns (address);
function build(address) virtual public returns (address);
}
abstract contract ProxyLike {
function owner() virtual public view returns (address);
}
abstract contract DSProxy {
function execute(address _target, bytes memory _data) virtual public payable returns (bytes32);
function setOwner(address owner_) virtual public;
}
contract Common {
uint256 constant RAY = 10 ** 27;
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, "mul-overflow");
}
function daiJoin_join(address apt, address urn, uint wad) public {
DaiJoinLike(apt).dai().transferFrom(msg.sender, address(this), wad);
DaiJoinLike(apt).dai().approve(apt, wad);
DaiJoinLike(apt).join(urn, wad);
}
}
contract SaverProxyActions is Common {
event CDPAction(string indexed, uint indexed, uint, uint);
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x, "sub-overflow");
}
function toInt(uint x) internal pure returns (int y) {
y = int(x);
require(y >= 0, "int-overflow");
}
function toRad(uint wad) internal pure returns (uint rad) {
rad = mul(wad, 10 ** 27);
}
function convertTo18(address gemJoin, uint256 amt) internal returns (uint256 wad) {
wad = mul(
amt,
10 ** (18 - GemJoinLike(gemJoin).dec())
);
}
function _getDrawDart(
address vat,
address jug,
address urn,
bytes32 ilk,
uint wad
) internal returns (int dart) {
uint rate = JugLike(jug).drip(ilk);
uint dai = VatLike(vat).dai(urn);
if (dai < mul(wad, RAY)) {
dart = toInt(sub(mul(wad, RAY), dai) / rate);
dart = mul(uint(dart), rate) < mul(wad, RAY) ? dart + 1 : dart;
}
}
function _getWipeDart(
address vat,
uint dai,
address urn,
bytes32 ilk
) internal view returns (int dart) {
(, uint rate,,,) = VatLike(vat).ilks(ilk);
(, uint art) = VatLike(vat).urns(ilk, urn);
dart = toInt(dai / rate);
dart = uint(dart) <= art ? - dart : - toInt(art);
}
function _getWipeAllWad(
address vat,
address usr,
address urn,
bytes32 ilk
) internal view returns (uint wad) {
(, uint rate,,,) = VatLike(vat).ilks(ilk);
(, uint art) = VatLike(vat).urns(ilk, urn);
uint dai = VatLike(vat).dai(usr);
uint rad = sub(mul(art, rate), dai);
wad = rad / RAY;
wad = mul(wad, RAY) < rad ? wad + 1 : wad;
}
function transfer(address gem, address dst, uint wad) public {
GemLike(gem).transfer(dst, wad);
}
function ethJoin_join(address apt, address urn) public payable {
GemJoinLike(apt).gem().deposit{value: msg.value}();
GemJoinLike(apt).gem().approve(address(apt), msg.value);
GemJoinLike(apt).join(urn, msg.value);
}
function gemJoin_join(address apt, address urn, uint wad, bool transferFrom) public {
if (transferFrom) {
GemJoinLike(apt).gem().transferFrom(msg.sender, address(this), wad);
GemJoinLike(apt).gem().approve(apt, 0);
GemJoinLike(apt).gem().approve(apt, wad);
}
GemJoinLike(apt).join(urn, wad);
}
function hope(
address obj,
address usr
) public {
HopeLike(obj).hope(usr);
}
function nope(
address obj,
address usr
) public {
HopeLike(obj).nope(usr);
}
function open(
address manager,
bytes32 ilk,
address usr
) public returns (uint cdp) {
cdp = ManagerLike(manager).open(ilk, usr);
}
function give(
address manager,
uint cdp,
address usr
) public {
ManagerLike(manager).give(cdp, usr);
emit CDPAction('give', cdp, 0, 0);
}
function giveToProxy(
address proxyRegistry,
address manager,
uint cdp,
address dst
) public {
address proxy = ProxyRegistryLike(proxyRegistry).proxies(dst);
if (proxy == address(0) || ProxyLike(proxy).owner() != dst) {
uint csize;
assembly {
csize := extcodesize(dst)
}
require(csize == 0, "Dst-is-a-contract");
proxy = ProxyRegistryLike(proxyRegistry).build(dst);
}
give(manager, cdp, proxy);
}
function cdpAllow(
address manager,
uint cdp,
address usr,
uint ok
) public {
ManagerLike(manager).cdpAllow(cdp, usr, ok);
}
function urnAllow(
address manager,
address usr,
uint ok
) public {
ManagerLike(manager).urnAllow(usr, ok);
}
function flux(
address manager,
uint cdp,
address dst,
uint wad
) public {
ManagerLike(manager).flux(cdp, dst, wad);
}
function move(
address manager,
uint cdp,
address dst,
uint rad
) public {
ManagerLike(manager).move(cdp, dst, rad);
}
function frob(
address manager,
uint cdp,
int dink,
int dart
) public {
ManagerLike(manager).frob(cdp, dink, dart);
}
function quit(
address manager,
uint cdp,
address dst
) public {
ManagerLike(manager).quit(cdp, dst);
}
function enter(
address manager,
address src,
uint cdp
) public {
ManagerLike(manager).enter(src, cdp);
}
function shift(
address manager,
uint cdpSrc,
uint cdpOrg
) public {
ManagerLike(manager).shift(cdpSrc, cdpOrg);
}
function makeGemBag(
address gemJoin
) public returns (address bag) {
bag = GNTJoinLike(gemJoin).make(address(this));
}
function lockETH(
address manager,
address ethJoin,
uint cdp
) public payable {
ethJoin_join(ethJoin, address(this));
VatLike(ManagerLike(manager).vat()).frob(
ManagerLike(manager).ilks(cdp),
ManagerLike(manager).urns(cdp),
address(this),
address(this),
toInt(msg.value),
0
);
emit CDPAction('lockETH', cdp, msg.value, 0);
}
function lockGem(
address manager,
address gemJoin,
uint cdp,
uint wad,
bool transferFrom
) public {
gemJoin_join(gemJoin, address(this), wad, transferFrom);
VatLike(ManagerLike(manager).vat()).frob(
ManagerLike(manager).ilks(cdp),
ManagerLike(manager).urns(cdp),
address(this),
address(this),
toInt(convertTo18(gemJoin, wad)),
0
);
emit CDPAction('lockGem', cdp, wad, 0);
}
function freeETH(
address manager,
address ethJoin,
uint cdp,
uint wad
) public {
frob(manager, cdp, -toInt(wad), 0);
flux(manager, cdp, address(this), wad);
GemJoinLike(ethJoin).exit(address(this), wad);
GemJoinLike(ethJoin).gem().withdraw(wad);
msg.sender.transfer(wad);
emit CDPAction('freeETH', cdp, wad, 0);
}
function freeGem(
address manager,
address gemJoin,
uint cdp,
uint wad
) public {
uint wad18 = convertTo18(gemJoin, wad);
frob(manager, cdp, -toInt(wad18), 0);
flux(manager, cdp, address(this), wad18);
GemJoinLike(gemJoin).exit(msg.sender, wad);
emit CDPAction('freeGem', cdp, wad, 0);
}
function exitETH(
address manager,
address ethJoin,
uint cdp,
uint wad
) public {
flux(manager, cdp, address(this), wad);
GemJoinLike(ethJoin).exit(address(this), wad);
GemJoinLike(ethJoin).gem().withdraw(wad);
msg.sender.transfer(wad);
}
function exitGem(
address manager,
address gemJoin,
uint cdp,
uint wad
) public {
flux(manager, cdp, address(this), convertTo18(gemJoin, wad));
GemJoinLike(gemJoin).exit(msg.sender, wad);
}
function draw(
address manager,
address jug,
address daiJoin,
uint cdp,
uint wad
) public {
address urn = ManagerLike(manager).urns(cdp);
address vat = ManagerLike(manager).vat();
bytes32 ilk = ManagerLike(manager).ilks(cdp);
frob(manager, cdp, 0, _getDrawDart(vat, jug, urn, ilk, wad));
move(manager, cdp, address(this), toRad(wad));
if (VatLike(vat).can(address(this), address(daiJoin)) == 0) {
VatLike(vat).hope(daiJoin);
}
DaiJoinLike(daiJoin).exit(msg.sender, wad);
emit CDPAction('draw', cdp, 0, wad);
}
function wipe(
address manager,
address daiJoin,
uint cdp,
uint wad
) public {
address vat = ManagerLike(manager).vat();
address urn = ManagerLike(manager).urns(cdp);
bytes32 ilk = ManagerLike(manager).ilks(cdp);
address own = ManagerLike(manager).owns(cdp);
if (own == address(this) || ManagerLike(manager).cdpCan(own, cdp, address(this)) == 1) {
daiJoin_join(daiJoin, urn, wad);
frob(manager, cdp, 0, _getWipeDart(vat, VatLike(vat).dai(urn), urn, ilk));
} else {
daiJoin_join(daiJoin, address(this), wad);
VatLike(vat).frob(
ilk,
urn,
address(this),
address(this),
0,
_getWipeDart(vat, wad * RAY, urn, ilk)
);
}
emit CDPAction('wipe', cdp, 0, wad);
}
function wipeAll(
address manager,
address daiJoin,
uint cdp
) public {
address vat = ManagerLike(manager).vat();
address urn = ManagerLike(manager).urns(cdp);
bytes32 ilk = ManagerLike(manager).ilks(cdp);
(, uint art) = VatLike(vat).urns(ilk, urn);
address own = ManagerLike(manager).owns(cdp);
if (own == address(this) || ManagerLike(manager).cdpCan(own, cdp, address(this)) == 1) {
daiJoin_join(daiJoin, urn, _getWipeAllWad(vat, urn, urn, ilk));
frob(manager, cdp, 0, -int(art));
} else {
daiJoin_join(daiJoin, address(this), _getWipeAllWad(vat, address(this), urn, ilk));
VatLike(vat).frob(
ilk,
urn,
address(this),
address(this),
0,
-int(art)
);
}
emit CDPAction('wipeAll', cdp, 0, art);
}
function lockETHAndDraw(
address manager,
address jug,
address ethJoin,
address daiJoin,
uint cdp,
uint wadD
) public payable {
address urn = ManagerLike(manager).urns(cdp);
address vat = ManagerLike(manager).vat();
bytes32 ilk = ManagerLike(manager).ilks(cdp);
ethJoin_join(ethJoin, urn);
frob(manager, cdp, toInt(msg.value), _getDrawDart(vat, jug, urn, ilk, wadD));
move(manager, cdp, address(this), toRad(wadD));
if (VatLike(vat).can(address(this), address(daiJoin)) == 0) {
VatLike(vat).hope(daiJoin);
}
DaiJoinLike(daiJoin).exit(msg.sender, wadD);
}
function openLockETHAndDraw(
address manager,
address jug,
address ethJoin,
address daiJoin,
bytes32 ilk,
uint wadD
) public payable returns (uint cdp) {
cdp = open(manager, ilk, address(this));
lockETHAndDraw(manager, jug, ethJoin, daiJoin, cdp, wadD);
emit CDPAction('openLockETHAndDraw', cdp, msg.value, wadD);
}
function lockGemAndDraw(
address manager,
address jug,
address gemJoin,
address daiJoin,
uint cdp,
uint wadC,
uint wadD,
bool transferFrom
) public {
address urn = ManagerLike(manager).urns(cdp);
address vat = ManagerLike(manager).vat();
bytes32 ilk = ManagerLike(manager).ilks(cdp);
gemJoin_join(gemJoin, urn, wadC, transferFrom);
frob(manager, cdp, toInt(convertTo18(gemJoin, wadC)), _getDrawDart(vat, jug, urn, ilk, wadD));
move(manager, cdp, address(this), toRad(wadD));
if (VatLike(vat).can(address(this), address(daiJoin)) == 0) {
VatLike(vat).hope(daiJoin);
}
DaiJoinLike(daiJoin).exit(msg.sender, wadD);
}
function openLockGemAndDraw(
address manager,
address jug,
address gemJoin,
address daiJoin,
bytes32 ilk,
uint wadC,
uint wadD,
bool transferFrom
) public returns (uint cdp) {
cdp = open(manager, ilk, address(this));
lockGemAndDraw(manager, jug, gemJoin, daiJoin, cdp, wadC, wadD, transferFrom);
emit CDPAction('openLockGemAndDraw', cdp, wadC, wadD);
}
function wipeAllAndFreeETH(
address manager,
address ethJoin,
address daiJoin,
uint cdp,
uint wadC
) public {
address vat = ManagerLike(manager).vat();
address urn = ManagerLike(manager).urns(cdp);
bytes32 ilk = ManagerLike(manager).ilks(cdp);
(, uint art) = VatLike(vat).urns(ilk, urn);
daiJoin_join(daiJoin, urn, _getWipeAllWad(vat, urn, urn, ilk));
frob(
manager,
cdp,
-toInt(wadC),
-int(art)
);
flux(manager, cdp, address(this), wadC);
GemJoinLike(ethJoin).exit(address(this), wadC);
GemJoinLike(ethJoin).gem().withdraw(wadC);
msg.sender.transfer(wadC);
emit CDPAction('wipeAllAndFreeETH', cdp, wadC, art);
}
function wipeAndFreeGem(
address manager,
address gemJoin,
address daiJoin,
uint cdp,
uint wadC,
uint wadD
) public {
address urn = ManagerLike(manager).urns(cdp);
daiJoin_join(daiJoin, urn, wadD);
uint wad18 = convertTo18(gemJoin, wadC);
frob(
manager,
cdp,
-toInt(wad18),
_getWipeDart(ManagerLike(manager).vat(), VatLike(ManagerLike(manager).vat()).dai(urn), urn, ManagerLike(manager).ilks(cdp))
);
flux(manager, cdp, address(this), wad18);
GemJoinLike(gemJoin).exit(msg.sender, wadC);
}
function wipeAllAndFreeGem(
address manager,
address gemJoin,
address daiJoin,
uint cdp,
uint wadC
) public {
address vat = ManagerLike(manager).vat();
address urn = ManagerLike(manager).urns(cdp);
bytes32 ilk = ManagerLike(manager).ilks(cdp);
(, uint art) = VatLike(vat).urns(ilk, urn);
daiJoin_join(daiJoin, urn, _getWipeAllWad(vat, urn, urn, ilk));
uint wad18 = convertTo18(gemJoin, wadC);
frob(
manager,
cdp,
-toInt(wad18),
-int(art)
);
flux(manager, cdp, address(this), wad18);
GemJoinLike(gemJoin).exit(msg.sender, wadC);
emit CDPAction('wipeAllAndFreeGem', cdp, wadC, art);
}
function createProxyAndCDP(
address manager,
address jug,
address ethJoin,
address daiJoin,
bytes32 ilk,
uint wadD,
address registry
) public payable returns(uint) {
address proxy = ProxyRegistryInterface(registry).build(msg.sender);
uint cdp = openLockETHAndDraw(manager,
jug,
ethJoin,
daiJoin,
ilk,
wadD
);
give(manager, cdp, address(proxy));
return cdp;
}
function createProxyAndGemCDP(
address manager,
address jug,
address gemJoin,
address daiJoin,
bytes32 ilk,
uint wadC,
uint wadD,
bool transferFrom,
address registry
) public returns(uint) {
address proxy = ProxyRegistryInterface(registry).build(msg.sender);
uint cdp = openLockGemAndDraw(manager,
jug,
gemJoin,
daiJoin,
ilk,
wadC,
wadD,
transferFrom);
give(manager, cdp, address(proxy));
return cdp;
}
}
文件 137 的 152:SavingsLogger.sol
pragma solidity ^0.6.0;
contract SavingsLogger {
event Deposit(address indexed sender, uint8 protocol, uint256 amount);
event Withdraw(address indexed sender, uint8 protocol, uint256 amount);
event Swap(address indexed sender, uint8 fromProtocol, uint8 toProtocol, uint256 amount);
function logDeposit(address _sender, uint8 _protocol, uint256 _amount) external {
emit Deposit(_sender, _protocol, _amount);
}
function logWithdraw(address _sender, uint8 _protocol, uint256 _amount) external {
emit Withdraw(_sender, _protocol, _amount);
}
function logSwap(address _sender, uint8 _protocolFrom, uint8 _protocolTo, uint256 _amount)
external
{
emit Swap(_sender, _protocolFrom, _protocolTo, _amount);
}
}
文件 138 的 152:SavingsProxy.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./ProtocolInterface.sol";
import "../interfaces/ERC20.sol";
import "../interfaces/ITokenInterface.sol";
import "../interfaces/ComptrollerInterface.sol";
import "./dydx/ISoloMargin.sol";
import "./SavingsLogger.sol";
import "./dsr/DSRSavingsProtocol.sol";
import "./compound/CompoundSavingsProtocol.sol";
contract SavingsProxy is DSRSavingsProtocol, CompoundSavingsProtocol {
address public constant ADAI_ADDRESS = 0xfC1E690f61EFd961294b3e1Ce3313fBD8aa4f85d;
address public constant SAVINGS_DYDX_ADDRESS = 0x03b1565e070df392e48e7a8e01798C4B00E534A5;
address public constant SAVINGS_AAVE_ADDRESS = 0x535B9035E9bA8D7efe0FeAEac885fb65b303E37C;
address public constant NEW_IDAI_ADDRESS = 0x493C57C4763932315A328269E1ADaD09653B9081;
address public constant COMP_ADDRESS = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B;
address public constant SAVINGS_LOGGER_ADDRESS = 0x89b3635BD2bAD145C6f92E82C9e83f06D5654984;
address public constant SOLO_MARGIN_ADDRESS = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
enum SavingsProtocol {Compound, Dydx, Fulcrum, Dsr, Aave}
function deposit(SavingsProtocol _protocol, uint256 _amount) public {
if (_protocol == SavingsProtocol.Dsr) {
dsrDeposit(_amount, true);
} else if (_protocol == SavingsProtocol.Compound) {
compDeposit(msg.sender, _amount);
} else {
_deposit(_protocol, _amount, true);
}
SavingsLogger(SAVINGS_LOGGER_ADDRESS).logDeposit(msg.sender, uint8(_protocol), _amount);
}
function withdraw(SavingsProtocol _protocol, uint256 _amount) public {
if (_protocol == SavingsProtocol.Dsr) {
dsrWithdraw(_amount, true);
} else if (_protocol == SavingsProtocol.Compound) {
compWithdraw(msg.sender, _amount);
} else {
_withdraw(_protocol, _amount, true);
}
SavingsLogger(SAVINGS_LOGGER_ADDRESS).logWithdraw(msg.sender, uint8(_protocol), _amount);
}
function swap(SavingsProtocol _from, SavingsProtocol _to, uint256 _amount) public {
if (_from == SavingsProtocol.Dsr) {
dsrWithdraw(_amount, false);
} else if (_from == SavingsProtocol.Compound) {
compWithdraw(msg.sender, _amount);
} else {
_withdraw(_from, _amount, false);
}
uint256 amountToDeposit = ERC20(DAI_ADDRESS).balanceOf(address(this));
if (_to == SavingsProtocol.Dsr) {
dsrDeposit(amountToDeposit, false);
} else if (_from == SavingsProtocol.Compound) {
compDeposit(msg.sender, _amount);
} else {
_deposit(_to, amountToDeposit, false);
}
SavingsLogger(SAVINGS_LOGGER_ADDRESS).logSwap(
msg.sender,
uint8(_from),
uint8(_to),
_amount
);
}
function withdrawDai() public {
ERC20(DAI_ADDRESS).transfer(msg.sender, ERC20(DAI_ADDRESS).balanceOf(address(this)));
}
function claimComp() public {
ComptrollerInterface(COMP_ADDRESS).claimComp(address(this));
}
function getAddress(SavingsProtocol _protocol) public pure returns (address) {
if (_protocol == SavingsProtocol.Dydx) {
return SAVINGS_DYDX_ADDRESS;
}
if (_protocol == SavingsProtocol.Aave) {
return SAVINGS_AAVE_ADDRESS;
}
}
function _deposit(SavingsProtocol _protocol, uint256 _amount, bool _fromUser) internal {
if (_fromUser) {
ERC20(DAI_ADDRESS).transferFrom(msg.sender, address(this), _amount);
}
approveDeposit(_protocol);
ProtocolInterface(getAddress(_protocol)).deposit(address(this), _amount);
endAction(_protocol);
}
function _withdraw(SavingsProtocol _protocol, uint256 _amount, bool _toUser) public {
approveWithdraw(_protocol);
ProtocolInterface(getAddress(_protocol)).withdraw(address(this), _amount);
endAction(_protocol);
if (_toUser) {
withdrawDai();
}
}
function endAction(SavingsProtocol _protocol) internal {
if (_protocol == SavingsProtocol.Dydx) {
setDydxOperator(false);
}
}
function approveDeposit(SavingsProtocol _protocol) internal {
if (_protocol == SavingsProtocol.Compound || _protocol == SavingsProtocol.Fulcrum || _protocol == SavingsProtocol.Aave) {
ERC20(DAI_ADDRESS).approve(getAddress(_protocol), uint256(-1));
}
if (_protocol == SavingsProtocol.Dydx) {
ERC20(DAI_ADDRESS).approve(SOLO_MARGIN_ADDRESS, uint256(-1));
setDydxOperator(true);
}
}
function approveWithdraw(SavingsProtocol _protocol) internal {
if (_protocol == SavingsProtocol.Compound) {
ERC20(NEW_CDAI_ADDRESS).approve(getAddress(_protocol), uint256(-1));
}
if (_protocol == SavingsProtocol.Dydx) {
setDydxOperator(true);
}
if (_protocol == SavingsProtocol.Fulcrum) {
ERC20(NEW_IDAI_ADDRESS).approve(getAddress(_protocol), uint256(-1));
}
if (_protocol == SavingsProtocol.Aave) {
ERC20(ADAI_ADDRESS).approve(getAddress(_protocol), uint256(-1));
}
}
function setDydxOperator(bool _trusted) internal {
ISoloMargin.OperatorArg[] memory operatorArgs = new ISoloMargin.OperatorArg[](1);
operatorArgs[0] = ISoloMargin.OperatorArg({
operator: getAddress(SavingsProtocol.Dydx),
trusted: _trusted
});
ISoloMargin(SOLO_MARGIN_ADDRESS).setOperators(operatorArgs);
}
}
文件 139 的 152:ShifterRegistry.sol
pragma solidity ^0.6.0;
import "../auth/AdminAuth.sol";
contract ShifterRegistry is AdminAuth {
mapping (string => address) public contractAddresses;
bool public finalized;
function changeContractAddr(string memory _contractName, address _protoAddr) public onlyOwner {
require(!finalized);
contractAddresses[_contractName] = _protoAddr;
}
function lock() public onlyOwner {
finalized = true;
}
function getAddr(string memory _contractName) public view returns (address contractAddr) {
contractAddr = contractAddresses[_contractName];
require(contractAddr != address(0), "No contract address registred");
}
}
文件 140 的 152:Spotter.sol
pragma solidity ^0.6.0;
import "./PipInterface.sol";
abstract contract Spotter {
struct Ilk {
PipInterface pip;
uint256 mat;
}
mapping (bytes32 => Ilk) public ilks;
uint256 public par;
}
文件 141 的 152:StaticV2.sol
pragma solidity ^0.6.0;
abstract contract StaticV2 {
enum Method { Boost, Repay }
struct CdpHolder {
uint128 minRatio;
uint128 maxRatio;
uint128 optimalRatioBoost;
uint128 optimalRatioRepay;
address owner;
uint cdpId;
bool boostEnabled;
bool nextPriceEnabled;
}
struct SubPosition {
uint arrPos;
bool subscribed;
}
}
文件 142 的 152:SubscriptionsProxyV2.sol
pragma solidity ^0.6.0;
import "../../DS/DSGuard.sol";
import "../../DS/DSAuth.sol";
contract SubscriptionsInterfaceV2 {
function subscribe(uint _cdpId, uint128 _minRatio, uint128 _maxRatio, uint128 _optimalBoost, uint128 _optimalRepay, bool _boostEnabled, bool _nextPriceEnabled) external {}
function unsubscribe(uint _cdpId) external {}
}
contract SubscriptionsProxyV2 {
address public constant MONITOR_PROXY_ADDRESS = 0x7456f4218874eAe1aF8B83a64848A1B89fEB7d7C;
address public constant OLD_SUBSCRIPTION = 0x83152CAA0d344a2Fd428769529e2d490A88f4393;
address public constant FACTORY_ADDRESS = 0x5a15566417e6C1c9546523066500bDDBc53F88C7;
function migrate(uint _cdpId, uint128 _minRatio, uint128 _maxRatio, uint128 _optimalRatioBoost, uint128 _optimalRatioRepay, bool _boostEnabled, bool _nextPriceEnabled, address _subscriptions) public {
SubscriptionsInterfaceV2(OLD_SUBSCRIPTION).unsubscribe(_cdpId);
subscribe(_cdpId, _minRatio, _maxRatio, _optimalRatioBoost, _optimalRatioRepay, _boostEnabled, _nextPriceEnabled, _subscriptions);
}
function subscribe(uint _cdpId, uint128 _minRatio, uint128 _maxRatio, uint128 _optimalRatioBoost, uint128 _optimalRatioRepay, bool _boostEnabled, bool _nextPriceEnabled, address _subscriptions) public {
address currAuthority = address(DSAuth(address(this)).authority());
DSGuard guard = DSGuard(currAuthority);
if (currAuthority == address(0)) {
guard = DSGuardFactory(FACTORY_ADDRESS).newGuard();
DSAuth(address(this)).setAuthority(DSAuthority(address(guard)));
}
guard.permit(MONITOR_PROXY_ADDRESS, address(this), bytes4(keccak256("execute(address,bytes)")));
SubscriptionsInterfaceV2(_subscriptions).subscribe(_cdpId, _minRatio, _maxRatio, _optimalRatioBoost, _optimalRatioRepay, _boostEnabled, _nextPriceEnabled);
}
function update(uint _cdpId, uint128 _minRatio, uint128 _maxRatio, uint128 _optimalRatioBoost, uint128 _optimalRatioRepay, bool _boostEnabled, bool _nextPriceEnabled, address _subscriptions) public {
SubscriptionsInterfaceV2(_subscriptions).subscribe(_cdpId, _minRatio, _maxRatio, _optimalRatioBoost, _optimalRatioRepay, _boostEnabled, _nextPriceEnabled);
}
function unsubscribe(uint _cdpId, address _subscriptions) public {
SubscriptionsInterfaceV2(_subscriptions).unsubscribe(_cdpId);
}
}
文件 143 的 152:SubscriptionsV2.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../../interfaces/Manager.sol";
import "./StaticV2.sol";
import "../saver/MCDSaverProxy.sol";
import "../../interfaces/Vat.sol";
import "../../interfaces/Spotter.sol";
import "../../auth/AdminAuth.sol";
contract SubscriptionsV2 is AdminAuth, StaticV2 {
bytes32 internal constant ETH_ILK = 0x4554482d41000000000000000000000000000000000000000000000000000000;
bytes32 internal constant BAT_ILK = 0x4241542d41000000000000000000000000000000000000000000000000000000;
address public constant MANAGER_ADDRESS = 0x5ef30b9986345249bc32d8928B7ee64DE9435E39;
address public constant VAT_ADDRESS = 0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B;
address public constant SPOTTER_ADDRESS = 0x65C79fcB50Ca1594B025960e539eD7A9a6D434A3;
CdpHolder[] public subscribers;
mapping (uint => SubPosition) public subscribersPos;
mapping (bytes32 => uint) public minLimits;
uint public changeIndex;
Manager public manager = Manager(MANAGER_ADDRESS);
Vat public vat = Vat(VAT_ADDRESS);
Spotter public spotter = Spotter(SPOTTER_ADDRESS);
MCDSaverProxy public saverProxy;
event Subscribed(address indexed owner, uint cdpId);
event Unsubscribed(address indexed owner, uint cdpId);
event Updated(address indexed owner, uint cdpId);
event ParamUpdates(address indexed owner, uint cdpId, uint128, uint128, uint128, uint128, bool boostEnabled);
constructor(address _saverProxy) public {
saverProxy = MCDSaverProxy(payable(_saverProxy));
minLimits[ETH_ILK] = 1700000000000000000;
minLimits[BAT_ILK] = 1700000000000000000;
}
function subscribe(uint _cdpId, uint128 _minRatio, uint128 _maxRatio, uint128 _optimalBoost, uint128 _optimalRepay, bool _boostEnabled, bool _nextPriceEnabled) external {
require(isOwner(msg.sender, _cdpId), "Must be called by Cdp owner");
uint128 localMaxRatio = _boostEnabled ? _maxRatio : uint128(-1);
require(checkParams(manager.ilks(_cdpId), _minRatio, localMaxRatio), "Must be correct params");
SubPosition storage subInfo = subscribersPos[_cdpId];
CdpHolder memory subscription = CdpHolder({
minRatio: _minRatio,
maxRatio: localMaxRatio,
optimalRatioBoost: _optimalBoost,
optimalRatioRepay: _optimalRepay,
owner: msg.sender,
cdpId: _cdpId,
boostEnabled: _boostEnabled,
nextPriceEnabled: _nextPriceEnabled
});
changeIndex++;
if (subInfo.subscribed) {
subscribers[subInfo.arrPos] = subscription;
emit Updated(msg.sender, _cdpId);
emit ParamUpdates(msg.sender, _cdpId, _minRatio, localMaxRatio, _optimalBoost, _optimalRepay, _boostEnabled);
} else {
subscribers.push(subscription);
subInfo.arrPos = subscribers.length - 1;
subInfo.subscribed = true;
emit Subscribed(msg.sender, _cdpId);
}
}
function unsubscribe(uint _cdpId) external {
require(isOwner(msg.sender, _cdpId), "Must be called by Cdp owner");
_unsubscribe(_cdpId);
}
function isOwner(address _owner, uint _cdpId) internal view returns (bool) {
return getOwner(_cdpId) == _owner;
}
function checkParams(bytes32 _ilk, uint128 _minRatio, uint128 _maxRatio) internal view returns (bool) {
if (_minRatio < minLimits[_ilk]) {
return false;
}
if (_minRatio > _maxRatio) {
return false;
}
return true;
}
function _unsubscribe(uint _cdpId) internal {
require(subscribers.length > 0, "Must have subscribers in the list");
SubPosition storage subInfo = subscribersPos[_cdpId];
require(subInfo.subscribed, "Must first be subscribed");
uint lastCdpId = subscribers[subscribers.length - 1].cdpId;
SubPosition storage subInfo2 = subscribersPos[lastCdpId];
subInfo2.arrPos = subInfo.arrPos;
subscribers[subInfo.arrPos] = subscribers[subscribers.length - 1];
subscribers.pop();
changeIndex++;
subInfo.subscribed = false;
subInfo.arrPos = 0;
emit Unsubscribed(msg.sender, _cdpId);
}
function getOwner(uint _cdpId) public view returns(address) {
return manager.owns(_cdpId);
}
function getSubscribedInfo(uint _cdpId) public view returns(bool, uint128, uint128, uint128, uint128, address, uint coll, uint debt) {
SubPosition memory subInfo = subscribersPos[_cdpId];
if (!subInfo.subscribed) return (false, 0, 0, 0, 0, address(0), 0, 0);
(coll, debt) = saverProxy.getCdpInfo(manager, _cdpId, manager.ilks(_cdpId));
CdpHolder memory subscriber = subscribers[subInfo.arrPos];
return (
true,
subscriber.minRatio,
subscriber.maxRatio,
subscriber.optimalRatioRepay,
subscriber.optimalRatioBoost,
subscriber.owner,
coll,
debt
);
}
function getCdpHolder(uint _cdpId) public view returns (bool subscribed, CdpHolder memory) {
SubPosition memory subInfo = subscribersPos[_cdpId];
if (!subInfo.subscribed) return (false, CdpHolder(0, 0, 0, 0, address(0), 0, false, false));
CdpHolder memory subscriber = subscribers[subInfo.arrPos];
return (true, subscriber);
}
function getIlkInfo(bytes32 _ilk, uint _cdpId) public view returns(bytes32 ilk, uint art, uint rate, uint spot, uint line, uint dust, uint mat, uint par) {
if (_ilk == bytes32(0)) {
_ilk = manager.ilks(_cdpId);
}
ilk = _ilk;
(,mat) = spotter.ilks(_ilk);
par = spotter.par();
(art, rate, spot, line, dust) = vat.ilks(_ilk);
}
function getSubscribers() public view returns (CdpHolder[] memory) {
return subscribers;
}
function getSubscribersByPage(uint _page, uint _perPage) public view returns (CdpHolder[] memory) {
CdpHolder[] memory holders = new CdpHolder[](_perPage);
uint start = _page * _perPage;
uint end = start + _perPage;
uint count = 0;
for (uint i=start; i<end; i++) {
holders[count] = subscribers[i];
count++;
}
return holders;
}
function changeMinRatios(bytes32 _ilk, uint _newRatio) public onlyOwner {
minLimits[_ilk] = _newRatio;
}
function unsubscribeByAdmin(uint _cdpId) public onlyOwner {
SubPosition storage subInfo = subscribersPos[_cdpId];
if (subInfo.subscribed) {
_unsubscribe(_cdpId);
}
}
}
文件 144 的 152:TokenInterface.sol
pragma solidity ^0.6.0;
abstract contract TokenInterface {
function allowance(address, address) public virtual returns (uint256);
function balanceOf(address) public virtual returns (uint256);
function approve(address, uint256) public virtual;
function transfer(address, uint256) public virtual returns (bool);
function transferFrom(address, address, uint256) public virtual returns (bool);
function deposit() public virtual payable;
function withdraw(uint256) public virtual;
}
文件 145 的 152:Types.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import { SafeMath } from "../../../utils/SafeMath.sol";
import { Math } from "./Math.sol";
library Types {
using Math for uint256;
enum AssetDenomination {
Wei,
Par
}
enum AssetReference {
Delta,
Target
}
struct AssetAmount {
bool sign;
AssetDenomination denomination;
AssetReference ref;
uint256 value;
}
struct TotalPar {
uint128 borrow;
uint128 supply;
}
struct Par {
bool sign;
uint128 value;
}
function zeroPar()
internal
pure
returns (Par memory)
{
return Par({
sign: false,
value: 0
});
}
function sub(
Par memory a,
Par memory b
)
internal
pure
returns (Par memory)
{
return add(a, negative(b));
}
function add(
Par memory a,
Par memory b
)
internal
pure
returns (Par memory)
{
Par memory result;
if (a.sign == b.sign) {
result.sign = a.sign;
result.value = SafeMath.add(a.value, b.value).to128();
} else {
if (a.value >= b.value) {
result.sign = a.sign;
result.value = SafeMath.sub(a.value, b.value).to128();
} else {
result.sign = b.sign;
result.value = SafeMath.sub(b.value, a.value).to128();
}
}
return result;
}
function equals(
Par memory a,
Par memory b
)
internal
pure
returns (bool)
{
if (a.value == b.value) {
if (a.value == 0) {
return true;
}
return a.sign == b.sign;
}
return false;
}
function negative(
Par memory a
)
internal
pure
returns (Par memory)
{
return Par({
sign: !a.sign,
value: a.value
});
}
function isNegative(
Par memory a
)
internal
pure
returns (bool)
{
return !a.sign && a.value > 0;
}
function isPositive(
Par memory a
)
internal
pure
returns (bool)
{
return a.sign && a.value > 0;
}
function isZero(
Par memory a
)
internal
pure
returns (bool)
{
return a.value == 0;
}
struct Wei {
bool sign;
uint256 value;
}
function zeroWei()
internal
pure
returns (Wei memory)
{
return Wei({
sign: false,
value: 0
});
}
function sub(
Wei memory a,
Wei memory b
)
internal
pure
returns (Wei memory)
{
return add(a, negative(b));
}
function add(
Wei memory a,
Wei memory b
)
internal
pure
returns (Wei memory)
{
Wei memory result;
if (a.sign == b.sign) {
result.sign = a.sign;
result.value = SafeMath.add(a.value, b.value);
} else {
if (a.value >= b.value) {
result.sign = a.sign;
result.value = SafeMath.sub(a.value, b.value);
} else {
result.sign = b.sign;
result.value = SafeMath.sub(b.value, a.value);
}
}
return result;
}
function equals(
Wei memory a,
Wei memory b
)
internal
pure
returns (bool)
{
if (a.value == b.value) {
if (a.value == 0) {
return true;
}
return a.sign == b.sign;
}
return false;
}
function negative(
Wei memory a
)
internal
pure
returns (Wei memory)
{
return Wei({
sign: !a.sign,
value: a.value
});
}
function isNegative(
Wei memory a
)
internal
pure
returns (bool)
{
return !a.sign && a.value > 0;
}
function isPositive(
Wei memory a
)
internal
pure
returns (bool)
{
return a.sign && a.value > 0;
}
function isZero(
Wei memory a
)
internal
pure
returns (bool)
{
return a.value == 0;
}
}
文件 146 的 152:UniswapExchangeInterface.sol
pragma solidity ^0.6.0;
abstract contract UniswapExchangeInterface {
function getEthToTokenInputPrice(uint256 eth_sold)
external virtual
view
returns (uint256 tokens_bought);
function getEthToTokenOutputPrice(uint256 tokens_bought)
external virtual
view
returns (uint256 eth_sold);
function getTokenToEthInputPrice(uint256 tokens_sold)
external virtual
view
returns (uint256 eth_bought);
function getTokenToEthOutputPrice(uint256 eth_bought)
external virtual
view
returns (uint256 tokens_sold);
function tokenToEthTransferInput(
uint256 tokens_sold,
uint256 min_eth,
uint256 deadline,
address recipient
) external virtual returns (uint256 eth_bought);
function ethToTokenTransferInput(uint256 min_tokens, uint256 deadline, address recipient)
external virtual
payable
returns (uint256 tokens_bought);
function tokenToTokenTransferInput(
uint256 tokens_sold,
uint256 min_tokens_bought,
uint256 min_eth_bought,
uint256 deadline,
address recipient,
address token_addr
) external virtual returns (uint256 tokens_bought);
function ethToTokenTransferOutput(
uint256 tokens_bought,
uint256 deadline,
address recipient
) external virtual payable returns (uint256 eth_sold);
function tokenToEthTransferOutput(
uint256 eth_bought,
uint256 max_tokens,
uint256 deadline,
address recipient
) external virtual returns (uint256 tokens_sold);
function tokenToTokenTransferOutput(
uint256 tokens_bought,
uint256 max_tokens_sold,
uint256 max_eth_sold,
uint256 deadline,
address recipient,
address token_addr
) external virtual returns (uint256 tokens_sold);
}
文件 147 的 152:UniswapFactoryInterface.sol
pragma solidity ^0.6.0;
abstract contract UniswapFactoryInterface {
function getExchange(address token) external view virtual returns (address exchange);
}
文件 148 的 152:UniswapRouterInterface.sol
pragma solidity ^0.6.0;
abstract contract UniswapRouterInterface {
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
virtual
returns (uint[] memory amounts);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external virtual
returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external virtual returns (uint[] memory amounts);
function getAmountsOut(uint amountIn, address[] memory path) public virtual view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] memory path) public virtual view returns (uint[] memory amounts);
}
文件 149 的 152:UniswapV2Wrapper.sol
pragma solidity ^0.6.0;
import "../../utils/SafeERC20.sol";
import "../../interfaces/ExchangeInterfaceV2.sol";
import "../../interfaces/UniswapRouterInterface.sol";
import "../../DS/DSMath.sol";
import "../../auth/AdminAuth.sol";
contract UniswapV2Wrapper is DSMath, ExchangeInterfaceV2, AdminAuth {
address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
UniswapRouterInterface public constant router = UniswapRouterInterface(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
using SafeERC20 for ERC20;
function sell(address _srcAddr, address _destAddr, uint _srcAmount) external payable override returns (uint) {
_srcAddr = ethToWethAddr(_srcAddr);
_destAddr = ethToWethAddr(_destAddr);
uint[] memory amounts;
address[] memory path = new address[](2);
path[0] = _srcAddr;
path[1] = _destAddr;
ERC20(_srcAddr).safeApprove(address(router), _srcAmount);
if (_destAddr == WETH_ADDRESS) {
amounts = router.swapExactTokensForETH(_srcAmount, 1, path, msg.sender, block.timestamp + 1);
}
else {
amounts = router.swapExactTokensForTokens(_srcAmount, 1, path, msg.sender, block.timestamp + 1);
}
return amounts[amounts.length - 1];
}
function buy(address _srcAddr, address _destAddr, uint _destAmount) external override payable returns(uint) {
_srcAddr = ethToWethAddr(_srcAddr);
_destAddr = ethToWethAddr(_destAddr);
uint[] memory amounts;
address[] memory path = new address[](2);
path[0] = _srcAddr;
path[1] = _destAddr;
ERC20(_srcAddr).safeApprove(address(router), uint(-1));
if (_destAddr == WETH_ADDRESS) {
amounts = router.swapTokensForExactETH(_destAmount, uint(-1), path, msg.sender, block.timestamp + 1);
}
else {
amounts = router.swapTokensForExactTokens(_destAmount, uint(-1), path, msg.sender, block.timestamp + 1);
}
sendLeftOver(_srcAddr);
return amounts[0];
}
function getSellRate(address _srcAddr, address _destAddr, uint _srcAmount) public override view returns (uint) {
_srcAddr = ethToWethAddr(_srcAddr);
_destAddr = ethToWethAddr(_destAddr);
address[] memory path = new address[](2);
path[0] = _srcAddr;
path[1] = _destAddr;
uint[] memory amounts = router.getAmountsOut(_srcAmount, path);
return wdiv(amounts[amounts.length - 1], _srcAmount);
}
function getBuyRate(address _srcAddr, address _destAddr, uint _destAmount) public override view returns (uint) {
_srcAddr = ethToWethAddr(_srcAddr);
_destAddr = ethToWethAddr(_destAddr);
address[] memory path = new address[](2);
path[0] = _srcAddr;
path[1] = _destAddr;
uint[] memory amounts = router.getAmountsIn(_destAmount, path);
return wdiv(_destAmount, amounts[0]);
}
function sendLeftOver(address _srcAddr) internal {
msg.sender.transfer(address(this).balance);
if (_srcAddr != KYBER_ETH_ADDRESS) {
ERC20(_srcAddr).safeTransfer(msg.sender, ERC20(_srcAddr).balanceOf(address(this)));
}
}
function ethToWethAddr(address _src) internal pure returns (address) {
return _src == KYBER_ETH_ADDRESS ? WETH_ADDRESS : _src;
}
function getDecimals(address _token) internal view returns (uint256) {
if (_token == KYBER_ETH_ADDRESS) return 18;
return ERC20(_token).decimals();
}
receive() payable external {}
}
文件 150 的 152:UniswapWrapper.sol
pragma solidity ^0.6.0;
import "../../utils/SafeERC20.sol";
import "../../interfaces/KyberNetworkProxyInterface.sol";
import "../../interfaces/ExchangeInterfaceV2.sol";
import "../../interfaces/UniswapExchangeInterface.sol";
import "../../interfaces/UniswapFactoryInterface.sol";
import "../../DS/DSMath.sol";
import "../../auth/AdminAuth.sol";
contract UniswapWrapper is DSMath, ExchangeInterfaceV2, AdminAuth {
address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant UNISWAP_FACTORY = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
using SafeERC20 for ERC20;
function sell(address _srcAddr, address _destAddr, uint _srcAmount) external payable override returns (uint) {
address uniswapExchangeAddr;
uint destAmount;
_srcAddr = ethToWethAddr(_srcAddr);
_destAddr = ethToWethAddr(_destAddr);
if (_destAddr == WETH_ADDRESS) {
uniswapExchangeAddr = UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_srcAddr);
ERC20(_srcAddr).safeApprove(uniswapExchangeAddr, _srcAmount);
destAmount = UniswapExchangeInterface(uniswapExchangeAddr).
tokenToEthTransferInput(_srcAmount, 1, block.timestamp + 1, msg.sender);
}
else {
uniswapExchangeAddr = UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_srcAddr);
ERC20(_srcAddr).safeApprove(uniswapExchangeAddr, _srcAmount);
destAmount = UniswapExchangeInterface(uniswapExchangeAddr).
tokenToTokenTransferInput(_srcAmount, 1, 1, block.timestamp + 1, msg.sender, _destAddr);
}
return destAmount;
}
function buy(address _srcAddr, address _destAddr, uint _destAmount) external override payable returns(uint) {
address uniswapExchangeAddr;
uint srcAmount;
_srcAddr = ethToWethAddr(_srcAddr);
_destAddr = ethToWethAddr(_destAddr);
if (_destAddr == WETH_ADDRESS) {
uniswapExchangeAddr = UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_srcAddr);
ERC20(_srcAddr).safeApprove(uniswapExchangeAddr, uint(-1));
srcAmount = UniswapExchangeInterface(uniswapExchangeAddr).
tokenToEthTransferOutput(_destAmount, uint(-1), block.timestamp + 1, msg.sender);
}
else {
uniswapExchangeAddr = UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_srcAddr);
ERC20(_srcAddr).safeApprove(uniswapExchangeAddr, uint(-1));
srcAmount = UniswapExchangeInterface(uniswapExchangeAddr).
tokenToTokenTransferOutput(_destAmount, uint(-1), uint(-1), block.timestamp + 1, msg.sender, _destAddr);
}
sendLeftOver(_srcAddr);
return srcAmount;
}
function getSellRate(address _srcAddr, address _destAddr, uint _srcAmount) public override view returns (uint) {
_srcAddr = ethToWethAddr(_srcAddr);
_destAddr = ethToWethAddr(_destAddr);
if(_srcAddr == WETH_ADDRESS) {
address uniswapTokenAddress = UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_destAddr);
return wdiv(UniswapExchangeInterface(uniswapTokenAddress).getEthToTokenInputPrice(_srcAmount), _srcAmount);
} else if (_destAddr == WETH_ADDRESS) {
address uniswapTokenAddress = UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_srcAddr);
return wdiv(UniswapExchangeInterface(uniswapTokenAddress).getTokenToEthInputPrice(_srcAmount), _srcAmount);
} else {
uint ethBought = UniswapExchangeInterface(UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_srcAddr)).getTokenToEthInputPrice(_srcAmount);
return wdiv(UniswapExchangeInterface(UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_destAddr)).getEthToTokenInputPrice(ethBought), _srcAmount);
}
}
function getBuyRate(address _srcAddr, address _destAddr, uint _destAmount) public override view returns (uint) {
_srcAddr = ethToWethAddr(_srcAddr);
_destAddr = ethToWethAddr(_destAddr);
if(_srcAddr == WETH_ADDRESS) {
address uniswapTokenAddress = UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_destAddr);
return wdiv(1 ether, wdiv(UniswapExchangeInterface(uniswapTokenAddress).getEthToTokenOutputPrice(_destAmount), _destAmount));
} else if (_destAddr == WETH_ADDRESS) {
address uniswapTokenAddress = UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_srcAddr);
return wdiv(1 ether, wdiv(UniswapExchangeInterface(uniswapTokenAddress).getTokenToEthOutputPrice(_destAmount), _destAmount));
} else {
uint ethNeeded = UniswapExchangeInterface(UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_destAddr)).getTokenToEthOutputPrice(_destAmount);
return wdiv(1 ether, wdiv(UniswapExchangeInterface(UniswapFactoryInterface(UNISWAP_FACTORY).getExchange(_srcAddr)).getEthToTokenOutputPrice(ethNeeded), _destAmount));
}
}
function sendLeftOver(address _srcAddr) internal {
msg.sender.transfer(address(this).balance);
if (_srcAddr != KYBER_ETH_ADDRESS) {
ERC20(_srcAddr).safeTransfer(msg.sender, ERC20(_srcAddr).balanceOf(address(this)));
}
}
function ethToWethAddr(address _src) internal pure returns (address) {
return _src == KYBER_ETH_ADDRESS ? WETH_ADDRESS : _src;
}
receive() payable external {}
}
文件 151 的 152:Vat.sol
pragma solidity ^0.6.0;
abstract contract Vat {
struct Urn {
uint256 ink;
uint256 art;
}
struct Ilk {
uint256 Art;
uint256 rate;
uint256 spot;
uint256 line;
uint256 dust;
}
mapping (bytes32 => mapping (address => Urn )) public urns;
mapping (bytes32 => Ilk) public ilks;
mapping (bytes32 => mapping (address => uint)) public gem;
function can(address, address) virtual public view returns (uint);
function dai(address) virtual public view returns (uint);
function frob(bytes32, address, address, address, int, int) virtual public;
function hope(address) virtual public;
function move(address, address, uint) virtual public;
function fork(bytes32, address, address, int, int) virtual public;
}
文件 152 的 152:ZrxAllowlist.sol
pragma solidity ^0.6.0;
import "../auth/AdminAuth.sol";
contract ZrxAllowlist is AdminAuth {
mapping (address => bool) public zrxAllowlist;
mapping(address => bool) private nonPayableAddrs;
constructor() public {
zrxAllowlist[0x6958F5e95332D93D21af0D7B9Ca85B8212fEE0A5] = true;
zrxAllowlist[0x61935CbDd02287B511119DDb11Aeb42F1593b7Ef] = true;
zrxAllowlist[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true;
zrxAllowlist[0x080bf510FCbF18b91105470639e9561022937712] = true;
nonPayableAddrs[0x080bf510FCbF18b91105470639e9561022937712] = true;
}
function setAllowlistAddr(address _zrxAddr, bool _state) public onlyOwner {
zrxAllowlist[_zrxAddr] = _state;
}
function isZrxAddr(address _zrxAddr) public view returns (bool) {
return zrxAllowlist[_zrxAddr];
}
function addNonPayableAddr(address _nonPayableAddr) public onlyOwner {
nonPayableAddrs[_nonPayableAddr] = true;
}
function removeNonPayableAddr(address _nonPayableAddr) public onlyOwner {
nonPayableAddrs[_nonPayableAddr] = false;
}
function isNonPayableAddr(address _addr) public view returns(bool) {
return nonPayableAddrs[_addr];
}
}
{
"compilationTarget": {
"contracts/exchange/wrappers/UniswapV2Wrapper.sol": "UniswapV2Wrapper"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"name":"KYBER_ETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_srcAddr","type":"address"},{"internalType":"address","name":"_destAddr","type":"address"},{"internalType":"uint256","name":"_destAmount","type":"uint256"}],"name":"buy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_srcAddr","type":"address"},{"internalType":"address","name":"_destAddr","type":"address"},{"internalType":"uint256","name":"_destAmount","type":"uint256"}],"name":"getBuyRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_srcAddr","type":"address"},{"internalType":"address","name":"_destAddr","type":"address"},{"internalType":"uint256","name":"_srcAmount","type":"uint256"}],"name":"getSellRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract UniswapRouterInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_srcAddr","type":"address"},{"internalType":"address","name":"_destAddr","type":"address"},{"internalType":"uint256","name":"_srcAmount","type":"uint256"}],"name":"sell","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"setAdminByAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"setAdminByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwnerByAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawStuckFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]