-
Notifications
You must be signed in to change notification settings - Fork 745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Add a flashloan and make contract callable by anyone #14
base: master
Are you sure you want to change the base?
Changes from all commits
8060f6d
85fdafb
9890ff2
90d59f7
429545c
4857d85
7b6e167
061590e
ccefbae
57457cc
cb9a82b
3a4ac48
8e6d101
a4fcd37
edff905
fb4309f
3ad421e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,99 @@ | ||
//SPDX-License-Identifier: UNLICENSED | ||
pragma solidity 0.6.12; | ||
|
||
pragma experimental ABIEncoderV2; | ||
|
||
interface IERC20 { | ||
event Approval(address indexed owner, address indexed spender, uint value); | ||
event Transfer(address indexed from, address indexed to, uint value); | ||
|
||
function name() external view returns (string memory); | ||
function symbol() external view returns (string memory); | ||
function decimals() external view returns (uint8); | ||
function totalSupply() external view returns (uint); | ||
function balanceOf(address owner) external view returns (uint); | ||
function allowance(address owner, address spender) external view returns (uint); | ||
|
||
function approve(address spender, uint value) external returns (bool); | ||
function transfer(address to, uint value) external returns (bool); | ||
function transferFrom(address from, address to, uint value) external returns (bool); | ||
} | ||
import "./FlashLoanReceiverBase.sol"; | ||
import "./Interfaces.sol"; | ||
import "./Libraries.sol"; | ||
|
||
interface IWETH is IERC20 { | ||
function deposit() external payable; | ||
function withdraw(uint) external; | ||
} | ||
|
||
// This contract simply calls multiple targets sequentially, ensuring WETH balance before and after | ||
|
||
contract FlashBotsMultiCall { | ||
address private immutable owner; | ||
address private immutable executor; | ||
IWETH private constant WETH = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); | ||
contract FlashBotsMultiCallFL is FlashLoanReceiverBase { | ||
using SafeMath for uint256; | ||
address public constant WETH_address = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove executor? |
||
IWETH private constant WETH = IWETH(WETH_address); | ||
|
||
modifier onlyExecutor() { | ||
require(msg.sender == executor); | ||
_; | ||
constructor(ILendingPoolAddressesProvider _addressProvider) FlashLoanReceiverBase(_addressProvider) public payable { | ||
WETH.approve(address(LENDING_POOL), uint(-1)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. interesting! you don't move them back yourself, aave takes them back from you? |
||
} | ||
|
||
modifier onlyOwner() { | ||
require(msg.sender == owner); | ||
_; | ||
} | ||
/** | ||
This function is called after your contract has received the flash loaned amount | ||
*/ | ||
function executeOperation( | ||
address[] calldata assets, | ||
uint256[] calldata amounts, | ||
uint256[] calldata premiums, | ||
address initiator, | ||
bytes calldata params | ||
) | ||
external | ||
override | ||
returns (bool) | ||
{ | ||
uint aaveDebt = amounts[0].add(premiums[0]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess since there's no assets held in the contract, you don't need to limit msg.sender to aave? |
||
uniswapWethFLParams(amounts[0], params, aaveDebt); | ||
|
||
constructor(address _executor) public payable { | ||
owner = msg.sender; | ||
executor = _executor; | ||
if (msg.value > 0) { | ||
WETH.deposit{value: msg.value}(); | ||
} | ||
return true; | ||
} | ||
|
||
receive() external payable { | ||
function flashloan(uint256 amountToBorrow, bytes memory _params) external { | ||
address receiverAddress = address(this); | ||
|
||
address[] memory assets = new address[](1); | ||
assets[0] = WETH_address; | ||
|
||
uint256[] memory amounts = new uint256[](1); | ||
amounts[0] = amountToBorrow; | ||
|
||
uint256[] memory modes = new uint256[](1); | ||
modes[0] = 0; | ||
|
||
address onBehalfOf = address(this); | ||
uint16 referralCode = 161; | ||
|
||
LENDING_POOL.flashLoan( | ||
receiverAddress, | ||
assets, | ||
amounts, | ||
modes, | ||
onBehalfOf, | ||
_params, | ||
referralCode | ||
); | ||
} | ||
|
||
function uniswapWeth(uint256 _wethAmountToFirstMarket, uint256 _ethAmountToCoinbase, address[] memory _targets, bytes[] memory _payloads) external onlyExecutor payable { | ||
require (_targets.length == _payloads.length); | ||
uint256 _wethBalanceBefore = WETH.balanceOf(address(this)); | ||
WETH.transfer(_targets[0], _wethAmountToFirstMarket); | ||
function uniswapWethFLParams(uint256 _amountToFirstMarket, bytes memory _params, uint256 aaveDebt) internal { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just like the first one, anyone can perform arbitrary calls, so the "owner" here isn't really that empowered. more a convenience than anything |
||
(uint256 _ethAmountToCoinbase, address[] memory _targets, bytes[] memory _payloads) = abi.decode(_params, (uint256, address[], bytes[])); | ||
require(_targets.length == _payloads.length); | ||
|
||
WETH.transfer(_targets[0], _amountToFirstMarket); | ||
for (uint256 i = 0; i < _targets.length; i++) { | ||
(bool _success, bytes memory _response) = _targets[i].call(_payloads[i]); | ||
require(_success); _response; | ||
require(_success); | ||
} | ||
|
||
uint256 _wethBalanceAfter = WETH.balanceOf(address(this)); | ||
require(_wethBalanceAfter > _wethBalanceBefore + _ethAmountToCoinbase); | ||
if (_ethAmountToCoinbase == 0) return; | ||
|
||
uint256 _ethBalance = address(this).balance; | ||
if (_ethBalance < _ethAmountToCoinbase) { | ||
WETH.withdraw(_ethAmountToCoinbase - _ethBalance); | ||
} | ||
uint256 _profit = _wethBalanceAfter - aaveDebt - _ethAmountToCoinbase; | ||
|
||
require(_profit >= 0); | ||
|
||
WETH.withdraw(_ethAmountToCoinbase + _profit); | ||
block.coinbase.transfer(_ethAmountToCoinbase); | ||
tx.origin.transfer(_profit); | ||
} | ||
|
||
function call(address payable _to, uint256 _value, bytes calldata _data) external onlyOwner payable returns (bytes memory) { | ||
function call(address payable _to, uint256 _value, bytes calldata _data) external payable returns (bytes memory) { | ||
require(_to != address(0)); | ||
(bool _success, bytes memory _result) = _to.call{value: _value}(_data); | ||
require(_success); | ||
return _result; | ||
} | ||
|
||
receive() external payable { | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
//SPDX-License-Identifier: UNLICENSED | ||
pragma solidity 0.6.12; | ||
|
||
pragma experimental ABIEncoderV2; | ||
|
||
interface IERC20 { | ||
event Approval(address indexed owner, address indexed spender, uint value); | ||
event Transfer(address indexed from, address indexed to, uint value); | ||
|
||
function name() external view returns (string memory); | ||
function symbol() external view returns (string memory); | ||
function decimals() external view returns (uint8); | ||
function totalSupply() external view returns (uint); | ||
function balanceOf(address owner) external view returns (uint); | ||
function allowance(address owner, address spender) external view returns (uint); | ||
|
||
function approve(address spender, uint value) external returns (bool); | ||
function transfer(address to, uint value) external returns (bool); | ||
function transferFrom(address from, address to, uint value) external returns (bool); | ||
} | ||
|
||
interface IWETH is IERC20 { | ||
function deposit() external payable; | ||
function withdraw(uint) external; | ||
} | ||
|
||
// This contract simply calls multiple targets sequentially, ensuring WETH balance before and after | ||
|
||
contract FlashBotsMultiCall { | ||
address private immutable owner; | ||
address private immutable executor; | ||
IWETH private constant WETH = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); | ||
|
||
modifier onlyExecutor() { | ||
require(msg.sender == executor); | ||
_; | ||
} | ||
|
||
modifier onlyOwner() { | ||
require(msg.sender == owner); | ||
_; | ||
} | ||
|
||
constructor(address _executor) public payable { | ||
owner = msg.sender; | ||
executor = _executor; | ||
if (msg.value > 0) { | ||
WETH.deposit{value: msg.value}(); | ||
} | ||
} | ||
|
||
receive() external payable { | ||
} | ||
|
||
function uniswapWeth(uint256 _wethAmountToFirstMarket, uint256 _ethAmountToCoinbase, address[] memory _targets, bytes[] memory _payloads) external onlyExecutor payable { | ||
require (_targets.length == _payloads.length); | ||
uint256 _wethBalanceBefore = WETH.balanceOf(address(this)); | ||
WETH.transfer(_targets[0], _wethAmountToFirstMarket); | ||
for (uint256 i = 0; i < _targets.length; i++) { | ||
(bool _success, bytes memory _response) = _targets[i].call(_payloads[i]); | ||
require(_success); _response; | ||
} | ||
|
||
uint256 _wethBalanceAfter = WETH.balanceOf(address(this)); | ||
require(_wethBalanceAfter > _wethBalanceBefore + _ethAmountToCoinbase); | ||
if (_ethAmountToCoinbase == 0) return; | ||
|
||
uint256 _ethBalance = address(this).balance; | ||
if (_ethBalance < _ethAmountToCoinbase) { | ||
WETH.withdraw(_ethAmountToCoinbase - _ethBalance); | ||
} | ||
block.coinbase.transfer(_ethAmountToCoinbase); | ||
} | ||
|
||
function call(address payable _to, uint256 _value, bytes calldata _data) external onlyOwner payable returns (bytes memory) { | ||
require(_to != address(0)); | ||
(bool _success, bytes memory _result) = _to.call{value: _value}(_data); | ||
require(_success); | ||
return _result; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// SPDX-License-Identifier: agpl-3.0 | ||
pragma solidity 0.6.12; | ||
|
||
import "./Interfaces.sol"; | ||
import "./Libraries.sol"; | ||
|
||
abstract contract FlashLoanReceiverBase is IFlashLoanReceiver { | ||
using SafeERC20 for IERC20; | ||
using SafeMath for uint256; | ||
|
||
ILendingPoolAddressesProvider public immutable ADDRESSES_PROVIDER; | ||
ILendingPool public immutable LENDING_POOL; | ||
|
||
constructor(ILendingPoolAddressesProvider provider) public { | ||
ADDRESSES_PROVIDER = provider; | ||
LENDING_POOL = ILendingPool(provider.getLendingPool()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please update the link to this execution contract or send us its address.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1