← Bond stages

programs/bond_servicing/src/instructions/place.rs

Source snapshot · revision 5e22d3ea5fa4.

SHA-256 7ba0b26f62dfd740604fe1e6f29a415d1513e7cf27fd10705feb0243ad2e017a

1//! Placement: mints bonds to a registered holder's associated token account, before the first record moment and up to
2//! the bond's issue size. Updates the holder's quantity and the bond's supply, which the program alone changes.
3
4use anchor_lang::prelude::*;
5use anchor_spl::token_2022::{self, MintTo, Token2022};
6use anchor_spl::token_interface::{Mint, TokenAccount};
7
8use crate::constants::*;
9use crate::error::BondError;
10use crate::events::BondsPlaced;
11use crate::state::{Bond, HolderRecord};
12
13#[derive(Accounts)]
14pub struct Place<'info> {
15    pub registrar: Signer<'info>,
16
17    #[account(mut, has_one = registrar, has_one = mint)]
18    pub bond: Box<Account<'info, Bond>>,
19
20    #[account(mut)]
21    pub mint: Box<InterfaceAccount<'info, Mint>>,
22
23    #[account(mut, has_one = bond, seeds = [HOLDER_SEED, mint.key().as_ref(), holder.owner.as_ref()], bump = holder.bump)]
24    pub holder: Box<Account<'info, HolderRecord>>,
25
26    #[account(
27        mut,
28        associated_token::mint = mint,
29        associated_token::authority = holder.owner,
30        associated_token::token_program = token_program,
31    )]
32    pub holder_bonds: Box<InterfaceAccount<'info, TokenAccount>>,
33
34    pub token_program: Program<'info, Token2022>,
35}
36
37pub fn handle_place(ctx: Context<Place>, amount: u64) -> Result<()> {
38    let bond = &ctx.accounts.bond;
39    require!(bond.now()? < bond.record_time(0)?, BondError::PlacementClosed);
40    let new_supply = bond.supply.quantity.checked_add(amount).ok_or(BondError::IssueTooLarge)?;
41    require!(new_supply <= bond.max_supply, BondError::ExceedsIssueSize);
42    bond.check_serviceable(new_supply)?;
43    let mint_key = bond.mint;
44    let seeds: &[&[u8]] = &[BOND_SEED, mint_key.as_ref(), &[bond.bump]];
45    token_2022::mint_to(
46        CpiContext::new_with_signer(
47            ctx.accounts.token_program.key(),
48            MintTo {
49                mint: ctx.accounts.mint.to_account_info(),
50                to: ctx.accounts.holder_bonds.to_account_info(),
51                authority: ctx.accounts.bond.to_account_info(),
52            },
53            &[seeds],
54        ),
55        amount,
56    )?;
57
58    // Before the first record moment no history needs saving.
59    let holder = &mut ctx.accounts.holder;
60    holder.position.quantity = holder.position.quantity.checked_add(amount).ok_or(BondError::Overflow)?;
61    let bond = &mut ctx.accounts.bond;
62    bond.supply.quantity = bond.supply.quantity.checked_add(amount).ok_or(BondError::Overflow)?;
63    emit!(BondsPlaced { bond: bond.key(), owner: holder.owner, amount });
64    Ok(())
65}