# anchor_prescan report — research/x402-meridian
# generated 2026-10-08T05:28:29Z · candidate sites only, manual review required

## C1 Sysvar signature checks — is the signed MESSAGE compared, not just length-checked?
    research/x402-meridian/permit2/crypto.rs:3:use solana_sdk_ids::secp256k1_program;
    research/x402-meridian/permit2/crypto.rs:56:    require!(current_index > 0, Permit2Error::MissingSecp256k1Instruction);
    research/x402-meridian/permit2/crypto.rs:64:        secp256k1_program::ID,
    research/x402-meridian/permit2/crypto.rs:65:        Permit2Error::MissingSecp256k1Instruction
    research/x402-meridian/permit2/crypto.rs:68:    let offsets = parse_secp256k1_instruction(&secp_ix.data, secp_ix_index, data_hash)?;
    research/x402-meridian/permit2/crypto.rs:78:struct Secp256k1Offsets {
    research/x402-meridian/permit2/crypto.rs:83:fn parse_secp256k1_instruction(data: &[u8], self_index: u16, data_hash: &[u8; 32]) -> Result<Secp256k1Offsets> {
    research/x402-meridian/permit2/crypto.rs:87:        Permit2Error::MalformedSecp256k1Instruction
    research/x402-meridian/permit2/crypto.rs:92:        Permit2Error::MalformedSecp256k1Instruction
    research/x402-meridian/permit2/crypto.rs:97:        Permit2Error::MalformedSecp256k1Instruction
    research/x402-meridian/permit2/crypto.rs:109:        Permit2Error::MalformedSecp256k1Instruction
    research/x402-meridian/permit2/crypto.rs:113:        Permit2Error::MalformedSecp256k1Instruction
    research/x402-meridian/permit2/crypto.rs:118:        Permit2Error::MalformedSecp256k1Instruction
    research/x402-meridian/permit2/crypto.rs:125:        Permit2Error::MalformedSecp256k1Instruction
    research/x402-meridian/permit2/crypto.rs:134:    Ok(Secp256k1Offsets {
    research/x402-meridian/permit2/errors.rs:21:    #[msg("Preceding instruction must be a valid Secp256k1Program signature verification")]
    research/x402-meridian/permit2/errors.rs:22:    MissingSecp256k1Instruction,
    research/x402-meridian/permit2/errors.rs:23:    #[msg("Secp256k1Program instruction data is malformed")]
    research/x402-meridian/permit2/errors.rs:24:    MalformedSecp256k1Instruction,
  [FLAG] NO 'message == expected' comparison found — any correctly-sized payload may verify (Week-5 #275 class: CRITICAL)
    research/x402-meridian/permit2/crypto.rs:84:    const SIGNATURE_OFFSETS_SERIALIZED_SIZE: usize = 11;
    research/x402-meridian/permit2/crypto.rs:89:    let num_signatures = data[0];
    research/x402-meridian/permit2/crypto.rs:91:        num_signatures == 1,
    research/x402-meridian/permit2/crypto.rs:96:        data.len() >= 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE,
    research/x402-meridian/permit2/crypto.rs:99:    let o = &data[1..1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE];
    research/x402-meridian/permit2/crypto.rs:103:    let message_offset = u16::from_le_bytes([o[6], o[7]]) as usize;
    research/x402-meridian/permit2/crypto.rs:105:    let message_ix_index = o[10];
    research/x402-meridian/permit2/crypto.rs:112:        message_ix_index as u16 == self_index,

## C2 Signed time fields — every committed deadline/valid_* needs a Clock check
  signed/field 'deadline' present:
    research/x402-meridian/permit2/crypto.rs:29:        &permit.deadline.to_le_bytes(),
    research/x402-meridian/permit2/crypto.rs:45:        &permit.deadline.to_le_bytes(),
    research/x402-meridian/permit2/errors.rs:7:    #[msg("Signature deadline has passed")]
    research/x402-meridian/permit2/state.rs:32:    pub deadline: u64,
  [FLAG] 'deadline' committed but no on-chain Clock comparison found (Week-5 #273 class: CRITICAL if signed)
  signed/field 'valid_after' present:
    research/x402-meridian/x402/crypto.rs:23:        &witness.valid_after.to_le_bytes(),
    research/x402-meridian/x402/lib.rs:40:            (clock.unix_timestamp as u64) >= witness.valid_after,
    research/x402-meridian/x402/state.rs:8:    pub valid_after: u64,
    -> clock comparison against 'valid_after' FOUND

## C3 Domain tags — must bind program id / cluster context
    research/x402-meridian/permit2/crypto.rs:9:pub const DOMAIN_TAG: &[u8] = b"solana-permit2:SignatureTransfer";
    research/x402-meridian/permit2/crypto.rs:23:        DOMAIN_TAG,
    research/x402-meridian/permit2/crypto.rs:39:        DOMAIN_TAG,
    research/x402-meridian/permit2/lib.rs:16:    DOMAIN_TAG,
    research/x402-meridian/permit2/lib.rs:94:            DOMAIN_TAG,
    research/x402-meridian/x402/crypto.rs:5:const WITNESS_DOMAIN_TAG: &[u8] = b"solana-x402:Exact:Witness";
    research/x402-meridian/x402/crypto.rs:21:        WITNESS_DOMAIN_TAG,
  [FLAG] domain tag is a bare string literal — replayable across clones/clusters (Week-5 #281 class: CRITICAL)

## C4 TokenInterface init — init/init_if_needed must pin token::token_program
    research/x402-meridian/permit2/context.rs:3:use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
    research/x402-meridian/permit2/context.rs:16:    pub mint: InterfaceAccount<'info, Mint>,
    research/x402-meridian/permit2/context.rs:35:    pub vault_token_account: InterfaceAccount<'info, TokenAccount>,
    research/x402-meridian/permit2/context.rs:37:    pub token_program: Interface<'info, TokenInterface>,
    research/x402-meridian/permit2/context.rs:47:    pub mint: InterfaceAccount<'info, Mint>,
    research/x402-meridian/permit2/context.rs:57:    pub vault_token_account: InterfaceAccount<'info, TokenAccount>,
    research/x402-meridian/permit2/context.rs:60:    pub depositor_token_account: InterfaceAccount<'info, TokenAccount>,
    research/x402-meridian/permit2/context.rs:62:    pub token_program: Interface<'info, TokenInterface>,
  [FLAG] TokenInterface account(s) with init and NO token::token_program pin — wrong-program ATA bricking (Week-5 #276 class: HIGH)

## C5 Mint acceptance — freeze_authority / Token-2022 extensions on vault mints
    research/x402-meridian/permit2/context.rs:16:    pub mint: InterfaceAccount<'info, Mint>,
    research/x402-meridian/permit2/context.rs:47:    pub mint: InterfaceAccount<'info, Mint>,
    research/x402-meridian/permit2/context.rs:70:    pub mint: InterfaceAccount<'info, Mint>,
    research/x402-meridian/permit2/events.rs:6:    pub mint: Pubkey,
    research/x402-meridian/permit2/events.rs:14:    pub mint: Pubkey,
    research/x402-meridian/permit2/instructions.rs:73:                    mint: ctx.accounts.mint.to_account_info(),
    research/x402-meridian/permit2/instructions.rs:86:        mint: mint_key,
    research/x402-meridian/permit2/lib.rs:45:                    mint: ctx.accounts.mint.to_account_info(),
    research/x402-meridian/permit2/lib.rs:56:            mint: ctx.accounts.mint.key(),
    research/x402-meridian/permit2/state.rs:11:    pub mint: Pubkey,
  [FLAG] mint init accepted with no freeze_authority/extension rejection — stranded-deposit risk (Week-5 #277/#279 class)

## C6 Software crypto where a syscall exists
    research/x402-meridian/permit2/crypto.rs:4:use tiny_keccak::{Hasher, Keccak};
    research/x402-meridian/x402/crypto.rs:1:use tiny_keccak::{Hasher, Keccak};
  [FLAG] tiny_keccak software keccak — solana_program::keccak syscall is ~2x cheaper (Week-5 #278 class: LOW)

## C7 Event completeness — state-changing ixs should emit all index keys
  events in research/x402-meridian/permit2/events.rs:
    research/x402-meridian/permit2/events.rs: 3: #[event]
    research/x402-meridian/permit2/events.rs: 4: pub struct Deposited {
    research/x402-meridian/permit2/events.rs: 5:     pub eth_address: [u8; 20],
    research/x402-meridian/permit2/events.rs: 6:     pub mint: Pubkey,
    research/x402-meridian/permit2/events.rs: 7:     pub depositor: Pubkey,
    research/x402-meridian/permit2/events.rs: 8:     pub amount: u64,
    research/x402-meridian/permit2/events.rs: 9: }
    research/x402-meridian/permit2/events.rs: 11: #[event]
    research/x402-meridian/permit2/events.rs: 12: pub struct PermitTransferExecuted {
    research/x402-meridian/permit2/events.rs: 13:     pub eth_address: [u8; 20],
    research/x402-meridian/permit2/events.rs: 14:     pub mint: Pubkey,
    research/x402-meridian/permit2/events.rs: 15:     pub to: Pubkey,
  events in research/x402-meridian/x402/events.rs:
    research/x402-meridian/x402/events.rs: 3: #[event]
    research/x402-meridian/x402/events.rs: 4: pub struct Settled {
    research/x402-meridian/x402/events.rs: 5:     pub eth_address: [u8; 20],
    research/x402-meridian/x402/events.rs: 6:     pub to: Pubkey,
    research/x402-meridian/x402/events.rs: 7:     pub amount: u64,
    research/x402-meridian/x402/events.rs: 8:     pub nonce: u64,
    research/x402-meridian/x402/events.rs: 9: }

## C8 Fund-path arithmetic — money math with zero checked_/saturating_ in file
  [FLAG] research/x402-meridian/permit2/crypto.rs — 6 raw arith site(s), zero checked_/saturating_ in file (Week-4 arithmetic class: CRITICAL)
  [FLAG] research/x402-meridian/permit2/state.rs — 2 raw arith site(s), zero checked_/saturating_ in file (Week-4 arithmetic class: CRITICAL)
  [FLAG] research/x402-meridian/x402/errors.rs — 1 raw arith site(s), zero checked_/saturating_ in file (Week-4 arithmetic class: CRITICAL)

## C9 Authority fields — Signer-typed or has_one-bound, not raw AccountInfo
    research/x402-meridian/permit2/context.rs:14:    pub payer: Signer<'info>,
    research/x402-meridian/permit2/context.rs:108:    pub payer: Signer<'info>,

## C10 Initialize contexts — can first caller capture authority, or prefund brick init?
  (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': 2 site(s)
  'close\s*=': 1 site(s)
  'has_one': 1 site(s)
  'seeds\s*=': 8 site(s)
  'bump': 19 site(s)
  'Clock::get': 1 site(s)
  'as u64|as u32|as u16|as u8': 4 site(s)
  --- detail ---
    research/x402-meridian/permit2/context.rs:85:        init_if_needed,
    research/x402-meridian/permit2/context.rs:111:        init_if_needed,
    research/x402-meridian/permit2/context.rs:133:        close = rent_payer,

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