# Buy Token

Purchases tokens from the bonding curve using SOL.

## Instruction INDEX

2

## Instruction

```rust
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

```javascript
// 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,
})
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.something.cool/sc-bonding-curve/functions/buy-token.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
