mirror of
https://github.com/chainstacklabs/pumpfun-bonkfun-bot.git
synced 2026-08-17 01:08:05 +00:00
fix: fixes in initial implementation
This commit is contained in:
@@ -3,6 +3,7 @@ import os
|
|||||||
import struct
|
import struct
|
||||||
|
|
||||||
import base58
|
import base58
|
||||||
|
from dotenv import load_dotenv
|
||||||
from solana.rpc.async_api import AsyncClient
|
from solana.rpc.async_api import AsyncClient
|
||||||
from solana.rpc.commitment import Confirmed
|
from solana.rpc.commitment import Confirmed
|
||||||
from solana.rpc.types import MemcmpOpts, TxOpts
|
from solana.rpc.types import MemcmpOpts, TxOpts
|
||||||
@@ -14,6 +15,8 @@ from solders.pubkey import Pubkey
|
|||||||
from solders.transaction import VersionedTransaction
|
from solders.transaction import VersionedTransaction
|
||||||
from spl.token.instructions import get_associated_token_address
|
from spl.token.instructions import get_associated_token_address
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
RPC_ENDPOINT = os.environ.get("SOLANA_NODE_RPC_ENDPOINT")
|
RPC_ENDPOINT = os.environ.get("SOLANA_NODE_RPC_ENDPOINT")
|
||||||
TOKEN_MINT = Pubkey.from_string("35ySx7Rt3RqeTp75QB81FgRvPT5yDY2m5BupsUYDpump")
|
TOKEN_MINT = Pubkey.from_string("35ySx7Rt3RqeTp75QB81FgRvPT5yDY2m5BupsUYDpump")
|
||||||
PRIVATE_KEY = base58.b58decode(os.environ.get("SOLANA_PRIVATE_KEY"))
|
PRIVATE_KEY = base58.b58decode(os.environ.get("SOLANA_PRIVATE_KEY"))
|
||||||
@@ -32,6 +35,9 @@ SYSTEM_TOKEN_PROGRAM = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss62
|
|||||||
SYSTEM_PROGRAM = Pubkey.from_string("11111111111111111111111111111111")
|
SYSTEM_PROGRAM = Pubkey.from_string("11111111111111111111111111111111")
|
||||||
SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM = Pubkey.from_string("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")
|
SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM = Pubkey.from_string("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")
|
||||||
PUMP_SWAP_EVENT_AUTHORITY = Pubkey.from_string("GS4CU59F31iL7aR2Q8zVS8DRrcRnXX1yjQ66TqNVQnaR")
|
PUMP_SWAP_EVENT_AUTHORITY = Pubkey.from_string("GS4CU59F31iL7aR2Q8zVS8DRrcRnXX1yjQ66TqNVQnaR")
|
||||||
|
LAMPORTS_PER_SOL = 1_000_000_000
|
||||||
|
COMPUTE_UNIT_PRICE = 10_000
|
||||||
|
COMPUTE_UNIT_BUDGET = 100_000
|
||||||
|
|
||||||
|
|
||||||
async def get_market_address_by_base_mint(client: AsyncClient, base_mint_address: Pubkey, amm_program_id: Pubkey) -> Pubkey:
|
async def get_market_address_by_base_mint(client: AsyncClient, base_mint_address: Pubkey, amm_program_id: Pubkey) -> Pubkey:
|
||||||
@@ -88,29 +94,17 @@ async def get_market_data(client: AsyncClient, market_address: Pubkey):
|
|||||||
|
|
||||||
return parsed_data
|
return parsed_data
|
||||||
|
|
||||||
async def get_token_price_from_pool(client: AsyncClient, pool_base_token_account: Pubkey, pool_quote_token_account: Pubkey) -> float:
|
async def calculate_token_pool_price(client: AsyncClient, pool_base_token_account: Pubkey, pool_quote_token_account: Pubkey) -> float:
|
||||||
base_balance_resp = await client.get_token_account_balance(pool_base_token_account)
|
base_balance_resp = await client.get_token_account_balance(pool_base_token_account)
|
||||||
quote_balance_resp = await client.get_token_account_balance(pool_quote_token_account)
|
quote_balance_resp = await client.get_token_account_balance(pool_quote_token_account)
|
||||||
|
|
||||||
base_amount = float(base_balance_resp.value.ui_amount)
|
base_amount = float(base_balance_resp.value.ui_amount)
|
||||||
quote_amount = float(quote_balance_resp.value.ui_amount)
|
quote_amount = float(quote_balance_resp.value.ui_amount)
|
||||||
token_price = base_amount / quote_amount
|
token_price = quote_amount / base_amount
|
||||||
|
|
||||||
return token_price, base_amount, quote_amount
|
return token_price
|
||||||
|
|
||||||
async def calculate_sol_amount_from_token(client: AsyncClient, token_amount: float, pool_base_token_account: Pubkey, pool_quote_token_account: Pubkey) -> float:
|
def create_ata_idempotent_ix(payer_pubkey, owner_pubkey) -> Instruction:
|
||||||
_, base_amount, quote_amount = await get_token_price_from_pool(client, pool_base_token_account, pool_quote_token_account)
|
|
||||||
|
|
||||||
k = base_amount * quote_amount
|
|
||||||
new_base_amount = base_amount + token_amount
|
|
||||||
new_quote_amount = k / new_base_amount
|
|
||||||
sol_amount = quote_amount - new_quote_amount
|
|
||||||
|
|
||||||
sol_received = sol_amount * (1 - 0.25 / 100)
|
|
||||||
|
|
||||||
return sol_received
|
|
||||||
|
|
||||||
def create_ata_idempotent_ix(payer_pubkey, owner_pubkey):
|
|
||||||
"""
|
"""
|
||||||
Create an instruction to create an Associated Token Account for WSOL in an idempotent way.
|
Create an instruction to create an Associated Token Account for WSOL in an idempotent way.
|
||||||
"""
|
"""
|
||||||
@@ -131,32 +125,26 @@ async def sell_pump_swap(client: AsyncClient, pump_fun_amm_pool: Pubkey, payer:
|
|||||||
user_quote_token_account: Pubkey, pool_base_token_account: Pubkey,
|
user_quote_token_account: Pubkey, pool_base_token_account: Pubkey,
|
||||||
pool_quote_token_account: Pubkey, slippage: float = 0.25):
|
pool_quote_token_account: Pubkey, slippage: float = 0.25):
|
||||||
|
|
||||||
token_balance = await client.get_token_account_balance(user_quote_token_account)
|
# Get token balance
|
||||||
|
token_balance = int((await client.get_token_account_balance(user_base_token_account)).value.amount)
|
||||||
token_balance_decimal = token_balance / 10**TOKEN_DECIMALS
|
token_balance_decimal = token_balance / 10**TOKEN_DECIMALS
|
||||||
print(f"Token balance: {token_balance_decimal}")
|
print(f"Token balance: {token_balance_decimal}")
|
||||||
if token_balance == 0:
|
if token_balance == 0:
|
||||||
print("No tokens to sell.")
|
print("No tokens to sell.")
|
||||||
return
|
return
|
||||||
|
|
||||||
token_price, base_amount, quote_amount = await get_token_price_from_pool(client, pool_base_token_account, pool_quote_token_account)
|
# Calculate token price
|
||||||
|
token_price_sol = await calculate_token_pool_price(client, pool_base_token_account, pool_quote_token_account)
|
||||||
|
print(f"Price per Token: {token_price_sol:.20f} SOL")
|
||||||
|
|
||||||
k = base_amount * quote_amount
|
# Calculate minimum SOL output
|
||||||
new_quote_amount = quote_amount + token_balance_decimal
|
amount = token_balance
|
||||||
new_base_amount = k / new_quote_amount
|
min_sol_output = float(token_balance_decimal) * float(token_price_sol)
|
||||||
expected_sol_amount = base_amount - new_base_amount
|
slippage_factor = 1 - slippage
|
||||||
|
min_sol_output = int((min_sol_output * slippage_factor) * LAMPORTS_PER_SOL)
|
||||||
expected_sol_after_fee = expected_sol_amount * (1 - 0.25 / 100)
|
|
||||||
min_sol_output_float = expected_sol_after_fee * (1 - slippage)
|
|
||||||
min_sol_output = min(int(min_sol_output_float * 10**9), 18_446_744_073_709_551_615)
|
|
||||||
|
|
||||||
print(f"Selling {token_balance_decimal} tokens")
|
print(f"Selling {token_balance_decimal} tokens")
|
||||||
print(f"Expected SOL: {expected_sol_after_fee:.9f}")
|
print(f"Minimum SOL output: {min_sol_output / LAMPORTS_PER_SOL:.10f} SOL")
|
||||||
print(f"Min SOL with {slippage*100}% slippage: {min_sol_output/10**9:.9f}")
|
|
||||||
|
|
||||||
print(f"Token balance to sell (raw): {token_balance}")
|
|
||||||
print(f"Min SOL output (raw): {min_sol_output}")
|
|
||||||
|
|
||||||
data = SELL_DISCRIMINATOR + struct.pack("<Q", token_balance) + struct.pack("<Q", min_sol_output)
|
|
||||||
|
|
||||||
accounts = [
|
accounts = [
|
||||||
AccountMeta(pubkey=pump_fun_amm_pool, is_signer=False, is_writable=False),
|
AccountMeta(pubkey=pump_fun_amm_pool, is_signer=False, is_writable=False),
|
||||||
@@ -178,8 +166,11 @@ async def sell_pump_swap(client: AsyncClient, pump_fun_amm_pool: Pubkey, payer:
|
|||||||
AccountMeta(pubkey=PUMP_AMM_PROGRAM_ID, is_signer=False, is_writable=False),
|
AccountMeta(pubkey=PUMP_AMM_PROGRAM_ID, is_signer=False, is_writable=False),
|
||||||
]
|
]
|
||||||
|
|
||||||
compute_limit_ix = set_compute_unit_limit(87_122)
|
data = SELL_DISCRIMINATOR + struct.pack("<Q", amount) + struct.pack("<Q", min_sol_output)
|
||||||
compute_price_ix = set_compute_unit_price(10_000)
|
|
||||||
|
compute_limit_ix = set_compute_unit_limit(COMPUTE_UNIT_BUDGET)
|
||||||
|
compute_price_ix = set_compute_unit_price(COMPUTE_UNIT_PRICE)
|
||||||
|
|
||||||
create_ata_ix = create_ata_idempotent_ix(
|
create_ata_ix = create_ata_idempotent_ix(
|
||||||
payer_pubkey=payer.pubkey(),
|
payer_pubkey=payer.pubkey(),
|
||||||
owner_pubkey=payer.pubkey()
|
owner_pubkey=payer.pubkey()
|
||||||
@@ -210,6 +201,7 @@ async def sell_pump_swap(client: AsyncClient, pump_fun_amm_pool: Pubkey, payer:
|
|||||||
tx_hash = tx_sig.value
|
tx_hash = tx_sig.value
|
||||||
print(f"Transaction sent: https://explorer.solana.com/tx/{tx_hash}")
|
print(f"Transaction sent: https://explorer.solana.com/tx/{tx_hash}")
|
||||||
await client.confirm_transaction(tx_hash, commitment="confirmed")
|
await client.confirm_transaction(tx_hash, commitment="confirmed")
|
||||||
|
|
||||||
print("Transaction confirmed")
|
print("Transaction confirmed")
|
||||||
return tx_hash
|
return tx_hash
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -219,18 +211,18 @@ async def sell_pump_swap(client: AsyncClient, pump_fun_amm_pool: Pubkey, payer:
|
|||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
async with AsyncClient(RPC_ENDPOINT) as client:
|
async with AsyncClient(RPC_ENDPOINT) as client:
|
||||||
market_address = await get_market_address_by_base_mint(client, TOKEN_MINT)
|
market_address = await get_market_address_by_base_mint(client, TOKEN_MINT, PUMP_AMM_PROGRAM_ID)
|
||||||
market_data = await get_market_data(client, market_address)
|
market_data = await get_market_data(client, market_address)
|
||||||
|
|
||||||
await sell_pump_swap(
|
await sell_pump_swap(
|
||||||
client,
|
client,
|
||||||
PUMP_AMM_PROGRAM_ID,
|
PUMP_AMM_PROGRAM_ID,
|
||||||
PAYER,
|
PAYER,
|
||||||
Pubkey.from_string(TOKEN_MINT),
|
TOKEN_MINT,
|
||||||
await get_associated_token_address(PAYER, TOKEN_MINT),
|
get_associated_token_address(PAYER.pubkey(), TOKEN_MINT),
|
||||||
await get_associated_token_address(PAYER, SOL),
|
get_associated_token_address(PAYER.pubkey(), SOL),
|
||||||
market_data["pool_base_token_account"],
|
Pubkey.from_string(market_data["pool_base_token_account"]),
|
||||||
market_data["pool_quote_token_account"],
|
Pubkey.from_string(market_data["pool_quote_token_account"]),
|
||||||
SLIPPAGE
|
SLIPPAGE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user