# anchor_prescan report — research/arena/stake-flow
# generated 2026-10-08T05:27:08Z · candidate sites only, manual review required

## C1 Sysvar signature checks — is the signed MESSAGE compared, not just length-checked?
    (no sysvar signature verification in tree)

## C2 Signed time fields — every committed deadline/valid_* needs a Clock check
  signed/field 'expiry' present:
    223:    /// User stakes tokens in locked mode. Creates a UserStake PDA with lockup expiry.
    253:        // SECURITY: Lockup expiry calculated with checked math
    -> clock comparison against 'expiry' FOUND

## C3 Domain tags — must bind program id / cluster context

## C4 TokenInterface init — init/init_if_needed must pin token::token_program
    46:    self, Burn, Mint, MintTo, TokenAccount, TokenInterface, TransferChecked,
    938:    pub stake_token_mint: InterfaceAccount<'info, Mint>,
    950:    pub stx_mint: InterfaceAccount<'info, Mint>,
    961:    pub stake_vault: InterfaceAccount<'info, TokenAccount>,
    972:    pub reserve_vault: InterfaceAccount<'info, TokenAccount>,
    977:    pub token_program: Interface<'info, TokenInterface>,
    1027:    pub stx_mint: InterfaceAccount<'info, Mint>,
    1029:    pub stake_token_mint: InterfaceAccount<'info, Mint>,
    -> token_program pin found (verify EVERY init site, not just one)

## C5 Mint acceptance — freeze_authority / Token-2022 extensions on vault mints
    181:                    mint: ctx.accounts.stake_token_mint.to_account_info(),
    198:                    mint: ctx.accounts.stx_mint.to_account_info(),
    239:                    mint: ctx.accounts.stake_token_mint.to_account_info(),
    310:                    mint: ctx.accounts.stx_mint.to_account_info(),
    327:                    mint: ctx.accounts.stake_token_mint.to_account_info(),
    409:                    mint: ctx.accounts.stake_token_mint.to_account_info(),
    491:                    mint: ctx.accounts.stake_token_mint.to_account_info(),
    595:                    mint: ctx.accounts.stake_token_mint.to_account_info(),
    622:                    mint: ctx.accounts.stake_token_mint.to_account_info(),
    670:                        mint: ctx.accounts.stake_token_mint.to_account_info(),

## C6 Software crypto where a syscall exists

## C7 Event completeness — state-changing ixs should emit all index keys
  events in research/arena/stake-flow/programs/stake-flow/src/lib.rs:
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1478: #[event]
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1479: pub struct ProtocolInitialized {
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1480:     pub admin: Pubkey,
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1481:     pub liquid_rate: u64,
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1482:     pub locked_rate: u64,
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1483: }
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1485: #[event]
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1486: pub struct OperatorChanged {
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1487:     pub old_operator: Pubkey,
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1488:     pub new_operator: Pubkey,
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1489: }
    research/arena/stake-flow/programs/stake-flow/src/lib.rs: 1491: #[event]

## C8 Fund-path arithmetic — money math with zero checked_/saturating_ in file

## C9 Authority fields — Signer-typed or has_one-bound, not raw AccountInfo
    975:    pub admin: Signer<'info>,
    992:    pub admin: Signer<'info>,
    1008:    pub authority: Signer<'info>,
    1433:    pub admin: Pubkey,                  // 32
    1434:    pub operator: Pubkey,               // 32
    1480:    pub admin: Pubkey,
  authority-like fields: 6 | Signer-typed: 3 | has_one-bound: 1

## C10 Initialize contexts — can first caller capture authority, or prefund brick init?
  init site in research/arena/stake-flow/programs/stake-flow/src/lib.rs (constraint/has_one/address lines: 22) — verify payer/authority is bound to expected admin (FrankSol F-12/F-13 class: MEDIUM, first-caller captures YieldState.authority / Pool.admin)
    92:        config.admin = ctx.accounts.admin.key();
    148:    /// User stakes tokens in liquid mode. Receives stX tokens at current exchange rate.
    650:        // SECURITY: Ensure source and destination vaults are different
    786:        // NOTE: UserStake account is closed via `close = user` constraint — rent returned to user
    930:        payer = admin,
    943:        payer = admin,
    947:        mint::authority = protocol_config,
    948:        mint::freeze_authority = protocol_config,
  (also check: vault/config PDAs that must sign but are created via init — prefunded lamports cause 'already in use' DoS; FrankSol F-11 MEDIUM)

## C11 Status/state enums — every write must be conditioned on legal current state

## C12 Slippage/min-out — compare user receives AFTER fees, not gross amount
    (no slippage/min-out fields in tree)

## S Standing checks — sites for manual review
  'init_if_needed': 1 site(s)
  'close\s*=': 4 site(s)
  'has_one': 5 site(s)
  'seeds\s*=': 49 site(s)
  'bump': 51 site(s)
  'Clock::get': 6 site(s)
  'as u64|as u32|as u16|as u8': 10 site(s)
  'try_into|checked_|saturating_|unwrap\(\)|expect\(': 38 site(s)
  --- detail ---
    1290:        init_if_needed,
    430:        // NOTE: UserStake account is closed via `close = user` constraint
    786:        // NOTE: UserStake account is closed via `close = user` constraint — rent returned to user
    1182:        close = user,
    1339:        close = user,

# END — triage order: C1 > C2 > C3 > C4 > C8 > C9 > C11 > C10 > C12 > C5 > C6 > C7 > S
