Skip to content

Instantly share code, notes, and snippets.

@ElementalBrian
Created October 1, 2020 20:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ElementalBrian/07de6b2f1aa2d24d87aee9ece92a2bcb to your computer and use it in GitHub Desktop.
Save ElementalBrian/07de6b2f1aa2d24d87aee9ece92a2bcb to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.6.6+commit.6c089d02.js&optimize=false&gist=
pragma solidity ^0.6.6;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
/**
* @dev Converts an `address` into `address payable`. Note that this is
* simply a type cast: the actual underlying value is not changed.
*
* _Available since v2.4.0._
*/
function toPayable(address account) internal pure returns (address payable) {
return address(uint160(account));
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*
* _Available since v2.4.0._
*/
function sendValue(address recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-call-value
(bool success, ) = recipient.call.value(amount)("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}
pragma solidity ^0.6.6;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
interface IToken {
function flashBorrow(uint256 borrowAmount, address borrower, address target, string calldata signature, bytes calldata data) external payable returns (bytes memory);
}
interface UniswapV2 {
function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns(uint256 amountA, uint256 amountB, uint256 liquidity);
function addLiquidityETH(address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) external returns(uint256 amountToken, uint256 amountETH, uint256 liquidity);
function removeLiquidityETH(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) external returns(uint256 amountToken, uint256 amountETH);
function removeLiquidity(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns(uint256 amountA, uint256 amountB);
function swapExactETHForTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) external returns(uint256[] memory amounts);
function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) external returns(uint256[] memory amounts);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns(uint[] memory amounts);
}
interface bzxLiq {
function liquidate(bytes32 loanId, address receiver, uint256 closeAmount) payable external;
}
contract borrow2liquidate {
address payable owner;
modifier onlyOwner() {
if (msg.sender == owner) _;
}
constructor() public payable {
owner = msg.sender;
}
address uniAddress = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
UniswapV2 uniInt = UniswapV2(uniAddress);
address bzxContract = 0xD8Ee69652E4e4838f2531732a46d1f7F584F0b7f;
bzxLiq bzx = bzxLiq(0xD8Ee69652E4e4838f2531732a46d1f7F584F0b7f);
address currentCToken;
address currentLToken;
uint256 currentMaxLiq;
bytes32 currentLoanId;
function setLoanInfo(address cToken, address lToken, uint maxLiq, bytes32 loanId2) public onlyOwner {
currentCToken = cToken;
currentLToken = lToken;
currentMaxLiq = maxLiq;
currentLoanId = loanId2;
}
function getLoanInfo(bytes32 loanId) public view returns(bytes32 loanId1, address loanToken, address collateralToken, uint256 principal, uint256 collateral, uint256 maxLiquidatable) {
(bytes32 loanId1, , address loanToken, address collateralToken, uint256 principal, uint256 collateral, , , , , , , , uint256 maxLiquidatable, ) = bzx.getLoan(loanId);
return (loanId1, loanToken, collateralToken, principal, collateral, maxLiquidatable);
}
function doFlash(address tokenAddToUse, uint maxLiquidatable) public onlyOwner {
//something something bzrx roman's iToken contract
}
function startUniswap(address sellToken, address buyToken, uint256 amountSent) public returns(uint256 amounts1) {
ERC20 sellToken1 = ERC20(sellToken);
ERC20 buyToken1 = ERC20(currentLToken);
sellToken1.approve(uniAddress, 100000000000000000000000000000000000);
require(sellToken1.balanceOf(address(this)) >= amountSent, "insufficient balance");
address[] memory addresses = new address[](2);
uint256[] memory amounts = finishUniswap(addresses, amountSent);
uint256 resultingTokens = amounts[1];
return resultingTokens;
}
function finishUniswap(address[] memory theAddresses, uint amount) public returns(uint256[] memory amounts1) {
uint256 deadline = 1000000000000000;
uint256[] memory amounts = usi.swapExactTokensForTokens(amount, 1, theAddresses, address(this), deadline);
return amounts;
}
function withdraw(address token) public onlyOwner returns(bool) {
if (address(token) == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
uint256 amount = address(this).balance;
uint256 rest = address(this).balance;
msg.sender.transfer(rest);
}
else {
ERC20 tokenToken = ERC20(token);
uint256 tokenBalance = tokenToken.balanceOf(address(this));
require(tokenToken.transfer(defiEducationProject, (tokenBalance / 10)));
uint256 newTokenBalance = tokenToken.balanceOf(address(this));
require(tokenToken.transfer(msg.sender, (newTokenBalance)));
}
return true;
}
function performTrade(bool isItEther, uint256 amount1) public returns(uint256) {
uint256 startingETHBalance = address(this).balance;
ERC20 tokenToReceive = ERC20(currentCToken);
uint256 startingCBalance = tokenToReceive.balanceOf(address(this));
if (isItEther == true) {
} else {
ERC20 bzLToken = ERC20(currentLToken);
if (bzLToken.allowance(address(this), bzxAddress) <= currentMaxLiq) {
bzLToken.approve(bzxAddress, (currentMaxLiq * 100));
}
}
if (isItEther == false) {
bzx.liquidate(currentLoanId, address(this), currentMaxLiq);
} else {
bzx.liquidate.value(amount1)(currentLoanId, address(this), currentMaxLiq);
}
uint256 amountBack = 0;
if (address(this).balance > startingETHBalance) {
uint256 newETH = address(this).balance - startingETHBalance;
wethToken.deposit.value(newETH)();
amountBack = startUniswap(wethAddress, currentLToken, newETH);
}
else {
uint256 difCBalance = tokenToReceive.balanceOf(address(this)) - startingCBalance;
require(difCBalance >0, "no profit");
amountBack = startUniswap(currentCToken, currentLToken, difCBalance);
}
return amountBack;
}
}
pragma solidity >= 0.6.6;
interface bzxRead {
function getLoan(bytes32 loanId) external view returns(bytes32 loanId1, uint96 endTimestamp, address loanToken, address collateralToken, uint256 principal, uint256 collateral, uint256 interestOwedPerDay, uint256 interestDepositRemaining, uint256 startRate, uint256 startMargin, uint256 maintenanceMargin, uint256 currentMargin, uint256 maxLoanTerm, uint256 maxLiquidatable, uint256 maxSeizable);
}
interface bzxWrite {
function liquidate(bytes32 loanId, address receiver, uint256 closeAmount) payable external;
}
interface UniswapV2 {
function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns(uint256 amountA, uint256 amountB, uint256 liquidity);
function addLiquidityETH(address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) external returns(uint256 amountToken, uint256 amountETH, uint256 liquidity);
function removeLiquidityETH(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) external returns(uint256 amountToken, uint256 amountETH);
function removeLiquidity(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns(uint256 amountA, uint256 amountB);
function swapExactETHForTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) external returns(uint256[] memory amounts);
function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) external returns(uint256[] memory amounts);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns(uint[] memory amounts);
}
interface FlashLoanInterface {
function flashLoan(address _receiver, address _reserve, uint256 _amount, bytes calldata _params) external;
}
interface ERC20 {
function totalSupply() external view returns(uint supply);
function balanceOf(address _owner) external view returns(uint balance);
function transfer(address _to, uint _value) external returns(bool success);
function transferFrom(address _from, address _to, uint _value) external returns(bool success);
function approve(address _spender, uint _value) external returns(bool success);
function allowance(address _owner, address _spender) external view returns(uint remaining);
function decimals() external view returns(uint digits);
event Approval(address indexed _owner, address indexed _spender, uint _value);
function deposit() external payable;
function withdraw(uint256 wad) external;
}
contract BZXAAVEFLASHLIQUIDATE {
address payable owner;
address ETH_TOKEN_ADDRESS = address(0x0);
address payable aaveRepaymentAddress = 0x3dfd23A6c5E8BbcFc9581d2E864a68feb6a076d3;
address uniAddress = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
bzxRead bzx0 = bzxRead(0xD8Ee69652E4e4838f2531732a46d1f7F584F0b7f);
address bzx1Address = 0xD8Ee69652E4e4838f2531732a46d1f7F584F0b7f;
bzxWrite bzx1 = bzxWrite(0xD8Ee69652E4e4838f2531732a46d1f7F584F0b7f);
UniswapV2 usi = UniswapV2(uniAddress);
FlashLoanInterface fli = FlashLoanInterface(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
bytes theBytes;
address aaveEthAddress = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address wethAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
ERC20 wethToken = ERC20(wethAddress);
address payable defiEducationProject = 0x3F9dc36Db04740af8700AdeC2cC317B9B9EACEF5;
address currentCToken;
address currentLToken;
uint256 currentMaxLiq;
bytes32 currentLoanId;
modifier onlyOwner() {
if (msg.sender == owner) _;
}
constructor() public payable {
owner = msg.sender;
}
fallback() external payable {
}
function updateBZXs(address newAddress) onlyOwner public {
bzxRead bzx0 = bzxRead(newAddress);
address bzx1Address = newAddress;
bzxWrite bzx1 = bzxWrite(newAddress);
}
function updateFlashLoanAddress(address newAddress) onlyOwner public {
FlashLoanInterface fli = FlashLoanInterface(newAddress);
}
function updateAaveEthAddress(address newAddress) onlyOwner public {
aaveEthAddress = newAddress;
}
function updateAaveRepayment(address payable newAddress) onlyOwner public {
aaveRepaymentAddress = newAddress;
}
function updateUniAddress(address newAddress) onlyOwner public {
UniswapV2 usi = UniswapV2(newAddress);
}
function setLoanInfo(address cToken, address lToken, uint maxLiq, bytes32 loanId2) public onlyOwner {
currentCToken = cToken;
currentLToken = lToken;
currentMaxLiq = maxLiq;
currentLoanId = loanId2;
}
function getLoanInfo1(bytes32 loanId) public view returns(bytes32 loanId1, address loanToken, address collateralToken, uint256 principal, uint256 collateral, uint256 maxLiquidatable) {
// return bzx0.getLoan(loanId);
(bytes32 loanId1, , address loanToken, address collateralToken, uint256 principal, uint256 collateral, , , , , , , , uint256 maxLiquidatable, ) = bzx0.getLoan(loanId);
return (loanId1, loanToken, collateralToken, principal, collateral, maxLiquidatable);
}
function flashLoanAndLiquidate(bytes32 loanId) onlyOwner public {
//getLoan
//get amount and which token you need to pay / flash loan borrow
(bytes32 loanId1, uint96 endTimestamp, address loanToken, address collateralToken, uint256 principal, uint256 collateral, , , , , , uint256 currentMargin, uint256 maxLoanTerm, uint256 maxLiquidatable, uint256 maxSeizable) = bzx0.getLoan(loanId);
currentCToken = collateralToken;
currentLToken = loanToken;
currentMaxLiq = maxLiquidatable;
currentLoanId = loanId;
address tokenAddToUse = loanToken;
if (loanToken == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) {
tokenAddToUse = aaveEthAddress;
}
performFlash(tokenAddToUse, maxLiquidatable);
//flash borrow that amount
//and then flash function will call bzx liquidate function, swap the returned token from to our repayment tokenof aave, and pay back avave with fee
}
function performFlash(address tokenAddToUse, uint maxLiquidatable) public onlyOwner {
fli.flashLoan(address(this), tokenAddToUse, maxLiquidatable, theBytes);
}
function performUniswap(address sellToken, address buyToken, uint256 amountSent) public returns(uint256 amounts1) {
ERC20 sellToken1 = ERC20(sellToken);
ERC20 buyToken1 = ERC20(currentLToken);
if (sellToken1.allowance(address(this), uniAddress) <= amountSent) {
sellToken1.approve(uniAddress, 100000000000000000000000000000000000);
}
require(sellToken1.balanceOf(address(this)) >= amountSent, "You dont have enough Ctoken to perform this in performUniswap");
address[] memory addresses = new address[](2);
addresses[0] = sellToken;
addresses[1] = buyToken;
uint256[] memory amounts = performUniswapActual(addresses, amountSent);
uint256 resultingTokens = amounts[1];
return resultingTokens;
}
function performUniswapActual(address[] memory theAddresses, uint amount) public returns(uint256[] memory amounts1) {
//uint256 amounts = uniswapContract.getAmountsOut(amount,theAddresses );
uint256 deadline = 1000000000000000;
uint256[] memory amounts = usi.swapExactTokensForTokens(amount, 1, theAddresses, address(this), deadline);
return amounts;
}
function performTrade(bool isItEther, uint256 amount1) public returns(uint256) {
uint256 startingETHBalance = address(this).balance;
ERC20 tokenToReceive = ERC20(currentCToken);
uint256 startingCBalance = tokenToReceive.balanceOf(address(this));
if (isItEther == true) {
} else {
ERC20 bzLToken = ERC20(currentLToken);
if (bzLToken.allowance(address(this), bzx1Address) <= currentMaxLiq) {
bzLToken.approve(bzx1Address, (currentMaxLiq * 100));
}
}
if (isItEther == false) {
bzx1.liquidate(currentLoanId, address(this), currentMaxLiq);
} else {
bzx1.liquidate.value(amount1)(currentLoanId, address(this), currentMaxLiq);
}
uint256 amountBack = 0;
if (address(this).balance > startingETHBalance) {
uint256 newETH = address(this).balance - startingETHBalance;
wethToken.deposit.value(newETH)();
amountBack = performUniswap(wethAddress, currentLToken, newETH);
}
else {
uint256 difCBalance = tokenToReceive.balanceOf(address(this)) - startingCBalance;
require(difCBalance >0, "Balance of Collateral token didnt go up after swap didnt go up");
amountBack = performUniswap(currentCToken, currentLToken, difCBalance);
}
return amountBack;
}
function executeOperation(address _reserve, uint256 _amount, uint256 _fee, bytes calldata _params) external {
bool isEther;
if (_reserve == aaveEthAddress) {
isEther = true;
} else {
isEther = false;
}
uint256 tradeResp = performTrade(isEther, _amount);
require(tradeResp > 0, "You didnt fet anything from uni");
if (_reserve == aaveEthAddress) {
uint256 repayAmount = (_amount + _fee);
uint256 ourEthBalance = address(this).balance;
wethToken.withdraw((_amount + _fee));
require(tradeResp >= (repayAmount / 10), "Not enough eth");
//aaveRepaymentAddress.call.value(repayAmount)();
//aaveRepaymentAddress.send((_amount+_fee));
aaveRepaymentAddress.call {
value: repayAmount
}("");
} else {
ERC20 firstToken = ERC20(_reserve);
firstToken.transfer(aaveRepaymentAddress, (_amount + _fee));
}
}
function changeOwner(address payable newOwner) public onlyOwner {
owner = newOwner;
}
function getTokenBalance(address tokenAddress) public view returns(uint256) {
ERC20 theToken = ERC20(tokenAddress);
return theToken.balanceOf(address(this));
}
// send token 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE if you want to withdraw ether
//10% of profit will be sent to the DeFiEducationProject for creation and publication of more code like this
function withdraw(address token) public onlyOwner returns(bool) {
//for ether withdrawal from smart contract
if (address(token) == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
uint256 amount = address(this).balance;
defiEducationProject.transfer((amount / 10));
uint256 rest = address(this).balance;
msg.sender.transfer(rest);
}
//for ether withdrawal from smart contract. Note on dividing by zero: likely will error.
else {
ERC20 tokenToken = ERC20(token);
uint256 tokenBalance = tokenToken.balanceOf(address(this));
require(tokenToken.transfer(defiEducationProject, (tokenBalance / 10)));
uint256 newTokenBalance = tokenToken.balanceOf(address(this));
require(tokenToken.transfer(msg.sender, (newTokenBalance)));
}
return true;
}
function kill() virtual public {
if (msg.sender == owner) {
selfdestruct(owner);
}
}
}
pragma solidity ^0.6.6;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
contract Context {
// Empty internal constructor, to prevent people from mistakenly deploying
// an instance of this contract, which should be used via inheritance.
constructor () internal { }
// solhint-disable-previous-line no-empty-blocks
function _msgSender() internal view returns (address payable) {
return msg.sender;
}
function _msgData() internal view returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
pragma solidity =0.6.6;
import 'SafeMath.sol';
contract ERC20 {
using SafeMath for uint;
string public constant name = 'Test Token';
string public constant symbol = 'TT';
uint8 public constant decimals = 18;
uint public totalSupply;
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;
bytes32 public DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint) public nonces;
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
constructor(uint _totalSupply) public {
uint chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
keccak256(bytes(name)),
keccak256(bytes('1')),
chainId,
address(this)
)
);
_mint(msg.sender, _totalSupply);
}
function _mint(address to, uint value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(address owner, address spender, uint value) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(address from, address to, uint value) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint value) external returns (bool) {
if (allowance[from][msg.sender] != uint(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
require(deadline >= block.timestamp, 'EXPIRED');
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'INVALID_SIGNATURE');
_approve(owner, spender, value);
}
}
pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;
interface Structs {
struct Val {
uint256 value;
}
enum ActionType {
Deposit, // supply tokens
Withdraw, // borrow tokens
Transfer, // transfer balance between accounts
Buy, // buy an amount of some token (externally)
Sell, // sell an amount of some token (externally)
Trade, // trade tokens against another account
Liquidate, // liquidate an undercollateralized or expiring account
Vaporize, // use excess tokens to zero-out a completely negative account
Call // send arbitrary data to an address
}
enum AssetDenomination {
Wei // the amount is denominated in wei
}
enum AssetReference {
Delta // the amount is given as a delta from the current value
}
struct AssetAmount {
bool sign; // true if positive
AssetDenomination denomination;
AssetReference ref;
uint256 value;
}
struct ActionArgs {
ActionType actionType;
uint256 accountId;
AssetAmount amount;
uint256 primaryMarketId;
uint256 secondaryMarketId;
address otherAddress;
uint256 otherAccountId;
bytes data;
}
struct Info {
address owner; // The address that owns the account
uint256 number; // A nonce that allows a single address to control many accounts
}
struct Wei {
bool sign; // true if positive
uint256 value;
}
}
contract DyDxPool is Structs {
function getAccountWei(Info memory account, uint256 marketId) public view returns (Wei memory);
function operate(Info[] memory, ActionArgs[] memory) public;
}
pragma solidity ^0.5.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see `ERC20Detailed`.
*/
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
}
pragma solidity ^0.5.0;
contract DyDxFlashLoan is Structs {
DyDxPool pool = DyDxPool(0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e);
address public WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public SAI = 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359;
address public USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address public DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
mapping(address => uint256) public currencies;
constructor() public {
currencies[WETH] = 1;
currencies[SAI] = 2;
currencies[USDC] = 3;
currencies[DAI] = 4;
}
modifier onlyPool() {
require(
msg.sender == address(pool),
"FlashLoan: could be called by DyDx pool only"
);
_;
}
function tokenToMarketId(address token) public view returns (uint256) {
uint256 marketId = currencies[token];
require(marketId != 0, "FlashLoan: Unsupported token");
return marketId - 1;
}
// the DyDx will call `callFunction(address sender, Info memory accountInfo, bytes memory data) public` after during `operate` call
function flashloan(address token, uint256 amount, bytes memory data)
internal
{
IERC20(token).approve(address(pool), amount + 1);
Info[] memory infos = new Info[](1);
ActionArgs[] memory args = new ActionArgs[](3);
infos[0] = Info(address(this), 0);
AssetAmount memory wamt = AssetAmount(
false,
AssetDenomination.Wei,
AssetReference.Delta,
amount
);
ActionArgs memory withdraw;
withdraw.actionType = ActionType.Withdraw;
withdraw.accountId = 0;
withdraw.amount = wamt;
withdraw.primaryMarketId = tokenToMarketId(token);
withdraw.otherAddress = address(this);
args[0] = withdraw;
ActionArgs memory call;
call.actionType = ActionType.Call;
call.accountId = 0;
call.otherAddress = address(this);
call.data = data;
args[1] = call;
ActionArgs memory deposit;
AssetAmount memory damt = AssetAmount(
true,
AssetDenomination.Wei,
AssetReference.Delta,
amount + 1
);
deposit.actionType = ActionType.Deposit;
deposit.accountId = 0;
deposit.amount = damt;
deposit.primaryMarketId = tokenToMarketId(token);
deposit.otherAddress = address(this);
args[2] = deposit;
pool.operate(infos, args);
}
}
pragma solidity ^0.5.0;
contract Flashloan is DyDxFlashLoan {
uint256 public loan;
constructor() public payable {
(bool success, ) = WETH.call.value(msg.value)("");
require(success, "fail to get weth");
}
function getFlashloan(address flashToken, uint256 flashAmount) external {
uint256 balanceBefore = IERC20(flashToken).balanceOf(address(this));
bytes memory data = abi.encode(flashToken, flashAmount, balanceBefore);
flashloan(flashToken, flashAmount, data); // execution goes to `callFunction`
}
function callFunction(
address, /* sender */
Info calldata, /* accountInfo */
bytes calldata data
) external onlyPool {
(address flashToken, uint256 flashAmount, uint256 balanceBefore) = abi
.decode(data, (address, uint256, uint256));
uint256 balanceAfter = IERC20(flashToken).balanceOf(address(this));
require(
balanceAfter - balanceBefore == flashAmount,
"contract did not get the loan"
);
loan = balanceAfter;
// Use the money here!
}
}
pragma solidity ^0.6.6;
import "SafeMath.sol";
import "IERC20.sol";
import "SafeERC20.sol";
import "IFlashLoanReceiver.sol";
import "ILendingPoolAddressesProvider.sol";
import "Withdrawable.sol";
abstract contract FlashLoanReceiverBase is IFlashLoanReceiver, Withdrawable {
using SafeERC20 for IERC20;
using SafeMath for uint256;
address constant ethAddress = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
ILendingPoolAddressesProvider public addressesProvider;
constructor(address _addressProvider) public {
addressesProvider = ILendingPoolAddressesProvider(_addressProvider);
}
receive() payable external {}
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 == ethAddress) {
(bool success, ) = _destination.call{value: _amount}("");
require(success == true, "Couldn't transfer ETH");
return;
}
IERC20(_reserve).safeTransfer(_destination, _amount);
}
function getBalanceInternal(address _target, address _reserve) internal view returns(uint256) {
if(_reserve == ethAddress) {
return _target.balance;
}
return IERC20(_reserve).balanceOf(_target);
}
}
pragma solidity ^0.6.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity ^0.6.6;
/**
* @title IFlashLoanReceiver interface
* @notice Interface for the Aave fee IFlashLoanReceiver.
* @author Aave
* @dev implement this interface to develop a flashloan-compatible flashLoanReceiver contract
**/
interface IFlashLoanReceiver {
function executeOperation(address _reserve, uint256 _amount, uint256 _fee, bytes calldata _params) external;
}
pragma solidity ^0.6.6;
interface ILendingPool {
function addressesProvider () external view returns ( address );
function deposit ( address _reserve, uint256 _amount, uint16 _referralCode ) external payable;
function redeemUnderlying ( address _reserve, address _user, uint256 _amount ) external;
function borrow ( address _reserve, uint256 _amount, uint256 _interestRateMode, uint16 _referralCode ) external;
function repay ( address _reserve, uint256 _amount, address _onBehalfOf ) external payable;
function swapBorrowRateMode ( address _reserve ) external;
function rebalanceFixedBorrowRate ( address _reserve, address _user ) external;
function setUserUseReserveAsCollateral ( address _reserve, bool _useAsCollateral ) external;
function liquidationCall ( address _collateral, address _reserve, address _user, uint256 _purchaseAmount, bool _receiveAToken ) external payable;
function flashLoan ( address _receiver, address _reserve, uint256 _amount, bytes calldata _params ) external;
function getReserveConfigurationData ( address _reserve ) external view returns ( uint256 ltv, uint256 liquidationThreshold, uint256 liquidationDiscount, address interestRateStrategyAddress, bool usageAsCollateralEnabled, bool borrowingEnabled, bool fixedBorrowRateEnabled, bool isActive );
function getReserveData ( address _reserve ) external view returns ( uint256 totalLiquidity, uint256 availableLiquidity, uint256 totalBorrowsFixed, uint256 totalBorrowsVariable, uint256 liquidityRate, uint256 variableBorrowRate, uint256 fixedBorrowRate, uint256 averageFixedBorrowRate, uint256 utilizationRate, uint256 liquidityIndex, uint256 variableBorrowIndex, address aTokenAddress, uint40 lastUpdateTimestamp );
function getUserAccountData ( address _user ) external view returns ( uint256 totalLiquidityETH, uint256 totalCollateralETH, uint256 totalBorrowsETH, uint256 availableBorrowsETH, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor );
function getUserReserveData ( address _reserve, address _user ) external view returns ( uint256 currentATokenBalance, uint256 currentUnderlyingBalance, uint256 currentBorrowBalance, uint256 principalBorrowBalance, uint256 borrowRateMode, uint256 borrowRate, uint256 liquidityRate, uint256 originationFee, uint256 variableBorrowIndex, uint256 lastUpdateTimestamp, bool usageAsCollateralEnabled );
function getReserves () external view;
}
pragma solidity ^0.6.6;
/**
@title ILendingPoolAddressesProvider interface
@notice provides the interface to fetch the LendingPoolCore address
*/
interface ILendingPoolAddressesProvider {
function getLendingPoolCore() external view returns (address payable);
function getLendingPool() external view returns (address);
}
// This file is part of Truffle suite and helps keep track of your deployments
pragma solidity ^0.6.6;
contract Migrations {
address public owner;
uint public last_completed_migration;
constructor() public {
owner = msg.sender;
}
modifier restricted() {
if (msg.sender == owner) _;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
}
pragma solidity ^0.6.6;
import "Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner(), "unauthorized");
_;
}
/**
* @dev Returns true if the caller is the current owner.
*/
function isOwner() public view returns (bool) {
return _msgSender() == _owner;
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
pragma solidity ^0.6.6;
import "SafeMath.sol";
import "Address.sol";
import "IERC20.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 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(IERC20 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));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
require(address(token).isContract(), "SafeERC20: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
pragma solidity >=0.4.21 <0.7.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* _Available since v2.4.0._
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b != 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Integer division of two numbers, rounding up and truncating the quotient
*/
function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {
return divCeil(a, b, "SafeMath: division by zero");
}
/**
* @dev Integer division of two numbers, rounding up and truncating the quotient
*/
function divCeil(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b != 0, errorMessage);
if (a == 0) {
return 0;
}
uint256 c = ((a - 1) / b) + 1;
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {
return _a < _b ? _a : _b;
}
}
pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;
interface Structs {
struct Val {
uint256 value;
}
enum ActionType {
Deposit, // supply tokens
Withdraw, // borrow tokens
Transfer, // transfer balance between accounts
Buy, // buy an amount of some token (externally)
Sell, // sell an amount of some token (externally)
Trade, // trade tokens against another account
Liquidate, // liquidate an undercollateralized or expiring account
Vaporize, // use excess tokens to zero-out a completely negative account
Call // send arbitrary data to an address
}
enum AssetDenomination {
Wei // the amount is denominated in wei
}
enum AssetReference {
Delta // the amount is given as a delta from the current value
}
struct AssetAmount {
bool sign; // true if positive
AssetDenomination denomination;
AssetReference ref;
uint256 value;
}
struct ActionArgs {
ActionType actionType;
uint256 accountId;
AssetAmount amount;
uint256 primaryMarketId;
uint256 secondaryMarketId;
address otherAddress;
uint256 otherAccountId;
bytes data;
}
struct Info {
address owner; // The address that owns the account
uint256 number; // A nonce that allows a single address to control many accounts
}
struct Wei {
bool sign; // true if positive
uint256 value;
}
}
contract DyDxPool is Structs {
function getAccountWei(Info memory account, uint256 marketId) public view returns (Wei memory);
function operate(Info[] memory, ActionArgs[] memory) public;
}
pragma solidity ^0.5.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see `ERC20Detailed`.
*/
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity ^0.5.0;
contract DyDxFlashLoan is Structs {
DyDxPool pool = DyDxPool(0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e);
address public WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public SAI = 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359;
address public USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address public DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
mapping(address => uint256) public currencies;
constructor() public {
currencies[WETH] = 1;
currencies[SAI] = 2;
currencies[USDC] = 3;
currencies[DAI] = 4;
}
modifier onlyPool() {
require(
msg.sender == address(pool),
"FlashLoan: could be called by DyDx pool only"
);
_;
}
function tokenToMarketId(address token) public view returns (uint256) {
uint256 marketId = currencies[token];
require(marketId != 0, "FlashLoan: Unsupported token");
return marketId - 1;
}
// the DyDx will call `callFunction(address sender, Info memory accountInfo, bytes memory data) public` after during `operate` call
function flashloan(address token, uint256 amount, bytes memory data)
internal
{
IERC20(token).approve(address(pool), amount + 1);
Info[] memory infos = new Info[](1);
ActionArgs[] memory args = new ActionArgs[](3);
infos[0] = Info(address(this), 0);
AssetAmount memory wamt = AssetAmount(
false,
AssetDenomination.Wei,
AssetReference.Delta,
amount
);
ActionArgs memory withdraw;
withdraw.actionType = ActionType.Withdraw;
withdraw.accountId = 0;
withdraw.amount = wamt;
withdraw.primaryMarketId = tokenToMarketId(token);
withdraw.otherAddress = address(this);
args[0] = withdraw;
ActionArgs memory call;
call.actionType = ActionType.Call;
call.accountId = 0;
call.otherAddress = address(this);
call.data = data;
args[1] = call;
ActionArgs memory deposit;
AssetAmount memory damt = AssetAmount(
true,
AssetDenomination.Wei,
AssetReference.Delta,
amount + 1
);
deposit.actionType = ActionType.Deposit;
deposit.accountId = 0;
deposit.amount = damt;
deposit.primaryMarketId = tokenToMarketId(token);
deposit.otherAddress = address(this);
args[2] = deposit;
pool.operate(infos, args);
}
}
pragma solidity ^0.5.0;
contract IOneSplit {
function getExpectedReturn(
IERC20 fromToken,
IERC20 toToken,
uint256 amount,
uint256 parts,
uint256 disableFlags
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
);
function swap(
IERC20 fromToken,
IERC20 toToken,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256 disableFlags
) public payable;
}
contract TradingBot is DyDxFlashLoan {
uint256 public loan;
// Addresses
address payable OWNER;
// OneSplit Config
address ONE_SPLIT_ADDRESS = 0xC586BeF4a0992C495Cf22e1aeEE4E446CECDee0E;
uint256 PARTS = 10;
uint256 FLAGS = 0;
// ZRX Config
address ZRX_EXCHANGE_ADDRESS = 0x61935CbDd02287B511119DDb11Aeb42F1593b7Ef;
address ZRX_ERC20_PROXY_ADDRESS = 0x95E6F48254609A6ee006F7D493c8e5fB97094ceF;
address ZRX_STAKING_PROXY = 0xa26e80e7Dea86279c6d778D702Cc413E6CFfA777; // Fee collector
// Modifiers
modifier onlyOwner() {
require(msg.sender == OWNER, "caller is not the owner!");
_;
}
// Allow the contract to receive Ether
function () external payable {}
constructor() public payable {
_getWeth(msg.value);
_approveWeth(msg.value);
OWNER = msg.sender;
}
function getFlashloan(address flashToken, uint256 flashAmount, address arbToken, bytes calldata zrxData, uint256 oneSplitMinReturn, uint256[] calldata oneSplitDistribution) external payable onlyOwner {
uint256 balanceBefore = IERC20(flashToken).balanceOf(address(this));
bytes memory data = abi.encode(flashToken, flashAmount, balanceBefore, arbToken, zrxData, oneSplitMinReturn, oneSplitDistribution);
flashloan(flashToken, flashAmount, data); // execution goes to `callFunction`
// and this point we have succefully paid the dept
}
function callFunction(
address, /* sender */
Info calldata, /* accountInfo */
bytes calldata data
) external onlyPool {
(address flashToken, uint256 flashAmount, uint256 balanceBefore, address arbToken, bytes memory zrxData, uint256 oneSplitMinReturn, uint256[] memory oneSplitDistribution) = abi
.decode(data, (address, uint256, uint256, address, bytes, uint256, uint256[]));
uint256 balanceAfter = IERC20(flashToken).balanceOf(address(this));
require(
balanceAfter - balanceBefore == flashAmount,
"contract did not get the loan"
);
loan = balanceAfter;
// do whatever you want with the money
// the dept will be automatically withdrawn from this contract at the end of execution
_arb(flashToken, arbToken, flashAmount, zrxData, oneSplitMinReturn, oneSplitDistribution);
}
function arb(address _fromToken, address _toToken, uint256 _fromAmount, bytes memory _0xData, uint256 _1SplitMinReturn, uint256[] memory _1SplitDistribution) onlyOwner payable public {
_arb(_fromToken, _toToken, _fromAmount, _0xData, _1SplitMinReturn, _1SplitDistribution);
}
function _arb(address _fromToken, address _toToken, uint256 _fromAmount, bytes memory _0xData, uint256 _1SplitMinReturn, uint256[] memory _1SplitDistribution) internal {
// Track original balance
uint256 _startBalance = IERC20(_fromToken).balanceOf(address(this));
// Perform the arb trade
_trade(_fromToken, _toToken, _fromAmount, _0xData, _1SplitMinReturn, _1SplitDistribution);
// Track result balance
uint256 _endBalance = IERC20(_fromToken).balanceOf(address(this));
// Require that arbitrage is profitable
require(_endBalance > _startBalance, "End balance must exceed start balance.");
}
function trade(address _fromToken, address _toToken, uint256 _fromAmount, bytes memory _0xData, uint256 _1SplitMinReturn, uint256[] memory _1SplitDistribution) onlyOwner payable public {
_trade(_fromToken, _toToken, _fromAmount, _0xData, _1SplitMinReturn, _1SplitDistribution);
}
function _trade(address _fromToken, address _toToken, uint256 _fromAmount, bytes memory _0xData, uint256 _1SplitMinReturn, uint256[] memory _1SplitDistribution) internal {
// Track the balance of the token RECEIVED from the trade
uint256 _beforeBalance = IERC20(_toToken).balanceOf(address(this));
// Swap on 0x: give _fromToken, receive _toToken
_zrxSwap(_fromToken, _fromAmount, _0xData);
// Calculate the how much of the token we received
uint256 _afterBalance = IERC20(_toToken).balanceOf(address(this));
// Read _toToken balance after swap
uint256 _toAmount = _afterBalance - _beforeBalance;
// Swap on 1Split: give _toToken, receive _fromToken
_oneSplitSwap(_toToken, _fromToken, _toAmount, _1SplitMinReturn, _1SplitDistribution);
}
function zrxSwap(address _from, uint256 _amount, bytes memory _calldataHexString) onlyOwner public payable {
_zrxSwap(_from, _amount, _calldataHexString);
}
function _zrxSwap(address _from, uint256 _amount, bytes memory _calldataHexString) internal {
// Approve tokens
IERC20 _fromIERC20 = IERC20(_from);
_fromIERC20.approve(ZRX_ERC20_PROXY_ADDRESS, _amount);
// Swap tokens
address(ZRX_EXCHANGE_ADDRESS).call.value(msg.value)(_calldataHexString);
// Reset approval
_fromIERC20.approve(ZRX_ERC20_PROXY_ADDRESS, 0);
}
function oneSplitSwap(address _from, address _to, uint256 _amount, uint256 _minReturn, uint256[] memory _distribution) onlyOwner public payable {
_oneSplitSwap(_from, _to, _amount, _minReturn, _distribution);
}
function _oneSplitSwap(address _from, address _to, uint256 _amount, uint256 _minReturn, uint256[] memory _distribution) internal {
// Setup contracts
IERC20 _fromIERC20 = IERC20(_from);
IERC20 _toIERC20 = IERC20(_to);
IOneSplit _oneSplitContract = IOneSplit(ONE_SPLIT_ADDRESS);
// Approve tokens
_fromIERC20.approve(ONE_SPLIT_ADDRESS, _amount);
// Swap tokens: give _from, get _to
_oneSplitContract.swap(_fromIERC20, _toIERC20, _amount, _minReturn, _distribution, FLAGS);
// Reset approval
_fromIERC20.approve(ONE_SPLIT_ADDRESS, 0);
}
function getWeth() public payable onlyOwner {
_getWeth(msg.value);
}
function _getWeth(uint256 _amount) internal {
(bool success, ) = WETH.call.value(_amount)("");
require(success, "failed to get weth");
}
function approveWeth(uint256 _amount) public onlyOwner {
_approveWeth(_amount);
}
function _approveWeth(uint256 _amount) internal {
IERC20(WETH).approve(ZRX_STAKING_PROXY, _amount);
}
// KEEP THIS FUNCTION IN CASE THE CONTRACT RECEIVES TOKENS!
function withdrawToken(address _tokenAddress) public onlyOwner {
uint256 balance = IERC20(_tokenAddress).balanceOf(address(this));
IERC20(_tokenAddress).transfer(OWNER, balance);
}
// KEEP THIS FUNCTION IN CASE THE CONTRACT KEEPS LEFTOVER ETHER!
function withdrawEther() public onlyOwner {
address self = address(this); // workaround for a possible solidity bug
uint256 balance = self.balance;
address(OWNER).transfer(balance);
}
}
pragma solidity ^0.6.6;
import "ERC20.sol";
import "SafeERC20.sol";
import "Ownable.sol";
/**
Ensures that any contract that inherits from this contract is able to
withdraw funds that are accidentally received or stuck.
*/
contract Withdrawable is Ownable {
using SafeERC20 for ERC20;
address constant ETHER = address(0);
event LogWithdraw(
address indexed _from,
address indexed _assetAddress,
uint amount
);
/**
* @dev Withdraw asset.
* @param _assetAddress Asset to be withdrawn.
*/
function withdraw(address _assetAddress) public onlyOwner {
uint assetBalance;
if (_assetAddress == ETHER) {
address self = address(this); // workaround for a possible solidity bug
assetBalance = self.balance;
msg.sender.transfer(assetBalance);
} else {
assetBalance = ERC20(_assetAddress).balanceOf(address(this));
}
emit LogWithdraw(msg.sender, _assetAddress, assetBalance);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment