# sendfun-sdk
Rust SDK for the send.fun programs on Solana.
- `launchpad`: token creation, bonding curve trades, migration.
- `dex`: AMM trades after migration.
- `nexus`: staking and partner fees.
- `transfer_hook`: Token-2022 transfer-hook resolution.
- `utils`: `MintInfo`.
The SDK builds instructions, decodes accounts and events, and calculates quotes
(`launchpad::quote`, `dex::quote`). It has no RPC client and does not send
transactions.
Fetch accounts with your own client. Compatible: `solana-rpc-client` 3.x and
4.1+, blocking and nonblocking. Not compatible: 4.0.x.
Decode an account with the `from_account` function of its type. `from_account`
checks the owner, then the discriminator:
```rust,ignore
use sendfun_sdk::launchpad::accounts::BondingCurve;
let account = rpc.get_account(&address)?;
let curve = BondingCurve::from_account(&account.owner, &account.data)?;
```
`get_account` fails when the account does not exist. For an account that can
be missing, use `get_account_with_commitment`. Its `value` is `None` for a
missing account. Decode with `from_account_maybe`. It returns `Ok(None)` for an
uncreated PDA that holds lamports.
## Install
```sh
cargo add sendfun-sdk
```
Optional features:
- `serde`: `Serialize` and `Deserialize` on accounts, events and types.
- `anchor`: `anchor-lang` interop for on-chain callers.
## Rules
- For a trade, read `platform_config` from the bonding curve or the pool.
- A partner other than `DEFAULT_PARTNER` must sign.
- `constants::find_platform_address(slug)` returns the key of a platform.
- Each trade, migrate and create builder takes a `MintInfo` for the base mint
and a `MintInfo` for the quote mint. For the new base mint of a create, use
`MintInfo::launch`. Load a `MintInfo` as below. Refresh it on a timer, like
any account: load it and fill it again. For WSOL and USDC, you can also use `constants::WSOL_MINT_INFO`
and `constants::USDC_MINT_INFO`.
- The trade and migrate builders refuse a base mint that is not a Token-2022
mint.
- A build can fail with `HookError::NotLoaded`. See its doc.
- The SDK refuses a hook list that it cannot resolve before the instruction
runs. A transaction can still fail at the hook. Simulate it.
- Do not edit the `generated` modules. They come from the program IDLs.
Read the mints and the `Clock` in one call, then fill each hook:
```rust,ignore
use sendfun_sdk::transfer_hook::{AccountView, FetchedAccount};
use sendfun_sdk::utils::MintInfo;
use sendfun_sdk::constants::CLOCK_SYSVAR_ID as CLOCK;
// One call, so the fee is the fee at the mint read.
let accounts = rpc.get_multiple_accounts(&[base_mint, quote_mint, CLOCK])?;
let [Some(base), Some(quote), Some(clock)] = accounts.as_slice() else {
return Err("missing account".into());
};
let clock = AccountView { owner: &clock.owner, data: &clock.data };
let mut base_mint_info = MintInfo::load(
base_mint,
AccountView { owner: &base.owner, data: &base.data },
clock,
)?;
let mut quote_mint_info = MintInfo::load(
quote_mint,
AccountView { owner: "e.owner, data: "e.data },
clock,
)?;
for info in [&mut base_mint_info, &mut quote_mint_info] {
loop {
let next = info.missing()?;
if next.is_empty() {
break;
}
for (address, account) in next.iter().zip(rpc.get_multiple_accounts(&next)?) {
info.insert(*address, account.map(|a| FetchedAccount { owner: a.owner, data: a.data }));
}
}
}
```
A builder quotes the fee at the epoch of the read. Read the mint again when the
epoch changes. `transfer_fee` holds the whole `FeeSchedule`: `fee_at(epoch)`
gives the fee at another epoch, and `newer_epoch` the epoch the fee changes.
`MintInfo::load_at` reads a mint at an epoch, with no `Clock`. `hook_program` and `validation_address()` give a hooked
mint's hook program and the account that holds its list.
A router that cannot simulate checks each trade direction with
`transfer_hook::route::trade`. It takes both `MintInfo`s, and reads every other
account a list reads from the router's own cache. `transfer_hook::route::screen`
checks a direction for any trader, before the router knows the trader.
`transfer_hook::route::MarketLoad` loads and screens a market at each update. It
names the accounts to fetch and the accounts to declare for the next update.
## Documentation
<https://docs.send.fun>
## License
MIT, see the `LICENSE` file.