Skip to content

Commit

Permalink
token supply webserver endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
sug0 committed Feb 7, 2025
1 parent d58203c commit af04490
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 4 deletions.
2 changes: 1 addition & 1 deletion orm/src/token_supplies_per_epoch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::schema::token_supplies_per_epoch;
#[derive(Debug, Clone, Queryable, Selectable)]
#[diesel(table_name = token_supplies_per_epoch)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct TokenSupplies {
pub struct TokenSuppliesDb {
pub id: i32,
pub address: String,
pub epoch: i32,
Expand Down
37 changes: 37 additions & 0 deletions swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,29 @@ paths:
value:
- address: tnam1pkg30gnt4q0zn7j00r6hms4ajrxn6f5ysyyl7w9m
trace: transfer/channel-2/uatom
/api/v1/chain/token-supply:
get:
summary: Get the supply of some token at the given epoch
parameters:
- in: query
name: address
schema:
type: string
required: true
description: Address of the token
- in: query
name: epoch
schema:
type: integer
minimum: 0
description: Epoch to query
responses:
"200":
description: Chain token supply
content:
application/json:
schema:
$ref: "#/components/schemas/TokenSupply"
/api/v1/chain/parameters:
get:
summary: Get chain parameters
Expand Down Expand Up @@ -1140,6 +1163,20 @@ components:
type: string
trace:
type: string
TokenSupply:
type: object
required:
[
address,
totalSupply,
]
properties:
address:
type: string
totalSupply:
type: string
effectiveSupply:
type: string
Parameters:
type: object
required:
Expand Down
4 changes: 4 additions & 0 deletions webserver/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ impl ApplicationServer {
.route("/chain/parameters", get(chain_handlers::get_parameters))
.route("/chain/rpc-url", get(chain_handlers::get_rpc_url))
.route("/chain/token", get(chain_handlers::get_tokens))
.route(
"/chain/token-supply",
get(chain_handlers::get_token_supply),
)
.route(
"/chain/block/latest",
get(chain_handlers::get_last_processed_block),
Expand Down
10 changes: 10 additions & 0 deletions webserver/src/dto/chain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use serde::{Deserialize, Serialize};
use validator::Validate;

#[derive(Clone, Serialize, Deserialize, Validate)]
#[serde(rename_all = "camelCase")]
pub struct TokenSupply {
#[validate(range(min = 0))]
pub epoch: Option<i32>,
pub address: String,
}
1 change: 1 addition & 0 deletions webserver/src/dto/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod chain;
pub mod crawler_state;
pub mod gas;
pub mod governance;
Expand Down
14 changes: 14 additions & 0 deletions webserver/src/handler/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ use axum::extract::State;
use axum::http::HeaderMap;
use axum::response::Sse;
use axum::response::sse::{Event, KeepAlive};
use axum_extra::extract::Query;
use futures::Stream;
use tokio_stream::StreamExt;

use crate::dto::chain::TokenSupply as TokenSupplyDto;
use crate::error::api::ApiError;
use crate::response::chain::{
LastProcessedBlock, LastProcessedEpoch, Parameters, RpcUrl, Token,
TokenSupply as TokenSupplyRsp,
};
use crate::state::common::CommonState;

Expand Down Expand Up @@ -99,3 +102,14 @@ pub async fn get_last_processed_epoch(
epoch: last_processed_block.to_string(),
}))
}

pub async fn get_token_supply(
Query(query): Query<TokenSupplyDto>,
State(state): State<CommonState>,
) -> Result<Json<Option<TokenSupplyRsp>>, ApiError> {
let supply = state
.chain_service
.get_token_supply(query.address, query.epoch)
.await?;
Ok(Json(supply))
}
57 changes: 55 additions & 2 deletions webserver/src/repository/chain.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use axum::async_trait;
use diesel::dsl::max;
use diesel::{
ExpressionMethods, JoinOnDsl, QueryDsl, RunQueryDsl, SelectableHelper,
BoolExpressionMethods, ExpressionMethods, JoinOnDsl, OptionalExtension,
QueryDsl, RunQueryDsl, SelectableHelper,
};
use orm::crawler_state::{ChainCrawlerStateDb, CrawlerNameDb};
use orm::parameters::ParametersDb;
use orm::schema::{chain_parameters, crawler_state, ibc_token, token};
use orm::schema::{
chain_parameters, crawler_state, ibc_token, token, token_supplies_per_epoch,
};
use orm::token::{IbcTokenDb, TokenDb};
use orm::token_supplies_per_epoch::TokenSuppliesDb;

use crate::appstate::AppState;

Expand All @@ -30,6 +34,12 @@ pub trait ChainRepositoryTrait {
async fn find_tokens(
&self,
) -> Result<Vec<(TokenDb, Option<IbcTokenDb>)>, String>;

async fn get_token_supply(
&self,
address: String,
epoch: Option<i32>,
) -> Result<Option<TokenSuppliesDb>, String>;
}

#[async_trait]
Expand Down Expand Up @@ -120,4 +130,47 @@ impl ChainRepositoryTrait for ChainRepository {
.map_err(|e| e.to_string())?
.map_err(|e| e.to_string())
}

async fn get_token_supply(
&self,
address: String,
epoch: Option<i32>,
) -> Result<Option<TokenSuppliesDb>, String> {
let conn = self.app_state.get_db_connection().await;

conn.interact(move |conn| {
conn.build_transaction().read_only().run(move |conn| {
let epoch = epoch.map_or_else(
|| {
crawler_state::dsl::crawler_state
.filter(
crawler_state::dsl::name
.eq(CrawlerNameDb::Chain),
)
.select(max(
crawler_state::dsl::last_processed_epoch,
))
.first::<Option<i32>>(conn)
.map(|maybe_epoch| maybe_epoch.unwrap_or(0i32))
},
Ok,
)?;

token_supplies_per_epoch::table
.filter(
token_supplies_per_epoch::dsl::address
.eq(&address)
.and(
token_supplies_per_epoch::dsl::epoch.eq(&epoch),
),
)
.select(TokenSuppliesDb::as_select())
.first(conn)
.optional()
})
})
.await
.map_err(|e| e.to_string())?
.map_err(|e| e.to_string())
}
}
8 changes: 8 additions & 0 deletions webserver/src/response/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,11 @@ impl From<SharedToken> for Token {
}
}
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TokenSupply {
pub address: String,
pub total_supply: String,
pub effective_supply: Option<String>,
}
20 changes: 19 additions & 1 deletion webserver/src/service/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use shared::token::{IbcToken, Token};
use crate::appstate::AppState;
use crate::error::chain::ChainError;
use crate::repository::chain::{ChainRepository, ChainRepositoryTrait};
use crate::response::chain::Parameters;
use crate::response::chain::{Parameters, TokenSupply};

#[derive(Clone)]
pub struct ChainService {
Expand Down Expand Up @@ -65,4 +65,22 @@ impl ChainService {

Ok(tokens)
}

pub async fn get_token_supply(
&self,
address: String,
epoch: Option<i32>,
) -> Result<Option<TokenSupply>, ChainError> {
let maybe_token_supply_db = self
.chain_repo
.get_token_supply(address, epoch)
.await
.map_err(ChainError::Database)?;

Ok(maybe_token_supply_db.map(|supply| TokenSupply {
address: supply.address,
total_supply: supply.total.to_string(),
effective_supply: supply.effective.map(|s| s.to_string()),
}))
}
}

0 comments on commit af04490

Please sign in to comment.