diff --git a/contracts/connectors/dydxFlash.sol b/contracts/connectors/dydxFlash.sol new file mode 100644 index 0000000..a4edf9b --- /dev/null +++ b/contracts/connectors/dydxFlash.sol @@ -0,0 +1,68 @@ +pragma solidity ^0.6.0; + +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +// import files from common directory +import { TokenInterface , MemoryInterface, EventInterface} from "../common/interfaces.sol"; +import { Stores } from "../common/stores.sol"; +import { DSMath } from "../common/math.sol"; + + +/** + * @title ConnectBasic. + * @dev Connector to deposit/withdraw assets. + */ + +interface AccountInterface { + function enable(address) external; + function disable(address) external; +} + +interface DydxFlashInterface { + function initiateFlashLoan(address _token, uint256 _amount, bytes calldata data) external; +} + +contract BasicResolver is Stores { + + using SafeERC20 for IERC20; + + /** + * @dev Return ethereum address + */ + function getDydxLoanAddr() internal pure returns (address) { + return address(0); // check9898 - change to dydx flash contract address + } + + function getWethAddr() internal pure returns (address) { + return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + } + + /** + * @dev Deposit Assets To Smart Account. + * @param token Token Address. + * @param tokenAmt Token Amount. + * @param data targets & data for cast. + */ + function borrowAndCast(address token, uint tokenAmt, bytes memory data) public payable { + AccountInterface(address(this)).enable(getDydxLoanAddr()); + + address _token = token == getEthAddr() ? getWethAddr() : token; + + DydxFlashInterface(getDydxLoanAddr()).initiateFlashLoan(_token, tokenAmt, data); + + if (token == getEthAddr()) { + payable(getDydxLoanAddr()).transfer(tokenAmt); + } else { + IERC20(token).transfer(getDydxLoanAddr(), tokenAmt); + } + + AccountInterface(address(this)).disable(getDydxLoanAddr()); + } + +} + + +contract ConnectBasic is BasicResolver { + string public constant name = "dydx-flashloan-v1"; +} diff --git a/contracts/flashloan/dydx.sol b/contracts/flashloan/dydx.sol new file mode 100644 index 0000000..68211c9 --- /dev/null +++ b/contracts/flashloan/dydx.sol @@ -0,0 +1,62 @@ +pragma solidity ^0.6.0; +pragma experimental ABIEncoderV2; + +import "@studydefi/money-legos/dydx/contracts/DydxFlashloanBase.sol"; +import "@studydefi/money-legos/dydx/contracts/ICallee.sol"; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface DSAInterface { + function cast(address[] calldata _targets, bytes[] calldata _datas, address _origin) external payable; +} + +contract DydxFlashloaner is ICallee, DydxFlashloanBase { + + address public constant soloAddr = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e; + + struct CastData { + address[] targets; + bytes[] data; + } + + // check9898 - add block re-entrance + function callFunction( + address sender, + Account.Info memory account, + bytes memory data + ) public { + CastData memory cd = abi.decode(data, (CastData)); + + // check9898 - change to DSA address & origin address too + DSAInterface(address(0)).cast(cd.targets, cd.data, address(0)); + } + + // check9898 - if ETH then change 0xeeeee into WETH address and change the token into ETH before sending + function initiateFlashLoan(address _token, uint256 _amount, bytes calldata data) + external + { + ISoloMargin solo = ISoloMargin(soloAddr); + + // Get marketId from token address + uint256 marketId = _getMarketIdFromTokenAddress(soloAddr, _token); + + IERC20(_token).approve(soloAddr, _amount + 2); + + Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3); + + operations[0] = _getWithdrawAction(marketId, _amount); + operations[1] = _getCallAction(data); + operations[2] = _getDepositAction(marketId, repayAmount); + + Account.Info[] memory accountInfos = new Account.Info[](1); + accountInfos[0] = _getAccountInfo(); + + IERC20 _tokenContract = IERC20(_token); + uint iniBal = _tokenContract.balanceOf(address(this)); + + solo.operate(accountInfos, operations); + + uint finBal = _tokenContract.balanceOf(address(this)); + require(sub(iniBal, finBal) < 10, "amount-paid-less"); + } +} \ No newline at end of file