helius_rust_client/models/
nft.rs

1use serde::Deserialize;
2use serde_json::{json, Value};
3
4use solana_client::client_error::{ClientError, ClientErrorKind, Result as ClientResult};
5
6use super::{
7    enriched_transaction::{NativeTransfer, TokenTransfer},
8    enums::{CompressedNftEventType, NftEventType, SaleType, TokenStandard, TransactionSource},
9};
10
11#[derive(Deserialize, Debug, PartialEq)]
12#[serde(rename_all = "camelCase")]
13pub struct ActiveListing {
14    pub transaction_signature: String,
15    pub marketplace: String,
16    pub amount: u64,
17    pub seller: String,
18}
19
20#[derive(Deserialize, Debug, PartialEq)]
21#[serde(rename_all = "camelCase")]
22pub struct NftMetadata {
23    pub mint: String,
24    pub name: String,
25    pub burned: bool,
26    pub first_verified_creator: String,
27    pub verified_collection_address: String,
28    pub active_listings: Vec<ActiveListing>,
29}
30
31#[derive(Deserialize, Debug, PartialEq, Clone)]
32#[serde(rename_all = "camelCase")]
33pub struct CompressedNftEvent {
34    event_type: CompressedNftEventType,
35    tree_id: String,
36    asset_id: String,
37    leaf_index: u64,
38    instruction_index: u64,
39    inner_instruction_index: u64,
40}
41
42#[derive(Deserialize, Debug, PartialEq, Clone)]
43#[serde(rename_all = "camelCase")]
44pub struct NftEvent {
45    pub amount: i128, // Sometimes has negatives, although it should be lamports?
46    pub fee: u64,
47    pub fee_payer: String,
48    pub signature: String,
49    pub slot: u64,
50    pub timestamp: u64,
51    #[serde(rename = "type")]
52    pub event_type: NftEventType,
53    pub buyer: String,
54    pub seller: String,
55    pub staker: String,
56    pub nfts: Vec<NftToken>,
57}
58
59#[derive(Deserialize, Debug, PartialEq, Clone)]
60#[serde(rename_all = "camelCase")]
61pub struct NftEventV2 {
62    #[serde(rename = "type")]
63    pub event_type: NftEventType,
64    pub source: TransactionSource,
65    pub amount: i128, // Sometimes has negatives, although it should be lamports?
66    pub fee: u64,
67    pub fee_payer: String,
68    pub signature: String,
69    pub slot: u64,
70    pub timestamp: u64,
71    pub sale_type: SaleType,
72    pub buyer: String,
73    pub seller: String,
74    pub staker: String,
75    pub nfts: Value,
76    pub native_transfers: Vec<NativeTransfer>,
77    pub token_transfers: Vec<TokenTransfer>,
78    pub pagination_token: Option<String>,
79}
80
81#[derive(Deserialize, Debug, PartialEq, Clone)]
82#[serde(rename_all = "camelCase")]
83pub struct NftToken {
84    pub mint: String,
85    pub token_standard: TokenStandard,
86}
87
88#[derive(Deserialize, Debug, PartialEq)]
89#[serde(rename_all = "camelCase")]
90pub struct MintListResult {
91    pub mint: String,
92    pub name: String,
93}
94
95#[derive(Deserialize, Debug, PartialEq)]
96#[serde(rename_all = "camelCase")]
97pub struct TokenBalancesResponse {
98    pub native_balance: u64,
99    pub tokens: Vec<TokenBalance>,
100}
101
102#[derive(Deserialize, Debug, PartialEq)]
103#[serde(rename_all = "camelCase")]
104pub struct MintListResponse {
105    pub result: Vec<MintListResult>,
106    pub pagination_token: String,
107}
108
109#[derive(Deserialize, Debug, PartialEq)]
110#[serde(rename_all = "camelCase")]
111pub struct NftResponse {
112    pub number_of_pages: usize,
113    pub nfts: NftInfo,
114}
115
116#[derive(Deserialize, Debug, PartialEq)]
117#[serde(rename = "nft")]
118#[serde(rename_all = "camelCase")]
119pub struct NftInfo {
120    pub name: String,
121    pub token_address: String,
122    pub collection_address: String,
123    pub collection_name: String,
124    pub image_url: String,
125    pub traits: Vec<Trait>,
126}
127
128#[derive(Deserialize, Debug, PartialEq)]
129#[serde(rename_all = "camelCase")]
130pub struct Trait {
131    pub trait_type: String,
132    pub value: String,
133}
134
135#[derive(Deserialize, Debug, PartialEq)]
136#[serde(rename_all = "camelCase")]
137pub struct TokenBalance {
138    pub token_account: String,
139    pub mint: String,
140    pub amount: u64,
141    pub decimals: u8,
142}
143
144/// Request parameters for the `https://api.helius.xyz/v1/mintlist` endpoint. The API only accepts one of verified_collection_addresses or first_verified_creators, not both.
145#[derive(Debug, Default)]
146pub struct MintListRequestConfig {
147    pub verified_collection_addresses: Option<Vec<String>>,
148    pub first_verified_creators: Option<Vec<String>>,
149    pub limit: Option<usize>,
150    pub pagination_token: Option<String>,
151}
152impl MintListRequestConfig {
153    pub fn generate_request_body(self) -> ClientResult<serde_json::Value> {
154        if self.verified_collection_addresses.is_some() && self.first_verified_creators.is_some() {
155            return single_verified_args_error();
156        }
157
158        if self.verified_collection_addresses.is_some() {
159            Ok(json!({
160                "query" : {
161                    "verifiedCollectionAddresses": self.verified_collection_addresses.unwrap(),
162                },
163                "options": {
164                    "limit": self.limit,
165                    "paginationToken": self.pagination_token
166                }
167            }))
168        } else {
169            Ok(json!({
170                "query": {
171                    "firstVerifiedCreators": self.first_verified_creators.unwrap(),
172                },
173                "options": {
174                    "limit": self.limit,
175                    "paginationToken": self.pagination_token
176                }
177            }))
178        }
179    }
180}
181
182#[derive(Deserialize, Debug, PartialEq)]
183#[serde(rename_all = "camelCase")]
184pub struct ActiveListingsResponse {
185    pub result: Vec<ListingResult>,
186    pub pagination_token: String,
187}
188
189#[derive(Deserialize, Debug, PartialEq)]
190#[serde(rename_all = "camelCase")]
191pub struct ListingResult {
192    pub mint: String,
193    pub name: String,
194    pub first_verified_creator: String,
195    pub verified_collection_address: String,
196    pub active_listings: Vec<ActiveListing>,
197}
198
199/// Request parameters for the `https://api.helius.xyz/v1/active-listings` endpoint. The API only accepts one of verified_collection_addresses or first_verified_creators, not both.
200#[derive(Debug, Default)]
201pub struct ActiveListingsRequestConfig {
202    pub marketplaces: Vec<String>,
203    pub verified_collection_addresses: Option<Vec<String>>,
204    pub first_verified_creators: Option<Vec<String>>,
205    pub limit: Option<usize>,
206    pub pagination_token: Option<String>,
207}
208impl ActiveListingsRequestConfig {
209    pub fn generate_request_body(self) -> ClientResult<serde_json::Value> {
210        if self.verified_collection_addresses.is_some() && self.first_verified_creators.is_some() {
211            return single_verified_args_error();
212        }
213
214        if self.verified_collection_addresses.is_some() {
215            Ok(json!({
216                "query" : {
217                    "marketplaces": self.marketplaces,
218                    "verifiedCollectionAddresses": self.verified_collection_addresses.unwrap(),
219                },
220                "options": {
221                    "limit": self.limit,
222                    "paginationToken": self.pagination_token
223                }
224            }))
225        } else {
226            Ok(json!({
227                "query": {
228                    "marketplaces": self.marketplaces,
229                    "firstVerifiedCreators": self.first_verified_creators.unwrap(),
230                },
231                "options": {
232                    "limit": self.limit,
233                    "paginationToken": self.pagination_token
234                }
235            }))
236        }
237    }
238}
239
240fn single_verified_args_error<T>() -> ClientResult<T> {
241    Err(ClientError::from(ClientErrorKind::Custom(
242        "API only accepts one of first_verified_creators or verified_collection_addresses"
243            .to_string(),
244    )))
245}