> ## Documentation Index
> Fetch the complete documentation index at: https://docs.donate.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# Solana (SVM)

> Integrate Donate.gg on Solana using the Donation Relay program

Donate.gg uses a config-driven donation pipeline. You interact with our on-chain program using metadata from [Donation configs](/partner-api/donation-configs): the `configId` returned by the API is the on-chain routing key.

For **EVM** chains, see [EVM](/blockchain/evm).

## How it works

<Steps>
  <Step title="Create a config via the API">
    Use the [Configs](/partner-api/donation-configs) endpoint to create a config that defines your
    charity beneficiaries and weights. You receive an `id` object with `hex` and `base58` fields.
    Both encode the same 32-byte identifier that routes donations to the correct destinations.
  </Step>

  <Step title="Submit the Solana transaction">
    Call a public donate instruction on the Donation Relay program: SPL Token / Token-2022 use
    `donate_v1` or `donate_pubkey_config_id_v1`; native SOL uses `donate_native_v1` or
    `donate_native_pubkey_config_id_v1` (see below for accounts and arguments).
  </Step>
</Steps>

***

The **Donation Relay** program routes donations into a per-config, per-mint **`debouncer_v1`** PDA. For **SPL Token and Token-2022**, you transfer from the donor’s token account. For **native SOL**, dedicated instructions move lamports through an ephemeral wrapped-SOL vault (`donate_native_wsol_tmp_v1`) inside the program. Donations are accumulated per epoch; the relayer closes epochs and runs distribution (not callable by integrators).

### Program ID and IDL

| Item         | Value                                                                                                        |
| ------------ | ------------------------------------------------------------------------------------------------------------ |
| Program ID   | `RLAYHr9TRFcKB2ubYQhspcnXiaGpaVzNQvHytt47RZu`                                                                |
| On-chain IDL | [Solana Explorer (IDL)](https://explorer.solana.com/address/RLAYHr9TRFcKB2ubYQhspcnXiaGpaVzNQvHytt47RZu/idl) |

The contract has been audited by [Halborn](https://halborn.com) and has gone through multiple rounds of review.

### Mapping `configId` from the API

The API returns config IDs as `{ "hex": "0x...", "base58": "..." }`. Both encode the same 32 bytes.

* **`donate_v1`** / **`donate_native_v1`**: use `id.hex`. Strip the `0x` prefix and decode the hex to `[u8; 32]` (left-to-right byte order).
* **`donate_pubkey_config_id_v1`** / **`donate_native_pubkey_config_id_v1`**: use `id.base58` directly as a `Pubkey` (convenient when your stack already uses `PublicKey` types).

### Instructions (integrators)

There are four public donate instructions, in two pairs. Within each pair the **account layout and semantics are identical**; only **`config_id` encoding** in the instruction data differs. On-chain names use snake\_case (`donate_native_v1`, …). Generated **TypeScript** clients typically expose the native pair as **`donateNativeV1`** and **`donateNativePubkeyConfigIdV1`** (for example UMI) or **`getDonateNativeV1Instruction`** / **`getDonateNativePubkeyConfigIdV1Instruction`** (Codama-style kits); the SPL instructions follow the same pattern (`donate_v1` → `donateV1` / `getDonateV1Instruction`, etc.).

#### SPL Token and Token-2022 (`donate_v1`, `donate_pubkey_config_id_v1`)

| Instruction                  | `config_id` in args | When to use                                                            |
| ---------------------------- | ------------------- | ---------------------------------------------------------------------- |
| `donate_v1`                  | `[u8; 32]`          | Matches EVM-style raw bytes from your backend.                         |
| `donate_pubkey_config_id_v1` | `pubkey` (32 bytes) | Same logic, ergonomic for Solana `PublicKey` / Explorer-style tooling. |

Both transfer **`amount`** (base units of **`mint`**) from the donor’s token account into the **`debouncer_v1`** vault ATA for `(config_id, mint)`, with **`tip_bps`**, **`message`** (UTF-8; **max 255 bytes**), and **`credited_to`**.

#### Native SOL (`donate_native_v1`, `donate_native_pubkey_config_id_v1`)

| Instruction                         | `config_id` in args | When to use                                  |
| ----------------------------------- | ------------------- | -------------------------------------------- |
| `donate_native_v1`                  | `[u8; 32]`          | Raw 32-byte config id (same as `donate_v1`). |
| `donate_native_pubkey_config_id_v1` | `pubkey`            | Same as `donate_pubkey_config_id_v1`.        |

These instructions donate **lamports** equal to **`amount`**: the program transfers lamports from the donor to an **ephemeral `donate_native_wsol_tmp_v1` PDA** (wrapped-SOL token account), calls **`sync_native`**, runs the same donation core as SPL (`transfer_checked` into the **`debouncer_v1`** vault), then **`close_account`** on the temp vault (rent returns to the donor). Arguments **`tip_bps`**, **`message`**, and **`credited_to`** match the SPL donate instructions. **`mint`** must be the canonical **wrapped SOL** mint for the **`token_program`** you pass: legacy SPL Token `So11111111111111111111111111111111111111112`, or Token-2022 `9pan9bMn5HatX4EJdBwg9VgCa7Uz5HL8N1m5D3NdXejP`.

All four instructions emit **`DonationMadeV1Event`** (see [Events](#events)).

### Account metas (order)

Pass accounts in this order (matches the IDL). Several PDAs use **`init_if_needed`** (or **`init`** for the native temp vault); the donor (`from`) pays rent when accounts are created.

PDAs are derived with the relay program ID as the program id. **`config_id`** in seeds is always the **32-byte** config identifier (for `*_pubkey_config_id_*` instructions, the same bytes as the `Pubkey` argument).

#### `donate_v1` and `donate_pubkey_config_id_v1`

| #  | Account                    | Notes                                                                     |
| -- | -------------------------- | ------------------------------------------------------------------------- |
| 1  | `epoch_tracker_v1`         | PDA: seeds `epoch_tracker_v1` · `config_id` (32 bytes) · `mint`.          |
| 2  | `debouncer_v1`             | PDA: seeds `debouncer_v1` · `config_id` (32 bytes) · `mint`.              |
| 3  | `debouncer_v1` vault ATA   | ATA: authority = `debouncer_v1`, `mint`, correct token program.           |
| 4  | `mint`                     | SPL or Token-2022 mint (must pass program [mint policy](#mint-policy)).   |
| 5  | `from_token_account`       | Donor’s ATA for `mint` (authority = `from`).                              |
| 6  | `from`                     | Donor signer; also payer for `init_if_needed`.                            |
| 7  | `mint_whitelist_v1`        | PDA: single seed `mint_whitelist_v1` (global whitelist account).          |
| 8  | `associated_token_program` | Associated Token program: `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`. |
| 9  | `token_program`            | SPL Token **or** Token-2022 program, matching `mint` and accounts.        |
| 10 | `system_program`           | System program.                                                           |
| 11 | `event_authority`          | PDA: seed `__event_authority` (Anchor event CPI).                         |
| 12 | `program`                  | Donation Relay program ID (self).                                         |

#### `donate_native_v1` and `donate_native_pubkey_config_id_v1`

Same as SPL, except the donor’s source of funds is **`donate_native_wsol_tmp_v1`** (program-owned PDA, **`init`** per instruction) instead of the donor’s ATA.

| #  | Account                     | Notes                                                                                                                           |
| -- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| 1  | `epoch_tracker_v1`          | Same PDA seeds as SPL, with **WSOL `mint`**.                                                                                    |
| 2  | `debouncer_v1`              | Same as SPL.                                                                                                                    |
| 3  | `debouncer_v1` vault ATA    | Debouncer ATA for WSOL `mint`.                                                                                                  |
| 4  | `mint`                      | Canonical WSOL mint for the chosen `token_program` (see above).                                                                 |
| 5  | `donate_native_wsol_tmp_v1` | PDA: seeds `donate_native_wsol_tmp_v1` · `from` · `token_program`; ephemeral vault for this donation.                           |
| 6  | `from`                      | Donor signer; pays lamports for **`amount`**, rent for `init` / `init_if_needed`, and receives temp-account rent back on close. |
| 7  | `mint_whitelist_v1`         | Same as SPL.                                                                                                                    |
| 8  | `associated_token_program`  | Same as SPL.                                                                                                                    |
| 9  | `token_program`             | Allowed native-donate programs only (legacy SPL Token or Token-2022, matching `mint`).                                          |
| 10 | `system_program`            | System program.                                                                                                                 |
| 11 | `event_authority`           | Same as SPL.                                                                                                                    |
| 12 | `program`                   | Donation Relay program ID (self).                                                                                               |

### Minimum SOL and rent

The donate instructions use **`init_if_needed`** on **`epoch_tracker_v1`**, **`debouncer_v1`**, and the **`debouncer_v1` vault**, with **`payer = from`** (the donor signer). Native donate also \*\*`init`\*\*s **`donate_native_wsol_tmp_v1`** each time. **Network transaction fees** are additional (often paid by the same key as `from`, depending on your client).

Rent-exempt **lamports** come from the cluster [`Rent`](https://docs.solana.com/developing/programming-model/accounts#rent) sysvar. The table below uses the standard mainnet-style formula (2-year exemption, **3480** lamports per byte-year, **128**-byte account overhead). If your RPC or cluster parameters differ, use `getMinimumBalanceForRentExemption(dataLength)` with the **on-chain data length** (program account `space`, or token account size).

#### First donation for a given `(config_id, mint)`

These accounts are created once per config + mint pair (WSOL mint for native donate). Sizes match the on-chain program (`EpochTrackerV1` / `DebouncerV1` account `space`, standard SPL token account **165** bytes for the **`debouncer_v1` vault**).

| Account                              | Data length                            | Rent-exempt minimum (typical)                 |
| ------------------------------------ | -------------------------------------- | --------------------------------------------- |
| `epoch_tracker_v1`                   | 90 bytes                               | **1,517,280** lamports (\~**0.00151728** SOL) |
| `debouncer_v1`                       | 82 bytes                               | **1,461,600** lamports (\~**0.0014616** SOL)  |
| `debouncer_v1` vault (token account) | 165 bytes (standard SPL token account) | **2,039,280** lamports (\~**0.00203928** SOL) |
| **Total (one-time, stays on-chain)** |                                        | **5,018,160** lamports (\~**0.00501816** SOL) |

#### Native SOL (`donate_native_*`) - temporary wrapped-SOL vault

**`donate_native_wsol_tmp_v1`** is a **165-byte** token account (same rent as above: **\~0.00203928** SOL). It is \*\*`init`\*\*d at the start of the instruction and \*\*`close_account`\*\*d at the end, with rent **returned to `from` in the same transaction**. It is **not** an extra long-term cost, but the donor wallet must still have enough **lamports at execution time** to cover **donation `amount` + this rent** (plus any first-time rows above) until the close runs.

#### After the first donation (same `config_id` + `mint`)

No further rent is charged for **`epoch_tracker_v1`**, **`debouncer_v1`**, or the **`debouncer_v1` vault**. For **native** donate, each transaction still briefly needs **`amount` + \~0.00203928 SOL** (`donate_native_wsol_tmp_v1`) plus fees. For **SPL** donate, the donor only needs SPL balance + SOL for fees (and an existing funded `from_token_account`).

### Native SOL (overview)

Use **`donate_native_v1`** / **`donate_native_pubkey_config_id_v1`** when you want donors to spend **native lamports** without maintaining their own WSOL ATA balance; the program wraps through **`donate_native_wsol_tmp_v1`** for you.

Alternatively, you can still **pre-wrap SOL** into the donor’s WSOL ATA and call **`donate_v1`** / **`donate_pubkey_config_id_v1`** with the WSOL mint, same as any other SPL mint.

### Mint policy

Mints must either appear on the on-chain **`mint_whitelist_v1`** PDA or satisfy **strict safety checks** (for example, no active mint/freeze authority; Token-2022 extensions such as transfer fee, transfer hook, and others are validated). Unsupported or unsafe mints fail with errors such as `InvalidMint`.

If you need a mint allowlisted, coordinate with Donate.gg; updating the whitelist is **`upsert_mint_whitelist_v1`** (relayer-only).

### Events

After a successful donation, observe **`DonationMadeV1Event`**:

| Field                      | Type       | Meaning                                   |
| -------------------------- | ---------- | ----------------------------------------- |
| `daas_event_discriminator` | enum       | Event family discriminator.               |
| `config_id`                | `[u8; 32]` | Config the donation applied to.           |
| `mint`                     | `pubkey`   | Donated mint.                             |
| `epoch`                    | `u128`     | Epoch when the donation was recorded.     |
| `gross_amount`             | `u64`      | Total amount transferred in (base units). |
| `tip`                      | `u64`      | Tip portion from `tip_bps`.               |
| `message`                  | `string`   | Donor message.                            |
| `credited_to`              | `pubkey`   | Credited party.                           |

### Relayer-only instructions (do not integrate)

These require the relayer signer and are **not** for end-user wallets:

* `close_donation_epoch_v1`
* `distribute_non_swap_output_mint_v1`
* `swap_then_distribute_v1`
* `upsert_mint_whitelist_v1`
