Created
August 28, 2025 08:52
-
-
Save thlorenz/811a613eb63b646b6c135d6d2b59b62f to your computer and use it in GitHub Desktop.
Analyzing Solana Feepayer enforcement on Transaction Sanitization
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "feepayer" | |
version = "0.1.0" | |
edition = "2024" | |
[dependencies] | |
solana-instruction = "3.0.0" | |
solana-pubkey = "3.0.0" | |
solana-sanitize = "3.0.1" | |
solana-transaction = { version = "3.0.1", features = ["blake3"] } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashSet; | |
use solana_sanitize::Sanitize; | |
use solana_instruction::{AccountMeta, Instruction}; | |
use solana_pubkey::Pubkey; | |
use solana_transaction::{sanitized::SanitizedTransaction, Transaction}; | |
fn sanitize_ixs(ixs: &[Instruction], payer: Option<Pubkey>, label: &str) -> Transaction { | |
let tx = Transaction::new_with_payer(ixs, payer.as_ref()); | |
let res = tx.sanitize(); | |
eprintln!("{label:18}: {res:?}"); | |
tx | |
} | |
fn main() { | |
let program = Pubkey::default(); | |
let payer = Pubkey::new_unique(); | |
// No accounts | |
let ix = Instruction::new_with_bytes(program, &[], vec![]); | |
sanitize_ixs(&[ix], None, "Empty Accounts"); | |
// Readonly Payer | |
let payer_meta = AccountMeta::new_readonly(payer, false); | |
let ix = Instruction::new_with_bytes(program, &[], vec![payer_meta]); | |
sanitize_ixs(&[ix], None, "Readonly"); | |
// Readonly signing payer | |
let payer_meta = AccountMeta::new_readonly(payer, true); | |
let ix = Instruction::new_with_bytes(program, &[], vec![payer_meta]); | |
sanitize_ixs(&[ix], None, "Readonly signing"); | |
// Writable Payer | |
let payer_meta = AccountMeta::new(payer, false); | |
let ix = Instruction::new_with_bytes(program, &[], vec![payer_meta]); | |
sanitize_ixs(&[ix], None, "Writable"); | |
// Writable signing payer | |
let payer_meta = AccountMeta::new(payer, true); | |
let ix = Instruction::new_with_bytes(program, &[], vec![payer_meta]); | |
let tx = sanitize_ixs(&[ix], None, "Writable signing"); | |
let sanitized = SanitizedTransaction::try_from_legacy_transaction(tx.clone(), &HashSet::new()); | |
eprintln!(" : {sanitized:#?}"); | |
// Explicit payer | |
let ix = Instruction::new_with_bytes(program, &[], vec![]); | |
let tx = sanitize_ixs(&[ix], Some(payer), "Explicit payer"); | |
let sanitized = SanitizedTransaction::try_from_legacy_transaction(tx.clone(), &HashSet::new()); | |
eprintln!(" : {sanitized:#?}"); | |
// Explicit payer used as readonly in ix | |
let payer_meta = AccountMeta::new_readonly(payer, false); | |
let ix = Instruction::new_with_bytes(program, &[], vec![payer_meta]); | |
let tx = sanitize_ixs( | |
&[ix], | |
Some(payer), | |
"Explicit payer included as readonly not signing", | |
); | |
let sanitized = SanitizedTransaction::try_from_legacy_transaction(tx.clone(), &HashSet::new()); | |
eprintln!(" : {sanitized:#?}"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment