pub mod explorer;
use {
anchor_lang::{
prelude::borsh::BorshSchema,
prelude::Pubkey,
prelude::*,
solana_program::{self, instruction::Instruction},
AnchorDeserialize,
},
static_pubkey::static_pubkey,
std::{
fmt::{Debug, Display, Formatter},
convert::TryFrom,
hash::Hash,
},
base64,
};
pub static PAYER_PUBKEY: Pubkey = static_pubkey!("C1ockworkPayer11111111111111111111111111111");
pub fn anchor_sighash(name: &str) -> [u8; 8] {
let namespace = "global";
let preimage = format!("{}:{}", namespace, name);
let mut sighash = [0u8; 8];
sighash.copy_from_slice(
&anchor_lang::solana_program::hash::hash(preimage.as_bytes()).to_bytes()[..8],
);
sighash
}
#[derive(AnchorDeserialize, AnchorSerialize, BorshSchema, Clone, Debug, PartialEq)]
pub struct ClockData {
pub slot: u64,
pub epoch_start_timestamp: i64,
pub epoch: u64,
pub leader_schedule_epoch: u64,
pub unix_timestamp: i64,
}
impl From<Clock> for ClockData {
fn from(clock: Clock) -> Self {
ClockData {
slot: clock.slot,
epoch_start_timestamp: clock.epoch_start_timestamp,
epoch: clock.epoch,
leader_schedule_epoch: clock.leader_schedule_epoch,
unix_timestamp: clock.unix_timestamp,
}
}
}
impl From<&ClockData> for Clock {
fn from(clock: &ClockData) -> Self {
Clock {
slot: clock.slot,
epoch_start_timestamp: clock.epoch_start_timestamp,
epoch: clock.epoch,
leader_schedule_epoch: clock.leader_schedule_epoch,
unix_timestamp: clock.unix_timestamp,
}
}
}
impl TryFrom<Vec<u8>> for ClockData {
type Error = Error;
fn try_from(data: Vec<u8>) -> std::result::Result<Self, Self::Error> {
Ok(
borsh::try_from_slice_with_schema::<ClockData>(data.as_slice())
.map_err(|_err| ErrorCode::AccountDidNotDeserialize)?,
)
}
}
#[derive(AnchorDeserialize, AnchorSerialize, Clone, Debug)]
pub struct ThreadResponse {
pub kickoff_instruction: Option<InstructionData>,
pub next_instruction: Option<InstructionData>,
}
impl Default for ThreadResponse {
fn default() -> Self {
return Self {
kickoff_instruction: None,
next_instruction: None,
};
}
}
#[derive(AnchorDeserialize, AnchorSerialize, BorshSchema, Clone, Debug, Hash, PartialEq)]
pub struct InstructionData {
pub program_id: Pubkey,
pub accounts: Vec<AccountMetaData>,
pub data: Vec<u8>,
}
impl From<Instruction> for InstructionData {
fn from(instruction: Instruction) -> Self {
InstructionData {
program_id: instruction.program_id,
accounts: instruction
.accounts
.iter()
.map(|a| AccountMetaData {
pubkey: a.pubkey,
is_signer: a.is_signer,
is_writable: a.is_writable,
})
.collect(),
data: instruction.data,
}
}
}
impl From<&InstructionData> for Instruction {
fn from(instruction: &InstructionData) -> Self {
Instruction {
program_id: instruction.program_id,
accounts: instruction
.accounts
.iter()
.map(|a| AccountMeta {
pubkey: a.pubkey,
is_signer: a.is_signer,
is_writable: a.is_writable,
})
.collect(),
data: instruction.data.clone(),
}
}
}
impl TryFrom<Vec<u8>> for InstructionData {
type Error = Error;
fn try_from(data: Vec<u8>) -> std::result::Result<Self, Self::Error> {
Ok(
borsh::try_from_slice_with_schema::<InstructionData>(data.as_slice())
.map_err(|_err| ErrorCode::AccountDidNotDeserialize)?,
)
}
}
#[derive(AnchorDeserialize, AnchorSerialize, BorshSchema, Clone, Debug, Hash, PartialEq)]
pub struct AccountMetaData {
pub pubkey: Pubkey,
pub is_signer: bool,
pub is_writable: bool,
}
impl AccountMetaData {
pub fn new(pubkey: Pubkey, is_signer: bool) -> Self {
Self {
pubkey,
is_signer,
is_writable: true,
}
}
pub fn new_readonly(pubkey: Pubkey, is_signer: bool) -> Self {
Self {
pubkey,
is_signer,
is_writable: false,
}
}
}
#[derive(AnchorDeserialize, AnchorSerialize, Clone, Debug)]
pub struct CrateInfo {
pub spec: String,
pub blob: String,
}
impl Display for CrateInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "spec:{} blob:{}", self.spec, self.blob)
}
}
pub trait ProgramLogsDeserializable {
fn try_from_program_logs(
program_logs: Vec<String>,
program_id: &Pubkey,
) -> std::result::Result<Self, ErrorCode> where Self: Sized;
}
impl<T> ProgramLogsDeserializable for T
where
T: AnchorDeserialize
{
fn try_from_program_logs(
program_logs: Vec<String>,
program_id: &Pubkey,
) -> std::result::Result<T, ErrorCode> {
let preimage = format!("Program return: {} ", program_id.to_string());
let get_return_data_base64 = program_logs
.iter()
.find(|&s| s.starts_with(&preimage))
.ok_or(ErrorCode::AccountDidNotDeserialize)?
.strip_prefix(&preimage)
.ok_or(ErrorCode::AccountDidNotDeserialize)?;
let decoded = base64::decode(get_return_data_base64)
.map_err(|_err| ErrorCode::AccountDidNotDeserialize)?;
T::try_from_slice(&decoded).map_err(|_err| ErrorCode::AccountDidNotDeserialize)
}
}