Skip to main content

FyuzClient

Struct FyuzClient 

Source
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

Source

pub async fn health(&self) -> Result<HealthStatus>

GET /health — liveness probe.

let client = fyuz::FyuzClient::new()?;
assert_eq!(client.health().await?.status, "ok");
Source

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);
}
Source

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);
}
Source

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);
Source

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);
}
Source

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"),
}
Source

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);
Source

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;
}
Source

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);
}
Source

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());
Source

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);
}
Source

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

Source

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);
Source

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);
}
Source

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);
}
Source

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),
}
Source

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);
}
Source

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);
}
Source

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);
Source

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);
}
Source

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);
Source

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

Source

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);
Source

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()?;
Source

pub fn base_url(&self) -> &Url

The base URL every request is resolved against.

Source

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"),
}
Source

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);

Trait Implementations§

Source§

impl Clone for FyuzClient

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for FyuzClient

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more