use std::hash::Hasher;
use crate::pubkey::Pubkey;
use derive_more::{From, Into};
use pyo3::{prelude::*, types::PyBytes};
use serde::{Deserialize, Serialize};
use solana_sdk::{
instruction::{
AccountMeta as AccountMetaOriginal, CompiledInstruction as CompiledInstructionOriginal,
Instruction as InstructionOriginal,
},
pubkey::Pubkey as PubkeyOriginal,
};
use solders_macros::{common_methods, pyhash, richcmp_eq_only};
use solders_traits::{
impl_display, py_from_bytes_general_via_bincode, pybytes_general_via_bincode,
CommonMethodsCore, PyHash, RichcmpEqualityOnly,
};
#[pyclass(module = "solders.instruction", subclass)]
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize, From, Into)]
pub struct AccountMeta(AccountMetaOriginal);
#[pyhash]
#[richcmp_eq_only]
#[common_methods]
#[pymethods]
impl AccountMeta {
#[new]
pub fn new(pubkey: &Pubkey, is_signer: bool, is_writable: bool) -> Self {
let underlying_pubkey = pubkey.into();
let underlying = if is_writable {
AccountMetaOriginal::new(underlying_pubkey, is_signer)
} else {
AccountMetaOriginal::new_readonly(underlying_pubkey, is_signer)
};
underlying.into()
}
#[getter]
pub fn pubkey(&self) -> Pubkey {
self.0.pubkey.into()
}
#[getter]
pub fn is_signer(&self) -> bool {
self.0.is_signer
}
#[getter]
pub fn is_writable(&self) -> bool {
self.0.is_writable
}
#[staticmethod]
pub fn from_bytes(data: &[u8]) -> PyResult<Self> {
Self::py_from_bytes(data)
}
}
pybytes_general_via_bincode!(AccountMeta);
impl RichcmpEqualityOnly for AccountMeta {}
py_from_bytes_general_via_bincode!(AccountMeta);
solders_traits::common_methods_default!(AccountMeta);
impl PyHash for AccountMeta {}
impl_display!(AccountMeta);
#[allow(clippy::derive_hash_xor_eq)]
impl std::hash::Hash for AccountMeta {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.pubkey.hash(state);
self.0.is_signer.hash(state);
self.0.is_writable.hash(state);
}
}
#[pyclass(module = "solders.instruction", subclass)]
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize, From, Into)]
pub struct Instruction(pub InstructionOriginal);
#[richcmp_eq_only]
#[common_methods]
#[pymethods]
impl Instruction {
#[new]
pub fn new(program_id: &Pubkey, data: &[u8], accounts: Vec<AccountMeta>) -> Self {
let underlying_accounts: Vec<AccountMetaOriginal> =
accounts.into_iter().map(|x| x.0).collect();
let underlying =
InstructionOriginal::new_with_bytes(program_id.into(), data, underlying_accounts);
underlying.into()
}
#[getter]
pub fn program_id(&self) -> Pubkey {
self.0.program_id.into()
}
#[getter]
pub fn data<'a>(&self, py: Python<'a>) -> &'a PyBytes {
PyBytes::new(py, &self.0.data)
}
#[getter]
pub fn accounts(&self) -> Vec<AccountMeta> {
self.0
.accounts
.clone()
.into_iter()
.map(AccountMeta)
.collect()
}
#[setter]
pub fn set_accounts(&mut self, accounts: Vec<AccountMeta>) {
self.0.accounts = accounts
.into_iter()
.map(AccountMetaOriginal::from)
.collect();
}
#[staticmethod]
pub fn from_bytes(data: &[u8]) -> PyResult<Self> {
Self::py_from_bytes(data)
}
}
pybytes_general_via_bincode!(Instruction);
impl RichcmpEqualityOnly for Instruction {}
py_from_bytes_general_via_bincode!(Instruction);
solders_traits::common_methods_default!(Instruction);
impl_display!(Instruction);
impl AsRef<InstructionOriginal> for Instruction {
fn as_ref(&self) -> &InstructionOriginal {
&self.0
}
}
#[pyclass(module = "solders.instruction", subclass)]
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize, From, Into)]
pub struct CompiledInstruction(CompiledInstructionOriginal);
#[richcmp_eq_only]
#[common_methods]
#[pymethods]
impl CompiledInstruction {
#[new]
pub fn new(program_id_index: u8, data: &[u8], accounts: &[u8]) -> Self {
CompiledInstructionOriginal::new_from_raw_parts(
program_id_index,
data.to_vec(),
accounts.to_vec(),
)
.into()
}
pub fn program_id(&self, program_ids: Vec<Pubkey>) -> Pubkey {
let underlying_pubkeys: Vec<PubkeyOriginal> =
program_ids.iter().map(PubkeyOriginal::from).collect();
let underlying = *self.0.program_id(&underlying_pubkeys);
underlying.into()
}
#[getter]
pub fn program_id_index(&self) -> u8 {
self.0.program_id_index
}
#[getter]
pub fn accounts<'a>(&self, py: Python<'a>) -> &'a PyBytes {
PyBytes::new(py, &self.0.accounts)
}
#[setter]
pub fn set_accounts(&mut self, accounts: Vec<u8>) {
self.0.accounts = accounts
}
#[getter]
pub fn data<'a>(&self, py: Python<'a>) -> &'a PyBytes {
PyBytes::new(py, &self.0.data)
}
#[staticmethod]
pub fn from_bytes(data: &[u8]) -> PyResult<Self> {
Self::py_from_bytes(data)
}
}
pybytes_general_via_bincode!(CompiledInstruction);
impl RichcmpEqualityOnly for CompiledInstruction {}
py_from_bytes_general_via_bincode!(CompiledInstruction);
solders_traits::common_methods_default!(CompiledInstruction);
impl_display!(CompiledInstruction);
impl AsRef<CompiledInstructionOriginal> for CompiledInstruction {
fn as_ref(&self) -> &CompiledInstructionOriginal {
&self.0
}
}