pub struct FyuzClient { /* private fields */ }Expand description
Async client for the Fyuz public REST API.
Cloning is cheap — the underlying reqwest::Client and configuration are
shared behind an Arc, and the connection pool is shared with it. Create
one per process and clone it around rather than building a new one per call.
use fyuz::{DiscoverParams, DiscoverTab, FyuzClient};
let client = FyuzClient::new()?;
let trending = client
.discover(&DiscoverParams::new().tab(DiscoverTab::Trending).limit(10))
.await?;
for token in &trending {
println!("{} {:.0}% to graduation", token.symbol, token.graduation_pct);
}Implementations§
Source§impl FyuzClient
impl FyuzClient
Sourcepub async fn health(&self) -> Result<HealthStatus>
pub async fn health(&self) -> Result<HealthStatus>
GET /health — liveness probe.
let client = fyuz::FyuzClient::new()?;
assert_eq!(client.health().await?.status, "ok");Sourcepub async fn get_config(&self) -> Result<ChainConfig>
pub async fn get_config(&self) -> Result<ChainConfig>
GET /config — the chains this deployment serves.
let client = fyuz::FyuzClient::new()?;
for chain in client.get_config().await?.chains {
println!("{} (chain id {})", chain.name, chain.chain_id);
}Sourcepub async fn discover(
&self,
params: &DiscoverParams,
) -> Result<Vec<DiscoverToken>>
pub async fn discover( &self, params: &DiscoverParams, ) -> Result<Vec<DiscoverToken>>
GET /discover — the discovery feed, and the best single endpoint for
bulk market-data ingestion.
One row per token with market cap, 24h volume, buy/sell counts, holder count, price change and graduation progress.
use fyuz::{DiscoverParams, DiscoverTab};
let client = fyuz::FyuzClient::new()?;
let almost_there = client
.discover(&DiscoverParams::new().tab(DiscoverTab::Graduating).limit(20))
.await?;
for token in &almost_there {
println!("{:<8} {:>6.2}% of the way to a PancakeSwap pair", token.symbol, token.graduation_pct);
}Sourcepub async fn list_tokens(&self, params: &ListTokensParams) -> Result<TokenPage>
pub async fn list_tokens(&self, params: &ListTokensParams) -> Result<TokenPage>
GET /tokens — one page of the token list.
Use token_pages to walk every page instead of
paging by hand.
use fyuz::{ListTokensParams, SortDirection};
let client = fyuz::FyuzClient::new()?;
let page = client
.list_tokens(
&ListTokensParams::new()
.order_type("marketcap")
.order_flag(SortDirection::Desc)
.page_size(50),
)
.await?;
println!("{} of {} tokens", page.token_list.len(), page.token_count);Sourcepub fn token_pages(&self, params: &ListTokensParams) -> TokenPager
pub fn token_pages(&self, params: &ListTokensParams) -> TokenPager
Walk every page of GET /tokens.
The returned TokenPager issues one request per page and stops when
the server’s tokenCount is covered.
use fyuz::ListTokensParams;
let client = fyuz::FyuzClient::new()?;
let mut pager = client.token_pages(&ListTokensParams::new().page_size(100));
while let Some(token) = pager.next_token().await? {
println!("{} {}", token.token_symbol, token.marketcap);
}Sourcepub async fn get_king(&self) -> Result<Option<Token>>
pub async fn get_king(&self) -> Result<Option<Token>>
GET /tokens/king — the current king of the hill: the
highest-market-cap token still on the bonding curve.
None means the hill is empty, which is a real state rather than an
error: a token leaves the moment it graduates, so between a graduation
and the next launch there is no king.
The API wraps the token in a {"king": …} envelope; it is unwrapped
here.
let client = fyuz::FyuzClient::new()?;
match client.get_king().await? {
Some(king) => println!("{} at ${}", king.token_name, king.marketcap),
None => println!("no king right now"),
}Sourcepub async fn get_token(
&self,
network: &str,
token_address: &str,
params: &TokenDetailParams,
) -> Result<TokenDetail>
pub async fn get_token( &self, network: &str, token_address: &str, params: &TokenDetailParams, ) -> Result<TokenDetail>
GET /tokens/{network}/{tokenAddress} — full token record plus recent
trades, holders, 15-minute price and 1-day liquidity.
curve_holding is None when the on-chain read failed. That means
unknown, not zero — do not render it as 0.
Answers 404 for an unknown token; check with
Error::is_not_found.
use fyuz::TokenDetailParams;
let client = fyuz::FyuzClient::new()?;
let detail = client
.get_token("bsc", "0x23a84ba5bf7bf3236491fa2b5a9807a274337135", &TokenDetailParams::new())
.await?;
let graduated = detail.token_details.pair_address.is_some();
println!("graduated: {graduated}, {} trades", detail.trades_count);Sourcepub async fn get_recent_trades(
&self,
params: &RecentTradesParams,
) -> Result<RecentTrades>
pub async fn get_recent_trades( &self, params: &RecentTradesParams, ) -> Result<RecentTrades>
GET /trades/recent — the platform-wide trade feed.
Pass the highest Trade::id you have already seen as
RecentTradesParams::latest_trade_id to poll incrementally.
use fyuz::RecentTradesParams;
let client = fyuz::FyuzClient::new()?;
let mut cursor = 0i64;
let feed = client
.get_recent_trades(&RecentTradesParams::new().latest_trade_id(cursor))
.await?;
if let Some(newest) = feed.trades.first() {
cursor = newest.id;
}Sourcepub async fn get_token_trades(
&self,
token_address: &str,
params: &TokenTradesParams,
) -> Result<Vec<Trade>>
pub async fn get_token_trades( &self, token_address: &str, params: &TokenTradesParams, ) -> Result<Vec<Trade>>
POST /trades — one token’s trade history, newest first.
This is a POST only because the token address travels in the body; it
is a read, it changes nothing, and it needs no authentication.
use fyuz::TokenTradesParams;
let client = fyuz::FyuzClient::new()?;
let trades = client
.get_token_trades(
"0x23a84ba5bf7bf3236491fa2b5a9807a274337135",
&TokenTradesParams::new().limit(100),
)
.await?;
for trade in &trades {
// eth_amount is a decimal string: keep it as one.
println!("{} {} BNB", trade.trade_side, trade.eth_amount);
}Sourcepub async fn get_chart_data(
&self,
params: &ChartDataParams,
) -> Result<Vec<Candle>>
pub async fn get_chart_data( &self, params: &ChartDataParams, ) -> Result<Vec<Candle>>
GET /trades/getChartData — OHLCV candles, shaped for TradingView-style
charting libraries.
use fyuz::ChartDataParams;
let client = fyuz::FyuzClient::new()?;
let candles = client
.get_chart_data(&ChartDataParams::new(
"0x23a84ba5bf7bf3236491fa2b5a9807a274337135",
"5",
1_750_000_000,
1_750_086_400,
))
.await?;
println!("{} candles", candles.len());Sourcepub async fn get_token_analytics(
&self,
network: &str,
address: &str,
) -> Result<TokenAnalytics>
pub async fn get_token_analytics( &self, network: &str, address: &str, ) -> Result<TokenAnalytics>
GET /analytics/token/{network}/{address} — holder concentration,
buy/sell split, volume, graduation progress and bundle-buyer detection.
Answers 404 for an unknown token.
let client = fyuz::FyuzClient::new()?;
let a = client
.get_token_analytics("bsc", "0x23a84ba5bf7bf3236491fa2b5a9807a274337135")
.await?;
if a.bundle_flag {
println!("{} addresses bought in the launch block", a.bundle_buyers);
}Sourcepub async fn get_top_traders(
&self,
network: &str,
address: &str,
) -> Result<Vec<TopTrader>>
pub async fn get_top_traders( &self, network: &str, address: &str, ) -> Result<Vec<TopTrader>>
GET /analytics/top-traders/{network}/{address} — a token’s most
profitable traders, with the creator flagged.
let client = fyuz::FyuzClient::new()?;
let traders = client
.get_top_traders("bsc", "0x23a84ba5bf7bf3236491fa2b5a9807a274337135")
.await?;
for t in traders.iter().take(5) {
println!("{} {:+.2} USD", t.address, t.total_pnl_usd);
}Source§impl FyuzClient
impl FyuzClient
Sourcepub async fn get_wallet(&self, address: &str) -> Result<WalletStats>
pub async fn get_wallet(&self, address: &str) -> Result<WalletStats>
GET /wallet/{address} — average-cost PnL rolled up across every token
the wallet has traded, plus win rate, volume and holding value.
let client = fyuz::FyuzClient::new()?;
let w = client.get_wallet("0x1111111111111111111111111111111111111111").await?;
println!("{:+.2} USD over {} trades", w.total_pnl_usd, w.trade_count);Sourcepub async fn get_portfolio(&self, address: &str) -> Result<Portfolio>
pub async fn get_portfolio(&self, address: &str) -> Result<Portfolio>
GET /portfolio/{address} — current holdings with per-position PnL.
An address with no trades returns zeroed totals and an empty
positions list rather than a 404.
let client = fyuz::FyuzClient::new()?;
let p = client.get_portfolio("0x1111111111111111111111111111111111111111").await?;
for pos in &p.positions {
println!("{:<8} ${:>10.2} ({:+.1}%)", pos.symbol, pos.value_usd, pos.unrealized_pnl_pct);
}Sourcepub async fn get_user_leaderboard(
&self,
limit: Option<i64>,
) -> Result<Vec<LeaderboardEntry>>
pub async fn get_user_leaderboard( &self, limit: Option<i64>, ) -> Result<Vec<LeaderboardEntry>>
GET /users/leaderboard — the global points leaderboard.
The board resets after every Distributor payout: only activity since the
last settled round counts. limit is clamped by the server to 1-500;
None takes the server default of 100.
Rows arrive pre-ranked — LeaderboardEntry::rank is authoritative, so
do not re-sort them.
let client = fyuz::FyuzClient::new()?;
for row in client.get_user_leaderboard(Some(10)).await? {
println!("#{:<3} {} {:.1} pts", row.rank, row.address, row.points);
}Sourcepub async fn get_user_profile(&self, address: &str) -> Result<UserProfile>
pub async fn get_user_profile(&self, address: &str) -> Result<UserProfile>
GET /users/profile/{address} — public profile: identity, holdings,
comments, launched tokens and current-round points.
Answers 404 for an address with no profile; check with
Error::is_not_found.
let client = fyuz::FyuzClient::new()?;
match client.get_user_profile("0x1111111111111111111111111111111111111111").await {
Ok(profile) => println!("{:?}", profile.user.username),
Err(e) if e.is_not_found() => println!("no profile"),
Err(e) => return Err(e),
}Sourcepub async fn get_top_holders(
&self,
count: i64,
params: &TopHoldersParams,
) -> Result<Vec<TopHolderEntry>>
pub async fn get_top_holders( &self, count: i64, params: &TopHoldersParams, ) -> Result<Vec<TopHolderEntry>>
GET /users/top/{count} — the wallets with the most USD volume over a
window.
use fyuz::TopHoldersParams;
let client = fyuz::FyuzClient::new()?;
let top = client
.get_top_holders(10, &TopHoldersParams::new().network("bsc"))
.await?;
for row in &top {
println!("{} ${:.0}", row.address, row.volume);
}Sourcepub async fn get_kings_history(&self) -> Result<Vec<KingReign>>
pub async fn get_kings_history(&self) -> Result<Vec<KingReign>>
GET /kings/history — past King-of-the-Hill reigns, most recent first,
capped at 100.
An ongoing reign has KingReign::ended_at of None and a
duration_secs that counts up to now.
let client = fyuz::FyuzClient::new()?;
for reign in client.get_kings_history().await? {
let state = if reign.ended_at.is_none() { "reigning" } else { "past" };
println!("{:<8} {state} for {}s", reign.symbol, reign.duration_secs);
}Sourcepub async fn get_season(&self) -> Result<Season>
pub async fn get_season(&self) -> Result<Season>
GET /season — the current season window, prize pot and standings.
let client = fyuz::FyuzClient::new()?;
let season = client.get_season().await?;
println!("{}: {} BNB pot", season.name, season.prize_pot_eth);Sourcepub async fn get_referral_leaderboard(
&self,
limit: Option<i64>,
) -> Result<Vec<ReferralLeaderEntry>>
pub async fn get_referral_leaderboard( &self, limit: Option<i64>, ) -> Result<Vec<ReferralLeaderEntry>>
GET /referrals/leaderboard — referrers ranked by active referrals.
limit is clamped by the server to 1-500; None takes the server
default of 100.
let client = fyuz::FyuzClient::new()?;
for row in client.get_referral_leaderboard(None).await? {
println!("#{} {} — {} referrals", row.rank, row.address, row.referral_count);
}Sourcepub async fn get_tier(&self, address: &str) -> Result<TierInfo>
pub async fn get_tier(&self, address: &str) -> Result<TierInfo>
GET /tier/{address} — display-only trader tier from lifetime USD
volume: Bronze ($0), Silver ($100), Gold ($1,000), Diamond ($10,000).
let client = fyuz::FyuzClient::new()?;
let tier = client.get_tier("0x1111111111111111111111111111111111111111").await?;
println!("{} — {:.0}% to {:?}", tier.tier, tier.progress_pct, tier.next_tier);Sourcepub async fn get_rewards(&self, address: &str) -> Result<Rewards>
pub async fn get_rewards(&self, address: &str) -> Result<Rewards>
GET /rewards/{address} — streaks, points and quest/achievement state.
Read-only: rewards are granted automatically by the indexer as they are earned, so there is no claim step on this surface.
let client = fyuz::FyuzClient::new()?;
let r = client.get_rewards("0x1111111111111111111111111111111111111111").await?;
println!("{} day streak, {:.1} pts", r.current_streak, r.points);Source§impl FyuzClient
impl FyuzClient
Sourcepub fn new() -> Result<Self>
pub fn new() -> Result<Self>
Build a client pointed at https://api.fyuz.fun with the default 30s timeout and 3 retries.
let client = fyuz::FyuzClient::new()?;
println!("{}", client.health().await?.status);Sourcepub fn builder() -> FyuzClientBuilder
pub fn builder() -> FyuzClientBuilder
Start configuring a client.
use std::time::Duration;
let client = fyuz::FyuzClient::builder()
.base_url("http://127.0.0.1:8080")?
.timeout(Duration::from_secs(5))
.max_retries(5)
.build()?;Sourcepub fn distributor(&self) -> Distributor<'_>
pub fn distributor(&self) -> Distributor<'_>
The Distributor endpoints (/distributor/*), grouped together.
let client = fyuz::FyuzClient::new()?;
let pot = client.distributor().get_pot().await?;
match pot.pot_bnb {
Some(bnb) => println!("{bnb} BNB in the pot"),
// `None` means unknown, never zero.
None => println!("pot unavailable right now"),
}Sourcepub fn trade(&self) -> TradeApi<'_>
pub fn trade(&self) -> TradeApi<'_>
Bonding-curve trading: quotes, and unsigned buy/sell/approve transactions.
Builds transactions only — it never handles a key. See TradeApi.
use fyuz::{parse_units, BuyParams};
let client = fyuz::FyuzClient::new()?;
let built = client
.trade()
.build_buy(
&BuyParams::new("0x0000000000000000000000000000000000000001", parse_units("0.5", 18)?)
.slippage_bps(100),
)
.await?;
println!("{}", built.transaction.data);