Problem
The Core Engine has no /api/v1/pool/fee endpoint. While the backend proxies pool data from the Core Engine and pool.stats() returns fee_bps, there is no dedicated endpoint that returns JUST the pool fee configuration. This matters for:
- Frontend components that need to display the current fee without fetching full pool stats
- Clients that want to monitor fee changes over time (if fee is governance-updatable)
- Clients that need fee_bps for client-side calculation of output amounts
Current situation: Fee is buried inside GET /pool/stats:
{
"price_token0_in_token1": 0.0001,
"price_token1_in_token0": 10000,
"k_invariant": "10000000000000",
"fee_bps": 30, ← fee is here but requires fetching all stats
"reserves": {...}
}
Root Cause
No dedicated fee endpoint was designed. The fee is derivable from stats but fetching stats requires a Soroban RPC call to the contract, which is heavier than querying just the fee.
Impact
- Fee-only queries fetch the entire pool state (expensive Soroban call)
- No way to subscribe to fee changes specifically (webhook/polling would need to diff full stats)
- Slight inefficiency for mobile app displaying just the fee percentage
Fix
Add GET /pool/fee to the Core Engine pool handler:
// In the Axum pool router:
pub async fn get_fee(State(state): State<Arc<AppState>>) -> impl IntoResponse {
match state.pool_adapter.get_fee().await {
Ok(fee_bps) => (StatusCode::OK, Json(json!({
"fee_bps": fee_bps,
"fee_percent": fee_bps as f64 / 100.0,
"fee_description": format!("{:.2}% per swap", fee_bps as f64 / 100.0),
}))).into_response(),
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": e.to_string()
}))).into_response(),
}
}
Wire into router:
let pool_router = Router::new()
.route("/pool/reserves", get(get_reserves))
.route("/pool/stats", get(get_stats))
.route("/pool/fee", get(get_fee)) // ← add this
// ...
Response format:
GET /api/v1/pool/fee
{
"fee_bps": 30,
"fee_percent": 0.30,
"fee_description": "0.30% per swap"
}
Also add to Backend pool/client.go:
func (c *Client) GetFee(ctx context.Context) (*feeConfig, error) {
resp, err := c.get(ctx, "/pool/fee")
// ...
}
And Backend pool handler:
// GET /api/v1/pool/fee
func (h *Handler) GetFee(c *gin.Context) {
fee, err := h.svc.GetFee(c.Request.Context())
if err != nil {
utils.InternalServerError(c, "fee failed: "+err.Error())
return
}
utils.OK(c, "fee retrieved", fee)
}
Steps to Verify
curl http://localhost:8080/api/v1/pool/fee → {"fee_bps": 30, "fee_percent": 0.30, ...}
- Response is cached (same 30-second TTL as other pool endpoints)
- Frontend
pool.fee() API call returns fee_bps without fetching full stats
- Mobile app
bpsToPercent(await poolService.getFee()) shows "0.30%"
Problem
The Core Engine has no
/api/v1/pool/feeendpoint. While the backend proxies pool data from the Core Engine andpool.stats()returnsfee_bps, there is no dedicated endpoint that returns JUST the pool fee configuration. This matters for:Current situation: Fee is buried inside
GET /pool/stats:{ "price_token0_in_token1": 0.0001, "price_token1_in_token0": 10000, "k_invariant": "10000000000000", "fee_bps": 30, ← fee is here but requires fetching all stats "reserves": {...} }Root Cause
No dedicated fee endpoint was designed. The fee is derivable from
statsbut fetching stats requires a Soroban RPC call to the contract, which is heavier than querying just the fee.Impact
Fix
Add
GET /pool/feeto the Core Engine pool handler:Wire into router:
Response format:
Also add to Backend
pool/client.go:And Backend pool handler:
Steps to Verify
curl http://localhost:8080/api/v1/pool/fee→{"fee_bps": 30, "fee_percent": 0.30, ...}pool.fee()API call returnsfee_bpswithout fetching full statsbpsToPercent(await poolService.getFee())shows"0.30%"