use pyo3::{basic::CompareOp, 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 crate::{handle_py_err, pubkey::Pubkey, RichcmpEqualityOnly};
#[pyclass(module = "solders.instruction", subclass)]
#[derive(PartialEq, Debug, Clone)]
pub struct AccountMeta(AccountMetaOriginal);
#[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
}
pub fn __repr__(&self) -> String {
format!("{:#?}", self)
}
pub fn __str__(&self) -> String {
format!("{:?}", self)
}
pub fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
self.richcmp(other, op)
}
}
impl RichcmpEqualityOnly for AccountMeta {}
impl From<AccountMetaOriginal> for AccountMeta {
fn from(am: AccountMetaOriginal) -> Self {
Self(am)
}
}
impl From<AccountMeta> for AccountMetaOriginal {
fn from(am: AccountMeta) -> Self {
am.0
}
}
#[pyclass(module = "solders.instruction", subclass)]
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct Instruction(pub InstructionOriginal);
#[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();
}
pub fn __repr__(&self) -> String {
format!("{:#?}", self)
}
pub fn __str__(&self) -> String {
format!("{:?}", self)
}
pub fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
self.richcmp(other, op)
}
pub fn __bytes__<'a>(&self, py: Python<'a>) -> &'a PyBytes {
let ser = bincode::serialize(&self).unwrap();
PyBytes::new(py, &ser)
}
#[staticmethod]
pub fn from_bytes(data: &[u8]) -> PyResult<Self> {
let deser = bincode::deserialize::<Self>(data);
handle_py_err(deser)
}
}
impl RichcmpEqualityOnly for Instruction {}
impl From<InstructionOriginal> for Instruction {
fn from(ix: InstructionOriginal) -> Self {
Self(ix)
}
}
impl From<Instruction> for InstructionOriginal {
fn from(ix: Instruction) -> InstructionOriginal {
ix.0
}
}
impl AsRef<InstructionOriginal> for Instruction {
fn as_ref(&self) -> &InstructionOriginal {
&self.0
}
}
#[pyclass(module = "solders.instruction", subclass)]
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
pub struct CompiledInstruction(CompiledInstructionOriginal);
#[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)
}
pub fn __repr__(&self) -> String {
format!("{:#?}", self)
}
pub fn __str__(&self) -> String {
format!("{:?}", self)
}
pub fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
self.richcmp(other, op)
}
pub fn __bytes__<'a>(&self, py: Python<'a>) -> &'a PyBytes {
let ser = bincode::serialize(&self).unwrap();
PyBytes::new(py, &ser)
}
#[staticmethod]
pub fn from_bytes(data: &[u8]) -> PyResult<Self> {
let deser = bincode::deserialize::<Self>(data);
handle_py_err(deser)
}
}
impl RichcmpEqualityOnly for CompiledInstruction {}
impl From<CompiledInstructionOriginal> for CompiledInstruction {
fn from(ix: CompiledInstructionOriginal) -> Self {
Self(ix)
}
}
impl From<CompiledInstruction> for CompiledInstructionOriginal {
fn from(ix: CompiledInstruction) -> Self {
ix.0
}
}
impl AsRef<CompiledInstructionOriginal> for CompiledInstruction {
fn as_ref(&self) -> &CompiledInstructionOriginal {
&self.0
}
}