← Program logic

programs/bond_servicing/src/instructions/open_event.rs

Source at revision e5ff2b3cb157, the source of the program deployed on devnet. SHA-256 of this file a8db517b219ea888576d5cdc91793be6722aaee2cbae5f206e3403e84b4c6bcd

1//! Open a coupon (index < periods) or the redemption (index = periods) once its record moment has passed.
2//! Anyone may call it: everything it writes follows from the terms and the bond's supply history.
3//!   - supply at the record moment: from the supply history, no holder count needed;
4//!   - budget: the event's amount for the whole supply, rounded down once (each holder's amount is rounded
5//!     down on its own, so the holders' amounts never exceed it);
6//!   - vault: a cash account of this event alone, owned by the Bond PDA, so events cannot spend each other's
7//!     cash.
8
9use anchor_lang::prelude::*;
10use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
11
12use crate::constants::*;
13use crate::error::BondError;
14use crate::events::EventOpened;
15use crate::state::{Bond, Event, EventKind};
16
17#[derive(Accounts)]
18#[instruction(index: u16)]
19pub struct OpenEvent<'info> {
20    #[account(mut)]
21    pub payer: Signer<'info>,
22
23    #[account(has_one = cash_mint)]
24    pub bond: Box<Account<'info, Bond>>,
25
26    #[account(
27        init,
28        payer = payer,
29        space = 8 + Event::INIT_SPACE,
30        seeds = [EVENT_SEED, bond.key().as_ref(), &index.to_le_bytes()],
31        bump,
32    )]
33    pub event: Box<Account<'info, Event>>,
34
35    pub cash_mint: Box<InterfaceAccount<'info, Mint>>,
36
37    #[account(
38        init,
39        payer = payer,
40        seeds = [VAULT_SEED, event.key().as_ref()],
41        bump,
42        token::mint = cash_mint,
43        token::authority = bond,
44        token::token_program = cash_token_program,
45    )]
46    pub vault: Box<InterfaceAccount<'info, TokenAccount>>,
47
48    pub cash_token_program: Interface<'info, TokenInterface>,
49    pub system_program: Program<'info, System>,
50}
51
52pub fn handle_open_event(ctx: Context<OpenEvent>, index: u16) -> Result<()> {
53    let bond = &ctx.accounts.bond;
54    let period = bond.period_of(index)?;
55    let record_time = bond.record_time(index)?;
56    require!(bond.now()? >= record_time, BondError::RecordMomentNotReached);
57
58    let is_redemption = index == bond.redemption_event();
59    let supply = bond.supply.at_moment(period);
60    let budget = if is_redemption { bond.principal(supply)? } else { bond.coupon(supply, period)? };
61
62    let event = &mut ctx.accounts.event;
63    event.bond = bond.key();
64    event.index = index;
65    event.kind = if is_redemption { EventKind::Redemption } else { EventKind::Coupon };
66    event.record_time = record_time;
67    event.payment_time = bond.payment_time(index)?;
68    event.supply_at_record = supply;
69    event.budget = budget;
70    event.vault = ctx.accounts.vault.key();
71    event.funded = false;
72    event.bump = ctx.bumps.event;
73    emit!(EventOpened { bond: bond.key(), event: index, supply_at_record: supply, budget, vault: event.vault });
74    Ok(())
75}