◂ labs
TIER 1 · THE ACCOUNT MODEL · 3-type-cosplay
TYPE COSPLAY
Two account structs with identical layout but different meaning. Pass account B where A is expected: fields reinterpreted, authority fields become balances. Anchor fixes this with the 8-byte discriminator — raw Solana programs must roll their own.
seen in the wild
The reason Anchor prepends a type discriminator to every account — without it, bytes are just bytes.
rust · anchor
use anchor_lang::prelude::*;
use borsh::{BorshDeserialize, BorshSerialize};
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod type_cosplay_insecure {
use super::*;
pub fn update_user(ctx: Context<UpdateUser>) -> ProgramResult {
let user = User::try_from_slice(&ctx.accounts.user.data.borrow()).unwrap();
if ctx.accounts.user.owner != ctx.program_id {
return Err(ProgramError::IllegalOwner);
}
if user.authority != ctx.accounts.authority.key() {
return Err(ProgramError::InvalidAccountData);
}
msg!("GM {}", user.authority);
Ok(())
}
}
#[derive(Accounts)]
pub struct UpdateUser<'info> {
user: AccountInfo<'info>,
authority: Signer<'info>,
}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct User {
authority: Pubkey,
}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Metadata {
account: Pubkey,
}
next labREINITIALIZATION ▸