-
Notifications
You must be signed in to change notification settings - Fork 9
/
flashloan3swap
194 lines (146 loc) · 6.33 KB
/
flashloan3swap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
pragma solidity ^0.5.5;
import "https://github.com/Thaddeus19/flashloans/blob/Thaddeus19-version2.5/FlashLoanReceiverBase.sol";
import "https://github.com/mrdavey/ez-flashloan/blob/remix/contracts/aave/ILendingPool.sol";
import "https://github.com/Robsonsjre/FlashloanUsecases/blob/master/contracts/interfaces/IUniswap.sol";
//1 DAI = 1000000000000000000 (18 decimals)
/*
* Arbitrageur is a contract to simulate the usage of flashloans
* to make profit out of a market inbalacement
*
* For this example we deployed 2 Uniswap instances which we'll
* call by ExchangeA and ExchangeB
*
* The steps happens as following:
* 1. Borrow DAI from Aave
* 2. Buy BAT with DAI on ExchangeA
* 3. Sell BAT for MKR on ExchangeB
* 4. Buy KNC with DAI on ExchangeA
* 5. Repay Aave loan
* 6. Keep the profits
*/
contract Arbitrageur is
FlashLoanReceiverBase(address(0x506B0B2CF20FAA8f38a4E2B524EE43e1f4458Cc5)){ //first step declare the addresses of the token contracts and the exchanges
//Red Kovan token addresses
address public constant KNC_ADDRESS =0x3F80c39c0b96A0945f9F0E9f55d8A8891c5671A8;
//address public constant MKR_ADDRESS = 0x61e4CAE3DA7FD189e52a4879C7B8067D7C2Cc0FA;
address public constant DAI_ADDRESS = 0xFf795577d9AC8bD7D90Ee22b6C1703490b6512FD;
address public constant BAT_ADDRESS = 0x2d12186Fbb9f9a8C28B3FfdD4c42920f8539D738;
//Exchange creation addresses
address public constant UNISWAP_FACTORY_A = 0xECc6C0542710a0EF07966D7d1B10fA38bbb86523;
address public constant UNISWAP_FACTORY_B = 0x54Ac34e5cE84C501165674782582ADce2FDdc8F4;
address public constant UNISWAP_FACTORY_C = 0xECc6C0542710a0EF07966D7d1B10fA38bbb86523;
//Statement of exchange and lending pool
ILendingPool public lendingPool;
IUniswapExchange public exchangeA;
IUniswapExchange public exchangeB;
IUniswapExchange public exchangeC;
IUniswapFactory public uniswapFactoryA;
IUniswapFactory public uniswapFactoryB;
IUniswapFactory public uniswapFactoryC;
constructor() public {
// Instantiate Uniswap Factory A
uniswapFactoryA = IUniswapFactory(UNISWAP_FACTORY_A);
// get Exchange A Address
address exchangeA_address = uniswapFactoryA.getExchange(DAI_ADDRESS);
// Instantiate Exchange A
exchangeA = IUniswapExchange(exchangeA_address);
//Instantiate Uniswap Factory B
uniswapFactoryB = IUniswapFactory(UNISWAP_FACTORY_B);
// get Exchange B Address
address exchangeB_address = uniswapFactoryB.getExchange(BAT_ADDRESS);
//Instantiate Exchange B
exchangeB = IUniswapExchange(exchangeB_address);
// Instantiate Uniswap Factory C
uniswapFactoryC = IUniswapFactory(UNISWAP_FACTORY_C);
// get Exchange C Address
address exchangeC_address = uniswapFactoryC.getExchange(KNC_ADDRESS);
// Instantiate Exchange C
exchangeC = IUniswapExchange(exchangeC_address);
// get lendingPoolAddress
address lendingPoolAddress = addressesProvider.getLendingPool();
//Instantiate Aaave Lending Pool B
lendingPool = ILendingPool(lendingPoolAddress);
}
/*Smartcontract events
if you don't want to run to save gas just disable the emit*/
event loanProfit(uint256 revenue, uint256 totalDebt, uint256 dairevenue);
event StartLoan(address indexed borrower, uint256 amount, address asset);
event buyBat(uint amount, address BAT, uint swap);
event buyKnc(uint bat, address KNC, uint swap2);
event buyDai(uint maker, address DAI, uint swap3);
/*--------------------------------------------------------------------------------------*/
/*
* Start the arbitrage
*/
function makeArbitrage(uint256 amount) public onlyOwner {
bytes memory data = "0x0";
ERC20 dai = ERC20(DAI_ADDRESS);
lendingPool.flashLoan(address(this), DAI_ADDRESS, amount, data);
emit StartLoan(address(this), amount, DAI_ADDRESS);
// Any left amount of DAI is considered profit
uint256 profit = dai.balanceOf(address(this));
// Sending back the profits
require(
dai.transfer(msg.sender, profit),
"Could not transfer back the profit"
);
}
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params
) external {
require(_amount <= getBalanceInternal(address(this), _reserve), "Invalid balance, was the flashLoan successful?"); //check the contract has the specified balance
// If transactions are not mined until deadline the transaction is reverted
uint256 deadline = getDeadline();
ERC20 dai = ERC20(DAI_ADDRESS);
ERC20 bat = ERC20(BAT_ADDRESS);
ERC20 knc = ERC20(KNC_ADDRESS);
// Buying BAT at Uniswap 1
require(
dai.approve(address(exchangeA), _amount),
"Could not approve DAI sell"
);
uint256 tokenBought = exchangeA.tokenToTokenSwapInput(
_amount,
1,
1,
deadline,
BAT_ADDRESS
); emit buyBat(_amount, BAT_ADDRESS, tokenBought);
require(
bat.approve(address(exchangeB), tokenBought),
"Could not approve BAT sell"
);
// Selling BAT at Uniswap 2
uint256 daiBought = exchangeB.tokenToTokenSwapInput(
tokenBought,
1,
1,
deadline,
KNC_ADDRESS
);emit buyKnc(tokenBought, KNC_ADDRESS, daiBought);
// Buying KNC at Uniswap 1
require(
knc.approve(address(exchangeC), daiBought),
"Could not approve KNC sell"
);
uint256 sellknc = exchangeC.tokenToTokenSwapInput(
daiBought,
1,
1,
deadline,
DAI_ADDRESS
); emit buyDai(daiBought, DAI_ADDRESS, sellknc);
// Repay loan
uint256 totalDebt = _amount.add(_fee);
uint256 revenue = sellknc - totalDebt;
require(sellknc > totalDebt, "Did not profit");
transferFundsBackToPoolInternal(_reserve, totalDebt);
emit loanProfit(revenue, totalDebt, sellknc);
}
function getDeadline() internal view returns (uint256) {
return now + 3000;
}
}