1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//! Async Rust client for the [Fyuz](https://fyuz.fun) public REST API.
//!
//! Fyuz is a bonding-curve token launchpad on BNB Smart Chain. A new token
//! trades on an internal bonding curve until it reaches a **$30,000 market cap**,
//! at which point it *graduates* into a PancakeSwap V2 pair.
//!
//! **Before graduation there is no DEX pool anywhere.** `pair_address` is
//! `None`, no on-chain pair exists to quote, and this API is the *only* source
//! of price, liquidity and volume data for that token. Anything you build that
//! reads pre-graduation prices from a DEX aggregator will simply find nothing.
//!
//! Every endpoint in this crate is unauthenticated and safe to poll.
//!
//! # Quickstart
//!
//! ```no_run
//! use fyuz::{DiscoverParams, DiscoverTab, FyuzClient};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), fyuz::Error> {
//! let client = FyuzClient::new()?;
//!
//! let trending = client
//! .discover(&DiscoverParams::new().tab(DiscoverTab::Trending).limit(10))
//! .await?;
//!
//! for token in &trending {
//! println!(
//! "{:<10} ${:>12.0} mcap {:>6.2}% to graduation",
//! token.symbol, token.marketcap, token.graduation_pct
//! );
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! # Decimal strings, and why they are not floats
//!
//! Token balances, prices, market caps and every `*_wei` field come back as
//! **decimal strings** and stay [`String`] in this crate's models. An 18-decimal
//! token amount, or a `uint256` wei total, does not survive a round trip through
//! `f64`:
//!
//! ```
//! let wire = "123456789012345678901234567890";
//! // What a "just parse it as a number" client would do:
//! let lossy = wire.parse::<f64>().unwrap();
//! assert_ne!(format!("{lossy:.0}"), wire); // silently wrong
//! ```
//!
//! If you need arithmetic, parse into a big-integer or decimal type of your
//! choosing (`rust_decimal`, `bigdecimal`, `primitive_types::U256`, …) at the
//! edge of your own code. The SDK deliberately does not pick one for you, and
//! deliberately never parses these into `f64` on your behalf.
//!
//! Aggregates that the server already computed in floating point — `volume_usd`,
//! `points`, `reward_eth`, `pot_bnb`, PnL figures — arrive as JSON numbers and
//! are modelled as `f64`.
//!
//! Timestamps get the same treatment for the same reason, one step further: the
//! RFC-3339 `created_at`/`updated_at` strings and the unix-second `date` and
//! `round_end` fields stay as they arrived. There is no date type in `core`, and
//! picking `chrono` or `time` for you would put a dependency — and a major
//! version of it — into every downstream build to save one `parse` call. This is
//! the one helper the TypeScript, Go and Python SDKs have that this one
//! deliberately does not.
//!
//! # Where Fyuz is deployed
//!
//! [`addresses`] carries the deployed proxy addresses as compile-time constants,
//! looked up by chain id or slug:
//!
//! ```
//! let bsc = fyuz::deployment_for_chain_id(56).expect("mainnet is in the book");
//! assert_eq!(bsc.fyuz, "0x33a98bef6496684a8dac83734d9ceb0cefc7019c");
//! ```
//!
//! `GET /config` still wins wherever it answers — the launchpad is behind an
//! upgradeable proxy, and a published crate that trusted its own copy would keep
//! calling a dead address after a redeploy. The book is what covers the cases the
//! API cannot: BSC testnet, which the public API does not serve at all, and a
//! `/config` response that arrives without a `contractAddress`.
//!
//! # `None` is not `0`
//!
//! [`Pot::pot_bnb`](models::Pot::pot_bnb),
//! [`Claimable::claimable_wei`](models::Claimable::claimable_wei),
//! [`TokenDetail::curve_holding`](models::TokenDetail::curve_holding) and the
//! nullable `*_wei` fields on [`RoundReceipt`] are `None`
//! when the value is **unknown** — the RPC was unreachable, or the settlement is
//! not indexed yet. Rendering `0` in that case tells a user something false.
//!
//! # Rate limits and retries
//!
//! The API allows 120 requests per minute per IP and answers `429` with
//! `{"error": "Too many requests"}` past that. The client retries `429`s, `5xx`s
//! and transport failures automatically with exponential backoff and full
//! jitter, honouring `Retry-After` when the server sends one. Other `4xx`
//! statuses are never retried. Three retries is the default:
//!
//! ```no_run
//! # fn demo() -> Result<(), fyuz::Error> {
//! use std::time::Duration;
//!
//! let client = fyuz::FyuzClient::builder()
//! .timeout(Duration::from_secs(10))
//! .max_retries(5)
//! .user_agent("acme-indexer/2.1 (ops@acme.example)")
//! .build()?;
//! # let _ = client;
//! # Ok(())
//! # }
//! ```
//!
//! Once the retries are spent the call fails with [`Error::RateLimited`], which
//! is a distinct variant precisely so a backpressure handler can match on it.
//!
//! # What is not here
//!
//! Only the public, unauthenticated surface is implemented. The API-key-gated
//! routes (recording a distribution round, posting chats, watchlists, paper
//! trading, airdrops, …) are deliberately absent — including `POST
//! /distributor/rounds`, which shares a path with
//! [`Distributor::list_rounds`] but is not a public endpoint.
pub use ;
pub use ;
pub use Distributor;
pub use ;
pub use ;
pub use TokenPager;
pub use ;
pub use ;
pub use ;
pub use ;
// Every response model is re-exported at the crate root for convenience; they
// also live in `fyuz::models` if you prefer the namespace.
pub use *;