diff --git a/idl/pump_fun_idl.json b/idl/pump_fun_idl.json index 0b68baf7..35a90726 100644 --- a/idl/pump_fun_idl.json +++ b/idl/pump_fun_idl.json @@ -739,7 +739,6 @@ }, { "name": "fee_config", - "optional": true, "pda": { "seeds": [ { @@ -803,7 +802,6 @@ }, { "name": "fee_program", - "optional": true, "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" } ], @@ -826,6 +824,422 @@ } ] }, + { + "name": "buy_exact_sol_in", + "docs": [ + "Given a budget of spendable SOL, buy at least min_tokens_out", + "Account creation and fees will be deducted from the spendable SOL", + "", + "f(sol) = tokens, where tokens >= min_tokens_out and sol > rent + fees", + "", + "max_slippage = min_tokens_out = 1", + "", + "Make sure the sol budget is enough to cover creation of the following accounts (unless already created):", + "- creator_vault: rent.minimum_balance(SystemAccount::LEN)", + "- user_volume_accumulator: rent.minimum_balance(UserVolumeAccumulator::LEN)" + ], + "discriminator": [ + 56, + 252, + 116, + 8, + 158, + 223, + 205, + 95 + ], + "accounts": [ + { + "name": "global", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "fee_recipient", + "writable": true + }, + { + "name": "mint" + }, + { + "name": "bonding_curve", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ] + }, + { + "kind": "account", + "path": "mint" + } + ] + } + }, + { + "name": "associated_bonding_curve", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "bonding_curve" + }, + { + "kind": "const", + "value": [ + 6, + 221, + 246, + 225, + 215, + 101, + 161, + 147, + 217, + 203, + 225, + 70, + 206, + 235, + 121, + 172, + 28, + 180, + 133, + 237, + 95, + 91, + 55, + 145, + 58, + 140, + 245, + 133, + 126, + 255, + 0, + 169 + ] + }, + { + "kind": "account", + "path": "mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "associated_user", + "writable": true + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "creator_vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 99, + 114, + 101, + 97, + 116, + 111, + 114, + 45, + 118, + 97, + 117, + 108, + 116 + ] + }, + { + "kind": "account", + "path": "bonding_curve.creator", + "account": "BondingCurve" + } + ] + } + }, + { + "name": "event_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 95, + 95, + 101, + 118, + 101, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ] + } + }, + { + "name": "program", + "address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" + }, + { + "name": "global_volume_accumulator", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108, + 95, + 118, + 111, + 108, + 117, + 109, + 101, + 95, + 97, + 99, + 99, + 117, + 109, + 117, + 108, + 97, + 116, + 111, + 114 + ] + } + ] + } + }, + { + "name": "user_volume_accumulator", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 117, + 115, + 101, + 114, + 95, + 118, + 111, + 108, + 117, + 109, + 101, + 95, + 97, + 99, + 99, + 117, + 109, + 117, + 108, + 97, + 116, + 111, + 114 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "fee_config", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 102, + 101, + 101, + 95, + 99, + 111, + 110, + 102, + 105, + 103 + ] + }, + { + "kind": "const", + "value": [ + 1, + 86, + 224, + 246, + 147, + 102, + 90, + 207, + 68, + 219, + 21, + 104, + 191, + 23, + 91, + 170, + 81, + 137, + 203, + 151, + 245, + 210, + 255, + 59, + 101, + 93, + 43, + 182, + 253, + 109, + 24, + 176 + ] + } + ], + "program": { + "kind": "account", + "path": "fee_program" + } + } + }, + { + "name": "fee_program", + "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" + } + ], + "args": [ + { + "name": "spendable_sol_in", + "type": "u64" + }, + { + "name": "min_tokens_out", + "type": "u64" + }, + { + "name": "track_volume", + "type": { + "defined": { + "name": "OptionBool" + } + } + } + ] + }, { "name": "claim_token_incentives", "discriminator": [ @@ -2568,7 +2982,6 @@ }, { "name": "fee_config", - "optional": true, "pda": { "seeds": [ { @@ -2632,7 +3045,6 @@ }, { "name": "fee_program", - "optional": true, "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" } ], @@ -3851,6 +4263,21 @@ { "code": 6039, "name": "InvalidIncentiveMint" + }, + { + "code": 6040, + "name": "BuyNotEnoughSolToCoverRent", + "msg": "Buy: Not enough SOL to cover for rent exemption." + }, + { + "code": 6041, + "name": "BuyNotEnoughSolToCoverFees", + "msg": "Buy: Not enough SOL to cover for fees." + }, + { + "code": 6042, + "name": "BuySlippageBelowMinTokensOut", + "msg": "Slippage: Would buy less tokens than expected min_tokens_out" } ], "types": [ @@ -4573,6 +5000,9 @@ }, { "name": "TradeEvent", + "docs": [ + "ix_name: \"buy\" | \"sell\" | \"buy_exact_sol_in\"" + ], "type": { "kind": "struct", "fields": [ @@ -4659,6 +5089,10 @@ { "name": "last_update_timestamp", "type": "i64" + }, + { + "name": "ix_name", + "type": "string" } ] } diff --git a/idl/pump_swap_idl.json b/idl/pump_swap_idl.json index a11620e0..f18194f0 100644 --- a/idl/pump_swap_idl.json +++ b/idl/pump_swap_idl.json @@ -620,7 +620,6 @@ }, { "name": "fee_config", - "optional": true, "pda": { "seeds": [ { @@ -684,7 +683,6 @@ }, { "name": "fee_program", - "optional": true, "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" } ], @@ -707,6 +705,434 @@ } ] }, + { + "name": "buy_exact_quote_in", + "docs": [ + "Given a budget of spendable_quote_in, buy at least min_base_amount_out", + "Fees will be deducted from spendable_quote_in", + "", + "f(quote) = tokens, where tokens >= min_base_amount_out", + "", + "Make sure the payer has enough SOL to cover creation of the following accounts (unless already created):", + "- protocol_fee_recipient_token_account: rent.minimum_balance(TokenAccount::LEN)", + "- coin_creator_vault_ata: rent.minimum_balance(TokenAccount::LEN)", + "- user_volume_accumulator: rent.minimum_balance(UserVolumeAccumulator::LEN)" + ], + "discriminator": [ + 198, + 46, + 21, + 82, + 180, + 217, + 232, + 112 + ], + "accounts": [ + { + "name": "pool" + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "global_config" + }, + { + "name": "base_mint", + "relations": [ + "pool" + ] + }, + { + "name": "quote_mint", + "relations": [ + "pool" + ] + }, + { + "name": "user_base_token_account", + "writable": true + }, + { + "name": "user_quote_token_account", + "writable": true + }, + { + "name": "pool_base_token_account", + "writable": true, + "relations": [ + "pool" + ] + }, + { + "name": "pool_quote_token_account", + "writable": true, + "relations": [ + "pool" + ] + }, + { + "name": "protocol_fee_recipient" + }, + { + "name": "protocol_fee_recipient_token_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "protocol_fee_recipient" + }, + { + "kind": "account", + "path": "quote_token_program" + }, + { + "kind": "account", + "path": "quote_mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "base_token_program" + }, + { + "name": "quote_token_program" + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "associated_token_program", + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + }, + { + "name": "event_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 95, + 95, + 101, + 118, + 101, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ] + } + }, + { + "name": "program", + "address": "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA" + }, + { + "name": "coin_creator_vault_ata", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "coin_creator_vault_authority" + }, + { + "kind": "account", + "path": "quote_token_program" + }, + { + "kind": "account", + "path": "quote_mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "coin_creator_vault_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 99, + 114, + 101, + 97, + 116, + 111, + 114, + 95, + 118, + 97, + 117, + 108, + 116 + ] + }, + { + "kind": "account", + "path": "pool.coin_creator", + "account": "Pool" + } + ] + } + }, + { + "name": "global_volume_accumulator", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108, + 95, + 118, + 111, + 108, + 117, + 109, + 101, + 95, + 97, + 99, + 99, + 117, + 109, + 117, + 108, + 97, + 116, + 111, + 114 + ] + } + ] + } + }, + { + "name": "user_volume_accumulator", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 117, + 115, + 101, + 114, + 95, + 118, + 111, + 108, + 117, + 109, + 101, + 95, + 97, + 99, + 99, + 117, + 109, + 117, + 108, + 97, + 116, + 111, + 114 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "fee_config", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 102, + 101, + 101, + 95, + 99, + 111, + 110, + 102, + 105, + 103 + ] + }, + { + "kind": "const", + "value": [ + 12, + 20, + 222, + 252, + 130, + 94, + 198, + 118, + 148, + 37, + 8, + 24, + 187, + 101, + 64, + 101, + 244, + 41, + 141, + 49, + 86, + 213, + 113, + 180, + 212, + 248, + 9, + 12, + 24, + 233, + 168, + 99 + ] + } + ], + "program": { + "kind": "account", + "path": "fee_program" + } + } + }, + { + "name": "fee_program", + "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" + } + ], + "args": [ + { + "name": "spendable_quote_in", + "type": "u64" + }, + { + "name": "min_base_amount_out", + "type": "u64" + }, + { + "name": "track_volume", + "type": { + "defined": { + "name": "OptionBool" + } + } + } + ] + }, { "name": "claim_token_incentives", "discriminator": [ @@ -2279,7 +2705,6 @@ }, { "name": "fee_config", - "optional": true, "pda": { "seeds": [ { @@ -2343,7 +2768,6 @@ }, { "name": "fee_program", - "optional": true, "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" } ], @@ -3465,6 +3889,16 @@ { "code": 6038, "name": "InvalidIncentiveMint" + }, + { + "code": 6039, + "name": "BuyNotEnoughQuoteTokensToCoverFees", + "msg": "buy: Not enough quote tokens to cover for fees." + }, + { + "code": 6040, + "name": "BuySlippageBelowMinBaseAmountOut", + "msg": "buy: slippage - would buy less tokens than expected min_base_amount_out" } ], "types": [ @@ -3574,6 +4008,9 @@ }, { "name": "BuyEvent", + "docs": [ + "ix_name: \"buy\" | \"buy_exact_quote_in\"" + ], "type": { "kind": "struct", "fields": [ @@ -3688,6 +4125,14 @@ { "name": "last_update_timestamp", "type": "i64" + }, + { + "name": "min_base_amount_out", + "type": "u64" + }, + { + "name": "ix_name", + "type": "string" } ] } diff --git a/learning-examples/bonding-curve-progress/poll_bonding_curve_progress.py b/learning-examples/bonding-curve-progress/poll_bonding_curve_progress.py index 1c8b1c95..9e823c2a 100644 --- a/learning-examples/bonding-curve-progress/poll_bonding_curve_progress.py +++ b/learning-examples/bonding-curve-progress/poll_bonding_curve_progress.py @@ -16,7 +16,7 @@ # Constants RPC_URL: Final[str] = os.getenv("SOLANA_NODE_RPC_ENDPOINT") -TOKEN_MINT: Final[str] = "xWrzYY4c1LnbSkLrd2LDUg9vw7YtVyJhGmw7MABpump" +TOKEN_MINT: Final[str] = "YOUR_TOKEN_MINT_ADDRESS_HERE" # Replace with actual token mint address PUMP_PROGRAM_ID: Final[Pubkey] = Pubkey.from_string( "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" ) diff --git a/learning-examples/fetch_price.py b/learning-examples/fetch_price.py index 94905ab0..cf89cf06 100644 --- a/learning-examples/fetch_price.py +++ b/learning-examples/fetch_price.py @@ -12,7 +12,7 @@ LAMPORTS_PER_SOL: Final[int] = 1_000_000_000 TOKEN_DECIMALS: Final[int] = 6 -CURVE_ADDRESS: Final[str] = "6GXfUqrmPM4VdN1NoDZsE155jzRegJngZRjMkGyby7do" +CURVE_ADDRESS: Final[str] = "YOUR_BONDING_CURVE_ADDRESS_HERE" # Replace with actual bonding curve address # Here and later all the discriminators are precalculated. See learning-examples/calculate_discriminator.py EXPECTED_DISCRIMINATOR: Final[bytes] = struct.pack(" bytes: return Instruction(PUMP_PROGRAM, data, accounts) +def create_extend_account_instruction( + bonding_curve: Pubkey, + user: Pubkey, +) -> Instruction: + """Create the extend_account instruction to expand bonding curve account size.""" + accounts = [ + AccountMeta(pubkey=bonding_curve, is_signer=False, is_writable=True), + AccountMeta(pubkey=user, is_signer=True, is_writable=True), + AccountMeta(pubkey=SYSTEM_PROGRAM, is_signer=False, is_writable=False), + AccountMeta(pubkey=PUMP_EVENT_AUTHORITY, is_signer=False, is_writable=False), + AccountMeta(pubkey=PUMP_PROGRAM, is_signer=False, is_writable=False), + ] + + # No arguments for extend_account instruction + data = EXTEND_ACCOUNT_DISCRIMINATOR + + return Instruction(PUMP_PROGRAM, data, accounts) + + def create_buy_instruction( global_state: Pubkey, fee_recipient: Pubkey, @@ -205,6 +227,7 @@ def create_buy_instruction( creator_vault: Pubkey, token_amount: int, max_sol_cost: int, + track_volume: bool = True, ) -> Instruction: """Create the buy instruction.""" accounts = [ @@ -242,10 +265,15 @@ def create_buy_instruction( ), ] + # Encode OptionBool for track_volume + # OptionBool: [0] = None, [1, 0] = Some(false), [1, 1] = Some(true) + track_volume_bytes = bytes([1, 1 if track_volume else 0]) + data = ( BUY_DISCRIMINATOR + struct.pack("