diff --git a/crates/metaboard/src/metaboard_client.rs b/crates/metaboard/src/metaboard_client.rs
index 514f7aee..fbb7fe57 100644
--- a/crates/metaboard/src/metaboard_client.rs
+++ b/crates/metaboard/src/metaboard_client.rs
@@ -1,6 +1,10 @@
use crate::cynic_client::{CynicClient, CynicClientError};
use crate::types::metas::*;
-use alloy::primitives::hex::{decode, encode, FromHexError};
+use alloy::primitives::{
+ hex::{decode, encode, FromHexError},
+ Address,
+};
+use core::str::FromStr;
use reqwest::Url;
use thiserror::Error;
@@ -26,6 +30,17 @@ pub enum MetaboardSubgraphClientError {
#[source]
source: FromHexError,
},
+ #[error("Error parsing metaboard address {address}: {source}")]
+ AddressParseError {
+ address: String,
+ #[source]
+ source:
::Err,
+ },
+ #[error("Request error fetching metaboard addresses: {source}")]
+ RequestErrorMetaBoards {
+ #[source]
+ source: CynicClientError,
+ },
}
pub struct MetaboardSubgraphClient {
@@ -111,6 +126,35 @@ impl MetaboardSubgraphClient {
Ok(meta_bytes)
}
+
+ /// Fetch MetaBoard contract addresses from the subgraph.
+ pub async fn get_metaboard_addresses(
+ &self,
+ first: Option,
+ skip: Option,
+ ) -> Result, MetaboardSubgraphClientError> {
+ let data =
+ self.query::(
+ MetaBoardAddressesVariables { first, skip },
+ )
+ .await
+ .map_err(|e| MetaboardSubgraphClientError::RequestErrorMetaBoards { source: e })?;
+
+ let mut addresses = Vec::with_capacity(data.meta_boards.len());
+ for board in data.meta_boards {
+ let address_hex = board.address.0;
+ let address = Address::from_str(&address_hex).map_err(|e| {
+ MetaboardSubgraphClientError::AddressParseError {
+ address: address_hex.clone(),
+ source: e,
+ }
+ })?;
+
+ addresses.push(address);
+ }
+
+ Ok(addresses)
+ }
}
#[cfg(test)]
@@ -289,4 +333,69 @@ mod tests {
_ => panic!("Unexpected result: {:?}", result),
}
}
+
+ #[tokio::test]
+ async fn test_get_metaboard_addresses_success() {
+ let server = MockServer::start_async().await;
+ let url = Url::parse(&server.url("/")).unwrap();
+
+ server.mock(|when, then| {
+ when.method(POST).path("/").body_contains("metaBoards");
+ then.status(200).json_body_obj(&{
+ serde_json::json!({
+ "data": {
+ "metaBoards": [
+ {
+ "address": "0x0000000000000000000000000000000000000001",
+ },
+ {
+ "address": "0x0000000000000000000000000000000000000002",
+ }
+ ]
+ }
+ })
+ });
+ });
+
+ let client = MetaboardSubgraphClient::new(url);
+
+ let result = client
+ .get_metaboard_addresses(Some(10), Some(0))
+ .await
+ .unwrap();
+
+ assert_eq!(result.len(), 2);
+
+ assert_eq!(
+ result[0],
+ Address::from_str("0x0000000000000000000000000000000000000001").unwrap()
+ );
+ assert_eq!(
+ result[1],
+ Address::from_str("0x0000000000000000000000000000000000000002").unwrap()
+ );
+ }
+
+ #[tokio::test]
+ async fn test_get_metaboard_addresses_empty() {
+ let server = MockServer::start_async().await;
+ let url = Url::parse(&server.url("/")).unwrap();
+
+ server.mock(|when, then| {
+ when.method(POST).path("/").body_contains("metaBoards");
+ then.status(200).json_body_obj(&{
+ serde_json::json!({
+ "data": {
+ "metaBoards": []
+ }
+ })
+ });
+ });
+
+ let client = MetaboardSubgraphClient::new(url);
+
+ let result = client.get_metaboard_addresses(Some(5), None).await.unwrap();
+
+ assert!(result.is_empty());
+ }
}
diff --git a/crates/metaboard/src/types/metas.rs b/crates/metaboard/src/types/metas.rs
index 37164c1c..e8a71eb3 100644
--- a/crates/metaboard/src/types/metas.rs
+++ b/crates/metaboard/src/types/metas.rs
@@ -23,6 +23,19 @@ pub struct MetasBySubject {
pub meta_v1_s: Vec,
}
+#[derive(cynic::QueryVariables, Debug, Default)]
+pub struct MetaBoardAddressesVariables {
+ pub first: Option,
+ pub skip: Option,
+}
+
+#[derive(cynic::QueryFragment, Debug)]
+#[cynic(graphql_type = "Query", variables = "MetaBoardAddressesVariables")]
+pub struct MetaBoardAddresses {
+ #[arguments(first: $first, skip: $skip)]
+ pub meta_boards: Vec,
+}
+
#[derive(cynic::QueryFragment, Debug)]
pub struct MetaV1 {
pub meta_hash: Bytes,