cowprotocol / cowprotocol/solana-programs

Gate `Initialize` so it can't be frontrun

Open
#86 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
2
Forks
1
Avg merge
3d 1h
Merged PRs (30d)
32

Description

Claude recommended this code so that we can gate Initialize using the upgrade authority of the program:

use pinocchio::{
    account_info::AccountInfo,
    program_error::ProgramError,
    pubkey::Pubkey,
    ProgramResult,
};

const BPF_LOADER_UPGRADEABLE_ID: Pubkey =
    pinocchio_pubkey::pubkey!("BPFLoaderUpgradeab1e11111111111111111111111");

/// Assert `authority` is the upgrade authority of THIS program.
/// Expects the program's own executable account, its ProgramData account,
/// and the claimed authority (signer).
fn assert_upgrade_authority(
    program: &AccountInfo,
    program_data: &AccountInfo,
    authority: &AccountInfo,
) -> ProgramResult {
    // 1. Signer actually signed.
    if !authority.is_signer() {
        return Err(ProgramError::MissingRequiredSignature);
    }

    // 2. `program` is our own program account.
    if program.key() != &crate::ID {
        return Err(ProgramError::IncorrectProgramId);
    }

    // 3. Both loader accounts owned by BPFLoaderUpgradeable.
    if !program.is_owned_by(&BPF_LOADER_UPGRADEABLE_ID)
        || !program_data.is_owned_by(&BPF_LOADER_UPGRADEABLE_ID)
    {
        return Err(ProgramError::InvalidAccountOwner);
    }

    // 4. Program account must point at the ProgramData we were handed.
    //    Layout: [u32 discriminant = 2][programdata_address: Pubkey(32)]
    {
        let data = program.try_borrow_data()?;
        if data.len() < 36 || data[0..4] != [2, 0, 0, 0] {
            return Err(ProgramError::InvalidAccountData);
        }
        if &data[4..36] != program_data.key().as_ref() {
            return Err(ProgramError::InvalidAccountData);
        }
    }

    // 5. ProgramData: upgrade authority must be Some(authority).
    //    Layout: [u32 discriminant = 3][slot: u64][Option<Pubkey>]
    //            option tag @ 12, pubkey @ 13..45
    {
        let data = program_data.try_borrow_data()?;
        if data.len() < 45 || data[0..4] != [3, 0, 0, 0] {
            return Err(ProgramError::InvalidAccountData);
        }
        if data[12] != 1 {
            // None => program is immutable, nobody qualifies
            return Err(ProgramError::InvalidAccountData);
        }
        if &data[13..45] != authority.key().as_ref() {
            return Err(ProgramError::InvalidAccountData);
        }
    }

    Ok(())
}

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Locate the Initialize instruction and its account handling, then review the proposed Rust authority-checking code against the program's existing structure. Done means Initialize is gated by the program's upgrade authority and invalid loader, account, signer, or authority data is rejected; no test or file path is named in the issue.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
blockchain, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.