switchboard-on-demand 0.4.8

A Rust library to interact with the Switchboard Solana program.
Documentation
use std::convert::TryInto;

use anyhow::Result;

pub const HASHED_PUBKEY_SERIALIZED_SIZE: usize = 20;
pub const SIGNATURE_SERIALIZED_SIZE: usize = 64;
pub const SIGNATURE_OFFSETS_SERIALIZED_SIZE: usize = 11;

#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct SecpSignatureOffsets {
    pub signature_offset: u16,
    pub signature_instruction_index: u8,
    pub eth_address_offset: u16,
    pub eth_address_instruction_index: u8,
    pub message_data_offset: u16,
    pub message_data_size: u16,
    pub message_instruction_index: u8,
}

#[derive(Debug)]
pub struct ParsedSignatureData {
    pub offsets: SecpSignatureOffsets,
    pub eth_address: [u8; HASHED_PUBKEY_SERIALIZED_SIZE],
    pub signature: [u8; SIGNATURE_SERIALIZED_SIZE],
    pub recovery_id: u8,
    pub message: Vec<u8>,
}

pub struct SecpSysvar;
impl SecpSysvar {
    pub fn parse_combined_secp256k1_instruction(data: &[u8]) -> Result<Vec<ParsedSignatureData>> {
        let mut parsed_signatures = Vec::new();
        let num_signatures = data[0] as usize;
        let mut offset = 1;
        for _ in 0..num_signatures {
            let signature_offset = u16::from_le_bytes([data[offset], data[offset + 1]]);
            let signature_instruction_index = data[offset + 2];
            let eth_address_offset = u16::from_le_bytes([data[offset + 3], data[offset + 4]]);
            let eth_address_instruction_index = data[offset + 5];
            let message_data_offset = u16::from_le_bytes([data[offset + 6], data[offset + 7]]);
            let message_data_size = u16::from_le_bytes([data[offset + 8], data[offset + 9]]);
            let message_instruction_index = data[offset + 10];

            let offsets = SecpSignatureOffsets {
                signature_offset,
                signature_instruction_index,
                eth_address_offset,
                eth_address_instruction_index,
                message_data_offset,
                message_data_size,
                message_instruction_index,
            };

            let eth_address = data[eth_address_offset as usize
                ..eth_address_offset as usize + HASHED_PUBKEY_SERIALIZED_SIZE]
                .try_into()
                .unwrap();
            let signature = data
                [signature_offset as usize..signature_offset as usize + SIGNATURE_SERIALIZED_SIZE]
                .try_into()
                .unwrap();
            let recovery_id = data[signature_offset as usize + SIGNATURE_SERIALIZED_SIZE];
            let message = data[message_data_offset as usize
                ..message_data_offset as usize + message_data_size as usize]
                .to_vec();

            parsed_signatures.push(ParsedSignatureData {
                offsets,
                eth_address,
                signature,
                recovery_id,
                message,
            });
            offset += SIGNATURE_OFFSETS_SERIALIZED_SIZE;
        }

        Ok(parsed_signatures)
    }
}