wasm_client_solana 0.11.2

A wasm compatible solana rpc and pubsub client
Documentation
use serde::Deserialize;
use serde::Serialize;
use serde_tuple::Deserialize_tuple;
use serde_tuple::Serialize_tuple;
use serde_with::DisplayFromStr;
use serde_with::serde_as;
use serde_with::skip_serializing_none;
use solana_signature::Signature;
#[cfg(test)]
use solana_transaction_status_client_types_wasm::option_serializer::OptionSerializer;

use crate::impl_http_method;
use crate::rpc_config::RpcTransactionConfig;
use crate::solana_transaction_status::EncodedConfirmedTransactionWithStatusMeta;

#[serde_as]
#[skip_serializing_none]
#[derive(Debug, Serialize_tuple, Deserialize_tuple)]
pub struct GetTransactionRequest {
	#[serde_as(as = "DisplayFromStr")]
	pub signature: Signature,
	pub config: Option<RpcTransactionConfig>,
}

impl_http_method!(GetTransactionRequest, "getTransaction");

impl GetTransactionRequest {
	pub fn new(signature: Signature) -> Self {
		Self {
			signature,
			config: None,
		}
	}

	pub fn new_with_config(signature: Signature, config: RpcTransactionConfig) -> Self {
		Self {
			signature,
			config: Some(config),
		}
	}
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct GetTransactionResponse(Option<EncodedConfirmedTransactionWithStatusMeta>);

impl From<GetTransactionResponse> for Option<EncodedConfirmedTransactionWithStatusMeta> {
	fn from(value: GetTransactionResponse) -> Self {
		value.0
	}
}

#[cfg(test)]
mod tests {
	use std::str::FromStr;

	use assert2::check;
	use solana_message::MessageHeader;

	use super::*;
	use crate::ClientRequest;
	use crate::ClientResponse;
	use crate::methods::HttpMethod;
	use crate::solana_transaction_status::EncodedTransaction;
	use crate::solana_transaction_status::UiCompiledInstruction;
	use crate::solana_transaction_status::UiMessage;
	use crate::solana_transaction_status::UiRawMessage;
	use crate::solana_transaction_status::UiTransaction;
	use crate::solana_transaction_status::UiTransactionEncoding;
	use crate::solana_transaction_status::UiTransactionStatusMeta;

	// Serialization differs a bit from the RPC API but it is allowed too
	#[test]
	fn request() {
		let request = ClientRequest::builder()
			.method(GetTransactionRequest::NAME)
			.id(1)
			.params(GetTransactionRequest::new_with_config(Signature::from_str("2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv").unwrap(), RpcTransactionConfig {
					encoding: Some(UiTransactionEncoding::Json),
					..Default::default()
			}))
			.build();

		insta::assert_compact_json_snapshot!(request, @r###"
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTransaction",
    "params": [
      "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv",
      {
        "encoding": "json"
      }
    ]
  }
  "###);
	}

	#[test]
	fn response() {
		let raw_json = r#"{"jsonrpc":"2.0","result":{"meta":{"err":null,"fee":5000,"innerInstructions":[],"postBalances":[499998932500,26858640,1,1,1],"postTokenBalances":[],"preBalances":[499998937500,26858640,1,1,1],"preTokenBalances":[],"rewards":[],"status":{"Ok":null}},"slot":430,"transaction":{"message":{"accountKeys":["3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe","AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":1},"instructions":[{"accounts":[1,2,3,0],"data":"37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1","programIdIndex":4}],"recentBlockhash":"mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B"},"signatures":["2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv"]}},"blockTime":null,"id":1}"#;

		let response: ClientResponse<GetTransactionResponse> =
			serde_json::from_str(raw_json).unwrap();

		check!(response.id == 1);
		check!(response.jsonrpc == "2.0");
		check!(
            response.result.0 ==
            Some(EncodedConfirmedTransactionWithStatusMeta {
                block_time: None,
                transaction_index: None,
                slot: 430,
                transaction:
                    crate::solana_transaction_status::EncodedTransactionWithStatusMeta {
                        transaction: EncodedTransaction::Json(UiTransaction {
                            message: UiMessage::Raw(UiRawMessage {
                                header: MessageHeader {
                                    num_readonly_signed_accounts: 0,
                                    num_readonly_unsigned_accounts: 3,
                                    num_required_signatures: 1
                                },
                                address_table_lookups: None,
                                recent_blockhash: "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B".parse().unwrap(),
                                instructions: vec![UiCompiledInstruction {
                                    program_id_index: 4,
                                    accounts: vec![1, 2, 3, 0],
                                    data: "37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1".to_string(),
																		stack_height: None,
                                }],
                                account_keys: vec![
                                    "3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe".parse().unwrap(),
                                    "AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc".parse().unwrap(),
                                    "SysvarS1otHashes111111111111111111111111111".parse().unwrap(),
                                    "SysvarC1ock11111111111111111111111111111111".parse().unwrap(),
                                    "Vote111111111111111111111111111111111111111".parse().unwrap(),
                                ],
                                transaction_config: None,
                            }),
                            signatures: vec!["2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv".parse().unwrap()]
                        }),
                        version: None,
                        meta: Some(UiTransactionStatusMeta {
                            err: None,
                            fee: 5000,
                            inner_instructions: OptionSerializer::Some(vec![]),
                            post_balances: vec![499_998_932_500, 26_858_640, 1, 1, 1],
                            post_token_balances: OptionSerializer::Some(vec![]),
                            pre_balances: vec![499_998_937_500, 26_858_640, 1, 1, 1],
                            pre_token_balances: OptionSerializer::Some(vec![]),
                            rewards: OptionSerializer::Some(vec![]),
                            status: Ok(()),
                            loaded_addresses: OptionSerializer::Skip,
                            log_messages: OptionSerializer::None,
                            return_data: OptionSerializer::Skip,
														compute_units_consumed: OptionSerializer::Skip,
														cost_units: OptionSerializer::Skip,
                        }),
                    }
            })
        );
	}
}