forked from Supercycled/cake_sniper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTrigger2.sol
237 lines (180 loc) · 8.32 KB
/
Trigger2.sol
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
import "./Context.sol";
import "./Ownable.sol";
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);
}
interface ISandwichRouter {
function sandwichExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function sandwichTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
}
interface IWBNB {
function withdraw(uint) external;
function deposit() external payable;
}
interface IPancakeFactory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
contract Trigger2 is Ownable {
// bsc variables
address constant wbnb= 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
address constant cakeFactory = 0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73;
// eth variables
// address constant wbnb= 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
// address constant cakeRouter = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
// address constant cakeFactory = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
address payable private administrator;
address private sandwichRouter = 0xE86d6A7549cFF2536918a206b6418DE0baE95e99;
uint private wbnbIn;
uint private minTknOut;
address private tokenToBuy;
address private tokenPaired;
bool private snipeLock;
mapping(address => bool) public authenticatedSeller;
constructor(){
administrator = payable(msg.sender);
authenticatedSeller[msg.sender] = true;
}
receive() external payable {
IWBNB(wbnb).deposit{value: msg.value}();
}
//================== main functions ======================
// Trigger2 is the smart contract in charge or performing liquidity sniping and sandwich attacks.
// For liquidity sniping, its role is to hold the BNB, perform the swap once dark_forester detect the tx in the mempool and if all checks are passed; then route the tokens sniped to the owner.
// For liquidity sniping, it require a first call to configureSnipe in order to be armed. Then, it can snipe on whatever pair no matter the paired token (BUSD / WBNB etc..).
// This contract uses a custtom router which is a copy of PCS router but with modified selectors, so that our tx are more difficult to listen than those directly going through PCS router.
// perform the liquidity sniping
function snipeListing() external returns(bool success){
require(IERC20(wbnb).balanceOf(address(this)) >= wbnbIn, "snipe: not enough wbnb on the contract");
IERC20(wbnb).approve(sandwichRouter, wbnbIn);
require(snipeLock == false, "snipe: sniping is locked. See configure");
snipeLock = true;
address[] memory path;
if (tokenPaired != wbnb){
path = new address[](3);
path[0] = wbnb;
path[1] = tokenPaired;
path[2] = tokenToBuy;
} else {
path = new address[](2);
path[0] = wbnb;
path[1] = tokenToBuy;
}
ISandwichRouter(sandwichRouter).sandwichExactTokensForTokens(
wbnbIn,
minTknOut,
path,
administrator,
block.timestamp + 120
);
return true;
}
// manage the "in" phase of the sandwich attack
function sandwichIn(address tokenOut, uint amountIn, uint amountOutMin) external returns(bool success) {
require(msg.sender == administrator || msg.sender == owner(), "in: must be called by admin or owner");
require(IERC20(wbnb).balanceOf(address(this)) >= amountIn, "in: not enough wbnb on the contract");
IERC20(wbnb).approve(sandwichRouter, amountIn);
address[] memory path;
path = new address[](2);
path[0] = wbnb;
path[1] = tokenOut;
ISandwichRouter(sandwichRouter).sandwichExactTokensForTokens(
amountIn,
amountOutMin,
path,
address(this),
block.timestamp + 120
);
return true;
}
// manage the "out" phase of the sandwich. Should be accessible to all authenticated sellers
function sandwichOut(address tokenIn, uint amountOutMin) external returns(bool success) {
require(authenticatedSeller[msg.sender] == true, "out: must be called by authenticated seller");
uint amountIn = IERC20(tokenIn).balanceOf(address(this));
require(amountIn >= 0, "out: empty balance for this token");
IERC20(tokenIn).approve(sandwichRouter, amountIn);
address[] memory path;
path = new address[](2);
path[0] = tokenIn;
path[1] = wbnb;
ISandwichRouter(sandwichRouter).sandwichExactTokensForTokens(
amountIn,
amountOutMin,
path,
address(this),
block.timestamp + 120
);
return true;
}
//================== owner functions=====================
function authenticateSeller(address _seller) external onlyOwner {
authenticatedSeller[_seller] = true;
}
function getAdministrator() external view onlyOwner returns( address payable){
return administrator;
}
function setAdministrator(address payable _newAdmin) external onlyOwner returns(bool success){
administrator = _newAdmin;
authenticatedSeller[_newAdmin] = true;
return true;
}
function getSandwichRouter() external view onlyOwner returns(address){
return sandwichRouter;
}
function setSandwichRouter(address _newRouter) external onlyOwner returns(bool success){
sandwichRouter = _newRouter;
return true;
}
// must be called before sniping
function configureSnipe(address _tokenPaired, uint _amountIn, address _tknToBuy, uint _amountOutMin) external onlyOwner returns(bool success){
tokenPaired = _tokenPaired;
wbnbIn = _amountIn;
tokenToBuy = _tknToBuy;
minTknOut= _amountOutMin;
snipeLock = false;
return true;
}
function getSnipeConfiguration() external view onlyOwner returns(address, uint, address, uint, bool){
return (tokenPaired, wbnbIn, tokenToBuy, minTknOut, snipeLock);
}
// here we precise amount param as certain bep20 tokens uses strange tax system preventing to send back whole balance
function emmergencyWithdrawTkn(address _token, uint _amount) external onlyOwner returns(bool success){
require(IERC20(_token).balanceOf(address(this)) >= _amount, "not enough tokens in contract");
IERC20(_token).transfer(administrator, _amount);
return true;
}
// souldn't be of any use as receive function automaticaly wrap bnb incoming
function emmergencyWithdrawBnb() external onlyOwner returns(bool success){
require(address(this).balance >0 , "contract has an empty BNB balance");
administrator.transfer(address(this).balance);
return true;
}
}