Buy Token

Purchases tokens from the bonding curve using SOL.

Instruction INDEX

2

Instruction

SCBondingCurveInstruction::BuyToken {
    pda_token_nonce: u8,
    sol_to_spend: u64,
    min_token_to_receive: u64,
    logging_account_bump: u8,
}

Parameters

Parameter
Type
Description

pda_token_nonce

u8

Nonce for the token owner PDA

sol_to_spend

u64

Amount of SOL to spend in lamports

min_token_to_receive

u64

Minimum acceptable token amount to receive (slippage protection)

logging_account_bump

u8

Bump for the logging authority PDA

Account Setup

#
Account
Description
Derivation

1

Payer account

Transaction signer (User wallet)

-

2

System program

System program

SystemProgram.programId

3

Token program

SPL Token program

TOKEN_PROGRAM_ID

4

Token owner PDA

Bonding curve account

[Buffer.from("token_owner"), mint.toBuffer(), [nonce]]

5

Token mint

Token mint address

Provided by user

6

Owner token account

Token account for PDA

getAssociatedTokenAddress(mint, ownerPDA, true)

7

User token account

User's token account

getAssociatedTokenAddress(mint, userWallet, false)

8

Fee account

Platform fee account

Fixed address (see Reference section)

9

Properties account

Platform configuration

[Buffer.from("settings")]

10

Program account

SC Bonding Curve program

SC Bonding Curve program ID

11

Log authority account

For structured logs

[Buffer.from("logging_authority")]

Function Logic

  1. Verifies the PDA token owner matches the expected PDA for the token mint

  2. Retrieves platform fee from properties account (currently 1%)

  3. Calculates amount without fee (99% of sol_to_spend)

  4. Retrieves current pool balances (virtual + real SOL and tokens)

  5. Calculates expected token amount using the bonding curve formula

  6. Verifies expected token amount meets minimum specified (slippage check)

  7. Checks if purchase would finalize the token sale

  8. If finalizing, adjusts amounts accordingly and marks the token as finalized

  9. Transfers SOL to the bonding curve and fee account

  10. Transfers tokens to the user

  11. Updates pool balances in the bonding curve account

  12. Records buy data in logs

Price Calculation

token_amount = pool_token_balance * sol_amount / (pool_sol_balance + sol_amount)

Where:

  • pool_token_balance = virtual_token + real_token

  • pool_sol_balance = virtual_sol + real_sol

  • sol_amount = amount of SOL after fee deduction

Notes

  • The platform fee is deducted from the SOL amount before calculating token amount

  • If the purchase would leave less than POOL_MIGRATION_RESERVES tokens in the pool, the token sale is finalized

  • A finalized token can no longer be traded on the bonding curve and is ready for migration

Example Usage

// Derive PDAs and other accounts
const [tokenOwnerPDA, pdaTokenNonce] = PublicKey.findProgramAddressSync(
  [Buffer.from("token_owner"), tokenMint.toBuffer()],
  SC_BONDING_CURVE_PROGRAM_ID
)

const [propertiesAccount] = PublicKey.findProgramAddressSync(
  [Buffer.from("settings")],
  SC_BONDING_CURVE_PROGRAM_ID
)

const [logAuthority, logAuthorityBump] = PublicKey.findProgramAddressSync(
  [Buffer.from("logging_authority")],
  SC_BONDING_CURVE_PROGRAM_ID
)

// Get token accounts
const ownerTokenAccount = getAssociatedTokenAddressSync(tokenMint, tokenOwnerPDA, true)

const userTokenAccount = getAssociatedTokenAddressSync(tokenMint, wallet.publicKey, false)

// Create instruction data buffer
const data = Buffer.alloc(18)
data.writeUint8(2, 0) // Instruction code for BuyToken
data.writeUint8(pdaTokenNonce, 1) // PDA nonce
data.writeBigUInt64LE(solToSpend, 2) // SOL amount
data.writeBigUInt64LE(minTokenToReceive, 10) // Minimum tokens
data.writeUint8(logAuthorityBump, 18) // Log authority bump

const buyTokenIx = new TransactionInstruction({
  programId: SC_BONDING_CURVE_PROGRAM_ID,
  keys: [
    { pubkey: wallet.publicKey, isSigner: true, isWritable: true },
    { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
    { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
    { pubkey: tokenOwnerPDA, isSigner: false, isWritable: true },
    { pubkey: tokenMint, isSigner: false, isWritable: false },
    { pubkey: ownerTokenAccount, isSigner: false, isWritable: true },
    { pubkey: userTokenAccount, isSigner: false, isWritable: true },
    { pubkey: FEE_ACCOUNT, isSigner: false, isWritable: true },
    { pubkey: propertiesAccount, isSigner: false, isWritable: false },
    { pubkey: SC_BONDING_CURVE_PROGRAM_ID, isSigner: false, isWritable: false },
    { pubkey: logAuthority, isSigner: false, isWritable: false },
  ],
  data: data,
})

Last updated