Created
August 7, 2024 04:18
-
-
Save korrio/a5799bfd55c64a0e10555ca822dd5c5c to your computer and use it in GitHub Desktop.
bot4.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import asyncio | |
import time | |
from web3 import Web3 | |
from web3.middleware import geth_poa_middleware | |
import aiohttp | |
from colorama import Fore, Style, init | |
import ssl | |
import certifi | |
from decimal import Decimal | |
init(autoreset=True) | |
# Configuration | |
POLYGON_RPC_URL = "https://polygon-mainnet.g.alchemy.com/v2/jssjArgnoSmS2Uv5RMVwQAySLhkBsOnJ" | |
PRIVATE_KEY = '' | |
WALLET_ADDRESS = '' | |
PARASWAP_API_URL = "https://apiv5.paraswap.io" | |
# Connect to Polygon network | |
w3 = Web3(Web3.HTTPProvider(POLYGON_RPC_URL)) | |
w3.middleware_onion.inject(geth_poa_middleware, layer=0) | |
# Token and contract addresses | |
WMATIC = w3.to_checksum_address("0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270") | |
USDC = w3.to_checksum_address("0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174") | |
SUSHISWAP_ROUTER = w3.to_checksum_address("0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506") | |
QUICKSWAP_ROUTER = w3.to_checksum_address("0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff") | |
# ABIs | |
ERC20_ABI = [ | |
{"constant":True,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"type":"function"}, | |
{"constant":False,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"type":"function"}, | |
{"constant":True,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"type":"function"}, | |
] | |
ROUTER_ABI = [ | |
{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"}, | |
{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"}, | |
] | |
WMATIC_ABI = [ | |
{"constant": True,"inputs": [],"name": "name","outputs": [{"name": "","type": "string"}],"type": "function"}, | |
{"constant": False,"inputs": [{"name": "guy","type": "address"},{"name": "wad","type": "uint256"}],"name": "approve","outputs": [{"name": "","type": "bool"}],"type": "function"}, | |
{"constant": True,"inputs": [],"name": "totalSupply","outputs": [{"name": "","type": "uint256"}],"type": "function"}, | |
{"constant": False,"inputs": [{"name": "src","type": "address"},{"name": "dst","type": "address"},{"name": "wad","type": "uint256"}],"name": "transferFrom","outputs": [{"name": "","type": "bool"}],"type": "function"}, | |
{"constant": False,"inputs": [{"name": "wad","type": "uint256"}],"name": "withdraw","outputs": [],"type": "function"}, | |
{"constant": True,"inputs": [],"name": "decimals","outputs": [{"name": "","type": "uint8"}],"type": "function"}, | |
{"constant": True,"inputs": [{"name": "","type": "address"}],"name": "balanceOf","outputs": [{"name": "","type": "uint256"}],"type": "function"}, | |
{"constant": True,"inputs": [],"name": "symbol","outputs": [{"name": "","type": "string"}],"type": "function"}, | |
{"constant": False,"inputs": [{"name": "dst","type": "address"},{"name": "wad","type": "uint256"}],"name": "transfer","outputs": [{"name": "","type": "bool"}],"type": "function"}, | |
{"constant": False,"inputs": [],"name": "deposit","outputs": [],"type": "function"}, | |
{"constant": True,"inputs": [{"name": "","type": "address"},{"name": "","type": "address"}],"name": "allowance","outputs": [{"name": "","type": "uint256"}],"type": "function"}, | |
{"payable": True,"type": "fallback"}, | |
{"anonymous": False,"inputs": [{"indexed": True,"name": "src","type": "address"},{"indexed": True,"name": "guy","type": "address"},{"indexed": False,"name": "wad","type": "uint256"}],"name": "Approval","type": "event"}, | |
{"anonymous": False,"inputs": [{"indexed": True,"name": "src","type": "address"},{"indexed": True,"name": "dst","type": "address"},{"indexed": False,"name": "wad","type": "uint256"}],"name": "Transfer","type": "event"}, | |
{"anonymous": False,"inputs": [{"indexed": True,"name": "dst","type": "address"},{"indexed": False,"name": "wad","type": "uint256"}],"name": "Deposit","type": "event"}, | |
{"anonymous": False,"inputs": [{"indexed": True,"name": "src","type": "address"},{"indexed": False,"name": "wad","type": "uint256"}],"name": "Withdrawal","type": "event"} | |
] | |
# Contract instances | |
wmatic_contract = w3.eth.contract(address=WMATIC, abi=WMATIC_ABI) | |
usdc_contract = w3.eth.contract(address=USDC, abi=ERC20_ABI) | |
sushiswap_contract = w3.eth.contract(address=SUSHISWAP_ROUTER, abi=ROUTER_ABI) | |
quickswap_contract = w3.eth.contract(address=QUICKSWAP_ROUTER, abi=ROUTER_ABI) | |
async def get_paraswap_price(session, src_token, dst_token, amount): | |
url = f"{PARASWAP_API_URL}/prices" | |
params = { | |
"srcToken": src_token, | |
"destToken": dst_token, | |
"amount": amount, | |
"srcDecimals": 18 if src_token == WMATIC else 6, | |
"destDecimals": 18 if dst_token == WMATIC else 6, | |
"side": "SELL", | |
"network": 137, | |
"userAddress": WALLET_ADDRESS | |
} | |
try: | |
# สร้าง SSL context ที่ไม่ตรวจสอบ certificate | |
ssl_context = ssl.create_default_context() | |
ssl_context.check_hostname = False | |
ssl_context.verify_mode = ssl.CERT_NONE | |
print(f"{Fore.YELLOW}คำเตือน: กำลังใช้การเชื่อมต่อที่ไม่ปลอดภัย (ไม่ตรวจสอบ SSL certificate)") | |
connector = aiohttp.TCPConnector(ssl=ssl_context) | |
async with aiohttp.ClientSession(connector=connector) as new_session: | |
async with new_session.get(url, params=params) as response: | |
if response.status != 200: | |
print(f"{Fore.RED}ParaSwap API error: {await response.text()}") | |
return None | |
data = await response.json() | |
print(f"ParaSwap Price API Response: {data}") # เพิ่มการ log ข้อมูลที่ได้รับ | |
if 'priceRoute' not in data: | |
print(f"{Fore.RED}Missing 'priceRoute' in ParaSwap API response") | |
return None | |
return data['priceRoute'] | |
except Exception as e: | |
print(f"{Fore.RED}Unexpected error fetching ParaSwap price: {e}") | |
return None | |
def check_wmatic_allowance(spender_address): | |
allowance = wmatic_contract.functions.allowance(WALLET_ADDRESS, spender_address).call() | |
print(f"การอนุมัติ WMATIC ปัจจุบันสำหรับ {spender_address}: {w3.from_wei(allowance, 'ether')} WMATIC") | |
return allowance | |
async def approve_token(token_address, spender, amount): | |
token_contract = w3.eth.contract(address=token_address, abi=ERC20_ABI) | |
try: | |
# ตรวจสอบการอนุมัติปัจจุบัน | |
current_allowance = token_contract.functions.allowance(WALLET_ADDRESS, spender).call() | |
if current_allowance >= amount: | |
print(f"{Fore.GREEN}มีการอนุมัติเพียงพออยู่แล้ว") | |
return True | |
# อนุมัติจำนวนใหม่ | |
print(f"{Fore.YELLOW}กำลังอนุมัติโทเคน...") | |
approve_txn = token_contract.functions.approve(spender, amount).build_transaction({ | |
'from': WALLET_ADDRESS, | |
'gas': 100000, | |
'gasPrice': w3.eth.gas_price, | |
'nonce': w3.eth.get_transaction_count(WALLET_ADDRESS), | |
}) | |
signed_txn = w3.eth.account.sign_transaction(approve_txn, PRIVATE_KEY) | |
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction) | |
receipt = w3.eth.wait_for_transaction_receipt(tx_hash) | |
if receipt['status'] == 1: | |
print(f"{Fore.GREEN}การอนุมัติโทเคนสำเร็จ Transaction hash: {receipt['transactionHash'].hex()}") | |
return True | |
else: | |
print(f"{Fore.RED}การอนุมัติโทเคนล้มเหลว") | |
return False | |
except Exception as e: | |
print(f"{Fore.RED}เกิดข้อผิดพลาดในการอนุมัติโทเคน: {str(e)}") | |
return False | |
async def approve_wmatic(spender_address, amount): | |
approve_txn = wmatic_contract.functions.approve(spender_address, amount).build_transaction({ | |
'from': WALLET_ADDRESS, | |
'gas': 100000, | |
'gasPrice': w3.eth.gas_price, | |
'nonce': w3.eth.get_transaction_count(WALLET_ADDRESS), | |
}) | |
signed_txn = w3.eth.account.sign_transaction(approve_txn, PRIVATE_KEY) | |
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction) | |
receipt = w3.eth.wait_for_transaction_receipt(tx_hash) | |
if receipt['status'] == 1: | |
print(f"{Fore.GREEN}การอนุมัติ WMATIC สำเร็จ: {w3.from_wei(amount, 'ether')} WMATIC") | |
return True | |
else: | |
print(f"{Fore.RED}การอนุมัติ WMATIC ล้มเหลว") | |
return False | |
async def check_price_difference(token_a, token_b, amount, wallet_address): | |
token_a_name = "WMATIC" if token_a == WMATIC else "USDC" | |
token_b_name = "USDC" if token_b == USDC else "WMATIC" | |
print(f"{Fore.CYAN}ตรวจสอบราคา {token_a_name}/{token_b_name}") | |
print(f"{Fore.CYAN}จำนวนเงิน: {w3.from_wei(amount, 'ether' if token_a == WMATIC else 'mwei')} {token_a_name}") | |
path = [token_a, token_b] | |
# ดึงราคาจาก DEX ต่างๆ | |
prices = {} | |
for dex, contract in [("QuickSwap", quickswap_contract), ("SushiSwap", sushiswap_contract)]: | |
try: | |
amounts_out = contract.functions.getAmountsOut(amount, path).call() | |
prices[dex] = amounts_out[1] | |
except Exception as e: | |
print(f"{Fore.RED}ไม่สามารถดึงราคาจาก {dex}: {e}") | |
# ดึงราคาจาก ParaSwap | |
async with aiohttp.ClientSession() as session: | |
paraswap_price = await get_paraswap_price(session, token_a, token_b, str(amount)) | |
if paraswap_price: | |
prices["ParaSwap"] = int(paraswap_price['destAmount']) | |
if len(prices) < 2: | |
print(f"{Fore.RED}ไม่สามารถเปรียบเทียบราคาได้ เนื่องจากมีข้อมูลไม่เพียงพอ") | |
return None | |
best_dex = max(prices, key=prices.get) | |
worst_dex = min(prices, key=prices.get) | |
best_price = prices[best_dex] | |
worst_price = prices[worst_dex] | |
difference = best_price - worst_price | |
profit_percentage = (difference / worst_price) * 100 | |
print(f"\n{Fore.GREEN}ผลการตรวจสอบโอกาสอาร์บิทราจ:") | |
for dex, price in prices.items(): | |
print(f"{Fore.YELLOW}{dex}: {w3.from_wei(price, 'mwei' if token_b == USDC else 'ether')} {token_b_name}") | |
print(f"{Fore.CYAN}ส่วนต่างราคาสูงสุด: {w3.from_wei(difference, 'mwei' if token_b == USDC else 'ether')} {token_b_name}") | |
print(f"{Fore.CYAN}เปอร์เซ็นต์กำไรที่เป็นไปได้: {profit_percentage:.2f}%") | |
if profit_percentage > 0.7: | |
print(f"{Fore.GREEN}พบโอกาสอาร์บิทราจ: ซื้อบน {worst_dex}, ขายบน {best_dex}") | |
return worst_dex, best_dex, amount, profit_percentage | |
else: | |
print(f"{Fore.YELLOW}ไม่พบโอกาสอาร์บิทราจที่คุ้มค่า (กำไรน้อยกว่า 0.5%)") | |
return None | |
async def swap_on_paraswap(token_in, token_out, amount_in, max_retries=3): | |
for attempt in range(max_retries): | |
try: | |
# ตรวจสอบยอดคงเหลือ | |
balance = await check_token_balance(token_in, WALLET_ADDRESS) | |
if balance < amount_in: | |
return {'success': False, 'error': f'ยอดคงเหลือไม่เพียงพอ: มี {w3.from_wei(balance, "ether" if token_in == WMATIC else "mwei")}, ต้องการ {w3.from_wei(amount_in, "ether" if token_in == WMATIC else "mwei")}'} | |
# บันทึกยอดคงเหลือเริ่มต้นของโทเคนที่จะได้รับ | |
initial_out_balance = await check_token_balance(token_out, WALLET_ADDRESS) | |
ssl_context = ssl.create_default_context() | |
ssl_context.check_hostname = False | |
ssl_context.verify_mode = ssl.CERT_NONE | |
print(f"{Fore.YELLOW}คำเตือน: กำลังใช้การเชื่อมต่อที่ไม่ปลอดภัย (ไม่ตรวจสอบ SSL certificate)") | |
connector = aiohttp.TCPConnector(ssl=ssl_context) | |
async with aiohttp.ClientSession(connector=connector) as session: | |
price_route = await get_paraswap_price(session, token_in, token_out, str(amount_in)) | |
if not price_route: | |
return {'success': False, 'error': 'Failed to get ParaSwap price route'} | |
token_proxy = Web3.to_checksum_address(price_route['tokenTransferProxy']) | |
# ตรวจสอบและอนุมัติโทเคน (ถ้าจำเป็น) | |
if token_in != WMATIC: | |
allowance = await check_token_allowance(token_in, WALLET_ADDRESS, token_proxy) | |
if allowance < amount_in: | |
approve_result = await approve_token(token_in, token_proxy, 2**256 - 1) # Max approval | |
if not approve_result: | |
return {'success': False, 'error': 'Failed to approve token'} | |
url = f"{PARASWAP_API_URL}/transactions/137" | |
payload = { | |
"srcToken": token_in, | |
"destToken": token_out, | |
"srcAmount": str(amount_in), | |
"destAmount": str(price_route['destAmount']), | |
"priceRoute": price_route, | |
"userAddress": WALLET_ADDRESS, | |
"partner": "paraswap.io", | |
"receiver": WALLET_ADDRESS | |
} | |
async with session.post(url, json=payload) as response: | |
if response.status != 200: | |
error_text = await response.text() | |
if "The rate has changed" in error_text: | |
print(f"{Fore.YELLOW}ราคาเปลี่ยนแปลง กำลังลองใหม่... (ครั้งที่ {attempt + 1})") | |
continue | |
print(f"{Fore.RED}ParaSwap API error: {error_text}") | |
return {'success': False, 'error': f"ParaSwap API error: {error_text}"} | |
transaction = await response.json() | |
print(f"ParaSwap API Response: {transaction}") | |
required_keys = ['to', 'from', 'data', 'value', 'gasPrice', 'gas'] | |
if not all(key in transaction for key in required_keys): | |
print(f"{Fore.RED}Missing required transaction data") | |
return {'success': False, 'error': 'Incomplete transaction data'} | |
tx = transaction | |
tx['nonce'] = w3.eth.get_transaction_count(WALLET_ADDRESS) | |
# แปลงค่า gasPrice, gas และ value เป็น integer | |
tx['gasPrice'] = int(tx['gasPrice']) | |
tx['gas'] = int(tx['gas']) | |
tx['value'] = int(tx['value']) | |
# ตรวจสอบและแก้ไขค่า 'value' | |
if token_in == WMATIC: | |
if tx['value'] == 0: | |
tx['value'] = amount_in | |
print(f"Swapping WMATIC, value set to: {tx['value']}") | |
else: | |
tx['value'] = 0 | |
print(f"Swapping {token_in}, value set to: {tx['value']}") | |
signed_txn = w3.eth.account.sign_transaction(tx, PRIVATE_KEY) | |
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction) | |
print(f"{Fore.YELLOW}ส่งธุรกรรม ParaSwap แล้ว Hash: {tx_hash.hex()}") | |
receipt = await wait_for_transaction_receipt_with_timeout(tx_hash, timeout=300) | |
if receipt['status'] == 1: | |
print(f"{Fore.GREEN}การสวอปผ่าน ParaSwap สำเร็จ") | |
# ตรวจสอบจำนวนโทเคนที่ได้รับจริง | |
final_out_balance = await check_token_balance(token_out, WALLET_ADDRESS) | |
actual_amount_out = final_out_balance - initial_out_balance | |
print(f"ได้รับ {w3.from_wei(actual_amount_out, 'ether' if token_out == WMATIC else 'mwei')} {token_out}") | |
return {'success': True, 'amount_out': actual_amount_out, 'tx_hash': tx_hash.hex()} | |
else: | |
print(f"{Fore.RED}การสวอปผ่าน ParaSwap ล้มเหลว") | |
return {'success': False, 'error': 'Transaction failed', 'receipt': receipt} | |
except Exception as e: | |
print(f"{Fore.RED}เกิดข้อผิดพลาดในการสวอปผ่าน ParaSwap: {str(e)}") | |
if attempt < max_retries - 1: | |
print(f"{Fore.YELLOW}กำลังลองใหม่... (ครั้งที่ {attempt + 2})") | |
else: | |
return {'success': False, 'error': str(e)} | |
return {'success': False, 'error': 'Max retries reached'} | |
async def check_token_balance(token_address, wallet_address): | |
token_contract = w3.eth.contract(address=token_address, abi=ERC20_ABI) | |
balance = token_contract.functions.balanceOf(wallet_address).call() | |
return balance | |
async def check_token_allowance(token_address, owner, spender): | |
token_contract = w3.eth.contract(address=token_address, abi=ERC20_ABI) | |
allowance = token_contract.functions.allowance(owner, spender).call() | |
return allowance | |
async def approve_token(token_address, spender, amount): | |
token_contract = w3.eth.contract(address=token_address, abi=ERC20_ABI) | |
try: | |
tx = token_contract.functions.approve(spender, amount).build_transaction({ | |
'from': WALLET_ADDRESS, | |
'nonce': w3.eth.get_transaction_count(WALLET_ADDRESS), | |
}) | |
signed_tx = w3.eth.account.sign_transaction(tx, PRIVATE_KEY) | |
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) | |
receipt = await wait_for_transaction_receipt_with_timeout(tx_hash) | |
if receipt['status'] == 1: | |
print(f"{Fore.GREEN}Token approval successful") | |
return True | |
else: | |
print(f"{Fore.RED}Token approval failed") | |
return False | |
except Exception as e: | |
print(f"{Fore.RED}Error in token approval: {str(e)}") | |
return False | |
async def wait_for_transaction_receipt_with_timeout(tx_hash, timeout=300): | |
start_time = time.time() | |
while time.time() - start_time < timeout: | |
try: | |
receipt = w3.eth.get_transaction_receipt(tx_hash) | |
if receipt is not None: | |
return receipt | |
except Exception as e: | |
print(f"Error getting receipt: {e}") | |
await asyncio.sleep(1) | |
raise TimeoutError(f"Transaction not mined within {timeout} seconds") | |
async def swap_on_dex(dex, token_in, token_out, amount_in): | |
router_contract = sushiswap_contract if dex == "SushiSwap" else quickswap_contract | |
path = [token_in, token_out] | |
deadline = int(time.time()) + 300 # 5 minutes | |
try: | |
# ตรวจสอบยอดคงเหลือและการอนุมัติ | |
balance = wmatic_contract.functions.balanceOf(WALLET_ADDRESS).call() | |
allowance = wmatic_contract.functions.allowance(WALLET_ADDRESS, router_contract.address).call() | |
print(f"ยอด WMATIC คงเหลือ: {w3.from_wei(balance, 'ether')}") | |
print(f"การอนุมัติ WMATIC ปัจจุบัน: {w3.from_wei(allowance, 'ether')}") | |
if balance < amount_in: | |
print(f"{Fore.RED}ยอดคงเหลือไม่เพียงพอสำหรับการสวอป") | |
return {'success': False, 'error': 'Insufficient balance'} | |
if allowance < amount_in: | |
print(f"{Fore.YELLOW}กำลังอนุมัติ WMATIC...") | |
await approve_wmatic(router_contract.address, 2**256 - 1) | |
# คำนวณจำนวนขั้นต่ำที่จะได้รับ | |
amounts_out = router_contract.functions.getAmountsOut(amount_in, path).call() | |
min_amount_out = int(amounts_out[1] * 0.95) # 5% slippage | |
print(f"จำนวนที่คาดว่าจะได้รับ: {w3.from_wei(amounts_out[1], 'mwei' if token_out == USDC else 'ether')} {token_out}") | |
print(f"จำนวนขั้นต่ำที่จะได้รับ: {w3.from_wei(min_amount_out, 'mwei' if token_out == USDC else 'ether')} {token_out}") | |
# สร้างและส่งธุรกรรม | |
swap_txn = router_contract.functions.swapExactTokensForTokens( | |
amount_in, | |
min_amount_out, | |
path, | |
WALLET_ADDRESS, | |
deadline | |
).build_transaction({ | |
'from': WALLET_ADDRESS, | |
'gas': 300000, # เพิ่ม gas limit | |
'gasPrice': w3.eth.gas_price, | |
'nonce': w3.eth.get_transaction_count(WALLET_ADDRESS), | |
}) | |
signed_txn = w3.eth.account.sign_transaction(swap_txn, PRIVATE_KEY) | |
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction) | |
print(f"ส่งธุรกรรมแล้ว Hash: {tx_hash.hex()}") | |
receipt = w3.eth.wait_for_transaction_receipt(tx_hash) | |
if receipt['status'] == 1: | |
print(f"{Fore.GREEN}การสวอปสำเร็จ") | |
return {'success': True, 'amount_out': amounts_out[1], 'tx_hash': tx_hash.hex()} | |
else: | |
print(f"{Fore.RED}การสวอปล้มเหลว") | |
print(f"รายละเอียดธุรกรรม: {receipt}") | |
return {'success': False, 'error': 'Transaction failed', 'receipt': receipt} | |
except Exception as e: | |
print(f"{Fore.RED}เกิดข้อผิดพลาดในการสวอปบน {dex}: {str(e)}") | |
return {'success': False, 'error': str(e)} | |
async def execute_arbitrage(amount, buy_dex, sell_dex, max_retries=3): | |
try: | |
# ตรวจสอบยอด MATIC เริ่มต้น | |
initial_matic_balance = w3.eth.get_balance(WALLET_ADDRESS) | |
print(f"ยอด MATIC เริ่มต้น: {w3.from_wei(initial_matic_balance, 'ether')} MATIC") | |
# ห่อ MATIC เป็น WMATIC ถ้าจำเป็น | |
wmatic_contract = w3.eth.contract(address=WMATIC, abi=WMATIC_ABI) | |
wmatic_balance = await check_token_balance(WMATIC, WALLET_ADDRESS) | |
if wmatic_balance < amount: | |
wrap_amount = amount - wmatic_balance | |
wrap_tx = wmatic_contract.functions.deposit().build_transaction({ | |
'from': WALLET_ADDRESS, | |
'value': wrap_amount, | |
'gas': 100000, | |
'gasPrice': get_polygon_gas_price(), | |
'nonce': w3.eth.get_transaction_count(WALLET_ADDRESS), | |
}) | |
signed_tx = w3.eth.account.sign_transaction(wrap_tx, PRIVATE_KEY) | |
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) | |
await wait_for_transaction_receipt_with_timeout(tx_hash) | |
print(f"Wrapped {w3.from_wei(wrap_amount, 'ether')} MATIC to WMATIC") | |
# ซื้อ USDC ด้วย WMATIC | |
if buy_dex == "ParaSwap": | |
buy_result = await swap_on_paraswap(WMATIC, USDC, amount, max_retries) | |
else: | |
buy_result = await swap_on_dex(buy_dex, WMATIC, USDC, amount) | |
if not buy_result['success']: | |
print(f"{Fore.RED}การซื้อบน {buy_dex} ล้มเหลว: {buy_result.get('error', 'Unknown error')}") | |
return False | |
usdc_amount = buy_result['amount_out'] | |
print(f"{Fore.GREEN}การซื้อสำเร็จ ได้รับ {w3.from_wei(usdc_amount, 'mwei')} USDC") | |
# ตรวจสอบยอด USDC ที่ได้รับจริง | |
actual_usdc_balance = await check_token_balance(USDC, WALLET_ADDRESS) | |
print(f"ยอด USDC ที่มีจริง: {w3.from_wei(actual_usdc_balance, 'mwei')} USDC") | |
if actual_usdc_balance < usdc_amount: | |
print(f"{Fore.YELLOW}คำเตือน: ยอด USDC ที่ได้รับน้อยกว่าที่คาดการณ์") | |
usdc_amount = actual_usdc_balance | |
# ขาย USDC เพื่อรับ WMATIC | |
if sell_dex == "ParaSwap": | |
sell_result = await swap_on_paraswap(USDC, WMATIC, usdc_amount, max_retries) | |
else: | |
sell_result = await swap_on_dex(sell_dex, USDC, WMATIC, usdc_amount) | |
if not sell_result['success']: | |
print(f"{Fore.RED}การขายบน {sell_dex} ล้มเหลว: {sell_result.get('error', 'Unknown error')}") | |
print(f"{Fore.YELLOW}คำเตือน: การซื้อสำเร็จแล้ว แต่การขายล้มเหลว") | |
print(f"{Fore.YELLOW}กำลังพยายามคืน USDC เป็น WMATIC...") | |
revert_result = await swap_on_dex(buy_dex, USDC, WMATIC, usdc_amount) | |
if revert_result['success']: | |
print(f"{Fore.GREEN}คืน USDC เป็น WMATIC สำเร็จ") | |
wmatic_received = revert_result['amount_out'] | |
loss = Decimal(str(amount)) - Decimal(str(wmatic_received)) | |
print(f"{Fore.YELLOW}การสูญเสียจากการคืน: {w3.from_wei(w3.to_wei(loss, 'ether'), 'ether')} WMATIC") | |
else: | |
print(f"{Fore.RED}ไม่สามารถคืน USDC เป็น WMATIC ได้ โปรดดำเนินการด้วยตนเอง") | |
print(f"{Fore.RED}USDC ที่ติดอยู่: {w3.from_wei(usdc_amount, 'mwei')} USDC") | |
return False | |
final_wmatic_balance = await check_token_balance(WMATIC, WALLET_ADDRESS) | |
wmatic_received = Decimal(str(final_wmatic_balance)) - Decimal(str(amount)) | |
profit = wmatic_received if wmatic_received > 0 else Decimal('0') | |
loss = -wmatic_received if wmatic_received < 0 else Decimal('0') | |
profit_wei = w3.to_wei(profit, 'ether') | |
loss_wei = w3.to_wei(loss, 'ether') | |
print(f"{Fore.GREEN}อาร์บิทราจเสร็จสิ้น") | |
print(f"WMATIC ที่ใช้: {w3.from_wei(amount, 'ether')}") | |
print(f"WMATIC ที่ได้รับ: {w3.from_wei(final_wmatic_balance, 'ether')}") | |
if profit > 0: | |
print(f"กำไร: {w3.from_wei(profit_wei, 'ether')} WMATIC") | |
if loss > 0: | |
print(f"ขาดทุน: {w3.from_wei(loss_wei, 'ether')} WMATIC") | |
# ปิดการแปลง WMATIC กลับเป็น MATIC | |
# unwrap_tx = wmatic_contract.functions.withdraw(final_wmatic_balance).build_transaction({ | |
# 'from': WALLET_ADDRESS, | |
# 'gas': 100000, | |
# 'gasPrice': get_polygon_gas_price(), | |
# 'nonce': w3.eth.get_transaction_count(WALLET_ADDRESS), | |
# }) | |
# signed_tx = w3.eth.account.sign_transaction(unwrap_tx, PRIVATE_KEY) | |
# tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) | |
# await wait_for_transaction_receipt_with_timeout(tx_hash) | |
# print(f"Unwrapped {w3.from_wei(final_wmatic_balance, 'ether')} WMATIC to MATIC") | |
# final_matic_balance = w3.eth.get_balance(WALLET_ADDRESS) | |
# total_profit = Decimal(str(final_matic_balance)) - Decimal(str(initial_matic_balance)) | |
# print(f"กำไร/ขาดทุนสุทธิ: {w3.from_wei(w3.to_wei(total_profit, 'ether'), 'ether')} MATIC") | |
return True | |
except Exception as e: | |
print(f"{Fore.RED}เกิดข้อผิดพลาดระหว่างการทำอาร์บิทราจ: {e}") | |
return False | |
def get_polygon_gas_price(): | |
gas_price = w3.eth.gas_price | |
return int(gas_price * 1.1) # เพิ่ม gas price อีก 10% เพื่อให้แน่ใจว่าธุรกรรมจะผ่าน | |
async def check_token_balance(token_address, wallet_address): | |
token_contract = w3.eth.contract(address=token_address, abi=ERC20_ABI) | |
balance = token_contract.functions.balanceOf(wallet_address).call() | |
return int(balance) | |
async def wait_for_transaction_receipt_with_timeout(tx_hash, timeout=300): | |
start_time = time.time() | |
while time.time() - start_time < timeout: | |
try: | |
receipt = w3.eth.get_transaction_receipt(tx_hash) | |
if receipt is not None: | |
return receipt | |
except Exception as e: | |
print(f"Error getting receipt: {e}") | |
await asyncio.sleep(1) | |
raise TimeoutError(f"Transaction not mined within {timeout} seconds") | |
async def run_arbitrage_bot(): | |
AMOUNT_IN = w3.to_wei(1, 'ether') # 1 WMATIC | |
while True: | |
try: | |
print(f"\n{Fore.CYAN}{Style.BRIGHT}เริ่มตรวจสอบโอกาสอาร์บิทราจ...") | |
opportunity = await check_price_difference(WMATIC, USDC, AMOUNT_IN, WALLET_ADDRESS) | |
if opportunity: | |
worst_dex, best_dex, amount, profit_percentage = opportunity | |
print(f"{Fore.GREEN}พบโอกาสอาร์บิทราจ: ซื้อบน {worst_dex}, ขายบน {best_dex}") | |
if await execute_arbitrage(amount, worst_dex, best_dex): | |
print(f"{Fore.GREEN}อาร์บิทราจสำเร็จ กำไร: {profit_percentage:.2f}%") | |
else: | |
print(f"{Fore.RED}การทำอาร์บิทราจล้มเหลว") | |
else: | |
print(f"{Fore.YELLOW}ไม่พบโอกาสอาร์บิทราจในรอบนี้") | |
except Exception as e: | |
print(f'{Fore.RED}เกิดข้อผิดพลาดในลูปหลัก: {e}') | |
print(f"{Fore.CYAN}รอ 10 วินาทีก่อนตรวจสอบครั้งถัดไป...") | |
await asyncio.sleep(10) | |
async def main(): | |
print(f"{Fore.GREEN}{Style.BRIGHT}เริ่มต้นบอทอาร์บิทราจ...") | |
if not w3.is_connected(): | |
print(f"{Fore.RED}ไม่สามารถเชื่อมต่อกับ Polygon network ได้") | |
return | |
print(f"{Fore.GREEN}เชื่อมต่อกับ Polygon network สำเร็จ") | |
print(f"{Fore.YELLOW}กระเป๋าเงินที่ใช้: {WALLET_ADDRESS}") | |
# ตรวจสอบยอดคงเหลือ | |
wmatic_balance = wmatic_contract.functions.balanceOf(WALLET_ADDRESS).call() | |
usdc_balance = usdc_contract.functions.balanceOf(WALLET_ADDRESS).call() | |
print(f"{Fore.CYAN}ยอด WMATIC คงเหลือ: {w3.from_wei(wmatic_balance, 'ether')} WMATIC") | |
print(f"{Fore.CYAN}ยอด USDC คงเหลือ: {w3.from_wei(usdc_balance, 'mwei')} USDC") | |
try: | |
await run_arbitrage_bot() | |
except KeyboardInterrupt: | |
print(f"{Fore.YELLOW}บอทถูกหยุดโดยผู้ใช้") | |
if __name__ == "__main__": | |
asyncio.run(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment