文件 1 的 1:MCDCreateFlashLoan.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
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);
}
}
}
} 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;
} 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);
} 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);
} 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);
}
}
}
} 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;
}
} 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");
}
}
} 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);
}
}
} 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];
}
} 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});
}
} 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;
}
} 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];
}
}
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, 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, 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(getBalance(exData.destAddr) >= 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 _srcAmount) internal view returns(uint256) {
if (_srcAddr != WETH_ADDRESS) return address(this).balance;
if (address(this).balance > _srcAmount) return address(this).balance - _srcAmount;
return address(this).balance;
}
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 {}
} 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);
}
} 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);
}
} 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;
} 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);
} 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;
} abstract contract DSAuthority {
function canCall(address src, address dst, bytes4 sig) public virtual view returns (bool);
} 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);
}
}
} 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);
_;
}
} 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;
}
}
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 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 (isEthJoinAddr(_joinAddr)) {
MCDCreateProxyActions(CREATE_PROXY_ACTIONS).openLockETHAndDraw{value: address(this).balance}(
MANAGER_ADDRESS,
JUG_ADDRESS,
_joinAddr,
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);
}
function isEthJoinAddr(address _joinAddr) internal view returns (bool) {
if (_joinAddr == 0x9759A6Ac90977b93B58547b4A71c78317f391A28) return false;
if (address(Join(_joinAddr).gem()) == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) {
return true;
}
return false;
}
receive() external override(FlashLoanReceiverBase, SaverExchangeCore) payable {}
}