diff --git a/README.md b/README.md index 00a1c61..2105378 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ Make sure you have the required packages installed `pip install -r requirements. Make sure you have your endpoints set up in `config.py`. -Quick note on a couple of new scripts in `/learning-examples`: +Quick note on a couple on a few new scripts in `/learning-examples`: + +*(this is basically a changelog now)* ## Bonding curve state check @@ -29,3 +31,38 @@ Note that it's using the [blockSubscribe]([url](https://docs.chainstack.com/refe To run: `python listen_to_raydium_migration.py` + +**The new two additions are based on this question [associatedBondingCurve #26](https://github.com/chainstacklabs/pump-fun-bot/issues/26)** + +You can take the compute the associatedBondingCurve address following the [Solana docs PDA](https://solana.com/docs/core/pda) description logic. Take the following as input *as seed* (order seems to matter): + +- bondingCurve address +- the Solana system token program address: `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` +- the token mint address + +And compute against the Solana system associated token account program address: `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`. + +The implications of this are kinda huge: +* you can now use `logsSubscribe` to snipe the tokens and you are not limited to the `blockSubscribe` method +* see which one is faster +* not every provider supports `blockSubscribe` on lower tier plans or at all, but everyone supports `logsSubscribe` + +The following script showcase the implementation. + +## Compute associated bonding curve + +`compute_associated_bonding_curve.py` — computes the associated bonding curve for a given token. + +To run: + +`python compute_associated_bonding_curve.py` and then enter the token mint address. + +## Listen to new direct full details + +`listen_new_direct_full_details.py` — listens to the new direct full details events and prints the signature, the token address, and the bonding curve address. + +To run: + +`python listen_new_direct_full_details.py` + +So now you can run `listen_create_from_blocksubscribe.py` and `listen_new_direct_full_details.py` at the same time and see which one is faster. \ No newline at end of file diff --git a/config.py b/config.py index ad7fa32..6c4eda6 100644 --- a/config.py +++ b/config.py @@ -19,7 +19,7 @@ SELL_SLIPPAGE = 0.2 # 20% slippage tolerance for selling # Your nodes -# You can also get a trader node https://docs.chainstack.com/docs/warp-transactions +# You can also get a trader node https://docs.chainstack.com/docs/solana-trader-nodes RPC_ENDPOINT = "SOLANA_NODE_RPC_ENDPOINT" WSS_ENDPOINT = "SOLANA_NODE_WSS_ENDPOINT" diff --git a/learning-examples/compute_associated_bonding_curve.py b/learning-examples/compute_associated_bonding_curve.py new file mode 100644 index 0000000..3caa9aa --- /dev/null +++ b/learning-examples/compute_associated_bonding_curve.py @@ -0,0 +1,62 @@ +import sys +import os +from solders.pubkey import Pubkey + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +from config import PUMP_PROGRAM + +def get_bonding_curve_address(mint: Pubkey, program_id: Pubkey) -> tuple[Pubkey, int]: + """ + Derives the bonding curve address for a given mint + """ + return Pubkey.find_program_address( + [ + b"bonding-curve", + bytes(mint) + ], + program_id + ) + +def find_associated_bonding_curve(mint: Pubkey, bonding_curve: Pubkey) -> Pubkey: + """ + Find the associated bonding curve for a given mint and bonding curve. + This uses the standard ATA derivation. + """ + from config import SYSTEM_TOKEN_PROGRAM as TOKEN_PROGRAM_ID + from config import SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM as ATA_PROGRAM_ID + + derived_address, _ = Pubkey.find_program_address( + [ + bytes(bonding_curve), + bytes(TOKEN_PROGRAM_ID), + bytes(mint), + ], + ATA_PROGRAM_ID + ) + return derived_address + +def main(): + + mint_address = input("Enter the token mint address: ") + + try: + mint = Pubkey.from_string(mint_address) + + bonding_curve_address, bump = get_bonding_curve_address(mint, PUMP_PROGRAM) + + # Calculate the associated bonding curve + associated_bonding_curve = find_associated_bonding_curve(mint, bonding_curve_address) + + print("\nResults:") + print("-" * 50) + print(f"Token Mint: {mint}") + print(f"Bonding Curve: {bonding_curve_address}") + print(f"Associated Bonding Curve: {associated_bonding_curve}") + print(f"Bonding Curve Bump: {bump}") + print("-" * 50) + + except ValueError as e: + print(f"Error: Invalid address format - {str(e)}") + +if __name__ == "__main__": + main() diff --git a/learning-examples/listen_new_direct_full_details.py b/learning-examples/listen_new_direct_full_details.py new file mode 100644 index 0000000..4904da9 --- /dev/null +++ b/learning-examples/listen_new_direct_full_details.py @@ -0,0 +1,146 @@ +import asyncio +import json +import websockets +import base58 +import base64 +import struct +import sys +import os +from solders.pubkey import Pubkey + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +from config import ( + WSS_ENDPOINT, + PUMP_PROGRAM, + SYSTEM_TOKEN_PROGRAM as TOKEN_PROGRAM_ID, + SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM as ATA_PROGRAM_ID +) + +def find_associated_bonding_curve(mint: Pubkey, bonding_curve: Pubkey) -> Pubkey: + """ + Find the associated bonding curve for a given mint and bonding curve. + This uses the standard ATA derivation. + """ + derived_address, _ = Pubkey.find_program_address( + [ + bytes(bonding_curve), + bytes(TOKEN_PROGRAM_ID), + bytes(mint), + ], + ATA_PROGRAM_ID + ) + return derived_address + +# Load the IDL JSON file +with open('../idl/pump_fun_idl.json', 'r') as f: + idl = json.load(f) + +# Extract the "create" instruction definition +create_instruction = next(instr for instr in idl['instructions'] if instr['name'] == 'create') + +def parse_create_instruction(data): + if len(data) < 8: + return None + offset = 8 + parsed_data = {} + + # Parse fields based on CreateEvent structure + fields = [ + ('name', 'string'), + ('symbol', 'string'), + ('uri', 'string'), + ('mint', 'publicKey'), + ('bondingCurve', 'publicKey'), + ('user', 'publicKey'), + ] + + try: + for field_name, field_type in fields: + if field_type == 'string': + length = struct.unpack('