Pangea API
Historical and real-time streaming of indexed data using the Pangea client.
Getting started
Request your Passport
Join our Discord and request your Pangea Passport.
Add your credentials
Create a .env
file in your project root directory and define your credentials:
PANGEA_USERNAME=xxxxx
PANGEA_PASSWORD=xxxxx
Install the Pangea client
cargo add pangea-client
Start building
This example streams prices from the Uniswap V3 USDC/WETH 5bps pool.
Code
// Step 1: Import dependencies
use futures::StreamExt;
use std::{collections::HashSet, sync::Arc};
use pangea_client::{
core::types::ChainId, query::Bound,
ClientBuilder, Format, WsProvider,
provider::UniswapV3Provider, requests::uniswap_v3::GetPricesRequest // Get data from the Uniswap V3 Prices toolbox
};
#[tokio::main]
async fn main() {
// Step 2: Load environment variables
dotenvy::dotenv_override().ok();
// Step 3: Initialize the client
let client = match ClientBuilder::default()
.endpoint("app.pangea.foundation") // Set the endpoint
.build::<WsProvider>()
.await
{
Ok(client) => Arc::new(client),
Err(e) => {
eprintln!("Client failed to initialize:\n{e}");
return;
}
};
// Step 4: Create and send request
{
let request = GetPricesRequest { // Get prices data
chains: HashSet::from([ChainId::ETH]), // On Ethereum mainnet
from_block: Bound::FromLatest(1000), // Start the stream 1000 blocks from the latest block
to_block: Bound::Subscribe, // Subscribe to real-time stream
pool_address__in: HashSet::from(["0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640" // Filter on the USDC/WETH 5bps pool
.parse()
.unwrap()]),
..Default::default()
};
let stream = match client
.get_prices_by_format(request, Format::JsonStream, false) // Return JSONStream format
.await
{
Ok(stream) => stream,
Err(e) => {
eprintln!("Request failed\n{e}");
return;
}
};
futures::pin_mut!(stream);
// Step 5: Stream and print output
while let Some(chunk) = stream.next().await {
let chunk = String::from_utf8(chunk.unwrap()).unwrap();
println!("{chunk}");
}
}
}
Response
{
chain: 1,
block_number: 22896999,
block_hash: '0x10cbf7f2674c54baa3dc062ae8e18a6de5c527ecddc51787d7cebb38cbc74d6b',
transaction_hash: '0x6db5bb7e60f532e9ed14fb78c9ed03084a4a1a70f9994357cf03747bff1ca3aa',
transaction_index: 2,
log_index: 41,
pool_address: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
virtual0: 1.8451065547937724e-15,
virtual1: 3.904927454923885e+51,
price: 2965.9761137086434,
sender: '0x51c72848c68a965f66fa7a88855f9f7784502a7f',
receiver: '0x51c72848c68a965f66fa7a88855f9f7784502a7f',
amount0: 110958.214084,
amount1: -37.420036648501004,
liquidity: 2684214455492374500,
tick: 196370,
token0_address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
token0_decimals: 6,
token0_name: 'USD//C',
token0_symbol: 'USDC',
token1_address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
token1_decimals: 18,
token1_name: 'Wrapped Ether',
token1_symbol: 'WETH',
timestamp: 1752249779
}
...
Chain selection
Each chain is identified by an endpoint and ChainId which must be configured.
Set the endpoint
Set the endpoint upon client initialisation.
.endpoint("app.pangea.foundation")
Set the ChainId
Set the ChainId in the request query parameters.
chains: HashSet::from([ChainId::ETH]),
Dataset selection
Select which dataset to request data from.
In Rust, you need to use
the provider
and the requests
:
provider::UniswapV3Provider, requests::uniswap_v3::GetPricesRequest
Then make your request:
let request = GetPricesRequest {
And use the method name:
.get_prices_by_format(request, Format::JsonStream, false)
In NodeJS and Python, you only need to make the request:
const handle = await client.get_uniswap_v3_prices(
Query parameters
Requests are filtered using query parameters, which are either mandatory or optional.
let request = GetPricesRequest {
chains: HashSet::from([ChainId::ETH]),
from_block: Bound::FromLatest(1000),
to_block: Bound::Subscribe,
pool_address__in: HashSet::from(["0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
.parse()
.unwrap()]),
..Default::default()
};
ChainId
Block range
To request data between two specific blocks, use positive integer values:
from_block: Bound::Exact(21000000),
to_block: Bound::Exact(21010000),
To request data at the latest available block, use Latest
(in Rust) or "latest"
(in NodeJS and Python):
from_block: Bound::Exact(21000000),
to_block: Bound::Latest,
To subscribe to a real-time stream of data, use Subscribe
(in Rust) or "none"
(in NodeJS and Python) as the value for to_block
:
from_block: Bound::Exact(21000000),
to_block: Bound::Subscribe,
To request data for an exact range from the latest available block, use a negative integer as the from_block
value in combination with either Latest
(in Rust) or "latest"
(in NodeJS and Python), or with Subscribe
(in Rust) or "none"
(in NodeJS and Python), as the to_block
value.
from_block: Bound::Exact(-10000),
to_block: Bound::Latest,
Optional parameters
Each dataset has its own optional query parameters, detailed descriptions of which can be found in the API reference documentation.
Parameters with the __in
suffix accept a list of values.
Parameters with the __gte
or __lte
suffix will return values greater/less than or equal to the provided value.
Complex queries can be achieved by combining any number of different query parameters.
Response format
Set the reponse format for the request.
Json
, JsonStream
, and Arrow-IPC
formats are supported.
.get_prices_by_format(request, Format::JsonStream, false)
Getting help
If you have any questions, join our Discord and get help from the community.