fix pump upgrade

This commit is contained in:
William
2025-05-13 06:34:57 +08:00
parent ee0f18a279
commit 3a60969b22
6 changed files with 143 additions and 346 deletions
+17 -149
View File
@@ -25,10 +25,11 @@
//! - `get_final_market_cap_sol`: Calculates the final market cap in SOL after all tokens are sold
//! - `get_buy_out_price`: Calculates the price to buy out all remaining tokens
use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Serialize, Deserialize};
use solana_sdk::pubkey::Pubkey;
/// Represents a bonding curve for token pricing and liquidity management
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
/// Represents the global configuration account for token pricing and fees
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BondingCurveAccount {
/// Unique identifier for the bonding curve
pub discriminator: u64,
@@ -44,6 +45,8 @@ pub struct BondingCurveAccount {
pub token_total_supply: u64,
/// Whether the bonding curve is complete/finalized
pub complete: bool,
/// Creator of the bonding curve
pub creator: Pubkey,
}
impl BondingCurveAccount {
@@ -57,25 +60,17 @@ impl BondingCurveAccount {
/// * `real_sol_reserves` - Actual SOL reserves available
/// * `token_total_supply` - Total supply of tokens
/// * `complete` - Whether the curve is complete
pub fn new(
discriminator: u64,
virtual_token_reserves: u64,
virtual_sol_reserves: u64,
real_token_reserves: u64,
real_sol_reserves: u64,
token_total_supply: u64,
complete: bool,
) -> Self {
Self {
discriminator,
virtual_token_reserves,
virtual_sol_reserves,
real_token_reserves,
real_sol_reserves,
token_total_supply,
complete,
}
}
// pub fn new(mint: &Pubkey, dev_buy_token_amount: u64, dev_buy_sol_amount: u64) -> Self {
// Self {
// // account: get_bonding_curve_pda(mint).unwrap(),
// virtual_token_reserves: INITIAL_VIRTUAL_TOKEN_RESERVES - dev_buy_token_amount,
// virtual_sol_reserves: INITIAL_VIRTUAL_SOL_RESERVES + dev_buy_sol_amount,
// real_token_reserves: INITIAL_REAL_TOKEN_RESERVES - dev_buy_token_amount,
// real_sol_reserves: dev_buy_sol_amount,
// token_total_supply: TOKEN_TOTAL_SUPPLY,
// complete: false,
// }
// }
/// Calculates the amount of tokens received for a given SOL amount
///
@@ -204,130 +199,3 @@ impl BondingCurveAccount {
token_price
}
}
#[cfg(test)]
mod tests {
use super::*;
fn get_bonding_curve() -> BondingCurveAccount {
BondingCurveAccount::new(
1, // discriminator
1000, // virtual_token_reserves
1000, // virtual_sol_reserves
500, // real_token_reserves
500, // real_sol_reserves
1000, // token_total_supply
false, // complete
)
}
fn get_large_bonding_curve() -> BondingCurveAccount {
BondingCurveAccount::new(
1, // discriminator
u64::MAX / 2, // virtual_token_reserves
u64::MAX / 2, // virtual_sol_reserves
u64::MAX / 4, // real_token_reserves
u64::MAX / 4, // real_sol_reserves
u64::MAX / 2, // token_total_supply
false, // complete
)
}
#[test]
fn test_bonding_curve_account() {
let bonding_curve: BondingCurveAccount = get_bonding_curve();
// Test buy price calculation
assert_eq!(bonding_curve.get_buy_price(0).unwrap(), 0);
let buy_price = bonding_curve.get_buy_price(100).unwrap();
assert!(buy_price > 0);
assert!(buy_price <= bonding_curve.real_token_reserves);
// Test sell price calculation
assert_eq!(bonding_curve.get_sell_price(0, 250).unwrap(), 0);
let sell_price = bonding_curve.get_sell_price(100, 250).unwrap();
assert!(sell_price > 0);
}
#[test]
fn test_bonding_curve_complete() {
let mut bonding_curve: BondingCurveAccount = get_bonding_curve();
// Test operations work when not complete
assert!(bonding_curve.get_buy_price(100).is_ok());
assert!(bonding_curve.get_sell_price(100, 250).is_ok());
// Set curve to complete
bonding_curve.complete = true;
// Test operations fail when complete
assert!(bonding_curve.get_buy_price(100).is_err());
assert!(bonding_curve.get_sell_price(100, 250).is_err());
}
#[test]
fn test_market_cap_calculations() {
let bonding_curve: BondingCurveAccount = get_bonding_curve();
// Test market cap calculations
let market_cap = bonding_curve.get_market_cap_sol();
assert!(market_cap > 0);
let final_market_cap = bonding_curve.get_final_market_cap_sol(250);
assert!(final_market_cap > 0);
}
#[test]
fn test_buy_out_price() {
let bonding_curve: BondingCurveAccount = get_bonding_curve();
let buy_out_price = bonding_curve.get_buy_out_price(100, 250);
assert!(buy_out_price > 0);
// Test with amount less than real_sol_reserves
let small_buy_out = bonding_curve.get_buy_out_price(400, 250);
assert!(small_buy_out > 0);
}
#[test]
fn test_overflow_buy_price() {
let bonding_curve = get_large_bonding_curve();
// Test buying with large SOL amount
let buy_price = bonding_curve.get_buy_price(u64::MAX).unwrap();
assert!(buy_price > 0);
assert!(buy_price <= bonding_curve.real_token_reserves);
}
#[test]
fn test_overflow_sell_price() {
let bonding_curve = get_large_bonding_curve();
// Test selling large token amount
let sell_price = bonding_curve.get_sell_price(u64::MAX / 4, 250).unwrap();
assert!(sell_price > 0);
}
#[test]
fn test_overflow_market_cap() {
let bonding_curve = get_large_bonding_curve();
// Test market cap with large values
let market_cap = bonding_curve.get_market_cap_sol();
assert!(market_cap > 0);
let final_market_cap = bonding_curve.get_final_market_cap_sol(250);
assert!(final_market_cap > 0);
}
#[test]
fn test_overflow_buy_out_price() {
let bonding_curve = get_large_bonding_curve();
// Test buy out with large token amount
let buy_out_price = bonding_curve.get_buy_out_price(u64::MAX / 4, 250);
assert!(buy_out_price > 0);
}
}
+76 -6
View File
@@ -21,14 +21,66 @@ pub mod seeds {
/// Seed for bonding curve PDAs
pub const BONDING_CURVE_SEED: &[u8] = b"bonding-curve";
/// Seed for creator vault PDAs
pub const CREATOR_VAULT_SEED: &[u8] = b"creator-vault";
/// Seed for metadata PDAs
pub const METADATA_SEED: &[u8] = b"metadata";
}
pub mod global_constants {
use solana_sdk::{pubkey, pubkey::Pubkey};
pub const INITIAL_VIRTUAL_TOKEN_RESERVES: u64 = 1_073_000_000_000_000;
pub const INITIAL_VIRTUAL_SOL_RESERVES: u64 = 30_000_000_000;
pub const INITIAL_REAL_TOKEN_RESERVES: u64 = 793_100_000_000_000;
pub const TOKEN_TOTAL_SUPPLY: u64 = 1_000_000_000_000_000;
pub const FEE_BASIS_POINTS: u64 = 95;
pub const ENABLE_MIGRATE: bool = false;
pub const POOL_MIGRATION_FEE: u64 = 15_000_001;
pub const CREATOR_FEE: u64 = 5;
pub const SCALE: u64 = 1_000_000; // 10^6 for token decimals
pub const LAMPORTS_PER_SOL: u64 = 1_000_000_000; // 10^9 for solana lamports
pub const TOTAL_SUPPLY: u64 = 1_000_000_000 * SCALE; // 1 billion tokens
pub const BONDING_CURVE_SUPPLY: u64 = 793_100_000 * SCALE; // total supply of bonding curve tokens
pub const COMPLETION_LAMPORTS: u64 = 85 * LAMPORTS_PER_SOL; // ~ 85 SOL
/// Public key for the fee recipient
pub const FEE_RECIPIENT: Pubkey = pubkey!("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV");
/// Public key for the global PDA
pub const GLOBAL_ACCOUNT: Pubkey = pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf");
/// Public key for the authority
pub const AUTHORITY: Pubkey = pubkey!("FFWtrEQ4B4PKQoVuHYzZq8FabGkVatYzDpEVHsK5rrhF");
/// Public key for the withdraw authority
pub const WITHDRAW_AUTHORITY: Pubkey = pubkey!("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg");
pub const PUMPFUN_AMM_FEE_1: Pubkey = pubkey!("7VtfL8fvgNfhz17qKRMjzQEXgbdpnHHHQRh54R9jP2RJ"); // Pump.fun AMM: Protocol Fee 1
pub const PUMPFUN_AMM_FEE_2: Pubkey = pubkey!("7hTckgnGnLQR6sdH7YkqFTAA7VwTfYFaZ6EhEsU3saCX"); // Pump.fun AMM: Protocol Fee 2
pub const PUMPFUN_AMM_FEE_3: Pubkey = pubkey!("9rPYyANsfQZw3DnDmKE3YCQF5E8oD89UXoHn9JFEhJUz"); // Pump.fun AMM: Protocol Fee 3
pub const PUMPFUN_AMM_FEE_4: Pubkey = pubkey!("AVmoTthdrX6tKt4nDjco2D775W2YK3sDhxPcMmzUAmTY"); // Pump.fun AMM: Protocol Fee 4
pub const PUMPFUN_AMM_FEE_5: Pubkey = pubkey!("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM"); // Pump.fun AMM: Protocol Fee 5
pub const PUMPFUN_AMM_FEE_6: Pubkey = pubkey!("FWsW1xNtWscwNmKv6wVsU1iTzRN6wmmk3MjxRP5tT7hz"); // Pump.fun AMM: Protocol Fee 6
pub const PUMPFUN_AMM_FEE_7: Pubkey = pubkey!("G5UZAVbAf46s7cKWoyKu8kYTip9DGTpbLZ2qa9Aq69dP"); // Pump.fun AMM: Protocol Fee 7
}
/// Constants related to program accounts and authorities
pub mod accounts {
use std::collections::{HashMap, HashSet};
use solana_sdk::{pubkey, pubkey::Pubkey};
/// Public key for the Pump.fun program
@@ -47,8 +99,7 @@ pub mod accounts {
pub const TOKEN_PROGRAM: Pubkey = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
/// Associated Token Program ID
pub const ASSOCIATED_TOKEN_PROGRAM: Pubkey =
pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
pub const ASSOCIATED_TOKEN_PROGRAM: Pubkey = pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
/// Rent Sysvar ID
pub const RENT: Pubkey = pubkey!("SysvarRent111111111111111111111111111111111");
@@ -64,7 +115,6 @@ pub mod accounts {
"3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT",
];
/// Tip accounts
pub const NEXTBLOCK_TIP_ACCOUNTS: &[&str] = &[
"NextbLoCkVtMGcV47JzewQdvBpLqT9TxQFozQkN98pE",
@@ -85,12 +135,32 @@ pub mod accounts {
"Cix2bHfqPcKcM233mzxbLk14kSggUUiz2A87fJtGivXr",
];
pub const NOZOMI_TIP_ACCOUNTS: &[&str] = &[
"TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq",
"noz3jAjPiHuBPqiSPkkugaJDkJscPuRhYnSpbi8UvC4",
"noz3str9KXfpKknefHji8L1mPgimezaiUyCHYMDv1GE",
"noz6uoYCDijhu1V7cutCpwxNiSovEwLdRHPwmgCGDNo",
"noz9EPNcT7WH6Sou3sr3GGjHQYVkN3DNirpbvDkv9YJ",
"nozc5yT15LazbLTFVZzoNZCwjh3yUtW86LoUyqsBu4L",
"nozFrhfnNGoyqwVuwPAW4aaGqempx4PU6g6D9CJMv7Z",
"nozievPk7HyK1Rqy1MPJwVQ7qQg2QoJGyP71oeDwbsu",
"noznbgwYnBLDHu8wcQVCEw6kDrXkPdKkydGJGNXGvL7",
"nozNVWs5N8mgzuD3qigrCG2UoKxZttxzZ85pvAQVrbP",
"nozpEGbwx4BcGp6pvEdAh1JoC2CQGZdU6HbNP1v2p6P",
"nozrhjhkCr3zXT3BiT4WCodYCUFeQvcdUkM7MqhKqge",
"nozrwQtWhEdrA6W8dkbt9gnUaMs52PdAv5byipnadq3",
"nozUacTVWub3cL4mJmGCYjKZTnE9RbdY5AP46iQgbPJ",
"nozWCyTPppJjRuw2fpzDhhWbW355fzosWSzrrMYB1Qk",
"nozWNju6dY353eMkMqURqwQEoM3SFgEKC6psLCSfUne",
"nozxNBgWohjR75vdspfxR5H9ceC7XXH99xpxhVGt3Bb"
];
pub const AMM_PROGRAM: Pubkey = pubkey!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8");
}
pub mod trade {
pub const TRADER_TIP_AMOUNT: f64 = 0.0001;
pub const DEFAULT_SLIPPAGE: u64 = 3000; // 30%
pub const DEFAULT_SLIPPAGE: u64 = 1000; // 10%
pub const DEFAULT_COMPUTE_UNIT_LIMIT: u32 = 78000;
pub const DEFAULT_COMPUTE_UNIT_PRICE: u64 = 500000;
pub const DEFAULT_BUY_TIP_FEE: f64 = 0.0006;
+10 -172
View File
@@ -9,15 +9,6 @@
//! - `create`: Instruction to create a new token with an associated bonding curve.
//! - `buy`: Instruction to buy tokens from a bonding curve by providing SOL.
//! - `sell`: Instruction to sell tokens back to the bonding curve in exchange for SOL.
use std::sync::Arc;
use spl_associated_token_account::instruction::create_associated_token_account;
use spl_token::instruction::close_account;
use crate::common::SolanaRpcClient;
use crate::constants::trade::DEFAULT_SLIPPAGE;
use crate::ipfs::TokenMetadataIPFS;
use crate::pumpfun::common::{calculate_with_slippage_buy, calculate_with_slippage_sell, get_bonding_curve_account, get_buy_amount_with_slippage, get_global_account, get_initial_buy_price, get_token_balance, get_token_balance_and_ata};
use crate::{
constants,
pumpfun::common::{
@@ -33,7 +24,6 @@ use solana_sdk::{
signer::Signer,
};
use anyhow::{anyhow, Result};
pub struct Create {
pub _name: String,
pub _symbol: String,
@@ -156,24 +146,25 @@ pub fn create(payer: &Keypair, mint: &Keypair, args: Create) -> Instruction {
pub fn buy(
payer: &Keypair,
mint: &Pubkey,
bonding_curve: &Pubkey,
creator_vault: &Pubkey,
fee_recipient: &Pubkey,
args: Buy,
) -> Instruction {
let bonding_curve: Pubkey = get_bonding_curve_pda(mint).unwrap();
Instruction::new_with_bytes(
constants::accounts::PUMPFUN,
&args.data(),
vec![
AccountMeta::new_readonly(get_global_pda(), false),
AccountMeta::new_readonly(constants::global_constants::GLOBAL_ACCOUNT, false),
AccountMeta::new(*fee_recipient, false),
AccountMeta::new_readonly(*mint, false),
AccountMeta::new(bonding_curve, false),
AccountMeta::new(get_associated_token_address(&bonding_curve, mint), false),
AccountMeta::new(*bonding_curve, false),
AccountMeta::new(get_associated_token_address(bonding_curve, mint), false),
AccountMeta::new(get_associated_token_address(&payer.pubkey(), mint), false),
AccountMeta::new(payer.pubkey(), true),
AccountMeta::new_readonly(constants::accounts::SYSTEM_PROGRAM, false),
AccountMeta::new_readonly(constants::accounts::TOKEN_PROGRAM, false),
AccountMeta::new_readonly(constants::accounts::RENT, false),
AccountMeta::new(*creator_vault, false),
AccountMeta::new_readonly(constants::accounts::EVENT_AUTHORITY, false),
AccountMeta::new_readonly(constants::accounts::PUMPFUN, false),
],
@@ -199,15 +190,16 @@ pub fn buy(
pub fn sell(
payer: &Keypair,
mint: &Pubkey,
bonding_curve: &Pubkey,
creator_vault: &Pubkey,
fee_recipient: &Pubkey,
args: Sell,
) -> Instruction {
let bonding_curve: Pubkey = get_bonding_curve_pda(mint).unwrap();
Instruction::new_with_bytes(
constants::accounts::PUMPFUN,
&args.data(),
vec![
AccountMeta::new_readonly(get_global_pda(), false),
AccountMeta::new_readonly(constants::global_constants::GLOBAL_ACCOUNT, false),
AccountMeta::new(*fee_recipient, false),
AccountMeta::new_readonly(*mint, false),
AccountMeta::new(bonding_curve, false),
@@ -215,7 +207,7 @@ pub fn sell(
AccountMeta::new(get_associated_token_address(&payer.pubkey(), mint), false),
AccountMeta::new(payer.pubkey(), true),
AccountMeta::new_readonly(constants::accounts::SYSTEM_PROGRAM, false),
AccountMeta::new_readonly(constants::accounts::ASSOCIATED_TOKEN_PROGRAM, false),
AccountMeta::new(*creator_vault, false),
AccountMeta::new_readonly(constants::accounts::TOKEN_PROGRAM, false),
AccountMeta::new_readonly(constants::accounts::EVENT_AUTHORITY, false),
AccountMeta::new_readonly(constants::accounts::PUMPFUN, false),
@@ -223,157 +215,3 @@ pub fn sell(
)
}
pub async fn build_create_and_buy_instructions(
rpc: Arc<SolanaRpcClient>,
payer: Arc<Keypair>,
mint: Arc<Keypair>,
ipfs: TokenMetadataIPFS,
amount_sol: u64,
slippage_basis_points: Option<u64>,
) -> Result<Vec<Instruction>, anyhow::Error> {
if amount_sol == 0 {
return Err(anyhow!("build_create_and_buy_instructions: Amount cannot be zero"));
}
let rpc = rpc.as_ref();
let global_account = get_global_account(&rpc).await?;
let buy_amount = global_account.get_initial_buy_price(amount_sol);
let buy_amount_with_slippage =
get_buy_amount_with_slippage(amount_sol, slippage_basis_points);
let mut instructions = vec![];
instructions.push(create(
payer.as_ref(),
mint.as_ref(),
Create {
_name: ipfs.metadata.name.clone(),
_symbol: ipfs.metadata.symbol.clone(),
_uri: ipfs.metadata_uri.clone(),
_creator: payer.pubkey(),
},
));
let ata = get_associated_token_address(&payer.pubkey(), &mint.pubkey());
instructions.push(create_associated_token_account(
&payer.pubkey(),
&payer.pubkey(),
&mint.pubkey(),
&constants::accounts::TOKEN_PROGRAM,
));
instructions.push(buy(
payer.as_ref(),
&mint.pubkey(),
&global_account.fee_recipient,
Buy {
_amount: buy_amount,
_max_sol_cost: buy_amount_with_slippage,
},
));
Ok(instructions)
}
pub async fn build_buy_instructions(
rpc: Arc<SolanaRpcClient>,
payer: Arc<Keypair>,
mint: Arc<Pubkey>,
amount_sol: u64,
slippage_basis_points: Option<u64>,
) -> Result<Vec<Instruction>, anyhow::Error> {
if amount_sol == 0 {
return Err(anyhow!("build_buy_instructions:Amount cannot be zero"));
}
let global_account = get_global_account(&rpc).await?;
let buy_amount = match get_bonding_curve_account(&rpc, mint.as_ref()).await {
Ok(account) => {
account.get_buy_price(amount_sol).map_err(|e| anyhow!(e))?
},
Err(_e) => {
let initial_buy_amount = get_initial_buy_price(&global_account, amount_sol).await?;
initial_buy_amount * 80 / 100
}
};
let buy_amount_with_slippage = calculate_with_slippage_buy(amount_sol, slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE));
let mut instructions = vec![];
// let ata = get_associated_token_address(&payer.pubkey(), &mint);
// match rpc.get_account(&ata).await {
// Ok(_) => {},
// Err(_) => {
// instructions.push(create_associated_token_account(
// &payer.pubkey(),
// &payer.pubkey(),
// &mint,
// &constants::accounts::TOKEN_PROGRAM,
// ));
// }
// }
instructions.push(create_associated_token_account(
&payer.pubkey(),
&payer.pubkey(),
&mint,
&constants::accounts::TOKEN_PROGRAM,
));
instructions.push(buy(
payer.as_ref(),
&mint,
&global_account.fee_recipient,
Buy {
_amount: buy_amount,
_max_sol_cost: buy_amount_with_slippage,
},
));
Ok(instructions)
}
pub async fn build_sell_instructions(
rpc: Arc<SolanaRpcClient>,
payer: Arc<Keypair>,
mint: Arc<Pubkey>,
amount_token: u64,
slippage_basis_points: Option<u64>,
) -> Result<Vec<Instruction>, anyhow::Error> {
if amount_token == 0 {
return Err(anyhow!("build_sell_instructions: Amount cannot be zero"));
}
let ata = get_associated_token_address(&payer.pubkey(), mint.as_ref());
let global_account = get_global_account(&rpc).await?;
let bonding_curve_account = get_bonding_curve_account(&rpc, mint.as_ref()).await?;
let min_sol_output = bonding_curve_account
.get_sell_price(amount_token, global_account.fee_basis_points)
.map_err(|e| anyhow!(e))?;
let min_sol_output_with_slippage = calculate_with_slippage_sell(
min_sol_output,
slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE),
);
let mut instructions = vec![];
instructions.push(sell(
payer.as_ref(),
&mint,
&global_account.fee_recipient,
Sell {
_amount: amount_token,
_min_sol_output: min_sol_output_with_slippage,
},
));
instructions.push(close_account(
&spl_token::ID,
&ata,
&payer.pubkey(),
&payer.pubkey(),
&[&payer.pubkey()],
)?);
Ok(instructions)
}
+10 -13
View File
@@ -146,17 +146,12 @@ pub async fn build_buy_instructions(
return Err(anyhow!("Amount cannot be zero"));
}
let rpc = rpc.as_ref();
let global_account = get_global_account(rpc).await?;
let buy_amount = match get_bonding_curve_account(rpc, mint.as_ref()).await {
Ok(account) => account.get_buy_price(amount_sol).map_err(|e| anyhow!(e))?,
Err(_e) => {
println!("Bonding curve account not found, using initial buy price: {}", _e);
let initial_buy_amount = get_initial_buy_price(&global_account, amount_sol).await?;
initial_buy_amount * 80 / 100
}
};
let buy_amount_with_slippage = calculate_with_slippage_buy(amount_sol, slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE));
let (bonding_curve_account, bonding_curve_pda) = get_bonding_curve_account(&rpc, &mint).await?;
let creator_vault_pda = get_creator_vault_pda(&bonding_curve_account.creator).unwrap();
let (buy_token_amount, max_sol_cost) = get_buy_token_amount(&bonding_curve_account, buy_sol_cost, slippage_basis_points)?;
let mut instructions = vec![];
instructions.push(create_associated_token_account(
&payer.pubkey(),
@@ -168,10 +163,12 @@ pub async fn build_buy_instructions(
instructions.push(instruction::buy(
payer.as_ref(),
&mint,
&bonding_curve_pda,
&creator_vault_pda,
&global_account.fee_recipient,
instruction::Buy {
_amount: buy_amount,
_max_sol_cost: buy_amount_with_slippage,
_amount: buy_token_amount,
_max_sol_cost: max_sol_cost,
},
));
+25 -5
View File
@@ -88,9 +88,7 @@ pub async fn get_token_balance_and_ata(rpc: &SolanaRpcClient, payer: &Keypair, m
#[inline]
pub async fn get_sol_balance(rpc: &SolanaRpcClient, account: &Pubkey) -> Result<u64, anyhow::Error> {
println!("get_sol_balance account: {}", account);
let balance = rpc.get_balance(account).await?;
println!("get_sol_balance balance: {}", balance);
Ok(balance)
}
@@ -118,6 +116,14 @@ pub fn get_bonding_curve_pda(mint: &Pubkey) -> Option<Pubkey> {
pda.map(|pubkey| pubkey.0)
}
#[inline]
pub fn get_creator_vault_pda(creator: &Pubkey) -> Option<Pubkey> {
let seeds: &[&[u8]; 2] = &[constants::seeds::CREATOR_VAULT_SEED, creator.as_ref()];
let program_id: &Pubkey = &constants::accounts::PUMPFUN;
let pda: Option<(Pubkey, u8)> = Pubkey::try_find_program_address(seeds, program_id);
pda.map(|pubkey| pubkey.0)
}
#[inline]
pub fn get_metadata_pda(mint: &Pubkey) -> Pubkey {
Pubkey::find_program_address(
@@ -155,7 +161,7 @@ pub async fn get_initial_buy_price(global_account: &Arc<accounts::GlobalAccount>
pub async fn get_bonding_curve_account(
rpc: &SolanaRpcClient,
mint: &Pubkey,
) -> Result<Arc<accounts::BondingCurveAccount>, anyhow::Error> {
) -> Result<(Arc<accounts::BondingCurveAccount>, Pubkey), anyhow::Error> {
let bonding_curve_pda = get_bonding_curve_pda(mint)
.ok_or(anyhow!("Bonding curve not found"))?;
@@ -164,8 +170,22 @@ pub async fn get_bonding_curve_account(
return Err(anyhow!("Bonding curve not found"));
}
let bonding_curve = Arc::new(accounts::BondingCurveAccount::try_from_slice(&account.data)?);
Ok(bonding_curve)
let bonding_curve = Arc::new(bincode::deserialize::<accounts::BondingCurveAccount>(&account.data)?);
Ok((bonding_curve, bonding_curve_pda))
}
#[inline]
pub fn get_buy_token_amount(
bonding_curve_account: &BondingCurveAccount,
buy_sol_cost: u64,
slippage_basis_points: Option<u64>,
) -> anyhow::Result<(u64, u64)> {
let buy_token = bonding_curve_account.get_buy_price(buy_sol_cost).map_err(|e| anyhow!(e))?;
let max_sol_cost = calculate_with_slippage_buy(buy_sol_cost, slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE));
Ok((buy_token, max_sol_cost))
}
#[inline]
+5 -1
View File
@@ -196,7 +196,7 @@ pub async fn build_sell_instructions(
}
let global_account = get_global_account(rpc.as_ref()).await?;
let bonding_curve_account = get_bonding_curve_account(rpc.as_ref(), &mint).await?;
let (bonding_curve_account, bonding_curve_pda) = get_bonding_curve_account(&rpc, &mint).await?;
let min_sol_output = bonding_curve_account
.get_sell_price(amount, global_account.fee_basis_points)
.map_err(|e| anyhow!(e))?;
@@ -205,10 +205,14 @@ pub async fn build_sell_instructions(
slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE),
);
let creator_vault_pda = get_creator_vault_pda(&bonding_curve_account.creator).unwrap();
let instructions = vec![
instruction::sell(
payer.as_ref(),
&mint,
&bonding_curve_pda,
&creator_vault_pda,
&global_account.fee_recipient,
instruction::Sell {
_amount: amount,