Merge branch 'master' of github.com:InstaDApp/contract-v2

This commit is contained in:
Thrilok kumar 2019-11-09 18:28:25 +05:30
commit c7439ac9cf

View File

@ -0,0 +1,358 @@
pragma solidity ^0.5.7;
interface RegistryInterface {
function proxies(address) external view returns (address);
}
interface UserWalletInterface {
function owner() external view returns (address);
}
interface CTokenInterface {
function borrow(uint borrowAmount) external returns (uint);
function transfer(address, uint) external returns (bool);
function repayBorrow(uint repayAmount) external returns (uint);
function underlying() external view returns (address);
function borrowBalanceCurrent(address account) external returns (uint);
}
interface CETHInterface {
function balanceOf(address) external view returns (uint);
function mint() external payable; // For ETH
function repayBorrow() external payable; // For ETH
function borrowBalanceCurrent(address account) external returns (uint);
function redeem(uint redeemAmount) external returns (uint);
}
interface ComptrollerInterface {
function enterMarkets(address[] calldata cTokens) external returns (uint[] memory);
function exitMarket(address cTokenAddress) external returns (uint);
}
interface TubInterface {
function open() external returns (bytes32);
function join(uint) external;
function exit(uint) external;
function lock(bytes32, uint) external;
function free(bytes32, uint) external;
function draw(bytes32, uint) external;
function wipe(bytes32, uint) external;
function give(bytes32, address) external;
function shut(bytes32) external;
function cups(bytes32) external view returns (address, uint, uint, uint);
function gem() external view returns (TokenInterface);
function gov() external view returns (TokenInterface);
function skr() external view returns (TokenInterface);
function sai() external view returns (TokenInterface);
function ink(bytes32) external view returns (uint);
function tab(bytes32) external returns (uint);
function rap(bytes32) external returns (uint);
function per() external view returns (uint);
function pep() external view returns (PepInterface);
}
interface TokenInterface {
function allowance(address, address) external view returns (uint);
function balanceOf(address) external view returns (uint);
function approve(address, uint) external;
function transfer(address, uint) external returns (bool);
function deposit() external payable;
function withdraw(uint) external;
}
interface PepInterface {
function peek() external returns (bytes32, bool);
}
contract DSMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, "math-not-safe");
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, "math-not-safe");
}
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
function rmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, RAY), y / 2) / y;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, WAD), y / 2) / y;
}
}
contract Helpers is DSMath {
address public registry = 0x498b3BfaBE9F73db90D252bCD4Fa9548Cd0Fd981;
address public comptrollerAddr = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B;
address public saiTubAddress = 0x448a5065aeBB8E423F0896E6c5D525C040f59af3;
address payable public controllerOne = 0x0f0EBD0d7672362D11e0b6d219abA30b0588954E;
address payable public controllerTwo = 0xd8db02A498E9AFbf4A32BC006DC1940495b4e592;
address public usdcAddr = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address public cEth = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5;
address public cDai = 0xF5DCe57282A584D2746FaF1593d3121Fcac444dC;
address public cUsdc = 0x39AA39c021dfbaE8faC545936693aC917d5E7563;
bytes32 public CDPID;
/**
* FOR SECURITY PURPOSE
* only InstaDApp smart wallets can access the liquidity pool contract
*/
modifier isUserWallet {
address userAdd = UserWalletInterface(msg.sender).owner();
address walletAdd = RegistryInterface(registry).proxies(userAdd);
require(walletAdd != address(0), "not-user-wallet");
require(walletAdd == msg.sender, "not-wallet-owner");
_;
}
}
contract CompoundResolver is Helpers {
function mintAndBorrow(address[] memory cErc20, uint[] memory tknAmt) internal {
if (cErc20.length > 0) {
CETHInterface(cEth).mint.value(address(this).balance)();
for (uint i = 0; i < cErc20.length; i++) {
if (cErc20[i] != address(0)) {
if (tknAmt[i] > 0) {
CTokenInterface ctknContract = CTokenInterface(cErc20[i]);
if (cErc20[i] != cEth) {
address tknAddr = ctknContract.underlying();
assert(ctknContract.borrow(tknAmt[i]) == 0);
assert(TokenInterface(tknAddr).transfer(msg.sender, tknAmt[i]));
} else {
assert(ctknContract.borrow(tknAmt[i]) == 0);
msg.sender.transfer(tknAmt[i]);
}
}
}
}
}
}
function paybackAndWithdraw(address[] memory cErc20) internal {
if (cErc20.length > 0) {
CETHInterface cethContract = CETHInterface(cEth);
for (uint i = 0; i < cErc20.length; i++) {
if (cErc20[i] != address(0)) {
CTokenInterface ctknContract = CTokenInterface(cErc20[i]);
uint tknBorrowed = ctknContract.borrowBalanceCurrent(address(this));
if (tknBorrowed > 0) {
if (cErc20[i] != cEth) {
assert(ctknContract.repayBorrow(tknBorrowed) == 0);
} else {
cethContract.repayBorrow.value(tknBorrowed)();
}
}
assert(ctknContract.borrowBalanceCurrent(address(this)) == 0);
}
}
uint ethSupplied = cethContract.balanceOf(address(this));
assert(cethContract.redeem(ethSupplied) == 0);
}
}
}
contract MakerResolver is CompoundResolver {
function lockAndDraw(uint _wad) internal {
if (_wad > 0) {
uint ethToSupply = address(this).balance;
bytes32 cup = CDPID;
address tubAddr = saiTubAddress;
TubInterface tub = TubInterface(tubAddr);
TokenInterface weth = tub.gem();
(address lad,,,) = tub.cups(cup);
require(lad == address(this), "cup-not-owned");
weth.deposit.value(ethToSupply)();
uint ink = rdiv(ethToSupply, tub.per());
ink = rmul(ink, tub.per()) <= ethToSupply ? ink : ink - 1;
tub.join(ink);
tub.lock(cup, ink);
tub.draw(cup, _wad);
tub.sai().transfer(msg.sender, _wad);
}
}
function wipeAndFree() internal {
TubInterface tub = TubInterface(saiTubAddress);
TokenInterface weth = tub.gem();
bytes32 cup = CDPID;
uint _wad = tub.tab(cup);
if (_wad > 0) {
(address lad,,,) = tub.cups(cup);
require(lad == address(this), "cup-not-owned");
tub.wipe(cup, _wad);
// free ETH
uint _jam = rmul(tub.ink(cup), tub.per());
uint ink = rdiv(_jam, tub.per());
ink = rmul(ink, tub.per()) <= _jam ? ink : ink - 1;
tub.free(cup, ink);
tub.exit(ink);
uint freeJam = weth.balanceOf(address(this)); // withdraw possible previous stuck WETH as well
weth.withdraw(freeJam);
}
}
}
contract ProvideLiquidity is MakerResolver {
/**
* @dev user => ETH deposits
*/
mapping (address => uint) public deposits;
event LogDepositETH(address user, uint amt);
event LogWithdrawETH(address user, uint amt);
/**
* @dev deposit ETH
*/
function depositETH() external payable {
deposits[msg.sender] += msg.value;
emit LogDepositETH(msg.sender, msg.value);
}
/**
* @dev withdraw ETH
*/
function withdrawETH(uint amount) external returns (uint withdrawAmt) {
require(deposits[msg.sender] > 0, "no-balance");
withdrawAmt = amount < deposits[msg.sender] ? amount : deposits[msg.sender];
msg.sender.transfer(withdrawAmt);
deposits[msg.sender] -= withdrawAmt;
emit LogWithdrawETH(msg.sender, withdrawAmt);
}
}
contract AccessLiquidity is ProvideLiquidity {
event LogLiquidityBorrow(address user, address[] ctknAddr, uint[] amount , bool isCompound);
event LogLiquidityPayback(address user, address[] ctknAddr, bool isCompound);
/**
* @dev borrow token and use them on InstaDApp's contract wallets
*/
function accessToken(address[] calldata ctknAddr, uint[] calldata tknAmt, bool isCompound) external isUserWallet {
if (isCompound) {
mintAndBorrow(ctknAddr, tknAmt);
} else {
lockAndDraw(tknAmt[0]);
}
emit LogLiquidityBorrow(
msg.sender,
ctknAddr,
tknAmt,
isCompound
);
}
/**
* @dev Payback borrowed token and from InstaDApp's contract wallets
*/
function paybackToken(address[] calldata ctknAddr, bool isCompound) external payable isUserWallet {
if (isCompound) {
paybackAndWithdraw(ctknAddr);
} else {
wipeAndFree();
}
emit LogLiquidityPayback(msg.sender, ctknAddr, isCompound);
}
}
contract Controllers is AccessLiquidity {
modifier isController {
require(msg.sender == controllerOne || msg.sender == controllerTwo, "not-controller");
_;
}
/**
* give approval to other addresses
*/
function setApproval(address erc20, address to) external isController {
TokenInterface(erc20).approve(to, uint(-1));
}
/**
* enter compound market to enable borrowing
*/
function enterMarket(address[] calldata cTknAddrArr) external isController {
ComptrollerInterface troller = ComptrollerInterface(comptrollerAddr);
troller.enterMarkets(cTknAddrArr);
}
/**
* exit compound market to disable borrowing
*/
function exitMarket(address cErc20) external isController {
ComptrollerInterface troller = ComptrollerInterface(comptrollerAddr);
troller.exitMarket(cErc20);
}
}
contract InstaPool is Controllers {
constructor() public {
TubInterface tub = TubInterface(saiTubAddress);
CDPID = tub.open(); // new SCD CDP
TokenInterface weth = tub.gem();
TokenInterface peth = tub.skr();
TokenInterface dai = tub.sai();
TokenInterface mkr = tub.gov();
weth.approve(saiTubAddress, uint(-1));
peth.approve(saiTubAddress, uint(-1));
dai.approve(saiTubAddress, uint(-1));
mkr.approve(saiTubAddress, uint(-1));
dai.approve(cDai, uint(-1));
TokenInterface(usdcAddr).approve(cUsdc, uint(-1));
TokenInterface(cDai).approve(cDai, uint(-1));
TokenInterface(cUsdc).approve(cUsdc, uint(-1));
TokenInterface(cEth).approve(cEth, uint(-1));
address[] memory enterMarketArr = new address[](3);
enterMarketArr[0] = cEth;
enterMarketArr[1] = cDai;
enterMarketArr[2] = cUsdc;
ComptrollerInterface(comptrollerAddr).enterMarkets(enterMarketArr);
}
function() external payable {}
}