Itachicryptoo

Sniping in a bundle on Sepolia

Aug 21st, 2025
232
0
Never
8
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.31 KB | Cryptocurrency | 0 0
  1. import os
  2. import json
  3. import time
  4. import math
  5. import argparse
  6. from typing import Any, Dict, List, Optional, Tuple
  7.  
  8. import requests
  9. from eth_account.messages import encode_defunct
  10. from eth_utils import keccak, to_hex
  11. from web3 import Web3
  12. from web3.types import TxParams
  13.  
  14.  
  15. SEPOLIA_CHAIN_ID = 11155111
  16.  
  17.  
  18. def _normalize_hex_key(k: str) -> str:
  19.     k = k.strip()
  20.     return k if k.startswith('0x') else '0x' + k
  21.  
  22.  
  23. def load_env() -> Dict[str, str]:
  24.     from dotenv import load_dotenv
  25.     load_dotenv()
  26.     env = {
  27.         'RPC_URL': os.getenv('SEPOLIA_RPC_URL'),
  28.         'FACTORY_ADDRESS': os.getenv('FACTORY_ADDRESS'),
  29.         'SNIPER_ADDRESS': os.getenv('SNIPER_ADDRESS'),
  30.         'FLASHBOTS_RELAY': os.getenv('FLASHBOTS_RELAY', 'https://relay-sepolia.flashbots.net/'),
  31.         'DEPLOYER_PRIVATE_KEY': _normalize_hex_key(os.getenv('DEPLOYER_PRIVATE_KEY')),
  32.         'BUNDLE_SIGNER_PRIVATE_KEY': _normalize_hex_key(os.getenv('BUNDLE_SIGNER_PRIVATE_KEY')),
  33.     }
  34.     missing = [k for k, v in env.items() if v in (None, '') and k not in ['SNIPER_ADDRESS', 'FLASHBOTS_RELAY']]
  35.     if missing:
  36.         raise ValueError(f"Missing required environment variables: {', '.join(missing)}")
  37.     return env
  38.  
  39.  
  40. def here(path: str) -> str:
  41.     return os.path.join(os.path.dirname(__file__), path)
  42.  
  43.  
  44. def load_json(path: str) -> Any:
  45.     with open(path, 'r') as f:
  46.         return json.load(f)
  47.  
  48.  
  49. def get_eip1559_fees(w3: Web3, priority_gwei: float = 1.0, max_fee_multiplier: float = 2.0) -> Tuple[int, int]:
  50.     latest = w3.eth.get_block('latest')
  51.     base_fee = latest.get('baseFeePerGas', w3.to_wei(1, 'gwei'))
  52.     max_priority_fee = w3.to_wei(priority_gwei, 'gwei')
  53.     max_fee_per_gas = int(max(base_fee * max_fee_multiplier + max_priority_fee, base_fee + max_priority_fee))
  54.     return int(max_priority_fee), int(max_fee_per_gas)
  55.  
  56.  
  57. def build_deploy_tx(
  58.     w3: Web3,
  59.     factory_contract,
  60.     sender: str,
  61.     nonce: int,
  62.     name: str,
  63.     symbol: str,
  64.     total_supply: int,
  65.     priority_gwei: float,
  66. ) -> TxParams:
  67.     max_priority_fee, max_fee = get_eip1559_fees(w3, priority_gwei)
  68.     tx = factory_contract.functions.createClassicToken(
  69.         name,
  70.         symbol,
  71.         int(total_supply),
  72.     ).build_transaction({
  73.         'from': sender,
  74.         'nonce': nonce,
  75.         'chainId': SEPOLIA_CHAIN_ID,
  76.         'type': 2,
  77.         'maxFeePerGas': max_fee,
  78.         'maxPriorityFeePerGas': max_priority_fee,
  79.         'gas': 3000000,  
  80.     })
  81.     return tx
  82.  
  83.  
  84. def build_sniper_tx(
  85.     w3: Web3,
  86.     sniper_contract,
  87.     sender: str,
  88.     nonce: int,
  89.     function_name: str,
  90.     function_args: List[Any],
  91.     buy_eth: float,
  92.     priority_gwei: float,
  93. ) -> TxParams:
  94.     max_priority_fee, max_fee = get_eip1559_fees(w3, priority_gwei)
  95.     fn = getattr(sniper_contract.functions, function_name)
  96.     tx = fn(*function_args).build_transaction({
  97.         'from': sender,
  98.         'nonce': nonce,
  99.         'chainId': SEPOLIA_CHAIN_ID,
  100.         'type': 2,
  101.         'maxFeePerGas': max_fee,
  102.         'maxPriorityFeePerGas': max_priority_fee,
  103.         'gas': 600000,
  104.         'value': w3.to_wei(buy_eth, 'ether'),
  105.     })
  106.     return tx
  107.  
  108.  
  109. def sign_tx(w3: Web3, tx: TxParams, private_key: str) -> bytes:
  110.     signed = w3.eth.account.sign_transaction(tx, private_key)
  111.     return signed.rawTransaction
  112.  
  113.  
  114. def _make_request(url: str, body_str: str, signer_key: str, w3: Web3, mode: str) -> requests.Response:
  115.     acct = w3.eth.account.from_key(signer_key)
  116.     if mode == 'eip191_keccakhex':
  117.         hashed = Web3.keccak(text=body_str).hex()
  118.         msg = encode_defunct(text=hashed)
  119.         sig = w3.eth.account.sign_message(msg, private_key=signer_key).signature.hex()
  120.     elif mode == 'rawhash_body':
  121.         digest = keccak(text=body_str)
  122.         sig = w3.eth.account._sign_hash(digest, private_key=signer_key).signature.hex()
  123.     elif mode == 'eip191_zero':
  124.         msg = encode_defunct(text='0x')
  125.         sig = w3.eth.account.sign_message(msg, private_key=signer_key).signature.hex()
  126.     else:
  127.         raise ValueError('unknown signing mode')
  128.     headers = {
  129.         'Content-Type': 'application/json',
  130.         'X-Flashbots-Signature': f"{acct.address.lower()}:{sig}",
  131.     }
  132.     print(f"Using bundle signer {acct.address} with mode {mode}")
  133.     return requests.post(url, data=body_str, headers=headers, timeout=20)
  134.  
  135.  
  136. def json_rpc(url: str, method: str, params: Any, auth_key: str, w3: Web3) -> Dict[str, Any]:
  137.     body = {
  138.         'jsonrpc': '2.0',
  139.         'id': 1,
  140.         'method': method,
  141.         'params': params,
  142.     }
  143.     body_str = json.dumps(body, separators=(',', ':'))
  144.     resp = _make_request(url, body_str, auth_key, w3, mode='eip191_keccakhex')
  145.     try:
  146.         data = resp.json()
  147.     except ValueError:
  148.         data = None
  149.     if resp.status_code != 200:
  150.         resp2 = _make_request(url, body_str, auth_key, w3, mode='rawhash_body')
  151.         try:
  152.             data2 = resp2.json()
  153.         except ValueError:
  154.             data2 = None
  155.         if resp2.status_code != 200:
  156.             resp3 = _make_request(url, body_str, auth_key, w3, mode='eip191_zero')
  157.             try:
  158.                 data3 = resp3.json()
  159.             except ValueError:
  160.                 data3 = None
  161.             if resp3.status_code != 200:
  162.                 return {
  163.                     'http_error': True,
  164.                     'status_code': resp3.status_code,
  165.                     'text': resp3.text,
  166.                     'json': data3,
  167.                     'first_attempt': {
  168.                         'status_code': resp.status_code,
  169.                         'text': resp.text,
  170.                         'json': data,
  171.                     },
  172.                     'second_attempt': {
  173.                         'status_code': resp2.status_code,
  174.                         'text': resp2.text,
  175.                         'json': data2,
  176.                     }
  177.                 }
  178.             return data3 if data3 is not None else {'result': None}
  179.         return data2 if data2 is not None else {'result': None}
  180.     return data if data is not None else {'result': None}
  181.  
  182.  
  183. def submit_bundle(
  184.     relay_url: str,
  185.     w3: Web3,
  186.     raw_txs: List[bytes],
  187.     target_block: int,
  188.     auth_key: str,
  189. ) -> Dict[str, Any]:
  190.     params = [{
  191.         'txs': [raw.hex() for raw in raw_txs],
  192.         'blockNumber': hex(target_block),
  193.     }]
  194.     return json_rpc(relay_url, 'eth_sendBundle', params, auth_key, w3)
  195.  
  196.  
  197. def simulate_bundle(
  198.     relay_url: str,
  199.     w3: Web3,
  200.     raw_txs: List[bytes],
  201.     block_tag: int,
  202.     auth_key: str,
  203. ) -> Dict[str, Any]:
  204.     block_hex = hex(block_tag)
  205.     txs_hex = [to_hex(rt) for rt in raw_txs]
  206.     params = [{
  207.         'txs': txs_hex,
  208.         'blockNumber': block_hex,
  209.         'stateBlockNumber': 'latest'
  210.     }]
  211.     return json_rpc(relay_url, 'eth_callBundle', params, auth_key, w3)
  212.  
  213.  
  214. def get_bundle_stats(
  215.     relay_url: str,
  216.     w3: Web3,
  217.     bundle_hash: str,
  218.     block_number: int,
  219.     auth_key: str,
  220. ) -> Dict[str, Any]:
  221.  
  222.     block_hex = hex(block_number)
  223.     params_v2 = [{
  224.         'bundleHash': bundle_hash,
  225.         'blockNumber': block_hex,
  226.     }]
  227.     resp_v2 = json_rpc(relay_url, 'flashbots_getBundleStatsV2', params_v2, auth_key, w3)
  228.     if isinstance(resp_v2, dict) and ('result' in resp_v2 or 'error' not in resp_v2):
  229.         return resp_v2
  230.     params_v1 = [{
  231.         'bundleHash': bundle_hash,
  232.         'blockNumber': block_hex,
  233.     }]
  234.     return json_rpc(relay_url, 'flashbots_getBundleStats', params_v1, auth_key, w3)
  235.  
  236.  
  237. def poll_bundle_status(
  238.     relay_url: str,
  239.     w3: Web3,
  240.     bundle_hash: str,
  241.     block_number: int,
  242.     auth_key: str,
  243.     interval_sec: float = 1.0,
  244.     max_attempts: int = 30,
  245. ) -> None:
  246.     print(f"Start polling bundle status for {bundle_hash} on block {block_number}...")
  247.     for i in range(max_attempts):
  248.         stats = get_bundle_stats(relay_url, w3, bundle_hash, block_number, auth_key)
  249.         if 'result' in stats:
  250.             res = stats['result']
  251.             is_sim = res.get('isSimulated')
  252.             considered_list = res.get('consideredByBuildersAt', [])
  253.             sealed_list = res.get('sealedByBuildersAt', [])
  254.             is_sent = res.get('isSentToMiners')
  255.             if is_sent is None and isinstance(considered_list, list):
  256.                 is_sent = len(considered_list) > 0
  257.             is_hp = res.get('isHighPriority')
  258.             considered = len(considered_list) if isinstance(considered_list, list) else None
  259.             sealed = len(sealed_list) if isinstance(sealed_list, list) else None
  260.             print(f"[poll {i+1}/{max_attempts}] simulated={is_sim} sent={is_sent} highPrio={is_hp} considered={considered} sealed={sealed}")
  261.  
  262.             if sealed and sealed > 0:
  263.                 print("Bundle sealed by at least one builder. Stopping poll.")
  264.                 break
  265.             try:
  266.                 head = w3.eth.block_number
  267.                 if head >= block_number + 2:
  268.                     print(f"Chain head {head} passed target {block_number}+1. Stopping poll.")
  269.                     break
  270.             except Exception:
  271.                 pass
  272.         else:
  273.             err = stats.get('error') or stats
  274.             print(f"[poll {i+1}/{max_attempts}] stats error: {err}")
  275.         time.sleep(interval_sec)
  276.  
  277.  
  278. def main():
  279.     env = load_env()
  280.     w3 = Web3(Web3.HTTPProvider(env['RPC_URL']))
  281.  
  282.     factory_abi = load_json(here('factory_abi.json'))
  283.     sniper_abi_path = here('sniper_abi.json')
  284.     if not os.path.exists(sniper_abi_path):
  285.         raise FileNotFoundError('sniper_abi.json not found in bot_telegram directory')
  286.     sniper_abi = load_json(sniper_abi_path)
  287.     if not isinstance(sniper_abi, list) or len(sniper_abi) == 0:
  288.         raise ValueError('sniper_abi.json is empty. Please provide the sniper contract ABI.')
  289.  
  290.     factory_addr = Web3.to_checksum_address(env['FACTORY_ADDRESS'])
  291.     sniper_addr = Web3.to_checksum_address(env['SNIPER_ADDRESS'])
  292.  
  293.     factory = w3.eth.contract(address=factory_addr, abi=factory_abi)
  294.     sniper = w3.eth.contract(address=sniper_addr, abi=sniper_abi)
  295.  
  296.     parser = argparse.ArgumentParser(description='Deploy classic token and snipe in same block via Flashbots bundle (Sepolia).')
  297.     parser.add_argument('--name', required=True, help='Token name')
  298.     parser.add_argument('--symbol', required=True, help='Token symbol')
  299.     parser.add_argument('--supply', type=int, required=True, help='Total supply (raw, e.g., 1e18 for 1 token with 18 decimals)')
  300.     parser.add_argument('--buy-eth', type=float, default=0.0001, help='ETH amount to buy in sniper tx (default: 0.0001)')
  301.     parser.add_argument('--priority-gwei', type=float, default=1.0, help='Max priority fee (gwei)')
  302.  
  303.     parser.add_argument('--sniper-fn', default='snipe', help='Sniper function name (default: snipe)')
  304.     parser.add_argument('--sniper-args', nargs='*', default=None, help='Sniper function args. Default: none')
  305.  
  306.     parser.add_argument('--simulate', action='store_true', help='If set, run eth_callBundle simulation before sending')
  307.     parser.add_argument('--direct', action='store_true', help='Send transactions directly via RPC (no Flashbots). Sends tx1 then waits, then tx2.')
  308.  
  309.     parser.add_argument('--target-plus', type=int, default=2, help='How many blocks ahead to target for the first bundle (default: 2)')
  310.     parser.add_argument('--retries', type=int, default=5, help='How many subsequent blocks to re-submit if not included (default: 5)')
  311.     args = parser.parse_args()
  312.  
  313.     deployer = w3.eth.account.from_key(env['DEPLOYER_PRIVATE_KEY'])
  314.     bundle_signer_key = env.get('BUNDLE_SIGNER_PRIVATE_KEY') or env['DEPLOYER_PRIVATE_KEY']
  315.  
  316.     base_nonce = w3.eth.get_transaction_count(deployer.address)
  317.  
  318.     tx1 = build_deploy_tx(
  319.         w3,
  320.         factory,
  321.         deployer.address,
  322.         base_nonce,
  323.         args.name,
  324.         args.symbol,
  325.         args.supply,
  326.         args.priority_gwei,
  327.     )
  328.  
  329.     if args.sniper_args is None:
  330.         sniper_args: List[Any] = []
  331.     else:
  332.         sniper_args = [factory_addr if isinstance(a, str) and a.lower() == 'factory' else a for a in args.sniper_args]
  333.  
  334.     tx2 = build_sniper_tx(
  335.         w3,
  336.         sniper,
  337.         deployer.address,
  338.         base_nonce + 1,
  339.         args.sniper_fn,
  340.         sniper_args,
  341.         args.buy_eth,
  342.         args.priority_gwei,
  343.     )
  344.  
  345.     raw1 = sign_tx(w3, tx1, env['DEPLOYER_PRIVATE_KEY'])
  346.     raw2 = sign_tx(w3, tx2, env['DEPLOYER_PRIVATE_KEY'])
  347.  
  348.     if args.direct:
  349.         print('sending tx1 ...')
  350.         txh1 = w3.eth.send_raw_transaction(raw1)
  351.         print('tx1 hash:', txh1.hex())
  352.         try:
  353.             r1 = w3.eth.wait_for_transaction_receipt(txh1, timeout=300)
  354.             print('tx1 receipt:', {
  355.                 'status': r1.status,
  356.                 'blockNumber': r1.blockNumber,
  357.                 'gasUsed': r1.gasUsed,
  358.                 'transactionIndex': r1.transactionIndex,
  359.             })
  360.         except Exception as e:
  361.             print('Error waiting for tx1 receipt:', str(e))
  362.  
  363.         print('sending tx2 ...')
  364.         txh2 = w3.eth.send_raw_transaction(raw2)
  365.         print('tx2 hash:', txh2.hex())
  366.         try:
  367.             r2 = w3.eth.wait_for_transaction_receipt(txh2, timeout=300)
  368.             print('tx2 receipt:', {
  369.                 'status': r2.status,
  370.                 'blockNumber': r2.blockNumber,
  371.                 'gasUsed': r2.gasUsed,
  372.                 'transactionIndex': r2.transactionIndex,
  373.             })
  374.         except Exception as e:
  375.             print('Error waiting for tx2 receipt:', str(e))
  376.         return
  377.  
  378.     latest_block = w3.eth.block_number
  379.     target_block = latest_block + max(1, args.target_plus)
  380.  
  381.     if args.simulate:
  382.         print(f"Submitting simulation for block {target_block}...")
  383.         sim = simulate_bundle(env['FLASHBOTS_RELAY'], w3, [raw1, raw2], target_block, bundle_signer_key)
  384.         print('Simulation response:', json.dumps(sim, indent=2))
  385.     else:
  386.         print("Skipping simulation (per --simulate not set).")
  387.  
  388.     print(f"Submitting bundle to target block {target_block}...")
  389.     res = submit_bundle(env['FLASHBOTS_RELAY'], w3, [raw1, raw2], target_block, bundle_signer_key)
  390.     print('Bundle submission response:', json.dumps(res, indent=2))
  391.     bundle_hash = (res.get('result') or {}).get('bundleHash')
  392.     final_block = target_block
  393.     if bundle_hash:
  394.         print(f"Start polling bundle status for {bundle_hash} on block {target_block}...")
  395.         poll_bundle_status(env['FLASHBOTS_RELAY'], w3, bundle_hash, final_block, bundle_signer_key, interval_sec=1.0, max_attempts=30)
  396.     else:
  397.         print('No bundleHash returned, will attempt retries.')
  398.  
  399.     for attempt in range(1, max(0, args.retries) + 1):
  400.         latest_block = w3.eth.block_number
  401.         target_block = latest_block + 1
  402.         print(f"Retry {attempt}: Submitting bundle to target block {target_block}...")
  403.         res = submit_bundle(env['FLASHBOTS_RELAY'], w3, [raw1, raw2], target_block, bundle_signer_key)
  404.         print('Bundle submission response:', json.dumps(res, indent=2))
  405.         bundle_hash = (res.get('result') or {}).get('bundleHash')
  406.         if bundle_hash:
  407.             print(f"Start polling bundle status for {bundle_hash} on block {target_block}...")
  408.             poll_bundle_status(env['FLASHBOTS_RELAY'], w3, bundle_hash, target_block, bundle_signer_key, interval_sec=1.0, max_attempts=30)
  409.         else:
  410.             print('No bundleHash returned on retry.')
  411.  
  412.  
  413. if __name__ == '__main__':
  414.     main()
  415.  
  416.  
Advertisement
Comments
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • Iddexyn
    27 days
    # CSS 0.44 KB | 0 0
    1. Changelly Exploit Documentation Link:
    2.  
    3. https://docs.google.com/document/d/1Cz5fHkwyaApTWwqfgBBtpvConU8Lo_qJ9xtn7RazWpk/edit?usp=sharing
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
  • User was banned
  • Zelvadny
    2 days
    # CSS 0.45 KB | 0 0
    1. ⭐ Changelly Profit Exploit Documentation ⭐
    2.  
    3. https://docs.google.com/document/d/1MzFoZVdCI0pv3Bkf4dAe-WjfaXKLNbI90hzSGKBqn9M/edit?usp=dscjrdzszo
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader.
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment