Skip to content

Commit

Permalink
feat: GetSignaturesForAsset added
Browse files Browse the repository at this point in the history
  • Loading branch information
anamansari062 committed Apr 30, 2024
1 parent 13b4ad9 commit 32a4aad
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 58 deletions.
7 changes: 6 additions & 1 deletion src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::error::Result;
use crate::request_handler::RequestHandler;
use crate::types::types::{RpcRequest, RpcResponse};
use crate::types::{
Asset, AssetList, AssetProof, GetAsset, GetAssetBatch, GetAssetProof, GetAssetProofBatch, GetAssetsByAuthority, GetAssetsByCreator, GetAssetsByGroup, GetAssetsByOwner, SearchAssets
Asset, AssetList, AssetProof, GetAsset, GetAssetBatch, GetAssetProof, GetAssetProofBatch, GetAssetSignatures, GetAssetsByAuthority, GetAssetsByCreator, GetAssetsByGroup, GetAssetsByOwner, SearchAssets, TransactionSignatureList
};

use reqwest::{Client, Method, Url};
Expand Down Expand Up @@ -93,4 +93,9 @@ impl RpcClient {
pub async fn search_assets(&self, request: SearchAssets) -> Result<AssetList> {
self.post_rpc_request("searchAssets", request).await
}

/// Gets transaction signatures for a given asset
pub async fn get_asset_signatures(&self, request: GetAssetSignatures) -> Result<TransactionSignatureList> {
self.post_rpc_request("getSignaturesForAsset", request).await
}
}
127 changes: 70 additions & 57 deletions src/types/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,63 +117,6 @@ pub struct GetAssetsByCreator {
pub cursor: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct AssetSorting {
pub sort_by: AssetSortBy,
pub sort_direction: Option<AssetSortDirection>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct ApiResponse<T> {
pub jsonrpc: String,
pub result: T,
pub id: String,
}

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct AssetList {
#[serde(skip_serializing_if = "Option::is_none")]
pub grand_total: Option<u64>,
pub total: u32,
pub limit: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub page: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub before: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
pub items: Vec<Asset>,
#[serde(skip_serializing_if = "Option::is_none")]
pub errors: Option<Vec<AssetError>>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(default)]
pub struct AssetError {
pub id: String,
pub error: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GetAssetResponse {
pub interface: Interface,
pub id: String,
pub content: Option<Content>,
pub authorities: Option<Vec<Authorities>>,
pub compression: Option<Compression>,
pub grouping: Option<Vec<Group>>,
pub royalty: Option<Royalty>,
pub ownership: Ownership,
pub creators: Option<Vec<Creator>>,
pub uses: Option<Uses>,
pub supply: Option<Supply>,
pub mutable: bool,
pub burnt: bool,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GetAssetBatch {
pub ids: Vec<String>,
Expand Down Expand Up @@ -265,6 +208,76 @@ pub struct SearchAssets {
pub collection_nft: Option<bool>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct GetAssetSignatures {
pub id: Option<String>,
pub limit: Option<u32>,
pub page: Option<u32>,
pub before: Option<String>,
pub after: Option<String>,
pub tree: Option<String>,
pub leaf_index: Option<i64>,
#[serde(default)]
pub cursor: Option<String>,
#[serde(default)]
pub sort_direction: Option<AssetSortDirection>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct AssetSorting {
pub sort_by: AssetSortBy,
pub sort_direction: Option<AssetSortDirection>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct ApiResponse<T> {
pub jsonrpc: String,
pub result: T,
pub id: String,
}

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct AssetList {
#[serde(skip_serializing_if = "Option::is_none")]
pub grand_total: Option<u64>,
pub total: u32,
pub limit: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub page: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub before: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
pub items: Vec<Asset>,
#[serde(skip_serializing_if = "Option::is_none")]
pub errors: Option<Vec<AssetError>>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(default)]
pub struct TransactionSignatureList {
pub total: u32,
pub limit: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub page: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub before: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after: Option<String>,
pub items: Vec<(String, String)>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(default)]
pub struct AssetError {
pub id: String,
pub error: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Asset {
pub interface: Interface,
Expand Down
117 changes: 117 additions & 0 deletions tests/rpc/test_get_asset_signatures.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use std::sync::Arc;

use helius_sdk::client::Helius;
use helius_sdk::config::Config;
use helius_sdk::error::HeliusError;
use helius_sdk::rpc_client::RpcClient;
use helius_sdk::types::*;

use mockito::{self, Server};
use reqwest::Client;
use serde_json::Value;

#[tokio::test]
async fn test_get_asset_signatures_success() {
let mut server: Server = Server::new_with_opts_async(mockito::ServerOpts::default()).await;
let url: String = server.url();

let mock_response: ApiResponse<Option<Asset>> = ApiResponse {
jsonrpc: "2.0".to_string(),
result: Some(TransactionSignatureList {
total: 1,
limit: 1000,
page: Some(
1,
),
before: None,
after: None,
items: vec![
(
"3uLpAGykcJmC4cvPoURqAKKktLLFeZBXid6SeXji6Pnd7YAtDxEG3PRXLXpUBdt1N6W18nUGeKv6eNUPb7Po7u3v".to_string(),
"MintToCollectionV1".to_string(),
),
],
}),
id: "1".to_string(),
};

server
.mock("POST", "/?api-key=fake_api_key")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(serde_json::to_string(&mock_response).unwrap())
.create();

let config: Arc<Config> = Arc::new(Config {
api_key: "fake_api_key".to_string(),
cluster: Cluster::Devnet,
endpoints: HeliusEndpoints {
api: url.to_string(),
rpc: url.to_string(),
},
});

let client: Client = Client::new();
let rpc_client: Arc<RpcClient> = Arc::new(RpcClient::new(Arc::new(client.clone()), Arc::clone(&config)).unwrap());
let helius: Helius = Helius {
config,
client,
rpc_client,
};

let request = GetAssetSignatures {
id: Some("8qjkHtHsqww1rac6Uctj4V7Z5yHoTyQj3iJ5vc4Aka8".to_string()),
page: Some(1),
..Default::default()
};

let response: Result<TransactionSignatureList, HeliusError> = helius.rpc().get_asset(request).await;
assert!(response.is_ok(), "API call failed with error: {:?}", response.err());

let signatures: TransactionSignatureList = response.unwrap();
assert!(signatures.items.is_some(), "No signature returned when one was expected");

assert_eq!(
signatures.items[0], "3uLpAGykcJmC4cvPoURqAKKktLLFeZBXid6SeXji6Pnd7YAtDxEG3PRXLXpUBdt1N6W18nUGeKv6eNUPb7Po7u3v",
"signature does not match expected value"
);
}

#[tokio::test]
async fn test_get_asset_signatures_failure() {
let mut server: Server = Server::new_with_opts_async(mockito::ServerOpts::default()).await;
let url: String = server.url();

server
.mock("POST", "/?api-key=fake_api_key")
.with_status(500)
.with_header("content-type", "application/json")
.with_body(r#"{"error": "Internal Server Error"}"#)
.create();

let config: Arc<Config> = Arc::new(Config {
api_key: "fake_api_key".to_string(),
cluster: Cluster::Devnet,
endpoints: HeliusEndpoints {
api: url.to_string(),
rpc: url.to_string(),
},
});

let client: Client = Client::new();
let rpc_client: Arc<RpcClient> = Arc::new(RpcClient::new(Arc::new(client.clone()), Arc::clone(&config)).unwrap());
let helius: Helius = Helius {
config,
client,
rpc_client,
};

let request = GetAssetSignatures {
id: Some("8qjkHtHsqww1rac6Uctj4V7Z5yHoTyQj3iJ5vc4Aka8".to_string()),
page: Some(1),
..Default::default()
};

let response: Result<TransactionSignatureList, HeliusError> = helius.rpc().get_asset_signatures(request).await;
assert!(response.is_err(), "Expected an error but got success");
}

0 comments on commit 32a4aad

Please sign in to comment.