├── .gitignore ├── Examples ├── .env.template ├── Close_Burn_Spl_tokenAccount.py ├── TransferSol.py ├── Transfer_spl_token.py ├── Unwrap_Sol.py └── Wrap_Sol.py ├── Jito ├── .env.template ├── buy_with_jito.py ├── sell_with_jito.py └── utils │ ├── birdeye.py │ ├── create_close_account.py │ ├── layouts.py │ └── pool_information.py ├── PumpDotFun ├── .env.template ├── __pycache__ │ └── buy.cpython-311.pyc ├── buy.py ├── sell.py └── utils │ ├── __pycache__ │ ├── coin_data.cpython-311.pyc │ ├── constants.cpython-311.pyc │ └── utility.cpython-311.pyc │ ├── coin_data.py │ ├── constants.py │ └── utility.py ├── WrapSol__PriorityFees ├── .env.template ├── buy_wrap_sol.py ├── close_tokenAccount.py ├── sell_wrap_sol.py ├── unwrap_sol.py ├── utils │ ├── create_close_account.py │ ├── layouts.py │ └── pool_information.py └── wrap_sol.py ├── readme.md └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | **/.env 2 | -------------------------------------------------------------------------------- /Examples/.env.template: -------------------------------------------------------------------------------- 1 | #Rename to .env 2 | #Your RPC URL 3 | RPC_HTTPS_URL="" 4 | RPC_WS_URL="" 5 | #YOur Private KEy 6 | PrivateKey="" 7 | Amount_to_snipe=0.0001 8 | # Amount of SOL --> WSOL 9 | amount_to_wrap=0.02 10 | WSOL_TokenAccount="" #Your WSOL Token Account 11 | 12 | JITO_PAYER="" #The private of the jito account 13 | TIP_ACCOUNT="Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY" #Jito Tip Account 14 | TIP_AMOUNT=0.0002122 #Amount to tip -------------------------------------------------------------------------------- /Examples/Close_Burn_Spl_tokenAccount.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | from solana.rpc.commitment import Finalized 4 | from solders.compute_budget import set_compute_unit_price, set_compute_unit_limit 5 | from solders.message import MessageV0 6 | from solders.pubkey import Pubkey 7 | from solders.keypair import Keypair 8 | from solana.rpc.async_api import AsyncClient 9 | from solders.transaction import VersionedTransaction 10 | from solana.rpc.api import Client 11 | from solana.transaction import Transaction 12 | from solana.rpc import types 13 | from spl.token.constants import TOKEN_PROGRAM_ID 14 | from spl.token.instructions import burn, BurnParams, CloseAccountParams, close_account 15 | from dotenv import load_dotenv 16 | load_dotenv() 17 | payer = Keypair.from_base58_string(os.getenv('PrivateKey')) 18 | solana_client = Client(os.getenv("RPC_HTTPS_URL")) 19 | async_solana_client = AsyncClient(os.getenv("RPC_HTTPS_URL")) 20 | 21 | async def get_token_accountsCount(wallet_address: Pubkey): 22 | owner = wallet_address 23 | opts = types.TokenAccountOpts(program_id=Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")) 24 | response = await async_solana_client.get_token_accounts_by_owner(owner, opts) 25 | return response.value 26 | 27 | 28 | async def main(): 29 | 30 | 31 | 32 | wallet_address= payer.pubkey() 33 | response = await get_token_accountsCount(wallet_address) 34 | solana_token_accounts = {str(token_account.pubkey): token_account for token_account in response} 35 | tokenAccount_list= list(solana_token_accounts.keys()) 36 | while len(tokenAccount_list)>0: 37 | try: 38 | for token in tokenAccount_list: 39 | burn_instruction=[] 40 | 41 | c = await async_solana_client.get_account_info_json_parsed(Pubkey.from_string(token)) 42 | mint_address=Pubkey.from_string(c.value.data.parsed['info']['mint']) 43 | token_account=Pubkey.from_string(token) 44 | balance = solana_client.get_token_account_balance(Pubkey.from_string(token)) 45 | amount=balance.value.amount 46 | print(amount) 47 | params = BurnParams( 48 | amount=int(amount), account=token_account, mint=mint_address, owner=payer.pubkey(), program_id=TOKEN_PROGRAM_ID, 49 | ) 50 | 51 | burn_inst= burn(params) 52 | close_account_params = CloseAccountParams(account=token_account, 53 | dest=payer.pubkey(), 54 | owner=payer.pubkey(), 55 | program_id=TOKEN_PROGRAM_ID) 56 | transaction = Transaction() 57 | 58 | transaction.add(close_account(close_account_params), set_compute_unit_price(25_232), set_compute_unit_limit(200_337)) 59 | burn_instruction.extend([burn_inst,transaction.instructions[0],transaction.instructions[1],transaction.instructions[2]]) 60 | 61 | block_hash = solana_client.get_latest_blockhash(commitment=Finalized) 62 | print(block_hash.value.blockhash) 63 | 64 | msg = MessageV0.try_compile( 65 | payer=payer.pubkey(), 66 | instructions=[instruction for instruction in burn_instruction], 67 | address_lookup_table_accounts=[], 68 | recent_blockhash=block_hash.value.blockhash, 69 | ) 70 | 71 | tx1 = VersionedTransaction(msg, [payer]) 72 | txn_sig=solana_client.send_transaction(tx1) 73 | print(txn_sig.value) 74 | 75 | tokenAccount_list.remove(token) 76 | 77 | 78 | except Exception as e: 79 | print(e) 80 | continue 81 | 82 | 83 | asyncio.run(main()) -------------------------------------------------------------------------------- /Examples/TransferSol.py: -------------------------------------------------------------------------------- 1 | 2 | import asyncio 3 | import os 4 | import time 5 | from solana.transaction import Transaction 6 | from solana.rpc.commitment import Confirmed 7 | from solders.keypair import Keypair 8 | from solders.system_program import TransferParams, transfer 9 | from solana.rpc.async_api import AsyncClient 10 | from solders.pubkey import Pubkey 11 | from solders.transaction import VersionedTransaction 12 | from solders.message import MessageV0 13 | from jito_searcher_client import get_async_searcher_client 14 | from jito_searcher_client.convert import versioned_tx_to_protobuf_packet 15 | from jito_searcher_client.generated.bundle_pb2 import Bundle 16 | from jito_searcher_client.generated.searcher_pb2 import NextScheduledLeaderRequest, NextScheduledLeaderResponse, SendBundleRequest 17 | from dotenv import load_dotenv 18 | from solana.rpc.api import Client 19 | 20 | load_dotenv() 21 | payer = Keypair.from_base58_string(os.getenv('PrivateKey')) 22 | RPC_HTTPS_URL = os.getenv("RPC_HTTPS_URL") 23 | solana_client = Client(RPC_HTTPS_URL) 24 | async_solana_client = AsyncClient(RPC_HTTPS_URL) 25 | LAMPORTS_PER_SOL = 1000000000 26 | 27 | Wallet_to_receive = Pubkey.from_string("777cz6dNUWu4hGNKda7gmnnqTz1RUxB2BGpP3S9ky466") # Enter Wallet to receive SOL 28 | params = TransferParams( 29 | from_pubkey=payer.pubkey(), 30 | to_pubkey=Wallet_to_receive, 31 | lamports=int(0.0005 * 10**9) # Amount of SOL to transfer 32 | ) 33 | 34 | transaction = Transaction() 35 | transaction.add(transfer(params)) 36 | transaction.sign(payer) 37 | 38 | 39 | async def send_and_confirm_transaction(client, transaction, payer, max_attempts=3): 40 | attempts = 0 41 | while attempts < max_attempts: 42 | try: 43 | ### SENDING THROUGH JITO 44 | print("Sending Through Jito") 45 | 46 | jito_payer = Keypair.from_base58_string(os.getenv("JITO_PAYER")) 47 | BLOCK_ENGINE_URL = "frankfurt.mainnet.block-engine.jito.wtf" 48 | jito_client = await get_async_searcher_client(BLOCK_ENGINE_URL, jito_payer) 49 | 50 | txs = [] 51 | tip_account_pubkey = Pubkey.from_string(os.getenv("TIP_ACCOUNT")) 52 | 53 | is_leader_slot = False 54 | print("waiting for jito leader...") 55 | while not is_leader_slot: 56 | time.sleep(0.5) 57 | next_leader: NextScheduledLeaderResponse = await jito_client.GetNextScheduledLeader( 58 | NextScheduledLeaderRequest()) 59 | num_slots_to_leader = next_leader.next_leader_slot - next_leader.current_slot 60 | print(f"waiting {num_slots_to_leader} slots to jito leader") 61 | is_leader_slot = num_slots_to_leader <= 5 62 | 63 | ix = transfer( 64 | TransferParams( 65 | from_pubkey=payer.pubkey(), to_pubkey=tip_account_pubkey, 66 | lamports=int(0.000020002 * LAMPORTS_PER_SOL) # TIP AMOUNT 67 | ) 68 | ) 69 | 70 | 71 | block_hash = solana_client.get_latest_blockhash(commitment=Confirmed) 72 | 73 | print(block_hash.value.blockhash) 74 | 75 | 76 | msg = MessageV0.try_compile( 77 | payer=payer.pubkey(), 78 | instructions=[transaction.instructions[0],ix], 79 | address_lookup_table_accounts=[], 80 | recent_blockhash=block_hash.value.blockhash, 81 | ) 82 | 83 | tx1 = VersionedTransaction(msg, [payer]) 84 | 85 | txs.append(tx1) 86 | 87 | packets = [versioned_tx_to_protobuf_packet(tx) for tx in txs] 88 | uuid_response = await jito_client.SendBundle(SendBundleRequest(bundle=Bundle(header=None, packets=packets))) 89 | 90 | print(f"bundle uuid: {uuid_response.uuid}") 91 | block_height = solana_client.get_block_height(Confirmed).value 92 | print(f"Block height: {block_height}") 93 | 94 | for tx in txs: 95 | confirmation_resp = await async_solana_client.confirm_transaction( 96 | 97 | tx.signatures[0], 98 | commitment=Confirmed, 99 | sleep_seconds=0.5, 100 | last_valid_block_height=block_height + 15 101 | ) 102 | print(f"Confirmation Response: {confirmation_resp.value}") 103 | 104 | if confirmation_resp.value[0].err is None and str( 105 | confirmation_resp.value[0].confirmation_status) == "TransactionConfirmationStatus.Confirmed": 106 | print("Transaction Confirmed") 107 | print(f"Transaction Signature: https://solscan.io/tx/{tx.signatures[0]}") 108 | return 109 | 110 | attempts += 1 111 | print("Transaction not confirmed, retrying...") 112 | except Exception as e: 113 | print(f"Attempt {attempts}: Exception occurred - {e}") 114 | attempts += 1 115 | 116 | if attempts == max_attempts: 117 | print("Maximum attempts reached. Transaction could not be confirmed.") 118 | 119 | asyncio.run(send_and_confirm_transaction(solana_client, transaction, payer)) 120 | -------------------------------------------------------------------------------- /Examples/Transfer_spl_token.py: -------------------------------------------------------------------------------- 1 | 2 | import asyncio 3 | import os 4 | import time 5 | from solana.rpc.commitment import Confirmed 6 | from solders.keypair import Keypair 7 | from solana.rpc.async_api import AsyncClient 8 | from solders.pubkey import Pubkey 9 | from dotenv import load_dotenv 10 | from solana.rpc.api import Client 11 | from spl.token.client import Token 12 | from spl.token.constants import TOKEN_PROGRAM_ID 13 | from solana.transaction import Transaction 14 | from solders.transaction import VersionedTransaction 15 | from solders.message import MessageV0 16 | from jito_searcher_client import get_async_searcher_client 17 | from jito_searcher_client.convert import versioned_tx_to_protobuf_packet 18 | from jito_searcher_client.generated.bundle_pb2 import Bundle 19 | from jito_searcher_client.generated.searcher_pb2 import NextScheduledLeaderRequest, SendBundleRequest 20 | from solders.system_program import TransferParams as SoldersTransferParams 21 | from solders.system_program import transfer as solders_transfer 22 | import spl.token.instructions as spl_token 23 | load_dotenv() 24 | 25 | # Load environment variables 26 | payer = Keypair.from_base58_string(os.getenv('PrivateKey')) 27 | 28 | RPC_HTTPS_URL = os.getenv("RPC_HTTPS_URL") 29 | solana_client = Client(RPC_HTTPS_URL) 30 | async_solana_client = AsyncClient(RPC_HTTPS_URL) 31 | LAMPORTS_PER_SOL = 1000000000 32 | 33 | # Token-related setup 34 | mint = Pubkey.from_string("RUpbmGF6p42AAeN1QvhFReZejQry1cLkE1PUYFVVpnL") 35 | program_id = TOKEN_PROGRAM_ID 36 | spl_client = Token(conn=solana_client, pubkey=mint, program_id=TOKEN_PROGRAM_ID, payer=payer) 37 | mint_info = spl_client.get_mint_info() 38 | decimals = mint_info.decimals 39 | 40 | 41 | source = Pubkey.from_string('FJRDY392XSyfV9nFZC8SZij1hB3hsH121pCQi1KrvH6b') #sender 42 | dest = Pubkey.from_string('777cz6dNUWu4hGNKda7gmnnqTz1RUxB2BGpP3S9ky466') #receiver 43 | 44 | # Token accounts 45 | source_token_account = spl_client.get_accounts_by_owner(owner=source, commitment=None, encoding='base64').value[ 46 | 0].pubkey 47 | 48 | try: 49 | dest_token_account = spl_client.get_accounts_by_owner(owner=dest, commitment=None, encoding='base64').value[0].pubkey 50 | print(dest_token_account) 51 | account_info = spl_client.get_account_info(dest_token_account) 52 | is_initialized = account_info.is_initialized 53 | 54 | 55 | print(f"Associated token account for the destination wallet: {dest_token_account}") 56 | 57 | except Exception as e: 58 | print(e) 59 | print("Creating new Associative Account when sending transaction") 60 | dest_token_account = spl_token.get_associated_token_address(owner=dest, mint=mint) 61 | print(dest_token_account) 62 | is_initialized= False 63 | 64 | 65 | async def send_and_confirm_transaction_via_jito(client, payer, max_attempts=3): 66 | attempts = 0 67 | while attempts <= max_attempts: 68 | try: 69 | # initialize receiving token account 70 | ix = spl_token.create_associated_token_account(owner=dest, mint=mint, payer=payer.pubkey()) 71 | 72 | #sending token Instructions 73 | ix2 = spl_token.transfer_checked(spl_token.TransferCheckedParams( 74 | program_id=TOKEN_PROGRAM_ID, 75 | source=source_token_account, 76 | mint=mint, 77 | dest=dest_token_account, 78 | owner=payer.pubkey(), 79 | amount=int(float(1000) * 10 ** decimals), 80 | decimals=8, 81 | signers=[payer.pubkey()] 82 | )) 83 | 84 | # # SENDING THROUGH JITO 85 | print("Sending Through Jito") 86 | # 87 | jito_payer = Keypair.from_base58_string(os.getenv("JITO_PAYER")) 88 | BLOCK_ENGINE_URL = "frankfurt.mainnet.block-engine.jito.wtf" 89 | jito_client = await get_async_searcher_client(BLOCK_ENGINE_URL, jito_payer) 90 | txs = [] 91 | tip_account_pubkey = Pubkey.from_string(os.getenv("TIP_ACCOUNT")) 92 | is_leader_slot = False 93 | print("waiting for jito leader...") 94 | while not is_leader_slot: 95 | time.sleep(0.5) 96 | next_leader = await jito_client.GetNextScheduledLeader(NextScheduledLeaderRequest()) 97 | num_slots_to_leader = next_leader.next_leader_slot - next_leader.current_slot 98 | print(f"waiting {num_slots_to_leader} slots to jito leader") 99 | is_leader_slot = num_slots_to_leader <= 5 100 | 101 | 102 | ix3 = solders_transfer( 103 | SoldersTransferParams( 104 | from_pubkey=payer.pubkey(), to_pubkey=tip_account_pubkey, 105 | lamports=int(0.000020002 * LAMPORTS_PER_SOL) # TIP AMOUNT 106 | ) 107 | ) 108 | 109 | 110 | transaction=Transaction() 111 | 112 | if is_initialized: 113 | transaction.add(ix2,ix3) 114 | else: 115 | transaction.add(ix,ix2,ix3) 116 | 117 | instructions = [ix for ix in transaction.instructions] 118 | 119 | block_hash = solana_client.get_latest_blockhash(commitment=Confirmed).value.blockhash 120 | print(block_hash) 121 | 122 | msg = MessageV0.try_compile( 123 | payer=payer.pubkey(), 124 | instructions=instructions, 125 | address_lookup_table_accounts=[], 126 | recent_blockhash=block_hash, 127 | ) 128 | 129 | tx1 = VersionedTransaction(msg, [payer]) 130 | 131 | txs.append(tx1) 132 | 133 | packets = [versioned_tx_to_protobuf_packet(tx) for tx in txs] 134 | uuid_response = await jito_client.SendBundle(SendBundleRequest(bundle=Bundle(header=None, packets=packets))) 135 | 136 | print(f"bundle uuid: {uuid_response.uuid}") 137 | block_height = solana_client.get_block_height(Confirmed).value 138 | print(f"Block height: {block_height}") 139 | 140 | for tx in txs: 141 | confirmation_resp = await async_solana_client.confirm_transaction( 142 | tx.signatures[0], 143 | commitment=Confirmed, 144 | sleep_seconds=0.5, 145 | last_valid_block_height=block_height + 15 146 | ) 147 | 148 | if confirmation_resp.value[0].err is None and str( 149 | confirmation_resp.value[0].confirmation_status) == "TransactionConfirmationStatus.Confirmed": 150 | print("Transaction Confirmed") 151 | print(f"Transaction Signature: https://solscan.io/tx/{tx.signatures[0]}") 152 | return 153 | 154 | attempts += 1 155 | print("Transaction not confirmed, retrying...") 156 | 157 | except Exception as e: 158 | print(f"Attempt {attempts}: Exception occurred - {e}") 159 | attempts += 1 160 | 161 | if attempts == max_attempts: 162 | print("Maximum attempts reached. Transaction could not be confirmed.") 163 | 164 | asyncio.run(send_and_confirm_transaction_via_jito(solana_client, payer)) 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /Examples/Unwrap_Sol.py: -------------------------------------------------------------------------------- 1 | 2 | import asyncio 3 | import os 4 | import time 5 | from solana.rpc.commitment import Confirmed 6 | from solders.keypair import Keypair 7 | from solana.rpc.async_api import AsyncClient 8 | from solders.pubkey import Pubkey 9 | from dotenv import load_dotenv 10 | from solana.rpc.api import Client 11 | from spl.token.client import Token 12 | from spl.token.constants import TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT 13 | from solana.transaction import Transaction 14 | from solders.transaction import VersionedTransaction 15 | from solders.message import MessageV0 16 | from jito_searcher_client import get_async_searcher_client 17 | from jito_searcher_client.convert import versioned_tx_to_protobuf_packet 18 | from jito_searcher_client.generated.bundle_pb2 import Bundle 19 | from jito_searcher_client.generated.searcher_pb2 import NextScheduledLeaderRequest, SendBundleRequest 20 | from solders.system_program import TransferParams as SoldersTransferParams 21 | from solders.system_program import transfer as solders_transfer 22 | import spl.token.instructions as spl_token 23 | load_dotenv() 24 | 25 | # Load environment variables 26 | payer = Keypair.from_base58_string(os.getenv('PrivateKey')) 27 | 28 | RPC_HTTPS_URL = os.getenv("RPC_HTTPS_URL") 29 | solana_client = Client(RPC_HTTPS_URL) 30 | async_solana_client = AsyncClient(RPC_HTTPS_URL) 31 | LAMPORTS_PER_SOL = 1000000000 32 | tip_account_pubkey = Pubkey.from_string(os.getenv("TIP_ACCOUNT")) 33 | 34 | wallet_solToken_acc = spl_token.get_associated_token_address(owner=payer.pubkey(), mint=WRAPPED_SOL_MINT) 35 | 36 | spl_client = Token(solana_client, WRAPPED_SOL_MINT, TOKEN_PROGRAM_ID, payer) 37 | 38 | 39 | async def send_and_confirm_transaction_via_jito(client, payer, max_attempts=3): 40 | 41 | 42 | attempts = 0 43 | max_attempts = 3 44 | while attempts < max_attempts: 45 | 46 | try: 47 | token_acct_details = spl_client.get_account_info(wallet_solToken_acc) 48 | is_initialized = token_acct_details.is_initialized 49 | 50 | except Exception as e: 51 | print("Sol TOken Account is not initalized therefor it can't be closed") 52 | print(e) 53 | return 54 | 55 | try: 56 | 57 | transaction = Transaction() 58 | # Add close_account instruction to reclaim the rent-exempt reserve 59 | ix = spl_token.close_account(spl_token.CloseAccountParams(account=wallet_solToken_acc, 60 | dest=payer.pubkey(), 61 | owner=payer.pubkey(), 62 | program_id=TOKEN_PROGRAM_ID)) 63 | ix2 = solders_transfer( 64 | SoldersTransferParams( 65 | from_pubkey=payer.pubkey(), to_pubkey=tip_account_pubkey, 66 | lamports=int(0.000020002 * LAMPORTS_PER_SOL) # TIP AMOUNT 67 | ) 68 | ) 69 | print("Sending Through Jito") 70 | # 71 | jito_payer = Keypair.from_base58_string(os.getenv("JITO_PAYER")) 72 | BLOCK_ENGINE_URL = "frankfurt.mainnet.block-engine.jito.wtf" 73 | jito_client = await get_async_searcher_client(BLOCK_ENGINE_URL, jito_payer) 74 | txs = [] 75 | is_leader_slot = False 76 | print("waiting for jito leader...") 77 | while not is_leader_slot: 78 | time.sleep(0.5) 79 | next_leader = await jito_client.GetNextScheduledLeader(NextScheduledLeaderRequest()) 80 | num_slots_to_leader = next_leader.next_leader_slot - next_leader.current_slot 81 | print(f"waiting {num_slots_to_leader} slots to jito leader") 82 | is_leader_slot = num_slots_to_leader <= 5 83 | 84 | 85 | transaction.add(ix, ix2) 86 | 87 | instructions = [ix for ix in transaction.instructions] 88 | 89 | block_hash = solana_client.get_latest_blockhash(commitment=Confirmed).value.blockhash 90 | print(block_hash) 91 | 92 | msg = MessageV0.try_compile( 93 | payer=payer.pubkey(), 94 | instructions=instructions, 95 | address_lookup_table_accounts=[], 96 | recent_blockhash=block_hash, 97 | ) 98 | 99 | tx1 = VersionedTransaction(msg, [payer]) 100 | 101 | txs.append(tx1) 102 | 103 | packets = [versioned_tx_to_protobuf_packet(tx) for tx in txs] 104 | uuid_response = await jito_client.SendBundle(SendBundleRequest(bundle=Bundle(header=None, packets=packets))) 105 | 106 | print(f"bundle uuid: {uuid_response.uuid}") 107 | block_height = solana_client.get_block_height(Confirmed).value 108 | print(f"Block height: {block_height}") 109 | 110 | for tx in txs: 111 | confirmation_resp = await async_solana_client.confirm_transaction( 112 | tx.signatures[0], 113 | commitment=Confirmed, 114 | sleep_seconds=0.5, 115 | last_valid_block_height=block_height + 15 116 | ) 117 | 118 | if confirmation_resp.value[0].err is None and str( 119 | confirmation_resp.value[0].confirmation_status) == "TransactionConfirmationStatus.Confirmed": 120 | print("Transaction Confirmed") 121 | print(f"Transaction Signature: https://solscan.io/tx/{tx.signatures[0]}") 122 | return 123 | 124 | attempts += 1 125 | print("Transaction not confirmed, retrying...") 126 | 127 | 128 | 129 | 130 | 131 | except Exception as e: 132 | print(f"Attempt {attempts}: Exception occurred - {e}") 133 | attempts += 1 134 | if attempts == max_attempts: 135 | print("Maximum attempts reached. Transaction could not be confirmed.") 136 | 137 | 138 | asyncio.run(send_and_confirm_transaction_via_jito(solana_client, payer)) 139 | -------------------------------------------------------------------------------- /Examples/Wrap_Sol.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | import time 4 | from solana.rpc.commitment import Confirmed 5 | from solders.keypair import Keypair 6 | from solana.rpc.async_api import AsyncClient 7 | from solders.pubkey import Pubkey 8 | from dotenv import load_dotenv 9 | from solana.rpc.api import Client 10 | from spl.token.client import Token 11 | from spl.token.constants import TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT 12 | from solana.transaction import Transaction 13 | from solders.transaction import VersionedTransaction 14 | from solders.message import MessageV0 15 | from jito_searcher_client import get_async_searcher_client 16 | from jito_searcher_client.convert import versioned_tx_to_protobuf_packet 17 | from jito_searcher_client.generated.bundle_pb2 import Bundle 18 | from jito_searcher_client.generated.searcher_pb2 import NextScheduledLeaderRequest, SendBundleRequest 19 | from solders.system_program import TransferParams as SoldersTransferParams 20 | from solders.system_program import transfer as solders_transfer 21 | import spl.token.instructions as spl_token 22 | load_dotenv() 23 | 24 | # Load environment variables 25 | payer = Keypair.from_base58_string(os.getenv('PrivateKey')) 26 | 27 | RPC_HTTPS_URL = os.getenv("RPC_HTTPS_URL") 28 | solana_client = Client(RPC_HTTPS_URL) 29 | async_solana_client = AsyncClient(RPC_HTTPS_URL) 30 | LAMPORTS_PER_SOL = 1000000000 31 | tip_account_pubkey = Pubkey.from_string(os.getenv("TIP_ACCOUNT")) 32 | 33 | wallet_solToken_acc = spl_token.get_associated_token_address(owner=payer.pubkey(), mint=WRAPPED_SOL_MINT) 34 | 35 | spl_client = Token(solana_client, WRAPPED_SOL_MINT, TOKEN_PROGRAM_ID, payer) 36 | print(wallet_solToken_acc) 37 | 38 | async def send_and_confirm_transaction_via_jito(client, payer, max_attempts=3): 39 | is_initialized=False 40 | attempts = 0 41 | while attempts < max_attempts: 42 | transaction= Transaction() 43 | ix = spl_token.create_associated_token_account(owner=payer.pubkey(), mint=WRAPPED_SOL_MINT, 44 | payer=payer.pubkey()) 45 | 46 | try: 47 | token_acct_details = spl_client.get_account_info(wallet_solToken_acc) 48 | is_initialized = token_acct_details.is_initialized 49 | print(is_initialized) 50 | 51 | 52 | except Exception as e: 53 | print("WSOL Token Account Will be initialized",e) 54 | transaction.add(ix) 55 | 56 | try: 57 | #Initialize WSOL Token Account 58 | 59 | amount_to_wrap = int(float(os.getenv('amount_to_wrap')) * 10 ** 9) 60 | ix2 = solders_transfer(SoldersTransferParams( 61 | from_pubkey=payer.pubkey(), 62 | to_pubkey=wallet_solToken_acc, 63 | lamports=amount_to_wrap 64 | )) 65 | ix3 = spl_token.sync_native(spl_token.SyncNativeParams( 66 | program_id=TOKEN_PROGRAM_ID, 67 | account=wallet_solToken_acc 68 | )) 69 | 70 | 71 | #jito Tip 72 | ix4 = solders_transfer( 73 | SoldersTransferParams( 74 | from_pubkey=payer.pubkey(), to_pubkey=tip_account_pubkey, 75 | lamports=int(0.000020002 * LAMPORTS_PER_SOL) # TIP AMOUNT 76 | )) 77 | print("Sending Through Jito") 78 | # 79 | jito_payer = Keypair.from_base58_string(os.getenv("JITO_PAYER")) 80 | BLOCK_ENGINE_URL = "frankfurt.mainnet.block-engine.jito.wtf" 81 | jito_client = await get_async_searcher_client(BLOCK_ENGINE_URL, jito_payer) 82 | txs = [] 83 | is_leader_slot = False 84 | print("waiting for jito leader...") 85 | while not is_leader_slot: 86 | time.sleep(0.5) 87 | next_leader = await jito_client.GetNextScheduledLeader(NextScheduledLeaderRequest()) 88 | num_slots_to_leader = next_leader.next_leader_slot - next_leader.current_slot 89 | # print(f"waiting {num_slots_to_leader} slots to jito leader") 90 | is_leader_slot = num_slots_to_leader <= 5 91 | 92 | if is_initialized: 93 | transaction.add( ix2,ix3, ix4) 94 | else: 95 | print("sending else") 96 | transaction.add(ix2, ix3, ix4) 97 | 98 | 99 | instructions = [ix for ix in transaction.instructions] 100 | 101 | block_hash = solana_client.get_latest_blockhash(commitment=Confirmed).value.blockhash 102 | print(block_hash) 103 | 104 | msg = MessageV0.try_compile( 105 | payer=payer.pubkey(), 106 | instructions=instructions, 107 | address_lookup_table_accounts=[], 108 | recent_blockhash=block_hash, 109 | ) 110 | 111 | tx1 = VersionedTransaction(msg, [payer]) 112 | 113 | txs.append(tx1) 114 | 115 | packets = [versioned_tx_to_protobuf_packet(tx) for tx in txs] 116 | uuid_response = await jito_client.SendBundle( 117 | SendBundleRequest(bundle=Bundle(header=None, packets=packets))) 118 | 119 | print(f"bundle uuid: {uuid_response.uuid}") 120 | block_height = solana_client.get_block_height(Confirmed).value 121 | print(f"Block height: {block_height}") 122 | 123 | for tx in txs: 124 | confirmation_resp = await async_solana_client.confirm_transaction( 125 | tx.signatures[0], 126 | commitment=Confirmed, 127 | sleep_seconds=0.5, 128 | last_valid_block_height=block_height + 15 129 | ) 130 | 131 | if confirmation_resp.value[0].err is None and str( 132 | confirmation_resp.value[ 133 | 0].confirmation_status) == "TransactionConfirmationStatus.Confirmed": 134 | print("Transaction Confirmed") 135 | print(f"Transaction Signature: https://solscan.io/tx/{tx.signatures[0]}") 136 | return 137 | 138 | attempts += 1 139 | print("Transaction not confirmed, retrying...") 140 | 141 | except Exception as e: 142 | print(e) 143 | print(f"Attempt {attempts}: Transaction not confirmed within Block_Limits. Attempting to resend.") 144 | 145 | attempts += 1 146 | if attempts == max_attempts: 147 | print("Maximum attempts reached. Transaction could not be confirmed.") 148 | 149 | 150 | asyncio.run(send_and_confirm_transaction_via_jito(solana_client, payer)) 151 | -------------------------------------------------------------------------------- /Jito/.env.template: -------------------------------------------------------------------------------- 1 | RPC_HTTPS_URL="https://mainnet.helius-rpc.com/?api-key=" 2 | PrivateKey="" #YOur Private KEy 3 | WSOL_TokenAccount="4mncAGe5Re1dnX1K6mPsKPQDmJijLrHrQxT3C4fShtjU" 4 | JITO_PRIVATE_KEY="2noErrLG2aN1B5EoGk8YKhL8JggmotYJyfwS9GT5XRmq9A8jLa9wNnDxdeXJMCRrjjChdsEZzLurx1mzDHVCScG7" 5 | TIP_ACCOUNT_PUBKEY="HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe" -------------------------------------------------------------------------------- /Jito/buy_with_jito.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import datetime 3 | import time 4 | 5 | from jito_searcher_client import get_async_searcher_client 6 | from jito_searcher_client.convert import versioned_tx_to_protobuf_packet 7 | from jito_searcher_client.generated.bundle_pb2 import Bundle 8 | from jito_searcher_client.generated.searcher_pb2 import ( 9 | 10 | NextScheduledLeaderRequest, 11 | NextScheduledLeaderResponse, 12 | SendBundleRequest, 13 | 14 | 15 | 16 | 17 | ) 18 | from solana.rpc.types import TokenAccountOpts 19 | from solders.pubkey import Pubkey 20 | from solana.rpc.commitment import Confirmed 21 | from solana.rpc.api import RPCException 22 | from solana.rpc.api import Client 23 | from solders.keypair import Keypair 24 | from solders.compute_budget import set_compute_unit_price,set_compute_unit_limit 25 | from utils.create_close_account import fetch_pool_keys, get_token_account, make_swap_instruction 26 | from utils.birdeye import getSymbol 27 | from solana.rpc.async_api import AsyncClient 28 | from solders.transaction import VersionedTransaction 29 | from solders.message import MessageV0 30 | from solders.system_program import transfer, TransferParams 31 | 32 | from utils.pool_information import gen_pool, getpoolIdByMint 33 | import os 34 | from dotenv import load_dotenv 35 | 36 | # Load.env file 37 | load_dotenv() 38 | 39 | # config = dotenv_values(".env") 40 | 41 | RPC_HTTPS_URL= os.getenv("RPC_HTTPS_URL") 42 | solana_client = Client(os.getenv("RPC_HTTPS_URL")) 43 | async_solana_client = AsyncClient(os.getenv("RPC_HTTPS_URL")) 44 | payer=Keypair.from_base58_string(os.getenv("PrivateKey")) 45 | Wsol_TokenAccount=os.getenv('WSOL_TokenAccount') 46 | 47 | AMM_PROGRAM_ID = Pubkey.from_string('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8') 48 | SERUM_PROGRAM_ID = Pubkey.from_string('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX') 49 | LAMPORTS_PER_SOL = 1000000000 50 | MAX_RETRIES = 3 51 | RETRY_DELAY = 3 52 | 53 | class style(): 54 | BLACK = '\033[30m' 55 | RED = '\033[31m' 56 | GREEN = '\033[32m' 57 | YELLOW = '\033[33m' 58 | BLUE = '\033[34m' 59 | MAGENTA = '\033[35m' 60 | CYAN = '\033[36m' 61 | WHITE = '\033[37m' 62 | UNDERLINE = '\033[4m' 63 | RESET = '\033[0m' 64 | 65 | 66 | def getTimestamp(): 67 | while True: 68 | timeStampData = datetime.datetime.now() 69 | currentTimeStamp = "[" + timeStampData.strftime("%H:%M:%S.%f")[:-3] + "]" 70 | return currentTimeStamp 71 | 72 | async def get_specific_token_account(owner_pubkey: str, mint_pubkey: str): 73 | async with AsyncClient(RPC_HTTPS_URL) as client: 74 | owner_pubkey_obj = Pubkey.from_string(owner_pubkey) 75 | mint_pubkey_obj = Pubkey.from_string(mint_pubkey) 76 | # Using get_token_accounts_by_owner to fetch token accounts 77 | opts = TokenAccountOpts(mint=mint_pubkey_obj) 78 | response = await client.get_token_accounts_by_owner(owner_pubkey_obj, opts) 79 | if len(response.value) ==1 : 80 | return response.value[0].pubkey # Return the first account found 81 | return None 82 | 83 | 84 | 85 | 86 | async def buy(solana_client, TOKEN_TO_SWAP_BUY, payer, amount): 87 | 88 | 89 | retry_count = 0 90 | while retry_count < MAX_RETRIES: 91 | try: 92 | # Re-init transaction preparation 93 | token_symbol, SOl_Symbol = getSymbol(TOKEN_TO_SWAP_BUY) 94 | mint = Pubkey.from_string(TOKEN_TO_SWAP_BUY) 95 | # mint= TOKEN_TO_SWAP_BUY 96 | 97 | try: 98 | 99 | tokenPool_ID = await getpoolIdByMint(mint, AsyncClient(RPC_HTTPS_URL, commitment=Confirmed)) 100 | 101 | if tokenPool_ID is not False: 102 | 103 | fetch_pool_key = await gen_pool(str(tokenPool_ID), AsyncClient(RPC_HTTPS_URL, commitment=Confirmed)) 104 | pool_keys = fetch_pool_key 105 | else: 106 | print("AMMID NOT FOUND SEARCHING WILL BE FETCHING WITH RAYDIUM SDK") 107 | return 108 | 109 | # pool_keys = fetch_pool_keys(str(mint)) 110 | except Exception as e: 111 | print(e) 112 | amount_in = int(amount * LAMPORTS_PER_SOL) 113 | 114 | swap_associated_token_address, swap_token_account_Instructions = get_token_account(solana_client, payer.pubkey(), mint) 115 | swap_tx = [] 116 | 117 | WSOL_token_account = Pubkey.from_string(Wsol_TokenAccount) 118 | instructions_swap = make_swap_instruction(amount_in, WSOL_token_account, swap_associated_token_address, pool_keys, mint, solana_client, payer) 119 | if swap_token_account_Instructions != None: 120 | 121 | swap_tx.append(swap_token_account_Instructions) 122 | 123 | swap_tx.extend([instructions_swap, set_compute_unit_price(25_232), set_compute_unit_limit(200_337)]) 124 | 125 | ###SENDING THROUGH JITO 126 | print("Sending Through Jito") 127 | 128 | jito_payer = Keypair.from_base58_string(os.getenv("JITO_PRIVATE_KEY")) 129 | BLOCK_ENGINE_URL = "amsterdam.mainnet.block-engine.jito.wtf" 130 | # jito_client= get_searcher_client(BLOCK_ENGINE_URL,jito_payer) 131 | jito_client = await get_async_searcher_client(BLOCK_ENGINE_URL, jito_payer) 132 | txs = [] 133 | tip_account_pubkey = Pubkey.from_string(os.getenv("TIP_ACCOUNT_PUBKEY")) 134 | 135 | print("Converting Transactions") 136 | # jito_client = get_searcher_client(BLOCK_ENGINE_URL, payer) 137 | 138 | is_leader_slot = False 139 | print("waiting for jito leader...") 140 | while not is_leader_slot: 141 | time.sleep(0.5) 142 | next_leader: NextScheduledLeaderResponse = await jito_client.GetNextScheduledLeader( 143 | NextScheduledLeaderRequest()) 144 | num_slots_to_leader = next_leader.next_leader_slot - next_leader.current_slot 145 | print(f"waiting {num_slots_to_leader} slots to jito leader") 146 | is_leader_slot = num_slots_to_leader <= 5 147 | 148 | ix = transfer( 149 | TransferParams( 150 | from_pubkey=payer.pubkey(), to_pubkey=tip_account_pubkey, 151 | lamports=int(0.00020002 * LAMPORTS_PER_SOL) #TIP AMOUNT 152 | ) 153 | ) 154 | swap_tx.append(ix) 155 | 156 | 157 | 158 | msg = MessageV0.try_compile( 159 | payer.pubkey(), 160 | swap_tx, 161 | [], 162 | solana_client.get_latest_blockhash().value.blockhash, 163 | ) 164 | 165 | 166 | 167 | tx1 = VersionedTransaction(msg, [payer]) 168 | 169 | 170 | txs.append(tx1) 171 | 172 | packets = [versioned_tx_to_protobuf_packet(tx) for tx in txs] 173 | uuid_response = await jito_client.SendBundle(SendBundleRequest(bundle=Bundle(header=None, packets=packets))) 174 | 175 | print(f"bundle uuid: {uuid_response.uuid}") 176 | block_height = solana_client.get_block_height(Confirmed).value 177 | print(f"Block height: {block_height}") 178 | 179 | for tx in txs: 180 | 181 | confirmation_resp = await async_solana_client.confirm_transaction( 182 | tx.signatures[0], 183 | commitment=Confirmed, 184 | sleep_seconds=0.5, 185 | last_valid_block_height=block_height + 15 186 | 187 | ) 188 | 189 | if confirmation_resp.value[0].err == None and str( 190 | confirmation_resp.value[0].confirmation_status) == "TransactionConfirmationStatus.Confirmed": 191 | print(style.GREEN + "Transaction Confirmed", style.RESET) 192 | print(style.GREEN, f"Transaction Signature: https://solscan.io/tx/{tx.signatures[0]}", style.RESET) 193 | 194 | return tx.signatures[0] 195 | 196 | return True 197 | 198 | 199 | except asyncio.TimeoutError: 200 | print("Transaction confirmation timed out. Retrying...") 201 | retry_count += 1 202 | time.sleep(RETRY_DELAY) 203 | except RPCException as e: 204 | print(f"RPC Error: [{e.args[0].message}]... Retrying...") 205 | retry_count += 1 206 | time.sleep(RETRY_DELAY) 207 | except Exception as e: 208 | print(f"Unhandled exception: {e}. Retrying...") 209 | retry_count += 1 210 | time.sleep(RETRY_DELAY) 211 | 212 | print("Failed to confirm transaction after maximum retries.") 213 | return False 214 | 215 | async def main(): 216 | 217 | token_toBuy="RUpbmGF6p42AAeN1QvhFReZejQry1cLkE1PUYFVVpnL" 218 | print(payer.pubkey()) 219 | await buy(solana_client, token_toBuy, payer, 0.01008572) 220 | 221 | asyncio.run(main()) -------------------------------------------------------------------------------- /Jito/sell_with_jito.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import datetime 3 | import time 4 | 5 | from jito_searcher_client import get_async_searcher_client 6 | from jito_searcher_client.convert import tx_to_protobuf_packet, versioned_tx_to_protobuf_packet 7 | from jito_searcher_client.generated.bundle_pb2 import Bundle 8 | from jito_searcher_client.generated.searcher_pb2 import ( 9 | 10 | NextScheduledLeaderRequest, 11 | NextScheduledLeaderResponse, 12 | SendBundleRequest, 13 | 14 | ) 15 | from solana.rpc.types import TokenAccountOpts 16 | from solders.pubkey import Pubkey 17 | from solana.rpc.commitment import Confirmed 18 | from solana.rpc.api import RPCException 19 | from solana.rpc.api import Client 20 | from solders.keypair import Keypair 21 | from solders.compute_budget import set_compute_unit_price, set_compute_unit_limit 22 | from utils.create_close_account import fetch_pool_keys, get_token_account, make_swap_instruction 23 | from utils.birdeye import getSymbol 24 | from solana.rpc.async_api import AsyncClient 25 | from solders.transaction import VersionedTransaction 26 | from solders.message import MessageV0 27 | from solders.system_program import transfer, TransferParams 28 | 29 | from utils.pool_information import gen_pool, getpoolIdByMint 30 | import os 31 | from dotenv import load_dotenv 32 | 33 | # Load.env file 34 | load_dotenv() 35 | 36 | # config = dotenv_values(".env") 37 | 38 | RPC_HTTPS_URL = os.getenv("RPC_HTTPS_URL") 39 | solana_client = Client(os.getenv("RPC_HTTPS_URL")) 40 | async_solana_client = AsyncClient(os.getenv("RPC_HTTPS_URL")) 41 | payer = Keypair.from_base58_string(os.getenv("PrivateKey")) 42 | Wsol_TokenAccount = os.getenv('WSOL_TokenAccount') 43 | 44 | AMM_PROGRAM_ID = Pubkey.from_string('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8') 45 | SERUM_PROGRAM_ID = Pubkey.from_string('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX') 46 | LAMPORTS_PER_SOL = 1000000000 47 | MAX_RETRIES = 2 48 | RETRY_DELAY = 3 49 | 50 | 51 | class style(): 52 | BLACK = '\033[30m' 53 | RED = '\033[31m' 54 | GREEN = '\033[32m' 55 | YELLOW = '\033[33m' 56 | BLUE = '\033[34m' 57 | MAGENTA = '\033[35m' 58 | CYAN = '\033[36m' 59 | WHITE = '\033[37m' 60 | UNDERLINE = '\033[4m' 61 | RESET = '\033[0m' 62 | 63 | 64 | def getTimestamp(): 65 | while True: 66 | timeStampData = datetime.datetime.now() 67 | currentTimeStamp = "[" + timeStampData.strftime("%H:%M:%S.%f")[:-3] + "]" 68 | return currentTimeStamp 69 | 70 | 71 | async def get_specific_token_account(owner_pubkey: str, mint_pubkey: str): 72 | async with AsyncClient(RPC_HTTPS_URL) as client: 73 | owner_pubkey_obj = Pubkey.from_string(owner_pubkey) 74 | mint_pubkey_obj = Pubkey.from_string(mint_pubkey) 75 | # Using get_token_accounts_by_owner to fetch token accounts 76 | opts = TokenAccountOpts(mint=mint_pubkey_obj) 77 | response = await client.get_token_accounts_by_owner(owner_pubkey_obj, opts) 78 | if len(response.value) == 1: 79 | return response.value[0].pubkey # Return the first account found 80 | return None 81 | 82 | 83 | async def sell(solana_client, TOKEN_TO_SWAP_SELL, payer): 84 | retry_count = 0 85 | while retry_count < MAX_RETRIES: 86 | try: 87 | token_symbol, SOl_Symbol = getSymbol(TOKEN_TO_SWAP_SELL) 88 | mint = Pubkey.from_string(TOKEN_TO_SWAP_SELL) 89 | pool_keys=None 90 | 91 | # mint= TOKEN_TO_SWAP_SELL 92 | sol = Pubkey.from_string("So11111111111111111111111111111111111111112") 93 | TOKEN_PROGRAM_ID = solana_client.get_account_info_json_parsed(mint).value.owner 94 | 95 | try: 96 | 97 | tokenPool_ID = await getpoolIdByMint(mint, AsyncClient(RPC_HTTPS_URL, commitment=Confirmed)) 98 | 99 | if tokenPool_ID is not False: 100 | 101 | fetch_pool_key = await gen_pool(str(tokenPool_ID), AsyncClient(RPC_HTTPS_URL, commitment=Confirmed)) 102 | pool_keys = fetch_pool_key 103 | # print(pool_keys) 104 | else: 105 | print("AMMID NOT FOUND SEARCHING WILL BE FETCHING WITH RAYDIUM SDK.. THis happens") 106 | 107 | # pool_keys= fetch_pool_keys(str(mint)) 108 | except Exception as e: 109 | print(e) 110 | 111 | 112 | 113 | 114 | opts = TokenAccountOpts(mint=mint) 115 | response = await async_solana_client.get_token_accounts_by_owner(payer.pubkey(), opts) 116 | tokenAccount = response.value[0].pubkey 117 | print(tokenAccount) 118 | balance = await async_solana_client.get_token_account_balance(tokenAccount) 119 | 120 | amount_in = int(balance.value.amount) 121 | print("Token Balance : ", amount_in) 122 | 123 | if int(amount_in) == 0: 124 | return "NO BALANCE" 125 | 126 | 127 | WSOL_token_account, WSOL_token_account_Instructions = get_token_account(solana_client, payer.pubkey(), sol) 128 | 129 | print("3. Create Swap Instructions...") 130 | instructions_swap = make_swap_instruction(amount_in, 131 | tokenAccount, 132 | WSOL_token_account, 133 | pool_keys, 134 | mint, 135 | solana_client, 136 | payer 137 | ) 138 | 139 | swap_tx = [] 140 | if WSOL_token_account_Instructions != None: 141 | swap_tx.append(WSOL_token_account_Instructions) 142 | swap_tx.extend([instructions_swap,set_compute_unit_price(25_500),set_compute_unit_limit(200_337)]) 143 | 144 | ###SENDING THROUGH JITO 145 | print("Sending Through Jito") 146 | 147 | jito_payer = Keypair.from_base58_string(os.getenv("JITO_PRIVATE_KEY")) 148 | BLOCK_ENGINE_URL = "frankfurt.mainnet.block-engine.jito.wtf" 149 | jito_client = await get_async_searcher_client(BLOCK_ENGINE_URL, jito_payer) #Update this line to avoid rate limit due to private key of jito Auth been made available publicly here. 150 | txs = [] 151 | tip_account_pubkey = Pubkey.from_string(os.getenv("TIP_ACCOUNT_PUBKEY")) 152 | 153 | print("Converting Transactions") 154 | # jito_client = get_searcher_client(BLOCK_ENGINE_URL, payer) 155 | 156 | is_leader_slot = False 157 | print("waiting for jito leader...") 158 | while not is_leader_slot: 159 | time.sleep(0.5) 160 | next_leader: NextScheduledLeaderResponse = await jito_client.GetNextScheduledLeader( 161 | NextScheduledLeaderRequest()) 162 | num_slots_to_leader = next_leader.next_leader_slot - next_leader.current_slot 163 | print(f"waiting {num_slots_to_leader} slots to jito leader") 164 | is_leader_slot = num_slots_to_leader <= 5 165 | 166 | ix = transfer( 167 | TransferParams( 168 | from_pubkey=payer.pubkey(), to_pubkey=tip_account_pubkey, 169 | lamports=int(0.00020002 * LAMPORTS_PER_SOL) # TIP AMOUNT 170 | ) 171 | ) 172 | swap_tx.append(ix) 173 | 174 | msg = MessageV0.try_compile( 175 | payer.pubkey(), 176 | swap_tx, 177 | [], 178 | solana_client.get_latest_blockhash().value.blockhash, 179 | ) 180 | 181 | 182 | tx1 = VersionedTransaction(msg, [payer]) 183 | 184 | txs.append(tx1) 185 | 186 | packets = [versioned_tx_to_protobuf_packet(tx) for tx in txs] 187 | uuid_response = await jito_client.SendBundle(SendBundleRequest(bundle=Bundle(header=None, packets=packets))) 188 | 189 | print(f"bundle uuid: {uuid_response.uuid}") 190 | block_height = solana_client.get_block_height(Confirmed).value 191 | print(f"Block height: {block_height}") 192 | 193 | for tx in txs: 194 | 195 | confirmation_resp = await async_solana_client.confirm_transaction( 196 | tx.signatures[0], 197 | commitment=Confirmed, 198 | sleep_seconds=0.5, 199 | last_valid_block_height=block_height + 15 200 | 201 | ) 202 | 203 | if confirmation_resp.value[0].err == None and str( 204 | confirmation_resp.value[0].confirmation_status) == "TransactionConfirmationStatus.Confirmed": 205 | print(style.GREEN + "Transaction Confirmed", style.RESET) 206 | print(style.GREEN, f"Transaction Signature: https://solscan.io/tx/{tx.signatures[0]}", style.RESET) 207 | 208 | return tx.signatures[0] 209 | 210 | return True 211 | 212 | 213 | except asyncio.TimeoutError: 214 | print("Transaction confirmation timed out. Retrying...") 215 | retry_count += 1 216 | time.sleep(RETRY_DELAY) 217 | except RPCException as e: 218 | print(f"RPC Error: [{e.args[0].message}]... Retrying...") 219 | retry_count += 1 220 | time.sleep(RETRY_DELAY) 221 | except Exception as e: 222 | print(f"Unhandled exception: {e}. Retrying...") 223 | retry_count += 1 224 | time.sleep(RETRY_DELAY) 225 | 226 | print("Failed to confirm transaction after maximum retries.") 227 | return False 228 | 229 | 230 | async def main(): 231 | token_toBuy = "RUpbmGF6p42AAeN1QvhFReZejQry1cLkE1PUYFVVpnL" 232 | print(payer.pubkey()) 233 | await sell(solana_client, token_toBuy, payer) 234 | 235 | 236 | asyncio.run(main()) -------------------------------------------------------------------------------- /Jito/utils/birdeye.py: -------------------------------------------------------------------------------- 1 | import requests, json, os, sys 2 | from configparser import ConfigParser 3 | 4 | config = ConfigParser() 5 | config.read(os.path.join(sys.path[0], 'data', 'config.ini')) 6 | # birdeye_api = config.get("BIRDEYE", "API") 7 | 8 | """I modified it to dexscreener, forgot to change the filename""" 9 | 10 | 11 | def getBaseToken(token_address): 12 | url = f"https://api.dexscreener.com/latest/dex/pairs/solana/{token_address}" 13 | response = requests.get(url).json() 14 | return response['pair']['baseToken']['address'] 15 | 16 | 17 | """ 18 | USDT and USDC prices will be excluded 19 | """ 20 | 21 | 22 | def get_price(token_address): 23 | url = f"https://api.dexscreener.com/latest/dex/tokens/{token_address}" 24 | exclude = ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'] 25 | response = requests.get(url).json() 26 | 27 | if token_address not in exclude: 28 | for pair in response['pairs']: 29 | if pair['quoteToken']['address'] == 'So11111111111111111111111111111111111111112': 30 | return float(pair['priceUsd']) 31 | else: 32 | return response['pairs'][0]['priceUsd'] 33 | return None 34 | 35 | 36 | """Common addresses like usdc and usdt will be excluded as we know their symbols""" 37 | 38 | 39 | def getSymbol(token): 40 | # usdc and usdt 41 | exclude = ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'] 42 | 43 | if token not in exclude: 44 | url = f"https://api.dexscreener.com/latest/dex/tokens/{token}" 45 | 46 | Token_Symbol = "" 47 | Sol_symbol = "" 48 | try: 49 | response = requests.get(url) 50 | 51 | # Check if the request was successful (status code 200) 52 | if response.status_code == 200: 53 | resp = response.json() 54 | print("Response:", resp['pairs'][0]['baseToken']['symbol']) 55 | for pair in resp['pairs']: 56 | quoteToken = pair['quoteToken']['symbol'] 57 | 58 | if quoteToken == 'SOL': 59 | Token_Symbol = pair['baseToken']['symbol'] 60 | Sol_symbol = quoteToken 61 | return Token_Symbol, Sol_symbol 62 | 63 | 64 | else: 65 | print(f"[getSymbol] Request failed with status code {response.status_code}") 66 | 67 | except requests.exceptions.RequestException as e: 68 | print(f"[getSymbol] error occurred: {e}") 69 | except: 70 | a = 1 71 | 72 | return Token_Symbol, Sol_symbol 73 | else: 74 | if token == 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v': 75 | return "USDC", "SOL" 76 | elif token == 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v': 77 | return "USDT", "SOL" 78 | -------------------------------------------------------------------------------- /Jito/utils/create_close_account.py: -------------------------------------------------------------------------------- 1 | from spl.token.instructions import create_associated_token_account, get_associated_token_address 2 | from solders.pubkey import Pubkey 3 | from solders.instruction import Instruction 4 | from solana.rpc.types import TokenAccountOpts 5 | from solana.transaction import AccountMeta 6 | from utils.layouts import SWAP_LAYOUT 7 | import json, requests 8 | LAMPORTS_PER_SOL = 1000000000 9 | AMM_PROGRAM_ID = Pubkey.from_string('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8') 10 | SERUM_PROGRAM_ID = Pubkey.from_string('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX') 11 | 12 | 13 | 14 | 15 | def make_swap_instruction(amount_in: int, token_account_in: Pubkey.from_string, token_account_out: Pubkey.from_string, 16 | accounts: dict, mint, ctx, owner) -> Instruction: 17 | tokenPk = mint 18 | accountProgramId = ctx.get_account_info_json_parsed(tokenPk) 19 | TOKEN_PROGRAM_ID = accountProgramId.value.owner 20 | 21 | keys = [ 22 | AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), 23 | AccountMeta(pubkey=accounts["amm_id"], is_signer=False, is_writable=True), 24 | AccountMeta(pubkey=accounts["authority"], is_signer=False, is_writable=False), 25 | AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True), 26 | AccountMeta(pubkey=accounts["target_orders"], is_signer=False, is_writable=True), 27 | AccountMeta(pubkey=accounts["base_vault"], is_signer=False, is_writable=True), 28 | AccountMeta(pubkey=accounts["quote_vault"], is_signer=False, is_writable=True), 29 | AccountMeta(pubkey=SERUM_PROGRAM_ID, is_signer=False, is_writable=False), 30 | AccountMeta(pubkey=accounts["market_id"], is_signer=False, is_writable=True), 31 | AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True), 32 | AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True), 33 | AccountMeta(pubkey=accounts["event_queue"], is_signer=False, is_writable=True), 34 | AccountMeta(pubkey=accounts["market_base_vault"], is_signer=False, is_writable=True), 35 | AccountMeta(pubkey=accounts["market_quote_vault"], is_signer=False, is_writable=True), 36 | AccountMeta(pubkey=accounts["market_authority"], is_signer=False, is_writable=False), 37 | AccountMeta(pubkey=token_account_in, is_signer=False, is_writable=True), # UserSourceTokenAccount 38 | AccountMeta(pubkey=token_account_out, is_signer=False, is_writable=True), # UserDestTokenAccount 39 | AccountMeta(pubkey=owner.pubkey(), is_signer=True, is_writable=False) # UserOwner 40 | ] 41 | 42 | data = SWAP_LAYOUT.build( 43 | dict( 44 | instruction=9, 45 | amount_in=int(amount_in), 46 | min_amount_out=0 47 | ) 48 | ) 49 | return Instruction(AMM_PROGRAM_ID, data, keys) 50 | 51 | 52 | def get_token_account(ctx, 53 | owner: Pubkey.from_string, 54 | mint: Pubkey.from_string): 55 | try: 56 | account_data = ctx.get_token_accounts_by_owner(owner, TokenAccountOpts(mint)) 57 | return account_data.value[0].pubkey, None 58 | except: 59 | swap_associated_token_address = get_associated_token_address(owner, mint) 60 | swap_token_account_Instructions = create_associated_token_account(owner, owner, mint) 61 | return swap_associated_token_address, swap_token_account_Instructions 62 | 63 | 64 | def sell_get_token_account(ctx, 65 | owner: Pubkey.from_string, 66 | mint: Pubkey.from_string): 67 | try: 68 | account_data = ctx.get_token_accounts_by_owner(owner, TokenAccountOpts(mint)) 69 | return account_data.value[0].pubkey 70 | except: 71 | print("Mint Token Not found") 72 | return None 73 | 74 | 75 | def extract_pool_info(pools_list: list, mint: str) -> dict: 76 | for pool in pools_list: 77 | 78 | if pool['baseMint'] == mint and pool['quoteMint'] == 'So11111111111111111111111111111111111111112': 79 | return pool 80 | elif pool['quoteMint'] == mint and pool['baseMint'] == 'So11111111111111111111111111111111111111112': 81 | return pool 82 | raise Exception(f'{mint} pool not found!') 83 | 84 | 85 | def fetch_pool_keys(mint: str): 86 | amm_info = {} 87 | all_pools = {} 88 | try: 89 | # Using this so it will be faster else no option, we go the slower way. 90 | with open('all_pools.json', 'r') as file: 91 | all_pools = json.load(file) 92 | amm_info = extract_pool_info(all_pools, mint) 93 | except: 94 | resp = requests.get('https://api.raydium.io/v2/sdk/liquidity/mainnet.json', stream=True) 95 | pools = resp.json() 96 | official = pools['official'] 97 | unofficial = pools['unOfficial'] 98 | all_pools = official + unofficial 99 | 100 | # Store all_pools in a JSON file 101 | with open('all_pools.json', 'w') as file: 102 | json.dump(all_pools, file) 103 | try: 104 | amm_info = extract_pool_info(all_pools, mint) 105 | except: 106 | return "failed" 107 | 108 | return { 109 | 'amm_id': Pubkey.from_string(amm_info['id']), 110 | 'authority': Pubkey.from_string(amm_info['authority']), 111 | 'base_mint': Pubkey.from_string(amm_info['baseMint']), 112 | 'base_decimals': amm_info['baseDecimals'], 113 | 'quote_mint': Pubkey.from_string(amm_info['quoteMint']), 114 | 'quote_decimals': amm_info['quoteDecimals'], 115 | 'lp_mint': Pubkey.from_string(amm_info['lpMint']), 116 | 'open_orders': Pubkey.from_string(amm_info['openOrders']), 117 | 'target_orders': Pubkey.from_string(amm_info['targetOrders']), 118 | 'base_vault': Pubkey.from_string(amm_info['baseVault']), 119 | 'quote_vault': Pubkey.from_string(amm_info['quoteVault']), 120 | 'market_id': Pubkey.from_string(amm_info['marketId']), 121 | 'market_base_vault': Pubkey.from_string(amm_info['marketBaseVault']), 122 | 'market_quote_vault': Pubkey.from_string(amm_info['marketQuoteVault']), 123 | 'market_authority': Pubkey.from_string(amm_info['marketAuthority']), 124 | 'bids': Pubkey.from_string(amm_info['marketBids']), 125 | 'asks': Pubkey.from_string(amm_info['marketAsks']), 126 | 'event_queue': Pubkey.from_string(amm_info['marketEventQueue']) 127 | } 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /Jito/utils/layouts.py: -------------------------------------------------------------------------------- 1 | from io import BytesIO 2 | 3 | import requests 4 | from borsh_construct import CStruct, String, U8, U16, U64, Vec, Option, Bool, Enum 5 | 6 | from construct import Bytes, Int8ul, Int64ul, Padding, BitsInteger, BitsSwapped, BitStruct, Const, Flag, BytesInteger 7 | from construct import Struct as cStruct 8 | 9 | import base58, json 10 | 11 | 12 | from spl.token.instructions import create_associated_token_account, get_associated_token_address 13 | 14 | from solders.pubkey import Pubkey 15 | from solders.instruction import Instruction 16 | 17 | from solana.rpc.types import TokenAccountOpts 18 | from solana.transaction import AccountMeta 19 | 20 | 21 | class MyEncoder(json.JSONEncoder): 22 | def default(self, o): 23 | if type(o) is bytes: 24 | return o.decode("utf-8") 25 | return super(MyEncoder, self).default(o) 26 | 27 | 28 | def remove_bytesio(obj): 29 | if isinstance(obj, dict): 30 | return { 31 | k: remove_bytesio(v) for k, v in obj.items() if not isinstance(v, BytesIO) 32 | } 33 | elif isinstance(obj, list): 34 | return [remove_bytesio(v) for v in obj if not isinstance(v, BytesIO)] 35 | else: 36 | return obj 37 | 38 | def get_offset(struct, field): 39 | offset = 0 40 | for item in struct.subcons: 41 | if item.name == field: 42 | return offset 43 | else: 44 | offset += item.sizeof() 45 | return None 46 | def convert_bytes_to_pubkey(obj): 47 | if isinstance(obj, dict): 48 | return {k: convert_bytes_to_pubkey(v) for k, v in obj.items()} 49 | elif isinstance(obj, list): 50 | return [convert_bytes_to_pubkey(v) for v in obj] 51 | elif isinstance(obj, bytes): 52 | return str(Pubkey.from_bytes(obj)) 53 | else: 54 | return obj 55 | 56 | 57 | def getMetaData(data): 58 | decoded_info = base58.b58decode(data) 59 | # structure of the instruction 60 | instruction_structure = CStruct( 61 | "instructionDiscriminator" / U8, 62 | "createMetadataAccountArgsV3" 63 | / CStruct( 64 | "data" 65 | / CStruct( 66 | "name" / String, 67 | "symbol" / String, 68 | "uri" / String, 69 | "sellerFeeBasisPoints" / U16, 70 | "creators" 71 | / Option( 72 | Vec(CStruct("address" / Bytes(32), "verified" / Bool, "share" / U8)) 73 | ), 74 | "collection" / Option(CStruct("verified" / Bool, "key" / Bytes(32))), 75 | "uses" 76 | / Option( 77 | CStruct( 78 | "useMethod" 79 | / Enum("Burn", "Multiple", "Single", enum_name="UseMethod"), 80 | "remaining" / U64, 81 | "total" / U64, 82 | ) 83 | ), 84 | ), 85 | "isMutable" / Bool, 86 | "collectionDetails" 87 | / Option(String), # fixme: string is not correct, insert correct type 88 | ), 89 | ) 90 | metadata = instruction_structure.parse(decoded_info) 91 | metadata = remove_bytesio(metadata) 92 | metadata = convert_bytes_to_pubkey(metadata) 93 | 94 | return json.dumps(metadata) 95 | 96 | 97 | SWAP_LAYOUT = cStruct( 98 | "instruction" / Int8ul, "amount_in" / Int64ul, "min_amount_out" / Int64ul 99 | ) 100 | 101 | 102 | 103 | AMM_INFO_LAYOUT_V4_1 = cStruct( 104 | "status" / Int64ul, 105 | "nonce" / Int64ul, 106 | "orderNum" / Int64ul, 107 | "depth" / Int64ul, 108 | "coinDecimals" / Int64ul, 109 | "pcDecimals" / Int64ul, 110 | "state" / Int64ul, 111 | "resetFlag" / Int64ul, 112 | "minSize" / Int64ul, 113 | "volMaxCutRatio" / Int64ul, 114 | "amountWaveRatio" / Int64ul, 115 | "coinLotSize" / Int64ul, 116 | "pcLotSize" / Int64ul, 117 | "minPriceMultiplier" / Int64ul, 118 | "maxPriceMultiplier" / Int64ul, 119 | "systemDecimalsValue" / Int64ul, 120 | # // Fees 121 | "minSeparateNumerator" / Int64ul, 122 | "minSeparateDenominator" / Int64ul, 123 | "tradeFeeNumerator" / Int64ul, 124 | "tradeFeeDenominator" / Int64ul, 125 | "pnlNumerator" / Int64ul, 126 | "pnlDenominator" / Int64ul, 127 | "swapFeeNumerator" / Int64ul, 128 | "swapFeeDenominator" / Int64ul, 129 | # // OutPutData 130 | "needTakePnlCoin" / Int64ul, 131 | "needTakePnlPc" / Int64ul, 132 | "totalPnlPc" / Int64ul, 133 | "totalPnlCoin" / Int64ul, 134 | "poolOpenTime" / Int64ul, 135 | "punishPcAmount" / Int64ul, 136 | "punishCoinAmount" / Int64ul, 137 | "orderbookToInitTime" / Int64ul, 138 | "swapCoinInAmount" / BytesInteger(16, signed=False, swapped=True), 139 | "swapPcOutAmount" / BytesInteger(16, signed=False, swapped=True), 140 | "swapCoin2PcFee" / Int64ul, 141 | "swapPcInAmount" / BytesInteger(16, signed=False, swapped=True), 142 | "swapCoinOutAmount" / BytesInteger(16, signed=False, swapped=True), 143 | "swapPc2CoinFee" / Int64ul, 144 | "poolCoinTokenAccount" / Bytes(32), 145 | "poolPcTokenAccount" / Bytes(32), 146 | "coinMintAddress" / Bytes(32), 147 | "pcMintAddress" / Bytes(32), 148 | "lpMintAddress" / Bytes(32), 149 | "ammOpenOrders" / Bytes(32), 150 | "serumMarket" / Bytes(32), 151 | "serumProgramId" / Bytes(32), 152 | "ammTargetOrders" / Bytes(32), 153 | "poolWithdrawQueue" / Bytes(32), 154 | "poolTempLpTokenAccount" / Bytes(32), 155 | "ammOwner" / Bytes(32), 156 | "pnlOwner" / Bytes(32), 157 | ) 158 | 159 | 160 | ACCOUNT_FLAGS_LAYOUT = BitsSwapped( 161 | BitStruct( 162 | "initialized" / Flag, 163 | "market" / Flag, 164 | "open_orders" / Flag, 165 | "request_queue" / Flag, 166 | "event_queue" / Flag, 167 | "bids" / Flag, 168 | "asks" / Flag, 169 | Const(0, BitsInteger(57)), # Padding 170 | ) 171 | ) 172 | 173 | MARKET_LAYOUT = cStruct( 174 | Padding(5), 175 | "account_flags" / ACCOUNT_FLAGS_LAYOUT, 176 | "own_address" / Bytes(32), 177 | "vault_signer_nonce" / Int64ul, 178 | "base_mint" / Bytes(32), 179 | "quote_mint" / Bytes(32), 180 | "base_vault" / Bytes(32), 181 | "base_deposits_total" / Int64ul, 182 | "base_fees_accrued" / Int64ul, 183 | "quote_vault" / Bytes(32), 184 | "quote_deposits_total" / Int64ul, 185 | "quote_fees_accrued" / Int64ul, 186 | "quote_dust_threshold" / Int64ul, 187 | "request_queue" / Bytes(32), 188 | "event_queue" / Bytes(32), 189 | "bids" / Bytes(32), 190 | "asks" / Bytes(32), 191 | "base_lot_size" / Int64ul, 192 | "quote_lot_size" / Int64ul, 193 | "fee_rate_bps" / Int64ul, 194 | "referrer_rebate_accrued" / Int64ul, 195 | Padding(7), 196 | ) 197 | 198 | MINT_LAYOUT = cStruct(Padding(44), "decimals" / Int8ul, Padding(37)) 199 | 200 | 201 | POOL_INFO_LAYOUT = cStruct("instruction" / Int8ul, "simulate_type" / Int8ul) 202 | 203 | LIQ_LAYOUT = cStruct("instruction" / Int8ul, "amount_in" / Int64ul) 204 | 205 | 206 | ###BUYING 207 | 208 | AMM_PROGRAM_ID = Pubkey.from_string('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8') 209 | SERUM_PROGRAM_ID = Pubkey.from_string('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX') 210 | def get_token_account(ctx, 211 | owner: Pubkey.from_string, 212 | mint: Pubkey.from_string): 213 | try: 214 | account_data = ctx.get_token_accounts_by_owner(owner, TokenAccountOpts(mint)) 215 | return account_data.value[0].pubkey, None 216 | except: 217 | swap_associated_token_address = get_associated_token_address(owner, mint) 218 | swap_token_account_Instructions = create_associated_token_account(owner, owner, mint) 219 | return swap_associated_token_address, swap_token_account_Instructions 220 | 221 | 222 | def make_swap_instruction(amount_in: int, token_account_in: Pubkey.from_string, token_account_out: Pubkey.from_string, 223 | accounts: dict, mint, ctx, owner) -> Instruction: 224 | tokenPk = mint 225 | accountProgramId = ctx.get_account_info_json_parsed(tokenPk) 226 | TOKEN_PROGRAM_ID = accountProgramId.value.owner 227 | 228 | keys = [ 229 | AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), 230 | AccountMeta(pubkey=accounts["amm_id"], is_signer=False, is_writable=True), 231 | AccountMeta(pubkey=accounts["authority"], is_signer=False, is_writable=False), 232 | AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True), 233 | AccountMeta(pubkey=accounts["target_orders"], is_signer=False, is_writable=True), 234 | AccountMeta(pubkey=accounts["base_vault"], is_signer=False, is_writable=True), 235 | AccountMeta(pubkey=accounts["quote_vault"], is_signer=False, is_writable=True), 236 | AccountMeta(pubkey=SERUM_PROGRAM_ID, is_signer=False, is_writable=False), 237 | AccountMeta(pubkey=accounts["market_id"], is_signer=False, is_writable=True), 238 | AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True), 239 | AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True), 240 | AccountMeta(pubkey=accounts["event_queue"], is_signer=False, is_writable=True), 241 | AccountMeta(pubkey=accounts["market_base_vault"], is_signer=False, is_writable=True), 242 | AccountMeta(pubkey=accounts["market_quote_vault"], is_signer=False, is_writable=True), 243 | AccountMeta(pubkey=accounts["market_authority"], is_signer=False, is_writable=False), 244 | AccountMeta(pubkey=token_account_in, is_signer=False, is_writable=True), # UserSourceTokenAccount 245 | AccountMeta(pubkey=token_account_out, is_signer=False, is_writable=True), # UserDestTokenAccount 246 | AccountMeta(pubkey=owner.pubkey(), is_signer=True, is_writable=False) # UserOwner 247 | ] 248 | 249 | data = SWAP_LAYOUT.build( 250 | dict( 251 | instruction=9, 252 | amount_in=int(amount_in), 253 | min_amount_out=0 254 | ) 255 | ) 256 | return Instruction(AMM_PROGRAM_ID, data, keys) 257 | 258 | def getSymbol(token): 259 | # usdc and usdt 260 | exclude = ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'] 261 | 262 | if token not in exclude: 263 | url = f"https://api.dexscreener.com/latest/dex/tokens/{token}" 264 | 265 | Token_Symbol = "" 266 | Sol_symbol = "" 267 | try: 268 | response = requests.get(url) 269 | 270 | # Check if the request was successful (status code 200) 271 | if response.status_code == 200: 272 | resp = response.json() 273 | print("Response:", resp['pairs'][0]['baseToken']['symbol']) 274 | for pair in resp['pairs']: 275 | quoteToken = pair['quoteToken']['symbol'] 276 | 277 | if quoteToken == 'SOL': 278 | Token_Symbol = pair['baseToken']['symbol'] 279 | Sol_symbol = quoteToken 280 | return Token_Symbol, Sol_symbol 281 | 282 | 283 | else: 284 | print(f"[getSymbol] Request failed with status code {response.status_code}") 285 | 286 | except requests.exceptions.RequestException as e: 287 | print(f"[getSymbol] error occurred: {e}") 288 | except: 289 | a = 1 290 | 291 | return Token_Symbol, Sol_symbol 292 | else: 293 | if token == 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v': 294 | return "USDC", "SOL" 295 | elif token == 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v': 296 | return "USDT", "SOL" 297 | 298 | from borsh_construct import CStruct, U64, Bytes 299 | from construct import Bytes, Int8ul, Int32ul, Int64ul, Pass, Switch 300 | 301 | PUBLIC_KEY_LAYOUT = Bytes(32) 302 | market_state_layout_v3 = CStruct( 303 | "blob1" / Bytes(5), 304 | "blob2" / Bytes(8), 305 | "ownAddress" / PUBLIC_KEY_LAYOUT, 306 | "vaultSignerNonce" / U64, 307 | "baseMint" / PUBLIC_KEY_LAYOUT, 308 | "quoteMint" / PUBLIC_KEY_LAYOUT, 309 | "baseVault" / PUBLIC_KEY_LAYOUT, 310 | "baseDepositsTotal" / U64, 311 | "baseFeesAccrued" / U64, 312 | "quoteVault" / PUBLIC_KEY_LAYOUT, 313 | "quoteDepositsTotal" / U64, 314 | "quoteFeesAccrued" / U64, 315 | "quoteDustThreshold" / U64, 316 | "requestQueue" / PUBLIC_KEY_LAYOUT, 317 | "eventQueue" / PUBLIC_KEY_LAYOUT, 318 | "bids" / PUBLIC_KEY_LAYOUT, 319 | "asks" / PUBLIC_KEY_LAYOUT, 320 | "baseLotSize" / U64, 321 | "quoteLotSize" / U64, 322 | "feeRateBps" / U64, 323 | "referrerRebatesAccrued" / U64, 324 | "blob3" / Bytes(7) 325 | ) 326 | SPL_ACCOUNT_LAYOUT = CStruct( 327 | "mint" / PUBLIC_KEY_LAYOUT, 328 | "owner" / PUBLIC_KEY_LAYOUT, 329 | "amount" / U64, 330 | "delegateOption" / Int32ul, 331 | "delegate" / PUBLIC_KEY_LAYOUT, 332 | "state" / Int8ul, 333 | "isNativeOption" / Int32ul, 334 | "isNative" / U64, 335 | "delegatedAmount" / U64, 336 | "closeAuthorityOption" / Int32ul, 337 | "closeAuthority" / PUBLIC_KEY_LAYOUT 338 | ) 339 | 340 | 341 | SPL_MINT_LAYOUT = CStruct( 342 | "mintAuthorityOption"/ Int32ul, 343 | 'mintAuthority'/PUBLIC_KEY_LAYOUT, 344 | 'supply'/U64, 345 | 'decimals'/Int8ul, 346 | 'isInitialized'/Int8ul, 347 | 'freezeAuthorityOption'/Int32ul, 348 | 'freezeAuthority'/PUBLIC_KEY_LAYOUT 349 | ) -------------------------------------------------------------------------------- /Jito/utils/pool_information.py: -------------------------------------------------------------------------------- 1 | import base58 2 | from solana.rpc.async_api import AsyncClient 3 | from solana.rpc.types import MemcmpOpts 4 | import time 5 | from solana.rpc.commitment import Confirmed 6 | 7 | from WrapSol__PriorityFees.utils.layouts import AMM_INFO_LAYOUT_V4_1, MARKET_LAYOUT,get_offset 8 | from solders.pubkey import Pubkey 9 | import os 10 | from dotenv import load_dotenv 11 | 12 | # Load.env file 13 | # load_dotenv() 14 | load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), '..', '.env')) 15 | 16 | RPC_HTTPS_URL= os.getenv("RPC_HTTPS_URL") 17 | # config = dotenv_values("Trade/.env") 18 | # print(config) 19 | 20 | WSOL = Pubkey.from_string("So11111111111111111111111111111111111111112") 21 | ASSOCIATED_TOKEN_PROGRAM_ID = Pubkey.from_string( 22 | "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" 23 | ) 24 | 25 | MINT_LEN: int = 82 26 | """Data length of a token mint account.""" 27 | 28 | ACCOUNT_LEN: int = 165 29 | """Data length of a token account.""" 30 | 31 | MULTISIG_LEN: int = 355 32 | """Data length of a multisig token account.""" 33 | 34 | TOKEN_PROGRAM_ID: Pubkey = Pubkey.from_string( 35 | "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" 36 | ) 37 | TOKEN_PROGRAM_ID_2022: Pubkey = Pubkey.from_string( 38 | "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" 39 | ) 40 | 41 | RAY_V4 = Pubkey.from_string("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8") 42 | PUMP_FUN_PROGRAM = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P") 43 | PUMP_LIQUIDITY_MIGRATOR = Pubkey.from_string("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg") 44 | 45 | RAY_AUTHORITY_V4 = Pubkey.from_string("5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1") 46 | 47 | OPEN_BOOK_PROGRAM = Pubkey.from_string("srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX") 48 | # offset_base_mint = get_offset(MARKET_LAYOUT, 'base_mint') 49 | offset_base_mint = get_offset(AMM_INFO_LAYOUT_V4_1, 'coinMintAddress') 50 | offset_quote_mint = get_offset(AMM_INFO_LAYOUT_V4_1, 'pcMintAddress') 51 | 52 | 53 | LAMPORTS_PER_SOL = 1000000000 54 | # RPC_HTTPS_URL=config["RPC_HTTPS_URL"] 55 | 56 | def is_solana_address_pump(address): 57 | address=str(address) 58 | """ 59 | Check if the given Solana address ends with 'pump'. 60 | 61 | :param address: The Solana address string to check. 62 | :return: True if the address ends with 'pump', False otherwise. 63 | """ 64 | 65 | return address.endswith('pump') 66 | 67 | async def getpoolIdByMint(mint, ctx): 68 | start_time = time.time() 69 | pump_token=is_solana_address_pump(str(mint)) 70 | if pump_token: 71 | 72 | memcmp_opts_base = MemcmpOpts(offset=432, bytes=str(mint)) 73 | 74 | else: 75 | memcmp_opts_base = MemcmpOpts(offset=400, bytes=str(mint)) 76 | # print(memcmp_opts_base) 77 | filters_tokens = [memcmp_opts_base] 78 | 79 | while True: 80 | try: 81 | if time.time() - start_time > 5: 82 | return False 83 | 84 | 85 | poolids = (await ctx.get_program_accounts(pubkey=RAY_V4, commitment=Confirmed, encoding="jsonParsed", 86 | filters=filters_tokens)).value 87 | # print(poolids) 88 | break 89 | except : 90 | pass 91 | if(len(poolids) > 0): 92 | return poolids[0].pubkey 93 | else: 94 | return None 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | async def gen_pool(amm_id, ctx): 107 | 108 | 109 | try: 110 | amm_id = Pubkey.from_string(amm_id) 111 | ctx = AsyncClient(RPC_HTTPS_URL, commitment=Confirmed) 112 | 113 | start = time.time() 114 | while True: 115 | try: 116 | amm_data = (await ctx.get_account_info_json_parsed(amm_id)).value.data 117 | break 118 | except: 119 | if (time.time() - start) > 3: 120 | return {"error" : "server timeout - took too long to find the pool info"} 121 | pass 122 | 123 | amm_data_decoded = AMM_INFO_LAYOUT_V4_1.parse(amm_data) 124 | OPEN_BOOK_PROGRAM = Pubkey.from_bytes(amm_data_decoded.serumProgramId) 125 | marketId = Pubkey.from_bytes(amm_data_decoded.serumMarket) 126 | # print("Market --- ", marketId)) 127 | try: 128 | while True: 129 | try: 130 | marketInfo = ( 131 | await ctx.get_account_info_json_parsed(marketId) 132 | ).value.data 133 | break 134 | except: 135 | if (time.time() - start) > 3: 136 | return {"error" : "server timeout - took too long to find the pool info"} 137 | pass 138 | 139 | market_decoded = MARKET_LAYOUT.parse(marketInfo) 140 | 141 | 142 | pool_keys = { 143 | "amm_id": amm_id, 144 | "base_mint": Pubkey.from_bytes(market_decoded.base_mint), 145 | "quote_mint": Pubkey.from_bytes(market_decoded.quote_mint), 146 | "lp_mint": Pubkey.from_bytes(amm_data_decoded.lpMintAddress), 147 | "version": 4, 148 | 149 | "base_decimals": amm_data_decoded.coinDecimals, 150 | "quote_decimals": amm_data_decoded.pcDecimals, 151 | "lpDecimals": amm_data_decoded.coinDecimals, 152 | "programId": RAY_V4, 153 | "authority": RAY_AUTHORITY_V4, 154 | 155 | "open_orders": Pubkey.from_bytes(amm_data_decoded.ammOpenOrders), 156 | 157 | "target_orders": Pubkey.from_bytes(amm_data_decoded.ammTargetOrders), 158 | 159 | 160 | "base_vault": Pubkey.from_bytes(amm_data_decoded.poolCoinTokenAccount), 161 | "quote_vault": Pubkey.from_bytes(amm_data_decoded.poolPcTokenAccount), 162 | 163 | "withdrawQueue": Pubkey.from_bytes(amm_data_decoded.poolWithdrawQueue), 164 | "lpVault": Pubkey.from_bytes(amm_data_decoded.poolTempLpTokenAccount), 165 | 166 | "marketProgramId": OPEN_BOOK_PROGRAM, 167 | "market_id": marketId, 168 | 169 | "market_authority": Pubkey.create_program_address( 170 | [bytes(marketId)] 171 | + [bytes([market_decoded.vault_signer_nonce])] 172 | + [bytes(7)], 173 | OPEN_BOOK_PROGRAM, 174 | ), 175 | 176 | "market_base_vault": Pubkey.from_bytes(market_decoded.base_vault), 177 | "market_quote_vault": Pubkey.from_bytes(market_decoded.quote_vault), 178 | "bids": Pubkey.from_bytes(market_decoded.bids), 179 | "asks": Pubkey.from_bytes(market_decoded.asks), 180 | "event_queue": Pubkey.from_bytes(market_decoded.event_queue), 181 | "pool_open_time": amm_data_decoded.poolOpenTime 182 | } 183 | 184 | Buy_keys = [ 185 | 'amm_id', 'authority', 'base_mint', 'base_decimals', 'quote_mint', 'quote_decimals', 186 | 'lp_mint', 'open_orders', 'target_orders', 'base_vault', 'quote_vault', 'market_id', 187 | 'market_base_vault', 'market_quote_vault', 'market_authority', 'bids', 'asks', 'event_queue' 188 | ] 189 | 190 | transactionkeys = {key: pool_keys[key] for key in Buy_keys} 191 | 192 | return transactionkeys 193 | 194 | 195 | 196 | except: 197 | {"error" : "unexpected error occured"} 198 | except: 199 | return {"error" : "incorrect pair address"} 200 | 201 | -------------------------------------------------------------------------------- /PumpDotFun/.env.template: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY = "" 2 | RPC_URL = "https://mainnet.helius-rpc.com/?api-key=Your API KEY" 3 | UNIT_BUDGET = 100_000 4 | UNIT_PRICE = 1_000_000 -------------------------------------------------------------------------------- /PumpDotFun/__pycache__/buy.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henrytirla/Solana-Trading-Bot/9c38fc65bee63779b21914743d28b0294eeefdb7/PumpDotFun/__pycache__/buy.cpython-311.pyc -------------------------------------------------------------------------------- /PumpDotFun/buy.py: -------------------------------------------------------------------------------- 1 | #https://github.com/AL-THE-BOT-FATHER/pump_fun_py credit 2 | import json 3 | import struct 4 | import time 5 | from solana.transaction import Signature 6 | from solana.rpc.commitment import Processed, Confirmed 7 | from solana.rpc.types import TokenAccountOpts, TxOpts 8 | from solana.transaction import AccountMeta 9 | from solders.keypair import Keypair 10 | from spl.token.instructions import ( 11 | CloseAccountParams, 12 | close_account, 13 | create_associated_token_account, 14 | get_associated_token_address, 15 | ) 16 | from solders.compute_budget import set_compute_unit_limit, set_compute_unit_price # type: ignore 17 | from solders.instruction import Instruction 18 | from solders.message import MessageV0 19 | from solders.transaction import VersionedTransaction 20 | from solana.rpc.api import Client, Keypair 21 | from solders.compute_budget import set_compute_unit_price,set_compute_unit_limit 22 | from PumpDotFun.utils.constants import * 23 | from utils.coin_data import get_coin_data, sol_for_tokens, tokens_for_sol 24 | import os 25 | from utils.utility import confirm_txn, get_token_balance,get_token_price 26 | 27 | 28 | 29 | 30 | from dotenv import load_dotenv 31 | 32 | # Load.env file 33 | load_dotenv() 34 | 35 | # config = dotenv_values(".env") 36 | UNIT_BUDGET= os.getenv("UNIT_BUDGET") 37 | UNIT_PRICE= os.getenv("UNIT_PRICE") 38 | RPC_HTTPS_URL= os.getenv("RPC_URL") 39 | client = Client(os.getenv("RPC_URL")) 40 | payer_keypair=Keypair.from_base58_string(os.getenv("PRIVATE_KEY")) 41 | def buy(mint_str: str, sol_in: float = 0.01, slippage: int = 5) -> bool: 42 | try: 43 | print(f"Starting buy transaction for mint: {mint_str}") 44 | 45 | coin_data = get_coin_data(mint_str) 46 | 47 | if not coin_data: 48 | print("Failed to retrieve coin data.") 49 | return False 50 | 51 | if coin_data.complete: 52 | print("Warning: This token has bonded and is only tradable on Raydium.") 53 | return 54 | 55 | MINT = coin_data.mint 56 | BONDING_CURVE = coin_data.bonding_curve 57 | ASSOCIATED_BONDING_CURVE = coin_data.associated_bonding_curve 58 | USER = payer_keypair.pubkey() 59 | 60 | print("Fetching or creating associated token account...") 61 | try: 62 | ASSOCIATED_USER = client.get_token_accounts_by_owner(USER, TokenAccountOpts(MINT)).value[0].pubkey 63 | token_account_instruction = None 64 | print(f"Token account found: {ASSOCIATED_USER}") 65 | except: 66 | ASSOCIATED_USER = get_associated_token_address(USER, MINT) 67 | token_account_instruction = create_associated_token_account(USER, USER, MINT) 68 | print(f"Creating token account : {ASSOCIATED_USER}") 69 | 70 | print("Calculating transaction amounts...") 71 | sol_dec = 1e9 72 | token_dec = 1e6 73 | virtual_sol_reserves = coin_data.virtual_sol_reserves / sol_dec 74 | virtual_token_reserves = coin_data.virtual_token_reserves / token_dec 75 | amount = sol_for_tokens(sol_in, virtual_sol_reserves, virtual_token_reserves) 76 | amount = int(amount * token_dec) 77 | 78 | slippage_adjustment = 1 + (slippage / 100) 79 | max_sol_cost = int((sol_in * slippage_adjustment) * sol_dec) 80 | print(f"Amount: {amount}, Max Sol Cost: {max_sol_cost}") 81 | 82 | print("Creating swap instructions...") 83 | keys = [ 84 | AccountMeta(pubkey=GLOBAL, is_signer=False, is_writable=False), 85 | AccountMeta(pubkey=FEE_RECIPIENT, is_signer=False, is_writable=True), 86 | AccountMeta(pubkey=MINT, is_signer=False, is_writable=False), 87 | AccountMeta(pubkey=BONDING_CURVE, is_signer=False, is_writable=True), 88 | AccountMeta(pubkey=ASSOCIATED_BONDING_CURVE, is_signer=False, is_writable=True), 89 | AccountMeta(pubkey=ASSOCIATED_USER, is_signer=False, is_writable=True), 90 | AccountMeta(pubkey=USER, is_signer=True, is_writable=True), 91 | AccountMeta(pubkey=SYSTEM_PROGRAM, is_signer=False, is_writable=False), 92 | AccountMeta(pubkey=TOKEN_PROGRAM, is_signer=False, is_writable=False), 93 | AccountMeta(pubkey=RENT, is_signer=False, is_writable=False), 94 | AccountMeta(pubkey=EVENT_AUTHORITY, is_signer=False, is_writable=False), 95 | AccountMeta(pubkey=PUMP_FUN_PROGRAM, is_signer=False, is_writable=False) 96 | ] 97 | 98 | data = bytearray() 99 | data.extend(bytes.fromhex("66063d1201daebea")) 100 | data.extend(struct.pack(' bool: 38 | try: 39 | print(f"Starting sell transaction for mint: {mint_str}") 40 | 41 | if not (1 <= percentage <= 100): 42 | print("Percentage must be between 1 and 100.") 43 | return False 44 | 45 | coin_data = get_coin_data(mint_str) 46 | 47 | if not coin_data: 48 | print("Failed to retrieve coin data.") 49 | return False 50 | 51 | if coin_data.complete: 52 | print("Warning: This token has bonded and is only tradable on Raydium.") 53 | return 54 | 55 | MINT = coin_data.mint 56 | BONDING_CURVE = coin_data.bonding_curve 57 | ASSOCIATED_BONDING_CURVE = coin_data.associated_bonding_curve 58 | USER = payer_keypair.pubkey() 59 | ASSOCIATED_USER = get_associated_token_address(USER, MINT) 60 | 61 | print("Retrieving token balance...") 62 | token_balance = get_token_balance(mint_str) 63 | if token_balance == 0 or token_balance is None: 64 | print("Token balance is zero. Nothing to sell.") 65 | return False 66 | print(f"Token Balance: {token_balance}") 67 | 68 | print("Calculating transaction amounts...") 69 | sol_dec = 1e9 70 | token_dec = 1e6 71 | amount = int(token_balance * token_dec) 72 | 73 | virtual_sol_reserves = coin_data.virtual_sol_reserves / sol_dec 74 | virtual_token_reserves = coin_data.virtual_token_reserves / token_dec 75 | sol_out = tokens_for_sol(token_balance, virtual_sol_reserves, virtual_token_reserves) 76 | 77 | slippage_adjustment = 1 - (slippage / 100) 78 | min_sol_output = int((sol_out * slippage_adjustment) * sol_dec) 79 | print(f"Amount: {amount}, Minimum Sol Out: {min_sol_output}") 80 | 81 | print("Creating swap instructions...") 82 | keys = [ 83 | AccountMeta(pubkey=GLOBAL, is_signer=False, is_writable=False), 84 | AccountMeta(pubkey=FEE_RECIPIENT, is_signer=False, is_writable=True), 85 | AccountMeta(pubkey=MINT, is_signer=False, is_writable=False), 86 | AccountMeta(pubkey=BONDING_CURVE, is_signer=False, is_writable=True), 87 | AccountMeta(pubkey=ASSOCIATED_BONDING_CURVE, is_signer=False, is_writable=True), 88 | AccountMeta(pubkey=ASSOCIATED_USER, is_signer=False, is_writable=True), 89 | AccountMeta(pubkey=USER, is_signer=True, is_writable=True), 90 | AccountMeta(pubkey=SYSTEM_PROGRAM, is_signer=False, is_writable=False), 91 | AccountMeta(pubkey=ASSOC_TOKEN_ACC_PROG, is_signer=False, is_writable=False), 92 | AccountMeta(pubkey=TOKEN_PROGRAM, is_signer=False, is_writable=False), 93 | AccountMeta(pubkey=EVENT_AUTHORITY, is_signer=False, is_writable=False), 94 | AccountMeta(pubkey=PUMP_FUN_PROGRAM, is_signer=False, is_writable=False) 95 | ] 96 | 97 | data = bytearray() 98 | data.extend(bytes.fromhex("33e685a4017f83ad")) 99 | data.extend(struct.pack(' Optional[CoinData]: 64 | bonding_curve, associated_bonding_curve = derive_bonding_curve_accounts(mint_str) 65 | if bonding_curve is None or associated_bonding_curve is None: 66 | return None 67 | 68 | virtual_reserves = get_virtual_reserves(bonding_curve) 69 | if virtual_reserves is None: 70 | return None 71 | 72 | try: 73 | return CoinData( 74 | mint=Pubkey.from_string(mint_str), 75 | bonding_curve=bonding_curve, 76 | associated_bonding_curve=associated_bonding_curve, 77 | virtual_token_reserves=int(virtual_reserves.virtualTokenReserves), 78 | virtual_sol_reserves=int(virtual_reserves.virtualSolReserves), 79 | token_total_supply=int(virtual_reserves.tokenTotalSupply), 80 | complete=bool(virtual_reserves.complete), 81 | ) 82 | except Exception as e: 83 | print(e) 84 | return None 85 | 86 | 87 | def sol_for_tokens(sol_spent, sol_reserves, token_reserves): 88 | new_sol_reserves = sol_reserves + sol_spent 89 | new_token_reserves = (sol_reserves * token_reserves) / new_sol_reserves 90 | token_received = token_reserves - new_token_reserves 91 | return round(token_received) 92 | 93 | 94 | def tokens_for_sol(tokens_to_sell, sol_reserves, token_reserves): 95 | new_token_reserves = token_reserves + tokens_to_sell 96 | new_sol_reserves = (sol_reserves * token_reserves) / new_token_reserves 97 | sol_received = sol_reserves - new_sol_reserves 98 | return sol_received 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /PumpDotFun/utils/constants.py: -------------------------------------------------------------------------------- 1 | from solders.pubkey import Pubkey 2 | 3 | GLOBAL = Pubkey.from_string("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf") 4 | FEE_RECIPIENT = Pubkey.from_string("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM") 5 | SYSTEM_PROGRAM = Pubkey.from_string("11111111111111111111111111111111") 6 | TOKEN_PROGRAM = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") 7 | ASSOC_TOKEN_ACC_PROG = Pubkey.from_string("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL") 8 | RENT = Pubkey.from_string("SysvarRent111111111111111111111111111111111") 9 | EVENT_AUTHORITY = Pubkey.from_string("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1") 10 | PUMP_FUN_PROGRAM = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P") -------------------------------------------------------------------------------- /PumpDotFun/utils/utility.py: -------------------------------------------------------------------------------- 1 | import json 2 | import time 3 | from solana.rpc.commitment import Processed, Confirmed 4 | from solana.rpc.types import TokenAccountOpts 5 | from solana.transaction import Signature 6 | from solders.pubkey import Pubkey # type: ignore 7 | from solana.rpc.api import Client, Keypair 8 | 9 | from PumpDotFun.utils.coin_data import get_coin_data 10 | import os 11 | 12 | from dotenv import load_dotenv 13 | 14 | 15 | # Load .env file explicitly from the root directory 16 | load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), '..', '.env')) 17 | # Load.env file 18 | 19 | 20 | # config = dotenv_values(".env") 21 | UNIT_BUDGET= os.getenv("UNIT_BUDGET") 22 | UNIT_PRICE= os.getenv("UNIT_PRICE") 23 | RPC_HTTPS_URL= os.getenv("RPC_URL") 24 | client = Client(os.getenv("RPC_URL")) 25 | payer_keypair=Keypair.from_base58_string(os.getenv("PRIVATE_KEY")) 26 | 27 | 28 | def get_token_balance(mint_str: str) -> float | None: 29 | try: 30 | mint = Pubkey.from_string(mint_str) 31 | response = client.get_token_accounts_by_owner_json_parsed( 32 | payer_keypair.pubkey(), 33 | TokenAccountOpts(mint=mint), 34 | commitment=Processed 35 | ) 36 | 37 | accounts = response.value 38 | if accounts: 39 | token_amount = accounts[0].account.data.parsed['info']['tokenAmount']['uiAmount'] 40 | return float(token_amount) 41 | 42 | return None 43 | except Exception as e: 44 | print(f"Error fetching token balance: {e}") 45 | return None 46 | 47 | 48 | def confirm_txn(txn_sig: Signature, max_retries: int = 20, retry_interval: int = 3) -> bool: 49 | retries = 1 50 | 51 | while retries < max_retries: 52 | try: 53 | txn_res = client.get_transaction(txn_sig, encoding="json", commitment=Confirmed, 54 | max_supported_transaction_version=0) 55 | txn_json = json.loads(txn_res.value.transaction.meta.to_json()) 56 | 57 | if txn_json['err'] is None: 58 | print("Transaction confirmed... try count:", retries) 59 | return True 60 | 61 | print("Error: Transaction not confirmed. Retrying...") 62 | if txn_json['err']: 63 | print("Transaction failed.") 64 | return False 65 | except Exception as e: 66 | print("Awaiting confirmation... try count:", retries) 67 | retries += 1 68 | time.sleep(retry_interval) 69 | 70 | print("Max retries reached. Transaction confirmation failed.") 71 | return None 72 | 73 | 74 | def get_token_price(mint_str: str) -> float: 75 | try: 76 | coin_data = get_coin_data(mint_str) 77 | 78 | if not coin_data: 79 | print("Failed to retrieve coin data...") 80 | return None 81 | 82 | virtual_sol_reserves = coin_data.virtual_sol_reserves / 10 ** 9 83 | virtual_token_reserves = coin_data.virtual_token_reserves / 10 ** 6 84 | 85 | token_price = virtual_sol_reserves / virtual_token_reserves 86 | print(f"Token Price: {token_price:.20f} SOL") 87 | 88 | return token_price 89 | 90 | except Exception as e: 91 | print(f"Error calculating token price: {e}") 92 | return None 93 | -------------------------------------------------------------------------------- /WrapSol__PriorityFees/.env.template: -------------------------------------------------------------------------------- 1 | RPC_HTTPS_URL="https://mainnet.helius-rpc.com/?api-key=" #Your RPC URL 2 | PrivateKey="" #YOur Private KEy 3 | WSOL_TokenAccount="4mncAGe5Re1dnX1K6mPsKPQDmJijLrHrQxT3C4fShtjU" #Your WSOL Token Account 4 | Amount_to_Wrap=0.025 # Amount of SOL --> WSOL -------------------------------------------------------------------------------- /WrapSol__PriorityFees/buy_wrap_sol.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import datetime 3 | import time 4 | from solders.message import MessageV0 5 | from solders.transaction import VersionedTransaction 6 | from solana.rpc.types import TokenAccountOpts, TxOpts 7 | from solders.pubkey import Pubkey 8 | from solana.rpc.commitment import Confirmed 9 | from solana.rpc.api import RPCException 10 | from solana.rpc.api import Client 11 | from solders.keypair import Keypair 12 | from solders.compute_budget import set_compute_unit_price,set_compute_unit_limit 13 | 14 | from utils.create_close_account import get_token_account, make_swap_instruction 15 | from utils.birdeye import getSymbol 16 | from solana.rpc.async_api import AsyncClient 17 | from utils.pool_information import gen_pool, getpoolIdByMint 18 | import os 19 | from dotenv import load_dotenv 20 | 21 | 22 | # Load.env file 23 | load_dotenv() 24 | 25 | # config = dotenv_values(".env") 26 | 27 | RPC_HTTPS_URL= os.getenv("RPC_HTTPS_URL") 28 | solana_client = Client(os.getenv("RPC_HTTPS_URL")) 29 | 30 | async_solana_client = AsyncClient(os.getenv("RPC_HTTPS_URL")) 31 | payer=Keypair.from_base58_string(os.getenv("PrivateKey")) 32 | Wsol_TokenAccount=os.getenv('WSOL_TokenAccount') 33 | 34 | 35 | AMM_PROGRAM_ID = Pubkey.from_string('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8') 36 | SERUM_PROGRAM_ID = Pubkey.from_string('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX') 37 | LAMPORTS_PER_SOL = 1000000000 38 | MAX_RETRIES = 2 39 | RETRY_DELAY = 3 40 | 41 | class style(): 42 | BLACK = '\033[30m' 43 | RED = '\033[31m' 44 | GREEN = '\033[32m' 45 | YELLOW = '\033[33m' 46 | BLUE = '\033[34m' 47 | MAGENTA = '\033[35m' 48 | CYAN = '\033[36m' 49 | WHITE = '\033[37m' 50 | UNDERLINE = '\033[4m' 51 | RESET = '\033[0m' 52 | 53 | 54 | def getTimestamp(): 55 | while True: 56 | timeStampData = datetime.datetime.now() 57 | currentTimeStamp = "[" + timeStampData.strftime("%H:%M:%S.%f")[:-3] + "]" 58 | return currentTimeStamp 59 | 60 | async def get_specific_token_account(owner_pubkey: str, mint_pubkey: str): 61 | async with AsyncClient(RPC_HTTPS_URL) as client: 62 | owner_pubkey_obj = Pubkey.from_string(owner_pubkey) 63 | mint_pubkey_obj = Pubkey.from_string(mint_pubkey) 64 | # Using get_token_accounts_by_owner to fetch token accounts 65 | opts = TokenAccountOpts(mint=mint_pubkey_obj) 66 | response = await client.get_token_accounts_by_owner(owner_pubkey_obj, opts) 67 | if len(response.value) ==1 : 68 | return response.value[0].pubkey # Return the first account found 69 | return None 70 | 71 | 72 | 73 | 74 | async def buy(solana_client, TOKEN_TO_SWAP_BUY, payer, amount): 75 | 76 | 77 | retry_count = 0 78 | while retry_count < MAX_RETRIES: 79 | try: 80 | # Re-init transaction preparation 81 | token_symbol, SOl_Symbol = getSymbol(TOKEN_TO_SWAP_BUY) 82 | mint = Pubkey.from_string(TOKEN_TO_SWAP_BUY) 83 | # mint= TOKEN_TO_SWAP_BUY 84 | 85 | try: 86 | print("Fetching pool keys...") 87 | 88 | 89 | tokenPool_ID = await getpoolIdByMint(mint, AsyncClient(RPC_HTTPS_URL, commitment=Confirmed)) 90 | print(tokenPool_ID) 91 | if tokenPool_ID: 92 | print("AMMID FOUND") 93 | 94 | fetch_pool_key = await gen_pool(str(tokenPool_ID), AsyncClient(RPC_HTTPS_URL, commitment=Confirmed)) 95 | pool_keys = fetch_pool_key 96 | else: 97 | print("AMMID NOT FOUND SEARCHING WILL BE FETCHING WITH RAYDIUM SDK") 98 | 99 | 100 | #pool_keys = fetch_pool_keys(str(mint)) 101 | except Exception as e: 102 | print(e) 103 | 104 | 105 | amount_in = int(amount * LAMPORTS_PER_SOL) 106 | 107 | swap_associated_token_address, swap_token_account_Instructions = get_token_account(solana_client, payer.pubkey(), mint) 108 | swap_tx = [] 109 | WSOL_token_account = Pubkey.from_string(Wsol_TokenAccount) 110 | instructions_swap = make_swap_instruction(amount_in, WSOL_token_account, swap_associated_token_address, pool_keys, mint, solana_client, payer) 111 | if swap_token_account_Instructions != None: 112 | 113 | swap_tx.append(swap_token_account_Instructions) 114 | 115 | swap_tx.extend([instructions_swap, 116 | set_compute_unit_price(498_750), 117 | set_compute_unit_limit(4_000_000)]) 118 | 119 | #Do not edit Compute Unit Price and Compute Unit Limit if you have no idea what you are doing. Current test confirm txn in 1-5s 120 | 121 | 122 | # Execute Transaction 123 | print("Execute Transaction...") 124 | compiled_message = MessageV0.try_compile( 125 | payer.pubkey(), 126 | swap_tx, 127 | [], 128 | solana_client.get_latest_blockhash().value.blockhash, 129 | ) 130 | print("Sending transaction...") 131 | txn = await async_solana_client.send_transaction( 132 | txn=VersionedTransaction(compiled_message, [payer]), 133 | opts=TxOpts(skip_preflight=True), 134 | ) 135 | print("Transaction Signature:", txn.value) 136 | txid_string_sig = txn.value 137 | if txid_string_sig: 138 | print("Transaction sent") 139 | print(getTimestamp()) 140 | print(style.RED,f"Transaction Signature Waiting to be confirmed: https://solscan.io/tx/{txid_string_sig}"+style.RESET) 141 | print("Waiting Confirmation") 142 | 143 | block_height = solana_client.get_block_height(Confirmed).value 144 | print(f"Block height: {block_height}") 145 | 146 | 147 | confirmation_resp = await async_solana_client.confirm_transaction( 148 | txid_string_sig, 149 | commitment=Confirmed, 150 | sleep_seconds=0.5, 151 | last_valid_block_height=block_height + 50 152 | 153 | 154 | ) 155 | 156 | 157 | if confirmation_resp.value[0].err== None and str(confirmation_resp.value[0].confirmation_status) =="TransactionConfirmationStatus.Confirmed": 158 | print(style.GREEN+"Transaction Confirmed",style.RESET) 159 | print(style.GREEN,f"Transaction Signature: https://solscan.io/tx/{txid_string_sig}",style.RESET) 160 | 161 | return True 162 | 163 | else: 164 | print("Transaction not confirmed") 165 | return False 166 | 167 | except asyncio.TimeoutError: 168 | print("Transaction confirmation timed out. Retrying...") 169 | retry_count += 1 170 | time.sleep(RETRY_DELAY) 171 | except RPCException as e: 172 | print(f"RPC Error: [{e.args[0].message}]... Retrying...") 173 | retry_count += 1 174 | time.sleep(RETRY_DELAY) 175 | except Exception as e: 176 | print(f"Unhandled exception: {e}. Retrying...") 177 | retry_count += 1 178 | time.sleep(RETRY_DELAY) 179 | 180 | print("Failed to confirm transaction after maximum retries.") 181 | return False 182 | 183 | async def main(): 184 | #7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr 185 | #RUpbmGF6p42AAeN1QvhFReZejQry1cLkE1PUYFVVpnL 186 | 187 | token_toBuy="3WdmE9BAHgVyB1JNswSUcj6RmkxnsvfJTd6RFnQ4pump" 188 | print(payer.pubkey()) 189 | await buy(solana_client, token_toBuy, payer, 0.00065) 190 | 191 | asyncio.run(main()) -------------------------------------------------------------------------------- /WrapSol__PriorityFees/close_tokenAccount.py: -------------------------------------------------------------------------------- 1 | 2 | import asyncio 3 | import os 4 | import datetime 5 | from solana.rpc.commitment import Finalized, Confirmed 6 | from solana.rpc.types import TxOpts 7 | from solders.compute_budget import set_compute_unit_price, set_compute_unit_limit 8 | from solders.message import MessageV0 9 | from solders.pubkey import Pubkey 10 | from solders.keypair import Keypair 11 | from solana.rpc.async_api import AsyncClient 12 | from solders.transaction import VersionedTransaction 13 | from solana.rpc.api import Client 14 | from solana.rpc import types 15 | from spl.token.constants import TOKEN_PROGRAM_ID 16 | from spl.token.instructions import burn, BurnParams, CloseAccountParams, close_account 17 | from dotenv import load_dotenv 18 | load_dotenv() 19 | prompt= input("Do you want to close the token account? (yes/no): Stop the script if it's No, If yes press enter " 20 | "to continue") 21 | 22 | payer=Keypair.from_base58_string(os.getenv("PrivateKey")) 23 | solana_client = Client(os.getenv("RPC_HTTPS_URL")) 24 | async_solana_client = AsyncClient(os.getenv("RPC_HTTPS_URL")) 25 | 26 | def getTimestamp(): 27 | while True: 28 | timeStampData = datetime.datetime.now() 29 | currentTimeStamp = "[" + timeStampData.strftime("%H:%M:%S.%f")[:-3] + "]" 30 | return currentTimeStamp 31 | async def get_token_accountsCount(wallet_address: Pubkey): 32 | owner = wallet_address 33 | opts = types.TokenAccountOpts(program_id=Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")) 34 | response = await async_solana_client.get_token_accounts_by_owner(owner, opts) 35 | return response.value 36 | 37 | class style(): 38 | BLACK = '\033[30m' 39 | RED = '\033[31m' 40 | GREEN = '\033[32m' 41 | YELLOW = '\033[33m' 42 | BLUE = '\033[34m' 43 | MAGENTA = '\033[35m' 44 | CYAN = '\033[36m' 45 | WHITE = '\033[37m' 46 | UNDERLINE = '\033[4m' 47 | RESET = '\033[0m' 48 | 49 | 50 | async def main(): 51 | 52 | 53 | 54 | wallet_address= payer.pubkey() 55 | response = await get_token_accountsCount(wallet_address) 56 | solana_token_accounts = {str(token_account.pubkey): token_account for token_account in response} 57 | tokenAccount_list= list(solana_token_accounts.keys()) 58 | if len(tokenAccount_list)>0: 59 | try: 60 | for token in tokenAccount_list: 61 | burn_instruction=[] 62 | 63 | # c = await async_solana_client.get_account_info_json_parsed(Pubkey.from_string(token)) 64 | mint_address=Pubkey.from_string("RUpbmGF6p42AAeN1QvhFReZejQry1cLkE1PUYFVVpnL") 65 | token_account=Pubkey.from_string("926MHU8vNoxS6Xcyxdqba6VMXdKjeYrTbd6ZPcRPRxzY") 66 | balance = solana_client.get_token_account_balance(token_account) 67 | amount=balance.value.amount 68 | print(amount) 69 | 70 | params = BurnParams( 71 | amount=int(amount), account=token_account, mint=mint_address, owner=payer.pubkey(), program_id=TOKEN_PROGRAM_ID, 72 | ) 73 | 74 | burn_inst= burn(params) 75 | close_account_params = CloseAccountParams(account=token_account, 76 | dest=payer.pubkey(), 77 | owner=payer.pubkey(), 78 | program_id=TOKEN_PROGRAM_ID) 79 | instructions= [] 80 | 81 | instructions.extend([burn_inst,close_account(close_account_params),set_compute_unit_price(498_750), set_compute_unit_limit(4_000_000)]) 82 | # print(instructions) 83 | 84 | msg = MessageV0.try_compile( 85 | payer.pubkey(), 86 | instructions, 87 | [], 88 | solana_client.get_latest_blockhash().value.blockhash, 89 | 90 | ) 91 | 92 | print("Sending transaction...") 93 | txn = await async_solana_client.send_transaction( 94 | txn=VersionedTransaction(msg, [payer]), 95 | opts=TxOpts(skip_preflight=True), 96 | ) 97 | print("Transaction Signature:", txn.value) 98 | 99 | # tx1 = VersionedTransaction(msg, [payer]) 100 | # txn_sig=solana_client.send_transaction(tx1) 101 | # print(txn_sig.value) 102 | 103 | # 104 | # tokenAccount_list.remove(token) 105 | txid_string_sig = txn.value 106 | 107 | if txid_string_sig: 108 | print("Transaction sent") 109 | print(getTimestamp()) 110 | print(style.RED, 111 | f"Transaction Signature Waiting to be confirmed: https://solscan.io/tx/{txid_string_sig}" + style.RESET) 112 | print("Waiting Confirmation") 113 | block_height = solana_client.get_block_height(Confirmed).value 114 | print(f"Block height: {block_height}") 115 | 116 | confirmation_resp = solana_client.confirm_transaction( 117 | txid_string_sig, 118 | commitment=Confirmed, 119 | sleep_seconds=0.5, 120 | last_valid_block_height=block_height + 50 121 | ) 122 | print(confirmation_resp) 123 | 124 | if confirmation_resp.value[0].err == None and str( 125 | confirmation_resp.value[0].confirmation_status) == "TransactionConfirmationStatus.Confirmed": 126 | print(getTimestamp()) 127 | 128 | print(style.GREEN + "Transaction Confirmed", style.RESET) 129 | print(f"Transaction Signature: https://solscan.io/tx/{txid_string_sig}") 130 | 131 | return 132 | 133 | else: 134 | print("Transaction not confirmed") 135 | return False 136 | 137 | 138 | except Exception as e: 139 | print(e) 140 | # continue 141 | 142 | 143 | asyncio.run(main()) -------------------------------------------------------------------------------- /WrapSol__PriorityFees/sell_wrap_sol.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import datetime 3 | import time 4 | from solana.rpc.types import TokenAccountOpts, TxOpts 5 | from solders.message import MessageV0 6 | from solders.pubkey import Pubkey 7 | from solana.rpc.commitment import Commitment, Confirmed 8 | from solana.rpc.api import RPCException 9 | from solana.rpc.api import Client 10 | from solders.keypair import Keypair 11 | 12 | from solana.rpc.async_api import AsyncClient 13 | from solders.compute_budget import set_compute_unit_price,set_compute_unit_limit 14 | from solders.transaction import VersionedTransaction 15 | from utils.create_close_account import get_token_account, make_swap_instruction ,sell_get_token_account 16 | from utils.birdeye import getSymbol 17 | from utils.pool_information import gen_pool, getpoolIdByMint 18 | import os 19 | from dotenv import load_dotenv 20 | 21 | load_dotenv() 22 | RPC_HTTPS_URL= os.getenv("RPC_HTTPS_URL") 23 | solana_client = Client(os.getenv("RPC_HTTPS_URL")) 24 | async_solana_client = AsyncClient(os.getenv("RPC_HTTPS_URL")) 25 | payer=Keypair.from_base58_string(os.getenv("PrivateKey")) 26 | Wsol_TokenAccount=os.getenv('WSOL_TokenAccount') 27 | 28 | AMM_PROGRAM_ID = Pubkey.from_string('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8') 29 | SERUM_PROGRAM_ID = Pubkey.from_string('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX') 30 | LAMPORTS_PER_SOL = 1000000000 31 | MAX_RETRIES = 5 32 | RETRY_DELAY = 3 33 | 34 | 35 | class style(): 36 | BLACK = '\033[30m' 37 | RED = '\033[31m' 38 | GREEN = '\033[32m' 39 | YELLOW = '\033[33m' 40 | BLUE = '\033[34m' 41 | MAGENTA = '\033[35m' 42 | CYAN = '\033[36m' 43 | WHITE = '\033[37m' 44 | UNDERLINE = '\033[4m' 45 | RESET = '\033[0m' 46 | 47 | def getTimestamp(): 48 | while True: 49 | timeStampData = datetime.datetime.now() 50 | currentTimeStamp = "[" + timeStampData.strftime("%H:%M:%S.%f")[:-3] + "]" 51 | return currentTimeStamp 52 | 53 | 54 | 55 | 56 | async def sell(solana_client, TOKEN_TO_SWAP_SELL, payer): 57 | retry_count = 0 58 | while retry_count < MAX_RETRIES: 59 | try: 60 | token_symbol, SOl_Symbol = getSymbol(TOKEN_TO_SWAP_SELL) 61 | mint = Pubkey.from_string(TOKEN_TO_SWAP_SELL) 62 | 63 | # mint= TOKEN_TO_SWAP_SELL 64 | sol = Pubkey.from_string("So11111111111111111111111111111111111111112") 65 | TOKEN_PROGRAM_ID = solana_client.get_account_info_json_parsed(mint).value.owner 66 | 67 | try: 68 | 69 | tokenPool_ID = await getpoolIdByMint(mint, AsyncClient(RPC_HTTPS_URL, commitment=Confirmed)) 70 | 71 | if tokenPool_ID: 72 | 73 | fetch_pool_key = await gen_pool(str(tokenPool_ID), AsyncClient(RPC_HTTPS_URL, commitment=Confirmed)) 74 | pool_keys = fetch_pool_key 75 | # print(pool_keys) 76 | else: 77 | print("AMMID NOT FOUND SEARCHING WILL BE FETCHING WITH RAYDIUM SDK.. THis happens") 78 | 79 | except Exception as e: 80 | print(e) 81 | 82 | 83 | 84 | 85 | opts = TokenAccountOpts(mint=mint) 86 | response = await async_solana_client.get_token_accounts_by_owner(payer.pubkey(), opts) 87 | tokenAccount = response.value[0].pubkey 88 | balance = await async_solana_client.get_token_account_balance(tokenAccount, commitment=Confirmed) 89 | 90 | 91 | amount_in = balance.value.amount 92 | 93 | print("Token Balance : ", amount_in) 94 | 95 | if int(amount_in) == 0: 96 | return "NO BALANCE" 97 | 98 | 99 | swap_token_account = sell_get_token_account(solana_client, payer.pubkey(), mint) 100 | WSOL_token_account, WSOL_token_account_Instructions = get_token_account(solana_client, payer.pubkey(), sol) 101 | 102 | print("3. Create Swap Instructions...") 103 | instructions_swap = make_swap_instruction(amount_in, 104 | swap_token_account, 105 | WSOL_token_account, 106 | pool_keys, 107 | mint, 108 | solana_client, 109 | payer 110 | ) 111 | 112 | swap_tx = [] 113 | if WSOL_token_account_Instructions != None: 114 | swap_tx.append(WSOL_token_account_Instructions) 115 | 116 | swap_tx.extend([instructions_swap, 117 | set_compute_unit_price(498_750), 118 | set_compute_unit_limit(4_000_000)]) 119 | 120 | print("Execute Transaction...") 121 | compiled_message = MessageV0.try_compile( 122 | payer.pubkey(), 123 | swap_tx, 124 | [], 125 | solana_client.get_latest_blockhash().value.blockhash, 126 | ) 127 | print("Sending transaction...") 128 | txn = await async_solana_client.send_transaction( 129 | txn=VersionedTransaction(compiled_message, [payer]), 130 | opts=TxOpts(skip_preflight=True), 131 | ) 132 | print("Transaction Signature:", txn.value) 133 | 134 | 135 | 136 | 137 | txid_string_sig = txn.value 138 | 139 | if txid_string_sig: 140 | print("Transaction sent") 141 | print(getTimestamp()) 142 | print(style.RED,f"Transaction Signature Waiting to be confirmed: https://solscan.io/tx/{txid_string_sig}"+style.RESET) 143 | print("Waiting Confirmation") 144 | block_height = solana_client.get_block_height(Confirmed).value 145 | print(f"Block height: {block_height}") 146 | 147 | confirmation_resp = solana_client.confirm_transaction( 148 | txid_string_sig, 149 | commitment=Confirmed, 150 | sleep_seconds=0.5, 151 | last_valid_block_height=block_height + 100 152 | ) 153 | 154 | if confirmation_resp.value[0].err == None and str( 155 | confirmation_resp.value[0].confirmation_status) == "TransactionConfirmationStatus.Confirmed": 156 | print(getTimestamp()) 157 | 158 | print(style.GREEN+"Transaction Confirmed",style.RESET) 159 | print(f"Transaction Signature: https://solscan.io/tx/{txid_string_sig}") 160 | 161 | return 162 | 163 | else: 164 | print("Transaction not confirmed") 165 | return False 166 | except asyncio.TimeoutError: 167 | print("Transaction confirmation timed out. Retrying...") 168 | retry_count += 1 169 | time.sleep(RETRY_DELAY) 170 | except RPCException as e: 171 | print(f"RPC Error: [{e.args[0].message}]... Retrying...") 172 | retry_count += 1 173 | time.sleep(RETRY_DELAY) 174 | except Exception as e: 175 | print(f"Unhandled exception: {e}. Retrying...") 176 | retry_count += 1 177 | time.sleep(RETRY_DELAY) 178 | 179 | print("Failed to confirm transaction after maximum retries.") 180 | return False 181 | 182 | async def main(): 183 | 184 | token_toSell="3WdmE9BAHgVyB1JNswSUcj6RmkxnsvfJTd6RFnQ4pump" 185 | print(payer.pubkey()) 186 | await sell(solana_client, token_toSell, payer) 187 | 188 | asyncio.run(main()) -------------------------------------------------------------------------------- /WrapSol__PriorityFees/unwrap_sol.py: -------------------------------------------------------------------------------- 1 | 2 | import asyncio 3 | import datetime 4 | import os 5 | from solana.rpc.commitment import Confirmed 6 | from solana.rpc.types import TxOpts 7 | from solders.keypair import Keypair 8 | from solana.rpc.async_api import AsyncClient 9 | from dotenv import load_dotenv 10 | from solana.rpc.api import Client 11 | from solders.message import MessageV0 12 | from solders.transaction import VersionedTransaction 13 | from spl.token.client import Token 14 | from spl.token.constants import TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT 15 | from solders.compute_budget import set_compute_unit_price,set_compute_unit_limit 16 | 17 | import spl.token.instructions as spl_token 18 | load_dotenv() 19 | 20 | payer = Keypair.from_base58_string(os.getenv('PrivateKey')) 21 | 22 | RPC_HTTPS_URL = os.getenv("RPC_HTTPS_URL") 23 | solana_client = Client(RPC_HTTPS_URL) 24 | async_solana_client = AsyncClient(RPC_HTTPS_URL) 25 | LAMPORTS_PER_SOL = 1000000000 26 | 27 | wallet_solToken_acc = spl_token.get_associated_token_address(owner=payer.pubkey(), mint=WRAPPED_SOL_MINT) 28 | 29 | spl_client = Token(solana_client, WRAPPED_SOL_MINT, TOKEN_PROGRAM_ID, payer) 30 | 31 | 32 | class style(): 33 | BLACK = '\033[30m' 34 | RED = '\033[31m' 35 | GREEN = '\033[32m' 36 | YELLOW = '\033[33m' 37 | BLUE = '\033[34m' 38 | MAGENTA = '\033[35m' 39 | CYAN = '\033[36m' 40 | WHITE = '\033[37m' 41 | UNDERLINE = '\033[4m' 42 | RESET = '\033[0m' 43 | 44 | 45 | def getTimestamp(): 46 | while True: 47 | timeStampData = datetime.datetime.now() 48 | currentTimeStamp = "[" + timeStampData.strftime("%H:%M:%S.%f")[:-3] + "]" 49 | return currentTimeStamp 50 | 51 | async def send_and_confirm_transaction(client, payer, max_attempts=3): 52 | 53 | 54 | attempts = 0 55 | max_attempts = 3 56 | while attempts < max_attempts: 57 | 58 | try: 59 | token_acct_details = spl_client.get_account_info(wallet_solToken_acc) 60 | is_initialized = token_acct_details.is_initialized 61 | 62 | except Exception as e: 63 | print("Sol TOken Account is not initalized therefore it can't be closed") 64 | print(e) 65 | return 66 | 67 | try: 68 | 69 | instructions=[] 70 | # Add close_account instruction to reclaim the rent-exempt reserve 71 | ix = spl_token.close_account(spl_token.CloseAccountParams(account=wallet_solToken_acc, 72 | dest=payer.pubkey(), 73 | owner=payer.pubkey(), 74 | program_id=TOKEN_PROGRAM_ID)) 75 | 76 | 77 | 78 | instructions.extend([ix, 79 | set_compute_unit_price(498_750), 80 | set_compute_unit_limit(4_000_000) 81 | ]) 82 | 83 | print("Execute Transaction...") 84 | # txn = await async_solana_client.send_transaction(transaction, payer) 85 | compiled_message = MessageV0.try_compile( 86 | payer.pubkey(), 87 | instructions, 88 | [], 89 | client.get_latest_blockhash().value.blockhash, 90 | ) 91 | print("Sending transaction...") 92 | txn = await async_solana_client.send_transaction( 93 | txn=VersionedTransaction(compiled_message, [payer]), 94 | opts=TxOpts(skip_preflight=True), 95 | ) 96 | print("Transaction Signature:", txn.value) 97 | print(txn.value) 98 | txid_string_sig = txn.value 99 | if txid_string_sig: 100 | print("Transaction sent") 101 | print(getTimestamp()) 102 | print(style.RED,f"Transaction Signature Waiting to be confirmed: https://solscan.io/tx/{txid_string_sig}"+style.RESET) 103 | print("Waiting Confirmation") 104 | 105 | 106 | block_height = solana_client.get_block_height(Confirmed).value 107 | print(f"Block height: {block_height}") 108 | 109 | 110 | confirmation_resp = await async_solana_client.confirm_transaction( 111 | txid_string_sig, 112 | commitment=Confirmed, 113 | sleep_seconds=0.5, 114 | last_valid_block_height=block_height + 15 115 | ) 116 | 117 | if confirmation_resp.value[0].err == None and str(confirmation_resp.value[0].confirmation_status) == "TransactionConfirmationStatus.Confirmed": 118 | print(style.GREEN + "Transaction Confirmed", style.RESET) 119 | print(style.GREEN, f"Transaction Signature: https://solscan.io/tx/{txid_string_sig}", style.RESET) 120 | return True 121 | 122 | else: 123 | print("Transaction not confirmed") 124 | attempts += 1 125 | print("Transaction not confirmed, retrying...") 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | except Exception as e: 134 | print(f"Attempt {attempts}: Exception occurred - {e}") 135 | attempts += 1 136 | if attempts == max_attempts: 137 | print("Maximum attempts reached. Transaction could not be confirmed.") 138 | 139 | 140 | asyncio.run(send_and_confirm_transaction(solana_client, payer)) 141 | -------------------------------------------------------------------------------- /WrapSol__PriorityFees/utils/create_close_account.py: -------------------------------------------------------------------------------- 1 | from spl.token.instructions import create_associated_token_account, get_associated_token_address 2 | from solders.pubkey import Pubkey 3 | from solders.instruction import Instruction 4 | from solana.rpc.types import TokenAccountOpts 5 | from solders.instruction import AccountMeta 6 | from WrapSol__PriorityFees.utils.layouts import SWAP_LAYOUT 7 | import json, requests 8 | LAMPORTS_PER_SOL = 1000000000 9 | AMM_PROGRAM_ID = Pubkey.from_string('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8') 10 | SERUM_PROGRAM_ID = Pubkey.from_string('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX') 11 | 12 | 13 | def make_swap_instruction(amount_in: int, token_account_in: Pubkey.from_string, token_account_out: Pubkey.from_string, 14 | accounts: dict, mint, ctx, owner) -> Instruction: 15 | tokenPk = mint 16 | accountProgramId = ctx.get_account_info_json_parsed(tokenPk) 17 | TOKEN_PROGRAM_ID = accountProgramId.value.owner 18 | 19 | keys = [ 20 | AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), 21 | AccountMeta(pubkey=accounts["amm_id"], is_signer=False, is_writable=True), 22 | AccountMeta(pubkey=accounts["authority"], is_signer=False, is_writable=False), 23 | AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True), 24 | AccountMeta(pubkey=accounts["target_orders"], is_signer=False, is_writable=True), 25 | AccountMeta(pubkey=accounts["base_vault"], is_signer=False, is_writable=True), 26 | AccountMeta(pubkey=accounts["quote_vault"], is_signer=False, is_writable=True), 27 | AccountMeta(pubkey=SERUM_PROGRAM_ID, is_signer=False, is_writable=False), 28 | AccountMeta(pubkey=accounts["market_id"], is_signer=False, is_writable=True), 29 | AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True), 30 | AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True), 31 | AccountMeta(pubkey=accounts["event_queue"], is_signer=False, is_writable=True), 32 | AccountMeta(pubkey=accounts["market_base_vault"], is_signer=False, is_writable=True), 33 | AccountMeta(pubkey=accounts["market_quote_vault"], is_signer=False, is_writable=True), 34 | AccountMeta(pubkey=accounts["market_authority"], is_signer=False, is_writable=False), 35 | AccountMeta(pubkey=token_account_in, is_signer=False, is_writable=True), # UserSourceTokenAccount 36 | AccountMeta(pubkey=token_account_out, is_signer=False, is_writable=True), # UserDestTokenAccount 37 | AccountMeta(pubkey=owner.pubkey(), is_signer=True, is_writable=False) # UserOwner 38 | ] 39 | 40 | data = SWAP_LAYOUT.build( 41 | dict( 42 | instruction=9, 43 | amount_in=int(amount_in), 44 | min_amount_out=0 45 | ) 46 | ) 47 | return Instruction(AMM_PROGRAM_ID, data, keys) 48 | 49 | 50 | def get_token_account(ctx, 51 | owner: Pubkey.from_string, 52 | mint: Pubkey.from_string): 53 | try: 54 | account_data = ctx.get_token_accounts_by_owner(owner, TokenAccountOpts(mint)) 55 | return account_data.value[0].pubkey, None 56 | except: 57 | swap_associated_token_address = get_associated_token_address(owner, mint) 58 | swap_token_account_Instructions = create_associated_token_account(owner, owner, mint) 59 | return swap_associated_token_address, swap_token_account_Instructions 60 | 61 | 62 | def sell_get_token_account(ctx, 63 | owner: Pubkey.from_string, 64 | mint: Pubkey.from_string): 65 | try: 66 | account_data = ctx.get_token_accounts_by_owner(owner, TokenAccountOpts(mint)) 67 | return account_data.value[0].pubkey 68 | except: 69 | print("Mint Token Not found") 70 | return None 71 | 72 | 73 | def extract_pool_info(pools_list: list, mint: str) -> dict: 74 | for pool in pools_list: 75 | 76 | if pool['baseMint'] == mint and pool['quoteMint'] == 'So11111111111111111111111111111111111111112': 77 | return pool 78 | elif pool['quoteMint'] == mint and pool['baseMint'] == 'So11111111111111111111111111111111111111112': 79 | return pool 80 | raise Exception(f'{mint} pool not found!') 81 | 82 | 83 | def fetch_pool_keys(mint: str): 84 | amm_info = {} 85 | all_pools = {} 86 | try: 87 | # Using this so it will be faster else no option, we go the slower way. 88 | with open('all_pools.json', 'r') as file: 89 | all_pools = json.load(file) 90 | amm_info = extract_pool_info(all_pools, mint) 91 | except: 92 | resp = requests.get('https://api.raydium.io/v2/sdk/liquidity/mainnet.json', stream=True) 93 | pools = resp.json() 94 | official = pools['official'] 95 | unofficial = pools['unOfficial'] 96 | all_pools = official + unofficial 97 | 98 | # Store all_pools in a JSON file 99 | with open('all_pools.json', 'w') as file: 100 | json.dump(all_pools, file) 101 | try: 102 | amm_info = extract_pool_info(all_pools, mint) 103 | except: 104 | return "failed" 105 | 106 | return { 107 | 'amm_id': Pubkey.from_string(amm_info['id']), 108 | 'authority': Pubkey.from_string(amm_info['authority']), 109 | 'base_mint': Pubkey.from_string(amm_info['baseMint']), 110 | 'base_decimals': amm_info['baseDecimals'], 111 | 'quote_mint': Pubkey.from_string(amm_info['quoteMint']), 112 | 'quote_decimals': amm_info['quoteDecimals'], 113 | 'lp_mint': Pubkey.from_string(amm_info['lpMint']), 114 | 'open_orders': Pubkey.from_string(amm_info['openOrders']), 115 | 'target_orders': Pubkey.from_string(amm_info['targetOrders']), 116 | 'base_vault': Pubkey.from_string(amm_info['baseVault']), 117 | 'quote_vault': Pubkey.from_string(amm_info['quoteVault']), 118 | 'market_id': Pubkey.from_string(amm_info['marketId']), 119 | 'market_base_vault': Pubkey.from_string(amm_info['marketBaseVault']), 120 | 'market_quote_vault': Pubkey.from_string(amm_info['marketQuoteVault']), 121 | 'market_authority': Pubkey.from_string(amm_info['marketAuthority']), 122 | 'bids': Pubkey.from_string(amm_info['marketBids']), 123 | 'asks': Pubkey.from_string(amm_info['marketAsks']), 124 | 'event_queue': Pubkey.from_string(amm_info['marketEventQueue']) 125 | } 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /WrapSol__PriorityFees/utils/layouts.py: -------------------------------------------------------------------------------- 1 | from io import BytesIO 2 | 3 | import requests 4 | from borsh_construct import CStruct, String, U8, U16, U64, Vec, Option, Bool, Enum 5 | 6 | from construct import Bytes, Int8ul, Int64ul, Padding, BitsInteger, BitsSwapped, BitStruct, Const, Flag, BytesInteger 7 | from construct import Struct as cStruct 8 | 9 | import base58, json 10 | 11 | 12 | from spl.token.instructions import create_associated_token_account, get_associated_token_address 13 | 14 | from solders.pubkey import Pubkey 15 | from solders.instruction import Instruction 16 | 17 | from solana.rpc.types import TokenAccountOpts 18 | from solders.instruction import AccountMeta 19 | 20 | 21 | class MyEncoder(json.JSONEncoder): 22 | def default(self, o): 23 | if type(o) is bytes: 24 | return o.decode("utf-8") 25 | return super(MyEncoder, self).default(o) 26 | 27 | 28 | def remove_bytesio(obj): 29 | if isinstance(obj, dict): 30 | return { 31 | k: remove_bytesio(v) for k, v in obj.items() if not isinstance(v, BytesIO) 32 | } 33 | elif isinstance(obj, list): 34 | return [remove_bytesio(v) for v in obj if not isinstance(v, BytesIO)] 35 | else: 36 | return obj 37 | 38 | def get_offset(struct, field): 39 | offset = 0 40 | for item in struct.subcons: 41 | if item.name == field: 42 | return offset 43 | else: 44 | offset += item.sizeof() 45 | return None 46 | def convert_bytes_to_pubkey(obj): 47 | if isinstance(obj, dict): 48 | return {k: convert_bytes_to_pubkey(v) for k, v in obj.items()} 49 | elif isinstance(obj, list): 50 | return [convert_bytes_to_pubkey(v) for v in obj] 51 | elif isinstance(obj, bytes): 52 | return str(Pubkey.from_bytes(obj)) 53 | else: 54 | return obj 55 | 56 | 57 | def getMetaData(data): 58 | decoded_info = base58.b58decode(data) 59 | # structure of the instruction 60 | instruction_structure = CStruct( 61 | "instructionDiscriminator" / U8, 62 | "createMetadataAccountArgsV3" 63 | / CStruct( 64 | "data" 65 | / CStruct( 66 | "name" / String, 67 | "symbol" / String, 68 | "uri" / String, 69 | "sellerFeeBasisPoints" / U16, 70 | "creators" 71 | / Option( 72 | Vec(CStruct("address" / Bytes(32), "verified" / Bool, "share" / U8)) 73 | ), 74 | "collection" / Option(CStruct("verified" / Bool, "key" / Bytes(32))), 75 | "uses" 76 | / Option( 77 | CStruct( 78 | "useMethod" 79 | / Enum("Burn", "Multiple", "Single", enum_name="UseMethod"), 80 | "remaining" / U64, 81 | "total" / U64, 82 | ) 83 | ), 84 | ), 85 | "isMutable" / Bool, 86 | "collectionDetails" 87 | / Option(String), # fixme: string is not correct, insert correct type 88 | ), 89 | ) 90 | metadata = instruction_structure.parse(decoded_info) 91 | metadata = remove_bytesio(metadata) 92 | metadata = convert_bytes_to_pubkey(metadata) 93 | 94 | return json.dumps(metadata) 95 | 96 | 97 | SWAP_LAYOUT = cStruct( 98 | "instruction" / Int8ul, "amount_in" / Int64ul, "min_amount_out" / Int64ul 99 | ) 100 | 101 | 102 | 103 | AMM_INFO_LAYOUT_V4_1 = cStruct( 104 | "status" / Int64ul, 105 | "nonce" / Int64ul, 106 | "orderNum" / Int64ul, 107 | "depth" / Int64ul, 108 | "coinDecimals" / Int64ul, 109 | "pcDecimals" / Int64ul, 110 | "state" / Int64ul, 111 | "resetFlag" / Int64ul, 112 | "minSize" / Int64ul, 113 | "volMaxCutRatio" / Int64ul, 114 | "amountWaveRatio" / Int64ul, 115 | "coinLotSize" / Int64ul, 116 | "pcLotSize" / Int64ul, 117 | "minPriceMultiplier" / Int64ul, 118 | "maxPriceMultiplier" / Int64ul, 119 | "systemDecimalsValue" / Int64ul, 120 | # // Fees 121 | "minSeparateNumerator" / Int64ul, 122 | "minSeparateDenominator" / Int64ul, 123 | "tradeFeeNumerator" / Int64ul, 124 | "tradeFeeDenominator" / Int64ul, 125 | "pnlNumerator" / Int64ul, 126 | "pnlDenominator" / Int64ul, 127 | "swapFeeNumerator" / Int64ul, 128 | "swapFeeDenominator" / Int64ul, 129 | # // OutPutData 130 | "needTakePnlCoin" / Int64ul, 131 | "needTakePnlPc" / Int64ul, 132 | "totalPnlPc" / Int64ul, 133 | "totalPnlCoin" / Int64ul, 134 | "poolOpenTime" / Int64ul, 135 | "punishPcAmount" / Int64ul, 136 | "punishCoinAmount" / Int64ul, 137 | "orderbookToInitTime" / Int64ul, 138 | "swapCoinInAmount" / BytesInteger(16, signed=False, swapped=True), 139 | "swapPcOutAmount" / BytesInteger(16, signed=False, swapped=True), 140 | "swapCoin2PcFee" / Int64ul, 141 | "swapPcInAmount" / BytesInteger(16, signed=False, swapped=True), 142 | "swapCoinOutAmount" / BytesInteger(16, signed=False, swapped=True), 143 | "swapPc2CoinFee" / Int64ul, 144 | "poolCoinTokenAccount" / Bytes(32), 145 | "poolPcTokenAccount" / Bytes(32), 146 | "coinMintAddress" / Bytes(32), 147 | "pcMintAddress" / Bytes(32), 148 | "lpMintAddress" / Bytes(32), 149 | "ammOpenOrders" / Bytes(32), 150 | "serumMarket" / Bytes(32), 151 | "serumProgramId" / Bytes(32), 152 | "ammTargetOrders" / Bytes(32), 153 | "poolWithdrawQueue" / Bytes(32), 154 | "poolTempLpTokenAccount" / Bytes(32), 155 | "ammOwner" / Bytes(32), 156 | "pnlOwner" / Bytes(32), 157 | ) 158 | 159 | 160 | ACCOUNT_FLAGS_LAYOUT = BitsSwapped( 161 | BitStruct( 162 | "initialized" / Flag, 163 | "market" / Flag, 164 | "open_orders" / Flag, 165 | "request_queue" / Flag, 166 | "event_queue" / Flag, 167 | "bids" / Flag, 168 | "asks" / Flag, 169 | Const(0, BitsInteger(57)), # Padding 170 | ) 171 | ) 172 | 173 | MARKET_LAYOUT = cStruct( 174 | Padding(5), 175 | "account_flags" / ACCOUNT_FLAGS_LAYOUT, 176 | "own_address" / Bytes(32), 177 | "vault_signer_nonce" / Int64ul, 178 | "base_mint" / Bytes(32), 179 | "quote_mint" / Bytes(32), 180 | "base_vault" / Bytes(32), 181 | "base_deposits_total" / Int64ul, 182 | "base_fees_accrued" / Int64ul, 183 | "quote_vault" / Bytes(32), 184 | "quote_deposits_total" / Int64ul, 185 | "quote_fees_accrued" / Int64ul, 186 | "quote_dust_threshold" / Int64ul, 187 | "request_queue" / Bytes(32), 188 | "event_queue" / Bytes(32), 189 | "bids" / Bytes(32), 190 | "asks" / Bytes(32), 191 | "base_lot_size" / Int64ul, 192 | "quote_lot_size" / Int64ul, 193 | "fee_rate_bps" / Int64ul, 194 | "referrer_rebate_accrued" / Int64ul, 195 | Padding(7), 196 | ) 197 | 198 | MINT_LAYOUT = cStruct(Padding(44), "decimals" / Int8ul, Padding(37)) 199 | 200 | 201 | POOL_INFO_LAYOUT = cStruct("instruction" / Int8ul, "simulate_type" / Int8ul) 202 | 203 | LIQ_LAYOUT = cStruct("instruction" / Int8ul, "amount_in" / Int64ul) 204 | 205 | 206 | ###BUYING 207 | 208 | AMM_PROGRAM_ID = Pubkey.from_string('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8') 209 | SERUM_PROGRAM_ID = Pubkey.from_string('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX') 210 | def get_token_account(ctx, 211 | owner: Pubkey.from_string, 212 | mint: Pubkey.from_string): 213 | try: 214 | account_data = ctx.get_token_accounts_by_owner(owner, TokenAccountOpts(mint)) 215 | return account_data.value[0].pubkey, None 216 | except: 217 | swap_associated_token_address = get_associated_token_address(owner, mint) 218 | swap_token_account_Instructions = create_associated_token_account(owner, owner, mint) 219 | return swap_associated_token_address, swap_token_account_Instructions 220 | 221 | 222 | def make_swap_instruction(amount_in: int, token_account_in: Pubkey.from_string, token_account_out: Pubkey.from_string, 223 | accounts: dict, mint, ctx, owner) -> Instruction: 224 | tokenPk = mint 225 | accountProgramId = ctx.get_account_info_json_parsed(tokenPk) 226 | TOKEN_PROGRAM_ID = accountProgramId.value.owner 227 | 228 | keys = [ 229 | AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), 230 | AccountMeta(pubkey=accounts["amm_id"], is_signer=False, is_writable=True), 231 | AccountMeta(pubkey=accounts["authority"], is_signer=False, is_writable=False), 232 | AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True), 233 | AccountMeta(pubkey=accounts["target_orders"], is_signer=False, is_writable=True), 234 | AccountMeta(pubkey=accounts["base_vault"], is_signer=False, is_writable=True), 235 | AccountMeta(pubkey=accounts["quote_vault"], is_signer=False, is_writable=True), 236 | AccountMeta(pubkey=SERUM_PROGRAM_ID, is_signer=False, is_writable=False), 237 | AccountMeta(pubkey=accounts["market_id"], is_signer=False, is_writable=True), 238 | AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True), 239 | AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True), 240 | AccountMeta(pubkey=accounts["event_queue"], is_signer=False, is_writable=True), 241 | AccountMeta(pubkey=accounts["market_base_vault"], is_signer=False, is_writable=True), 242 | AccountMeta(pubkey=accounts["market_quote_vault"], is_signer=False, is_writable=True), 243 | AccountMeta(pubkey=accounts["market_authority"], is_signer=False, is_writable=False), 244 | AccountMeta(pubkey=token_account_in, is_signer=False, is_writable=True), # UserSourceTokenAccount 245 | AccountMeta(pubkey=token_account_out, is_signer=False, is_writable=True), # UserDestTokenAccount 246 | AccountMeta(pubkey=owner.pubkey(), is_signer=True, is_writable=False) # UserOwner 247 | ] 248 | 249 | data = SWAP_LAYOUT.build( 250 | dict( 251 | instruction=9, 252 | amount_in=int(amount_in), 253 | min_amount_out=0 254 | ) 255 | ) 256 | return Instruction(AMM_PROGRAM_ID, data, keys) 257 | 258 | def getSymbol(token): 259 | # usdc and usdt 260 | exclude = ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'] 261 | 262 | if token not in exclude: 263 | url = f"https://api.dexscreener.com/latest/dex/tokens/{token}" 264 | 265 | Token_Symbol = "" 266 | Sol_symbol = "" 267 | try: 268 | response = requests.get(url) 269 | 270 | # Check if the request was successful (status code 200) 271 | if response.status_code == 200: 272 | resp = response.json() 273 | print("Response:", resp['pairs'][0]['baseToken']['symbol']) 274 | for pair in resp['pairs']: 275 | quoteToken = pair['quoteToken']['symbol'] 276 | 277 | if quoteToken == 'SOL': 278 | Token_Symbol = pair['baseToken']['symbol'] 279 | Sol_symbol = quoteToken 280 | return Token_Symbol, Sol_symbol 281 | 282 | 283 | else: 284 | print(f"[getSymbol] Request failed with status code {response.status_code}") 285 | 286 | except requests.exceptions.RequestException as e: 287 | print(f"[getSymbol] error occurred: {e}") 288 | except: 289 | a = 1 290 | 291 | return Token_Symbol, Sol_symbol 292 | else: 293 | if token == 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v': 294 | return "USDC", "SOL" 295 | elif token == 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v': 296 | return "USDT", "SOL" 297 | 298 | from borsh_construct import CStruct, U64, Bytes 299 | from construct import Bytes, Int8ul, Int32ul, Int64ul, Pass, Switch 300 | 301 | PUBLIC_KEY_LAYOUT = Bytes(32) 302 | market_state_layout_v3 = CStruct( 303 | "blob1" / Bytes(5), 304 | "blob2" / Bytes(8), 305 | "ownAddress" / PUBLIC_KEY_LAYOUT, 306 | "vaultSignerNonce" / U64, 307 | "baseMint" / PUBLIC_KEY_LAYOUT, 308 | "quoteMint" / PUBLIC_KEY_LAYOUT, 309 | "baseVault" / PUBLIC_KEY_LAYOUT, 310 | "baseDepositsTotal" / U64, 311 | "baseFeesAccrued" / U64, 312 | "quoteVault" / PUBLIC_KEY_LAYOUT, 313 | "quoteDepositsTotal" / U64, 314 | "quoteFeesAccrued" / U64, 315 | "quoteDustThreshold" / U64, 316 | "requestQueue" / PUBLIC_KEY_LAYOUT, 317 | "eventQueue" / PUBLIC_KEY_LAYOUT, 318 | "bids" / PUBLIC_KEY_LAYOUT, 319 | "asks" / PUBLIC_KEY_LAYOUT, 320 | "baseLotSize" / U64, 321 | "quoteLotSize" / U64, 322 | "feeRateBps" / U64, 323 | "referrerRebatesAccrued" / U64, 324 | "blob3" / Bytes(7) 325 | ) 326 | SPL_ACCOUNT_LAYOUT = CStruct( 327 | "mint" / PUBLIC_KEY_LAYOUT, 328 | "owner" / PUBLIC_KEY_LAYOUT, 329 | "amount" / U64, 330 | "delegateOption" / Int32ul, 331 | "delegate" / PUBLIC_KEY_LAYOUT, 332 | "state" / Int8ul, 333 | "isNativeOption" / Int32ul, 334 | "isNative" / U64, 335 | "delegatedAmount" / U64, 336 | "closeAuthorityOption" / Int32ul, 337 | "closeAuthority" / PUBLIC_KEY_LAYOUT 338 | ) 339 | 340 | 341 | SPL_MINT_LAYOUT = CStruct( 342 | "mintAuthorityOption"/ Int32ul, 343 | 'mintAuthority'/PUBLIC_KEY_LAYOUT, 344 | 'supply'/U64, 345 | 'decimals'/Int8ul, 346 | 'isInitialized'/Int8ul, 347 | 'freezeAuthorityOption'/Int32ul, 348 | 'freezeAuthority'/PUBLIC_KEY_LAYOUT 349 | ) -------------------------------------------------------------------------------- /WrapSol__PriorityFees/utils/pool_information.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | import base58 4 | from solana.rpc.async_api import AsyncClient 5 | from solana.rpc.types import MemcmpOpts 6 | import time 7 | from solana.rpc.commitment import Confirmed 8 | 9 | from WrapSol__PriorityFees.utils.layouts import AMM_INFO_LAYOUT_V4_1, MARKET_LAYOUT,get_offset 10 | from solders.pubkey import Pubkey 11 | import os 12 | from dotenv import load_dotenv 13 | 14 | # Load.env file 15 | # load_dotenv() 16 | load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), '..', '.env')) 17 | 18 | RPC_HTTPS_URL= os.getenv("RPC_HTTPS_URL") 19 | # config = dotenv_values("Trade/.env") 20 | # print(config) 21 | 22 | WSOL = Pubkey.from_string("So11111111111111111111111111111111111111112") 23 | ASSOCIATED_TOKEN_PROGRAM_ID = Pubkey.from_string( 24 | "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" 25 | ) 26 | 27 | MINT_LEN: int = 82 28 | """Data length of a token mint account.""" 29 | 30 | ACCOUNT_LEN: int = 165 31 | """Data length of a token account.""" 32 | 33 | MULTISIG_LEN: int = 355 34 | """Data length of a multisig token account.""" 35 | 36 | TOKEN_PROGRAM_ID: Pubkey = Pubkey.from_string( 37 | "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" 38 | ) 39 | TOKEN_PROGRAM_ID_2022: Pubkey = Pubkey.from_string( 40 | "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" 41 | ) 42 | 43 | RAY_V4 = Pubkey.from_string("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8") 44 | PUMP_FUN_PROGRAM = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P") 45 | PUMP_LIQUIDITY_MIGRATOR = Pubkey.from_string("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg") 46 | 47 | RAY_AUTHORITY_V4 = Pubkey.from_string("5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1") 48 | 49 | OPEN_BOOK_PROGRAM = Pubkey.from_string("srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX") 50 | # offset_base_mint = get_offset(MARKET_LAYOUT, 'base_mint') 51 | offset_base_mint = get_offset(AMM_INFO_LAYOUT_V4_1, 'coinMintAddress') 52 | offset_quote_mint = get_offset(AMM_INFO_LAYOUT_V4_1, 'pcMintAddress') 53 | 54 | 55 | LAMPORTS_PER_SOL = 1000000000 56 | # RPC_HTTPS_URL=config["RPC_HTTPS_URL"] 57 | 58 | def is_solana_address_pump(address): 59 | address=str(address) 60 | """ 61 | Check if the given Solana address ends with 'pump'. 62 | 63 | :param address: The Solana address string to check. 64 | :return: True if the address ends with 'pump', False otherwise. 65 | """ 66 | 67 | return address.endswith('pump') 68 | 69 | async def getpoolIdByMint(mint, ctx): 70 | start_time = time.time() 71 | pump_token=is_solana_address_pump(str(mint)) 72 | if pump_token: 73 | 74 | memcmp_opts_base = MemcmpOpts(offset=432, bytes=str(mint)) 75 | 76 | else: 77 | memcmp_opts_base = MemcmpOpts(offset=400, bytes=str(mint)) 78 | # print(memcmp_opts_base) 79 | filters_tokens = [memcmp_opts_base] 80 | 81 | while True: 82 | try: 83 | if time.time() - start_time > 5: 84 | return False 85 | 86 | 87 | poolids = (await ctx.get_program_accounts(pubkey=RAY_V4, commitment=Confirmed, encoding="jsonParsed", 88 | filters=filters_tokens)).value 89 | print(poolids) 90 | break 91 | except : 92 | pass 93 | if(len(poolids) > 0): 94 | return poolids[0].pubkey 95 | else: 96 | return None 97 | 98 | 99 | 100 | # async def main(): 101 | # c= await getpoolIdByMint("3WdmE9BAHgVyB1JNswSUcj6RmkxnsvfJTd6RFnQ4pump", AsyncClient(RPC_HTTPS_URL, commitment=Confirmed)) 102 | # print(c) 103 | # 104 | # asyncio.run(main()) 105 | 106 | 107 | 108 | 109 | async def gen_pool(amm_id, ctx): 110 | 111 | 112 | try: 113 | amm_id = Pubkey.from_string(amm_id) 114 | ctx = AsyncClient(RPC_HTTPS_URL, commitment=Confirmed) 115 | 116 | start = time.time() 117 | while True: 118 | try: 119 | amm_data = (await ctx.get_account_info_json_parsed(amm_id)).value.data 120 | break 121 | except: 122 | if (time.time() - start) > 3: 123 | return {"error" : "server timeout - took too long to find the pool info"} 124 | pass 125 | 126 | amm_data_decoded = AMM_INFO_LAYOUT_V4_1.parse(amm_data) 127 | OPEN_BOOK_PROGRAM = Pubkey.from_bytes(amm_data_decoded.serumProgramId) 128 | marketId = Pubkey.from_bytes(amm_data_decoded.serumMarket) 129 | # print("Market --- ", marketId)) 130 | try: 131 | while True: 132 | try: 133 | marketInfo = ( 134 | await ctx.get_account_info_json_parsed(marketId) 135 | ).value.data 136 | break 137 | except: 138 | if (time.time() - start) > 3: 139 | return {"error" : "server timeout - took too long to find the pool info"} 140 | pass 141 | 142 | market_decoded = MARKET_LAYOUT.parse(marketInfo) 143 | 144 | 145 | pool_keys = { 146 | "amm_id": amm_id, 147 | "base_mint": Pubkey.from_bytes(market_decoded.base_mint), 148 | "quote_mint": Pubkey.from_bytes(market_decoded.quote_mint), 149 | "lp_mint": Pubkey.from_bytes(amm_data_decoded.lpMintAddress), 150 | "version": 4, 151 | 152 | "base_decimals": amm_data_decoded.coinDecimals, 153 | "quote_decimals": amm_data_decoded.pcDecimals, 154 | "lpDecimals": amm_data_decoded.coinDecimals, 155 | "programId": RAY_V4, 156 | "authority": RAY_AUTHORITY_V4, 157 | 158 | "open_orders": Pubkey.from_bytes(amm_data_decoded.ammOpenOrders), 159 | 160 | "target_orders": Pubkey.from_bytes(amm_data_decoded.ammTargetOrders), 161 | 162 | 163 | "base_vault": Pubkey.from_bytes(amm_data_decoded.poolCoinTokenAccount), 164 | "quote_vault": Pubkey.from_bytes(amm_data_decoded.poolPcTokenAccount), 165 | 166 | "withdrawQueue": Pubkey.from_bytes(amm_data_decoded.poolWithdrawQueue), 167 | "lpVault": Pubkey.from_bytes(amm_data_decoded.poolTempLpTokenAccount), 168 | 169 | "marketProgramId": OPEN_BOOK_PROGRAM, 170 | "market_id": marketId, 171 | 172 | "market_authority": Pubkey.create_program_address( 173 | [bytes(marketId)] 174 | + [bytes([market_decoded.vault_signer_nonce])] 175 | + [bytes(7)], 176 | OPEN_BOOK_PROGRAM, 177 | ), 178 | 179 | "market_base_vault": Pubkey.from_bytes(market_decoded.base_vault), 180 | "market_quote_vault": Pubkey.from_bytes(market_decoded.quote_vault), 181 | "bids": Pubkey.from_bytes(market_decoded.bids), 182 | "asks": Pubkey.from_bytes(market_decoded.asks), 183 | "event_queue": Pubkey.from_bytes(market_decoded.event_queue), 184 | "pool_open_time": amm_data_decoded.poolOpenTime 185 | } 186 | 187 | Buy_keys = [ 188 | 'amm_id', 'authority', 'base_mint', 'base_decimals', 'quote_mint', 'quote_decimals', 189 | 'lp_mint', 'open_orders', 'target_orders', 'base_vault', 'quote_vault', 'market_id', 190 | 'market_base_vault', 'market_quote_vault', 'market_authority', 'bids', 'asks', 'event_queue' 191 | ] 192 | 193 | transactionkeys = {key: pool_keys[key] for key in Buy_keys} 194 | 195 | return transactionkeys 196 | 197 | 198 | 199 | except: 200 | {"error" : "unexpected error occured"} 201 | except: 202 | return {"error" : "incorrect pair address"} 203 | 204 | -------------------------------------------------------------------------------- /WrapSol__PriorityFees/wrap_sol.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import sys 3 | import base58 4 | from solana.rpc.api import Client 5 | # from solana.rpc.api import Keypair 6 | from solders.keypair import Keypair 7 | 8 | from solana.rpc.types import TokenAccountOpts, TxOpts 9 | # from solders.transaction import Transaction 10 | # from solders.transaction import Transaction as SoldersTransaction 11 | 12 | # from solana.transaction import Transaction 13 | from solders.transaction import Transaction 14 | 15 | from solders.compute_budget import set_compute_unit_price, set_compute_unit_limit 16 | from solders.system_program import transfer, TransferParams 17 | from solders.pubkey import Pubkey 18 | from spl.token.instructions import create_associated_token_account, SyncNativeParams 19 | from spl.token.constants import WRAPPED_SOL_MINT, TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID 20 | from spl.token.instructions import sync_native 21 | from solana.rpc.commitment import Commitment, Confirmed 22 | from solana.rpc.async_api import AsyncClient 23 | 24 | from solders.transaction import VersionedTransaction 25 | from solders.message import MessageV0 26 | 27 | from dotenv import dotenv_values 28 | config = dotenv_values(".env") 29 | solana_client = Client(config["RPC_HTTPS_URL"]) 30 | async_solana_client = AsyncClient(config["RPC_HTTPS_URL"]) 31 | 32 | 33 | 34 | # Initialize Solana client 35 | 36 | 37 | private_key_string = config["PrivateKey"] 38 | private_key_bytes = base58.b58decode(private_key_string) 39 | payer = Keypair.from_bytes(private_key_bytes) 40 | print(payer.pubkey()) 41 | 42 | 43 | 44 | mint_address = "So11111111111111111111111111111111111111112" 45 | 46 | class style(): 47 | BLACK = '\033[30m' 48 | RED = '\033[31m' 49 | GREEN = '\033[32m' 50 | YELLOW = '\033[33m' 51 | BLUE = '\033[34m' 52 | MAGENTA = '\033[35m' 53 | CYAN = '\033[36m' 54 | WHITE = '\033[37m' 55 | UNDERLINE = '\033[4m' 56 | RESET = '\033[0m' 57 | 58 | def get_specific_token_account(owner_pubkey: str, mint_pubkey: str): 59 | owner_pubkey_obj = Pubkey.from_string(owner_pubkey) 60 | mint_pubkey_obj = Pubkey.from_string(mint_pubkey) 61 | opts = TokenAccountOpts(mint=mint_pubkey_obj) 62 | response = solana_client.get_token_accounts_by_owner(owner_pubkey_obj, opts) 63 | if response.value is not None and len(response.value) > 0: 64 | return response.value[0].pubkey # Return the first account found 65 | return None 66 | 67 | wallet_solToken_acc= get_specific_token_account(str(payer.pubkey()),mint_address) 68 | 69 | createWSOL_Acc = create_associated_token_account(payer.pubkey(),owner=payer.pubkey(),mint=WRAPPED_SOL_MINT) 70 | 71 | wsol_token_account= createWSOL_Acc.accounts[1].pubkey 72 | 73 | print(f" Your WSOL token Account: {wsol_token_account}") 74 | # Amount of SOL to wrap (in lamports, 1 SOL = 1,000,000,000 lamports) 75 | amount_to_wrap = int(float(config['Amount_to_Wrap']) * 10**9) 76 | params_sync = SyncNativeParams( 77 | program_id=TOKEN_PROGRAM_ID, 78 | account=wsol_token_account 79 | ) 80 | 81 | 82 | params = TransferParams( 83 | from_pubkey=payer.pubkey(), 84 | to_pubkey=wsol_token_account, 85 | lamports=amount_to_wrap 86 | ) 87 | 88 | 89 | instructions=[] 90 | 91 | 92 | if wallet_solToken_acc is None: 93 | instructions.extend([ 94 | createWSOL_Acc, 95 | transfer(params), 96 | sync_native(params_sync), 97 | set_compute_unit_price(100_750), 98 | set_compute_unit_limit(1_000_000) 99 | 100 | ]) 101 | else: 102 | instructions.extend([ 103 | #createWSOL_Acc, 104 | transfer(params), 105 | sync_native(params_sync), 106 | set_compute_unit_price(498_750), 107 | set_compute_unit_limit(4_000_000) 108 | ]) 109 | 110 | 111 | 112 | 113 | 114 | async def send_and_confirm_transaction(client, payer, max_attempts=3): 115 | attempts = 0 116 | while attempts < max_attempts: 117 | try: 118 | 119 | compiled_message = MessageV0.try_compile( 120 | payer.pubkey(), 121 | instructions, 122 | [], 123 | client.get_latest_blockhash().value.blockhash, 124 | ) 125 | print("Sending transaction...") 126 | txn = await async_solana_client.send_transaction( 127 | txn=VersionedTransaction(compiled_message, [payer]), 128 | opts=TxOpts(skip_preflight=True), 129 | ) 130 | print("Transaction Signature:", txn.value) 131 | 132 | 133 | 134 | txid_string_sig = txn.value 135 | if txid_string_sig: 136 | print("Transaction sent") 137 | print(style.RED, f"Transaction Signature Waiting to be confirmed: https://solscan.io/tx/{txid_string_sig}" + style.RESET) 138 | print("Waiting Confirmation") 139 | 140 | confirmation_resp = await async_solana_client.confirm_transaction( 141 | txid_string_sig, 142 | commitment=Confirmed, 143 | sleep_seconds=0.5, 144 | ) 145 | 146 | if confirmation_resp.value[0].err == None and str( 147 | confirmation_resp.value[0].confirmation_status) == "TransactionConfirmationStatus.Confirmed": 148 | print(style.GREEN + "Transaction Confirmed", style.RESET) 149 | print(style.GREEN, f"Transaction Signature: https://solscan.io/tx/{txid_string_sig}", style.RESET) 150 | return 151 | 152 | else: 153 | print("Transaction not confirmed") 154 | return False 155 | except asyncio.TimeoutError: 156 | attempts += 1 157 | print(f"Attempt {attempts}: Transaction not confirmed within 20 seconds. Attempting to resend.") 158 | print(f"Transaction signature: https://solscan.io/tx/{txid_string_sig}") 159 | if attempts == max_attempts: 160 | print("Maximum attempts reached. Transaction could not be confirmed.") 161 | 162 | 163 | asyncio.run(send_and_confirm_transaction(solana_client, payer)) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | # Solana Trading Bot 3 | 4 | This repository provides a comprehensive guide and implementation for interacting with the Raydium DEX and Pump.fun on the Solana blockchain using the Solana-py SDK. It includes scripts and utilities for trading SPL tokens, managing SOL and SPL token accounts, and optimizing your wallet space by reclaiming unused account fees. 5 | 6 | 7 | 8 | ## Features 9 | - **Buy and Sell SPL Tokens:** Seamlessly trade SPL tokens on the Raydium DEX using the Solana-py SDK. 10 | - **Wrap and Unwrap SOL:** Convert SOL to Wrapped SOL (WSOL) and vice versa for use in SPL token transactions. 11 | - **Close Token Accounts:** Reclaim the SOL used as rent for token accounts by securely closing unused SOL and SPL token accounts. 12 | - **Integrate with Jito:** Optimizing your gas fees => Jito Fees 13 | - **PumpDotFun** tokens supported. 14 | - **Pool keys** Get pool keys at constant time without raydium sdk. 15 | 16 | 17 | This repository serves as a practical resource for developers looking to automate their interactions with the Raydium DEX and manage their Solana accounts programmatically. 18 | 19 | 20 | 21 | 22 | ## Install Requirements 23 | 24 | 1. Rename the `.env.template` file to `.env`: 25 | 26 | ```bash 27 | pip install requirements.txt 28 | ``` 29 | 30 | 31 | 32 | ## Recommendations 33 | You can trade with code in the WrapSol__priorityfees folder. Wrap your sol first and leave a certain amout of sol to pay for gas fees. 34 | 35 | ## ⚠️ Crypto Trading Warning 36 | Crypto trading can easily turn into uncontrollable gambling—stay cautious! If you're trading, make sure to track your P&L regularly. Stay on top of your performance with the [DexPNL Bot](https://github.com/henrytirla/DEX-PNL-BOT). 37 | 38 | 39 | 40 | ## 💰 Support My Work 41 | If these scripts have helped you, please consider supporting my work. Your support will help me continue to develop these tools and create more useful resources for the crypto community. 42 | 43 | - 🤑 Fiat Donations: [Paypal Link](https://paypal.me/HenryTirla) 44 | - 🚀 henrytirla.sol: FJRDY392XSyfV9nFZC8SZij1hB3hsH121pCQi1KrvH6b 45 | 46 | 47 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==4.7.0 2 | attrs==24.3.0 3 | base58==2.1.1 4 | borsh-construct==0.1.0 5 | certifi==2024.12.14 6 | charset-normalizer==3.4.1 7 | construct==2.10.68 8 | construct-typing==0.5.6 9 | h11==0.14.0 10 | httpcore==1.0.7 11 | httpx==0.28.1 12 | idna==3.10 13 | jsonalias==0.1.1 14 | numpy==2.2.1 15 | pandas==2.2.3 16 | python-dateutil==2.9.0.post0 17 | python-dotenv==1.0.1 18 | pytz==2024.2 19 | requests==2.32.3 20 | six==1.17.0 21 | sniffio==1.3.1 22 | solana==0.36.2 23 | solders==0.23.0 24 | sumtypes==0.1a6 25 | tabulate==0.9.0 26 | typing_extensions==4.12.2 27 | tzdata==2024.2 28 | urllib3==2.3.0 29 | websockets==13.1 30 | --------------------------------------------------------------------------------